two become one ;) merged kernel.py into frprog.py
[pyfrprog.git] / frprog.py
1 #!/usr/bin/env python
2 import sys, time
3 from SerialPort_linux import *
4
5 # serial device to communicate with
6 DEVICE="/dev/ttyUSB0"
7 # baudrate used for initialization
8 INIT_BAUDRATE=9600
9 # baudrate used for communication with the internal bootloader after init
10 BOOTLOADER_BAUDRATE=38400
11 # baudrate used for communication with the pkernel program that does the flashing eventually
12 KERNEL_BAUDRATE=115200
13
14 # contains the last received checksum from a READ, WRITE or CHECKSUM command
15 last_checksum = 0
16
17 def sendByte(byte):
18         time.sleep(0.001) # just to get sure, wait 1ms
19         tty.write(chr(byte))
20
21 def sendWord(word):
22         sendByte(word & 0xFF)
23         sendByte((word >> 8) & 0xFF)
24
25 def sendDWord(dword):
26         sendByte(dword & 0xFF)
27         sendByte((dword >> 8) & 0xFF)
28         sendByte((dword >> 16) & 0xFF)
29         sendByte((dword >> 24) & 0xFF)
30
31 def recvByte():
32         return ord(tty.read())
33
34 def recvChecksum():
35         global last_checksum
36         last_checksum = recvByte()
37         last_checksum |= (recvByte() << 8)
38
39 def cmdREAD(address, size):
40         # send READ command
41         sendByte(0x01)
42         if (recvByte() != 0xF1):
43                 raise Exception
44         sendByte(0x02)
45         if (recvByte() != 0x82):
46                 raise Exception
47         # tell desired address and size
48         sendDWord(address)
49         sendWord(size)
50         # get binary stream of data
51         data = []
52         for i in range(0, size):
53                 data.append(recvByte())
54         # get checksum
55         recvChecksum()
56         return data
57
58 def cmdWRITE(address, size, data):
59         # send WRITE command
60         sendByte(0x01)
61         if (recvByte() != 0xF1):
62                 raise Exception
63         sendByte(0x03)
64         if (recvByte() != 0x83):
65                 raise Exception
66         # tell desired address and size
67         sendDWord(address)
68         sendWord(size)
69         # write binary stream of data
70         for i in range(0, size):
71                 sendByte(data[i])
72         # get checksum
73         recvChecksum()
74
75 # TODO: test this function!
76 def cmdCALL(address):
77         # send CALL command
78         sendByte(0x01)
79         if (recvByte() != 0xF1):
80                 raise Exception
81         sendByte(0x04)
82         if (recvByte() != 0x84):
83                 raise Exception
84         # tell desired address
85         sendDWord(address)
86         # wait for return parameter - not needed here!
87         #return recvByte()
88
89 # TODO: test this function!
90 def cmdCHECKSUM():
91         # call CHECKSUM command
92         sendByte(0x01)
93         if (recvByte() != 0xF1):
94                 raise Exception
95         sendByte(0x05)
96         if (recvByte() != 0x84):
97                 raise Exception
98         # get checksum
99         recvChecksum()
100
101 def cmdBAUDRATE(baudrate):
102         # send BAUDRATE command
103         sendByte(0x01)
104         if (recvByte() != 0xF1):
105                 raise Exception
106         sendByte(0x06)
107         if (recvByte() != 0x86):
108                 raise Exception
109         # send desired baudrate
110         sendDWord(baudrate)
111
112 def pkernCHIPERASE():
113         sendByte(0x15)
114         if (recvByte() != 0x45):
115                 raise Exception
116         # wait till completion...
117         if (recvByte() != 0x23):
118                 raise Exception
119
120 def pkernERASE(address, size):
121         sendByte(0x12)
122         if (recvByte() != 0x11):
123                 raise Exception
124         sendDWord(address)
125         sendWord(size)
126         if (recvByte() != 0x18):
127                 raise Exception
128
129
130 def pkernWRITE(address, size, data):
131         # send WRITE command
132         sendByte(0x13)
133         if (recvByte() != 0x37):
134                 raise Exception
135         # tell desired address and size
136         sendDWord(address)
137         sendWord(size)
138
139         # write binary stream of data
140         for i in range(0, size):
141                 sendByte(data[i])
142
143         if (recvByte() != 0x28):
144                 raise Exception
145
146
147 class FlashSequence(object):
148         def __init__(self, address, data):
149                 self.address = address
150                 self.data = data
151
152 def readMHXFile(filename): # desired mhx filename
153         fp = open(filename, "r")
154         retval = [] # returns a list of FlashSequence objects
155         linecount = 0
156         for line in fp:
157                 linecount += 1
158                 # get rid of newline characters
159                 line = line.strip()
160
161                 # we're only interested in S2 (data sequence with 3 address bytes) records by now
162                 if line[0:2] == "S2":
163                         byte_count = int(line[2:4], 16)
164                         # just to get sure, check if byte count field is valid
165                         if (len(line)-4) != (byte_count*2):
166                                 print sys.argv[0] + ": Warning - inavlid byte count field in " + \
167                                         sys.argv[1] + ":" + str(linecount) + ", skipping line!"
168                                 continue
169
170                         # address and checksum bytes are not needed
171                         byte_count -= 4
172                         address = int(line[4:10], 16)
173                         datastr = line[10:10+byte_count*2]
174
175                         # convert data hex-byte-string to real byte data list
176                         data = []
177                         for i in range(0, len(datastr)/2):
178                                 data.append(int(datastr[2*i:2*i+2], 16))
179
180                         # add flash sequence to our list
181                         retval.append(FlashSequence(address, data))
182         fp.close()
183         return retval
184
185
186 # check command line arguments
187 if len(sys.argv) != 3:
188         print "Usage: " + sys.argv[0] + " [pkernel mhx-file] [target mhx-file]"
189         sys.exit(1)
190
191 # read in data from mhx-files before starting
192 try:
193         bootloaderseqs = readMHXFile(sys.argv[1])
194         pkernelseqs = readMHXFile(sys.argv[2])
195 except IOError as error:
196         print sys.argv[0] + ": Error - couldn't open file " + error.filename + "!"
197         sys.exit(1)
198
199 print "Initializing serial port..."
200 tty = SerialPort(DEVICE, 100, INIT_BAUDRATE)
201
202 print "Please press RESET on your board..."
203
204 while True:
205         tty.write('V')
206         tty.flush()
207         try: 
208                 if tty.read() == 'F':
209                         break
210         except SerialPortException: 
211                 # timeout happened, who cares ;-)
212                 pass
213
214 print "OK, trying to set baudrate..."
215 # set baudrate
216 cmdBAUDRATE(BOOTLOADER_BAUDRATE)
217 tty = SerialPort(DEVICE, 100, BOOTLOADER_BAUDRATE)
218
219 print "Transfering pkernel program to IRAM",
220 # let the fun begin!
221 for seq in bootloaderseqs:
222         if(seq.address <= 0x40000):
223                 addr = seq.address
224         else:
225                 continue
226         #print "RAMing", len(seq.data), "bytes at address", hex(addr)
227         cmdWRITE(addr, len(seq.data), seq.data)
228         tty.flush()
229         sys.stdout.write(".")
230         sys.stdout.flush()
231 print
232
233 # execute our pkernel finally and set pkernel conform baudrate
234 cmdCALL(0x30000)
235 time.sleep(0.5) # just to get sure that the pkernel is really running!
236 del tty
237 tty = SerialPort(DEVICE, None, KERNEL_BAUDRATE)
238
239 print "Performing ChipErase..."
240 pkernCHIPERASE()
241 print "Chip erasing done."
242
243 print "Flashing",
244 for seq in pkernelseqs:
245         # skip seqs only consisting of 0xffs
246         seqset = list(set(seq.data))
247         if len(seqset) == 1 and seqset[0] == 0xff:
248                 continue
249         #print "Flashing", len(seq.data), "bytes at address", hex(seq.address)
250         pkernWRITE(seq.address, len(seq.data), seq.data)
251         tty.flush()
252         sys.stdout.write(".")
253         sys.stdout.flush()
254 print
255 print "Flashing done."
256
257 sendByte(0x97) # exit and restart
258 print "Program was started. Have fun!"
259
260 # some tests here.......
261 """
262 # execute (existing) program in ram
263 cmdCALL(0x00033ffc)
264 sys.exit(0)
265 """
266
267 # read something from the IRAM
268 #print cmdREAD(0x00030000, 32)
269
270 #data = []
271 #for i in range(0, 32):
272 #       data.append(i)
273 #cmdWRITE(0x00030000, 32, data)
274
275
276 """
277 # write something to the begin of the IRAM
278 data_wr = []
279 checksum = 0
280 for i in range(0, 0x400):
281         value = i%256
282         data_wr.append(value)
283         checksum = (checksum + value) % (2**16)
284
285 print "Calculated checksum:", checksum
286 print "Writing", data_wr, "to the IRAM..."
287 cmdWRITE(0x00030000, len(data_wr), data_wr)
288 print "Received Checksum:", last_checksum
289 print
290
291 print "Reading from the IRAM again..."
292 data_re = cmdREAD(0x00030000, len(data_wr))
293 print "Received data:", data_re, "Checksum:", last_checksum
294 """
295
296 """
297 # see whats in the iram at the moment
298 data_wr = []
299 print "Reading from the IRAM..."
300 data_re = cmdREAD(0x00030000, 0x10000-4)
301 print "Received data:", data_re, "Checksum:", last_checksum
302 """
303
304 """
305 # see whats in the dram at the moment
306 data_wr = []
307 print "Reading from the DRAM..."
308 data_re = cmdREAD(0x0002C000, 0x10000-0xC000-4)
309 print "Received data:", data_re, "Checksum:", last_checksum
310 """
311
312 """
313 # blank the iram
314 data_wr = []
315 for i in range(0, 0x10000-4):
316         value = 0
317         data_wr.append(value)
318
319 print "Writing", data_wr, "to the IRAM..."
320 cmdWRITE(0x00030000, len(data_wr), data_wr)
321 print "Received Checksum:", last_checksum
322 print
323 """
324
325 """
326 # blank the dram
327 data_wr = []
328 for i in range(0, 0x10000-0xC000-4):
329         value = 0
330         data_wr.append(value)
331
332 print "Writing", data_wr, "to the DRAM..."
333 cmdWRITE(0x0002C000, len(data_wr), data_wr)
334 print "Received Checksum:", last_checksum
335 print
336 """
337
338 """
339 # write some data in the iram and try to execute it
340 data_wr =[
341                 0x9B,0x00,
342                 0x0D,0x4e,
343                 0xcf,0xf1,
344                 0x16,0x01,
345                 0x9b,0x05,
346                 0x04,0xc7,
347                 0xc1,0x06,
348                 0x16,0x56,
349                 0xe0,0xfb, #branch
350                 0x9f,0xa0,0x9f,0xa0,0x9f,0xa0, #nop
351                 0x9f,0xa0,0x9f,0xa0,0x9f,0xa0,
352                 0x9f,0xa0,0x9f,0xa0,0x9f,0xa0,
353                 0x9f,0xa0,0x9f,0xa0,0x9f,0xa0,
354                 0x9f,0xa0,0x9f,0xa0,0x9f,0xa0,
355                 0x9f,0xa0,0x9f,0xa0,0x9f,0xa0,
356                 0x9f,0xa0,0x9f,0xa0,0x9f,0xa0]
357 print "Writing", data_wr, "to the IRAM..."
358 cmdWRITE(0x00030000, len(data_wr), data_wr)
359 print "Received Checksum:", last_checksum
360 print
361 cmdCALL(0x00030000)
362 """