Contiki 2.6

cc2530-rf.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2011, George Oikonomou - <oikonomou@users.sourceforge.net>
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the Institute nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  *
00029  * This file is part of the Contiki operating system.
00030  */
00031 
00032 /**
00033  * \file
00034  *         Implementation of the cc2530 RF driver
00035  *
00036  * \author
00037  *         George Oikonomou - <oikonomou@users.sourceforge.net>
00038  */
00039 #include "contiki.h"
00040 #include "dev/radio.h"
00041 #include "dev/cc2530-rf.h"
00042 #include "cc253x.h"
00043 #include "sfr-bits.h"
00044 #include "sys/clock.h"
00045 #include "sys/rtimer.h"
00046 
00047 #include "net/packetbuf.h"
00048 #include "net/rime/rimestats.h"
00049 #include "net/rime/rimeaddr.h"
00050 #include "net/netstack.h"
00051 
00052 #include <string.h>
00053 /*---------------------------------------------------------------------------*/
00054 #define CHECKSUM_LEN 2
00055 /*---------------------------------------------------------------------------*/
00056 #if CC2530_RF_CONF_LEDS
00057 #define CC2530_RF_LEDS CC2530_RF_CONF_LEDS
00058 #else
00059 #define CC2530_RF_LEDS 0
00060 #endif
00061 
00062 #if CC2530_RF_LEDS
00063 #include "dev/leds.h"
00064 #define RF_RX_LED_ON()          leds_on(LEDS_RED);
00065 #define RF_RX_LED_OFF()         leds_off(LEDS_RED);
00066 #define RF_TX_LED_ON()          leds_on(LEDS_GREEN);
00067 #define RF_TX_LED_OFF()         leds_off(LEDS_GREEN);
00068 #else
00069 #define RF_RX_LED_ON()
00070 #define RF_RX_LED_OFF()         
00071 #define RF_TX_LED_ON()
00072 #define RF_TX_LED_OFF()         
00073 #endif
00074 /*---------------------------------------------------------------------------*/
00075 #define DEBUG 0
00076 #if DEBUG
00077 #include "debug.h"
00078 #define PUTSTRING(...) putstring(__VA_ARGS__)
00079 #define PUTHEX(...) puthex(__VA_ARGS__)
00080 #else
00081 #define PUTSTRING(...)
00082 #define PUTHEX(...)
00083 #endif
00084 /*---------------------------------------------------------------------------*/
00085 /* Local RF Flags */
00086 #define RX_ACTIVE  0x80
00087 #define WAS_OFF    0x10
00088 #define RF_ON      0x01
00089 
00090 /* Bit Masks for the last byte in the RX FIFO */
00091 #define CRC_BIT_MASK 0x80
00092 #define LQI_BIT_MASK 0x7F
00093 /* RSSI Offset */
00094 #define RSSI_OFFSET    73
00095 
00096 /* 192 ms, radio off -> on interval */
00097 #define ONOFF_TIME                    RTIMER_ARCH_SECOND / 3125
00098 /*---------------------------------------------------------------------------*/
00099 #if CC2530_RF_CONF_HEXDUMP
00100 #include "uart0.h"
00101 static const uint8_t magic[] = { 0x53, 0x6E, 0x69, 0x66 }; /* Snif */
00102 #endif
00103 /*---------------------------------------------------------------------------*/
00104 #ifdef CC2530_RF_CONF_AUTOACK
00105 #define CC2530_RF_AUTOACK CC2530_RF_CONF_AUTOACK
00106 #else
00107 #define CC2530_RF_AUTOACK 1
00108 #endif
00109 /*---------------------------------------------------------------------------*/
00110 static uint8_t __data rf_flags;
00111 
00112 static int on(void); /* prepare() needs our prototype */
00113 static int off(void); /* transmit() needs our prototype */
00114 static int channel_clear(void); /* transmit() needs our prototype */
00115 /*---------------------------------------------------------------------------*/
00116 int8_t
00117 cc2530_rf_channel_set(uint8_t channel)
00118 {
00119   PUTSTRING("RF: Set Chan\n");
00120 
00121   if((channel < CC2530_RF_CHANNEL_MIN) || (channel > CC2530_RF_CHANNEL_MAX)) {
00122     return -1;
00123   }
00124 
00125   /* Changes to FREQCTRL take effect after the next recalibration */
00126   off();
00127   FREQCTRL = (CC2530_RF_CHANNEL_MIN
00128       + (channel - CC2530_RF_CHANNEL_MIN) * CC2530_RF_CHANNEL_SPACING);
00129   on();
00130 
00131   return (int8_t) channel;
00132 }
00133 /*---------------------------------------------------------------------------*/
00134 uint8_t
00135 cc2530_rf_power_set(uint8_t new_power)
00136 {
00137   PUTSTRING("RF: Set Power\n");
00138   /* off() */
00139   TXPOWER = new_power;
00140   /* on() */
00141 
00142   return TXPOWER;
00143 }
00144 /*---------------------------------------------------------------------------*/
00145 void
00146 cc2530_rf_set_addr(uint16_t pan)
00147 {
00148 #if RIMEADDR_SIZE==8 /* EXT_ADDR[7:0] is ignored when using short addresses */
00149   int i;
00150   for(i = (RIMEADDR_SIZE - 1); i >= 0; --i) {
00151     ((uint8_t *)&EXT_ADDR0)[i] = rimeaddr_node_addr.u8[RIMEADDR_SIZE - 1 - i];
00152   }
00153 #endif
00154 
00155   PAN_ID0 = pan & 0xFF;
00156   PAN_ID1 = pan >> 8;
00157 
00158   SHORT_ADDR0 = rimeaddr_node_addr.u8[RIMEADDR_SIZE - 1];
00159   SHORT_ADDR1 = rimeaddr_node_addr.u8[RIMEADDR_SIZE - 2];
00160 }
00161 /*---------------------------------------------------------------------------*/
00162 /* Netstack API radio driver functions */
00163 /*---------------------------------------------------------------------------*/
00164 static int
00165 init(void)
00166 {
00167   PUTSTRING("RF: Init\n");
00168 
00169   if(rf_flags & RF_ON) {
00170     return 0;
00171   }
00172 
00173 #if CC2530_RF_LOW_POWER_RX
00174   /* Reduce RX power consumption current to 20mA at the cost of sensitivity */
00175   RXCTRL = 0x00;
00176   FSCTRL = 0x50;
00177 #else
00178   RXCTRL = 0x3F;
00179   FSCTRL = 0x55;
00180 #endif /* CC2530_RF_LOW_POWER_RX */
00181 
00182   CCACTRL0 = CC2530_RF_CCA_THRES;
00183 
00184   /*
00185    * According to the user guide, these registers must be updated from their
00186    * defaults for optimal performance
00187    *
00188    * Table 23-6, Sec. 23.15.1, p. 259
00189    */
00190   TXFILTCFG = 0x09; /* TX anti-aliasing filter */
00191   AGCCTRL1 = 0x15;  /* AGC target value */
00192   FSCAL1 = 0x00;    /* Reduce the VCO leakage */
00193 
00194   /* Auto ACKs and CRC calculation, default RX and TX modes with FIFOs */
00195   FRMCTRL0 = FRMCTRL0_AUTOCRC;
00196 #if CC2530_RF_AUTOACK
00197   FRMCTRL0 |= FRMCTRL0_AUTOACK;
00198 #endif
00199 
00200   /* Disable source address matching and autopend */
00201   SRCMATCH = 0; /* investigate */
00202 
00203   /* MAX FIFOP threshold */
00204   FIFOPCTRL = CC2530_RF_MAX_PACKET_LEN;
00205 
00206   cc2530_rf_power_set(CC2530_RF_TX_POWER);
00207   cc2530_rf_channel_set(CC2530_RF_CHANNEL);
00208 
00209   RF_TX_LED_OFF();
00210   RF_RX_LED_OFF();
00211 
00212   rf_flags |= RF_ON;
00213 
00214   return 1;
00215 }
00216 /*---------------------------------------------------------------------------*/
00217 static int
00218 prepare(const void *payload, unsigned short payload_len)
00219 {
00220   uint8_t i;
00221 
00222   PUTSTRING("RF: Prepare 0x");
00223   PUTHEX(payload_len + CHECKSUM_LEN);
00224   PUTSTRING(" bytes\n");
00225 
00226   /*
00227    * When we transmit in very quick bursts, make sure previous transmission
00228    * is not still in progress before re-writing to the TX FIFO
00229    */
00230   while(FSMSTAT1 & FSMSTAT1_TX_ACTIVE);
00231 
00232   if((rf_flags & RX_ACTIVE) == 0) {
00233     on();
00234   }
00235 
00236   CC2530_CSP_ISFLUSHTX();
00237 
00238   PUTSTRING("RF: data = ");
00239   /* Send the phy length byte first */
00240   RFD = payload_len + CHECKSUM_LEN; /* Payload plus FCS */
00241   for(i = 0; i < payload_len; i++) {
00242     RFD = ((unsigned char*) (payload))[i];
00243     PUTHEX(((unsigned char*)(payload))[i]);
00244   }
00245   PUTSTRING("\n");
00246 
00247   /* Leave space for the FCS */
00248   RFD = 0;
00249   RFD = 0;
00250 
00251   return 0;
00252 }
00253 /*---------------------------------------------------------------------------*/
00254 static int
00255 transmit(unsigned short transmit_len)
00256 {
00257   uint8_t counter;
00258   int ret = RADIO_TX_ERR;
00259   rtimer_clock_t t0;
00260   transmit_len; /* hush the warning */
00261 
00262   if(!(rf_flags & RX_ACTIVE)) {
00263     t0 = RTIMER_NOW();
00264     on();
00265     rf_flags |= WAS_OFF;
00266     while (RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + ONOFF_TIME));
00267   }
00268 
00269   if(channel_clear() == CC2530_RF_CCA_BUSY) {
00270     RIMESTATS_ADD(contentiondrop);
00271     return RADIO_TX_COLLISION;
00272   }
00273 
00274   /*
00275    * prepare() double checked that TX_ACTIVE is low. If SFD is high we are
00276    * receiving. Abort transmission and bail out with RADIO_TX_COLLISION
00277    */
00278   if(FSMSTAT1 & FSMSTAT1_SFD) {
00279     RIMESTATS_ADD(contentiondrop);
00280     return RADIO_TX_COLLISION;
00281   }
00282 
00283   /* Start the transmission */
00284   RF_TX_LED_ON();
00285   ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
00286   ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);
00287 
00288   CC2530_CSP_ISTXON();
00289 
00290   counter = 0;
00291   while(!(FSMSTAT1 & FSMSTAT1_TX_ACTIVE) && (counter++ < 3)) {
00292     clock_delay_usec(6);
00293   }
00294 
00295   if(!(FSMSTAT1 & FSMSTAT1_TX_ACTIVE)) {
00296     PUTSTRING("RF: TX never active.\n");
00297     CC2530_CSP_ISFLUSHTX();
00298     ret = RADIO_TX_ERR;
00299   } else {
00300     /* Wait for the transmission to finish */
00301     while(FSMSTAT1 & FSMSTAT1_TX_ACTIVE);
00302     ret = RADIO_TX_OK;
00303   }
00304   ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
00305   ENERGEST_ON(ENERGEST_TYPE_LISTEN);
00306 
00307   if(rf_flags & WAS_OFF){
00308     off();
00309   }
00310 
00311   RIMESTATS_ADD(lltx);
00312 
00313   RF_TX_LED_OFF();
00314 
00315   /* OK, sent. We are now ready to send more */
00316   return ret;
00317 }
00318 /*---------------------------------------------------------------------------*/
00319 static int
00320 send(void *payload, unsigned short payload_len)
00321 {
00322   prepare(payload, payload_len);
00323   return transmit(payload_len);
00324 }
00325 /*---------------------------------------------------------------------------*/
00326 static int
00327 read(void *buf, unsigned short bufsize)
00328 {
00329   uint8_t i;
00330   uint8_t len;
00331   uint8_t crc_corr;
00332   int8_t rssi;
00333 
00334   PUTSTRING("RF: Read\n");
00335 
00336   /* Check the length */
00337   len = RFD;
00338 
00339   /* Check for validity */
00340   if(len > CC2530_RF_MAX_PACKET_LEN) {
00341     /* Oops, we must be out of sync. */
00342     PUTSTRING("RF: bad sync\n");
00343 
00344     RIMESTATS_ADD(badsynch);
00345     CC2530_CSP_ISFLUSHRX();
00346     return 0;
00347   }
00348 
00349   if(len <= CC2530_RF_MIN_PACKET_LEN) {
00350     PUTSTRING("RF: too short\n");
00351 
00352     RIMESTATS_ADD(tooshort);
00353     CC2530_CSP_ISFLUSHRX();
00354     return 0;
00355   }
00356 
00357   if(len - CHECKSUM_LEN > bufsize) {
00358     PUTSTRING("RF: too long\n");
00359 
00360     RIMESTATS_ADD(toolong);
00361     CC2530_CSP_ISFLUSHRX();
00362     return 0;
00363   }
00364 
00365 #if CC2530_RF_CONF_HEXDUMP
00366   /* If we reach here, chances are the FIFO is holding a valid frame */
00367   uart0_writeb(magic[0]);
00368   uart0_writeb(magic[1]);
00369   uart0_writeb(magic[2]);
00370   uart0_writeb(magic[3]);
00371   uart0_writeb(len);
00372 #endif
00373 
00374   RF_RX_LED_ON();
00375 
00376   PUTSTRING("RF: read (0x");
00377   PUTHEX(len);
00378   PUTSTRING(" bytes) = ");
00379   len -= CHECKSUM_LEN;
00380   for(i = 0; i < len; ++i) {
00381     ((unsigned char*)(buf))[i] = RFD;
00382 #if CC2530_RF_CONF_HEXDUMP
00383     uart0_writeb(((unsigned char*)(buf))[i]);
00384 #endif
00385     PUTHEX(((unsigned char*)(buf))[i]);
00386   }
00387   PUTSTRING("\n");
00388 
00389   /* Read the RSSI and CRC/Corr bytes */
00390   rssi = ((int8_t) RFD) - RSSI_OFFSET;
00391   crc_corr = RFD;
00392 
00393 #if CC2530_RF_CONF_HEXDUMP
00394   uart0_writeb(rssi);
00395   uart0_writeb(crc_corr);
00396 #endif
00397 
00398   /* MS bit CRC OK/Not OK, 7 LS Bits, Correlation value */
00399   if(crc_corr & CRC_BIT_MASK) {
00400     packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rssi);
00401     packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, crc_corr & LQI_BIT_MASK);
00402     RIMESTATS_ADD(llrx);
00403   } else {
00404     RIMESTATS_ADD(badcrc);
00405     CC2530_CSP_ISFLUSHRX();
00406     RF_RX_LED_OFF();
00407     return 0;
00408   }
00409 
00410   /* If FIFOP==1 and FIFO==0 then we had a FIFO overflow at some point. */
00411   if((FSMSTAT1 & (FSMSTAT1_FIFO | FSMSTAT1_FIFOP)) == FSMSTAT1_FIFOP) {
00412     /*
00413      * If we reach here means that there might be more intact packets in the
00414      * FIFO despite the overflow. This can happen with bursts of small packets.
00415      *
00416      * Only flush if the FIFO is actually empty. If not, then next pass we will
00417      * pick up one more packet or flush due to an error.
00418      */
00419     if(!RXFIFOCNT) {
00420       CC2530_CSP_ISFLUSHRX();
00421     }
00422   }
00423 
00424   RF_RX_LED_OFF();
00425 
00426   return (len);
00427 }
00428 /*---------------------------------------------------------------------------*/
00429 static int
00430 channel_clear(void)
00431 {
00432   if(FSMSTAT1 & FSMSTAT1_CCA) {
00433     return CC2530_RF_CCA_CLEAR;
00434   }
00435   return CC2530_RF_CCA_BUSY;
00436 }
00437 /*---------------------------------------------------------------------------*/
00438 static int
00439 receiving_packet(void)
00440 {
00441   PUTSTRING("RF: Receiving\n");
00442 
00443   /*
00444    * SFD high while transmitting and receiving.
00445    * TX_ACTIVE high only when transmitting
00446    *
00447    * FSMSTAT1 & (TX_ACTIVE | SFD) == SFD <=> receiving
00448    */
00449   return (FSMSTAT1 & (FSMSTAT1_TX_ACTIVE | FSMSTAT1_SFD) == FSMSTAT1_SFD);
00450 }
00451 /*---------------------------------------------------------------------------*/
00452 static int
00453 pending_packet(void)
00454 {
00455   return (FSMSTAT1 & FSMSTAT1_FIFOP);
00456 }
00457 /*---------------------------------------------------------------------------*/
00458 static int
00459 on(void)
00460 {
00461   if(!(rf_flags & RX_ACTIVE)) {
00462     CC2530_CSP_ISFLUSHRX();
00463     CC2530_CSP_ISRXON();
00464 
00465     rf_flags |= RX_ACTIVE;
00466   }
00467 
00468   ENERGEST_ON(ENERGEST_TYPE_LISTEN);
00469   return 1;
00470 }
00471 /*---------------------------------------------------------------------------*/
00472 static int
00473 off(void)
00474 {
00475   CC2530_CSP_ISRFOFF();
00476   CC2530_CSP_ISFLUSHRX();
00477 
00478   rf_flags &= ~RX_ACTIVE;
00479 
00480   ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
00481   return 1;
00482 }
00483 /*---------------------------------------------------------------------------*/
00484 const struct radio_driver cc2530_rf_driver =
00485 {
00486     init,
00487     prepare,
00488     transmit,
00489     send,
00490     read,
00491     channel_clear,
00492     receiving_packet,
00493     pending_packet,
00494     on,
00495     off,
00496 };
00497 /*---------------------------------------------------------------------------*/