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