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 #include "log/log.h"
25 #include "stats/stats.h"
26 #include "btshell.h"
27 #include "cmd.h"
28
29 /* BLE */
30 #include "nimble/ble.h"
31 #include "nimble/nimble_opt.h"
32 #include "nimble/ble_hci_trans.h"
33 #include "host/ble_hs.h"
34 #include "host/ble_hs_adv.h"
35 #include "host/ble_uuid.h"
36 #include "host/ble_att.h"
37 #include "host/ble_gap.h"
38 #include "host/ble_gatt.h"
39 #include "host/ble_store.h"
40 #include "host/ble_sm.h"
41
42 /* Mandatory services. */
43 #include "services/gap/ble_svc_gap.h"
44 #include "services/gatt/ble_svc_gatt.h"
45
46 /* XXX: An app should not include private headers from a library. The btshell
47 * app uses some of nimble's internal details for logging.
48 */
49 #include "../src/ble_hs_conn_priv.h"
50 #include "../src/ble_hs_atomic_priv.h"
51 #include "../src/ble_hs_hci_priv.h"
52
53 #include "nimble/npl_shell.h"
54
55 #if MYNEWT_VAL(BLE_ROLE_CENTRAL)
56 #define BTSHELL_MAX_SVCS 32
57 #define BTSHELL_MAX_CHRS 64
58 #define BTSHELL_MAX_DSCS 64
59 #else
60 #define BTSHELL_MAX_SVCS 1
61 #define BTSHELL_MAX_CHRS 1
62 #define BTSHELL_MAX_DSCS 1
63 #endif
64
65 #if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
66 #define BTSHELL_COC_MTU (256)
67 /* We use same pool for incoming and outgoing sdu */
68 #define BTSHELL_COC_BUF_COUNT (3 * MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM))
69
70 #define INT_TO_PTR(x) (void *)((intptr_t)(x))
71 #define PTR_TO_INT(x) (int) ((intptr_t)(x))
72 #endif
73
74 bssnz_t struct btshell_conn btshell_conns[MYNEWT_VAL(BLE_MAX_CONNECTIONS)];
75 int btshell_num_conns;
76
77 static os_membuf_t btshell_svc_mem[
78 OS_MEMPOOL_SIZE(BTSHELL_MAX_SVCS, sizeof(struct btshell_svc))
79 ];
80 static struct os_mempool btshell_svc_pool;
81
82 static os_membuf_t btshell_chr_mem[
83 OS_MEMPOOL_SIZE(BTSHELL_MAX_CHRS, sizeof(struct btshell_chr))
84 ];
85 static struct os_mempool btshell_chr_pool;
86
87 static os_membuf_t btshell_dsc_mem[
88 OS_MEMPOOL_SIZE(BTSHELL_MAX_DSCS, sizeof(struct btshell_dsc))
89 ];
90 static struct os_mempool btshell_dsc_pool;
91
92 #if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
93 static os_membuf_t btshell_coc_conn_mem[
94 OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM),
95 sizeof(struct btshell_l2cap_coc))
96 ];
97 static struct os_mempool btshell_coc_conn_pool;
98
99 static os_membuf_t btshell_sdu_coc_mem[
100 OS_MEMPOOL_SIZE(BTSHELL_COC_BUF_COUNT, BTSHELL_COC_MTU)
101 ];
102 struct os_mbuf_pool sdu_os_mbuf_pool;
103 static struct os_mempool sdu_coc_mbuf_mempool;
104 #endif
105
106 static struct ble_npl_callout btshell_tx_timer;
107 struct btshell_tx_data_s
108 {
109 uint16_t tx_num;
110 uint16_t tx_rate;
111 uint16_t tx_handle;
112 uint16_t tx_len;
113 };
114 static struct btshell_tx_data_s btshell_tx_data;
115 int btshell_full_disc_prev_chr_val;
116
117 #define XSTR(s) STR(s)
118 #ifndef STR
119 #define STR(s) #s
120 #endif
121
122
123 #ifdef DEVICE_NAME
124 #define BTSHELL_AUTO_DEVICE_NAME XSTR(DEVICE_NAME)
125 #else
126 #define BTSHELL_AUTO_DEVICE_NAME ""
127 #endif
128
129 #if MYNEWT_VAL(BLE_EXT_ADV)
130 struct {
131 bool restart;
132 uint16_t conn_handle;
133 } ext_adv_restart[BLE_ADV_INSTANCES];
134 #endif
135
136 static struct {
137 bool restart;
138 uint8_t own_addr_type;
139 ble_addr_t direct_addr;
140 int32_t duration_ms;
141 struct ble_gap_adv_params params;
142 } adv_params;
143
144 static void
btshell_print_error(char * msg,uint16_t conn_handle,const struct ble_gatt_error * error)145 btshell_print_error(char *msg, uint16_t conn_handle,
146 const struct ble_gatt_error *error)
147 {
148 if (msg == NULL) {
149 msg = "ERROR";
150 }
151
152 console_printf("%s: conn_handle=%d status=%d att_handle=%d\n",
153 msg, conn_handle, error->status, error->att_handle);
154 }
155
156 static void
btshell_print_adv_fields(const struct ble_hs_adv_fields * fields)157 btshell_print_adv_fields(const struct ble_hs_adv_fields *fields)
158 {
159 uint8_t *u8p;
160 int i;
161
162 if (fields->flags != 0) {
163 console_printf(" flags=0x%02x:\n", fields->flags);
164
165 if (!(fields->flags & BLE_HS_ADV_F_DISC_LTD) &&
166 !(fields->flags & BLE_HS_ADV_F_DISC_GEN)) {
167 console_printf(" Non-discoverable mode\n");
168 }
169
170 if (fields->flags & BLE_HS_ADV_F_DISC_LTD) {
171 console_printf(" Limited discoverable mode\n");
172 }
173
174 if (fields->flags & BLE_HS_ADV_F_DISC_GEN) {
175 console_printf(" General discoverable mode\n");
176 }
177
178 if (fields->flags & BLE_HS_ADV_F_BREDR_UNSUP) {
179 console_printf(" BR/EDR not supported\n");
180 }
181 }
182
183 if (fields->uuids16 != NULL) {
184 console_printf(" uuids16(%scomplete)=",
185 fields->uuids16_is_complete ? "" : "in");
186 for (i = 0; i < fields->num_uuids16; i++) {
187 print_uuid(&fields->uuids16[i].u);
188 console_printf(" ");
189 }
190 console_printf("\n");
191 }
192
193 if (fields->uuids32 != NULL) {
194 console_printf(" uuids32(%scomplete)=",
195 fields->uuids32_is_complete ? "" : "in");
196 for (i = 0; i < fields->num_uuids32; i++) {
197 print_uuid(&fields->uuids32[i].u);
198 console_printf(" ");
199 }
200 console_printf("\n");
201 }
202
203 if (fields->uuids128 != NULL) {
204 console_printf(" uuids128(%scomplete)=",
205 fields->uuids128_is_complete ? "" : "in");
206 for (i = 0; i < fields->num_uuids128; i++) {
207 print_uuid(&fields->uuids128[i].u);
208 console_printf(" ");
209 }
210 console_printf("\n");
211 }
212
213 if (fields->name != NULL) {
214 console_printf(" name(%scomplete)=",
215 fields->name_is_complete ? "" : "in");
216 console_write((char *)fields->name, fields->name_len);
217 console_printf("\n");
218 }
219
220 if (fields->tx_pwr_lvl_is_present) {
221 console_printf(" tx_pwr_lvl=%d\n", fields->tx_pwr_lvl);
222 }
223
224 if (fields->slave_itvl_range != NULL) {
225 console_printf(" slave_itvl_range=");
226 print_bytes(fields->slave_itvl_range,
227 BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN);
228 console_printf("\n");
229 }
230
231 if (fields->svc_data_uuid16 != NULL) {
232 console_printf(" svc_data_uuid16=");
233 print_bytes(fields->svc_data_uuid16,
234 fields->svc_data_uuid16_len);
235 console_printf("\n");
236 }
237
238 if (fields->public_tgt_addr != NULL) {
239 console_printf(" public_tgt_addr=");
240 u8p = fields->public_tgt_addr;
241 for (i = 0; i < fields->num_public_tgt_addrs; i++) {
242 print_addr(u8p);
243 u8p += BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN;
244 }
245 console_printf("\n");
246 }
247
248 if (fields->appearance_is_present) {
249 console_printf(" appearance=0x%04x\n", fields->appearance);
250 }
251
252 if (fields->adv_itvl_is_present) {
253 console_printf(" adv_itvl=0x%04x\n", fields->adv_itvl);
254 }
255
256 if (fields->svc_data_uuid32 != NULL) {
257 console_printf(" svc_data_uuid32=");
258 print_bytes(fields->svc_data_uuid32,
259 fields->svc_data_uuid32_len);
260 console_printf("\n");
261 }
262
263 if (fields->svc_data_uuid128 != NULL) {
264 console_printf(" svc_data_uuid128=");
265 print_bytes(fields->svc_data_uuid128,
266 fields->svc_data_uuid128_len);
267 console_printf("\n");
268 }
269
270 if (fields->uri != NULL) {
271 console_printf(" uri=");
272 print_bytes(fields->uri, fields->uri_len);
273 console_printf("\n");
274 }
275
276 if (fields->mfg_data != NULL) {
277 console_printf(" mfg_data=");
278 print_bytes(fields->mfg_data, fields->mfg_data_len);
279 console_printf("\n");
280 }
281 }
282
283 static int
btshell_conn_find_idx(uint16_t handle)284 btshell_conn_find_idx(uint16_t handle)
285 {
286 int i;
287
288 for (i = 0; i < btshell_num_conns; i++) {
289 if (btshell_conns[i].handle == handle) {
290 return i;
291 }
292 }
293
294 return -1;
295 }
296
297 static struct btshell_conn *
btshell_conn_find(uint16_t handle)298 btshell_conn_find(uint16_t handle)
299 {
300 int idx;
301
302 idx = btshell_conn_find_idx(handle);
303 if (idx == -1) {
304 return NULL;
305 } else {
306 return btshell_conns + idx;
307 }
308 }
309
310 static struct btshell_svc *
btshell_svc_find_prev(struct btshell_conn * conn,uint16_t svc_start_handle)311 btshell_svc_find_prev(struct btshell_conn *conn, uint16_t svc_start_handle)
312 {
313 struct btshell_svc *prev;
314 struct btshell_svc *svc;
315
316 prev = NULL;
317 SLIST_FOREACH(svc, &conn->svcs, next) {
318 if (svc->svc.start_handle >= svc_start_handle) {
319 break;
320 }
321
322 prev = svc;
323 }
324
325 return prev;
326 }
327
328 static struct btshell_svc *
btshell_svc_find(struct btshell_conn * conn,uint16_t svc_start_handle,struct btshell_svc ** out_prev)329 btshell_svc_find(struct btshell_conn *conn, uint16_t svc_start_handle,
330 struct btshell_svc **out_prev)
331 {
332 struct btshell_svc *prev;
333 struct btshell_svc *svc;
334
335 prev = btshell_svc_find_prev(conn, svc_start_handle);
336 if (prev == NULL) {
337 svc = SLIST_FIRST(&conn->svcs);
338 } else {
339 svc = SLIST_NEXT(prev, next);
340 }
341
342 if (svc != NULL && svc->svc.start_handle != svc_start_handle) {
343 svc = NULL;
344 }
345
346 if (out_prev != NULL) {
347 *out_prev = prev;
348 }
349 return svc;
350 }
351
352 static struct btshell_svc *
btshell_svc_find_range(struct btshell_conn * conn,uint16_t attr_handle)353 btshell_svc_find_range(struct btshell_conn *conn, uint16_t attr_handle)
354 {
355 struct btshell_svc *svc;
356
357 SLIST_FOREACH(svc, &conn->svcs, next) {
358 if (svc->svc.start_handle <= attr_handle &&
359 svc->svc.end_handle >= attr_handle) {
360
361 return svc;
362 }
363 }
364
365 return NULL;
366 }
367
368 static void
btshell_chr_delete(struct btshell_chr * chr)369 btshell_chr_delete(struct btshell_chr *chr)
370 {
371 struct btshell_dsc *dsc;
372
373 while ((dsc = SLIST_FIRST(&chr->dscs)) != NULL) {
374 SLIST_REMOVE_HEAD(&chr->dscs, next);
375 os_memblock_put(&btshell_dsc_pool, dsc);
376 }
377
378 os_memblock_put(&btshell_chr_pool, chr);
379 }
380
381 static void
btshell_svc_delete(struct btshell_svc * svc)382 btshell_svc_delete(struct btshell_svc *svc)
383 {
384 struct btshell_chr *chr;
385
386 while ((chr = SLIST_FIRST(&svc->chrs)) != NULL) {
387 SLIST_REMOVE_HEAD(&svc->chrs, next);
388 btshell_chr_delete(chr);
389 }
390
391 os_memblock_put(&btshell_svc_pool, svc);
392 }
393
394 static struct btshell_svc *
btshell_svc_add(uint16_t conn_handle,const struct ble_gatt_svc * gatt_svc)395 btshell_svc_add(uint16_t conn_handle, const struct ble_gatt_svc *gatt_svc)
396 {
397 struct btshell_conn *conn;
398 struct btshell_svc *prev;
399 struct btshell_svc *svc;
400
401 conn = btshell_conn_find(conn_handle);
402 if (conn == NULL) {
403 MODLOG_DFLT(DEBUG, "RECEIVED SERVICE FOR UNKNOWN CONNECTION; "
404 "HANDLE=%d\n",
405 conn_handle);
406 return NULL;
407 }
408
409 svc = btshell_svc_find(conn, gatt_svc->start_handle, &prev);
410 if (svc != NULL) {
411 /* Service already discovered. */
412 return svc;
413 }
414
415 svc = os_memblock_get(&btshell_svc_pool);
416 if (svc == NULL) {
417 MODLOG_DFLT(DEBUG, "OOM WHILE DISCOVERING SERVICE\n");
418 return NULL;
419 }
420 memset(svc, 0, sizeof *svc);
421
422 svc->svc = *gatt_svc;
423 SLIST_INIT(&svc->chrs);
424
425 if (prev == NULL) {
426 SLIST_INSERT_HEAD(&conn->svcs, svc, next);
427 } else {
428 SLIST_INSERT_AFTER(prev, svc, next);
429 }
430
431 return svc;
432 }
433
434 static struct btshell_chr *
btshell_chr_find_prev(const struct btshell_svc * svc,uint16_t chr_val_handle)435 btshell_chr_find_prev(const struct btshell_svc *svc, uint16_t chr_val_handle)
436 {
437 struct btshell_chr *prev;
438 struct btshell_chr *chr;
439
440 prev = NULL;
441 SLIST_FOREACH(chr, &svc->chrs, next) {
442 if (chr->chr.val_handle >= chr_val_handle) {
443 break;
444 }
445
446 prev = chr;
447 }
448
449 return prev;
450 }
451
452 static struct btshell_chr *
btshell_chr_find(const struct btshell_svc * svc,uint16_t chr_val_handle,struct btshell_chr ** out_prev)453 btshell_chr_find(const struct btshell_svc *svc, uint16_t chr_val_handle,
454 struct btshell_chr **out_prev)
455 {
456 struct btshell_chr *prev;
457 struct btshell_chr *chr;
458
459 prev = btshell_chr_find_prev(svc, chr_val_handle);
460 if (prev == NULL) {
461 chr = SLIST_FIRST(&svc->chrs);
462 } else {
463 chr = SLIST_NEXT(prev, next);
464 }
465
466 if (chr != NULL && chr->chr.val_handle != chr_val_handle) {
467 chr = NULL;
468 }
469
470 if (out_prev != NULL) {
471 *out_prev = prev;
472 }
473 return chr;
474 }
475
476 static struct btshell_chr *
btshell_chr_add(uint16_t conn_handle,uint16_t svc_start_handle,const struct ble_gatt_chr * gatt_chr)477 btshell_chr_add(uint16_t conn_handle, uint16_t svc_start_handle,
478 const struct ble_gatt_chr *gatt_chr)
479 {
480 struct btshell_conn *conn;
481 struct btshell_chr *prev;
482 struct btshell_chr *chr;
483 struct btshell_svc *svc;
484
485 conn = btshell_conn_find(conn_handle);
486 if (conn == NULL) {
487 MODLOG_DFLT(DEBUG, "RECEIVED SERVICE FOR UNKNOWN CONNECTION; "
488 "HANDLE=%d\n",
489 conn_handle);
490 return NULL;
491 }
492
493 svc = btshell_svc_find(conn, svc_start_handle, NULL);
494 if (svc == NULL) {
495 MODLOG_DFLT(DEBUG, "CAN'T FIND SERVICE FOR DISCOVERED CHR; HANDLE=%d\n",
496 conn_handle);
497 return NULL;
498 }
499
500 chr = btshell_chr_find(svc, gatt_chr->val_handle, &prev);
501 if (chr != NULL) {
502 /* Characteristic already discovered. */
503 return chr;
504 }
505
506 chr = os_memblock_get(&btshell_chr_pool);
507 if (chr == NULL) {
508 MODLOG_DFLT(DEBUG, "OOM WHILE DISCOVERING CHARACTERISTIC\n");
509 return NULL;
510 }
511 memset(chr, 0, sizeof *chr);
512
513 chr->chr = *gatt_chr;
514
515 if (prev == NULL) {
516 SLIST_INSERT_HEAD(&svc->chrs, chr, next);
517 } else {
518 SLIST_NEXT(prev, next) = chr;
519 }
520
521 return chr;
522 }
523
524 static struct btshell_dsc *
btshell_dsc_find_prev(const struct btshell_chr * chr,uint16_t dsc_handle)525 btshell_dsc_find_prev(const struct btshell_chr *chr, uint16_t dsc_handle)
526 {
527 struct btshell_dsc *prev;
528 struct btshell_dsc *dsc;
529
530 prev = NULL;
531 SLIST_FOREACH(dsc, &chr->dscs, next) {
532 if (dsc->dsc.handle >= dsc_handle) {
533 break;
534 }
535
536 prev = dsc;
537 }
538
539 return prev;
540 }
541
542 static struct btshell_dsc *
btshell_dsc_find(const struct btshell_chr * chr,uint16_t dsc_handle,struct btshell_dsc ** out_prev)543 btshell_dsc_find(const struct btshell_chr *chr, uint16_t dsc_handle,
544 struct btshell_dsc **out_prev)
545 {
546 struct btshell_dsc *prev;
547 struct btshell_dsc *dsc;
548
549 prev = btshell_dsc_find_prev(chr, dsc_handle);
550 if (prev == NULL) {
551 dsc = SLIST_FIRST(&chr->dscs);
552 } else {
553 dsc = SLIST_NEXT(prev, next);
554 }
555
556 if (dsc != NULL && dsc->dsc.handle != dsc_handle) {
557 dsc = NULL;
558 }
559
560 if (out_prev != NULL) {
561 *out_prev = prev;
562 }
563 return dsc;
564 }
565
566 static struct btshell_dsc *
btshell_dsc_add(uint16_t conn_handle,uint16_t chr_val_handle,const struct ble_gatt_dsc * gatt_dsc)567 btshell_dsc_add(uint16_t conn_handle, uint16_t chr_val_handle,
568 const struct ble_gatt_dsc *gatt_dsc)
569 {
570 struct btshell_conn *conn;
571 struct btshell_dsc *prev;
572 struct btshell_dsc *dsc;
573 struct btshell_svc *svc;
574 struct btshell_chr *chr;
575
576 conn = btshell_conn_find(conn_handle);
577 if (conn == NULL) {
578 MODLOG_DFLT(DEBUG, "RECEIVED SERVICE FOR UNKNOWN CONNECTION; "
579 "HANDLE=%d\n",
580 conn_handle);
581 return NULL;
582 }
583
584 svc = btshell_svc_find_range(conn, chr_val_handle);
585 if (svc == NULL) {
586 MODLOG_DFLT(DEBUG, "CAN'T FIND SERVICE FOR DISCOVERED DSC; HANDLE=%d\n",
587 conn_handle);
588 return NULL;
589 }
590
591 chr = btshell_chr_find(svc, chr_val_handle, NULL);
592 if (chr == NULL) {
593 MODLOG_DFLT(DEBUG, "CAN'T FIND CHARACTERISTIC FOR DISCOVERED DSC; "
594 "HANDLE=%d\n",
595 conn_handle);
596 return NULL;
597 }
598
599 dsc = btshell_dsc_find(chr, gatt_dsc->handle, &prev);
600 if (dsc != NULL) {
601 /* Descriptor already discovered. */
602 return dsc;
603 }
604
605 dsc = os_memblock_get(&btshell_dsc_pool);
606 if (dsc == NULL) {
607 console_printf("OOM WHILE DISCOVERING DESCRIPTOR\n");
608 return NULL;
609 }
610 memset(dsc, 0, sizeof *dsc);
611
612 dsc->dsc = *gatt_dsc;
613
614 if (prev == NULL) {
615 SLIST_INSERT_HEAD(&chr->dscs, dsc, next);
616 } else {
617 SLIST_NEXT(prev, next) = dsc;
618 }
619
620 return dsc;
621 }
622
623 static struct btshell_conn *
btshell_conn_add(struct ble_gap_conn_desc * desc)624 btshell_conn_add(struct ble_gap_conn_desc *desc)
625 {
626 struct btshell_conn *conn;
627
628 assert(btshell_num_conns < MYNEWT_VAL(BLE_MAX_CONNECTIONS));
629
630 conn = btshell_conns + btshell_num_conns;
631 btshell_num_conns++;
632
633 conn->handle = desc->conn_handle;
634 SLIST_INIT(&conn->svcs);
635 SLIST_INIT(&conn->coc_list);
636
637 return conn;
638 }
639
640 static void
btshell_conn_delete_idx(int idx)641 btshell_conn_delete_idx(int idx)
642 {
643 struct btshell_conn *conn;
644 struct btshell_svc *svc;
645
646 assert(idx >= 0 && idx < btshell_num_conns);
647
648 conn = btshell_conns + idx;
649 while ((svc = SLIST_FIRST(&conn->svcs)) != NULL) {
650 SLIST_REMOVE_HEAD(&conn->svcs, next);
651 btshell_svc_delete(svc);
652 }
653
654 /* This '#if' is not strictly necessary. It is here to prevent a spurious
655 * warning from being reported.
656 */
657 #if MYNEWT_VAL(BLE_MAX_CONNECTIONS) > 1
658 int i;
659 for (i = idx + 1; i < btshell_num_conns; i++) {
660 btshell_conns[i - 1] = btshell_conns[i];
661 }
662 #endif
663
664 btshell_num_conns--;
665 }
666
667 static int
btshell_on_mtu(uint16_t conn_handle,const struct ble_gatt_error * error,uint16_t mtu,void * arg)668 btshell_on_mtu(uint16_t conn_handle, const struct ble_gatt_error *error,
669 uint16_t mtu, void *arg)
670 {
671 switch (error->status) {
672 case 0:
673 console_printf("mtu exchange complete: conn_handle=%d mtu=%d\n",
674 conn_handle, mtu);
675 break;
676
677 default:
678 btshell_print_error(NULL, conn_handle, error);
679 break;
680 }
681
682 return 0;
683 }
684
685 static void
btshell_full_disc_complete(int rc)686 btshell_full_disc_complete(int rc)
687 {
688 console_printf("full discovery complete; rc=%d\n", rc);
689 btshell_full_disc_prev_chr_val = 0;
690 }
691
692 static void
btshell_disc_full_dscs(uint16_t conn_handle)693 btshell_disc_full_dscs(uint16_t conn_handle)
694 {
695 struct btshell_conn *conn;
696 struct btshell_chr *chr;
697 struct btshell_svc *svc;
698 int rc;
699
700 conn = btshell_conn_find(conn_handle);
701 if (conn == NULL) {
702 MODLOG_DFLT(DEBUG, "Failed to discover descriptors for conn=%d; "
703 "not connected\n", conn_handle);
704 btshell_full_disc_complete(BLE_HS_ENOTCONN);
705 return;
706 }
707
708 SLIST_FOREACH(svc, &conn->svcs, next) {
709 SLIST_FOREACH(chr, &svc->chrs, next) {
710 if (!chr_is_empty(svc, chr) &&
711 SLIST_EMPTY(&chr->dscs) &&
712 btshell_full_disc_prev_chr_val <= chr->chr.def_handle) {
713
714 rc = btshell_disc_all_dscs(conn_handle,
715 chr->chr.val_handle,
716 chr_end_handle(svc, chr));
717 if (rc != 0) {
718 btshell_full_disc_complete(rc);
719 }
720
721 btshell_full_disc_prev_chr_val = chr->chr.val_handle;
722 return;
723 }
724 }
725 }
726
727 /* All descriptors discovered. */
728 btshell_full_disc_complete(0);
729 }
730
731 static void
btshell_disc_full_chrs(uint16_t conn_handle)732 btshell_disc_full_chrs(uint16_t conn_handle)
733 {
734 struct btshell_conn *conn;
735 struct btshell_svc *svc;
736 int rc;
737
738 conn = btshell_conn_find(conn_handle);
739 if (conn == NULL) {
740 MODLOG_DFLT(DEBUG, "Failed to discover characteristics for conn=%d; "
741 "not connected\n", conn_handle);
742 btshell_full_disc_complete(BLE_HS_ENOTCONN);
743 return;
744 }
745
746 SLIST_FOREACH(svc, &conn->svcs, next) {
747 if (!svc_is_empty(svc) && SLIST_EMPTY(&svc->chrs)) {
748 rc = btshell_disc_all_chrs(conn_handle, svc->svc.start_handle,
749 svc->svc.end_handle);
750 if (rc != 0) {
751 btshell_full_disc_complete(rc);
752 }
753 return;
754 }
755 }
756
757 /* All characteristics discovered. */
758 btshell_disc_full_dscs(conn_handle);
759 }
760
761 static int
btshell_on_disc_s(uint16_t conn_handle,const struct ble_gatt_error * error,const struct ble_gatt_svc * service,void * arg)762 btshell_on_disc_s(uint16_t conn_handle, const struct ble_gatt_error *error,
763 const struct ble_gatt_svc *service, void *arg)
764 {
765 switch (error->status) {
766 case 0:
767 btshell_svc_add(conn_handle, service);
768 break;
769
770 case BLE_HS_EDONE:
771 console_printf("service discovery successful\n");
772 if (btshell_full_disc_prev_chr_val > 0) {
773 btshell_disc_full_chrs(conn_handle);
774 }
775 break;
776
777 default:
778 btshell_print_error(NULL, conn_handle, error);
779 break;
780 }
781
782 return 0;
783 }
784
785 static int
btshell_on_disc_c(uint16_t conn_handle,const struct ble_gatt_error * error,const struct ble_gatt_chr * chr,void * arg)786 btshell_on_disc_c(uint16_t conn_handle, const struct ble_gatt_error *error,
787 const struct ble_gatt_chr *chr, void *arg)
788 {
789 intptr_t svc_start_handle;
790
791 svc_start_handle = (intptr_t)arg;
792
793 switch (error->status) {
794 case 0:
795 btshell_chr_add(conn_handle, svc_start_handle, chr);
796 break;
797
798 case BLE_HS_EDONE:
799 console_printf("characteristic discovery successful\n");
800 if (btshell_full_disc_prev_chr_val > 0) {
801 btshell_disc_full_chrs(conn_handle);
802 }
803 break;
804
805 default:
806 btshell_print_error(NULL, conn_handle, error);
807 break;
808 }
809
810 return 0;
811 }
812
813 static int
btshell_on_disc_d(uint16_t conn_handle,const struct ble_gatt_error * error,uint16_t chr_val_handle,const struct ble_gatt_dsc * dsc,void * arg)814 btshell_on_disc_d(uint16_t conn_handle, const struct ble_gatt_error *error,
815 uint16_t chr_val_handle, const struct ble_gatt_dsc *dsc,
816 void *arg)
817 {
818 switch (error->status) {
819 case 0:
820 btshell_dsc_add(conn_handle, chr_val_handle, dsc);
821 break;
822
823 case BLE_HS_EDONE:
824 console_printf("descriptor discovery successful\n");
825 if (btshell_full_disc_prev_chr_val > 0) {
826 btshell_disc_full_dscs(conn_handle);
827 }
828 break;
829
830 default:
831 btshell_print_error(NULL, conn_handle, error);
832 break;
833 }
834
835 return 0;
836 }
837
838 static int
btshell_on_read(uint16_t conn_handle,const struct ble_gatt_error * error,struct ble_gatt_attr * attr,void * arg)839 btshell_on_read(uint16_t conn_handle, const struct ble_gatt_error *error,
840 struct ble_gatt_attr *attr, void *arg)
841 {
842 switch (error->status) {
843 case 0:
844 console_printf("characteristic read; conn_handle=%d "
845 "attr_handle=%d len=%d value=", conn_handle,
846 attr->handle, OS_MBUF_PKTLEN(attr->om));
847 print_mbuf(attr->om);
848 console_printf("\n");
849 break;
850
851 case BLE_HS_EDONE:
852 console_printf("characteristic read complete\n");
853 break;
854
855 default:
856 btshell_print_error(NULL, conn_handle, error);
857 break;
858 }
859
860 return 0;
861 }
862
863 static int
btshell_on_write(uint16_t conn_handle,const struct ble_gatt_error * error,struct ble_gatt_attr * attr,void * arg)864 btshell_on_write(uint16_t conn_handle, const struct ble_gatt_error *error,
865 struct ble_gatt_attr *attr, void *arg)
866 {
867 switch (error->status) {
868 case 0:
869 console_printf("characteristic write complete; conn_handle=%d "
870 "attr_handle=%d\n", conn_handle, attr->handle);
871 break;
872
873 default:
874 btshell_print_error(NULL, conn_handle, error);
875 break;
876 }
877
878 return 0;
879 }
880
881 static int
btshell_on_write_reliable(uint16_t conn_handle,const struct ble_gatt_error * error,struct ble_gatt_attr * attrs,uint8_t num_attrs,void * arg)882 btshell_on_write_reliable(uint16_t conn_handle,
883 const struct ble_gatt_error *error,
884 struct ble_gatt_attr *attrs, uint8_t num_attrs,
885 void *arg)
886 {
887 int i;
888
889 switch (error->status) {
890 case 0:
891 console_printf("characteristic write reliable complete; "
892 "conn_handle=%d", conn_handle);
893
894 for (i = 0; i < num_attrs; i++) {
895 console_printf(" attr_handle=%d len=%d value=", attrs[i].handle,
896 OS_MBUF_PKTLEN(attrs[i].om));
897 print_mbuf(attrs[i].om);
898 }
899 console_printf("\n");
900 break;
901
902 default:
903 btshell_print_error(NULL, conn_handle, error);
904 break;
905 }
906
907 return 0;
908 }
909
910 static void
btshell_decode_adv_data(uint8_t * adv_data,uint8_t adv_data_len,void * arg)911 btshell_decode_adv_data(uint8_t *adv_data, uint8_t adv_data_len, void *arg)
912 {
913 struct btshell_scan_opts *scan_opts = arg;
914 struct ble_hs_adv_fields fields;
915
916 console_printf(" length_data=%d data=", adv_data_len);
917
918 if (scan_opts) {
919 adv_data_len = min(adv_data_len, scan_opts->limit);
920 }
921
922 print_bytes(adv_data, adv_data_len);
923 console_printf(" fields:\n");
924 ble_hs_adv_parse_fields(&fields, adv_data, adv_data_len);
925 btshell_print_adv_fields(&fields);
926 console_printf("\n");
927 }
928
929 #if MYNEWT_VAL(BLE_EXT_ADV)
930 static void
btshell_decode_event_type(struct ble_gap_ext_disc_desc * desc,void * arg)931 btshell_decode_event_type(struct ble_gap_ext_disc_desc *desc, void *arg)
932 {
933 struct btshell_scan_opts *scan_opts = arg;
934 uint8_t directed = 0;
935
936 if (desc->props & BLE_HCI_ADV_LEGACY_MASK) {
937 if (scan_opts && scan_opts->ignore_legacy) {
938 return;
939 }
940
941 console_printf("Legacy PDU type %d", desc->legacy_event_type);
942 if (desc->legacy_event_type == BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) {
943 directed = 1;
944 }
945 goto common_data;
946 }
947
948 console_printf("Extended adv: ");
949 if (desc->props & BLE_HCI_ADV_CONN_MASK) {
950 console_printf("'conn' ");
951 }
952 if (desc->props & BLE_HCI_ADV_SCAN_MASK) {
953 console_printf("'scan' ");
954 }
955 if (desc->props & BLE_HCI_ADV_DIRECT_MASK) {
956 console_printf("'dir' ");
957 directed = 1;
958 }
959
960 if (desc->props & BLE_HCI_ADV_SCAN_RSP_MASK) {
961 console_printf("'scan rsp' ");
962 }
963
964 switch(desc->data_status) {
965 case BLE_GAP_EXT_ADV_DATA_STATUS_COMPLETE:
966 console_printf("complete");
967 break;
968 case BLE_GAP_EXT_ADV_DATA_STATUS_INCOMPLETE:
969 console_printf("incomplete");
970 break;
971 case BLE_GAP_EXT_ADV_DATA_STATUS_TRUNCATED:
972 console_printf("truncated");
973 break;
974 default:
975 console_printf("reserved %d", desc->data_status);
976 break;
977 }
978
979 common_data:
980 console_printf(" rssi=%d txpower=%d, pphy=%d, sphy=%d, sid=%d,"
981 " addr_type=%d addr=",
982 desc->rssi, desc->tx_power, desc->prim_phy, desc->sec_phy,
983 desc->sid, desc->addr.type);
984 print_addr(desc->addr.val);
985 if (directed) {
986 console_printf(" init_addr_type=%d inita=", desc->direct_addr.type);
987 print_addr(desc->direct_addr.val);
988 }
989
990 console_printf("\n");
991
992 if(!desc->length_data) {
993 return;
994 }
995
996 btshell_decode_adv_data(desc->data, desc->length_data, arg);
997 }
998 #endif
999
1000 static int
1001 btshell_gap_event(struct ble_gap_event *event, void *arg);
1002
1003 static int
btshell_restart_adv(struct ble_gap_event * event)1004 btshell_restart_adv(struct ble_gap_event *event)
1005 {
1006 int rc = 0;
1007 #if MYNEWT_VAL(BLE_EXT_ADV)
1008 uint8_t i;
1009 #endif
1010
1011 if (event->type != BLE_GAP_EVENT_DISCONNECT) {
1012 return -1;
1013 }
1014
1015 #if MYNEWT_VAL(BLE_EXT_ADV)
1016 for (i = 0; i < BLE_ADV_INSTANCES; ++i) {
1017 if (ext_adv_restart[i].restart &&
1018 (ext_adv_restart[i].conn_handle ==
1019 event->disconnect.conn.conn_handle)) {
1020 rc = ble_gap_ext_adv_start(i, 0, 0);
1021 break;
1022 }
1023 }
1024 #else
1025 if (!adv_params.restart) {
1026 return 0;
1027 }
1028
1029 rc = ble_gap_adv_start(adv_params.own_addr_type, &adv_params.direct_addr,
1030 adv_params.duration_ms, &adv_params.params,
1031 btshell_gap_event, NULL);
1032 #endif
1033
1034 return rc;
1035 }
1036
1037 static int
btshell_gap_event(struct ble_gap_event * event,void * arg)1038 btshell_gap_event(struct ble_gap_event *event, void *arg)
1039 {
1040 struct ble_gap_conn_desc desc;
1041 int conn_idx;
1042 int rc;
1043
1044 switch (event->type) {
1045 case BLE_GAP_EVENT_CONNECT:
1046 console_printf("connection %s; status=%d ",
1047 event->connect.status == 0 ? "established" : "failed",
1048 event->connect.status);
1049
1050 if (event->connect.status == 0) {
1051 rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
1052 assert(rc == 0);
1053 print_conn_desc(&desc);
1054 btshell_conn_add(&desc);
1055 }
1056 return 0;
1057
1058 case BLE_GAP_EVENT_DISCONNECT:
1059 console_printf("disconnect; reason=%d ", event->disconnect.reason);
1060 print_conn_desc(&event->disconnect.conn);
1061
1062 conn_idx = btshell_conn_find_idx(event->disconnect.conn.conn_handle);
1063 if (conn_idx != -1) {
1064 btshell_conn_delete_idx(conn_idx);
1065 }
1066
1067 return btshell_restart_adv(event);
1068 #if MYNEWT_VAL(BLE_EXT_ADV)
1069 case BLE_GAP_EVENT_EXT_DISC:
1070 btshell_decode_event_type(&event->ext_disc, arg);
1071 return 0;
1072 #endif
1073 case BLE_GAP_EVENT_DISC:
1074 console_printf("received advertisement; event_type=%d rssi=%d "
1075 "addr_type=%d addr=", event->disc.event_type,
1076 event->disc.rssi, event->disc.addr.type);
1077 print_addr(event->disc.addr.val);
1078
1079 /*
1080 * There is no adv data to print in case of connectable
1081 * directed advertising
1082 */
1083 if (event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) {
1084 console_printf("\nConnectable directed advertising event\n");
1085 return 0;
1086 }
1087
1088 btshell_decode_adv_data(event->disc.data, event->disc.length_data, arg);
1089
1090 return 0;
1091
1092 case BLE_GAP_EVENT_CONN_UPDATE:
1093 console_printf("connection updated; status=%d ",
1094 event->conn_update.status);
1095 rc = ble_gap_conn_find(event->conn_update.conn_handle, &desc);
1096 assert(rc == 0);
1097 print_conn_desc(&desc);
1098 return 0;
1099
1100 case BLE_GAP_EVENT_CONN_UPDATE_REQ:
1101 console_printf("connection update request\n");
1102 *event->conn_update_req.self_params =
1103 *event->conn_update_req.peer_params;
1104 return 0;
1105
1106 case BLE_GAP_EVENT_PASSKEY_ACTION:
1107 console_printf("passkey action event; action=%d",
1108 event->passkey.params.action);
1109 if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) {
1110 console_printf(" numcmp=%lu",
1111 (unsigned long)event->passkey.params.numcmp);
1112 }
1113 console_printf("\n");
1114 return 0;
1115
1116
1117 case BLE_GAP_EVENT_DISC_COMPLETE:
1118 console_printf("discovery complete; reason=%d\n",
1119 event->disc_complete.reason);
1120 return 0;
1121
1122 case BLE_GAP_EVENT_ADV_COMPLETE:
1123 #if MYNEWT_VAL(BLE_EXT_ADV)
1124 console_printf("advertise complete; reason=%d, instance=%u, handle=%d\n",
1125 event->adv_complete.reason, event->adv_complete.instance,
1126 event->adv_complete.conn_handle);
1127
1128 ext_adv_restart[event->adv_complete.instance].conn_handle =
1129 event->adv_complete.conn_handle;
1130 #else
1131 console_printf("advertise complete; reason=%d\n",
1132 event->adv_complete.reason);
1133 #endif
1134 return 0;
1135
1136 case BLE_GAP_EVENT_ENC_CHANGE:
1137 console_printf("encryption change event; status=%d ",
1138 event->enc_change.status);
1139 rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc);
1140 assert(rc == 0);
1141 print_conn_desc(&desc);
1142 return 0;
1143
1144 case BLE_GAP_EVENT_NOTIFY_RX:
1145 console_printf("notification rx event; attr_handle=%d indication=%d "
1146 "len=%d data=",
1147 event->notify_rx.attr_handle,
1148 event->notify_rx.indication,
1149 OS_MBUF_PKTLEN(event->notify_rx.om));
1150
1151 print_mbuf(event->notify_rx.om);
1152 console_printf("\n");
1153 return 0;
1154
1155 case BLE_GAP_EVENT_NOTIFY_TX:
1156 console_printf("notification tx event; status=%d attr_handle=%d "
1157 "indication=%d\n",
1158 event->notify_tx.status,
1159 event->notify_tx.attr_handle,
1160 event->notify_tx.indication);
1161 return 0;
1162
1163 case BLE_GAP_EVENT_SUBSCRIBE:
1164 console_printf("subscribe event; conn_handle=%d attr_handle=%d "
1165 "reason=%d prevn=%d curn=%d previ=%d curi=%d\n",
1166 event->subscribe.conn_handle,
1167 event->subscribe.attr_handle,
1168 event->subscribe.reason,
1169 event->subscribe.prev_notify,
1170 event->subscribe.cur_notify,
1171 event->subscribe.prev_indicate,
1172 event->subscribe.cur_indicate);
1173 return 0;
1174
1175 case BLE_GAP_EVENT_MTU:
1176 console_printf("mtu update event; conn_handle=%d cid=%d mtu=%d\n",
1177 event->mtu.conn_handle,
1178 event->mtu.channel_id,
1179 event->mtu.value);
1180 return 0;
1181
1182 case BLE_GAP_EVENT_IDENTITY_RESOLVED:
1183 console_printf("identity resolved ");
1184 rc = ble_gap_conn_find(event->identity_resolved.conn_handle, &desc);
1185 assert(rc == 0);
1186 print_conn_desc(&desc);
1187 return 0;
1188
1189 case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE:
1190 console_printf("PHY update complete; status=%d, conn_handle=%d "
1191 " tx_phy=%d, rx_phy=%d\n",
1192 event->phy_updated.status,
1193 event->phy_updated.conn_handle,
1194 event->phy_updated.tx_phy,
1195 event->phy_updated.rx_phy);
1196 return 0;
1197
1198 case BLE_GAP_EVENT_REPEAT_PAIRING:
1199 /* We already have a bond with the peer, but it is attempting to
1200 * establish a new secure link. This app sacrifices security for
1201 * convenience: just throw away the old bond and accept the new link.
1202 */
1203
1204 /* Delete the old bond. */
1205 rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc);
1206 assert(rc == 0);
1207 ble_store_util_delete_peer(&desc.peer_id_addr);
1208
1209 /* Return BLE_GAP_REPEAT_PAIRING_RETRY to indicate that the host should
1210 * continue with the pairing operation.
1211 */
1212 return BLE_GAP_REPEAT_PAIRING_RETRY;
1213
1214 default:
1215 return 0;
1216 }
1217 }
1218
1219 static void
btshell_on_l2cap_update(uint16_t conn_handle,int status,void * arg)1220 btshell_on_l2cap_update(uint16_t conn_handle, int status, void *arg)
1221 {
1222 console_printf("l2cap update complete; conn_handle=%d status=%d\n",
1223 conn_handle, status);
1224 }
1225
1226 static void
btshell_tx_timer_cb(struct ble_npl_event * ev)1227 btshell_tx_timer_cb(struct ble_npl_event *ev)
1228 {
1229 int i;
1230 uint8_t len;
1231 int32_t timeout;
1232 uint8_t *dptr;
1233 struct os_mbuf *om;
1234
1235 if ((btshell_tx_data.tx_num == 0) || (btshell_tx_data.tx_len == 0)) {
1236 return;
1237 }
1238
1239 len = btshell_tx_data.tx_len;
1240
1241 om = NULL;
1242 if (os_msys_num_free() >= 4) {
1243 om = os_msys_get_pkthdr(len + 4, sizeof(struct ble_mbuf_hdr));
1244 }
1245
1246 if (om) {
1247 /* Put the HCI header in the mbuf */
1248 om->om_len = len + 4;
1249 put_le16(om->om_data, btshell_tx_data.tx_handle);
1250 put_le16(om->om_data + 2, len);
1251 dptr = om->om_data + 4;
1252
1253 /*
1254 * NOTE: first byte gets 0xff so not confused with l2cap channel.
1255 * The rest of the data gets filled with incrementing pattern starting
1256 * from 0.
1257 */
1258 put_le16(dptr, len - 4);
1259 dptr[2] = 0xff;
1260 dptr[3] = 0xff;
1261 dptr += 4;
1262 len -= 4;
1263
1264 for (i = 0; i < len; ++i) {
1265 *dptr = i;
1266 ++dptr;
1267 }
1268
1269 /* Set packet header length */
1270 OS_MBUF_PKTHDR(om)->omp_len = om->om_len;
1271 ble_hci_trans_hs_acl_tx(om);
1272
1273 --btshell_tx_data.tx_num;
1274 }
1275
1276 if (btshell_tx_data.tx_num) {
1277 timeout = (int32_t)btshell_tx_data.tx_rate;
1278 timeout = (timeout * OS_TICKS_PER_SEC) / 1000;
1279 ble_npl_callout_reset(&btshell_tx_timer, timeout);
1280 }
1281 }
1282
1283 int
btshell_exchange_mtu(uint16_t conn_handle)1284 btshell_exchange_mtu(uint16_t conn_handle)
1285 {
1286 int rc;
1287
1288 rc = ble_gattc_exchange_mtu(conn_handle, btshell_on_mtu, NULL);
1289 return rc;
1290 }
1291
1292 int
btshell_disc_all_chrs(uint16_t conn_handle,uint16_t start_handle,uint16_t end_handle)1293 btshell_disc_all_chrs(uint16_t conn_handle, uint16_t start_handle,
1294 uint16_t end_handle)
1295 {
1296 intptr_t svc_start_handle;
1297 int rc;
1298
1299 svc_start_handle = start_handle;
1300 rc = ble_gattc_disc_all_chrs(conn_handle, start_handle, end_handle,
1301 btshell_on_disc_c, (void *)svc_start_handle);
1302 return rc;
1303 }
1304
1305 int
btshell_disc_chrs_by_uuid(uint16_t conn_handle,uint16_t start_handle,uint16_t end_handle,const ble_uuid_t * uuid)1306 btshell_disc_chrs_by_uuid(uint16_t conn_handle, uint16_t start_handle,
1307 uint16_t end_handle, const ble_uuid_t *uuid)
1308 {
1309 intptr_t svc_start_handle;
1310 int rc;
1311
1312 svc_start_handle = start_handle;
1313 rc = ble_gattc_disc_chrs_by_uuid(conn_handle, start_handle, end_handle,
1314 uuid, btshell_on_disc_c,
1315 (void *)svc_start_handle);
1316 return rc;
1317 }
1318
1319 int
btshell_disc_svcs(uint16_t conn_handle)1320 btshell_disc_svcs(uint16_t conn_handle)
1321 {
1322 int rc;
1323
1324 rc = ble_gattc_disc_all_svcs(conn_handle, btshell_on_disc_s, NULL);
1325 return rc;
1326 }
1327
1328 int
btshell_disc_svc_by_uuid(uint16_t conn_handle,const ble_uuid_t * uuid)1329 btshell_disc_svc_by_uuid(uint16_t conn_handle, const ble_uuid_t *uuid)
1330 {
1331 int rc;
1332
1333 rc = ble_gattc_disc_svc_by_uuid(conn_handle, uuid,
1334 btshell_on_disc_s, NULL);
1335 return rc;
1336 }
1337
1338 int
btshell_disc_all_dscs(uint16_t conn_handle,uint16_t start_handle,uint16_t end_handle)1339 btshell_disc_all_dscs(uint16_t conn_handle, uint16_t start_handle,
1340 uint16_t end_handle)
1341 {
1342 int rc;
1343
1344 rc = ble_gattc_disc_all_dscs(conn_handle, start_handle, end_handle,
1345 btshell_on_disc_d, NULL);
1346 return rc;
1347 }
1348
1349 int
btshell_disc_full(uint16_t conn_handle)1350 btshell_disc_full(uint16_t conn_handle)
1351 {
1352 struct btshell_conn *conn;
1353 struct btshell_svc *svc;
1354
1355 /* Undiscover everything first. */
1356 conn = btshell_conn_find(conn_handle);
1357 if (conn == NULL) {
1358 return BLE_HS_ENOTCONN;
1359 }
1360
1361 while ((svc = SLIST_FIRST(&conn->svcs)) != NULL) {
1362 SLIST_REMOVE_HEAD(&conn->svcs, next);
1363 btshell_svc_delete(svc);
1364 }
1365
1366 btshell_full_disc_prev_chr_val = 1;
1367 btshell_disc_svcs(conn_handle);
1368
1369 return 0;
1370 }
1371
1372 int
btshell_find_inc_svcs(uint16_t conn_handle,uint16_t start_handle,uint16_t end_handle)1373 btshell_find_inc_svcs(uint16_t conn_handle, uint16_t start_handle,
1374 uint16_t end_handle)
1375 {
1376 int rc;
1377
1378 rc = ble_gattc_find_inc_svcs(conn_handle, start_handle, end_handle,
1379 btshell_on_disc_s, NULL);
1380 return rc;
1381 }
1382
1383 int
btshell_read(uint16_t conn_handle,uint16_t attr_handle)1384 btshell_read(uint16_t conn_handle, uint16_t attr_handle)
1385 {
1386 struct os_mbuf *om;
1387 int rc;
1388
1389 if (conn_handle == BLE_HS_CONN_HANDLE_NONE) {
1390 rc = ble_att_svr_read_local(attr_handle, &om);
1391 if (rc == 0) {
1392 console_printf("read local; attr_handle=%d len=%d value=",
1393 attr_handle, OS_MBUF_PKTLEN(om));
1394 print_mbuf(om);
1395 console_printf("\n");
1396
1397 os_mbuf_free_chain(om);
1398 }
1399 } else {
1400 rc = ble_gattc_read(conn_handle, attr_handle, btshell_on_read, NULL);
1401 }
1402 return rc;
1403 }
1404
1405 int
btshell_read_long(uint16_t conn_handle,uint16_t attr_handle,uint16_t offset)1406 btshell_read_long(uint16_t conn_handle, uint16_t attr_handle, uint16_t offset)
1407 {
1408 int rc;
1409
1410 rc = ble_gattc_read_long(conn_handle, attr_handle, offset,
1411 btshell_on_read, NULL);
1412 return rc;
1413 }
1414
1415 int
btshell_read_by_uuid(uint16_t conn_handle,uint16_t start_handle,uint16_t end_handle,const ble_uuid_t * uuid)1416 btshell_read_by_uuid(uint16_t conn_handle, uint16_t start_handle,
1417 uint16_t end_handle, const ble_uuid_t *uuid)
1418 {
1419 int rc;
1420
1421 rc = ble_gattc_read_by_uuid(conn_handle, start_handle, end_handle, uuid,
1422 btshell_on_read, NULL);
1423 return rc;
1424 }
1425
1426 int
btshell_read_mult(uint16_t conn_handle,uint16_t * attr_handles,int num_attr_handles)1427 btshell_read_mult(uint16_t conn_handle, uint16_t *attr_handles,
1428 int num_attr_handles)
1429 {
1430 int rc;
1431
1432 rc = ble_gattc_read_mult(conn_handle, attr_handles, num_attr_handles,
1433 btshell_on_read, NULL);
1434 return rc;
1435 }
1436
1437 int
btshell_write(uint16_t conn_handle,uint16_t attr_handle,struct os_mbuf * om)1438 btshell_write(uint16_t conn_handle, uint16_t attr_handle, struct os_mbuf *om)
1439 {
1440 int rc;
1441
1442 if (conn_handle == BLE_HS_CONN_HANDLE_NONE) {
1443 rc = ble_att_svr_write_local(attr_handle, om);
1444 } else {
1445 rc = ble_gattc_write(conn_handle, attr_handle, om,
1446 btshell_on_write, NULL);
1447 }
1448
1449 return rc;
1450 }
1451
1452 int
btshell_write_no_rsp(uint16_t conn_handle,uint16_t attr_handle,struct os_mbuf * om)1453 btshell_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle,
1454 struct os_mbuf *om)
1455 {
1456 int rc;
1457
1458 rc = ble_gattc_write_no_rsp(conn_handle, attr_handle, om);
1459
1460 return rc;
1461 }
1462
1463 int
btshell_write_long(uint16_t conn_handle,uint16_t attr_handle,uint16_t offset,struct os_mbuf * om)1464 btshell_write_long(uint16_t conn_handle, uint16_t attr_handle,
1465 uint16_t offset, struct os_mbuf *om)
1466 {
1467 int rc;
1468
1469 rc = ble_gattc_write_long(conn_handle, attr_handle, offset,
1470 om, btshell_on_write, NULL);
1471 return rc;
1472 }
1473
1474 int
btshell_write_reliable(uint16_t conn_handle,struct ble_gatt_attr * attrs,int num_attrs)1475 btshell_write_reliable(uint16_t conn_handle,
1476 struct ble_gatt_attr *attrs,
1477 int num_attrs)
1478 {
1479 int rc;
1480
1481 rc = ble_gattc_write_reliable(conn_handle, attrs, num_attrs,
1482 btshell_on_write_reliable, NULL);
1483 return rc;
1484 }
1485
1486 #if MYNEWT_VAL(BLE_EXT_ADV)
1487 int
btshell_ext_adv_configure(uint8_t instance,const struct ble_gap_ext_adv_params * params,int8_t * selected_tx_power)1488 btshell_ext_adv_configure(uint8_t instance,
1489 const struct ble_gap_ext_adv_params *params,
1490 int8_t *selected_tx_power)
1491 {
1492 return ble_gap_ext_adv_configure(instance, params, selected_tx_power,
1493 btshell_gap_event, NULL);
1494 }
1495
1496 int
btshell_ext_adv_start(uint8_t instance,int duration,int max_events,bool restart)1497 btshell_ext_adv_start(uint8_t instance, int duration,
1498 int max_events, bool restart)
1499 {
1500 int rc;
1501
1502 /* Advertising restart doesn't make sense
1503 * with limited duration or events
1504 */
1505 if (restart && (duration == 0) && (max_events == 0)) {
1506 ext_adv_restart[instance].restart = restart;
1507 }
1508
1509 rc = ble_gap_ext_adv_start(instance, duration, max_events);
1510
1511 return rc;
1512 }
1513
1514 int
btshell_ext_adv_stop(uint8_t instance)1515 btshell_ext_adv_stop(uint8_t instance)
1516 {
1517 int rc;
1518
1519 ext_adv_restart[instance].restart = false;
1520
1521 rc = ble_gap_ext_adv_stop(instance);
1522
1523 return rc;
1524 }
1525 #endif
1526
1527 int
btshell_adv_stop(void)1528 btshell_adv_stop(void)
1529 {
1530 int rc;
1531
1532 adv_params.restart = false;
1533
1534 rc = ble_gap_adv_stop();
1535 return rc;
1536 }
1537
1538 int
btshell_adv_start(uint8_t own_addr_type,const ble_addr_t * direct_addr,int32_t duration_ms,const struct ble_gap_adv_params * params,bool restart)1539 btshell_adv_start(uint8_t own_addr_type, const ble_addr_t *direct_addr,
1540 int32_t duration_ms, const struct ble_gap_adv_params *params,
1541 bool restart)
1542 {
1543 int rc;
1544
1545 if (restart) {
1546 adv_params.restart = restart;
1547 adv_params.own_addr_type = own_addr_type;
1548 adv_params.duration_ms = duration_ms;
1549
1550 if (direct_addr) {
1551 memcpy(&adv_params.direct_addr, direct_addr, sizeof(adv_params.direct_addr));
1552 }
1553
1554 if (params) {
1555 memcpy(&adv_params.params, params, sizeof(adv_params.params));
1556 }
1557 }
1558
1559 rc = ble_gap_adv_start(own_addr_type, direct_addr, duration_ms, params,
1560 btshell_gap_event, NULL);
1561 return rc;
1562 }
1563
1564 int
btshell_conn_initiate(uint8_t own_addr_type,const ble_addr_t * peer_addr,int32_t duration_ms,struct ble_gap_conn_params * params)1565 btshell_conn_initiate(uint8_t own_addr_type, const ble_addr_t *peer_addr,
1566 int32_t duration_ms, struct ble_gap_conn_params *params)
1567 {
1568 int rc;
1569
1570 rc = ble_gap_connect(own_addr_type, peer_addr, duration_ms, params,
1571 btshell_gap_event, NULL);
1572
1573 return rc;
1574 }
1575
1576 int
btshell_ext_conn_initiate(uint8_t own_addr_type,const ble_addr_t * peer_addr,int32_t duration_ms,struct ble_gap_conn_params * phy_1m_params,struct ble_gap_conn_params * phy_2m_params,struct ble_gap_conn_params * phy_coded_params)1577 btshell_ext_conn_initiate(uint8_t own_addr_type, const ble_addr_t *peer_addr,
1578 int32_t duration_ms,
1579 struct ble_gap_conn_params *phy_1m_params,
1580 struct ble_gap_conn_params *phy_2m_params,
1581 struct ble_gap_conn_params *phy_coded_params)
1582 {
1583 #if !MYNEWT_VAL(BLE_EXT_ADV)
1584 console_printf("BLE extended advertising not supported.");
1585 console_printf(" Configure nimble host to enable it\n");
1586 return 0;
1587 #else
1588 int rc;
1589 uint8_t phy_mask = 0;
1590
1591 if (phy_1m_params) {
1592 phy_mask |= BLE_GAP_LE_PHY_1M_MASK;
1593 }
1594
1595 if (phy_2m_params) {
1596 phy_mask |= BLE_GAP_LE_PHY_2M_MASK;
1597 }
1598
1599 if (phy_coded_params) {
1600 phy_mask |= BLE_GAP_LE_PHY_CODED_MASK;
1601 }
1602
1603 rc = ble_gap_ext_connect(own_addr_type, peer_addr, duration_ms, phy_mask,
1604 phy_1m_params, phy_2m_params, phy_coded_params,
1605 btshell_gap_event, NULL);
1606
1607 return rc;
1608 #endif
1609 }
1610
1611 int
btshell_conn_cancel(void)1612 btshell_conn_cancel(void)
1613 {
1614 int rc;
1615
1616 rc = ble_gap_conn_cancel();
1617 return rc;
1618 }
1619
1620 int
btshell_term_conn(uint16_t conn_handle,uint8_t reason)1621 btshell_term_conn(uint16_t conn_handle, uint8_t reason)
1622 {
1623 int rc;
1624
1625 rc = ble_gap_terminate(conn_handle, reason);
1626 return rc;
1627 }
1628
1629 int
btshell_wl_set(ble_addr_t * addrs,int addrs_count)1630 btshell_wl_set(ble_addr_t *addrs, int addrs_count)
1631 {
1632 int rc;
1633
1634 rc = ble_gap_wl_set(addrs, addrs_count);
1635 return rc;
1636 }
1637
1638 int
btshell_scan(uint8_t own_addr_type,int32_t duration_ms,const struct ble_gap_disc_params * disc_params,void * cb_args)1639 btshell_scan(uint8_t own_addr_type, int32_t duration_ms,
1640 const struct ble_gap_disc_params *disc_params, void *cb_args)
1641 {
1642 int rc;
1643
1644 rc = ble_gap_disc(own_addr_type, duration_ms, disc_params,
1645 btshell_gap_event, cb_args);
1646 return rc;
1647 }
1648
1649 int
btshell_ext_scan(uint8_t own_addr_type,uint16_t duration,uint16_t period,uint8_t filter_duplicates,uint8_t filter_policy,uint8_t limited,const struct ble_gap_ext_disc_params * uncoded_params,const struct ble_gap_ext_disc_params * coded_params,void * cb_args)1650 btshell_ext_scan(uint8_t own_addr_type, uint16_t duration, uint16_t period,
1651 uint8_t filter_duplicates, uint8_t filter_policy,
1652 uint8_t limited,
1653 const struct ble_gap_ext_disc_params *uncoded_params,
1654 const struct ble_gap_ext_disc_params *coded_params,
1655 void *cb_args)
1656 {
1657 #if !MYNEWT_VAL(BLE_EXT_ADV)
1658 console_printf("BLE extended advertising not supported.");
1659 console_printf(" Configure nimble host to enable it\n");
1660 return 0;
1661 #else
1662 int rc;
1663
1664 rc = ble_gap_ext_disc(own_addr_type, duration, period, filter_duplicates,
1665 filter_policy, limited, uncoded_params, coded_params,
1666 btshell_gap_event, cb_args);
1667 return rc;
1668 #endif
1669 }
1670
1671 int
btshell_scan_cancel(void)1672 btshell_scan_cancel(void)
1673 {
1674 int rc;
1675
1676 rc = ble_gap_disc_cancel();
1677 return rc;
1678 }
1679
1680 int
btshell_update_conn(uint16_t conn_handle,struct ble_gap_upd_params * params)1681 btshell_update_conn(uint16_t conn_handle, struct ble_gap_upd_params *params)
1682 {
1683 int rc;
1684
1685 rc = ble_gap_update_params(conn_handle, params);
1686 return rc;
1687 }
1688
1689 void
btshell_notify(uint16_t attr_handle)1690 btshell_notify(uint16_t attr_handle)
1691 {
1692 ble_gatts_chr_updated(attr_handle);
1693 }
1694
1695 int
btshell_datalen(uint16_t conn_handle,uint16_t tx_octets,uint16_t tx_time)1696 btshell_datalen(uint16_t conn_handle, uint16_t tx_octets, uint16_t tx_time)
1697 {
1698 int rc;
1699
1700 rc = ble_hs_hci_util_set_data_len(conn_handle, tx_octets, tx_time);
1701 return rc;
1702 }
1703
1704 int
btshell_l2cap_update(uint16_t conn_handle,struct ble_l2cap_sig_update_params * params)1705 btshell_l2cap_update(uint16_t conn_handle,
1706 struct ble_l2cap_sig_update_params *params)
1707 {
1708 int rc;
1709
1710 rc = ble_l2cap_sig_update(conn_handle, params, btshell_on_l2cap_update,
1711 NULL);
1712 return rc;
1713 }
1714
1715 int
btshell_sec_pair(uint16_t conn_handle)1716 btshell_sec_pair(uint16_t conn_handle)
1717 {
1718 #if !NIMBLE_BLE_SM
1719 return BLE_HS_ENOTSUP;
1720 #endif
1721
1722 int rc;
1723
1724 rc = ble_gap_pair_initiate(conn_handle);
1725 return rc;
1726 }
1727
1728 int
btshell_sec_unpair(ble_addr_t * peer_addr)1729 btshell_sec_unpair(ble_addr_t *peer_addr)
1730 {
1731 #if !NIMBLE_BLE_SM
1732 return BLE_HS_ENOTSUP;
1733 #endif
1734
1735 int rc;
1736
1737 rc = ble_gap_unpair(peer_addr);
1738 return rc;
1739 }
1740
1741 int
btshell_sec_start(uint16_t conn_handle)1742 btshell_sec_start(uint16_t conn_handle)
1743 {
1744 #if !NIMBLE_BLE_SM
1745 return BLE_HS_ENOTSUP;
1746 #endif
1747
1748 int rc;
1749
1750 rc = ble_gap_security_initiate(conn_handle);
1751 return rc;
1752 }
1753
1754 int
btshell_sec_restart(uint16_t conn_handle,uint8_t * ltk,uint16_t ediv,uint64_t rand_val,int auth)1755 btshell_sec_restart(uint16_t conn_handle,
1756 uint8_t *ltk,
1757 uint16_t ediv,
1758 uint64_t rand_val,
1759 int auth)
1760 {
1761 #if !NIMBLE_BLE_SM
1762 return BLE_HS_ENOTSUP;
1763 #endif
1764
1765 struct ble_store_value_sec value_sec;
1766 struct ble_store_key_sec key_sec;
1767 struct ble_gap_conn_desc desc;
1768 ble_hs_conn_flags_t conn_flags;
1769 int rc;
1770
1771 if (ltk == NULL) {
1772 /* The user is requesting a store lookup. */
1773 rc = ble_gap_conn_find(conn_handle, &desc);
1774 if (rc != 0) {
1775 return rc;
1776 }
1777
1778 memset(&key_sec, 0, sizeof key_sec);
1779 key_sec.peer_addr = desc.peer_id_addr;
1780
1781 rc = ble_hs_atomic_conn_flags(conn_handle, &conn_flags);
1782 if (rc != 0) {
1783 return rc;
1784 }
1785 if (conn_flags & BLE_HS_CONN_F_MASTER) {
1786 rc = ble_store_read_peer_sec(&key_sec, &value_sec);
1787 } else {
1788 rc = ble_store_read_our_sec(&key_sec, &value_sec);
1789 }
1790 if (rc != 0) {
1791 return rc;
1792 }
1793
1794 ltk = value_sec.ltk;
1795 ediv = value_sec.ediv;
1796 rand_val = value_sec.rand_num;
1797 auth = value_sec.authenticated;
1798 }
1799
1800 rc = ble_gap_encryption_initiate(conn_handle, ltk, ediv, rand_val, auth);
1801 return rc;
1802 }
1803
1804 /**
1805 * Called to start transmitting 'num' packets at rate 'rate' of size 'size'
1806 * to connection handle 'handle'
1807 *
1808 * @param handle
1809 * @param len
1810 * @param rate
1811 * @param num
1812 *
1813 * @return int
1814 */
1815 int
btshell_tx_start(uint16_t handle,uint16_t len,uint16_t rate,uint16_t num)1816 btshell_tx_start(uint16_t handle, uint16_t len, uint16_t rate, uint16_t num)
1817 {
1818 /* Cannot be currently in a session */
1819 if (num == 0) {
1820 return 0;
1821 }
1822
1823 /* Do not allow start if already in progress */
1824 if (btshell_tx_data.tx_num != 0) {
1825 return -1;
1826 }
1827
1828 /* XXX: for now, must have contiguous mbuf space */
1829 if ((len + 4) > MYNEWT_VAL_MSYS_1_BLOCK_SIZE) {
1830 return -2;
1831 }
1832
1833 btshell_tx_data.tx_num = num;
1834 btshell_tx_data.tx_rate = rate;
1835 btshell_tx_data.tx_len = len;
1836 btshell_tx_data.tx_handle = handle;
1837
1838 ble_npl_callout_reset(&btshell_tx_timer, 0);
1839
1840 return 0;
1841 }
1842
1843 int
btshell_rssi(uint16_t conn_handle,int8_t * out_rssi)1844 btshell_rssi(uint16_t conn_handle, int8_t *out_rssi)
1845 {
1846 int rc;
1847
1848 rc = ble_gap_conn_rssi(conn_handle, out_rssi);
1849 if (rc != 0) {
1850 return rc;
1851 }
1852
1853 return 0;
1854 }
1855
1856 static void
btshell_on_reset(int reason)1857 btshell_on_reset(int reason)
1858 {
1859 console_printf("Error: Resetting state; reason=%d\n", reason);
1860 }
1861
1862 static void
btshell_on_sync(void)1863 btshell_on_sync(void)
1864 {
1865 console_printf("Host and controller synced\n");
1866 }
1867
1868 #if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) != 0
1869
1870 static int
btshell_l2cap_coc_add(uint16_t conn_handle,struct ble_l2cap_chan * chan)1871 btshell_l2cap_coc_add(uint16_t conn_handle, struct ble_l2cap_chan *chan)
1872 {
1873 struct btshell_conn *conn;
1874 struct btshell_l2cap_coc *coc;
1875 struct btshell_l2cap_coc *prev, *cur;
1876
1877 conn = btshell_conn_find(conn_handle);
1878 assert(conn != NULL);
1879
1880 coc = os_memblock_get(&btshell_coc_conn_pool);
1881 if (!coc) {
1882 return ENOMEM;
1883 }
1884
1885 coc->chan = chan;
1886
1887 prev = NULL;
1888 SLIST_FOREACH(cur, &conn->coc_list, next) {
1889 prev = cur;
1890 }
1891
1892 if (prev == NULL) {
1893 SLIST_INSERT_HEAD(&conn->coc_list, coc, next);
1894 } else {
1895 SLIST_INSERT_AFTER(prev, coc, next);
1896 }
1897
1898 return 0;
1899 }
1900
1901 static void
btshell_l2cap_coc_remove(uint16_t conn_handle,struct ble_l2cap_chan * chan)1902 btshell_l2cap_coc_remove(uint16_t conn_handle, struct ble_l2cap_chan *chan)
1903 {
1904 struct btshell_conn *conn;
1905 struct btshell_l2cap_coc *coc;
1906 struct btshell_l2cap_coc *cur;
1907
1908 conn = btshell_conn_find(conn_handle);
1909 assert(conn != NULL);
1910
1911 coc = NULL;
1912 SLIST_FOREACH(cur, &conn->coc_list, next) {
1913 if (cur->chan == chan) {
1914 coc = cur;
1915 break;
1916 }
1917 }
1918
1919 if (!coc) {
1920 return;
1921 }
1922
1923 SLIST_REMOVE(&conn->coc_list, coc, btshell_l2cap_coc, next);
1924 os_memblock_put(&btshell_coc_conn_pool, coc);
1925 }
1926
1927 static void
btshell_l2cap_coc_recv(struct ble_l2cap_chan * chan,struct os_mbuf * sdu)1928 btshell_l2cap_coc_recv(struct ble_l2cap_chan *chan, struct os_mbuf *sdu)
1929 {
1930 console_printf("LE CoC SDU received, chan: 0x%08lx, data len %d\n",
1931 (uint32_t) chan, OS_MBUF_PKTLEN(sdu));
1932
1933 os_mbuf_free_chain(sdu);
1934 sdu = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0);
1935 assert(sdu != NULL);
1936
1937 ble_l2cap_recv_ready(chan, sdu);
1938 }
1939
1940 static int
btshell_l2cap_coc_accept(uint16_t conn_handle,uint16_t peer_mtu,struct ble_l2cap_chan * chan)1941 btshell_l2cap_coc_accept(uint16_t conn_handle, uint16_t peer_mtu,
1942 struct ble_l2cap_chan *chan)
1943 {
1944 struct os_mbuf *sdu_rx;
1945
1946 console_printf("LE CoC accepting, chan: 0x%08lx, peer_mtu %d\n",
1947 (uint32_t) chan, peer_mtu);
1948
1949 sdu_rx = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0);
1950 if (!sdu_rx) {
1951 return BLE_HS_ENOMEM;
1952 }
1953
1954 ble_l2cap_recv_ready(chan, sdu_rx);
1955
1956 return 0;
1957 }
1958
1959 static int
btshell_l2cap_event(struct ble_l2cap_event * event,void * arg)1960 btshell_l2cap_event(struct ble_l2cap_event *event, void *arg)
1961 {
1962 int accept_response;
1963
1964 switch(event->type) {
1965 case BLE_L2CAP_EVENT_COC_CONNECTED:
1966 if (event->connect.status) {
1967 console_printf("LE COC error: %d\n", event->connect.status);
1968 return 0;
1969 }
1970
1971 console_printf("LE COC connected, conn: %d, chan: 0x%08lx, scid: 0x%04x, "
1972 "dcid: 0x%04x, our_mtu: 0x%04x, peer_mtu: 0x%04x\n",
1973 event->connect.conn_handle,
1974 (uint32_t) event->connect.chan,
1975 ble_l2cap_get_scid(event->connect.chan),
1976 ble_l2cap_get_dcid(event->connect.chan),
1977 ble_l2cap_get_our_mtu(event->connect.chan),
1978 ble_l2cap_get_peer_mtu(event->connect.chan));
1979
1980 btshell_l2cap_coc_add(event->connect.conn_handle,
1981 event->connect.chan);
1982
1983 return 0;
1984 case BLE_L2CAP_EVENT_COC_DISCONNECTED:
1985 console_printf("LE CoC disconnected, chan: 0x%08lx\n",
1986 (uint32_t) event->disconnect.chan);
1987
1988 btshell_l2cap_coc_remove(event->disconnect.conn_handle,
1989 event->disconnect.chan);
1990 return 0;
1991 case BLE_L2CAP_EVENT_COC_ACCEPT:
1992 accept_response = PTR_TO_INT(arg);
1993 if (accept_response) {
1994 return accept_response;
1995 }
1996
1997 return btshell_l2cap_coc_accept(event->accept.conn_handle,
1998 event->accept.peer_sdu_size,
1999 event->accept.chan);
2000
2001 case BLE_L2CAP_EVENT_COC_DATA_RECEIVED:
2002 btshell_l2cap_coc_recv(event->receive.chan, event->receive.sdu_rx);
2003 return 0;
2004 default:
2005 return 0;
2006 }
2007 }
2008 #endif
2009
2010 int
btshell_l2cap_create_srv(uint16_t psm,int accept_response)2011 btshell_l2cap_create_srv(uint16_t psm, int accept_response)
2012 {
2013 #if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) == 0
2014 console_printf("BLE L2CAP LE COC not supported.");
2015 console_printf(" Configure nimble host to enable it\n");
2016 return 0;
2017 #else
2018
2019 return ble_l2cap_create_server(psm, BTSHELL_COC_MTU, btshell_l2cap_event,
2020 INT_TO_PTR(accept_response));
2021 #endif
2022 }
2023
2024 int
btshell_l2cap_connect(uint16_t conn_handle,uint16_t psm)2025 btshell_l2cap_connect(uint16_t conn_handle, uint16_t psm)
2026 {
2027 #if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) == 0
2028 console_printf("BLE L2CAP LE COC not supported.");
2029 console_printf(" Configure nimble host to enable it\n");
2030 return 0;
2031 #else
2032
2033 struct os_mbuf *sdu_rx;
2034
2035 sdu_rx = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0);
2036 assert(sdu_rx != NULL);
2037
2038 return ble_l2cap_connect(conn_handle, psm, BTSHELL_COC_MTU, sdu_rx,
2039 btshell_l2cap_event, NULL);
2040 #endif
2041 }
2042
2043 int
btshell_l2cap_disconnect(uint16_t conn_handle,uint16_t idx)2044 btshell_l2cap_disconnect(uint16_t conn_handle, uint16_t idx)
2045 {
2046 #if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) == 0
2047 console_printf("BLE L2CAP LE COC not supported.");
2048 console_printf(" Configure nimble host to enable it\n");
2049 return 0;
2050 #else
2051
2052 struct btshell_conn *conn;
2053 struct btshell_l2cap_coc *coc;
2054 int i;
2055 int rc = 0;
2056
2057 conn = btshell_conn_find(conn_handle);
2058 assert(conn != NULL);
2059
2060 i = 0;
2061 SLIST_FOREACH(coc, &conn->coc_list, next) {
2062 if (i == idx) {
2063 break;
2064 }
2065 i++;
2066 }
2067 assert(coc != NULL);
2068
2069 rc = ble_l2cap_disconnect(coc->chan);
2070 if (rc) {
2071 console_printf("Could not disconnect channel rc=%d\n", rc);
2072 }
2073
2074 return rc;
2075 #endif
2076 }
2077
2078 int
btshell_l2cap_send(uint16_t conn_handle,uint16_t idx,uint16_t bytes)2079 btshell_l2cap_send(uint16_t conn_handle, uint16_t idx, uint16_t bytes)
2080 {
2081 #if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) == 0
2082 console_printf("BLE L2CAP LE COC not supported.");
2083 console_printf(" Configure nimble host to enable it\n");
2084 return 0;
2085 #else
2086
2087 struct btshell_conn *conn;
2088 struct btshell_l2cap_coc *coc;
2089 struct os_mbuf *sdu_tx;
2090 uint8_t b[] = {0x00, 0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88, 0x99};
2091 int i;
2092 int rc;
2093
2094 console_printf("conn=%d, idx=%d, bytes=%d\n", conn_handle, idx, bytes);
2095
2096 conn = btshell_conn_find(conn_handle);
2097 if (conn == NULL) {
2098 console_printf("conn=%d does not exist\n", conn_handle);
2099 return 0;
2100 }
2101
2102 i = 0;
2103 SLIST_FOREACH(coc, &conn->coc_list, next) {
2104 if (i == idx) {
2105 break;
2106 }
2107 i++;
2108 }
2109 if (coc == NULL) {
2110 console_printf("Are you sure your channel exist?\n");
2111 return 0;
2112 }
2113
2114 sdu_tx = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0);
2115 if (sdu_tx == NULL) {
2116 console_printf("No memory in the test sdu pool\n");
2117 return 0;
2118 }
2119
2120 /* For the testing purpose we fill up buffer with known data, easy
2121 * to validate on other side. In this loop we add as many full chunks as we
2122 * can
2123 */
2124 for (i = 0; i < bytes / sizeof(b); i++) {
2125 rc = os_mbuf_append(sdu_tx, b, sizeof(b));
2126 if (rc) {
2127 console_printf("Cannot append data %i !\n", i);
2128 os_mbuf_free_chain(sdu_tx);
2129 return rc;
2130 }
2131 }
2132
2133 /* Here we add the rest < sizeof(b) */
2134 rc = os_mbuf_append(sdu_tx, b, bytes - (sizeof(b) * i));
2135 if (rc) {
2136 console_printf("Cannot append data %i !\n", i);
2137 os_mbuf_free_chain(sdu_tx);
2138 return rc;
2139 }
2140
2141 rc = ble_l2cap_send(coc->chan, sdu_tx);
2142 if (rc) {
2143 console_printf("Could not send data rc=%d\n", rc);
2144 os_mbuf_free_chain(sdu_tx);
2145 }
2146
2147 return rc;
2148
2149 #endif
2150 }
2151
2152 static void
btshell_init_ext_adv_restart(void)2153 btshell_init_ext_adv_restart(void)
2154 {
2155 #if MYNEWT_VAL(BLE_EXT_ADV)
2156 int i;
2157
2158 for (i = 0; i < BLE_ADV_INSTANCES; ++i) {
2159 ext_adv_restart[i].conn_handle = BLE_HS_CONN_HANDLE_NONE;
2160 }
2161 #endif
2162 }
2163
2164 extern int nimble_ble_enable(void);
2165 extern struct ble_npl_eventq *nimble_port_get_dflt_eventq(void);
2166 /**
2167 * main
2168 *
2169 * The main task for the project. This function initializes the packages,
2170 * then starts serving events from default event queue.
2171 *
2172 * @return int NOTE: this function should never return!
2173 */
btshell_init(void)2174 int btshell_init(void)
2175 {
2176 int rc;
2177
2178 /* Initialize some application specific memory pools. */
2179 rc = os_mempool_init(&btshell_svc_pool, BTSHELL_MAX_SVCS,
2180 sizeof (struct btshell_svc), btshell_svc_mem,
2181 "btshell_svc_pool");
2182 assert(rc == 0);
2183
2184 rc = os_mempool_init(&btshell_chr_pool, BTSHELL_MAX_CHRS,
2185 sizeof (struct btshell_chr), btshell_chr_mem,
2186 "btshell_chr_pool");
2187 assert(rc == 0);
2188
2189 rc = os_mempool_init(&btshell_dsc_pool, BTSHELL_MAX_DSCS,
2190 sizeof (struct btshell_dsc), btshell_dsc_mem,
2191 "btshell_dsc_pool");
2192 assert(rc == 0);
2193
2194 #if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) != 0
2195 /* For testing we want to support all the available channels */
2196 rc = os_mempool_init(&sdu_coc_mbuf_mempool, BTSHELL_COC_BUF_COUNT,
2197 BTSHELL_COC_MTU, btshell_sdu_coc_mem,
2198 "btshell_coc_sdu_pool");
2199 assert(rc == 0);
2200
2201 rc = os_mbuf_pool_init(&sdu_os_mbuf_pool, &sdu_coc_mbuf_mempool,
2202 BTSHELL_COC_MTU, BTSHELL_COC_BUF_COUNT);
2203 assert(rc == 0);
2204
2205 rc = os_mempool_init(&btshell_coc_conn_pool,
2206 MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM),
2207 sizeof (struct btshell_l2cap_coc), btshell_coc_conn_mem,
2208 "btshell_coc_conn_pool");
2209 assert(rc == 0);
2210 #endif
2211
2212 /* Initialize the NimBLE host configuration. */
2213 ble_hs_cfg.reset_cb = btshell_on_reset;
2214 ble_hs_cfg.sync_cb = btshell_on_sync;
2215 ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb;
2216 ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
2217
2218 rc = gatt_svr_init();
2219 assert(rc == 0);
2220
2221 cmd_init();
2222
2223 /* Set the default device name. */
2224 rc = ble_svc_gap_device_name_set("nimble-btshell");
2225 assert(rc == 0);
2226
2227 /* Create a callout (timer). This callout is used by the "tx" btshell
2228 * command to repeatedly send packets of sequential data bytes.
2229 */
2230 ble_npl_callout_init(&btshell_tx_timer, nimble_port_get_dflt_eventq(),
2231 btshell_tx_timer_cb, NULL);
2232
2233 btshell_init_ext_adv_restart();
2234
2235 /* startup bluetooth host stack*/
2236 ble_hs_thread_startup();
2237
2238 return 0;
2239 }
2240
2241 /**
2242 * Bluetooth shell porting on RT-Thread
2243 */
2244 #include <rtthread.h>
2245 #include <rtdevice.h>
2246 #include <rthw.h>
2247
2248 #define BTSHELL_RX_FIFO_SIZE 256
2249
2250 #define ESC_KEY 0x1B
2251 #define BACKSPACE_KEY 0x08
2252 #define DELECT_KEY 0x7F
2253
2254 struct shell_console
2255 {
2256 struct rt_semaphore *rx_end;
2257 struct rt_ringbuffer *rx_fifo;
2258 rt_err_t (*old_rx_ind)(rt_device_t dev, rt_size_t size);
2259 };
2260
2261 static struct shell_console btshell_console;
2262
uart_console_rx_ind(rt_device_t dev,rt_size_t size)2263 static rt_err_t uart_console_rx_ind(rt_device_t dev, rt_size_t size)
2264 {
2265 uint8_t ch;
2266 rt_size_t i;
2267
2268 for (i = 0; i < size; i++)
2269 {
2270 /* read a char */
2271 if (rt_device_read(dev, 0, &ch, 1))
2272 {
2273 rt_ringbuffer_put_force(btshell_console.rx_fifo, &ch, 1);
2274 rt_sem_release(btshell_console.rx_end);
2275 }
2276 }
2277
2278 return RT_EOK;
2279 }
2280
rt_btshell_init(void)2281 static int rt_btshell_init(void)
2282 {
2283 rt_base_t level;
2284 rt_device_t uart_console;
2285
2286 /* create semaphore for the end of char recived */
2287 btshell_console.rx_end = rt_sem_create("btshell", 0, RT_IPC_FLAG_FIFO);
2288 if (btshell_console.rx_end == RT_NULL)
2289 {
2290 goto __exit;
2291 }
2292
2293 /* create recived fifo */
2294 btshell_console.rx_fifo = rt_ringbuffer_create(BTSHELL_RX_FIFO_SIZE);
2295 if (btshell_console.rx_fifo == RT_NULL)
2296 {
2297 goto __exit;
2298 }
2299
2300 level = rt_hw_interrupt_disable();
2301 uart_console = rt_console_get_device();
2302 if(uart_console)
2303 {
2304 /* back uart console old indicate callback */
2305 btshell_console.old_rx_ind = uart_console->rx_indicate;
2306 rt_device_set_rx_indicate(uart_console, uart_console_rx_ind);
2307 }
2308 rt_hw_interrupt_enable(level);
2309
2310 return RT_EOK;
2311
2312 __exit:
2313 if (btshell_console.rx_end != RT_NULL)
2314 {
2315 rt_sem_delete(btshell_console.rx_end);
2316 btshell_console.rx_end = RT_NULL;
2317 }
2318
2319 if (btshell_console.rx_fifo != RT_NULL)
2320 {
2321 rt_ringbuffer_destroy(btshell_console.rx_fifo);
2322 btshell_console.rx_fifo = RT_NULL;
2323 }
2324
2325 return -RT_ERROR;
2326 }
2327
rt_btshell_deinit(void)2328 static void rt_btshell_deinit(void)
2329 {
2330 rt_base_t level;
2331 rt_device_t uart_console;
2332
2333 level = rt_hw_interrupt_disable();
2334 uart_console = rt_console_get_device();
2335 if(uart_console)
2336 {
2337 rt_device_set_rx_indicate(uart_console, btshell_console.old_rx_ind);
2338 }
2339 rt_hw_interrupt_enable(level);
2340
2341 if (btshell_console.rx_end != RT_NULL)
2342 {
2343 rt_sem_delete(btshell_console.rx_end);
2344 btshell_console.rx_end = RT_NULL;
2345 }
2346
2347 if (btshell_console.rx_fifo != RT_NULL)
2348 {
2349 rt_ringbuffer_destroy(btshell_console.rx_fifo);
2350 btshell_console.rx_fifo = RT_NULL;
2351 }
2352 }
2353
uart_console_getchar(void)2354 static char uart_console_getchar(void)
2355 {
2356 char ch;
2357
2358 rt_sem_take(btshell_console.rx_end, RT_WAITING_FOREVER);
2359 rt_ringbuffer_getchar(btshell_console.rx_fifo, (rt_uint8_t *)&ch);
2360
2361 return ch;
2362 }
2363
rt_btshell_parser(void)2364 static void rt_btshell_parser(void)
2365 {
2366 char ch;
2367 char cur_line[FINSH_CMD_SIZE] = { 0 };
2368 rt_size_t cur_line_len = 0;
2369
2370 rt_kprintf("======== Welcome to enter bluetooth shell mode ========\n");
2371 rt_kprintf("Press 'ESC' to exit.\n");
2372 /* process user input */
2373 while (ESC_KEY != (ch = uart_console_getchar()))
2374 {
2375 if (ch == BACKSPACE_KEY || ch == DELECT_KEY)
2376 {
2377 if (cur_line_len)
2378 {
2379 cur_line[--cur_line_len] = 0;
2380 rt_kprintf("\b \b");
2381 }
2382 continue;
2383 }
2384 else if (ch == '\r' || ch == '\n')
2385 {
2386 cur_line[cur_line_len++] = '\0';
2387 rt_kprintf("\n");
2388 shell_process_command(cur_line);
2389 cur_line_len = 0;
2390 }
2391 else
2392 {
2393 rt_kprintf("%c", ch);
2394 cur_line[cur_line_len++] = ch;
2395 }
2396 }
2397 rt_kprintf("\n");
2398 }
2399
btshell_entry(int argc,char * argv[])2400 static int btshell_entry(int argc, char *argv[])
2401 {
2402 static int btshell_init_flag = 0;
2403
2404 if (btshell_init_flag == 0)
2405 {
2406 btshell_init();
2407 btshell_init_flag = 1;
2408 }
2409 rt_btshell_init();
2410 rt_btshell_parser();
2411 rt_btshell_deinit();
2412
2413 return 0;
2414 }
2415
2416 MSH_CMD_EXPORT_ALIAS(btshell_entry, btshell, "bluetooth shell mode");
2417