41#include "dev/watchdog.h"
49#include "lib/random.h"
51#include <ti/devices/DeviceFamily.h>
52#include DeviceFamily_constructPath(driverlib/rf_common_cmd.h)
53#include DeviceFamily_constructPath(driverlib/rf_mailbox.h)
54#include DeviceFamily_constructPath(driverlib/rf_ble_mailbox.h)
55#include DeviceFamily_constructPath(driverlib/rf_prop_mailbox.h)
56#if defined(DeviceFamily_CC13X0)
57#include "driverlib/rf_ieee_mailbox.h"
59#include DeviceFamily_constructPath(driverlib/rf_ieee_mailbox.h)
62#include <ti/drivers/rf/RF.h>
76#define LOG_MODULE "Radio"
77#define LOG_LEVEL LOG_LEVEL_NONE
79#define CMD_FS_RETRIES 3
81#define RF_EVENTS_CMD_DONE (RF_EventCmdDone | RF_EventLastCmdDone | \
82 RF_EventFGCmdDone | RF_EventLastFGCmdDone)
84#define CMD_STATUS(cmd) (CC_ACCESS_NOW(RF_Op, cmd).status)
86#define CMD_HANDLE_OK(handle) (((handle) != RF_ALLOC_ERROR) && \
87 ((handle) != RF_SCHEDULE_CMD_ERROR))
89#define EVENTS_CMD_DONE(events) (((events) & RF_EVENTS_CMD_DONE) != 0)
92#define BLE_ADV_CHANNEL_MIN 37
93#define BLE_ADV_CHANNEL_MAX 39
96#define NUM_BLE_ADV_CHANNELS (BLE_ADV_CHANNEL_MAX - BLE_ADV_CHANNEL_MIN + 1)
99#define SYNTH_RECAL_INTERVAL (CLOCK_SECOND * 60 * 3)
101#define SYNTH_RECAL_JITTER (CLOCK_SECOND * 10)
103static struct etimer synth_recal_timer;
105#if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0)
106typedef rfc_CMD_BLE_ADV_NC_t ble_cmd_adv_nc_t;
107#elif (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X2_CC26X2)
108typedef rfc_CMD_BLE5_ADV_NC_t ble_cmd_adv_nc_t;
111static RF_Object rf_netstack;
113#if RF_CONF_BLE_BEACON_ENABLE
114static RF_Object rf_ble;
117static volatile RF_CmdHandle cmd_rx_handle;
120static volatile bool rf_start_recalib_timer;
121static volatile bool rx_buf_full;
123static rfc_CMD_SYNC_STOP_RAT_t netstack_cmd_stop_rat;
124static rfc_CMD_SYNC_START_RAT_t netstack_cmd_start_rat;
126simplelink_radio_mode_t *radio_mode;
129cmd_rx_cb(RF_Handle client, RF_CmdHandle command, RF_EventMask events)
135 if(radio_mode->poll_mode) {
139 if(events & RF_EventRxEntryDone) {
143 if(events & RF_EventRxBufFull) {
149static inline clock_time_t
150synth_recal_interval(
void)
156 return SYNTH_RECAL_INTERVAL + (
random_rand() % SYNTH_RECAL_JITTER) - (SYNTH_RECAL_JITTER / 2);
160cmd_rx_is_active(
void)
166 const uint16_t status = CMD_STATUS(netstack_cmd_rx);
167 return (status == ACTIVE) ||
174 const bool is_active = cmd_rx_is_active();
177 CMD_STATUS(netstack_cmd_rx) = DONE_STOPPED;
178 RF_cancelCmd(&rf_netstack, cmd_rx_handle, RF_ABORT_GRACEFULLY);
182 return (uint_fast8_t)is_active;
186cmd_rx_restore(uint_fast8_t rx_key)
188 const bool was_active = (rx_key != 0) ?
true :
false;
194 RF_ScheduleCmdParams sched_params;
195 RF_ScheduleCmdParams_init(&sched_params);
197 sched_params.priority = RF_PriorityNormal;
198 sched_params.endTime = 0;
199 sched_params.allowDelay = RF_AllowDelayAny;
201 CMD_STATUS(netstack_cmd_rx) = PENDING;
203 cmd_rx_handle = RF_scheduleCmd(
205 (RF_Op *)&netstack_cmd_rx,
208 RF_EventRxEntryDone | RF_EventRxBufFull);
210 if(!CMD_HANDLE_OK(cmd_rx_handle)) {
211 LOG_ERR(
"Unable to restore RX command, handle=%d status=0x%04x",
212 cmd_rx_handle, CMD_STATUS(netstack_cmd_rx));
213 return RF_RESULT_ERROR;
223 RF_flushCmd(&rf_netstack, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY);
224#if RF_CONF_BLE_BEACON_ENABLE
225 RF_flushCmd(&rf_ble, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY);
229 RF_ScheduleCmdParams sched_params;
230 RF_ScheduleCmdParams_init(&sched_params);
232 sched_params.priority = RF_PriorityNormal;
233 sched_params.endTime = 0;
234 sched_params.allowDelay = RF_AllowDelayAny;
236 CMD_STATUS(netstack_cmd_stop_rat) = PENDING;
240 (RF_Op *)&netstack_cmd_stop_rat,
246 RF_yield(&rf_netstack);
247#if RF_CONF_BLE_BEACON_ENABLE
251 ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
260 RF_ScheduleCmdParams sched_params;
263 RF_ScheduleCmdParams_init(&sched_params);
265 sched_params.priority = RF_PriorityNormal;
266 sched_params.endTime = 0;
267 sched_params.allowDelay = RF_AllowDelayAny;
269 CMD_STATUS(netstack_cmd_stop_rat) = PENDING;
273 (RF_Op *)&netstack_cmd_stop_rat,
279 RF_ScheduleCmdParams_init(&sched_params);
281 sched_params.priority = RF_PriorityNormal;
282 sched_params.endTime = 0;
283 sched_params.allowDelay = RF_AllowDelayAny;
285 netstack_cmd_start_rat.rat0 = 0;
286 CMD_STATUS(netstack_cmd_start_rat) = PENDING;
290 (RF_Op *)&netstack_cmd_start_rat,
300rf_set_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t dbm)
302 const RF_Stat stat = RF_setTxPower(handle, RF_TxPowerTable_findValue(table, dbm));
304 return (stat == RF_StatSuccess)
310rf_get_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t *dbm)
312 *dbm = RF_TxPowerTable_findPowerLevel(table, RF_getTxPower(handle));
314 return (*dbm != RF_TxPowerTable_INVALID_DBM)
320netstack_open(RF_Params *params)
322 netstack_cmd_stop_rat.commandNo = CMD_SYNC_STOP_RAT;
323 netstack_cmd_stop_rat.condition.rule = COND_NEVER;
324 netstack_cmd_start_rat.commandNo = CMD_SYNC_START_RAT;
325 netstack_cmd_start_rat.condition.rule = COND_NEVER;
326 return RF_open(&rf_netstack, &netstack_mode, (RF_RadioSetup *)&netstack_cmd_radio_setup, params);
330netstack_sched_fs(
void)
332 const uint_fast8_t rx_key = cmd_rx_disable();
342#if (RF_MODE == RF_MODE_2_4_GHZ)
344 cmd_rx_restore(rx_key);
349 if(radio_mode->poll_mode) {
354 RF_ScheduleCmdParams sched_params;
355 RF_ScheduleCmdParams_init(&sched_params);
357 sched_params.priority = RF_PriorityNormal;
358 sched_params.endTime = 0;
359 sched_params.allowDelay = RF_AllowDelayAny;
361 CMD_STATUS(netstack_cmd_fs) = PENDING;
363 RF_CmdHandle fs_handle = RF_scheduleCmd(
365 (RF_Op *)&netstack_cmd_fs,
370 cmd_rx_restore(rx_key);
372 if(!CMD_HANDLE_OK(fs_handle)) {
373 LOG_ERR(
"Unable to schedule FS command, handle=%d status=0x%04x\n",
374 fs_handle, CMD_STATUS(netstack_cmd_fs));
375 return RF_RESULT_ERROR;
386 bool synth_error =
false;
387 uint8_t num_tries = 0;
390 CMD_STATUS(netstack_cmd_fs) = PENDING;
394 (RF_Op *)&netstack_cmd_fs,
399 synth_error = (EVENTS_CMD_DONE(events)) && (CMD_STATUS(netstack_cmd_fs) == ERROR_SYNTH_PROG);
401 }
while(synth_error && (num_tries++ < CMD_FS_RETRIES));
403 cmd_rx_restore(rx_key);
405 return (CMD_STATUS(netstack_cmd_fs) == DONE_OK)
412netstack_sched_ieee_tx(uint16_t payload_length,
bool ack_request)
415 RF_EventMask tx_events = 0;
417 RF_ScheduleCmdParams sched_params;
418 RF_ScheduleCmdParams_init(&sched_params);
420 sched_params.priority = RF_PriorityNormal;
421 sched_params.endTime = 0;
422 sched_params.allowDelay = RF_AllowDelayAny;
424 const bool rx_is_active = cmd_rx_is_active();
425 const bool rx_needed = (ack_request && !rx_is_active);
433 res = netstack_sched_rx(
false);
434 if(res != RF_RESULT_OK) {
439 CMD_STATUS(netstack_cmd_tx) = PENDING;
441 RF_CmdHandle tx_handle = RF_scheduleCmd(
443 (RF_Op *)&netstack_cmd_tx,
448 if(!CMD_HANDLE_OK(tx_handle)) {
449 LOG_ERR(
"Unable to schedule TX command, handle=%d status=0x%04x\n",
450 tx_handle, CMD_STATUS(netstack_cmd_tx));
451 return RF_RESULT_ERROR;
455 ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT);
457 ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);
461 if(radio_mode->poll_mode) {
462 const uint16_t frame_length = payload_length + RADIO_PHY_HEADER_LEN + RADIO_PHY_OVERHEAD;
464 US_TO_RTIMERTICKS(RADIO_BYTE_AIR_TIME * frame_length + 300));
466 tx_events = RF_pendCmd(&rf_netstack, tx_handle, 0);
475 ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN);
477 ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
480 if(radio_mode->poll_mode) {
481 if(CMD_STATUS(netstack_cmd_tx) != IEEE_DONE_OK) {
482 LOG_ERR(
"Pending on scheduled TX command generated error, status=0x%04x\n",
483 CMD_STATUS(netstack_cmd_tx));
484 return RF_RESULT_ERROR;
487 if(!EVENTS_CMD_DONE(tx_events)) {
488 LOG_ERR(
"Pending on TX comand generated error, events=0x%08llx status=0x%04x\n",
489 tx_events, CMD_STATUS(netstack_cmd_tx));
490 return RF_RESULT_ERROR;
498netstack_sched_prop_tx(uint16_t payload_length)
500 RF_EventMask tx_events = 0;
502 RF_ScheduleCmdParams sched_params;
503 RF_ScheduleCmdParams_init(&sched_params);
505 sched_params.priority = RF_PriorityNormal;
506 sched_params.endTime = 0;
507 sched_params.allowDelay = RF_AllowDelayAny;
509 CMD_STATUS(netstack_cmd_tx) = PENDING;
511 RF_CmdHandle tx_handle = RF_scheduleCmd(
513 (RF_Op *)&netstack_cmd_tx,
518 if(!CMD_HANDLE_OK(tx_handle)) {
519 LOG_ERR(
"Unable to schedule TX command, handle=%d status=0x%04x\n",
520 tx_handle, CMD_STATUS(netstack_cmd_tx));
521 return RF_RESULT_ERROR;
528 const bool rx_key = cmd_rx_disable();
531 ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT);
533 ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);
537 if(radio_mode->poll_mode) {
538 const uint16_t frame_length = payload_length + RADIO_PHY_HEADER_LEN + RADIO_PHY_OVERHEAD;
540 US_TO_RTIMERTICKS(RADIO_BYTE_AIR_TIME * frame_length + 1200));
542 tx_events = RF_pendCmd(&rf_netstack, tx_handle, 0);
545 cmd_rx_restore(rx_key);
548 ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN);
550 ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
553 if(radio_mode->poll_mode) {
554 if(CMD_STATUS(netstack_cmd_tx) != PROP_DONE_OK) {
555 LOG_ERR(
"Pending on scheduled TX command generated error, status=0x%04x\n",
556 CMD_STATUS(netstack_cmd_tx));
557 return RF_RESULT_ERROR;
560 if(!EVENTS_CMD_DONE(tx_events)) {
561 LOG_ERR(
"Pending on scheduled TX command generated error, events=0x%08llx status=0x%04x\n",
562 tx_events, CMD_STATUS(netstack_cmd_tx));
563 return RF_RESULT_ERROR;
571netstack_sched_rx(
bool start)
573 if(cmd_rx_is_active()) {
574 LOG_WARN(
"Already in RX when scheduling RX\n");
578 RF_ScheduleCmdParams sched_params;
581 RF_ScheduleCmdParams_init(&sched_params);
583 sched_params.priority = RF_PriorityNormal;
584 sched_params.endTime = 0;
585 sched_params.allowDelay = RF_AllowDelayAny;
587 netstack_cmd_start_rat.rat0 = 0;
588 CMD_STATUS(netstack_cmd_start_rat) = PENDING;
592 (RF_Op *)&netstack_cmd_start_rat,
598 RF_ScheduleCmdParams_init(&sched_params);
600 sched_params.priority = RF_PriorityNormal;
601 sched_params.endTime = 0;
602 sched_params.allowDelay = RF_AllowDelayAny;
604 CMD_STATUS(netstack_cmd_rx) = PENDING;
606 cmd_rx_handle = RF_scheduleCmd(
608 (RF_Op *)&netstack_cmd_rx,
611 RF_EventRxEntryDone | RF_EventRxBufFull);
613 if(!CMD_HANDLE_OK(cmd_rx_handle)) {
614 LOG_ERR(
"Unable to schedule RX command, handle=%d status=0x%04x\n",
615 cmd_rx_handle, CMD_STATUS(netstack_cmd_rx));
616 return RF_RESULT_ERROR;
619 ENERGEST_ON(ENERGEST_TYPE_LISTEN);
623 rf_start_recalib_timer =
true;
631netstack_stop_rx(
void)
633 if(!cmd_rx_is_active()) {
634 LOG_WARN(
"RX not active when stopping RX\n");
638 CMD_STATUS(netstack_cmd_rx) = DONE_STOPPED;
639 const RF_Stat stat = RF_cancelCmd(&rf_netstack, cmd_rx_handle, RF_ABORT_GRACEFULLY);
642 ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
644 return (stat == RF_StatSuccess)
650ble_open(RF_Params *params)
652#if RF_CONF_BLE_BEACON_ENABLE
653 return RF_open(&rf_ble, &ble_mode, (RF_RadioSetup *)&ble_cmd_radio_setup, params);
656 return (RF_Handle)NULL;
660#if RF_CONF_BLE_BEACON_ENABLE
662init_ble_adv_array(ble_cmd_adv_nc_t *ble_adv_array, uint8_t bm_channel)
664 RF_Op *first_ble_adv = NULL;
665 ble_cmd_adv_nc_t *cmd_adv_37 = &ble_adv_array[0];
666 ble_cmd_adv_nc_t *cmd_adv_38 = &ble_adv_array[1];
667 ble_cmd_adv_nc_t *cmd_adv_39 = &ble_adv_array[2];
670 if(bm_channel & BLE_ADV_CHANNEL_37) {
672 memcpy(cmd_adv_37, &ble_cmd_adv_nc,
sizeof(ble_cmd_adv_nc));
674 cmd_adv_37->channel = 37;
676 cmd_adv_37->whitening.init = 0x65;
683 if(bm_channel & BLE_ADV_CHANNEL_38) {
684 cmd_adv_37->pNextOp = (RF_Op *)cmd_adv_38;
685 cmd_adv_37->condition.rule = COND_ALWAYS;
686 }
else if(bm_channel & BLE_ADV_CHANNEL_39) {
687 cmd_adv_37->pNextOp = (RF_Op *)cmd_adv_39;
688 cmd_adv_37->condition.rule = COND_ALWAYS;
690 cmd_adv_37->pNextOp = NULL;
691 cmd_adv_37->condition.rule = COND_NEVER;
695 first_ble_adv = (RF_Op *)cmd_adv_37;
699 if(bm_channel & BLE_ADV_CHANNEL_38) {
700 memcpy(cmd_adv_38, &ble_cmd_adv_nc,
sizeof(ble_cmd_adv_nc));
702 cmd_adv_38->channel = 38;
704 cmd_adv_38->whitening.init = 0x66;
710 if(bm_channel & BLE_ADV_CHANNEL_39) {
711 cmd_adv_38->pNextOp = (RF_Op *)cmd_adv_39;
712 cmd_adv_38->condition.rule = COND_ALWAYS;
714 cmd_adv_38->pNextOp = NULL;
715 cmd_adv_38->condition.rule = COND_NEVER;
722 if(first_ble_adv == NULL) {
723 first_ble_adv = (RF_Op *)cmd_adv_38;
728 if(bm_channel & BLE_ADV_CHANNEL_39) {
729 memcpy(cmd_adv_39, &ble_cmd_adv_nc,
sizeof(ble_cmd_adv_nc));
731 cmd_adv_39->channel = 39;
733 cmd_adv_39->whitening.init = 0x67;
736 cmd_adv_39->pNextOp = NULL;
737 cmd_adv_39->condition.rule = COND_NEVER;
743 if(first_ble_adv == NULL) {
744 first_ble_adv = (RF_Op *)cmd_adv_39;
748 return first_ble_adv;
753ble_sched_beacons(uint8_t bm_channel)
755#if RF_CONF_BLE_BEACON_ENABLE
761 ble_cmd_adv_nc_t ble_cmd_adv_nc_array[NUM_BLE_ADV_CHANNELS];
763 RF_Op *initial_adv = NULL;
764 RF_ScheduleCmdParams sched_params;
765 RF_CmdHandle beacon_handle;
766 RF_EventMask beacon_events;
767 rf_result_t rf_result;
770 if((bm_channel & BLE_ADV_CHANNEL_ALL) == 0) {
774 initial_adv = init_ble_adv_array(ble_cmd_adv_nc_array, bm_channel);
776 if(initial_adv == NULL) {
777 LOG_ERR(
"Initializing BLE Advertisement chain failed\n");
778 return RF_RESULT_ERROR;
781 RF_ScheduleCmdParams_init(&sched_params);
782 sched_params.priority = RF_PriorityNormal;
783 sched_params.endTime = 0;
784 sched_params.allowDelay = RF_AllowDelayAny;
792 beacon_handle = RF_scheduleCmd(
799 if(!CMD_HANDLE_OK(beacon_handle)) {
800 LOG_ERR(
"Unable to schedule BLE Beacon command, handle=%d status=0x%04x\n",
801 beacon_handle, CMD_STATUS(ble_cmd_adv_nc));
803 return RF_RESULT_ERROR;
807 rf_result = cmd_rx_restore(cmd_rx_disable());
810 beacon_events = RF_pendCmd(&rf_ble, beacon_handle, 0);
812 if(rf_result != RF_RESULT_OK) {
813 LOG_ERR(
"Rescheduling CMD_RX failed when BLE advertising\n");
815 return RF_RESULT_ERROR;
818 if(!EVENTS_CMD_DONE(beacon_events)) {
819 LOG_ERR(
"Pending on scheduled BLE Beacon command generated error, events=0x%08llx status=0x%04x\n",
820 beacon_events, CMD_STATUS(ble_cmd_adv_nc));
822 return RF_RESULT_ERROR;
828 return RF_RESULT_ERROR;
832PROCESS(rf_sched_process,
"RF Scheduler Process");
842 (ev == PROCESS_EVENT_TIMER));
845 if(rf_start_recalib_timer) {
846 rf_start_recalib_timer =
false;
848 clock_time_t interval = synth_recal_interval();
849 LOG_INFO(
"Starting synth re-calibration timer, next timeout %lu\n", interval);
854 if(ev == PROCESS_EVENT_POLL) {
866 LOG_ERR(
"RX buffer full, restart RX status=0x%04x\n", CMD_STATUS(netstack_cmd_rx));
871 netstack_sched_rx(
false);
877 NETSTACK_MAC.
input();
880 }
while(NETSTACK_RADIO.pending_packet());
884 if((ev == PROCESS_EVENT_TIMER) &&
887 clock_time_t interval = synth_recal_interval();
888 LOG_DBG(
"Re-calibrate synth, next interval %lu\n", interval);
Default definitions of C compiler quirk work-arounds.
Header file of the CC13xx/CC26xx RF data queue.
Header file for the energy estimation mechanism.
unsigned short random_rand(void)
Generates a new random number using the cc2538 RNG.
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
void watchdog_periodic(void)
Writes the WDT clear sequence.
int etimer_expired(struct etimer *et)
Check if an event timer has expired.
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer.
void packetbuf_set_datalen(uint16_t len)
Set the length of the data in the packetbuf.
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
#define PACKETBUF_SIZE
The size of the packetbuf, in bytes.
void packetbuf_clear(void)
Clear and reset the packetbuf.
#define PROCESS(name, strname)
Declare a process.
#define PROCESS_BEGIN()
Define the beginning of a process.
#define PROCESS_END()
Define the end of a process.
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
void process_poll(struct process *p)
Request a process to be polled.
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.
static void start(void)
Start measurement.
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 for the Contiki process interface.
Header file of the generic radio mode API.
Header file of common CC13xx/CC26xx RF functionality.
Header file of the CC13xx/CC26xx RF scheduler.
Header file of RF settings for CC13xx/CC26xx.
void(* input)(void)
Callback for getting notified of incoming packet.