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>
62#include DeviceFamily_constructPath(inc/hw_rfc_dbell.h)
63#include DeviceFamily_constructPath(driverlib/rfc.h)
82#if RADIO_PAYLOAD_BIT_REVERSE
88#define LOG_MODULE "Radio"
89#define LOG_LEVEL LOG_LEVEL_NONE
92#define CLAMP(v, vmin, vmax) (MAX(MIN(v, vmax), vmin))
95#define PROP_MODE_DYN_WHITENER PROP_MODE_CONF_DW
96#define PROP_MODE_USE_CRC16 PROP_MODE_CONF_USE_CRC16
97#define PROP_MODE_CENTER_FREQ PROP_MODE_CONF_CENTER_FREQ
98#define PROP_MODE_LO_DIVIDER PROP_MODE_CONF_LO_DIVIDER
99#define PROP_MODE_CCA_RSSI_THRESHOLD PROP_MODE_CONF_CCA_RSSI_THRESHOLD
105 CCA_STATE_INVALID = 2
108#if MAC_CONF_WITH_TSCH
109static volatile uint8_t is_receiving_packet;
113#define DOT_4G_PHR_NUM_BYTES 2
114#define DOT_4G_LEN_OFFSET 0xFC
115#define DOT_4G_SYNCWORD 0x0055904E
118#define DOT_4G_PHR_CRC16 0x10
119#define DOT_4G_PHR_DW 0x08
121#if PROP_MODE_USE_CRC16
123#define DOT_4G_PHR_CRC_BIT DOT_4G_PHR_CRC16
127#define DOT_4G_PHR_CRC_BIT 0
131#if PROP_MODE_DYN_WHITENER
132#define DOT_4G_PHR_DW_BIT DOT_4G_PHR_DW
134#define DOT_4G_PHR_DW_BIT 0
153#define MAX_PAYLOAD_LEN 125
156#define TIMEOUT_ENTER_RX_WAIT (RTIMER_SECOND >> 10)
162#define RAT_TIMESTAMP_OFFSET USEC_TO_RAT(RADIO_PHY_HEADER_LEN * RADIO_BYTE_AIR_TIME - 270)
165#define TX_BUF_HDR_LEN 2
166#define TX_BUF_PAYLOAD_LEN 180
168#define TX_BUF_SIZE (TX_BUF_HDR_LEN + TX_BUF_PAYLOAD_LEN)
171typedef uint16_t lensz_t;
173#define FRAME_OFFSET sizeof(lensz_t)
177#define RX_SENSITIVITY_DBM -110
178#define RX_SATURATION_DBM 10
179#define ED_MIN_DBM_ABOVE_RX_SENSITIVITY 10
182#define ED_RF_POWER_MIN_DBM (RX_SENSITIVITY_DBM + ED_MIN_DBM_ABOVE_RX_SENSITIVITY)
183#define ED_RF_POWER_MAX_DBM RX_SATURATION_DBM
186typedef rfc_propRxOutput_t rx_output_t;
197 struct ctimer overflow_timer;
198 rtimer_clock_t last_overflow;
199 volatile uint32_t overflow_count;
202 bool (* rx_is_active)(void);
205 uint8_t tx_buf[TX_BUF_SIZE] CC_ALIGN(4);
208 rx_output_t rx_stats;
211 int8_t rssi_threshold;
227static prop_radio_t prop_radio;
231#define cmd_radio_setup rf_cmd_prop_radio_div_setup
232#define cmd_fs rf_cmd_prop_fs
233#define cmd_tx rf_cmd_prop_tx_adv
234#define cmd_rx rf_cmd_prop_rx_adv
237#define v_cmd_radio_setup CC_ACCESS_NOW(rfc_CMD_PROP_RADIO_DIV_SETUP_t, rf_cmd_prop_radio_div_setup)
238#define v_cmd_fs CC_ACCESS_NOW(rfc_CMD_FS_t, rf_cmd_prop_fs)
239#define v_cmd_tx CC_ACCESS_NOW(rfc_CMD_PROP_TX_ADV_t, rf_cmd_prop_tx_adv)
240#define v_cmd_rx CC_ACCESS_NOW(rfc_CMD_PROP_RX_ADV_t, rf_cmd_prop_rx_adv)
245 return v_cmd_tx.status == ACTIVE;
251 return v_cmd_rx.status == ACTIVE;
254static int channel_clear(
void);
257static rf_result_t set_channel_force(uint16_t channel);
262 cmd_radio_setup.config.frontEndMode = RF_SUB_1_GHZ_FRONT_END_MODE;
263 cmd_radio_setup.config.biasMode = RF_SUB_1_GHZ_BIAS_MODE;
264 cmd_radio_setup.centerFreq = PROP_MODE_CENTER_FREQ;
265 cmd_radio_setup.loDivider = PROP_MODE_LO_DIVIDER;
267 cmd_tx.numHdrBits = DOT_4G_PHR_NUM_BYTES * 8;
268 cmd_tx.syncWord = DOT_4G_SYNCWORD;
270 cmd_rx.syncWord0 = DOT_4G_SYNCWORD;
271 cmd_rx.syncWord1 = 0x00000000;
272 cmd_rx.maxPktLen = RADIO_PHY_OVERHEAD + MAX_PAYLOAD_LEN;
273 cmd_rx.hdrConf.numHdrBits = DOT_4G_PHR_NUM_BYTES * 8;
274 cmd_rx.lenOffset = DOT_4G_LEN_OFFSET;
275 cmd_rx.pQueue = data_queue_init(
sizeof(lensz_t));
276 cmd_rx.pOutput = (uint8_t *)&prop_radio.rx_stats;
283 bool stop_rx =
false;
284 int8_t rssi = RF_GET_RSSI_ERROR_VAL;
287 if(!rx_is_active()) {
289 if(v_cmd_rx.status != PENDING) {
290 res = netstack_sched_rx(
false);
291 if(res != RF_RESULT_OK) {
292 LOG_ERR(
"RSSI measurement failed to schedule RX\n");
303 if(!rx_is_active()) {
304 LOG_ERR(
"RSSI measurement failed to turn on RX, RX status=0x%04X\n", v_cmd_rx.status);
305 return RF_RESULT_ERROR;
310 rssi = RF_getRssi(prop_radio.rf_handle);
322 uint32_t freq_khz = v_cmd_fs.frequency * 1000;
330 freq_khz += (((v_cmd_fs.fractFreq * 1000) + 65535) / 65536);
332 return (uint8_t)((freq_khz - DOT_15_4G_CHAN0_FREQ) / DOT_15_4G_FREQ_SPACING);
336set_channel(uint16_t channel)
338 if(!dot_15_4g_chan_in_range(channel)) {
339 LOG_WARN(
"Supplied hannel %d is illegal, defaults to %d\n",
340 (
int)channel, DOT_15_4G_DEFAULT_CHAN);
341 channel = DOT_15_4G_DEFAULT_CHAN;
344 if(channel == prop_radio.channel) {
349 return set_channel_force(channel);
354set_channel_force(uint16_t channel)
358 if(prop_radio.rf_is_on) {
363 const uint32_t new_freq = dot_15_4g_freq(channel);
364 const uint16_t freq = (uint16_t)(new_freq / 1000);
365 const uint16_t frac = (uint16_t)(((new_freq - (freq * 1000)) * 0x10000) / 1000);
367 LOG_DBG(
"Set channel to %d, frequency 0x%04X.0x%04X (%" PRIu32
")\n",
368 (
int)channel, freq, frac, new_freq);
370 v_cmd_fs.frequency = freq;
371 v_cmd_fs.fractFreq = frac;
373 res = netstack_sched_fs();
375 if(res != RF_RESULT_OK) {
379 prop_radio.channel = channel;
384calculate_lqi(int8_t rssi)
391 rssi = CLAMP(rssi, ED_RF_POWER_MIN_DBM, ED_RF_POWER_MAX_DBM);
399 return (ED_MAX * (rssi - ED_RF_POWER_MIN_DBM)) / (ED_RF_POWER_MAX_DBM - ED_RF_POWER_MIN_DBM);
403set_send_on_cca(
bool enable)
405 prop_radio.send_on_cca = enable;
409prepare(
const void *payload,
unsigned short payload_len)
411 if(payload_len > TX_BUF_PAYLOAD_LEN || payload_len > MAX_PAYLOAD_LEN) {
415 memcpy(prop_radio.tx_buf + TX_BUF_HDR_LEN, payload, payload_len);
418#if RADIO_PAYLOAD_BIT_REVERSE
419 bitrev_array(prop_radio.tx_buf + TX_BUF_HDR_LEN, payload_len);
425transmit(
unsigned short transmit_len)
429 if(transmit_len > MAX_PAYLOAD_LEN) {
430 LOG_ERR(
"Too long\n");
435 LOG_ERR(
"A transmission is already active\n");
439 if(prop_radio.send_on_cca && !channel_clear()) {
440 LOG_WARN(
"Channel is not clear for transmission\n");
445 const uint16_t total_length = transmit_len + CRC_LEN;
454 prop_radio.tx_buf[0] = ((total_length >> 0) & 0xFF);
455 prop_radio.tx_buf[1] = ((total_length >> 8) & 0xFF) + DOT_4G_PHR_DW_BIT + DOT_4G_PHR_CRC_BIT;
459 v_cmd_tx.pktLen = transmit_len + DOT_4G_PHR_NUM_BYTES;
460 v_cmd_tx.pPkt = prop_radio.tx_buf;
462 res = netstack_sched_prop_tx(transmit_len);
464 if(res != RF_RESULT_OK) {
465 LOG_WARN(
"Channel is not clear for transmission\n");
469 return (res == RF_RESULT_OK)
475send(
const void *payload,
unsigned short payload_len)
477 prepare(payload, payload_len);
478 return transmit(payload_len);
482read(
void *buf,
unsigned short buf_len)
484 volatile data_entry_t *data_entry = data_queue_current_entry();
488 while((data_entry->status == DATA_ENTRY_BUSY) &&
489 RTIMER_CLOCK_LT(
RTIMER_NOW(), t0 + RADIO_FRAME_DURATION(MAX_PAYLOAD_LEN)));
491#if MAC_CONF_WITH_TSCH
493 is_receiving_packet = 0;
496 if(data_entry->status != DATA_ENTRY_FINISHED) {
521 uint8_t *
const frame_ptr = (uint8_t *)&data_entry->data;
522 const lensz_t frame_len = *(lensz_t *)frame_ptr;
526 LOG_ERR(
"Received frame is too short, len=%d\n", frame_len);
528 data_queue_release_entry();
532 const uint8_t *payload_ptr = frame_ptr +
sizeof(lensz_t);
533 const unsigned short payload_len = (
unsigned short)(frame_len -
FRAME_SHAVE);
536 if(payload_len > buf_len) {
537 LOG_ERR(
"Payload of received frame is too large for local buffer, len=%d buf_len=%d\n",
538 payload_len, buf_len);
540 data_queue_release_entry();
544 memcpy(buf, payload_ptr, payload_len);
547#if RADIO_PAYLOAD_BIT_REVERSE
552 prop_radio.last.rssi = (int8_t)payload_ptr[payload_len];
554 prop_radio.last.corr_lqi = calculate_lqi(prop_radio.last.rssi);
557 memcpy(&rat_ticks, payload_ptr + payload_len + 1, 4);
560 prop_radio.last.timestamp = rat_to_timestamp(rat_ticks, RAT_TIMESTAMP_OFFSET);
562 if(!prop_radio.poll_mode) {
566 packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (packetbuf_attr_t)prop_radio.last.rssi);
567 packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, (packetbuf_attr_t)prop_radio.last.corr_lqi);
570 data_queue_release_entry();
571 return (
int)payload_len;
577 const int8_t rssi = get_rssi();
579 if(rssi == RF_GET_RSSI_ERROR_VAL) {
580 return CCA_STATE_INVALID;
583 return (rssi < prop_radio.rssi_threshold)
592 LOG_ERR(
"Channel clear called while in TX\n");
596 const uint8_t cca_state = cca_request();
599 return cca_state == CCA_STATE_IDLE;
603receiving_packet(
void)
605 if(!prop_radio.rf_is_on) {
609#if MAC_CONF_WITH_TSCH
617 if(!is_receiving_packet) {
621 if(HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFHWIFG) & RFC_DBELL_RFHWIFG_MDMSOFT) {
622 is_receiving_packet = 1;
626 is_receiving_packet = (cca_request() == CCA_STATE_BUSY);
627 if(!is_receiving_packet) {
629 RFCHwIntClear(RFC_DBELL_RFHWIFG_MDMSOFT);
633 return is_receiving_packet;
655 if(cca_request() == CCA_STATE_BUSY) {
667 const data_entry_t *
const read_entry = data_queue_current_entry();
668 volatile const data_entry_t *curr_entry = read_entry;
674 const uint8_t status = curr_entry->status;
675 if((status == DATA_ENTRY_FINISHED) ||
676 (status == DATA_ENTRY_BUSY)) {
681 curr_entry = (data_entry_t *)curr_entry->pNextEntry;
682 }
while(curr_entry != read_entry);
684 if(num_pending > 0 && !prop_radio.poll_mode) {
697 if(prop_radio.rf_is_on) {
698 LOG_WARN(
"Radio is already on\n");
704 res = netstack_sched_rx(
true);
706 if(res != RF_RESULT_OK) {
707 return RF_RESULT_ERROR;
710 prop_radio.rf_is_on =
true;
717 if(!prop_radio.rf_is_on) {
718 LOG_WARN(
"Radio is already off\n");
724 prop_radio.rf_is_on =
false;
740 *value = (prop_radio.rf_is_on)
753 if(prop_radio.poll_mode) {
764 res = rf_get_tx_power(prop_radio.rf_handle, rf_tx_power_table, (int8_t *)&value);
765 return ((res == RF_RESULT_OK) &&
766 (*value != RF_TxPowerTable_INVALID_DBM))
771 *value = prop_radio.rssi_threshold;
776 return (*value == RF_GET_RSSI_ERROR_VAL)
781 *value = prop_radio.last.rssi;
785 *value = prop_radio.last.corr_lqi;
789 *value = DOT_15_4G_CHAN_MIN;
793 *value = DOT_15_4G_CHAN_MAX;
801 *value = (
radio_value_t)tx_power_max(rf_tx_power_table, rf_tx_power_table_size);
804 case RADIO_CONST_MAX_PAYLOAD_LEN:
822 return (on() == RF_RESULT_OK)
833 res = set_channel((uint16_t)value);
834 return (res == RF_RESULT_OK)
839 if(!tx_power_in_range((int8_t)value, rf_tx_power_table, rf_tx_power_table_size)) {
842 res = rf_set_tx_power(prop_radio.rf_handle, rf_tx_power_table, (int8_t)value);
843 return (res == RF_RESULT_OK)
853 const bool old_poll_mode = prop_radio.poll_mode;
855 if(old_poll_mode == prop_radio.poll_mode) {
858 if(!prop_radio.rf_is_on) {
863 res = netstack_sched_rx(
false);
864 return (res == RF_RESULT_OK)
877 prop_radio.rssi_threshold = (int8_t)value;
886get_object(radio_param_t param,
void *dest,
size_t size)
895 if(size !=
sizeof(rtimer_clock_t)) {
899 *(rtimer_clock_t *)dest = prop_radio.last.timestamp;
909set_object(radio_param_t param,
const void *src,
size_t size)
918 RF_TxPowerTable_Value tx_power_value;
921 prop_radio.rx_is_active = rx_is_active;
923 radio_mode = (simplelink_radio_mode_t *)&prop_radio;
925 if(prop_radio.rf_handle) {
926 LOG_WARN(
"Radio is already initialized\n");
931 prop_radio.rf_is_on =
false;
934 prop_radio.rssi_threshold = PROP_MODE_CCA_RSSI_THRESHOLD;
939 RF_Params_init(&rf_params);
943 prop_radio.rf_handle = netstack_open(&rf_params);
945 if(prop_radio.rf_handle == NULL) {
946 LOG_ERR(
"Unable to open RF driver during initialization\n");
947 return RF_RESULT_ERROR;
952 tx_power_value = RF_TxPowerTable_findValue(rf_tx_power_table, RF_TXPOWER_DBM);
953 if(tx_power_value.rawValue != RF_TxPowerTable_INVALID_VALUE) {
954 rf_stat = RF_setTxPower(prop_radio.rf_handle, tx_power_value);
955 if(rf_stat == RF_StatSuccess) {
956 LOG_INFO(
"TX power configured to %d dBm\n", RF_TXPOWER_DBM);
958 LOG_WARN(
"Setting TX power to %d dBm failed, stat=0x%02X", RF_TXPOWER_DBM, rf_stat);
961 LOG_WARN(
"Unable to find TX power %d dBm in the TX power table\n", RF_TXPOWER_DBM);
964 ENERGEST_ON(ENERGEST_TYPE_LISTEN);
Bit reversal library header.
Default definitions of C compiler quirk work-arounds.
Header file of the CC13xx/CC26xx RF data queue.
Header file for the energy estimation mechanism.
void bitrev_array(uint8_t *data, size_t len)
Reverse bits in all bytes of an array (in-place)
#define RF_CONF_INACTIVITY_TIMEOUT
2 ms
#define FRAME_SHAVE
RSSI (1) + Timestamp (4) + Status (1)
static int read(void *buf, unsigned short buf_len)
void process_start(struct process *p, process_data_t data)
Start a process.
void process_poll(struct process *p)
Request a process to be polled.
#define RADIO_RX_MODE_POLL_MODE
Enable/disable/get the state of radio driver poll mode operation.
#define RADIO_TX_MODE_SEND_ON_CCA
Radio TX mode control / retrieval.
enum radio_result_e radio_result_t
Radio return values when setting or getting radio parameters.
int radio_value_t
Each radio has a set of parameters that designate the current configuration and state of the radio.
@ RADIO_RESULT_ERROR
An error occurred when getting/setting the parameter, but the arguments were otherwise correct.
@ RADIO_RESULT_NOT_SUPPORTED
The parameter is not supported.
@ RADIO_RESULT_INVALID_VALUE
The value argument was incorrect.
@ RADIO_RESULT_OK
The parameter was set/read successfully.
@ RADIO_PARAM_POWER_MODE
When getting the value of this parameter, the radio driver should indicate whether the radio is on or...
@ RADIO_PARAM_RSSI
Received signal strength indicator in dBm.
@ RADIO_PARAM_LAST_PACKET_TIMESTAMP
Last packet timestamp, of type rtimer_clock_t.
@ RADIO_PARAM_LAST_RSSI
The RSSI value of the last received packet.
@ RADIO_PARAM_RX_MODE
Radio receiver mode determines if the radio has address filter (RADIO_RX_MODE_ADDRESS_FILTER) and aut...
@ RADIO_PARAM_CHANNEL
Channel used for radio communication.
@ RADIO_PARAM_LAST_LINK_QUALITY
Link quality indicator of the last received packet.
@ RADIO_PARAM_TXPOWER
Transmission power in dBm.
@ RADIO_CONST_CHANNEL_MAX
The highest radio channel number.
@ RADIO_PARAM_CCA_THRESHOLD
Clear channel assessment threshold in dBm.
@ RADIO_CONST_TXPOWER_MIN
The minimum transmission power in dBm.
@ RADIO_CONST_CHANNEL_MIN
The lowest radio channel number.
@ RADIO_CONST_TXPOWER_MAX
The maximum transmission power in dBm.
@ RADIO_PARAM_TX_MODE
Radio transmission mode determines if the radio has send on CCA (RADIO_TX_MODE_SEND_ON_CCA) enabled o...
@ RADIO_POWER_MODE_OFF
Radio powered off and in the lowest possible power consumption state.
@ RADIO_POWER_MODE_ON
Radio powered on and able to receive frames.
@ RADIO_TX_COLLISION
TX failed due to a collision.
@ RADIO_TX_ERR
An error occurred during transmission.
@ RADIO_TX_OK
TX was successful and where an ACK was requested one was received.
#define RTIMER_BUSYWAIT_UNTIL(cond, max_time)
Busy-wait until a condition for at most max_time.
#define RTIMER_NOW()
Get the current clock time.
Header file for the logging system.
#define IEEE802154_DEFAULT_CHANNEL
The default channel for IEEE 802.15.4 networks.
Include file for the Contiki low-layer network stack (NETSTACK)
Header file for the Packet buffer (packetbuf) management.
Header file of the generic radio mode API.
Header file of the CC13xx/CC26xx RAT timer handler.
Header file of common CC13xx/CC26xx RF functionality.
Header file for the real-time timer module.
Header file of the CC13xx/CC26xx RF scheduler.
Header file of RF settings for CC13xx/CC26xx.
Header file with descriptors for the various modes of operation defined in IEEE 802....
The structure of a Contiki-NG radio device driver.
radio_result_t(* get_object)(radio_param_t param, void *dest, size_t size)
Get a radio parameter object.
int(* prepare)(const void *payload, unsigned short payload_len)
Prepare the radio with a packet to be sent.
radio_result_t(* set_value)(radio_param_t param, radio_value_t value)
Set a radio parameter value.
int(* off)(void)
Turn the radio off.
int(* init)(void)
Initialise the radio hardware.
int(* send)(const void *payload, unsigned short payload_len)
Prepare & transmit a packet.
int(* receiving_packet)(void)
Check if the radio driver is currently receiving a packet.
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.
int(* transmit)(unsigned short transmit_len)
Send the packet that has previously been prepared.
int(* pending_packet)(void)
Check if a packet has been received and is available in the radio driver's buffers.
radio_result_t(* get_value)(radio_param_t param, radio_value_t *value)
Get a radio parameter value.
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 of TX power functionality of CC13xx/CC26xx.