3 import os,sys,termios,atexit
5 from select import select
8 from matplotlib import pylab
17 warnings.filterwarnings("ignore","tempnam",RuntimeWarning, __name__)
20 log = logging.getLogger("MicrobShell")
21 _handler = logging.StreamHandler()
22 _handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
23 log.addHandler(_handler)
26 MICROB_PATH=os.path.dirname(sys.argv[0])
31 def crc_ccitt_update (crc, data):
32 """crc argument is the previous value of 16 bits crc (the initial
33 value is 0xffff). 'data' is the 8 bits value added to crc. The
34 function returns the new crc value."""
40 ret = (data << 8) & 0xffff
41 ret |= ((crc >> 8) & 0xff)
42 ret ^= ((data >> 4) & 0xff)
43 ret ^= ((data << 3) & 0xffff)
51 crc = crc_ccitt_update(crc, ord(buf[i]))
54 return (crc << 16) + (sum & 0xffff)
56 def prog_page(ser, addr, buf):
57 """program a page from buf at addr"""
59 # switch in program mode
65 if not s.endswith("addr?\r\n"):
66 print "failed (don't match addr)"
68 ser.write("%x\n"%addr)
70 if not s.startswith("ok"):
74 # fill page with buf data
75 page = [ '\xff' ] * SPM_PAGE_SIZE
77 while i < SPM_PAGE_SIZE and i < len(buf):
83 while i < SPM_PAGE_SIZE:
92 avr_crc = int(ser.readline()[0:8], 16)
96 print "failed: bad crc %x %x"%(crc, avr_crc)
102 if not s.startswith("OK"):
107 def prog_metadata(ser, addr, buf):
110 page = struct.pack(">LL", length, crc)
111 filename = os.path.join(MICROB_PATH, "binaries/%x_%x.bin"%(length, crc))
112 print "saving in %s"%(filename)
113 f = open(filename, "w")
116 return prog_page(ser, addr, page)
118 def get_same_bin_file(ser):
119 l = read32(ser, METADATA_ADDR)
120 c = read32(ser, METADATA_ADDR + 4)
121 filename = os.path.join(MICROB_PATH,
122 "binaries/%x_%x.bin"%(l, c))
125 f = open(filename, "r")
130 print "found old bin matching <%s>"%(filename)
133 def read32(ser, addr):
134 """read a 32 bits value at addr"""
142 # switch in program mode
150 if not s.endswith("addr?\r\n"):
151 print "failed (don't match addr)"
154 ser.write("%x\n"%addr)
159 def check_crc(ser, buf, offset, size):
160 """Process the crc of buf, ask for a crc of the flash, and check
161 that value is correct"""
171 if not s.endswith("addr?\r\n"):
172 print "failed <%s>"%s
174 ser.write("%x\n"%offset)
178 if not s.startswith("size?"):
181 ser.write("%x\n"%size)
184 crc = do_crc(buf[offset:offset+size])
185 avr_crc = int(ser.readline()[0:8], 16)
191 def __init__(self, ser, filein, fileout=None):
194 self.fin = open(filein, "a", 0)
196 self.fileout = fileout
197 self.fout = open(fileout, "a", 0)
199 self.fileout = filein
202 return self.ser.fileno()
203 def read(self, *args):
204 res = self.ser.read(*args)
211 class Interp(cmd.Cmd):
213 def __init__(self, tty, baudrate=57600):
214 cmd.Cmd.__init__(self)
215 self.ser = serial.Serial(tty,baudrate=baudrate)
216 self.escape = "\x01" # C-a
217 self.quitraw = "\x02" # C-b
218 self.serial_logging = False
219 self.default_in_log_file = "/tmp/microb.in.log"
220 self.default_out_log_file = "/tmp/microb.out.log"
222 def do_quit(self, args):
225 def do_log(self, args):
226 """Activate serial logs.
227 log <filename> logs input and output to <filename>
228 log <filein> <fileout> logs input to <filein> and output to <fileout>
229 log logs to /tmp/microb.log or the last used file"""
231 if self.serial_logging:
232 log.error("Already logging to %s and %s" % (self.ser.filein,
235 self.serial_logging = True
236 files = [os.path.expanduser(x) for x in args.split()]
238 files = [self.default_in_log_file, self.default_out_log_file]
239 elif len(files) == 1:
240 self.default_in_log_file = files[0]
241 self.default_out_log_file = None
242 elif len(files) == 2:
243 self.default_in_log_file = files[0]
244 self.default_out_log_file = files[1]
246 print "Can't parse arguments"
248 self.ser = SerialLogger(self.ser, *files)
249 log.info("Starting serial logging to %s and %s" % (self.ser.filein,
253 def do_unlog(self, args):
254 if self.serial_logging:
255 log.info("Stopping serial logging to %s and %s" % (self.ser.filein,
257 self.ser = self.ser.ser
258 self.serial_logging = False
260 log.error("No log to stop")
263 def do_raw(self, args):
265 stdin = os.open("/dev/stdin",os.O_RDONLY)
266 stdout = os.open("/dev/stdout",os.O_WRONLY)
268 stdin_termios = termios.tcgetattr(stdin)
269 raw_termios = stdin_termios[:]
272 log.info("Switching to RAW mode")
275 raw_termios[0] &= ~(termios.IGNBRK | termios.BRKINT |
276 termios.PARMRK | termios.ISTRIP |
277 termios.INLCR | termios.IGNCR |
278 termios.ICRNL | termios.IXON)
280 raw_termios[1] &= ~termios.OPOST;
282 raw_termios[2] &= ~(termios.CSIZE | termios.PARENB);
283 raw_termios[2] |= termios.CS8;
285 raw_termios[3] &= ~(termios.ECHO | termios.ECHONL |
286 termios.ICANON | termios.ISIG |
289 termios.tcsetattr(stdin, termios.TCSADRAIN, raw_termios)
293 ins,outs,errs=select([stdin,self.ser],[],[])
300 self.ser.write(self.escape)
301 elif c == self.quitraw:
304 self.ser.write(self.escape)
312 os.write(stdout,self.ser.read())
314 termios.tcsetattr(stdin, termios.TCSADRAIN, stdin_termios)
315 log.info("Back to normal mode")
317 def bootloader(self, filename, boardnum):
318 self.ser.write("
\ 3")
320 self.ser.write("bootloader\n")
324 print "start programming"
325 self.ser.flushInput()
332 old_buf = get_same_bin_file(self.ser)
335 while addr < len(buf):
336 if addr > METADATA_ADDR and old_buf != None and \
337 old_buf[addr:addr+SPM_PAGE_SIZE] == buf[addr:addr+SPM_PAGE_SIZE]:
338 sys.stdout.write("-")
340 addr += SPM_PAGE_SIZE
343 if check_crc(self.ser, buf, addr, SPM_PAGE_SIZE) == 0:
344 sys.stdout.write("*")
346 elif prog_page(self.ser, addr,
347 buf[addr:addr+SPM_PAGE_SIZE]) != 0:
349 addr += SPM_PAGE_SIZE
350 if check_crc(self.ser, buf, 0, len(buf)):
354 if prog_metadata(self.ser, METADATA_ADDR, buf) != 0:
355 print "metadata failed"
361 def do_bootloader(self, args):
362 self.bootloader(args, 0)
365 if __name__ == "__main__":
367 import readline,atexit
371 histfile = os.path.join(os.environ["HOME"], ".microb_history")
372 atexit.register(readline.write_history_file, histfile)
374 readline.read_history_file(histfile)
378 device = "/dev/ttyS0"
379 if len(sys.argv) > 1:
381 interp = Interp(device)
385 except KeyboardInterrupt:
390 log.exception("%s" % l.splitlines()[-1])