Contiki-NG
sched.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holder nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28 * OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30/**
31 * \addtogroup cc13xx-cc26xx-rf-sched
32 * @{
33 *
34 * \file
35 * Implementation of the CC13xx/CC26xx RF scheduler.
36 * \author
37 * Edvard Pettersen <e.pettersen@ti.com>
38 */
39/*---------------------------------------------------------------------------*/
40#include "contiki.h"
41#include "dev/watchdog.h"
42#include "sys/cc.h"
43#include "sys/etimer.h"
44#include "sys/process.h"
45#include "sys/energest.h"
46#include "net/netstack.h"
47#include "net/packetbuf.h"
48#include "net/mac/mac.h"
49#include "lib/random.h"
50/*---------------------------------------------------------------------------*/
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"
58#else
59#include DeviceFamily_constructPath(driverlib/rf_ieee_mailbox.h)
60#endif
61
62#include <ti/drivers/rf/RF.h>
63/*---------------------------------------------------------------------------*/
64#include "rf/rf.h"
65#include "rf/sched.h"
66#include "rf/data-queue.h"
67#include "rf/settings.h"
68#include "rf/radio-mode.h"
69/*---------------------------------------------------------------------------*/
70#include <stdbool.h>
71#include <stdint.h>
72#include <string.h>
73/*---------------------------------------------------------------------------*/
74/* Log configuration */
75#include "sys/log.h"
76#define LOG_MODULE "Radio"
77#define LOG_LEVEL LOG_LEVEL_NONE
78/*---------------------------------------------------------------------------*/
79#define CMD_FS_RETRIES 3
80
81#define RF_EVENTS_CMD_DONE (RF_EventCmdDone | RF_EventLastCmdDone | \
82 RF_EventFGCmdDone | RF_EventLastFGCmdDone)
83
84#define CMD_STATUS(cmd) (CC_ACCESS_NOW(RF_Op, cmd).status)
85
86#define CMD_HANDLE_OK(handle) (((handle) != RF_ALLOC_ERROR) && \
87 ((handle) != RF_SCHEDULE_CMD_ERROR))
88
89#define EVENTS_CMD_DONE(events) (((events) & RF_EVENTS_CMD_DONE) != 0)
90/*---------------------------------------------------------------------------*/
91/* BLE advertisement channel range (inclusive) */
92#define BLE_ADV_CHANNEL_MIN 37
93#define BLE_ADV_CHANNEL_MAX 39
94
95/* Number of BLE advertisement channels */
96#define NUM_BLE_ADV_CHANNELS (BLE_ADV_CHANNEL_MAX - BLE_ADV_CHANNEL_MIN + 1)
97/*---------------------------------------------------------------------------*/
98/* Synth re-calibration every 3 minutes */
99#define SYNTH_RECAL_INTERVAL (CLOCK_SECOND * 60 * 3)
100/* Set re-calibration interval with a jitter of 10 seconds */
101#define SYNTH_RECAL_JITTER (CLOCK_SECOND * 10)
102
103static struct etimer synth_recal_timer;
104/*---------------------------------------------------------------------------*/
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;
109#endif
110/*---------------------------------------------------------------------------*/
111static RF_Object rf_netstack;
112
113#if RF_CONF_BLE_BEACON_ENABLE
114static RF_Object rf_ble;
115#endif
116
117static volatile RF_CmdHandle cmd_rx_handle;
118
119static volatile bool rf_is_on;
120static volatile bool rf_start_recalib_timer;
121static volatile bool rx_buf_full;
122
123static rfc_CMD_SYNC_STOP_RAT_t netstack_cmd_stop_rat;
124static rfc_CMD_SYNC_START_RAT_t netstack_cmd_start_rat;
125
126simplelink_radio_mode_t *radio_mode;
127/*---------------------------------------------------------------------------*/
128static void
129cmd_rx_cb(RF_Handle client, RF_CmdHandle command, RF_EventMask events)
130{
131 /* Unused arguments */
132 (void)client;
133 (void)command;
134
135 if(radio_mode->poll_mode) {
136 return;
137 }
138
139 if(events & RF_EventRxEntryDone) {
140 process_poll(&rf_sched_process);
141 }
142
143 if(events & RF_EventRxBufFull) {
144 rx_buf_full = true;
145 process_poll(&rf_sched_process);
146 }
147}
148/*---------------------------------------------------------------------------*/
149static inline clock_time_t
150synth_recal_interval(void)
151{
152 /*
153 * Add jitter centered around SYNTH_RECAL_INTERVAL, giving a plus/minus
154 * jitter seconds halved.
155 */
156 return SYNTH_RECAL_INTERVAL + (random_rand() % SYNTH_RECAL_JITTER) - (SYNTH_RECAL_JITTER / 2);
157}
158/*---------------------------------------------------------------------------*/
159static inline bool
160cmd_rx_is_active(void)
161{
162 /*
163 * Active in this case means RX command is either running to be running,
164 * that is ACTIVE for running or PENDING for to be running.
165 */
166 const uint16_t status = CMD_STATUS(netstack_cmd_rx);
167 return (status == ACTIVE) ||
168 (status == PENDING);
169}
170/*---------------------------------------------------------------------------*/
171static uint_fast8_t
172cmd_rx_disable(void)
173{
174 const bool is_active = cmd_rx_is_active();
175
176 if(is_active) {
177 CMD_STATUS(netstack_cmd_rx) = DONE_STOPPED;
178 RF_cancelCmd(&rf_netstack, cmd_rx_handle, RF_ABORT_GRACEFULLY);
179 cmd_rx_handle = 0;
180 }
181
182 return (uint_fast8_t)is_active;
183}
184/*---------------------------------------------------------------------------*/
185static rf_result_t
186cmd_rx_restore(uint_fast8_t rx_key)
187{
188 const bool was_active = (rx_key != 0) ? true : false;
189
190 if(!was_active) {
191 return RF_RESULT_OK;
192 }
193
194 RF_ScheduleCmdParams sched_params;
195 RF_ScheduleCmdParams_init(&sched_params);
196
197 sched_params.priority = RF_PriorityNormal;
198 sched_params.endTime = 0;
199 sched_params.allowDelay = RF_AllowDelayAny;
200
201 CMD_STATUS(netstack_cmd_rx) = PENDING;
202
203 cmd_rx_handle = RF_scheduleCmd(
204 &rf_netstack,
205 (RF_Op *)&netstack_cmd_rx,
206 &sched_params,
207 cmd_rx_cb,
208 RF_EventRxEntryDone | RF_EventRxBufFull);
209
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;
214 }
215
216 return RF_RESULT_OK;
217}
218/*---------------------------------------------------------------------------*/
219rf_result_t
220rf_yield(void)
221{
222 /* Force abort of any ongoing RF operation */
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);
226#endif
227
228 /* Stop SYNC RAT to get current RAT */
229 RF_ScheduleCmdParams sched_params;
230 RF_ScheduleCmdParams_init(&sched_params);
231
232 sched_params.priority = RF_PriorityNormal;
233 sched_params.endTime = 0;
234 sched_params.allowDelay = RF_AllowDelayAny;
235
236 CMD_STATUS(netstack_cmd_stop_rat) = PENDING;
237
238 RF_scheduleCmd(
239 &rf_netstack,
240 (RF_Op *)&netstack_cmd_stop_rat,
241 &sched_params,
242 NULL,
243 0);
244
245 /* Trigger a manual power-down */
246 RF_yield(&rf_netstack);
247#if RF_CONF_BLE_BEACON_ENABLE
248 RF_yield(&rf_ble);
249#endif
250
251 ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
252 rf_is_on = false;
253
254 return RF_RESULT_OK;
255}
256/*---------------------------------------------------------------------------*/
257rf_result_t
258rf_restart_rat(void)
259{
260 RF_ScheduleCmdParams sched_params;
261
262 /* Stop SYNC RAT */
263 RF_ScheduleCmdParams_init(&sched_params);
264
265 sched_params.priority = RF_PriorityNormal;
266 sched_params.endTime = 0;
267 sched_params.allowDelay = RF_AllowDelayAny;
268
269 CMD_STATUS(netstack_cmd_stop_rat) = PENDING;
270
271 RF_scheduleCmd(
272 &rf_netstack,
273 (RF_Op *)&netstack_cmd_stop_rat,
274 &sched_params,
275 NULL,
276 0);
277
278 /* Start SYNC RAT */
279 RF_ScheduleCmdParams_init(&sched_params);
280
281 sched_params.priority = RF_PriorityNormal;
282 sched_params.endTime = 0;
283 sched_params.allowDelay = RF_AllowDelayAny;
284
285 netstack_cmd_start_rat.rat0 = 0;
286 CMD_STATUS(netstack_cmd_start_rat) = PENDING;
287
288 RF_scheduleCmd(
289 &rf_netstack,
290 (RF_Op *)&netstack_cmd_start_rat,
291 &sched_params,
292 NULL,
293 0);
294
295 return RF_RESULT_OK;
296}
297
298/*---------------------------------------------------------------------------*/
299rf_result_t
300rf_set_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t dbm)
301{
302 const RF_Stat stat = RF_setTxPower(handle, RF_TxPowerTable_findValue(table, dbm));
303
304 return (stat == RF_StatSuccess)
305 ? RF_RESULT_OK
306 : RF_RESULT_ERROR;
307}
308/*---------------------------------------------------------------------------*/
309rf_result_t
310rf_get_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t *dbm)
311{
312 *dbm = RF_TxPowerTable_findPowerLevel(table, RF_getTxPower(handle));
313
314 return (*dbm != RF_TxPowerTable_INVALID_DBM)
315 ? RF_RESULT_OK
316 : RF_RESULT_ERROR;
317}
318/*---------------------------------------------------------------------------*/
319RF_Handle
320netstack_open(RF_Params *params)
321{
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);
327}
328/*---------------------------------------------------------------------------*/
329rf_result_t
330netstack_sched_fs(void)
331{
332 const uint_fast8_t rx_key = cmd_rx_disable();
333
334 /*
335 * For IEEE-mode, restarting CMD_IEEE_RX re-calibrates the synth by using the
336 * channel field in the CMD_IEEE_RX command. It is assumed this field is
337 * already configured before this function is called. However, if
338 * CMD_IEEE_RX wasn't active, manually calibrate the synth with CMD_FS.
339 *
340 * For Prop-mode, the synth is always manually calibrated with CMD_FS.
341 */
342#if (RF_MODE == RF_MODE_2_4_GHZ)
343 if(rx_key) {
344 cmd_rx_restore(rx_key);
345 return RF_RESULT_OK;
346 }
347#endif /* RF_MODE == RF_MODE_2_4_GHZ */
348
349 if(radio_mode->poll_mode) {
350 /*
351 * In poll mode; cannot execute the command, can just schedule it.
352 * Retrying is not possible.
353 */
354 RF_ScheduleCmdParams sched_params;
355 RF_ScheduleCmdParams_init(&sched_params);
356
357 sched_params.priority = RF_PriorityNormal;
358 sched_params.endTime = 0;
359 sched_params.allowDelay = RF_AllowDelayAny;
360
361 CMD_STATUS(netstack_cmd_fs) = PENDING;
362
363 RF_CmdHandle fs_handle = RF_scheduleCmd(
364 &rf_netstack,
365 (RF_Op *)&netstack_cmd_fs,
366 &sched_params,
367 NULL,
368 0);
369
370 cmd_rx_restore(rx_key);
371
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;
376 }
377
378 return RF_RESULT_OK;
379
380 } else {
381 /*
382 * Not in poll mode. Execute the command immediately,
383 * wait for result, retry if neccessary.
384 */
385 RF_EventMask events;
386 bool synth_error = false;
387 uint8_t num_tries = 0;
388
389 do {
390 CMD_STATUS(netstack_cmd_fs) = PENDING;
391
392 events = RF_runCmd(
393 &rf_netstack,
394 (RF_Op *)&netstack_cmd_fs,
395 RF_PriorityNormal,
396 NULL,
397 0);
398
399 synth_error = (EVENTS_CMD_DONE(events)) && (CMD_STATUS(netstack_cmd_fs) == ERROR_SYNTH_PROG);
400
401 } while(synth_error && (num_tries++ < CMD_FS_RETRIES));
402
403 cmd_rx_restore(rx_key);
404
405 return (CMD_STATUS(netstack_cmd_fs) == DONE_OK)
406 ? RF_RESULT_OK
407 : RF_RESULT_ERROR;
408 }
409}
410/*---------------------------------------------------------------------------*/
411rf_result_t
412netstack_sched_ieee_tx(uint16_t payload_length, bool ack_request)
413{
414 rf_result_t res;
415 RF_EventMask tx_events = 0;
416
417 RF_ScheduleCmdParams sched_params;
418 RF_ScheduleCmdParams_init(&sched_params);
419
420 sched_params.priority = RF_PriorityNormal;
421 sched_params.endTime = 0;
422 sched_params.allowDelay = RF_AllowDelayAny;
423
424 const bool rx_is_active = cmd_rx_is_active();
425 const bool rx_needed = (ack_request && !rx_is_active);
426
427 /*
428 * If we expect ACK after transmission, RX must be running to be able to
429 * run the RX_ACK command. Therefore, turn on RX before starting the
430 * chained TX command.
431 */
432 if(rx_needed) {
433 res = netstack_sched_rx(false);
434 if(res != RF_RESULT_OK) {
435 return res;
436 }
437 }
438
439 CMD_STATUS(netstack_cmd_tx) = PENDING;
440
441 RF_CmdHandle tx_handle = RF_scheduleCmd(
442 &rf_netstack,
443 (RF_Op *)&netstack_cmd_tx,
444 &sched_params,
445 NULL,
446 0);
447
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;
452 }
453
454 if(rx_is_active) {
455 ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT);
456 } else {
457 ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);
458 }
459
460 /* Wait until TX operation finishes */
461 if(radio_mode->poll_mode) {
462 const uint16_t frame_length = payload_length + RADIO_PHY_HEADER_LEN + RADIO_PHY_OVERHEAD;
463 RTIMER_BUSYWAIT_UNTIL((CMD_STATUS(netstack_cmd_tx) & 0xC00) != 0,
464 US_TO_RTIMERTICKS(RADIO_BYTE_AIR_TIME * frame_length + 300));
465 } else {
466 tx_events = RF_pendCmd(&rf_netstack, tx_handle, 0);
467 }
468
469 /* Stop RX if it was turned on only for ACK */
470 if(rx_needed) {
471 netstack_stop_rx();
472 }
473
474 if(rx_is_active) {
475 ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN);
476 } else {
477 ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
478 }
479
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;
485 }
486 } else {
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;
491 }
492 }
493
494 return RF_RESULT_OK;
495}
496/*---------------------------------------------------------------------------*/
497rf_result_t
498netstack_sched_prop_tx(uint16_t payload_length)
499{
500 RF_EventMask tx_events = 0;
501
502 RF_ScheduleCmdParams sched_params;
503 RF_ScheduleCmdParams_init(&sched_params);
504
505 sched_params.priority = RF_PriorityNormal;
506 sched_params.endTime = 0;
507 sched_params.allowDelay = RF_AllowDelayAny;
508
509 CMD_STATUS(netstack_cmd_tx) = PENDING;
510
511 RF_CmdHandle tx_handle = RF_scheduleCmd(
512 &rf_netstack,
513 (RF_Op *)&netstack_cmd_tx,
514 &sched_params,
515 NULL,
516 0);
517
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;
522 }
523
524 /*
525 * Prop TX requires any on-going RX operation to be stopped to be
526 * able to transmit. Therefore, disable RX if running.
527 */
528 const bool rx_key = cmd_rx_disable();
529
530 if(rx_key) {
531 ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT);
532 } else {
533 ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);
534 }
535
536 /* Wait until TX operation finishes */
537 if(radio_mode->poll_mode) {
538 const uint16_t frame_length = payload_length + RADIO_PHY_HEADER_LEN + RADIO_PHY_OVERHEAD;
539 RTIMER_BUSYWAIT_UNTIL((CMD_STATUS(netstack_cmd_tx) & 0xC00) != 0,
540 US_TO_RTIMERTICKS(RADIO_BYTE_AIR_TIME * frame_length + 1200));
541 } else {
542 tx_events = RF_pendCmd(&rf_netstack, tx_handle, 0);
543 }
544
545 cmd_rx_restore(rx_key);
546
547 if(rx_key) {
548 ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN);
549 } else {
550 ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
551 }
552
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;
558 }
559 } else {
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;
564 }
565 }
566
567 return RF_RESULT_OK;
568}
569/*---------------------------------------------------------------------------*/
570rf_result_t
571netstack_sched_rx(bool start)
572{
573 if(cmd_rx_is_active()) {
574 LOG_WARN("Already in RX when scheduling RX\n");
575 return RF_RESULT_OK;
576 }
577
578 RF_ScheduleCmdParams sched_params;
579 if(start) {
580 /* Start SYNC RAT */
581 RF_ScheduleCmdParams_init(&sched_params);
582
583 sched_params.priority = RF_PriorityNormal;
584 sched_params.endTime = 0;
585 sched_params.allowDelay = RF_AllowDelayAny;
586
587 netstack_cmd_start_rat.rat0 = 0;
588 CMD_STATUS(netstack_cmd_start_rat) = PENDING;
589
590 RF_scheduleCmd(
591 &rf_netstack,
592 (RF_Op *)&netstack_cmd_start_rat,
593 &sched_params,
594 NULL,
595 0);
596 }
597
598 RF_ScheduleCmdParams_init(&sched_params);
599
600 sched_params.priority = RF_PriorityNormal;
601 sched_params.endTime = 0;
602 sched_params.allowDelay = RF_AllowDelayAny;
603
604 CMD_STATUS(netstack_cmd_rx) = PENDING;
605
606 cmd_rx_handle = RF_scheduleCmd(
607 &rf_netstack,
608 (RF_Op *)&netstack_cmd_rx,
609 &sched_params,
610 cmd_rx_cb,
611 RF_EventRxEntryDone | RF_EventRxBufFull);
612
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;
617 }
618
619 ENERGEST_ON(ENERGEST_TYPE_LISTEN);
620 rf_is_on = true;
621
622 if(start) {
623 rf_start_recalib_timer = true;
624 process_poll(&rf_sched_process);
625 }
626
627 return RF_RESULT_OK;
628}
629/*---------------------------------------------------------------------------*/
630rf_result_t
631netstack_stop_rx(void)
632{
633 if(!cmd_rx_is_active()) {
634 LOG_WARN("RX not active when stopping RX\n");
635 return RF_RESULT_OK;
636 }
637
638 CMD_STATUS(netstack_cmd_rx) = DONE_STOPPED;
639 const RF_Stat stat = RF_cancelCmd(&rf_netstack, cmd_rx_handle, RF_ABORT_GRACEFULLY);
640 cmd_rx_handle = 0;
641
642 ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
643
644 return (stat == RF_StatSuccess)
645 ? RF_RESULT_OK
646 : RF_RESULT_ERROR;
647}
648/*---------------------------------------------------------------------------*/
649RF_Handle
650ble_open(RF_Params *params)
651{
652#if RF_CONF_BLE_BEACON_ENABLE
653 return RF_open(&rf_ble, &ble_mode, (RF_RadioSetup *)&ble_cmd_radio_setup, params);
654
655#else
656 return (RF_Handle)NULL;
657#endif
658}
659/*---------------------------------------------------------------------------*/
660#if RF_CONF_BLE_BEACON_ENABLE
661static RF_Op *
662init_ble_adv_array(ble_cmd_adv_nc_t *ble_adv_array, uint8_t bm_channel)
663{
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];
668
669 /* Setup channel 37 advertisement if enabled */
670 if(bm_channel & BLE_ADV_CHANNEL_37) {
671 /* Default configurations from ble_cmd_adv_nc */
672 memcpy(cmd_adv_37, &ble_cmd_adv_nc, sizeof(ble_cmd_adv_nc));
673
674 cmd_adv_37->channel = 37;
675 /* Magic number: initialization for whitener, specific for channel 37 */
676 cmd_adv_37->whitening.init = 0x65;
677
678 /*
679 * The next advertisement is chained depending on whether they are
680 * enbled or not. If both 38 and 39 are disabled, then there is no
681 * chaining.
682 */
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;
689 } else {
690 cmd_adv_37->pNextOp = NULL;
691 cmd_adv_37->condition.rule = COND_NEVER;
692 }
693
694 /* Channel 37 will always be first if enabled */
695 first_ble_adv = (RF_Op *)cmd_adv_37;
696 }
697
698 /* Setup channel 38 advertisement if enabled */
699 if(bm_channel & BLE_ADV_CHANNEL_38) {
700 memcpy(cmd_adv_38, &ble_cmd_adv_nc, sizeof(ble_cmd_adv_nc));
701
702 cmd_adv_38->channel = 38;
703 /* Magic number: initialization for whitener, specific for channel 38 */
704 cmd_adv_38->whitening.init = 0x66;
705
706 /*
707 * The next advertisement is chained depending on whether they are
708 * enbled or not. If 39 is disabled, then there is no chaining.
709 */
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;
713 } else {
714 cmd_adv_38->pNextOp = NULL;
715 cmd_adv_38->condition.rule = COND_NEVER;
716 }
717
718 /*
719 * Channel 38 is only first if the first_ble_adv pointer is not
720 * set by channel 37.
721 */
722 if(first_ble_adv == NULL) {
723 first_ble_adv = (RF_Op *)cmd_adv_38;
724 }
725 }
726
727 /* Setup channel 39 advertisement if enabled */
728 if(bm_channel & BLE_ADV_CHANNEL_39) {
729 memcpy(cmd_adv_39, &ble_cmd_adv_nc, sizeof(ble_cmd_adv_nc));
730
731 cmd_adv_39->channel = 39;
732 /* Magic number: initialization for whitener, specific for channel 39 */
733 cmd_adv_39->whitening.init = 0x67;
734
735 /* Channel 39 is always the last advertisement in the chain */
736 cmd_adv_39->pNextOp = NULL;
737 cmd_adv_39->condition.rule = COND_NEVER;
738
739 /*
740 * Channel 39 is only first if the first_ble_adv pointer is not
741 * set by channel 37 or channel 38.
742 */
743 if(first_ble_adv == NULL) {
744 first_ble_adv = (RF_Op *)cmd_adv_39;
745 }
746 }
747
748 return first_ble_adv;
749}
750#endif /* RF_CONF_BLE_BEACON_ENABLE */
751/*---------------------------------------------------------------------------*/
752rf_result_t
753ble_sched_beacons(uint8_t bm_channel)
754{
755#if RF_CONF_BLE_BEACON_ENABLE
756 /*
757 * Allocate the advertisement commands on the stack rather than statically
758 * to RAM in order to save space. We don't need them after the
759 * advertisements have been transmitted.
760 */
761 ble_cmd_adv_nc_t ble_cmd_adv_nc_array[NUM_BLE_ADV_CHANNELS];
762
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;
768
769 /* If no channels are mapped, then early return OK */
770 if((bm_channel & BLE_ADV_CHANNEL_ALL) == 0) {
771 return RF_RESULT_OK;
772 }
773
774 initial_adv = init_ble_adv_array(ble_cmd_adv_nc_array, bm_channel);
775
776 if(initial_adv == NULL) {
777 LOG_ERR("Initializing BLE Advertisement chain failed\n");
778 return RF_RESULT_ERROR;
779 }
780
781 RF_ScheduleCmdParams_init(&sched_params);
782 sched_params.priority = RF_PriorityNormal;
783 sched_params.endTime = 0;
784 sched_params.allowDelay = RF_AllowDelayAny;
785
786 /*
787 * The most efficient way to schedule the command is as follows:
788 * 1. Schedule the BLE advertisement chain
789 * 2. Reschedule the RX command IF it was running.
790 * 3. Pend on the BLE avertisement chain
791 */
792 beacon_handle = RF_scheduleCmd(
793 &rf_ble,
794 initial_adv,
795 &sched_params,
796 NULL,
797 0);
798
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));
802
803 return RF_RESULT_ERROR;
804 }
805
806 /* Note that this only reschedules RX if it is running */
807 rf_result = cmd_rx_restore(cmd_rx_disable());
808
809 /* Wait until Beacon operation finishes */
810 beacon_events = RF_pendCmd(&rf_ble, beacon_handle, 0);
811
812 if(rf_result != RF_RESULT_OK) {
813 LOG_ERR("Rescheduling CMD_RX failed when BLE advertising\n");
814
815 return RF_RESULT_ERROR;
816 }
817
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));
821
822 return RF_RESULT_ERROR;
823 }
824
825 return RF_RESULT_OK;
826
827#else
828 return RF_RESULT_ERROR;
829#endif
830}
831/*---------------------------------------------------------------------------*/
832PROCESS(rf_sched_process, "RF Scheduler Process");
833/*---------------------------------------------------------------------------*/
834PROCESS_THREAD(rf_sched_process, ev, data)
835{
836 int len;
837
839
840 while(1) {
841 PROCESS_YIELD_UNTIL((ev == PROCESS_EVENT_POLL) ||
842 (ev == PROCESS_EVENT_TIMER));
843
844 /* start the synth re-calibration timer once. */
845 if(rf_start_recalib_timer) {
846 rf_start_recalib_timer = false;
847 if(rf_is_on) {
848 clock_time_t interval = synth_recal_interval();
849 LOG_INFO("Starting synth re-calibration timer, next timeout %lu\n", interval);
850 etimer_set(&synth_recal_timer, interval);
851 }
852 }
853
854 if(ev == PROCESS_EVENT_POLL) {
855 do {
857
859 len = NETSTACK_RADIO.read(packetbuf_dataptr(), PACKETBUF_SIZE);
860
861 /*
862 * RX will stop if the RX buffers are full. In this case, restart
863 * RX after we've freed at least on packet.
864 */
865 if(rx_buf_full) {
866 LOG_ERR("RX buffer full, restart RX status=0x%04x\n", CMD_STATUS(netstack_cmd_rx));
867 rx_buf_full = false;
868
869 /* Restart RX. */
870 netstack_stop_rx();
871 netstack_sched_rx(false);
872 }
873
874 if(len > 0) {
876
877 NETSTACK_MAC.input();
878 }
879 /* Only break when no more packets pending */
880 } while(NETSTACK_RADIO.pending_packet());
881 }
882
883 /* Scheduling CMD_FS will re-calibrate the synth. */
884 if((ev == PROCESS_EVENT_TIMER) &&
885 etimer_expired(&synth_recal_timer)) {
886 if(rf_is_on) {
887 clock_time_t interval = synth_recal_interval();
888 LOG_DBG("Re-calibrate synth, next interval %lu\n", interval);
889
890 netstack_sched_fs();
891 etimer_set(&synth_recal_timer, interval);
892 }
893 }
894 }
895 PROCESS_END();
896}
897/*---------------------------------------------------------------------------*/
898/** @} */
Default definitions of C compiler quirk work-arounds.
Header file of the CC13xx/CC26xx RF data queue.
Header file for the energy estimation mechanism.
Event timer header file.
unsigned short random_rand(void)
Generates a new random number using the cc2538 RNG.
Definition: random.c:58
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1154
void watchdog_periodic(void)
Writes the WDT clear sequence.
Definition: watchdog.c:85
int etimer_expired(struct etimer *et)
Check if an event timer has expired.
Definition: etimer.c:213
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer.
Definition: etimer.c:177
void packetbuf_set_datalen(uint16_t len)
Set the length of the data in the packetbuf.
Definition: packetbuf.c:136
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
Definition: packetbuf.c:143
#define PACKETBUF_SIZE
The size of the packetbuf, in bytes.
Definition: packetbuf.h:67
void packetbuf_clear(void)
Clear and reset the packetbuf.
Definition: packetbuf.c:75
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Definition: process.h:178
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
static uint8_t rf_is_on(void)
Checks whether the RFC domain is accessible and the RFC is in IEEE RX.
Definition: ieee-mode.c:267
#define RTIMER_BUSYWAIT_UNTIL(cond, max_time)
Busy-wait until a condition for at most max_time.
Definition: rtimer.h:211
static void start(void)
Start measurement.
Header file for the logging system.
MAC driver header file.
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.
A timer.
Definition: etimer.h:76
void(* input)(void)
Callback for getting notified of incoming packet.
Definition: mac.h:72