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 
56 #include <ti/drivers/rf/RF.h>
57 /*---------------------------------------------------------------------------*/
58 #include "rf/rf.h"
59 #include "rf/sched.h"
60 #include "rf/data-queue.h"
61 #include "rf/settings.h"
62 /*---------------------------------------------------------------------------*/
63 #include <stdbool.h>
64 #include <stdint.h>
65 #include <string.h>
66 /*---------------------------------------------------------------------------*/
67 /* Log configuration */
68 #include "sys/log.h"
69 #define LOG_MODULE "Radio"
70 #define LOG_LEVEL LOG_LEVEL_NONE
71 /*---------------------------------------------------------------------------*/
72 #define CMD_FS_RETRIES 3
73 
74 #define RF_EVENTS_CMD_DONE (RF_EventCmdDone | RF_EventLastCmdDone | \
75  RF_EventFGCmdDone | RF_EventLastFGCmdDone)
76 
77 #define CMD_STATUS(cmd) (CC_ACCESS_NOW(RF_Op, cmd).status)
78 
79 #define CMD_HANDLE_OK(handle) (((handle) != RF_ALLOC_ERROR) && \
80  ((handle) != RF_SCHEDULE_CMD_ERROR))
81 
82 #define EVENTS_CMD_DONE(events) (((events) & RF_EVENTS_CMD_DONE) != 0)
83 /*---------------------------------------------------------------------------*/
84 /* BLE advertisement channel range (inclusive) */
85 #define BLE_ADV_CHANNEL_MIN 37
86 #define BLE_ADV_CHANNEL_MAX 39
87 
88 /* Number of BLE advertisement channels */
89 #define NUM_BLE_ADV_CHANNELS (BLE_ADV_CHANNEL_MAX - BLE_ADV_CHANNEL_MIN + 1)
90 /*---------------------------------------------------------------------------*/
91 /* Synth re-calibration every 3 minutes */
92 #define SYNTH_RECAL_INTERVAL (CLOCK_SECOND * 60 * 3)
93 /* Set re-calibration interval with a jitter of 10 seconds */
94 #define SYNTH_RECAL_JITTER (CLOCK_SECOND * 10)
95 
96 static struct etimer synth_recal_timer;
97 /*---------------------------------------------------------------------------*/
98 #if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0)
99 typedef rfc_CMD_BLE_ADV_NC_t ble_cmd_adv_nc_t;
100 #elif (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X2_CC26X2)
101 typedef rfc_CMD_BLE5_ADV_NC_t ble_cmd_adv_nc_t;
102 #endif
103 /*---------------------------------------------------------------------------*/
104 static RF_Object rf_netstack;
105 
106 #if RF_CONF_BLE_BEACON_ENABLE
107 static RF_Object rf_ble;
108 #endif
109 
110 static RF_CmdHandle cmd_rx_handle;
111 
112 static bool rf_is_on;
113 static volatile bool rx_buf_full;
114 /*---------------------------------------------------------------------------*/
115 static void
116 cmd_rx_cb(RF_Handle client, RF_CmdHandle command, RF_EventMask events)
117 {
118  /* Unused arguments */
119  (void)client;
120  (void)command;
121 
122  if(events & RF_EventRxEntryDone) {
123  process_poll(&rf_sched_process);
124  }
125 
126  if(events & RF_EventRxBufFull) {
127  rx_buf_full = true;
128  process_poll(&rf_sched_process);
129  }
130 }
131 /*---------------------------------------------------------------------------*/
132 static inline clock_time_t
133 synth_recal_interval(void)
134 {
135  /*
136  * Add jitter centered around SYNTH_RECAL_INTERVAL, giving a plus/minus
137  * jitter seconds halved.
138  */
139  return SYNTH_RECAL_INTERVAL + (random_rand() % SYNTH_RECAL_JITTER) - (SYNTH_RECAL_JITTER / 2);
140 }
141 /*---------------------------------------------------------------------------*/
142 static inline bool
143 cmd_rx_is_active(void)
144 {
145  /*
146  * Active in this case means RX command is either running to be running,
147  * that is ACTIVE for running or PENDING for to be running.
148  */
149  const uint16_t status = CMD_STATUS(netstack_cmd_rx);
150  return (status == ACTIVE) ||
151  (status == PENDING);
152 }
153 /*---------------------------------------------------------------------------*/
154 static uint_fast8_t
155 cmd_rx_disable(void)
156 {
157  const bool is_active = cmd_rx_is_active();
158 
159  if(is_active) {
160  CMD_STATUS(netstack_cmd_rx) = DONE_STOPPED;
161  RF_cancelCmd(&rf_netstack, cmd_rx_handle, RF_ABORT_GRACEFULLY);
162  cmd_rx_handle = 0;
163  }
164 
165  return (uint_fast8_t)is_active;
166 }
167 /*---------------------------------------------------------------------------*/
168 static rf_result_t
169 cmd_rx_restore(uint_fast8_t rx_key)
170 {
171  const bool was_active = (rx_key != 0) ? true : false;
172 
173  if(!was_active) {
174  return RF_RESULT_OK;
175  }
176 
177  RF_ScheduleCmdParams sched_params;
178  RF_ScheduleCmdParams_init(&sched_params);
179 
180  sched_params.priority = RF_PriorityNormal;
181  sched_params.endTime = 0;
182  sched_params.allowDelay = RF_AllowDelayAny;
183 
184  CMD_STATUS(netstack_cmd_rx) = PENDING;
185 
186  cmd_rx_handle = RF_scheduleCmd(
187  &rf_netstack,
188  (RF_Op *)&netstack_cmd_rx,
189  &sched_params,
190  cmd_rx_cb,
191  RF_EventRxEntryDone | RF_EventRxBufFull);
192 
193  if(!CMD_HANDLE_OK(cmd_rx_handle)) {
194  LOG_ERR("Unable to restore RX command, handle=%d status=0x%04x",
195  cmd_rx_handle, CMD_STATUS(netstack_cmd_rx));
196  return RF_RESULT_ERROR;
197  }
198 
199  return RF_RESULT_OK;
200 }
201 /*---------------------------------------------------------------------------*/
202 rf_result_t
203 rf_yield(void)
204 {
205  /* Force abort of any ongoing RF operation */
206  RF_flushCmd(&rf_netstack, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY);
207 #if RF_CONF_BLE_BEACON_ENABLE
208  RF_flushCmd(&rf_ble, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY);
209 #endif
210 
211  /* Trigger a manual power-down */
212  RF_yield(&rf_netstack);
213 #if RF_CONF_BLE_BEACON_ENABLE
214  RF_yield(&rf_ble);
215 #endif
216 
217  ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
218 
219  etimer_stop(&synth_recal_timer);
220  rf_is_on = false;
221 
222  return RF_RESULT_OK;
223 }
224 /*---------------------------------------------------------------------------*/
225 rf_result_t
226 rf_set_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t dbm)
227 {
228  const RF_Stat stat = RF_setTxPower(handle, RF_TxPowerTable_findValue(table, dbm));
229 
230  return (stat == RF_StatSuccess)
231  ? RF_RESULT_OK
232  : RF_RESULT_ERROR;
233 }
234 /*---------------------------------------------------------------------------*/
235 rf_result_t
236 rf_get_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t *dbm)
237 {
238  *dbm = RF_TxPowerTable_findPowerLevel(table, RF_getTxPower(handle));
239 
240  return (*dbm != RF_TxPowerTable_INVALID_DBM)
241  ? RF_RESULT_OK
242  : RF_RESULT_ERROR;
243 }
244 /*---------------------------------------------------------------------------*/
245 RF_Handle
246 netstack_open(RF_Params *params)
247 {
248  return RF_open(&rf_netstack, &netstack_mode, (RF_RadioSetup *)&netstack_cmd_radio_setup, params);
249 }
250 /*---------------------------------------------------------------------------*/
251 rf_result_t
252 netstack_sched_fs(void)
253 {
254  const uint_fast8_t rx_key = cmd_rx_disable();
255 
256  /*
257  * For IEEE-mode, restarting CMD_IEEE_RX re-calibrates the synth by using the
258  * channel field in the CMD_IEEE_RX command. It is assumed this field is
259  * already configured before this function is called. However, if
260  * CMD_IEEE_RX wasn't active, manually calibrate the synth with CMD_FS.
261  *
262  * For Prop-mode, the synth is always manually calibrated with CMD_FS.
263  */
264 #if (RF_MODE == RF_CORE_MODE_2_4_GHZ)
265  if(rx_key) {
266  cmd_rx_restore(rx_key);
267  return RF_RESULT_OK;
268  }
269 #endif /* RF_MODE == RF_CORE_MODE_2_4_GHZ */
270 
271  RF_EventMask events;
272  bool synth_error = false;
273  uint8_t num_tries = 0;
274 
275  do {
276  CMD_STATUS(netstack_cmd_fs) = PENDING;
277 
278  events = RF_runCmd(
279  &rf_netstack,
280  (RF_Op *)&netstack_cmd_fs,
281  RF_PriorityNormal,
282  NULL,
283  0);
284 
285  synth_error = (EVENTS_CMD_DONE(events)) && (CMD_STATUS(netstack_cmd_fs) == ERROR_SYNTH_PROG);
286 
287  } while(synth_error && (num_tries++ < CMD_FS_RETRIES));
288 
289  cmd_rx_restore(rx_key);
290 
291  return (CMD_STATUS(netstack_cmd_fs) == DONE_OK)
292  ? RF_RESULT_OK
293  : RF_RESULT_ERROR;
294 }
295 /*---------------------------------------------------------------------------*/
296 rf_result_t
297 netstack_sched_ieee_tx(bool ack_request)
298 {
299  rf_result_t res;
300 
301  RF_ScheduleCmdParams sched_params;
302  RF_ScheduleCmdParams_init(&sched_params);
303 
304  sched_params.priority = RF_PriorityNormal;
305  sched_params.endTime = 0;
306  sched_params.allowDelay = RF_AllowDelayAny;
307 
308  const bool rx_is_active = cmd_rx_is_active();
309  const bool rx_needed = (ack_request && !rx_is_active);
310 
311  /*
312  * If we expect ACK after transmission, RX must be running to be able to
313  * run the RX_ACK command. Therefore, turn on RX before starting the
314  * chained TX command.
315  */
316  if(rx_needed) {
317  res = netstack_sched_rx(false);
318  if(res != RF_RESULT_OK) {
319  return res;
320  }
321  }
322 
323  CMD_STATUS(netstack_cmd_tx) = PENDING;
324 
325  RF_CmdHandle tx_handle = RF_scheduleCmd(
326  &rf_netstack,
327  (RF_Op *)&netstack_cmd_tx,
328  &sched_params,
329  NULL,
330  0);
331 
332  if(!CMD_HANDLE_OK(tx_handle)) {
333  LOG_ERR("Unable to schedule TX command, handle=%d status=0x%04x\n",
334  tx_handle, CMD_STATUS(netstack_cmd_tx));
335  return RF_RESULT_ERROR;
336  }
337 
338  if(rx_is_active) {
339  ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT);
340  } else {
341  ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);
342  }
343 
344  /* Wait until TX operation finishes */
345  RF_EventMask tx_events = RF_pendCmd(&rf_netstack, tx_handle, 0);
346 
347  /* Stop RX if it was turned on only for ACK */
348  if(rx_needed) {
349  netstack_stop_rx();
350  }
351 
352  if(rx_is_active) {
353  ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN);
354  } else {
355  ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
356  }
357 
358  if(!EVENTS_CMD_DONE(tx_events)) {
359  LOG_ERR("Pending on TX comand generated error, events=0x%08llx status=0x%04x\n",
360  tx_events, CMD_STATUS(netstack_cmd_tx));
361  return RF_RESULT_ERROR;
362  }
363 
364  return RF_RESULT_OK;
365 }
366 /*---------------------------------------------------------------------------*/
367 rf_result_t
368 netstack_sched_prop_tx(void)
369 {
370  RF_ScheduleCmdParams sched_params;
371  RF_ScheduleCmdParams_init(&sched_params);
372 
373  sched_params.priority = RF_PriorityNormal;
374  sched_params.endTime = 0;
375  sched_params.allowDelay = RF_AllowDelayAny;
376 
377  CMD_STATUS(netstack_cmd_tx) = PENDING;
378 
379  RF_CmdHandle tx_handle = RF_scheduleCmd(
380  &rf_netstack,
381  (RF_Op *)&netstack_cmd_tx,
382  &sched_params,
383  NULL,
384  0);
385 
386  if(!CMD_HANDLE_OK(tx_handle)) {
387  LOG_ERR("Unable to schedule TX command, handle=%d status=0x%04x\n",
388  tx_handle, CMD_STATUS(netstack_cmd_tx));
389  return RF_RESULT_ERROR;
390  }
391 
392  /*
393  * Prop TX requires any on-going RX operation to be stopped to be
394  * able to transmit. Therefore, disable RX if running.
395  */
396  const bool rx_key = cmd_rx_disable();
397 
398  if(rx_key) {
399  ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT);
400  } else {
401  ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);
402  }
403 
404  /* Wait until TX operation finishes */
405  RF_EventMask tx_events = RF_pendCmd(&rf_netstack, tx_handle, 0);
406 
407  cmd_rx_restore(rx_key);
408 
409  if(rx_key) {
410  ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN);
411  } else {
412  ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
413  }
414 
415  if(!EVENTS_CMD_DONE(tx_events)) {
416  LOG_ERR("Pending on scheduled TX command generated error, events=0x%08llx status=0x%04x\n",
417  tx_events, CMD_STATUS(netstack_cmd_tx));
418  return RF_RESULT_ERROR;
419  }
420 
421  return RF_RESULT_OK;
422 }
423 /*---------------------------------------------------------------------------*/
424 rf_result_t
425 netstack_sched_rx(bool start)
426 {
427  if(cmd_rx_is_active()) {
428  LOG_WARN("Already in RX when scheduling RX\n");
429  return RF_RESULT_OK;
430  }
431 
432  RF_ScheduleCmdParams sched_params;
433  RF_ScheduleCmdParams_init(&sched_params);
434 
435  sched_params.priority = RF_PriorityNormal;
436  sched_params.endTime = 0;
437  sched_params.allowDelay = RF_AllowDelayAny;
438 
439  CMD_STATUS(netstack_cmd_rx) = PENDING;
440 
441  cmd_rx_handle = RF_scheduleCmd(
442  &rf_netstack,
443  (RF_Op *)&netstack_cmd_rx,
444  &sched_params,
445  cmd_rx_cb,
446  RF_EventRxEntryDone | RF_EventRxBufFull);
447 
448  if(!CMD_HANDLE_OK(cmd_rx_handle)) {
449  LOG_ERR("Unable to schedule RX command, handle=%d status=0x%04x\n",
450  cmd_rx_handle, CMD_STATUS(netstack_cmd_rx));
451  return RF_RESULT_ERROR;
452  }
453 
454  ENERGEST_ON(ENERGEST_TYPE_LISTEN);
455 
456  if(start) {
457  rf_is_on = true;
458  process_poll(&rf_sched_process);
459  }
460 
461  return RF_RESULT_OK;
462 }
463 /*---------------------------------------------------------------------------*/
464 rf_result_t
465 netstack_stop_rx(void)
466 {
467  if(!cmd_rx_is_active()) {
468  LOG_WARN("RX not active when stopping RX\n");
469  return RF_RESULT_OK;
470  }
471 
472  CMD_STATUS(netstack_cmd_rx) = DONE_STOPPED;
473  const RF_Stat stat = RF_cancelCmd(&rf_netstack, cmd_rx_handle, RF_ABORT_GRACEFULLY);
474  cmd_rx_handle = 0;
475 
476  ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
477 
478  return (stat == RF_StatSuccess)
479  ? RF_RESULT_OK
480  : RF_RESULT_ERROR;
481 }
482 /*---------------------------------------------------------------------------*/
483 RF_Handle
484 ble_open(RF_Params *params)
485 {
486 #if RF_CONF_BLE_BEACON_ENABLE
487  return RF_open(&rf_ble, &ble_mode, (RF_RadioSetup *)&ble_cmd_radio_setup, params);
488 
489 #else
490  return (RF_Handle)NULL;
491 #endif
492 }
493 /*---------------------------------------------------------------------------*/
494 #if RF_CONF_BLE_BEACON_ENABLE
495 static RF_Op *
496 init_ble_adv_array(ble_cmd_adv_nc_t *ble_adv_array, uint8_t bm_channel)
497 {
498  RF_Op *first_ble_adv = NULL;
499  ble_cmd_adv_nc_t *cmd_adv_37 = &ble_adv_array[0];
500  ble_cmd_adv_nc_t *cmd_adv_38 = &ble_adv_array[1];
501  ble_cmd_adv_nc_t *cmd_adv_39 = &ble_adv_array[2];
502 
503  /* Setup channel 37 advertisement if enabled */
504  if(bm_channel & BLE_ADV_CHANNEL_37) {
505  /* Default configurations from ble_cmd_adv_nc */
506  memcpy(cmd_adv_37, &ble_cmd_adv_nc, sizeof(ble_cmd_adv_nc));
507 
508  cmd_adv_37->channel = 37;
509  /* Magic number: initialization for whitener, specific for channel 37 */
510  cmd_adv_37->whitening.init = 0x65;
511 
512  /*
513  * The next advertisement is chained depending on whether they are
514  * enbled or not. If both 38 and 39 are disabled, then there is no
515  * chaining.
516  */
517  if(bm_channel & BLE_ADV_CHANNEL_38) {
518  cmd_adv_37->pNextOp = (RF_Op *)cmd_adv_38;
519  cmd_adv_37->condition.rule = COND_ALWAYS;
520  } else if(bm_channel & BLE_ADV_CHANNEL_39) {
521  cmd_adv_37->pNextOp = (RF_Op *)cmd_adv_39;
522  cmd_adv_37->condition.rule = COND_ALWAYS;
523  } else {
524  cmd_adv_37->pNextOp = NULL;
525  cmd_adv_37->condition.rule = COND_NEVER;
526  }
527 
528  /* Channel 37 will always be first if enabled */
529  first_ble_adv = (RF_Op *)cmd_adv_37;
530  }
531 
532  /* Setup channel 38 advertisement if enabled */
533  if(bm_channel & BLE_ADV_CHANNEL_38) {
534  memcpy(cmd_adv_38, &ble_cmd_adv_nc, sizeof(ble_cmd_adv_nc));
535 
536  cmd_adv_38->channel = 38;
537  /* Magic number: initialization for whitener, specific for channel 38 */
538  cmd_adv_38->whitening.init = 0x66;
539 
540  /*
541  * The next advertisement is chained depending on whether they are
542  * enbled or not. If 39 is disabled, then there is no chaining.
543  */
544  if(bm_channel & BLE_ADV_CHANNEL_39) {
545  cmd_adv_38->pNextOp = (RF_Op *)cmd_adv_39;
546  cmd_adv_38->condition.rule = COND_ALWAYS;
547  } else {
548  cmd_adv_38->pNextOp = NULL;
549  cmd_adv_38->condition.rule = COND_NEVER;
550  }
551 
552  /*
553  * Channel 38 is only first if the first_ble_adv pointer is not
554  * set by channel 37.
555  */
556  if(first_ble_adv == NULL) {
557  first_ble_adv = (RF_Op *)cmd_adv_38;
558  }
559  }
560 
561  /* Setup channel 39 advertisement if enabled */
562  if(bm_channel & BLE_ADV_CHANNEL_39) {
563  memcpy(cmd_adv_39, &ble_cmd_adv_nc, sizeof(ble_cmd_adv_nc));
564 
565  cmd_adv_39->channel = 39;
566  /* Magic number: initialization for whitener, specific for channel 39 */
567  cmd_adv_39->whitening.init = 0x67;
568 
569  /* Channel 39 is always the last advertisement in the chain */
570  cmd_adv_39->pNextOp = NULL;
571  cmd_adv_39->condition.rule = COND_NEVER;
572 
573  /*
574  * Channel 39 is only first if the first_ble_adv pointer is not
575  * set by channel 37 or channel 38.
576  */
577  if(first_ble_adv == NULL) {
578  first_ble_adv = (RF_Op *)cmd_adv_39;
579  }
580  }
581 
582  return first_ble_adv;
583 }
584 #endif /* RF_CONF_BLE_BEACON_ENABLE */
585 /*---------------------------------------------------------------------------*/
586 rf_result_t
587 ble_sched_beacons(uint8_t bm_channel)
588 {
589 #if RF_CONF_BLE_BEACON_ENABLE
590  /*
591  * Allocate the advertisement commands on the stack rather than statically
592  * to RAM in order to save space. We don't need them after the
593  * advertisements have been transmitted.
594  */
595  ble_cmd_adv_nc_t ble_cmd_adv_nc_array[NUM_BLE_ADV_CHANNELS];
596 
597  RF_Op *initial_adv = NULL;
598  RF_ScheduleCmdParams sched_params;
599  RF_CmdHandle beacon_handle;
600  RF_EventMask beacon_events;
601  rf_result_t rf_result;
602 
603  /* If no channels are mapped, then early return OK */
604  if((bm_channel & BLE_ADV_CHANNEL_ALL) == 0) {
605  return RF_RESULT_OK;
606  }
607 
608  initial_adv = init_ble_adv_array(ble_cmd_adv_nc_array, bm_channel);
609 
610  if(initial_adv == NULL) {
611  LOG_ERR("Initializing BLE Advertisement chain failed\n");
612  return RF_RESULT_ERROR;
613  }
614 
615  RF_ScheduleCmdParams_init(&sched_params);
616  sched_params.priority = RF_PriorityNormal;
617  sched_params.endTime = 0;
618  sched_params.allowDelay = RF_AllowDelayAny;
619 
620  /*
621  * The most efficient way to schedule the command is as follows:
622  * 1. Schedule the BLE advertisement chain
623  * 2. Reschedule the RX command IF it was running.
624  * 3. Pend on the BLE avertisement chain
625  */
626  beacon_handle = RF_scheduleCmd(
627  &rf_ble,
628  initial_adv,
629  &sched_params,
630  NULL,
631  0);
632 
633  if(!CMD_HANDLE_OK(beacon_handle)) {
634  LOG_ERR("Unable to schedule BLE Beacon command, handle=%d status=0x%04x\n",
635  beacon_handle, CMD_STATUS(ble_cmd_adv_nc));
636 
637  return RF_RESULT_ERROR;
638  }
639 
640  /* Note that this only reschedules RX if it is running */
641  rf_result = cmd_rx_restore(cmd_rx_disable());
642 
643  /* Wait until Beacon operation finishes */
644  beacon_events = RF_pendCmd(&rf_ble, beacon_handle, 0);
645 
646  if(rf_result != RF_RESULT_OK) {
647  LOG_ERR("Rescheduling CMD_RX failed when BLE advertising\n");
648 
649  return RF_RESULT_ERROR;
650  }
651 
652  if(!EVENTS_CMD_DONE(beacon_events)) {
653  LOG_ERR("Pending on scheduled BLE Beacon command generated error, events=0x%08llx status=0x%04x\n",
654  beacon_events, CMD_STATUS(ble_cmd_adv_nc));
655 
656  return RF_RESULT_ERROR;
657  }
658 
659  return RF_RESULT_OK;
660 
661 #else
662  return RF_RESULT_ERROR;
663 #endif
664 }
665 /*---------------------------------------------------------------------------*/
666 PROCESS(rf_sched_process, "RF Scheduler Process");
667 /*---------------------------------------------------------------------------*/
668 PROCESS_THREAD(rf_sched_process, ev, data)
669 {
670  int len;
671 
672  PROCESS_BEGIN();
673 
674  while(1) {
675  PROCESS_YIELD_UNTIL((ev == PROCESS_EVENT_POLL) ||
676  (ev == PROCESS_EVENT_TIMER));
677 
678  /* start the synth re-calibration timer once. */
679  if(rf_is_on) {
680  rf_is_on = false;
681  clock_time_t interval = synth_recal_interval();
682  LOG_INFO("Starting synth re-calibration timer, next timeout %lu\n", interval);
683  etimer_set(&synth_recal_timer, interval);
684  }
685 
686  if(ev == PROCESS_EVENT_POLL) {
687  do {
689 
690  packetbuf_clear();
691  len = NETSTACK_RADIO.read(packetbuf_dataptr(), PACKETBUF_SIZE);
692 
693  /*
694  * RX will stop if the RX buffers are full. In this case, restart
695  * RX after we've freed at least on packet.
696  */
697  if(rx_buf_full) {
698  LOG_ERR("RX buffer full, restart RX status=0x%04x\n", CMD_STATUS(netstack_cmd_rx));
699  rx_buf_full = false;
700 
701  /* Restart RX. */
702  netstack_stop_rx();
703  netstack_sched_rx(false);
704  }
705 
706  if(len > 0) {
708 
709  NETSTACK_MAC.input();
710  }
711  /* Only break when we receive -1 => No available data */
712  } while(len >= 0);
713  }
714 
715  /* Scheduling CMD_FS will re-calibrate the synth. */
716  if((ev == PROCESS_EVENT_TIMER) &&
717  etimer_expired(&synth_recal_timer)) {
718  clock_time_t interval = synth_recal_interval();
719  LOG_DBG("Re-calibrate synth, next interval %lu\n", interval);
720 
721  netstack_sched_fs();
722  etimer_set(&synth_recal_timer, interval);
723  }
724  }
725  PROCESS_END();
726 }
727 /*---------------------------------------------------------------------------*/
728 /** @} */
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
Definition: packetbuf.c:143
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
void etimer_stop(struct etimer *et)
Stop a pending event timer.
Definition: etimer.c:243
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
void packetbuf_clear(void)
Clear and reset the packetbuf.
Definition: packetbuf.c:75
Header file for the energy estimation mechanism
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Definition: process.h:178
#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
static void start(void)
Start measurement.
Header file of the CC13xx/CC26xx RF scheduler.
Event timer header file.
void(* input)(void)
Callback for getting notified of incoming packet.
Definition: mac.h:72
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
#define PACKETBUF_SIZE
The size of the packetbuf, in bytes.
Definition: packetbuf.h:67
Header file for the Contiki process interface.
int etimer_expired(struct etimer *et)
Check if an event timer has expired.
Definition: etimer.c:213
Header file of the CC13xx/CC26xx RF data queue.
A timer.
Definition: etimer.h:76
Header file of RF settings for CC13xx/CC26xx.
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)
void watchdog_periodic(void)
Writes the WDT clear sequence.
Definition: watchdog.c:85
Default definitions of C compiler quirk work-arounds.
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1107
unsigned short random_rand(void)
Generates a new random number using the cc2538 RNG.
Definition: random.c:58
Header file for the logging system
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
MAC driver header file