#!/usr/bin/env python import serial import sys import time # the PIC will reject any attempt to write to addresses before this BOOTLOADER_END = 0x200 class IHXFile: def __init__(self, filename): self.fr = file(filename, "r") d = self.fr.read() d = d.splitlines() self.records = [] for l in d: r = {} if l[0] != ":": print "invalid HEX file" self.records = "Fail" return r['count'] = int(l[1:3], 16) r['addr'] = int(l[3:7], 16) r['type'] = int(l[7:9], 16) r['data'] = "" for c in range(9, 9 + (r['count'] * 2), 2): r['data'] += chr(int(l[c:c+2],16)) chk = r['count'] chk += (r['addr'] >> 8) chk += (r['addr'] & 0xFF) chk += (r['type']) for ca in r['data']: chk += ord(ca) chk += int(l[9 + (r['count']*2):11 + (r['count']*2)], 16) chk &= 0xFF if chk != 0: print "Checksum error" self.records = "Fail" return self.records.append(r) self.rptr = 0 self.bptr = 0 def next_64bytes(self): # return a string containing 64 bytes of data and the start address # in a struct with a type out = {} out['data'] = "" out['addr'] = -1 out['type'] = 0 while len(out['data']) < 64: rec = self.records[self.rptr] # print rec # return {'type': 1} if rec['type'] == 0: # normal data record if out['addr'] == -1: out['addr'] = ((rec['addr'] + self.bptr) / 64) * 64 # print "out['addr'] =", ((rec['addr'] + self.bptr) / 64) * 64 # print "rec['addr'] + self.bptr =", rec['addr'] + self.bptr while(out['addr'] + len(out['data']) < (rec['addr'] + self.bptr)): out['data'] += "\x00" while((self.bptr < len(rec['data'])) and (len(out['data']) < 64)): if (out['addr'] + len(out['data'])) == (rec['addr'] + self.bptr): # this segment is consecutive to what went before out['data'] += rec['data'][self.bptr] self.bptr += 1 else: # print out['addr'] + len(out['data']), rec['addr'] + self.bptr # segment is non-consecutive, pad with zeros until we get to # 64 bytes in this packet or the start of the next record out['data'] += "\x00" if len(out['data']) < 64: # otherwise the record ran out of data self.bptr = 0 self.rptr += 1 elif rec['type'] == 1: # end of file if len(out['data']) > 0: # some data already so pad with zeros and don't move the record pointer while len(out['data']) < 64: out['data'] += "\x00" else: # return a list of 64 empty bytes and a null address plus the type out['data'] = "\x00" * 64 out['type'] = 1 out['addr'] = 0 self.rptr += 1 elif rec['type'] == 4: if len(out['data']) > 0: # pad the current block and return while len(out['data']) < 64: out['data'] += "\x00" else: # return a list of empty data with the new address and the type out['addr'] = (ord(rec['data'][0]) << 8) + ord(rec['data'][1]) out['data'] = "\x00" * 64 out['type'] = 4 self.rptr += 1 else: print "Unhandled record type" return -1 return out def checksum(msg): c = 0 for ca in msg: c ^= ord(ca) return chr(c) if __name__ == "__main__": s = serial.Serial("/dev/ttyS0") s.setWriteTimeout(1.0) # make sure the PIC is in run mode msg = "\x0F" while len(msg) < 22: msg += "\x55" s.write("\xAA" + msg + checksum(msg)) time.sleep(0.2) # put PIC into flash mode msg = "\x09" while len(msg) < 22: msg += " " s.write("\xAA" + msg + checksum(msg)) d = s.read() print repr(d) if d != "\x06": print "Failed to enter flash mode!" sys.exit(2) i = IHXFile(sys.argv[1]) r = i.next_64bytes() n = 0 while r['type'] != 1: print "doing record %d type %d address %04X" % (n, r['type'], r['addr']) n += 1 if r['type'] == 4: if r['addr'] < 1: msg = chr(4) + chr(r['addr'] >> 8) + chr(r['addr'] & 0xff) + "\xaa" * 64 # print repr(msg[0:4]) s.write(msg + checksum(msg)) if s.read() != chr(6): print "Command to set high address rejected!" sys.exit(2) else: # print "" break else: if r['addr'] > BOOTLOADER_END: msg = chr(0) + chr(r['addr'] >> 8) + chr(r['addr'] & 0xFF) + r['data'] # print "Length", len(msg), repr(msg) #for c in msg + checksum(msg): # s.write(c) # time.sleep(0.2) s.write(msg + checksum(msg)) if s.read() != chr(6): print "Write to address %04X rejected!" % r['addr'] sys.exit(2) # else: # print "too early" #print "%04X %04X:" % (ha, r['addr']), repr(r['data']) time.sleep(0.2) r = i.next_64bytes() msg = chr(1) + chr(0) + chr(0) + "\xaa" * 64 s.write(msg + checksum(msg)) if s.read() != chr(6): print "End and reboot not accepted!" sys.exit(2)