1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 #include <assert.h>
21 #include <string.h>
22 #include <stdio.h>
23 #include <errno.h>
24
25 #include "nimble/npl_shell.h"
26 #include "config/config.h"
27 #include "nimble/ble.h"
28 #include "host/ble_hs.h"
29 #include "host/util/util.h"
30
31 #include"patterns.h"
32
33 static uint8_t id_addr_type;
34
35 static void start_legacy_duration(uint8_t pattern, bool configure);
36 static void start_ext_max_events(uint8_t pattern, bool configure);
37
38 static int
start_ext_max_events_gap_event(struct ble_gap_event * event,void * arg)39 start_ext_max_events_gap_event(struct ble_gap_event *event, void *arg)
40 {
41 static uint8_t pattern = 1;
42
43 switch (event->type) {
44 case BLE_GAP_EVENT_ADV_COMPLETE:
45 break;
46 default:
47 assert(0);
48 return 0;
49 }
50
51 assert(event->adv_complete.instance == 4);
52 assert(event->adv_complete.reason == BLE_HS_ETIMEOUT);
53 assert(event->adv_complete.num_ext_adv_events == 10);
54
55 console_printf("instance %u terminated\n", event->adv_complete.instance);
56
57 pattern++;
58
59 start_ext_max_events(pattern, false);
60
61 return 0;
62 }
63
64 /* Starts advertising instance with 100 max events and changing adv data pattern
65 * and SID.
66 */
67 static void
start_ext_max_events(uint8_t pattern,bool configure)68 start_ext_max_events(uint8_t pattern, bool configure)
69 {
70 struct ble_gap_ext_adv_params params;
71 static uint8_t adv_data[600];
72 struct os_mbuf *data;
73 uint8_t instance = 4;
74 ble_addr_t addr;
75 int events = 10;
76 int rc;
77
78 if (configure) {
79 /* use defaults for non-set params */
80 memset (¶ms, 0, sizeof(params));
81
82 /* advertise using random addr */
83 params.own_addr_type = BLE_OWN_ADDR_RANDOM;
84
85 params.primary_phy = BLE_HCI_LE_PHY_1M;
86 params.secondary_phy = BLE_HCI_LE_PHY_1M;
87 params.tx_power = 127;
88 params.sid = pattern % 16;
89
90 /* allow larger interval, 400 * 0.625ms with 100 events will give up to
91 * ~2.5 seconds for instance
92 */
93 params.itvl_min = BLE_GAP_ADV_FAST_INTERVAL1_MIN;
94 params.itvl_max = 400;
95
96 /* configure instance 0 */
97 rc = ble_gap_ext_adv_configure(instance, ¶ms, NULL,
98 start_ext_max_events_gap_event, NULL);
99 assert (rc == 0);
100
101 /* set random (NRPA) address for instance */
102 rc = ble_hs_id_gen_rnd(1, &addr);
103 assert (rc == 0);
104
105 rc = ble_gap_ext_adv_set_addr(instance, &addr );
106 assert (rc == 0);
107 }
108
109 /* in this case both advertising data and scan response is allowed, but
110 * both are limited to 31 bytes each
111 */
112
113 /* get mbuf for adv data */
114 data = os_msys_get_pkthdr(600, 0);
115 assert(data);
116
117 memset(adv_data, pattern, sizeof(adv_data));
118
119 /* fill mbuf with adv data */
120 rc = os_mbuf_append(data, adv_data, 600);
121 assert(rc == 0);
122
123 rc = ble_gap_ext_adv_set_data(instance, data);
124 assert (rc == 0);
125
126 /* start advertising */
127 rc = ble_gap_ext_adv_start(instance, 0, events);
128 assert (rc == 0);
129
130 console_printf("instance %u started (PDUs with max events %d)\n",
131 instance, events);
132 }
133
134 static int
start_legacy_duration_gap_event(struct ble_gap_event * event,void * arg)135 start_legacy_duration_gap_event(struct ble_gap_event *event, void *arg)
136 {
137 static uint8_t pattern = 1;
138
139 switch (event->type) {
140 case BLE_GAP_EVENT_ADV_COMPLETE:
141 break;
142 default:
143 assert(0);
144 return 0;
145 }
146
147 assert(event->adv_complete.instance == 3);
148 assert(event->adv_complete.reason == BLE_HS_ETIMEOUT);
149
150 console_printf("instance %u terminated\n", event->adv_complete.instance);
151
152 pattern++;
153
154 start_legacy_duration(pattern, false);
155
156 return 0;
157 }
158
159 /* Starts advertising instance with 5sec timeout and changing adv data pattern
160 * and SID.
161 */
162 static void
start_legacy_duration(uint8_t pattern,bool configure)163 start_legacy_duration(uint8_t pattern, bool configure)
164 {
165 struct ble_gap_ext_adv_params params;
166 uint8_t adv_data[31];
167 struct os_mbuf *data;
168 uint8_t instance = 3;
169 ble_addr_t addr;
170 int duration = 500; /* 5seconds, 10ms units */
171 int rc;
172
173 if (configure) {
174 /* use defaults for non-set params */
175 memset (¶ms, 0, sizeof(params));
176
177 /* enable advertising using legacy PDUs */
178 params.legacy_pdu = 1;
179
180 /* advertise using random addr */
181 params.own_addr_type = BLE_OWN_ADDR_RANDOM;
182
183 params.primary_phy = BLE_HCI_LE_PHY_1M;
184 params.secondary_phy = BLE_HCI_LE_PHY_1M;
185 params.tx_power = 127;
186 params.sid = pattern % 16;
187
188 /* configure instance 0 */
189 rc = ble_gap_ext_adv_configure(instance, ¶ms, NULL,
190 start_legacy_duration_gap_event, NULL);
191 assert (rc == 0);
192
193 /* set random (NRPA) address for instance */
194 rc = ble_hs_id_gen_rnd(1, &addr);
195 assert (rc == 0);
196
197 rc = ble_gap_ext_adv_set_addr(instance, &addr );
198 assert (rc == 0);
199 }
200
201 /* in this case both advertising data and scan response is allowed, but
202 * both are limited to 31 bytes each
203 */
204
205 /* get mbuf for adv data */
206 data = os_msys_get_pkthdr(31, 0);
207 assert(data);
208
209 memset(adv_data, pattern, sizeof(adv_data));
210
211 /* fill mbuf with adv data */
212 rc = os_mbuf_append(data, adv_data, 31);
213 assert(rc == 0);
214
215 rc = ble_gap_ext_adv_set_data(instance, data);
216 assert (rc == 0);
217
218 /* start advertising */
219 rc = ble_gap_ext_adv_start(instance, duration, 0);
220 assert (rc == 0);
221
222 console_printf("instance %u started (legacy PDUs with duration %d)\n",
223 instance, duration);
224 }
225
226 /* this is simple non-connectable scannable instance using legacy PUDs that
227 * runs forever
228 */
229 static void
start_scannable_legacy_ext(void)230 start_scannable_legacy_ext(void)
231 {
232 struct ble_gap_ext_adv_params params;
233 struct os_mbuf *data;
234 uint8_t instance = 2;
235 ble_addr_t addr;
236 int rc;
237
238 /* use defaults for non-set params */
239 memset (¶ms, 0, sizeof(params));
240
241 /* enable scannable advertising using legacy PDUs */
242 params.scannable = 1;
243 params.legacy_pdu = 1;
244
245 /* advertise using random addr */
246 params.own_addr_type = BLE_OWN_ADDR_RANDOM;
247
248 params.primary_phy = BLE_HCI_LE_PHY_1M;
249 params.secondary_phy = BLE_HCI_LE_PHY_1M;
250 params.tx_power = 127;
251 params.sid = 2;
252
253 /* configure instance 0 */
254 rc = ble_gap_ext_adv_configure(instance, ¶ms, NULL, NULL, NULL);
255 assert (rc == 0);
256
257 /* set random (NRPA) address for instance */
258 rc = ble_hs_id_gen_rnd(1, &addr);
259 assert (rc == 0);
260
261 rc = ble_gap_ext_adv_set_addr(instance, &addr );
262 assert (rc == 0);
263
264 /* in this case both advertising data and scan response is allowed, but
265 * both are limited to 31 bytes each
266 */
267
268 /* get mbuf for adv data */
269 data = os_msys_get_pkthdr(31, 0);
270 assert(data);
271
272 /* fill mbuf with adv data */
273 rc = os_mbuf_append(data, ext_adv_pattern_1, 31);
274 assert(rc == 0);
275
276 rc = ble_gap_ext_adv_set_data(instance, data);
277 assert (rc == 0);
278
279 /* get mbuf for scan rsp data */
280 data = os_msys_get_pkthdr(31, 0);
281 assert(data);
282
283 /* fill mbuf with scan rsp data */
284 rc = os_mbuf_append(data, ext_adv_pattern_1 + 31, 31);
285 assert(rc == 0);
286
287 rc = ble_gap_ext_adv_rsp_set_data(instance, data);
288 assert (rc == 0);
289
290 /* start advertising */
291 rc = ble_gap_ext_adv_start(instance, 0, 0);
292 assert (rc == 0);
293
294 console_printf("instance %u started (scannable legacy PDUs)\n", instance);
295 }
296
297 static int
scannable_ext_gap_event(struct ble_gap_event * event,void * arg)298 scannable_ext_gap_event(struct ble_gap_event *event, void *arg)
299 {
300 switch (event->type) {
301 default:
302 break;
303 }
304
305 return 0;
306 }
307
308 /* this is simple scannable instance that runs forever
309 * TODO Get scan request notifications.
310 */
311 static void
start_scannable_ext(void)312 start_scannable_ext(void)
313 {
314 struct ble_gap_ext_adv_params params;
315 struct os_mbuf *data;
316 uint8_t instance = 1;
317 ble_addr_t addr;
318 int rc;
319
320 /* use defaults for non-set params */
321 memset (¶ms, 0, sizeof(params));
322
323 /* enable scannable advertising */
324 params.scannable = 1;
325
326 /* enable scan request notification */
327 params.scan_req_notif = 1;
328
329 /* advertise using random addr */
330 params.own_addr_type = BLE_OWN_ADDR_RANDOM;
331
332 params.primary_phy = BLE_HCI_LE_PHY_1M;
333 params.secondary_phy = BLE_HCI_LE_PHY_1M;
334 params.tx_power = 127;
335 params.sid = 1;
336
337 /* configure instance 0 */
338 rc = ble_gap_ext_adv_configure(instance, ¶ms, NULL,
339 scannable_ext_gap_event, NULL);
340 assert (rc == 0);
341
342 /* set random (NRPA) address for instance */
343 rc = ble_hs_id_gen_rnd(1, &addr);
344 assert (rc == 0);
345
346 rc = ble_gap_ext_adv_set_addr(instance, &addr );
347 assert (rc == 0);
348
349 /* in this case only scan response is allowed */
350
351 /* get mbuf for scan rsp data */
352 data = os_msys_get_pkthdr(sizeof(ext_adv_pattern_1), 0);
353 assert(data);
354
355 /* fill mbuf with scan rsp data */
356 rc = os_mbuf_append(data, ext_adv_pattern_1, sizeof(ext_adv_pattern_1));
357 assert(rc == 0);
358
359 rc = ble_gap_ext_adv_rsp_set_data(instance, data);
360 assert (rc == 0);
361
362 /* start advertising */
363 rc = ble_gap_ext_adv_start(instance, 0, 0);
364 assert (rc == 0);
365
366 console_printf("instance %u started (scannable)\n", instance);
367 }
368
369 /* this is simple non-connectable instance that runs forever */
370 static void
start_non_connectable_ext(void)371 start_non_connectable_ext(void)
372 {
373 struct ble_gap_ext_adv_params params;
374 struct os_mbuf *data;
375 uint8_t instance = 0;
376 int rc;
377
378 /* use defaults for non-set params */
379 memset (¶ms, 0, sizeof(params));
380
381 /* advertise using ID addr */
382 params.own_addr_type = id_addr_type;
383
384 params.primary_phy = BLE_HCI_LE_PHY_1M;
385 params.secondary_phy = BLE_HCI_LE_PHY_1M;
386 params.tx_power = 127;
387 params.sid = 0;
388
389 /* configure instance */
390 rc = ble_gap_ext_adv_configure(instance, ¶ms, NULL, NULL, NULL);
391 assert (rc == 0);
392
393 /* in this case only advertisign data is allowed */
394
395 /* get mbuf for adv data */
396 data = os_msys_get_pkthdr(sizeof(ext_adv_pattern_1), 0);
397 assert(data);
398
399 /* fill mbuf with adv data */
400 rc = os_mbuf_append(data, ext_adv_pattern_1, sizeof(ext_adv_pattern_1));
401 assert(rc == 0);
402
403 rc = ble_gap_ext_adv_set_data(instance, data);
404 assert (rc == 0);
405
406 /* start advertising */
407 rc = ble_gap_ext_adv_start(instance, 0, 0);
408 assert (rc == 0);
409
410 console_printf("instance %u started (non-con non-scan)\n", instance);
411 }
412
413 static void
on_sync(void)414 on_sync(void)
415 {
416 int rc;
417
418 console_printf("Synced, starting advertising\n");
419
420 /* Make sure we have proper identity address set (public preferred) */
421 rc = ble_hs_util_ensure_addr(0);
422 assert(rc == 0);
423
424 /* configure global address */
425 rc = ble_hs_id_infer_auto(0, &id_addr_type);
426 assert(rc == 0);
427
428 start_non_connectable_ext();
429
430 start_scannable_ext();
431
432 start_scannable_legacy_ext();
433
434 start_legacy_duration(0, true);
435
436 start_ext_max_events(0, true);
437 }
438
439 /*
440 * main
441 *
442 * The main task for the project. This function initializes the packages,
443 * then starts serving events from default event queue.
444 *
445 * @return int NOTE: this function should never return!
446 */
ext_advertiser_entry(void)447 int ext_advertiser_entry(void)
448 {
449 console_printf("Extended Advertising sample application\n");
450
451 /* Set sync callback */
452 ble_hs_cfg.sync_cb = on_sync;
453
454 /* startup bluetooth host stack*/
455 ble_hs_thread_startup();
456
457 return 0;
458 }
459 MSH_CMD_EXPORT_ALIAS(ext_advertiser_entry, ext_advertiser, "bluetooth external advertiser sample");
460