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, serial, 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);
139 def RF_getfreq(self):
140 """Get the frequency in Hz."""
141 fsctrl=self.peek(0x18);
142 mhz=2048+(fsctrl&0x3ff)
144 def RF_setchan(self,channel):
145 if channel < 11 or channel > 26:
146 print "Only 802.15.4 channels 11 to 26 are currently supported.";
148 self.RF_setfreq( ( (channel-11)*5 + 2405 ) * 1000000 );
149 def RF_getsmac(self):
150 """Return the source MAC address."""
152 def RF_setsmac(self,mac):
153 """Set the source MAC address."""
155 def RF_gettmac(self):
156 """Return the target MAC address."""
158 def RF_settmac(self,mac):
159 """Set the target MAC address."""
161 def RF_getrssi(self):
162 """Returns the received signal strenght, with a weird offset."""
163 rssival=self.peek(0x13)&0xFF; #raw RSSI register
165 lastpacket=range(0,0xff);
166 def RF_rxpacket(self):
167 """Get a packet from the radio. Returns None if none is waiting. In
168 order to not require the SFD, FIFO, or FIFOP lines, this
169 implementation works by comparing the buffer to the older
175 self.writecmd(self.CCSPIAPP,0x80,len(data),data);
178 self.lastpacket=buffer;
182 def RF_txpacket(self,packet):
183 """Send a packet through the radio."""
184 self.writecmd(self.CCSPIAPP,0x81,len(packet),packet);
190 def RF_modulated_spectrum(self):
191 """Hold a carrier wave on the present frequency."""
192 # print "Don't know how to hold a carrier.";
196 # set MDMCTRL1.TX_MODE to 3 0x12 3:2
199 mdmctrl1=self.peek(0x12);
200 #print "mdmctrl1 was %04x" % mdmctrl1;
201 mdmctrl1=mdmctrl1|0x00c0; #MDMCTRL1.TX_MODE = 3
202 self.poke(0x12, mdmctrl1); #MDMCTRL1
204 mdmctrl1=self.peek(0x12);
205 #print "mdmctrl1 is %04x" % mdmctrl1;
207 # http://e2e.ti.com/support/low_power_rf/f/155/t/15914.aspx?PageIndex=2
209 self.strobe(0x02); #STXCAL
210 #print "STXCAL status: %s" % self.status()
213 self.strobe(0x09); #SFLUSHTX
214 #print "SFLUSHTX status: %s" % self.status()
216 self.strobe(0x04); #STXON
217 #print "STXON status: %s" % self.status()
219 def RF_carrier(self):
220 """Hold a carrier wave on the present frequency."""
221 # print "Don't know how to hold a carrier.";
225 # set MDMCTRL1.TX_MODE to 2 or 3 0x12 3:2
226 # set DACTST to 0x1800 0x2E
229 mdmctrl1=self.peek(0x12);
230 #print "mdmctrl1 was %04x" % mdmctrl1;
231 mdmctrl1=mdmctrl1|0x0080;
232 mdmctrl1=mdmctrl1&0x0080; #MDMCTRL1.TX_MODE = 2
233 self.poke(0x12, mdmctrl1); #MDMCTRL1
235 mdmctrl1=self.peek(0x12);
236 #print "mdmctrl1 is %04x" % mdmctrl1;
238 self.poke(0x2E, 0x1800); #DACTST
239 dactst=self.peek(0x2E);
240 #print "dactst is %04x" % dactst;
242 # see above for why this is here
243 self.strobe(0x02); #STXCAL
244 #print "STXCAL status: %s" % self.status()
245 self.strobe(0x09); #SFLUSHTX
246 #print "SFLUSHTX status: %s" % self.status()
248 self.strobe(0x04); #STXON
249 #print "STXON status: %s" % self.status()
251 def RF_promiscuity(self,promiscuous=1):
252 mdmctrl0=self.peek(0x11);
254 mdmctrl0=mdmctrl0&(~0x800);
256 mdmctrl0=mdmctrl0|0x800;
257 self.poke(0x11,mdmctrl0);
259 def RF_autocrc(self,autocrc=1):
260 mdmctrl0=self.peek(0x11);
262 mdmctrl0=mdmctrl0&(~0x0020);
264 mdmctrl0=mdmctrl0|0x0020;
265 self.poke(0x11,mdmctrl0);
268 def RF_setpacketlen(self,len=16):
269 """Set the number of bytes in the expected payload."""
270 #self.poke(0x11,len);
272 def RF_getpacketlen(self):
273 """Set the number of bytes in the expected payload."""
274 #len=self.peek(0x11);
278 def RF_getmaclen(self):
279 """Get the number of bytes in the MAC address."""
280 choices=[0, 3, 4, 5];
281 choice=self.peek(0x03)&3;
282 self.maclen=choices[choice];
284 def RF_setmaclen(self,len):
285 """Set the number of bytes in the MAC address."""
286 choices=["illegal", "illegal", "illegal",
289 self.poke(0x03,choice);
291 def printpacket(self,packet):
295 s="%s %02x" % (s,ord(foo));
298 def printdissect(self,packet):
300 from scapy.all import Dot15d4
302 print "To use packet disection, Scapy must be installed and have the Dot15d4 extension present."
303 print "try: hg clone http://hg.secdev.org/scapy-com";
304 print " sudo ./setup.py install";
305 self.printpacket(packet);
307 scapyd = Dot15d4(packet[1:]);