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 # hack because dump32 does not work
120 l1 = read32(ser, METADATA_ADDR) & 0xFFFF
121 l2 = read32(ser, METADATA_ADDR + 2) & 0xFFFF
122 c1 = read32(ser, METADATA_ADDR + 4) & 0xFFFF
123 c2 = read32(ser, METADATA_ADDR + 6) & 0xFFFF
126 filename = os.path.join(MICROB_PATH,
127 "binaries/%x_%x.bin"%(l, c))
130 f = open(filename, "r")
135 print "found old bin matching <%s>"%(filename)
138 def read32(ser, addr):
139 """read a 32 bits value at addr"""
147 # switch in program mode
155 if not s.endswith("addr?\r\n"):
156 print "failed (don't match addr)"
159 ser.write("%x\n"%addr)
164 def check_crc(ser, buf, offset, size):
165 """Process the crc of buf, ask for a crc of the flash, and check
166 that value is correct"""
176 if not s.endswith("addr?\r\n"):
177 print "failed <%s>"%s
179 ser.write("%x\n"%offset)
183 if not s.startswith("size?"):
186 ser.write("%x\n"%size)
189 crc = do_crc(buf[offset:offset+size])
190 avr_crc = int(ser.readline()[0:8], 16)
196 def __init__(self, ser, filein, fileout=None):
199 self.fin = open(filein, "a", 0)
201 self.fileout = fileout
202 self.fout = open(fileout, "a", 0)
204 self.fileout = filein
207 return self.ser.fileno()
208 def read(self, *args):
209 res = self.ser.read(*args)
216 class Interp(cmd.Cmd):
218 def __init__(self, tty, baudrate=57600):
219 cmd.Cmd.__init__(self)
220 self.ser = serial.Serial(tty,baudrate=baudrate)
221 self.escape = "\x01" # C-a
222 self.quitraw = "\x02" # C-b
223 self.serial_logging = False
224 self.default_in_log_file = "/tmp/microb.in.log"
225 self.default_out_log_file = "/tmp/microb.out.log"
227 def do_quit(self, args):
230 def do_log(self, args):
231 """Activate serial logs.
232 log <filename> logs input and output to <filename>
233 log <filein> <fileout> logs input to <filein> and output to <fileout>
234 log logs to /tmp/microb.log or the last used file"""
236 if self.serial_logging:
237 log.error("Already logging to %s and %s" % (self.ser.filein,
240 self.serial_logging = True
241 files = [os.path.expanduser(x) for x in args.split()]
243 files = [self.default_in_log_file, self.default_out_log_file]
244 elif len(files) == 1:
245 self.default_in_log_file = files[0]
246 self.default_out_log_file = None
247 elif len(files) == 2:
248 self.default_in_log_file = files[0]
249 self.default_out_log_file = files[1]
251 print "Can't parse arguments"
253 self.ser = SerialLogger(self.ser, *files)
254 log.info("Starting serial logging to %s and %s" % (self.ser.filein,
258 def do_unlog(self, args):
259 if self.serial_logging:
260 log.info("Stopping serial logging to %s and %s" % (self.ser.filein,
262 self.ser = self.ser.ser
263 self.serial_logging = False
265 log.error("No log to stop")
268 def do_raw(self, args):
270 stdin = os.open("/dev/stdin",os.O_RDONLY)
271 stdout = os.open("/dev/stdout",os.O_WRONLY)
273 stdin_termios = termios.tcgetattr(stdin)
274 raw_termios = stdin_termios[:]
277 log.info("Switching to RAW mode")
280 raw_termios[0] &= ~(termios.IGNBRK | termios.BRKINT |
281 termios.PARMRK | termios.ISTRIP |
282 termios.INLCR | termios.IGNCR |
283 termios.ICRNL | termios.IXON)
285 raw_termios[1] &= ~termios.OPOST;
287 raw_termios[2] &= ~(termios.CSIZE | termios.PARENB);
288 raw_termios[2] |= termios.CS8;
290 raw_termios[3] &= ~(termios.ECHO | termios.ECHONL |
291 termios.ICANON | termios.ISIG |
294 termios.tcsetattr(stdin, termios.TCSADRAIN, raw_termios)
298 ins,outs,errs=select([stdin,self.ser],[],[])
305 self.ser.write(self.escape)
306 elif c == self.quitraw:
309 self.ser.write(self.escape)
317 os.write(stdout,self.ser.read())
319 termios.tcsetattr(stdin, termios.TCSADRAIN, stdin_termios)
320 log.info("Back to normal mode")
322 def bootloader(self, filename, boardnum):
323 self.ser.write("
\ 3")
325 self.ser.write("bootloader\n")
329 print "start programming"
330 self.ser.flushInput()
337 #old_buf = get_same_bin_file(self.ser)
340 while addr < len(buf):
341 if addr > METADATA_ADDR and old_buf != None and \
342 old_buf[addr:addr+SPM_PAGE_SIZE] == buf[addr:addr+SPM_PAGE_SIZE]:
343 sys.stdout.write("-")
345 addr += SPM_PAGE_SIZE
348 if check_crc(self.ser, buf, addr, SPM_PAGE_SIZE) == 0:
349 sys.stdout.write("*")
351 elif prog_page(self.ser, addr,
352 buf[addr:addr+SPM_PAGE_SIZE]) != 0:
354 addr += SPM_PAGE_SIZE
355 if check_crc(self.ser, buf, 0, len(buf)):
359 if prog_metadata(self.ser, METADATA_ADDR, buf) != 0:
360 print "metadata failed"
366 def do_bootloader(self, args):
367 self.bootloader(args, 0)
369 def do_mainboard(self, args):
370 filename = os.path.join(MICROB_PATH, "../mainboard/main.bin")
371 self.bootloader(filename, 1)
373 def do_cobboard(self, args):
374 filename = os.path.join(MICROB_PATH, "../cobboard/main.bin")
375 self.bootloader(filename, 2)
377 def do_ballboard(self, args):
378 filename = os.path.join(MICROB_PATH, "../ballboard/main.bin")
379 self.bootloader(filename, 3)
381 def do_toto(self, args):
384 self.ser.write("pwm s3(3C) 200\n")
386 self.ser.write("pwm s3(3C) 250\n")
388 if __name__ == "__main__":
390 import readline,atexit
394 histfile = os.path.join(os.environ["HOME"], ".microb_history")
395 atexit.register(readline.write_history_file, histfile)
397 readline.read_history_file(histfile)
401 device = "/dev/ttyS0"
402 if len(sys.argv) > 1:
404 interp = Interp(device)
408 except KeyboardInterrupt:
413 log.exception("%s" % l.splitlines()[-1])