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