9c6b09cc8b09e6019c9a0f9b73bdcea6008a0d17
[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_RX_FLUSH:
265     //Flush the buffer.
266     CLRSS;
267     ccspitrans8(CCSPI_SFLUSHRX);
268     SETSS;
269
270     txdata(app,verb,0);
271     break;
272
273   case CCSPI_REFLEX:
274     ccspireflexjam(len?cmddataword[0]:0);
275     break;
276
277   case CCSPI_REFLEX_AUTOACK:
278 #if defined(FIFOP) && defined(SFD) && defined(FIFO) && defined(PLED2DIR) && defined(PLED2PIN) && defined(PLED2OUT)
279     //txdata(app, verb, 1);
280     debugstr("AutoACK");
281     char byte[4];
282     while(1) {
283         //Has there been an overflow in the RX buffer?
284         if((!FIFO)&&FIFOP){
285           //debugstr("Clearing overflow");
286           CLRSS;
287           ccspitrans8(0x08); //SFLUSHRX
288           SETSS;
289         }
290
291         //Wait until a packet is received
292         while(!SFD);
293         //Turn on LED 2 (green) as signal
294             PLED2DIR |= PLED2PIN;
295             PLED2OUT &= ~PLED2PIN;
296
297         //Put radio in TX mode
298         //Note: Not doing this slows down jamming, so can't jam short packets.
299         //      However, if we do this, it seems to mess up our RXFIFO ability.
300         //CLRSS;
301         //ccspitrans8(0x04);
302         //SETSS;
303         //Load the jamming packet
304         CLRSS;
305         ccspitrans8(CCSPI_TXFIFO);
306         char pkt[7] = {0x07, 0x01, 0x08, 0xff, 0xff, 0xff, 0xff};
307         for(i=0;i<pkt[0];i++)
308           ccspitrans8(pkt[i]);
309         SETSS;
310         //Transmit the jamming packet
311         CLRSS;
312         ccspitrans8(0x04);  //STXON
313         SETSS;
314         msdelay(200);       //Instead of examining SFD line status
315         //Flush TX buffer.
316         CLRSS;
317         ccspitrans8(0x09);  //SFLUSHTX
318         SETSS;
319
320         //Get the orignally received packet, up to the seqnum field.
321         CLRSS;
322         ccspitrans8(CCSPI_RXFIFO | 0x40);
323         for(i=0;i<4;i++)
324             cmddata[i]=ccspitrans8(0xde);
325         SETSS;
326         //Flush RX buffer.
327         CLRSS;
328         ccspitrans8(0x08); //SFLUSHRX
329         SETSS;
330         //Send the sequence number of the jammed packet back to the client
331         //itoa(cmddata[3], byte, 16);
332         //debugstr(byte);
333         //txdata(app,verb,cmddata[3]);
334
335         //TODO turn on AUTOCRC for it to apply to the TX???
336         //     this may overcome issues of bad crc / length issues?
337         //mdmctrl0 (0x11) register set bit 5 to true.
338
339         //Create the forged ACK packet
340         cmddata[0] = 6;     //length of ack frame plus length
341         cmddata[1] = 0x02;  //first byte of FCF
342         cmddata[2] = 0x00;  //second byte of FCF
343         //[3] is already filled with the sequence number
344         int crc = 0;
345         for(i=1;i<4;i++) {
346             int c = cmddata[i];
347             int q = (crc ^ c) & 15;             //Do low-order 4 bits
348             crc = (crc / 16) ^ (q * 4225);
349             q = (crc ^ (c / 16)) & 15;          //And high 4 bits
350             crc = (crc / 16) ^ (q * 4225);
351         }
352         cmddata[4] = crc & 0xFF;
353         cmddata[5] = (crc >> 8) & 0xFF;
354
355         for(i=0;i<cmddata[0];i++) {
356             itoa(cmddata[i], byte, 16);
357             debugstr(byte);
358         }
359         //Load the forged ACK packet
360         CLRSS;
361         ccspitrans8(CCSPI_TXFIFO);
362         for(i=0;i<cmddata[0];i++)
363           ccspitrans8(cmddata[i]);
364         SETSS;
365         //Transmit the forged ACK packet
366         while(SFD);
367         CLRSS;
368         ccspitrans8(0x04);  //STXON
369         SETSS;
370         msdelay(200);       //TODO try doing this based on SFD line status instead
371         //Flush TX buffer
372         CLRSS;
373         ccspitrans8(0x09);  //SFLUSHTX
374         SETSS;
375
376         //TODO disable AUTOCRC here again to go back to promiscous mode
377
378         //Turn off LED 2 (green) as signal
379         PLED2DIR |= PLED2PIN;
380         PLED2OUT |= PLED2PIN;
381     }
382     //TODO the firmware stops staying in this mode after a while, and stops jamming... need to find a fix.
383 #else
384     debugstr("Can't reflexively jam without SFD, FIFO, FIFOP, and P2LEDx definitions - try using telosb platform.");
385     txdata(app,NOK,0);
386 #endif
387     break;
388
389   case CCSPI_TX_FLUSH:
390     //Flush the buffer.
391     CLRSS;
392     ccspitrans8(CCSPI_SFLUSHTX);
393     SETSS;
394
395     txdata(app,verb,0);
396     break;
397   case CCSPI_TX:
398 #ifdef FIFOP
399
400     //Wait for last packet to TX.
401     //while(ccspi_status()&BIT3);
402     
403     //Flush TX buffer.
404     CLRSS;
405     ccspitrans8(0x09); //SFLUSHTX
406     SETSS;
407     
408
409     //Load the packet.
410     CLRSS;
411     ccspitrans8(CCSPI_TXFIFO);
412     for(i=0;i<cmddata[0];i++)
413       ccspitrans8(cmddata[i]);
414     SETSS;
415
416     //Transmit the packet.
417     CLRSS;
418     ccspitrans8(0x04); //STXON
419     SETSS;
420
421     //Wait for the pulse on SFD, after which the packet has been sent.
422     while(!SFD);
423     while(SFD);
424     
425     txdata(app,verb,0);
426 #else
427     debugstr("Can't TX a packet with SFD and FIFOP definitions.");
428     txdata(app,NOK,0);
429 #endif
430     break;
431   default:
432     debugstr("Not yet supported in CCSPI");
433     txdata(app,verb,0);
434     break;
435   }
436
437 }