55#include <ti/devices/DeviceFamily.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_mailbox.h)
65#if defined(DeviceFamily_CC13X0)
66#include "driverlib/rf_ieee_mailbox.h"
68#include DeviceFamily_constructPath(driverlib/rf_ieee_mailbox.h)
71#include <ti/drivers/rf/RF.h>
92#define LOG_MODULE "Radio"
93#define LOG_LEVEL LOG_LEVEL_NONE
96#define IEEE_MODE_AUTOACK IEEE_MODE_CONF_AUTOACK
97#define IEEE_MODE_PROMISCOUS IEEE_MODE_CONF_PROMISCOUS
98#define IEEE_MODE_CCA_RSSI_THRESHOLD IEEE_MODE_CONF_CCA_RSSI_THRESHOLD
103#define TIMEOUT_ENTER_RX_WAIT (RTIMER_SECOND >> 10)
106#if defined(DEVICE_LINE_CC13XX)
107#define RAT_TIMESTAMP_OFFSET USEC_TO_RAT(800)
109#define RAT_TIMESTAMP_OFFSET USEC_TO_RAT(-50)
112#define STATUS_CORRELATION 0x3f
113#define STATUS_REJECT_FRAME 0x40
114#define STATUS_CRC_FAIL 0x80
120#define CHECKSUM_LEN 2
127#define MAX_PAYLOAD_LEN (127 - CHECKSUM_LEN)
129#define FRAME_FCF_OFFSET 0
130#define FRAME_SEQNUM_OFFSET 2
132#define FRAME_ACK_REQUEST 0x20
135#define TX_BUF_SIZE 180
138typedef uint8_t lensz_t;
140#define FRAME_OFFSET sizeof(lensz_t)
147 CCA_STATE_INVALID = 2
151typedef rfc_ieeeRxOutput_t rx_output_t;
152typedef rfc_CMD_IEEE_MOD_FILT_t cmd_mod_filt_t;
153typedef rfc_CMD_IEEE_CCA_REQ_t cmd_cca_req_t;
164 struct ctimer overflow_timer;
165 rtimer_clock_t last_overflow;
166 volatile uint32_t overflow_count;
169 bool (* rx_is_active)(void);
172 uint8_t tx_buf[TX_BUF_SIZE] CC_ALIGN(4);
175 rx_output_t rx_stats;
190static ieee_radio_t ieee_radio;
193static cmd_mod_filt_t cmd_mod_filt;
196#define cmd_radio_setup rf_cmd_ieee_radio_setup
197#define cmd_fs rf_cmd_ieee_fs
198#define cmd_tx rf_cmd_ieee_tx
199#define cmd_rx rf_cmd_ieee_rx
200#define cmd_rx_ack rf_cmd_ieee_rx_ack
203#define v_cmd_radio_setup CC_ACCESS_NOW(rfc_CMD_RADIO_SETUP_t, rf_cmd_ieee_radio_setup)
204#define v_cmd_fs CC_ACCESS_NOW(rfc_CMD_FS_t, rf_cmd_ieee_fs)
205#define v_cmd_tx CC_ACCESS_NOW(rfc_CMD_IEEE_TX_t, rf_cmd_ieee_tx)
206#define v_cmd_rx CC_ACCESS_NOW(rfc_CMD_IEEE_RX_t, rf_cmd_ieee_rx)
207#define v_cmd_rx_ack CC_ACCESS_NOW(rfc_CMD_IEEE_RX_ACK_t, rf_cmd_ieee_rx_ack)
212 return v_cmd_rx.status == ACTIVE;
216static int init(
void);
217static int prepare(
const void *,
unsigned short);
218static int transmit(
unsigned short);
219static int send(
const void *,
unsigned short);
220static int read(
void *,
unsigned short);
221static int channel_clear(
void);
222static int receiving_packet(
void);
223static int pending_packet(
void);
229static radio_result_t set_object(radio_param_t,
const void *,
size_t);
234 cmd_radio_setup.config.frontEndMode = RF_2_4_GHZ_FRONT_END_MODE;
235 cmd_radio_setup.config.biasMode = RF_2_4_GHZ_BIAS_MODE;
237 cmd_rx.pRxQ = data_queue_init(
sizeof(lensz_t));
238 cmd_rx.pOutput = &ieee_radio.rx_stats;
240#if IEEE_MODE_PROMISCOUS
241 cmd_rx.frameFiltOpt.frameFiltEn = 0;
243 cmd_rx.frameFiltOpt.frameFiltEn = 1;
247 cmd_rx.frameFiltOpt.autoAckEn = 1;
249 cmd_rx.frameFiltOpt.autoAckEn = 0;
252 cmd_rx.ccaRssiThr = IEEE_MODE_CCA_RSSI_THRESHOLD;
254 cmd_tx.pNextOp = (RF_Op *)&cmd_rx_ack;
255 cmd_tx.condition.rule = COND_NEVER;
265 cmd_rx_ack.startTrigger.triggerType = TRIG_NOW;
266 cmd_rx_ack.endTrigger.triggerType = TRIG_REL_START;
267 cmd_rx_ack.endTime = RF_convertUsToRatTicks(700);
270 cmd_mod_filt.commandNo = CMD_IEEE_MOD_FILT;
271 memcpy(&(cmd_mod_filt.newFrameFiltOpt), &(cmd_rx.frameFiltOpt),
sizeof(cmd_rx.frameFiltOpt));
272 memcpy(&(cmd_mod_filt.newFrameTypes), &(cmd_rx.frameTypes),
sizeof(cmd_rx.frameTypes));
276set_channel(uint8_t channel)
278 if(!dot_15_4g_chan_in_range(channel)) {
279 LOG_WARN(
"Supplied hannel %d is illegal, defaults to %d\n",
280 (
int)channel, DOT_15_4G_DEFAULT_CHAN);
281 channel = DOT_15_4G_DEFAULT_CHAN;
289 if(channel == v_cmd_rx.channel) {
294 if(ieee_radio.rf_is_on) {
299 v_cmd_rx.channel = channel;
301 const uint32_t new_freq = dot_15_4g_freq(channel);
302 const uint16_t freq = (uint16_t)(new_freq / 1000);
303 const uint16_t frac = (uint16_t)(((new_freq - (freq * 1000)) * 0x10000) / 1000);
305 LOG_DBG(
"Set channel to %d, frequency 0x%04X.0x%04X (%" PRIu32
")\n",
306 (
int)channel, freq, frac, new_freq);
308 v_cmd_fs.frequency = freq;
309 v_cmd_fs.fractFreq = frac;
311 return netstack_sched_fs();
315set_send_on_cca(
bool enable)
317 ieee_radio.send_on_cca = enable;
324 RF_TxPowerTable_Value tx_power_value;
327 ieee_radio.rx_is_active = rx_is_active;
328 radio_mode = (simplelink_radio_mode_t *)&ieee_radio;
330 if(ieee_radio.rf_handle) {
331 LOG_WARN(
"Radio already initialized\n");
336 ieee_radio.rf_is_on =
false;
341 RF_Params_init(&rf_params);
344 ieee_radio.rf_handle = netstack_open(&rf_params);
346 if(ieee_radio.rf_handle == NULL) {
347 LOG_ERR(
"Unable to open RF driver\n");
348 return RF_RESULT_ERROR;
351 set_channel(DOT_15_4G_DEFAULT_CHAN);
353 tx_power_value = RF_TxPowerTable_findValue(rf_tx_power_table, RF_TXPOWER_DBM);
354 if(tx_power_value.rawValue != RF_TxPowerTable_INVALID_VALUE) {
355 rf_stat = RF_setTxPower(ieee_radio.rf_handle, tx_power_value);
356 if(rf_stat == RF_StatSuccess) {
357 LOG_INFO(
"TX power configured to %d dBm\n", RF_TXPOWER_DBM);
359 LOG_WARN(
"Setting TX power to %d dBm failed, stat=0x%02X", RF_TXPOWER_DBM, rf_stat);
362 LOG_WARN(
"Unable to find TX power %d dBm in the TX power table\n", RF_TXPOWER_DBM);
365 ENERGEST_ON(ENERGEST_TYPE_LISTEN);
377prepare(
const void *payload,
unsigned short payload_len)
379 if(payload_len > TX_BUF_SIZE || payload_len > MAX_PAYLOAD_LEN) {
382 memcpy(ieee_radio.tx_buf, payload, payload_len);
387transmit(
unsigned short transmit_len)
391 if(transmit_len > MAX_PAYLOAD_LEN) {
392 LOG_ERR(
"Too long\n");
396 if(ieee_radio.send_on_cca && channel_clear() != 1) {
397 LOG_WARN(
"Channel is not clear for transmission\n");
406 if(!ieee_radio.poll_mode &&
407 (ieee_radio.tx_buf[FRAME_FCF_OFFSET] & FRAME_ACK_REQUEST)) {
414 v_cmd_tx.condition.rule = COND_STOP_ON_FALSE;
417 v_cmd_rx_ack.status = IDLE;
419 v_cmd_rx_ack.seqNo = ieee_radio.tx_buf[FRAME_SEQNUM_OFFSET];
422 v_cmd_tx.condition.rule = COND_NEVER;
426 v_cmd_tx.payloadLen = (uint8_t)transmit_len;
427 v_cmd_tx.pPayload = ieee_radio.tx_buf;
429 res = netstack_sched_ieee_tx(transmit_len, ack_request);
431 if(res != RF_RESULT_OK) {
436 switch(v_cmd_rx_ack.status) {
452send(
const void *payload,
unsigned short payload_len)
454 prepare(payload, payload_len);
455 return transmit(payload_len);
459read(
void *buf,
unsigned short buf_len)
461 volatile data_entry_t *data_entry = data_queue_current_entry();
465 while((data_entry->status == DATA_ENTRY_BUSY) &&
466 RTIMER_CLOCK_LT(
RTIMER_NOW(), t0 + RADIO_FRAME_DURATION(MAX_PAYLOAD_LEN))) ;
468 if(data_entry->status != DATA_ENTRY_FINISHED) {
493 uint8_t *
const frame_ptr = (uint8_t *)&data_entry->data;
494 const lensz_t frame_len = *(lensz_t *)frame_ptr;
497 if(frame_len < FRAME_SHAVE) {
498 LOG_ERR(
"Received frame too short, len=%d\n", frame_len);
500 data_queue_release_entry();
504 const uint8_t *payload_ptr = frame_ptr +
sizeof(lensz_t);
505 const unsigned short payload_len = (
unsigned short)(frame_len - FRAME_SHAVE);
508 if(payload_len > buf_len) {
509 LOG_ERR(
"MAC payload too large for buffer, len=%d buf_len=%d\n",
510 payload_len, buf_len);
512 data_queue_release_entry();
516 memcpy(buf, payload_ptr, payload_len);
519 ieee_radio.last.rssi = (int8_t)payload_ptr[payload_len + 2];
521 ieee_radio.last.corr_lqi = (uint8_t)(payload_ptr[payload_len + 3] & STATUS_CORRELATION);
523 const uint32_t rat_ticks = *(uint32_t *)(payload_ptr + payload_len + 4);
525 ieee_radio.last.timestamp = rat_to_timestamp(rat_ticks, RAT_TIMESTAMP_OFFSET);
527 if(!ieee_radio.poll_mode) {
531 packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (packetbuf_attr_t)ieee_radio.last.rssi);
532 packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, (packetbuf_attr_t)ieee_radio.last.corr_lqi);
535 data_queue_release_entry();
536 return (
int)payload_len;
540cca_request(cmd_cca_req_t *cmd_cca_req)
542 RF_Stat stat = RF_StatRadioInactiveError;
544 bool stop_rx =
false;
547 if(!rx_is_active()) {
549 if(v_cmd_rx.status != PENDING) {
550 res = netstack_sched_rx(
false);
551 if(res != RF_RESULT_OK) {
552 LOG_ERR(
"CCA request failed to schedule RX\n");
563 if(!rx_is_active()) {
564 LOG_ERR(
"CCA request failed to turn on RX, RX status=0x%04X\n", v_cmd_rx.status);
565 return RF_RESULT_ERROR;
571 memset(cmd_cca_req, 0x00,
sizeof(cmd_cca_req_t));
572 cmd_cca_req->commandNo = CMD_IEEE_CCA_REQ;
573 cmd_cca_req->ccaInfo.ccaState = CCA_STATE_INVALID;
575 stat = RF_runImmediateCmd(ieee_radio.rf_handle, (uint32_t *)cmd_cca_req);
577 if(stat != RF_StatCmdDoneSuccess) {
578 LOG_ERR(
"CCA request command failed, stat=0x%02X\n", stat);
582 return RF_RESULT_ERROR;
584 }
while(cmd_cca_req->ccaInfo.ccaState == CCA_STATE_INVALID);
596 cmd_cca_req_t cmd_cca_req;
598 if(cca_request(&cmd_cca_req) != RF_RESULT_OK) {
603 return cmd_cca_req.ccaInfo.ccaState == CCA_STATE_IDLE;
607receiving_packet(
void)
609 cmd_cca_req_t cmd_cca_req;
611 if(cca_request(&cmd_cca_req) != RF_RESULT_OK) {
616 if((cmd_cca_req.ccaInfo.ccaEnergy == CCA_STATE_BUSY) &&
617 (cmd_cca_req.ccaInfo.ccaCorr == CCA_STATE_BUSY) &&
618 (cmd_cca_req.ccaInfo.ccaSync == CCA_STATE_BUSY)) {
619 LOG_WARN(
"We are TXing ACK, therefore not receiving packets\n");
624 return cmd_cca_req.ccaInfo.ccaSync == CCA_STATE_BUSY;
630 const data_entry_t *
const read_entry = data_queue_current_entry();
631 volatile const data_entry_t *curr_entry = read_entry;
637 const uint8_t status = curr_entry->status;
638 if((status == DATA_ENTRY_FINISHED) ||
639 (status == DATA_ENTRY_BUSY)) {
644 curr_entry = (data_entry_t *)curr_entry->pNextEntry;
645 }
while(curr_entry != read_entry);
647 if(num_pending > 0 && !ieee_radio.poll_mode) {
660 if(ieee_radio.rf_is_on) {
661 LOG_WARN(
"Radio is already on\n");
667 res = netstack_sched_rx(
true);
669 if(res != RF_RESULT_OK) {
670 return RF_RESULT_ERROR;
673 ieee_radio.rf_is_on =
true;
680 if(!ieee_radio.rf_is_on) {
681 LOG_WARN(
"Radio is already off\n");
687 ieee_radio.rf_is_on =
false;
704 *value = (ieee_radio.rf_is_on)
727 if(v_cmd_rx.frameFiltOpt.frameFiltEn) {
730 if(v_cmd_rx.frameFiltOpt.autoAckEn) {
733 if(ieee_radio.poll_mode) {
745 res = rf_get_tx_power(ieee_radio.rf_handle, rf_tx_power_table, (int8_t *)&value);
746 return ((res == RF_RESULT_OK) &&
747 (*value != RF_TxPowerTable_INVALID_DBM))
753 *value = v_cmd_rx.ccaRssiThr;
758 *value = RF_getRssi(ieee_radio.rf_handle);
759 return (*value == RF_GET_RSSI_ERROR_VAL)
779 *value = (
radio_value_t)tx_power_max(rf_tx_power_table, rf_tx_power_table_size);
792 case RADIO_CONST_MAX_PAYLOAD_LEN:
812 return (on() == RF_RESULT_OK)
824 if(!dot_15_4g_chan_in_range(value)) {
827 set_channel((uint8_t)value);
832 v_cmd_rx.localPanID = (uint16_t)value;
833 if(!ieee_radio.rf_is_on) {
838 res = netstack_sched_rx(
false);
839 return (res == RF_RESULT_OK)
845 v_cmd_rx.localShortAddr = (uint16_t)value;
846 if(!ieee_radio.rf_is_on) {
851 res = netstack_sched_rx(
false);
852 return (res == RF_RESULT_OK)
865 v_cmd_rx.frameFiltOpt.frameFiltStop = 1;
867 v_cmd_rx.frameFiltOpt.slottedAckEn = 0;
868 v_cmd_rx.frameFiltOpt.autoPendEn = 0;
869 v_cmd_rx.frameFiltOpt.defaultPend = 0;
870 v_cmd_rx.frameFiltOpt.bPendDataReqOnly = 0;
871 v_cmd_rx.frameFiltOpt.bPanCoord = 0;
872 v_cmd_rx.frameFiltOpt.bStrictLenFilter = 0;
874 const bool old_poll_mode = ieee_radio.poll_mode;
876 if(old_poll_mode == ieee_radio.poll_mode) {
878 memcpy(&cmd_mod_filt.newFrameFiltOpt, &(cmd_rx.frameFiltOpt),
sizeof(cmd_rx.frameFiltOpt));
879 const RF_Stat stat = RF_runImmediateCmd(ieee_radio.rf_handle, (uint32_t *)&cmd_mod_filt);
880 if(stat != RF_StatCmdDoneSuccess) {
881 LOG_ERR(
"Setting address filter failed, stat=0x%02X\n", stat);
886 if(!ieee_radio.rf_is_on) {
891 res = netstack_sched_rx(
false);
892 return (res == RF_RESULT_OK)
907 if(!tx_power_in_range((int8_t)value, rf_tx_power_table, rf_tx_power_table_size)) {
910 res = rf_set_tx_power(ieee_radio.rf_handle, rf_tx_power_table, (int8_t)value);
911 return (res == RF_RESULT_OK)
917 v_cmd_rx.ccaRssiThr = (int8_t)value;
918 if(!ieee_radio.rf_is_on) {
923 res = netstack_sched_rx(
false);
924 return (res == RF_RESULT_OK)
934get_object(radio_param_t param,
void *dest,
size_t size)
943 const size_t srcSize =
sizeof(v_cmd_rx.localExtAddr);
944 if(size != srcSize) {
948 const uint8_t *pSrc = (uint8_t *)&(v_cmd_rx.localExtAddr);
949 uint8_t *pDest = dest;
950 for(
size_t i = 0; i < srcSize; ++i) {
951 pDest[i] = pSrc[srcSize - 1 - i];
958 if(size !=
sizeof(rtimer_clock_t)) {
962 *(rtimer_clock_t *)dest = ieee_radio.last.timestamp;
972set_object(radio_param_t param,
const void *src,
size_t size)
983 const size_t destSize =
sizeof(v_cmd_rx.localExtAddr);
984 if(size != destSize) {
988 const uint8_t *pSrc = (
const uint8_t *)src;
989 volatile uint8_t *pDest = (uint8_t *)&(v_cmd_rx.localExtAddr);
990 for(
size_t i = 0; i < destSize; ++i) {
991 pDest[i] = pSrc[destSize - 1 - i];
994 if(!rx_is_active()) {
999 res = netstack_sched_rx(
false);
1000 return (res == RF_RESULT_OK)
Default definitions of C compiler quirk work-arounds.
Header file for the callback timer.
Header file of the CC13xx/CC26xx RF data queue.
Header file for the energy estimation mechanism.
#define RF_CONF_INACTIVITY_TIMEOUT
2 ms
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_ADDRESS_FILTER
Enable address-based frame filtering.
#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.
#define RADIO_RX_MODE_AUTOACK
Enable automatic transmission of ACK frames.
@ 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_PARAM_64BIT_ADDR
Long (64 bits) address for the radio, which is used by the address filter.
@ RADIO_CONST_CHANNEL_MAX
The highest radio channel number.
@ RADIO_PARAM_PAN_ID
The personal area network identifier (PAN ID), which is used by the h/w frame filtering functionality...
@ 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_16BIT_ADDR
The short address (16 bits) for the radio, which is used by the h/w filter.
@ 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_NOACK
A unicast frame was sent OK but an ACK was not received.
@ 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.
static uint8_t rf_is_on(void)
Checks whether the RFC domain is accessible and the RFC is in IEEE RX.
#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 link-layer address representation.
Header file for the logging system.
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(* read)(void *buf, unsigned short buf_len)
Read a received packet into a buffer.
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.