Contiki-NG
ble-beacond.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-ble
32  * @{
33  *
34  * \file
35  * Implementation for the CC13xx/CC26xx BLE Beacon Daemon.
36  * \author
37  * Edvard Pettersen <e.pettersen@ti.com>
38  */
39 /*---------------------------------------------------------------------------*/
40 #include "contiki.h"
41 #include "sys/cc.h"
42 #include "sys/clock.h"
43 #include "sys/etimer.h"
44 #include "sys/process.h"
45 #include "net/linkaddr.h"
46 #include "net/netstack.h"
47 /*---------------------------------------------------------------------------*/
48 #include <ti/devices/DeviceFamily.h>
49 #include DeviceFamily_constructPath(driverlib/chipinfo.h)
50 #include DeviceFamily_constructPath(driverlib/rf_ble_cmd.h)
51 #include DeviceFamily_constructPath(driverlib/rf_common_cmd.h)
52 
53 #include <ti/drivers/rf/RF.h>
54 /*---------------------------------------------------------------------------*/
55 #include "rf/sched.h"
56 #include "rf/ble-addr.h"
57 #include "rf/ble-beacond.h"
58 #include "rf/tx-power.h"
59 #include "rf/settings.h"
60 /*---------------------------------------------------------------------------*/
61 #include <stdbool.h>
62 #include <stdint.h>
63 #include <stdio.h>
64 #include <string.h>
65 /*---------------------------------------------------------------------------*/
66 /* Log configuration */
67 #include "sys/log.h"
68 #define LOG_MODULE "Radio"
69 #define LOG_LEVEL LOG_LEVEL_NONE
70 /*---------------------------------------------------------------------------*/
71 #if RF_CONF_BLE_BEACON_ENABLE
72 /*---------------------------------------------------------------------------*/
73 /* BLE Advertisement channels. Not to be changed by the user. */
74 typedef enum {
75  BLE_ADV_CHANNEL_37 = (1 << 0),
76  BLE_ADV_CHANNEL_38 = (1 << 1),
77  BLE_ADV_CHANNEL_39 = (1 << 2),
78 
79  BLE_ADV_CHANNEL_ALL = (BLE_ADV_CHANNEL_37 |
80  BLE_ADV_CHANNEL_38 |
81  BLE_ADV_CHANNEL_39),
82 } ble_adv_channel_t;
83 
84 #define BLE_ADV_CHANNEL_MIN 37
85 #define BLE_ADV_CHANNEL_MAX 39
86 /*---------------------------------------------------------------------------*/
87 /* Maximum BLE advertisement size. Not to be changed by the user. */
88 #define BLE_ADV_MAX_SIZE 31
89 /*---------------------------------------------------------------------------*/
90 /* BLE Intervals: Send a burst of advertisements every BLE_ADV_INTERVAL secs */
91 #define BLE_ADV_INTERVAL (CLOCK_SECOND * 5)
92 #define BLE_ADV_DUTY_CYCLE (CLOCK_SECOND / 10)
93 #define BLE_ADV_MESSAGES 10
94 
95 /* BLE Advertisement-related macros */
96 #define BLE_ADV_TYPE_DEVINFO 0x01
97 #define BLE_ADV_TYPE_NAME 0x09
98 #define BLE_ADV_TYPE_MANUFACTURER 0xFF
99 #define BLE_ADV_NAME_BUF_LEN BLE_ADV_MAX_SIZE
100 #define BLE_ADV_PAYLOAD_BUF_LEN 64
101 #define BLE_UUID_SIZE 16
102 /*---------------------------------------------------------------------------*/
103 typedef struct {
104  /* Outgoing frame buffer */
105  uint8_t tx_buf[BLE_ADV_PAYLOAD_BUF_LEN] CC_ALIGN(4);
106 
107  /* Config data */
108  size_t adv_name_len;
109  char adv_name[BLE_ADV_NAME_BUF_LEN];
110 
111  /* Indicates whether deamon is active or not */
112  bool is_active;
113 
114  /* Periodic timer for sending out BLE advertisements */
115  clock_time_t ble_adv_interval;
116  struct etimer ble_adv_et;
117 
118  /* RF driver */
119  RF_Handle rf_handle;
120 } ble_beacond_t;
121 
122 static ble_beacond_t ble_beacond;
123 /*---------------------------------------------------------------------------*/
124 PROCESS(ble_beacond_process, "RF BLE Beacon Daemon Process");
125 /*---------------------------------------------------------------------------*/
126 rf_ble_beacond_result_t
128 {
129  ble_adv_par.pDeviceAddress = (uint16_t *)ble_addr_ptr();
130 
131  RF_Params rf_params;
132  RF_Params_init(&rf_params);
133 
134  /* Should immediately turn off radio if possible */
135  rf_params.nInactivityTimeout = 0;
136 
137  ble_beacond.rf_handle = ble_open(&rf_params);
138 
139  if(ble_beacond.rf_handle == NULL) {
140  return RF_BLE_BEACOND_ERROR;
141  }
142 
143  return RF_BLE_BEACOND_OK;
144 }
145 /*---------------------------------------------------------------------------*/
146 rf_ble_beacond_result_t
147 rf_ble_beacond_config(clock_time_t interval, const char *name)
148 {
149  rf_ble_beacond_result_t res;
150 
151  res = RF_BLE_BEACOND_ERROR;
152 
153  if(interval > 0) {
154  ble_beacond.ble_adv_interval = interval;
155 
156  res = RF_BLE_BEACOND_OK;
157  }
158 
159  if(name != NULL) {
160  const size_t name_len = strlen(name);
161 
162  if((name_len == 0) || (name_len >= BLE_ADV_NAME_BUF_LEN)) {
163  ble_beacond.adv_name_len = name_len;
164  memcpy(ble_beacond.adv_name, name, name_len);
165 
166  res = RF_BLE_BEACOND_OK;
167  }
168  }
169 
170  return res;
171 }
172 /*---------------------------------------------------------------------------*/
173 rf_ble_beacond_result_t
175 {
176  if(ble_beacond.is_active) {
177  return RF_BLE_BEACOND_OK;
178  }
179 
180  ble_beacond.is_active = true;
181 
182  process_start(&ble_beacond_process, NULL);
183 
184  return RF_BLE_BEACOND_OK;
185 }
186 /*---------------------------------------------------------------------------*/
187 rf_ble_beacond_result_t
189 {
190  if(!ble_beacond.is_active) {
191  return RF_BLE_BEACOND_OK;
192  }
193 
194  ble_beacond.is_active = false;
195 
196  process_exit(&ble_beacond_process);
197 
198  return RF_BLE_BEACOND_OK;
199 }
200 /*---------------------------------------------------------------------------*/
201 int8_t
202 rf_ble_is_active(void)
203 {
204  return (int8_t)ble_beacond.is_active;
205 }
206 /*---------------------------------------------------------------------------*/
207 rf_ble_beacond_result_t
208 rf_ble_set_tx_power(int8_t dbm)
209 {
210  rf_result_t res;
211 
212  if(!tx_power_in_range(dbm, ble_tx_power_table, ble_tx_power_table_size)) {
213  return RADIO_RESULT_INVALID_VALUE;
214  }
215 
216  res = rf_set_tx_power(ble_beacond.rf_handle, ble_tx_power_table, dbm);
217 
218  return (res == RF_RESULT_OK)
219  ? RF_BLE_BEACOND_OK
220  : RF_BLE_BEACOND_ERROR;
221 }
222 /*---------------------------------------------------------------------------*/
223 int8_t
225 {
226  rf_result_t res;
227 
228  int8_t dbm;
229  res = rf_get_tx_power(ble_beacond.rf_handle, ble_tx_power_table, &dbm);
230 
231  if(res != RF_RESULT_OK) {
232  return RF_TxPowerTable_INVALID_DBM;
233  }
234 
235  return dbm;
236 }
237 /*---------------------------------------------------------------------------*/
238 static rf_ble_beacond_result_t
239 ble_beacon_burst(uint8_t channels_bm, uint8_t *data, uint8_t len)
240 {
241  rf_result_t res;
242 
243  uint8_t channel;
244  for(channel = BLE_ADV_CHANNEL_MIN; channel <= BLE_ADV_CHANNEL_MAX; ++channel) {
245  const uint8_t channel_bv = (1 << (channel - BLE_ADV_CHANNEL_MIN));
246  if((channel_bv & channels_bm) == 0) {
247  continue;
248  }
249 
250  ble_adv_par.advLen = len;
251  ble_adv_par.pAdvData = data;
252 
253  ble_cmd_beacon.channel = channel;
254 
255  res = ble_sched_beacon(NULL, 0);
256 
257  if(res != RF_RESULT_OK) {
258  return RF_BLE_BEACOND_ERROR;
259  }
260  }
261 
262  return RF_BLE_BEACOND_OK;
263 }
264 /*---------------------------------------------------------------------------*/
265 PROCESS_THREAD(ble_beacond_process, ev, data)
266 {
267  static size_t i;
268  static size_t len;
269 
270  PROCESS_BEGIN();
271 
272  while(1) {
273  etimer_set(&ble_beacond.ble_adv_et, ble_beacond.ble_adv_interval);
274  PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&ble_beacond.ble_adv_et) ||
275  (ev == PROCESS_EVENT_EXIT));
276 
277  if(ev == PROCESS_EVENT_EXIT) {
278  PROCESS_EXIT();
279  }
280 
281  /* Set the adv payload each pass: The device name may have changed */
282  len = 0;
283 
284  /* Device info */
285  ble_beacond.tx_buf[len++] = (uint8_t)0x02; /* 2 bytes */
286  ble_beacond.tx_buf[len++] = (uint8_t)BLE_ADV_TYPE_DEVINFO;
287  ble_beacond.tx_buf[len++] = (uint8_t)0x1A; /* LE general discoverable + BR/EDR */
288  ble_beacond.tx_buf[len++] = (uint8_t)ble_beacond.adv_name_len;
289  ble_beacond.tx_buf[len++] = (uint8_t)BLE_ADV_TYPE_NAME;
290 
291  memcpy(ble_beacond.tx_buf + len, ble_beacond.adv_name, ble_beacond.adv_name_len);
292  len += ble_beacond.adv_name_len;
293 
294  /*
295  * Send BLE_ADV_MESSAGES beacon bursts. Each burst on all three
296  * channels, with a BLE_ADV_DUTY_CYCLE interval between bursts
297  */
298  ble_beacon_burst(BLE_ADV_CHANNEL_ALL, ble_beacond.tx_buf, len);
299  for(i = 1; i < BLE_ADV_MESSAGES; ++i) {
300  etimer_set(&ble_beacond.ble_adv_et, BLE_ADV_DUTY_CYCLE);
301  PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&ble_beacond.ble_adv_et));
302 
303  ble_beacon_burst(BLE_ADV_CHANNEL_ALL, ble_beacond.tx_buf, len);
304  }
305  }
306  PROCESS_END();
307 }
308 /*---------------------------------------------------------------------------*/
309 #else /* RF_CONF_BLE_BEACON_ENABLE */
310 /*---------------------------------------------------------------------------*/
311 rf_ble_beacond_result_t
313 {
314  return RF_BLE_BEACOND_DISABLED;
315 }
316 /*---------------------------------------------------------------------------*/
317 rf_ble_beacond_result_t
318 rf_ble_beacond_config(clock_time_t interval, const char *name)
319 {
320  (void)interval;
321  (void)name;
322  return RF_BLE_BEACOND_DISABLED;
323 }
324 /*---------------------------------------------------------------------------*/
325 rf_ble_beacond_result_t
327 {
328  return RF_BLE_BEACOND_DISABLED;
329 }
330 
331 /*---------------------------------------------------------------------------*/
332 rf_ble_beacond_result_t
334 {
335  return RF_BLE_BEACOND_DISABLED;
336 }
337 /*---------------------------------------------------------------------------*/
338 int8_t
340 {
341  return -1;
342 }
343 /*---------------------------------------------------------------------------*/
344 rf_ble_beacond_result_t
345 rf_ble_set_tx_power(int8_t power)
346 {
347  (void)power;
348  return RF_BLE_BEACOND_DISABLED;
349 }
350 /*---------------------------------------------------------------------------*/
351 int8_t
353 {
354  return ~(int8_t)(0);
355 }
356 /*---------------------------------------------------------------------------*/
357 #endif /* RF_CONF_BLE_BEACON_ENABLE */
358 /*---------------------------------------------------------------------------*/
359 /** @} */
rf_ble_beacond_result_t rf_ble_beacond_start(void)
Start the BLE advertisement/beacon daemon.
Definition: ble-beacond.c:326
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
Header file of TX power functionality of CC13xx/CC26xx.
Header file for the CC13xx/CC26xx BLE Beacon Daemon.
#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
#define PROCESS_WAIT_EVENT_UNTIL(c)
Wait for an event to be posted to the process, with an extra condition.
Definition: process.h:157
uint8_t * ble_addr_ptr(void)
Retrieve the pointer to where the BLE address is stored.
Definition: ble-addr.c:58
rf_ble_beacond_result_t rf_ble_beacond_config(clock_time_t interval, const char *name)
Set the device name to use with the BLE advertisement/beacon daemon.
Definition: ble-beacond.c:318
int8_t rf_ble_get_tx_power(void)
Get TX power for BLE advertisements.
Definition: ble-beacond.c:352
rf_ble_beacond_result_t rf_ble_beacond_stop(void)
Stop the BLE advertisement/beacon daemon.
Definition: ble-beacond.c:333
void process_exit(struct process *p)
Cause a process to exit.
Definition: process.c:202
rf_ble_beacond_result_t rf_ble_set_tx_power(int8_t power)
Set TX power for BLE advertisements.
Definition: ble-beacond.c:345
Header file of the CC13xx/CC26xx RF scheduler.
Event timer header file.
int8_t rf_ble_is_active(void)
Check whether the BLE beacond is currently active.
Definition: ble-beacond.c:339
Header file for the Contiki process interface.
int etimer_expired(struct etimer *et)
Check if an event timer has expired.
Definition: etimer.c:213
rf_ble_beacond_result_t rf_ble_beacond_init(void)
Initialize the BLE advertisement/beacon daemon.
Definition: ble-beacond.c:312
A timer.
Definition: etimer.h:75
Header file of RF settings for CC13xx/CC26xx.
Include file for the Contiki low-layer network stack (NETSTACK)
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:1035
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 process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
#define PROCESS_EXIT()
Exit the currently running process.
Definition: process.h:200