Bug fixes and new features added to zigduino firmware and client.
[goodfet] / client / GoodFETatmel128.py
index 876725c..903603b 100644 (file)
@@ -1,4 +1,4 @@
-# GoodFET client to interface zigduino/atmel128 radio
+# GoodFETclient to interface zigduino/atmel128 radio
 # forked by bx from code by neighbor Travis Goodspeed
 from GoodFETAVR import GoodFETAVR
 import sys, binascii, os, array, time, glob, struct
@@ -7,96 +7,109 @@ fmt = ("B", "<H", None, "<L")
 
 class GoodFETatmel128rfa1(GoodFETAVR):
     ATMELRADIOAPP = 0x53
+    autocrc = 0
+    verbose = False
+    connected = 0
+    enable_AACK = False
+    def serInit(self, port=None, timeout=2, attemptlimit=None):
+        if port==None:
+            port=os.environ.get("GOODFET");
+        self.pyserInit(port, timeout, attemptlimit)
+
     def pyserInit(self, port, timeout, attemptlimit):
         """Open the serial port"""
-        # Make timeout None to wait forever, 0 for non-blocking mode.
-        import serial;
-
-        if os.name=='nt' and sys.version.find('64 bit')!=-1:
-            print "WARNING: PySerial requires a 32-bit Python build in Windows.";
-
-        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:
-                port = glob_list[0];
-        if port is None:
-            glob_list = glob.glob("/dev/ttyUSB*");
-            if len(glob_list) > 0:
-                port = glob_list[0];
-        if port is None:
-            glob_list = glob.glob("/dev/ttyU0");
-            if len(glob_list) > 0:
-                port = glob_list[0];
-        if port is None and 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;
-
-        baud=115200;
-        self.serialport = serial.Serial(
-            port,
-            baud,
-            parity = serial.PARITY_NONE,
-            timeout=timeout
-            )
-
-        self.verb=0;
-        self.data=""
-        attempts=0;
-        connected=0;
-
-        while connected==0:
-            while self.verb!=0x7F or self.data!="http://goodfet.sf.net/":
-                if attemptlimit is not None and attempts >= attemptlimit:
-                    return
-                elif attempts==2 and os.environ.get("board")!='telosb':
-                    print "See the GoodFET FAQ about missing info flash.";
-                    self.serialport.setTimeout(0.2);
-                    #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);
-
-                attempts=attempts+1;
-                self.readcmd(); #Read the first command.
-                if self.verbose:
-                    print "Got %02x,%02x:'%s'" % (self.app,self.verb,self.data);
-
-            #Here we have a connection, but maybe not a good one.
-            #print "We have a connection."
-            for foo in range(1,30):
-                time.sleep(1)
-                if not self.monitorecho():
-                    connected = 0
-                    if self.verbose:
-                        print "Comm error on try %i." % (foo)
+        if self.connected == 0:
+            if (not (attemptlimit == None)) and (attemptlimit <= 1):
+                # it always takes at least 2 tries
+                attemptlimit == 2
+
+            # Make timeout None to wait forever, 0 for non-blocking mode.
+            import serial;
+
+            if os.name=='nt' and sys.version.find('64 bit')!=-1:
+                print "WARNING: PySerial requires a 32-bit Python build in Windows.";
+
+            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:
-                    connected = 1
-                    break
-        if self.verbose:
-            print "Connected after %02i attempts." % attempts;
-        self.serialport.setTimeout(12);
+                    port = os.environ.get("GOODFET");
+            if port is None:
+                glob_list = glob.glob("/dev/tty.usbserial*");
+                if len(glob_list) > 0:
+                    port = glob_list[0];
+            if port is None:
+                glob_list = glob.glob("/dev/ttyUSB*");
+                if len(glob_list) > 0:
+                    port = glob_list[0];
+            if port is None:
+                glob_list = glob.glob("/dev/ttyU0");
+                if len(glob_list) > 0:
+                    port = glob_list[0];
+            if port is None and 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;
+
+            baud=115200;
+
+            self.serialport = serial.Serial(
+                port,
+                baud,
+                parity = serial.PARITY_NONE,
+                timeout=timeout
+                )
+
+            self.verb=0;
+            self.data=""
+            attempts=0;
+            self.connected=0;
+
+            while self.connected==0:
+                self.serialport.setDTR(False)
+                while self.verb!=0x7F or self.data!="http://goodfet.sf.net/":
+                    if attemptlimit is not None and attempts >= attemptlimit:
+                        return
+
+                    attempts=attempts+1;
+                    self.readcmd(); #Read the first command.
+                    if self.verbose:
+                        print "Got %02x,%02x:'%s'" % (self.app,self.verb,self.data);
+
+                #Here we have a connection, but maybe not a good one.
+                #print "We have a connection."
+                for foo in range(1,30):
+                    time.sleep(1)
+                    if not self.monitorecho():
+                        self.connected = 0
+                        if self.verbose:
+                            print "Comm error on try %i." % (foo)
+                    else:
+                        self.connected = 1
+                        break
+            if self.verbose:
+                print "Connected after %02i attempts." % attempts;
+            self.serialport.setTimeout(12);
+
+    def serClose(self):
+        self.connected = 0
+        self.serialport.close()
 
 
     def writecmd(self, app, verb, count=0, data=[]):
         """Write a command and some data to the GoodFET."""
         self.serialport.write(chr(app));
         self.serialport.write(chr(verb));
-
+        if self.verbose:
+            print "Tx: ( 0x%02x, 0x%02x, %d )" % ( app, verb, count )
         if count > 0:
             if(isinstance(data,list)):
                 old = data
@@ -107,29 +120,31 @@ class GoodFETatmel128rfa1(GoodFETAVR):
 
         #little endian 16-bit length
             count = len(outstr)
-            self.serialport.write(chr(count&0xFF));
-            self.serialport.write(chr(count>>8));
+        self.serialport.write(chr(count&0xFF));
+        self.serialport.write(chr(count>>8));
+        if count > 0:
             if self.verbose:
-                print "Tx: ( 0x%02x, 0x%02x, %d )" % ( app, verb, count )
                 print "sending: %s" %outstr.encode("hex")
-
             self.serialport.write(outstr);
-        else: # count == 0
-            self.serialport.write("\x00")
-            self.serialport.write("\x00")
+
 
         if not self.besilent:
             out = self.readcmd()
-            #if out:
-            #    print "read: " + out
+            if out and self.verbose:
+                print "read: " + out.encode("hex")
             return out
         else:
-            return []
+            return None
 
     def readcmd(self):
+
         """Read a reply from the GoodFET."""
         app = self.serialport.read(1)
+
         if len(app) < 1:
+            if self.verbose:
+                print "Rx: None"
+
             self.app = 0
             self.verb = 0
             self.count = 0
@@ -137,10 +152,19 @@ class GoodFETatmel128rfa1(GoodFETAVR):
             return
 
         self.app=ord(app);
-        self.verb=ord(self.serialport.read(1));
-
-        self.count= ord(self.serialport.read(1)) + (ord(self.serialport.read(1))<<8)
 
+        v = self.serialport.read(1);
+        if v:
+            self.verb = ord(v)
+        else:
+            self.verb = 0
+            
+        c1 = self.serialport.read(1)
+        c2 = self.serialport.read(1)
+        if (c1 and c2):
+            self.count= ord(c1) + (ord(c2)<<8)
+        else:
+            self.count = 0
         if self.verbose:
             print "Rx: ( 0x%02x, 0x%02x, %i )" % ( self.app, self.verb, self.count )
 
@@ -164,13 +188,14 @@ class GoodFETatmel128rfa1(GoodFETAVR):
         else:
             self.poke(0x8, chan)
 
-    def peek(self,reg,bytes=-1):
+    def peek(self,reg,bytes=1):
         """Read a Register. """
         #Automatically calibrate the len.
-        if bytes==-1:
-            bytes=1;
-            #if reg==0x0a or reg==0x0b or reg==0x10: bytes=5;
-        data = [reg, 0, bytes%255, bytes>>8] + ([0]*bytes)
+        if bytes != 1:
+            print "Warning, currently cannot poke more than 1 byte"
+            bytes = 1
+        data = [reg, 0, bytes%255, bytes>>8] #+ ([0]*bytes)
+        self.data = None
         self.writecmd(self.ATMELRADIOAPP,0x02,len(data),data);
         toret=0;
         #print self.data.encode("hex")
@@ -183,26 +208,28 @@ class GoodFETatmel128rfa1(GoodFETAVR):
         else:
             return -1
 
-    def poke(self,reg,val,bytes=-1):
+    def poke(self,reg,val,bytes=1): # todo, support >1 byte
         """Write an Register."""
+        data = [reg, 0] #+ ([0]*bytes)
         data=[reg, 0]
-
-        #Automatically calibrate the len.
-        if bytes==-1:
-            bytes=1;
-            #if reg==0x0a or reg==0x0b or reg==0x10: bytes=5;
+        if bytes != 1:
+            print "Warning, currently cannot poke more than 1 byte"
+            bytes = 1
         for i in range(0,bytes):
             data=data+[(val>>(8*i))&0xFF];
 
         self.writecmd(self.ATMELRADIOAPP,0x03,len(data),data);
-        if self.peek(reg,bytes)!=val:
+        newval = self.peek(reg,bytes)
+        if newval!=val:
             print "Warning, failed to set r%02x=%02x, got %02x." %(
                 reg,
                 val,
-                self.peek(reg,bytes));
+                newval);
 
         return;
 
+    def setup(self):
+        self.RF_setup()
 
     def RF_setup(self):
         self.writecmd(self.ATMELRADIOAPP, 0x10, 0, None)
@@ -218,5 +245,37 @@ class GoodFETatmel128rfa1(GoodFETAVR):
         else:
             return None
 
-    def RX_txpacket(self, payload):
-        self.writecmd(self.ATMELRADIOAPP, 0x81, len(payload)+1,chr(len(payload))+payload)
+    def RF_txpacket(self, payload):
+        if type(payload) == list: #convert to string
+            import array
+            payload = array.array('B', payload).tostring()
+        self.writecmd(self.ATMELRADIOAPP, 0x81, len(payload), payload)
+
+
+    def RF_getrssi(self):
+        """Returns the received signal strength"""
+        base = -90
+        val = self.peek(0x7) & 0x7f # read rssi bits
+        if val == 0:
+            return base - 1
+        elif val < 0x53:
+            return val + base
+        else:
+            return 0x53 + base
+
+    def RF_enable_AACK(self, enable = True):
+        if (enable and (not self.enable_AACK)):
+            self.enable_AACK = True
+            self.writecmd(self.ATMELRADIOAPP, 0x84)
+        elif ((not enable) and self.enable_AACK):
+            self.enable_AACK = False
+            self.writecmd(self.ATMELRADIOAPP, 0x85)
+
+
+    def RF_autocrc(self, autocrc=1):
+        self.autocrc = autocrc
+        if autocrc:
+            self.writecmd(self.ATMELRADIOAPP, 0x86)
+        else:
+            self.writecmd(self.ATMELRADIOAPP, 0x87)
+