Restored instruction to flush CC2420 buffer.
[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 //! Writes a register
91 u8 ccspi_regwrite(u8 reg, const u8 *buf, int len){
92   CLRSS;
93
94   reg=ccspitrans8(reg);
95   while(len--)
96     ccspitrans8(*buf++);
97
98   SETSS;
99   return reg;//status
100 }
101 //! Reads a register
102 u8 ccspi_regread(u8 reg, u8 *buf, int len){
103   CLRSS;
104
105   reg=ccspitrans8(reg);
106   while(len--)
107     *buf++=ccspitrans8(0);
108
109   SETSS;
110   return reg;//status
111 }
112
113 //! Handles a Chipcon SPI command.
114 void ccspi_handle_fn( uint8_t const app,
115                       uint8_t const verb,
116                       uint32_t const len){
117   unsigned long i;
118   u8 j;
119
120   //debugstr("Chipcon SPI handler.");
121
122   switch(verb){
123   case PEEK:
124     cmddata[0]|=0x40; //Set the read bit.
125     //DO NOT BREAK HERE.
126   case READ:
127   case WRITE:
128   case POKE:
129     CLRSS; //Drop !SS to begin transaction.
130     j=cmddata[0];//Backup address.
131     for(i=0;i<len;i++)
132       cmddata[i]=ccspitrans8(cmddata[i]);
133     SETSS;  //Raise !SS to end transaction.
134     cmddata[0]=j&~0x40;//Restore address.
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       
170       
171       //Only should transmit length of one more than the reported
172       // length of the frame, which holds the length byte:
173       txdata(app,verb,cmddata[0]+1);
174     }else{
175       //No packet.
176       txdata(app,verb,0);
177     }
178 #else
179     debugstr("Can't RX a packet with SFD and FIFOP definitions.");
180     txdata(app,NOK,0);
181 #endif
182     break;
183   case CCSPI_RX_FLUSH:
184     //Flush the buffer.
185     CLRSS;
186     ccspitrans8(CCSPI_SFLUSHRX);
187     SETSS;
188
189     txdata(app,verb,0);
190     break;
191
192   case CCSPI_REFLEX:
193 #if defined(FIFOP) && defined(SFD) && defined(FIFO) && defined(PLED2DIR) && defined(PLED2PIN) && defined(PLED2OUT)
194     txdata(app,verb,1);  //Just sending some response back to client
195     while(1) {
196         //Wait until a packet is received
197         while(!SFD);
198         //Turn on LED 2 (green) as signal
199             PLED2DIR |= PLED2PIN;
200             PLED2OUT &= ~PLED2PIN;
201
202         //Put radio in TX mode
203         CLRSS;
204         ccspitrans8(0x04);
205         SETSS;
206
207         //Load the jamming packet.
208         //Note: attempts to preload this actually slowed the jam time down from 7 to 9 bytes.
209         CLRSS;
210         ccspitrans8(CCSPI_TXFIFO);
211         char pkt[15] = {0x0f, 0x01, 0x08, 0x82, 0xff, 0xff, 0xff, 0xff, 0xde, 0xad, 0xbe, 0xef, 0xba, 0xbe, 0xc0};
212         //char pkt[12] = {0x0c, 0x01, 0x08, 0x82, 0xff, 0xff, 0xff, 0xff, 0xde, 0xad, 0xbe, 0xef};
213         for(i=0;i<pkt[0];i++)
214           ccspitrans8(pkt[i]);
215         SETSS;
216
217         //Transmit the packet.
218         CLRSS;
219         ccspitrans8(0x04); //STXON
220         SETSS;
221         msdelay(100);      //Instead of waiting for pulse on SFD
222         //Flush TX buffer.
223         CLRSS;
224         ccspitrans8(0x09); //SFLUSHTX
225         SETSS;
226
227         //Turn off LED 2 (green) as signal
228             PLED2DIR |= PLED2PIN;
229             PLED2OUT |= PLED2PIN;
230     }
231     //TODO the firmware stops staying in this mode after a while, and stops jamming... need to find a fix.
232     break;
233 #else
234     debugstr("Can't reflexively jam without SFD, FIFO, FIFOP, and P2LEDx definitions - try using telosb platform.");
235     txdata(app,NOK,0);
236 #endif
237
238   case CCSPI_REFLEX_AUTOACK:
239 #if defined(FIFOP) && defined(SFD) && defined(FIFO) && defined(PLED2DIR) && defined(PLED2PIN) && defined(PLED2OUT)
240     //txdata(app, verb, 1);
241     debugstr("AutoACK");
242     char byte[4];
243     while(1) {
244         //Has there been an overflow in the RX buffer?
245         if((!FIFO)&&FIFOP){
246           //debugstr("Clearing overflow");
247           CLRSS;
248           ccspitrans8(0x08); //SFLUSHRX
249           SETSS;
250         }
251
252         //Wait until a packet is received
253         while(!SFD);
254         //Turn on LED 2 (green) as signal
255             PLED2DIR |= PLED2PIN;
256             PLED2OUT &= ~PLED2PIN;
257
258         //Put radio in TX mode
259         //Note: Not doing this slows down jamming, so can't jam short packets.
260         //      However, if we do this, it seems to mess up our RXFIFO ability.
261         //CLRSS;
262         //ccspitrans8(0x04);
263         //SETSS;
264         //Load the jamming packet
265         CLRSS;
266         ccspitrans8(CCSPI_TXFIFO);
267         char pkt[7] = {0x07, 0x01, 0x08, 0xff, 0xff, 0xff, 0xff};
268         for(i=0;i<pkt[0];i++)
269           ccspitrans8(pkt[i]);
270         SETSS;
271         //Transmit the jamming packet
272         CLRSS;
273         ccspitrans8(0x04);  //STXON
274         SETSS;
275         msdelay(200);       //Instead of examining SFD line status
276         //Flush TX buffer.
277         CLRSS;
278         ccspitrans8(0x09);  //SFLUSHTX
279         SETSS;
280
281         //Get the orignally received packet, up to the seqnum field.
282         CLRSS;
283         ccspitrans8(CCSPI_RXFIFO | 0x40);
284         for(i=0;i<4;i++)
285             cmddata[i]=ccspitrans8(0xde);
286         SETSS;
287         //Flush RX buffer.
288         CLRSS;
289         ccspitrans8(0x08); //SFLUSHRX
290         SETSS;
291         //Send the sequence number of the jammed packet back to the client
292         //itoa(cmddata[3], byte, 16);
293         //debugstr(byte);
294         //txdata(app,verb,cmddata[3]);
295
296         //TODO turn on AUTOCRC for it to apply to the TX???
297         //     this may overcome issues of bad crc / length issues?
298         //mdmctrl0 (0x11) register set bit 5 to true.
299
300         //Create the forged ACK packet
301         cmddata[0] = 6;     //length of ack frame plus length
302         cmddata[1] = 0x02;  //first byte of FCF
303         cmddata[2] = 0x00;  //second byte of FCF
304         //[3] is already filled with the sequence number
305         int crc = 0;
306         for(i=1;i<4;i++) {
307             int c = cmddata[i];
308             int q = (crc ^ c) & 15;             //Do low-order 4 bits
309             crc = (crc / 16) ^ (q * 4225);
310             q = (crc ^ (c / 16)) & 15;          //And high 4 bits
311             crc = (crc / 16) ^ (q * 4225);
312         }
313         cmddata[4] = crc & 0xFF;
314         cmddata[5] = (crc >> 8) & 0xFF;
315
316         for(i=0;i<cmddata[0];i++) {
317             itoa(cmddata[i], byte, 16);
318             debugstr(byte);
319         }
320         //Load the forged ACK packet
321         CLRSS;
322         ccspitrans8(CCSPI_TXFIFO);
323         for(i=0;i<cmddata[0];i++)
324           ccspitrans8(cmddata[i]);
325         SETSS;
326         //Transmit the forged ACK packet
327         while(SFD);
328         CLRSS;
329         ccspitrans8(0x04);  //STXON
330         SETSS;
331         msdelay(200);       //TODO try doing this based on SFD line status instead
332         //Flush TX buffer
333         CLRSS;
334         ccspitrans8(0x09);  //SFLUSHTX
335         SETSS;
336
337         //TODO disable AUTOCRC here again to go back to promiscous mode
338
339         //Turn off LED 2 (green) as signal
340             PLED2DIR |= PLED2PIN;
341             PLED2OUT |= PLED2PIN;
342     }
343     //TODO the firmware stops staying in this mode after a while, and stops jamming... need to find a fix.
344 #else
345     debugstr("Can't reflexively jam without SFD, FIFO, FIFOP, and P2LEDx definitions - try using telosb platform.");
346     txdata(app,NOK,0);
347 #endif
348     break;
349
350   case CCSPI_TX_FLUSH:
351     //Flush the buffer.
352     CLRSS;
353     ccspitrans8(CCSPI_SFLUSHTX);
354     SETSS;
355
356     txdata(app,verb,0);
357     break;
358   case CCSPI_TX:
359 #ifdef FIFOP
360
361     //Wait for last packet to TX.
362     //while(ccspi_status()&BIT3);
363     
364     //Flush TX buffer.
365     CLRSS;
366     ccspitrans8(0x09); //SFLUSHTX
367     SETSS;
368     
369
370     //Load the packet.
371     CLRSS;
372     ccspitrans8(CCSPI_TXFIFO);
373     for(i=0;i<cmddata[0];i++)
374       ccspitrans8(cmddata[i]);
375     SETSS;
376
377     //Transmit the packet.
378     CLRSS;
379     ccspitrans8(0x04); //STXON
380     SETSS;
381
382     //Wait for the pulse on SFD, after which the packet has been sent.
383     while(!SFD);
384     while(SFD);
385     
386     txdata(app,verb,0);
387 #else
388     debugstr("Can't TX a packet with SFD and FIFOP definitions.");
389     txdata(app,NOK,0);
390 #endif
391     break;
392   default:
393     debugstr("Not yet supported in CCSPI");
394     txdata(app,verb,0);
395     break;
396   }
397
398 }