2 # GoodFET Chipcon RF Radio Client
4 # (C) 2009, 2012 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 & (~0x0800)); #MDMCTRL0, promiscuous
24 self.poke(0x12, 0x0500); #MDMCTRL1
25 self.poke(0x1C, 0x007F); #IOCFG0
26 self.poke(0x19, 0x01C4); #SECCTRL0, disabling crypto
27 #self.poke(0x19, 0x0204); #SECCTRL0, as seen elsewhere.
31 return self.peek(0x1E); #MANFIDL
33 manfidl=self.peek(0x1E);
34 #manfidh=self.peek(0x1f);
36 return "%s" % (self.CCversions[manfidl]);
38 return "Unknown0x%04x" % manfidl;
39 def trans8(self,byte):
40 """Read and write 8 bits by CCSPI."""
41 data=self.CCSPItrans([byte]);
45 """Exchange data by CCSPI."""
47 self.writecmd(self.CCSPIAPP,0x00,len(data),data);
49 def strobe(self,reg=0x00):
50 """Strobes a strobe register, returning the status."""
53 return ord(self.data[0]);
54 def CC_RFST_IDLE(self):
55 """Switch the radio to idle mode, clearing overflows and errors."""
56 self.strobe(0x06); #SRXOFF
58 """Switch the radio to TX mode."""
59 self.strobe(0x04); #0x05 for CCA
61 """Switch the radio to RX mode."""
62 self.strobe(0x03); #RX ON
63 def CC_RFST_CAL(self):
64 """Calibrate strobe the radio."""
65 self.strobe(0x02); #RX Calibrate
66 def CC_RFST(self,state=0x00):
69 def peek(self,reg,bytes=2):
70 """Read a CCSPI Register. For long regs, result is flipped."""
72 #Reg is ORed with 0x40 by the GoodFET.
75 #Automatically calibrate the len.
78 self.writecmd(self.CCSPIAPP,0x02,len(data),data);
81 (ord(self.data[1])<<8)
84 def poke(self,reg,val,bytes=2):
85 """Write a CCSPI Register."""
86 data=[reg,(val>>8)&0xFF,val&0xFF];
87 self.writecmd(self.CCSPIAPP,0x03,len(data),data);
88 if self.peek(reg,bytes)!=val and reg!=0x18:
89 print "Warning, failed to set r%02x=0x%04x, got %02x." %(
92 self.peek(reg,bytes));
97 """Read the status byte."""
98 statusbits={0x80: "?",
99 0x40: "XOSC16M_STABLE",
100 0x20: "TX_UNDERFLOW",
106 status=self.strobe(0x00);
111 str="%s %s" % (statusbits[i],str);
115 #Radio stuff begins here.
116 def RF_setenc(self,code="802.15.4"):
117 """Set the encoding type."""
120 """Get the encoding type."""
122 def RF_getrate(self):
124 def RF_setrate(self,rate=0):
126 def RF_getsync(self):
127 return self.peek(0x14);
128 def RF_setsync(self,sync=0xa70F):
129 """Set the SYNC preamble.
130 Use 0xA70F for 0xA7."""
131 self.poke(0x14,sync);
134 def RF_setfreq(self,frequency):
135 """Set the frequency in Hz."""
136 mhz=frequency/1000000;
138 fsctrl=self.peek(0x18)&(~0x3FF);
139 fsctrl=fsctrl+int(mhz-2048)
140 self.poke(0x18,fsctrl);
141 #self.CC_RFST_IDLE();
142 self.strobe(0x02);#SCAL
144 self.strobe(0x03);#SRXON
145 def RF_getfreq(self):
146 """Get the frequency in Hz."""
147 fsctrl=self.peek(0x18);
148 mhz=2048+(fsctrl&0x3ff)
150 def RF_setchan(self,channel):
151 """Set the ZigBee/802.15.4 channel number."""
152 if channel < 11 or channel > 26:
153 print "Only 802.15.4 channels 11 to 26 are currently supported.";
155 self.RF_setfreq( ( (channel-11)*5 + 2405 ) * 1000000 );
156 def RF_getsmac(self):
157 """Return the source MAC address."""
159 def RF_setsmac(self,mac):
160 """Set the source MAC address."""
162 def RF_gettmac(self):
163 """Return the target MAC address."""
165 def RF_settmac(self,mac):
166 """Set the target MAC address."""
168 def RF_getrssi(self):
169 """Returns the received signal strength, with a weird offset."""
170 rssival=self.peek(0x13)&0xFF; #raw RSSI register
172 lastpacket=range(0,0xff);
173 def RF_rxpacket(self):
174 """Get a packet from the radio. Returns None if none is waiting. In
175 order to not require the SFD, FIFO, or FIFOP lines, this
176 implementation works by comparing the buffer to the older
182 self.writecmd(self.CCSPIAPP,0x80,len(data),data);
185 self.lastpacket=buffer;
188 #self.strobe(0x08); #SFLUSHRX
191 def RF_txpacket(self,packet):
192 """Send a packet through the radio."""
193 self.writecmd(self.CCSPIAPP,0x81,len(packet),packet);
198 def RF_reflexjam(self,duration=0):
199 """Place the device into reflexive jamming mode."""
200 data = [duration&0xff,
202 self.writecmd(self.CCSPIAPP,0xA0,len(data),data);
205 def RF_reflexjam_autoack(self):
206 """Place the device into reflexive jamming mode
207 and that also sends a forged ACK if needed."""
209 self.writecmd(self.CCSPIAPP,0xA1,len(data),data);
210 print "Got:", data, "and", self.data
213 def RF_modulated_spectrum(self):
214 """Hold a carrier wave on the present frequency."""
215 # print "Don't know how to hold a carrier.";
219 # set MDMCTRL1.TX_MODE to 3 0x12 3:2
222 mdmctrl1=self.peek(0x12);
223 #print "mdmctrl1 was %04x" % mdmctrl1;
224 mdmctrl1=mdmctrl1|0x00c0; #MDMCTRL1.TX_MODE = 3
225 self.poke(0x12, mdmctrl1); #MDMCTRL1
227 mdmctrl1=self.peek(0x12);
228 #print "mdmctrl1 is %04x" % mdmctrl1;
230 # http://e2e.ti.com/support/low_power_rf/f/155/t/15914.aspx?PageIndex=2
232 self.strobe(0x02); #STXCAL
233 #print "STXCAL status: %s" % self.status()
236 self.strobe(0x09); #SFLUSHTX
237 #print "SFLUSHTX status: %s" % self.status()
239 self.strobe(0x04); #STXON
240 #print "STXON status: %s" % self.status()
242 def RF_carrier(self):
243 """Hold a carrier wave on the present frequency."""
244 # print "Don't know how to hold a carrier.";
248 # set MDMCTRL1.TX_MODE to 2 or 3 0x12 3:2
249 # set DACTST to 0x1800 0x2E
252 mdmctrl1=self.peek(0x12);
253 #print "mdmctrl1 was %04x" % mdmctrl1;
254 mdmctrl1=mdmctrl1|0x0080;
255 mdmctrl1=mdmctrl1&0x0080; #MDMCTRL1.TX_MODE = 2
256 self.poke(0x12, mdmctrl1); #MDMCTRL1
258 mdmctrl1=self.peek(0x12);
259 #print "mdmctrl1 is %04x" % mdmctrl1;
261 self.poke(0x2E, 0x1800); #DACTST
262 dactst=self.peek(0x2E);
263 #print "dactst is %04x" % dactst;
265 # see above for why this is here
266 self.strobe(0x02); #STXCAL
267 #print "STXCAL status: %s" % self.status()
268 self.strobe(0x09); #SFLUSHTX
269 #print "SFLUSHTX status: %s" % self.status()
271 self.strobe(0x04); #STXON
272 #print "STXON status: %s" % self.status()
274 def RF_promiscuity(self,promiscuous=1):
275 mdmctrl0=self.peek(0x11);
277 mdmctrl0=mdmctrl0&(~0x800);
279 mdmctrl0=mdmctrl0|0x800;
280 self.poke(0x11,mdmctrl0);
282 def RF_autocrc(self,autocrc=1):
283 mdmctrl0=self.peek(0x11);
285 mdmctrl0=mdmctrl0&(~0x0020);
287 mdmctrl0=mdmctrl0|0x0020;
288 self.poke(0x11,mdmctrl0);
290 def RF_autoack(self,autoack=1):
291 mdmctrl0=self.peek(0x11);
293 mdmctrl0=mdmctrl0&(~0x0010);
295 mdmctrl0=mdmctrl0|0x0010;
296 self.poke(0x11,mdmctrl0);
299 def RF_setpacketlen(self,len=16):
300 """Set the number of bytes in the expected payload."""
301 #self.poke(0x11,len);
303 def RF_getpacketlen(self):
304 """Set the number of bytes in the expected payload."""
305 #len=self.peek(0x11);
309 def RF_getmaclen(self):
310 """Get the number of bytes in the MAC address."""
311 choices=[0, 3, 4, 5];
312 choice=self.peek(0x03)&3;
313 self.maclen=choices[choice];
315 def RF_setmaclen(self,len):
316 """Set the number of bytes in the MAC address."""
317 choices=["illegal", "illegal", "illegal",
320 self.poke(0x03,choice);
322 def printpacket(self,packet,prefix="#"):
326 s="%s %02x" % (s,ord(foo));
327 print "%s%s" % (prefix,s);
329 def printdissect(self,packet):
331 from scapy.all import Dot15d4
333 print "To use packet disection, Scapy must be installed and have the Dot15d4 extension present."
334 print "try: hg clone http://hg.secdev.org/scapy-com";
335 print " sudo ./setup.py install";
336 self.printpacket(packet);
338 scapyd = Dot15d4(packet[1:]);