44 #include "sys/clock.h"
54 #define CHECKSUM_LEN 2
56 #if CC2530_RF_CONF_LEDS
57 #define CC2530_RF_LEDS CC2530_RF_CONF_LEDS
59 #define CC2530_RF_LEDS 0
64 #define RF_RX_LED_ON() leds_on(LEDS_RED);
65 #define RF_RX_LED_OFF() leds_off(LEDS_RED);
66 #define RF_TX_LED_ON() leds_on(LEDS_GREEN);
67 #define RF_TX_LED_OFF() leds_off(LEDS_GREEN);
69 #define RF_RX_LED_ON()
70 #define RF_RX_LED_OFF()
71 #define RF_TX_LED_ON()
72 #define RF_TX_LED_OFF()
78 #define PUTSTRING(...) putstring(__VA_ARGS__)
79 #define PUTHEX(...) puthex(__VA_ARGS__)
81 #define PUTSTRING(...)
86 #define RX_ACTIVE 0x80
91 #define CRC_BIT_MASK 0x80
92 #define LQI_BIT_MASK 0x7F
94 #define RSSI_OFFSET 73
97 #define ONOFF_TIME RTIMER_ARCH_SECOND / 3125
99 #define CC2530_RF_CHANNEL_SET_ERROR -1
101 #define CC2530_RF_TX_POWER_TXCTRL_MIN_VAL 0x09
102 #define CC2530_RF_TX_POWER_TXCTRL_DEF_VAL 0x69
104 #if CC2530_RF_CONF_HEXDUMP
106 static const uint8_t magic[] = { 0x53, 0x6E, 0x69, 0x66 };
109 #ifdef CC2530_RF_CONF_AUTOACK
110 #define CC2530_RF_AUTOACK CC2530_RF_CONF_AUTOACK
112 #define CC2530_RF_AUTOACK 1
115 static uint8_t CC_AT_DATA rf_flags;
118 static int off(
void);
119 static int channel_clear(
void);
122 typedef struct output_config {
127 static const output_config_t output_power[] = {
147 #define OUTPUT_CONFIG_COUNT (sizeof(output_power) / sizeof(output_config_t))
150 #define OUTPUT_POWER_MIN (output_power[OUTPUT_CONFIG_COUNT - 1].power)
151 #define OUTPUT_POWER_MAX (output_power[0].power)
160 return (uint8_t)((FREQCTRL + 44) / 5);
170 set_channel(uint8_t channel)
172 PUTSTRING(
"RF: Set Chan\n");
174 if((channel < CC2530_RF_CHANNEL_MIN) || (channel > CC2530_RF_CHANNEL_MAX)) {
175 return CC2530_RF_CHANNEL_SET_ERROR;
181 FREQCTRL = (CC2530_RF_CHANNEL_MIN
182 + (channel - CC2530_RF_CHANNEL_MIN) * CC2530_RF_CHANNEL_SPACING);
185 return (int8_t)channel;
195 set_pan_id(uint16_t pan)
197 PAN_ID0 = pan & 0xFF;
208 set_short_addr(uint16_t addr)
210 SHORT_ADDR0 = addr & 0xFF;
211 SHORT_ADDR1 = addr >> 8;
233 while((RSSISTAT & RSSISTAT_RSSI_VALID) == 0);
238 if((rf_flags & WAS_OFF) == WAS_OFF) {
239 rf_flags &= ~WAS_OFF;
248 get_cca_threshold(
void)
250 return (int8_t)CCACTRL0 - RSSI_OFFSET;
257 CCACTRL0 = (value + RSSI_OFFSET) & 0xFF;
265 uint8_t reg_val = TXPOWER;
267 if(TXCTRL == CC2530_RF_TX_POWER_TXCTRL_MIN_VAL) {
268 return OUTPUT_POWER_MIN;
277 for(i = 0; i < OUTPUT_CONFIG_COUNT; i++) {
278 if(reg_val >= output_power[i].txpower_val) {
279 return output_power[i].power;
282 return OUTPUT_POWER_MIN;
296 if(power <= output_power[OUTPUT_CONFIG_COUNT - 1].power) {
297 TXCTRL = CC2530_RF_TX_POWER_TXCTRL_MIN_VAL;
298 TXPOWER = output_power[OUTPUT_CONFIG_COUNT - 1].txpower_val;
302 for(i = OUTPUT_CONFIG_COUNT - 2; i >= 0; --i) {
303 if(power <= output_power[i].power) {
305 TXCTRL = CC2530_RF_TX_POWER_TXCTRL_DEF_VAL;
306 TXPOWER = output_power[i].txpower_val;
313 set_frame_filtering(uint8_t enable)
316 FRMFILT0 |= FRMFILT0_FRAME_FILTER_EN;
318 FRMFILT0 &= ~FRMFILT0_FRAME_FILTER_EN;
323 set_auto_ack(uint8_t enable)
326 FRMCTRL0 |= FRMCTRL0_AUTOACK;
328 FRMCTRL0 &= ~FRMCTRL0_AUTOACK;
337 PUTSTRING(
"RF: Init\n");
339 if(rf_flags & RF_ON) {
343 #if CC2530_RF_LOW_POWER_RX
352 CCACTRL0 = CC2530_RF_CCA_THRES;
365 FRMCTRL0 = FRMCTRL0_AUTOCRC;
366 #if CC2530_RF_AUTOACK
367 FRMCTRL0 |= FRMCTRL0_AUTOACK;
374 FIFOPCTRL = CC2530_RF_MAX_PACKET_LEN;
376 TXPOWER = CC2530_RF_TX_POWER;
387 prepare(
const void *payload,
unsigned short payload_len)
391 PUTSTRING(
"RF: Prepare 0x");
392 PUTHEX(payload_len + CHECKSUM_LEN);
393 PUTSTRING(
" bytes\n");
399 while(FSMSTAT1 & FSMSTAT1_TX_ACTIVE);
401 if((rf_flags & RX_ACTIVE) == 0) {
405 CC2530_CSP_ISFLUSHTX();
407 PUTSTRING(
"RF: data = ");
409 RFD = payload_len + CHECKSUM_LEN;
410 for(i = 0; i < payload_len; i++) {
411 RFD = ((
unsigned char *)(payload))[i];
412 PUTHEX(((
unsigned char *)(payload))[i]);
424 transmit(
unsigned short transmit_len)
427 int ret = RADIO_TX_ERR;
431 if(!(rf_flags & RX_ACTIVE)) {
435 while(RTIMER_CLOCK_LT(
RTIMER_NOW(), t0 + ONOFF_TIME));
438 if(channel_clear() == CC2530_RF_CCA_BUSY) {
439 RIMESTATS_ADD(contentiondrop);
440 return RADIO_TX_COLLISION;
447 if(FSMSTAT1 & FSMSTAT1_SFD) {
448 RIMESTATS_ADD(contentiondrop);
449 return RADIO_TX_COLLISION;
454 ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
455 ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);
460 while(!(FSMSTAT1 & FSMSTAT1_TX_ACTIVE) && (counter++ < 3)) {
464 if(!(FSMSTAT1 & FSMSTAT1_TX_ACTIVE)) {
465 PUTSTRING(
"RF: TX never active.\n");
466 CC2530_CSP_ISFLUSHTX();
470 while(FSMSTAT1 & FSMSTAT1_TX_ACTIVE);
473 ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
474 ENERGEST_ON(ENERGEST_TYPE_LISTEN);
476 if(rf_flags & WAS_OFF) {
489 send(
void *payload,
unsigned short payload_len)
491 prepare(payload, payload_len);
492 return transmit(payload_len);
496 read(
void *buf,
unsigned short bufsize)
503 PUTSTRING(
"RF: Read\n");
509 if(len > CC2530_RF_MAX_PACKET_LEN) {
511 PUTSTRING(
"RF: bad sync\n");
513 RIMESTATS_ADD(badsynch);
514 CC2530_CSP_ISFLUSHRX();
518 if(len <= CC2530_RF_MIN_PACKET_LEN) {
519 PUTSTRING(
"RF: too short\n");
521 RIMESTATS_ADD(tooshort);
522 CC2530_CSP_ISFLUSHRX();
526 if(len - CHECKSUM_LEN > bufsize) {
527 PUTSTRING(
"RF: too long\n");
529 RIMESTATS_ADD(toolong);
530 CC2530_CSP_ISFLUSHRX();
534 #if CC2530_RF_CONF_HEXDUMP
536 io_arch_writeb(magic[0]);
537 io_arch_writeb(magic[1]);
538 io_arch_writeb(magic[2]);
539 io_arch_writeb(magic[3]);
545 PUTSTRING(
"RF: read (0x");
547 PUTSTRING(
" bytes) = ");
549 for(i = 0; i < len; ++i) {
550 ((
unsigned char *)(buf))[i] = RFD;
551 #if CC2530_RF_CONF_HEXDUMP
552 io_arch_writeb(((
unsigned char *)(buf))[i]);
554 PUTHEX(((
unsigned char *)(buf))[i]);
559 rssi = ((int8_t) RFD) - RSSI_OFFSET;
562 #if CC2530_RF_CONF_HEXDUMP
563 io_arch_writeb(rssi);
564 io_arch_writeb(crc_corr);
569 if(crc_corr & CRC_BIT_MASK) {
570 packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rssi);
571 packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, crc_corr & LQI_BIT_MASK);
574 RIMESTATS_ADD(badcrc);
575 CC2530_CSP_ISFLUSHRX();
581 if((FSMSTAT1 & (FSMSTAT1_FIFO | FSMSTAT1_FIFOP)) == FSMSTAT1_FIFOP) {
590 CC2530_CSP_ISFLUSHRX();
602 if(FSMSTAT1 & FSMSTAT1_CCA) {
603 return CC2530_RF_CCA_CLEAR;
605 return CC2530_RF_CCA_BUSY;
609 receiving_packet(
void)
611 PUTSTRING(
"RF: Receiving\n");
619 return (FSMSTAT1 & (FSMSTAT1_TX_ACTIVE | FSMSTAT1_SFD) == FSMSTAT1_SFD);
625 return (FSMSTAT1 & FSMSTAT1_FIFOP);
631 if(!(rf_flags & RX_ACTIVE)) {
632 CC2530_CSP_ISFLUSHRX();
635 rf_flags |= RX_ACTIVE;
638 ENERGEST_ON(ENERGEST_TYPE_LISTEN);
645 CC2530_CSP_ISRFOFF();
646 CC2530_CSP_ISFLUSHRX();
648 rf_flags &= ~RX_ACTIVE;
650 ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
654 static radio_result_t
658 return RADIO_RESULT_INVALID_VALUE;
662 case RADIO_PARAM_POWER_MODE:
663 *value = RXENABLE == 0 ? RADIO_POWER_MODE_OFF : RADIO_POWER_MODE_ON;
664 return RADIO_RESULT_OK;
665 case RADIO_PARAM_CHANNEL:
667 return RADIO_RESULT_OK;
668 case RADIO_PARAM_PAN_ID:
669 *value = get_pan_id();
670 return RADIO_RESULT_OK;
671 case RADIO_PARAM_16BIT_ADDR:
672 *value = get_short_addr();
673 return RADIO_RESULT_OK;
674 case RADIO_PARAM_RX_MODE:
676 if(FRMFILT0 & FRMFILT0_FRAME_FILTER_EN) {
679 if(FRMCTRL0 & FRMCTRL0_AUTOACK) {
680 *value |= RADIO_RX_MODE_AUTOACK;
682 return RADIO_RESULT_OK;
683 case RADIO_PARAM_TXPOWER:
684 *value = get_tx_power();
685 return RADIO_RESULT_OK;
686 case RADIO_PARAM_CCA_THRESHOLD:
687 *value = get_cca_threshold();
688 return RADIO_RESULT_OK;
689 case RADIO_PARAM_RSSI:
691 return RADIO_RESULT_OK;
692 case RADIO_CONST_CHANNEL_MIN:
693 *value = CC2530_RF_CHANNEL_MIN;
694 return RADIO_RESULT_OK;
695 case RADIO_CONST_CHANNEL_MAX:
696 *value = CC2530_RF_CHANNEL_MAX;
697 return RADIO_RESULT_OK;
698 case RADIO_CONST_TXPOWER_MIN:
699 *value = OUTPUT_POWER_MIN;
700 return RADIO_RESULT_OK;
701 case RADIO_CONST_TXPOWER_MAX:
702 *value = OUTPUT_POWER_MAX;
703 return RADIO_RESULT_OK;
705 return RADIO_RESULT_NOT_SUPPORTED;
709 static radio_result_t
713 case RADIO_PARAM_POWER_MODE:
714 if(value == RADIO_POWER_MODE_ON) {
716 return RADIO_RESULT_OK;
718 if(value == RADIO_POWER_MODE_OFF) {
720 return RADIO_RESULT_OK;
722 return RADIO_RESULT_INVALID_VALUE;
723 case RADIO_PARAM_CHANNEL:
724 if(value < CC2530_RF_CHANNEL_MIN || value > CC2530_RF_CHANNEL_MAX) {
725 return RADIO_RESULT_INVALID_VALUE;
727 if(set_channel(value) == CC2530_RF_CHANNEL_SET_ERROR) {
728 return RADIO_RESULT_ERROR;
730 return RADIO_RESULT_OK;
731 case RADIO_PARAM_PAN_ID:
732 set_pan_id(value & 0xffff);
733 return RADIO_RESULT_OK;
734 case RADIO_PARAM_16BIT_ADDR:
735 set_short_addr(value & 0xffff);
736 return RADIO_RESULT_OK;
737 case RADIO_PARAM_RX_MODE:
739 RADIO_RX_MODE_AUTOACK)) {
740 return RADIO_RESULT_INVALID_VALUE;
744 set_auto_ack((value & RADIO_RX_MODE_AUTOACK) != 0);
746 return RADIO_RESULT_OK;
747 case RADIO_PARAM_TXPOWER:
748 if(value < OUTPUT_POWER_MIN || value > OUTPUT_POWER_MAX) {
749 return RADIO_RESULT_INVALID_VALUE;
753 return RADIO_RESULT_OK;
754 case RADIO_PARAM_CCA_THRESHOLD:
755 set_cca_threshold(value);
756 return RADIO_RESULT_OK;
758 return RADIO_RESULT_NOT_SUPPORTED;
762 static radio_result_t
763 get_object(radio_param_t param,
void *dest,
size_t size)
768 if(param == RADIO_PARAM_64BIT_ADDR) {
769 if(size != 8 || !dest) {
770 return RADIO_RESULT_INVALID_VALUE;
774 for(i = 0; i < 8; i++) {
775 target[i] = ((uint8_t *)&EXT_ADDR0)[7 - i] & 0xFF;
778 return RADIO_RESULT_OK;
780 return RADIO_RESULT_NOT_SUPPORTED;
783 static radio_result_t
784 set_object(radio_param_t param,
const void *src,
size_t size)
788 if(param == RADIO_PARAM_64BIT_ADDR) {
789 if(size != 8 || !src) {
790 return RADIO_RESULT_INVALID_VALUE;
793 for(i = 0; i < 8; i++) {
794 ((uint8_t *)&EXT_ADDR0)[i] = ((uint8_t *)src)[7 - i];
797 return RADIO_RESULT_OK;
799 return RADIO_RESULT_NOT_SUPPORTED;
#define RADIO_RX_MODE_ADDRESS_FILTER
The radio reception mode controls address filtering and automatic transmission of acknowledgements in...
void clock_delay_usec(uint16_t dt)
Delay a given number of microseconds.
Header file for the radio API
Header file for the Rime buffer (packetbuf) management
The structure of a device driver for a radio in Contiki.
Definitions for TI/Chipcon cc2530, cc2531 and cc2533 SFR registers.
int(* pending_packet)(void)
Check if the radio driver has just received a packet.
int radio_value_t
Each radio has a set of parameters that designate the current configuration and state of the radio...
int(* prepare)(const void *payload, unsigned short payload_len)
Prepare the radio with a packet to be sent.
int(* send)(const void *payload, unsigned short payload_len)
Prepare & transmit a packet.
Header file with definitions of bit masks for some cc2530 SFRs
int(* receiving_packet)(void)
Check if the radio driver is currently receiving a packet.
int(* channel_clear)(void)
Perform a Clear-Channel Assessment (CCA) to find out if there is a packet in the air or not...
Header file for the real-time timer module.
int(* on)(void)
Turn the radio on.
radio_result_t(* get_value)(radio_param_t param, radio_value_t *value)
Get a radio parameter value.
Platform-specific header file which switches between UART and USB input/output, depending on whether we are building for the cc2531 USB dongle or the SmartRF
radio_result_t(* get_object)(radio_param_t param, void *dest, size_t size)
Get a radio parameter object.
int(* transmit)(unsigned short transmit_len)
Send the packet that has previously been prepared.
Implementation of the cc2530 RF driver
#define RTIMER_NOW()
Get the current clock time.
Header file for Rime statistics
radio_result_t(* set_object)(radio_param_t param, const void *src, size_t size)
Set a radio parameter object.
radio_result_t(* set_value)(radio_param_t param, radio_value_t value)
Set a radio parameter value.
int(* read)(void *buf, unsigned short buf_len)
Read a received packet into a buffer.
int(* off)(void)
Turn the radio off.
Include file for the Contiki low-layer network stack (NETSTACK)
Header file for the Rime address representation