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