X-Git-Url: http://git.rot13.org/?p=goodfet;a=blobdiff_plain;f=client%2Fgoodfet.bsl;h=5923bd6184e74b4e39dc900a01856d9050cfedad;hp=974df03970753dbabaed84e8a1397caa15b0b1f1;hb=cf8e51297dbdac9c89a68ecf7ee57e422030930f;hpb=cd93d96fd4bcc66ffaeed376702e3e3d414409e7 diff --git a/client/goodfet.bsl b/client/goodfet.bsl index 974df03..5923bd6 100755 --- a/client/goodfet.bsl +++ b/client/goodfet.bsl @@ -13,9 +13,25 @@ # Forked by Travis Goodspeed 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] @@ -204,10 +220,27 @@ deviceids = { } #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): @@ -258,9 +291,11 @@ class LowLevel: 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 @@ -312,8 +347,10 @@ 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 + + if not self.z1: + self.SetRSTpin() #enable power + self.SetTESTpin() #enable power self.serialport.flushInput() self.serialport.flushOutput() @@ -523,6 +560,83 @@ class LowLevel: 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" @@ -564,6 +678,12 @@ class LowLevel: 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 @@ -574,8 +694,8 @@ class LowLevel: 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 @@ -773,6 +893,10 @@ class Memory: 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""" @@ -841,7 +965,39 @@ class BootStrapLoader(LowLevel): 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""" @@ -1136,22 +1292,33 @@ class BootStrapLoader(LowLevel): 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: @@ -1242,7 +1409,7 @@ General options: -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 @@ -1283,15 +1450,20 @@ General options: --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) @@ -1361,6 +1533,7 @@ def hexify(line, bytes, width=16): #Main: def main(itest=1): global DEBUG + global board import getopt filetype = None filename = None @@ -1371,7 +1544,7 @@ def main(itest=1): wait = 0 #wait at the end goaddr = None bsl = BootStrapLoader() - toinit = [] + deviceinit = [] todo = [] startaddr = None size = 2 @@ -1385,39 +1558,7 @@ def main(itest=1): bsl.invertRST = 1 bsl.invertTEST = itest - - if(os.environ.get("board")=='telosb' or - os.environ.get("board")=='telosbbt' or - os.environ.get("platform")=='telosb'): - bsl.swapRSTTEST = 1 - bsl.telosI2C = 1 - mayuseBSL = 0 - - 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) - + try: opts, args = getopt.getopt(sys.argv[1:], "hc:P:wf:m:eEpvrg:UDudsxbITNB:S:V14", @@ -1430,7 +1571,8 @@ def main(itest=1): "swap-reset-test", "telos-latch", "telos-i2c", "telos", "telosb", "tmote","no-BSL-download", "force-BSL-download", "slow", "dumpivt", "dumpinfo", "fromweb", - "goodfet40", "goodfet30", "goodfet20", "goodfet10", + "goodfet40", "goodfet30", "goodthopter", "goodfet20", "goodfet10", + "z1", "nhbadge", "nhbadgeb", "goodfet" ] ) @@ -1486,13 +1628,14 @@ def main(itest=1): 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 @@ -1578,7 +1721,7 @@ def main(itest=1): 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", ): @@ -1587,6 +1730,8 @@ def main(itest=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 @@ -1600,6 +1745,9 @@ def main(itest=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", ): @@ -1642,6 +1790,58 @@ def main(itest=1): 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 @@ -1669,12 +1869,16 @@ def main(itest=1): 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") @@ -1699,6 +1903,11 @@ def main(itest=1): 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: @@ -1709,13 +1918,13 @@ def main(itest=1): 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