Contiki 3.x
rf-ble.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015, 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 /**
32  * \addtogroup rf-core-ble
33  * @{
34  *
35  * \file
36  * Implementation of the CC13xx/CC26xx RF BLE driver
37  */
38 /*---------------------------------------------------------------------------*/
39 #include "contiki-conf.h"
40 #include "sys/process.h"
41 #include "sys/clock.h"
42 #include "sys/cc.h"
43 #include "sys/etimer.h"
44 #include "net/netstack.h"
45 #include "net/linkaddr.h"
46 #include "dev/oscillators.h"
47 #include "rf-core/rf-core.h"
48 #include "rf-core/rf-ble.h"
49 #include "rf-core/api/ble_cmd.h"
50 #include "rf-core/api/common_cmd.h"
51 #include "ti-lib.h"
52 /*---------------------------------------------------------------------------*/
53 #include <stdint.h>
54 #include <stdbool.h>
55 #include <stdio.h>
56 /*---------------------------------------------------------------------------*/
57 #define DEBUG 0
58 #if DEBUG
59 #define PRINTF(...) printf(__VA_ARGS__)
60 #else
61 #define PRINTF(...)
62 #endif
63 /*---------------------------------------------------------------------------*/
64 /* BLE Intervals: Send a burst of advertisements every BLE_ADV_INTERVAL secs */
65 #define BLE_ADV_INTERVAL (CLOCK_SECOND * 5)
66 #define BLE_ADV_DUTY_CYCLE (CLOCK_SECOND / 10)
67 #define BLE_ADV_MESSAGES 10
68 
69 /* BLE Advertisement-related macros */
70 #define BLE_ADV_TYPE_DEVINFO 0x01
71 #define BLE_ADV_TYPE_NAME 0x09
72 #define BLE_ADV_TYPE_MANUFACTURER 0xFF
73 #define BLE_ADV_NAME_BUF_LEN 32
74 #define BLE_ADV_PAYLOAD_BUF_LEN 64
75 #define BLE_UUID_SIZE 16
76 /*---------------------------------------------------------------------------*/
77 static unsigned char ble_params_buf[32] CC_ALIGN(4);
78 static uint8_t ble_mode_on = RF_BLE_IDLE;
79 static struct etimer ble_adv_et;
80 static uint8_t payload[BLE_ADV_PAYLOAD_BUF_LEN];
81 static int p = 0;
82 static int i;
83 /*---------------------------------------------------------------------------*/
84 typedef struct default_ble_tx_power_s {
85  uint16_t ib:6;
86  uint16_t gc:2;
87  uint16_t boost:1;
88  uint16_t temp_coeff:7;
89 } default_ble_tx_power_t;
90 
91 static default_ble_tx_power_t tx_power = { 0x29, 0x00, 0x00, 0x00 };
92 /*---------------------------------------------------------------------------*/
93 /* BLE beacond config */
94 static struct ble_beacond_config {
95  clock_time_t interval;
96  char adv_name[BLE_ADV_NAME_BUF_LEN];
97 } beacond_config = { .interval = BLE_ADV_INTERVAL };
98 /*---------------------------------------------------------------------------*/
99 /* BLE overrides */
100 static uint32_t ble_overrides[] = {
101  0x00364038, /* Synth: Set RTRIM (POTAILRESTRIM) to 6 */
102  0x000784A3, /* Synth: Set FREF = 3.43 MHz (24 MHz / 7) */
103  0xA47E0583, /* Synth: Set loop bandwidth after lock to 80 kHz (K2) */
104  0xEAE00603, /* Synth: Set loop bandwidth after lock to 80 kHz (K3, LSB) */
105  0x00010623, /* Synth: Set loop bandwidth after lock to 80 kHz (K3, MSB) */
106  0x00456088, /* Adjust AGC reference level */
107  0xFFFFFFFF, /* End of override list */
108 };
109 /*---------------------------------------------------------------------------*/
110 PROCESS(rf_ble_beacon_process, "CC13xx / CC26xx RF BLE Beacon Process");
111 /*---------------------------------------------------------------------------*/
112 static int
113 send_ble_adv_nc(int channel, uint8_t *adv_payload, int adv_payload_len)
114 {
115  uint32_t cmd_status;
116  rfc_CMD_BLE_ADV_NC_t cmd;
117  rfc_bleAdvPar_t *params;
118 
119  params = (rfc_bleAdvPar_t *)ble_params_buf;
120 
121  /* Clear both buffers */
122  memset(&cmd, 0x00, sizeof(cmd));
123  memset(ble_params_buf, 0x00, sizeof(ble_params_buf));
124 
125  /* Adv NC */
126  cmd.commandNo = CMD_BLE_ADV_NC;
127  cmd.condition.rule = COND_NEVER;
128  cmd.whitening.bOverride = 0;
129  cmd.whitening.init = 0;
130  cmd.pParams = params;
131  cmd.channel = channel;
132 
133  /* Set up BLE Advertisement parameters */
134  params->pDeviceAddress = (uint16_t *)&linkaddr_node_addr.u8[LINKADDR_SIZE - 2];
135  params->endTrigger.triggerType = TRIG_NEVER;
136  params->endTime = TRIG_NEVER;
137 
138  /* Set up BLE Advertisement parameters */
139  params = (rfc_bleAdvPar_t *)ble_params_buf;
140  params->advLen = adv_payload_len;
141  params->pAdvData = adv_payload;
142 
143  if(rf_core_send_cmd((uint32_t)&cmd, &cmd_status) == RF_CORE_CMD_ERROR) {
144  PRINTF("send_ble_adv_nc: Chan=%d CMDSTA=0x%08lx, status=0x%04x\n",
145  channel, cmd_status, cmd.status);
146  return RF_CORE_CMD_ERROR;
147  }
148 
149  /* Wait until the command is done */
150  if(rf_core_wait_cmd_done(&cmd) != RF_CORE_CMD_OK) {
151  PRINTF("send_ble_adv_nc: Chan=%d CMDSTA=0x%08lx, status=0x%04x\n",
152  channel, cmd_status, cmd.status);
153  return RF_CORE_CMD_ERROR;
154  }
155 
156  return RF_CORE_CMD_OK;
157 }
158 /*---------------------------------------------------------------------------*/
159 void
160 rf_ble_beacond_config(clock_time_t interval, const char *name)
161 {
162  if(RF_BLE_ENABLED == 0) {
163  return;
164  }
165 
166  if(name != NULL) {
167  if(strlen(name) == 0 || strlen(name) >= BLE_ADV_NAME_BUF_LEN) {
168  return;
169  }
170 
171  memset(beacond_config.adv_name, 0, BLE_ADV_NAME_BUF_LEN);
172  memcpy(beacond_config.adv_name, name, strlen(name));
173  }
174 
175  if(interval != 0) {
176  beacond_config.interval = interval;
177  }
178 }
179 /*---------------------------------------------------------------------------*/
180 uint8_t
182 {
183  if(RF_BLE_ENABLED == 0) {
184  return RF_CORE_CMD_ERROR;
185  }
186 
187  if(ti_lib_chipinfo_supports_ble() == false) {
188  return RF_CORE_CMD_ERROR;
189  }
190 
191  if(beacond_config.adv_name[0] == 0) {
192  return RF_CORE_CMD_ERROR;
193  }
194 
195  ble_mode_on = RF_BLE_IDLE;
196 
197  process_start(&rf_ble_beacon_process, NULL);
198 
199  return RF_CORE_CMD_OK;
200 }
201 /*---------------------------------------------------------------------------*/
202 uint8_t
204 {
205  return ble_mode_on;
206 }
207 /*---------------------------------------------------------------------------*/
208 void
210 {
211  process_exit(&rf_ble_beacon_process);
212 }
213 /*---------------------------------------------------------------------------*/
214 static uint8_t
215 rf_radio_setup()
216 {
217  uint32_t cmd_status;
218  rfc_CMD_RADIO_SETUP_t cmd;
219 
220  /* Create radio setup command */
221  rf_core_init_radio_op((rfc_radioOp_t *)&cmd, sizeof(cmd), CMD_RADIO_SETUP);
222 
223  cmd.txPower.IB = tx_power.ib;
224  cmd.txPower.GC = tx_power.gc;
225  cmd.txPower.tempCoeff = tx_power.temp_coeff;
226  cmd.txPower.boost = tx_power.boost;
227  cmd.pRegOverride = ble_overrides;
228  cmd.mode = 0;
229 
230  /* Send Radio setup to RF Core */
231  if(rf_core_send_cmd((uint32_t)&cmd, &cmd_status) != RF_CORE_CMD_OK) {
232  PRINTF("rf_radio_setup: CMDSTA=0x%08lx, status=0x%04x\n",
233  cmd_status, cmd.status);
234  return RF_CORE_CMD_ERROR;
235  }
236 
237  /* Wait until radio setup is done */
238  if(rf_core_wait_cmd_done(&cmd) != RF_CORE_CMD_OK) {
239  PRINTF("rf_radio_setup: wait, CMDSTA=0x%08lx, status=0x%04x\n",
240  cmd_status, cmd.status);
241  return RF_CORE_CMD_ERROR;
242  }
243 
244  return RF_CORE_CMD_OK;
245 }
246 /*---------------------------------------------------------------------------*/
247 PROCESS_THREAD(rf_ble_beacon_process, ev, data)
248 {
249  uint8_t was_on;
250  int j;
251  uint32_t cmd_status;
252  bool interrupts_disabled;
253 
254  PROCESS_BEGIN();
255 
256  while(1) {
257  etimer_set(&ble_adv_et, beacond_config.interval);
258 
259  PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&ble_adv_et) || ev == PROCESS_EVENT_EXIT);
260 
261  if(ev == PROCESS_EVENT_EXIT) {
262  PROCESS_EXIT();
263  }
264 
265  /* Set the adv payload each pass: The device name may have changed */
266  p = 0;
267 
268  /* device info */
269  memset(payload, 0, BLE_ADV_PAYLOAD_BUF_LEN);
270  payload[p++] = 0x02; /* 2 bytes */
271  payload[p++] = BLE_ADV_TYPE_DEVINFO;
272  payload[p++] = 0x1a; /* LE general discoverable + BR/EDR */
273  payload[p++] = 1 + strlen(beacond_config.adv_name);
274  payload[p++] = BLE_ADV_TYPE_NAME;
275  memcpy(&payload[p], beacond_config.adv_name,
276  strlen(beacond_config.adv_name));
277  p += strlen(beacond_config.adv_name);
278 
279  for(i = 0; i < BLE_ADV_MESSAGES; i++) {
280  /*
281  * Under ContikiMAC, some IEEE-related operations will be called from an
282  * interrupt context. We need those to see that we are in BLE mode.
283  */
284  interrupts_disabled = ti_lib_int_master_disable();
285  ble_mode_on = RF_BLE_ACTIVE;
286  if(!interrupts_disabled) {
287  ti_lib_int_master_enable();
288  }
289 
290  /*
291  * Send BLE_ADV_MESSAGES beacon bursts. Each burst on all three
292  * channels, with a BLE_ADV_DUTY_CYCLE interval between bursts
293  *
294  * First, determine our state:
295  *
296  * If we are running NullRDC, we are likely in IEEE RX mode. We need to
297  * abort the IEEE BG Op before entering BLE mode.
298  * If we are ContikiMAC, we are likely off, in which case we need to
299  * boot the CPE before entering BLE mode
300  */
301  was_on = rf_core_is_accessible();
302 
303  if(was_on) {
304  /*
305  * We were on: If we are in the process of receiving a frame, abort the
306  * BLE beacon burst. Otherwise, terminate the primary radio Op so we
307  * can switch to BLE mode
308  */
309  if(NETSTACK_RADIO.receiving_packet()) {
310  PRINTF("rf_ble_beacon_process: We were receiving\n");
311 
312  /* Abort this pass */
313  break;
314  }
315 
317  } else {
318  /* Request the HF XOSC to source the HF clock. */
320 
321  /* We were off: Boot the CPE */
322  if(rf_core_boot() != RF_CORE_CMD_OK) {
323  PRINTF("rf_ble_beacon_process: rf_core_boot() failed\n");
324 
325  /* Abort this pass */
326  break;
327  }
328 
329  /* Trigger a switch to the XOSC, so that we can use the FS */
331  }
332 
333  /* Enter BLE mode */
334  if(rf_radio_setup() != RF_CORE_CMD_OK) {
335  PRINTF("cc26xx_rf_ble_beacon_process: Error entering BLE mode\n");
336  /* Continue so we can at least try to restore our previous state */
337  } else {
338  /* Send advertising packets on all 3 advertising channels */
339  for(j = 37; j <= 39; j++) {
340  if(send_ble_adv_nc(j, payload, p) != RF_CORE_CMD_OK) {
341  PRINTF("cc26xx_rf_ble_beacon_process: Channel=%d, "
342  "Error advertising\n", j);
343  /* Break the loop, but don't return just yet */
344  break;
345  }
346  }
347  }
348 
349  /* Send a CMD_STOP command to RF Core */
350  if(rf_core_send_cmd(CMDR_DIR_CMD(CMD_STOP), &cmd_status) != RF_CORE_CMD_OK) {
351  PRINTF("cc26xx_rf_ble_beacon_process: status=0x%08lx\n", cmd_status);
352  /* Continue... */
353  }
354 
355  if(was_on) {
356  /* We were on, go back to previous primary mode */
358  } else {
359  /* We were off. Shut back off */
361 
362  /* Switch HF clock source to the RCOSC to preserve power */
364  }
365  etimer_set(&ble_adv_et, BLE_ADV_DUTY_CYCLE);
366 
367  interrupts_disabled = ti_lib_int_master_disable();
368 
369  ble_mode_on = RF_BLE_IDLE;
370 
371  if(!interrupts_disabled) {
372  ti_lib_int_master_enable();
373  }
374 
375  /* Wait unless this is the last burst */
376  if(i < BLE_ADV_MESSAGES - 1) {
378  }
379  }
380 
381  interrupts_disabled = ti_lib_int_master_disable();
382 
383  ble_mode_on = RF_BLE_IDLE;
384 
385  if(!interrupts_disabled) {
386  ti_lib_int_master_enable();
387  }
388  }
389  PROCESS_END();
390 }
391 /*---------------------------------------------------------------------------*/
392 /**
393  * @}
394  * @}
395  */
uint8_t rf_ble_beacond_start()
Start the BLE advertisement/beacon daemon.
Definition: rf-ble.c:181
void rf_core_power_down()
Disable RFCORE clock domain in the MCU VD and turn off the RFCORE PD.
Definition: rf-core.c:269
Header file with macros which rename TI CC26xxware functions.
Default definitions of C compiler quirk work-arounds.
Header file for the CC13xx/CC26xx BLE driver.
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer.
Definition: etimer.c:177
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
A timer.
Definition: etimer.h:76
#define PROCESS_EXIT()
Exit the currently running process.
Definition: process.h:200
void process_exit(struct process *p)
Cause a process to exit.
Definition: process.c:202
void rf_core_primary_mode_abort()
Abort the currently running primary radio op.
Definition: rf-core.c:439
uint8_t rf_ble_is_active()
Check whether the BLE beacond is currently active.
Definition: rf-ble.c:203
void oscillators_switch_to_hf_xosc(void)
Performs the switch to the XOSC.
Definition: oscillators.c:116
#define PROCESS_WAIT_EVENT_UNTIL(c)
Wait for an event to be posted to the process, with an extra condition.
Definition: process.h:157
Header file for the CC13xx/CC26xx RF core driver.
Header file for the Rime address representation
uint8_t rf_core_is_accessible()
Check whether the RF core is accessible.
Definition: rf-core.c:110
#define NULL
The null pointer.
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_beacond_stop()
Stop the BLE advertisement/beacon daemon.
Definition: rf-ble.c:209
int etimer_expired(struct etimer *et)
Check if an event timer has expired.
Definition: etimer.c:213
uint8_t rf_core_boot()
Boot the RF Core.
Definition: rf-core.c:348
uint_fast8_t rf_core_send_cmd(uint32_t cmd, uint32_t *status)
Sends a command to the RF core.
Definition: rf-core.c:119
Header file for the Contiki process interface.
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
Event timer header file.
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:160
uint8_t rf_core_primary_mode_restore()
Abort the currently running primary radio op.
Definition: rf-core.c:449
linkaddr_t linkaddr_node_addr
The Rime address of the node.
Definition: linkaddr.c:48
Header file for the CC13xx/CC26xx oscillator control.
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_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:424
Include file for the Contiki low-layer network stack (NETSTACK)
uint_fast8_t rf_core_wait_cmd_done(void *cmd)
Block and wait for a Radio op to complete.
Definition: rf-core.c:185
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120