CVS: python msp430-downloader.py,1.10,1.11
Chris Liechti <[email protected]> Thu, 25 May 2006 15:14:49 -0700
| Newsgroups | gmane.comp.hardware.texas-instruments.msp430.gcc.cvs |
|---|---|
| Message-ID | <[email protected]> |
Update of /cvsroot/mspgcc/python In directory sc8-pr-cvs7.sourceforge.net:/tmp/cvs-serv1614/python Modified Files: msp430-downloader.py Log Message: - the downloader can interpret config files. - sample config Index: msp430-downloader.py =================================================================== RCS file: /cvsroot/mspgcc/python/msp430-downloader.py,v retrieving revision 1.10 retrieving revision 1.11 diff -u -w -d -r1.10 -r1.11 --- msp430-downloader.py 18 May 2006 22:54:13 -0000 1.10 +++ msp430-downloader.py 25 May 2006 22:14:47 -0000 1.11 @@ -7,7 +7,11 @@ file extensions to this program, so that a double click in the windoze exploder downloads the file. -(C) 2004 [email protected] +Now also with the ability to load the configuration from an ini file (.m43) +which itself can be bundled with a binary in a zip file (.z43). + +(C) 2004-2006 [email protected] + with inputs from David Brown """ import os, sys @@ -15,82 +19,275 @@ import mspgcc.jtag, mspgcc.memory from StringIO import StringIO import traceback +import ConfigParser name = 'msp430-downloader' #os.path.basename(os.path.splitext(sys.argv[0])[0]) -if len(sys.argv) < 2: - #~ EasyDialogs.Message("%s: Need a filename" % name) - #~ sys.exit(1) - filename = EasyDialogs.AskFileForOpen( - windowTitle = "Select MSP430 binary for download", - typeList=[ +# - - - - - - - - - - - - - - - default options - - - - - - - - - - - - - - - +class Options: pass +options = Options() +options.lpt = 'ask' +options.filename = None +options.erase_mode = 'ask' +options.loop = False +options.ask_start = False +options.fake_progress = False +options.debug = False +options.viewer = 'internal' +options.readme = None +options.backend = None +binary = None + +# - - - - - - - - - - - - - - - helper dialogboxes - - - - - - - - - - - - - - +def abort_on_error(message): + print "abort_on_error: %r" % message + EasyDialogs.Message("%s: %s" % (name, message)) + sys.exit(2) + +def abort_on_user_request(): + print "abort_on_user_request" + sys.exit(0) + +# - - - - - - - - - - - - config file interpretation - - - - - - - - - - - - - +def ask_for_binary(allow_manifests=True): + """show a file open dialog and return a filename""" + type_list = [ ('Binraries (*.hex, *.elf, *.a43)', '*.hex;*.elf;*.a43'), ('ELF executable (*.elf)', '*.elf'), ('Intel-hex (*.a43, *.hex)', '*.a43;*.hex'), ('TI-Text (*.txt)', '*.txt'), ('All files (*.*)', '*.*'), ] + if allow_manifests: + type_list.insert(-1, ('Downloader control files (*.m43, *.z43)', '*.m43;*.z43'),) + return EasyDialogs.AskFileForOpen( + windowTitle = "Select MSP430 binary for download", + typeList = type_list ) - if filename is None: - sys.exit(0) + + +def interpret_config(config, abspath=True): + """interpret the options in an ini file (ConfigParser object)""" + if config.has_option('modes', 'erase_mode'): + options.erase_mode = config.get('modes', 'erase_mode') + + if config.has_option('modes', 'interface'): + options.lpt = config.get('modes', 'interface') + + if config.has_option('modes', 'loop'): + options.loop = config.getboolean('modes', 'loop') + + if config.has_option('modes', 'debug'): + options.debug = config.getboolean('modes', 'debug') + + if config.has_option('modes', 'backend'): + back_name = config.get('modes', 'backend') + if back_name == 'ti': + options.backend = mspgcc.jtag.CTYPES_TI + elif back_name == 'parjtag': + options.backend = mspgcc.jtag.PARJTAG + elif back_name == 'mspgcc': + options.backend = mspgcc.jtag.CTYPES_MSPGCC else: - filename = sys.argv[1] -lpt = '1' + abort_on_error('Unsupported backend in configuation file: %r' % back_name) + if config.has_option('data', 'filename'): + options.filename = config.get('data', 'filename') + #patch relative paths to be relative to the config file + if abspath and not os.path.isabs(options.filename): + options.filename = os.path.join(os.path.dirname(config_filename), options.filename) -#redirect console output -sys.stdout = sys.stderr = StringIO() + if config.has_option('data', 'readme'): + options.readme = config.get('data', 'readme') + #patch relative paths to be relative to the config file + if abspath and not os.path.isabs(options.readme): + options.readme = os.path.abspath(os.path.join(os.path.dirname(config_filename), options.readme)) + if config.has_option('data', 'viewer'): + options.viewer = config.get('data', 'viewer') + +# - - - - - - - - - - - - - load binary or config - - - - - - - - - - - - - - - +# if parameter is given use this filename, open a requester otherwise +if len(sys.argv) < 2: + options.filename = ask_for_binary() + if options.filename is None: + abort_on_user_request() +else: + options.filename = sys.argv[1] + +# - - - - - - - - - - - detect and handle config files - - - - - - - - - - - - +# interpret manifest files here +if options.filename.endswith('.m43'): + # this is a simple ini file with settings + config_filename = options.filename + options.filename = None + config = ConfigParser.RawConfigParser() + config.read(config_filename) + interpret_config(config) + if options.readme: + if options.viewer == 'browser': + import webbrowser + webbrowser.open(options.readme) + else: + EasyDialogs.Message(file(options.readme).read()) +elif options.filename.endswith('.z43'): + # a zip file containing the manifest file and the binary and a readme + config_filename = options.filename + options.filename = None + import zipfile + archive = zipfile.ZipFile(config_filename) + #in a loop, search for the manifest file + for info in archive.infolist(): + if info.filename.endswith('.m43'): + config_filename = options.filename + config = ConfigParser.RawConfigParser() + config.readfp(StringIO(archive.read(info.filename))) + interpret_config(config, abspath=False) + #get binary from zip file + if options.filename: + binary = StringIO(archive.read(options.filename)) + #get readme from zip file and display it + if options.readme: + readme_text = archive.read(options.readme) + if options.viewer == 'browser': + import webbrowser + import tempfile + import atexit + tmp_name = tempfile.mktemp(options.readme) + tmp = file(tmp_name, 'wb') + tmp.write(readme_text) + tmp.close() + #ensure that the readme is deleted at the end + def cleanup(filename=tmp_name): + os.remove(tmp_name) + atexit.register(cleanup) + webbrowser.open(tmp_name) + else: + EasyDialogs.Message(readme_text) + + +# checks +if binary is None: + if options.filename is None: + options.filename = ask_for_binary() + if options.filename is None: + abort_on_user_request() + if not os.path.isabs(options.filename): + options.filename = os.path.abspath(options.filename) + if os.path.isfile(options.filename): + binary = mspgcc.memory.Memory() #prepare downloaded data + binary.loadFile(options.filename) #autodetect filetype + else: + abort_on_error("File not found:\n%s" % (options.filename,)) + +if options.loop: + # if in loop mode, ensure that there is a "ready to go" question in the loop + options.ask_start = True + +# init +mspgcc.jtag.init_backend(options.backend) +if mspgcc.jtag.backend == mspgcc.jtag.CTYPES_TI: + options.fake_progress = True +# - - - - - - - - - - - - - - optional questions - - - - - - - - - - - - - - - +if options.lpt == 'ask': #swap the buttons, so that cancel is the sparate button at left answer = EasyDialogs.AskYesNoCancel( - "MSP430 downloader\n\nDownload '%s'?\n\n" % (filename,), + "MSP430 downloader\n\nDownload '%s'?\n\n" % (options.filename,), default=0, cancel="USB", yes="Parallel port", no="Cancel" ) if answer == 0: #NO -> abort - print "User aborted" - sys.exit(2) + abort_on_user_request() elif answer == 1: #YES -> parallel - lpt = "1" + options.lpt = "1" else: #CANCEL -> USB - lpt = "TIUSB" + options.lpt = "TIUSB" -#~ answer = EasyDialogs.AskYesNoCancel("Use JTAG or BSL?", - #~ default=1,yes="BSL", no="JTAG") -#~ if answer == 0: #NO -> JTAG -#~ elif answer == 1: #YES -> BSL -#~ else: #CANCEL +# check for aliases for the interface +if options.lpt == 'parallel': + options.lpt = '1' + +# choose erase mode +if options.erase_mode == 'ask': + answer = EasyDialogs.AskYesNoCancel("Choose erase mode", + default=0, yes="ALL", cancel="Main only", no="Cancel") + if answer == 0: #NO + abort_on_user_request() + elif answer == 1: #YES + options.erase_mode = 'mass' + else: #CANCEL + options.erase_mode = 'main' + +# - - - - - - - - - - - - - - - - logging - - - - - - - - - - - - - - - - - - +if options.debug: + print '\n'.join(["%s: %r" % kv for kv in options.__dict__.items()]) + +# - - - - - - - - - - - - - main programming loop - - - - - - - - - - - - - - +# capture console output +sys.stdout = sys.stderr = StringIO() class ProgressJTAG(mspgcc.jtag.JTAG): def progess_update(self, count, total): self.bar.set(100*count/total) +while True: + if options.ask_start: + answer = EasyDialogs.AskYesNoCancel( + """\ + Ready to program... + + 1. Connect the programmer. + 2. Power on target + 3. Press 'Start' + """ + , + default=0, cancel='Start', yes='', no='Cancel' + ) + if answer == 0: #NO -> abort + print "User aborted" + break + elif answer == 1: #YES -> ?? + sys.exit(1) + else: #CANCEL -> start + pass + try: + if options.fake_progress: + jtagobj = mspgcc.jtag.JTAG() + else: jtagobj = ProgressJTAG() jtagobj.showprogess = True - jtagobj.bar = EasyDialogs.ProgressBar('Programming %r...' % filename, 100) - showError = 0 + jtagobj.bar = EasyDialogs.ProgressBar('Programming %r' % options.filename[-50:], 100) + showError = False try: - jtagobj.data = mspgcc.memory.Memory() #prepare downloaded data - jtagobj.data.loadFile(filename) #autodetect filetype + connected = False + jtagobj.data = binary jtagobj.bar.label('Connecting...') - jtagobj.open(lpt) #try to open port - jtagobj.connect() #try to connect to target + jtagobj.open(options.lpt) #try to open port try: + jtagobj.connect() #try to connect to target + connected = True + if options.fake_progress: jtagobj.bar.set(10) + jtagobj.bar.label('Erasing...') - answer = EasyDialogs.AskYesNoCancel("Choose erase mode", - default=1, yes="ALL", no="Main only") - if answer == 0: #NO - jtagobj.actionMainErase() - elif answer == 1: #YES + if options.erase_mode == 'mass' or options.erase_mode == 'all': jtagobj.actionMassErase() - else: #CANCEL - sys.exit(0) - showError = 1 + elif options.erase_mode == 'main': + jtagobj.actionMainErase() + if options.fake_progress: jtagobj.bar.set(20) + + showError = True jtagobj.bar.label('Programming...') jtagobj.actionProgram() + if options.fake_progress: jtagobj.bar.set(60) + + jtagobj.bar.label('Verifying...') + jtagobj.actionVerify() + if options.fake_progress: jtagobj.bar.set(100) finally: if sys.exc_info()[:1]: #if there is an exception pending jtagobj.verbose = 0 #do not write any more messages + if connected: + jtagobj.bar.label('Reset...') jtagobj.reset(1, 1) #reset and release target jtagobj.close() #Release communication port finally: @@ -99,16 +296,17 @@ if showError: EasyDialogs.Message('An error occoured: "%s"\n\nMessages:\n%s' % (e, sys.stdout.getvalue())) else: - EasyDialogs.Message("%s: Can't Connect to target" % name) + EasyDialogs.Message("%s: Can't connect to target" % name) except (SystemExit, KeyboardInterrupt): raise except Exception, e: - #~ s = StringIO() - #~ traceback.print_exc(file=s) - #~ print s.getvalue() - #~ EasyDialogs.Message(s.getvalue()) + if options.debug: + messages = sys.stdout.getvalue() + sys.__stdout__.write(messages) + traceback.print_exc(file=sys.__stdout__) EasyDialogs.Message('An error occoured: %s\nMessages:\n%s' % (e, sys.stdout.getvalue())) else: messages = sys.stdout.getvalue() - if messages: + if options.debug: sys.__stdout__.write(messages) EasyDialogs.Message('Messages:\n%s\nSuccess!' % (messages,)) + if not options.loop: break ------------------------------------------------------- All the advantages of Linux Managed Hosting--Without the Cost and Risk! Fully trained technicians. The highest number of Red Hat certifications in the hosting industry. Fanatical Support. Click to learn more http://sel.as-us.falkag.net/sel?cmd=lnk&kid=107521&bid=248729&dat=121642