81e54346189478ec6facf1876e0e7a157ee0d4a9
[goodfet] / client / GoodFETCCSPI.py
1 #!/usr/bin/env python
2 # GoodFET Chipcon RF Radio Client
3
4 # (C) 2009 Travis Goodspeed <travis at radiantmachines.com>
5 #
6 # This code is being rewritten and refactored.  You've been warned!
7
8 import sys, time, string, cStringIO, struct, glob, serial, os;
9
10 from GoodFET import GoodFET;
11
12 class GoodFETCCSPI(GoodFET):
13     CCSPIAPP=0x51;
14     CCversions={0x233d: "CC2420",
15                 }
16     def setup(self):
17         """Move the FET into the CCSPI application."""
18         self.writecmd(self.CCSPIAPP,0x10,0,self.data); #CCSPI/SETUP
19         
20         #Set up the radio for ZigBee
21         self.strobe(0x01);       #SXOSCON
22         self.strobe(0x02);       #SCAL
23         self.poke(0x11, 0x0AC2); #MDMCTRL0
24         self.poke(0x12, 0x0500); #MDMCTRL1
25         self.poke(0x1C, 0x007F); #IOCFG0
26         self.poke(0x19, 0x01C4); #SECCTRL0, disabling crypto
27         
28     def ident(self):
29         return self.peek(0x1E); #MANFIDL
30     def identstr(self):
31         manfidl=self.peek(0x1E);
32         #manfidh=self.peek(0x1f);
33         try:
34             return "%s" % (self.CCversions[manfidl]); 
35         except:
36             return "Unknown0x%04x" % manfidl;
37     def trans8(self,byte):
38         """Read and write 8 bits by CCSPI."""
39         data=self.CCSPItrans([byte]);
40         return ord(data[0]);
41     
42     def trans(self,data):
43         """Exchange data by CCSPI."""
44         self.data=data;
45         self.writecmd(self.CCSPIAPP,0x00,len(data),data);
46         return self.data;
47     def strobe(self,reg=0x00):
48         """Strobes a strobe register, returning the status."""
49         data=[reg];
50         self.trans(data);
51         return ord(self.data[0]);
52     def CC_RFST_IDLE(self):
53         """Switch the radio to idle mode, clearing overflows and errors."""
54         self.strobe(0x06); #SRXOFF
55     def CC_RFST_TX(self):
56         """Switch the radio to TX mode."""
57         self.strobe(0x04);  #0x05 for CCA
58     def CC_RFST_RX(self):
59         """Switch the radio to RX mode."""
60         self.strobe(0x03);
61     def CC_RFST_CAL(self):
62         """Calibrate strobe the radio."""
63         self.strobe(0x02);
64     def CC_RFST(self,state=0x00):
65         self.strobe(state);
66         return;
67     def peek(self,reg,bytes=2):
68         """Read a CCSPI Register.  For long regs, result is flipped."""
69         
70         #Reg is ORed with 0x40 by the GoodFET.
71         data=[reg,0,0];
72         
73         #Automatically calibrate the len.
74         bytes=2;
75         
76         self.writecmd(self.CCSPIAPP,0x02,len(data),data);
77         toret=(
78             ord(self.data[2])+
79             (ord(self.data[1])<<8)
80             );
81         return toret;
82     def poke(self,reg,val,bytes=2):
83         """Write a CCSPI Register."""
84         data=[reg,(val>>8)&0xFF,val&0xFF];
85         self.writecmd(self.CCSPIAPP,0x03,len(data),data);
86         if self.peek(reg,bytes)!=val:
87             print "Warning, failed to set r%02x=0x%04x, got %02x." %(
88                 reg,
89                 val,
90                 self.peek(reg,bytes));
91         return;
92     
93     def status(self):
94         """Read the status byte."""
95         statusbits={0x80: "?",
96                     0x40: "XOSC16M_STABLE",
97                     0x20: "TX_UNDERFLOW",
98                     0x10: "ENC_BUSY",
99                     0x08: "TX_ACTIVE",
100                     0x04: "LOCK",
101                     0x02: "RSSI_VALID",
102                     0x01: "?"};
103         status=self.strobe(0x00);
104         i=1;
105         str="";
106         while i<0x100:
107             if status&i:
108                str="%s %s" % (statusbits[i],str);
109             i*=2;
110         return str;
111     
112     #Radio stuff begins here.
113     def RF_setenc(self,code="802.15.4"):
114         """Set the encoding type."""
115         return;
116     def RF_getenc(self):
117         """Get the encoding type."""
118         return "802.15.4";
119     def RF_getrate(self):
120         return 0;
121     def RF_setrate(self,rate=0):
122         return 0;
123     def RF_setfreq(self,frequency):
124         """Set the frequency in Hz."""
125         mhz=frequency/1000000;
126         fsctrl=self.peek(0x18)&~0x3FF;
127         fsctrl=fsctrl+int(mhz-2048)
128         self.poke(0x18,fsctrl);
129         self.strobe(0x02);
130     def RF_getfreq(self):
131         """Get the frequency in Hz."""
132         fsctrl=self.peek(0x18);
133         mhz=2048+(fsctrl&0x3ff)
134         return mhz*1000000;
135     def RF_getsmac(self):
136         """Return the source MAC address."""
137         return 0xdeadbeef;
138     def RF_setsmac(self,mac):
139         """Set the source MAC address."""
140         return 0xdeadbeef;
141     def RF_gettmac(self):
142         """Return the target MAC address."""
143         return 0xdeadbeef;
144     def RF_settmac(self,mac):
145         """Set the target MAC address."""
146         return 0xdeadbeef;
147     def RF_getrssi(self):
148         """Returns the received signal strenght, with a weird offset."""
149         rssival=self.peek(0x13)&0xFF; #raw RSSI register
150         return rssival^0x80;
151     lastpacket=range(0,0xff);
152     def RF_rxpacket(self):
153         """Get a packet from the radio.  Returns None if none is waiting.  In
154         order to not require the SFD, FIFO, or FIFOP lines, this
155         implementation works by comparing the buffer to the older
156         contents.
157         """
158         
159         data="\0";
160         self.data=data;
161         self.writecmd(self.CCSPIAPP,0x80,len(data),data);
162         buffer=self.data;
163         
164         self.lastpacket=buffer;
165         if(len(buffer)==0):
166             return None;
167         return buffer;
168     def RF_txpacket(self,packet):
169         """Send a packet through the radio."""
170         self.writecmd(self.CCSPIAPP,0x81,len(packet),packet);
171         time.sleep(1);
172         self.strobe(0x09);
173         return;
174     
175     def RF_carrier(self):
176         """Hold a carrier wave on the present frequency."""
177         print "Don't know how to hold a carrier.";
178     def RF_promiscuity(self,promiscuous=1):
179         mdmctrl0=self.peek(0x11);
180         #print "mdmctrl0 was %04x" % mdmctrl0;
181         mdmctrl0=mdmctrl0&(~0x800);
182         #print "mdmctrl0 is now %04x" % mdmctrl0;
183         self.poke(0x11,mdmctrl0);
184         return;
185         
186     packetlen=16;
187     def RF_setpacketlen(self,len=16):
188         """Set the number of bytes in the expected payload."""
189         #self.poke(0x11,len);
190         self.packetlen=len;
191     def RF_getpacketlen(self):
192         """Set the number of bytes in the expected payload."""
193         #len=self.peek(0x11);
194         self.packetlen=len;
195         return len;
196     maclen=5;
197     def RF_getmaclen(self):
198         """Get the number of bytes in the MAC address."""
199         choices=[0, 3, 4, 5];
200         choice=self.peek(0x03)&3;
201         self.maclen=choices[choice];
202         return self.maclen;
203     def RF_setmaclen(self,len):
204         """Set the number of bytes in the MAC address."""
205         choices=["illegal", "illegal", "illegal", 
206                  1, 2, 3];
207         choice=choices[len];
208         self.poke(0x03,choice);
209         self.maclen=len;