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