3 #GoodFET Chipcon SPI Client
4 # (C) 2011 Travis Goodspeed
5 # Additions 2011-2012 Ryan Speers ryan@rmspeers.com
8 #Might be CC2420 Specific
14 from GoodFETCCSPI import GoodFETCCSPI;
17 print "Usage: %s verb [objects]\n" % sys.argv[0];
18 print "%s info" % sys.argv[0];
19 print "%s regs" % sys.argv[0];
20 print "%s test" % sys.argv[0];
21 print "%s peek 0x$start [0x$stop]" % sys.argv[0];
22 print "%s poke 0x$adr 0x$val" % sys.argv[0];
23 print "%s txtest" % sys.argv[0];
25 print "\n%s rssi" % sys.argv[0];
26 print "%s spectrum" % sys.argv[0];
27 print "%s spectrumcsv" % sys.argv[0];
29 print "\n%s surf" % sys.argv[0];
30 print "%s sniff [chan]" % sys.argv[0];
31 print "%s bsniff [chan]" % sys.argv[0];
32 print "%s sniffcrypt 0x$key [chan]" % sys.argv[0];
33 print "%s sniffdissect" % sys.argv[0];
35 print "\n%s txtoscount [-i|-r] TinyOS BlinkToLED" % sys.argv[0];
36 print "%s reflexjam [channel=11] [delay=0]" % sys.argv[0];
40 #Initialize FET and set baud rate
41 client=GoodFETCCSPI();
47 #Might read as all ones if chip has a startup delay.
49 if(sys.argv[1]=="carrier"):
51 client.RF_setfreq(eval(sys.argv[2]));
57 if(sys.argv[1]=="modulated_spectrum"):
59 client.RF_setfreq(eval(sys.argv[2]));
61 client.RF_modulated_spectrum();
65 if(sys.argv[1]=="reflexjam" or sys.argv[1]=="reflexjamack"):
66 #Setup the radio to listen promiscously on a frequency
67 client.RF_promiscuity(1);
70 freq=eval(sys.argv[2]);
72 client.RF_setfreq(freq);
74 client.RF_setchan(freq);
77 duration=eval(sys.argv[3]);
79 print "Reflexively jamming on %i MHz" % (client.RF_getfreq()/10**6);
80 #Now we let the firmware take over, watching for packets and jamming them.
81 #Standard reflexive jam is done with duration=0.
82 #To selectively jam packets that are above a certain length, set duration
83 # to the number of milliseconds needed to jam frames of that length.
84 # Api-Do project has script available to tune/test this duration.
85 # code.google.com/p/zigbeesecurity (rmspeers)
86 if sys.argv[1]=="reflexjam":
87 client.RF_reflexjam(duration);
88 elif sys.argv[1]=="reflexjamack":
89 client.RF_reflexjam_autoack();
91 if(sys.argv[1]=="info"):
92 print "Found %s" % client.identstr();
93 print "Freq: %05f MHz" % (client.RF_getfreq()/(10**6));
94 print "Status: %s" % client.status();
95 if(sys.argv[1]=="regs"):
96 for adr in range(0x10,0x40): #*1024):
98 print "%04x:=0x%04x" % (adr,val);
99 if(sys.argv[1]=="test"):
100 data=client.trans([0x20, 0xde, 0xad]);
101 print "%02x %02x" % (ord(data[1]), ord(data[2]));
102 data=client.trans([0x40|0x20, 0xde, 0xad]);
103 print "%02x %02x" % (ord(data[1]), ord(data[2]));
104 if(sys.argv[1]=="rssi"):
106 freq=eval(sys.argv[2]);
108 client.RF_setfreq(freq);
110 client.RF_setchan(freq);
111 print "Listening on %f MHz." % (client.RF_getfreq()/10.0**6);
113 client.strobe(0x02); #Calibrate
118 #client.strobe(0x03); #SRXON
119 rssi=client.RF_getrssi();
120 #client.CC_RFST_IDLE(); #idle
123 for foo in range(0,rssi>>2):
124 string=("%s."%string);
125 print "%02x %04i %s" % (rssi,rssi, string);
126 if(sys.argv[1]=="spectrum"):
127 for chan in range(2400000000,2480000000,5000000):
128 client.RF_setfreq(chan);
129 #print "Listening on %f MHz." % (client.RF_getfreq()/10.0**6);
131 client.strobe(0x02); #Calibrate
135 for foo in range(1,10):
137 rssi=client.RF_getrssi();
138 maxrssi=max(rssi,maxrssi);
140 for foo in range(50,rssi):
141 string=("%s."%string);
142 print "%04i %i %s" % (client.RF_getfreq()/10.0**6,rssi, string);
143 if(sys.argv[1]=="spectrumcsv"):
146 for freq in range(2400000000,2480000000,1000000):
147 client.RF_setfreq(freq);
149 client.strobe(0x02); #Calibrate
151 rssi=client.RF_getrssi();
153 print "%f %i %3i" % (
155 client.RF_getfreq()/10.0**6,
159 if sys.argv[1]=="surf":
160 print "Scanning channels [11,26].";
163 client.RF_promiscuity(1);
164 client.RF_autocrc(1);
168 chan=eval(sys.argv[2]);
172 #Now we're ready to get packets.
176 client.setup(); #Really oughtn't be necessary, but can't hurt.
177 client.RF_setchan(chan);
180 lasttime=time.time();
181 while packet==None and time.time()-lasttime<0.5:
182 packet=client.RF_rxpacket();
184 client.printpacket(packet=packet,
185 prefix=("%02d: "%chan));
189 if(sys.argv[1]=="sniff" or sys.argv[1]=="sniffdissect"):
191 client.RF_promiscuity(1);
192 client.RF_autocrc(1);
195 freq=eval(sys.argv[2]);
197 client.RF_setfreq(freq);
199 client.RF_setfreq(freq*1000000);
201 client.RF_setchan(freq);
203 print "Listening as %010x on %i MHz" % (client.RF_getsmac(),
204 client.RF_getfreq()/10**6);
205 #Now we're ready to get packets.
207 #client.setup(); #Really oughtn't be necessary, but can't hurt.
212 packet=client.RF_rxpacket();
213 if sys.argv[1]=="sniffdissect":
214 client.printdissect(packet);
216 client.printpacket(packet);
219 if(sys.argv[1]=="bsniff"):
221 client.RF_promiscuity(0);
222 client.RF_setsmac(0xFFFFFFFF);
223 client.RF_autocrc(1);
226 freq=eval(sys.argv[2]);
228 client.RF_setfreq(freq);
230 client.RF_setchan(freq);
232 print "Listening as %010x on %i MHz" % (client.RF_getsmac(),
233 client.RF_getfreq()/10**6);
234 #Now we're ready to get packets.
238 packet=client.RF_rxpacket();
239 client.printpacket(packet);
242 if(sys.argv[1]=="sniffcrypt"):
243 print "Zigbee crypto is pretty damned complicated, and this doesn't work yet.";
245 client.RF_promiscuity(1);
246 client.RF_setsmac(0xFFFFFFFF);
247 client.RF_autocrc(1);
248 #client.poke(0x19, 0x03C7); #SECCTRL0, enabling CCM crypto w/ KEY0
249 client.poke(0x19, 0x03C6); #SECCTRL0, enabling CTRL crypto w/ KEY0
251 #What follows is the nonce.
252 client.poke(0x20, 0x000a); #SECCTRL1, skipping 10 bytes of header
255 key=int(sys.argv[2],16);
256 print "Setting KEY0 to %x" % key;
257 client.RF_setkey(key);
259 freq=eval(sys.argv[3]);
261 client.RF_setfreq(freq);
263 client.RF_setchan(freq);
265 print "Listening as %010x on %i MHz" % (client.RF_getsmac(),
266 client.RF_getfreq()/10**6);
267 #Now we're ready to get packets.
271 packet=client.RF_rxpacketdec();
272 client.printpacket(packet);
275 if(sys.argv[1]=="txtest"):
277 freq=eval(sys.argv[2]);
279 client.RF_setfreq(freq);
281 client.RF_setchan(freq);
282 print "Transmitting DEADBEEF as %010x on %i MHz" % (
284 client.RF_getfreq()/10**6);
287 client.RF_txpacket([0x0f, 0x01, 0x08, 0x82,
288 0xff, 0xff, 0xff, 0xff,
289 0xde, 0xad, 0xbe, 0xef,
292 if(sys.argv[1]=="txtoscount"):
294 Clone of what TinyOS's RadioCountToLeds demo code does. Specify a
295 channel a TinyOS mote programmed with RadioCountToLeds is on, and
296 this will act as the second device. (ryan@rmspeers.com)
298 if (len(sys.argv)<=3):
299 print "Provide -r to work via replays or -i to work via incrementing itself.";
301 if (sys.argv[3]=="-r"):
302 client.RF_promiscuity(1);
303 client.RF_autocrc(1);
305 freq=eval(sys.argv[2]);
307 client.RF_setfreq(freq);
309 client.RF_setchan(freq);
310 if (sys.argv[3]=="-r"):
312 print "Listening as %010x on %i MHz" % (client.RF_getsmac(), client.RF_getfreq()/10**6);
313 print "Transmitting like the TinyOS CountToRadio program on %i MHz" % (client.RF_getfreq()/10**6);
314 if (sys.argv[3]=="-i"):
316 countpkt = [0x0f, 0x41, 0x88, 0xFF, 0x22, 0x00, 0xff, 0xff, 0x01, 0x00, 0x3f, 0x06, 0x00, 0xFF];
318 if (sys.argv[3]=="-r"): #give -r to do via replays from the other device
321 packet=client.RF_rxpacket();
323 client.RF_txpacket(pkt);
324 elif (sys.argv[3]=="-i"): #give -i to have it increment and send
325 #Use this code for it to actually do increments itself:
329 client.RF_txpacket(pkt);
334 if(sys.argv[1]=="txpiptest" or sys.argv[1]=="txpipscapy"):
336 freq=eval(sys.argv[2]);
338 client.RF_setfreq(freq);
340 client.RF_setchan(freq);
341 print "Transmitting on as %010x on %i MHz" % (
343 client.RF_getfreq()/10**6);
345 client.RF_setsync(0xFFFF);
348 if(sys.argv[1]=="txpiptest"):
351 #Real header, must begin with SFD.
356 0x1f, 0x01, 0x08, 0x82,
357 0xDF, 0xff, 0xff, 0xff,
358 0xde, 0xad, 0xbe, 0xef,
364 0x00, 0xA7, #CC2420 SFD
366 0x0f, 0x01, 0x08, 0x82,
367 0xff, 0xff, 0xff, 0xff,
368 0xde, 0xad, 0xbe, 0xef,
371 0xff, 0xff, 0xff, 0xff,
372 0xff, 0xff, 0xff, 0xff,
373 0xff, 0xff, 0xff, 0xff,
374 0xff, 0xff, 0xff, 0xff,
375 0xff, 0xff, 0xff, 0xff,
376 0xff, 0xff, 0xff, 0xff,
377 0xff, 0xff, 0xff, 0xff,
379 elif(sys.argv[1]=="txpipscapy"):
380 # NB: Requires Scapy with dot15d4.py layer. (rmspeers)
382 from scapy.all import Dot15d4, Dot15d4FCS, Dot15d4Data, Raw
385 print "To use packet building, Scapy must be installed and have the dot15d4 layer present."
386 print "try: hg clone http://hg.secdev.org/scapy-com";
387 print " sudo ./setup.py install";
388 #Overall method is to build from the inner packet outwards in the pkt string
390 scapyinner = Dot15d4FCS(seqnum=130)/Dot15d4Data()/Raw('\xde\xad\xbe\xef');
391 pkt = str(scapyinner); #build inner pkt to bytes, adding FCS automatically
392 pkt = struct.pack('b', len(pkt)) + pkt #prepend with its length
393 pkt = "\x00\x00\x00\x00\xA7" + pkt #add preamble and SFD to inner packet
394 # Make outer (wrapping) packet
395 scapyouter = Dot15d4(seqnum=130)/Dot15d4Data(dest_panid=0xffdf)/Raw('\xde\xad\xbe\xef\xba\xbe\xc0') #TODO why need these last 3 bytes?
396 pkt = str(scapyouter) + pkt
397 pkt = struct.pack('b', len(pkt)) + pkt #prepend with its length
398 pkt = '\x00\x00\x00\x00\xA7' + pkt + ('\xff'*28) #start with preamble/SFD and add 0xff fill at end
399 pkt = struct.pack('b', len(pkt)) + pkt #prepend with its length (originally used \x7f)
400 client.printpacket(pkt)
401 client.RF_autocrc(1);
402 client.RF_txpacket(pkt)
404 if(sys.argv[1]=="peek"):
407 start=int(sys.argv[2],16);
410 stop=int(sys.argv[3],16);
411 print "Peeking from %04x to %04x." % (start,stop);
413 print "%04x: 0x%04x" % (start,client.peek(start));
415 if(sys.argv[1]=="poke"):
419 start=int(sys.argv[2],16);
421 val=int(sys.argv[3],16);
422 print "Poking r%02x to become 0x%04x." % (start,val);
424 client.poke(start,val);