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_ENTER_RX_WAIT (RTIMER_SECOND >> 10) 105 #if defined(DEVICE_LINE_CC13XX) 106 #define RAT_TIMESTAMP_OFFSET USEC_TO_RAT(800) 108 #define RAT_TIMESTAMP_OFFSET USEC_TO_RAT(-50) 111 #define STATUS_CORRELATION 0x3f 112 #define STATUS_REJECT_FRAME 0x40 113 #define STATUS_CRC_FAIL 0x80 119 #define CHECKSUM_LEN 2 126 #define MAX_PAYLOAD_LEN (127 - CHECKSUM_LEN) 128 #define FRAME_FCF_OFFSET 0 129 #define FRAME_SEQNUM_OFFSET 2 131 #define FRAME_ACK_REQUEST 0x20 134 #define TX_BUF_SIZE 180 137 typedef uint8_t lensz_t;
139 #define FRAME_OFFSET sizeof(lensz_t) 140 #define FRAME_SHAVE 8 146 CCA_STATE_INVALID = 2
150 typedef rfc_ieeeRxOutput_t rx_output_t;
151 typedef rfc_CMD_IEEE_MOD_FILT_t cmd_mod_filt_t;
152 typedef rfc_CMD_IEEE_CCA_REQ_t cmd_cca_req_t;
163 struct ctimer overflow_timer;
164 rtimer_clock_t last_overflow;
165 volatile uint32_t overflow_count;
168 bool (* rx_is_active)(void);
171 uint8_t tx_buf[TX_BUF_SIZE] CC_ALIGN(4);
174 rx_output_t rx_stats;
189 static ieee_radio_t ieee_radio;
192 static cmd_mod_filt_t cmd_mod_filt;
195 #define cmd_radio_setup rf_cmd_ieee_radio_setup 196 #define cmd_fs rf_cmd_ieee_fs 197 #define cmd_tx rf_cmd_ieee_tx 198 #define cmd_rx rf_cmd_ieee_rx 199 #define cmd_rx_ack rf_cmd_ieee_rx_ack 202 #define v_cmd_radio_setup CC_ACCESS_NOW(rfc_CMD_RADIO_SETUP_t, rf_cmd_ieee_radio_setup) 203 #define v_cmd_fs CC_ACCESS_NOW(rfc_CMD_FS_t, rf_cmd_ieee_fs) 204 #define v_cmd_tx CC_ACCESS_NOW(rfc_CMD_IEEE_TX_t, rf_cmd_ieee_tx) 205 #define v_cmd_rx CC_ACCESS_NOW(rfc_CMD_IEEE_RX_t, rf_cmd_ieee_rx) 206 #define v_cmd_rx_ack CC_ACCESS_NOW(rfc_CMD_IEEE_RX_ACK_t, rf_cmd_ieee_rx_ack) 211 return v_cmd_rx.status == ACTIVE;
215 static int init(
void);
216 static int prepare(
const void *,
unsigned short);
217 static int transmit(
unsigned short);
218 static int send(
const void *,
unsigned short);
219 static int read(
void *,
unsigned short);
224 static int off(
void);
233 cmd_radio_setup.config.frontEndMode = RF_2_4_GHZ_FRONT_END_MODE;
234 cmd_radio_setup.config.biasMode = RF_2_4_GHZ_BIAS_MODE;
236 cmd_rx.pRxQ = data_queue_init(
sizeof(lensz_t));
237 cmd_rx.pOutput = &ieee_radio.rx_stats;
239 #if IEEE_MODE_PROMISCOUS 240 cmd_rx.frameFiltOpt.frameFiltEn = 0;
242 cmd_rx.frameFiltOpt.frameFiltEn = 1;
245 #if IEEE_MODE_AUTOACK 246 cmd_rx.frameFiltOpt.autoAckEn = 1;
248 cmd_rx.frameFiltOpt.autoAckEn = 0;
251 cmd_rx.ccaRssiThr = IEEE_MODE_CCA_RSSI_THRESHOLD;
253 cmd_tx.pNextOp = (RF_Op *)&cmd_rx_ack;
254 cmd_tx.condition.rule = COND_NEVER;
264 cmd_rx_ack.startTrigger.triggerType = TRIG_NOW;
265 cmd_rx_ack.endTrigger.triggerType = TRIG_REL_START;
266 cmd_rx_ack.endTime = RF_convertUsToRatTicks(700);
269 cmd_mod_filt.commandNo = CMD_IEEE_MOD_FILT;
270 memcpy(&(cmd_mod_filt.newFrameFiltOpt), &(cmd_rx.frameFiltOpt),
sizeof(cmd_rx.frameFiltOpt));
271 memcpy(&(cmd_mod_filt.newFrameTypes), &(cmd_rx.frameTypes),
sizeof(cmd_rx.frameTypes));
277 if(!dot_15_4g_chan_in_range(channel)) {
278 LOG_WARN(
"Supplied hannel %d is illegal, defaults to %d\n",
279 (
int)channel, DOT_15_4G_DEFAULT_CHAN);
280 channel = DOT_15_4G_DEFAULT_CHAN;
288 if(channel == v_cmd_rx.channel) {
293 if(ieee_radio.rf_is_on) {
298 v_cmd_rx.channel = channel;
300 const uint32_t new_freq = dot_15_4g_freq(channel);
301 const uint16_t freq = (uint16_t)(new_freq / 1000);
302 const uint16_t frac = (uint16_t)(((new_freq - (freq * 1000)) * 0x10000) / 1000);
304 LOG_DBG(
"Set channel to %d, frequency 0x%04X.0x%04X (%lu)\n",
305 (
int)channel, freq, frac, new_freq);
307 v_cmd_fs.frequency = freq;
308 v_cmd_fs.fractFreq = frac;
310 return netstack_sched_fs();
314 set_send_on_cca(
bool enable)
316 ieee_radio.send_on_cca = enable;
323 RF_TxPowerTable_Value tx_power_value;
326 ieee_radio.rx_is_active = rx_is_active;
327 radio_mode = (simplelink_radio_mode_t *)&ieee_radio;
329 if(ieee_radio.rf_handle) {
330 LOG_WARN(
"Radio already initialized\n");
335 ieee_radio.rf_is_on =
false;
340 RF_Params_init(&rf_params);
343 ieee_radio.rf_handle = netstack_open(&rf_params);
345 if(ieee_radio.rf_handle == NULL) {
346 LOG_ERR(
"Unable to open RF driver\n");
347 return RF_RESULT_ERROR;
352 tx_power_value = RF_TxPowerTable_findValue(rf_tx_power_table, RF_TXPOWER_DBM);
353 if(tx_power_value.rawValue != RF_TxPowerTable_INVALID_VALUE) {
354 rf_stat = RF_setTxPower(ieee_radio.rf_handle, tx_power_value);
355 if(rf_stat == RF_StatSuccess) {
356 LOG_INFO(
"TX power configured to %d dBm\n", RF_TXPOWER_DBM);
358 LOG_WARN(
"Setting TX power to %d dBm failed, stat=0x%02X", RF_TXPOWER_DBM, rf_stat);
361 LOG_WARN(
"Unable to find TX power %d dBm in the TX power table\n", RF_TXPOWER_DBM);
364 ENERGEST_ON(ENERGEST_TYPE_LISTEN);
376 prepare(
const void *payload,
unsigned short payload_len)
378 if(payload_len > TX_BUF_SIZE || payload_len > MAX_PAYLOAD_LEN) {
381 memcpy(ieee_radio.tx_buf, payload, payload_len);
386 transmit(
unsigned short transmit_len)
390 if(transmit_len > MAX_PAYLOAD_LEN) {
391 LOG_ERR(
"Too long\n");
396 LOG_WARN(
"Channel is not clear for transmission\n");
405 if(!ieee_radio.poll_mode &&
406 (ieee_radio.tx_buf[FRAME_FCF_OFFSET] & FRAME_ACK_REQUEST)) {
413 v_cmd_tx.condition.rule = COND_STOP_ON_FALSE;
416 v_cmd_rx_ack.status = IDLE;
418 v_cmd_rx_ack.seqNo = ieee_radio.tx_buf[FRAME_SEQNUM_OFFSET];
421 v_cmd_tx.condition.rule = COND_NEVER;
425 v_cmd_tx.payloadLen = (uint8_t)transmit_len;
426 v_cmd_tx.pPayload = ieee_radio.tx_buf;
428 res = netstack_sched_ieee_tx(transmit_len, ack_request);
430 if(res != RF_RESULT_OK) {
435 switch(v_cmd_rx_ack.status) {
451 send(
const void *payload,
unsigned short payload_len)
458 read(
void *buf,
unsigned short buf_len)
460 volatile data_entry_t *data_entry = data_queue_current_entry();
464 while((data_entry->status == DATA_ENTRY_BUSY) &&
465 RTIMER_CLOCK_LT(
RTIMER_NOW(), t0 + RADIO_FRAME_DURATION(MAX_PAYLOAD_LEN))) ;
467 if(data_entry->status != DATA_ENTRY_FINISHED) {
492 uint8_t *
const frame_ptr = (uint8_t *)&data_entry->data;
493 const lensz_t frame_len = *(lensz_t *)frame_ptr;
497 LOG_ERR(
"Received frame too short, len=%d\n", frame_len);
499 data_queue_release_entry();
503 const uint8_t *payload_ptr = frame_ptr +
sizeof(lensz_t);
504 const unsigned short payload_len = (
unsigned short)(frame_len -
FRAME_SHAVE);
507 if(payload_len > buf_len) {
508 LOG_ERR(
"MAC payload too large for buffer, len=%d buf_len=%d\n",
509 payload_len, buf_len);
511 data_queue_release_entry();
515 memcpy(buf, payload_ptr, payload_len);
518 ieee_radio.last.rssi = (int8_t)payload_ptr[payload_len + 2];
520 ieee_radio.last.corr_lqi = (uint8_t)(payload_ptr[payload_len + 3] & STATUS_CORRELATION);
522 const uint32_t rat_ticks = *(uint32_t *)(payload_ptr + payload_len + 4);
524 ieee_radio.last.timestamp = rat_to_timestamp(rat_ticks, RAT_TIMESTAMP_OFFSET);
526 if(!ieee_radio.poll_mode) {
530 packetbuf_set_attr(PACKETBUF_ATTR_RSSI, (packetbuf_attr_t)ieee_radio.last.rssi);
531 packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, (packetbuf_attr_t)ieee_radio.last.corr_lqi);
534 data_queue_release_entry();
535 return (
int)payload_len;
539 cca_request(cmd_cca_req_t *cmd_cca_req)
541 RF_Stat stat = RF_StatRadioInactiveError;
543 bool stop_rx =
false;
546 if(!rx_is_active()) {
548 if(v_cmd_rx.status != PENDING) {
549 res = netstack_sched_rx(
false);
550 if(res != RF_RESULT_OK) {
551 LOG_ERR(
"CCA request failed to schedule RX\n");
562 if(!rx_is_active()) {
563 LOG_ERR(
"CCA request failed to turn on RX, RX status=0x%04X\n", v_cmd_rx.status);
564 return RF_RESULT_ERROR;
570 memset(cmd_cca_req, 0x00,
sizeof(cmd_cca_req_t));
571 cmd_cca_req->commandNo = CMD_IEEE_CCA_REQ;
572 cmd_cca_req->ccaInfo.ccaState = CCA_STATE_INVALID;
574 stat = RF_runImmediateCmd(ieee_radio.rf_handle, (uint32_t *)cmd_cca_req);
576 if(stat != RF_StatCmdDoneSuccess) {
577 LOG_ERR(
"CCA request command failed, stat=0x%02X\n", stat);
581 return RF_RESULT_ERROR;
583 }
while(cmd_cca_req->ccaInfo.ccaState == CCA_STATE_INVALID);
595 cmd_cca_req_t cmd_cca_req;
597 if(cca_request(&cmd_cca_req) != RF_RESULT_OK) {
602 return cmd_cca_req.ccaInfo.ccaState == CCA_STATE_IDLE;
608 cmd_cca_req_t cmd_cca_req;
610 if(cca_request(&cmd_cca_req) != RF_RESULT_OK) {
615 if((cmd_cca_req.ccaInfo.ccaEnergy == CCA_STATE_BUSY) &&
616 (cmd_cca_req.ccaInfo.ccaCorr == CCA_STATE_BUSY) &&
617 (cmd_cca_req.ccaInfo.ccaSync == CCA_STATE_BUSY)) {
618 LOG_WARN(
"We are TXing ACK, therefore not receiving packets\n");
623 return cmd_cca_req.ccaInfo.ccaSync == CCA_STATE_BUSY;
629 const data_entry_t *
const read_entry = data_queue_current_entry();
630 volatile const data_entry_t *curr_entry = read_entry;
636 const uint8_t status = curr_entry->status;
637 if((status == DATA_ENTRY_FINISHED) ||
638 (status == DATA_ENTRY_BUSY)) {
643 curr_entry = (data_entry_t *)curr_entry->pNextEntry;
644 }
while(curr_entry != read_entry);
646 if(num_pending > 0 && !ieee_radio.poll_mode) {
659 if(ieee_radio.rf_is_on) {
660 LOG_WARN(
"Radio is already on\n");
666 res = netstack_sched_rx(
true);
668 if(res != RF_RESULT_OK) {
669 return RF_RESULT_ERROR;
672 ieee_radio.rf_is_on =
true;
679 if(!ieee_radio.rf_is_on) {
680 LOG_WARN(
"Radio is already off\n");
686 ieee_radio.rf_is_on =
false;
703 *value = (ieee_radio.rf_is_on)
726 if(v_cmd_rx.frameFiltOpt.frameFiltEn) {
729 if(v_cmd_rx.frameFiltOpt.autoAckEn) {
732 if(ieee_radio.poll_mode) {
744 res = rf_get_tx_power(ieee_radio.rf_handle, rf_tx_power_table, (int8_t *)&value);
745 return ((res == RF_RESULT_OK) &&
746 (*value != RF_TxPowerTable_INVALID_DBM))
752 *value = v_cmd_rx.ccaRssiThr;
757 *value = RF_getRssi(ieee_radio.rf_handle);
758 return (*value == RF_GET_RSSI_ERROR_VAL)
778 *value = (
radio_value_t)tx_power_max(rf_tx_power_table, rf_tx_power_table_size);
791 case RADIO_CONST_MAX_PAYLOAD_LEN:
811 return (
on() == RF_RESULT_OK)
823 if(!dot_15_4g_chan_in_range(value)) {
831 v_cmd_rx.localPanID = (uint16_t)value;
832 if(!ieee_radio.rf_is_on) {
837 res = netstack_sched_rx(
false);
838 return (res == RF_RESULT_OK)
844 v_cmd_rx.localShortAddr = (uint16_t)value;
845 if(!ieee_radio.rf_is_on) {
850 res = netstack_sched_rx(
false);
851 return (res == RF_RESULT_OK)
864 v_cmd_rx.frameFiltOpt.frameFiltStop = 1;
866 v_cmd_rx.frameFiltOpt.slottedAckEn = 0;
867 v_cmd_rx.frameFiltOpt.autoPendEn = 0;
868 v_cmd_rx.frameFiltOpt.defaultPend = 0;
869 v_cmd_rx.frameFiltOpt.bPendDataReqOnly = 0;
870 v_cmd_rx.frameFiltOpt.bPanCoord = 0;
871 v_cmd_rx.frameFiltOpt.bStrictLenFilter = 0;
873 const bool old_poll_mode = ieee_radio.poll_mode;
875 if(old_poll_mode == ieee_radio.poll_mode) {
877 memcpy(&cmd_mod_filt.newFrameFiltOpt, &(cmd_rx.frameFiltOpt),
sizeof(cmd_rx.frameFiltOpt));
878 const RF_Stat stat = RF_runImmediateCmd(ieee_radio.rf_handle, (uint32_t *)&cmd_mod_filt);
879 if(stat != RF_StatCmdDoneSuccess) {
880 LOG_ERR(
"Setting address filter failed, stat=0x%02X\n", stat);
885 if(!ieee_radio.rf_is_on) {
890 res = netstack_sched_rx(
false);
891 return (res == RF_RESULT_OK)
906 if(!tx_power_in_range((int8_t)value, rf_tx_power_table, rf_tx_power_table_size)) {
909 res = rf_set_tx_power(ieee_radio.rf_handle, rf_tx_power_table, (int8_t)value);
910 return (res == RF_RESULT_OK)
916 v_cmd_rx.ccaRssiThr = (int8_t)value;
917 if(!ieee_radio.rf_is_on) {
922 res = netstack_sched_rx(
false);
923 return (res == RF_RESULT_OK)
933 get_object(radio_param_t param,
void *dest,
size_t size)
942 const size_t srcSize =
sizeof(v_cmd_rx.localExtAddr);
943 if(size != srcSize) {
947 const uint8_t *pSrc = (uint8_t *)&(v_cmd_rx.localExtAddr);
948 uint8_t *pDest = dest;
949 for(
size_t i = 0; i < srcSize; ++i) {
950 pDest[i] = pSrc[srcSize - 1 - i];
957 if(size !=
sizeof(rtimer_clock_t)) {
961 *(rtimer_clock_t *)dest = ieee_radio.last.timestamp;
971 set_object(radio_param_t param,
const void *src,
size_t size)
982 const size_t destSize =
sizeof(v_cmd_rx.localExtAddr);
983 if(size != destSize) {
987 const uint8_t *pSrc = (
const uint8_t *)src;
988 volatile uint8_t *pDest = (uint8_t *)&(v_cmd_rx.localExtAddr);
989 for(
size_t i = 0; i < destSize; ++i) {
990 pDest[i] = pSrc[destSize - 1 - i];
993 if(!rx_is_active()) {
998 res = netstack_sched_rx(
false);
999 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.