I think this will add support for decryption of incoming packets, but I might be...
[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
158
159 //! Writes a register
160 u8 ccspi_regwrite(u8 reg, const u8 *buf, int len){
161   CLRSS;
162
163   reg=ccspitrans8(reg);
164   while(len--)
165     ccspitrans8(*buf++);
166
167   SETSS;
168   return reg;//status
169 }
170 //! Reads a register
171 u8 ccspi_regread(u8 reg, u8 *buf, int len){
172   CLRSS;
173
174   reg=ccspitrans8(reg);
175   while(len--)
176     *buf++=ccspitrans8(0);
177
178   SETSS;
179   return reg;//status
180 }
181
182 //! Handles a Chipcon SPI command.
183 void ccspi_handle_fn( uint8_t const app,
184                       uint8_t const verb,
185                       uint32_t const len){
186   unsigned long i;
187   u8 j;
188
189   //debugstr("Chipcon SPI handler.");
190
191   switch(verb){
192   case PEEK:
193     cmddata[0]|=0x40; //Set the read bit.
194     //DO NOT BREAK HERE.
195   case READ:
196   case WRITE:
197   case POKE:
198     CLRSS; //Drop !SS to begin transaction.
199     j=cmddata[0];//Backup address.
200     for(i=0;i<len;i++)
201       cmddata[i]=ccspitrans8(cmddata[i]);
202     SETSS;  //Raise !SS to end transaction.
203     cmddata[0]=j&~0x40;//Restore address.
204     txdata(app,verb,len);
205     break;
206   case SETUP:
207     ccspisetup();
208     txdata(app,verb,0);
209     break;
210   case CCSPI_RX:
211 #ifdef FIFOP
212     //Has there been an overflow?
213     if((!FIFO)&&FIFOP){
214       debugstr("Clearing overflow");
215       CLRSS;
216       ccspitrans8(0x08); //SFLUSHRX
217       SETSS;
218       txdata(app,verb,0); //no packet
219       return;
220     }
221
222     //Is there a packet?
223     if(FIFOP&&FIFO){
224       //Wait for completion.
225       while(SFD);
226       
227       //Get the packet.
228       CLRSS;
229       ccspitrans8(CCSPI_RXFIFO | 0x40);
230       //ccspitrans8(0x3F|0x40);
231       cmddata[0]=0x20; //to be replaced with length
232       
233       
234       /* This reads too far on some CC2420 revisions, but on others it
235          works fine.  It probably has to do with whether FIFO drops
236          before or after the SPI clocking.
237          
238          A software fix is to reset the CC2420 between packets.  This
239          works, but a better solution is desired.
240       */
241       for(i=0;i<cmddata[0]+1;i++)
242       //for(i=0;FIFO && i<0x80;i++)
243         cmddata[i]=ccspitrans8(0x00);
244       SETSS;
245
246       /* We used to flush the RX buffer after receive. No longer.
247       CLRSS;
248       ccspitrans8(0x08); //SFLUSHRX
249       SETSS;
250       */
251       
252       //Only should transmit a packet if the length is legal.
253       if(cmddata[0]&0x80) i=0;
254       txdata(app,verb,i);
255     }else{
256       //No packet.
257       txdata(app,verb,0);
258     }
259 #else
260     debugstr("Can't RX a packet with SFD and FIFOP definitions.");
261     txdata(app,NOK,0);
262 #endif
263     break;
264   case CCSPI_RXDEC:
265 #ifdef FIFOP
266     //Has there been an overflow?
267     if((!FIFO)&&FIFOP){
268       debugstr("Clearing overflow");
269       CLRSS;
270       ccspitrans8(0x08); //SFLUSHRX
271       SETSS;
272       txdata(app,verb,0); //no packet
273       return;
274     }
275
276     //Is there a packet?
277     if(FIFOP&&FIFO){
278       //Wait for completion.
279       while(SFD);
280       
281       //Decrypt the packet.
282       CLRSS; ccspitrans8(CCSPI_SRXDEC); SETSS;
283       
284       //Wait for decryption to complete.
285       while(!FIFO);
286       
287       //Get the packet.
288       CLRSS;
289       ccspitrans8(CCSPI_RXFIFO | 0x40);
290       //ccspitrans8(0x3F|0x40);
291       cmddata[0]=0x20; //to be replaced with length
292       
293       
294       /* This reads too far on some CC2420 revisions, but on others it
295          works fine.  It probably has to do with whether FIFO drops
296          before or after the SPI clocking.
297          
298          A software fix is to reset the CC2420 between packets.  This
299          works, but a better solution is desired.
300       */
301       for(i=0;i<cmddata[0]+1;i++)
302       //for(i=0;FIFO && i<0x80;i++)
303         cmddata[i]=ccspitrans8(0x00);
304       SETSS;
305       
306       //Only should transmit a packet if the length is legal.
307       if(cmddata[0]&0x80) i=0;
308       txdata(app,verb,i);
309     }else{
310       //No packet.
311       txdata(app,verb,0);
312     }
313 #else
314     debugstr("Can't RX a packet with SFD and FIFOP definitions.");
315     txdata(app,NOK,0);
316 #endif
317     break;
318   case CCSPI_RX_FLUSH:
319     //Flush the buffer.
320     CLRSS;
321     ccspitrans8(CCSPI_SFLUSHRX);
322     SETSS;
323
324     txdata(app,verb,0);
325     break;
326
327   case CCSPI_REFLEX:
328     ccspireflexjam(len?cmddataword[0]:0);
329     break;
330
331   case CCSPI_REFLEX_AUTOACK:
332 #if defined(FIFOP) && defined(SFD) && defined(FIFO) && defined(PLED2DIR) && defined(PLED2PIN) && defined(PLED2OUT)
333     //txdata(app, verb, 1);
334     debugstr("AutoACK");
335     char byte[4];
336     while(1) {
337         //Has there been an overflow in the RX buffer?
338         if((!FIFO)&&FIFOP){
339           //debugstr("Clearing overflow");
340           CLRSS;
341           ccspitrans8(0x08); //SFLUSHRX
342           SETSS;
343         }
344
345         //Wait until a packet is received
346         while(!SFD);
347         //Turn on LED 2 (green) as signal
348             PLED2DIR |= PLED2PIN;
349             PLED2OUT &= ~PLED2PIN;
350
351         //Put radio in TX mode
352         //Note: Not doing this slows down jamming, so can't jam short packets.
353         //      However, if we do this, it seems to mess up our RXFIFO ability.
354         //CLRSS;
355         //ccspitrans8(0x04);
356         //SETSS;
357         //Load the jamming packet
358         CLRSS;
359         ccspitrans8(CCSPI_TXFIFO);
360         char pkt[7] = {0x07, 0x01, 0x08, 0xff, 0xff, 0xff, 0xff};
361         for(i=0;i<pkt[0];i++)
362           ccspitrans8(pkt[i]);
363         SETSS;
364         //Transmit the jamming packet
365         CLRSS;
366         ccspitrans8(0x04);  //STXON
367         SETSS;
368         msdelay(200);       //Instead of examining SFD line status
369         //Flush TX buffer.
370         CLRSS;
371         ccspitrans8(0x09);  //SFLUSHTX
372         SETSS;
373
374         //Get the orignally received packet, up to the seqnum field.
375         CLRSS;
376         ccspitrans8(CCSPI_RXFIFO | 0x40);
377         for(i=0;i<4;i++)
378             cmddata[i]=ccspitrans8(0xde);
379         SETSS;
380         //Flush RX buffer.
381         CLRSS;
382         ccspitrans8(0x08); //SFLUSHRX
383         SETSS;
384         //Send the sequence number of the jammed packet back to the client
385         //itoa(cmddata[3], byte, 16);
386         //debugstr(byte);
387         //txdata(app,verb,cmddata[3]);
388
389         //TODO turn on AUTOCRC for it to apply to the TX???
390         //     this may overcome issues of bad crc / length issues?
391         //mdmctrl0 (0x11) register set bit 5 to true.
392
393         //Create the forged ACK packet
394         cmddata[0] = 6;     //length of ack frame plus length
395         cmddata[1] = 0x02;  //first byte of FCF
396         cmddata[2] = 0x00;  //second byte of FCF
397         //[3] is already filled with the sequence number
398         int crc = 0;
399         for(i=1;i<4;i++) {
400             int c = cmddata[i];
401             int q = (crc ^ c) & 15;             //Do low-order 4 bits
402             crc = (crc / 16) ^ (q * 4225);
403             q = (crc ^ (c / 16)) & 15;          //And high 4 bits
404             crc = (crc / 16) ^ (q * 4225);
405         }
406         cmddata[4] = crc & 0xFF;
407         cmddata[5] = (crc >> 8) & 0xFF;
408
409         for(i=0;i<cmddata[0];i++) {
410             itoa(cmddata[i], byte, 16);
411             debugstr(byte);
412         }
413         //Load the forged ACK packet
414         CLRSS;
415         ccspitrans8(CCSPI_TXFIFO);
416         for(i=0;i<cmddata[0];i++)
417           ccspitrans8(cmddata[i]);
418         SETSS;
419         //Transmit the forged ACK packet
420         while(SFD);
421         CLRSS;
422         ccspitrans8(0x04);  //STXON
423         SETSS;
424         msdelay(200);       //TODO try doing this based on SFD line status instead
425         //Flush TX buffer
426         CLRSS;
427         ccspitrans8(0x09);  //SFLUSHTX
428         SETSS;
429
430         //TODO disable AUTOCRC here again to go back to promiscous mode
431
432         //Turn off LED 2 (green) as signal
433         PLED2DIR |= PLED2PIN;
434         PLED2OUT |= PLED2PIN;
435     }
436     //TODO the firmware stops staying in this mode after a while, and stops jamming... need to find a fix.
437 #else
438     debugstr("Can't reflexively jam without SFD, FIFO, FIFOP, and P2LEDx definitions - try using telosb platform.");
439     txdata(app,NOK,0);
440 #endif
441     break;
442
443   case CCSPI_TX_FLUSH:
444     //Flush the buffer.
445     CLRSS;
446     ccspitrans8(CCSPI_SFLUSHTX);
447     SETSS;
448
449     txdata(app,verb,0);
450     break;
451   case CCSPI_TX:
452 #ifdef FIFOP
453
454     //Wait for last packet to TX.
455     //while(ccspi_status()&BIT3);
456     
457     //Flush TX buffer.
458     CLRSS;
459     ccspitrans8(0x09); //SFLUSHTX
460     SETSS;
461     
462
463     //Load the packet.
464     CLRSS;
465     ccspitrans8(CCSPI_TXFIFO);
466     for(i=0;i<cmddata[0];i++)
467       ccspitrans8(cmddata[i]);
468     SETSS;
469
470     //Transmit the packet.
471     CLRSS;
472     ccspitrans8(0x04); //STXON
473     SETSS;
474
475     //Wait for the pulse on SFD, after which the packet has been sent.
476     while(!SFD);
477     while(SFD);
478     
479     txdata(app,verb,0);
480 #else
481     debugstr("Can't TX a packet with SFD and FIFOP definitions.");
482     txdata(app,NOK,0);
483 #endif
484     break;
485   default:
486     debugstr("Not yet supported in CCSPI");
487     txdata(app,verb,0);
488     break;
489   }
490
491 }