6654e279e2bc3094667dbc7a034aca695578977c
[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 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];
24     
25     print "\n%s rssi" % sys.argv[0];
26     print "%s spectrum" % sys.argv[0];
27     print "%s spectrumcsv" % sys.argv[0];
28     
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];
34     
35     print "\n%s txtoscount [-i|-r]   TinyOS BlinkToLED" % sys.argv[0];
36     print "%s reflexjam [channel=11] [delay=0]" % sys.argv[0];
37
38     sys.exit();
39
40 #Initialize FET and set baud rate
41 client=GoodFETCCSPI();
42 client.serInit()
43
44 client.setup();
45
46 #Dummy read.
47 #Might read as all ones if chip has a startup delay.
48
49 if(sys.argv[1]=="carrier"):
50     if len(sys.argv)>2:
51         client.RF_setfreq(eval(sys.argv[2]));
52     while 1:
53         client.RF_carrier();
54     while(1):
55         time.sleep(1);
56
57 if(sys.argv[1]=="modulated_spectrum"):
58     if len(sys.argv)>2:
59         client.RF_setfreq(eval(sys.argv[2]));
60     while 1:
61         client.RF_modulated_spectrum();
62     while(1):
63         time.sleep(1);
64
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);
68     client.RF_autocrc(0);
69     if len(sys.argv)>2:
70         freq=eval(sys.argv[2]);
71         if freq>100:
72             client.RF_setfreq(freq);
73         else:
74             client.RF_setchan(freq);
75     duration=0;
76     if len(sys.argv)>3:
77         duration=eval(sys.argv[3]);
78     client.CC_RFST_RX();
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();
90
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):
97         val=client.peek(adr);
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"):
105     if len(sys.argv)>2:
106         freq=eval(sys.argv[2]);
107         if freq>100:
108             client.RF_setfreq(freq);
109         else:
110             client.RF_setchan(freq);
111     print "Listening on %f MHz." % (client.RF_getfreq()/10.0**6);
112         
113     client.strobe(0x02); #Calibrate
114     time.sleep(1);
115     
116     while 1:
117         client.CC_RFST_RX();
118         #client.strobe(0x03); #SRXON
119         rssi=client.RF_getrssi();
120         #client.CC_RFST_IDLE(); #idle
121         time.sleep(0.01);
122         string="";
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);
130         
131         client.strobe(0x02); #Calibrate
132         #time.sleep(0.01);
133         
134         maxrssi=0;
135         for foo in range(1,10):
136             client.CC_RFST_RX();
137             rssi=client.RF_getrssi();
138             maxrssi=max(rssi,maxrssi);
139         string="";
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"):
144     start=time.time();
145     while 1:
146         for freq in range(2400000000,2480000000,1000000):
147             client.RF_setfreq(freq);
148             
149             client.strobe(0x02); #Calibrate
150             client.CC_RFST_RX();
151             rssi=client.RF_getrssi();
152         
153             print "%f %i %3i" % (
154                 time.time()-start,
155                 client.RF_getfreq()/10.0**6,
156                 rssi); 
157         sys.stdout.flush();
158
159 if sys.argv[1]=="surf":
160     print "Scanning channels [11,26].";
161     
162     #Promiscuous mode.
163     client.RF_promiscuity(1);
164     client.RF_autocrc(1);
165     
166     chan=11;
167     if len(sys.argv)>2:
168         chan=eval(sys.argv[2]);
169         
170     client.CC_RFST_RX();
171     
172     #Now we're ready to get packets.
173     while 1:
174         if chan>26: chan=11;
175         
176         client.setup(); #Really oughtn't be necessary, but can't hurt.
177         client.RF_setchan(chan);
178         
179         packet=None;
180         lasttime=time.time();
181         while packet==None and time.time()-lasttime<0.5:
182             packet=client.RF_rxpacket();
183         if packet!=None:
184             client.printpacket(packet=packet,
185                            prefix=("%02d: "%chan));
186         sys.stdout.flush();
187         chan=chan+1;
188
189 if(sys.argv[1]=="sniff" or sys.argv[1]=="sniffdissect"):
190     #Promiscuous mode.
191     client.RF_promiscuity(1);
192     client.RF_autocrc(1);
193     
194     if len(sys.argv)>2:
195         freq=eval(sys.argv[2]);
196         if freq>3000:
197             client.RF_setfreq(freq);
198         elif freq>100:
199             client.RF_setfreq(freq*1000000);
200         else:
201             client.RF_setchan(freq);
202     client.CC_RFST_RX();
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.
206     while 1:
207         #client.setup(); #Really oughtn't be necessary, but can't hurt.
208         client.CC_RFST_RX();
209         
210         packet=None;
211         while packet==None:
212             packet=client.RF_rxpacket();
213         if sys.argv[1]=="sniffdissect":
214             client.printdissect(packet);
215         else:
216             client.printpacket(packet);
217         sys.stdout.flush();
218
219 if(sys.argv[1]=="bsniff"):
220     #Just broadcast.
221     client.RF_promiscuity(0);
222     client.RF_setsmac(0xFFFFFFFF);
223     client.RF_autocrc(1);
224     
225     if len(sys.argv)>2:
226         freq=eval(sys.argv[2]);
227         if freq>100:
228             client.RF_setfreq(freq);
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         packet=None;
237         while packet==None:
238             packet=client.RF_rxpacket();
239         client.printpacket(packet);
240         sys.stdout.flush();
241
242 if(sys.argv[1]=="sniffcrypt"):
243     print "Zigbee crypto is pretty damned complicated, and this doesn't work yet.";
244     #Just broadcast.
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
250     
251     #What follows is the nonce.
252     client.poke(0x20, 0x000a); #SECCTRL1, skipping 10 bytes of header
253     
254     if len(sys.argv)>2:
255         key=int(sys.argv[2],16);
256         print "Setting KEY0 to %x" % key;
257         client.RF_setkey(key);
258     if len(sys.argv)>3:
259         freq=eval(sys.argv[3]);
260         if freq>100:
261             client.RF_setfreq(freq);
262         else:
263             client.RF_setchan(freq);
264     client.CC_RFST_RX();
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.
268     while 1:
269         packet=None;
270         while packet==None:
271             packet=client.RF_rxpacketdec();
272         client.printpacket(packet);
273         sys.stdout.flush();
274
275 if(sys.argv[1]=="txtest"):
276     if len(sys.argv)>2:
277         freq=eval(sys.argv[2]);
278         if freq>100:
279             client.RF_setfreq(freq);
280         else:
281             client.RF_setchan(freq);
282     print "Transmitting DEADBEEF as %010x on %i MHz" % (
283         client.RF_getsmac(),
284         client.RF_getfreq()/10**6);
285     
286     while 1:
287         client.RF_txpacket([0x0f, 0x01, 0x08, 0x82,
288                             0xff, 0xff, 0xff, 0xff,
289                             0xde, 0xad, 0xbe, 0xef,
290                             0xba, 0xbe, 0xc0]);
291
292 if(sys.argv[1]=="txtoscount"):
293     '''
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)
297     '''
298     if (len(sys.argv)<=3):
299         print "Provide -r to work via replays or -i to work via incrementing itself.";
300         sys.exit(1);
301     if (sys.argv[3]=="-r"):
302         client.RF_promiscuity(1);
303     client.RF_autocrc(1);
304     if len(sys.argv)>2:
305         freq=eval(sys.argv[2]);
306         if freq>100:
307             client.RF_setfreq(freq);
308         else:
309             client.RF_setchan(freq);
310     if (sys.argv[3]=="-r"):
311         client.CC_RFST_RX();
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"):
315         i = 0;
316         countpkt = [0x0f, 0x41, 0x88, 0xFF, 0x22, 0x00, 0xff, 0xff, 0x01, 0x00, 0x3f, 0x06, 0x00, 0xFF];
317     while 1:
318         if (sys.argv[3]=="-r"): #give -r to do via replays from the other device
319             packet=None;
320             while packet==None:
321                 packet=client.RF_rxpacket();
322             pkt = packet[:14];
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:
326             pkt = countpkt[:];
327             pkt[3] = i;
328             pkt[13] = i+1;
329             client.RF_txpacket(pkt);
330             if i >= 31: i = 0;
331             else:       i += 1;
332             time.sleep(0.5);
333
334 if(sys.argv[1]=="txpiptest" or sys.argv[1]=="txpipscapy"):
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     print "Transmitting on as %010x on %i MHz" % (
342         client.RF_getsmac(),
343         client.RF_getfreq()/10**6);
344     
345     client.RF_setsync(0xFFFF);
346     
347     while 1:
348         if(sys.argv[1]=="txpiptest"):
349             client.RF_txpacket([
350                     0x7f, 
351                     #Real header, must begin with SFD.
352                     0x00, 0x00, 0x00,
353                     0x00, 0xA7,
354                     
355                     #Length
356                     0x1f, 0x01, 0x08, 0x82,
357                     0xDF, 0xff, 0xff, 0xff,
358                     0xde, 0xad, 0xbe, 0xef,
359                     0xba, 0xbe, 0xc0,
360                     
361                     #Preamble
362                     0x00, 0x00, 0x00,
363                     #SFD
364                     0x00, 0xA7,  #CC2420 SFD
365                     #Packet In Packet
366                     0x0f, 0x01, 0x08, 0x82,
367                     0xff, 0xff, 0xff, 0xff,
368                     0xde, 0xad, 0xbe, 0xef,
369                     0xba, 0xbe, 0xc0,
370                     
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,
378                     ]);
379         elif(sys.argv[1]=="txpipscapy"):
380             # NB: Requires Scapy with dot15d4.py layer. (rmspeers)
381             try:
382                 from scapy.all import Dot15d4, Dot15d4FCS, Dot15d4Data, Raw
383                 import struct
384             except ImportError:
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
389             # Make inner packet
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)
403
404 if(sys.argv[1]=="peek"):
405     start=0x0000;
406     if(len(sys.argv)>2):
407         start=int(sys.argv[2],16);
408     stop=start;
409     if(len(sys.argv)>3):
410         stop=int(sys.argv[3],16);
411     print "Peeking from %04x to %04x." % (start,stop);
412     while start<=stop:
413         print "%04x: 0x%04x" % (start,client.peek(start));
414         start=start+1;
415 if(sys.argv[1]=="poke"):
416     start=0x0000;
417     val=0x00;
418     if(len(sys.argv)>2):
419         start=int(sys.argv[2],16);
420     if(len(sys.argv)>3):
421         val=int(sys.argv[3],16);
422     print "Poking r%02x to become 0x%04x." % (start,val);
423     
424     client.poke(start,val);
425