1 /*
2 * Copyright (C) 2017 BlueKitchen GmbH
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
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 holders nor the names of
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * 4. Any redistribution, use, or modification is done solely for
17 * personal benefit and not for any commercial purpose or for
18 * monetary gain.
19 *
20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24 * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * Please inquire about commercial licensing options at
34 * [email protected]
35 *
36 */
37
38 #define BTSTACK_FILE__ "adv_bearer.c"
39
40 #define ENABLE_LOG_DEBUG
41
42 #include <inttypes.h>
43 #include <string.h>
44
45 #include "mesh/adv_bearer.h"
46 #include "ble/core.h"
47 #include "bluetooth.h"
48 #include "bluetooth_data_types.h"
49 #include "btstack_debug.h"
50 #include "btstack_util.h"
51 #include "btstack_run_loop.h"
52 #include "btstack_event.h"
53 #include "gap.h"
54
55 // issue: gap adv control in hci might be slow to update advertisements fast enough. for now add 10 ms extra to ADVERTISING_INTERVAL_CONNECTABLE_MIN_MS
56 // todo: track adv enable/disable events before next step
57
58 // min advertising interval 20 ms for connectable advertisements
59 #define ADVERTISING_INTERVAL_CONNECTABLE_MIN 0x30
60 #define ADVERTISING_INTERVAL_CONNECTABLE_MIN_MS (ADVERTISING_INTERVAL_CONNECTABLE_MIN * 625 / 1000)
61
62 // min advertising interval 100 ms for non-connectable advertisements (pre 5.0 controllers)
63 #define ADVERTISING_INTERVAL_NONCONNECTABLE_MIN 0xa0
64 #define ADVERTISING_INTERVAL_NONCONNECTABLE_MIN_MS (ADVERTISING_INTERVAL_NONCONNECTABLE_MIN * 625 / 1000)
65
66 // num adv bearer message types
67 #define NUM_TYPES 3
68
69 typedef enum {
70 MESH_NETWORK_ID,
71 MESH_BEACON_ID,
72 PB_ADV_ID,
73 INVALID_ID,
74 } message_type_id_t;
75
76 typedef enum {
77 STATE_IDLE,
78 STATE_BEARER,
79 STATE_GAP,
80 } state_t;
81
82
83 // prototypes
84 static void adv_bearer_run(void);
85
86 // globals
87
88 static btstack_packet_callback_registration_t hci_event_callback_registration;
89 static btstack_timer_source_t adv_timer;
90 static int adv_timer_active;
91 static bd_addr_t null_addr;
92
93 static btstack_packet_handler_t client_callbacks[NUM_TYPES];
94 static int request_can_send_now[NUM_TYPES];
95 static int last_sender;
96
97 // scheduler
98 static state_t adv_bearer_state;
99 static uint32_t gap_adv_next_ms;
100
101 // adv bearer packets
102 static uint8_t adv_bearer_buffer[31];
103 static uint8_t adv_bearer_buffer_length;
104 static uint8_t adv_bearer_count;
105 static uint16_t adv_bearer_interval;
106
107 // gap advertising
108 static int gap_advertising_enabled;
109 static uint16_t gap_adv_int_min = 0x30;
110 static uint16_t gap_adv_int_ms;
111 static uint16_t gap_adv_int_max = 0x30;
112 static uint8_t gap_adv_type = 0;
113 static uint8_t gap_direct_address_typ;
114 static bd_addr_t gap_direct_address;
115 static uint8_t gap_channel_map = 0x07;
116 static uint8_t gap_filter_policy = 0;
117
118 static btstack_linked_list_t gap_connectable_advertisements;
119
120 // dispatch advertising events
adv_bearer_packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)121 static void adv_bearer_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
122 const uint8_t * data;
123 int data_len;
124 message_type_id_t type_id;
125
126 switch (packet_type){
127 case HCI_EVENT_PACKET:
128 switch(packet[0]){
129 case BTSTACK_EVENT_STATE:
130 if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) break;
131 adv_bearer_run();
132 break;
133 case GAP_EVENT_ADVERTISING_REPORT:
134 // only non-connectable ind
135 if (gap_event_advertising_report_get_advertising_event_type(packet) != 0x03) break;
136 data = gap_event_advertising_report_get_data(packet);
137 data_len = gap_event_advertising_report_get_data_length(packet);
138
139 switch(data[1]){
140 case BLUETOOTH_DATA_TYPE_MESH_MESSAGE:
141 type_id = MESH_NETWORK_ID;
142 break;
143 case BLUETOOTH_DATA_TYPE_MESH_BEACON:
144 type_id = MESH_BEACON_ID;
145 break;
146 case BLUETOOTH_DATA_TYPE_PB_ADV:
147 type_id = PB_ADV_ID;
148 break;
149 default:
150 return;
151 }
152 if (client_callbacks[type_id]){
153 switch (type_id){
154 case PB_ADV_ID:
155 (*client_callbacks[type_id])(packet_type, channel, packet, size);
156 break;
157 case MESH_NETWORK_ID:
158 (*client_callbacks[type_id])(MESH_NETWORK_PACKET, 0, (uint8_t*) &data[2], data_len-2);
159 break;
160 case MESH_BEACON_ID:
161 (*client_callbacks[type_id])(MESH_BEACON_PACKET, 0, (uint8_t*) &data[2], data_len-2);
162 break;
163 default:
164 break;
165 }
166 }
167 break;
168 default:
169 break;
170 }
171 break;
172 default:
173 break;
174 }
175 }
176
177 // round-robin
adv_bearer_emit_can_send_now(void)178 static void adv_bearer_emit_can_send_now(void){
179
180 if (adv_bearer_count > 0) return;
181
182 int countdown = NUM_TYPES;
183 while (countdown--) {
184 last_sender++;
185 if (last_sender == NUM_TYPES) {
186 last_sender = 0;
187 }
188 if (request_can_send_now[last_sender]){
189 request_can_send_now[last_sender] = 0;
190 // emit can send now
191 log_debug("can send now");
192 uint8_t event[3];
193 event[0] = HCI_EVENT_MESH_META;
194 event[1] = 1;
195 event[2] = MESH_SUBEVENT_CAN_SEND_NOW;
196 (*client_callbacks[last_sender])(HCI_EVENT_PACKET, 0, &event[0], sizeof(event));
197 return;
198 }
199 }
200 }
201
adv_bearer_timeout_handler(btstack_timer_source_t * ts)202 static void adv_bearer_timeout_handler(btstack_timer_source_t * ts){
203 UNUSED(ts);
204 adv_timer_active = 0;
205 uint32_t now = btstack_run_loop_get_time_ms();
206 switch (adv_bearer_state){
207 case STATE_GAP:
208 log_debug("Timeout (state gap)");
209 gap_advertisements_enable(0);
210 if (gap_advertising_enabled){
211 gap_adv_next_ms = now + gap_adv_int_ms - ADVERTISING_INTERVAL_CONNECTABLE_MIN_MS;
212 log_debug("Next adv: %" PRIu32, gap_adv_next_ms);
213 }
214 adv_bearer_state = STATE_IDLE;
215 break;
216 case STATE_BEARER:
217 log_debug("Timeout (state bearer)");
218 gap_advertisements_enable(0);
219 adv_bearer_count--;
220 if (adv_bearer_count == 0){
221 adv_bearer_emit_can_send_now();
222 }
223 adv_bearer_state = STATE_IDLE;
224 break;
225 default:
226 break;
227 }
228 adv_bearer_run();
229 }
230
adv_bearer_set_timeout(uint32_t time_ms)231 static void adv_bearer_set_timeout(uint32_t time_ms){
232 btstack_run_loop_set_timer_handler(&adv_timer, &adv_bearer_timeout_handler);
233 btstack_run_loop_set_timer(&adv_timer, time_ms); // compile time constants
234 btstack_run_loop_add_timer(&adv_timer);
235 adv_timer_active = 1;
236 }
237
238 // scheduler
adv_bearer_run(void)239 static void adv_bearer_run(void){
240
241 if (hci_get_state() != HCI_STATE_WORKING) return;
242 if (adv_timer_active) return;
243
244 uint32_t now = btstack_run_loop_get_time_ms();
245 switch (adv_bearer_state){
246 case STATE_IDLE:
247 if (gap_advertising_enabled){
248 if ((int32_t)(now - gap_adv_next_ms) >= 0){
249 adv_bearer_connectable_advertisement_data_item_t * item = (adv_bearer_connectable_advertisement_data_item_t *) btstack_linked_list_pop(&gap_connectable_advertisements);
250 if (item == NULL){
251 gap_adv_next_ms += gap_adv_int_ms;
252 log_debug("Next adv: %" PRIu32, gap_adv_next_ms);
253 } else {
254 // queue again
255 btstack_linked_list_add_tail(&gap_connectable_advertisements, (void*) item);
256 // time to advertise again
257 log_debug("Start GAP ADV, %p", item);
258 gap_advertisements_set_params(ADVERTISING_INTERVAL_CONNECTABLE_MIN, ADVERTISING_INTERVAL_CONNECTABLE_MIN, gap_adv_type, gap_direct_address_typ, gap_direct_address, gap_channel_map, gap_filter_policy);
259 gap_advertisements_set_data(item->adv_length, item->adv_data);
260 gap_advertisements_enable(1);
261 adv_bearer_state = STATE_GAP;
262 adv_bearer_set_timeout(ADVERTISING_INTERVAL_CONNECTABLE_MIN_MS);
263 break;
264 }
265 }
266 }
267 if (adv_bearer_count > 0){
268 // schedule adv bearer message if enough time
269 // if ((gap_advertising_enabled) == 0 || ((int32_t)(gap_adv_next_ms - now) >= ADVERTISING_INTERVAL_NONCONNECTABLE_MIN_MS)){
270 log_debug("Send ADV Bearer message");
271 // configure LE advertisments: non-conn ind
272 gap_advertisements_set_params(ADVERTISING_INTERVAL_NONCONNECTABLE_MIN, ADVERTISING_INTERVAL_NONCONNECTABLE_MIN, 3, 0, null_addr, 0x07, 0);
273 gap_advertisements_set_data(adv_bearer_buffer_length, adv_bearer_buffer);
274 gap_advertisements_enable(1);
275 adv_bearer_state = STATE_BEARER;
276 adv_bearer_set_timeout(ADVERTISING_INTERVAL_NONCONNECTABLE_MIN_MS);
277 break;
278 // }
279 }
280 if (gap_advertising_enabled){
281 // use timer to wait for next adv
282 adv_bearer_set_timeout(gap_adv_next_ms - now);
283 }
284 break;
285 default:
286 break;
287 }
288 }
289
290 //
adv_bearer_prepare_message(const uint8_t * data,uint16_t data_len,uint8_t type,uint8_t count,uint16_t interval)291 static void adv_bearer_prepare_message(const uint8_t * data, uint16_t data_len, uint8_t type, uint8_t count, uint16_t interval){
292 btstack_assert(data_len <= (sizeof(adv_bearer_buffer)-2));
293 log_debug("adv bearer message, type 0x%x\n", type);
294 // prepare message
295 adv_bearer_buffer[0] = data_len+1;
296 adv_bearer_buffer[1] = type;
297 (void)memcpy(&adv_bearer_buffer[2], data, data_len);
298 adv_bearer_buffer_length = data_len + 2;
299
300 // setup trasmission schedule
301 adv_bearer_count = count;
302 adv_bearer_interval = interval;
303 }
304
305 //////
306
adv_bearer_request(message_type_id_t type_id)307 static void adv_bearer_request(message_type_id_t type_id){
308 request_can_send_now[type_id] = 1;
309 adv_bearer_emit_can_send_now();
310 }
311
adv_bearer_init(void)312 void adv_bearer_init(void){
313 // register for HCI Events
314 hci_event_callback_registration.callback = &adv_bearer_packet_handler;
315 hci_add_event_handler(&hci_event_callback_registration);
316 // idle
317 adv_bearer_state = STATE_IDLE;
318 memset(null_addr, 0, 6);
319 }
320
321 // adv bearer packet handler regisration
322
adv_bearer_register_for_network_pdu(btstack_packet_handler_t packet_handler)323 void adv_bearer_register_for_network_pdu(btstack_packet_handler_t packet_handler){
324 client_callbacks[MESH_NETWORK_ID] = packet_handler;
325 }
adv_bearer_register_for_beacon(btstack_packet_handler_t packet_handler)326 void adv_bearer_register_for_beacon(btstack_packet_handler_t packet_handler){
327 client_callbacks[MESH_BEACON_ID] = packet_handler;
328 }
adv_bearer_register_for_provisioning_pdu(btstack_packet_handler_t packet_handler)329 void adv_bearer_register_for_provisioning_pdu(btstack_packet_handler_t packet_handler){
330 client_callbacks[PB_ADV_ID] = packet_handler;
331 }
332
333 // adv bearer request to send
334
adv_bearer_request_can_send_now_for_network_pdu(void)335 void adv_bearer_request_can_send_now_for_network_pdu(void){
336 adv_bearer_request(MESH_NETWORK_ID);
337 }
adv_bearer_request_can_send_now_for_beacon(void)338 void adv_bearer_request_can_send_now_for_beacon(void){
339 adv_bearer_request(MESH_BEACON_ID);
340 }
adv_bearer_request_can_send_now_for_provisioning_pdu(void)341 void adv_bearer_request_can_send_now_for_provisioning_pdu(void){
342 adv_bearer_request(PB_ADV_ID);
343 }
344
345 // adv bearer send message
346
adv_bearer_send_network_pdu(const uint8_t * data,uint16_t data_len,uint8_t count,uint16_t interval)347 void adv_bearer_send_network_pdu(const uint8_t * data, uint16_t data_len, uint8_t count, uint16_t interval){
348 btstack_assert(data_len <= (sizeof(adv_bearer_buffer)-2));
349 adv_bearer_prepare_message(data, data_len, BLUETOOTH_DATA_TYPE_MESH_MESSAGE, count, interval);
350 adv_bearer_run();
351 }
adv_bearer_send_beacon(const uint8_t * data,uint16_t data_len)352 void adv_bearer_send_beacon(const uint8_t * data, uint16_t data_len){
353 btstack_assert(data_len <= (sizeof(adv_bearer_buffer)-2));
354 adv_bearer_prepare_message(data, data_len, BLUETOOTH_DATA_TYPE_MESH_BEACON, 3, 100);
355 adv_bearer_run();
356 }
adv_bearer_send_provisioning_pdu(const uint8_t * data,uint16_t data_len)357 void adv_bearer_send_provisioning_pdu(const uint8_t * data, uint16_t data_len){
358 btstack_assert(data_len <= (sizeof(adv_bearer_buffer)-2));
359 adv_bearer_prepare_message(data, data_len, BLUETOOTH_DATA_TYPE_PB_ADV, 3, 100);
360 adv_bearer_run();
361 }
362
363 // gap advertising
364
adv_bearer_advertisements_enable(int enabled)365 void adv_bearer_advertisements_enable(int enabled){
366 gap_advertising_enabled = enabled;
367 if (!gap_advertising_enabled) return;
368
369 // start right away
370 gap_adv_next_ms = btstack_run_loop_get_time_ms();
371 adv_bearer_run();
372 }
373
adv_bearer_advertisements_add_item(adv_bearer_connectable_advertisement_data_item_t * item)374 void adv_bearer_advertisements_add_item(adv_bearer_connectable_advertisement_data_item_t * item){
375 btstack_linked_list_add(&gap_connectable_advertisements, (void*) item);
376 }
377
adv_bearer_advertisements_remove_item(adv_bearer_connectable_advertisement_data_item_t * item)378 void adv_bearer_advertisements_remove_item(adv_bearer_connectable_advertisement_data_item_t * item){
379 btstack_linked_list_remove(&gap_connectable_advertisements, (void*) item);
380 }
381
adv_bearer_advertisements_set_params(uint16_t adv_int_min,uint16_t adv_int_max,uint8_t adv_type,uint8_t direct_address_typ,bd_addr_t direct_address,uint8_t channel_map,uint8_t filter_policy)382 void adv_bearer_advertisements_set_params(uint16_t adv_int_min, uint16_t adv_int_max, uint8_t adv_type,
383 uint8_t direct_address_typ, bd_addr_t direct_address, uint8_t channel_map, uint8_t filter_policy){
384
385 // assert adv_int_min/max >= 2 * ADVERTISING_INTERVAL_MIN
386
387 gap_adv_int_min = btstack_max(adv_int_min, 2 * ADVERTISING_INTERVAL_CONNECTABLE_MIN);
388 gap_adv_int_max = btstack_max(adv_int_max, 2 * ADVERTISING_INTERVAL_CONNECTABLE_MIN);
389 gap_adv_int_ms = gap_adv_int_min * 625 / 1000;
390 gap_adv_type = adv_type;
391 gap_direct_address_typ = direct_address_typ;
392 (void)memcpy(gap_direct_address, direct_address, 6);
393 gap_channel_map = channel_map;
394 gap_filter_policy = filter_policy;
395
396 log_info("GAP Adv interval %u ms", gap_adv_int_ms);
397 }
398