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