diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index 356b784cf7..a0bd437a33 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -147,6 +147,8 @@ static struct bt_scan_filter { bool pa_interval_set; } scan_filter; +static const char scan_response_label[] = "[DEVICE]: "; +static bool scan_verbose_output; /** * @brief Compares two strings without case sensitivy @@ -194,11 +196,94 @@ static bool data_cb(struct bt_data *data, void *user_data) } } +static void print_data_set(uint8_t type, uint8_t set_value_len, + const uint8_t *scan_data, uint8_t scan_data_len) +{ + uint8_t min_value_len = MIN(set_value_len, scan_data_len); + + shell_fprintf(ctx_shell, SHELL_INFO, "%*sType 0x%02x: ", + strlen(scan_response_label), "", + type); + for (uint8_t i = 0U; i < (scan_data_len / min_value_len); i++) { + if (i > 0L) { + shell_fprintf(ctx_shell, SHELL_INFO, ", "); + } + + shell_fprintf(ctx_shell, SHELL_INFO, "0x"); + for (uint8_t j = 0U; j < min_value_len; j++) { + shell_fprintf(ctx_shell, SHELL_INFO, "%02x", + scan_data[i * min_value_len + j]); + } + } + + shell_fprintf(ctx_shell, SHELL_INFO, "\n"); +} + +static bool data_verbose_cb(struct bt_data *data, void *user_data) +{ + switch (data->type) { + case BT_DATA_UUID16_SOME: + case BT_DATA_UUID16_ALL: + case BT_DATA_SOLICIT16: + case BT_DATA_SVC_DATA16: + print_data_set(data->type, 2, data->data, data->data_len); + break; + case BT_DATA_UUID32_SOME: + case BT_DATA_UUID32_ALL: + case BT_DATA_SVC_DATA32: + print_data_set(data->type, 4, data->data, data->data_len); + break; + case BT_DATA_UUID128_SOME: + case BT_DATA_UUID128_ALL: + case BT_DATA_SOLICIT128: + case BT_DATA_SVC_DATA128: + print_data_set(data->type, 16, data->data, data->data_len); + break; + case BT_DATA_NAME_SHORTENED: + case BT_DATA_NAME_COMPLETE: + case BT_DATA_BROADCAST_NAME: + shell_info(ctx_shell, "%*sType 0x%02x: %.*s", + strlen(scan_response_label), "", + data->type, data->data_len, data->data); + break; + case BT_DATA_PUB_TARGET_ADDR: + case BT_DATA_RAND_TARGET_ADDR: + case BT_DATA_LE_BT_DEVICE_ADDRESS: + print_data_set(data->type, BT_ADDR_SIZE, data->data, data->data_len); + break; + default: + print_data_set(data->type, 1, data->data, data->data_len); + } + + return true; +} + +static const char *scan_response_type_txt(uint8_t type) +{ + switch (type) { + case BT_GAP_ADV_TYPE_ADV_IND: + return "ADV_IND"; + case BT_GAP_ADV_TYPE_ADV_DIRECT_IND: + return "ADV_DIRECT_IND"; + case BT_GAP_ADV_TYPE_ADV_SCAN_IND: + return "ADV_SCAN_IND"; + case BT_GAP_ADV_TYPE_ADV_NONCONN_IND: + return "ADV_NONCONN_IND"; + case BT_GAP_ADV_TYPE_SCAN_RSP: + return "SCAN_RSP"; + case BT_GAP_ADV_TYPE_EXT_ADV: + return "EXT_ADV"; + default: + return "UNKNOWN"; + } +} + static void scan_recv(const struct bt_le_scan_recv_info *info, struct net_buf_simple *buf) { char le_addr[BT_ADDR_LE_STR_LEN]; char name[NAME_LEN]; + struct net_buf_simple buf_copy; if (scan_filter.rssi_set && (scan_filter.rssi > info->rssi)) { return; @@ -210,6 +295,11 @@ static void scan_recv(const struct bt_le_scan_recv_info *info, return; } + if (scan_verbose_output) { + /* call to bt_data_parse consumes netbufs so shallow clone for verbose output */ + net_buf_simple_clone(buf, &buf_copy); + } + (void)memset(name, 0, sizeof(name)); bt_data_parse(buf, data_cb, name); @@ -223,9 +313,10 @@ static void scan_recv(const struct bt_le_scan_recv_info *info, return; } - shell_print(ctx_shell, "[DEVICE]: %s, AD evt type %u, RSSI %i %s " + shell_print(ctx_shell, "%s%s, AD evt type %u, RSSI %i %s " "C:%u S:%u D:%d SR:%u E:%u Prim: %s, Secn: %s, " "Interval: 0x%04x (%u us), SID: 0x%x", + scan_response_label, le_addr, info->adv_type, info->rssi, name, (info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0, (info->adv_props & BT_GAP_ADV_PROP_SCANNABLE) != 0, @@ -236,6 +327,15 @@ static void scan_recv(const struct bt_le_scan_recv_info *info, info->interval, BT_CONN_INTERVAL_TO_US(info->interval), info->sid); + if (scan_verbose_output) { + shell_info(ctx_shell, + "%*s[SCAN DATA START - %s]", + strlen(scan_response_label), "", + scan_response_type_txt(info->adv_type)); + bt_data_parse(&buf_copy, data_verbose_cb, NULL); + shell_info(ctx_shell, "%*s[SCAN DATA END]", strlen(scan_response_label), ""); + } + /* Store address for later use */ #if defined(CONFIG_BT_CENTRAL) auto_connect.addr_set = true; @@ -1137,6 +1237,23 @@ static int cmd_scan(const struct shell *sh, size_t argc, char *argv[]) return 0; } +static int cmd_scan_verbose_output(const struct shell *sh, size_t argc, char *argv[]) +{ + const char *verbose_state; + + verbose_state = argv[1]; + if (!strcmp(verbose_state, "on")) { + scan_verbose_output = true; + } else if (!strcmp(verbose_state, "off")) { + scan_verbose_output = false; + } else { + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + + return 0; +} + static int cmd_scan_filter_set_name(const struct shell *sh, size_t argc, char *argv[]) { @@ -3735,6 +3852,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(bt_cmds, SHELL_CMD(scan-filter-clear, &bt_scan_filter_clear_cmds, "Scan filter clear commands", cmd_default_handler), + SHELL_CMD_ARG(scan-verbose-output, NULL, "", cmd_scan_verbose_output, 2, 0), #endif /* CONFIG_BT_OBSERVER */ #if defined(CONFIG_BT_BROADCASTER) SHELL_CMD_ARG(advertise, NULL,