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