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> 62 #include DeviceFamily_constructPath(inc/hw_rfc_dbell.h) 63 #include DeviceFamily_constructPath(driverlib/rfc.h) 83 #define LOG_MODULE "Radio" 84 #define LOG_LEVEL LOG_LEVEL_NONE 87 #define CLAMP(v, vmin, vmax) (MAX(MIN(v, vmax), vmin)) 90 #define PROP_MODE_DYN_WHITENER PROP_MODE_CONF_DW 91 #define PROP_MODE_USE_CRC16 PROP_MODE_CONF_USE_CRC16 92 #define PROP_MODE_CENTER_FREQ PROP_MODE_CONF_CENTER_FREQ 93 #define PROP_MODE_LO_DIVIDER PROP_MODE_CONF_LO_DIVIDER 94 #define PROP_MODE_CCA_RSSI_THRESHOLD PROP_MODE_CONF_CCA_RSSI_THRESHOLD 100 CCA_STATE_INVALID = 2
103 #if MAC_CONF_WITH_TSCH 104 static volatile uint8_t is_receiving_packet;
108 #define DOT_4G_PHR_NUM_BYTES 2 109 #define DOT_4G_LEN_OFFSET 0xFC 110 #define DOT_4G_SYNCWORD 0x0055904E 113 #define DOT_4G_PHR_CRC16 0x10 114 #define DOT_4G_PHR_DW 0x08 116 #if PROP_MODE_USE_CRC16 118 #define DOT_4G_PHR_CRC_BIT DOT_4G_PHR_CRC16 122 #define DOT_4G_PHR_CRC_BIT 0 126 #if PROP_MODE_DYN_WHITENER 127 #define DOT_4G_PHR_DW_BIT DOT_4G_PHR_DW 129 #define DOT_4G_PHR_DW_BIT 0 148 #define MAX_PAYLOAD_LEN 125 151 #define TIMEOUT_ENTER_RX_WAIT (RTIMER_SECOND >> 10) 157 #define RAT_TIMESTAMP_OFFSET USEC_TO_RAT(RADIO_PHY_HEADER_LEN * RADIO_BYTE_AIR_TIME - 270) 160 #define TX_BUF_HDR_LEN 2 161 #define TX_BUF_PAYLOAD_LEN 180 163 #define TX_BUF_SIZE (TX_BUF_HDR_LEN + TX_BUF_PAYLOAD_LEN) 166 typedef uint16_t lensz_t;
168 #define FRAME_OFFSET sizeof(lensz_t) 169 #define FRAME_SHAVE 6 172 #define RX_SENSITIVITY_DBM -110 173 #define RX_SATURATION_DBM 10 174 #define ED_MIN_DBM_ABOVE_RX_SENSITIVITY 10 177 #define ED_RF_POWER_MIN_DBM (RX_SENSITIVITY_DBM + ED_MIN_DBM_ABOVE_RX_SENSITIVITY) 178 #define ED_RF_POWER_MAX_DBM RX_SATURATION_DBM 181 typedef rfc_propRxOutput_t rx_output_t;
192 struct ctimer overflow_timer;
193 rtimer_clock_t last_overflow;
194 volatile uint32_t overflow_count;
197 bool (* rx_is_active)(void);
200 uint8_t tx_buf[TX_BUF_SIZE] CC_ALIGN(4);
203 rx_output_t rx_stats;
206 int8_t rssi_threshold;
222 static prop_radio_t prop_radio;
226 #define cmd_radio_setup rf_cmd_prop_radio_div_setup 227 #define cmd_fs rf_cmd_prop_fs 228 #define cmd_tx rf_cmd_prop_tx_adv 229 #define cmd_rx rf_cmd_prop_rx_adv 232 #define v_cmd_radio_setup CC_ACCESS_NOW(rfc_CMD_PROP_RADIO_DIV_SETUP_t, rf_cmd_prop_radio_div_setup) 233 #define v_cmd_fs CC_ACCESS_NOW(rfc_CMD_FS_t, rf_cmd_prop_fs) 234 #define v_cmd_tx CC_ACCESS_NOW(rfc_CMD_PROP_TX_ADV_t, rf_cmd_prop_tx_adv) 235 #define v_cmd_rx CC_ACCESS_NOW(rfc_CMD_PROP_RX_ADV_t, rf_cmd_prop_rx_adv) 240 return v_cmd_tx.status == ACTIVE;
246 return v_cmd_rx.status == ACTIVE;
251 static int off(
void);
252 static rf_result_t set_channel_force(uint16_t channel);
257 cmd_radio_setup.config.frontEndMode = RF_SUB_1_GHZ_FRONT_END_MODE;
258 cmd_radio_setup.config.biasMode = RF_SUB_1_GHZ_BIAS_MODE;
259 cmd_radio_setup.centerFreq = PROP_MODE_CENTER_FREQ;
260 cmd_radio_setup.loDivider = PROP_MODE_LO_DIVIDER;
262 cmd_tx.numHdrBits = DOT_4G_PHR_NUM_BYTES * 8;
263 cmd_tx.syncWord = DOT_4G_SYNCWORD;
265 cmd_rx.syncWord0 = DOT_4G_SYNCWORD;
266 cmd_rx.syncWord1 = 0x00000000;
267 cmd_rx.maxPktLen = RADIO_PHY_OVERHEAD + MAX_PAYLOAD_LEN;
268 cmd_rx.hdrConf.numHdrBits = DOT_4G_PHR_NUM_BYTES * 8;
269 cmd_rx.lenOffset = DOT_4G_LEN_OFFSET;
270 cmd_rx.pQueue = data_queue_init(
sizeof(lensz_t));
271 cmd_rx.pOutput = (uint8_t *)&prop_radio.rx_stats;
278 bool stop_rx =
false;
279 int8_t rssi = RF_GET_RSSI_ERROR_VAL;
282 if(!rx_is_active()) {
284 if(v_cmd_rx.status != PENDING) {
285 res = netstack_sched_rx(
false);
286 if(res != RF_RESULT_OK) {
287 LOG_ERR(
"RSSI measurement failed to schedule RX\n");
298 if(!rx_is_active()) {
299 LOG_ERR(
"RSSI measurement failed to turn on RX, RX status=0x%04X\n", v_cmd_rx.status);
300 return RF_RESULT_ERROR;
305 rssi = RF_getRssi(prop_radio.rf_handle);
317 uint32_t freq_khz = v_cmd_fs.frequency * 1000;
325 freq_khz += (((v_cmd_fs.fractFreq * 1000) + 65535) / 65536);
327 return (uint8_t)((freq_khz - DOT_15_4G_CHAN0_FREQ) / DOT_15_4G_FREQ_SPACING);
333 if(!dot_15_4g_chan_in_range(channel)) {
334 LOG_WARN(
"Supplied hannel %d is illegal, defaults to %d\n",
335 (
int)channel, DOT_15_4G_DEFAULT_CHAN);
336 channel = DOT_15_4G_DEFAULT_CHAN;
339 if(channel == prop_radio.channel) {
344 return set_channel_force(channel);
349 set_channel_force(uint16_t channel)
353 if(prop_radio.rf_is_on) {
358 const uint32_t new_freq = dot_15_4g_freq(channel);
359 const uint16_t freq = (uint16_t)(new_freq / 1000);
360 const uint16_t frac = (uint16_t)(((new_freq - (freq * 1000)) * 0x10000) / 1000);
362 LOG_DBG(
"Set channel to %d, frequency 0x%04X.0x%04X (%lu)\n",
363 (
int)channel, freq, frac, new_freq);
365 v_cmd_fs.frequency = freq;
366 v_cmd_fs.fractFreq = frac;
368 res = netstack_sched_fs();
370 if(res != RF_RESULT_OK) {
374 prop_radio.channel = channel;
379 calculate_lqi(int8_t rssi)
386 rssi = CLAMP(rssi, ED_RF_POWER_MIN_DBM, ED_RF_POWER_MAX_DBM);
394 return (ED_MAX * (rssi - ED_RF_POWER_MIN_DBM)) / (ED_RF_POWER_MAX_DBM - ED_RF_POWER_MIN_DBM);
398 set_send_on_cca(
bool enable)
400 prop_radio.send_on_cca = enable;
404 prepare(
const void *payload,
unsigned short payload_len)
406 if(payload_len > TX_BUF_PAYLOAD_LEN || payload_len > MAX_PAYLOAD_LEN) {
410 memcpy(prop_radio.tx_buf + TX_BUF_HDR_LEN, payload, payload_len);
415 transmit(
unsigned short transmit_len)
419 if(transmit_len > MAX_PAYLOAD_LEN) {
420 LOG_ERR(
"Too long\n");
425 LOG_ERR(
"A transmission is already active\n");
430 LOG_WARN(
"Channel is not clear for transmission\n");
435 const uint16_t total_length = transmit_len + CRC_LEN;
444 prop_radio.tx_buf[0] = ((total_length >> 0) & 0xFF);
445 prop_radio.tx_buf[1] = ((total_length >> 8) & 0xFF) + DOT_4G_PHR_DW_BIT + DOT_4G_PHR_CRC_BIT;
449 v_cmd_tx.pktLen = transmit_len + DOT_4G_PHR_NUM_BYTES;
450 v_cmd_tx.pPkt = prop_radio.tx_buf;
452 res = netstack_sched_prop_tx(transmit_len);
454 if(res != RF_RESULT_OK) {
455 LOG_WARN(
"Channel is not clear for transmission\n");
459 return (res == RF_RESULT_OK)
465 send(
const void *payload,
unsigned short payload_len)
472 read(
void *buf,
unsigned short buf_len)
474 volatile data_entry_t *data_entry = data_queue_current_entry();
478 while((data_entry->status == DATA_ENTRY_BUSY) &&
479 RTIMER_CLOCK_LT(
RTIMER_NOW(), t0 + RADIO_FRAME_DURATION(MAX_PAYLOAD_LEN)));
481 #if MAC_CONF_WITH_TSCH 483 is_receiving_packet = 0;
486 if(data_entry->status != DATA_ENTRY_FINISHED) {
511 uint8_t *
const frame_ptr = (uint8_t *)&data_entry->data;
512 const lensz_t frame_len = *(lensz_t *)frame_ptr;
516 LOG_ERR(
"Received frame is too short, len=%d\n", frame_len);
518 data_queue_release_entry();
522 const uint8_t *payload_ptr = frame_ptr +
sizeof(lensz_t);
523 const unsigned short payload_len = (
unsigned short)(frame_len -
FRAME_SHAVE);
526 if(payload_len > buf_len) {
527 LOG_ERR(
"Payload of received frame is too large for local buffer, len=%d buf_len=%d\n",
528 payload_len, buf_len);
530 data_queue_release_entry();
534 memcpy(buf, payload_ptr, payload_len);
537 prop_radio.last.rssi = (int8_t)payload_ptr[payload_len];
539 prop_radio.last.corr_lqi = calculate_lqi(prop_radio.last.rssi);
542 memcpy(&rat_ticks, payload_ptr + payload_len + 1, 4);
545 prop_radio.last.timestamp = rat_to_timestamp(rat_ticks, RAT_TIMESTAMP_OFFSET);
547 if(!prop_radio.poll_mode) {
551 packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (packetbuf_attr_t)prop_radio.last.rssi);
552 packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, (packetbuf_attr_t)prop_radio.last.corr_lqi);
555 data_queue_release_entry();
556 return (
int)payload_len;
562 const int8_t rssi = get_rssi();
564 if(rssi == RF_GET_RSSI_ERROR_VAL) {
565 return CCA_STATE_INVALID;
568 return (rssi < prop_radio.rssi_threshold)
577 LOG_ERR(
"Channel clear called while in TX\n");
581 const uint8_t cca_state = cca_request();
584 return cca_state == CCA_STATE_IDLE;
590 if(!prop_radio.rf_is_on) {
594 #if MAC_CONF_WITH_TSCH 602 if(!is_receiving_packet) {
606 if(HWREG(RFC_DBELL_BASE + RFC_DBELL_O_RFHWIFG) & RFC_DBELL_RFHWIFG_MDMSOFT) {
607 is_receiving_packet = 1;
611 is_receiving_packet = (cca_request() == CCA_STATE_BUSY);
612 if(!is_receiving_packet) {
614 RFCHwIntClear(RFC_DBELL_RFHWIFG_MDMSOFT);
618 return is_receiving_packet;
640 if(cca_request() == CCA_STATE_BUSY) {
652 const data_entry_t *
const read_entry = data_queue_current_entry();
653 volatile const data_entry_t *curr_entry = read_entry;
659 const uint8_t status = curr_entry->status;
660 if((status == DATA_ENTRY_FINISHED) ||
661 (status == DATA_ENTRY_BUSY)) {
666 curr_entry = (data_entry_t *)curr_entry->pNextEntry;
667 }
while(curr_entry != read_entry);
669 if(num_pending > 0 && !prop_radio.poll_mode) {
682 if(prop_radio.rf_is_on) {
683 LOG_WARN(
"Radio is already on\n");
689 res = netstack_sched_rx(
true);
691 if(res != RF_RESULT_OK) {
692 return RF_RESULT_ERROR;
695 prop_radio.rf_is_on =
true;
702 if(!prop_radio.rf_is_on) {
703 LOG_WARN(
"Radio is already off\n");
709 prop_radio.rf_is_on =
false;
725 *value = (prop_radio.rf_is_on)
738 if(prop_radio.poll_mode) {
749 res = rf_get_tx_power(prop_radio.rf_handle, rf_tx_power_table, (int8_t *)&value);
750 return ((res == RF_RESULT_OK) &&
751 (*value != RF_TxPowerTable_INVALID_DBM))
756 *value = prop_radio.rssi_threshold;
761 return (*value == RF_GET_RSSI_ERROR_VAL)
766 *value = prop_radio.last.rssi;
770 *value = prop_radio.last.corr_lqi;
774 *value = DOT_15_4G_CHAN_MIN;
778 *value = DOT_15_4G_CHAN_MAX;
786 *value = (
radio_value_t)tx_power_max(rf_tx_power_table, rf_tx_power_table_size);
789 case RADIO_CONST_MAX_PAYLOAD_LEN:
807 return (
on() == RF_RESULT_OK)
819 return (res == RF_RESULT_OK)
824 if(!tx_power_in_range((int8_t)value, rf_tx_power_table, rf_tx_power_table_size)) {
827 res = rf_set_tx_power(prop_radio.rf_handle, rf_tx_power_table, (int8_t)value);
828 return (res == RF_RESULT_OK)
838 const bool old_poll_mode = prop_radio.poll_mode;
840 if(old_poll_mode == prop_radio.poll_mode) {
843 if(!prop_radio.rf_is_on) {
848 res = netstack_sched_rx(
false);
849 return (res == RF_RESULT_OK)
862 prop_radio.rssi_threshold = (int8_t)value;
871 get_object(radio_param_t param,
void *dest,
size_t size)
880 if(size !=
sizeof(rtimer_clock_t)) {
884 *(rtimer_clock_t *)dest = prop_radio.last.timestamp;
894 set_object(radio_param_t param,
const void *src,
size_t size)
903 RF_TxPowerTable_Value tx_power_value;
906 prop_radio.rx_is_active = rx_is_active;
908 radio_mode = (simplelink_radio_mode_t *)&prop_radio;
910 if(prop_radio.rf_handle) {
911 LOG_WARN(
"Radio is already initialized\n");
916 prop_radio.rf_is_on =
false;
919 prop_radio.rssi_threshold = PROP_MODE_CCA_RSSI_THRESHOLD;
924 RF_Params_init(&rf_params);
928 prop_radio.rf_handle = netstack_open(&rf_params);
930 if(prop_radio.rf_handle == NULL) {
931 LOG_ERR(
"Unable to open RF driver during initialization\n");
932 return RF_RESULT_ERROR;
937 tx_power_value = RF_TxPowerTable_findValue(rf_tx_power_table, RF_TXPOWER_DBM);
938 if(tx_power_value.rawValue != RF_TxPowerTable_INVALID_VALUE) {
939 rf_stat = RF_setTxPower(prop_radio.rf_handle, tx_power_value);
940 if(rf_stat == RF_StatSuccess) {
941 LOG_INFO(
"TX power configured to %d dBm\n", RF_TXPOWER_DBM);
943 LOG_WARN(
"Setting TX power to %d dBm failed, stat=0x%02X", RF_TXPOWER_DBM, rf_stat);
946 LOG_WARN(
"Unable to find TX power %d dBm in the TX power table\n", RF_TXPOWER_DBM);
949 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.
The parameter is not supported.
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) + Timestamp (4) + Status (1)
Header file for the energy estimation mechanism
TX failed due to a collision.
The maximum transmission power in dBm.
Received signal strength indicator in dBm.
int(* receiving_packet)(void)
Check if the radio driver is currently receiving a packet.
Header file of the generic radio mode API.
radio_result_t(* set_value)(radio_param_t param, radio_value_t value)
Set a radio parameter value.
int(* pending_packet)(void)
Check if a packet has been received and is available in the radio driver's buffers.
The structure of a Contiki-NG radio device driver.
#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.
Channel used for radio communication.
The value argument was incorrect.
The parameter was set/read successfully.
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...
An error occurred when getting/setting the parameter, but the arguments were otherwise correct...
Header file of the CC13xx/CC26xx RAT timer handler.
Radio transmission mode determines if the radio has send on CCA (RADIO_TX_MODE_SEND_ON_CCA) enabled o...
#define IEEE802154_DEFAULT_CHANNEL
The default channel for IEEE 802.15.4 networks.
#define RTIMER_NOW()
Get the current clock time.
The RSSI value of the last received packet.
Clear channel assessment threshold in dBm.
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
The lowest radio channel number.
Radio receiver mode determines if the radio has address filter (RADIO_RX_MODE_ADDRESS_FILTER) and aut...
Header file for the real-time timer module.
The highest radio channel number.
Header file of the CC13xx/CC26xx RF data queue.
When getting the value of this parameter, the radio driver should indicate whether the radio is on or...
enum radio_result_e radio_result_t
Radio return values when setting or getting radio parameters.
#define RADIO_TX_MODE_SEND_ON_CCA
Radio TX mode control / retrieval.
int(* init)(void)
Initialise the radio hardware.
Header file of RF settings for CC13xx/CC26xx.
#define RADIO_RX_MODE_POLL_MODE
Enable/disable/get the state of radio driver poll mode operation.
Link quality indicator of the last received packet.
The minimum transmission power in dBm.
Radio powered on and able to receive frames.
int(* read)(void *buf, unsigned short buf_len)
Read a received packet into a buffer.
Transmission power in dBm.
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.
Last packet timestamp, of type rtimer_clock_t.
An error occurred during transmission.
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.
Radio powered off and in the lowest possible power consumption state.
TX was successful and where an ACK was requested one was received.
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.