78d7691de9f55e17601e0746517cf29622e58f78
[goodfet] / client / goodfet.ccspi
1 #!/usr/bin/env python
2
3 #GoodFET Chipcon SPI Client
4 # (C) 2011 Travis Goodspeed
5 # Additions 2011-2012 Ryan Speers ryan@rmspeers.com
6
7 #N.B.,
8 #Might be CC2420 Specific
9
10 import sys;
11 import binascii;
12 import array, time;
13
14 from GoodFETCCSPI import GoodFETCCSPI;
15
16 if(len(sys.argv)==1):
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 ram" % sys.argv[0];
21     print "%s ramtest" % sys.argv[0];
22     print "%s test" % sys.argv[0];
23     print "%s peek 0x$start [0x$stop]" % sys.argv[0];
24     print "%s poke 0x$adr 0x$val" % sys.argv[0];
25     print "%s txtest" % sys.argv[0];
26     
27     print "\n%s rssi" % sys.argv[0];
28     print "%s spectrum" % sys.argv[0];
29     print "%s spectrumcsv" % sys.argv[0];
30     
31     print "\n%s surf" % sys.argv[0];
32     print "%s sniff [chan]" % sys.argv[0];
33     print "%s sniffstrings [chan]" % sys.argv[0];
34     print "%s bsniff [chan]" % sys.argv[0];
35     print "%s sniffcrypt 0x$key [chan]" % sys.argv[0];
36     print "%s sniffdissect" % sys.argv[0];
37     
38     print "\n%s txtoscount [-i|-r]   TinyOS BlinkToLED" % sys.argv[0];
39     print "%s reflexjam [channel=11] [delay=0]" % sys.argv[0];
40
41     sys.exit();
42
43 #Initialize FET and set baud rate
44 client=GoodFETCCSPI();
45 client.serInit()
46
47 client.setup();
48
49 #Dummy read.
50 #Might read as all ones if chip has a startup delay.
51
52 if(sys.argv[1]=="carrier"):
53     if len(sys.argv)>2:
54         client.RF_setfreq(eval(sys.argv[2]));
55     while 1:
56         client.RF_carrier();
57     while(1):
58         time.sleep(1);
59
60 if(sys.argv[1]=="modulated_spectrum"):
61     if len(sys.argv)>2:
62         client.RF_setfreq(eval(sys.argv[2]));
63     while 1:
64         client.RF_modulated_spectrum();
65     while(1):
66         time.sleep(1);
67
68 if(sys.argv[1]=="reflexjam" or sys.argv[1]=="reflexjamack"):
69     #Setup the radio to listen promiscously on a frequency
70     client.RF_promiscuity(1);
71     client.RF_autocrc(0);
72     if len(sys.argv)>2:
73         freq=eval(sys.argv[2]);
74         if freq>100:
75             client.RF_setfreq(freq);
76         else:
77             client.RF_setchan(freq);
78     duration=0;
79     if len(sys.argv)>3:
80         duration=eval(sys.argv[3]);
81     client.CC_RFST_RX();
82     print "Reflexively jamming on %i MHz" % (client.RF_getfreq()/10**6);
83     #Now we let the firmware take over, watching for packets and jamming them.
84     #Standard reflexive jam is done with duration=0.
85     #To selectively jam packets that are above a certain length, set duration
86     # to the number of milliseconds needed to jam frames of that length.
87     # Api-Do project has script available to tune/test this duration.
88     #  code.google.com/p/zigbeesecurity (rmspeers)
89     if sys.argv[1]=="reflexjam":
90         client.RF_reflexjam(duration);
91     elif sys.argv[1]=="reflexjamack":
92         client.RF_reflexjam_autoack();
93
94 if(sys.argv[1]=="info"):
95     print "Found   %s" % client.identstr();
96     print "Freq:   %05f MHz" % (client.RF_getfreq()/(10**6));
97     print "Status: %s" % client.status();
98 if(sys.argv[1]=="regs"):
99     for adr in range(0x10,0x40): #*1024):
100         val=client.peek(adr);
101         print "%04x:=0x%04x" % (adr,val);
102 if(sys.argv[1]=="ram"):
103     for adr in range(0x0,0x16D,16):
104         row=client.peekram(adr,32);
105         s="";
106         for foo in row:
107             s=s+(" %02x" % ord(foo))
108         print "%04x: %s" % (adr,s);
109 if(sys.argv[1]=="ramtest"):
110     client.pokeram(0x00,[0xde,0xad,0xbe,0xef,
111                          0xde,0xad,0xbe,0xef,
112                          0xde,0xad,0xbe,0xef,
113                          0xde,0xad,0xbe,0xef,
114                          0xde,0xad,0xbe,0xef,
115                          0xde,0xad,0xbe,0xef,
116                          0xde,0xad,0xbe,0xef,
117                          0xde,0xad,0xbe,0xef,
118                          0xde,0xad,0xbe,0xef,
119                          0xde,0xad,0xbe,0xef,
120                          0xde,0xad,0xbe,0xef]);
121     
122     for adr in range(0x0,0x16D,16):
123         row=client.peekram(adr,32);
124         s="";
125         for foo in row:
126             s=s+(" %02x" % ord(foo))
127         print "%04x: %s" % (adr,s);
128 if(sys.argv[1]=="test"):
129     data=client.trans([0x20, 0xde, 0xad]);
130     print "%02x %02x" % (ord(data[1]), ord(data[2]));
131     data=client.trans([0x40|0x20, 0xde, 0xad]);
132     print "%02x %02x" % (ord(data[1]), ord(data[2]));
133 if(sys.argv[1]=="rssi"):
134     if len(sys.argv)>2:
135         freq=eval(sys.argv[2]);
136         if freq>100:
137             client.RF_setfreq(freq);
138         else:
139             client.RF_setchan(freq);
140     print "Listening on %f MHz." % (client.RF_getfreq()/10.0**6);
141         
142     client.strobe(0x02); #Calibrate
143     time.sleep(1);
144     
145     while 1:
146         client.CC_RFST_RX();
147         #client.strobe(0x03); #SRXON
148         rssi=client.RF_getrssi();
149         #client.CC_RFST_IDLE(); #idle
150         time.sleep(0.01);
151         string="";
152         for foo in range(0,rssi>>2):
153             string=("%s."%string);
154         print "%02x %04i %s" % (rssi,rssi, string); 
155 if(sys.argv[1]=="spectrum"):
156     for chan in range(2400000000,2480000000,5000000):
157         client.RF_setfreq(chan);
158         #print "Listening on %f MHz." % (client.RF_getfreq()/10.0**6);
159         
160         client.strobe(0x02); #Calibrate
161         #time.sleep(0.01);
162         
163         maxrssi=0;
164         for foo in range(1,10):
165             client.CC_RFST_RX();
166             rssi=client.RF_getrssi();
167             maxrssi=max(rssi,maxrssi);
168         string="";
169         for foo in range(50,rssi):
170             string=("%s."%string);
171         print "%04i %i %s" % (client.RF_getfreq()/10.0**6,rssi, string); 
172 if(sys.argv[1]=="spectrumcsv"):
173     start=time.time();
174     while 1:
175         for freq in range(2400000000,2480000000,1000000):
176             client.RF_setfreq(freq);
177             
178             client.strobe(0x02); #Calibrate
179             client.CC_RFST_RX();
180             rssi=client.RF_getrssi();
181         
182             print "%f %i %3i" % (
183                 time.time()-start,
184                 client.RF_getfreq()/10.0**6,
185                 rssi); 
186         sys.stdout.flush();
187
188 if sys.argv[1]=="surf":
189     print "Scanning channels [11,26].";
190     
191     #Promiscuous mode.
192     client.RF_promiscuity(1);
193     client.RF_autocrc(1);
194     
195     chan=11;
196     if len(sys.argv)>2:
197         chan=eval(sys.argv[2]);
198         
199     client.CC_RFST_RX();
200     
201     #Now we're ready to get packets.
202     while 1:
203         if chan>26: chan=11;
204         
205         client.setup(); #Really oughtn't be necessary, but can't hurt.
206         client.RF_setchan(chan);
207         
208         packet=None;
209         lasttime=time.time();
210         while packet==None and time.time()-lasttime<0.5:
211             packet=client.RF_rxpacket();
212         if packet!=None:
213             client.printpacket(packet=packet,
214                            prefix=("%02d: "%chan));
215         sys.stdout.flush();
216         chan=chan+1;
217
218 if(sys.argv[1]=="sniff" or sys.argv[1]=="sniffdissect" or sys.argv[1]=="sniffstrings"):
219     #Promiscuous mode.
220     client.RF_promiscuity(1);
221     client.RF_autocrc(1);
222     
223     if len(sys.argv)>2:
224         freq=eval(sys.argv[2]);
225         if freq>3000:
226             client.RF_setfreq(freq);
227         elif freq>100:
228             client.RF_setfreq(freq*1000000);
229         else:
230             client.RF_setchan(freq);
231     client.CC_RFST_RX();
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.
235     while 1:
236         #client.setup(); #Really oughtn't be necessary, but can't hurt.
237         client.CC_RFST_RX();
238         
239         packet=None;
240         while packet==None:
241             packet=client.RF_rxpacket();
242         if sys.argv[1]=="sniffdissect":
243             client.printdissect(packet);
244         elif sys.argv[1]=="sniffstrings":
245             print packet
246         else:
247             client.printpacket(packet);
248         sys.stdout.flush();
249
250 if(sys.argv[1]=="bsniff"):
251     #Just broadcast.
252     client.RF_promiscuity(0);
253     client.RF_setsmac(0xFFFFFFFF);
254     client.RF_autocrc(1);
255     
256     if len(sys.argv)>2:
257         freq=eval(sys.argv[2]);
258         if freq>100:
259             client.RF_setfreq(freq);
260         else:
261             client.RF_setchan(freq);
262     client.CC_RFST_RX();
263     print "Listening as %010x on %i MHz" % (client.RF_getsmac(),
264                                             client.RF_getfreq()/10**6);
265     #Now we're ready to get packets.
266     while 1:
267         packet=None;
268         while packet==None:
269             packet=client.RF_rxpacket();
270         client.printpacket(packet);
271         sys.stdout.flush();
272
273 if(sys.argv[1]=="sniffcrypt"):
274     print "Zigbee crypto is pretty damned complicated, and this doesn't work yet.";
275     #Just broadcast.
276     client.RF_promiscuity(1);
277     client.RF_setsmac(0xFFFFFFFF);
278     client.RF_autocrc(1);
279     #client.poke(0x19, 0x03C7); #SECCTRL0, enabling CCM crypto w/ KEY0
280     client.poke(0x19, 0x03C6); #SECCTRL0, enabling CTRL crypto w/ KEY0
281     
282     #What follows is the nonce.
283     client.poke(0x20, 0x000a); #SECCTRL1, skipping 10 bytes of header
284     
285     if len(sys.argv)>2:
286         key=int(sys.argv[2],16);
287         print "Setting KEY0 to %x" % key;
288         client.RF_setkey(key);
289     if len(sys.argv)>3:
290         freq=eval(sys.argv[3]);
291         if freq>100:
292             client.RF_setfreq(freq);
293         else:
294             client.RF_setchan(freq);
295     client.CC_RFST_RX();
296     print "Listening as %010x on %i MHz" % (client.RF_getsmac(),
297                                             client.RF_getfreq()/10**6);
298     #Now we're ready to get packets.
299     while 1:
300         packet=None;
301         while packet==None:
302             packet=client.RF_rxpacketdec();
303         client.printpacket(packet);
304         sys.stdout.flush();
305
306 if(sys.argv[1]=="txtest"):
307     if len(sys.argv)>2:
308         freq=eval(sys.argv[2]);
309         if freq>100:
310             client.RF_setfreq(freq);
311         else:
312             client.RF_setchan(freq);
313     print "Transmitting DEADBEEF as %010x on %i MHz" % (
314         client.RF_getsmac(),
315         client.RF_getfreq()/10**6);
316     
317     while 1:
318         client.RF_txpacket([0x0f, 0x01, 0x08, 0x82,
319                             0xff, 0xff, 0xff, 0xff,
320                             0xde, 0xad, 0xbe, 0xef,
321                             0xba, 0xbe, 0xc0]);
322
323 if(sys.argv[1]=="txtoscount"):
324     '''
325     Clone of what TinyOS's RadioCountToLeds demo code does.  Specify a
326     channel a TinyOS mote programmed with RadioCountToLeds is on, and
327     this will act as the second device. (ryan@rmspeers.com)
328     '''
329     if (len(sys.argv)<=3):
330         print "Provide -r to work via replays or -i to work via incrementing itself.";
331         sys.exit(1);
332     if (sys.argv[3]=="-r"):
333         client.RF_promiscuity(1);
334     client.RF_autocrc(1);
335     if len(sys.argv)>2:
336         freq=eval(sys.argv[2]);
337         if freq>100:
338             client.RF_setfreq(freq);
339         else:
340             client.RF_setchan(freq);
341     if (sys.argv[3]=="-r"):
342         client.CC_RFST_RX();
343         print "Listening as %010x on %i MHz" % (client.RF_getsmac(), client.RF_getfreq()/10**6);
344     print "Transmitting like the TinyOS CountToRadio program on %i MHz" % (client.RF_getfreq()/10**6);
345     if (sys.argv[3]=="-i"):
346         i = 0;
347         countpkt = [0x0f, 0x41, 0x88, 0xFF, 0x22, 0x00, 0xff, 0xff, 0x01, 0x00, 0x3f, 0x06, 0x00, 0xFF];
348     while 1:
349         if (sys.argv[3]=="-r"): #give -r to do via replays from the other device
350             packet=None;
351             while packet==None:
352                 packet=client.RF_rxpacket();
353             pkt = packet[:14];
354             client.RF_txpacket(pkt);
355         elif (sys.argv[3]=="-i"): #give -i to have it increment and send
356             #Use this code for it to actually do increments itself:
357             pkt = countpkt[:];
358             pkt[3] = i;
359             pkt[13] = i+1;
360             client.RF_txpacket(pkt);
361             if i >= 31: i = 0;
362             else:       i += 1;
363             time.sleep(0.5);
364
365 if(sys.argv[1]=="txpiptest" or sys.argv[1]=="txpipscapy"):
366     if len(sys.argv)>2:
367         freq=eval(sys.argv[2]);
368         if freq>100:
369             client.RF_setfreq(freq);
370         else:
371             client.RF_setchan(freq);
372     print "Transmitting on as %010x on %i MHz" % (
373         client.RF_getsmac(),
374         client.RF_getfreq()/10**6);
375     
376     client.RF_setsync(0xFFFF);
377     
378     while 1:
379         if(sys.argv[1]=="txpiptest"):
380             client.RF_txpacket([
381                     0x7f, 
382                     #Real header, must begin with SFD.
383                     0x00, 0x00, 0x00,
384                     0x00, 0xA7,
385                     
386                     #Length
387                     0x1f, 0x01, 0x08, 0x82,
388                     0xDF, 0xff, 0xff, 0xff,
389                     0xde, 0xad, 0xbe, 0xef,
390                     0xba, 0xbe, 0xc0,
391                     
392                     #Preamble
393                     0x00, 0x00, 0x00,
394                     #SFD
395                     0x00, 0xA7,  #CC2420 SFD
396                     #Packet In Packet
397                     0x0f, 0x01, 0x08, 0x82,
398                     0xff, 0xff, 0xff, 0xff,
399                     0xde, 0xad, 0xbe, 0xef,
400                     0xba, 0xbe, 0xc0,
401                     
402                     0xff, 0xff, 0xff, 0xff,
403                     0xff, 0xff, 0xff, 0xff,
404                     0xff, 0xff, 0xff, 0xff,
405                     0xff, 0xff, 0xff, 0xff,
406                     0xff, 0xff, 0xff, 0xff,
407                     0xff, 0xff, 0xff, 0xff,
408                     0xff, 0xff, 0xff, 0xff,
409                     ]);
410         elif(sys.argv[1]=="txpipscapy"):
411             # NB: Requires Scapy with dot15d4.py layer. (rmspeers)
412             try:
413                 from scapy.all import Dot15d4, Dot15d4FCS, Dot15d4Data, Raw
414                 import struct
415             except ImportError:
416                 print "To use packet building, Scapy must be installed and have the dot15d4 layer present."
417                 print "try: hg clone http://hg.secdev.org/scapy-com";
418                 print "     sudo ./setup.py install";
419             #Overall method is to build from the inner packet outwards in the pkt string
420             # Make inner packet
421             scapyinner = Dot15d4FCS(seqnum=130)/Dot15d4Data()/Raw('\xde\xad\xbe\xef');
422             pkt = str(scapyinner);                  #build inner pkt to bytes, adding FCS automatically
423             pkt = struct.pack('b', len(pkt)) + pkt  #prepend with its length
424             pkt = "\x00\x00\x00\x00\xA7" + pkt      #add preamble and SFD to inner packet
425             # Make outer (wrapping) packet
426             scapyouter = Dot15d4(seqnum=130)/Dot15d4Data(dest_panid=0xffdf)/Raw('\xde\xad\xbe\xef\xba\xbe\xc0') #TODO why need these last 3 bytes?
427             pkt = str(scapyouter) + pkt
428             pkt = struct.pack('b', len(pkt)) + pkt  #prepend with its length
429             pkt = '\x00\x00\x00\x00\xA7' + pkt + ('\xff'*28) #start with preamble/SFD and add 0xff fill at end
430             pkt = struct.pack('b', len(pkt)) + pkt  #prepend with its length (originally used \x7f)
431             client.printpacket(pkt)
432             client.RF_autocrc(1);
433             client.RF_txpacket(pkt)
434
435 if(sys.argv[1]=="peek"):
436     start=0x0000;
437     if(len(sys.argv)>2):
438         start=int(sys.argv[2],16);
439     stop=start;
440     if(len(sys.argv)>3):
441         stop=int(sys.argv[3],16);
442     print "Peeking from %04x to %04x." % (start,stop);
443     while start<=stop:
444         print "%04x: 0x%04x" % (start,client.peek(start));
445         start=start+1;
446 if(sys.argv[1]=="poke"):
447     start=0x0000;
448     val=0x00;
449     if(len(sys.argv)>2):
450         start=int(sys.argv[2],16);
451     if(len(sys.argv)>3):
452         val=int(sys.argv[3],16);
453     print "Poking r%02x to become 0x%04x." % (start,val);
454     
455     client.poke(start,val);
456