rmspeers on GoodFETCCSPI fixing RF_autocrc and adding support to act like a TinyOS...
[goodfet] / client / GoodFETCCSPI.py
index 2dfaa7e..3e17532 100644 (file)
@@ -19,10 +19,12 @@ class GoodFETCCSPI(GoodFET):
         
         #Set up the radio for ZigBee
         self.strobe(0x01);       #SXOSCON
+        self.strobe(0x02);       #SCAL
         self.poke(0x11, 0x0AC2); #MDMCTRL0
         self.poke(0x12, 0x0500); #MDMCTRL1
         self.poke(0x1C, 0x007F); #IOCFG0
         self.poke(0x19, 0x01C4); #SECCTRL0, disabling crypto
+        self.RF_setsync();
         
     def ident(self):
         return self.peek(0x1E); #MANFIDL
@@ -50,7 +52,7 @@ class GoodFETCCSPI(GoodFET):
         return ord(self.data[0]);
     def CC_RFST_IDLE(self):
         """Switch the radio to idle mode, clearing overflows and errors."""
-        self.strobe(0x00); #SNOP?
+        self.strobe(0x06); #SRXOFF
     def CC_RFST_TX(self):
         """Switch the radio to TX mode."""
         self.strobe(0x04);  #0x05 for CCA
@@ -91,8 +93,22 @@ class GoodFETCCSPI(GoodFET):
     
     def status(self):
         """Read the status byte."""
+        statusbits={0x80: "?",
+                    0x40: "XOSC16M_STABLE",
+                    0x20: "TX_UNDERFLOW",
+                    0x10: "ENC_BUSY",
+                    0x08: "TX_ACTIVE",
+                    0x04: "LOCK",
+                    0x02: "RSSI_VALID",
+                    0x01: "?"};
         status=self.strobe(0x00);
-        print "Status=%02x" % status;
+        i=1;
+        str="";
+        while i<0x100:
+            if status&i:
+               str="%s %s" % (statusbits[i],str);
+            i*=2;
+        return str;
     
     #Radio stuff begins here.
     def RF_setenc(self,code="802.15.4"):
@@ -105,17 +121,31 @@ class GoodFETCCSPI(GoodFET):
         return 0;
     def RF_setrate(self,rate=0):
         return 0;
+    def RF_getsync(self):
+        return self.peek(0x14);
+    def RF_setsync(self,sync=0xa70F):
+        """Set the SYNC preamble.
+        Use 0xA70F for 0xA7."""
+        self.poke(0x14,sync);
+        return;
+    
     def RF_setfreq(self,frequency):
         """Set the frequency in Hz."""
         mhz=frequency/1000000;
-        fsctrl=self.peek(0x18)&~0x3FF;
+        fsctrl=0x8000; #self.peek(0x18)&(~0x3FF);
         fsctrl=fsctrl+int(mhz-2048)
         self.poke(0x18,fsctrl);
+        self.strobe(0x02);
     def RF_getfreq(self):
         """Get the frequency in Hz."""
         fsctrl=self.peek(0x18);
         mhz=2048+(fsctrl&0x3ff)
         return mhz*1000000;
+    def RF_setchan(self,channel):
+        if channel < 11 or channel > 26:
+            print "Only 802.15.4 channels 11 to 26 are currently supported.";
+        else:
+            self.RF_setfreq( ( (channel-11)*5 + 2405 ) * 1000000 );
     def RF_getsmac(self):
         """Return the source MAC address."""
         return 0xdeadbeef;
@@ -130,15 +160,110 @@ class GoodFETCCSPI(GoodFET):
         return 0xdeadbeef;
     def RF_getrssi(self):
         """Returns the received signal strenght, with a weird offset."""
-        rssival=self.peek(0x13)&0xFF; #raw RSSI register, should normalize this
+        rssival=self.peek(0x13)&0xFF; #raw RSSI register
         return rssival^0x80;
+    lastpacket=range(0,0xff);
     def RF_rxpacket(self):
-        """Get a packet from the radio.  Returns None if none is waiting."""
-        print "Don't know how to get a packet.";
-        return None;
+        """Get a packet from the radio.  Returns None if none is waiting.  In
+        order to not require the SFD, FIFO, or FIFOP lines, this
+        implementation works by comparing the buffer to the older
+        contents.
+        """
+        
+        data="\0";
+        self.data=data;
+        self.writecmd(self.CCSPIAPP,0x80,len(data),data);
+        buffer=self.data;
+        
+        self.lastpacket=buffer;
+        if(len(buffer)==0):
+            return None;
+        return buffer;
+    def RF_txpacket(self,packet):
+        """Send a packet through the radio."""
+        self.writecmd(self.CCSPIAPP,0x81,len(packet),packet);
+        #time.sleep(1);
+        #self.strobe(0x09);
+        return;
+    
+
+    def RF_modulated_spectrum(self):
+        """Hold a carrier wave on the present frequency."""
+        # print "Don't know how to hold a carrier.";
+        # 33.1 p.55:
+        #  reset chip
+        #  SXOSCON
+        #  set MDMCTRL1.TX_MODE to 3   0x12  3:2 
+        #  STXON                            0x04
+
+        mdmctrl1=self.peek(0x12);
+        #print "mdmctrl1 was %04x" % mdmctrl1;
+        mdmctrl1=mdmctrl1|0x00c0;  #MDMCTRL1.TX_MODE = 3
+        self.poke(0x12, mdmctrl1); #MDMCTRL1
+
+        mdmctrl1=self.peek(0x12);
+        #print "mdmctrl1 is %04x" % mdmctrl1;
+
+        # http://e2e.ti.com/support/low_power_rf/f/155/t/15914.aspx?PageIndex=2
+        #   suggests this
+        self.strobe(0x02);         #STXCAL
+        #print "STXCAL status: %s" % self.status()
+
+        # is this necessary?
+        self.strobe(0x09);         #SFLUSHTX
+        #print "SFLUSHTX status: %s" % self.status()
+
+        self.strobe(0x04);         #STXON
+        #print "STXON status: %s" % self.status()
+
     def RF_carrier(self):
         """Hold a carrier wave on the present frequency."""
-        print "Don't know how to hold a carrier.";
+        # print "Don't know how to hold a carrier.";
+        # 33.1 p.54:
+        #  reset chip
+        #  SXOSCON
+        #  set MDMCTRL1.TX_MODE to 2 or 3   0x12  3:2 
+        #  set DACTST to 0x1800             0x2E
+        #  STXON                            0x04
+
+        mdmctrl1=self.peek(0x12);
+        #print "mdmctrl1 was %04x" % mdmctrl1;
+        mdmctrl1=mdmctrl1|0x0080; 
+        mdmctrl1=mdmctrl1&0x0080;  #MDMCTRL1.TX_MODE = 2
+        self.poke(0x12, mdmctrl1); #MDMCTRL1
+
+        mdmctrl1=self.peek(0x12);
+        #print "mdmctrl1 is %04x" % mdmctrl1;
+
+        self.poke(0x2E, 0x1800);   #DACTST
+        dactst=self.peek(0x2E);
+        #print "dactst is %04x" % dactst;
+
+        # see above for why this is here
+        self.strobe(0x02);         #STXCAL
+        #print "STXCAL status: %s" % self.status()
+        self.strobe(0x09);         #SFLUSHTX
+        #print "SFLUSHTX status: %s" % self.status()
+
+        self.strobe(0x04);         #STXON
+        #print "STXON status: %s" % self.status()
+
+    def RF_promiscuity(self,promiscuous=1):
+        mdmctrl0=self.peek(0x11);
+        if promiscuous>0:
+            mdmctrl0=mdmctrl0&(~0x800);
+        else:
+            mdmctrl0=mdmctrl0|0x800;
+        self.poke(0x11,mdmctrl0);
+        return;
+    def RF_autocrc(self,autocrc=1):
+        mdmctrl0=self.peek(0x11);
+        if autocrc==0:
+            mdmctrl0=mdmctrl0&(~0x0020);
+        else:
+            mdmctrl0=mdmctrl0|0x0020;
+        self.poke(0x11,mdmctrl0);
+        return;
     packetlen=16;
     def RF_setpacketlen(self,len=16):
         """Set the number of bytes in the expected payload."""
@@ -163,3 +288,22 @@ class GoodFETCCSPI(GoodFET):
         choice=choices[len];
         self.poke(0x03,choice);
         self.maclen=len;
+    def printpacket(self,packet):
+        s="";
+        i=0;
+        for foo in packet:
+            s="%s %02x" % (s,ord(foo));
+        print "#%s" % s;
+    def printdissect(self,packet):
+        try:
+            from scapy.all import Dot15d4
+        except ImportError:
+            print "To use packet disection, Scapy must be installed and have the Dot15d4 extension present."
+            print "try: hg clone http://hg.secdev.org/scapy-com";
+            print "     sudo ./setup.py install";
+        self.printpacket(packet);
+        try:
+            scapyd = Dot15d4(packet[1:]);
+            scapyd.show();
+        except:
+            pass;