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
29 return self.peek(0x1E); #MANFIDL
31 manfidl=self.peek(0x1E);
32 #manfidh=self.peek(0x1f);
34 return "%s" % (self.CCversions[manfidl]);
36 return "Unknown0x%04x" % manfidl;
37 def trans8(self,byte):
38 """Read and write 8 bits by CCSPI."""
39 data=self.CCSPItrans([byte]);
43 """Exchange data by CCSPI."""
45 self.writecmd(self.CCSPIAPP,0x00,len(data),data);
47 def strobe(self,reg=0x00):
48 """Strobes a strobe register, returning the status."""
51 return ord(self.data[0]);
52 def CC_RFST_IDLE(self):
53 """Switch the radio to idle mode, clearing overflows and errors."""
54 self.strobe(0x06); #SRXOFF
56 """Switch the radio to TX mode."""
57 self.strobe(0x04); #0x05 for CCA
59 """Switch the radio to RX mode."""
61 def CC_RFST_CAL(self):
62 """Calibrate strobe the radio."""
64 def CC_RFST(self,state=0x00):
67 def peek(self,reg,bytes=2):
68 """Read a CCSPI Register. For long regs, result is flipped."""
70 #Reg is ORed with 0x40 by the GoodFET.
73 #Automatically calibrate the len.
76 self.writecmd(self.CCSPIAPP,0x02,len(data),data);
79 (ord(self.data[1])<<8)
82 def poke(self,reg,val,bytes=2):
83 """Write a CCSPI Register."""
84 data=[reg,(val>>8)&0xFF,val&0xFF];
85 self.writecmd(self.CCSPIAPP,0x03,len(data),data);
86 if self.peek(reg,bytes)!=val:
87 print "Warning, failed to set r%02x=0x%04x, got %02x." %(
90 self.peek(reg,bytes));
94 """Read the status byte."""
95 statusbits={0x80: "?",
96 0x40: "XOSC16M_STABLE",
103 status=self.strobe(0x00);
108 str="%s %s" % (statusbits[i],str);
112 #Radio stuff begins here.
113 def RF_setenc(self,code="802.15.4"):
114 """Set the encoding type."""
117 """Get the encoding type."""
119 def RF_getrate(self):
121 def RF_setrate(self,rate=0):
123 def RF_setfreq(self,frequency):
124 """Set the frequency in Hz."""
125 mhz=frequency/1000000;
126 fsctrl=self.peek(0x18)&~0x3FF;
127 fsctrl=fsctrl+int(mhz-2048)
128 self.poke(0x18,fsctrl);
130 def RF_getfreq(self):
131 """Get the frequency in Hz."""
132 fsctrl=self.peek(0x18);
133 mhz=2048+(fsctrl&0x3ff)
135 def RF_setchan(self,channel):
136 if channel < 11 and channel > 26:
137 print "Only 802.15.4 channels 11 to 26 are currently supported.";
139 self.RF_setfreq( ( (channel-11)*5 + 2405 ) * 1000000 );
140 def RF_getsmac(self):
141 """Return the source MAC address."""
143 def RF_setsmac(self,mac):
144 """Set the source MAC address."""
146 def RF_gettmac(self):
147 """Return the target MAC address."""
149 def RF_settmac(self,mac):
150 """Set the target MAC address."""
152 def RF_getrssi(self):
153 """Returns the received signal strenght, with a weird offset."""
154 rssival=self.peek(0x13)&0xFF; #raw RSSI register
156 lastpacket=range(0,0xff);
157 def RF_rxpacket(self):
158 """Get a packet from the radio. Returns None if none is waiting. In
159 order to not require the SFD, FIFO, or FIFOP lines, this
160 implementation works by comparing the buffer to the older
166 self.writecmd(self.CCSPIAPP,0x80,len(data),data);
169 self.lastpacket=buffer;
173 def RF_txpacket(self,packet):
174 """Send a packet through the radio."""
175 self.writecmd(self.CCSPIAPP,0x81,len(packet),packet);
181 def RF_modulated_spectrum(self):
182 """Hold a carrier wave on the present frequency."""
183 # print "Don't know how to hold a carrier.";
187 # set MDMCTRL1.TX_MODE to 3 0x12 3:2
190 mdmctrl1=self.peek(0x12);
191 #print "mdmctrl1 was %04x" % mdmctrl1;
192 mdmctrl1=mdmctrl1|0x00c0; #MDMCTRL1.TX_MODE = 3
193 self.poke(0x12, mdmctrl1); #MDMCTRL1
195 mdmctrl1=self.peek(0x12);
196 #print "mdmctrl1 is %04x" % mdmctrl1;
198 # http://e2e.ti.com/support/low_power_rf/f/155/t/15914.aspx?PageIndex=2
200 self.strobe(0x02); #STXCAL
201 #print "STXCAL status: %s" % self.status()
204 self.strobe(0x09); #SFLUSHTX
205 #print "SFLUSHTX status: %s" % self.status()
207 self.strobe(0x04); #STXON
208 #print "STXON status: %s" % self.status()
210 def RF_carrier(self):
211 """Hold a carrier wave on the present frequency."""
212 # print "Don't know how to hold a carrier.";
216 # set MDMCTRL1.TX_MODE to 2 or 3 0x12 3:2
217 # set DACTST to 0x1800 0x2E
220 mdmctrl1=self.peek(0x12);
221 #print "mdmctrl1 was %04x" % mdmctrl1;
222 mdmctrl1=mdmctrl1|0x0080;
223 mdmctrl1=mdmctrl1&0x0080; #MDMCTRL1.TX_MODE = 2
224 self.poke(0x12, mdmctrl1); #MDMCTRL1
226 mdmctrl1=self.peek(0x12);
227 #print "mdmctrl1 is %04x" % mdmctrl1;
229 self.poke(0x2E, 0x1800); #DACTST
230 dactst=self.peek(0x2E);
231 #print "dactst is %04x" % dactst;
233 # see above for why this is here
234 self.strobe(0x02); #STXCAL
235 #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_promiscuity(self,promiscuous=1):
243 mdmctrl0=self.peek(0x11);
244 #print "mdmctrl0 was %04x" % mdmctrl0;
245 mdmctrl0=mdmctrl0&(~0x800);
246 #print "mdmctrl0 is now %04x" % mdmctrl0;
247 self.poke(0x11,mdmctrl0);
251 def RF_setpacketlen(self,len=16):
252 """Set the number of bytes in the expected payload."""
253 #self.poke(0x11,len);
255 def RF_getpacketlen(self):
256 """Set the number of bytes in the expected payload."""
257 #len=self.peek(0x11);
261 def RF_getmaclen(self):
262 """Get the number of bytes in the MAC address."""
263 choices=[0, 3, 4, 5];
264 choice=self.peek(0x03)&3;
265 self.maclen=choices[choice];
267 def RF_setmaclen(self,len):
268 """Set the number of bytes in the MAC address."""
269 choices=["illegal", "illegal", "illegal",
272 self.poke(0x03,choice);
274 def printpacket(self,packet):
278 s="%s %02x" % (s,ord(foo));
280 def printdissect(self,packet):
282 from scapy.all import Dot15d4
284 print "To use packet disection, Scapy must be installed and have the Dot15d4 extension present."
285 print "try: hg clone http://hg.secdev.org/scapy-com";
286 print " sudo ./setup.py install";
287 self.printpacket(packet);
289 scapyd = Dot15d4(packet[1:]);