Bluetooth: shell: Add LE Audio related advertisement data

This adds LE Audio related data to the shell advertisement data.

Signed-off-by: Mariusz Skamra <mariusz.skamra@codecoup.pl>
This commit is contained in:
Mariusz Skamra 2022-07-22 13:03:55 +02:00 committed by Carles Cufí
commit ea5f59f896
4 changed files with 243 additions and 19 deletions

View file

@ -31,6 +31,9 @@
#include <zephyr/bluetooth/rfcomm.h>
#include <zephyr/bluetooth/sdp.h>
#include <zephyr/bluetooth/iso.h>
#include <zephyr/bluetooth/audio/audio.h>
#include <zephyr/bluetooth/audio/capabilities.h>
#include <zephyr/bluetooth/audio/csis.h>
#include <zephyr/shell/shell.h>
@ -69,9 +72,19 @@ static struct bt_conn_auth_info_cb auth_info_cb;
*/
#define HCI_CMD_MAX_PARAM 65
enum {
SHELL_ADV_OPT_CONNECTABLE,
SHELL_ADV_OPT_DISCOVERABLE,
SHELL_ADV_OPT_EXT_ADV,
SHELL_ADV_OPT_NUM,
};
static ATOMIC_DEFINE(adv_opt, SHELL_ADV_OPT_NUM);
#if defined(CONFIG_BT_EXT_ADV)
uint8_t selected_adv;
struct bt_le_ext_adv *adv_sets[CONFIG_BT_EXT_ADV_MAX_ADV_SET];
static ATOMIC_DEFINE(adv_set_opt, SHELL_ADV_OPT_NUM)[CONFIG_BT_EXT_ADV_MAX_ADV_SET];
#endif /* CONFIG_BT_EXT_ADV */
#if defined(CONFIG_BT_OBSERVER) || defined(CONFIG_BT_USER_PHY_UPDATE)
@ -1147,14 +1160,85 @@ static int cmd_scan_filter_clear_addr(const struct shell *sh, size_t argc,
#endif /* CONFIG_BT_OBSERVER */
#if defined(CONFIG_BT_BROADCASTER)
static const struct bt_data ad_discov[] = {
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
};
static void ad_mode_parse(const struct shell *sh, size_t argc, char *argv[], bool *discov)
{
for (size_t argn = 0; argn < argc; argn++) {
const char *arg = argv[argn];
if (!strcmp(arg, "discov")) {
*discov = true;
break;
} else if (!strcmp(arg, "non_discov")) {
*discov = false;
break;
}
}
}
static ssize_t ad_init(struct bt_data *data_array, const size_t data_array_size,
const atomic_t *adv_opt)
{
const bool discoverable = atomic_test_bit(adv_opt, SHELL_ADV_OPT_DISCOVERABLE);
const bool adv_ext = atomic_test_bit(adv_opt, SHELL_ADV_OPT_EXT_ADV);
static uint8_t ad_flags;
size_t ad_len = 0;
/* Set BR/EDR Not Supported if LE-only device */
ad_flags = IS_ENABLED(CONFIG_BT_BREDR) ? 0 : BT_LE_AD_NO_BREDR;
if (discoverable) {
/* A privacy-enabled Set Member should advertise RSI values only when in
* the GAP Limited Discoverable mode.
*/
if (IS_ENABLED(CONFIG_BT_PRIVACY) && IS_ENABLED(CONFIG_BT_CSIS) && csis != NULL) {
ad_flags |= BT_LE_AD_LIMITED;
} else {
ad_flags |= BT_LE_AD_GENERAL;
}
}
if (ad_flags != 0) {
__ASSERT(data_array_size > ad_len, "No space for AD_FLAGS");
data_array[ad_len].type = BT_DATA_FLAGS;
data_array[ad_len].data_len = sizeof(ad_flags);
data_array[ad_len].data = &ad_flags;
ad_len++;
}
if (IS_ENABLED(CONFIG_BT_CSIS)) {
ssize_t csis_ad_len;
csis_ad_len = csis_ad_data_add(&data_array[ad_len],
data_array_size - ad_len, discoverable);
if (csis_ad_len < 0) {
shell_error(ctx_shell, "Failed to add CSIS data (err %d)", csis_ad_len);
return ad_len;
}
ad_len += csis_ad_len;
}
if (IS_ENABLED(CONFIG_BT_AUDIO) && IS_ENABLED(CONFIG_BT_EXT_ADV) && adv_ext) {
const bool connectable = atomic_test_bit(adv_opt, SHELL_ADV_OPT_CONNECTABLE);
size_t audio_ad_len;
audio_ad_len = audio_ad_data_add(&data_array[ad_len], data_array_size - ad_len,
discoverable, connectable);
if (audio_ad_len < 0) {
return audio_ad_len;
}
ad_len += audio_ad_len;
}
return ad_len;
}
static int cmd_advertise(const struct shell *sh, size_t argc, char *argv[])
{
struct bt_le_adv_param param = {};
const struct bt_data *ad;
struct bt_data ad[2];
bool discoverable = true;
size_t ad_len;
int err;
@ -1184,17 +1268,23 @@ static int cmd_advertise(const struct shell *sh, size_t argc, char *argv[])
goto fail;
}
ad = ad_discov;
ad_len = ARRAY_SIZE(ad_discov);
ad_mode_parse(sh, argc - 2, &argv[2], &discoverable);
atomic_clear(adv_opt);
atomic_set_bit_to(adv_opt, SHELL_ADV_OPT_CONNECTABLE,
(param.options & BT_LE_ADV_OPT_CONNECTABLE) > 0);
atomic_set_bit_to(adv_opt, SHELL_ADV_OPT_DISCOVERABLE, discoverable);
ad_len = ad_init(ad, ARRAY_SIZE(ad), adv_opt);
if (ad_len < 0) {
return -ENOEXEC;
}
for (size_t argn = 2; argn < argc; argn++) {
const char *arg = argv[argn];
if (!strcmp(arg, "discov")) {
/* Default */
} else if (!strcmp(arg, "non_discov")) {
ad = NULL;
ad_len = 0;
if (!strcmp(arg, "discov") || !strcmp(arg, "non_discov")) {
/* Skip */
} else if (!strcmp(arg, "fal")) {
param.options |= BT_LE_ADV_OPT_FILTER_SCAN_REQ;
param.options |= BT_LE_ADV_OPT_FILTER_CONN;
@ -1222,7 +1312,7 @@ static int cmd_advertise(const struct shell *sh, size_t argc, char *argv[])
}
}
err = bt_le_adv_start(&param, ad, ad_len, NULL, 0);
err = bt_le_adv_start(&param, ad_len > 0 ? ad : NULL, ad_len, NULL, 0);
if (err < 0) {
shell_error(sh, "Failed to start advertising (err %d)",
err);
@ -1399,6 +1489,12 @@ static int cmd_adv_create(const struct shell *sh, size_t argc, char *argv[])
adv_index = bt_le_ext_adv_get_index(adv);
adv_sets[adv_index] = adv;
atomic_clear(adv_set_opt[adv_index]);
atomic_set_bit_to(adv_set_opt[adv_index], SHELL_ADV_OPT_CONNECTABLE,
(param.options & BT_LE_ADV_OPT_CONNECTABLE) > 0);
atomic_set_bit_to(adv_set_opt[adv_index], SHELL_ADV_OPT_EXT_ADV,
(param.options & BT_LE_ADV_OPT_EXT_ADV) > 0);
shell_print(sh, "Created adv id: %d, adv: %p", adv_index, adv);
return 0;
@ -1426,15 +1522,15 @@ static int cmd_adv_param(const struct shell *sh, size_t argc, char *argv[])
static int cmd_adv_data(const struct shell *sh, size_t argc, char *argv[])
{
uint8_t discov_data = (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR);
struct bt_le_ext_adv *adv = adv_sets[selected_adv];
static uint8_t hex_data[1650];
struct bt_data *data;
struct bt_data ad[8];
struct bt_data sd[8];
size_t hex_data_len;
size_t ad_len = 0;
size_t ad_len;
size_t sd_len = 0;
bool discoverable = false;
size_t *data_len;
int err;
@ -1446,6 +1542,15 @@ static int cmd_adv_data(const struct shell *sh, size_t argc, char *argv[])
data = ad;
data_len = &ad_len;
ad_mode_parse(sh, argc - 1, &argv[1], &discoverable);
atomic_set_bit_to(adv_set_opt[selected_adv], SHELL_ADV_OPT_DISCOVERABLE, discoverable);
ad_len = ad_init(ad, ARRAY_SIZE(ad), adv_set_opt[selected_adv]);
if (ad_len < 0) {
return -ENOEXEC;
}
for (size_t argn = 1; argn < argc; argn++) {
const char *arg = argv[argn];
@ -1459,10 +1564,7 @@ static int cmd_adv_data(const struct shell *sh, size_t argc, char *argv[])
}
if (!strcmp(arg, "discov")) {
data[*data_len].type = BT_DATA_FLAGS;
data[*data_len].data_len = sizeof(discov_data);
data[*data_len].data = &discov_data;
(*data_len)++;
/* Skip */
} else if (!strcmp(arg, "scan-response")) {
if (data == sd) {
shell_print(sh, "Failed to set advertising data: "