Reflex jamming in CCSPI now has a selectable backoff,
[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;
58   P4OUT|=BIT6;
59
60   //Begin a new transaction.
61   CLRSS;
62   SETSS;
63 }
64
65 //! Read and write an CCSPI byte.
66 u8 ccspitrans8(u8 byte){
67   register unsigned int bit;
68   //This function came from the CCSPI Wikipedia article.
69   //Minor alterations.
70
71   for (bit = 0; bit < 8; bit++) {
72     /* write MOSI on trailing edge of previous clock */
73     if (byte & 0x80)
74       SETMOSI;
75     else
76       CLRMOSI;
77     byte <<= 1;
78
79     SETCLK;
80
81     /* read MISO on trailing edge */
82     byte |= READMISO;
83     CLRCLK;
84   }
85
86   return byte;
87 }
88
89
90 //! Reflexively jam on the present channel.
91 void ccspireflexjam(u16 delay){
92   unsigned long i;
93   #if defined(FIFOP) && defined(SFD) && defined(FIFO) && defined(PLED2DIR) && defined(PLED2PIN) && defined(PLED2OUT)
94   
95   prep_timer();
96   debugstr("Reflex jamming until reset.");
97   debughex(delay);
98   txdata(CCSPI,CCSPI_REFLEX,1);  //Let the client continue its business.
99   while(1) {
100     //Wait until a packet is received
101     while(!SFD){
102       //Has there been an overflow in the RX buffer?
103       if((!FIFO)&&FIFOP){
104         debugstr("Clearing RX overflow");
105         CLRSS;
106         ccspitrans8(0x08); //SFLUSHRX
107         SETSS;
108       }
109     }
110     //Turn on LED 2 (green) as signal
111     PLED2DIR |= PLED2PIN;
112     PLED2OUT &= ~PLED2PIN;
113     
114     
115     
116     //Wait a few us to send it.
117     delay_us(delay);
118
119     //Put radio in TX mode
120     CLRSS;
121     ccspitrans8(0x04);
122     SETSS;
123     
124     
125     //Load the jamming packet.
126     //Note: attempts to preload this actually slowed the jam time down from 7 to 9 bytes.
127     CLRSS;
128     ccspitrans8(CCSPI_TXFIFO);
129     char pkt[15] = {0x0f, 0x01, 0x08, 0x82, 0xff, 0xff, 0xff, 0xff, 0xde, 0xad, 0xbe, 0xef, 0xba, 0xbe, 0xc0};
130     //char pkt[12] = {0x0c, 0x01, 0x08, 0x82, 0xff, 0xff, 0xff, 0xff, 0xde, 0xad, 0xbe, 0xef};
131     for(i=0;i<pkt[0];i++)
132       ccspitrans8(pkt[i]);
133     SETSS;
134     
135     
136     //Transmit the packet.
137     CLRSS;
138     ccspitrans8(0x04); //STXON
139     SETSS;
140     
141     //msdelay(100+delay);      //Instead of waiting for pulse on SFD
142     delay_ms(1);
143     //Flush TX buffer.
144     CLRSS;
145     ccspitrans8(0x09); //SFLUSHTX
146     SETSS;
147
148     //Turn off LED 2 (green) as signal
149     PLED2DIR |= PLED2PIN;
150     PLED2OUT |= PLED2PIN;
151   }
152 #else
153   debugstr("Can't reflexively jam without SFD, FIFO, FIFOP, and P2LEDx definitions - try using telosb platform.");
154   txdata(app,NOK,0);
155 #endif
156 }
157
158
159
160 //! Writes a register
161 u8 ccspi_regwrite(u8 reg, const u8 *buf, int len){
162   CLRSS;
163
164   reg=ccspitrans8(reg);
165   while(len--)
166     ccspitrans8(*buf++);
167
168   SETSS;
169   return reg;//status
170 }
171 //! Reads a register
172 u8 ccspi_regread(u8 reg, u8 *buf, int len){
173   CLRSS;
174
175   reg=ccspitrans8(reg);
176   while(len--)
177     *buf++=ccspitrans8(0);
178
179   SETSS;
180   return reg;//status
181 }
182
183 //! Handles a Chipcon SPI command.
184 void ccspi_handle_fn( uint8_t const app,
185                       uint8_t const verb,
186                       uint32_t const len){
187   unsigned long i;
188   u8 j;
189
190   //debugstr("Chipcon SPI handler.");
191
192   switch(verb){
193   case PEEK:
194     cmddata[0]|=0x40; //Set the read bit.
195     //DO NOT BREAK HERE.
196   case READ:
197   case WRITE:
198   case POKE:
199     CLRSS; //Drop !SS to begin transaction.
200     j=cmddata[0];//Backup address.
201     for(i=0;i<len;i++)
202       cmddata[i]=ccspitrans8(cmddata[i]);
203     SETSS;  //Raise !SS to end transaction.
204     cmddata[0]=j&~0x40;//Restore address.
205     txdata(app,verb,len);
206     break;
207   case SETUP:
208     ccspisetup();
209     txdata(app,verb,0);
210     break;
211   case CCSPI_RX:
212 #ifdef FIFOP
213     //Has there been an overflow?
214     if((!FIFO)&&FIFOP){
215       //debugstr("Clearing overflow");
216       CLRSS;
217       ccspitrans8(0x08); //SFLUSHRX
218       SETSS;
219     }
220
221     //Is there a packet?
222     if(FIFOP&&FIFO){
223       //Wait for completion.
224       while(SFD);
225       
226       //Get the packet.
227       CLRSS;
228       ccspitrans8(CCSPI_RXFIFO | 0x40);
229       //ccspitrans8(0x3F|0x40);
230       cmddata[0]=0xff; //to be replaced with length
231       for(i=0;i<cmddata[0]+2;i++)
232         cmddata[i]=ccspitrans8(0xde);
233       SETSS;
234
235       //Flush buffer.
236       CLRSS;
237       ccspitrans8(0x08); //SFLUSHRX
238       SETSS;
239       
240       
241       //Only should transmit length of one more than the reported
242       // length of the frame, which holds the length byte:
243       txdata(app,verb,cmddata[0]+1);
244     }else{
245       //No packet.
246       txdata(app,verb,0);
247     }
248 #else
249     debugstr("Can't RX a packet with SFD and FIFOP definitions.");
250     txdata(app,NOK,0);
251 #endif
252     break;
253   case CCSPI_RX_FLUSH:
254     //Flush the buffer.
255     CLRSS;
256     ccspitrans8(CCSPI_SFLUSHRX);
257     SETSS;
258
259     txdata(app,verb,0);
260     break;
261
262   case CCSPI_REFLEX:
263     ccspireflexjam(len?cmddataword[0]:0);
264     break;
265
266   case CCSPI_REFLEX_AUTOACK:
267 #if defined(FIFOP) && defined(SFD) && defined(FIFO) && defined(PLED2DIR) && defined(PLED2PIN) && defined(PLED2OUT)
268     //txdata(app, verb, 1);
269     debugstr("AutoACK");
270     char byte[4];
271     while(1) {
272         //Has there been an overflow in the RX buffer?
273         if((!FIFO)&&FIFOP){
274           //debugstr("Clearing overflow");
275           CLRSS;
276           ccspitrans8(0x08); //SFLUSHRX
277           SETSS;
278         }
279
280         //Wait until a packet is received
281         while(!SFD);
282         //Turn on LED 2 (green) as signal
283             PLED2DIR |= PLED2PIN;
284             PLED2OUT &= ~PLED2PIN;
285
286         //Put radio in TX mode
287         //Note: Not doing this slows down jamming, so can't jam short packets.
288         //      However, if we do this, it seems to mess up our RXFIFO ability.
289         //CLRSS;
290         //ccspitrans8(0x04);
291         //SETSS;
292         //Load the jamming packet
293         CLRSS;
294         ccspitrans8(CCSPI_TXFIFO);
295         char pkt[7] = {0x07, 0x01, 0x08, 0xff, 0xff, 0xff, 0xff};
296         for(i=0;i<pkt[0];i++)
297           ccspitrans8(pkt[i]);
298         SETSS;
299         //Transmit the jamming packet
300         CLRSS;
301         ccspitrans8(0x04);  //STXON
302         SETSS;
303         msdelay(200);       //Instead of examining SFD line status
304         //Flush TX buffer.
305         CLRSS;
306         ccspitrans8(0x09);  //SFLUSHTX
307         SETSS;
308
309         //Get the orignally received packet, up to the seqnum field.
310         CLRSS;
311         ccspitrans8(CCSPI_RXFIFO | 0x40);
312         for(i=0;i<4;i++)
313             cmddata[i]=ccspitrans8(0xde);
314         SETSS;
315         //Flush RX buffer.
316         CLRSS;
317         ccspitrans8(0x08); //SFLUSHRX
318         SETSS;
319         //Send the sequence number of the jammed packet back to the client
320         //itoa(cmddata[3], byte, 16);
321         //debugstr(byte);
322         //txdata(app,verb,cmddata[3]);
323
324         //TODO turn on AUTOCRC for it to apply to the TX???
325         //     this may overcome issues of bad crc / length issues?
326         //mdmctrl0 (0x11) register set bit 5 to true.
327
328         //Create the forged ACK packet
329         cmddata[0] = 6;     //length of ack frame plus length
330         cmddata[1] = 0x02;  //first byte of FCF
331         cmddata[2] = 0x00;  //second byte of FCF
332         //[3] is already filled with the sequence number
333         int crc = 0;
334         for(i=1;i<4;i++) {
335             int c = cmddata[i];
336             int q = (crc ^ c) & 15;             //Do low-order 4 bits
337             crc = (crc / 16) ^ (q * 4225);
338             q = (crc ^ (c / 16)) & 15;          //And high 4 bits
339             crc = (crc / 16) ^ (q * 4225);
340         }
341         cmddata[4] = crc & 0xFF;
342         cmddata[5] = (crc >> 8) & 0xFF;
343
344         for(i=0;i<cmddata[0];i++) {
345             itoa(cmddata[i], byte, 16);
346             debugstr(byte);
347         }
348         //Load the forged ACK packet
349         CLRSS;
350         ccspitrans8(CCSPI_TXFIFO);
351         for(i=0;i<cmddata[0];i++)
352           ccspitrans8(cmddata[i]);
353         SETSS;
354         //Transmit the forged ACK packet
355         while(SFD);
356         CLRSS;
357         ccspitrans8(0x04);  //STXON
358         SETSS;
359         msdelay(200);       //TODO try doing this based on SFD line status instead
360         //Flush TX buffer
361         CLRSS;
362         ccspitrans8(0x09);  //SFLUSHTX
363         SETSS;
364
365         //TODO disable AUTOCRC here again to go back to promiscous mode
366
367         //Turn off LED 2 (green) as signal
368             PLED2DIR |= PLED2PIN;
369             PLED2OUT |= PLED2PIN;
370     }
371     //TODO the firmware stops staying in this mode after a while, and stops jamming... need to find a fix.
372 #else
373     debugstr("Can't reflexively jam without SFD, FIFO, FIFOP, and P2LEDx definitions - try using telosb platform.");
374     txdata(app,NOK,0);
375 #endif
376     break;
377
378   case CCSPI_TX_FLUSH:
379     //Flush the buffer.
380     CLRSS;
381     ccspitrans8(CCSPI_SFLUSHTX);
382     SETSS;
383
384     txdata(app,verb,0);
385     break;
386   case CCSPI_TX:
387 #ifdef FIFOP
388
389     //Wait for last packet to TX.
390     //while(ccspi_status()&BIT3);
391     
392     //Flush TX buffer.
393     CLRSS;
394     ccspitrans8(0x09); //SFLUSHTX
395     SETSS;
396     
397
398     //Load the packet.
399     CLRSS;
400     ccspitrans8(CCSPI_TXFIFO);
401     for(i=0;i<cmddata[0];i++)
402       ccspitrans8(cmddata[i]);
403     SETSS;
404
405     //Transmit the packet.
406     CLRSS;
407     ccspitrans8(0x04); //STXON
408     SETSS;
409
410     //Wait for the pulse on SFD, after which the packet has been sent.
411     while(!SFD);
412     while(SFD);
413     
414     txdata(app,verb,0);
415 #else
416     debugstr("Can't TX a packet with SFD and FIFOP definitions.");
417     txdata(app,NOK,0);
418 #endif
419     break;
420   default:
421     debugstr("Not yet supported in CCSPI");
422     txdata(app,verb,0);
423     break;
424   }
425
426 }