chiark / gitweb /
Open the serial port in the thread, so it no longer blocks the GUI during auto-detect...
[cura.git] / Cura / avr_isp / stk500v2.py
1 import os, struct, sys, time\r
2 \r
3 from serial import Serial\r
4 from serial import SerialException\r
5 \r
6 import ispBase, intelHex\r
7 \r
8 class Stk500v2(ispBase.IspBase):\r
9         def __init__(self):\r
10                 self.serial = None\r
11                 self.seq = 1\r
12                 self.lastAddr = -1\r
13         \r
14         def connect(self, port = 'COM3', speed = 115200):\r
15                 if self.serial != None:\r
16                         self.close()\r
17                 try:\r
18                         self.serial = Serial(port, speed, timeout=1, writeTimeout=10000)\r
19                 except SerialException as e:\r
20                         raise ispBase.IspError("Failed to open serial port")\r
21                 except:\r
22                         raise ispBase.IspError("Unexpected error while connecting to serial port:" + port + ":" + str(sys.exc_info()[0]))\r
23                 self.seq = 1\r
24                 \r
25                 #Reset the controller\r
26                 self.serial.setDTR(1)\r
27                 time.sleep(0.1)\r
28                 self.serial.setDTR(0)\r
29                 time.sleep(0.2)\r
30                 \r
31                 self.sendMessage([1])\r
32                 if self.sendMessage([0x10, 0xc8, 0x64, 0x19, 0x20, 0x00, 0x53, 0x03, 0xac, 0x53, 0x00, 0x00]) != [0x10, 0x00]:\r
33                         self.close()\r
34                         raise ispBase.IspError("Failed to enter programming mode")\r
35 \r
36         def close(self):\r
37                 if self.serial != None:\r
38                         self.serial.close()\r
39                         self.serial = None\r
40 \r
41         #Leave ISP does not reset the serial port, only resets the device, and returns the serial port after disconnecting it from the programming interface.\r
42         #       This allows you to use the serial port without opening it again.\r
43         def leaveISP(self):\r
44                 if self.serial != None:\r
45                         if self.sendMessage([0x11]) != [0x11, 0x00]:\r
46                                 raise ispBase.IspError("Failed to leave programming mode")\r
47                         ret = self.serial\r
48                         self.serial = None\r
49                         return ret\r
50                 return None\r
51         \r
52         def isConnected(self):\r
53                 return self.serial != None\r
54         \r
55         def sendISP(self, data):\r
56                 recv = self.sendMessage([0x1D, 4, 4, 0, data[0], data[1], data[2], data[3]])\r
57                 return recv[2:6]\r
58         \r
59         def writeFlash(self, flashData):\r
60                 #Set load addr to 0, in case we have more then 64k flash we need to enable the address extension\r
61                 flashSize = self.chip['pageSize'] * 2 * self.chip['pageCount']\r
62                 if flashSize > 0xFFFF:\r
63                         self.sendMessage([0x06, 0x80, 0x00, 0x00, 0x00])\r
64                 else:\r
65                         self.sendMessage([0x06, 0x00, 0x00, 0x00, 0x00])\r
66                 \r
67                 loadCount = (len(flashData) + 0xFF) / 0x100\r
68                 for i in xrange(0, loadCount):\r
69                         recv = self.sendMessage([0x13, 0x01, 0x00, 0xc1, 0x0a, 0x40, 0x4c, 0x20, 0x00, 0x00] + flashData[(i * 0x100):(i * 0x100 + 0x100)])\r
70                         if self.progressCallback != None:\r
71                                 self.progressCallback(i + 1, loadCount*2)\r
72         \r
73         def verifyFlash(self, flashData):\r
74                 #Set load addr to 0, in case we have more then 64k flash we need to enable the address extension\r
75                 flashSize = self.chip['pageSize'] * 2 * self.chip['pageCount']\r
76                 if flashSize > 0xFFFF:\r
77                         self.sendMessage([0x06, 0x80, 0x00, 0x00, 0x00])\r
78                 else:\r
79                         self.sendMessage([0x06, 0x00, 0x00, 0x00, 0x00])\r
80                 \r
81                 loadCount = (len(flashData) + 0xFF) / 0x100\r
82                 for i in xrange(0, loadCount):\r
83                         recv = self.sendMessage([0x14, 0x01, 0x00, 0x20])[2:0x102]\r
84                         if self.progressCallback != None:\r
85                                 self.progressCallback(loadCount + i + 1, loadCount*2)\r
86                         for j in xrange(0, 0x100):\r
87                                 if i * 0x100 + j < len(flashData) and flashData[i * 0x100 + j] != recv[j]:\r
88                                         raise ispBase.IspError('Verify error at: 0x%x' % (i * 0x100 + j))\r
89 \r
90         def sendMessage(self, data):\r
91                 message = struct.pack(">BBHB", 0x1B, self.seq, len(data), 0x0E)\r
92                 for c in data:\r
93                         message += struct.pack(">B", c)\r
94                 checksum = 0\r
95                 for c in message:\r
96                         checksum ^= ord(c)\r
97                 message += struct.pack(">B", checksum)\r
98                 try:\r
99                         self.serial.write(message)\r
100                         self.serial.flush()\r
101                 except SerialTimeoutException:\r
102                         raise ispBase.IspError('Serial send timeout')\r
103                 self.seq = (self.seq + 1) & 0xFF\r
104                 return self.recvMessage()\r
105         \r
106         def recvMessage(self):\r
107                 state = 'Start'\r
108                 checksum = 0\r
109                 while True:\r
110                         s = self.serial.read()\r
111                         if len(s) < 1:\r
112                                 raise ispBase.IspError("Timeout")\r
113                         b = struct.unpack(">B", s)[0]\r
114                         checksum ^= b\r
115                         #print(hex(b))\r
116                         if state == 'Start':\r
117                                 if b == 0x1B:\r
118                                         state = 'GetSeq'\r
119                                         checksum = 0x1B\r
120                         elif state == 'GetSeq':\r
121                                 state = 'MsgSize1'\r
122                         elif state == 'MsgSize1':\r
123                                 msgSize = b << 8\r
124                                 state = 'MsgSize2'\r
125                         elif state == 'MsgSize2':\r
126                                 msgSize |= b\r
127                                 state = 'Token'\r
128                         elif state == 'Token':\r
129                                 if b != 0x0E:\r
130                                         state = 'Start'\r
131                                 else:\r
132                                         state = 'Data'\r
133                                         data = []\r
134                         elif state == 'Data':\r
135                                 data.append(b)\r
136                                 if len(data) == msgSize:\r
137                                         state = 'Checksum'\r
138                         elif state == 'Checksum':\r
139                                 if checksum != 0:\r
140                                         state = 'Start'\r
141                                 else:\r
142                                         return data\r
143 \r
144 \r
145 def main():\r
146         programmer = Stk500v2()\r
147         programmer.connect()\r
148         programmer.programChip(intelHex.readHex("cfg_4f55234def059.hex"))\r
149         sys.exit(1)\r
150 \r
151 if __name__ == '__main__':\r
152         main()\r