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