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