]> defiant.homedns.org Git - pyshared.git/blob - bootloader.py
bootloader: Fix addr on last page
[pyshared.git] / bootloader.py
1 #!/usr/bin/env python
2 # -*- coding: iso-8859-15 -*-
3
4 import struct
5 import sys
6 import socket
7 from optparse import OptionParser
8 from time import sleep, time
9 from i2c import i2c
10
11 CMD_READ = 0x1
12 CMD_ERASE = 0x2
13 CMD_WRITE = 0x3
14 CMD_ERASE_ALL = 0x5
15 CMD_JUMP = 0x6
16 CMD_PAGESIZE = 0x7
17 CMD_I2C_ADDR = 0x80
18 CMD_INFO = 0x99
19
20 class bootloader:
21         def __init__(self, addr):
22                 self.i2c_addr = addr
23                 self.boot_addr = 0x0
24
25                 if not self.identify():
26                         raise Exception("Bootloader not running")
27                 self.pagesize = self.get_pagesize()
28         
29         def read_mem(self, addr, num):
30                 self.run_cmd(CMD_READ, addr, num)
31                 return self.read(num)
32
33         def erase(self, addr):
34                 self.run_cmd(CMD_ERASE)
35         
36         def erase_all(self):
37                 self.run_cmd(CMD_ERASE_ALL)
38
39         def __compare_memarea(self, addr, data):
40                 mem_cmp = self.read_mem(addr, self.pagesize)
41                 if mem_cmp != data:
42                         print "Expected:", data.encode("hex")
43                         print "Got:     ", mem_cmp.encode("hex")
44                         raise Exception("Compare mismatch at 0x%x" % addr)
45                 return
46         
47         def __program_memarea(self, addr, data):
48                 self.run_cmd(CMD_WRITE, addr, self.pagesize, data)
49                 sleep(0.1)
50
51         def compare(self, filename):
52                 return self.__process_hex(filename, self.__compare_memarea)
53         
54         def program(self, filename):
55                 return self.__process_hex(filename, self.__program_memarea)
56
57         def __process_hex(self, filename, handle):
58                 next_addr = None
59                 buf = ""
60                 lFirstRow = None
61
62                 f = open(filename, "r")
63                 count=0
64                 for line in f:
65                         if line[0] != ':':
66                                 raise Exception("Bad line start character")
67                         hex = line[1:].replace("\r\n", "")
68                         data = hex.decode("hex")
69                         num = ord(data[0])
70                         chksum = 0
71                         for c in data:
72                                 chksum+=ord(c)
73                         if chksum % 256 != 0:
74                                 raise Exception("Checksum error")
75                         addr, typ, data, chksum = struct.unpack(">HB%ssB" % num, data[1:])
76
77                         if typ == 0: # Data Record
78                                 count+=len(data)
79                                 if next_addr is not None:
80                                         if next_addr != addr:
81                                                 raise Exception("Gap in file")
82                                 buf_addr = addr-len(buf)
83                                 buf+=data
84                                 if len(buf) >= self.pagesize:
85                                         if not lFirstRow:
86                                                 # do the first as last one
87                                                 lFirstRow = (buf_addr, buf[:self.pagesize])
88                                         else:
89                                                 print "Addr 0x%x" % buf_addr
90                                                 handle(buf_addr, buf[:self.pagesize])
91                                                 buf_addr += self.pagesize
92                                         buf = buf[self.pagesize:]
93                         elif typ == 3: # Start Segment Address Record
94                                 self.boot_addr = int(data.encode("hex"), 16)
95                         elif typ == 1: # End of File Record
96                                 if len(buf) > 0:
97                                         # Send unhandled data
98                                         print "Addr (rest) 0x%x" % buf_addr
99                                         diff = self.pagesize-len(buf)
100                                         buf+=chr(0xff)*diff # fill with 0xff
101                                         handle(buf_addr, buf[:self.pagesize])
102                                         if lFirstRow: # was first
103                                                 buf_addr = lFirstRow[0]
104                                                 buf = lFirstRow[1]
105                                                 print "Addr (First) 0x%x" % buf_addr
106                                                 handle(buf_addr, buf)
107                         else:
108                                 raise Exception("Unknown type %d" % typ)
109                         
110                         next_addr = addr+num
111                 print "Byte count:", count
112                 f.close()
113
114         def jump(self, addr):
115                 self.run_cmd(CMD_JUMP)
116
117         def wait_ping(self):
118                 while(True):
119                         try:
120                                 self.identify()
121                                 break
122                         except:
123                                 sleep(1)
124
125         def load(self, filename):
126                 print "Erase..."
127                 self.erase_all()
128                 sleep(5)
129                 self.wait_ping()
130                 print "Erase Done."
131                 print "Program..."
132                 t1 = time()
133                 self.program(filename)
134                 print "Time: %.1fs" % (time() - t1)
135                 print "Compare..."
136                 t1 = time()
137                 self.compare(filename)
138                 print "Time: %.1fs" % (time() - t1)
139
140         def write(self, s):
141                 dev = i2c(self.i2c_addr)
142                 dev.write(s)
143                 dev.close()
144
145         def read(self, num):
146                 dev = i2c(self.i2c_addr)
147                 s = dev.read(num)
148                 dev.close()
149                 return s
150         
151         def run_cmd(self, cmd, addr=0x0, num=0, data=""):
152                 length = len(data)
153                 s1 = struct.pack("<BLB%ds" % (length), cmd, addr, num, data)
154                 self.write(s1)
155                 s2 = struct.pack("B", 0xff)
156                 self.write(s2)
157
158         def identify(self):
159                 self.run_cmd(CMD_INFO)
160                 s = self.read(10)
161                 return s == "Bootloader"
162
163         def get_pagesize(self):
164                 self.run_cmd(CMD_PAGESIZE)
165                 s = self.read(1)
166                 i = ord(s[0])
167                 if i not in [64, 128]:
168                         raise Exception("Unsupported pagesize")
169                 return i
170
171         def set_i2c_addr(self, addr):
172                 self.run_cmd(CMD_I2C_ADDR, addr)
173
174
175 def to_bootloader(addr):
176         dev = i2c(addr)
177         s = struct.pack("BB", 0xff, 0xa5)
178         dev.write(s)
179         dev.close()
180
181
182 if __name__ == "__main__":
183         usage = "usage: %prog [options] addr [ihex]"
184         parser = OptionParser(usage=usage)
185         parser.add_option("-b", "--start-bootloader", action="store_true", dest="bToBoot", default=False, help="Start Bootloader")
186         parser.add_option("-j", "--jump", action="store_true", dest="bJump", default=False, help="Jump to Program")
187         parser.add_option("-s", "--set-i2c-addr", dest="i2c_addr", type="int", help="Set I2C address")
188
189         (options, args) = parser.parse_args()
190         if not args:
191                 print "Missing Address"
192         else:
193                 addr = int(args[0], 16)
194                 if options.bToBoot:
195                         to_bootloader(addr)
196                         sleep(1)
197                 loader = bootloader(addr)
198                 if options.i2c_addr is not None:
199                         print "Setting i2c address to 0x%X" % (options.i2c_addr)
200                         loader.set_i2c_addr(options.i2c_addr)
201                 if len(args) > 1:
202                         loader.load(args[1])
203                 if options.bJump:
204                         print "Jump to Program"
205                         loader.jump(0x0)