2 # GoodFET Chipcon RF Radio Client
4 # (C) 2009 Travis Goodspeed <travis at radiantmachines.com>
6 # This code is being rewritten and refactored. You've been warned!
8 import sys, time, string, cStringIO, struct, glob, os;
10 from GoodFET import GoodFET;
12 class GoodFETCCSPI(GoodFET):
14 CCversions={0x233d: "CC2420",
17 """Move the FET into the CCSPI application."""
18 self.writecmd(self.CCSPIAPP,0x10,0,self.data); #CCSPI/SETUP
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
30 return self.peek(0x1E); #MANFIDL
32 manfidl=self.peek(0x1E);
33 #manfidh=self.peek(0x1f);
35 return "%s" % (self.CCversions[manfidl]);
37 return "Unknown0x%04x" % manfidl;
38 def trans8(self,byte):
39 """Read and write 8 bits by CCSPI."""
40 data=self.CCSPItrans([byte]);
44 """Exchange data by CCSPI."""
46 self.writecmd(self.CCSPIAPP,0x00,len(data),data);
48 def strobe(self,reg=0x00):
49 """Strobes a strobe register, returning the status."""
52 return ord(self.data[0]);
53 def CC_RFST_IDLE(self):
54 """Switch the radio to idle mode, clearing overflows and errors."""
55 self.strobe(0x06); #SRXOFF
57 """Switch the radio to TX mode."""
58 self.strobe(0x04); #0x05 for CCA
60 """Switch the radio to RX mode."""
62 def CC_RFST_CAL(self):
63 """Calibrate strobe the radio."""
65 def CC_RFST(self,state=0x00):
68 def peek(self,reg,bytes=2):
69 """Read a CCSPI Register. For long regs, result is flipped."""
71 #Reg is ORed with 0x40 by the GoodFET.
74 #Automatically calibrate the len.
77 self.writecmd(self.CCSPIAPP,0x02,len(data),data);
80 (ord(self.data[1])<<8)
83 def poke(self,reg,val,bytes=2):
84 """Write a CCSPI Register."""
85 data=[reg,(val>>8)&0xFF,val&0xFF];
86 self.writecmd(self.CCSPIAPP,0x03,len(data),data);
87 if self.peek(reg,bytes)!=val and reg!=0x18:
88 print "Warning, failed to set r%02x=0x%04x, got %02x." %(
91 self.peek(reg,bytes));
95 """Read the status byte."""
96 statusbits={0x80: "?",
97 0x40: "XOSC16M_STABLE",
104 status=self.strobe(0x00);
109 str="%s %s" % (statusbits[i],str);
113 #Radio stuff begins here.
114 def RF_setenc(self,code="802.15.4"):
115 """Set the encoding type."""
118 """Get the encoding type."""
120 def RF_getrate(self):
122 def RF_setrate(self,rate=0):
124 def RF_getsync(self):
125 return self.peek(0x14);
126 def RF_setsync(self,sync=0xa70F):
127 """Set the SYNC preamble.
128 Use 0xA70F for 0xA7."""
129 self.poke(0x14,sync);
132 def RF_setfreq(self,frequency):
133 """Set the frequency in Hz."""
134 mhz=frequency/1000000;
135 fsctrl=0x8000; #self.peek(0x18)&(~0x3FF);
136 fsctrl=fsctrl+int(mhz-2048)
137 self.poke(0x18,fsctrl);
138 self.strobe(0x02);#SCAL
139 self.strobe(0x03);#SRXON
140 def RF_getfreq(self):
141 """Get the frequency in Hz."""
142 fsctrl=self.peek(0x18);
143 mhz=2048+(fsctrl&0x3ff)
145 def RF_setchan(self,channel):
146 """Set the ZigBee/802.15.4 channel number."""
147 if channel < 11 or channel > 26:
148 print "Only 802.15.4 channels 11 to 26 are currently supported.";
150 self.RF_setfreq( ( (channel-11)*5 + 2405 ) * 1000000 );
151 def RF_getsmac(self):
152 """Return the source MAC address."""
154 def RF_setsmac(self,mac):
155 """Set the source MAC address."""
157 def RF_gettmac(self):
158 """Return the target MAC address."""
160 def RF_settmac(self,mac):
161 """Set the target MAC address."""
163 def RF_getrssi(self):
164 """Returns the received signal strenght, with a weird offset."""
165 rssival=self.peek(0x13)&0xFF; #raw RSSI register
167 lastpacket=range(0,0xff);
168 def RF_rxpacket(self):
169 """Get a packet from the radio. Returns None if none is waiting. In
170 order to not require the SFD, FIFO, or FIFOP lines, this
171 implementation works by comparing the buffer to the older
177 self.writecmd(self.CCSPIAPP,0x80,len(data),data);
180 self.lastpacket=buffer;
184 def RF_txpacket(self,packet):
185 """Send a packet through the radio."""
186 self.writecmd(self.CCSPIAPP,0x81,len(packet),packet);
191 def RF_reflexjam(self,duration=0):
192 """Place the device into reflexive jamming mode."""
193 data = [duration&0xff,
195 self.writecmd(self.CCSPIAPP,0xA0,len(data),data);
198 def RF_reflexjam_autoack(self):
199 """Place the device into reflexive jamming mode
200 and that also sends a forged ACK if needed."""
202 self.writecmd(self.CCSPIAPP,0xA1,len(data),data);
206 def RF_modulated_spectrum(self):
207 """Hold a carrier wave on the present frequency."""
208 # print "Don't know how to hold a carrier.";
212 # set MDMCTRL1.TX_MODE to 3 0x12 3:2
215 mdmctrl1=self.peek(0x12);
216 #print "mdmctrl1 was %04x" % mdmctrl1;
217 mdmctrl1=mdmctrl1|0x00c0; #MDMCTRL1.TX_MODE = 3
218 self.poke(0x12, mdmctrl1); #MDMCTRL1
220 mdmctrl1=self.peek(0x12);
221 #print "mdmctrl1 is %04x" % mdmctrl1;
223 # http://e2e.ti.com/support/low_power_rf/f/155/t/15914.aspx?PageIndex=2
225 self.strobe(0x02); #STXCAL
226 #print "STXCAL status: %s" % self.status()
229 self.strobe(0x09); #SFLUSHTX
230 #print "SFLUSHTX status: %s" % self.status()
232 self.strobe(0x04); #STXON
233 #print "STXON status: %s" % self.status()
235 def RF_carrier(self):
236 """Hold a carrier wave on the present frequency."""
237 # print "Don't know how to hold a carrier.";
241 # set MDMCTRL1.TX_MODE to 2 or 3 0x12 3:2
242 # set DACTST to 0x1800 0x2E
245 mdmctrl1=self.peek(0x12);
246 #print "mdmctrl1 was %04x" % mdmctrl1;
247 mdmctrl1=mdmctrl1|0x0080;
248 mdmctrl1=mdmctrl1&0x0080; #MDMCTRL1.TX_MODE = 2
249 self.poke(0x12, mdmctrl1); #MDMCTRL1
251 mdmctrl1=self.peek(0x12);
252 #print "mdmctrl1 is %04x" % mdmctrl1;
254 self.poke(0x2E, 0x1800); #DACTST
255 dactst=self.peek(0x2E);
256 #print "dactst is %04x" % dactst;
258 # see above for why this is here
259 self.strobe(0x02); #STXCAL
260 #print "STXCAL status: %s" % self.status()
261 self.strobe(0x09); #SFLUSHTX
262 #print "SFLUSHTX status: %s" % self.status()
264 self.strobe(0x04); #STXON
265 #print "STXON status: %s" % self.status()
267 def RF_promiscuity(self,promiscuous=1):
268 mdmctrl0=self.peek(0x11);
270 mdmctrl0=mdmctrl0&(~0x800);
272 mdmctrl0=mdmctrl0|0x800;
273 self.poke(0x11,mdmctrl0);
275 def RF_autocrc(self,autocrc=1):
276 mdmctrl0=self.peek(0x11);
278 mdmctrl0=mdmctrl0&(~0x0020);
280 mdmctrl0=mdmctrl0|0x0020;
281 self.poke(0x11,mdmctrl0);
283 def RF_autoack(self,autoack=1):
284 mdmctrl0=self.peek(0x11);
286 mdmctrl0=mdmctrl0&(~0x0010);
288 mdmctrl0=mdmctrl0|0x0010;
289 self.poke(0x11,mdmctrl0);
292 def RF_setpacketlen(self,len=16):
293 """Set the number of bytes in the expected payload."""
294 #self.poke(0x11,len);
296 def RF_getpacketlen(self):
297 """Set the number of bytes in the expected payload."""
298 #len=self.peek(0x11);
302 def RF_getmaclen(self):
303 """Get the number of bytes in the MAC address."""
304 choices=[0, 3, 4, 5];
305 choice=self.peek(0x03)&3;
306 self.maclen=choices[choice];
308 def RF_setmaclen(self,len):
309 """Set the number of bytes in the MAC address."""
310 choices=["illegal", "illegal", "illegal",
313 self.poke(0x03,choice);
315 def printpacket(self,packet):
319 s="%s %02x" % (s,ord(foo));
322 def printdissect(self,packet):
324 from scapy.all import Dot15d4
326 print "To use packet disection, Scapy must be installed and have the Dot15d4 extension present."
327 print "try: hg clone http://hg.secdev.org/scapy-com";
328 print " sudo ./setup.py install";
329 self.printpacket(packet);
331 scapyd = Dot15d4(packet[1:]);