updated some new experiment methods. you can now fuzz on all ids randomly as well...
[goodfet] / firmware / apps / radios / ccspi.c
1 /*! \file ccspi.c
2   \author Travis Goodspeed
3   \brief Chipcon SPI Register Interface
4
5   Unfortunately, there is very little similarity between the CC2420
6   and the CC2500, to name just two of the myriad of Chipcon SPI
7   radios.  Auto-detection will be a bit difficult, but more to the
8   point, all high level functionality must be moved into the client.
9 */
10
11 //Higher level left to client application.
12
13 #include "platform.h"
14 #include "command.h"
15 #include <stdlib.h> //added for itoa
16
17 #include "ccspi.h"
18 #include "spi.h"
19
20 //! Handles a Chipcon SPI command.
21 void ccspi_handle_fn( uint8_t const app,
22                       uint8_t const verb,
23                       uint32_t const len);
24
25 // define the ccspi app's app_t
26 app_t const ccspi_app = {
27
28         /* app number */
29         CCSPI,
30
31         /* handle fn */
32         ccspi_handle_fn,
33
34         /* name */
35         "CCSPI",
36
37         /* desc */
38         "\tThe CCSPI app adds support for the Chipcon SPI register\n"
39         "\tinterface. Unfortunately, there is very little similarity\n"
40         "\tbetween the CC2420 and the CC2500, to name just two of the\n"
41         "\tmyriad of Chipcon SPI radios.  Auto-detection will be a bit\n"
42         "\tdifficult, but more to the point, all high level functionality\n"
43         "\tmust be moved into the client.\n"
44 };
45
46 //! Set up the pins for CCSPI mode.
47 void ccspisetup(){
48   SPIDIR&=~MISO;
49   SPIDIR|=MOSI+SCK;
50   DIRSS;
51   DIRCE;
52
53   //P4OUT|=BIT5; //activate CC2420 voltage regulator
54   msdelay(100);
55
56   //Reset the CC2420.
57   /*P4OUT&=~BIT6; FIXME Does the new code work on Z1 and Telosb?
58     P4OUT|=BIT6;*/ 
59   CLRCE;
60   SETCE;
61
62   //Begin a new transaction.
63   CLRSS;
64   SETSS;
65 }
66
67 //! Read and write an CCSPI byte.
68 u8 ccspitrans8(u8 byte){
69   register unsigned int bit;
70   //This function came from the CCSPI Wikipedia article.
71   //Minor alterations.
72
73   for (bit = 0; bit < 8; bit++) {
74     /* write MOSI on trailing edge of previous clock */
75     if (byte & 0x80)
76       SETMOSI;
77     else
78       CLRMOSI;
79     byte <<= 1;
80
81     SETCLK;
82
83     /* read MISO on trailing edge */
84     byte |= READMISO;
85     CLRCLK;
86   }
87
88   return byte;
89 }
90
91
92 //! Reflexively jam on the present channel.
93 void ccspireflexjam(u16 delay){
94   unsigned long i;
95   #if defined(FIFOP) && defined(SFD) && defined(FIFO) && defined(PLED2DIR) && defined(PLED2PIN) && defined(PLED2OUT)
96   
97   prep_timer();
98   debugstr("Reflex jamming until reset.");
99   debughex(delay);
100   txdata(CCSPI,CCSPI_REFLEX,1);  //Let the client continue its business.
101   while(1) {
102     //Wait until a packet is received
103     while(!SFD){
104       //Has there been an overflow in the RX buffer?
105       if((!FIFO)&&FIFOP){
106         //debugstr("Clearing RX overflow");
107         CLRSS;
108         ccspitrans8(0x08); //SFLUSHRX
109         SETSS;
110       }
111     }
112     //Turn on LED 2 (green) as signal
113     PLED2DIR |= PLED2PIN;
114     PLED2OUT &= ~PLED2PIN;
115     
116     
117     
118     //Wait a few us to send it.
119     delay_us(delay);
120
121     //Transmit the packet.
122     CLRSS;
123     ccspitrans8(0x04);
124     SETSS;
125     
126     
127     //Load the next jamming packet.
128     //Note: attempts to preload this actually slowed the jam time down from 7 to 9 bytes.
129     CLRSS;
130     ccspitrans8(CCSPI_TXFIFO);
131     char pkt[5] = {0x05, 0, 0, 0, 0};
132     //char pkt[15] = {0x0f, 0x01, 0x08, 0x82, 0xff, 0xff, 0xff, 0xff, 0xde, 0xad, 0xbe, 0xef, 0xba, 0xbe, 0xc0};
133     //char pkt[12] = {0x0c, 0x01, 0x08, 0x82, 0xff, 0xff, 0xff, 0xff, 0xde, 0xad, 0xbe, 0xef};
134     for(i=0;i<pkt[0];i++)
135       ccspitrans8(pkt[i]);
136     SETSS;
137     
138     //* I think this might be unnecessary.
139     //msdelay(100+delay);      //Instead of waiting for pulse on SFD
140     //delay_ms(1);
141     //Flush TX buffer.
142     CLRSS;
143     ccspitrans8(0x09); //SFLUSHTX
144     SETSS;
145     
146     
147     //Turn off LED 2 (green) as signal
148     PLED2DIR |= PLED2PIN;
149     PLED2OUT |= PLED2PIN;
150   }
151 #else
152   debugstr("Can't reflexively jam without SFD, FIFO, FIFOP, and P2LEDx definitions - try using telosb platform.");
153   txdata(CCSPI,NOK,0);
154 #endif
155 }
156
157 //! Writes bytes into the CC2420's RAM.  Untested.
158 void ccspi_pokeram(u8 addr, char *data, int len){
159   CLRSS;
160   //Begin with the start address.
161   ccspitrans8(0x80 | (addr & 0x7F)); 
162   ccspitrans8(((addr>>1)&0xC0) // MSBits are high bits of 9-bit address.
163                                // Read/!Write bit should be clear to write.
164               );
165   
166   //Data goes here.
167   while(len--)
168     ccspitrans8(*data++);
169   
170   SETSS;
171 }
172
173 //! Read bytes from the CC2420's RAM.  Untested.
174 void ccspi_peekram(u16 addr, u8 *data, u16 len){
175   CLRSS;
176   
177   //Begin with the start address.
178   ccspitrans8(0x80 | (addr & 0x7F));
179   ccspitrans8(((addr>>1)&0xC0) // MSBits are high bits of 9-bit address.
180               | BIT5           // Read/!Write bit should be set to read.
181               ); 
182   
183   //Data goes here.
184   while(len--)
185     *data++=ccspitrans8(0);
186   
187   SETSS;
188 }
189
190 //! Updates the Nonce's sequence number.
191 void ccspi_updaterxnonce(u32 seq){
192   
193 }
194
195 //! Writes a register
196 u8 ccspi_regwrite(u8 reg, const u8 *buf, int len){
197   CLRSS;
198
199   reg=ccspitrans8(reg);
200   while(len--)
201     ccspitrans8(*buf++);
202
203   SETSS;
204   return reg;//status
205 }
206 //! Reads a register
207 u8 ccspi_regread(u8 reg, u8 *buf, int len){
208   CLRSS;
209
210   reg=ccspitrans8(reg);
211   while(len--)
212     *buf++=ccspitrans8(0);
213
214   SETSS;
215   return reg;//status
216 }
217
218 //! Handles a Chipcon SPI command.
219 void ccspi_handle_fn( uint8_t const app,
220                       uint8_t const verb,
221                       uint32_t const len){
222   unsigned long i;
223   u8 j;
224
225   switch(verb){
226   case PEEK:
227     cmddata[0]|=0x40; //Set the read bit.
228     //DO NOT BREAK HERE.
229   case READ:
230   case WRITE:
231   case POKE:
232     CLRSS; //Drop !SS to begin transaction.
233     j=cmddata[0];//Backup address.
234     for(i=0;i<len;i++)
235       cmddata[i]=ccspitrans8(cmddata[i]);
236     SETSS;  //Raise !SS to end transaction.
237     cmddata[0]=j&~0x40;//Restore address.
238     txdata(app,verb,len);
239     break;
240   case SETUP:
241     ccspisetup();
242     txdata(app,verb,0);
243     break;
244   case CCSPI_PEEK_RAM:
245     i=cmddataword[1]; // Backup length.
246     ccspi_peekram(cmddataword[0], // First word is the address.
247                    cmddata,        // Return in the same buffer.
248                    cmddataword[1]  // Second word is the length.
249                    );
250     txdata(app,verb,i);
251     break;
252   case CCSPI_POKE_RAM:
253     ccspi_pokeram(cmddataword[0], //First word is address
254                   cmddata+2,      //Remainder of buffer is dat.
255                   len-2           //Length implied by packet length.
256                   );
257     txdata(app,verb,0);
258     break;
259   case CCSPI_REPEAT_RX:
260
261     /* CCSPI_REPEAT_RX repeatedly requests new packets, forwarding
262        them to the server without waiting for the next request.  This
263        allows for sniffing of packets that would otherwise overflow
264        the buffer.
265     */
266
267     //debugstr("Looping CCSPI_RX.");
268     
269     //Loop forever in RX mode.
270     while(1){
271       ccspi_handle_fn(app,CCSPI_RX,0);
272     }
273     break;
274   case CCSPI_RX:
275 #ifdef FIFOP
276     //Has there been an overflow?
277     
278     if((!FIFO)&&FIFOP){
279       debugstr("Clearing overflow");
280       CLRSS;
281       ccspitrans8(0x08); //SFLUSHRX
282       ccspitrans8(0x08); //SFLUSHRX
283       SETSS;
284       txdata(app,verb,0); //no packet
285       return;
286     }
287         
288     /* Uncomment this to wait around a bit for the packet.
289        Might reduce dropped packet count.
290     i=1000; //Number of tries.
291     while(!(FIFOP&&FIFO) && i--);
292     */
293     
294     //Is there a packet?
295     if (FIFOP && FIFO){
296       //Wait for completion.
297       while(SFD);
298       
299       //Get the packet.
300       CLRSS;
301       ccspitrans8(CCSPI_RXFIFO | 0x40);
302       //ccspitrans8(0x3F|0x40);
303       cmddata[0]=0x20; //to be replaced with length
304       
305       
306       /* This reads too far on some CC2420 revisions, but on others it
307          works fine.  It probably has to do with whether FIFO drops
308          before or after the SPI clocking.
309          
310          A software fix is to reset the CC2420 between packets.  This
311          works, but a better solution is desired.
312       */
313       //for(i=0;i<cmddata[0]+1;i++)
314       for(i=0;FIFO && i<0x80;i++)
315         cmddata[i]=ccspitrans8(0x00);
316       SETSS;
317
318       /* We used to flush the RX buffer after receive. No longer.
319       CLRSS;
320       ccspitrans8(0x08); //SFLUSHRX
321       SETSS;
322       */
323       
324       //Only transmit a packet if the length is legal.
325       if(cmddata[0]&0x80 || cmddata[0]==0) i=0;
326       txdata(app,verb,i);
327     }else{
328       
329       //No packet.
330       txdata(app,verb,0);
331     }
332 #else
333     debugstr("Can't RX a packet with SFD and FIFOP definitions.");
334     txdata(app,NOK,0);
335 #endif
336     break;
337   case CCSPI_RXDEC:
338 #ifdef FIFOP
339     //Has there been an overflow?
340     if((!FIFO)&&FIFOP){
341       debugstr("Clearing overflow");
342       CLRSS;
343       ccspitrans8(0x08); //SFLUSHRX
344       SETSS;
345       txdata(app,verb,0); //no packet
346       return;
347     }
348
349     //Is there a packet?
350     if(FIFOP&&FIFO){
351       //Wait for completion.
352       while(SFD);
353       
354       CLRSS;
355       ccspitrans8(CCSPI_RXFIFO | 0x40);
356       // Grab the length.
357       cmddata[0]=ccspitrans8(0x00);
358       
359       //Read the header first.
360       for(i=1;i<cmddata[0]+1 && i<0x11;i++)
361         cmddata[i]=ccspitrans8(0x00);
362       SETSS;
363       
364       //Is the frame encrypted?
365       if(cmddata[1]&BIT3){
366         //Copy the sequence number to the Nonce.
367         
368         
369         //Decrypt the rest of the packet.
370         CLRSS; ccspitrans8(CCSPI_SRXDEC); SETSS;
371         
372         //Wait for decryption to complete.
373         while(!FIFO);
374       
375       }
376       
377       
378       //Get the packet, which is now decrypted in position.
379       CLRSS;
380       ccspitrans8(CCSPI_RXFIFO | 0x40);
381       //ccspitrans8(0x3F|0x40);
382       
383       
384       /* This reads too far on some CC2420 revisions, but on others it
385          works fine.  It probably has to do with whether FIFO drops
386          before or after the SPI clocking.
387          
388          A software fix is to reset the CC2420 between packets.  This
389          works, but a better solution is desired.
390       */
391       for(;i<cmddata[0]+1;i++)
392         cmddata[i]=ccspitrans8(0x00);
393       SETSS;
394       
395       //Only forward a packet if the length is legal.
396       if(cmddata[0]&0x80) i=0;
397       txdata(app,verb,i);
398     }else{
399       //No packet.
400       txdata(app,verb,0);
401     }
402 #else
403     debugstr("Can't RX a packet with SFD and FIFOP definitions.");
404     txdata(app,NOK,0);
405 #endif
406     break;
407   case CCSPI_RX_FLUSH:
408     //Flush the buffer.
409     CLRSS;
410     ccspitrans8(CCSPI_SFLUSHRX);
411     SETSS;
412
413     txdata(app,verb,0);
414     break;
415
416   case CCSPI_REFLEX:
417     ccspireflexjam(len?cmddataword[0]:0);
418     break;
419
420   case CCSPI_REFLEX_AUTOACK:
421 #if defined(FIFOP) && defined(SFD) && defined(FIFO) && defined(PLED2DIR) && defined(PLED2PIN) && defined(PLED2OUT)
422     //txdata(app, verb, 1);
423     debugstr("AutoACK");
424     char byte[4];
425     while(1) {
426         //Has there been an overflow in the RX buffer?
427         if((!FIFO)&&FIFOP){
428           //debugstr("Clearing overflow");
429           CLRSS;
430           ccspitrans8(0x08); //SFLUSHRX
431           SETSS;
432         }
433
434         //Wait until a packet is received
435         while(!SFD);
436         //Turn on LED 2 (green) as signal
437             PLED2DIR |= PLED2PIN;
438             PLED2OUT &= ~PLED2PIN;
439
440         //Put radio in TX mode
441         //Note: Not doing this slows down jamming, so can't jam short packets.
442         //      However, if we do this, it seems to mess up our RXFIFO ability.
443         //CLRSS;
444         //ccspitrans8(0x04);
445         //SETSS;
446         //Load the jamming packet
447         CLRSS;
448         ccspitrans8(CCSPI_TXFIFO);
449         char pkt[7] = {0x07, 0x01, 0x08, 0xff, 0xff, 0xff, 0xff};
450         for(i=0;i<pkt[0];i++)
451           ccspitrans8(pkt[i]);
452         SETSS;
453         //Transmit the jamming packet
454         CLRSS;
455         ccspitrans8(0x04);  //STXON
456         SETSS;
457         msdelay(200);       //Instead of examining SFD line status
458         //Flush TX buffer.
459         CLRSS;
460         ccspitrans8(0x09);  //SFLUSHTX
461         SETSS;
462
463         //Get the orignally received packet, up to the seqnum field.
464         CLRSS;
465         ccspitrans8(CCSPI_RXFIFO | 0x40);
466         for(i=0;i<4;i++)
467             cmddata[i]=ccspitrans8(0xde);
468         SETSS;
469         //Flush RX buffer.
470         CLRSS;
471         ccspitrans8(0x08); //SFLUSHRX
472         SETSS;
473         //Send the sequence number of the jammed packet back to the client
474         //itoa(cmddata[3], byte, 16);
475         //debugstr(byte);
476         //txdata(app,verb,cmddata[3]);
477
478         //TODO turn on AUTOCRC for it to apply to the TX???
479         //     this may overcome issues of bad crc / length issues?
480         //mdmctrl0 (0x11) register set bit 5 to true.
481
482         //Create the forged ACK packet
483         cmddata[0] = 6;     //length of ack frame plus length
484         cmddata[1] = 0x02;  //first byte of FCF
485         cmddata[2] = 0x00;  //second byte of FCF
486         //[3] is already filled with the sequence number
487         int crc = 0;
488         for(i=1;i<4;i++) {
489             int c = cmddata[i];
490             int q = (crc ^ c) & 15;             //Do low-order 4 bits
491             crc = (crc / 16) ^ (q * 4225);
492             q = (crc ^ (c / 16)) & 15;          //And high 4 bits
493             crc = (crc / 16) ^ (q * 4225);
494         }
495         cmddata[4] = crc & 0xFF;
496         cmddata[5] = (crc >> 8) & 0xFF;
497
498         for(i=0;i<cmddata[0];i++) {
499             itoa(cmddata[i], byte, 16);
500             debugstr(byte);
501         }
502         //Load the forged ACK packet
503         CLRSS;
504         ccspitrans8(CCSPI_TXFIFO);
505         for(i=0;i<cmddata[0];i++)
506           ccspitrans8(cmddata[i]);
507         SETSS;
508         //Transmit the forged ACK packet
509         while(SFD);
510         CLRSS;
511         ccspitrans8(0x04);  //STXON
512         SETSS;
513         msdelay(200);       //TODO try doing this based on SFD line status instead
514         //Flush TX buffer
515         CLRSS;
516         ccspitrans8(0x09);  //SFLUSHTX
517         SETSS;
518
519         //TODO disable AUTOCRC here again to go back to promiscous mode
520
521         //Turn off LED 2 (green) as signal
522         PLED2DIR |= PLED2PIN;
523         PLED2OUT |= PLED2PIN;
524     }
525     //TODO the firmware stops staying in this mode after a while, and stops jamming... need to find a fix.
526 #else
527     debugstr("Can't reflexively jam without SFD, FIFO, FIFOP, and P2LEDx definitions - try using telosb platform.");
528     txdata(app,NOK,0);
529 #endif
530     break;
531
532   case CCSPI_TX_FLUSH:
533     //Flush the buffer.
534     CLRSS;
535     ccspitrans8(CCSPI_SFLUSHTX);
536     SETSS;
537
538     txdata(app,verb,0);
539     break;
540   case CCSPI_TX:
541 #ifdef FIFOP
542
543     //Wait for last packet to TX.
544     //while(ccspi_status()&BIT3);
545     
546     //Flush TX buffer.
547     CLRSS;
548     ccspitrans8(0x09); //SFLUSHTX
549     SETSS;
550     
551
552     //Load the packet.
553     CLRSS;
554     ccspitrans8(CCSPI_TXFIFO);
555     for(i=0;i<cmddata[0];i++)
556       ccspitrans8(cmddata[i]);
557     SETSS;
558
559     //Transmit the packet.
560     CLRSS;
561     ccspitrans8(0x04); //STXON
562     SETSS;
563
564     //Wait for the pulse on SFD, after which the packet has been sent.
565     while(!SFD);
566     while(SFD);
567     
568     txdata(app,verb,0);
569 #else
570     debugstr("Can't TX a packet with SFD and FIFOP definitions.");
571     txdata(app,NOK,0);
572 #endif
573     break;
574   default:
575     debugstr("Not yet supported in CCSPI");
576     txdata(app,verb,0);
577     break;
578   }
579
580 }