xref: /nrf52832-nimble/packages/NimBLE-latest/apps/btshell/src/btshell.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
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