a124b536cea22c4358dc1f2bd1fd63d88548da25
[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   //debugstr("Chipcon SPI handler.");
226
227   switch(verb){
228   case PEEK:
229     cmddata[0]|=0x40; //Set the read bit.
230     //DO NOT BREAK HERE.
231   case READ:
232   case WRITE:
233   case POKE:
234     CLRSS; //Drop !SS to begin transaction.
235     j=cmddata[0];//Backup address.
236     for(i=0;i<len;i++)
237       cmddata[i]=ccspitrans8(cmddata[i]);
238     SETSS;  //Raise !SS to end transaction.
239     cmddata[0]=j&~0x40;//Restore address.
240     txdata(app,verb,len);
241     break;
242   case SETUP:
243     ccspisetup();
244     txdata(app,verb,0);
245     break;
246   case CCSPI_PEEK_RAM:
247     i=cmddataword[1]; // Backup length.
248     ccspi_peekram(cmddataword[0], // First word is the address.
249                    cmddata,        // Return in the same buffer.
250                    cmddataword[1]  // Second word is the length.
251                    );
252     txdata(app,verb,i);
253     break;
254   case CCSPI_POKE_RAM:
255     ccspi_pokeram(cmddataword[0], //First word is address
256                   cmddata+2,      //Remainder of buffer is dat.
257                   len-2           //Length implied by packet length.
258                   );
259     txdata(app,verb,0);
260     break;
261   case CCSPI_RX:
262 #ifdef FIFOP
263     //Has there been an overflow?
264     if((!FIFO)&&FIFOP){
265       debugstr("Clearing overflow");
266       CLRSS;
267       ccspitrans8(0x08); //SFLUSHRX
268       SETSS;
269       txdata(app,verb,0); //no packet
270       return;
271     }
272
273     //Is there a packet?
274     if(FIFOP&&FIFO){
275       //Wait for completion.
276       while(SFD);
277       
278       //Get the packet.
279       CLRSS;
280       ccspitrans8(CCSPI_RXFIFO | 0x40);
281       //ccspitrans8(0x3F|0x40);
282       cmddata[0]=0x20; //to be replaced with length
283       
284       
285       /* This reads too far on some CC2420 revisions, but on others it
286          works fine.  It probably has to do with whether FIFO drops
287          before or after the SPI clocking.
288          
289          A software fix is to reset the CC2420 between packets.  This
290          works, but a better solution is desired.
291       */
292       for(i=0;i<cmddata[0]+1;i++)
293       //for(i=0;FIFO && i<0x80;i++)
294         cmddata[i]=ccspitrans8(0x00);
295       SETSS;
296
297       /* We used to flush the RX buffer after receive. No longer.
298       CLRSS;
299       ccspitrans8(0x08); //SFLUSHRX
300       SETSS;
301       */
302       
303       //Only transmit a packet if the length is legal.
304       if(cmddata[0]&0x80) i=0;
305       txdata(app,verb,i);
306     }else{
307       //No packet.
308       txdata(app,verb,0);
309     }
310 #else
311     debugstr("Can't RX a packet with SFD and FIFOP definitions.");
312     txdata(app,NOK,0);
313 #endif
314     break;
315   case CCSPI_RXDEC:
316 #ifdef FIFOP
317     //Has there been an overflow?
318     if((!FIFO)&&FIFOP){
319       debugstr("Clearing overflow");
320       CLRSS;
321       ccspitrans8(0x08); //SFLUSHRX
322       SETSS;
323       txdata(app,verb,0); //no packet
324       return;
325     }
326
327     //Is there a packet?
328     if(FIFOP&&FIFO){
329       //Wait for completion.
330       while(SFD);
331       
332       CLRSS;
333       ccspitrans8(CCSPI_RXFIFO | 0x40);
334       // Grab the length.
335       cmddata[0]=ccspitrans8(0x00);
336       
337       //Read the header first.
338       for(i=1;i<cmddata[0]+1 && i<0x11;i++)
339         cmddata[i]=ccspitrans8(0x00);
340       SETSS;
341       
342       //Is the frame encrypted?
343       if(cmddata[1]&BIT3){
344         //Copy the sequence number to the Nonce.
345         
346         
347         //Decrypt the rest of the packet.
348         CLRSS; ccspitrans8(CCSPI_SRXDEC); SETSS;
349         
350         //Wait for decryption to complete.
351         while(!FIFO);
352       
353       }
354       
355       
356       //Get the packet, which is now decrypted in position.
357       CLRSS;
358       ccspitrans8(CCSPI_RXFIFO | 0x40);
359       //ccspitrans8(0x3F|0x40);
360       
361       
362       /* This reads too far on some CC2420 revisions, but on others it
363          works fine.  It probably has to do with whether FIFO drops
364          before or after the SPI clocking.
365          
366          A software fix is to reset the CC2420 between packets.  This
367          works, but a better solution is desired.
368       */
369       for(;i<cmddata[0]+1;i++)
370         cmddata[i]=ccspitrans8(0x00);
371       SETSS;
372       
373       //Only forward a packet if the length is legal.
374       if(cmddata[0]&0x80) i=0;
375       txdata(app,verb,i);
376     }else{
377       //No packet.
378       txdata(app,verb,0);
379     }
380 #else
381     debugstr("Can't RX a packet with SFD and FIFOP definitions.");
382     txdata(app,NOK,0);
383 #endif
384     break;
385   case CCSPI_RX_FLUSH:
386     //Flush the buffer.
387     CLRSS;
388     ccspitrans8(CCSPI_SFLUSHRX);
389     SETSS;
390
391     txdata(app,verb,0);
392     break;
393
394   case CCSPI_REFLEX:
395     ccspireflexjam(len?cmddataword[0]:0);
396     break;
397
398   case CCSPI_REFLEX_AUTOACK:
399 #if defined(FIFOP) && defined(SFD) && defined(FIFO) && defined(PLED2DIR) && defined(PLED2PIN) && defined(PLED2OUT)
400     //txdata(app, verb, 1);
401     debugstr("AutoACK");
402     char byte[4];
403     while(1) {
404         //Has there been an overflow in the RX buffer?
405         if((!FIFO)&&FIFOP){
406           //debugstr("Clearing overflow");
407           CLRSS;
408           ccspitrans8(0x08); //SFLUSHRX
409           SETSS;
410         }
411
412         //Wait until a packet is received
413         while(!SFD);
414         //Turn on LED 2 (green) as signal
415             PLED2DIR |= PLED2PIN;
416             PLED2OUT &= ~PLED2PIN;
417
418         //Put radio in TX mode
419         //Note: Not doing this slows down jamming, so can't jam short packets.
420         //      However, if we do this, it seems to mess up our RXFIFO ability.
421         //CLRSS;
422         //ccspitrans8(0x04);
423         //SETSS;
424         //Load the jamming packet
425         CLRSS;
426         ccspitrans8(CCSPI_TXFIFO);
427         char pkt[7] = {0x07, 0x01, 0x08, 0xff, 0xff, 0xff, 0xff};
428         for(i=0;i<pkt[0];i++)
429           ccspitrans8(pkt[i]);
430         SETSS;
431         //Transmit the jamming packet
432         CLRSS;
433         ccspitrans8(0x04);  //STXON
434         SETSS;
435         msdelay(200);       //Instead of examining SFD line status
436         //Flush TX buffer.
437         CLRSS;
438         ccspitrans8(0x09);  //SFLUSHTX
439         SETSS;
440
441         //Get the orignally received packet, up to the seqnum field.
442         CLRSS;
443         ccspitrans8(CCSPI_RXFIFO | 0x40);
444         for(i=0;i<4;i++)
445             cmddata[i]=ccspitrans8(0xde);
446         SETSS;
447         //Flush RX buffer.
448         CLRSS;
449         ccspitrans8(0x08); //SFLUSHRX
450         SETSS;
451         //Send the sequence number of the jammed packet back to the client
452         //itoa(cmddata[3], byte, 16);
453         //debugstr(byte);
454         //txdata(app,verb,cmddata[3]);
455
456         //TODO turn on AUTOCRC for it to apply to the TX???
457         //     this may overcome issues of bad crc / length issues?
458         //mdmctrl0 (0x11) register set bit 5 to true.
459
460         //Create the forged ACK packet
461         cmddata[0] = 6;     //length of ack frame plus length
462         cmddata[1] = 0x02;  //first byte of FCF
463         cmddata[2] = 0x00;  //second byte of FCF
464         //[3] is already filled with the sequence number
465         int crc = 0;
466         for(i=1;i<4;i++) {
467             int c = cmddata[i];
468             int q = (crc ^ c) & 15;             //Do low-order 4 bits
469             crc = (crc / 16) ^ (q * 4225);
470             q = (crc ^ (c / 16)) & 15;          //And high 4 bits
471             crc = (crc / 16) ^ (q * 4225);
472         }
473         cmddata[4] = crc & 0xFF;
474         cmddata[5] = (crc >> 8) & 0xFF;
475
476         for(i=0;i<cmddata[0];i++) {
477             itoa(cmddata[i], byte, 16);
478             debugstr(byte);
479         }
480         //Load the forged ACK packet
481         CLRSS;
482         ccspitrans8(CCSPI_TXFIFO);
483         for(i=0;i<cmddata[0];i++)
484           ccspitrans8(cmddata[i]);
485         SETSS;
486         //Transmit the forged ACK packet
487         while(SFD);
488         CLRSS;
489         ccspitrans8(0x04);  //STXON
490         SETSS;
491         msdelay(200);       //TODO try doing this based on SFD line status instead
492         //Flush TX buffer
493         CLRSS;
494         ccspitrans8(0x09);  //SFLUSHTX
495         SETSS;
496
497         //TODO disable AUTOCRC here again to go back to promiscous mode
498
499         //Turn off LED 2 (green) as signal
500         PLED2DIR |= PLED2PIN;
501         PLED2OUT |= PLED2PIN;
502     }
503     //TODO the firmware stops staying in this mode after a while, and stops jamming... need to find a fix.
504 #else
505     debugstr("Can't reflexively jam without SFD, FIFO, FIFOP, and P2LEDx definitions - try using telosb platform.");
506     txdata(app,NOK,0);
507 #endif
508     break;
509
510   case CCSPI_TX_FLUSH:
511     //Flush the buffer.
512     CLRSS;
513     ccspitrans8(CCSPI_SFLUSHTX);
514     SETSS;
515
516     txdata(app,verb,0);
517     break;
518   case CCSPI_TX:
519 #ifdef FIFOP
520
521     //Wait for last packet to TX.
522     //while(ccspi_status()&BIT3);
523     
524     //Flush TX buffer.
525     CLRSS;
526     ccspitrans8(0x09); //SFLUSHTX
527     SETSS;
528     
529
530     //Load the packet.
531     CLRSS;
532     ccspitrans8(CCSPI_TXFIFO);
533     for(i=0;i<cmddata[0];i++)
534       ccspitrans8(cmddata[i]);
535     SETSS;
536
537     //Transmit the packet.
538     CLRSS;
539     ccspitrans8(0x04); //STXON
540     SETSS;
541
542     //Wait for the pulse on SFD, after which the packet has been sent.
543     while(!SFD);
544     while(SFD);
545     
546     txdata(app,verb,0);
547 #else
548     debugstr("Can't TX a packet with SFD and FIFOP definitions.");
549     txdata(app,NOK,0);
550 #endif
551     break;
552   default:
553     debugstr("Not yet supported in CCSPI");
554     txdata(app,verb,0);
555     break;
556   }
557
558 }