1 /** @file
2 * @brief Bluetooth shell module
3 *
4 * Provide some Bluetooth shell commands that can be useful to applications.
5 */
6
7 /*
8 * Copyright (c) 2017 Intel Corporation
9 *
10 * SPDX-License-Identifier: Apache-2.0
11 */
12
13 #include <bt_errno.h>
14 #include <stddef.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <aos/ble.h>
18 #if AOS_COMP_CLI
19 #include "aos/cli.h"
20 #endif
21
22 #include <misc/byteorder.h>
23 #include <ble_os.h>
24 #include <ble_types/types.h>
25
26 #include <settings/settings.h>
27 //#include <yoc/partition.h>
28 #include <bluetooth/hci.h>
29 #include <bluetooth/bluetooth.h>
30 #include <bluetooth/conn.h>
31 #include <bluetooth/l2cap.h>
32 #include <bluetooth/rfcomm.h>
33 #include <bluetooth/sdp.h>
34 #include <common/log.h>
35 #include <host/conn_internal.h>
36
37
38 /** @brief Callback called when command is entered.
39 *
40 * @param argc Number of parameters passed.
41 * @param argv Array of option strings. First option is always command name.
42 *
43 * @return 0 in case of success or negative value in case of error.
44 */
45 typedef int (*shell_cmd_function_t)(int argc, char *argv[]);
46 // typedef int partition_t;
47 // static partition_t handle = -1;
48 // static hal_logic_partition_t *lp;
49
50
51 struct shell_cmd {
52 const char *cmd_name;
53 shell_cmd_function_t cb;
54 const char *help;
55 const char *desc;
56 };
57
58 #include "bt.h"
59 #include "gatt.h"
60 #include "ll.h"
61
62 #define DEVICE_NAME CONFIG_BT_DEVICE_NAME
63 #define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
64 #define CREDITS 15
65 #define DATA_MTU (23 * CREDITS)
66 #define DATA_BREDR_MTU 48
67
68 static u8_t selected_id = BT_ID_DEFAULT;
69
70 #if defined(CONFIG_BT_CONN)
71 struct bt_conn *default_conn;
72 int16_t g_bt_conn_handle = -1;
73 int16_t g_security_level = 0;
74 uint8_t ble_init_flag = 0;
75
76 typedef struct {
77 dev_addr_t addr;
78 uint8_t set_flag;
79 } wl_addr;
80
81 #define MAX_WL_SZIE 10
82 wl_addr wl_list[MAX_WL_SZIE]= {0};
83
84
85 /* Connection context for BR/EDR legacy pairing in sec mode 3 */
86 static int16_t g_pairing_handle = -1;
87 #endif /* CONFIG_BT_CONN */
88
89 static void device_find(ble_event_en event, void *event_data);
90 #if defined(CONFIG_BT_SMP)
91 static void smp_event(ble_event_en event, void *event_data);
92 #endif
93 static void conn_param_req(ble_event_en event, void *event_data);
94 static void conn_param_update(ble_event_en event, void *event_data);
95
96 #define L2CAP_DYM_CHANNEL_NUM 2
97
98 #if defined(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL)
99 NET_BUF_POOL_DEFINE(data_tx_pool, L2CAP_DYM_CHANNEL_NUM, DATA_MTU, BT_BUF_USER_DATA_MIN, NULL);
100 NET_BUF_POOL_DEFINE(data_rx_pool, L2CAP_DYM_CHANNEL_NUM, DATA_MTU, BT_BUF_USER_DATA_MIN, NULL);
101 #endif
102
103 #if defined(CONFIG_BT_BREDR)
104 NET_BUF_POOL_DEFINE(data_bredr_pool, 1, DATA_BREDR_MTU, BT_BUF_USER_DATA_MIN,
105 NULL);
106
107 #define SDP_CLIENT_USER_BUF_LEN 512
108 NET_BUF_POOL_DEFINE(sdp_client_pool, CONFIG_BT_MAX_CONN,
109 SDP_CLIENT_USER_BUF_LEN, BT_BUF_USER_DATA_MIN, NULL);
110 #endif /* CONFIG_BT_BREDR */
111
112 #if defined(CONFIG_BT_RFCOMM)
113
114 static struct bt_sdp_attribute spp_attrs[] = {
115 BT_SDP_NEW_SERVICE,
116 BT_SDP_LIST(
117 BT_SDP_ATTR_SVCLASS_ID_LIST,
118 BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 3),
119 BT_SDP_DATA_ELEM_LIST(
120 {
121 BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
122 BT_SDP_ARRAY_16(BT_SDP_SERIAL_PORT_SVCLASS)
123 },
124 )
125 ),
126 BT_SDP_LIST(
127 BT_SDP_ATTR_PROTO_DESC_LIST,
128 BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 12),
129 BT_SDP_DATA_ELEM_LIST(
130 {
131 BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 3),
132 BT_SDP_DATA_ELEM_LIST(
133 {
134 BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
135 BT_SDP_ARRAY_16(BT_SDP_PROTO_L2CAP)
136 },
137 )
138 },
139 {
140 BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 5),
141 BT_SDP_DATA_ELEM_LIST(
142 {
143 BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
144 BT_SDP_ARRAY_16(BT_SDP_PROTO_RFCOMM)
145 },
146 {
147 BT_SDP_TYPE_SIZE(BT_SDP_UINT8),
148 BT_SDP_ARRAY_8(BT_RFCOMM_CHAN_SPP)
149 },
150 )
151 },
152 )
153 ),
154 BT_SDP_LIST(
155 BT_SDP_ATTR_PROFILE_DESC_LIST,
156 BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 8),
157 BT_SDP_DATA_ELEM_LIST(
158 {
159 BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),
160 BT_SDP_DATA_ELEM_LIST(
161 {
162 BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
163 BT_SDP_ARRAY_16(BT_SDP_SERIAL_PORT_SVCLASS)
164 },
165 {
166 BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
167 BT_SDP_ARRAY_16(0x0102)
168 },
169 )
170 },
171 )
172 ),
173 BT_SDP_SERVICE_NAME("Serial Port"),
174 };
175
176 static struct bt_sdp_record spp_rec = BT_SDP_RECORD(spp_attrs);
177
178 #endif /* CONFIG_BT_RFCOMM */
179
180 #define NAME_LEN 30
181
addr_le_str(const bt_addr_le_t * addr)182 static char *addr_le_str(const bt_addr_le_t *addr)
183 {
184 static char bufs[2][27];
185 static u8_t cur;
186 char *str;
187
188 str = bufs[cur++];
189 cur %= ARRAY_SIZE(bufs);
190 bt_addr_le_to_str(addr, str, sizeof(bufs[cur]));
191
192 return str;
193 }
194
char2u8(char c)195 static uint8_t char2u8(char c)
196 {
197 if (c >= '0' && c <= '9') {
198 return (c - '0');
199 } else if (c >= 'a' && c <= 'f') {
200 return (c - 'a' + 10);
201 } else if (c >= 'A' && c <= 'F') {
202 return (c - 'A' + 10);
203 } else {
204 return 0;
205 }
206 }
207
str2hex(uint8_t hex[],char * s,uint8_t cnt)208 void str2hex(uint8_t hex[], char *s, uint8_t cnt)
209 {
210 uint8_t i;
211
212 if (!s) {
213 return;
214 }
215
216 for (i = 0; (*s != '\0') && (i < cnt); i++, s += 2) {
217 hex[i] = ((char2u8(*s) & 0x0f) << 4) | ((char2u8(*(s + 1))) & 0x0f);
218 }
219 }
220
bt_addr2str(const dev_addr_t * addr,char * str,uint16_t len)221 static inline int bt_addr2str(const dev_addr_t *addr, char *str,
222 uint16_t len)
223 {
224 char type[10];
225
226 switch (addr->type) {
227 case BT_ADDR_LE_PUBLIC:
228 strcpy(type, "public");
229 break;
230
231 case BT_ADDR_LE_RANDOM:
232 strcpy(type, "random");
233 break;
234
235 default:
236 snprintf(type, sizeof(type), "0x%02x", addr->type);
237 break;
238 }
239
240 return snprintf(str, len, "%02X:%02X:%02X:%02X:%02X:%02X (%s)",
241 addr->val[5], addr->val[4], addr->val[3],
242 addr->val[2], addr->val[1], addr->val[0], type);
243 }
244
245 #if 0
246 static int char2hex(const char *c, u8_t *x)
247 {
248 if (*c >= '0' && *c <= '9') {
249 *x = *c - '0';
250 } else if (*c >= 'a' && *c <= 'f') {
251 *x = *c - 'a' + 10;
252 } else if (*c >= 'A' && *c <= 'F') {
253 *x = *c - 'A' + 10;
254 } else {
255 return -EINVAL;
256 }
257
258 return 0;
259 }
260 #endif
261
str2bt_addr(const char * str,dev_addr_t * addr)262 static int str2bt_addr(const char *str, dev_addr_t *addr)
263 {
264 int i, j;
265 u8_t tmp;
266
267 if (strlen(str) != 17) {
268 return -EINVAL;
269 }
270
271 for (i = 5, j = 1; *str != '\0'; str++, j++) {
272 if (!(j % 3) && (*str != ':')) {
273 return -EINVAL;
274 } else if (*str == ':') {
275 i--;
276 continue;
277 }
278
279 addr->val[i] = addr->val[i] << 4;
280
281 if (char2hex(*str, &tmp) < 0) {
282 return -EINVAL;
283 }
284
285 addr->val[i] |= tmp;
286 }
287
288 return 0;
289 }
290
str2bt_addr_le(const char * str,const char * type,dev_addr_t * addr)291 static int str2bt_addr_le(const char *str, const char *type, dev_addr_t *addr)
292 {
293 int err;
294
295 err = str2bt_addr(str, addr);
296
297 if (err < 0) {
298 return err;
299 }
300
301 if (!strcmp(type, "public") || !strcmp(type, "(public)")) {
302 addr->type = DEV_ADDR_LE_PUBLIC;
303 } else if (!strcmp(type, "random") || !strcmp(type, "(random)")) {
304 addr->type = DEV_ADDR_LE_RANDOM;
305 } else {
306 return -EINVAL;
307 }
308
309 return 0;
310 }
311
conn_change(ble_event_en event,void * event_data)312 static void conn_change(ble_event_en event, void *event_data)
313 {
314 evt_data_gap_conn_change_t *e = (evt_data_gap_conn_change_t *)event_data;
315
316 connect_info_t info;
317 ble_stack_connect_info_get(e->conn_handle, &info);
318
319 if (e->connected == CONNECTED && e->err == 0) {
320 printf("Connected (%d): %s\n", e->conn_handle, addr_le_str((bt_addr_le_t *)&info.peer_addr));
321
322 if (g_bt_conn_handle == -1) {
323 g_bt_conn_handle = e->conn_handle;
324 }
325
326 /* clear connection reference for sec mode 3 pairing */
327 if (g_pairing_handle != -1) {
328 g_pairing_handle = -1;
329 }
330 } else {
331
332 printf("Disconected (%d): %s err %d\n", e->conn_handle, addr_le_str((bt_addr_le_t *)&info.peer_addr), e->err);
333
334 if (e->err == 31) {
335 while (1);
336 }
337
338 if (g_bt_conn_handle == e->conn_handle) {
339 g_bt_conn_handle = -1;
340 }
341
342 g_security_level = 0;
343 }
344 }
345
conn_security_change(ble_event_en event,void * event_data)346 static void conn_security_change(ble_event_en event, void *event_data)
347 {
348 evt_data_gap_security_change_t *e = (evt_data_gap_security_change_t *)event_data;
349 printf("conn %d security level change to level%d\n", e->conn_handle, e->level);
350 g_security_level = e->level;
351 }
352
event_callback(ble_event_en event,void * event_data)353 static int event_callback(ble_event_en event, void *event_data)
354 {
355 switch (event) {
356 case EVENT_GAP_CONN_CHANGE:
357 conn_change(event, event_data);
358 break;
359
360 case EVENT_GAP_CONN_SECURITY_CHANGE:
361 conn_security_change(event, event_data);
362 break;
363
364 case EVENT_GAP_DEV_FIND:
365 device_find(event, event_data);
366 break;
367
368 case EVENT_GAP_CONN_PARAM_REQ:
369 conn_param_req(event, event_data);
370 break;
371
372 case EVENT_GAP_CONN_PARAM_UPDATE:
373 conn_param_update(event, event_data);
374 break;
375 #if defined(CONFIG_BT_SMP)
376
377 case EVENT_SMP_PASSKEY_DISPLAY:
378 case EVENT_SMP_PASSKEY_CONFIRM:
379 case EVENT_SMP_PASSKEY_ENTER:
380 case EVENT_SMP_PAIRING_CONFIRM:
381 case EVENT_SMP_PAIRING_COMPLETE:
382 case EVENT_SMP_CANCEL:
383 smp_event(event, event_data);
384 break;
385 #endif
386
387 default:
388 //printf("Unhandle event %d\n", event);
389 break;
390 }
391
392 return 0;
393 }
394
395 static ble_event_cb_t ble_cb = {
396 .callback = event_callback,
397 };
398
cmd_init(int argc,char * argv[])399 static int cmd_init(int argc, char *argv[])
400 {
401 int err;
402 dev_addr_t addr;
403 init_param_t init = {NULL, NULL, 1};
404
405 #if defined(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL)
406 NET_BUF_POOL_INIT(data_tx_pool);
407 NET_BUF_POOL_INIT(data_rx_pool);
408 #endif
409
410 #if defined(CONFIG_BT_BREDR)
411 NET_BUF_POOL_INIT(data_bredr_pool);
412 NET_BUF_POOL_INIT(sdp_client_pool);
413 #endif /* CONFIG_BT_BREDR */
414
415 if (argc == 3) {
416 err = str2bt_addr_le(argv[1], argv[2], &addr);
417
418 if (err) {
419 printf("Invalid address\n");
420 return err;
421 }
422
423 init.dev_addr = &addr;
424 }
425
426 err = ble_stack_init(&init);
427
428 if (err) {
429 printf("Bluetooth init failed (err %d)\n", err);
430 return err;
431 }
432
433 err = ble_stack_event_register(&ble_cb);
434 if(err) {
435 printf("Bluetooth stack init fail\n");
436 return -1;
437 } else {
438 printf("Bluetooth stack init success\n");
439 }
440
441 ble_init_flag = 1;
442
443 return 0;
444 }
445
446 #if defined(CONFIG_BT_HCI) || defined(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL)
hexdump(const u8_t * data,size_t len)447 void hexdump(const u8_t *data, size_t len)
448 {
449 int n = 0;
450
451 while (len--) {
452 if (n % 16 == 0) {
453 printf("%08X ", n);
454 }
455
456 printf("%02X ", *data++);
457
458 n++;
459
460 if (n % 8 == 0) {
461 if (n % 16 == 0) {
462 printf("\n");
463 } else {
464 printf(" ");
465 }
466 }
467 }
468
469 if (n % 16) {
470 printf("\n");
471 }
472 }
473 #endif /* CONFIG_BT_HCI || CONFIG_BT_L2CAP_DYNAMIC_CHANNEL */
474
475 #if defined(CONFIG_BT_HCI)
cmd_hci_cmd(int argc,char * argv[])476 static int cmd_hci_cmd(int argc, char *argv[])
477 {
478 u8_t ogf;
479 u16_t ocf;
480 struct net_buf *buf = NULL, *rsp;
481 int err;
482
483 if (argc < 3) {
484 return -EINVAL;
485 }
486
487 ogf = strtoul(argv[1], NULL, 16);
488 ocf = strtoul(argv[2], NULL, 16);
489
490 if (argc > 3) {
491 int i;
492
493 buf = bt_hci_cmd_create(BT_OP(ogf, ocf), argc - 3);
494
495 for (i = 3; i < argc; i++) {
496 net_buf_add_u8(buf, strtoul(argv[i], NULL, 16));
497 }
498 }
499
500 err = bt_hci_cmd_send_sync(BT_OP(ogf, ocf), buf, &rsp);
501
502 if (err) {
503 printf("HCI command failed (err %d)\n", err);
504 } else {
505 hexdump(rsp->data, rsp->len);
506 net_buf_unref(rsp);
507 }
508
509 return 0;
510 }
511 #endif /* CONFIG_BT_HCI */
512
cmd_name(int argc,char * argv[])513 static int cmd_name(int argc, char *argv[])
514 {
515 int err;
516
517 if (argc < 2) {
518 printf("Bluetooth Local Name: %s\n", bt_get_name());
519 return 0;
520 }
521
522 err = bt_set_name(argv[1]);
523
524 if (err) {
525 printf("Unable to set name %s (err %d)", argv[1], err);
526 }
527
528 return 0;
529 }
530
cmd_id_create(int argc,char * argv[])531 static int cmd_id_create(int argc, char *argv[])
532 {
533 dev_addr_t addr;
534 int err;
535
536 if (argc > 1) {
537 err = str2bt_addr_le(argv[1], "random", &addr);
538
539 if (err) {
540 printf("Invalid address\n");
541 return err;
542 }
543 } else {
544 bt_addr_le_copy((bt_addr_le_t *)&addr, BT_ADDR_LE_ANY);
545 }
546
547 err = bt_id_create((bt_addr_le_t *)&addr, NULL);
548
549 if (err < 0) {
550 printf("Creating new ID failed (err %d)\n", err);
551 return 0;
552 }
553
554 printf("New identity (%d) created: %s\n", err, addr_le_str((bt_addr_le_t *)&addr));
555
556 return 0;
557 }
558
cmd_id_reset(int argc,char * argv[])559 static int cmd_id_reset(int argc, char *argv[])
560 {
561 bt_addr_le_t addr;
562 u8_t id;
563 int err;
564
565 if (argc < 2) {
566 printf("Identity identifier not specified\n");
567 return -EINVAL;
568 }
569
570 id = strtol(argv[1], NULL, 10);
571
572 if (argc > 2) {
573 err = str2bt_addr_le(argv[2], "random", (dev_addr_t *)&addr);
574
575 if (err) {
576 printf("Invalid address\n");
577 return err;
578 }
579 } else {
580 bt_addr_le_copy(&addr, BT_ADDR_LE_ANY);
581 }
582
583 err = bt_id_reset(id, &addr, NULL);
584
585 if (err < 0) {
586 printf("Resetting ID %u failed (err %d)\n", id, err);
587 return 0;
588 }
589
590 printf("Identity %u reset: %s\n", id, addr_le_str(&addr));
591
592 return 0;
593 }
594
cmd_id_delete(int argc,char * argv[])595 static int cmd_id_delete(int argc, char *argv[])
596 {
597 u8_t id;
598 int err;
599
600 if (argc < 2) {
601 printf("Identity identifier not specified\n");
602 return -EINVAL;
603 }
604
605 id = strtol(argv[1], NULL, 10);
606
607 err = bt_id_delete(id);
608
609 if (err < 0) {
610 printf("Deleting ID %u failed (err %d)\n", id, err);
611 return 0;
612 }
613
614 printf("Identity %u deleted\n", id);
615
616 return 0;
617 }
618
cmd_id_show(int argc,char * argv[])619 static int cmd_id_show(int argc, char *argv[])
620 {
621 bt_addr_le_t addrs[CONFIG_BT_ID_MAX];
622 size_t i, count = CONFIG_BT_ID_MAX;
623
624 bt_id_get(addrs, &count);
625
626 for (i = 0; i < count; i++) {
627 printf("%s%zu: %s\n", i == selected_id ? "*" : " ", i,
628 addr_le_str(&addrs[i]));
629 }
630
631 return 0;
632 }
633
cmd_id_select(int argc,char * argv[])634 static int cmd_id_select(int argc, char *argv[])
635 {
636 bt_addr_le_t addrs[CONFIG_BT_ID_MAX];
637 size_t count = CONFIG_BT_ID_MAX;
638 u8_t id;
639
640 if (argc < 2) {
641 return -EINVAL;
642 }
643
644 id = strtol(argv[1], NULL, 10);
645
646 bt_id_get(addrs, &count);
647
648 if (count <= id) {
649 printf("Invalid identity\n");
650 return 0;
651 }
652
653 //printf("Selected identity: %s\n", addr_le_str(&addrs[id]));
654 selected_id = id;
655
656 return 0;
657 }
658
parse_ad(uint8_t * data,uint16_t len,int (* cb)(ad_data_t * data,void * arg),void * cb_arg)659 static inline int parse_ad(uint8_t *data, uint16_t len, int (* cb)(ad_data_t *data, void *arg), void *cb_arg)
660 {
661 int num = 0;
662 uint8_t *pdata = data;
663 ad_data_t ad = {0};
664 int ret;
665
666 while (len) {
667 if (pdata[0] == 0) {
668 return num;
669 }
670
671 if (len < pdata[0] + 1) {
672 return -1;
673 };
674
675 ad.len = pdata[0] - 1;
676
677 ad.type = pdata[1];
678
679 ad.data = &pdata[2];
680
681 if (cb) {
682 ret = cb(&ad, cb_arg);
683
684 if (ret) {
685 break;
686 }
687 }
688
689 num++;
690 len -= (pdata[0] + 1);
691 pdata += (pdata[0] + 1);
692 }
693
694 return num;
695 }
696
697 uint8_t *pscan_ad = NULL;
698 uint8_t *pscan_sd = NULL;
699
scan_ad_cmp(ad_data_t * ad,void * arg)700 static int scan_ad_cmp(ad_data_t *ad, void *arg)
701 {
702 ad_data_t *ad2 = arg;
703
704 return (ad->type == ad2->type && ad->len == ad2->len
705 && 0 == memcmp(ad->data, ad2->data, ad->len));
706 }
707
scan_ad_callback(ad_data_t * ad,void * arg)708 static int scan_ad_callback(ad_data_t *ad, void *arg)
709 {
710 evt_data_gap_dev_find_t *e = arg;
711 int ad_num;
712 uint8_t *pad = NULL;
713 int ret;
714
715 if (e->adv_len) {
716 if (e->adv_type == 0x04) {
717 pad = pscan_sd;
718 } else {
719 pad = pscan_ad;
720 }
721
722 ad_num = parse_ad(pad, 31, NULL, NULL);
723
724 ret = parse_ad(pad, 31, scan_ad_cmp, (void *)ad);
725
726 if (ret < ad_num) {
727 return 1;
728 }
729 }
730
731 return 0;
732 }
733
device_find(ble_event_en event,void * event_data)734 static void device_find(ble_event_en event, void *event_data)
735 {
736 evt_data_gap_dev_find_t *e = event_data;
737 int ad_num = parse_ad(e->adv_data, e->adv_len, NULL, NULL);
738 int ret;
739 char addr_str[32] = {0};
740
741 bt_addr2str(&e->dev_addr, addr_str, sizeof(addr_str));
742
743 if (pscan_ad || pscan_sd) {
744 ret = parse_ad(e->adv_data, e->adv_len, scan_ad_callback, event_data);
745
746 if (ret < ad_num) {
747 printf("[DEVICE]: %s, adv type %d, rssi %d, Raw data:%s\n", addr_str, e->adv_type, e->rssi, bt_hex(e->adv_data, e->adv_len));
748 }
749 } else {
750 printf("[DEVICE]: %s, adv type %d, rssi %d, Raw data:%s\n", addr_str, e->adv_type, e->rssi, bt_hex(e->adv_data, e->adv_len));
751 }
752 }
753
conn_param_req(ble_event_en event,void * event_data)754 static void conn_param_req(ble_event_en event, void *event_data)
755 {
756 evt_data_gap_conn_param_req_t *e = event_data;
757 printf("LE conn param req: int (0x%04x, 0x%04x) lat %d to %d\n",
758 e->param.interval_min, e->param.interval_max, e->param.latency,
759 e->param.timeout);
760
761 e->accept = 1;
762 }
763
conn_param_update(ble_event_en event,void * event_data)764 static void conn_param_update(ble_event_en event, void *event_data)
765 {
766 evt_data_gap_conn_param_update_t *e = event_data;
767
768 printf("LE conn param updated: int 0x%04x lat %d to %d\n", e->interval,
769 e->latency, e->timeout);
770 }
771
772 static uint8_t scan_filter = 0;
cmd_scan_filter(int argc,char * argv[])773 static int cmd_scan_filter(int argc, char *argv[])
774 {
775 if (argc < 2) {
776 return -EINVAL;
777 }
778
779 scan_filter = atoi(argv[1]);
780
781 if (scan_filter > SCAN_FILTER_POLICY_WHITE_LIST) {
782 scan_filter = 0;
783 return -EINVAL;
784 }
785
786 printf("Set scan filter %s\n", scan_filter == 0 ? "SCAN_FILTER_POLICY_ANY_ADV" : "SCAN_FILTER_POLICY_WHITE_LIST");
787 return 0;
788 }
789
cmd_scan(int argc,char * argv[])790 static int cmd_scan(int argc, char *argv[])
791 {
792 static uint8_t scan_ad[31] = {0};
793 static uint8_t scan_sd[31] = {0};
794
795 scan_param_t params = {
796 SCAN_PASSIVE,
797 SCAN_FILTER_DUP_DISABLE,
798 SCAN_FAST_INTERVAL,
799 SCAN_FAST_WINDOW,
800 };
801
802 params.scan_filter = scan_filter;
803
804 if (argc < 2) {
805 return -EINVAL;
806 }
807
808
809 if (argc >= 2) {
810 if (!strcmp(argv[1], "active")) {
811 params.type = SCAN_ACTIVE;
812 } else if (!strcmp(argv[1], "off")) {
813 pscan_ad = NULL;
814 pscan_sd = NULL;
815 return ble_stack_scan_stop();
816 } else if (!strcmp(argv[1], "passive")) {
817 params.type = SCAN_PASSIVE;
818 } else {
819
820 return -EINVAL;
821 }
822 }
823
824 if (argc >= 3) {
825 if (!strcmp(argv[2], "dups")) {
826 params.filter_dup = SCAN_FILTER_DUP_DISABLE;
827 } else if (!strcmp(argv[2], "nodups")) {
828 params.filter_dup = SCAN_FILTER_DUP_ENABLE;
829 } else {
830 return -EINVAL;
831 }
832 }
833
834 if (argc >= 4) {
835 params.interval = strtol(argv[3], NULL, 10);
836 }
837
838 if (argc >= 5) {
839 params.window = strtol(argv[4], NULL, 10);
840 }
841
842 if (argc >= 6) {
843 pscan_ad = scan_ad;
844 memset(scan_ad, 0, sizeof(scan_ad));
845 str2hex(scan_ad, argv[5], sizeof(scan_ad));
846 }
847
848 if (argc >= 7) {
849 pscan_sd = scan_sd;
850 memset(scan_sd, 0, sizeof(scan_sd));
851 str2hex(scan_sd, argv[6], sizeof(scan_sd));
852 }
853
854 return ble_stack_scan_start(¶ms);
855 }
856
parse_ad_data(uint8_t * data,uint16_t len,ad_data_t * ad,uint8_t * ad_num)857 static inline int parse_ad_data(uint8_t *data, uint16_t len, ad_data_t *ad, uint8_t *ad_num)
858 {
859 uint8_t num = 0;
860 uint8_t *pdata = data;
861
862 while (len) {
863 if (len < pdata[0] + 1) {
864 *ad_num = 0;
865 return -1;
866 };
867
868 num++;
869
870 if (ad && num <= *ad_num) {
871 ad->len = pdata[0] - 1;
872 ad->type = pdata[1];
873 ad->data = &pdata[2];
874 }
875
876 len -= (pdata[0] + 1);
877 pdata += (pdata[0] + 1);
878
879 if (ad) {
880 ad++;
881 }
882 }
883
884 *ad_num = num;
885 return 0;
886 }
887
adv_ad_callback(ad_data_t * ad,void * arg)888 static inline int adv_ad_callback(ad_data_t *ad, void *arg)
889 {
890 ad_data_t **pad = (ad_data_t **)arg;
891
892 (*pad)->type = ad->type;
893 (*pad)->len = ad->len;
894 (*pad)->data = ad->data;
895 (*pad)++;
896 return 0;
897 }
898
cmd_advertise(int argc,char * argv[])899 static int cmd_advertise(int argc, char *argv[])
900 {
901 int err;
902 adv_param_t param = {0};
903 uint8_t ad_hex[31] = {0};
904 uint8_t sd_hex[31] = {0};
905 ad_data_t ad[10] = {0};
906 int8_t ad_num = 0;
907 ad_data_t sd[10] = {0};
908 int8_t sd_num = 0;
909
910
911 if (argc < 2) {
912 goto fail;
913 }
914
915 if (!strcmp(argv[1], "stop")) {
916 if (bt_le_adv_stop() < 0) {
917 printf("Failed to stop advertising\n");
918 } else {
919 printf("Advertising stopped\n");
920 }
921
922 return 0;
923 }
924
925 if (!strcmp(argv[1], "nconn")) {
926 param.type = ADV_NONCONN_IND;
927 } else if (!strcmp(argv[1], "conn")) {
928 param.type = ADV_IND;
929 }
930
931
932 if (argc > 2) {
933 if (strlen(argv[2]) > 62) {
934 printf("max len\n");
935 goto fail;
936 }
937
938 str2hex(ad_hex, argv[2], sizeof(ad_hex));
939
940 ad_data_t *pad = ad;
941 ad_num = parse_ad(ad_hex, strlen(argv[2]) / 2, adv_ad_callback, (void *)&pad);
942 }
943
944 if (argc > 3) {
945 if (strlen(argv[3]) > 62) {
946 printf("max len\n");
947 goto fail;
948 }
949
950 str2hex(sd_hex, argv[3], sizeof(sd_hex));
951 ad_data_t *psd = sd;
952 sd_num = parse_ad(sd_hex, strlen(argv[3]) / 2, adv_ad_callback, (void *)&psd);
953 }
954
955
956 param.ad = ad_num > 0 ?ad:NULL;
957 param.sd = sd_num> 0 ?sd:NULL;
958 param.ad_num = (uint8_t)ad_num;
959 param.sd_num = (uint8_t)sd_num;
960 param.interval_min = ADV_FAST_INT_MIN_2;
961 param.interval_max = ADV_FAST_INT_MAX_2;
962
963 err = ble_stack_adv_start(¶m);
964
965 if (err < 0) {
966 printf("Failed to start advertising (err %d)\n", err);
967 } else {
968 printf("adv_type:%x;adv_interval_min:%d (*0.625)ms;adv_interval_max:%d (*0.625)ms\n", param.type, (int)param.interval_min, (int)param.interval_max);
969 printf("Advertising started\n");
970 }
971
972 return 0;
973
974 fail:
975
976 return -EINVAL;
977 }
978
979 #if defined(CONFIG_BT_CONN)
cmd_connect_le(int argc,char * argv[])980 static int cmd_connect_le(int argc, char *argv[])
981 {
982 int err;
983 dev_addr_t addr;
984 int16_t conn_handle;
985 conn_param_t param = {
986 CONN_INT_MIN_INTERVAL,
987 CONN_INT_MAX_INTERVAL,
988 0,
989 400,
990 };
991
992 if (argc < 3) {
993 return -EINVAL;
994 }
995
996 if (argc >= 3) {
997 err = str2bt_addr_le(argv[1], argv[2], &addr);
998
999 if (err) {
1000 printf("Invalid peer address (err %d)\n", err);
1001 return 0;
1002 }
1003 }
1004
1005 if (argc >= 5) {
1006 param.interval_min = strtol(argv[3], NULL, 16);
1007 param.interval_max = strtol(argv[4], NULL, 16);
1008 }
1009
1010 if (argc >= 7) {
1011 param.latency = strtol(argv[5], NULL, 16);
1012 param.timeout = strtol(argv[6], NULL, 16);
1013 }
1014
1015 conn_handle = ble_stack_connect(&addr, ¶m, 0);
1016
1017 if (conn_handle < 0) {
1018 printf("Connection failed\n");
1019 return -EIO;
1020 }
1021
1022 return 0;
1023 }
1024
cmd_disconnect(int argc,char * argv[])1025 static int cmd_disconnect(int argc, char *argv[])
1026 {
1027 int16_t conn_handle = 0;
1028 int err;
1029
1030 if (g_bt_conn_handle != -1 && argc < 2) {
1031 conn_handle = g_bt_conn_handle;
1032 } else {
1033 if (argc < 2) {
1034 return -EINVAL;
1035 }
1036
1037 conn_handle = strtol(argv[1], NULL, 10);
1038 }
1039
1040 err = ble_stack_disconnect(conn_handle);
1041
1042 if (err) {
1043 printf("Disconnection failed (err %d)\n", err);
1044 }
1045
1046 return 0;
1047 }
1048
cmd_auto_conn(int argc,char * argv[])1049 static int cmd_auto_conn(int argc, char *argv[])
1050 {
1051 dev_addr_t addr;
1052 conn_param_t param = {
1053 CONN_INT_MIN_INTERVAL,
1054 CONN_INT_MAX_INTERVAL,
1055 0,
1056 400,
1057 };
1058 int err;
1059 conn_param_t *pparam = NULL;
1060 uint8_t auto_conn = 1;
1061
1062 if (argc < 3) {
1063 return -EINVAL;
1064 }
1065
1066 err = str2bt_addr_le(argv[1], argv[2], &addr);
1067
1068 if (err) {
1069 printf("Invalid peer address (err %d)\n", err);
1070 return -EINVAL;
1071 }
1072
1073 if (argc > 3) {
1074 if (!strcmp(argv[3], "on")) {
1075 auto_conn = 1;
1076 pparam = ¶m;
1077 } else if (!strcmp(argv[3], "off")) {
1078 auto_conn = 0;
1079 pparam = NULL;
1080 } else {
1081 return -EINVAL;
1082 }
1083 } else {
1084 auto_conn = 1;
1085 pparam = ¶m;
1086 }
1087
1088 err = ble_stack_connect(&addr, pparam, auto_conn);
1089
1090 if (err < 0) {
1091 return err;
1092 }
1093
1094 printf("connect (%d) pending\n", err);
1095 return 0;
1096 }
1097
cmd_select(int argc,char * argv[])1098 static int cmd_select(int argc, char *argv[])
1099 {
1100 struct bt_conn *conn;
1101 bt_addr_le_t addr;
1102 int err;
1103
1104 if (argc < 3) {
1105 return -EINVAL;
1106 }
1107
1108 err = str2bt_addr_le(argv[1], argv[2], (dev_addr_t *)&addr);
1109
1110 if (err) {
1111 printf("Invalid peer address (err %d)\n", err);
1112 return 0;
1113 }
1114
1115 conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &addr);
1116
1117 if (!conn) {
1118 printf("No matching connection found\n");
1119 return 0;
1120 }
1121
1122 if (default_conn) {
1123 bt_conn_unref(default_conn);
1124 }
1125
1126 default_conn = conn;
1127
1128 return 0;
1129 }
1130
cmd_conn_update(int argc,char * argv[])1131 static int cmd_conn_update(int argc, char *argv[])
1132 {
1133 conn_param_t param;
1134 int err;
1135
1136 if (argc < 5) {
1137 return -EINVAL;
1138 }
1139
1140 param.interval_min = strtoul(argv[1], NULL, 16);
1141 param.interval_max = strtoul(argv[2], NULL, 16);
1142 param.latency = strtoul(argv[3], NULL, 16);
1143 param.timeout = strtoul(argv[4], NULL, 16);
1144 err = ble_stack_connect_param_update(g_bt_conn_handle, ¶m);
1145
1146 if (err) {
1147 printf("conn update failed (err %d).\n", err);
1148 } else {
1149 printf("conn update initiated.\n");
1150 }
1151
1152 return 0;
1153 }
1154
cmd_oob(int argc,char * argv[])1155 static int cmd_oob(int argc, char *argv[])
1156 {
1157 char addr[BT_ADDR_LE_STR_LEN];
1158 struct bt_le_oob oob;
1159 int err;
1160
1161 err = bt_le_oob_get_local(selected_id, &oob);
1162
1163 if (err) {
1164 printf("OOB data failed\n");
1165 return 0;
1166 }
1167
1168 bt_addr_le_to_str(&oob.addr, addr, sizeof(addr));
1169
1170 printf("OOB data:\n");
1171 printf(" addr %s\n", addr);
1172
1173 return 0;
1174 }
1175
cmd_clear(int argc,char * argv[])1176 static int cmd_clear(int argc, char *argv[])
1177 {
1178 dev_addr_t addr;
1179 int err;
1180
1181 if (argc < 2) {
1182 printf("Specify remote address or \"all\"\n");
1183 return 0;
1184 }
1185
1186 if (strcmp(argv[1], "all") == 0) {
1187 // err = bt_unpair(selected_id, NULL);
1188 err = ble_stack_dev_unpair(NULL);
1189
1190 if (err) {
1191 printf("Failed to clear pairings (err %d)\n", err);
1192 } else {
1193 printf("Pairings successfully cleared\n");
1194 }
1195
1196 return 0;
1197 }
1198
1199 if (argc < 3) {
1200 #if defined(CONFIG_BT_BREDR)
1201 addr.type = BT_ADDR_LE_PUBLIC;
1202 err = str2bt_addr(argv[1], &addr.a);
1203 #else
1204 printf("Both address and address type needed\n");
1205 return 0;
1206 #endif
1207 } else {
1208 err = str2bt_addr_le(argv[1], argv[2], (dev_addr_t *)&addr);
1209 }
1210
1211 if (err) {
1212 printf("Invalid address\n");
1213 return 0;
1214 }
1215
1216 //err = bt_unpair(selected_id, &addr);
1217 err = ble_stack_dev_unpair(&addr);
1218
1219 if (err) {
1220 printf("Failed to clear pairing (err %d)\n", err);
1221 } else {
1222 printf("Pairing successfully cleared\n");
1223 }
1224
1225 return 0;
1226 }
1227 #endif /* CONFIG_BT_CONN */
1228
1229 #if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR)
cmd_security(int argc,char * argv[])1230 static int cmd_security(int argc, char *argv[])
1231 {
1232 int err, sec;
1233
1234 if (g_bt_conn_handle == -1) {
1235 printf("Not connected\n");
1236 return 0;
1237 }
1238
1239 if (argc < 2) {
1240 return -EINVAL;
1241 }
1242
1243 sec = *argv[1] - '0';
1244
1245 err = ble_stack_security(g_bt_conn_handle, sec);
1246
1247 if (err) {
1248 printf("Setting security failed (err %d)\n", err);
1249 }
1250
1251 return 0;
1252 }
1253
smp_passkey_display(evt_data_smp_passkey_display_t * e)1254 static void smp_passkey_display(evt_data_smp_passkey_display_t *e)
1255 {
1256 char addr[32];
1257
1258 bt_addr2str(&e->peer_addr, addr, 32);
1259
1260 printf("Passkey for %s: %s\n", addr, e->passkey);
1261 }
1262
smp_passkey_confirm(evt_data_smp_passkey_confirm_t * e)1263 static void smp_passkey_confirm(evt_data_smp_passkey_confirm_t *e)
1264 {
1265 char addr[32];
1266
1267 bt_addr2str(&e->peer_addr, addr, 32);
1268
1269 printf("Pairing passkey for %s: %s\n", addr, e->passkey);
1270 }
1271
smp_passkey_entry(evt_data_smp_passkey_enter_t * e)1272 static void smp_passkey_entry(evt_data_smp_passkey_enter_t *e)
1273 {
1274 char addr[32];
1275
1276 bt_addr2str(&e->peer_addr, addr, 32);
1277
1278 printf("Enter passkey for %s\n", addr);
1279 }
1280
smp_cancel(evt_data_smp_cancel_t * e)1281 static void smp_cancel(evt_data_smp_cancel_t *e)
1282 {
1283 char addr[32];
1284
1285 bt_addr2str(&e->peer_addr, addr, 32);
1286
1287 printf("Pairing cancelled: %s\n", addr);
1288
1289 /* clear connection reference for sec mode 3 pairing */
1290 if (g_pairing_handle) {
1291 g_pairing_handle = -1;
1292 }
1293 }
1294
smp_pairing_confirm(evt_data_smp_pairing_confirm_t * e)1295 static void smp_pairing_confirm(evt_data_smp_pairing_confirm_t *e)
1296 {
1297 char addr[32];
1298
1299 bt_addr2str(&e->peer_addr, addr, 32);
1300
1301 printf("Confirm pairing for %s\n", addr);
1302 }
1303
smp_pairing_complete(evt_data_smp_pairing_complete_t * e)1304 static void smp_pairing_complete(evt_data_smp_pairing_complete_t *e)
1305 {
1306 char addr[32];
1307
1308 bt_addr2str(&e->peer_addr, addr, 32);
1309
1310 if (e->err) {
1311 printf("Pairing failed with %s, err %d\n", addr, e->err);
1312 } else {
1313 printf("%s with %s\n", e->bonded ? "Bonded" : "Paired", addr);
1314 }
1315 }
1316
smp_event(ble_event_en event,void * event_data)1317 static void smp_event(ble_event_en event, void *event_data)
1318 {
1319 switch (event) {
1320 case EVENT_SMP_PASSKEY_DISPLAY:
1321 smp_passkey_display(event_data);
1322 break;
1323
1324 case EVENT_SMP_PASSKEY_CONFIRM:
1325 smp_passkey_confirm(event_data);
1326 break;
1327
1328 case EVENT_SMP_PASSKEY_ENTER:
1329 smp_passkey_entry(event_data);
1330 break;
1331
1332 case EVENT_SMP_PAIRING_CONFIRM:
1333 smp_pairing_confirm(event_data);
1334 break;
1335
1336 case EVENT_SMP_PAIRING_COMPLETE:
1337 smp_pairing_complete(event_data);
1338 break;
1339
1340 case EVENT_SMP_CANCEL:
1341 smp_cancel(event_data);
1342 break;
1343
1344 default:
1345 break;
1346 }
1347 }
1348
cmd_iocap_set(int argc,char * argv[])1349 static int cmd_iocap_set(int argc, char *argv[])
1350 {
1351 uint8_t io_cap = 0;
1352
1353 if (argc < 3) {
1354 return -EINVAL;
1355 }
1356
1357 if (!strcmp(argv[1], "NONE")) {
1358 io_cap |= IO_CAP_IN_NONE;
1359 } else if (!strcmp(argv[1], "YESNO")) {
1360 io_cap |= IO_CAP_IN_YESNO;
1361 } else if (!strcmp(argv[1], "KEYBOARD")) {
1362 io_cap |= IO_CAP_IN_KEYBOARD;
1363 } else {
1364 return -EINVAL;
1365 }
1366
1367 if (!strcmp(argv[2], "NONE")) {
1368 io_cap |= IO_CAP_OUT_NONE;
1369 } else if (!strcmp(argv[2], "DISPLAY")) {
1370 io_cap |= IO_CAP_OUT_DISPLAY;
1371 } else {
1372 return -EINVAL;
1373 }
1374
1375 return ble_stack_iocapability_set(io_cap);
1376 }
1377
cmd_auth_cancel(int argc,char * argv[])1378 static int cmd_auth_cancel(int argc, char *argv[])
1379 {
1380 int16_t conn_handle;
1381
1382 if (g_bt_conn_handle != -1) {
1383 conn_handle = g_bt_conn_handle;
1384 } else if (g_pairing_handle != -1) {
1385 conn_handle = g_pairing_handle;
1386 } else {
1387 conn_handle = 0;
1388 }
1389
1390 ble_stack_smp_cancel(conn_handle);
1391 return 0;
1392 }
1393
cmd_auth_passkey_confirm(int argc,char * argv[])1394 static int cmd_auth_passkey_confirm(int argc, char *argv[])
1395 {
1396 if (g_bt_conn_handle == -1) {
1397 printf("Not connected\n");
1398 return 0;
1399 }
1400
1401 ble_stack_smp_passkey_confirm(g_bt_conn_handle);
1402 return 0;
1403 }
1404
cmd_auth_pairing_confirm(int argc,char * argv[])1405 static int cmd_auth_pairing_confirm(int argc, char *argv[])
1406 {
1407 if (g_bt_conn_handle == -1) {
1408 printf("Not connected\n");
1409 return 0;
1410 }
1411
1412 ble_stack_smp_pairing_confirm(g_bt_conn_handle);
1413
1414 return 0;
1415 }
1416
1417 #if defined(CONFIG_BT_FIXED_PASSKEY)
cmd_fixed_passkey(int argc,char * argv[])1418 static int cmd_fixed_passkey(int argc, char *argv[])
1419 {
1420 unsigned int passkey;
1421 int err;
1422
1423 if (argc < 2) {
1424 bt_passkey_set(BT_PASSKEY_INVALID);
1425 printf("Fixed passkey cleared\n");
1426 return 0;
1427 }
1428
1429 passkey = atoi(argv[1]);
1430
1431 if (passkey > 999999) {
1432 printf("Passkey should be between 0-999999\n");
1433 return 0;
1434 }
1435
1436 err = bt_passkey_set(passkey);
1437
1438 if (err) {
1439 printf("Setting fixed passkey failed (err %d)\n", err);
1440 }
1441
1442 return 0;
1443 }
1444 #endif
1445
cmd_auth_passkey(int argc,char * argv[])1446 static int cmd_auth_passkey(int argc, char *argv[])
1447 {
1448 unsigned int passkey;
1449
1450 if (g_bt_conn_handle == -1) {
1451 printf("Not connected\n");
1452 return 0;
1453 }
1454
1455 if (argc < 2) {
1456 return -EINVAL;
1457 }
1458
1459 passkey = atoi(argv[1]);
1460
1461 if (passkey > 999999) {
1462 printf("Passkey should be between 0-999999\n");
1463 return 0;
1464 }
1465
1466 ble_stack_smp_passkey_entry(g_bt_conn_handle, passkey);
1467 return 0;
1468 }
1469 #endif /* CONFIG_BT_SMP) || CONFIG_BT_BREDR */
1470
1471 #if defined(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL)
1472 static bt_u32_t l2cap_rate;
1473
l2cap_recv_metrics(struct bt_l2cap_chan * chan,struct net_buf * buf)1474 static void l2cap_recv_metrics(struct bt_l2cap_chan *chan, struct net_buf *buf)
1475 {
1476 return;
1477 }
1478
l2cap_recv(struct bt_l2cap_chan * chan,struct net_buf * buf)1479 static void l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
1480 {
1481 printf("Incoming data channel %p psm %d len %u\n", chan, chan->psm, buf->len);
1482
1483 if (buf->len) {
1484 hexdump(buf->data, buf->len);
1485 }
1486 }
1487
l2cap_connected(struct bt_l2cap_chan * chan)1488 static void l2cap_connected(struct bt_l2cap_chan *chan)
1489 {
1490 printf("Channel %p psm %d connected\n", chan, chan->psm);
1491 }
1492
l2cap_disconnected(struct bt_l2cap_chan * chan)1493 static void l2cap_disconnected(struct bt_l2cap_chan *chan)
1494 {
1495 printf("Channel %p psm %d disconnected\n", chan, chan->psm);
1496 }
1497
l2cap_alloc_buf(struct bt_l2cap_chan * chan)1498 static struct net_buf *l2cap_alloc_buf(struct bt_l2cap_chan *chan)
1499 {
1500 /* print if metrics is disabled */
1501 if (chan->ops->recv != l2cap_recv_metrics) {
1502 printf("Channel %p requires buffer\n", chan);
1503 }
1504
1505 return net_buf_alloc(&data_rx_pool, K_FOREVER);
1506 }
1507
1508 static struct bt_l2cap_chan_ops l2cap_ops = {
1509 .alloc_buf = l2cap_alloc_buf,
1510 .recv = l2cap_recv,
1511 .connected = l2cap_connected,
1512 .disconnected = l2cap_disconnected,
1513 };
1514
1515 static struct bt_l2cap_le_chan l2cap_chan[L2CAP_DYM_CHANNEL_NUM] = {
1516 0
1517 };
1518
l2cap_accept(struct bt_conn * conn,struct bt_l2cap_chan ** chan)1519 static int l2cap_accept(struct bt_conn *conn, struct bt_l2cap_chan **chan)
1520 {
1521 printf("Incoming conn %p\n", conn);
1522
1523 int i;
1524
1525 for (i = 0; i < L2CAP_DYM_CHANNEL_NUM; i++) {
1526 if (l2cap_chan[i].chan.conn == NULL) {
1527 break;
1528 }
1529 }
1530
1531 if (i == L2CAP_DYM_CHANNEL_NUM) {
1532 printf("No channels available\n");
1533 return -ENOMEM;
1534 }
1535
1536 l2cap_chan[i].chan.ops = &l2cap_ops;
1537 l2cap_chan[i].rx.mtu = DATA_MTU;
1538
1539 *chan = &l2cap_chan[i].chan;
1540
1541 return 0;
1542 }
1543
1544 static struct bt_l2cap_server server[L2CAP_DYM_CHANNEL_NUM] = {
1545 0
1546 };
1547
1548
cmd_l2cap_register(int argc,char * argv[])1549 static int cmd_l2cap_register(int argc, char *argv[])
1550 {
1551 int i;
1552
1553 if (argc < 2) {
1554 return -EINVAL;
1555 }
1556
1557 for (i = 0; i < L2CAP_DYM_CHANNEL_NUM; i++) {
1558 if (server[i].psm == 0) {
1559 break;
1560 }
1561 }
1562
1563 if (i == L2CAP_DYM_CHANNEL_NUM) {
1564 printf("No more channel\n");
1565 return 0;
1566 }
1567
1568 server[i].accept = l2cap_accept;
1569 server[i].psm = strtoul(argv[1], NULL, 16);
1570
1571 if (argc > 2) {
1572 server[i].sec_level = strtoul(argv[2], NULL, 10);
1573 }
1574
1575 if (bt_l2cap_server_register(&server[i]) < 0) {
1576 printf("Unable to register psm\n");
1577 server[i].psm = 0;
1578 } else {
1579 printf("L2CAP psm %u sec_level %u registered\n", server[i].psm,
1580 server[i].sec_level);
1581 }
1582
1583 return 0;
1584 }
1585
cmd_l2cap_connect(int argc,char * argv[])1586 static int cmd_l2cap_connect(int argc, char *argv[])
1587 {
1588 u16_t psm;
1589 int err;
1590 int i;
1591
1592 if (g_bt_conn_handle == -1) {
1593 printf("Not connected\n");
1594 return 0;
1595 }
1596
1597 if (argc < 2) {
1598 return -EINVAL;
1599 }
1600
1601 for (i = 0; i < L2CAP_DYM_CHANNEL_NUM; i++) {
1602 if (l2cap_chan[i].chan.conn == NULL) {
1603 break;
1604 }
1605 }
1606
1607 if (i == L2CAP_DYM_CHANNEL_NUM) {
1608 printf("No more Channel\n");
1609 return -EINVAL;
1610 }
1611
1612 l2cap_chan[i].chan.ops = &l2cap_ops;
1613 l2cap_chan[i].rx.mtu = DATA_MTU;
1614
1615 psm = strtoul(argv[1], NULL, 16);
1616
1617 err = bt_l2cap_chan_connect(bt_conn_lookup_id(g_bt_conn_handle), &l2cap_chan[i].chan, psm);
1618
1619 if (err < 0) {
1620 printf("Unable to connect to psm %u (err %u)\n", psm, err);
1621 } else {
1622 printf("L2CAP connection pending\n");
1623 }
1624
1625 return 0;
1626 }
1627
cmd_l2cap_disconnect(int argc,char * argv[])1628 static int cmd_l2cap_disconnect(int argc, char *argv[])
1629 {
1630 int err;
1631 u16_t psm;
1632 int i;
1633
1634 psm = strtoul(argv[1], NULL, 16);
1635
1636 for (i = 0; i < L2CAP_DYM_CHANNEL_NUM; i++) {
1637 if (l2cap_chan[i].chan.psm == psm) {
1638 err = bt_l2cap_chan_disconnect(&l2cap_chan[i].chan);
1639
1640 if (err) {
1641 printf("Unable to disconnect: err %u\n", -err);
1642 }
1643
1644 return err;
1645 }
1646 }
1647
1648 return 0;
1649 }
1650
cmd_l2cap_send(int argc,char * argv[])1651 static int cmd_l2cap_send(int argc, char *argv[])
1652 {
1653 static u8_t buf_data[DATA_MTU] = { [0 ...(DATA_MTU - 1)] = 0xff };
1654 int ret, len, count = 1;
1655 struct net_buf *buf;
1656 u16_t psm = 0;
1657 int i;
1658
1659 if (argc > 1) {
1660 psm = strtoul(argv[1], NULL, 16);
1661 } else {
1662 return -EINVAL;
1663 }
1664
1665 if (argc > 2) {
1666 count = strtoul(argv[2], NULL, 10);
1667 }
1668
1669 for (i = 0; i < L2CAP_DYM_CHANNEL_NUM; i++) {
1670 if (l2cap_chan[i].chan.psm == psm) {
1671 break;
1672 }
1673 }
1674
1675 if (i == L2CAP_DYM_CHANNEL_NUM) {
1676 printf("Can't find channel\n");
1677 return -EINVAL;
1678 }
1679
1680 /* when mtu is 23, the max send num is 8, so 6*23 is safe */
1681 len = min(6*23, DATA_MTU - BT_L2CAP_CHAN_SEND_RESERVE);
1682
1683 while (count--) {
1684 buf = net_buf_alloc(&data_tx_pool, K_FOREVER);
1685 net_buf_reserve(buf, BT_L2CAP_CHAN_SEND_RESERVE);
1686
1687 net_buf_add_mem(buf, buf_data, len);
1688 ret = bt_l2cap_chan_send(&l2cap_chan[i].chan, buf);
1689
1690 if (ret < 0) {
1691 printf("Unable to send: %d\n", -ret);
1692 net_buf_unref(buf);
1693 break;
1694 }
1695 }
1696
1697 return 0;
1698 }
1699
cmd_l2cap_metrics(int argc,char * argv[])1700 static int cmd_l2cap_metrics(int argc, char *argv[])
1701 {
1702 const char *action;
1703
1704 if (argc < 2) {
1705 printf("l2cap rate: %u bps.\n", l2cap_rate);
1706
1707 return 0;
1708 }
1709
1710 action = argv[1];
1711
1712 if (!strcmp(action, "on")) {
1713 l2cap_ops.recv = l2cap_recv_metrics;
1714 } else if (!strcmp(action, "off")) {
1715 l2cap_ops.recv = l2cap_recv;
1716 } else {
1717 return -EINVAL;
1718 }
1719
1720 printf("l2cap metrics %s.\n", action);
1721
1722 return 0;
1723 }
1724
1725 #endif
1726
1727
1728
1729
1730 #if 0
1731 static int write_mac_addr(partition_t handle, const uint8_t *buffer, int length, int offset)
1732 {
1733 // if ((offset % lp->sector_size) == 0) {
1734 // if (partition_erase(handle, offset, (1 + length / lp->sector_size)) < 0) {
1735 // printf("erase addr:%x\r\n", offset);
1736 // return -1;
1737 // }
1738 // }
1739
1740 // if (partition_write(handle, offset, (void *)buffer, length) >= 0) {
1741 // return length;
1742 // }
1743
1744 // printf("write fail addr:%x length:%x\r\n", offset, length);
1745 return -1;
1746 }
1747
1748
1749 static int str2_char(const char *str, uint8_t *addr)
1750 {
1751 int i, j;
1752 u8_t tmp;
1753
1754 if (strlen(str) != 17) {
1755 return -EINVAL;
1756 }
1757
1758 for (i = 0, j = 1; *str != '\0'; str++, j++) {
1759 if (!(j % 3) && (*str != ':')) {
1760 return -EINVAL;
1761 } else if (*str == ':') {
1762 i++;
1763 continue;
1764 }
1765
1766 addr[i] = addr[i] << 4;
1767
1768 if (char2hex(*str, &tmp) < 0) {
1769 return -EINVAL;
1770 }
1771
1772 addr[i] |= tmp;
1773 }
1774
1775 return 0;
1776 }
1777
1778
1779 static int flash_opt_mac(int argc, char *argv[])
1780 {
1781 int err;
1782 uint8_t addr[6] = {0};
1783 uint8_t send_addr[6] = {0};
1784 const char *action;
1785
1786 handle = partition_open("FCDS");
1787 lp = hal_flash_get_info(handle);
1788
1789 action = argv[1];
1790
1791 if ((argc == 3) && (!strcmp(action, "write"))) {
1792 err = str2_char(argv[2], addr);
1793
1794 if (err < 0) {
1795 return err;
1796 }
1797
1798 if (err) {
1799 printf("Invalid address\n");
1800 return err;
1801 }
1802
1803 send_addr[0] = addr[2];
1804 send_addr[1] = addr[3];
1805 send_addr[2] = addr[4];
1806 send_addr[3] = addr[5];
1807 send_addr[4] = addr[0];
1808 send_addr[5] = addr[1];
1809
1810 if (write_mac_addr(handle, send_addr, sizeof(send_addr), 0) < 0) {
1811 return -1;
1812 }
1813 } else if (!strcmp(action, "read")) {
1814 partition_read(handle, 0, addr, sizeof(addr));
1815 printf("mac:%x:%x:%x:%x:%x:%x", addr[4], addr[5], addr[0], addr[1], addr[2], addr[3]);
1816 }
1817
1818 partition_close(handle);
1819
1820 return 0;
1821 }
1822 #endif
1823
1824 #if defined(CONFIG_BT_WHITELIST)
1825
get_wl_size()1826 static int get_wl_size()
1827 {
1828 int wl_actal_szie;
1829 wl_actal_szie = ble_stack_white_list_size();
1830 if(wl_actal_szie <= 0) {
1831 return -1;
1832 }
1833 if(wl_actal_szie > MAX_WL_SZIE) {
1834 printf("actual wl size is %d but upper wl list size is %d\n", wl_actal_szie, MAX_WL_SZIE);
1835 }
1836 return wl_actal_szie < MAX_WL_SZIE? wl_actal_szie : MAX_WL_SZIE;
1837 }
1838
is_wl_addr_exist(dev_addr_t addr)1839 bool is_wl_addr_exist(dev_addr_t addr)
1840 {
1841 uint8_t index = 0;
1842 uint8_t size = 0;
1843 size = get_wl_size();
1844 for(index = 0; index < size; index++) {
1845 if(wl_list[index].set_flag) {
1846 if(!memcmp(&wl_list[index].addr,&addr,sizeof(wl_list[index].addr))) {
1847 return 1;
1848 }
1849 }
1850 }
1851 if(index >= size) {
1852 return 0;
1853 }
1854 return 0;
1855 }
1856
add_addr_to_wl_list(dev_addr_t addr)1857 int add_addr_to_wl_list(dev_addr_t addr)
1858 {
1859 uint8_t index = 0;
1860 uint8_t size = 0;
1861 size = get_wl_size();
1862
1863 for(index = 0; index < size; index++) {
1864 if(!wl_list[index].set_flag) {
1865 memcpy(&wl_list[index].addr,&addr,sizeof(wl_list[index].addr));
1866 wl_list[index].set_flag = 1;
1867 break;
1868 }
1869 }
1870
1871 if(index >= size) {
1872 printf("wl list is full\r\n");
1873 return -1;
1874 } else {
1875 return 0;
1876 }
1877
1878 }
1879
remove_addr_form_wl_list(dev_addr_t addr)1880 int remove_addr_form_wl_list(dev_addr_t addr)
1881 {
1882 uint8_t index = 0;
1883 uint8_t size = 0;
1884
1885 size = get_wl_size();
1886
1887 for(index = 0; index < size; index++) {
1888 if(wl_list[index].set_flag) {
1889 if(!memcmp(&wl_list[index].addr, &addr, sizeof(addr))) {
1890 memset(&wl_list[index],0, sizeof(wl_addr));
1891 break;
1892 }
1893 }
1894 }
1895
1896 if(index >= size) {
1897 printf("wl addr not exist\r\n");
1898 return -1;
1899 } else {
1900 return 0;
1901 }
1902 }
1903
show_wl_list()1904 int show_wl_list()
1905 {
1906 int found_flag = 0;
1907 uint8_t index = 0;
1908 uint8_t size = 0;
1909 char addr_str[32] = {0};
1910
1911 size = get_wl_size();
1912
1913 for(index = 0; index < size; index++) {
1914 if(wl_list[index].set_flag) {
1915 bt_addr2str(&wl_list[index].addr, addr_str, sizeof(addr_str));
1916 found_flag = 1;
1917 printf("wl %d: %s\r\n",index,addr_str);
1918 }
1919 }
1920 if(!found_flag) {
1921 printf("wl addr not exit\r\n");
1922 return -1;
1923 } else {
1924 return 0;
1925 }
1926
1927 }
1928
clear_wl_list()1929 int clear_wl_list()
1930 {
1931 memset(wl_list,0,sizeof(wl_list));
1932 return 0;
1933 }
1934
1935
cmd_wl_size(int argc,char * argv[])1936 static int cmd_wl_size(int argc, char *argv[])
1937 {
1938 if(!ble_init_flag) {
1939 return -BLE_STACK_ERR_INIT;
1940 }
1941 int ret = ble_stack_white_list_size();
1942 printf("white list size is %d\n", ret);
1943 return 0;
1944 }
cmd_wl_add(int argc,char * argv[])1945 static int cmd_wl_add(int argc, char *argv[])
1946 {
1947 dev_addr_t addr;
1948 int err;
1949
1950 if(!ble_init_flag) {
1951 return -BLE_STACK_ERR_INIT;
1952 }
1953
1954 if (argc == 3) {
1955 err = str2bt_addr_le(argv[1], argv[2], &addr);
1956
1957 if (err) {
1958 printf("Invalid address\n");
1959 return err;
1960 }
1961 } else {
1962 return -EINVAL;
1963 }
1964 if(is_wl_addr_exist(addr)) {
1965 printf("wl addr already exist\r\n");
1966 return 0;
1967 }
1968
1969
1970 err = ble_stack_white_list_add(&addr);
1971 if(!err) {
1972 err = add_addr_to_wl_list(addr);
1973 if(err) {
1974 printf("add to upper wl list faild\r\n");
1975 } else {
1976 printf("Add %s (%s) to white list\n", argv[1], argv[2]);
1977 }
1978 } else {
1979 printf("add wl addr faild\r\n");
1980 }
1981 return 0;
1982 }
1983
cmd_wl_remove(int argc,char * argv[])1984 static int cmd_wl_remove(int argc, char *argv[])
1985 {
1986 if(!ble_init_flag) {
1987 return -BLE_STACK_ERR_INIT;
1988 }
1989
1990 dev_addr_t addr;
1991 int err;
1992
1993 if (argc == 3) {
1994 err = str2bt_addr_le(argv[1], argv[2], &addr);
1995
1996 if (err) {
1997 printf("Invalid address\n");
1998 return err;
1999 }
2000 } else {
2001 return -EINVAL;
2002 }
2003
2004 if(!is_wl_addr_exist(addr)) {
2005 printf("wl addr not exist\r\n");
2006 return -1;
2007 }
2008
2009
2010 err = ble_stack_white_list_remove(&addr);
2011 if(!err) {
2012 err = remove_addr_form_wl_list(addr);
2013 if(err) {
2014 printf("remove from upper wl list faild\r\n");
2015 } else {
2016 printf("Remove %s (%s) to white list\n", argv[1], argv[2]);
2017 }
2018 } else {
2019 printf("add wl addr faild\r\n");
2020 }
2021 return err;
2022 }
cmd_wl_clear(int argc,char * argv[])2023 static int cmd_wl_clear(int argc, char *argv[])
2024 {
2025 if(!ble_init_flag) {
2026 return -BLE_STACK_ERR_INIT;
2027 }
2028 int err = 0;
2029 printf("Clear white list\n");
2030 err = ble_stack_white_list_clear();
2031 if(!err) {
2032 clear_wl_list();
2033 }
2034 return err;
2035 }
2036
cmd_wl_show(int argc,char * argv[])2037 static int cmd_wl_show(int argc, char *argv[])
2038 {
2039 if(!ble_init_flag) {
2040 return -BLE_STACK_ERR_INIT;
2041 }
2042 show_wl_list();
2043 return 0;
2044 }
2045 #endif
2046
2047 #define HELP_NONE "[none]"
2048 #define HELP_ADDR_LE "<address: XX:XX:XX:XX:XX:XX> <type: (public|random)>"
2049
2050 static const struct shell_cmd bt_commands[] = {
2051 { "init", cmd_init, HELP_ADDR_LE },
2052 //{ "mac", flash_opt_mac, "<val:read/write> exp:write 11:22:33:44:55:66" },
2053 #if defined(CONFIG_BT_HCI)
2054 //{ "hci-cmd", cmd_hci_cmd, "<ogf> <ocf> [data]" },
2055 #endif
2056 { "id-create", cmd_id_create, "[addr]" },
2057 { "id-reset", cmd_id_reset, "<id> [addr]" },
2058 { "id-delete", cmd_id_delete, "<id>" },
2059 { "id-show", cmd_id_show, HELP_NONE },
2060 { "id-select", cmd_id_select, "<id>" },
2061 { "name", cmd_name, "[name]" },
2062 {
2063 "scan", cmd_scan,
2064 "<value: active, passive, off> <dup filter: dups, nodups> "\
2065 "<scan interval> <scan window> "\
2066 "<ad(len|adtype|addata ...): 0xxxxxxxx> <sd(len|adtype|addata ...): 0xxxxxxxx>"
2067 },
2068 {
2069 "scan_filter", cmd_scan_filter,
2070 "<filter_policy: 0 any adv 1 white list>"
2071 },
2072
2073 {
2074 "adv", cmd_advertise,
2075 "<type: stop, conn, nconn> <ad(len|adtype|addata ...): 0xxxxxxxx> <sd(len|adtype|addata ...): 0xxxxxxxx>"
2076 },
2077 #if defined(CONFIG_BT_CONN)
2078 {
2079 "connect", cmd_connect_le, HELP_ADDR_LE\
2080 " <interval_min> <interval_max>"\
2081 " <latency> <timeout>"
2082 },
2083 { "disconnect", cmd_disconnect, "[conn_handle]" },
2084 { "auto-conn", cmd_auto_conn, HELP_ADDR_LE" <action: on|off>"},
2085 { "select", cmd_select, HELP_ADDR_LE },
2086 { "conn-update", cmd_conn_update, "<min> <max> <latency> <timeout>" },
2087 { "oob", cmd_oob },
2088 { "clear", cmd_clear,"<dst:all,address> <type: (public|random>"},
2089 #if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR)
2090 { "security", cmd_security, "<security level: 0, 1, 2, 3>" },
2091 {
2092 "io-capability", cmd_iocap_set,
2093 "<io input: NONE,YESNO, KEYBOARD> <io output: NONE,DISPLAY>"
2094 },
2095 { "auth-cancel", cmd_auth_cancel, HELP_NONE },
2096 { "auth-passkey", cmd_auth_passkey, "<passkey>" },
2097 { "auth-passkey-confirm", cmd_auth_passkey_confirm, HELP_NONE },
2098 { "auth-pairing-confirm", cmd_auth_pairing_confirm, HELP_NONE },
2099 #if defined(CONFIG_BT_FIXED_PASSKEY)
2100 { "fixed-passkey", cmd_fixed_passkey, "[passkey]" },
2101 #endif
2102
2103 #endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR) */
2104 #if defined(CONFIG_BT_GATT_CLIENT)
2105 { "gatt-exchange-mtu", cmd_gatt_exchange_mtu, HELP_NONE },
2106 {
2107 "gatt-discover-primary", cmd_gatt_discover,
2108 "<UUID> [start handle] [end handle]"
2109 },
2110 {
2111 "gatt-discover-secondary", cmd_gatt_discover,
2112 "<UUID> [start handle] [end handle]"
2113 },
2114 {
2115 "gatt-discover-include", cmd_gatt_discover,
2116 "[UUID] [start handle] [end handle]"
2117 },
2118 {
2119 "gatt-discover-characteristic", cmd_gatt_discover,
2120 "[UUID] [start handle] [end handle]"
2121 },
2122 {
2123 "gatt-discover-descriptor", cmd_gatt_discover,
2124 "[UUID] [start handle] [end handle]"
2125 },
2126 { "gatt-read-format",cmd_gatt_read_show_format,"<format:0,1>"},
2127 { "gatt-read", cmd_gatt_read, "<handle> [offset]" },
2128 { "gatt-read-multiple", cmd_gatt_mread, "<handle 1> <handle 2> ..." },
2129 { "gatt-write", cmd_gatt_write, "<handle> <offset> <data> [length]" },
2130 {
2131 "gatt-write-without-response", cmd_gatt_write_without_rsp,
2132 "<handle> <data> [length] [repeat]"
2133 },
2134 {
2135 "gatt-write-signed", cmd_gatt_write_without_rsp,
2136 "<handle> <data> [length] [repeat]"
2137 },
2138 {
2139 "gatt-subscribe", cmd_gatt_subscribe,
2140 "<CCC handle> [ind]"
2141 },
2142 { "gatt-unsubscribe", cmd_gatt_unsubscribe, "<CCC handle>"},
2143 #endif /* CONFIG_BT_GATT_CLIENT */
2144 { "gatt-show-db", cmd_gatt_show_db, HELP_NONE },
2145 {
2146 "gatt-register-service", cmd_gatt_register_test_svc,
2147 "register pre-predefined test service"
2148 },
2149 {
2150 "gatt-register-service2", cmd_gatt_register_test_svc,
2151 "register pre-predefined test2 service"
2152 },
2153 {
2154 "gatt-transport-test-config", cmd_gatt_transport_test,
2155 "<type 0:server 1 client> <mode 0:loop 1:single> <server tx mode 0:notify 1:indicate> <server rx handle> <client tx mode 0:write 1:write_withoutresponse> "\
2156 "<data_len 0:stream 1~0xFFFFFFFF data size>"
2157 },
2158 {
2159 "gatt-transport-test-op", cmd_gatt_transport_test,
2160 "<op 0:stop 1:start 2:show result 3:reset>"
2161 },
2162
2163 #if defined(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL)
2164 { "l2cap-register", cmd_l2cap_register, "<psm> [sec_level]" },
2165 { "l2cap-connect", cmd_l2cap_connect, "<psm>" },
2166 { "l2cap-disconnect", cmd_l2cap_disconnect, "<psm>" },
2167 { "l2cap-send", cmd_l2cap_send, "<psm> <number of packets>" },
2168 { "l2cap-metrics", cmd_l2cap_metrics, "<value on, off>" },
2169 #endif
2170
2171
2172 #endif /* CONFIG_BT_CONN */
2173 #if defined(CONFIG_BT_CTLR_ADV_EXT)
2174 { "advx", cmd_advx, "<on off> [coded] [anon] [txp]" },
2175 { "scanx", cmd_scanx, "<on passive off> [coded]" },
2176 #endif /* CONFIG_BT_CTLR_ADV_EXT */
2177 #if defined(CONFIG_BT_CTLR_DTM)
2178 { "test_tx", cmd_test_tx, "<chan> <len> <type> <phy>" },
2179 { "test_rx", cmd_test_rx, "<chan> <phy> <mod_idx>" },
2180 { "test_end", cmd_test_end, HELP_NONE},
2181 #endif /* CONFIG_BT_CTLR_ADV_EXT */
2182 #if defined(CONFIG_BT_WHITELIST)
2183 { "wl-size", cmd_wl_size, HELP_NONE},
2184 { "wl-add", cmd_wl_add, HELP_ADDR_LE},
2185 { "wl-remove", cmd_wl_remove, HELP_ADDR_LE},
2186 { "wl-clear", cmd_wl_clear, HELP_NONE},
2187 { "wl-show", cmd_wl_show, HELP_NONE},
2188 #endif
2189 { NULL, NULL, NULL }
2190 };
2191
2192
cmd_ble_func(char * wbuf,int wbuf_len,int argc,char ** argv)2193 static void cmd_ble_func(char *wbuf, int wbuf_len, int argc, char **argv)
2194 {
2195 int i = 0;
2196 int err;
2197
2198 if (argc < 2) {
2199 printf("Ble support commands\n");
2200
2201 for (i = 0; bt_commands[i].cmd_name != NULL; i ++) {
2202 printf(" %s %s\n", bt_commands[i].cmd_name, bt_commands[i].help);
2203 }
2204
2205 return;
2206 }
2207
2208 for (i = 0; bt_commands[i].cmd_name != NULL; i ++) {
2209 if (strlen(bt_commands[i].cmd_name) == strlen(argv[1]) &&
2210 !strncmp(bt_commands[i].cmd_name, argv[1], strlen(bt_commands[i].cmd_name))) {
2211 if (bt_commands[i].cb) {
2212 err = bt_commands[i].cb(argc - 1, &argv[1]);
2213
2214 if (err) {
2215 printf("%s execute fail, %d\n", bt_commands[i].cmd_name, err);
2216 }
2217
2218 break;
2219 }
2220 }
2221 }
2222 }
2223
2224 #if AOS_COMP_CLI
cli_reg_cmd_ble(void)2225 void cli_reg_cmd_ble(void)
2226 {
2227 static const struct cli_command cmd_info = {
2228 "ble",
2229 "ble commands",
2230 cmd_ble_func,
2231 };
2232
2233 aos_cli_register_command(&cmd_info);
2234 }
2235 #endif /* AOS_COMP_CLI */
2236