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 
103 static struct etimer synth_recal_timer;
104 /*---------------------------------------------------------------------------*/
105 #if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X0_CC26X0)
106 typedef rfc_CMD_BLE_ADV_NC_t ble_cmd_adv_nc_t;
107 #elif (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X2_CC26X2)
108 typedef rfc_CMD_BLE5_ADV_NC_t ble_cmd_adv_nc_t;
109 #endif
110 /*---------------------------------------------------------------------------*/
111 static RF_Object rf_netstack;
112 
113 #if RF_CONF_BLE_BEACON_ENABLE
114 static RF_Object rf_ble;
115 #endif
116 
117 static RF_CmdHandle cmd_rx_handle;
118 
119 static bool rf_is_on;
120 static volatile bool rx_buf_full;
121 
122 static rfc_CMD_SYNC_STOP_RAT_t netstack_cmd_stop_rat;
123 static rfc_CMD_SYNC_START_RAT_t netstack_cmd_start_rat;
124 
125 simplelink_radio_mode_t *radio_mode;
126 /*---------------------------------------------------------------------------*/
127 static void
128 cmd_rx_cb(RF_Handle client, RF_CmdHandle command, RF_EventMask events)
129 {
130  /* Unused arguments */
131  (void)client;
132  (void)command;
133 
134  if(radio_mode->poll_mode) {
135  return;
136  }
137 
138  if(events & RF_EventRxEntryDone) {
139  process_poll(&rf_sched_process);
140  }
141 
142  if(events & RF_EventRxBufFull) {
143  rx_buf_full = true;
144  process_poll(&rf_sched_process);
145  }
146 }
147 /*---------------------------------------------------------------------------*/
148 static inline clock_time_t
149 synth_recal_interval(void)
150 {
151  /*
152  * Add jitter centered around SYNTH_RECAL_INTERVAL, giving a plus/minus
153  * jitter seconds halved.
154  */
155  return SYNTH_RECAL_INTERVAL + (random_rand() % SYNTH_RECAL_JITTER) - (SYNTH_RECAL_JITTER / 2);
156 }
157 /*---------------------------------------------------------------------------*/
158 static inline bool
159 cmd_rx_is_active(void)
160 {
161  /*
162  * Active in this case means RX command is either running to be running,
163  * that is ACTIVE for running or PENDING for to be running.
164  */
165  const uint16_t status = CMD_STATUS(netstack_cmd_rx);
166  return (status == ACTIVE) ||
167  (status == PENDING);
168 }
169 /*---------------------------------------------------------------------------*/
170 static uint_fast8_t
171 cmd_rx_disable(void)
172 {
173  const bool is_active = cmd_rx_is_active();
174 
175  if(is_active) {
176  CMD_STATUS(netstack_cmd_rx) = DONE_STOPPED;
177  RF_cancelCmd(&rf_netstack, cmd_rx_handle, RF_ABORT_GRACEFULLY);
178  cmd_rx_handle = 0;
179  }
180 
181  return (uint_fast8_t)is_active;
182 }
183 /*---------------------------------------------------------------------------*/
184 static rf_result_t
185 cmd_rx_restore(uint_fast8_t rx_key)
186 {
187  const bool was_active = (rx_key != 0) ? true : false;
188 
189  if(!was_active) {
190  return RF_RESULT_OK;
191  }
192 
193  RF_ScheduleCmdParams sched_params;
194  RF_ScheduleCmdParams_init(&sched_params);
195 
196  sched_params.priority = RF_PriorityNormal;
197  sched_params.endTime = 0;
198  sched_params.allowDelay = RF_AllowDelayAny;
199 
200  CMD_STATUS(netstack_cmd_rx) = PENDING;
201 
202  cmd_rx_handle = RF_scheduleCmd(
203  &rf_netstack,
204  (RF_Op *)&netstack_cmd_rx,
205  &sched_params,
206  cmd_rx_cb,
207  RF_EventRxEntryDone | RF_EventRxBufFull);
208 
209  if(!CMD_HANDLE_OK(cmd_rx_handle)) {
210  LOG_ERR("Unable to restore RX command, handle=%d status=0x%04x",
211  cmd_rx_handle, CMD_STATUS(netstack_cmd_rx));
212  return RF_RESULT_ERROR;
213  }
214 
215  return RF_RESULT_OK;
216 }
217 /*---------------------------------------------------------------------------*/
218 rf_result_t
219 rf_yield(void)
220 {
221  /* Force abort of any ongoing RF operation */
222  RF_flushCmd(&rf_netstack, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY);
223 #if RF_CONF_BLE_BEACON_ENABLE
224  RF_flushCmd(&rf_ble, RF_CMDHANDLE_FLUSH_ALL, RF_ABORT_GRACEFULLY);
225 #endif
226 
227  /* Stop SYNC RAT to get current RAT */
228  RF_ScheduleCmdParams sched_params;
229  RF_ScheduleCmdParams_init(&sched_params);
230 
231  sched_params.priority = RF_PriorityNormal;
232  sched_params.endTime = 0;
233  sched_params.allowDelay = RF_AllowDelayAny;
234 
235  CMD_STATUS(netstack_cmd_stop_rat) = PENDING;
236 
237  RF_scheduleCmd(
238  &rf_netstack,
239  (RF_Op *)&netstack_cmd_stop_rat,
240  &sched_params,
241  NULL,
242  0);
243 
244  /* Trigger a manual power-down */
245  RF_yield(&rf_netstack);
246 #if RF_CONF_BLE_BEACON_ENABLE
247  RF_yield(&rf_ble);
248 #endif
249 
250  ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
251 
252  etimer_stop(&synth_recal_timer);
253  rf_is_on = false;
254 
255  return RF_RESULT_OK;
256 }
257 /*---------------------------------------------------------------------------*/
258 rf_result_t
259 rf_restart_rat(void)
260 {
261  RF_ScheduleCmdParams sched_params;
262 
263  /* Stop SYNC RAT */
264  RF_ScheduleCmdParams_init(&sched_params);
265 
266  sched_params.priority = RF_PriorityNormal;
267  sched_params.endTime = 0;
268  sched_params.allowDelay = RF_AllowDelayAny;
269 
270  CMD_STATUS(netstack_cmd_stop_rat) = PENDING;
271 
272  RF_scheduleCmd(
273  &rf_netstack,
274  (RF_Op *)&netstack_cmd_stop_rat,
275  &sched_params,
276  NULL,
277  0);
278 
279  /* Start SYNC RAT */
280  RF_ScheduleCmdParams_init(&sched_params);
281 
282  sched_params.priority = RF_PriorityNormal;
283  sched_params.endTime = 0;
284  sched_params.allowDelay = RF_AllowDelayAny;
285 
286  netstack_cmd_start_rat.rat0 = 0;
287  CMD_STATUS(netstack_cmd_start_rat) = PENDING;
288 
289  RF_scheduleCmd(
290  &rf_netstack,
291  (RF_Op *)&netstack_cmd_start_rat,
292  &sched_params,
293  NULL,
294  0);
295 
296  return RF_RESULT_OK;
297 }
298 
299 /*---------------------------------------------------------------------------*/
300 rf_result_t
301 rf_set_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t dbm)
302 {
303  const RF_Stat stat = RF_setTxPower(handle, RF_TxPowerTable_findValue(table, dbm));
304 
305  return (stat == RF_StatSuccess)
306  ? RF_RESULT_OK
307  : RF_RESULT_ERROR;
308 }
309 /*---------------------------------------------------------------------------*/
310 rf_result_t
311 rf_get_tx_power(RF_Handle handle, RF_TxPowerTable_Entry *table, int8_t *dbm)
312 {
313  *dbm = RF_TxPowerTable_findPowerLevel(table, RF_getTxPower(handle));
314 
315  return (*dbm != RF_TxPowerTable_INVALID_DBM)
316  ? RF_RESULT_OK
317  : RF_RESULT_ERROR;
318 }
319 /*---------------------------------------------------------------------------*/
320 RF_Handle
321 netstack_open(RF_Params *params)
322 {
323  netstack_cmd_stop_rat.commandNo = CMD_SYNC_STOP_RAT;
324  netstack_cmd_stop_rat.condition.rule = COND_NEVER;
325  netstack_cmd_start_rat.commandNo = CMD_SYNC_START_RAT;
326  netstack_cmd_start_rat.condition.rule = COND_NEVER;
327  return RF_open(&rf_netstack, &netstack_mode, (RF_RadioSetup *)&netstack_cmd_radio_setup, params);
328 }
329 /*---------------------------------------------------------------------------*/
330 rf_result_t
331 netstack_sched_fs(void)
332 {
333  const uint_fast8_t rx_key = cmd_rx_disable();
334 
335  /*
336  * For IEEE-mode, restarting CMD_IEEE_RX re-calibrates the synth by using the
337  * channel field in the CMD_IEEE_RX command. It is assumed this field is
338  * already configured before this function is called. However, if
339  * CMD_IEEE_RX wasn't active, manually calibrate the synth with CMD_FS.
340  *
341  * For Prop-mode, the synth is always manually calibrated with CMD_FS.
342  */
343 #if (RF_MODE == RF_MODE_2_4_GHZ)
344  if(rx_key) {
345  cmd_rx_restore(rx_key);
346  return RF_RESULT_OK;
347  }
348 #endif /* RF_MODE == RF_MODE_2_4_GHZ */
349 
350  if(radio_mode->poll_mode) {
351  /*
352  * In poll mode; cannot execute the command, can just schedule it.
353  * Retrying is not possible.
354  */
355  RF_ScheduleCmdParams sched_params;
356  RF_ScheduleCmdParams_init(&sched_params);
357 
358  sched_params.priority = RF_PriorityNormal;
359  sched_params.endTime = 0;
360  sched_params.allowDelay = RF_AllowDelayAny;
361 
362  CMD_STATUS(netstack_cmd_fs) = PENDING;
363 
364  RF_CmdHandle fs_handle = RF_scheduleCmd(
365  &rf_netstack,
366  (RF_Op *)&netstack_cmd_fs,
367  &sched_params,
368  NULL,
369  0);
370 
371  cmd_rx_restore(rx_key);
372 
373  if(!CMD_HANDLE_OK(fs_handle)) {
374  LOG_ERR("Unable to schedule FS command, handle=%d status=0x%04x\n",
375  fs_handle, CMD_STATUS(netstack_cmd_fs));
376  return RF_RESULT_ERROR;
377  }
378 
379  return RF_RESULT_OK;
380 
381  } else {
382  /*
383  * Not in poll mode. Execute the command immediately,
384  * wait for result, retry if neccessary.
385  */
386  RF_EventMask events;
387  bool synth_error = false;
388  uint8_t num_tries = 0;
389 
390  do {
391  CMD_STATUS(netstack_cmd_fs) = PENDING;
392 
393  events = RF_runCmd(
394  &rf_netstack,
395  (RF_Op *)&netstack_cmd_fs,
396  RF_PriorityNormal,
397  NULL,
398  0);
399 
400  synth_error = (EVENTS_CMD_DONE(events)) && (CMD_STATUS(netstack_cmd_fs) == ERROR_SYNTH_PROG);
401 
402  } while(synth_error && (num_tries++ < CMD_FS_RETRIES));
403 
404  cmd_rx_restore(rx_key);
405 
406  return (CMD_STATUS(netstack_cmd_fs) == DONE_OK)
407  ? RF_RESULT_OK
408  : RF_RESULT_ERROR;
409  }
410 }
411 /*---------------------------------------------------------------------------*/
412 rf_result_t
413 netstack_sched_ieee_tx(uint16_t payload_length, bool ack_request)
414 {
415  rf_result_t res;
416  RF_EventMask tx_events = 0;
417 
418  RF_ScheduleCmdParams sched_params;
419  RF_ScheduleCmdParams_init(&sched_params);
420 
421  sched_params.priority = RF_PriorityNormal;
422  sched_params.endTime = 0;
423  sched_params.allowDelay = RF_AllowDelayAny;
424 
425  const bool rx_is_active = cmd_rx_is_active();
426  const bool rx_needed = (ack_request && !rx_is_active);
427 
428  /*
429  * If we expect ACK after transmission, RX must be running to be able to
430  * run the RX_ACK command. Therefore, turn on RX before starting the
431  * chained TX command.
432  */
433  if(rx_needed) {
434  res = netstack_sched_rx(false);
435  if(res != RF_RESULT_OK) {
436  return res;
437  }
438  }
439 
440  CMD_STATUS(netstack_cmd_tx) = PENDING;
441 
442  RF_CmdHandle tx_handle = RF_scheduleCmd(
443  &rf_netstack,
444  (RF_Op *)&netstack_cmd_tx,
445  &sched_params,
446  NULL,
447  0);
448 
449  if(!CMD_HANDLE_OK(tx_handle)) {
450  LOG_ERR("Unable to schedule TX command, handle=%d status=0x%04x\n",
451  tx_handle, CMD_STATUS(netstack_cmd_tx));
452  return RF_RESULT_ERROR;
453  }
454 
455  if(rx_is_active) {
456  ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT);
457  } else {
458  ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);
459  }
460 
461  /* Wait until TX operation finishes */
462  if(radio_mode->poll_mode) {
463  const uint16_t frame_length = payload_length + RADIO_PHY_HEADER_LEN + RADIO_PHY_OVERHEAD;
464  RTIMER_BUSYWAIT_UNTIL((CMD_STATUS(netstack_cmd_tx) & 0xC00) != 0,
465  US_TO_RTIMERTICKS(RADIO_BYTE_AIR_TIME * frame_length + 300));
466  } else {
467  tx_events = RF_pendCmd(&rf_netstack, tx_handle, 0);
468  }
469 
470  /* Stop RX if it was turned on only for ACK */
471  if(rx_needed) {
472  netstack_stop_rx();
473  }
474 
475  if(rx_is_active) {
476  ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN);
477  } else {
478  ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
479  }
480 
481  if(radio_mode->poll_mode) {
482  if(CMD_STATUS(netstack_cmd_tx) != IEEE_DONE_OK) {
483  LOG_ERR("Pending on scheduled TX command generated error, status=0x%04x\n",
484  CMD_STATUS(netstack_cmd_tx));
485  return RF_RESULT_ERROR;
486  }
487  } else {
488  if(!EVENTS_CMD_DONE(tx_events)) {
489  LOG_ERR("Pending on TX comand generated error, events=0x%08llx status=0x%04x\n",
490  tx_events, CMD_STATUS(netstack_cmd_tx));
491  return RF_RESULT_ERROR;
492  }
493  }
494 
495  return RF_RESULT_OK;
496 }
497 /*---------------------------------------------------------------------------*/
498 rf_result_t
499 netstack_sched_prop_tx(uint16_t payload_length)
500 {
501  RF_EventMask tx_events = 0;
502 
503  RF_ScheduleCmdParams sched_params;
504  RF_ScheduleCmdParams_init(&sched_params);
505 
506  sched_params.priority = RF_PriorityNormal;
507  sched_params.endTime = 0;
508  sched_params.allowDelay = RF_AllowDelayAny;
509 
510  CMD_STATUS(netstack_cmd_tx) = PENDING;
511 
512  RF_CmdHandle tx_handle = RF_scheduleCmd(
513  &rf_netstack,
514  (RF_Op *)&netstack_cmd_tx,
515  &sched_params,
516  NULL,
517  0);
518 
519  if(!CMD_HANDLE_OK(tx_handle)) {
520  LOG_ERR("Unable to schedule TX command, handle=%d status=0x%04x\n",
521  tx_handle, CMD_STATUS(netstack_cmd_tx));
522  return RF_RESULT_ERROR;
523  }
524 
525  /*
526  * Prop TX requires any on-going RX operation to be stopped to be
527  * able to transmit. Therefore, disable RX if running.
528  */
529  const bool rx_key = cmd_rx_disable();
530 
531  if(rx_key) {
532  ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT);
533  } else {
534  ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);
535  }
536 
537  /* Wait until TX operation finishes */
538  if(radio_mode->poll_mode) {
539  const uint16_t frame_length = payload_length + RADIO_PHY_HEADER_LEN + RADIO_PHY_OVERHEAD;
540  RTIMER_BUSYWAIT_UNTIL((CMD_STATUS(netstack_cmd_tx) & 0xC00) != 0,
541  US_TO_RTIMERTICKS(RADIO_BYTE_AIR_TIME * frame_length + 1200));
542  } else {
543  tx_events = RF_pendCmd(&rf_netstack, tx_handle, 0);
544  }
545 
546  cmd_rx_restore(rx_key);
547 
548  if(rx_key) {
549  ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN);
550  } else {
551  ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
552  }
553 
554  if(radio_mode->poll_mode) {
555  if(CMD_STATUS(netstack_cmd_tx) != PROP_DONE_OK) {
556  LOG_ERR("Pending on scheduled TX command generated error, status=0x%04x\n",
557  CMD_STATUS(netstack_cmd_tx));
558  return RF_RESULT_ERROR;
559  }
560  } else {
561  if(!EVENTS_CMD_DONE(tx_events)) {
562  LOG_ERR("Pending on scheduled TX command generated error, events=0x%08llx status=0x%04x\n",
563  tx_events, CMD_STATUS(netstack_cmd_tx));
564  return RF_RESULT_ERROR;
565  }
566  }
567 
568  return RF_RESULT_OK;
569 }
570 /*---------------------------------------------------------------------------*/
571 rf_result_t
572 netstack_sched_rx(bool start)
573 {
574  if(cmd_rx_is_active()) {
575  LOG_WARN("Already in RX when scheduling RX\n");
576  return RF_RESULT_OK;
577  }
578 
579  RF_ScheduleCmdParams sched_params;
580  if(start) {
581  /* Start SYNC RAT */
582  RF_ScheduleCmdParams_init(&sched_params);
583 
584  sched_params.priority = RF_PriorityNormal;
585  sched_params.endTime = 0;
586  sched_params.allowDelay = RF_AllowDelayAny;
587 
588  netstack_cmd_start_rat.rat0 = 0;
589  CMD_STATUS(netstack_cmd_start_rat) = PENDING;
590 
591  RF_scheduleCmd(
592  &rf_netstack,
593  (RF_Op *)&netstack_cmd_start_rat,
594  &sched_params,
595  NULL,
596  0);
597  }
598 
599  RF_ScheduleCmdParams_init(&sched_params);
600 
601  sched_params.priority = RF_PriorityNormal;
602  sched_params.endTime = 0;
603  sched_params.allowDelay = RF_AllowDelayAny;
604 
605  CMD_STATUS(netstack_cmd_rx) = PENDING;
606 
607  cmd_rx_handle = RF_scheduleCmd(
608  &rf_netstack,
609  (RF_Op *)&netstack_cmd_rx,
610  &sched_params,
611  cmd_rx_cb,
612  RF_EventRxEntryDone | RF_EventRxBufFull);
613 
614  if(!CMD_HANDLE_OK(cmd_rx_handle)) {
615  LOG_ERR("Unable to schedule RX command, handle=%d status=0x%04x\n",
616  cmd_rx_handle, CMD_STATUS(netstack_cmd_rx));
617  return RF_RESULT_ERROR;
618  }
619 
620  ENERGEST_ON(ENERGEST_TYPE_LISTEN);
621 
622  if(start) {
623  rf_is_on = true;
624  if(!radio_mode->poll_mode) {
625  process_poll(&rf_sched_process);
626  }
627  }
628 
629  return RF_RESULT_OK;
630 }
631 /*---------------------------------------------------------------------------*/
632 rf_result_t
633 netstack_stop_rx(void)
634 {
635  if(!cmd_rx_is_active()) {
636  LOG_WARN("RX not active when stopping RX\n");
637  return RF_RESULT_OK;
638  }
639 
640  CMD_STATUS(netstack_cmd_rx) = DONE_STOPPED;
641  const RF_Stat stat = RF_cancelCmd(&rf_netstack, cmd_rx_handle, RF_ABORT_GRACEFULLY);
642  cmd_rx_handle = 0;
643 
644  ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
645 
646  return (stat == RF_StatSuccess)
647  ? RF_RESULT_OK
648  : RF_RESULT_ERROR;
649 }
650 /*---------------------------------------------------------------------------*/
651 RF_Handle
652 ble_open(RF_Params *params)
653 {
654 #if RF_CONF_BLE_BEACON_ENABLE
655  return RF_open(&rf_ble, &ble_mode, (RF_RadioSetup *)&ble_cmd_radio_setup, params);
656 
657 #else
658  return (RF_Handle)NULL;
659 #endif
660 }
661 /*---------------------------------------------------------------------------*/
662 #if RF_CONF_BLE_BEACON_ENABLE
663 static RF_Op *
664 init_ble_adv_array(ble_cmd_adv_nc_t *ble_adv_array, uint8_t bm_channel)
665 {
666  RF_Op *first_ble_adv = NULL;
667  ble_cmd_adv_nc_t *cmd_adv_37 = &ble_adv_array[0];
668  ble_cmd_adv_nc_t *cmd_adv_38 = &ble_adv_array[1];
669  ble_cmd_adv_nc_t *cmd_adv_39 = &ble_adv_array[2];
670 
671  /* Setup channel 37 advertisement if enabled */
672  if(bm_channel & BLE_ADV_CHANNEL_37) {
673  /* Default configurations from ble_cmd_adv_nc */
674  memcpy(cmd_adv_37, &ble_cmd_adv_nc, sizeof(ble_cmd_adv_nc));
675 
676  cmd_adv_37->channel = 37;
677  /* Magic number: initialization for whitener, specific for channel 37 */
678  cmd_adv_37->whitening.init = 0x65;
679 
680  /*
681  * The next advertisement is chained depending on whether they are
682  * enbled or not. If both 38 and 39 are disabled, then there is no
683  * chaining.
684  */
685  if(bm_channel & BLE_ADV_CHANNEL_38) {
686  cmd_adv_37->pNextOp = (RF_Op *)cmd_adv_38;
687  cmd_adv_37->condition.rule = COND_ALWAYS;
688  } else if(bm_channel & BLE_ADV_CHANNEL_39) {
689  cmd_adv_37->pNextOp = (RF_Op *)cmd_adv_39;
690  cmd_adv_37->condition.rule = COND_ALWAYS;
691  } else {
692  cmd_adv_37->pNextOp = NULL;
693  cmd_adv_37->condition.rule = COND_NEVER;
694  }
695 
696  /* Channel 37 will always be first if enabled */
697  first_ble_adv = (RF_Op *)cmd_adv_37;
698  }
699 
700  /* Setup channel 38 advertisement if enabled */
701  if(bm_channel & BLE_ADV_CHANNEL_38) {
702  memcpy(cmd_adv_38, &ble_cmd_adv_nc, sizeof(ble_cmd_adv_nc));
703 
704  cmd_adv_38->channel = 38;
705  /* Magic number: initialization for whitener, specific for channel 38 */
706  cmd_adv_38->whitening.init = 0x66;
707 
708  /*
709  * The next advertisement is chained depending on whether they are
710  * enbled or not. If 39 is disabled, then there is no chaining.
711  */
712  if(bm_channel & BLE_ADV_CHANNEL_39) {
713  cmd_adv_38->pNextOp = (RF_Op *)cmd_adv_39;
714  cmd_adv_38->condition.rule = COND_ALWAYS;
715  } else {
716  cmd_adv_38->pNextOp = NULL;
717  cmd_adv_38->condition.rule = COND_NEVER;
718  }
719 
720  /*
721  * Channel 38 is only first if the first_ble_adv pointer is not
722  * set by channel 37.
723  */
724  if(first_ble_adv == NULL) {
725  first_ble_adv = (RF_Op *)cmd_adv_38;
726  }
727  }
728 
729  /* Setup channel 39 advertisement if enabled */
730  if(bm_channel & BLE_ADV_CHANNEL_39) {
731  memcpy(cmd_adv_39, &ble_cmd_adv_nc, sizeof(ble_cmd_adv_nc));
732 
733  cmd_adv_39->channel = 39;
734  /* Magic number: initialization for whitener, specific for channel 39 */
735  cmd_adv_39->whitening.init = 0x67;
736 
737  /* Channel 39 is always the last advertisement in the chain */
738  cmd_adv_39->pNextOp = NULL;
739  cmd_adv_39->condition.rule = COND_NEVER;
740 
741  /*
742  * Channel 39 is only first if the first_ble_adv pointer is not
743  * set by channel 37 or channel 38.
744  */
745  if(first_ble_adv == NULL) {
746  first_ble_adv = (RF_Op *)cmd_adv_39;
747  }
748  }
749 
750  return first_ble_adv;
751 }
752 #endif /* RF_CONF_BLE_BEACON_ENABLE */
753 /*---------------------------------------------------------------------------*/
754 rf_result_t
755 ble_sched_beacons(uint8_t bm_channel)
756 {
757 #if RF_CONF_BLE_BEACON_ENABLE
758  /*
759  * Allocate the advertisement commands on the stack rather than statically
760  * to RAM in order to save space. We don't need them after the
761  * advertisements have been transmitted.
762  */
763  ble_cmd_adv_nc_t ble_cmd_adv_nc_array[NUM_BLE_ADV_CHANNELS];
764 
765  RF_Op *initial_adv = NULL;
766  RF_ScheduleCmdParams sched_params;
767  RF_CmdHandle beacon_handle;
768  RF_EventMask beacon_events;
769  rf_result_t rf_result;
770 
771  /* If no channels are mapped, then early return OK */
772  if((bm_channel & BLE_ADV_CHANNEL_ALL) == 0) {
773  return RF_RESULT_OK;
774  }
775 
776  initial_adv = init_ble_adv_array(ble_cmd_adv_nc_array, bm_channel);
777 
778  if(initial_adv == NULL) {
779  LOG_ERR("Initializing BLE Advertisement chain failed\n");
780  return RF_RESULT_ERROR;
781  }
782 
783  RF_ScheduleCmdParams_init(&sched_params);
784  sched_params.priority = RF_PriorityNormal;
785  sched_params.endTime = 0;
786  sched_params.allowDelay = RF_AllowDelayAny;
787 
788  /*
789  * The most efficient way to schedule the command is as follows:
790  * 1. Schedule the BLE advertisement chain
791  * 2. Reschedule the RX command IF it was running.
792  * 3. Pend on the BLE avertisement chain
793  */
794  beacon_handle = RF_scheduleCmd(
795  &rf_ble,
796  initial_adv,
797  &sched_params,
798  NULL,
799  0);
800 
801  if(!CMD_HANDLE_OK(beacon_handle)) {
802  LOG_ERR("Unable to schedule BLE Beacon command, handle=%d status=0x%04x\n",
803  beacon_handle, CMD_STATUS(ble_cmd_adv_nc));
804 
805  return RF_RESULT_ERROR;
806  }
807 
808  /* Note that this only reschedules RX if it is running */
809  rf_result = cmd_rx_restore(cmd_rx_disable());
810 
811  /* Wait until Beacon operation finishes */
812  beacon_events = RF_pendCmd(&rf_ble, beacon_handle, 0);
813 
814  if(rf_result != RF_RESULT_OK) {
815  LOG_ERR("Rescheduling CMD_RX failed when BLE advertising\n");
816 
817  return RF_RESULT_ERROR;
818  }
819 
820  if(!EVENTS_CMD_DONE(beacon_events)) {
821  LOG_ERR("Pending on scheduled BLE Beacon command generated error, events=0x%08llx status=0x%04x\n",
822  beacon_events, CMD_STATUS(ble_cmd_adv_nc));
823 
824  return RF_RESULT_ERROR;
825  }
826 
827  return RF_RESULT_OK;
828 
829 #else
830  return RF_RESULT_ERROR;
831 #endif
832 }
833 /*---------------------------------------------------------------------------*/
834 PROCESS(rf_sched_process, "RF Scheduler Process");
835 /*---------------------------------------------------------------------------*/
836 PROCESS_THREAD(rf_sched_process, ev, data)
837 {
838  int len;
839 
840  PROCESS_BEGIN();
841 
842  while(1) {
843  PROCESS_YIELD_UNTIL((ev == PROCESS_EVENT_POLL) ||
844  (ev == PROCESS_EVENT_TIMER));
845 
846  /* start the synth re-calibration timer once. */
847  if(rf_is_on) {
848  rf_is_on = false;
849  clock_time_t interval = synth_recal_interval();
850  LOG_INFO("Starting synth re-calibration timer, next timeout %lu\n", interval);
851  etimer_set(&synth_recal_timer, interval);
852  }
853 
854  if(ev == PROCESS_EVENT_POLL) {
855  do {
857 
858  packetbuf_clear();
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  clock_time_t interval = synth_recal_interval();
887  LOG_DBG("Re-calibrate synth, next interval %lu\n", interval);
888 
889  netstack_sched_fs();
890  etimer_set(&synth_recal_timer, interval);
891  }
892  }
893  PROCESS_END();
894 }
895 /*---------------------------------------------------------------------------*/
896 /** @} */
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
Header file of the generic radio mode API.
#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 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:1110
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