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