# Forked by Travis Goodspeed <travis at tnbelt.com> for use with the GoodFET
# JTAG programmer.
+# This WIP is intended to save the info flash when using --fromweb.
+# DONE:
+# - Save info flash before actionMassErase
+# - Make actionFromweb use board name to get the right firmware image
+# - Program saved info after other programming is complete
+# - Make saveinfo detect missing info (all 0xFF)
+# - Download image from web before erasing
+# TODO:
+# - Trim unnecessary BSL unlocks
+# - Add param to override saveinfo with a provided info.txt
+# - Figure out better way to saveinfo when -P is required
+# - Maybe use the best guess from contrib/infos/ when nothing better is provided?
+# - If saveinfo gets something interesting, request a copy
+# - Use FTDI Serial Number to archive info text and/or password (dragorn's idea)
+# /sys/bus/usb-serial/devices/ttyUSB0/../../serial
+
import sys, time, string, cStringIO, struct
-sys.path.append("/usr/lib/tinyos")
-import serial, os, glob
+#sys.path.append("/usr/lib/tinyos") #We no longer require TinyOS.
+import serial, os, subprocess, glob
#forked from TinyOS Telos version.
VERSION = string.split("Revision: 1.39-goodfet-8 ")[1]
}
#GoodFET firmware
-firmware = {
- 0xf16c: "http://goodfet.sourceforge.net/dist/msp430x1612.hex",
- 0xf26f: "http://goodfet.sourceforge.net/dist/msp430x2618.hex",
- 0xf227: "http://goodfet.sourceforge.net/dist/msp430x2274.hex"
+FIRMWARE_BASEURL = "http://goodfet.sourceforge.net/dist/";
+
+board = None
+BOARDS = {
+ #'apimote': "apimote1", # .hex not uploaded yet
+ #'apimote1': "apimote1",
+ 'facedancer10': "facedancer10",
+ 'facedancer11': "facedancer11",
+ 'facedancer20': "facedancer20",
+ 'facedancer21': "facedancer21",
+ 'goodfet11': "goodfet11",
+ 'goodfet31': "goodfet31",
+ 'goodfet32': "goodfet32",
+ 'goodfet41': "goodfet41",
+ 'goodfet42': "goodfet42",
+ 'goodthopter10': "goodthopter10",
+ 'goodthopter11': "goodthopter11",
+ 'telosb': "telosb",
+ 'telosbbt': "telosb",
+ 'z1': "z1",
+ 'zolertiaz1': "z1",
}
class BSLException(Exception):
ERR_RX_NAK = "NAK received (wrong password?)"
#ERR_CMD_NOT_COMPLETED = "Command did not send ACK: indicates that it didn't complete correctly"
ERR_CMD_FAILED = "Command failed, is not defined or is not allowed"
- ERR_BSL_SYNC = "Bootstrap loader synchronization error"
+ ERR_BSL_SYNC = "Bootstrap loader synchronization error (maybe you need -P)"
ERR_FRAME_NUMBER = "Frame sequence number error."
-
+
+ z1 = 0;
+
def calcChecksum(self, data, length):
"""Calculates a checksum of "data"."""
checksum = 0
timeout = self.timeout
)
if DEBUG: sys.stderr.write("using serial port %r\n" % self.serialport.portstr)
- self.SetRSTpin() #enable power
- self.SetTESTpin() #enable power
+
+ if not self.z1:
+ self.SetRSTpin() #enable power
+ self.SetTESTpin() #enable power
self.serialport.flushInput()
self.serialport.flushOutput()
self.telosI2CWriteByte( 0x90 | (addr << 1) )
self.telosI2CWriteByte( cmdbyte )
self.telosI2CStop()
+ def writepicROM(self, address, data):
+ ''' Writes data to @address'''
+ for i in range(7,-1,-1):
+ self.picROMclock((address >> i) & 0x01)
+ self.picROMclock(0)
+ recbuf = 0
+ for i in range(7,-1,-1):
+ s = ((data >> i) & 0x01)
+ #print s
+ if i < 1:
+ r = not self.picROMclock(s, True)
+ else:
+ r = not self.picROMclock(s)
+ recbuf = (recbuf << 1) + r
+
+ self.picROMclock(0, True)
+ #k = 1
+ #while not self.serial.getCTS():
+ # pass
+ #time.sleep(0.1)
+ return recbuf
+
+ def readpicROM(self, address):
+ ''' reads a byte from @address'''
+ for i in range(7,-1,-1):
+ self.picROMclock((address >> i) & 0x01)
+ self.picROMclock(1)
+ recbuf = 0
+ r = 0
+ for i in range(7,-1,-1):
+ r = self.picROMclock(0)
+ recbuf = (recbuf << 1) + r
+ self.picROMclock(r)
+ #time.sleep(0.1)
+ return recbuf
+
+ def picROMclock(self, masterout, slow = False):
+ #print "setting masterout to "+str(masterout)
+ self.serialport.setRTS(masterout)
+ self.serialport.setDTR(1)
+ #time.sleep(0.02)
+ self.serialport.setDTR(0)
+ if slow:
+ time.sleep(0.02)
+ return self.serialport.getCTS()
+
+ def picROMfastclock(self, masterout):
+ #print "setting masterout to "+str(masterout)
+ self.serialport.setRTS(masterout)
+ self.serialport.setDTR(1)
+ self.serialport.setDTR(0)
+ time.sleep(0.02)
+ return self.serialport.getCTS()
+
+ def bslResetZ1(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
+
+ By now only BSL mode is accessed
+ '''
+
+ if DEBUG > 1: sys.stderr.write("* bslReset(invokeBSL=%s)\n" % invokeBSL)
+ if invokeBSL:
+ #sys.stderr.write("in Z1 bsl reset...\n")
+ time.sleep(0.1)
+ self.writepicROM(0xFF, 0xFF)
+ time.sleep(0.1)
+ #sys.stderr.write("z1 bsl reset done...\n")
+ else:
+ #sys.stderr.write("in Z1 reset...\n")
+ time.sleep(0.1)
+ self.writepicROM(0xFF, 0xFE)
+ time.sleep(0.1)
+ #sys.stderr.write("z1 reset done...\n")
def telosBReset(self,invokeBSL=0):
# "BSL entry sequence at dedicated JTAG pins"
if self.telosI2C:
self.telosBReset(invokeBSL)
return
+
+ if self.z1:
+ if DEBUG > 1: sys.stderr.write("* entering bsl with z1\n")
+ self.bslResetZ1(invokeBSL)
+ return
+
if DEBUG > 1: sys.stderr.write("* bslReset(invokeBSL=%s)\n" % invokeBSL)
self.SetRSTpin(1) #power suply
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
sys.stderr.write("ELF section %s at 0x%04x %d bytes\n" % (section.name, section.lma, len(section.data)))
if len(section.data):
self.segments.append( Segment(section.lma, section.data) )
+
+ def loadString(self, startAddr=0, string=None):
+ """fill memory with the contents of a binary chunk of data."""
+ self.segments.append(Segment(startAddr, string));
def loadFile(self, filename):
"""fill memory with the contents of a file. file type is determined from extension"""
self.data = None
self.maxData = self.MAXDATA
self.cpu = None
+ self.info = None
+ def fetchinfo(self):
+ data=self.uploadData(0x1000,256);
+ return data;
+
+ def dumpinfo(self):
+ data = self.fetchinfo();
+ hex="@1000\n";
+ for c in data:
+ hex+=("%02x "%ord(c));
+ hex+="\nq\n";
+ print hex;
+ return data;
+
+ def saveinfo(self):
+ sys.stderr.write('Checking for info flash...')
+ sys.stderr.flush()
+ data = self.fetchinfo();
+ good_data = False;
+ for c in data:
+ if ord(c) is not 255:
+ good_data=True;
+ break;
+ if good_data:
+ sys.stderr.write(' Saved!\n')
+ sys.stderr.flush()
+ self.info = Memory();
+ self.info.loadString(0x1000,data);
+ else:
+ sys.stderr.write(' None.\n')
+ sys.stderr.write('Look at contrib/infos/README.txt for better performance.\n')
+ sys.stderr.flush()
def preparePatch(self):
"""prepare to download patch"""
sys.stderr.flush()
else:
raise BSLException, "programming without data not possible"
+
+ def prepareFromweb(self):
+ """Grab GoodFET firmware from the web."""
+ url="%s%s.hex" % (FIRMWARE_BASEURL, self.board);
+ print "Grabbing %s firmware from %s" % (self.board, url);
+ fn="/tmp/.%s.hex" % self.board
+ try:
+ subprocess.call(['curl', '-sS', url, '-o', fn])
+ except OSError:
+ print "Failed to run curl, trying wget"
+ try:
+ subprocess.call(['wget', '-nv', url, '-O', fn])
+ except OSError:
+ print "Failed to fetch firmware. Maybe you need to install curl or wget?"
+ sys.exit()
+
def actionFromweb(self):
- """Grab GoodFET firmware from the web, then flash it."""
- print "Grabbing %x firmware." % self.dev_id;
- print "%s" % firmware[self.dev_id];
- fn="/tmp/.goodfet.hex"
- os.system("curl %s >%s" % (firmware[self.dev_id],fn))
-
+ """Flash the GoodFET firmware which has been downloaded in an earlier step."""
+ fn="/tmp/.%s.hex" % self.board
fw=Memory(fn);
- #fw.loadIhex(open(fn,"rb"));
sys.stderr.write("Program ...\n")
sys.stderr.flush()
self.programData(fw, self.ACTION_PROGRAM | self.ACTION_VERIFY)
sys.stderr.write("%i bytes programmed.\n" % self.byteCtr)
sys.stderr.flush()
-
+
def actionVerify(self):
"""Verify programmed data"""
if self.data is not None:
-P, --password=file Specify a file with the interrupt vectors that
are used as password. This can be any file that
has previously been used to program the device.
- (e.g. -P INT_VECT.TXT).
+ (e.g. -P INT_VECT.TXT or -P goodfet.hex).
-f, --framesize=num Max. number of data bytes within one transmitted
frame (16 to 240 in steps of 16) (e.g. -f 240).
-m, --erasecycles=num Number of mass erase cycles (default is 1). Some
--swap-reset-test, and --telos-latch
--telosb Implies options --swap-reset-test, --telos-i2c,
--no-BSL-download, and --speed=38400
+ --apimote Implies --swap-reset-test
--goodfet10
--goodfet20
--goodfet30
+ --goodthopter Same as GF30.
--tmote Identical operation to --telosb
+ --z1 Bootstrap a Z1
--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)
--slow Add delays when operating the conrol pins. Useful if
the pins/circuit has high capacitance.
+ --dumpinfo Print the info flash timing data so you can save a copy
+ for later. You must provide -P if flash is not empty.
Program Flow Specifiers:
-e, --masserase Mass Erase (clear all flash memory)
#Main:
def main(itest=1):
global DEBUG
+ global board
import getopt
filetype = None
filename = None
wait = 0 #wait at the end
goaddr = None
bsl = BootStrapLoader()
- toinit = []
+ deviceinit = []
todo = []
startaddr = None
size = 2
bsl.invertRST = 1
bsl.invertTEST = itest
-
- if comPort is None and os.environ.get("GOODFET")!=None:
- glob_list = glob.glob(os.environ.get("GOODFET"));
- if len(glob_list) > 0:
- comPort = glob_list[0];
- if comPort is None:
- glob_list = glob.glob("/dev/tty.usbserial*");
- if len(glob_list) > 0:
- comPort = glob_list[0];
- if comPort is None:
- glob_list = glob.glob("/dev/ttyUSB*");
- if len(glob_list) > 0:
- comPort = glob_list[0];
- if os.name=='nt':
- from scanwin32 import winScan;
- scan=winScan();
- for order,comport,desc,hwid in sorted(scan.comports()):
- if hwid.index('FTDI')==0:
- comPort=comport;
- #print "Using FTDI port %s" % port
-
-
- sys.stderr.write("MSP430 Bootstrap Loader Version: %s\n" % VERSION)
-
+
try:
opts, args = getopt.getopt(sys.argv[1:],
"hc:P:wf:m:eEpvrg:UDudsxbITNB:S:V14",
"swap-reset-test", "telos-latch", "telos-i2c", "telos", "telosb",
"tmote","no-BSL-download", "force-BSL-download", "slow",
"dumpivt", "dumpinfo", "fromweb",
- "goodfet30", "goodfet20", "goodfet10"
+ "goodfet40", "goodfet30", "goodthopter", "goodfet20", "goodfet10",
+ "z1",
+ "nhbadge", "nhbadgeb", "goodfet"
]
)
except getopt.GetoptError:
sys.stderr.write( "Number of mass erase cycles set to %i.\n" % meraseCycles)
bsl.meraseCycles = meraseCycles
elif o in ("-e", "--masserase"):
- toinit.append(bsl.actionMassErase) #Erase Flash
+ deviceinit.append(bsl.actionMassErase) #Erase Flash
elif o in ("-E", "--erasecheck"):
- toinit.append(bsl.actionEraseCheck) #Erase Check (by file)
+ deviceinit.append(bsl.actionEraseCheck) #Erase Check (by file)
elif o in ("-p", "--program"):
todo.append(bsl.actionProgram) #Program file
elif o in ("--fromweb"):
- toinit.append(bsl.actionMassErase) #Erase Flash
+ deviceinit.append(bsl.prepareFromweb) #Download firmware
+ deviceinit.append(bsl.actionMassErase) #Erase Flash
todo.append(bsl.actionFromweb) #Program GoodFET code
elif o in ("-v", "--verify"):
todo.append(bsl.actionVerify) #Verify file
elif o in ("--goodfet20", ):
bsl.invertRST = 1
bsl.invertTEST = 1
- elif o in ("--goodfet30", ):
+ elif o in ("--goodfet30", "--goodfet31", "--goodfet32", "--goodthopter" ):
bsl.invertRST = 1
bsl.invertTEST = 0
+ elif o in ("--goodfet40", ):
+ bsl.invertRST = 1
+ bsl.invertTEST = 1
+ elif o in ("--goodfet", ):
+ bsl.invertRST = 1
+ bsl.invertTEST = 1
+ elif o in ("--apimote",):
+ bsl.swapRSTTEST = 1;
+ elif o in ("--nhbadge", "--nhbadgeb" ):
+ bsl.invertRST = 1
+ bsl.invertTEST = 1
elif o in ("--telosb", ):
bsl.swapRSTTEST = 1
bsl.telosI2C = 1
bsl.telosI2C = 1
mayuseBSL = 0
speed = 38400
+ elif o in ("--z1", ):
+ bsl.z1 = 1
+ speed = 38400
elif o in ("--no-BSL-download", ):
mayuseBSL = 0
elif o in ("--force-BSL-download", ):
sys.stderr.write("Warning: option --reset ignored as --upload is specified!\n")
reset = 0
+
+ if os.environ.get("board")==None:
+ if board==None:
+ print "Board not specified. Defaulting to goodfet41.";
+ raw_input("Press Ctrl+C to cancel, or Enter to continue.");
+ board='goodfet41';
+ bsl.board=board;
+ else:
+ bsl.board=None;
+ try:
+ bsl.board=BOARDS[os.environ.get("board").lower()];
+ except:
+ pass;
+ if bsl.board==None:
+ print "Unknown board specified. Try goodfet41, facedancer11, or similar.";
+ sys.exit(2);
+
+ if bsl.board=='telosb':
+ bsl.swapRSTTEST = 1
+ bsl.telosI2C = 1
+ mayuseBSL = 0
+ if bsl.board=='z1':
+ bsl.z1 = 1
+ if bsl.board=='apimote':
+ bsl.swapRSTTEST = 1;
+
+
+ if comPort is None and os.environ.get("GOODFET")!=None:
+ glob_list = glob.glob(os.environ.get("GOODFET"));
+ if len(glob_list) > 0:
+ comPort = glob_list[0];
+ if comPort is None:
+ glob_list = glob.glob("/dev/tty.usbserial*");
+ if len(glob_list) > 0:
+ comPort = glob_list[0];
+ if comPort is None:
+ glob_list = glob.glob("/dev/ttyUSB*");
+ if len(glob_list) > 0:
+ comPort = glob_list[0];
+ if os.name=='nt':
+ from scanwin32 import winScan;
+ scan=winScan();
+ for order,comport,desc,hwid in sorted(scan.comports()):
+ try:
+ if hwid.index('FTDI')==0:
+ comPort=comport;
+ #print "Using FTDI port %s" % port
+ except:
+ #Do nothing.
+ a=1;
+ sys.stderr.write("MSP430 Bootstrap Loader Version: %s\n" % VERSION)
+
sys.stderr.flush()
#prepare data to download
bsl.comInit(comPort) #init port
+ if bsl.actionMassErase in deviceinit:
+ bsl.actionStartBSL()
+ bsl.saveinfo()
+
#initialization list
- if toinit: #erase and erase check
+ if deviceinit: #erase and erase check
if DEBUG: sys.stderr.write("Preparing device ...\n")
#bsl.actionStartBSL(usepatch=0, adjsp=0) #no workarounds needed
#if speed: bsl.actionChangeBaudrate(speed) #change baud rate as fast as possible
- for f in toinit: f()
+ for f in deviceinit: f()
if todo or goaddr or startaddr:
if DEBUG: sys.stderr.write("Actions ...\n")
sys.stderr.write(" %r\n" % f)
for f in todo: f() #work through todo list
+ if bsl.info is not None:
+ sys.stderr.write('Programming info flash...\n')
+ sys.stderr.flush()
+ bsl.programData(bsl.info, bsl.ACTION_PROGRAM)
+
if reset: #reset device first if desired
bsl.actionReset()
if dumpivt:
hex+=("%02x "%ord(c));
print hex;
if dumpinfo:
- bsl.txPasswd(); #default pass
- data=bsl.uploadData(0x1000,256);
- hex="@1000\n";
- for c in data:
- hex+=("%02x "%ord(c));
- hex+="\nq\n";
- print hex;
+ # I don't know what bslreset is all about, but if it is enabled and
+ # the wrong password is provided, the chip gets erased.
+ reset = True
+ if not bsl.passwd:
+ reset = False
+ bsl.actionStartBSL(bslreset=reset)
+ bsl.dumpinfo()
if goaddr is not None: #start user programm at specified address
bsl.actionRun(goaddr) #load PC and execute