]> defiant.homedns.org Git - pyshared.git/blob - bootloader.py
Added jump to bootloader
[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                                 buf_addr+=self.pagesize
96                                 diff = self.pagesize-len(buf)
97                                 buf+=chr(0xff)*diff # fill with 0xff
98                                 handle(buf_addr, buf[:self.pagesize])
99                                 if lFirstRow: # was first
100                                         buf_addr = lFirstRow[0]
101                                         buf = lFirstRow[1]
102                                         print "Addr (First) 0x%x" % buf_addr
103                                         handle(buf_addr, buf)
104                         else:
105                                 raise("Unknown type %d" % typ)
106                         
107                         next_addr = addr+num
108                 print "Byte count:", count
109                 f.close()
110
111         def jump(self, addr):
112                 self.run_cmd(CMD_JUMP)
113
114         def wait_ping(self):
115                 while(True):
116                         try:
117                                 self.identify()
118                                 break
119                         except:
120                                 sleep(1)
121
122         def load(self, filename):
123                 print "Erase..."
124                 self.erase_all()
125                 sleep(5)
126                 self.wait_ping()
127                 print "Erase Done."
128                 print "Program..."
129                 t1 = time()
130                 self.program(filename)
131                 print "Time: %.1fs" % (time() - t1)
132                 print "Compare..."
133                 t1 = time()
134                 self.compare(filename)
135                 print "Time: %.1fs" % (time() - t1)
136                 print "Jump:"
137                 self.jump(self.boot_addr)
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
168                 return i
169
170
171 def to_bootloader(addr):
172         dev = i2c(addr)
173         s = struct.pack("BB", 0xff, 0xa5)
174         dev.write(s)
175         dev.close()
176
177
178 if __name__ == "__main__":
179         usage = "usage: %prog [options] addr [ihex]"
180         parser = OptionParser(usage=usage)
181         parser.add_option("-b", "--start-bootloader", action="store_true", dest="bToBoot", default=False, help="Start Bootloader")
182         parser.add_option("-j", "--jump", action="store_true", dest="bJump", default=False, help="Jump to Program")
183
184         (options, args) = parser.parse_args()
185         if not args:
186                 print "Missing Address"
187         else:
188                 addr = int(args[0], 16)
189                 if options.bToBoot:
190                         to_bootloader(addr)
191                         sleep(1)
192                 loader = bootloader(addr)
193                 if len(args) > 1:
194                         loader.load(args[1])