4ab98fdb43b8f0ed6861ff1b1c54aca168cc6b85
[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);  //Let the client continue its business.
195     while(1) {
196       //Wait until a packet is received
197       while(!SFD){
198         //Has there been an overflow in the RX buffer?
199         if((!FIFO)&&FIFOP){
200           debugstr("Clearing RX overflow");
201           CLRSS;
202           ccspitrans8(0x08); //SFLUSHRX
203           SETSS;
204         }
205       }
206       //Turn on LED 2 (green) as signal
207       PLED2DIR |= PLED2PIN;
208       PLED2OUT &= ~PLED2PIN;
209
210       //Put radio in TX mode
211       CLRSS;
212       ccspitrans8(0x04);
213       SETSS;
214
215       //Load the jamming packet.
216       //Note: attempts to preload this actually slowed the jam time down from 7 to 9 bytes.
217       CLRSS;
218       ccspitrans8(CCSPI_TXFIFO);
219       char pkt[15] = {0x0f, 0x01, 0x08, 0x82, 0xff, 0xff, 0xff, 0xff, 0xde, 0xad, 0xbe, 0xef, 0xba, 0xbe, 0xc0};
220       //char pkt[12] = {0x0c, 0x01, 0x08, 0x82, 0xff, 0xff, 0xff, 0xff, 0xde, 0xad, 0xbe, 0xef};
221       for(i=0;i<pkt[0];i++)
222         ccspitrans8(pkt[i]);
223       SETSS;
224
225       //Transmit the packet.
226       CLRSS;
227       ccspitrans8(0x04); //STXON
228       SETSS;
229       msdelay(100);      //Instead of waiting for pulse on SFD
230       //Flush TX buffer.
231       CLRSS;
232       ccspitrans8(0x09); //SFLUSHTX
233       SETSS;
234
235       //Turn off LED 2 (green) as signal
236       PLED2DIR |= PLED2PIN;
237       PLED2OUT |= PLED2PIN;
238     }
239     //TODO the firmware stops staying in this mode after a while, and stops jamming... need to find a fix.
240     break;
241 #else
242     debugstr("Can't reflexively jam without SFD, FIFO, FIFOP, and P2LEDx definitions - try using telosb platform.");
243     txdata(app,NOK,0);
244 #endif
245
246   case CCSPI_REFLEX_AUTOACK:
247 #if defined(FIFOP) && defined(SFD) && defined(FIFO) && defined(PLED2DIR) && defined(PLED2PIN) && defined(PLED2OUT)
248     //txdata(app, verb, 1);
249     debugstr("AutoACK");
250     char byte[4];
251     while(1) {
252         //Has there been an overflow in the RX buffer?
253         if((!FIFO)&&FIFOP){
254           //debugstr("Clearing overflow");
255           CLRSS;
256           ccspitrans8(0x08); //SFLUSHRX
257           SETSS;
258         }
259
260         //Wait until a packet is received
261         while(!SFD);
262         //Turn on LED 2 (green) as signal
263             PLED2DIR |= PLED2PIN;
264             PLED2OUT &= ~PLED2PIN;
265
266         //Put radio in TX mode
267         //Note: Not doing this slows down jamming, so can't jam short packets.
268         //      However, if we do this, it seems to mess up our RXFIFO ability.
269         //CLRSS;
270         //ccspitrans8(0x04);
271         //SETSS;
272         //Load the jamming packet
273         CLRSS;
274         ccspitrans8(CCSPI_TXFIFO);
275         char pkt[7] = {0x07, 0x01, 0x08, 0xff, 0xff, 0xff, 0xff};
276         for(i=0;i<pkt[0];i++)
277           ccspitrans8(pkt[i]);
278         SETSS;
279         //Transmit the jamming packet
280         CLRSS;
281         ccspitrans8(0x04);  //STXON
282         SETSS;
283         msdelay(200);       //Instead of examining SFD line status
284         //Flush TX buffer.
285         CLRSS;
286         ccspitrans8(0x09);  //SFLUSHTX
287         SETSS;
288
289         //Get the orignally received packet, up to the seqnum field.
290         CLRSS;
291         ccspitrans8(CCSPI_RXFIFO | 0x40);
292         for(i=0;i<4;i++)
293             cmddata[i]=ccspitrans8(0xde);
294         SETSS;
295         //Flush RX buffer.
296         CLRSS;
297         ccspitrans8(0x08); //SFLUSHRX
298         SETSS;
299         //Send the sequence number of the jammed packet back to the client
300         //itoa(cmddata[3], byte, 16);
301         //debugstr(byte);
302         //txdata(app,verb,cmddata[3]);
303
304         //TODO turn on AUTOCRC for it to apply to the TX???
305         //     this may overcome issues of bad crc / length issues?
306         //mdmctrl0 (0x11) register set bit 5 to true.
307
308         //Create the forged ACK packet
309         cmddata[0] = 6;     //length of ack frame plus length
310         cmddata[1] = 0x02;  //first byte of FCF
311         cmddata[2] = 0x00;  //second byte of FCF
312         //[3] is already filled with the sequence number
313         int crc = 0;
314         for(i=1;i<4;i++) {
315             int c = cmddata[i];
316             int q = (crc ^ c) & 15;             //Do low-order 4 bits
317             crc = (crc / 16) ^ (q * 4225);
318             q = (crc ^ (c / 16)) & 15;          //And high 4 bits
319             crc = (crc / 16) ^ (q * 4225);
320         }
321         cmddata[4] = crc & 0xFF;
322         cmddata[5] = (crc >> 8) & 0xFF;
323
324         for(i=0;i<cmddata[0];i++) {
325             itoa(cmddata[i], byte, 16);
326             debugstr(byte);
327         }
328         //Load the forged ACK packet
329         CLRSS;
330         ccspitrans8(CCSPI_TXFIFO);
331         for(i=0;i<cmddata[0];i++)
332           ccspitrans8(cmddata[i]);
333         SETSS;
334         //Transmit the forged ACK packet
335         while(SFD);
336         CLRSS;
337         ccspitrans8(0x04);  //STXON
338         SETSS;
339         msdelay(200);       //TODO try doing this based on SFD line status instead
340         //Flush TX buffer
341         CLRSS;
342         ccspitrans8(0x09);  //SFLUSHTX
343         SETSS;
344
345         //TODO disable AUTOCRC here again to go back to promiscous mode
346
347         //Turn off LED 2 (green) as signal
348             PLED2DIR |= PLED2PIN;
349             PLED2OUT |= PLED2PIN;
350     }
351     //TODO the firmware stops staying in this mode after a while, and stops jamming... need to find a fix.
352 #else
353     debugstr("Can't reflexively jam without SFD, FIFO, FIFOP, and P2LEDx definitions - try using telosb platform.");
354     txdata(app,NOK,0);
355 #endif
356     break;
357
358   case CCSPI_TX_FLUSH:
359     //Flush the buffer.
360     CLRSS;
361     ccspitrans8(CCSPI_SFLUSHTX);
362     SETSS;
363
364     txdata(app,verb,0);
365     break;
366   case CCSPI_TX:
367 #ifdef FIFOP
368
369     //Wait for last packet to TX.
370     //while(ccspi_status()&BIT3);
371     
372     //Flush TX buffer.
373     CLRSS;
374     ccspitrans8(0x09); //SFLUSHTX
375     SETSS;
376     
377
378     //Load the packet.
379     CLRSS;
380     ccspitrans8(CCSPI_TXFIFO);
381     for(i=0;i<cmddata[0];i++)
382       ccspitrans8(cmddata[i]);
383     SETSS;
384
385     //Transmit the packet.
386     CLRSS;
387     ccspitrans8(0x04); //STXON
388     SETSS;
389
390     //Wait for the pulse on SFD, after which the packet has been sent.
391     while(!SFD);
392     while(SFD);
393     
394     txdata(app,verb,0);
395 #else
396     debugstr("Can't TX a packet with SFD and FIFOP definitions.");
397     txdata(app,NOK,0);
398 #endif
399     break;
400   default:
401     debugstr("Not yet supported in CCSPI");
402     txdata(app,verb,0);
403     break;
404   }
405
406 }