Contiki-NG
Loading...
Searching...
No Matches
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/*---------------------------------------------------------------------------*/
79static unsigned char ble_params_buf[32] CC_ALIGN(4);
80static uint8_t ble_mode_on = RF_BLE_IDLE;
81static struct etimer ble_adv_et;
82static uint8_t payload[BLE_ADV_PAYLOAD_BUF_LEN];
83static int p = 0;
84static int i;
85/*---------------------------------------------------------------------------*/
86/* BLE beacond config */
87static 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 */
99static 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 */
111typedef 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
116static 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[] */
140static const output_config_t *tx_power_current = &output_power[0];
141/*---------------------------------------------------------------------------*/
142PROCESS(rf_ble_beacon_process, "CC13xx / CC26xx RF BLE Beacon Process");
143/*---------------------------------------------------------------------------*/
144static int
145send_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 */
204void
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/*---------------------------------------------------------------------------*/
218void
219rf_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/*---------------------------------------------------------------------------*/
239uint8_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/*---------------------------------------------------------------------------*/
261uint8_t
263{
264 return ble_mode_on;
265}
266/*---------------------------------------------------------------------------*/
267void
269{
270 process_exit(&rf_ble_beacon_process);
271}
272static uint8_t
273rf_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/*---------------------------------------------------------------------------*/
307void
308rf_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/*---------------------------------------------------------------------------*/
412PROCESS_THREAD(rf_ble_beacon_process, ev, data)
413{
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 */
Default definitions of C compiler quirk work-arounds.
Event timer header file.
void oscillators_switch_to_hf_xosc(void)
Performs the switch to the XOSC.
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 oscillators_switch_to_hf_rc(void)
Switches MF and HF clock source to be the HF RC OSC.
static bool etimer_expired(struct etimer *et)
Check if an event timer has expired.
Definition etimer.h:201
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer.
Definition etimer.c:177
#define PROCESS(name, strname)
Declare a process.
Definition process.h:307
#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:212
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition process.h:120
#define PROCESS_WAIT_EVENT_UNTIL(c)
Wait for an event to be posted to the process, with an extra condition.
Definition process.h:157
#define PROCESS_END()
Define the end of a process.
Definition process.h:131
void process_start(struct process *p, process_data_t data)
Start a process.
Definition process.c:107
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition process.h:273
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
uint8_t rf_ble_beacond_start()
Start the BLE advertisement/beacon daemon.
Definition rf-ble.c:240
uint8_t rf_ble_is_active()
Check whether the BLE beacond is currently active.
Definition rf-ble.c:262
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
radio_value_t rf_ble_get_tx_power(void)
Get TX power for BLE advertisements.
Definition rf-ble.c:193
void rf_ble_set_tx_power(radio_value_t power)
Set TX power for BLE advertisements.
Definition rf-ble.c:205
void rf_ble_beacond_stop()
Stop the BLE advertisement/beacon daemon.
Definition rf-ble.c:268
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
void rf_core_primary_mode_abort()
Abort the currently running primary radio op.
Definition rf-core.c:568
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:553
void rf_core_power_down()
Disable RFCORE clock domain in the MCU VD and turn off the RFCORE PD.
Definition rf-core.c:385
uint_fast8_t rf_core_send_cmd(uint32_t cmd, uint32_t *status)
Sends a command to the RF core.
Definition rf-core.c:154
uint8_t rf_core_is_accessible()
Check whether the RF core is accessible.
Definition rf-core.c:145
uint8_t rf_core_boot()
Boot the RF Core.
Definition rf-core.c:451
uint_fast8_t rf_core_wait_cmd_done(void *cmd)
Block and wait for a Radio op to complete.
Definition rf-core.c:226
uint8_t rf_core_primary_mode_restore()
Abort the currently running primary radio op.
Definition rf-core.c:578
Header file for the link-layer address representation.
Include file for the Contiki low-layer network stack (NETSTACK)
Header file for the CC13xx/CC26xx oscillator control.
Header file for the Contiki process interface.
Header file for the CC13xx/CC26xx BLE driver.
Header file for the CC13xx/CC26xx RF core driver.
Header file with definitions related to RF switch support.
A timer.
Definition etimer.h:79
Header file with macros which rename TI CC26xxware functions.