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_setkey(self,key):
135 """Sets the first key for encryption to the given argument."""
136 print "ERROR: Forgot to set the key.";
139 def RF_setnonce(self,key):
140 """Sets the first key for encryption to the given argument."""
141 print "ERROR: Forgot to set the nonce.";
145 def RF_setfreq(self,frequency):
146 """Set the frequency in Hz."""
147 mhz=frequency/1000000;
149 fsctrl=self.peek(0x18)&(~0x3FF);
150 fsctrl=fsctrl+int(mhz-2048)
151 self.poke(0x18,fsctrl);
152 #self.CC_RFST_IDLE();
153 self.strobe(0x02);#SCAL
155 self.strobe(0x03);#SRXON
156 def RF_getfreq(self):
157 """Get the frequency in Hz."""
158 fsctrl=self.peek(0x18);
159 mhz=2048+(fsctrl&0x3ff)
161 def RF_setchan(self,channel):
162 """Set the ZigBee/802.15.4 channel number."""
163 if channel < 11 or channel > 26:
164 print "Only 802.15.4 channels 11 to 26 are currently supported.";
166 self.RF_setfreq( ( (channel-11)*5 + 2405 ) * 1000000 );
167 def RF_getsmac(self):
168 """Return the source MAC address."""
170 def RF_setsmac(self,mac):
171 """Set the source MAC address."""
173 def RF_gettmac(self):
174 """Return the target MAC address."""
176 def RF_settmac(self,mac):
177 """Set the target MAC address."""
179 def RF_getrssi(self):
180 """Returns the received signal strength, with a weird offset."""
181 rssival=self.peek(0x13)&0xFF; #raw RSSI register
184 def peekram(self,adr,count):
185 """Peeks data from CC2420 RAM."""
187 adr&0xFF,adr>>8, # Address first.
188 count&0xFF,count>>8 # Then length.
190 self.writecmd(self.CCSPIAPP,0x84,len(data),data);
192 def pokeram(self,adr,data):
193 """Pokes data into CC2420 RAM."""
194 data=[adr&0xFF, adr>>8]+data;
195 self.writecmd(self.CCSPIAPP,0x85,len(data),data);
198 lastpacket=range(0,0xff);
199 def RF_rxpacket(self):
200 """Get a packet from the radio. Returns None if none is
205 self.writecmd(self.CCSPIAPP,0x80,len(data),data);
208 self.lastpacket=buffer;
213 def RF_rxpacketrepeat(self):
214 """Gets packets from the radio, ignoring all future requests so as
215 not to waste time. Call RF_rxpacket() after this."""
217 self.writecmd(self.CCSPIAPP,0x91,0,None);
220 def RF_rxpacketdec(self):
221 """Get and decrypt a packet from the radio. Returns None if
226 self.writecmd(self.CCSPIAPP,0x90,len(data),data);
229 self.lastpacket=buffer;
235 def RF_txpacket(self,packet):
236 """Send a packet through the radio."""
237 self.writecmd(self.CCSPIAPP,0x81,len(packet),packet);
242 def RF_reflexjam(self,duration=0):
243 """Place the device into reflexive jamming mode."""
244 data = [duration&0xff,
246 self.writecmd(self.CCSPIAPP,0xA0,len(data),data);
249 def RF_reflexjam_autoack(self):
250 """Place the device into reflexive jamming mode
251 and that also sends a forged ACK if needed."""
253 self.writecmd(self.CCSPIAPP,0xA1,len(data),data);
254 print "Got:", data, "and", self.data
257 def RF_modulated_spectrum(self):
258 """Hold a carrier wave on the present frequency."""
259 # print "Don't know how to hold a carrier.";
263 # set MDMCTRL1.TX_MODE to 3 0x12 3:2
266 mdmctrl1=self.peek(0x12);
267 #print "mdmctrl1 was %04x" % mdmctrl1;
268 mdmctrl1=mdmctrl1|0x00c0; #MDMCTRL1.TX_MODE = 3
269 self.poke(0x12, mdmctrl1); #MDMCTRL1
271 mdmctrl1=self.peek(0x12);
272 #print "mdmctrl1 is %04x" % mdmctrl1;
274 # http://e2e.ti.com/support/low_power_rf/f/155/t/15914.aspx?PageIndex=2
276 self.strobe(0x02); #STXCAL
277 #print "STXCAL status: %s" % self.status()
280 self.strobe(0x09); #SFLUSHTX
281 #print "SFLUSHTX status: %s" % self.status()
283 self.strobe(0x04); #STXON
284 #print "STXON status: %s" % self.status()
286 def RF_carrier(self):
287 """Hold a carrier wave on the present frequency."""
288 # print "Don't know how to hold a carrier.";
292 # set MDMCTRL1.TX_MODE to 2 or 3 0x12 3:2
293 # set DACTST to 0x1800 0x2E
296 mdmctrl1=self.peek(0x12);
297 #print "mdmctrl1 was %04x" % mdmctrl1;
298 mdmctrl1=mdmctrl1|0x0080;
299 mdmctrl1=mdmctrl1&0x0080; #MDMCTRL1.TX_MODE = 2
300 self.poke(0x12, mdmctrl1); #MDMCTRL1
302 mdmctrl1=self.peek(0x12);
303 #print "mdmctrl1 is %04x" % mdmctrl1;
305 self.poke(0x2E, 0x1800); #DACTST
306 dactst=self.peek(0x2E);
307 #print "dactst is %04x" % dactst;
309 # see above for why this is here
310 self.strobe(0x02); #STXCAL
311 #print "STXCAL status: %s" % self.status()
312 self.strobe(0x09); #SFLUSHTX
313 #print "SFLUSHTX status: %s" % self.status()
315 self.strobe(0x04); #STXON
316 #print "STXON status: %s" % self.status()
318 def RF_promiscuity(self,promiscuous=1):
319 mdmctrl0=self.peek(0x11);
321 mdmctrl0=mdmctrl0&(~0x800);
323 mdmctrl0=mdmctrl0|0x800;
324 self.poke(0x11,mdmctrl0);
326 def RF_autocrc(self,autocrc=1):
327 mdmctrl0=self.peek(0x11);
329 mdmctrl0=mdmctrl0&(~0x0020);
331 mdmctrl0=mdmctrl0|0x0020;
332 self.poke(0x11,mdmctrl0);
334 def RF_autoack(self,autoack=1):
335 mdmctrl0=self.peek(0x11);
337 mdmctrl0=mdmctrl0&(~0x0010);
339 mdmctrl0=mdmctrl0|0x0010;
340 self.poke(0x11,mdmctrl0);
343 def RF_setpacketlen(self,len=16):
344 """Set the number of bytes in the expected payload."""
345 #self.poke(0x11,len);
347 def RF_getpacketlen(self):
348 """Set the number of bytes in the expected payload."""
349 #len=self.peek(0x11);
353 def RF_getmaclen(self):
354 """Get the number of bytes in the MAC address."""
355 choices=[0, 3, 4, 5];
356 choice=self.peek(0x03)&3;
357 self.maclen=choices[choice];
359 def RF_setmaclen(self,len):
360 """Set the number of bytes in the MAC address."""
361 choices=["illegal", "illegal", "illegal",
364 self.poke(0x03,choice);
366 def printpacket(self,packet,prefix="#"):
367 print self.packet2str(packet,prefix);
368 def packet2str(self,packet,prefix="#"):
372 s="%s %02x" % (s,ord(foo));
373 return "%s%s" % (prefix,s);
375 def printdissect(self,packet):
377 from scapy.all import Dot15d4
379 print "To use packet disection, Scapy must be installed and have the Dot15d4 extension present."
380 print "try: hg clone http://hg.secdev.org/scapy-com";
381 print " sudo ./setup.py install";
382 self.printpacket(packet);
384 scapyd = Dot15d4(packet[1:]);