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