2 \author Travis Goodspeed
3 \brief Chipcon SPI Register Interface
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.
11 //Higher level left to client application.
15 #include <stdlib.h> //added for itoa
20 //! Handles a Chipcon SPI command.
21 void ccspi_handle_fn( uint8_t const app,
25 // define the ccspi app's app_t
26 app_t const ccspi_app = {
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"
46 //! Set up the pins for CCSPI mode.
53 //P4OUT|=BIT5; //activate CC2420 voltage regulator
57 /*P4OUT&=~BIT6; FIXME Does the new code work on Z1 and Telosb?
62 //Begin a new transaction.
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.
73 for (bit = 0; bit < 8; bit++) {
74 /* write MOSI on trailing edge of previous clock */
83 /* read MISO on trailing edge */
92 //! Reflexively jam on the present channel.
93 void ccspireflexjam(u16 delay){
95 #if defined(FIFOP) && defined(SFD) && defined(FIFO) && defined(PLED2DIR) && defined(PLED2PIN) && defined(PLED2OUT)
98 debugstr("Reflex jamming until reset.");
100 txdata(CCSPI,CCSPI_REFLEX,1); //Let the client continue its business.
102 //Wait until a packet is received
104 //Has there been an overflow in the RX buffer?
106 //debugstr("Clearing RX overflow");
108 ccspitrans8(0x08); //SFLUSHRX
112 //Turn on LED 2 (green) as signal
113 PLED2DIR |= PLED2PIN;
114 PLED2OUT &= ~PLED2PIN;
118 //Wait a few us to send it.
121 //Transmit the packet.
127 //Load the next jamming packet.
128 //Note: attempts to preload this actually slowed the jam time down from 7 to 9 bytes.
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++)
138 //* I think this might be unnecessary.
139 //msdelay(100+delay); //Instead of waiting for pulse on SFD
143 ccspitrans8(0x09); //SFLUSHTX
147 //Turn off LED 2 (green) as signal
148 PLED2DIR |= PLED2PIN;
149 PLED2OUT |= PLED2PIN;
152 debugstr("Can't reflexively jam without SFD, FIFO, FIFOP, and P2LEDx definitions - try using telosb platform.");
157 //! Writes bytes into the CC2420's RAM. Untested.
158 void ccspi_pokeram(u8 addr, char *data, int len){
160 //Begin with the start address.
161 ccspitrans8(0x80 | (addr & 0x7F));
162 ccspitrans8(((addr>>1)&0xC0) // MSBits are high bits of 9-bit address.
163 // Read/!Write bit should be clear to write.
168 ccspitrans8(*data++);
173 //! Read bytes from the CC2420's RAM. Untested.
174 void ccspi_peekram(u16 addr, u8 *data, u16 len){
177 //Begin with the start address.
178 ccspitrans8(0x80 | (addr & 0x7F));
179 ccspitrans8(((addr>>1)&0xC0) // MSBits are high bits of 9-bit address.
180 | BIT5 // Read/!Write bit should be set to read.
185 *data++=ccspitrans8(0);
190 //! Updates the Nonce's sequence number.
191 void ccspi_updaterxnonce(u32 seq){
195 //! Writes a register
196 u8 ccspi_regwrite(u8 reg, const u8 *buf, int len){
199 reg=ccspitrans8(reg);
207 u8 ccspi_regread(u8 reg, u8 *buf, int len){
210 reg=ccspitrans8(reg);
212 *buf++=ccspitrans8(0);
218 //! Handles a Chipcon SPI command.
219 void ccspi_handle_fn( uint8_t const app,
227 cmddata[0]|=0x40; //Set the read bit.
232 CLRSS; //Drop !SS to begin transaction.
233 j=cmddata[0];//Backup address.
235 cmddata[i]=ccspitrans8(cmddata[i]);
236 SETSS; //Raise !SS to end transaction.
237 cmddata[0]=j&~0x40;//Restore address.
238 txdata(app,verb,len);
245 i=cmddataword[1]; // Backup length.
246 ccspi_peekram(cmddataword[0], // First word is the address.
247 cmddata, // Return in the same buffer.
248 cmddataword[1] // Second word is the length.
253 ccspi_pokeram(cmddataword[0], //First word is address
254 cmddata+2, //Remainder of buffer is dat.
255 len-2 //Length implied by packet length.
259 case CCSPI_REPEAT_RX:
261 /* CCSPI_REPEAT_RX repeatedly requests new packets, forwarding
262 them to the server without waiting for the next request. This
263 allows for sniffing of packets that would otherwise overflow
267 //debugstr("Looping CCSPI_RX.");
269 //Loop forever in RX mode.
271 ccspi_handle_fn(app,CCSPI_RX,0);
276 //Has there been an overflow?
279 debugstr("Clearing overflow");
281 ccspitrans8(0x08); //SFLUSHRX
282 ccspitrans8(0x08); //SFLUSHRX
284 txdata(app,verb,0); //no packet
288 /* Uncomment this to wait around a bit for the packet.
289 Might reduce dropped packet count.
290 i=1000; //Number of tries.
291 while(!(FIFOP&&FIFO) && i--);
296 //Wait for completion.
301 ccspitrans8(CCSPI_RXFIFO | 0x40);
302 //ccspitrans8(0x3F|0x40);
303 cmddata[0]=0x20; //to be replaced with length
306 /* This reads too far on some CC2420 revisions, but on others it
307 works fine. It probably has to do with whether FIFO drops
308 before or after the SPI clocking.
310 A software fix is to reset the CC2420 between packets. This
311 works, but a better solution is desired.
313 //for(i=0;i<cmddata[0]+1;i++)
314 for(i=0;FIFO && i<0x80;i++)
315 cmddata[i]=ccspitrans8(0x00);
318 /* We used to flush the RX buffer after receive. No longer.
320 ccspitrans8(0x08); //SFLUSHRX
324 //Only transmit a packet if the length is legal.
325 if(cmddata[0]&0x80 || cmddata[0]==0) i=0;
333 debugstr("Can't RX a packet with SFD and FIFOP definitions.");
339 //Has there been an overflow?
341 debugstr("Clearing overflow");
343 ccspitrans8(0x08); //SFLUSHRX
345 txdata(app,verb,0); //no packet
351 //Wait for completion.
355 ccspitrans8(CCSPI_RXFIFO | 0x40);
357 cmddata[0]=ccspitrans8(0x00);
359 //Read the header first.
360 for(i=1;i<cmddata[0]+1 && i<0x11;i++)
361 cmddata[i]=ccspitrans8(0x00);
364 //Is the frame encrypted?
366 //Copy the sequence number to the Nonce.
369 //Decrypt the rest of the packet.
370 CLRSS; ccspitrans8(CCSPI_SRXDEC); SETSS;
372 //Wait for decryption to complete.
378 //Get the packet, which is now decrypted in position.
380 ccspitrans8(CCSPI_RXFIFO | 0x40);
381 //ccspitrans8(0x3F|0x40);
384 /* This reads too far on some CC2420 revisions, but on others it
385 works fine. It probably has to do with whether FIFO drops
386 before or after the SPI clocking.
388 A software fix is to reset the CC2420 between packets. This
389 works, but a better solution is desired.
391 for(;i<cmddata[0]+1;i++)
392 cmddata[i]=ccspitrans8(0x00);
395 //Only forward a packet if the length is legal.
396 if(cmddata[0]&0x80) i=0;
403 debugstr("Can't RX a packet with SFD and FIFOP definitions.");
410 ccspitrans8(CCSPI_SFLUSHRX);
417 ccspireflexjam(len?cmddataword[0]:0);
420 case CCSPI_REFLEX_AUTOACK:
421 #if defined(FIFOP) && defined(SFD) && defined(FIFO) && defined(PLED2DIR) && defined(PLED2PIN) && defined(PLED2OUT)
422 //txdata(app, verb, 1);
426 //Has there been an overflow in the RX buffer?
428 //debugstr("Clearing overflow");
430 ccspitrans8(0x08); //SFLUSHRX
434 //Wait until a packet is received
436 //Turn on LED 2 (green) as signal
437 PLED2DIR |= PLED2PIN;
438 PLED2OUT &= ~PLED2PIN;
440 //Put radio in TX mode
441 //Note: Not doing this slows down jamming, so can't jam short packets.
442 // However, if we do this, it seems to mess up our RXFIFO ability.
446 //Load the jamming packet
448 ccspitrans8(CCSPI_TXFIFO);
449 char pkt[7] = {0x07, 0x01, 0x08, 0xff, 0xff, 0xff, 0xff};
450 for(i=0;i<pkt[0];i++)
453 //Transmit the jamming packet
455 ccspitrans8(0x04); //STXON
457 msdelay(200); //Instead of examining SFD line status
460 ccspitrans8(0x09); //SFLUSHTX
463 //Get the orignally received packet, up to the seqnum field.
465 ccspitrans8(CCSPI_RXFIFO | 0x40);
467 cmddata[i]=ccspitrans8(0xde);
471 ccspitrans8(0x08); //SFLUSHRX
473 //Send the sequence number of the jammed packet back to the client
474 //itoa(cmddata[3], byte, 16);
476 //txdata(app,verb,cmddata[3]);
478 //TODO turn on AUTOCRC for it to apply to the TX???
479 // this may overcome issues of bad crc / length issues?
480 //mdmctrl0 (0x11) register set bit 5 to true.
482 //Create the forged ACK packet
483 cmddata[0] = 6; //length of ack frame plus length
484 cmddata[1] = 0x02; //first byte of FCF
485 cmddata[2] = 0x00; //second byte of FCF
486 //[3] is already filled with the sequence number
490 int q = (crc ^ c) & 15; //Do low-order 4 bits
491 crc = (crc / 16) ^ (q * 4225);
492 q = (crc ^ (c / 16)) & 15; //And high 4 bits
493 crc = (crc / 16) ^ (q * 4225);
495 cmddata[4] = crc & 0xFF;
496 cmddata[5] = (crc >> 8) & 0xFF;
498 for(i=0;i<cmddata[0];i++) {
499 itoa(cmddata[i], byte, 16);
502 //Load the forged ACK packet
504 ccspitrans8(CCSPI_TXFIFO);
505 for(i=0;i<cmddata[0];i++)
506 ccspitrans8(cmddata[i]);
508 //Transmit the forged ACK packet
511 ccspitrans8(0x04); //STXON
513 msdelay(200); //TODO try doing this based on SFD line status instead
516 ccspitrans8(0x09); //SFLUSHTX
519 //TODO disable AUTOCRC here again to go back to promiscous mode
521 //Turn off LED 2 (green) as signal
522 PLED2DIR |= PLED2PIN;
523 PLED2OUT |= PLED2PIN;
525 //TODO the firmware stops staying in this mode after a while, and stops jamming... need to find a fix.
527 debugstr("Can't reflexively jam without SFD, FIFO, FIFOP, and P2LEDx definitions - try using telosb platform.");
535 ccspitrans8(CCSPI_SFLUSHTX);
543 //Wait for last packet to TX.
544 //while(ccspi_status()&BIT3);
548 ccspitrans8(0x09); //SFLUSHTX
554 ccspitrans8(CCSPI_TXFIFO);
555 for(i=0;i<cmddata[0];i++)
556 ccspitrans8(cmddata[i]);
559 //Transmit the packet.
561 ccspitrans8(0x04); //STXON
564 //Wait for the pulse on SFD, after which the packet has been sent.
570 debugstr("Can't TX a packet with SFD and FIFOP definitions.");
575 debugstr("Not yet supported in CCSPI");