apps/btshell: implement Broadcast source API

This patch adds commands to btshell to allow creating BIGs, BIG
subgroups and BISe and create and manage Broadcast advertisements.
This commit is contained in:
Krzysztof Kopyściński
2023-12-04 09:27:13 +01:00
committed by Krzysztof Kopyściński
parent 7e7b4f00c4
commit a621805349
6 changed files with 1033 additions and 46 deletions
+33
View File
@@ -28,6 +28,9 @@
#include "host/ble_gatt.h"
#include "host/ble_gap.h"
#if (MYNEWT_VAL(BLE_ISO_BROADCASTER))
#include "host/ble_audio_broadcast.h"
#endif
#ifdef __cplusplus
extern "C" {
@@ -182,6 +185,36 @@ int btshell_l2cap_send(uint16_t conn, uint16_t idx, uint16_t bytes);
int btshell_l2cap_reconfig(uint16_t conn_handle, uint16_t mtu,
uint8_t num, uint8_t idxs[]);
#if (MYNEWT_VAL(BLE_ISO_BROADCASTER))
int btshell_broadcast_base_add(uint8_t adv_instance, uint32_t presentation_delay);
int btshell_broadcast_big_sub_add(uint8_t adv_instance,
uint8_t codec_fmt,
uint16_t company_id,
uint16_t vendor_spec,
uint8_t *metadata,
unsigned int metadata_len,
uint8_t *codec_spec_cfg,
unsigned int codec_spec_cfg_len);
int btshell_broadcast_bis_add(uint8_t adv_instance,
uint8_t *codec_spec_cfg,
unsigned int codec_spec_cfg_len);
int btshell_broadcast_create(uint8_t adv_instance,
struct ble_gap_ext_adv_params *ext_params,
struct ble_gap_periodic_adv_params
*per_params,
const char *name,
struct ble_iso_big_params big_params,
uint8_t *extra_data,
unsigned int extra_data_len);
int btshell_broadcast_destroy(uint8_t adv_instance);
int btshell_broadcast_update(uint8_t adv_instance,
const char *name,
uint8_t *extra_data,
unsigned int extra_data_len);
int btshell_broadcast_start(uint8_t adv_instance);
int btshell_broadcast_stop(uint8_t adv_instance);
#endif
int btshell_gap_event(struct ble_gap_event *event, void *arg);
void btshell_sync_stats(uint16_t handle);
uint8_t btshell_get_default_own_addr_type(void);
+193
View File
@@ -42,6 +42,7 @@
#include "btshell.h"
#include "cmd_gatt.h"
#include "cmd_l2cap.h"
#include "cmd_leaudio.h"
#define BTSHELL_MODULE "btshell"
@@ -4168,6 +4169,140 @@ static const struct shell_cmd_help sync_stats_help = {
#endif
#endif
#if MYNEWT_VAL(BLE_ISO_BROADCASTER)
#if MYNEWT_VAL(SHELL_CMD_HELP)
static const struct shell_param leaudio_base_add_params[] = {
{"adv_instance", "Advertising instance, usage: =<UINT8>"},
{ "presentation_delay", "usage: =<UINT32>" },
{ NULL, NULL}
};
static const struct shell_cmd_help leaudio_base_add_help = {
.summary = "Add BASE configuration for broadcast",
.usage = NULL,
.params = leaudio_base_add_params,
};
static const struct shell_param leaudio_big_sub_add_params[] = {
{"adv_instance", "Advertising instance, usage: =<UINT8>"},
{ "codec_fmt", "usage: <UINT8>" },
{ "company_id", "usage: =<UINT16>" },
{ "vendor_spec", "usage: =<UINT16>" },
{ "codec_spec_config", "usage: =[XX:XX...]" },
{ "metadata", "usage: =[XX:XX...]" },
{ NULL, NULL}
};
static const struct shell_cmd_help leaudio_big_sub_add_help = {
.summary = "Add BIG subgroup configuration for broadcast",
.usage = NULL,
.params = leaudio_big_sub_add_params,
};
static const struct shell_param leaudio_bis_add_params[] = {
{"adv_instance", "Advertising instance, usage: =<UINT8>"},
{ "codec_spec_config", "usage: =[XX:XX...]" },
{ NULL, NULL}
};
static const struct shell_cmd_help leaudio_bis_add_help = {
.summary = "Add BIS configuration for broadcast announcements to last "
"added BIG subgroup",
.usage = NULL,
.params = leaudio_bis_add_params,
};
static const struct shell_param leaudio_broadcast_create_params[] = {
{"adv_instance", "Advertising instance, usage: =<UINT8>"},
{"ext_interval_min", "usage: =[0-UINT16_MAX], default: 0"},
{"ext_interval_max", "usage: =[0-UINT16_MAX], default: 0"},
{"per_interval_min", "usage: =[0-UINT16_MAX], default: 0"},
{"per_interval_max", "usage: =[0-UINT16_MAX], default: 0"},
{"name", "usage: =[string]"},
{"sdu_interval", "SDU interval, in us, usage: =<UINT32>"},
{"max_sdu", "max SDU size, in octets, usage: =<UINT16>"},
{"max_latency", "max transport latency, in ms, usage: =<UINT16>"},
{"rtn", "RTN, usage: =<UINT8>"},
{"phy", "PHY, usage: =<UINT8>"},
{"packing", "packing, optional, true if not given, usage: =<UINT8>"},
{"framing", "framing, optional, false if not given, usage: =<UINT8>"},
{"encryption", "optional, encryption, usage: =<UINT8>"},
{"broadcast_code", "optional, obligatory if encryption is enabled, "
"usage: =<XX:XX:...>, len=16 octets"},
{"extra_data", "usage: =[XX:XX...]"},
{ NULL, NULL}
};
static const struct shell_cmd_help leaudio_broadcast_create_help = {
.summary = "Add BIS configuration for broadcast to last added BIG "
"subgroup",
.usage = NULL,
.params = leaudio_broadcast_create_params,
};
static const struct shell_param leaudio_broadcast_destroy_params[] = {
{"adv_instance", "Advertising instance, usage: =<UINT8>"},
{ NULL, NULL}
};
static const struct shell_cmd_help leaudio_broadcast_destroy_help = {
.summary = "Destroy BASE",
.usage = NULL,
.params = leaudio_broadcast_destroy_params,
};
static const struct shell_param leaudio_broadcast_update_params[] = {
{"adv_instance", "Advertising instance, usage: =<UINT8>"},
{"name", "usage: =[string]"},
{"extra_data_len", "usage: =<UINT8>"},
{"extra_data", "usage: =[XX:XX...]"},
{ NULL, NULL}
};
static const struct shell_cmd_help leaudio_broadcast_update_help = {
.summary = "Update broadcast",
.usage = NULL,
.params = leaudio_broadcast_update_params,
};
static const struct shell_param leaudio_broadcast_start_params[] = {
{"adv_instance", "Advertising instance, usage: =<UINT8>"},
{ NULL, NULL}
};
static const struct shell_cmd_help leaudio_broadcast_start_help = {
.summary = "Start broadcast",
.usage = NULL,
.params = leaudio_broadcast_start_params,
};
static const struct shell_param leaudio_broadcast_stop_params[] = {
{"adv_instance", "Advertising instance, usage: =<UINT8>"},
{ NULL, NULL}
};
static const struct shell_cmd_help leaudio_broadcast_stop_help = {
.summary = "Stop broadcast",
.usage = NULL,
.params = leaudio_broadcast_stop_params,
};
#endif
#endif
static const struct shell_cmd btshell_commands[] = {
#if MYNEWT_VAL(BLE_EXT_ADV)
{
@@ -4664,6 +4799,64 @@ static const struct shell_cmd btshell_commands[] = {
#endif
},
#endif
#endif
#if MYNEWT_VAL(BLE_ISO)
{
.sc_cmd = "base_add",
.sc_cmd_func = cmd_leaudio_base_add,
#if MYNEWT_VAL(SHELL_CMD_HELP)
.help = &leaudio_base_add_help,
#endif
},
{
.sc_cmd = "big_sub_add",
.sc_cmd_func = cmd_leaudio_big_sub_add,
#if MYNEWT_VAL(SHELL_CMD_HELP)
.help = &leaudio_big_sub_add_help,
#endif
},
{
.sc_cmd = "bis_add",
.sc_cmd_func = cmd_leaudio_bis_add,
#if MYNEWT_VAL(SHELL_CMD_HELP)
.help = &leaudio_bis_add_help,
#endif
},
{
.sc_cmd = "broadcast_create",
.sc_cmd_func = cmd_leaudio_broadcast_create,
#if MYNEWT_VAL(SHELL_CMD_HELP)
.help = &leaudio_broadcast_create_help,
#endif
},
{
.sc_cmd = "broadcast_destroy",
.sc_cmd_func = cmd_leaudio_broadcast_destroy,
#if MYNEWT_VAL(SHELL_CMD_HELP)
.help = &leaudio_broadcast_destroy_help,
#endif
},
{
.sc_cmd = "broadcast_update",
.sc_cmd_func = cmd_leaudio_broadcast_update,
#if MYNEWT_VAL(SHELL_CMD_HELP)
.help = &leaudio_broadcast_update_help,
#endif
},
{
.sc_cmd = "broadcast_start",
.sc_cmd_func = cmd_leaudio_broadcast_start,
#if MYNEWT_VAL(SHELL_CMD_HELP)
.help = &leaudio_broadcast_start_help,
#endif
},
{
.sc_cmd = "broadcast_stop",
.sc_cmd_func = cmd_leaudio_broadcast_stop,
#if MYNEWT_VAL(SHELL_CMD_HELP)
.help = &leaudio_broadcast_stop_help,
#endif
},
#endif
{ 0 },
};
+385
View File
@@ -0,0 +1,385 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "host/ble_audio_broadcast.h"
#include "cmd_leaudio.h"
#include "btshell.h"
#include "console/console.h"
#include "errno.h"
#if (MYNEWT_VAL(BLE_ISO_BROADCASTER))
int
cmd_leaudio_base_add(int argc, char **argv)
{
uint32_t presentation_delay;
uint8_t adv_instance;
int rc;
rc = parse_arg_init(argc - 1, argv + 1);
if (rc != 0) {
return rc;
}
adv_instance = parse_arg_uint8("adv_instance", &rc);
if (rc != 0 || adv_instance >= BLE_ADV_INSTANCES) {
console_printf("invalid advertising instance\n");
return rc;
}
presentation_delay = parse_arg_uint32("presentation_delay", &rc);
if (rc != 0) {
return rc;
}
return btshell_broadcast_base_add(adv_instance, presentation_delay);
}
int
cmd_leaudio_big_sub_add(int argc, char **argv)
{
uint8_t adv_instance;
uint8_t codec_fmt;
uint16_t company_id;
uint16_t vendor_spec;
static uint8_t metadata[CMD_ADV_DATA_METADATA_MAX_SZ];
unsigned int metadata_len;
static uint8_t codec_spec_cfg[CMD_ADV_DATA_CODEC_SPEC_CFG_MAX_SZ];
unsigned int codec_spec_cfg_len;
int rc;
rc = parse_arg_init(argc - 1, argv + 1);
if (rc != 0) {
return rc;
}
adv_instance = parse_arg_uint8("adv_instance", &rc);
if (rc != 0 || adv_instance >= BLE_ADV_INSTANCES) {
console_printf("invalid advertising instance\n");
return rc;
}
codec_fmt = parse_arg_uint8("codec_fmt", &rc);
if (rc != 0) {
return rc;
}
company_id = parse_arg_uint16("company_id", &rc);
if (rc != 0) {
return rc;
}
vendor_spec = parse_arg_uint16("vendor_spec", &rc);
if (rc != 0) {
return rc;
}
rc = parse_arg_byte_stream("codec_spec_config",
CMD_ADV_DATA_CODEC_SPEC_CFG_MAX_SZ,
codec_spec_cfg, &codec_spec_cfg_len);
if (rc != 0 && rc != ENOENT) {
return rc;
}
rc = parse_arg_byte_stream("metadata", CMD_ADV_DATA_METADATA_MAX_SZ,
metadata, &metadata_len);
if (rc != 0 && rc != ENOENT) {
return rc;
}
return btshell_broadcast_big_sub_add(adv_instance,
codec_fmt, company_id,
vendor_spec,
metadata, metadata_len,
codec_spec_cfg, codec_spec_cfg_len);
}
int
cmd_leaudio_bis_add(int argc, char **argv)
{
uint8_t adv_instance;
static uint8_t codec_spec_cfg[CMD_ADV_DATA_CODEC_SPEC_CFG_MAX_SZ];
unsigned int codec_spec_cfg_len;
int rc;
rc = parse_arg_init(argc - 1, argv + 1);
if (rc != 0) {
return rc;
}
adv_instance = parse_arg_uint8("adv_instance", &rc);
if (rc != 0 || adv_instance >= BLE_ADV_INSTANCES) {
console_printf("invalid advertising instance\n");
return rc;
}
rc = parse_arg_byte_stream("codec_spec_config",
CMD_ADV_DATA_CODEC_SPEC_CFG_MAX_SZ,
codec_spec_cfg, &codec_spec_cfg_len);
if (rc != 0) {
return rc;
}
return btshell_broadcast_bis_add(adv_instance, codec_spec_cfg,
codec_spec_cfg_len);
}
int
cmd_leaudio_broadcast_create(int argc, char **argv)
{
struct ble_iso_big_params big_params;
uint8_t adv_instance;
const char *name;
uint8_t extra_data[CMD_ADV_DATA_EXTRA_MAX_SZ];
static uint8_t own_addr_type;
unsigned int extra_data_len;
struct ble_gap_periodic_adv_params periodic_params;
struct ble_gap_ext_adv_params extended_params = {
.scannable = 0,
.connectable = 0,
.primary_phy = BLE_HCI_LE_PHY_1M,
};
int rc;
rc = ble_hs_id_infer_auto(0, &own_addr_type);
if (rc != 0) {
return rc;
}
extended_params.own_addr_type = own_addr_type;
rc = parse_arg_init(argc - 1, argv + 1);
if (rc != 0) {
return rc;
}
adv_instance = parse_arg_uint8("adv_instance", &rc);
if (rc != 0 || adv_instance >= BLE_ADV_INSTANCES) {
console_printf("invalid advertising instance\n");
return rc;
}
extended_params.sid = adv_instance;
extended_params.itvl_min = parse_arg_uint8_dflt("ext_interval_min",
0, &rc);
if (rc != 0 && rc != ENOENT) {
console_printf("invalid extended advertising interval (min)\n");
return rc;
}
extended_params.itvl_max = parse_arg_uint8_dflt("ext_interval_max", 0,
&rc);
if (rc != 0 && rc != ENOENT) {
console_printf("invalid extended advertising interval (max)\n");
return rc;
}
periodic_params.itvl_min = parse_arg_uint8_dflt("per_interval_min", 0,
&rc);
if (rc != 0 && rc != ENOENT) {
console_printf("invalid periodic advertising interval (min)\n");
return rc;
}
periodic_params.itvl_max = parse_arg_uint8_dflt("per_interval_max", 0,
&rc);
if (rc != 0 && rc != ENOENT) {
console_printf("invalid periodic advertising interval (max)\n");
return rc;
}
name = parse_arg_extract("name");
big_params.sdu_interval = parse_arg_uint32_bounds("sdu_interval",
0x0000FF, 0x0FFFFF,
&rc);
if (rc != 0) {
console_printf("invalid SDU interval\n");
return rc;
}
big_params.max_sdu = parse_arg_uint16_bounds("max_sdu", 0x0001, 0x0FFF,
&rc);
if (rc != 0) {
console_printf("invalid max SDU size\n");
return rc;
}
big_params.max_transport_latency = parse_arg_uint16_bounds("max_latency",
0x0005, 0x0FA0,
&rc);
if (rc != 0) {
console_printf("invalid max transport latency\n");
return rc;
}
big_params.rtn = parse_arg_uint8_bounds("rtn", 0x00, 0x1E, &rc);
if (rc != 0) {
console_printf("invalid RTN\n");
return rc;
}
big_params.phy = parse_arg_uint8_bounds("phy", 0, 2, &rc);
if (rc != 0) {
console_printf("invalid PHY\n");
return rc;
}
extended_params.secondary_phy = big_params.phy;
big_params.packing = parse_arg_uint8_bounds_dflt("packing", 0, 1, 1, &rc);
if (rc != 0) {
console_printf("invalid packing\n");
return rc;
}
big_params.framing = parse_arg_uint8_bounds_dflt("framing", 0, 1, 0, &rc);
if (rc != 0) {
console_printf("invalid framing\n");
return rc;
}
big_params.encryption = parse_arg_uint8_bounds_dflt("encryption", 0, 1, 0, &rc);
if (rc != 0) {
console_printf("invalid encryption\n");
return rc;
}
if (big_params.encryption) {
big_params.broadcast_code = parse_arg_extract("broadcast_code");
if (big_params.broadcast_code == NULL) {
console_printf("broadcast code missing\n");
return ENOENT;
}
if (strlen(big_params.broadcast_code) > 16) {
console_printf("broadcast code too long\n");
return ENOENT;
}
}
rc = parse_arg_byte_stream("extra_data",
CMD_ADV_DATA_EXTRA_MAX_SZ,
extra_data, &extra_data_len);
if (rc == ENOENT) {
extra_data_len = 0;
} else if (rc != 0) {
return rc;
}
return btshell_broadcast_create(adv_instance,
&extended_params,
&periodic_params,
name,
big_params,
extra_data,
extra_data_len);
}
int
cmd_leaudio_broadcast_destroy(int argc, char **argv)
{
uint8_t adv_instance;
int rc;
rc = parse_arg_init(argc - 1, argv + 1);
if (rc != 0) {
return rc;
}
adv_instance = parse_arg_uint8("adv_instance", &rc);
if (rc != 0 || adv_instance >= BLE_ADV_INSTANCES) {
console_printf("invalid advertising instance\n");
return rc;
}
return btshell_broadcast_destroy(adv_instance);
}
int
cmd_leaudio_broadcast_update(int argc, char **argv)
{
uint8_t adv_instance;
uint8_t extra_data[CMD_ADV_DATA_EXTRA_MAX_SZ];
unsigned int extra_data_len;
const char *name;
int rc;
rc = parse_arg_init(argc - 1, argv + 1);
if (rc != 0) {
return rc;
}
adv_instance = parse_arg_uint8("adv_instance", &rc);
if (rc != 0 || adv_instance >= BLE_ADV_INSTANCES) {
console_printf("invalid advertising instance\n");
return rc;
}
rc = parse_arg_byte_stream("extra_data",
CMD_ADV_DATA_EXTRA_MAX_SZ,
extra_data, &extra_data_len);
if (rc != 0 && rc != ENOENT) {
return rc;
}
name = parse_arg_extract("name");
return btshell_broadcast_update(adv_instance, name, extra_data, extra_data_len);
}
int
cmd_leaudio_broadcast_start(int argc, char **argv)
{
uint8_t adv_instance;
int rc;
rc = parse_arg_init(argc - 1, argv + 1);
if (rc != 0) {
return rc;
}
adv_instance = parse_arg_uint8("adv_instance", &rc);
if (rc != 0 || adv_instance >= BLE_ADV_INSTANCES) {
console_printf("invalid advertising instance\n");
return rc;
}
return btshell_broadcast_start(adv_instance);
}
int
cmd_leaudio_broadcast_stop(int argc, char **argv)
{
uint8_t adv_instance;
int rc;
rc = parse_arg_init(argc - 1, argv + 1);
if (rc != 0) {
return rc;
}
adv_instance = parse_arg_uint8("adv_instance", &rc);
if (rc != 0 || adv_instance >= BLE_ADV_INSTANCES) {
console_printf("invalid advertising instance\n");
return rc;
}
return btshell_broadcast_stop(adv_instance);
}
#endif
+46
View File
@@ -0,0 +1,46 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_CMD_LEAUDIO_
#define H_CMD_LEAUDIO_
#include "cmd.h"
#define CMD_ADV_DATA_CODEC_SPEC_CFG_MAX_SZ (9)
/**
* Maximum Metadata size is maximum adv size minus minimum size of other
* fields in BASE advertising
*/
#define CMD_ADV_DATA_METADATA_MAX_SZ (MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE) - 27)
/**
* Maximum size of extra data included in BASE advertising. Assumes minimum
* size of other fields.
*/
#define CMD_ADV_DATA_EXTRA_MAX_SZ (MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE) - 27)
int cmd_leaudio_base_add(int argc, char **argv);
int cmd_leaudio_big_sub_add(int argc, char **argv);
int cmd_leaudio_bis_add(int argc, char **argv);
int cmd_leaudio_broadcast_create(int argc, char **argv);
int cmd_leaudio_broadcast_destroy(int argc, char **argv);
int cmd_leaudio_broadcast_update(int argc, char **argv);
int cmd_leaudio_broadcast_start(int argc, char **argv);
int cmd_leaudio_broadcast_stop(int argc, char **argv);
#endif /* H_CMD_LEAUDIO_ */
+359
View File
@@ -41,6 +41,8 @@
#include "host/ble_gatt.h"
#include "host/ble_store.h"
#include "host/ble_sm.h"
#include "host/ble_audio_common.h"
#include "host/ble_audio_broadcast.h"
#include "host/util/util.h"
/* Mandatory services. */
@@ -123,6 +125,57 @@ int btshell_full_disc_prev_chr_val;
struct ble_sm_sc_oob_data oob_data_local;
struct ble_sm_sc_oob_data oob_data_remote;
#if MYNEWT_VAL(BLE_ISO_BROADCASTER)
static struct {struct ble_audio_base *base; uint8_t adv_instance;}
btshell_base_list[MYNEWT_VAL(BLE_MAX_BIG)];
static os_membuf_t btshell_base_mem[
OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_MAX_BIG),
sizeof(struct ble_audio_base))
];
static struct os_mempool btshell_base_pool;
static os_membuf_t btshell_big_params_mem[
OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_MAX_BIG),
sizeof(struct ble_iso_big_params))
];
static struct os_mempool btshell_big_params_pool;
/** Mempool size: in worst case every BIS is in separate subgroup */
static os_membuf_t btshell_big_sub_mem[
OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_MAX_BIS),
sizeof(struct ble_audio_big_subgroup))
];
static struct os_mempool btshell_big_sub_pool;
static os_membuf_t btshell_bis_mem[
OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_MAX_BIS),
sizeof(struct ble_audio_bis))
];
static struct os_mempool btshell_bis_pool;
static os_membuf_t btshell_metadata_mem[
OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_MAX_BIS),
MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE) - 27)
];
static struct os_mempool btshell_metadata_pool;
/**
* Mempool size: theoretically it is possible that every BIG Subgroup has
* codec specific configuration, every BIS is in separate subgroup and also
* has one. This is inefficient but possible and should not cause error if
* used that way */
static os_membuf_t btshell_codec_spec_mem[
OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_MAX_BIS) * 2, 9)
];
static struct os_mempool btshell_codec_spec_pool;
static os_membuf_t btshell_big_params_mem[
OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_MAX_BIG), sizeof(struct ble_iso_big_params))
];
static struct os_mempool btshell_big_params_pool;
#endif
#define XSTR(s) STR(s)
#ifndef STR
#define STR(s) #s
@@ -2618,6 +2671,276 @@ btshell_get_default_own_addr_type(void)
return default_own_addr_type;
}
#if (MYNEWT_VAL(BLE_ISO_BROADCASTER))
static int
btshell_base_find_free(void)
{
int i;
for (i = 0; i < MYNEWT_VAL(BLE_MAX_BIG); i++) {
if (btshell_base_list[i].base == NULL) {
return i;
}
}
return -ENOMEM;
}
static struct ble_audio_base *
btshell_base_find(uint8_t adv_instance)
{
int i;
for (i = 0; i < MYNEWT_VAL(BLE_MAX_BIG); i++) {
if (btshell_base_list[i].adv_instance == adv_instance) {
return btshell_base_list[i].base;
}
}
return NULL;
}
static int
btshell_broadcast_destroy_fn(struct ble_audio_base *base, void *args)
{
struct ble_iso_big_params *big_params =
(struct ble_iso_big_params *)args;
struct ble_audio_big_subgroup *big_sub;
struct ble_audio_bis *bis;
STAILQ_FOREACH(big_sub, &base->subs, next) {
STAILQ_FOREACH(bis, &big_sub->bises, next) {
os_memblock_put(&btshell_bis_pool, bis);
os_memblock_put(&btshell_codec_spec_pool, bis->codec_spec_config);
STAILQ_REMOVE(&big_sub->bises, bis, ble_audio_bis, next);
}
os_memblock_put(&btshell_big_sub_pool, big_sub);
os_memblock_put(&btshell_codec_spec_pool, big_sub->codec_spec_config);
os_memblock_put(&btshell_metadata_pool, big_sub->metadata);
STAILQ_REMOVE(&base->subs, big_sub, ble_audio_big_subgroup, next);
}
os_memblock_put(&btshell_big_params_pool, big_params);
return 0;
}
int
btshell_broadcast_base_add(uint8_t adv_instance, uint32_t presentation_delay)
{
struct ble_audio_base *base;
int free_base_idx;
base = os_memblock_get(&btshell_base_pool);
if (!base) {
return ENOMEM;
}
free_base_idx = btshell_base_find_free();
if (free_base_idx < 0) {
return ENOMEM;
}
base->presentation_delay = presentation_delay;
btshell_base_list[free_base_idx].base = base;
btshell_base_list[free_base_idx].adv_instance = adv_instance;
return 0;
}
int
btshell_broadcast_big_sub_add(uint8_t adv_instance,
uint8_t codec_fmt, uint16_t company_id,
uint16_t vendor_spec,
uint8_t *metadata,
unsigned int metadata_len,
uint8_t *codec_spec_cfg,
unsigned int codec_spec_cfg_len)
{
struct ble_audio_big_subgroup *big_sub;
struct ble_audio_base *base;
uint8_t *new_metadata = NULL;
uint8_t *new_codec_spec_cfg = NULL;
big_sub = os_memblock_get(&btshell_big_sub_pool);
if (!big_sub) {
return ENOMEM;
}
base = btshell_base_find(adv_instance);
if (!base) {
os_memblock_put(&btshell_big_sub_pool, big_sub);
return ENOENT;
}
if (metadata_len > 0) {
new_metadata = os_memblock_get(&btshell_metadata_pool);
if (!new_metadata) {
os_memblock_put(&btshell_big_sub_pool, big_sub);
return ENOMEM;
}
memcpy(new_metadata, metadata, metadata_len);
}
if (codec_spec_cfg_len > 0) {
new_codec_spec_cfg = os_memblock_get(&btshell_codec_spec_pool);
if (!new_codec_spec_cfg) {
os_memblock_put(&btshell_big_sub_pool, big_sub);
os_memblock_put(&btshell_metadata_pool, new_metadata);
return ENOMEM;
}
memcpy(new_codec_spec_cfg, codec_spec_cfg, codec_spec_cfg_len);
}
big_sub->codec_id.format = codec_fmt;
big_sub->codec_id.company_id = company_id;
big_sub->codec_id.vendor_specific = vendor_spec;
big_sub->codec_id.vendor_specific = vendor_spec;
big_sub->codec_spec_config = codec_spec_cfg_len > 0 ?
new_codec_spec_cfg : NULL;
big_sub->codec_spec_config_len = codec_spec_cfg_len;
big_sub->metadata = metadata_len > 0 ? new_metadata : NULL;
big_sub->metadata_len = metadata_len;
if (STAILQ_EMPTY(&base->subs)) {
STAILQ_INSERT_HEAD(&base->subs, big_sub, next);
} else {
STAILQ_INSERT_TAIL(&base->subs, big_sub, next);
}
base->num_subgroups++;
return 0;
}
int
btshell_broadcast_bis_add(uint8_t adv_instance,
uint8_t *codec_spec_cfg,
unsigned int codec_spec_cfg_len)
{
struct ble_audio_bis *bis;
struct ble_audio_base *base;
struct ble_audio_big_subgroup *big_sub;
uint8_t *new_codec_spec_cfg;
base = btshell_base_find(adv_instance);
if (!base) {
return ENOENT;
}
big_sub = STAILQ_LAST(&base->subs, ble_audio_big_subgroup, next);
if (!big_sub) {
return ENOENT;
}
bis = os_memblock_get(&btshell_bis_pool);
if (!bis) {
return ENOMEM;
}
if (codec_spec_cfg_len > 0) {
new_codec_spec_cfg = os_memblock_get(&btshell_codec_spec_pool);
if (!new_codec_spec_cfg) {
os_memblock_put(&btshell_bis_pool, bis);
return ENOMEM;
}
memcpy(new_codec_spec_cfg, codec_spec_cfg, codec_spec_cfg_len);
}
bis->codec_spec_config = codec_spec_cfg_len > 0 ?
new_codec_spec_cfg : NULL;
bis->codec_spec_config_len = codec_spec_cfg_len;
if (STAILQ_EMPTY(&big_sub->bises)) {
STAILQ_INSERT_HEAD(&big_sub->bises, bis, next);
} else {
STAILQ_INSERT_TAIL(&big_sub->bises, bis, next);
}
big_sub->bis_cnt++;
return 0;
}
int
btshell_broadcast_create(uint8_t adv_instance,
struct ble_gap_ext_adv_params *ext_params,
struct ble_gap_periodic_adv_params *per_params,
const char *name,
struct ble_iso_big_params big_params,
uint8_t *extra_data,
unsigned int extra_data_len)
{
struct ble_audio_base *base;
struct ble_broadcast_create_params create_params;
struct ble_iso_big_params *big_params_ptr;
int rc;
base = btshell_base_find(adv_instance);
if (!base) {
return ENOENT;
}
big_params_ptr = os_memblock_get(&btshell_big_params_pool);
if (!big_params_ptr) {
return ENOMEM;
}
*big_params_ptr = big_params;
create_params.base = base;
create_params.extended_params = ext_params;
create_params.periodic_params = per_params;
create_params.name = name;
create_params.adv_instance = adv_instance;
create_params.big_params = big_params_ptr;
create_params.svc_data = extra_data;
create_params.svc_data_len = extra_data_len;
rc = ble_audio_broadcast_create(&create_params,
btshell_broadcast_destroy_fn,
(void *)big_params_ptr,
btshell_gap_event);
return rc;
}
int
btshell_broadcast_destroy(uint8_t adv_instance)
{
return ble_audio_broadcast_destroy(adv_instance);
}
int
btshell_broadcast_update(uint8_t adv_instance,
const char *name,
uint8_t *extra_data,
unsigned int extra_data_len)
{
struct ble_audio_base *base;
struct ble_broadcast_update_params params;
base = btshell_base_find(adv_instance);
params.name = name;
params.adv_instance = adv_instance;
params.svc_data = extra_data;
params.svc_data_len = extra_data_len;
params.broadcast_id = base->broadcast_id;
return ble_audio_broadcast_update(&params);
}
int
btshell_broadcast_start(uint8_t adv_instance)
{
return ble_audio_broadcast_start(adv_instance, NULL, NULL);
}
int
btshell_broadcast_stop(uint8_t adv_instance)
{
return ble_audio_broadcast_stop(adv_instance);
}
#endif
/**
* main
*
@@ -2667,7 +2990,43 @@ mynewt_main(int argc, char **argv)
"btshell_coc_conn_pool");
assert(rc == 0);
#endif
#if (MYNEWT_VAL(BLE_ISO_BROADCASTER))
rc = os_mempool_init(&btshell_base_pool, MYNEWT_VAL(BLE_MAX_BIG),
sizeof(struct ble_audio_base),
btshell_base_mem,
"btshell_base_pool");
assert(rc == 0);
rc = os_mempool_init(&btshell_big_params_pool, MYNEWT_VAL(BLE_MAX_BIG),
sizeof(struct ble_iso_big_params),
btshell_big_params_mem,
"btshell_big_params_pool");
assert(rc == 0);
rc = os_mempool_init(&btshell_big_sub_pool, MYNEWT_VAL(BLE_MAX_BIS),
sizeof(struct ble_audio_big_subgroup),
btshell_big_sub_mem,
"btshell_big_sub_pool");
assert(rc == 0);
rc = os_mempool_init(&btshell_bis_pool, MYNEWT_VAL(BLE_MAX_BIS),
sizeof(struct ble_audio_bis), btshell_bis_mem,
"btshell_bis_pool");
assert(rc == 0);
rc = os_mempool_init(&btshell_metadata_pool, MYNEWT_VAL(BLE_MAX_BIS),
MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE) - 27,
btshell_metadata_mem, "btshell_metadata_pool");
assert(rc == 0);
rc = os_mempool_init(&btshell_codec_spec_pool,
MYNEWT_VAL(BLE_MAX_BIS) * 2, 19,
btshell_codec_spec_mem, "btshell_codec_spec_pool");
assert(rc == 0);
rc = os_mempool_init(&btshell_big_params_pool,
MYNEWT_VAL(BLE_MAX_BIG),
sizeof(struct ble_iso_big_params),
btshell_big_params_mem, "btshell_big_params_pool");
assert(rc == 0);
#endif
/* Initialize the NimBLE host configuration. */
ble_hs_cfg.reset_cb = btshell_on_reset;
ble_hs_cfg.sync_cb = btshell_on_sync;
+17 -46
View File
@@ -282,28 +282,24 @@ ble_iso_tx_complete(uint16_t conn_handle, const uint8_t *data,
}
static int
ble_iso_tx_segmented(uint16_t conn_handle, uint16_t max_pdu,
const uint8_t *data, uint16_t data_len)
ble_iso_tx_segmented(uint16_t conn_handle, const uint8_t *data,
uint16_t data_len)
{
struct os_mbuf *om;
uint16_t data_left = data_len;
uint16_t packet_len;
uint16_t offset = 0;
uint8_t pb;
uint8_t ts;
int rc;
while (data_left) {
packet_len = min(max_pdu - (BLE_HCI_DATA_HDR_SZ + 4), data_left);
packet_len = min(MYNEWT_VAL(BLE_TRANSPORT_ISO_SIZE), data_left);
if (data_left == data_len) {
pb = BLE_HCI_ISO_PB_FIRST;
ts = 1;
} else if (packet_len == data_left) {
pb = BLE_HCI_ISO_PB_LAST;
ts = 0;
} else {
pb = BLE_HCI_ISO_PB_CONTINUATION;
ts = 0;
}
om = ble_hs_mbuf_bare_pkt();
@@ -311,32 +307,26 @@ ble_iso_tx_segmented(uint16_t conn_handle, uint16_t max_pdu,
return BLE_HS_ENOMEM;
}
os_mbuf_extend(om, ts == 1 ? 10: 8);
os_mbuf_extend(om, pb == BLE_HCI_ISO_PB_FIRST ? 8: 4);
/* Connection_Handle, PB_Flag, TS_Flag */
put_le16(&om->om_data[0],
BLE_HCI_ISO_HANDLE(conn_handle, pb, ts));
/* Data_Total_Length = Data length +
* Packet_Sequence_Number placeholder +
* optional timestamp*/
put_le16(&om->om_data[2], packet_len + 4 + 2 * ts);
BLE_HCI_ISO_HANDLE(conn_handle, pb, 0));
if (ts) {
/* Timestamp placeholder */
put_le16(&om->om_data[4], 0);
if (pb == BLE_HCI_ISO_PB_FIRST) {
/* Data_Total_Length = Data length +
* Packet_Sequence_Number placeholder*/
put_le16(&om->om_data[2], packet_len + 4);
/* Packet_Sequence_Number placeholder */
put_le16(&om->om_data[6], 0);
put_le16(&om->om_data[8], 0);
/* ISO_SDU_Length */
put_le16(&om->om_data[8], packet_len);
put_le16(&om->om_data[10], packet_len);
} else {
put_le16(&om->om_data[2], packet_len);
}
/* Packet_Sequence_Number placeholder */
put_le16(&om->om_data[4], 0);
/* ISO_SDU_Length */
put_le16(&om->om_data[6], packet_len);
rc = os_mbuf_append(om, data + offset, packet_len);
if (rc) {
return rc;
@@ -345,40 +335,21 @@ ble_iso_tx_segmented(uint16_t conn_handle, uint16_t max_pdu,
ble_transport_to_ll_iso(om);
offset += packet_len;
data_len -= packet_len;
data_left -= packet_len;
}
return 0;
}
int
ble_iso_tx(uint16_t conn_handle, const uint8_t *data, uint16_t data_len)
ble_iso_tx(uint16_t conn_handle, void *data, uint16_t data_len)
{
struct ble_iso_big *big;
uint16_t max_pdu = 0;
int rc;
int i;
SLIST_FOREACH(big, &ble_iso_bigs, next) {
for (i = 0; i < big->num_bis; i++) {
if (big->conn_handles[i] == conn_handle) {
max_pdu = big->max_pdu;
break;
}
}
if (max_pdu > 0) {
break;
}
}
if (!max_pdu) {
return BLE_HS_ENOENT;
}
if (data_len <= max_pdu) {
if (data_len <= MYNEWT_VAL(BLE_TRANSPORT_ISO_SIZE)) {
rc = ble_iso_tx_complete(conn_handle, data, data_len);
} else {
rc = ble_iso_tx_segmented(conn_handle, max_pdu, data, data_len);
rc = ble_iso_tx_segmented(conn_handle, data, data_len);
}
return rc;