Bluetooth: has: Make HAS registration dynamic

This changes HAS registration to be dynamic and let's the
application set Hearing Aid Type and binaural features.

Often, devices are flashed with generic firmware with some
features stored post factory production, requiring
the settings to be moved from compile time to run-time.

This change will increase the RAM usage as the GATT
service is moved from ROM to RAM.

Signed-off-by: Lars Knudsen <larsgk@gmail.com>
Co-author: Soren Engquist <soren@engquist.dk>
This commit is contained in:
Lars Knudsen 2022-11-30 12:56:02 +01:00 committed by Fabio Baltieri
commit 081b83531b
15 changed files with 201 additions and 117 deletions

View file

@ -14,49 +14,6 @@ menuconfig BT_HAS
if BT_HAS
choice BT_HAS_HEARING_AID_TYPE_CHOICE
prompt "Hearing Aid Type selection"
help
Select the Hearing Aid Type to compile.
config BT_HAS_HEARING_AID_MONAURAL
bool "Monaural Hearing Aid"
config BT_HAS_HEARING_AID_BINAURAL
depends on BT_CSIP_SET_MEMBER
bool "Binaural Hearing Aid"
config BT_HAS_HEARING_AID_BANDED
bool "Banded Hearing Aid"
endchoice # BT_HAS_HEARING_AID_TYPE_CHOICE
if BT_HAS_HEARING_AID_MONAURAL || BT_HAS_HEARING_AID_BINAURAL
choice BT_HAS_HEARING_AID_LOCATION
prompt "Hearing Aid Device Location"
help
Select the Hearing Aid Device location.
config BT_HAS_HEARING_AID_LEFT
bool "Left Ear"
config BT_HAS_HEARING_AID_RIGHT
bool "Right Ear"
endchoice # BT_HAS_HEARING_AID_LOCATION
endif # BT_HAS_HEARING_AID_MONAURAL || BT_HAS_HEARING_AID_BINAURAL
config BT_HAS_HEARING_AID_TYPE
int # hidden
range 0 2
default 0 if BT_HAS_HEARING_AID_BINAURAL
default 1 if BT_HAS_HEARING_AID_MONAURAL
default 2 if BT_HAS_HEARING_AID_BANDED
help
The value shall be one of 3 defined by the HAS 1.0 specification table 3.2
config BT_HAS_PRESET_COUNT
int "Preset record list size"
default 2
@ -70,24 +27,6 @@ config BT_HAS_PRESET_SUPPORT
if BT_HAS_PRESET_SUPPORT
if BT_HAS_HEARING_AID_BINAURAL
config BT_HAS_IDENTICAL_PRESET_RECORDS
bool "Identical preset records in Binaural Hearing Aid Set"
help
Set if the list of preset records is identical to the list of preset records
on the other member in the Binaural Hearing Aid Set.
This option sets Independent Presets field in Hearing Aid Features to 0b0.
config BT_HAS_PRESET_SYNC_SUPPORT
bool "Preset synchronization support"
depends on BT_HAS_IDENTICAL_PRESET_RECORDS
help
Set if the hearing aid has support for relaying active preset changes to the other
member in the Binaural Hearing Aid Set.
endif # BT_HAS_HEARING_AID_BINAURAL
config BT_HAS_PRESET_NAME_DYNAMIC
bool "Allow to set preset name on runtime"
help

View file

@ -6,6 +6,7 @@
#include <stdlib.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/check.h>
#include <zephyr/device.h>
@ -70,7 +71,7 @@ static ssize_t read_features(struct bt_conn *conn, const struct bt_gatt_attr *at
}
/* Hearing Access Service GATT Attributes */
BT_GATT_SERVICE_DEFINE(has_svc,
static struct bt_gatt_attr has_attrs[] = {
BT_GATT_PRIMARY_SERVICE(BT_UUID_HAS),
BT_AUDIO_CHRC(BT_UUID_HAS_HEARING_AID_FEATURES,
BT_GATT_CHRC_READ,
@ -92,11 +93,13 @@ BT_GATT_SERVICE_DEFINE(has_svc,
read_active_preset_index, NULL, NULL),
BT_AUDIO_CCC(ccc_cfg_changed),
#endif /* CONFIG_BT_HAS_PRESET_SUPPORT */
);
};
static struct bt_gatt_service has_svc;
#if defined(CONFIG_BT_HAS_PRESET_SUPPORT)
#define PRESET_CONTROL_POINT_ATTR &has_svc.attrs[4]
#define ACTIVE_PRESET_INDEX_ATTR &has_svc.attrs[7]
#define PRESET_CONTROL_POINT_ATTR &has_attrs[4]
#define ACTIVE_PRESET_INDEX_ATTR &has_attrs[7]
static struct has_client {
struct bt_conn *conn;
@ -865,19 +868,19 @@ static uint8_t handle_control_point_op(struct bt_conn *conn, struct net_buf_simp
case BT_HAS_OP_SET_PREV_PRESET:
return handle_set_prev_preset(false);
case BT_HAS_OP_SET_ACTIVE_PRESET_SYNC:
if (IS_ENABLED(CONFIG_BT_HAS_PRESET_SYNC_SUPPORT)) {
if ((has.features & BT_HAS_FEAT_PRESET_SYNC_SUPP) != 0) {
return handle_set_active_preset(buf, true);
} else {
return BT_HAS_ERR_PRESET_SYNC_NOT_SUPP;
}
case BT_HAS_OP_SET_NEXT_PRESET_SYNC:
if (IS_ENABLED(CONFIG_BT_HAS_PRESET_SYNC_SUPPORT)) {
if ((has.features & BT_HAS_FEAT_PRESET_SYNC_SUPP) != 0) {
return handle_set_next_preset(true);
} else {
return BT_HAS_ERR_PRESET_SYNC_NOT_SUPP;
}
case BT_HAS_OP_SET_PREV_PRESET_SYNC:
if (IS_ENABLED(CONFIG_BT_HAS_PRESET_SYNC_SUPPORT)) {
if ((has.features & BT_HAS_FEAT_PRESET_SYNC_SUPP) != 0) {
return handle_set_prev_preset(true);
} else {
return BT_HAS_ERR_PRESET_SYNC_NOT_SUPP;
@ -1123,48 +1126,51 @@ int bt_has_preset_name_change(uint8_t index, const char *name)
}
#endif /* CONFIG_BT_HAS_PRESET_SUPPORT */
static int has_init(const struct device *dev)
int bt_has_register(const struct bt_has_register_param *param)
{
ARG_UNUSED(dev);
int err;
LOG_DBG("param %p", param);
CHECKIF(!param) {
LOG_DBG("NULL params pointer");
return -EINVAL;
}
/* Initialize the supported features characteristic value */
has.features = CONFIG_BT_HAS_HEARING_AID_TYPE & BT_HAS_FEAT_HEARING_AID_TYPE_MASK;
has.features = param->type;
if (IS_ENABLED(CONFIG_BT_HAS_PRESET_SUPPORT)) {
has.features |= BT_HAS_FEAT_DYNAMIC_PRESETS;
}
if (IS_ENABLED(CONFIG_BT_HAS_HEARING_AID_BINAURAL)) {
if (IS_ENABLED(CONFIG_BT_HAS_PRESET_SYNC_SUPPORT)) {
has.features |= BT_HAS_FEAT_PRESET_SYNC_SUPP;
if (param->preset_sync_support) {
if (param->type != BT_HAS_HEARING_AID_TYPE_BINAURAL) {
LOG_DBG("Preset sync support only available for binaural hearing aid type");
return -EINVAL;
}
if (!IS_ENABLED(CONFIG_BT_HAS_IDENTICAL_PRESET_RECORDS)) {
has.features |= BT_HAS_FEAT_INDEPENDENT_PRESETS;
has.features |= BT_HAS_FEAT_PRESET_SYNC_SUPP;
}
if (param->independent_presets) {
if (param->type != BT_HAS_HEARING_AID_TYPE_BINAURAL) {
LOG_DBG("Independent presets only available for binaural hearing aid type");
return -EINVAL;
}
has.features |= BT_HAS_FEAT_INDEPENDENT_PRESETS;
}
if (IS_ENABLED(CONFIG_BT_HAS_PRESET_NAME_DYNAMIC)) {
has.features |= BT_HAS_FEAT_WRITABLE_PRESETS_SUPP;
}
if (IS_ENABLED(CONFIG_BT_PAC_SNK_LOC)) {
if (IS_ENABLED(CONFIG_BT_HAS_HEARING_AID_BANDED)) {
/* HAP_d1.0r00; 3.7 BAP Unicast Server role requirements
* A Banded Hearing Aid in the HA role shall set the
* Front Left and the Front Right bits to a value of 0b1
* in the Sink Audio Locations characteristic value.
*/
bt_pacs_set_location(BT_AUDIO_DIR_SINK,
(BT_AUDIO_LOCATION_FRONT_LEFT |
BT_AUDIO_LOCATION_FRONT_RIGHT));
} else if (IS_ENABLED(CONFIG_BT_HAS_HEARING_AID_LEFT)) {
bt_pacs_set_location(BT_AUDIO_DIR_SINK,
BT_AUDIO_LOCATION_FRONT_LEFT);
} else {
bt_pacs_set_location(BT_AUDIO_DIR_SINK,
BT_AUDIO_LOCATION_FRONT_RIGHT);
}
has_svc = (struct bt_gatt_service)BT_GATT_SERVICE(has_attrs);
err = bt_gatt_service_register(&has_svc);
if (err != 0) {
LOG_DBG("HAS service register failed: %d", err);
return err;
}
#if defined(CONFIG_BT_HAS_PRESET_SUPPORT)
@ -1173,5 +1179,3 @@ static int has_init(const struct device *dev)
return 0;
}
SYS_INIT(has_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);

View file

@ -75,6 +75,43 @@ static int cmd_preset_unreg(const struct shell *sh, size_t argc, char **argv)
return 0;
}
static int cmd_has_register(const struct shell *sh, size_t argc, char **argv)
{
int err;
struct bt_has_register_param param = {
.type = BT_HAS_HEARING_AID_TYPE_MONAURAL,
.preset_sync_support = false,
.independent_presets = false
};
for (size_t argn = 1; argn < argc; argn++) {
const char *arg = argv[argn];
if (strcmp(arg, "binaural") == 0) {
param.type = BT_HAS_HEARING_AID_TYPE_BINAURAL;
} else if (strcmp(arg, "monaural") == 0) {
param.type = BT_HAS_HEARING_AID_TYPE_MONAURAL;
} else if (strcmp(arg, "banded") == 0) {
param.type = BT_HAS_HEARING_AID_TYPE_BANDED;
} else if (strcmp(arg, "sync") == 0) {
param.preset_sync_support = true;
} else if (strcmp(arg, "independent") == 0) {
param.independent_presets = true;
} else {
shell_help(sh);
return SHELL_CMD_HELP_PRINTED;
}
}
err = bt_has_register(&param);
if (err != 0) {
shell_error(sh, "Could not register HAS: %d", err);
return err;
}
return 0;
}
struct print_list_entry_data {
int num;
const struct shell *sh;
@ -216,6 +253,10 @@ static int cmd_has(const struct shell *sh, size_t argc, char **argv)
}
SHELL_STATIC_SUBCMD_SET_CREATE(has_cmds,
SHELL_CMD_ARG(register, NULL,
"Initialize the service and register type "
"[binaural | monaural(default) | banded] [sync] [independent]",
cmd_has_register, 1, 3),
SHELL_CMD_ARG(preset-reg, NULL, "Register preset <index> <properties> <name>",
cmd_preset_reg, 4, 0),
SHELL_CMD_ARG(preset-unreg, NULL, "Unregister preset <index>", cmd_preset_unreg, 2, 0),