49 #include "sys/clock.h" 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> 91 #define LOG_MODULE "Radio" 92 #define LOG_LEVEL LOG_LEVEL_NONE 95 #define IEEE_MODE_AUTOACK IEEE_MODE_CONF_AUTOACK 96 #define IEEE_MODE_PROMISCOUS IEEE_MODE_CONF_PROMISCOUS 97 #define IEEE_MODE_CCA_RSSI_THRESHOLD IEEE_MODE_CONF_CCA_RSSI_THRESHOLD 102 #define TIMEOUT_DATA_ENTRY_BUSY (RTIMER_SECOND / 200) 105 #define TIMEOUT_ENTER_RX_WAIT (RTIMER_SECOND >> 10) 108 #if defined(DEVICE_LINE_CC13XX) 109 #define RAT_TIMESTAMP_OFFSET USEC_TO_RAT(800) 111 #define RAT_TIMESTAMP_OFFSET USEC_TO_RAT(-50) 114 #define STATUS_CORRELATION 0x3f 115 #define STATUS_REJECT_FRAME 0x40 116 #define STATUS_CRC_FAIL 0x80 122 #define CHECKSUM_LEN 2 129 #define MAX_PAYLOAD_LEN (127 - CHECKSUM_LEN) 131 #define FRAME_FCF_OFFSET 0 132 #define FRAME_SEQNUM_OFFSET 2 134 #define FRAME_ACK_REQUEST 0x20 137 #define TX_BUF_SIZE 180 140 typedef uint8_t lensz_t;
142 #define FRAME_OFFSET sizeof(lensz_t) 143 #define FRAME_SHAVE 8 149 CCA_STATE_INVALID = 2
153 typedef rfc_ieeeRxOutput_t rx_output_t;
154 typedef rfc_CMD_IEEE_MOD_FILT_t cmd_mod_filt_t;
155 typedef rfc_CMD_IEEE_CCA_REQ_t cmd_cca_req_t;
166 struct ctimer overflow_timer;
167 rtimer_clock_t last_overflow;
168 volatile uint32_t overflow_count;
171 bool (* rx_is_active)(void);
174 uint8_t tx_buf[TX_BUF_SIZE] CC_ALIGN(4);
177 rx_output_t rx_stats;
192 static ieee_radio_t ieee_radio;
195 static cmd_mod_filt_t cmd_mod_filt;
198 #define cmd_radio_setup rf_cmd_ieee_radio_setup 199 #define cmd_fs rf_cmd_ieee_fs 200 #define cmd_tx rf_cmd_ieee_tx 201 #define cmd_rx rf_cmd_ieee_rx 202 #define cmd_rx_ack rf_cmd_ieee_rx_ack 205 #define v_cmd_radio_setup CC_ACCESS_NOW(rfc_CMD_RADIO_SETUP_t, rf_cmd_ieee_radio_setup) 206 #define v_cmd_fs CC_ACCESS_NOW(rfc_CMD_FS_t, rf_cmd_ieee_fs) 207 #define v_cmd_tx CC_ACCESS_NOW(rfc_CMD_IEEE_TX_t, rf_cmd_ieee_tx) 208 #define v_cmd_rx CC_ACCESS_NOW(rfc_CMD_IEEE_RX_t, rf_cmd_ieee_rx) 209 #define v_cmd_rx_ack CC_ACCESS_NOW(rfc_CMD_IEEE_RX_ACK_t, rf_cmd_ieee_rx_ack) 214 return v_cmd_rx.status == ACTIVE;
218 static int init(
void);
219 static int prepare(
const void *,
unsigned short);
220 static int transmit(
unsigned short);
221 static int send(
const void *,
unsigned short);
222 static int read(
void *,
unsigned short);
227 static int off(
void);
236 cmd_radio_setup.config.frontEndMode = RF_2_4_GHZ_FRONT_END_MODE;
237 cmd_radio_setup.config.biasMode = RF_2_4_GHZ_BIAS_MODE;
239 cmd_rx.pRxQ = data_queue_init(
sizeof(lensz_t));
240 cmd_rx.pOutput = &ieee_radio.rx_stats;
242 #if IEEE_MODE_PROMISCOUS 243 cmd_rx.frameFiltOpt.frameFiltEn = 0;
245 cmd_rx.frameFiltOpt.frameFiltEn = 1;
248 #if IEEE_MODE_AUTOACK 249 cmd_rx.frameFiltOpt.autoAckEn = 1;
251 cmd_rx.frameFiltOpt.autoAckEn = 0;
254 cmd_rx.ccaRssiThr = IEEE_MODE_CCA_RSSI_THRESHOLD;
256 cmd_tx.pNextOp = (RF_Op *)&cmd_rx_ack;
257 cmd_tx.condition.rule = COND_NEVER;
267 cmd_rx_ack.startTrigger.triggerType = TRIG_NOW;
268 cmd_rx_ack.endTrigger.triggerType = TRIG_REL_START;
269 cmd_rx_ack.endTime = RF_convertUsToRatTicks(700);
272 cmd_mod_filt.commandNo = CMD_IEEE_MOD_FILT;
273 memcpy(&(cmd_mod_filt.newFrameFiltOpt), &(cmd_rx.frameFiltOpt),
sizeof(cmd_rx.frameFiltOpt));
274 memcpy(&(cmd_mod_filt.newFrameTypes), &(cmd_rx.frameTypes),
sizeof(cmd_rx.frameTypes));
280 if(!dot_15_4g_chan_in_range(channel)) {
281 LOG_WARN(
"Supplied hannel %d is illegal, defaults to %d\n",
282 (
int)channel, DOT_15_4G_DEFAULT_CHAN);
283 channel = DOT_15_4G_DEFAULT_CHAN;
291 if(channel == v_cmd_rx.channel) {
296 if(ieee_radio.rf_is_on) {
301 v_cmd_rx.channel = channel;
303 const uint32_t new_freq = dot_15_4g_freq(channel);
304 const uint16_t freq = (uint16_t)(new_freq / 1000);
305 const uint16_t frac = (uint16_t)(((new_freq - (freq * 1000)) * 0x10000) / 1000);
307 LOG_DBG(
"Set channel to %d, frequency 0x%04X.0x%04X (%lu)\n",
308 (
int)channel, freq, frac, new_freq);
310 v_cmd_fs.frequency = freq;
311 v_cmd_fs.fractFreq = frac;
313 return netstack_sched_fs();
317 set_send_on_cca(
bool enable)
319 ieee_radio.send_on_cca = enable;
326 RF_TxPowerTable_Value tx_power_value;
329 ieee_radio.rx_is_active = rx_is_active;
330 radio_mode = (simplelink_radio_mode_t *)&ieee_radio;
332 if(ieee_radio.rf_handle) {
333 LOG_WARN(
"Radio already initialized\n");
338 ieee_radio.rf_is_on =
false;
343 RF_Params_init(&rf_params);
346 ieee_radio.rf_handle = netstack_open(&rf_params);
348 if(ieee_radio.rf_handle == NULL) {
349 LOG_ERR(
"Unable to open RF driver\n");
350 return RF_RESULT_ERROR;
355 tx_power_value = RF_TxPowerTable_findValue(rf_tx_power_table, RF_TXPOWER_DBM);
356 if(tx_power_value.rawValue != RF_TxPowerTable_INVALID_VALUE) {
357 rf_stat = RF_setTxPower(ieee_radio.rf_handle, tx_power_value);
358 if(rf_stat == RF_StatSuccess) {
359 LOG_INFO(
"TX power configured to %d dBm\n", RF_TXPOWER_DBM);
361 LOG_WARN(
"Setting TX power to %d dBm failed, stat=0x%02X", RF_TXPOWER_DBM, rf_stat);
364 LOG_WARN(
"Unable to find TX power %d dBm in the TX power table\n", RF_TXPOWER_DBM);
367 ENERGEST_ON(ENERGEST_TYPE_LISTEN);
379 prepare(
const void *payload,
unsigned short payload_len)
381 if(payload_len > TX_BUF_SIZE || payload_len > MAX_PAYLOAD_LEN) {
384 memcpy(ieee_radio.tx_buf, payload, payload_len);
389 transmit(
unsigned short transmit_len)
393 if(transmit_len > MAX_PAYLOAD_LEN) {
394 LOG_ERR(
"Too long\n");
399 LOG_WARN(
"Channel is not clear for transmission\n");
408 if(!ieee_radio.poll_mode &&
409 (ieee_radio.tx_buf[FRAME_FCF_OFFSET] & FRAME_ACK_REQUEST)) {
416 v_cmd_tx.condition.rule = COND_STOP_ON_FALSE;
419 v_cmd_rx_ack.status = IDLE;
421 v_cmd_rx_ack.seqNo = ieee_radio.tx_buf[FRAME_SEQNUM_OFFSET];
424 v_cmd_tx.condition.rule = COND_NEVER;
428 v_cmd_tx.payloadLen = (uint8_t)transmit_len;
429 v_cmd_tx.pPayload = ieee_radio.tx_buf;
431 res = netstack_sched_ieee_tx(transmit_len, ack_request);
433 if(res != RF_RESULT_OK) {
438 switch(v_cmd_rx_ack.status) {
454 send(
const void *payload,
unsigned short payload_len)
461 read(
void *buf,
unsigned short buf_len)
463 volatile data_entry_t *data_entry = data_queue_current_entry();
467 while((data_entry->status == DATA_ENTRY_BUSY) &&
468 RTIMER_CLOCK_LT(
RTIMER_NOW(), t0 + TIMEOUT_DATA_ENTRY_BUSY)) ;
470 if(data_entry->status != DATA_ENTRY_FINISHED) {
495 uint8_t *
const frame_ptr = (uint8_t *)&data_entry->data;
496 const lensz_t frame_len = *(lensz_t *)frame_ptr;
500 LOG_ERR(
"Received frame too short, len=%d\n", frame_len);
502 data_queue_release_entry();
506 const uint8_t *payload_ptr = frame_ptr +
sizeof(lensz_t);
507 const unsigned short payload_len = (
unsigned short)(frame_len -
FRAME_SHAVE);
510 if(payload_len > buf_len) {
511 LOG_ERR(
"MAC payload too large for buffer, len=%d buf_len=%d\n",
512 payload_len, buf_len);
514 data_queue_release_entry();
518 memcpy(buf, payload_ptr, payload_len);
521 ieee_radio.last.rssi = (int8_t)payload_ptr[payload_len + 2];
523 ieee_radio.last.corr_lqi = (uint8_t)(payload_ptr[payload_len + 3] & STATUS_CORRELATION);
525 const uint32_t rat_ticks = *(uint32_t *)(payload_ptr + payload_len + 4);
527 ieee_radio.last.timestamp = rat_to_timestamp(rat_ticks, RAT_TIMESTAMP_OFFSET);
529 if(!ieee_radio.poll_mode) {
533 packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (packetbuf_attr_t)ieee_radio.last.rssi);
534 packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, (packetbuf_attr_t)ieee_radio.last.corr_lqi);
537 data_queue_release_entry();
538 return (
int)payload_len;
542 cca_request(cmd_cca_req_t *cmd_cca_req)
544 RF_Stat stat = RF_StatRadioInactiveError;
546 bool stop_rx =
false;
549 if(!rx_is_active()) {
551 if(v_cmd_rx.status != PENDING) {
552 res = netstack_sched_rx(
false);
553 if(res != RF_RESULT_OK) {
554 LOG_ERR(
"CCA request failed to schedule RX\n");
565 if(!rx_is_active()) {
566 LOG_ERR(
"CCA request failed to turn on RX, RX status=0x%04X\n", v_cmd_rx.status);
567 return RF_RESULT_ERROR;
573 memset(cmd_cca_req, 0x00,
sizeof(cmd_cca_req_t));
574 cmd_cca_req->commandNo = CMD_IEEE_CCA_REQ;
575 cmd_cca_req->ccaInfo.ccaState = CCA_STATE_INVALID;
577 stat = RF_runImmediateCmd(ieee_radio.rf_handle, (uint32_t *)cmd_cca_req);
579 if(stat != RF_StatCmdDoneSuccess) {
580 LOG_ERR(
"CCA request command failed, stat=0x%02X\n", stat);
584 return RF_RESULT_ERROR;
586 }
while(cmd_cca_req->ccaInfo.ccaState == CCA_STATE_INVALID);
598 cmd_cca_req_t cmd_cca_req;
600 if(cca_request(&cmd_cca_req) != RF_RESULT_OK) {
605 return cmd_cca_req.ccaInfo.ccaState == CCA_STATE_IDLE;
611 cmd_cca_req_t cmd_cca_req;
613 if(cca_request(&cmd_cca_req) != RF_RESULT_OK) {
618 if((cmd_cca_req.ccaInfo.ccaEnergy == CCA_STATE_BUSY) &&
619 (cmd_cca_req.ccaInfo.ccaCorr == CCA_STATE_BUSY) &&
620 (cmd_cca_req.ccaInfo.ccaSync == CCA_STATE_BUSY)) {
621 LOG_WARN(
"We are TXing ACK, therefore not receiving packets\n");
626 return cmd_cca_req.ccaInfo.ccaSync == CCA_STATE_BUSY;
632 const data_entry_t *
const read_entry = data_queue_current_entry();
633 volatile const data_entry_t *curr_entry = read_entry;
639 const uint8_t status = curr_entry->status;
640 if((status == DATA_ENTRY_FINISHED) ||
641 (status == DATA_ENTRY_BUSY)) {
646 curr_entry = (data_entry_t *)curr_entry->pNextEntry;
647 }
while(curr_entry != read_entry);
649 if(num_pending > 0 && !ieee_radio.poll_mode) {
662 if(ieee_radio.rf_is_on) {
663 LOG_WARN(
"Radio is already on\n");
669 res = netstack_sched_rx(
true);
671 if(res != RF_RESULT_OK) {
672 return RF_RESULT_ERROR;
675 ieee_radio.rf_is_on =
true;
682 if(!ieee_radio.rf_is_on) {
683 LOG_WARN(
"Radio is already off\n");
689 ieee_radio.rf_is_on =
false;
706 *value = (ieee_radio.rf_is_on)
729 if(v_cmd_rx.frameFiltOpt.frameFiltEn) {
732 if(v_cmd_rx.frameFiltOpt.autoAckEn) {
735 if(ieee_radio.poll_mode) {
747 res = rf_get_tx_power(ieee_radio.rf_handle, rf_tx_power_table, (int8_t *)&value);
748 return ((res == RF_RESULT_OK) &&
749 (*value != RF_TxPowerTable_INVALID_DBM))
755 *value = v_cmd_rx.ccaRssiThr;
760 *value = RF_getRssi(ieee_radio.rf_handle);
761 return (*value == RF_GET_RSSI_ERROR_VAL)
781 *value = (
radio_value_t)tx_power_max(rf_tx_power_table, rf_tx_power_table_size);
794 case RADIO_CONST_MAX_PAYLOAD_LEN:
814 return (
on() == RF_RESULT_OK)
826 if(!dot_15_4g_chan_in_range(value)) {
834 v_cmd_rx.localPanID = (uint16_t)value;
835 if(!ieee_radio.rf_is_on) {
840 res = netstack_sched_rx(
false);
841 return (res == RF_RESULT_OK)
847 v_cmd_rx.localShortAddr = (uint16_t)value;
848 if(!ieee_radio.rf_is_on) {
853 res = netstack_sched_rx(
false);
854 return (res == RF_RESULT_OK)
867 v_cmd_rx.frameFiltOpt.frameFiltStop = 1;
869 v_cmd_rx.frameFiltOpt.slottedAckEn = 0;
870 v_cmd_rx.frameFiltOpt.autoPendEn = 0;
871 v_cmd_rx.frameFiltOpt.defaultPend = 0;
872 v_cmd_rx.frameFiltOpt.bPendDataReqOnly = 0;
873 v_cmd_rx.frameFiltOpt.bPanCoord = 0;
874 v_cmd_rx.frameFiltOpt.bStrictLenFilter = 0;
876 const bool old_poll_mode = ieee_radio.poll_mode;
878 if(old_poll_mode == ieee_radio.poll_mode) {
880 memcpy(&cmd_mod_filt.newFrameFiltOpt, &(cmd_rx.frameFiltOpt),
sizeof(cmd_rx.frameFiltOpt));
881 const RF_Stat stat = RF_runImmediateCmd(ieee_radio.rf_handle, (uint32_t *)&cmd_mod_filt);
882 if(stat != RF_StatCmdDoneSuccess) {
883 LOG_ERR(
"Setting address filter failed, stat=0x%02X\n", stat);
888 if(!ieee_radio.rf_is_on) {
893 res = netstack_sched_rx(
false);
894 return (res == RF_RESULT_OK)
909 if(!tx_power_in_range((int8_t)value, rf_tx_power_table, rf_tx_power_table_size)) {
912 res = rf_set_tx_power(ieee_radio.rf_handle, rf_tx_power_table, (int8_t)value);
913 return (res == RF_RESULT_OK)
919 v_cmd_rx.ccaRssiThr = (int8_t)value;
920 if(!ieee_radio.rf_is_on) {
925 res = netstack_sched_rx(
false);
926 return (res == RF_RESULT_OK)
936 get_object(radio_param_t param,
void *dest,
size_t size)
945 const size_t srcSize =
sizeof(v_cmd_rx.localExtAddr);
946 if(size != srcSize) {
950 const uint8_t *pSrc = (uint8_t *)&(v_cmd_rx.localExtAddr);
951 uint8_t *pDest = dest;
952 for(
size_t i = 0; i < srcSize; ++i) {
953 pDest[i] = pSrc[srcSize - 1 - i];
960 if(size !=
sizeof(rtimer_clock_t)) {
964 *(rtimer_clock_t *)dest = ieee_radio.last.timestamp;
974 set_object(radio_param_t param,
const void *src,
size_t size)
985 const size_t destSize =
sizeof(v_cmd_rx.localExtAddr);
986 if(size != destSize) {
990 const uint8_t *pSrc = (
const uint8_t *)src;
991 volatile uint8_t *pDest = (uint8_t *)&(v_cmd_rx.localExtAddr);
992 for(
size_t i = 0; i < destSize; ++i) {
993 pDest[i] = pSrc[destSize - 1 - i];
996 if(!rx_is_active()) {
1001 res = netstack_sched_rx(
false);
1002 return (res == RF_RESULT_OK)
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.
Header file for the link-layer address representation
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.
The short address (16 bits) for the radio, which is used by the h/w filter.
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 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.
Header file for the callback timer
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 personal area network identifier (PAN ID), which is used by the h/w frame filtering functionality...
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.
A unicast frame was sent OK but an ACK was not received.
#define RADIO_RX_MODE_ADDRESS_FILTER
Enable address-based frame filtering.
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.
#define RADIO_RX_MODE_AUTOACK
Enable automatic transmission of ACK frames.
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.
Long (64 bits) address for the radio, which is used by the address filter.
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.