def _getPasswordFromFile(filename):
    '''从文件获得密码,做一层缓存以加快效率'''
    global __PASSWORD_FILE_MAP
    if filename is None:
        return "\xFF"*32
    if filename in __PASSWORD_FILE_MAP:
        return __PASSWORD_FILE_MAP[filename]
    passwd = memory.load(filename).get_range(0xffe0, 0xffff)
    __PASSWORD_FILE_MAP[filename] = passwd
    return passwd
Example #2
0
 def download_ver(self, old_file_path=None, new_file_path=None, mass_erase=False):
     self.forward_and_check("BSL\r\n", "BSLOK")
     self.serial.baudrate = 9600
     self.serial.parity = serial.PARITY_EVEN
     self.serial.timeout = 1        
     try:
         download_data = memory.Memory() # prepare downloaded data        
         data = memory.load(new_file_path)
         download_data.merge(data)
         self.start_bsl()
         if mass_erase:
             self.bsl_mass_erase()
             print "Mass Erase Success!\r\n"
         passwd = _getPasswordFromFile(old_file_path)
         self.BSL_RX_PASSWORD(passwd)
         self.set_baudrate(115200)
         for segment in download_data:
             print "Write segment at 0x%04x %d bytes\n" % (segment.startaddress, len(segment.data))
             uiLog(u"版本信息正在写入位置: 0x%04x %d bytes"%(segment.startaddress, len(segment.data)))
             data = segment.data
             if len(data) & 1:
                 data += '\xff'
             self.memory_write(segment.startaddress, data)
         print "version downloaded successfully, starting read and verification." 
         uiLog(u"版本写入完成,正在校验...")   
         #读回版本并验证
         for segment in download_data:
             sg = self.memory_read(segment.startaddress, len(segment.data))
             #这是bytearray对象
             if sg != segment.data:
                 raise
             print "verify %2.X OK"%segment.startaddress
         uiLog(u'版本校验成功')    
             
     except Exception as e:
         print "Program fail! " + str(e)
         superUiLog("Program fail! " + str(e))
         raise e
     else:
         print "Program OK!"
     finally:
         self.quit_bsl()
         self.quit_bsl()
         print "quit bsl"
         superUiLog("quite bsl")
         self.serial.baudrate = 115200
         self.serial.parity = serial.PARITY_NONE
         self.serial.timeout = 5
         self.set_TEST(False)
def getDCOFreq(dcoctl, bcsctl1, bcsctl2=0):
    """\
    Measure DCO frequency on a F1xx or F2xx device.

    return: frequency in Hz
    """
    funclet = memory.load('counter', cStringIO.StringIO(COUNTER_FUNCLET), format='titext')

    funclet[0].data = funclet[0].data[:6] \
                    + chr(dcoctl) + chr(bcsctl1) + chr(bcsctl2) \
                    + funclet[0].data[9:]
    runtime = jtag._parjtag.funclet(funclet[0].data, 100)
    count = jtag._parjtag.regread(14) | (jtag._parjtag.regread(15) << 16)

    return 1000*count*4/runtime
def getDCOPlusFreq(scfi0, scfi1, scfqctl, fll_ctl0, fll_ctl1):
    """\
    Measure DCO frequency on a F4xx device

    return: frequency in Hz.
    """
    funclet = memory.load("counter", cStringIO.StringIO(COUNTERPLUS_FUNCLET), format='titext')
    funclet[0].data = funclet[0].data[:6] \
                    + chr(scfi0) + chr(scfi1) \
                    + chr(scfqctl) + chr(fll_ctl0) \
                    + chr(fll_ctl1) + funclet[0].data[11:]
    #~ funclet..[0x205] = scfi0, scfi1, scfqctl, fll_ctl0, fll_ctl1
    runtime = jtag._parjtag.funclet(funclet[0].data, 100)
    count = jtag._parjtag.regread(14) | (jtag._parjtag.regread(15) << 16)
    return 1000*count*4/runtime
Example #5
0
def getDCOFreq(dcoctl, bcsctl1, bcsctl2=0):
    """\
    Measure DCO frequency on a F1xx or F2xx device.

    return: frequency in Hz
    """
    funclet = memory.load('counter', BytesIO(COUNTER_FUNCLET), format='titext')

    funclet[0].data = funclet[0].data[:6] \
        + chr(dcoctl) + chr(bcsctl1) + chr(bcsctl2) \
        + funclet[0].data[9:]
    runtime = jtag._parjtag.funclet(funclet[0].data, 100)
    count = jtag._parjtag.regread(14) | (jtag._parjtag.regread(15) << 16)

    return 1000 * count * 4 / runtime
Example #6
0
def getDCOPlusFreq(scfi0, scfi1, scfqctl, fll_ctl0, fll_ctl1):
    """\
    Measure DCO frequency on a F4xx device

    return: frequency in Hz.
    """
    funclet = memory.load('counter', BytesIO(COUNTERPLUS_FUNCLET), format='titext')
    funclet[0].data = funclet[0].data[:6] \
        + chr(scfi0) + chr(scfi1) \
        + chr(scfqctl) + chr(fll_ctl0) \
        + chr(fll_ctl1) + funclet[0].data[11:]
    #~ funclet..[0x205] = scfi0, scfi1, scfqctl, fll_ctl0, fll_ctl1
    runtime = jtag._parjtag.funclet(funclet[0].data, 100)
    count = jtag._parjtag.regread(14) | (jtag._parjtag.regread(15) << 16)
    return 1000 * count * 4 / runtime
Example #7
0
        # prepare output
        if self.options.output is None:
            self.output = sys.stdout
            if sys.platform == "win32":
                # ensure that the console is in binary mode
                import os, msvcrt
                msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
        else:
            self.output = open(self.options.output, 'wb')

        # prepare data to download / load files
        self.download_data = memory.Memory()                  # prepare downloaded data
        for filename in self.args:
            if filename == '-':
                data = memory.load(
                        '<stdin>',
                        sys.stdin,
                        format=self.options.input_format or "titext")
            else:
                data = memory.load(
                        filename,
                        format=self.options.input_format)
            self.download_data.merge(data)


    def do_the_work(self):
        """\
        Do the actual work, such as upload and download.
        """
        # debug messages
        if self.verbose > 1:
            # show a nice list of scheduled actions
Example #8
0
def main():
    global DEBUG
    import getopt
    filetype = None
    filename = None
    comPort = 0  # Default setting.
    speed = None
    unpatched = 0
    reset = 0
    wait = 0  # wait at the end
    goaddr = None
    bslobj = bsl.BootStrapLoader()
    toinit = []
    todo = []
    startaddr = None
    size = 2
    outputformat = HEX
    notimeout = 0
    bslrepl = None
    mayuseBSL = 1
    forceBSL = 0

    sys.stderr.write("MSP430 Bootstrap Loader Version: %s\n" % VERSION)

    try:
        opts, args = getopt.getopt(
            sys.argv[1:], "hc:P:wf:m:eEpvrg:UDudsxbiITNB:S:V14", [
                "help", "comport=", "password="******"wait", "framesize=",
                "erasecycles=", "masserase", "erasecheck", "program", "verify",
                "reset", "go=", "unpatched", "debug", "upload=", "download=",
                "size=", "hex", "bin", "ihex", "intelhex", "titext",
                "notimeout", "bsl=", "speed=", "bslversion", "f1x", "f4x",
                "invert-reset", "invert-test", "no-BSL-download",
                "force-BSL-download", "erase=", "slow", "swap-reset-test",
                "test-on-tx", "ignore-answer"
            ])
    except getopt.GetoptError:
        # print help information and exit:
        usage()
        sys.exit(2)

    for o, a in opts:
        if o in ("-h", "--help"):
            usage()
            sys.exit()
        elif o in ("-c", "--comport"):
            try:
                comPort = int(a)  # try to convert decimal
            except ValueError:
                comPort = a  # take the string and let serial driver decide
        elif o in ("-P", "--password"):
            # extract password from file
            bslobj.passwd = legacy_memory(memory.load(a)).getMemrange(
                0xffe0, 0xffff)
        elif o in ("-w", "--wait"):
            wait = 1
        elif o in ("-f", "--framesize"):
            try:
                maxData = int(a)  # try to convert decimal
            except ValueError:
                sys.stderr.write("Framesize must be a valid number\n")
                sys.exit(2)
            # Make sure that conditions for maxData are met:
            # ( >= 16 and == n*16 and <= MAX_DATA_BYTES!)
            if maxData > bsl.BootStrapLoader.MAX_DATA_BYTES:
                maxData = bsl.BootStrapLoader.MAX_DATA_BYTES
            elif maxData < 16:
                maxData = 16
            bslobj.maxData = maxData - (maxData % 16)
            sys.stderr.write(
                "Max. number of data bytes within one frame set to %i.\n" %
                maxData)
        elif o in ("-m", "--erasecycles"):
            try:
                meraseCycles = int(a)  # try to convert decimal
            except ValueError:
                sys.stderr.write("Erasecycles must be a valid number\n")
                sys.exit(2)
            # sanity check of value
            if meraseCycles < 1:
                sys.stderr.write("Erasecycles must be a positive number\n")
                sys.exit(2)
            if meraseCycles > 20:
                sys.stderr.write(
                    "Warning: erasecycles set to a large number (>20): %d\n" %
                    meraseCycles)
            sys.stderr.write("Number of mass erase cycles set to %i.\n" %
                             meraseCycles)
            bslobj.meraseCycles = meraseCycles
        elif o in ("-e", "--masserase"):
            toinit.append(bslobj.actionMassErase)  # Erase entire Flash
        elif o in ("-m", "--mainerase"):
            toinit.append(bslobj.actionMainErase)  # Erase main Flash
        elif o == "--erase":
            if '-' in a:
                adr, adr2 = a.split('-', 1)
                try:
                    adr = int(adr, 0)
                except ValueError:
                    sys.stderr.write(
                        "Address range start address must be a valid number in dec, hex or octal\n"
                    )
                    sys.exit(2)
                try:
                    adr2 = int(adr2, 0)
                except ValueError:
                    sys.stderr.write(
                        "Address range end address must be a valid number in dec, hex or octal\n"
                    )
                    sys.exit(2)
                while adr <= adr2:
                    if adr < 0x1100:
                        modulo = 64  # F2xx:64: F1xx, F4xx: 128 (segments get erased twice)
                    elif adr < 0x1200:
                        modulo = 256
                    else:
                        modulo = 512
                    adr = adr - (adr % modulo)
                    toinit.append(bslobj.makeActionSegmentErase(adr))
                    adr = adr + modulo
            else:
                try:
                    seg = int(a, 0)
                    toinit.append(bslobj.makeActionSegmentErase(seg))
                except ValueError:
                    sys.stderr.write(
                        "Segment address must be a valid number in dec, hex or octal or a range adr1-adr2\n"
                    )
                    sys.exit(2)
        elif o in ("-E", "--erasecheck"):
            toinit.append(bslobj.actionEraseCheck)  # Erase Check (by file)
        elif o in ("-p", "--programm"):
            todo.append(bslobj.actionProgram)  # Program file
        elif o in ("-v", "--verify"):
            todo.append(bslobj.actionVerify)  # Verify file
        elif o in ("-r", "--reset"):
            reset = 1
        elif o in ("-g", "--go"):
            try:
                goaddr = int(a)  # try to convert decimal
            except ValueError:
                try:
                    goaddr = int(a[2:], 16)  # try to convert hex
                except ValueError:
                    sys.stderr.write("Go address must be a valid number\n")
                    sys.exit(2)
            wait = 1
        elif o in ("-U", "--unpatched"):
            unpatched = 1
        elif o in ("-D", "--debug"):
            DEBUG = DEBUG + 1
            bsl.DEBUG = bsl.DEBUG + 1
        elif o in ("-u", "--upload"):
            try:
                startaddr = int(a)  # try to convert decimal
            except ValueError:
                try:
                    startaddr = int(a, 16)  # try to convert hex
                except ValueError:
                    sys.stderr.write("Upload address must be a valid number\n")
                    sys.exit(2)
        elif o in ("-s", "--size"):
            try:
                size = int(a)
            except ValueError:
                try:
                    size = int(a, 16)
                except ValueError:
                    sys.stderr.write("Size must be a valid number\n")
                    sys.exit(2)
        # outut formats
        elif o in ("-x", "--hex"):
            outputformat = HEX
        elif o in ("-b", "--bin"):
            outputformat = BINARY
        elif o in ("-i", "--ihex"):
            outputformat = INTELHEX
        # input formats
        elif o in ("-I", "--intelhex"):
            filetype = 0
        elif o in ("-T", "--titext"):
            filetype = 1
        # others
        elif o in ("-N", "--notimeout"):
            notimeout = 1
        elif o in ("-B", "--bsl"):
            bslrepl = legacy_memory(memory.load(a))  # File to program
        elif o in ("-V", "--bslversion"):
            todo.append(bslobj.actionReadBSLVersion
                        )  # load replacement BSL as first item
        elif o in ("-S", "--speed"):
            try:
                speed = int(a)  # try to convert decimal
            except ValueError:
                sys.stderr.write("Speed must be decimal number\n")
                sys.exit(2)
        elif o in ("-1", "--f1x"):
            bslobj.cpu = bsl.F1x
        elif o in ("-4", "--f4x"):
            bslobj.cpu = bsl.F4x
        elif o in ("--invert-reset", ):
            bslobj.invertRST = 1
        elif o in ("--invert-test", ):
            bslobj.invertTEST = 1
        elif o in ("--no-BSL-download", ):
            mayuseBSL = 0
        elif o in ("--force-BSL-download", ):
            forceBSL = 1
        elif o in ("--slow", ):
            bslobj.slowmode = 1
        elif o in ("--swap-reset-test", ):
            bslobj.swapResetTest = 1
        elif o in ("--test-on-tx", ):
            bslobj.testOnTX = 1
        elif o in ("--ignore-answer", ):
            bslobj.ignoreAnswer = 1

    if len(args) == 0:
        sys.stderr.write("Use -h for help\n")
    elif len(args) == 1:  # a filename is given
        if not todo:  # if there are no actions yet
            todo.extend([  # add some useful actions...
                bslobj.actionProgram,
                bslobj.actionVerify,
            ])
        filename = args[0]
    else:  # number of args is wrong
        usage()
        sys.exit(2)

    if DEBUG:  # debug infos
        sys.stderr.write("Debug level set to %d\n" % DEBUG)
        sys.stderr.write("Python version: %s\n" % sys.version)

    #sanity check of options
    if notimeout and goaddr is not None and startaddr is not None:
        sys.stderr.write(
            "Option --notimeout can not be used together with both --upload and --go\n"
        )
        sys.exit(1)

    if notimeout:
        sys.stderr.write(
            "Warning: option --notimeout can cause improper function in some cases!\n"
        )
        bslobj.timeout = 0

    if goaddr and reset:
        sys.stderr.write(
            "Warning: option --reset ignored as --go is specified!\n")
        reset = 0

    if startaddr and reset:
        sys.stderr.write(
            "Warning: option --reset ignored as --upload is specified!\n")
        reset = 0

    if toinit:
        if DEBUG > 0:  # debug
            #show a nice list of sheduled actions
            sys.stderr.write("TOINIT list:\n")
            for f in toinit:
                try:
                    sys.stderr.write("   %s\n" % f.func_name)
                except AttributeError:
                    sys.stderr.write("   %r\n" % f)
    if todo:
        if DEBUG > 0:  # debug
            #show a nice list of sheduled actions
            sys.stderr.write("TODO list:\n")
            for f in todo:
                try:
                    sys.stderr.write("   %s\n" % f.func_name)
                except AttributeError:
                    sys.stderr.write("   %r\n" % f)

    sys.stderr.flush()

    #prepare data to download
    if filetype is not None:  # if the filetype is given...
        if filename is None:
            raise ValueError("No filename but filetype specified")
        if filename == '-':  # get data from stdin
            file = sys.stdin
        else:
            file = open(filename, "rb")  # or from a file
        if filetype == 0:  # select load function
            bslobj.data = legacy_memory(memory.load(filename, file,
                                                    'ihex'))  # intel hex
        elif filetype == 1:
            bslobj.data = legacy_memory(memory.load(filename, file,
                                                    'titext'))  # TI's format
        else:
            raise ValueError("Illegal filetype specified")
    else:  # no filetype given...
        if filename == '-':  # for stdin:
            bslobj.data = legacy_memory(
                memory.load(filename, sys.stdin, 'ihex'))  # assume intel hex
        elif filename:
            bslobj.data = legacy_memory(
                memory.load(filename))  # autodetect otherwise

    if DEBUG > 3:
        sys.stderr.write("File: %r" % filename)

    bslobj.comInit(comPort)  # init port

    #initialization list
    if toinit:  # erase and erase check
        if DEBUG:
            sys.stderr.write("Preparing device ...\n")
        #bslobj.actionStartBSL(usepatch=0, adjsp=0)     # no workarounds needed
        #if speed: bslobj.actionChangeBaudrate(speed)   # change baud rate as fast as possible
        for f in toinit:
            f()

    if todo or goaddr or startaddr:
        if DEBUG:
            sys.stderr.write("Actions ...\n")
        #connect to the BSL
        bslobj.actionStartBSL(
            usepatch=not unpatched,
            replacementBSL=bslrepl,
            forceBSL=forceBSL,
            mayuseBSL=mayuseBSL,
            speed=speed,
        )

    #work list
    if todo:
        for f in todo:
            f()  # work through todo list

    if reset:  # reset device first if desired
        bslobj.actionReset()

    if goaddr is not None:  # start user program at specified address
        bslobj.actionRun(goaddr)  # load PC and execute

    # upload data block and output
    if startaddr is not None:
        if goaddr:  # if a program was started...
            # don't restart BSL but wait for the device to enter it itself
            sys.stderr.write("Waiting for device to reconnect for upload: ")
            sys.stderr.flush()
            bslobj.txPasswd(bslobj.passwd,
                            wait=1)  # synchronize, try forever...
            data = bslobj.uploadData(startaddr, size)  # upload data
        else:
            data = bslobj.uploadData(startaddr, size)  # upload data
        if outputformat == HEX:  # depending on output format
            hexdump((startaddr, data))  # print a hex display
        elif outputformat == INTELHEX:
            # output a intel-hex file
            address = startaddr
            start = 0
            while start < len(data):
                end = start + 16
                if end > len(data):
                    end = len(data)
                sys.stdout.write(intelhex._ihexline(address, data[start:end]))
                start += 16
                address += 16
            sys.stdout.write(intelhex._ihexline(
                0, [], end=True))  # append no data but an end line
        else:
            sys.stdout.write(data)  # binary output w/o newline!
        wait = 0  # wait makes no sense as after the upload the device is still in BSL

    if wait:  # wait at the end if desired
        sys.stderr.write("Press <ENTER> ...\n")  # display a prompt
        sys.stderr.flush()
        input()  # wait for newline

    bslobj.comDone()  # Release serial communication port
Example #9
0
def inner_main():
    from optparse import OptionParser

    parser = OptionParser(usage="""\
%prog [options] [INPUT...]

Simple hex file conversion tool.

It is also possible to specify multiple input files and create a single,
merged output.
""")

    parser.add_option("-o",
                      "--output",
                      dest="output",
                      help="write result to given file",
                      metavar="DESTINATION")

    parser.add_option("-i",
                      "--input-format",
                      dest="input_format",
                      help="input format name (%s)" %
                      (', '.join(memory.load_formats), ),
                      default=None,
                      metavar="TYPE")

    parser.add_option("-f",
                      "--output-format",
                      dest="output_format",
                      help="output format name (%s)" %
                      (', '.join(memory.save_formats), ),
                      default="titext",
                      metavar="TYPE")

    parser.add_option("-d",
                      "--debug",
                      dest="debug",
                      help="print debug messages",
                      default=False,
                      action='store_true')

    (options, args) = parser.parse_args()

    if options.input_format is not None and options.input_format not in memory.load_formats:
        parser.error('Input format %s not supported.' % (options.input_format))

    if options.output_format not in memory.save_formats:
        parser.error('Output format %s not supported.' %
                     (options.output_format))

    if not args:
        # if no files are given, read from stdin
        args = ['-']
        # default to TI-Text if no format is given
        if options.input_format is None:
            options.input_format = 'titext'

    global debug
    debug = options.debug

    # prepare output
    if options.output is None:
        try:
            out = sys.stdout.buffer  #detach()
        except AttributeError:
            out = sys.stdout
    else:
        out = open(options.output, 'wb')

    # get input
    data = memory.Memory()  # prepare downloaded data

    for filename in args:
        if filename == '-':
            try:
                fileobj = sys.stdin.detach()
            except AttributeError:
                fileobj = sys.stdin
            data.merge(
                memory.load('<stdin>', fileobj, format=options.input_format))
        else:
            data.merge(memory.load(filename, format=options.input_format))

    # write ihex file
    memory.save(data, out, options.output_format)
Example #10
0
        out = sys.stdout
        if sys.platform == "win32":
            # ensure that the console is in binary mode
            import os, msvcrt
            msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
    else:
        out = file(options.output, 'wb')

    # prepare data to download
    data = memory.Memory()  # prepare downloaded data

    for filename in args:
        if filename == '-':
            data.merge(
                memory.load('<stdin>',
                            sys.stdin,
                            format=options.input_format or "titext"))
        else:
            data.merge(memory.load(filename, format=options.input_format))

    jtagobj.data = data  # prepare downloaded data

    if options.verbose > 5: sys.stderr.write("File(s): %r\n" % args)

    # debug messages
    if toinit:
        if options.verbose:  # debug
            # show a nice list of scheduled actions
            sys.stderr.write("TOINIT list:\n")
            for f in toinit:
                try:
Example #11
0
        # prepare output
        if self.options.output is None:
            self.output = sys.stdout
            if sys.platform == "win32":
                # ensure that the console is in binary mode
                import os, msvcrt
                msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
        else:
            self.output = open(self.options.output, 'wb')

        # prepare data to download / load files
        self.download_data = memory.Memory()                  # prepare downloaded data
        for filename in self.args:
            if filename == '-':
                data = memory.load(
                        '<stdin>',
                        sys.stdin,
                        format=self.options.input_format or "titext")
            else:
                data = memory.load(
                        filename,
                        format=self.options.input_format)
            self.download_data.merge(data)


    def do_the_work(self):
        """\
        Do the actual work, such as upload and download.
        """
        # debug messages
        if self.verbose > 1:
            # show a nice list of scheduled actions
def inner_main():
    from optparse import OptionParser

    parser = OptionParser(usage="""\
%prog [options] [INPUT...]

Simple hex file conversion tool.

It is also possible to specify multiple input files and create a single,
merged output.
""")

    parser.add_option("-o", "--output",
            dest="output",
            help="write result to given file",
            metavar="DESTINATION")

    parser.add_option("-i", "--input-format",
            dest="input_format",
            help="input format name (%s)" % (', '.join(memory.load_formats),),
            default=None,
            metavar="TYPE")

    parser.add_option("-f", "--output-format",
            dest="output_format",
            help="output format name (%s)" % (', '.join(memory.save_formats),),
            default="titext",
            metavar="TYPE")

    parser.add_option("-d", "--debug",
            dest="debug",
            help="print debug messages",
            default=False,
            action='store_true')

    (options, args) = parser.parse_args()

    if options.input_format is not None and options.input_format not in memory.load_formats:
        parser.error('Input format %s not supported.' % (options.input_format))

    if options.output_format not in memory.save_formats:
        parser.error('Output format %s not supported.' % (options.output_format))

    if not args:
        # if no files are given, read from stdin
        args = ['-']
        # default to TI-Text if no format is given
        if options.input_format is None:
            options.input_format = 'titext'

    global debug
    debug = options.debug

    # prepare output
    if options.output is None:
        try:
            out = sys.stdout.buffer #detach()
        except AttributeError:
            out = sys.stdout
    else:
        out = open(options.output, 'wb')

    # get input
    data = memory.Memory()          # prepare downloaded data

    for filename in args:
        if filename == '-':
            try:
                fileobj = sys.stdin.detach()
            except AttributeError:
                fileobj = sys.stdin
            data.merge(memory.load('<stdin>', fileobj, format=options.input_format))
        else:
            data.merge(memory.load(filename, format=options.input_format))

    # write ihex file
    memory.save(data, out, options.output_format)
    # prepare output
    if options.output is None:
        out = sys.stdout
        if sys.platform == "win32":
            # ensure that the console is in binary mode
            import os, msvcrt
            msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
    else:
        out = file(options.output, 'wb')

    # prepare data to download
    data = memory.Memory()                  # prepare downloaded data

    for filename in args:
        if filename == '-':
            data.merge(memory.load('<stdin>', sys.stdin, format=options.input_format or "titext"))
        else:
            data.merge(memory.load(filename, format=options.input_format))

    jtagobj.data = data                     # prepare downloaded data

    if options.verbose > 5: sys.stderr.write("File(s): %r\n" % args)

    # debug messages
    if toinit:
        if options.verbose:       # debug
            # show a nice list of scheduled actions
            sys.stderr.write("TOINIT list:\n")
            for f in toinit:
                try:
                    sys.stderr.write("   %s\n" % f.func_name)
    def parse_args(self):
        (self.options, self.args) = None, []  # parse_args may terminate...
        (self.options, self.args) = self.parser.parse_args()

        self.debug = self.options.debug
        self.verbose = self.options.verbose

        if self.verbose > 3:
            level = logging.DEBUG
        elif self.verbose > 2:
            level = logging.INFO
        else:
            level = logging.WARN
        logging.basicConfig(level=level)

        if self.verbose > 1:  # debug infos
            sys.stderr.write("Debug is %s\n" % self.options.debug)
            sys.stderr.write("Verbosity level set to %d\n" %
                             self.options.verbose)
            #~ sys.stderr.write("logging module level set to %s\n" % (level,))
            sys.stderr.write("Python version: %s\n" % sys.version)

        if self.options.input_format is not None and self.options.input_format not in memory.load_formats:
            self.parser.error('Input format %s not supported.' %
                              (self.options.input_format))

        if self.options.output_format not in memory.save_formats:
            self.parser.error('Output format %s not supported.' %
                              (self.options.output_format))

        # sanity check of options
        if self.options.do_run is not None and self.options.do_reset:
            if self.verbose:
                sys.stderr.write(
                    "Warning: option --reset ignored as --go is specified!\n")
            self.options.do_reset = False

        if self.options.upload_list and self.options.do_reset:
            if self.verbose:
                sys.stderr.write(
                    "Warning: option --reset ignored as --upload is specified!\n"
                )
            self.options.do_reset = False

        if self.options.upload_list and self.options.do_wait:
            if self.verbose:
                sys.stderr.write(
                    "Warning: option --wait ignored as --upload is specified!\n"
                )
            self.options.do_wait = False

        # create a list of functions an arguments
        if self.options.do_mass_erase:
            self.add_action(self.mass_erase)
        if self.options.do_main_erase:
            self.add_action(self.main_erase)
        if self.options.do_erase_by_file:
            self.add_action(self.erase_by_file)
        if self.options.do_info_erase:
            self.add_action(self.erase_infomem)
        for a in self.options.erase_list:
            try:
                adr, adr2 = parseAddressRange(a)
                if adr2 is not None:
                    while adr <= adr2:
                        if not (0x1000 <= adr <= 0xffff):
                            self.parser.error(
                                "Start address for --erase is not within Flash memory: 0x%04x"
                                % (adr, ))
                        elif adr < 0x1100:
                            modulo = 64  # F2xx XXX: on F1xx/F4xx are segments erased twice
                        elif adr < 0x1200:
                            modulo = 256
                        else:
                            modulo = 512
                        adr = adr - (adr % modulo)
                        self.add_action(self.erase, adr)
                        adr = adr + modulo
                else:
                    self.add_action(self.erase, adr)
            except ValueError as e:
                self.parser.error("--erase: %s" % e)

        default_action = True
        if self.options.do_erase_check:
            self.add_action(self.erase_check_by_file)
            default_action = False
        if self.options.do_program:
            self.add_action(self.program_file)
            default_action = False
        if self.options.do_verify:
            self.add_action(self.verify_by_file)
            default_action = False
        if self.options.do_upload_by_file:
            self.add_action(self.upload_by_file)
            default_action = False

        # as default action (no other given by user), program if a file is given
        if default_action and self.args:
            self.add_action(self.program_file)

        for a in self.options.upload_list:
            try:
                start, end = parseAddressRange(a)
                if end is None:
                    end = start + 15
                self.add_action(self.upload, start, end)
            except ValueError as e:
                self.parser.error("--upload: %s" % e)

        if self.options.do_reset:
            self.add_action(self.reset)

        if self.options.upload_list or self.options.do_upload_by_file:
            self.upload_data = memory.Memory()

        if self.options.do_run:
            self.add_action(self.execute, self.options.do_run)
        else:
            # XXX reset otherwise, independently of -r option. imitate old behavior
            self.add_action(self.reset)

        # prepare output
        if self.options.output is None:
            self.output = sys.stdout
            if sys.platform == "win32":
                # ensure that the console is in binary mode
                import os, msvcrt
                #msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
        else:
            self.output = open(self.options.output, 'wb')

        # prepare data to download / load files
        self.download_data = memory.Memory()  # prepare downloaded data
        for filename in self.args:
            if filename == '-':
                data = memory.load('<stdin>',
                                   sys.stdin,
                                   format=self.options.input_format
                                   or "titext")
            else:
                data = memory.load(filename, format=self.options.input_format)
            self.download_data.merge(data)
def main():
    global DEBUG
    import getopt
    filetype    = None
    filename    = None
    comPort     = 0     # Default setting.
    speed       = None
    unpatched   = 0
    reset       = 0
    wait        = 0     # wait at the end
    goaddr      = None
    bslobj      = bsl.BootStrapLoader()
    toinit      = []
    todo        = []
    startaddr   = None
    size        = 2
    outputformat= HEX
    notimeout   = 0
    bslrepl     = None
    mayuseBSL   = 1
    forceBSL    = 0

    sys.stderr.write("MSP430 Bootstrap Loader Version: %s\n" % VERSION)

    try:
        opts, args = getopt.getopt(sys.argv[1:],
            "hc:P:wf:m:eEpvrg:UDudsxbiITNB:S:V14",
            ["help", "comport=", "password="******"wait", "framesize=",
             "erasecycles=", "masserase", "erasecheck", "program",
             "verify", "reset", "go=", "unpatched", "debug",
             "upload=", "download=", "size=", "hex", "bin", "ihex",
             "intelhex", "titext", "notimeout", "bsl=", "speed=",
             "bslversion", "f1x", "f4x", "invert-reset", "invert-test",
             "no-BSL-download", "force-BSL-download", "erase=", "slow",
             "swap-reset-test", "test-on-tx", "ignore-answer"]
        )
    except getopt.GetoptError:
        # print help information and exit:
        usage()
        sys.exit(2)

    for o, a in opts:
        if o in ("-h", "--help"):
            usage()
            sys.exit()
        elif o in ("-c", "--comport"):
            try:
                comPort = int(a)                    # try to convert decimal
            except ValueError:
                comPort = a                         # take the string and let serial driver decide
        elif o in ("-P", "--password"):
            # extract password from file
            bslobj.passwd = legacy_memory(memory.load(a)).getMemrange(0xffe0, 0xffff)
        elif o in ("-w", "--wait"):
            wait = 1
        elif o in ("-f", "--framesize"):
            try:
                maxData = int(a)                    # try to convert decimal
            except ValueError:
                sys.stderr.write("Framesize must be a valid number\n")
                sys.exit(2)
            # Make sure that conditions for maxData are met:
            # ( >= 16 and == n*16 and <= MAX_DATA_BYTES!)
            if maxData > bsl.BootStrapLoader.MAX_DATA_BYTES:
                maxData = bsl.BootStrapLoader.MAX_DATA_BYTES
            elif maxData < 16:
                maxData = 16
            bslobj.maxData = maxData - (maxData % 16)
            sys.stderr.write( "Max. number of data bytes within one frame set to %i.\n" % maxData)
        elif o in ("-m", "--erasecycles"):
            try:
                meraseCycles = int(a)              # try to convert decimal
            except ValueError:
                sys.stderr.write("Erasecycles must be a valid number\n")
                sys.exit(2)
            # sanity check of value
            if meraseCycles < 1:
                sys.stderr.write("Erasecycles must be a positive number\n")
                sys.exit(2)
            if meraseCycles > 20:
                sys.stderr.write("Warning: erasecycles set to a large number (>20): %d\n" % meraseCycles)
            sys.stderr.write( "Number of mass erase cycles set to %i.\n" % meraseCycles)
            bslobj.meraseCycles = meraseCycles
        elif o in ("-e", "--masserase"):
            toinit.append(bslobj.actionMassErase)  # Erase entire Flash
        elif o in ("-m", "--mainerase"):
            toinit.append(bslobj.actionMainErase)  # Erase main Flash
        elif o == "--erase":
            if '-' in a:
                adr, adr2 = a.split('-', 1)
                try:
                    adr = int(adr, 0)
                except ValueError:
                    sys.stderr.write("Address range start address must be a valid number in dec, hex or octal\n")
                    sys.exit(2)
                try:
                    adr2 = int(adr2, 0)
                except ValueError:
                    sys.stderr.write("Address range end address must be a valid number in dec, hex or octal\n")
                    sys.exit(2)
                while adr <= adr2:
                    if adr < 0x1100:
                        modulo = 64                # F2xx:64: F1xx, F4xx: 128 (segments get erased twice)
                    elif adr < 0x1200:
                        modulo = 256
                    else:
                        modulo = 512
                    adr = adr - (adr % modulo)
                    toinit.append(bslobj.makeActionSegmentErase(adr))
                    adr = adr + modulo
            else:
                try:
                    seg = int(a, 0)
                    toinit.append(bslobj.makeActionSegmentErase(seg))
                except ValueError:
                    sys.stderr.write("Segment address must be a valid number in dec, hex or octal or a range adr1-adr2\n")
                    sys.exit(2)
        elif o in ("-E", "--erasecheck"):
            toinit.append(bslobj.actionEraseCheck) # Erase Check (by file)
        elif o in ("-p", "--programm"):
            todo.append(bslobj.actionProgram)      # Program file
        elif o in ("-v", "--verify"):
            todo.append(bslobj.actionVerify)       # Verify file
        elif o in ("-r", "--reset"):
            reset = 1
        elif o in ("-g", "--go"):
            try:
                goaddr = int(a)                    # try to convert decimal
            except ValueError:
                try:
                    goaddr = int(a[2:],16)         # try to convert hex
                except ValueError:
                    sys.stderr.write("Go address must be a valid number\n")
                    sys.exit(2)
            wait = 1
        elif o in ("-U", "--unpatched"):
            unpatched = 1
        elif o in ("-D", "--debug"):
            DEBUG = DEBUG + 1
            bsl.DEBUG = bsl.DEBUG + 1
        elif o in ("-u", "--upload"):
            try:
                startaddr = int(a)                  # try to convert decimal
            except ValueError:
                try:
                    startaddr = int(a,16)           # try to convert hex
                except ValueError:
                    sys.stderr.write("Upload address must be a valid number\n")
                    sys.exit(2)
        elif o in ("-s", "--size"):
            try:
                size = int(a)
            except ValueError:
                try:
                    size = int(a,16)
                except ValueError:
                    sys.stderr.write("Size must be a valid number\n")
                    sys.exit(2)
        # outut formats
        elif o in ("-x", "--hex"):
            outputformat = HEX
        elif o in ("-b", "--bin"):
            outputformat = BINARY
        elif o in ("-i", "--ihex"):
            outputformat = INTELHEX
        # input formats
        elif o in ("-I", "--intelhex"):
            filetype = 0
        elif o in ("-T", "--titext"):
            filetype = 1
        # others
        elif o in ("-N", "--notimeout"):
            notimeout = 1
        elif o in ("-B", "--bsl"):
            bslrepl = legacy_memory(memory.load(a)) # File to program
        elif o in ("-V", "--bslversion"):
            todo.append(bslobj.actionReadBSLVersion) # load replacement BSL as first item
        elif o in ("-S", "--speed"):
            try:
                speed = int(a)                      # try to convert decimal
            except ValueError:
                sys.stderr.write("Speed must be decimal number\n")
                sys.exit(2)
        elif o in ("-1", "--f1x"):
            bslobj.cpu = bsl.F1x
        elif o in ("-4", "--f4x"):
            bslobj.cpu = bsl.F4x
        elif o in ("--invert-reset", ):
            bslobj.invertRST = 1
        elif o in ("--invert-test", ):
            bslobj.invertTEST = 1
        elif o in ("--no-BSL-download", ):
            mayuseBSL = 0
        elif o in ("--force-BSL-download", ):
            forceBSL = 1
        elif o in ("--slow", ):
            bslobj.slowmode = 1
        elif o in ("--swap-reset-test", ):
            bslobj.swapResetTest = 1
        elif o in ("--test-on-tx", ):
            bslobj.testOnTX = 1
        elif o in ("--ignore-answer", ):
            bslobj.ignoreAnswer = 1

    if len(args) == 0:
        sys.stderr.write("Use -h for help\n")
    elif len(args) == 1:                            # a filename is given
        if not todo:                                # if there are no actions yet
            todo.extend([                           # add some useful actions...
                bslobj.actionProgram,
                bslobj.actionVerify,
            ])
        filename = args[0]
    else:                                           # number of args is wrong
        usage()
        sys.exit(2)

    if DEBUG:   #debug infos
        sys.stderr.write("Debug level set to %d\n" % DEBUG)
        sys.stderr.write("Python version: %s\n" % sys.version)

    #sanity check of options
    if notimeout and goaddr is not None and startaddr is not None:
        sys.stderr.write("Option --notimeout can not be used together with both --upload and --go\n")
        sys.exit(1)

    if notimeout:
        sys.stderr.write("Warning: option --notimeout can cause improper function in some cases!\n")
        bslobj.timeout = 0

    if goaddr and reset:
        sys.stderr.write("Warning: option --reset ignored as --go is specified!\n")
        reset = 0

    if startaddr and reset:
        sys.stderr.write("Warning: option --reset ignored as --upload is specified!\n")
        reset = 0

    if toinit:
        if DEBUG > 0:       #debug
            #show a nice list of sheduled actions
            sys.stderr.write("TOINIT list:\n")
            for f in toinit:
                try:
                    sys.stderr.write("   %s\n" % f.func_name)
                except AttributeError:
                    sys.stderr.write("   %r\n" % f)
    if todo:
        if DEBUG > 0:       #debug
            #show a nice list of sheduled actions
            sys.stderr.write("TODO list:\n")
            for f in todo:
                try:
                    sys.stderr.write("   %s\n" % f.func_name)
                except AttributeError:
                    sys.stderr.write("   %r\n" % f)

    sys.stderr.flush()

    #prepare data to download
    if filetype is not None:                        # if the filetype is given...
        if filename is None:
            raise ValueError("No filename but filetype specified")
        if filename == '-':                         # get data from stdin
            file = sys.stdin
        else:
            file = open(filename, "rb")             # or from a file
        if filetype == 0:                           # select load function
            bslobj.data = legacy_memory(memory.load(filename, file, 'ihex')) # intel hex
        elif filetype == 1:
            bslobj.data = legacy_memory(memory.load(filename, file, 'titext')) # TI's format
        else:
            raise ValueError("Illegal filetype specified")
    else:                                           # no filetype given...
        if filename == '-':                         # for stdin:
            bslobj.data = legacy_memory(memory.load(filename, sys.stdin, 'ihex')) # assume intel hex
        elif filename:
            bslobj.data = legacy_memory(memory.load(filename)) # autodetect otherwise

    if DEBUG > 3: sys.stderr.write("File: %r" % filename)

    bslobj.comInit(comPort)                         # init port

    #initialization list
    if toinit:  #erase and erase check
        if DEBUG: sys.stderr.write("Preparing device ...\n")
        #bslobj.actionStartBSL(usepatch=0, adjsp=0)     # no workarounds needed
        #if speed: bslobj.actionChangeBaudrate(speed)   # change baud rate as fast as possible
        for f in toinit: f()

    if todo or goaddr or startaddr:
        if DEBUG: sys.stderr.write("Actions ...\n")
        #connect to the BSL
        bslobj.actionStartBSL(
            usepatch=not unpatched,
            replacementBSL=bslrepl,
            forceBSL=forceBSL,
            mayuseBSL=mayuseBSL,
            speed=speed,
        )

    #work list
    if todo:
        for f in todo: f()                          # work through todo list

    if reset:                                       # reset device first if desired
        bslobj.actionReset()

    if goaddr is not None:                          # start user program at specified address
        bslobj.actionRun(goaddr)                    # load PC and execute

    # upload data block and output
    if startaddr is not None:
        if goaddr:                                  # if a program was started...
            # don't restart BSL but wait for the device to enter it itself
            sys.stderr.write("Waiting for device to reconnect for upload: ")
            sys.stderr.flush()
            bslobj.txPasswd(bslobj.passwd, wait=1)     # synchronize, try forever...
            data = bslobj.uploadData(startaddr, size)  # upload data
        else:
            data = bslobj.uploadData(startaddr, size)  # upload data
        if outputformat == HEX:                     # depending on output format
            hexdump( (startaddr, data) )            # print a hex display
        elif outputformat == INTELHEX:
            # output a intel-hex file
            address = startaddr
            start = 0
            while start < len(data):
                end = start + 16
                if end > len(data): end = len(data)
                sys.stdout.write(intelhex._ihexline(address, data[start:end]))
                start += 16
                address += 16
            sys.stdout.write(intelhex._ihexline(0, [], end=True))   # append no data but an end line
        else:
            sys.stdout.write(data)                  # binary output w/o newline!
        wait = 0    # wait makes no sense as after the upload the device is still in BSL

    if wait:                                        # wait at the end if desired
        sys.stderr.write("Press <ENTER> ...\n")     # display a prompt
        sys.stderr.flush()
        raw_input()                                 # wait for newline

    bslobj.comDone()                                # Release serial communication port
Example #16
0
def main():
    from optparse import OptionParser, OptionGroup, TitledHelpFormatter

    # i dont like how texts are re-wrapped and paragraphs are joined. get rid
    # of that
    class Formatter(TitledHelpFormatter):
        def format_description(self, description):
            return description

    parser = OptionParser(
        usage="""\
%prog [OPTIONS] [FILE [FILE...]]

Version: %version

If "-" is specified as file the data is read from stdin and TI-text format
is expected by default.
""",
        formatter=Formatter(),
        version=VERSION)

    vars = {
        'prog': sys.argv[0],
        'version': VERSION,
        'msp430': (sys.platform != 'win32') and 'libMSP430.so' or 'MSP430.dll',
        'msp430mspgcc': (sys.platform != 'win32') and 'libMSP430mspgcc.so' or 'MSP430mspgcc.dll',
    }

    parser.add_option(
        "--help-backend",
        dest="help_backend",
        help="show help about the different backends",
        default=False,
        action='store_true')

    parser.add_option(
        "-d", "--debug",
        dest="debug",
        help="print debug messages",
        default=False,
        action='store_true')

    parser.add_option(
        "-v", "--verbose",
        dest="verbose",
        help="show more messages (can be given multiple times)",
        default=0,
        action='count')

    parser.add_option(
        "-q", "--quiet",
        dest="quiet",
        help="suppress all messages",
        default=False,
        action='store_true')

    parser.add_option(
        "-R", "--ramsize",
        dest="ramsize",
        type="int",
        help="specify the amount of RAM to be used to program flash (default: auto detected)",
        default=None)

    group = OptionGroup(parser, "Programing", """\
File format is auto detected, unless --input-format is used.
Preferred file extensions are ".txt" for TI-Text format, ".a43" or ".hex" for
Intel HEX. ELF files can also be loaded.
""")

    group.add_option(
        "-i", "--input-format",
        dest="input_format",
        help="input format name (%s)" % (', '.join(memory.load_formats),),
        default=None,
        metavar="TYPE")

    group.add_option(
        "-S", "--progress",
        dest="progress",
        help="show progress while programming",
        default=False,
        action='store_true')

    parser.add_option_group(group)

    group = OptionGroup(parser, "Connection", """\
Note: On Windows, use "USB", "TIUSB" or "COM5" etc if using MSP430.dll from TI.
      On other platforms, e.g. Linux, use "/dev/ttyUSB0" etc. if using
      libMSP430.so.
      If a %(msp430)s is found, it is preferred, otherwise
      %(msp430mspgcc)s is used.

Note: --slowdown > 50 can result in failures for the RAM size auto detection
      (use --ramsize option to fix this). Use the --verbose option and watch
      the outputs. The DCO clock adjustment and thus the Flash timing may be
      inaccurate for large values.
""" % vars)

    group.add_option(
        "--backend",
        dest="backend",
        help="select an alternate backend. See --help-backend for more information",
        default=None)

    group.add_option(
        "-l", "--lpt",
        dest="port_name",
        metavar="PORT",
        help='specify an other parallel port or serial port for the USBFET (the later '
             'requires %(msp430)s instead of %(msp430mspgcc)s).  (defaults to "LPT1" '
             '("/dev/parport0" on Linux))' % vars,
        default=None)

    group.add_option(
        "--spy-bi-wire-jtag",
        dest="spy_bi_wire_jtag",
        help="interface is 4 wire on a spy-bi-wire capable device",
        default=False,
        action='store_true')

    group.add_option(
        "--spy-bi-wire",
        dest="spy_bi_wire",
        help="interface is 2 wire on a spy-bi-wire capable device",
        default=False,
        action='store_true')

    group.add_option(
        "--slowdown",
        dest="slowdown",
        metavar="MICROSECONDS",
        help="artificially slow down the communication. Can help with long "
             "lines, try values between 1 and 50 (parallel port interface with "
             "mspgcc's HIL library only). (experts only)",
        default=None)

    parser.add_option_group(group)

    group = OptionGroup(parser, "Funclets", """\
Note: Writing and/or reading RAM before and/or after running a funclet may not
      work as expected on devices with the JTAG bug like the F123.

Note: Only possible with %(msp430mspgcc)s, not other backends.
""" % vars)

    group.add_option(
        "--funclet",
        dest="funclet",
        help="the given file is a funclet (a small program to be run in RAM)",
        default=None,
        metavar="FILENAME")

    group.add_option(
        "--parameter",
        dest="funclet_parameter",
        metavar="<KEY>=<VALUE>",
        help='Pass parameters to funclets. Registers can be written like '
             '"R15=123" or "R4=0x55" A string can be written to memory with '
             '"0x2e0=hello" --parameter can be given more than once',
        default=[],
        action='append')

    group.add_option(
        "--result",
        dest="funclet_result",
        metavar="VALUE",
        help='Read results from funclets. "Rall" reads all registers (case '
             'insensitive) "R15" reads R15 etc. Address ranges can be read '
             'with "0x2e0-0x2ff". See also --upload.  --result can be given '
             'more than once.',
        default=[],
        action='append')

    group.add_option(
        "--timeout",
        dest="funclet_timeout",
        metavar="VALUE",
        type="float",
        help='Abort the funclet after the given time in seconds if it does '
             'not exit no itself. (default 1)',
        default=1)

    parser.add_option_group(group)

    group = OptionGroup(parser, "Program flow specifiers", """\
Program flow specifiers default to "-P" if a file is given.
Don't forget to specify "-e", "-eE" or "-m" when programming flash!

"-P" already verifies the programmed data, "-V" adds an additional
verification through uploading the written data for a 1:1 compare.

No default action is taken if "-P" and/or "-V" is given, say specifying
only "-V" does a "check by file" of a programmed device.

Multiple --erase options are allowed. It is possible to use address
ranges such as 0xf000-0xf0ff or 0xf000/4k.

NOTE: SegmentA on F2xx is NOT erased with --masserase, that must be
      done separately with --erase=0x10c0 or --eraseinfo".
""")

    group.add_option(
        "-e", "--masserase",
        dest="do_mass_erase",
        help="mass erase (clear all flash memory)",
        default=False,
        action='store_true')

    group.add_option(
        "-m", "--mainerase",
        dest="do_main_erase",
        help="erase main flash memory only",
        default=False,
        action='store_true')

    group.add_option(
        "--eraseinfo",
        dest="do_info_erase",
        help="erase info flash memory only (0x1000-0x10ff)",
        default=False,
        action='store_true')

    group.add_option(
        "--erase",
        dest="erase_list",
        help="selectively erase segment at the specified address or address range",
        default=[],
        action='append')

    group.add_option(
        "-E", "--erasecheck",
        dest="do_erase_check",
        help="erase check by file",
        default=False,
        action='store_true')

    group.add_option(
        "-P", "--program",
        dest="do_program",
        help="program file",
        default=False,
        action='store_true')

    group.add_option(
        "-V", "--verify",
        dest="do_verify",
        help="verify by file",
        default=False,
        action='store_true')

    parser.add_option_group(group)

    group = OptionGroup(parser, "JTAG fuse", """\
WARNING: This is not reversible, use with care!  Note: Not supported with the
         simple parallel port adapter (7V source required).",
""")

    group.add_option(
        "--secure",
        dest="do_secure",
        help="blow JTAG security fuse",
        default=False,
        action='store_true')

    parser.add_option_group(group)

    group = OptionGroup(parser, "Data retrieving", """\
It is possible to use address ranges such as 0xf000-0xf0ff or 0xf000/256.
Multiple --upload options are allowed.
""")

    group.add_option(
        "-u", "--upload",
        dest="upload_list",
        metavar="ADDRESS",
        help='upload a data block, can be passed multiple times',
        default=[],
        action='append')

    group.add_option(
        "-o", "--output",
        dest="output",
        help="write result to given file",
        metavar="DESTINATION")

    group.add_option(
        "-f", "--output-format",
        dest="output_format",
        help="output format name (%s)" % (', '.join(memory.save_formats),),
        default="hex",
        metavar="TYPE")

    parser.add_option_group(group)

    group = OptionGroup(parser, "Do before exit")

    group.add_option(
        "-g", "--go",
        dest="do_run",
        metavar="ADDRESS",
        type="int",
        help='start program execution at specified address, this implies option --wait',
        default=None,
        action='store')

    group.add_option(
        "-r", "--reset",
        dest="do_reset",
        help="perform a normal device reset that will start the program that is specified in the reset interrupt vector",
        default=False,
        action='store_true')

    group.add_option(
        "-w", "--wait",
        dest="wait",
        help="wait for <ENTER> before closing the port",
        default=False,
        action='store_true')

    group.add_option(
        "--no-close",
        dest="no_close",
        help="do not close port on exit, allows to power devices from the parallel port interface",
        default=False,
        action='store_true')

    parser.add_option_group(group)

    group = OptionGroup(parser, "Examples", """\
Mass erase and program from file: "%(prog)s -e firmware.elf"
Dump information memory: "%(prog)s --upload=0x1000-0x10ff"
""" % vars)
    parser.add_option_group(group)

    (options, args) = parser.parse_args()

    if options.input_format is not None and options.input_format not in memory.load_formats:
        parser.error('Input format %s not supported.' % (options.input_format))

    if options.output_format not in memory.save_formats:
        parser.error('Output format %s not supported.' % (options.output_format))

    reset = False
    goaddr = None
    jtagobj = jtag.JTAG()
    toinit = []
    todo = []
    uploadlist = []
    funclet = None
    parameters = []
    results = []

    if options.help_backend:
        help_on_backends()
        sys.exit()

    if options.backend is not None:
        if options.backend == 'mspgcc':
            backend = jtag.CTYPES_MSPGCC
        elif options.backend == 'parjtag':
            backend = jtag.PARJTAG
        elif options.backend == 'ti':
            backend = jtag.CTYPES_TI
        else:
            raise parser.error("no such backend: %r" % options.backend)
        jtag.init_backend(backend)

    if options.spy_bi_wire:
        jtag.interface = 'spy-bi-wire'
    if options.spy_bi_wire_jtag:
        jtag.interface = 'spy-bi-wire-jtag'

    if options.do_mass_erase:
        toinit.append(jtagobj.actionMassErase)      # Erase Flash
    if options.do_main_erase:
        toinit.append(jtagobj.actionMainErase)      # Erase main Flash
    for a in options.erase_list:
        try:
            adr, adr2 = parseAddressRange(a)
            if adr2 is not None:
                while adr <= adr2:
                    if not (0x1000 <= adr <= 0xffff):
                        sys.stderr.write("Start address is not within Flash memory\n")
                        sys.exit(2)
                    elif adr < 0x1100:
                        modulo = 64     # F2xx XXX: on F1xx/F4xx are segments erased twice
                    elif adr < 0x1200:
                        modulo = 256
                    else:
                        modulo = 512
                    adr = adr - (adr % modulo)
                    toinit.append(jtagobj.makeActionSegmentErase(adr))
                    adr = adr + modulo
            else:
                toinit.append(jtagobj.makeActionSegmentErase(adr))
        except ValueError as e:
            parser.error("--erase: %s" % e)
    if options.do_info_erase:
        # F2xx XXX: on F1xx/F4xx are segments erased twice
        toinit.append(jtagobj.makeActionSegmentErase(0x1000))
        toinit.append(jtagobj.makeActionSegmentErase(0x1040))
        toinit.append(jtagobj.makeActionSegmentErase(0x1080))
        toinit.append(jtagobj.makeActionSegmentErase(0x10c0))
    if options.do_erase_check:
        toinit.append(jtagobj.actionEraseCheck)     # Erase Check (by file)

    if options.do_program:
        todo.append(jtagobj.actionProgram)          # Program file
    if options.do_verify:
        todo.append(jtagobj.actionVerify)           # Verify file
    if options.do_secure:
        todo.append(jtagobj.actionSecure)
    if options.do_reset:
        reset = True

    if options.debug:
        global DEBUG
        DEBUG = True
    if options.verbose:
        try:
            jtagobj.setDebugLevel(options.verbose)
        except IOError:
            sys.stderr.write("WARNING: Failed to set debug level in backend library\n")
        memory.DEBUG = options.verbose
        jtag.DEBUG = options.verbose

    for a in options.upload_list:
        try:
            start, end = parseAddressRange(a)
            if end is not None:
                uploadlist.append((start, end))
            else:
                uploadlist.append((start, start + 15))
        except ValueError as e:
            parser.error("--upload: %s" % e)

    # others
    if options.funclet:
        funclet = True

    if options.progress:
        jtagobj.showprogess = 1

    for a in options.funclet_parameter:
        if '=' in a:
            key, value = a.lower().split('=', 2)
            if key[0] == 'r':
                regnum = int(key[1:])
                value = int(value, 0)
                parameters.append((jtagobj.setCPURegister, (regnum, value)))
            else:
                address = int(key, 0)
                parameters.append((jtagobj.downloadData, (address, value)))
        else:
            parser.erro("Expected <key>=<value> pair in --parameter option, but no '=' found.")

    for a in options.funclet_result:
        a = a.lower()
        if a == 'rall':
            for regnum in range(16):
                results.append(('R%-2d = 0x%%04x' % regnum, jtagobj.getCPURegister, (regnum,)))
        elif a[0] == 'r':
            regnum = int(a[1:])
            results.append(('R%-2d = 0x%%04x' % regnum, jtagobj.getCPURegister, (regnum,)))
        else:
            try:
                start, end = parseAddressRange(a)
                if end is None:
                    end = start
            except ValueError as e:
                parser.error("--result: %s" % e)
            results.append(('0x%04x: %%r' % start, jtagobj.uploadData, (start, end - start)))

    if options.quiet:
        jtagobj.verbose = 0

    if options.slowdown is not None:
        import ctypes
        if sys.platform == 'win32':
            HIL_SetSlowdown = ctypes.windll.HIL.HIL_SetSlowdown
        else:
            # XXX and posix platforms?!
            HIL_SetSlowdown = ctypes.cdll.HIL.HIL_SetSlowdown
        HIL_SetSlowdown = ctypes.windll.HIL.HIL_SetSlowdown
        HIL_SetSlowdown.argtypes = [ctypes.c_ulong]
        #~ HIL_SetSlowdown.restype   = ctypes.c_int # actually void
        # set slowdown
        HIL_SetSlowdown(options.slowdown)

    if options.verbose:
        if options.quiet:
            options.quiet = False
            sys.stderr.write("Disabling --quiet as --verbose is active\n")

    if not options.quiet:
        sys.stderr.write("MSP430 JTAG programmer Version: %s\n" % VERSION)

    if not args:
        if not options.quiet:
            sys.stderr.write("Use -h for help\n")
    elif args:                                          # a filename is given
        if not funclet:
            if not todo:                                # if there are no actions yet
                todo.insert(0, jtagobj.actionProgram)   # add some useful actions...
    else:                                               # number of args is wrong
        parser.error("Unsuitable number of arguments")

    if options.verbose:   # debug infos
        sys.stderr.write("Debug is %s\n" % DEBUG)
        sys.stderr.write("Verbosity level set to %d\n" % options.verbose)
        sys.stderr.write("Python version: %s\n" % sys.version)
        #~ sys.stderr.write("JTAG backend: %s\n" % jtag.backend)

    # sanity check of options
    if goaddr and reset:
        if not options.quiet:
            sys.stderr.write("Warning: option --reset ignored as --go is specified!\n")
        reset = False

    if options.upload_list and reset:
        if not options.quiet:
            sys.stderr.write("Warning: option --reset ignored as --upload is specified!\n")
        reset = False

    if options.upload_list and options.wait:
        if not options.quiet:
            sys.stderr.write("Warning: option --wait ignored as --upload is specified!\n")
        options.wait = False

    # prepare output
    if options.output is None:
        out = sys.stdout
        if sys.platform == "win32":
            # ensure that the console is in binary mode
            import os, msvcrt
            msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
    else:
        out = open(options.output, 'wb')

    # prepare data to download
    data = memory.Memory()                  # prepare downloaded data

    for filename in args:
        if filename == '-':
            data.merge(memory.load('<stdin>', sys.stdin, format=options.input_format or "titext"))
        else:
            data.merge(memory.load(filename, format=options.input_format))

    jtagobj.data = data                     # prepare downloaded data

    if options.verbose > 5:
        sys.stderr.write("File(s): %r\n" % args)

    # debug messages
    if toinit:
        if options.verbose:       # debug
            # show a nice list of scheduled actions
            sys.stderr.write("TOINIT list:\n")
            for f in toinit:
                try:
                    sys.stderr.write("   %s\n" % f.func_name)
                except AttributeError:
                    sys.stderr.write("   %r\n" % f)
    if todo:
        if options.verbose:       # debug
            # show a nice list of scheduled actions
            sys.stderr.write("TODO list:\n")
            for f in todo:
                try:
                    sys.stderr.write("   %s\n" % f.func_name)
                except AttributeError:
                    sys.stderr.write("   %r\n" % f)

    sys.stderr.flush()

    abort_due_to_error = 1
    release_done = 0
    jtagobj.open(options.port_name)                     # try to open port
    try:
        if options.ramsize is not None:
            jtagobj.setRamsize(options.ramsize)

        jtagobj.connect()                               # connect to target

        # initialization list
        if toinit:  # erase and erase check
            if options.verbose:
                sys.stderr.write("Preparing device ...\n")
            for f in toinit:
                f()

        # work list
        if todo:
            for f in todo:
                f()                          # work through TODO list

        if reset:                                       # reset device first if desired
            jtagobj.reset()

        for function, args in parameters:
            function(*args)

        if funclet is not None:                         # download and start funclet
            jtagobj.actionFunclet(options.timeout)

        if goaddr is not None:                          # start user program at specified address
            jtagobj.actionRun(goaddr)                   # load PC and execute

        for format, function, args in results:
            print(format % function(*args))

        # upload data block and output
        if uploadlist:
            if goaddr:                                  # if a program was started...
                raise NotImplementedError
                # TODO:
                # sys.stderr.write("Waiting to device for reconnect for upload: ")
            data = memory.Memory()
            for start, end in uploadlist:
                size = end - start + 1
                if options.verbose > 2:
                    sys.stderr.write("Upload 0x%04x %d bytes\n" % (start, size))
                data.append(memory.Segment(start, jtagobj.uploadData(start, size)))  # upload data
            memory.save(data, out, options.output_format)
            options.wait = False   # wait makes no sense as after upload, the device is still stopped

        if options.wait:                                # wait at the end if desired
            jtagobj.reset(1, 1)                         # reset and release target
            release_done = 1
            if not options.quiet:
                sys.stderr.write("Press <ENTER> ...\n")  # display a prompt
                sys.stderr.flush()
            input()                                 # wait for newline

        abort_due_to_error = 0
    finally:
        if abort_due_to_error:
            sys.stderr.write("Cleaning up after error...\n")
        if not release_done:
            jtagobj.reset(1, 1)                         # reset and release target
        if not options.no_close:
            jtagobj.close()                             # release communication port
        elif options.verbose:
            sys.stderr.write("WARNING: JTAG port is left open (--no-close)\n")