Contiki 2.6
|
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 /*---------------------------------------------------------------------------*/