]> defiant.homedns.org Git - pyshared.git/blob - bootloader.py
Bootloader: Allow to set i2c addr
[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 = buf[self.pagesize:]
92                         elif typ == 3: # Start Segment Address Record
93                                 self.boot_addr = int(data.encode("hex"), 16)
94                         elif typ == 1: # End of File Record
95                                 if len(buf) > 0:
96                                         # Send unhandled data
97                                         print "Addr (rest) 0x%x" % buf_addr
98                                         diff = self.pagesize-len(buf)
99                                         buf+=chr(0xff)*diff # fill with 0xff
100                                         handle(buf_addr, buf[:self.pagesize])
101                                         if lFirstRow: # was first
102                                                 buf_addr = lFirstRow[0]
103                                                 buf = lFirstRow[1]
104                                                 print "Addr (First) 0x%x" % buf_addr
105                                                 handle(buf_addr, buf)
106                         else:
107                                 raise Exception("Unknown type %d" % typ)
108                         
109                         next_addr = addr+num
110                 print "Byte count:", count
111                 f.close()
112
113         def jump(self, addr):
114                 self.run_cmd(CMD_JUMP)
115
116         def wait_ping(self):
117                 while(True):
118                         try:
119                                 self.identify()
120                                 break
121                         except:
122                                 sleep(1)
123
124         def load(self, filename):
125                 print "Erase..."
126                 self.erase_all()
127                 sleep(5)
128                 self.wait_ping()
129                 print "Erase Done."
130                 print "Program..."
131                 t1 = time()
132                 self.program(filename)
133                 print "Time: %.1fs" % (time() - t1)
134                 print "Compare..."
135                 t1 = time()
136                 self.compare(filename)
137                 print "Time: %.1fs" % (time() - t1)
138
139         def write(self, s):
140                 dev = i2c(self.i2c_addr)
141                 dev.write(s)
142                 dev.close()
143
144         def read(self, num):
145                 dev = i2c(self.i2c_addr)
146                 s = dev.read(num)
147                 dev.close()
148                 return s
149         
150         def run_cmd(self, cmd, addr=0x0, num=0, data=""):
151                 length = len(data)
152                 s1 = struct.pack("<BLB%ds" % (length), cmd, addr, num, data)
153                 self.write(s1)
154                 s2 = struct.pack("B", 0xff)
155                 self.write(s2)
156
157         def identify(self):
158                 self.run_cmd(CMD_INFO)
159                 s = self.read(10)
160                 return s == "Bootloader"
161
162         def get_pagesize(self):
163                 self.run_cmd(CMD_PAGESIZE)
164                 s = self.read(1)
165                 i = ord(s[0])
166                 if i not in [64, 128]:
167                         raise Exception("Unsupported pagesize")
168                 return i
169
170         def set_i2c_addr(self, addr):
171                 self.run_cmd(CMD_I2C_ADDR, addr)
172
173
174 def to_bootloader(addr):
175         dev = i2c(addr)
176         s = struct.pack("BB", 0xff, 0xa5)
177         dev.write(s)
178         dev.close()
179
180
181 if __name__ == "__main__":
182         usage = "usage: %prog [options] addr [ihex]"
183         parser = OptionParser(usage=usage)
184         parser.add_option("-b", "--start-bootloader", action="store_true", dest="bToBoot", default=False, help="Start Bootloader")
185         parser.add_option("-j", "--jump", action="store_true", dest="bJump", default=False, help="Jump to Program")
186         parser.add_option("-s", "--set-i2c-addr", dest="i2c_addr", type="int", help="Set I2C address")
187
188         (options, args) = parser.parse_args()
189         if not args:
190                 print "Missing Address"
191         else:
192                 addr = int(args[0], 16)
193                 if options.bToBoot:
194                         to_bootloader(addr)
195                         sleep(1)
196                 loader = bootloader(addr)
197                 if options.i2c_addr is not None:
198                         print "Setting i2c address to 0x%X" % (options.i2c_addr)
199                         loader.set_i2c_addr(options.i2c_addr)
200                 if len(args) > 1:
201                         loader.load(args[1])
202                 if options.bJump:
203                         print "Jump to Program"
204                         loader.jump(0x0)