Contiki-NG
rf-ble.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015, Texas Instruments Incorporated - http://www.ti.com/
3  * Copyright (c) 2017, University of Bristol - http://www.bristol.ac.uk/
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the copyright holder nor the names of its
15  * contributors may be used to endorse or promote products derived
16  * from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29  * OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 /*---------------------------------------------------------------------------*/
32 /**
33  * \addtogroup rf-core-ble
34  * @{
35  *
36  * \file
37  * Implementation of the CC13xx/CC26xx RF BLE driver
38  */
39 /*---------------------------------------------------------------------------*/
40 #include "contiki.h"
41 #include "sys/process.h"
42 #include "sys/clock.h"
43 #include "sys/cc.h"
44 #include "sys/etimer.h"
45 #include "net/netstack.h"
46 #include "net/linkaddr.h"
47 #include "dev/oscillators.h"
48 #include "rf-core/rf-core.h"
49 #include "rf-core/rf-switch.h"
50 #include "rf-core/rf-ble.h"
51 #include "driverlib/rf_ble_cmd.h"
52 #include "driverlib/rf_common_cmd.h"
53 #include "ti-lib.h"
54 /*---------------------------------------------------------------------------*/
55 #include <stdint.h>
56 #include <stdbool.h>
57 #include <stdio.h>
58 /*---------------------------------------------------------------------------*/
59 #define DEBUG 0
60 #if DEBUG
61 #define PRINTF(...) printf(__VA_ARGS__)
62 #else
63 #define PRINTF(...)
64 #endif
65 /*---------------------------------------------------------------------------*/
66 /* BLE Intervals: Send a burst of advertisements every BLE_ADV_INTERVAL secs */
67 #define BLE_ADV_INTERVAL (CLOCK_SECOND * 5)
68 #define BLE_ADV_DUTY_CYCLE (CLOCK_SECOND / 10)
69 #define BLE_ADV_MESSAGES 10
70 
71 /* BLE Advertisement-related macros */
72 #define BLE_ADV_TYPE_DEVINFO 0x01
73 #define BLE_ADV_TYPE_NAME 0x09
74 #define BLE_ADV_TYPE_MANUFACTURER 0xFF
75 #define BLE_ADV_NAME_BUF_LEN BLE_ADV_MAX_SIZE
76 #define BLE_ADV_PAYLOAD_BUF_LEN 64
77 #define BLE_UUID_SIZE 16
78 /*---------------------------------------------------------------------------*/
79 static unsigned char ble_params_buf[32] CC_ALIGN(4);
80 static uint8_t ble_mode_on = RF_BLE_IDLE;
81 static struct etimer ble_adv_et;
82 static uint8_t payload[BLE_ADV_PAYLOAD_BUF_LEN];
83 static int p = 0;
84 static int i;
85 /*---------------------------------------------------------------------------*/
86 /* BLE beacond config */
87 static struct ble_beacond_config {
88  clock_time_t interval;
89  char adv_name[BLE_ADV_NAME_BUF_LEN];
90 } beacond_config = { .interval = BLE_ADV_INTERVAL };
91 /*---------------------------------------------------------------------------*/
92 #ifdef RF_BLE_CONF_BOARD_OVERRIDES
93 #define RF_BLE_BOARD_OVERRIDES RF_BLE_CONF_BOARD_OVERRIDES
94 #else
95 #define RF_BLE_BOARD_OVERRIDES
96 #endif
97 /*---------------------------------------------------------------------------*/
98 /* BLE overrides */
99 static uint32_t ble_overrides[] = {
100  0x00364038, /* Synth: Set RTRIM (POTAILRESTRIM) to 6 */
101  0x000784A3, /* Synth: Set FREF = 3.43 MHz (24 MHz / 7) */
102  0xA47E0583, /* Synth: Set loop bandwidth after lock to 80 kHz (K2) */
103  0xEAE00603, /* Synth: Set loop bandwidth after lock to 80 kHz (K3, LSB) */
104  0x00010623, /* Synth: Set loop bandwidth after lock to 80 kHz (K3, MSB) */
105  0x00456088, /* Adjust AGC reference level */
106  RF_BLE_BOARD_OVERRIDES
107  0xFFFFFFFF, /* End of override list */
108 };
109 /*---------------------------------------------------------------------------*/
110 /* TX Power dBm lookup table - values from SmartRF Studio */
111 typedef struct output_config {
112  radio_value_t dbm;
113  uint16_t tx_power; /* Value for the CMD_RADIO_SETUP.txPower field */
114 } output_config_t;
115 
116 static const output_config_t output_power[] = {
117  { 5, 0x9330 },
118  { 4, 0x9324 },
119  { 3, 0x5a1c },
120  { 2, 0x4e18 },
121  { 1, 0x4214 },
122  { 0, 0x3161 },
123  { -3, 0x2558 },
124  { -6, 0x1d52 },
125  { -9, 0x194e },
126  { -12, 0x144b },
127  { -15, 0x0ccb },
128  { -18, 0x0cc9 },
129  { -21, 0x0cc7 },
130 };
131 
132 #define OUTPUT_CONFIG_COUNT (sizeof(output_power) / sizeof(output_config_t))
133 
134 /* Max and Min Output Power in dBm */
135 #define OUTPUT_POWER_MIN (output_power[OUTPUT_CONFIG_COUNT - 1].dbm)
136 #define OUTPUT_POWER_MAX (output_power[0].dbm)
137 #define OUTPUT_POWER_UNKNOWN 0xFFFF
138 
139 /* Default TX Power - position in output_power[] */
140 static const output_config_t *tx_power_current = &output_power[0];
141 /*---------------------------------------------------------------------------*/
142 PROCESS(rf_ble_beacon_process, "CC13xx / CC26xx RF BLE Beacon Process");
143 /*---------------------------------------------------------------------------*/
144 static int
145 send_ble_adv_nc(int channel, uint8_t *adv_payload, int adv_payload_len)
146 {
147  uint32_t cmd_status;
148  rfc_CMD_BLE_ADV_NC_t cmd;
149  rfc_bleAdvPar_t *params;
150 
151  params = (rfc_bleAdvPar_t *)ble_params_buf;
152 
153  /* Clear both buffers */
154  memset(&cmd, 0x00, sizeof(cmd));
155  memset(ble_params_buf, 0x00, sizeof(ble_params_buf));
156 
157  /* Adv NC */
158  cmd.commandNo = CMD_BLE_ADV_NC;
159  cmd.condition.rule = COND_NEVER;
160  cmd.whitening.bOverride = 0;
161  cmd.whitening.init = 0;
162  cmd.pParams = params;
163  cmd.channel = channel;
164 
165  /* Set up BLE Advertisement parameters */
166  params->pDeviceAddress = (uint16_t *)BLE_ADDRESS_PTR;
167  params->endTrigger.triggerType = TRIG_NEVER;
168  params->endTime = TRIG_NEVER;
169 
170  /* Set up BLE Advertisement parameters */
171  params = (rfc_bleAdvPar_t *)ble_params_buf;
172  params->advLen = adv_payload_len;
173  params->pAdvData = adv_payload;
174 
175  if(rf_core_send_cmd((uint32_t)&cmd, &cmd_status) == RF_CORE_CMD_ERROR) {
176  PRINTF("send_ble_adv_nc: Chan=%d CMDSTA=0x%08lx, status=0x%04x\n",
177  channel, cmd_status, cmd.status);
178  return RF_CORE_CMD_ERROR;
179  }
180 
181  /* Wait until the command is done */
182  if(rf_core_wait_cmd_done(&cmd) != RF_CORE_CMD_OK) {
183  PRINTF("send_ble_adv_nc: Chan=%d CMDSTA=0x%08lx, status=0x%04x\n",
184  channel, cmd_status, cmd.status);
185  return RF_CORE_CMD_ERROR;
186  }
187 
188  return RF_CORE_CMD_OK;
189 }
190 /*---------------------------------------------------------------------------*/
191 /* Returns the current TX power in dBm */
194 {
195  return tx_power_current->dbm;
196 }
197 /*---------------------------------------------------------------------------*/
198 /*
199  * Set TX power to 'at least' power dBm
200  * This works with a lookup table. If the value of 'power' does not exist in
201  * the lookup table, TXPOWER will be set to the immediately higher available
202  * value
203  */
204 void
206 {
207  int i;
208 
209  /* First, find the correct setting and save it */
210  for(i = OUTPUT_CONFIG_COUNT - 1; i >= 0; --i) {
211  if(power <= output_power[i].dbm) {
212  tx_power_current = &output_power[i];
213  break;
214  }
215  }
216 }
217 /*---------------------------------------------------------------------------*/
218 void
219 rf_ble_beacond_config(clock_time_t interval, const char *name)
220 {
221  if(RF_BLE_ENABLED == 0) {
222  return;
223  }
224 
225  if(name != NULL) {
226  if(strlen(name) == 0 || strlen(name) >= BLE_ADV_NAME_BUF_LEN) {
227  return;
228  }
229 
230  memset(beacond_config.adv_name, 0, BLE_ADV_NAME_BUF_LEN);
231  memcpy(beacond_config.adv_name, name, strlen(name));
232  }
233 
234  if(interval != 0) {
235  beacond_config.interval = interval;
236  }
237 }
238 /*---------------------------------------------------------------------------*/
239 uint8_t
241 {
242  if(RF_BLE_ENABLED == 0) {
243  return RF_CORE_CMD_ERROR;
244  }
245 
246  if(ti_lib_chipinfo_supports_ble() == false) {
247  return RF_CORE_CMD_ERROR;
248  }
249 
250  if(beacond_config.adv_name[0] == 0) {
251  return RF_CORE_CMD_ERROR;
252  }
253 
254  ble_mode_on = RF_BLE_IDLE;
255 
256  process_start(&rf_ble_beacon_process, NULL);
257 
258  return RF_CORE_CMD_OK;
259 }
260 /*---------------------------------------------------------------------------*/
261 uint8_t
263 {
264  return ble_mode_on;
265 }
266 /*---------------------------------------------------------------------------*/
267 void
269 {
270  process_exit(&rf_ble_beacon_process);
271 }
272 static uint8_t
273 rf_radio_setup()
274 {
275  uint32_t cmd_status;
276  rfc_CMD_RADIO_SETUP_t cmd;
277 
278  rf_switch_select_path(RF_SWITCH_PATH_2_4GHZ);
279 
280  /* Create radio setup command */
281  rf_core_init_radio_op((rfc_radioOp_t *)&cmd, sizeof(cmd), CMD_RADIO_SETUP);
282 
283  cmd.txPower = tx_power_current->tx_power;
284  cmd.pRegOverride = ble_overrides;
285  cmd.config.frontEndMode = RF_CORE_RADIO_SETUP_FRONT_END_MODE;
286  cmd.config.biasMode = RF_CORE_RADIO_SETUP_BIAS_MODE;
287  cmd.mode = 0;
288 
289  /* Send Radio setup to RF Core */
290  if(rf_core_send_cmd((uint32_t)&cmd, &cmd_status) != RF_CORE_CMD_OK) {
291  PRINTF("rf_radio_setup: CMDSTA=0x%08lx, status=0x%04x\n",
292  cmd_status, cmd.status);
293  return RF_CORE_CMD_ERROR;
294  }
295 
296  /* Wait until radio setup is done */
297  if(rf_core_wait_cmd_done(&cmd) != RF_CORE_CMD_OK) {
298  PRINTF("rf_radio_setup: wait, CMDSTA=0x%08lx, status=0x%04x\n",
299  cmd_status, cmd.status);
300  return RF_CORE_CMD_ERROR;
301  }
302 
303  return RF_CORE_CMD_OK;
304 }
305 /*---------------------------------------------------------------------------*/
306 /*---------------------------------------------------------------------------*/
307 void
308 rf_ble_beacon_single(uint8_t channel, uint8_t *data, uint8_t len)
309 {
310  uint32_t cmd_status;
311  bool interrupts_disabled;
312  uint8_t j, channel_selected;
313  uint8_t was_on;
314 
315  /* Adhere to the maximum BLE advertisement payload size */
316  if(len > BLE_ADV_NAME_BUF_LEN) {
317  len = BLE_ADV_NAME_BUF_LEN;
318  }
319 
320  /*
321  * Under ContikiMAC, some IEEE-related operations will be called from an
322  * interrupt context. We need those to see that we are in BLE mode.
323  */
324  interrupts_disabled = ti_lib_int_master_disable();
325  ble_mode_on = RF_BLE_ACTIVE;
326  if(!interrupts_disabled) {
327  ti_lib_int_master_enable();
328  }
329 
330  /*
331  * First, determine our state:
332  *
333  * If we are running CSMA, we are likely in IEEE RX mode. We need to
334  * abort the IEEE BG Op before entering BLE mode.
335  * If we are ContikiMAC, we are likely off, in which case we need to
336  * boot the CPE before entering BLE mode
337  */
338  was_on = rf_core_is_accessible();
339 
340  if(was_on) {
341  /*
342  * We were on: If we are in the process of receiving a frame, abort the
343  * BLE beacon burst. Otherwise, terminate the primary radio Op so we
344  * can switch to BLE mode
345  */
346  if(NETSTACK_RADIO.receiving_packet()) {
347  PRINTF("rf_ble_beacon_single: We were receiving\n");
348 
349  /* Abort this pass */
350  return;
351  }
352 
354  } else {
355 
357 
358  /* We were off: Boot the CPE */
359  if(rf_core_boot() != RF_CORE_CMD_OK) {
360  /* Abort this pass */
361  PRINTF("rf_ble_beacon_single: rf_core_boot() failed\n");
362  return;
363  }
364 
366 
367  /* Enter BLE mode */
368  if(rf_radio_setup() != RF_CORE_CMD_OK) {
369  /* Continue so we can at least try to restore our previous state */
370  PRINTF("rf_ble_beacon_single: Error entering BLE mode\n");
371  } else {
372 
373  for(j = 0; j < 3; j++) {
374  channel_selected = (channel >> j) & 0x01;
375  if(channel_selected == 1) {
376  if(send_ble_adv_nc(37 + j, data, len) != RF_CORE_CMD_OK) {
377  /* Continue... */
378  PRINTF("rf_ble_beacon_single: Channel=%d, "
379  "Error advertising\n", 37 + j);
380  }
381  }
382  }
383  }
384 
385  /* Send a CMD_STOP command to RF Core */
386  if(rf_core_send_cmd(CMDR_DIR_CMD(CMD_STOP), &cmd_status) != RF_CORE_CMD_OK) {
387  /* Continue... */
388  PRINTF("rf_ble_beacon_single: status=0x%08lx\n", cmd_status);
389  }
390 
391  if(was_on) {
392  /* We were on, go back to previous primary mode */
394  } else {
395  /* We were off. Shut back off */
397 
398  /* Switch HF clock source to the RCOSC to preserve power */
400  }
401 
402  interrupts_disabled = ti_lib_int_master_disable();
403 
404  ble_mode_on = RF_BLE_IDLE;
405 
406  if(!interrupts_disabled) {
407  ti_lib_int_master_enable();
408  }
409  }
410 }
411 /*---------------------------------------------------------------------------*/
412 PROCESS_THREAD(rf_ble_beacon_process, ev, data)
413 {
414  PROCESS_BEGIN();
415 
416  while(1) {
417  etimer_set(&ble_adv_et, beacond_config.interval);
418 
419  PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&ble_adv_et) || ev == PROCESS_EVENT_EXIT);
420 
421  if(ev == PROCESS_EVENT_EXIT) {
422  PROCESS_EXIT();
423  }
424 
425  /* Set the adv payload each pass: The device name may have changed */
426  p = 0;
427 
428  /* device info */
429  memset(payload, 0, BLE_ADV_PAYLOAD_BUF_LEN);
430  payload[p++] = 0x02; /* 2 bytes */
431  payload[p++] = BLE_ADV_TYPE_DEVINFO;
432  payload[p++] = 0x1a; /* LE general discoverable + BR/EDR */
433  payload[p++] = 1 + strlen(beacond_config.adv_name);
434  payload[p++] = BLE_ADV_TYPE_NAME;
435  memcpy(&payload[p], beacond_config.adv_name,
436  strlen(beacond_config.adv_name));
437  p += strlen(beacond_config.adv_name);
438 
439  /*
440  * Send BLE_ADV_MESSAGES beacon bursts. Each burst on all three
441  * channels, with a BLE_ADV_DUTY_CYCLE interval between bursts
442  */
443  for(i = 0; i < BLE_ADV_MESSAGES; i++) {
444 
445  rf_ble_beacon_single(BLE_ADV_CHANNEL_ALL, payload, p);
446 
447  etimer_set(&ble_adv_et, BLE_ADV_DUTY_CYCLE);
448 
449  /* Wait unless this is the last burst */
450  if(i < BLE_ADV_MESSAGES - 1) {
452  }
453  }
454  }
455  PROCESS_END();
456 }
457 /*---------------------------------------------------------------------------*/
458 /**
459  * @}
460  * @}
461  */
void oscillators_request_hf_xosc(void)
Requests the HF XOSC as the source for the HF clock, but does not perform the actual switch...
Definition: oscillators.c:94
void rf_ble_beacond_stop()
Stop the BLE advertisement/beacon daemon.
Definition: rf-ble.c:268
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
Header file with macros which rename TI CC26xxware functions.
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
Header file for the link-layer address representation
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
radio_value_t rf_ble_get_tx_power(void)
Get TX power for BLE advertisements.
Definition: rf-ble.c:193
void rf_core_power_down()
Disable RFCORE clock domain in the MCU VD and turn off the RFCORE PD.
Definition: rf-core.c:387
void rf_ble_beacond_config(clock_time_t interval, const char *name)
Set the device name to use with the BLE advertisement/beacon daemon.
Definition: rf-ble.c:219
#define PROCESS_WAIT_EVENT_UNTIL(c)
Wait for an event to be posted to the process, with an extra condition.
Definition: process.h:157
void rf_ble_set_tx_power(radio_value_t power)
Set TX power for BLE advertisements.
Definition: rf-ble.c:205
Header file for the CC13xx/CC26xx RF core driver.
int radio_value_t
Each radio has a set of parameters that designate the current configuration and state of the radio...
Definition: radio.h:88
void rf_core_primary_mode_abort()
Abort the currently running primary radio op.
Definition: rf-core.c:570
void process_exit(struct process *p)
Cause a process to exit.
Definition: process.c:202
Header file for the CC13xx/CC26xx oscillator control.
void oscillators_switch_to_hf_rc(void)
Switches MF and HF clock source to be the HF RC OSC.
Definition: oscillators.c:134
void rf_ble_beacon_single(uint8_t channel, uint8_t *data, uint8_t len)
Transmit a single BLE advertisement in one or more advertisement channels.
Definition: rf-ble.c:308
Event timer header file.
Header file for the Contiki process interface.
int etimer_expired(struct etimer *et)
Check if an event timer has expired.
Definition: etimer.c:213
void rf_core_init_radio_op(rfc_radioOp_t *op, uint16_t len, uint16_t command)
Prepare a buffer to host a Radio Op.
Definition: rf-core.c:555
uint8_t rf_ble_is_active()
Check whether the BLE beacond is currently active.
Definition: rf-ble.c:262
uint8_t rf_core_primary_mode_restore()
Abort the currently running primary radio op.
Definition: rf-core.c:580
Header file for the CC13xx/CC26xx BLE driver.
Header file with definitions related to RF switch support.
A timer.
Definition: etimer.h:76
uint8_t rf_core_is_accessible()
Check whether the RF core is accessible.
Definition: rf-core.c:147
void oscillators_switch_to_hf_xosc(void)
Performs the switch to the XOSC.
Definition: oscillators.c:116
uint_fast8_t rf_core_send_cmd(uint32_t cmd, uint32_t *status)
Sends a command to the RF core.
Definition: rf-core.c:156
Include file for the Contiki low-layer network stack (NETSTACK)
Default definitions of C compiler quirk work-arounds.
uint8_t rf_ble_beacond_start()
Start the BLE advertisement/beacon daemon.
Definition: rf-ble.c:240
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1110
uint8_t rf_core_boot()
Boot the RF Core.
Definition: rf-core.c:453
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer.
Definition: etimer.c:177
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
uint_fast8_t rf_core_wait_cmd_done(void *cmd)
Block and wait for a Radio op to complete.
Definition: rf-core.c:228
#define PROCESS_EXIT()
Exit the currently running process.
Definition: process.h:200