# binwatch - Tiny binary wristwatch. {{{ # # Copyright (C) 2010 Nicolas Schodet # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # Contact : # Web: http://ni.fr.eu.org/ # Email: # }}} */ """binwatch bootloader control.""" import struct import dev2.twi class ProtocolError (RuntimeError): pass class Bootloader: INFO = 0 START = 1 READ = 2 PAGE_WRITE = 3 READ_FUSES = 4 def __init__ (self, address, serial): """Initialise and set address and serial object to use.""" self.address = address self.twi = dev2.twi.Twi (serial) def _command (self, command, fmt, rfmt, *params): """Send a command and check response. - command: command to send. - fmt: command format (see struct). - rfmt: response format. - params: command parameters. Will return unpacked response or None on error.""" s = struct.pack (' flash_size: raise RuntimeError ("flash too small") # Set flash range. if start is None: start = 0 if stop is None: stop = len (data) if start % page_size != 0 or stop % page_size != 0: raise RuntimeError ("unaligned range") # Program pages. for page in xrange (start, stop, page_size): bootloader.page_write (page, page_size, data[page:page + page_size]) if progress: progress ('program', page + page_size - start, stop - start) # Verify. if verify: for page in xrange (start, stop, page_size): r = bootloader.read (page, page_size) if page == 0: match = r[2:] == data[page + 2:page + page_size] else: match = r == data[page:page + page_size] if not match: raise RuntimeError ( "verification mismatch at address 0x04x" % page) if progress: progress ('verify', page + page_size - start, stop - start) def dump (bootloader, progress = None, start = None, stop = None): """Dump all flash data using bootloader.""" # Get bootloader parameters. _, page_size, flash_size = bootloader.info () # Set flash range. if start is None: start = 0 if stop is None: stop = flash_size if start % page_size != 0 or stop % page_size != 0: raise RuntimeError ("unaligned range") # Read. data = [ ] for page in xrange (start, stop, page_size): r = bootloader.read (page, page_size) data.append (r) if progress: progress ('dump', page + page_size - start, stop - start) return ''.join (data) def progress (step, current, total): """Print current progress.""" print "\r%s: %3d%%" % (step, current * 100 / total), if current == total: print '' import sys sys.stdout.flush () def command (args = None): """Implement command line interface.""" # Parse options. import optparse parser = optparse.OptionParser () parser.add_option ('-d', '--dump', help = "dump flash to FILE", metavar = 'FILE') parser.add_option ('-f', '--flash', help = "flash from FILE", metavar = 'FILE') parser.add_option ('-s', '--start', action = 'store_true', help = "start application program") parser.add_option ('-i', '--info', action = 'store_true', help = "get page and flash size") parser.add_option ('-t', '--tty', help = "tty connected to dev2", metavar = 'TTY') parser.add_option ('-a', '--address', type = 'int', default = 0xb8, help = "define bootloader slave address", metavar = 'ADDR') parser.add_option ('--start-addr', type = 'int', help = "set start address", metavar = 'ADDR') parser.add_option ('--stop-addr', type = 'int', help = "set stop address", metavar = 'ADDR') (options, extra) = parser.parse_args (args = args) if extra: parser.error ("extra unused arguments") if options.tty is None: parser.error ("no tty to open") # Apply. import serial try: s = serial.Serial (options.tty) bl = Bootloader (options.address, s) if options.info: print bl.info () if options.dump is not None: f = open (options.dump, 'w') f.write (dump (bl, progress = progress, start = options.start_addr, stop = options.stop_addr)) f.close () if options.flash is not None: flash (bl, open (options.flash).read (), progress = progress, start = options.start_addr, stop = options.stop_addr) if options.start: bl.start () except Exception, e: import sys print >> sys.stderr, e.message sys.exit (1) if __name__ == '__main__': command ()