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