]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - tools/platforms/msp430/pybsl/tos-bsl.in
Incorporate new modular tos-bsl.
[tinyos-2.x.git] / tools / platforms / msp430 / pybsl / tos-bsl.in
index ee0d4152ddbdeaa1124b34f4d397f484da91101a..4cd94d86da85ea28b840d70d83279301ba56e1c0 100644 (file)
 #
 # fixes from Colin Domoney
 #
-# based on the application note slas96b.pdf from Texas Instruments, Inc.,
+# based on the application note slaa96b.pdf from Texas Instruments, Inc.,
 # Volker Rzehak
 # additional infos from slaa089a.pdf
+#
+# Modularization by R. Steve McKown, <rsmckown@gmail.com>.
+# Based upon work Copyright (c) 2006-2007 by Sporian Microsystems, Inc.
+#
+#
+# Set and clear of digital signals
+# ================================
+#
+# All functions that can set or clear a digital pin or signal state do so
+# relative to the assertion state of its signal.  That is, setXXX(1) asserts
+# signal XXX and setXXX(0) unasserts signal XXX.  Asserting a signal means its
+# logic value is set to that value that asserts, or activates, its condition.
+# Signals may be either active high or active low, as shown in the chart below.
+#
+#     signal    -- asserted --  - unasserted -
+#     active    --- value  ---  --- value  ---
+#     state     logic  voltage  logic  voltage
+#     ----------------------------------------
+#      high       1      Vcc      0      GND
+#      low        0      GND      1      VCC
+#
+# It is the responsibility of the setXXX functions to properly convert the
+# set request into the proper output value.  This provides a consistency for
+# applications using the set functions, since they no longer care the manner
+# in which an asserted or unasserted signal are actually represented in the
+# transmission medium.
+#
+#
+# Important information about RS-232C signals
+# ===========================================
+#
+# RS-232C signals are active low.  Confusingly, however, RS-232C physical
+# drivers effectively invert the value, such that a high value, or MARK, is
+# delivered over the wire as a negative voltage while a low value, or SPACE, is
+# delivered as a positive voltage.  By looking at an RS-232C signal on an
+# oscilloscope, one might conclude that the RS-232C signals are active high for
+# this reason.  Here is how RS-232 breaks down:
+#
+#    signal   logical   RS-232C       RS-232C        TTL RS-232
+#    state     value   value name  output voltage  output voltage
+# ---------------------------------------------------------------
+#   asserted   0/low     SPACE       +3v...+15v         GND (0V)
+#  unasserted  1/high    MARK        -3v...-15v         VCC
+#
+# Note that some RS-232 signals, notably TxD (transmit data) and RxD (receive
+# data), can be idle.  An idle signal is always unasserted.
+#
+# Using this guidance, an asserted DTR signal is logic low, is 0V in TTL RS-232
+# and +3V..15V in RS-232C.
+#
+# PC serial ports often break the spec and treat 0v as a logic 1/MARK instead
+# of an invalid value.
+#
+#
+# Important MSP430 signals
+# ========================
+#
+# The BSL protocol is entered by manipulating the RST and TCK pins on MSP430
+# uC's with dedicated JTAG pins, and by manipulating RST and TEST pins on
+# MSP430 uC's with shared JTAG pins.  The assertion state of TEST and TCK
+# are the same, so we use the term TTCK to imply either or both of them
+# simultaneously.
+#
+# RST and TCK are active low signals.  TEST is active high.
+#
+# An MSP430 is reset by simplying asserting RST for a short period then
+# unasserting it.
+#
+# The BSL mode is entered by performing this sequence of events, subject to
+# timing constraints documented by TI:
+#   Assert RST
+#   Assert TTCK
+#   Unssert TTCK
+#   Assert TTCK
+#   Unssert RST
+#   Unssert TTCK
+#
+#
+# The TI slaa096d Document
+# ========================
+#
+# The TI slaa096d document defines a circuit that can be used to program MSP430
+# parts using the BSL protocol.  Other platforms, such as Telos, EyesIFx and
+# Tinynode to name a few, also incorporate support for BSL using circuitry
+# that can vary significantly from the TI schematic.
+#
+# The code presented in the TI document does not use a consistent methodology
+# to indicate what is happening when a setXXX(n) function is called.  In some
+# cases, 'n' represents the assertion state, where 1=asserted and 0=unasserted.
+# In other cases, 'n' represents the inverse of the assertion state.  In yet
+# other cases, 'n' represents the logic value of the signal on a given pin, or
+# the inverse of the logic value.
+#
+# To improve readability and allow for modular, pluggable BSL handling, this
+# code explicitly defines all setXXX(n) functions where 'n' represents the
+# assertion state of the signal.  In other words, when n==1 the signal is
+# asserted and when n==0 the signal is unasserted.  One can trivially determine
+# the logic state of any signal pin by applying the current assertion state to
+# the signal's active state (see the charts above).
+#
+# Device support
+# ==============
+#
+# To add support for a new MSP430-based device, create a new class deriving
+# from bsl_standard or one of its specializations.
+#
 
-import sys, time, string, cStringIO, struct
+import sys, fcntl, time, string, cStringIO, struct
 sys.path.append("@tinyoslibdir@")
 import serial
 
@@ -183,17 +289,20 @@ q
 #cpu types for "change baudrate"
 #use strings as ID so that they can be used in outputs too
 F1x                     = "F1x family"
+F2x                     = "F2x family"
 F4x                     = "F4x family"
 
 #known device list
 deviceids = {
     0xf149: F1x,
+    0xf169: F1x,
     0xf16c: F1x, #for telosb
     0xf112: F1x,
     0xf413: F4x,
     0xf123: F1x,
     0xf449: F4x,
     0x1232: F1x,
+    0xf26f: F2x,
 }
 
 class BSLException(Exception):
@@ -266,14 +375,6 @@ class LowLevel:
         else:
             self.prolongFactor = aProlongFactor
 
-        #flags for inverted use of control pins
-        #used for some hardware
-        self.invertRST = 0
-        self.invertTEST = 0
-       self.swapRSTTEST = 0
-       self.telosLatch = 0
-       self.telosI2C = 0
-        
         self.protocolMode = self.MODE_BSL
         self.BSLMemAccessWarning = 0                #Default: no warning.
         self.slowmode = 0
@@ -298,8 +399,7 @@ class LowLevel:
             timeout = self.timeout
         )
         if DEBUG: sys.stderr.write("using serial port %r\n" % self.serialport.portstr)
-        self.SetRSTpin()                        #enable power
-        self.SetTESTpin()                       #enable power
+        self.bslInit()                          #enable power
         self.serialport.flushInput()
         self.serialport.flushOutput()
 
@@ -310,8 +410,7 @@ class LowLevel:
         used in other programs.
         Returns zero if the function is successful."""
         if DEBUG > 1: sys.stderr.write("* comDone()")
-        self.SetRSTpin(1)                       #disable power
-        self.SetTESTpin(0)                      #disable power
+        self.bslDone()                          #disable power
         self.serialport.close()
 
     def comRxHeader(self):
@@ -437,141 +536,6 @@ class LowLevel:
 
         raise BSLException("Unknown header 0x%02x\nAre you downloading to RAM into an old device that requires the patch? Try option -U" % rxHeader)
 
-    def SetDTR(self, level, invert):
-        """Controls DTR pin (0: GND; 1: VCC; unless inverted flag is set)"""
-        if invert:
-            self.serialport.setDTR(not level)
-        else:
-            self.serialport.setDTR(level)
-        if self.slowmode:
-            time.sleep(0.040)
-
-    def SetRTS(self, level, invert):
-        """Controls RTS pin (0: GND; 1: VCC; unless inverted flag is set)"""
-        if invert:
-            self.serialport.setRTS(not level)
-        else:
-            self.serialport.setRTS(level)
-        if self.slowmode:
-            time.sleep(0.040)
-
-    def SetRSTpin(self, level=1):
-        """Controls RST/NMI pin (0: GND; 1: VCC; unless inverted flag is set)"""
-        if self.swapRSTTEST:
-            self.SetRTS(level, self.invertRST)
-        else:
-            self.SetDTR(level, self.invertRST)
-
-    def SetTESTpin(self, level=1):
-        """Controls TEST pin (inverted on board: 0: VCC; 1: GND; unless inverted flag is set)"""
-        if self.swapRSTTEST:
-            self.SetDTR(level, self.invertTEST)
-        else:
-            self.SetRTS(level, self.invertTEST)
-
-    def telosSetSCL(self, level):
-        self.serialport.setRTS(not level)
-
-    def telosSetSDA(self, level):
-        self.serialport.setDTR(not level)
-
-    def telosI2CStart(self):
-       self.telosSetSDA(1)
-       self.telosSetSCL(1)
-       self.telosSetSDA(0)
-
-    def telosI2CStop(self):
-       self.telosSetSDA(0)
-       self.telosSetSCL(1)
-       self.telosSetSDA(1)
-
-    def telosI2CWriteBit(self, bit):
-       self.telosSetSCL(0)
-       self.telosSetSDA(bit)
-        time.sleep(2e-6)
-       self.telosSetSCL(1)
-        time.sleep(1e-6)
-       self.telosSetSCL(0)
-
-    def telosI2CWriteByte(self, byte):
-        self.telosI2CWriteBit( byte & 0x80 );
-        self.telosI2CWriteBit( byte & 0x40 );
-        self.telosI2CWriteBit( byte & 0x20 );
-        self.telosI2CWriteBit( byte & 0x10 );
-        self.telosI2CWriteBit( byte & 0x08 );
-        self.telosI2CWriteBit( byte & 0x04 );
-        self.telosI2CWriteBit( byte & 0x02 );
-        self.telosI2CWriteBit( byte & 0x01 );
-        self.telosI2CWriteBit( 0 );  # "acknowledge"
-
-    def telosI2CWriteCmd(self, addr, cmdbyte):
-       self.telosI2CStart()
-        self.telosI2CWriteByte( 0x90 | (addr << 1) )
-       self.telosI2CWriteByte( cmdbyte )
-       self.telosI2CStop()
-
-    def telosBReset(self,invokeBSL=0):
-
-       # "BSL entry sequence at dedicated JTAG pins"
-        # rst !s0: 0 0 0 0 1 1
-       # tck !s1: 1 0 1 0 0 1
-        #   s0|s1: 1 3 1 3 2 0
-
-       # "BSL entry sequence at shared JTAG pins"
-        # rst !s0: 0 0 0 0 1 1
-       # tck !s1: 0 1 0 1 1 0
-        #   s0|s1: 3 1 3 1 0 2
-
-       if invokeBSL:
-         self.telosI2CWriteCmd(0,1)
-         self.telosI2CWriteCmd(0,3)
-         self.telosI2CWriteCmd(0,1)
-         self.telosI2CWriteCmd(0,3)
-         self.telosI2CWriteCmd(0,2)
-         self.telosI2CWriteCmd(0,0)
-       else:
-         self.telosI2CWriteCmd(0,3)
-         self.telosI2CWriteCmd(0,2)
-       self.telosI2CWriteCmd(0,0)
-        time.sleep(0.250)       #give MSP430's oscillator time to stabilize
-       self.serialport.flushInput()  #clear buffers
-
-    def bslReset(self, invokeBSL=0):
-        """Applies BSL entry sequence on RST/NMI and TEST/VPP pins
-        Parameters:
-            invokeBSL = 1: complete sequence
-            invokeBSL = 0: only RST/NMI pin accessed
-
-        RST is inverted twice on boot loader hardware
-        TEST is inverted (only once)
-        Need positive voltage on DTR, RTS for power-supply of hardware"""
-       if self.telosI2C:
-         self.telosBReset(invokeBSL)
-         return
-
-        if DEBUG > 1: sys.stderr.write("* bslReset(invokeBSL=%s)\n" % invokeBSL)
-        self.SetRSTpin(1)       #power suply
-        self.SetTESTpin(1)      #power suply
-        time.sleep(0.250)       #charge capacitor on boot loader hardware
-
-       if self.telosLatch:
-         self.SetTESTpin(0)
-         self.SetRSTpin(0)
-         self.SetTESTpin(1)
-
-        self.SetRSTpin(0)       #RST  pin: GND
-        if invokeBSL:
-            self.SetTESTpin(1)  #TEST pin: GND
-            self.SetTESTpin(0)  #TEST pin: Vcc
-            self.SetTESTpin(1)  #TEST pin: GND
-            self.SetTESTpin(0)  #TEST pin: Vcc
-            self.SetRSTpin (1)  #RST  pin: Vcc
-            self.SetTESTpin(1)  #TEST pin: GND
-        else:
-            self.SetRSTpin(1)   #RST  pin: Vcc
-        time.sleep(0.250)       #give MSP430's oscillator time to stabilize
-
-        self.serialport.flushInput()    #clear buffers
 
     def bslSync(self,wait=0):
         """Transmits Synchronization character and expects to receive Acknowledge character
@@ -765,6 +729,8 @@ class Memory:
             self.loadTIText(open(filename, "rb"))
         elif filename[-4:].lower() in ('.a43', '.hex'):
             self.loadIHex(open(filename, "rb"))
+        elif filename[-5:].lower() in ('.ihex'):
+            self.loadIHex(open(filename, "rb"))
         else:
             self.loadELF(open(filename, "rb"))
 
@@ -874,7 +840,7 @@ class BootStrapLoader(LowLevel):
                     continue
 
     def programBlk(self, addr, blkout, action):
-        """programm a memory block"""
+        """program a memory block"""
         if DEBUG > 1: sys.stderr.write("* programBlk()\n")
 
         #Check, if specified range is erased
@@ -894,7 +860,7 @@ class BootStrapLoader(LowLevel):
     #list of tuples or lists:
     #segements = [ (addr1, [d0,d1,d2,...]), (addr2, [e0,e1,e2,...])]
     def programData(self, segments, action):
-        """programm or verify data"""
+        """program or verify data"""
         if DEBUG > 1: sys.stderr.write("* programData()\n")
         for seg in segments:
             currentAddr = seg.startaddress
@@ -964,6 +930,19 @@ class BootStrapLoader(LowLevel):
         #Transmit password to get access to protected BSL functions.
         self.txPasswd()
 
+    def actionMainErase(self):
+        """Erase the main flash memory only"""
+        sys.stderr.write("Main Erase...\n")
+        sys.stderr.flush()
+        self.bslReset(1)                            #Invoke the boot loader.
+        self.txPasswd(self.passwd)                  #transmit password
+        for i in range(self.meraseCycles):
+            if i == 1: sys.stderr.write("Additional Main Erase Cycles...\n")
+           self.bslTxRx(self.BSL_ERASE,            #Command: Segment Erase
+                               0xfffe,             #Any address within flash memory.
+                               0xa504)             #Required setting for main erase!
+        self.passwd = None                          #Password gets erased
+
     def actionStartBSL(self, usepatch=1, adjsp=1, replacementBSL=None, forceBSL=0, mayuseBSL=0, speed=None, bslreset=1):
         """start BSL, download patch if desired and needed, adjust SP if desired"""
         sys.stderr.write("Invoking BSL...\n")
@@ -1020,11 +999,16 @@ class BootStrapLoader(LowLevel):
                     sys.stderr.write("Using built in BSL replacement for F4x devices\n")
                     sys.stderr.flush()
                 replacementBSL.loadTIText(cStringIO.StringIO(F4X_BSL))  #parse embedded BSL
-            else:
+            elif self.cpu == F1x:
                 if DEBUG:
                     sys.stderr.write("Using built in BSL replacement for F1x devices\n")
                     sys.stderr.flush()
                 replacementBSL.loadTIText(cStringIO.StringIO(F1X_BSL))  #parse embedded BSL
+           else:
+                if DEBUG:
+                    sys.stderr.write("NO built in BSL replacement for F2x devices\n")
+                    sys.stderr.flush()
+                #replacementBSL.loadTIText(cStringIO.StringIO(F1X_BSL))  #parse embedded BSL
     
         #now download the new BSL, if allowed and needed (version lower than the
         #the replacement) or forced
@@ -1121,7 +1105,7 @@ class BootStrapLoader(LowLevel):
             raise BSLException, "verify without data not possible"
 
     def actionReset(self):
-        """perform a reset, start user programm"""
+        """perform a reset, start user program"""
         sys.stderr.write("Reset device ...\n")
         sys.stderr.flush()
         self.bslReset(0) #only reset
@@ -1140,6 +1124,11 @@ class BootStrapLoader(LowLevel):
             19200:[0x86e0, 0x0001],
             38400:[0x87e0, 0x0002],
         },
+        F2x: {
+             9600:[0x8580, 0x0000],
+            19200:[0x8b00, 0x0001],
+            38400:[0x8c80, 0x0002],
+        },
         F4x: {
              9600:[0x9800, 0x0000],
             19200:[0xb000, 0x0001],
@@ -1175,6 +1164,342 @@ class BootStrapLoader(LowLevel):
         print "Device Type: 0x%04x\nBSL version: 0x%04x\n" % (family_type, bsl_version)
 
 
+class bsl_standard(BootStrapLoader):
+    """
+       This class supports the TI RS-232C programmer presented in slaa096d.
+       The programmer and the MSP430 being programmed are powered from power
+       scavenged off the DTR and RTS lines.  Therefore, it is important that
+       DTR and RTS are asserted for some period before programming to charge
+       the programmer's power capacitor.  Recall that an asserted RS-232
+       signal generates a voltage between +3v and +15v.
+
+       Per the documentation the signals' assertion states map as follows:
+       rs232.DTR -> (invert) -> msp430.RST
+       rs232.RTS -> (invert) -> msp430.TTCK
+           msp430.TTCK -> msp430.TCK
+           msp430.TTCK -> (invert) -> msp430.TEST
+    """
+    def __init__(self, *args, **kargs):
+        BootStrapLoader.__init__(self, *args, **kargs)
+
+    def mayuseBSL(self):
+       return 1
+
+    def speed(self):
+       return None
+
+    def setRST(self, assertme):
+       """
+           Calling setRST(1) asserts the RST signal at the msp430.  Since RST
+           is active low, asserted=GND and unasserted=Vcc.
+
+           Do not override this method
+       """
+       self.lsetRST(assertme)
+       if (self.slowmode):
+           time.sleep(0.040)
+
+    def setTTCK(self, assertme):
+       """
+           Calling setTTCK(1) asserts TTCK.  TTCK is a pseudo-signal that
+           acts as TCK and/or TEST.  TCK is active high and TEST is active low.
+
+           Do not override this method
+       """
+       self.lsetTTCK(assertme)
+       if (self.slowmode):
+           time.sleep(0.040)
+
+    def lsetRST(self, assertme):
+       """ rs232.DTR -> (invert) -> msp430.RST """
+       self.serialport.setDTR(not assertme)
+
+    def lsetTTCK(self, assertme):
+       """ rs232.RTS -> (invert) -> msp430.TTCK """
+       self.serialport.setRTS(not assertme)
+
+    def bslInit(self):
+       """ Initial state: RST and TTCK are unasserted """
+       self.setRST(0)
+       self.setTTCK(0)
+
+    def bslPrepare(self):
+       """
+           bslInit unaserted RST and TTCK, which asserted DTR and RTS.  Wait
+           a while to allow the programmer power cap to charge from the V+
+           supplied by DTR and RTS.
+       """
+        time.sleep(0.250)
+
+    def bslDone(self):
+       """ Unasserting RST and TTCK also cuts power to the programmer """
+       self.setRST(0)
+       self.setTTCK(0)
+
+    def bslReset(self, invokeBSL=0):
+        if DEBUG > 1: sys.stderr.write("* bslReset(invokeBSL=%s)\n" % invokeBSL)
+       self.bslInit()
+       self.bslPrepare()
+        self.setRST(1)
+        if invokeBSL:
+            self.setTTCK(1)
+            self.setTTCK(0)
+            self.setTTCK(1)
+            self.setRST(0)
+            self.setTTCK(0)
+        else:
+            self.setRST(0)
+        time.sleep(0.250)      # Allow MSP430 oscillator time to stabilize
+        self.serialport.flushInput()
+
+
+class bsl_telosa(bsl_standard):
+    """
+       The telosa hardware allows for programming its MSP430 via a USB port
+       through a USB/serial chip.  The mapping of serial to uC signals differ
+       from the standard TI bsl hardware supported in bsl_standard.  DTR from
+       the USB/serial chip is tied directly to TCK and RST is configured
+       through inverters and a type D flip-flop to help prevent spurious uC
+       resets.
+
+       The signals' assertion states map as follows:
+       usbserial.RTS -> msp430.RST
+       usbserial.DTR -> msp430.TCK
+
+       When performing a bslReset(), RST must first be asserted by clearing
+       the onboard flip-flop:
+           assert usbserial.DTR
+           assert usbserial.RTS
+           unassert usbserial.DTR
+    """
+    def __init__(self, *args, **kargs):
+        bsl_standard.__init__(self, *args, **kargs)
+
+    def lsetRST(self, assertme):
+       """ rs232.RTS -> msp430.RST """
+       self.serialport.setRTS(assertme);
+
+    def lsetTTCK(self, assertme):
+       """ rs232.DTR -> msp430.TTCK """
+       self.serialport.setDTR(assertme);
+
+    def bslPrepare(self):
+       """ Run the standard bslPrepare, then set the telosa flip-flop """
+       bsl_standard.bslPrepare(self)
+       self.serialport.setDTR(1)
+       self.serialport.setRTS(1)
+       self.serialport.setDTR(0)
+
+
+class bsl_telosb(bsl_standard):
+    """
+       The telosb allows programming of its MSP430 via a USB port through a
+       USB/serial chip.  It incorporates an I2C switch, whose SDA and SCL
+       inputs driven by the serial DTR and RTS signals.  Switch outputs are
+       tied to the uC RST and TCK pins.
+
+       The signals' assertion states map as follows:
+       usbserial.RTS -> (invert) -> I2C.SCL
+       usbserial.DTR -> (invert) -> I2C.SDA
+    """
+    def __init__(self, *args, **kargs):
+        bsl_standard.__init__(self, *args, **kargs)
+
+    def mayuseBSL(self):
+       return 0
+
+    def speed(self):
+       return 38400
+
+    def setSCL(self, level):
+        self.serialport.setRTS(not level)
+
+    def setSDA(self, level):
+        self.serialport.setDTR(not level)
+
+    def i2cStart(self):
+       self.setSDA(1)
+       self.setSCL(1)
+       self.setSDA(0)
+
+    def i2cStop(self):
+       self.setSDA(0)
+       self.setSCL(1)
+       self.setSDA(1)
+
+    def i2cWriteBit(self, bit):
+       self.setSCL(0)
+       self.setSDA(bit)
+        time.sleep(2e-6)
+       self.setSCL(1)
+        time.sleep(1e-6)
+       self.setSCL(0)
+
+    def i2cWriteByte(self, byte):
+        self.i2cWriteBit( byte & 0x80 );
+        self.i2cWriteBit( byte & 0x40 );
+        self.i2cWriteBit( byte & 0x20 );
+        self.i2cWriteBit( byte & 0x10 );
+        self.i2cWriteBit( byte & 0x08 );
+        self.i2cWriteBit( byte & 0x04 );
+        self.i2cWriteBit( byte & 0x02 );
+        self.i2cWriteBit( byte & 0x01 );
+        self.i2cWriteBit( 0 );  # "acknowledge"
+
+    def i2cWriteCmd(self, addr, cmdbyte):
+       self.i2cStart()
+        self.i2cWriteByte( 0x90 | (addr << 1) )
+       self.i2cWriteByte( cmdbyte )
+       self.i2cStop()
+
+    def bslInit(self):
+       """ Not needed for telosb """
+
+    def bslDone(self):
+       """ Not needed for telosb """
+
+    def bslReset(self,invokeBSL=0):
+       # "BSL entry sequence at dedicated JTAG pins"
+        # rst !s0: 0 0 0 0 1 1
+       # tck !s1: 1 0 1 0 0 1
+        #   s0|s1: 1 3 1 3 2 0
+
+       # "BSL entry sequence at shared JTAG pins"
+        # rst !s0: 0 0 0 0 1 1
+       # tck !s1: 0 1 0 1 1 0
+        #   s0|s1: 3 1 3 1 0 2
+
+       if invokeBSL:
+         self.i2cWriteCmd(0,1)
+         self.i2cWriteCmd(0,3)
+         self.i2cWriteCmd(0,1)
+         self.i2cWriteCmd(0,3)
+         self.i2cWriteCmd(0,2)
+         self.i2cWriteCmd(0,0)
+       else:
+         self.i2cWriteCmd(0,3)
+         self.i2cWriteCmd(0,2)
+       self.i2cWriteCmd(0,0)
+        time.sleep(0.250)       #give MSP430's oscillator time to stabilize
+       self.serialport.flushInput()  #clear buffers
+
+
+class bsl_cp2103(bsl_standard):
+    """
+        Some boards allow programming of their MSP430 via an onboard cp2103
+       USB/serial chip configured such that two of its gpio pins are tied
+       directly to the RST and TCK pins of the uC.  In this configuration the
+       RST and TCK signals are pulled up and the cp2103's gpio pins are
+       configured as open drain outputs.  The gpio pins are active low and
+       are unasserted on power-up.
+
+       The signals' assertion states map as follows:
+       usbserial.GPIO_3 -> msp430.RST
+       usbserial.GPIO_2 -> msp430.TCK
+    """
+    def __init__(self, *args, **kargs):
+        bsl_standard.__init__(self, *args, **kargs)
+       self.cp2103 = None
+
+    def mayuseBSL(self):
+       return 0
+
+    def speed(self):
+       return 38400
+
+    def lsetRST(self, assertme):
+       """ usbserial.GPIO_3 -> msp430.RST """
+       self.cp2103.setGpio3(assertme);
+
+    def lsetTTCK(self, assertme):
+       """ usbserial.GPIO_2 -> msp430.TTCK """
+       self.cp2103.setGpio2(assertme);
+
+    def bslInit(self):
+       if not self.cp2103:
+           # We can't define cp2103 until the first call to bslInit, since
+           # self.serialport is not instantiated until then.
+           self.cp2103 = cp2103_factory(self.serialport)
+       bsl_standard.bslInit(self)
+
+
+GPIOBIC  = 0x89f2
+GPIOBIS  = 0x89f3
+GPIO_2 = 0x04
+GPIO_3 = 0x08
+
+class cp2103_posix:
+    """
+       Implements cp2103 gpio access for posix systems using ioctl() calls.
+       Requires a cp210x driver providing gpio control.
+    """
+    def __init__(self, serialport):
+       sys.stderr.write("cp2103_posix\n")
+       self.fd = serialport.fd
+
+    def setGpio2(self, assertme):
+       """ set not assertme to the gpio pin """
+        if not self.fd: raise "connection not open"
+        if assertme:
+            fcntl.ioctl(self.fd, GPIOBIC, GPIO_2)
+        else:
+            fcntl.ioctl(self.fd, GPIOBIS, GPIO_2)
+       time.sleep(0.010) # no sleep = too fast
+
+    def setGpio3(self, assertme):
+       """ set not assertme to the gpio pin """
+        if not self.fd: raise "connection not open"
+        if assertme:
+            fcntl.ioctl(self.fd, GPIOBIC, GPIO_3)
+        else:
+            fcntl.ioctl(self.fd, GPIOBIS, GPIO_3)
+       time.sleep(0.010) # no sleep = too fast
+
+
+class cp2103_cygwin:
+    """
+       Implements cp2103 gpio access for windows cygwin systems via the
+        cp210x VCP and the CP210xRuntime.dll.
+    """
+    def __init__(self, serialport):
+       import cp210xrt
+       sys.stderr.write("cp2103_cygwin\n")
+       self.fd = serialport.fd
+
+    def setGpio2(self, assertme):
+       """ set not assertme to the gpio pin """
+       import cp210xrt
+        if assertme:
+           cp210xrt.writeLatch(self.fd, GPIO_2, 0)
+       else:
+           cp210xrt.writeLatch(self.fd, GPIO_2, GPIO_2)
+
+    def setGpio3(self, assertme):
+       """ set not assertme to the gpio pin """
+       import cp210xrt
+        if assertme:
+           cp210xrt.writeLatch(self.fd, GPIO_3, 0)
+       else:
+           cp210xrt.writeLatch(self.fd, GPIO_3, GPIO_3)
+
+
+def cp2103_factory(serialport):
+    import os;
+    if os.name == 'posix':
+       if sys.platform == 'cygwin':
+           return cp2103_cygwin(serialport)
+       else:
+           return cp2103_posix(serialport)
+    else:
+       raise "No cp2103 support is available for your platform."
+
+
+def getClass(classname, modulename="__main__"):
+    """ Used by main() to select the appropriate bsl class based on device """
+    return getattr(__import__(modulename, globals(), locals(), [classname]),
+           classname)
+
+
 def usage():
     """print some help message"""
     sys.stderr.write("""
@@ -1221,22 +1546,20 @@ General options:
                         Possible values are 9600, 19200, 38400
                         (default 9600)
   -1, --f1x             Specify CPU family, in case autodetect fails
+  -2, --f2x             Specify CPU family, in case autodetect fails
   -4, --f4x             Specify CPU family, in case autodetect fails
-                        --F1x and --f2x are only needed when the "change
+                        --f1x, --f2x and --f4x are only needed when the "change
                         baudrate" feature is used and the autodetect feature
                         fails. If the device ID that is uploaded is known, it
                         has precedence to the command line option.
-  --invert-reset        Invert signal on RST pin (used for some BSL hardware)
-  --invert-test         Invert signal on TEST/TCK pin (used for some BSL
-                        hardware)
-  --swap-reset-test     Swap the RST and TEST pins (used for some BSL hardware)
-  --telos-latch         Special twiddle in BSL reset for Telos hardware
-  --telos-i2c           DTR/RTS map via an I2C switch to TCK/RST in Telos Rev.B
-  --telos               Implies options --invert-reset, --invert-test, 
-                        --swap-reset-test, and --telos-latch
-  --telosb              Implies options --swap-reset-test, --telos-i2c,
-                        --no-BSL-download, and --speed=38400
-  --tmote               Identical operation to --telosb
+  --device=device       Required device.  Supported devices are:
+                            standard - Standard BSL programmer per TI specs
+                           telosa - Telos revA and compatible boards
+                           telosb - Telos revB and compatible boards
+                           cp2103 - Boards using cp2103 gpio for BSL support
+                           cp2103_old - The old cp2103 gpio format
+                       Most settings for a device are defined within the
+                       device specific bsl_{device} class.
   --no-BSL-download     Do not download replacement BSL (disable automatic)
   --force-BSL-download  Download replacement BSL even if not needed (the one
                         in the device would have the required features)
@@ -1245,6 +1568,7 @@ General options:
 
 Program Flow Specifiers:
   -e, --masserase       Mass Erase (clear all flash memory)
+  -M, --mainerase       Erase main flash memory only (requires --password)
   -E, --erasecheck      Erase Check by file
   -p, --program         Program file
   -v, --verify          Verify by file
@@ -1263,11 +1587,11 @@ Data retreiving:
                         to redirect the output into a file.
 
 Do before exit:
-  -g, --go=address      Start programm execution at specified address.
+  -g, --go=address      Start program execution at specified address.
                         This implies option --wait.
   -r, --reset           Reset connected MSP430. Starts application.
                         This is a normal device reset and will start
-                        the programm that is specified in the reset
+                        the program that is specified in the reset
                         vector. (see also -g)
   -w, --wait            Wait for <ENTER> before closing serial port.
 
@@ -1320,7 +1644,7 @@ def main():
     reset       = 0
     wait        = 0     #wait at the end
     goaddr      = None
-    bsl         = BootStrapLoader()
+    bsl         = None  # now defined dynamically BootStrapLoader()
     toinit      = []
     todo        = []
     startaddr   = None
@@ -1335,21 +1659,35 @@ def main():
 
     try:
         opts, args = getopt.getopt(sys.argv[1:],
-            "hc:P:wf:m:eEpvrg:UDudsxbITNB:S:V14",
+            "hc:P:wf:m:eMEpvrg:UDu:ds:xbITNB:S:V124",
             ["help", "comport=", "password=", "wait", "framesize=",
-             "erasecycles=", "masserase", "erasecheck", "program",
+             "erasecycles=", "masserase", "mainerase", "erasecheck", "program",
              "verify", "reset", "go=", "unpatched", "debug",
              "upload=", "download=", "size=", "hex", "bin",
              "intelhex", "titext", "notimeout", "bsl=", "speed=",
-             "bslversion", "f1x", "f4x", "invert-reset", "invert-test",
-            "swap-reset-test", "telos-latch", "telos-i2c", "telos", "telosb",
-             "tmote","no-BSL-download", "force-BSL-download", "slow"]
+             "bslversion", "f1x", "f2x", "f4x", "no-BSL-download",
+            "force-BSL-download", "slow", "device=" ]
         )
     except getopt.GetoptError:
         # print help information and exit:
         usage()
         sys.exit(2)
 
+    # Get the --device setting first.  If none, then use bsl_standard
+    for o, a in opts:
+       if o in ("--device", ):
+           # TBD: dynamically instantiate the correct bootloader class
+           bsl = getClass("bsl_%s" % a)()
+    if not bsl:
+       bsl = getClass("bsl_standard")()
+    if not callable(bsl.preparePatch):
+       raise BSLException("Invalid device %s\n" % a)
+    sys.stderr.write("Using device class %s\n" % bsl.__class__.__name__)
+    if callable(bsl.mayuseBSL):
+       mayuseBSL = bsl.mayuseBSL()
+    if callable(bsl.speed):
+       speed = bsl.speed()
+
     for o, a in opts:
         if o in ("-h", "--help"):
             usage()
@@ -1394,9 +1732,11 @@ def main():
             bsl.meraseCycles = meraseCycles
         elif o in ("-e", "--masserase"):
             toinit.append(bsl.actionMassErase)        #Erase Flash
+        elif o in ("-M", "--mainerase"):
+            toinit.append(bsl.actionMainErase)  #Erase main Flash
         elif o in ("-E", "--erasecheck"):
             toinit.append(bsl.actionEraseCheck)       #Erase Check (by file)
-        elif o in ("-p", "--programm"):
+        elif o in ("-p", "--program"):
             todo.append(bsl.actionProgram)          #Program file
         elif o in ("-v", "--verify"):
             todo.append(bsl.actionVerify)           #Verify file
@@ -1456,34 +1796,14 @@ def main():
                 sys.stderr.write("speed must be decimal number\n")
                 sys.exit(2)
         elif o in ("-1", "--f1x"):
+           # TBD: the cpu spec would best be defined in the device, eh?
             bsl.cpu = F1x
+        elif o in ("-2", "--f2x"):
+           # TBD: the cpu spec would best be defined in the device, eh?
+            bsl.cpu = F2x
         elif o in ("-4", "--f4x"):
+           # TBD: the cpu spec would best be defined in the device, eh?
             bsl.cpu = F4x
-        elif o in ("--invert-reset", ):
-            bsl.invertRST = 1
-        elif o in ("--invert-test", ):
-            bsl.invertTEST = 1
-        elif o in ("--swap-reset-test", ):
-            bsl.swapRSTTEST = 1
-        elif o in ("--telos-latch", ):
-            bsl.telosLatch = 1
-        elif o in ("--telos-i2c", ):
-            bsl.telosI2C = 1
-        elif o in ("--telos", ):
-            bsl.invertRST = 1
-            bsl.invertTEST = 1
-            bsl.swapRSTTEST = 1
-            bsl.telosLatch = 1
-        elif o in ("--telosb", ):
-            bsl.swapRSTTEST = 1
-            bsl.telosI2C = 1
-            mayuseBSL = 0
-           speed = 38400
-        elif o in ("--tmote", ):
-            bsl.swapRSTTEST = 1
-            bsl.telosI2C = 1
-            mayuseBSL = 0
-           speed = 38400
         elif o in ("--no-BSL-download", ):
             mayuseBSL = 0
         elif o in ("--force-BSL-download", ):
@@ -1585,7 +1905,7 @@ def main():
     if reset:                                       #reset device first if desired
         bsl.actionReset()
 
-    if goaddr is not None:                          #start user programm at specified address
+    if goaddr is not None:                          #start user program at specified address
         bsl.actionRun(goaddr)                       #load PC and execute
 
     #upload datablock and output