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 sniffstrings [chan]" % sys.argv[0];
32 print "%s bsniff [chan]" % sys.argv[0];
33 print "%s sniffcrypt 0x$key [chan]" % sys.argv[0];
34 print "%s sniffdissect" % sys.argv[0];
36 print "\n%s txtoscount [-i|-r] TinyOS BlinkToLED" % sys.argv[0];
37 print "%s reflexjam [channel=11] [delay=0]" % sys.argv[0];
41 #Initialize FET and set baud rate
42 client=GoodFETCCSPI();
48 #Might read as all ones if chip has a startup delay.
50 if(sys.argv[1]=="carrier"):
52 client.RF_setfreq(eval(sys.argv[2]));
58 if(sys.argv[1]=="modulated_spectrum"):
60 client.RF_setfreq(eval(sys.argv[2]));
62 client.RF_modulated_spectrum();
66 if(sys.argv[1]=="reflexjam" or sys.argv[1]=="reflexjamack"):
67 #Setup the radio to listen promiscously on a frequency
68 client.RF_promiscuity(1);
71 freq=eval(sys.argv[2]);
73 client.RF_setfreq(freq);
75 client.RF_setchan(freq);
78 duration=eval(sys.argv[3]);
80 print "Reflexively jamming on %i MHz" % (client.RF_getfreq()/10**6);
81 #Now we let the firmware take over, watching for packets and jamming them.
82 #Standard reflexive jam is done with duration=0.
83 #To selectively jam packets that are above a certain length, set duration
84 # to the number of milliseconds needed to jam frames of that length.
85 # Api-Do project has script available to tune/test this duration.
86 # code.google.com/p/zigbeesecurity (rmspeers)
87 if sys.argv[1]=="reflexjam":
88 client.RF_reflexjam(duration);
89 elif sys.argv[1]=="reflexjamack":
90 client.RF_reflexjam_autoack();
92 if(sys.argv[1]=="info"):
93 print "Found %s" % client.identstr();
94 print "Freq: %05f MHz" % (client.RF_getfreq()/(10**6));
95 print "Status: %s" % client.status();
96 if(sys.argv[1]=="regs"):
97 for adr in range(0x10,0x40): #*1024):
99 print "%04x:=0x%04x" % (adr,val);
100 if(sys.argv[1]=="test"):
101 data=client.trans([0x20, 0xde, 0xad]);
102 print "%02x %02x" % (ord(data[1]), ord(data[2]));
103 data=client.trans([0x40|0x20, 0xde, 0xad]);
104 print "%02x %02x" % (ord(data[1]), ord(data[2]));
105 if(sys.argv[1]=="rssi"):
107 freq=eval(sys.argv[2]);
109 client.RF_setfreq(freq);
111 client.RF_setchan(freq);
112 print "Listening on %f MHz." % (client.RF_getfreq()/10.0**6);
114 client.strobe(0x02); #Calibrate
119 #client.strobe(0x03); #SRXON
120 rssi=client.RF_getrssi();
121 #client.CC_RFST_IDLE(); #idle
124 for foo in range(0,rssi>>2):
125 string=("%s."%string);
126 print "%02x %04i %s" % (rssi,rssi, string);
127 if(sys.argv[1]=="spectrum"):
128 for chan in range(2400000000,2480000000,5000000):
129 client.RF_setfreq(chan);
130 #print "Listening on %f MHz." % (client.RF_getfreq()/10.0**6);
132 client.strobe(0x02); #Calibrate
136 for foo in range(1,10):
138 rssi=client.RF_getrssi();
139 maxrssi=max(rssi,maxrssi);
141 for foo in range(50,rssi):
142 string=("%s."%string);
143 print "%04i %i %s" % (client.RF_getfreq()/10.0**6,rssi, string);
144 if(sys.argv[1]=="spectrumcsv"):
147 for freq in range(2400000000,2480000000,1000000):
148 client.RF_setfreq(freq);
150 client.strobe(0x02); #Calibrate
152 rssi=client.RF_getrssi();
154 print "%f %i %3i" % (
156 client.RF_getfreq()/10.0**6,
160 if sys.argv[1]=="surf":
161 print "Scanning channels [11,26].";
164 client.RF_promiscuity(1);
165 client.RF_autocrc(1);
169 chan=eval(sys.argv[2]);
173 #Now we're ready to get packets.
177 client.setup(); #Really oughtn't be necessary, but can't hurt.
178 client.RF_setchan(chan);
181 lasttime=time.time();
182 while packet==None and time.time()-lasttime<0.5:
183 packet=client.RF_rxpacket();
185 client.printpacket(packet=packet,
186 prefix=("%02d: "%chan));
190 if(sys.argv[1]=="sniff" or sys.argv[1]=="sniffdissect" or sys.argv[1]=="sniffstrings"):
192 client.RF_promiscuity(1);
193 client.RF_autocrc(1);
196 freq=eval(sys.argv[2]);
198 client.RF_setfreq(freq);
200 client.RF_setfreq(freq*1000000);
202 client.RF_setchan(freq);
204 print "Listening as %010x on %i MHz" % (client.RF_getsmac(),
205 client.RF_getfreq()/10**6);
206 #Now we're ready to get packets.
208 #client.setup(); #Really oughtn't be necessary, but can't hurt.
213 packet=client.RF_rxpacket();
214 if sys.argv[1]=="sniffdissect":
215 client.printdissect(packet);
216 elif sys.argv[1]=="sniffstrings":
219 client.printpacket(packet);
222 if(sys.argv[1]=="bsniff"):
224 client.RF_promiscuity(0);
225 client.RF_setsmac(0xFFFFFFFF);
226 client.RF_autocrc(1);
229 freq=eval(sys.argv[2]);
231 client.RF_setfreq(freq);
233 client.RF_setchan(freq);
235 print "Listening as %010x on %i MHz" % (client.RF_getsmac(),
236 client.RF_getfreq()/10**6);
237 #Now we're ready to get packets.
241 packet=client.RF_rxpacket();
242 client.printpacket(packet);
245 if(sys.argv[1]=="sniffcrypt"):
246 print "Zigbee crypto is pretty damned complicated, and this doesn't work yet.";
248 client.RF_promiscuity(1);
249 client.RF_setsmac(0xFFFFFFFF);
250 client.RF_autocrc(1);
251 #client.poke(0x19, 0x03C7); #SECCTRL0, enabling CCM crypto w/ KEY0
252 client.poke(0x19, 0x03C6); #SECCTRL0, enabling CTRL crypto w/ KEY0
254 #What follows is the nonce.
255 client.poke(0x20, 0x000a); #SECCTRL1, skipping 10 bytes of header
258 key=int(sys.argv[2],16);
259 print "Setting KEY0 to %x" % key;
260 client.RF_setkey(key);
262 freq=eval(sys.argv[3]);
264 client.RF_setfreq(freq);
266 client.RF_setchan(freq);
268 print "Listening as %010x on %i MHz" % (client.RF_getsmac(),
269 client.RF_getfreq()/10**6);
270 #Now we're ready to get packets.
274 packet=client.RF_rxpacketdec();
275 client.printpacket(packet);
278 if(sys.argv[1]=="txtest"):
280 freq=eval(sys.argv[2]);
282 client.RF_setfreq(freq);
284 client.RF_setchan(freq);
285 print "Transmitting DEADBEEF as %010x on %i MHz" % (
287 client.RF_getfreq()/10**6);
290 client.RF_txpacket([0x0f, 0x01, 0x08, 0x82,
291 0xff, 0xff, 0xff, 0xff,
292 0xde, 0xad, 0xbe, 0xef,
295 if(sys.argv[1]=="txtoscount"):
297 Clone of what TinyOS's RadioCountToLeds demo code does. Specify a
298 channel a TinyOS mote programmed with RadioCountToLeds is on, and
299 this will act as the second device. (ryan@rmspeers.com)
301 if (len(sys.argv)<=3):
302 print "Provide -r to work via replays or -i to work via incrementing itself.";
304 if (sys.argv[3]=="-r"):
305 client.RF_promiscuity(1);
306 client.RF_autocrc(1);
308 freq=eval(sys.argv[2]);
310 client.RF_setfreq(freq);
312 client.RF_setchan(freq);
313 if (sys.argv[3]=="-r"):
315 print "Listening as %010x on %i MHz" % (client.RF_getsmac(), client.RF_getfreq()/10**6);
316 print "Transmitting like the TinyOS CountToRadio program on %i MHz" % (client.RF_getfreq()/10**6);
317 if (sys.argv[3]=="-i"):
319 countpkt = [0x0f, 0x41, 0x88, 0xFF, 0x22, 0x00, 0xff, 0xff, 0x01, 0x00, 0x3f, 0x06, 0x00, 0xFF];
321 if (sys.argv[3]=="-r"): #give -r to do via replays from the other device
324 packet=client.RF_rxpacket();
326 client.RF_txpacket(pkt);
327 elif (sys.argv[3]=="-i"): #give -i to have it increment and send
328 #Use this code for it to actually do increments itself:
332 client.RF_txpacket(pkt);
337 if(sys.argv[1]=="txpiptest" or sys.argv[1]=="txpipscapy"):
339 freq=eval(sys.argv[2]);
341 client.RF_setfreq(freq);
343 client.RF_setchan(freq);
344 print "Transmitting on as %010x on %i MHz" % (
346 client.RF_getfreq()/10**6);
348 client.RF_setsync(0xFFFF);
351 if(sys.argv[1]=="txpiptest"):
354 #Real header, must begin with SFD.
359 0x1f, 0x01, 0x08, 0x82,
360 0xDF, 0xff, 0xff, 0xff,
361 0xde, 0xad, 0xbe, 0xef,
367 0x00, 0xA7, #CC2420 SFD
369 0x0f, 0x01, 0x08, 0x82,
370 0xff, 0xff, 0xff, 0xff,
371 0xde, 0xad, 0xbe, 0xef,
374 0xff, 0xff, 0xff, 0xff,
375 0xff, 0xff, 0xff, 0xff,
376 0xff, 0xff, 0xff, 0xff,
377 0xff, 0xff, 0xff, 0xff,
378 0xff, 0xff, 0xff, 0xff,
379 0xff, 0xff, 0xff, 0xff,
380 0xff, 0xff, 0xff, 0xff,
382 elif(sys.argv[1]=="txpipscapy"):
383 # NB: Requires Scapy with dot15d4.py layer. (rmspeers)
385 from scapy.all import Dot15d4, Dot15d4FCS, Dot15d4Data, Raw
388 print "To use packet building, Scapy must be installed and have the dot15d4 layer present."
389 print "try: hg clone http://hg.secdev.org/scapy-com";
390 print " sudo ./setup.py install";
391 #Overall method is to build from the inner packet outwards in the pkt string
393 scapyinner = Dot15d4FCS(seqnum=130)/Dot15d4Data()/Raw('\xde\xad\xbe\xef');
394 pkt = str(scapyinner); #build inner pkt to bytes, adding FCS automatically
395 pkt = struct.pack('b', len(pkt)) + pkt #prepend with its length
396 pkt = "\x00\x00\x00\x00\xA7" + pkt #add preamble and SFD to inner packet
397 # Make outer (wrapping) packet
398 scapyouter = Dot15d4(seqnum=130)/Dot15d4Data(dest_panid=0xffdf)/Raw('\xde\xad\xbe\xef\xba\xbe\xc0') #TODO why need these last 3 bytes?
399 pkt = str(scapyouter) + pkt
400 pkt = struct.pack('b', len(pkt)) + pkt #prepend with its length
401 pkt = '\x00\x00\x00\x00\xA7' + pkt + ('\xff'*28) #start with preamble/SFD and add 0xff fill at end
402 pkt = struct.pack('b', len(pkt)) + pkt #prepend with its length (originally used \x7f)
403 client.printpacket(pkt)
404 client.RF_autocrc(1);
405 client.RF_txpacket(pkt)
407 if(sys.argv[1]=="peek"):
410 start=int(sys.argv[2],16);
413 stop=int(sys.argv[3],16);
414 print "Peeking from %04x to %04x." % (start,stop);
416 print "%04x: 0x%04x" % (start,client.peek(start));
418 if(sys.argv[1]=="poke"):
422 start=int(sys.argv[2],16);
424 val=int(sys.argv[3],16);
425 print "Poking r%02x to become 0x%04x." % (start,val);
427 client.poke(start,val);