48 #include "sys/clock.h" 51 #include "dev/watchdog.h" 54 #include <ti/devices/DeviceFamily.h> 55 #include DeviceFamily_constructPath(driverlib/rf_mailbox.h) 56 #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h) 57 #include DeviceFamily_constructPath(driverlib/rf_data_entry.h) 58 #include DeviceFamily_constructPath(driverlib/rf_prop_cmd.h) 59 #include DeviceFamily_constructPath(driverlib/rf_prop_mailbox.h) 61 #include <ti/drivers/rf/RF.h> 79 #define LOG_MODULE "Radio" 80 #define LOG_LEVEL LOG_LEVEL_NONE 83 #define CLAMP(v, vmin, vmax) (MAX(MIN(v, vmax), vmin)) 86 #define PROP_MODE_DYN_WHITENER PROP_MODE_CONF_DW 87 #define PROP_MODE_USE_CRC16 PROP_MODE_CONF_USE_CRC16 88 #define PROP_MODE_CENTER_FREQ PROP_MODE_CONF_CENTER_FREQ 89 #define PROP_MODE_LO_DIVIDER PROP_MODE_CONF_LO_DIVIDER 90 #define PROP_MODE_CCA_RSSI_THRESHOLD PROP_MODE_CONF_CCA_RSSI_THRESHOLD 100 #define DOT_4G_MAX_FRAME_LEN 2047 101 #define DOT_4G_PHR_LEN 2 104 #define DOT_4G_PHR_CRC16 0x10 105 #define DOT_4G_PHR_DW 0x08 107 #if PROP_MODE_USE_CRC16 109 #define DOT_4G_PHR_CRC_BIT DOT_4G_PHR_CRC16 113 #define DOT_4G_PHR_CRC_BIT 0 117 #if PROP_MODE_DYN_WHITENER 118 #define DOT_4G_PHR_DW_BIT DOT_4G_PHR_DW 120 #define DOT_4G_PHR_DW_BIT 0 124 #define TIMEOUT_ENTER_RX_WAIT (RTIMER_SECOND >> 10) 127 #define TIMEOUT_DATA_ENTRY_BUSY (RTIMER_SECOND / 250) 130 #define TX_BUF_HDR_LEN 2 131 #define TX_BUF_PAYLOAD_LEN 180 133 #define TX_BUF_SIZE (TX_BUF_HDR_LEN + TX_BUF_PAYLOAD_LEN) 136 typedef uint16_t lensz_t;
138 #define FRAME_OFFSET sizeof(lensz_t) 139 #define FRAME_SHAVE 2 142 #define RX_SENSITIVITY_DBM -110 143 #define RX_SATURATION_DBM 10 144 #define ED_MIN_DBM_ABOVE_RX_SENSITIVITY 10 147 #define ED_RF_POWER_MIN_DBM (RX_SENSITIVITY_DBM + ED_MIN_DBM_ABOVE_RX_SENSITIVITY) 148 #define ED_RF_POWER_MAX_DBM RX_SATURATION_DBM 151 typedef rfc_propRxOutput_t rx_output_t;
155 uint8_t tx_buf[TX_BUF_SIZE] CC_ALIGN(4);
158 rx_output_t rx_stats;
161 int8_t rssi_threshold;
171 static prop_radio_t prop_radio;
174 #define cmd_radio_setup (*(volatile rfc_CMD_PROP_RADIO_DIV_SETUP_t *)&rf_cmd_prop_radio_div_setup) 175 #define cmd_fs (*(volatile rfc_CMD_FS_t *) &rf_cmd_prop_fs) 176 #define cmd_tx (*(volatile rfc_CMD_PROP_TX_ADV_t *) &rf_cmd_prop_tx_adv) 177 #define cmd_rx (*(volatile rfc_CMD_PROP_RX_ADV_t *) &rf_cmd_prop_rx_adv) 182 return cmd_tx.status == ACTIVE;
188 return cmd_rx.status == ACTIVE;
192 static int off(
void);
197 cmd_radio_setup.config.frontEndMode = RF_SUB_1_GHZ_FRONT_END_MODE;
198 cmd_radio_setup.config.biasMode = RF_SUB_1_GHZ_BIAS_MODE;
199 cmd_radio_setup.centerFreq = PROP_MODE_CENTER_FREQ;
200 cmd_radio_setup.loDivider = PROP_MODE_LO_DIVIDER;
202 data_queue_t *data_queue = data_queue_init(
sizeof(lensz_t));
204 cmd_rx.maxPktLen = DOT_4G_MAX_FRAME_LEN - cmd_rx.lenOffset;
205 cmd_rx.pQueue = data_queue;
206 cmd_rx.pOutput = (uint8_t *)&prop_radio.rx_stats;
213 bool stop_rx =
false;
214 int8_t rssi = RF_GET_RSSI_ERROR_VAL;
217 if(!rx_is_active()) {
219 if(cmd_rx.status != PENDING) {
220 res = netstack_sched_rx(
false);
221 if(res != RF_RESULT_OK) {
222 LOG_ERR(
"RSSI measurement failed to schedule RX\n");
233 if(!rx_is_active()) {
234 LOG_ERR(
"RSSI measurement failed to turn on RX, RX status=0x%04X\n", cmd_rx.status);
235 return RF_RESULT_ERROR;
240 rssi = RF_getRssi(prop_radio.rf_handle);
252 uint32_t freq_khz = cmd_fs.frequency * 1000;
260 freq_khz += (((cmd_fs.fractFreq * 1000) + 65535) / 65536);
262 return (uint8_t)((freq_khz - DOT_15_4G_CHAN0_FREQ) / DOT_15_4G_FREQ_SPACING);
270 if(!dot_15_4g_chan_in_range(channel)) {
271 LOG_WARN(
"Supplied hannel %d is illegal, defaults to %d\n",
272 (
int)channel, DOT_15_4G_DEFAULT_CHAN);
273 channel = DOT_15_4G_DEFAULT_CHAN;
276 if(channel == prop_radio.channel) {
281 const uint32_t new_freq = dot_15_4g_freq(channel);
282 const uint16_t freq = (uint16_t)(new_freq / 1000);
283 const uint16_t frac = (uint16_t)(((new_freq - (freq * 1000)) * 0x10000) / 1000);
285 LOG_DBG(
"Set channel to %d, frequency 0x%04X.0x%04X (%lu)\n",
286 (
int)channel, freq, frac, new_freq);
288 cmd_fs.frequency = freq;
289 cmd_fs.fractFreq = frac;
291 res = netstack_sched_fs();
293 if(res != RF_RESULT_OK) {
297 prop_radio.channel = channel;
302 calculate_lqi(int8_t rssi)
309 rssi = CLAMP(rssi, ED_RF_POWER_MIN_DBM, ED_RF_POWER_MAX_DBM);
317 return (ED_MAX * (rssi - ED_RF_POWER_MIN_DBM)) / (ED_RF_POWER_MAX_DBM - ED_RF_POWER_MIN_DBM);
321 prepare(
const void *payload,
unsigned short payload_len)
323 if(payload_len > TX_BUF_PAYLOAD_LEN || payload_len > NETSTACK_RADIO_MAX_PAYLOAD_LEN) {
327 memcpy(prop_radio.tx_buf + TX_BUF_HDR_LEN, payload, payload_len);
332 transmit(
unsigned short transmit_len)
336 if(transmit_len > NETSTACK_RADIO_MAX_PAYLOAD_LEN) {
337 LOG_ERR(
"Too long\n");
342 LOG_ERR(
"A transmission is already active\n");
347 const uint16_t total_length = transmit_len + CRC_LEN;
356 prop_radio.tx_buf[0] = ((total_length >> 0) & 0xFF);
357 prop_radio.tx_buf[1] = ((total_length >> 8) & 0xFF) + DOT_4G_PHR_DW_BIT + DOT_4G_PHR_CRC_BIT;
361 cmd_tx.pktLen = transmit_len + DOT_4G_PHR_LEN;
362 cmd_tx.pPkt = prop_radio.tx_buf;
364 res = netstack_sched_prop_tx();
366 return (res == RF_RESULT_OK)
372 send(
const void *payload,
unsigned short payload_len)
379 read(
void *buf,
unsigned short buf_len)
381 volatile data_entry_t *data_entry = data_queue_current_entry();
385 while((data_entry->status == DATA_ENTRY_BUSY) &&
386 RTIMER_CLOCK_LT(
RTIMER_NOW(), t0 + TIMEOUT_DATA_ENTRY_BUSY)) ;
388 if(data_entry->status != DATA_ENTRY_FINISHED) {
414 uint8_t *
const frame_ptr = (uint8_t *)&data_entry->data;
415 const lensz_t frame_len = *(lensz_t *)frame_ptr;
419 LOG_ERR(
"Received rame is too short, len=%d\n", frame_len);
421 data_queue_release_entry();
425 const uint8_t *payload_ptr = frame_ptr +
sizeof(lensz_t);
426 const unsigned short payload_len = (
unsigned short)(frame_len -
FRAME_SHAVE);
429 if(payload_len > buf_len) {
430 LOG_ERR(
"Payload of received frame is too large for local buffer, len=%d buf_len=%d\n",
431 payload_len, buf_len);
433 data_queue_release_entry();
437 memcpy(buf, payload_ptr, payload_len);
440 const int8_t rssi = (int8_t)payload_ptr[payload_len];
442 const uint8_t lqi = calculate_lqi(rssi);
444 packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (packetbuf_attr_t)rssi);
445 packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, (packetbuf_attr_t)lqi);
447 data_queue_release_entry();
448 return (
int)payload_len;
454 const int8_t rssi = get_rssi();
456 if(rssi == RF_GET_RSSI_ERROR_VAL) {
457 return CCA_STATE_INVALID;
460 return (rssi < prop_radio.rssi_threshold)
469 LOG_ERR(
"Channel clear called while in TX\n");
473 const uint8_t cca_state = cca_request();
476 return cca_state == CCA_STATE_IDLE;
482 if(!rx_is_active()) {
486 const uint8_t cca_state = cca_request();
488 return cca_state == CCA_STATE_BUSY;
494 const data_entry_t *
const read_entry = data_queue_current_entry();
495 volatile const data_entry_t *curr_entry = read_entry;
501 const uint8_t status = curr_entry->status;
502 if((status == DATA_ENTRY_FINISHED) ||
503 (status == DATA_ENTRY_BUSY)) {
508 curr_entry = (data_entry_t *)curr_entry->pNextEntry;
509 }
while(curr_entry != read_entry);
511 if(num_pending > 0) {
524 if(prop_radio.rf_is_on) {
525 LOG_WARN(
"Radio is already on\n");
531 res = netstack_sched_rx(
true);
533 if(res != RF_RESULT_OK) {
534 return RF_RESULT_ERROR;
537 prop_radio.rf_is_on =
true;
544 if(!prop_radio.rf_is_on) {
545 LOG_WARN(
"Radio is already off\n");
551 prop_radio.rf_is_on =
false;
555 static radio_result_t
561 return RADIO_RESULT_INVALID_VALUE;
565 case RADIO_PARAM_POWER_MODE:
567 *value = (prop_radio.rf_is_on)
568 ? RADIO_POWER_MODE_ON
569 : RADIO_POWER_MODE_OFF;
571 return RADIO_RESULT_OK;
573 case RADIO_PARAM_CHANNEL:
575 return RADIO_RESULT_OK;
577 case RADIO_PARAM_TXPOWER:
578 res = rf_get_tx_power(prop_radio.rf_handle, rf_tx_power_table, (int8_t *)&value);
579 return ((res == RF_RESULT_OK) &&
580 (*value != RF_TxPowerTable_INVALID_DBM))
582 : RADIO_RESULT_ERROR;
584 case RADIO_PARAM_CCA_THRESHOLD:
585 *value = prop_radio.rssi_threshold;
586 return RADIO_RESULT_OK;
588 case RADIO_PARAM_RSSI:
590 return (*value == RF_GET_RSSI_ERROR_VAL)
594 case RADIO_CONST_CHANNEL_MIN:
595 *value = DOT_15_4G_CHAN_MIN;
596 return RADIO_RESULT_OK;
598 case RADIO_CONST_CHANNEL_MAX:
599 *value = DOT_15_4G_CHAN_MAX;
600 return RADIO_RESULT_OK;
602 case RADIO_CONST_TXPOWER_MIN:
604 return RADIO_RESULT_OK;
606 case RADIO_CONST_TXPOWER_MAX:
607 *value = (
radio_value_t)tx_power_max(rf_tx_power_table, rf_tx_power_table_size);
608 return RADIO_RESULT_OK;
611 return RADIO_RESULT_NOT_SUPPORTED;
615 static radio_result_t
621 case RADIO_PARAM_POWER_MODE:
623 if(value == RADIO_POWER_MODE_ON) {
624 return (
on() == RF_RESULT_OK)
626 : RADIO_RESULT_ERROR;
627 }
else if(value == RADIO_POWER_MODE_OFF) {
629 return RADIO_RESULT_OK;
632 return RADIO_RESULT_INVALID_VALUE;
634 case RADIO_PARAM_CHANNEL:
636 return (res == RF_RESULT_OK)
638 : RADIO_RESULT_ERROR;
640 case RADIO_PARAM_TXPOWER:
641 if(!tx_power_in_range((int8_t)value, rf_tx_power_table, rf_tx_power_table_size)) {
642 return RADIO_RESULT_INVALID_VALUE;
644 res = rf_set_tx_power(prop_radio.rf_handle, rf_tx_power_table, (int8_t)value);
645 return (res == RF_RESULT_OK)
647 : RADIO_RESULT_ERROR;
649 case RADIO_PARAM_RX_MODE:
650 return RADIO_RESULT_OK;
652 case RADIO_PARAM_CCA_THRESHOLD:
653 prop_radio.rssi_threshold = (int8_t)value;
654 return RADIO_RESULT_OK;
657 return RADIO_RESULT_NOT_SUPPORTED;
661 static radio_result_t
662 get_object(radio_param_t param,
void *dest,
size_t size)
664 return RADIO_RESULT_NOT_SUPPORTED;
667 static radio_result_t
668 set_object(radio_param_t param,
const void *src,
size_t size)
670 return RADIO_RESULT_NOT_SUPPORTED;
676 if(prop_radio.rf_handle) {
677 LOG_WARN(
"Radio is already initialized\n");
682 prop_radio.rf_is_on =
false;
685 prop_radio.rssi_threshold = PROP_MODE_CCA_RSSI_THRESHOLD;
691 RF_Params_init(&rf_params);
695 prop_radio.rf_handle = netstack_open(&rf_params);
697 if(prop_radio.rf_handle == NULL) {
698 LOG_ERR(
"Unable to open RF driver during initialization\n");
699 return RF_RESULT_ERROR;
704 ENERGEST_ON(ENERGEST_TYPE_LISTEN);
radio_result_t(* get_object)(radio_param_t param, void *dest, size_t size)
Get a radio parameter object.
Header file with descriptors for the various modes of operation defined in IEEE 802.15.4g.
int(* prepare)(const void *payload, unsigned short payload_len)
Prepare the radio with a packet to be sent.
Header file of TX power functionality of CC13xx/CC26xx.
static uint8_t rf_is_on(void)
Checks whether the RFC domain is accessible and the RFC is in IEEE RX.
#define FRAME_SHAVE
RSSI (1) + Status (1)
Header file for the energy estimation mechanism
int(* receiving_packet)(void)
Check if the radio driver is currently receiving a packet.
radio_result_t(* set_value)(radio_param_t param, radio_value_t value)
Set a radio parameter value.
int(* pending_packet)(void)
Check if the radio driver has just received a packet.
The structure of a device driver for a radio in Contiki.
#define RTIMER_BUSYWAIT_UNTIL(cond, max_time)
Busy-wait until a condition for at most max_time.
static void set_channel(uint8_t channel)
Set the current operating channel.
int(* channel_clear)(void)
Perform a Clear-Channel Assessment (CCA) to find out if there is a packet in the air or not...
int radio_value_t
Each radio has a set of parameters that designate the current configuration and state of the radio...
#define IEEE802154_DEFAULT_CHANNEL
The default channel for IEEE 802.15.4 networks.
#define RTIMER_NOW()
Get the current clock time.
Header file of the CC13xx/CC26xx RF scheduler.
int(* send)(const void *payload, unsigned short payload_len)
Prepare & transmit a packet.
int(* transmit)(unsigned short transmit_len)
Send the packet that has previously been prepared.
void process_poll(struct process *p)
Request a process to be polled.
int(* off)(void)
Turn the radio off.
#define RF_CONF_INACTIVITY_TIMEOUT
2 ms
Header file for the real-time timer module.
Header file of the CC13xx/CC26xx RF data queue.
Header file of RF settings for CC13xx/CC26xx.
int(* read)(void *buf, unsigned short buf_len)
Read a received packet into a buffer.
Header file of common CC13xx/CC26xx RF functionality.
Header file for the Packet buffer (packetbuf) management
Include file for the Contiki low-layer network stack (NETSTACK)
radio_result_t(* get_value)(radio_param_t param, radio_value_t *value)
Get a radio parameter value.
Default definitions of C compiler quirk work-arounds.
Header file for the logging system
radio_result_t(* set_object)(radio_param_t param, const void *src, size_t size)
Set a radio parameter object.
int(* on)(void)
Turn the radio on.
void process_start(struct process *p, process_data_t data)
Start a process.
static uint8_t get_channel()
Get the current operating channel.