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_getsmac(self):
136 """Return the source MAC address."""
138 def RF_setsmac(self,mac):
139 """Set the source MAC address."""
141 def RF_gettmac(self):
142 """Return the target MAC address."""
144 def RF_settmac(self,mac):
145 """Set the target MAC address."""
147 def RF_getrssi(self):
148 """Returns the received signal strenght, with a weird offset."""
149 rssival=self.peek(0x13)&0xFF; #raw RSSI register
151 lastpacket=range(0,0xff);
152 def RF_rxpacket(self):
153 """Get a packet from the radio. Returns None if none is waiting. In
154 order to not require the SFD, FIFO, or FIFOP lines, this
155 implementation works by comparing the buffer to the older
161 self.writecmd(self.CCSPIAPP,0x80,len(data),data);
164 self.lastpacket=buffer;
168 def RF_txpacket(self,packet):
169 """Send a packet through the radio."""
170 self.writecmd(self.CCSPIAPP,0x81,len(packet),packet);
176 def RF_modulated_spectrum(self):
177 """Hold a carrier wave on the present frequency."""
178 # print "Don't know how to hold a carrier.";
182 # set MDMCTRL1.TX_MODE to 3 0x12 3:2
185 mdmctrl1=self.peek(0x12);
186 #print "mdmctrl1 was %04x" % mdmctrl1;
187 mdmctrl1=mdmctrl1|0x00c0; #MDMCTRL1.TX_MODE = 3
188 self.poke(0x12, mdmctrl1); #MDMCTRL1
190 mdmctrl1=self.peek(0x12);
191 #print "mdmctrl1 is %04x" % mdmctrl1;
193 # http://e2e.ti.com/support/low_power_rf/f/155/t/15914.aspx?PageIndex=2
195 self.strobe(0x02); #STXCAL
196 #print "STXCAL status: %s" % self.status()
199 self.strobe(0x09); #SFLUSHTX
200 #print "SFLUSHTX status: %s" % self.status()
202 self.strobe(0x04); #STXON
203 #print "STXON status: %s" % self.status()
205 def RF_carrier(self):
206 """Hold a carrier wave on the present frequency."""
207 # print "Don't know how to hold a carrier.";
211 # set MDMCTRL1.TX_MODE to 2 or 3 0x12 3:2
212 # set DACTST to 0x1800 0x2E
215 mdmctrl1=self.peek(0x12);
216 #print "mdmctrl1 was %04x" % mdmctrl1;
217 mdmctrl1=mdmctrl1|0x0080;
218 mdmctrl1=mdmctrl1&0x0080; #MDMCTRL1.TX_MODE = 2
219 self.poke(0x12, mdmctrl1); #MDMCTRL1
221 mdmctrl1=self.peek(0x12);
222 #print "mdmctrl1 is %04x" % mdmctrl1;
224 self.poke(0x2E, 0x1800); #DACTST
225 dactst=self.peek(0x2E);
226 #print "dactst is %04x" % dactst;
228 # see above for why this is here
229 self.strobe(0x02); #STXCAL
230 #print "STXCAL status: %s" % self.status()
231 self.strobe(0x09); #SFLUSHTX
232 #print "SFLUSHTX status: %s" % self.status()
234 self.strobe(0x04); #STXON
235 #print "STXON status: %s" % self.status()
237 def RF_promiscuity(self,promiscuous=1):
238 mdmctrl0=self.peek(0x11);
239 #print "mdmctrl0 was %04x" % mdmctrl0;
240 mdmctrl0=mdmctrl0&(~0x800);
241 #print "mdmctrl0 is now %04x" % mdmctrl0;
242 self.poke(0x11,mdmctrl0);
246 def RF_setpacketlen(self,len=16):
247 """Set the number of bytes in the expected payload."""
248 #self.poke(0x11,len);
250 def RF_getpacketlen(self):
251 """Set the number of bytes in the expected payload."""
252 #len=self.peek(0x11);
256 def RF_getmaclen(self):
257 """Get the number of bytes in the MAC address."""
258 choices=[0, 3, 4, 5];
259 choice=self.peek(0x03)&3;
260 self.maclen=choices[choice];
262 def RF_setmaclen(self,len):
263 """Set the number of bytes in the MAC address."""
264 choices=["illegal", "illegal", "illegal",
267 self.poke(0x03,choice);
269 def printpacket(self,packet):
273 s="%s %02x" % (s,ord(foo));
275 def printdissect(self,packet):
277 from scapy.all import Dot15d4
279 print "To use packet disection, Scapy must be installed and have the Dot15d4 extension present."
280 print "try: hg clone http://hg.secdev.org/scapy-com";
281 print " sudo ./setup.py install";
282 self.printpacket(packet);
284 scapyd = Dot15d4(packet[1:]);