Fixed printing of None in CCSPI dissection w/ scapy.
[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
176     def RF_modulated_spectrum(self):
177         """Hold a carrier wave on the present frequency."""
178         # print "Don't know how to hold a carrier.";
179         # 33.1 p.55:
180         #  reset chip
181         #  SXOSCON
182         #  set MDMCTRL1.TX_MODE to 3   0x12  3:2 
183         #  STXON                            0x04
184
185         mdmctrl1=self.peek(0x12);
186         #print "mdmctrl1 was %04x" % mdmctrl1;
187         mdmctrl1=mdmctrl1|0x00c0;  #MDMCTRL1.TX_MODE = 3
188         self.poke(0x12, mdmctrl1); #MDMCTRL1
189
190         mdmctrl1=self.peek(0x12);
191         #print "mdmctrl1 is %04x" % mdmctrl1;
192
193         # http://e2e.ti.com/support/low_power_rf/f/155/t/15914.aspx?PageIndex=2
194         #   suggests this
195         self.strobe(0x02);         #STXCAL
196         #print "STXCAL status: %s" % self.status()
197
198         # is this necessary?
199         self.strobe(0x09);         #SFLUSHTX
200         #print "SFLUSHTX status: %s" % self.status()
201
202         self.strobe(0x04);         #STXON
203         #print "STXON status: %s" % self.status()
204
205     def RF_carrier(self):
206         """Hold a carrier wave on the present frequency."""
207         # print "Don't know how to hold a carrier.";
208         # 33.1 p.54:
209         #  reset chip
210         #  SXOSCON
211         #  set MDMCTRL1.TX_MODE to 2 or 3   0x12  3:2 
212         #  set DACTST to 0x1800             0x2E
213         #  STXON                            0x04
214
215         mdmctrl1=self.peek(0x12);
216         #print "mdmctrl1 was %04x" % mdmctrl1;
217         mdmctrl1=mdmctrl1|0x0080; 
218         mdmctrl1=mdmctrl1&0x0080;  #MDMCTRL1.TX_MODE = 2
219         self.poke(0x12, mdmctrl1); #MDMCTRL1
220
221         mdmctrl1=self.peek(0x12);
222         #print "mdmctrl1 is %04x" % mdmctrl1;
223
224         self.poke(0x2E, 0x1800);   #DACTST
225         dactst=self.peek(0x2E);
226         #print "dactst is %04x" % dactst;
227
228         # see above for why this is here
229         self.strobe(0x02);         #STXCAL
230         #print "STXCAL status: %s" % self.status()
231         self.strobe(0x09);         #SFLUSHTX
232         #print "SFLUSHTX status: %s" % self.status()
233
234         self.strobe(0x04);         #STXON
235         #print "STXON status: %s" % self.status()
236
237     def RF_promiscuity(self,promiscuous=1):
238         mdmctrl0=self.peek(0x11);
239         #print "mdmctrl0 was %04x" % mdmctrl0;
240         mdmctrl0=mdmctrl0&(~0x800);
241         #print "mdmctrl0 is now %04x" % mdmctrl0;
242         self.poke(0x11,mdmctrl0);
243         return;
244         
245     packetlen=16;
246     def RF_setpacketlen(self,len=16):
247         """Set the number of bytes in the expected payload."""
248         #self.poke(0x11,len);
249         self.packetlen=len;
250     def RF_getpacketlen(self):
251         """Set the number of bytes in the expected payload."""
252         #len=self.peek(0x11);
253         self.packetlen=len;
254         return len;
255     maclen=5;
256     def RF_getmaclen(self):
257         """Get the number of bytes in the MAC address."""
258         choices=[0, 3, 4, 5];
259         choice=self.peek(0x03)&3;
260         self.maclen=choices[choice];
261         return self.maclen;
262     def RF_setmaclen(self,len):
263         """Set the number of bytes in the MAC address."""
264         choices=["illegal", "illegal", "illegal", 
265                  1, 2, 3];
266         choice=choices[len];
267         self.poke(0x03,choice);
268         self.maclen=len;
269     def printpacket(self,packet):
270         s="";
271         i=0;
272         for foo in packet:
273             s="%s %02x" % (s,ord(foo));
274         print "#%s" % s;
275     def printdissect(self,packet):
276         try:
277             from scapy.all import Dot15d4
278         except ImportError:
279             print "To use packet disection, Scapy must be installed and have the Dot15d4 extension present."
280         self.printpacket(packet);
281         try:
282             scapyd = Dot15d4(packet[1:]);
283             scapyd.show();
284         except:
285             pass;