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