TelosB support by platform variable.
[goodfet] / client / GoodFET.py
index a2f3160..10f2e6f 100755 (executable)
@@ -8,13 +8,16 @@
 import sys, time, string, cStringIO, struct, glob, serial, os;
 import sqlite3;
 
+fmt = ("B", "<H", None, "<L")
+
 def getClient(name="GoodFET"):
-    import GoodFET, GoodFETCC, GoodFETAVR, GoodFETSPI, GoodFETMSP430;
+    import GoodFET, GoodFETCC, GoodFETAVR, GoodFETSPI, GoodFETMSP430, GoodFETNRF;
     if(name=="GoodFET" or name=="monitor"): return GoodFET.GoodFET();
     elif name=="cc" or name=="chipcon": return GoodFETCC.GoodFETCC();
     elif name=="avr": return GoodFETAVR.GoodFETAVR();
     elif name=="spi": return GoodFETSPI.GoodFETSPI();
     elif name=="msp430": return GoodFETMSP430.GoodFETMSP430();
+    elif name=="nrf": return GoodFETNRF.GoodFETNRF();
     
     print "Unsupported target: %s" % name;
     sys.exit(0);
@@ -56,6 +59,7 @@ class GoodFET:
     verbose=False
     
     GLITCHAPP=0x71;
+    MONITORAPP=0x00;
     symbols=SymbolTable();
     
     def __init__(self, *args, **kargs):
@@ -67,13 +71,16 @@ class GoodFET:
         return self.symbols.get(name);
     def timeout(self):
         print "timeout\n";
-    def serInit(self, port=None, timeout=None):
+    def serInit(self, port=None, timeout=2):
         """Open the serial port"""
+        # Make timeout None to wait forever, 0 for non-blocking mode.
         
         if port is None and os.environ.get("GOODFET")!=None:
             glob_list = glob.glob(os.environ.get("GOODFET"));
             if len(glob_list) > 0:
                 port = glob_list[0];
+            else:
+                port = os.environ.get("GOODFET");
         if port is None:
             glob_list = glob.glob("/dev/tty.usbserial*");
             if len(glob_list) > 0:
@@ -82,6 +89,17 @@ class GoodFET:
             glob_list = glob.glob("/dev/ttyUSB*");
             if len(glob_list) > 0:
                 port = 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:
+                        port=comport;
+                        #print "Using FTDI port %s" % port
+                except:
+                    #Do nothing.
+                    a=1;
         
         self.serialport = serial.Serial(
             port,
@@ -91,21 +109,115 @@ class GoodFET:
             timeout=timeout
             )
         
-        #Explicitly set RTS and DTR to halt board.
-        self.serialport.setRTS(1);
-        self.serialport.setDTR(1);
-        #Drop DTR, which is !RST, low to begin the app.
-        self.serialport.setDTR(0);
-        self.serialport.flushInput()
-        self.serialport.flushOutput()
-        
-        #Read and handle the initial command.
-        #time.sleep(1);
-        self.readcmd(); #Read the first command.
-        if(self.verb!=0x7F):
-            print "Verb %02x is wrong.  Incorrect firmware or bad Info guess?" % self.verb;
-            print "http://goodfet.sf.net/faq/";
-        #print "Connected."
+        self.verb=0;
+        attempts=0;
+        connected=0;
+        while connected==0:
+            while self.verb!=0x7F or self.data!="http://goodfet.sf.net/":
+                #print "Resyncing.";
+                self.serialport.flushInput()
+                self.serialport.flushOutput()
+                #Explicitly set RTS and DTR to halt board.
+                self.serialport.setRTS(1);
+                self.serialport.setDTR(1);
+                #Drop DTR, which is !RST, low to begin the app.
+                self.serialport.setDTR(0);
+                
+                #TelosB reset, prefer software to I2C SPST Switch.
+                if(os.environ.get("platform")=='telosb'):
+                    self.telosBReset();
+                #self.serialport.write(chr(0x80));
+                #self.serialport.write(chr(0x80));
+                #self.serialport.write(chr(0x80));
+                #self.serialport.write(chr(0x80));
+                
+                
+                self.serialport.flushInput()
+                self.serialport.flushOutput()
+                #time.sleep(60);
+                attempts=attempts+1;
+                self.readcmd(); #Read the first command.
+            #Here we have a connection, but maybe not a good one.
+            connected=1;
+            olds=self.infostring();
+            clocking=self.monitorclocking();
+            for foo in range(1,30):
+                if not self.monitorecho():
+                    if self.verbose: print "Comm error on %i try, resyncing out of %s." % (foo,
+                                                  clocking);
+                    connected=0;
+                    break;
+        if self.verbose: print "Connected after %02i attempts." % attempts;
+        self.mon_connected();
+    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)
+
+        # This line was not defined inside the else: block, not sure where it
+        # should be however
+        self.telosI2CWriteCmd(0,0)
+        time.sleep(0.250)       #give MSP430's oscillator time to stabilize
+        self.serialport.flushInput()  #clear buffers
+
+
     def getbuffer(self,size=0x1c00):
         writecmd(0,0xC2,[size&0xFF,(size>>16)&0xFF]);
         print "Got %02x%02x buffer size." % (self.data[1],self.data[0]);
@@ -159,17 +271,25 @@ class GoodFET:
                     print "Rx: ( 0x%02x, 0x%02x, 0x%04x )" % ( self.app, self.verb, self.count )
             
                 #Debugging string; print, but wait.
-                if self.app==0xFF and self.verb==0xFF:
-                    print "# DEBUG %s" % self.serialport.read(self.count);
+                if self.app==0xFF:
+                    if self.verb==0xFF:
+                        print "# DEBUG %s" % self.serialport.read(self.count)
+                           elif self.verb==0xFE:
+                        print "# DEBUG 0x%x" % struct.unpack(fmt[self.count-1], self.serialport.read(self.count))[0]
+                    elif self.verb==0xFD:
+                        #Do nothing, just wait so there's no timeout.
+                        print "# NOP.";
+                        
                     sys.stdout.flush();
-                    return []
                 else:
                     self.data=self.serialport.read(self.count);
                     return self.data;
             except TypeError:
-                print "Error: waiting for serial read timed out (most likely)."
-                sys.exit(-1)
-
+                if self.connected:
+                    print "Error: waiting for serial read timed out (most likely).";
+                    print "This shouldn't happen after syncing.  Exiting for safety.";
+                    sys.exit(-1)
+                return self.data;
     #Glitching stuff.
     def glitchApp(self,app):
         """Glitch into a device by its application."""
@@ -214,7 +334,11 @@ class GoodFET:
         self.besilent=s;
         print "besilent is %i" % self.besilent;
         self.writecmd(0,0xB0,1,[s]);
-        
+    connected=0;
+    def mon_connected(self):
+        """Announce to the monitor that the connection is good."""
+        self.connected=1;
+        self.writecmd(0,0xB1,0,[]);
     def out(self,byte):
         """Write a byte to P5OUT."""
         self.writecmd(0,0xA1,1,[byte]);
@@ -238,6 +362,9 @@ class GoodFET:
     def peekword(self,address):
         """Read a word of memory from the monitor."""
         return self.peekbyte(address)+(self.peekbyte(address+1)<<8);
+    def peek(self,address):
+        """Read a word of memory from the monitor."""
+        return self.peekbyte(address)+(self.peekbyte(address+1)<<8);
     def pokebyte(self,address,value):
         """Set a byte of memory by the monitor."""
         self.data=[address&0xff,address>>8,value];
@@ -300,17 +427,32 @@ class GoodFET:
     def monitortest(self):
         """Self-test several functions through the monitor."""
         print "Performing monitor self-test.";
-        
-        if self.peekword(0x0c00)!=0x0c04 and self.peekword(0x0c00)!=0x0c06:
-            print "ERROR Fetched wrong value from 0x0c04.";
-        self.pokebyte(0x0021,0); #Drop LED
-        if self.peekbyte(0x0021)!=0:
-            print "ERROR, P1OUT not cleared.";
-        self.pokebyte(0x0021,1); #Light LED
-        
+        self.monitorclocking();
+        for f in range(0,3000):
+            a=self.peekword(0x0c00);
+            b=self.peekword(0x0c02);
+            if a!=0x0c04 and a!=0x0c06:
+                print "ERROR Fetched %04x, %04x" % (a,b);
+            self.pokebyte(0x0021,0); #Drop LED
+            if self.peekbyte(0x0021)!=0:
+                print "ERROR, P1OUT not cleared.";
+            self.pokebyte(0x0021,1); #Light LED
+            if not self.monitorecho():
+                print "Echo test failed.";
         print "Self-test complete.";
-    
-    
+        self.monitorclocking();
+    def monitorecho(self):
+        data="The quick brown fox jumped over the lazy dog.";
+        self.writecmd(self.MONITORAPP,0x81,len(data),data);
+        if self.data!=data:
+            if self.verbose: print "Comm error recognized by monitorecho().";
+            return 0;
+        return 1;
+    def monitorclocking(self):
+        DCOCTL=self.peekbyte(0x0056);
+        BCSCTL1=self.peekbyte(0x0057);
+        return "0x%02x, 0x%02x" % (DCOCTL, BCSCTL1);
+
     # The following functions ought to be implemented in
     # every client.
 
@@ -347,7 +489,6 @@ class GoodFET:
     def dump(self,file,start=0,stop=0xffff):
         """Dump an intel hex file from code memory."""
         print "Dump not implemented.";
-
     def peek32(self,address, memory="vn"):
         return (self.peek16(address,memory)+
                 (self.peek16(address+2,memory)<<16));
@@ -356,5 +497,8 @@ class GoodFET:
                 (self.peek8(address+1,memory)<<8));
     def peek8(self,address, memory="vn"):
         return self.peekbyte(address); #monitor
+    def peekword(self,address, memory="vn"):
+        return self.peek(address); #monitor
+    
     def loadsymbols(self):
         return;