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