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));
96 """Read the status byte."""
97 statusbits={0x80: "?",
98 0x40: "XOSC16M_STABLE",
105 status=self.strobe(0x00);
110 str="%s %s" % (statusbits[i],str);
114 #Radio stuff begins here.
115 def RF_setenc(self,code="802.15.4"):
116 """Set the encoding type."""
119 """Get the encoding type."""
121 def RF_getrate(self):
123 def RF_setrate(self,rate=0):
125 def RF_getsync(self):
126 return self.peek(0x14);
127 def RF_setsync(self,sync=0xa70F):
128 """Set the SYNC preamble.
129 Use 0xA70F for 0xA7."""
130 self.poke(0x14,sync);
133 def RF_setfreq(self,frequency):
134 """Set the frequency in Hz."""
135 mhz=frequency/1000000;
136 fsctrl=0x8000; #self.peek(0x18)&(~0x3FF);
137 fsctrl=fsctrl+int(mhz-2048)
138 self.poke(0x18,fsctrl);
139 self.strobe(0x02);#SCAL
140 self.strobe(0x03);#SRXON
141 def RF_getfreq(self):
142 """Get the frequency in Hz."""
143 fsctrl=self.peek(0x18);
144 mhz=2048+(fsctrl&0x3ff)
146 def RF_setchan(self,channel):
147 """Set the ZigBee/802.15.4 channel number."""
148 if channel < 11 or channel > 26:
149 print "Only 802.15.4 channels 11 to 26 are currently supported.";
151 self.RF_setfreq( ( (channel-11)*5 + 2405 ) * 1000000 );
152 def RF_getsmac(self):
153 """Return the source MAC address."""
155 def RF_setsmac(self,mac):
156 """Set the source MAC address."""
158 def RF_gettmac(self):
159 """Return the target MAC address."""
161 def RF_settmac(self,mac):
162 """Set the target MAC address."""
164 def RF_getrssi(self):
165 """Returns the received signal strenght, with a weird offset."""
166 rssival=self.peek(0x13)&0xFF; #raw RSSI register
168 lastpacket=range(0,0xff);
169 def RF_rxpacket(self):
170 """Get a packet from the radio. Returns None if none is waiting. In
171 order to not require the SFD, FIFO, or FIFOP lines, this
172 implementation works by comparing the buffer to the older
178 self.writecmd(self.CCSPIAPP,0x80,len(data),data);
181 self.lastpacket=buffer;
185 def RF_txpacket(self,packet):
186 """Send a packet through the radio."""
187 self.writecmd(self.CCSPIAPP,0x81,len(packet),packet);
192 def RF_reflexjam(self,duration=0):
193 """Place the device into reflexive jamming mode."""
194 data = [duration&0xff,
196 self.writecmd(self.CCSPIAPP,0xA0,len(data),data);
199 def RF_reflexjam_autoack(self):
200 """Place the device into reflexive jamming mode
201 and that also sends a forged ACK if needed."""
203 self.writecmd(self.CCSPIAPP,0xA1,len(data),data);
204 print "Got:", data, "and", self.data
207 def RF_modulated_spectrum(self):
208 """Hold a carrier wave on the present frequency."""
209 # print "Don't know how to hold a carrier.";
213 # set MDMCTRL1.TX_MODE to 3 0x12 3:2
216 mdmctrl1=self.peek(0x12);
217 #print "mdmctrl1 was %04x" % mdmctrl1;
218 mdmctrl1=mdmctrl1|0x00c0; #MDMCTRL1.TX_MODE = 3
219 self.poke(0x12, mdmctrl1); #MDMCTRL1
221 mdmctrl1=self.peek(0x12);
222 #print "mdmctrl1 is %04x" % mdmctrl1;
224 # http://e2e.ti.com/support/low_power_rf/f/155/t/15914.aspx?PageIndex=2
226 self.strobe(0x02); #STXCAL
227 #print "STXCAL status: %s" % self.status()
230 self.strobe(0x09); #SFLUSHTX
231 #print "SFLUSHTX status: %s" % self.status()
233 self.strobe(0x04); #STXON
234 #print "STXON status: %s" % self.status()
236 def RF_carrier(self):
237 """Hold a carrier wave on the present frequency."""
238 # print "Don't know how to hold a carrier.";
242 # set MDMCTRL1.TX_MODE to 2 or 3 0x12 3:2
243 # set DACTST to 0x1800 0x2E
246 mdmctrl1=self.peek(0x12);
247 #print "mdmctrl1 was %04x" % mdmctrl1;
248 mdmctrl1=mdmctrl1|0x0080;
249 mdmctrl1=mdmctrl1&0x0080; #MDMCTRL1.TX_MODE = 2
250 self.poke(0x12, mdmctrl1); #MDMCTRL1
252 mdmctrl1=self.peek(0x12);
253 #print "mdmctrl1 is %04x" % mdmctrl1;
255 self.poke(0x2E, 0x1800); #DACTST
256 dactst=self.peek(0x2E);
257 #print "dactst is %04x" % dactst;
259 # see above for why this is here
260 self.strobe(0x02); #STXCAL
261 #print "STXCAL status: %s" % self.status()
262 self.strobe(0x09); #SFLUSHTX
263 #print "SFLUSHTX status: %s" % self.status()
265 self.strobe(0x04); #STXON
266 #print "STXON status: %s" % self.status()
268 def RF_promiscuity(self,promiscuous=1):
269 mdmctrl0=self.peek(0x11);
271 mdmctrl0=mdmctrl0&(~0x800);
273 mdmctrl0=mdmctrl0|0x800;
274 self.poke(0x11,mdmctrl0);
276 def RF_autocrc(self,autocrc=1):
277 mdmctrl0=self.peek(0x11);
279 mdmctrl0=mdmctrl0&(~0x0020);
281 mdmctrl0=mdmctrl0|0x0020;
282 self.poke(0x11,mdmctrl0);
284 def RF_autoack(self,autoack=1):
285 mdmctrl0=self.peek(0x11);
287 mdmctrl0=mdmctrl0&(~0x0010);
289 mdmctrl0=mdmctrl0|0x0010;
290 self.poke(0x11,mdmctrl0);
293 def RF_setpacketlen(self,len=16):
294 """Set the number of bytes in the expected payload."""
295 #self.poke(0x11,len);
297 def RF_getpacketlen(self):
298 """Set the number of bytes in the expected payload."""
299 #len=self.peek(0x11);
303 def RF_getmaclen(self):
304 """Get the number of bytes in the MAC address."""
305 choices=[0, 3, 4, 5];
306 choice=self.peek(0x03)&3;
307 self.maclen=choices[choice];
309 def RF_setmaclen(self,len):
310 """Set the number of bytes in the MAC address."""
311 choices=["illegal", "illegal", "illegal",
314 self.poke(0x03,choice);
316 def printpacket(self,packet):
320 s="%s %02x" % (s,ord(foo));
323 def printdissect(self,packet):
325 from scapy.all import Dot15d4
327 print "To use packet disection, Scapy must be installed and have the Dot15d4 extension present."
328 print "try: hg clone http://hg.secdev.org/scapy-com";
329 print " sudo ./setup.py install";
330 self.printpacket(packet);
332 scapyd = Dot15d4(packet[1:]);