diff --git a/include/zephyr/bluetooth/audio/has.h b/include/zephyr/bluetooth/audio/has.h index 1d023cc2e1f..09b5255d59a 100644 --- a/include/zephyr/bluetooth/audio/has.h +++ b/include/zephyr/bluetooth/audio/has.h @@ -45,9 +45,9 @@ struct bt_has; /** Hearing Aid device type */ enum bt_has_hearing_aid_type { - BT_HAS_HEARING_AID_TYPE_BINAURAL, - BT_HAS_HEARING_AID_TYPE_MONAURAL, - BT_HAS_HEARING_AID_TYPE_BANDED, + BT_HAS_HEARING_AID_TYPE_BINAURAL = 0x00, + BT_HAS_HEARING_AID_TYPE_MONAURAL = 0x01, + BT_HAS_HEARING_AID_TYPE_BANDED = 0x02, }; /** Preset Properties values */ @@ -67,6 +67,18 @@ enum bt_has_capabilities { BT_HAS_PRESET_SUPPORT = BIT(0), }; +/** @brief Structure for registering a Hearing Access Service instance. */ +struct bt_has_register_param { + /** Hearing Aid Type value */ + enum bt_has_hearing_aid_type type; + + /** Preset Synchronization Support. Only applicable for binaural hearing aids. */ + bool preset_sync_support; + + /** Independent Presets. Only applicable for binaural hearing aids. */ + bool independent_presets; +}; + /** @brief Preset record definition */ struct bt_has_preset_record { /** Unique preset index. */ @@ -315,6 +327,15 @@ struct bt_has_preset_register_param { const struct bt_has_preset_ops *ops; }; +/** + * @brief Register the Hearing Access Service instance. + * + * @param param Hearing Access Service register parameters. + * + * @return 0 if success, errno on failure. + */ +int bt_has_register(const struct bt_has_register_param *param); + /** * @brief Register preset. * diff --git a/samples/bluetooth/hap_ha/CMakeLists.txt b/samples/bluetooth/hap_ha/CMakeLists.txt index f9f705fd7ca..3e594ca5ba3 100644 --- a/samples/bluetooth/hap_ha/CMakeLists.txt +++ b/samples/bluetooth/hap_ha/CMakeLists.txt @@ -11,7 +11,7 @@ target_sources(app PRIVATE src/vcp_vol_renderer.c ) -target_sources_ifdef(CONFIG_BT_HAS_HEARING_AID_BINAURAL app PRIVATE +target_sources_ifdef(CONFIG_HAP_HA_HEARING_AID_BINAURAL app PRIVATE src/csip_set_member.c ) diff --git a/samples/bluetooth/hap_ha/Kconfig b/samples/bluetooth/hap_ha/Kconfig index c1d941962e7..358380b9641 100644 --- a/samples/bluetooth/hap_ha/Kconfig +++ b/samples/bluetooth/hap_ha/Kconfig @@ -19,4 +19,34 @@ config HAP_HA_SET_RANK help Rank of this device in set. +choice HAP_HA_HEARING_AID_TYPE_CHOICE + prompt "Hearing Aid Type selection" + help + Select the Hearing Aid Type to compile. + +config HAP_HA_HEARING_AID_MONAURAL + bool "Monaural Hearing Aid" + +config HAP_HA_HEARING_AID_BINAURAL + depends on BT_CSIP_SET_MEMBER + bool "Binaural Hearing Aid" + +config HAP_HA_HEARING_AID_BANDED + bool "Banded Hearing Aid" + +endchoice # HAP_HA_HEARING_AID_TYPE_CHOICE + +choice HAP_HA_HEARING_AID_LOCATION + prompt "Hearing Aid Device Location" + help + Select the Hearing Aid Device location. + +config HAP_HA_HEARING_AID_LEFT + bool "Left Ear" + +config HAP_HA_HEARING_AID_RIGHT + bool "Right Ear" + +endchoice # HAP_HA_HEARING_AID_LOCATION + endmenu diff --git a/samples/bluetooth/hap_ha/banded.conf b/samples/bluetooth/hap_ha/banded.conf index 36f82797e55..0b24e2b2439 100644 --- a/samples/bluetooth/hap_ha/banded.conf +++ b/samples/bluetooth/hap_ha/banded.conf @@ -1,4 +1,4 @@ -CONFIG_BT_HAS_HEARING_AID_BANDED=y +CONFIG_HAP_HA_HEARING_AID_BANDED=y # If the HA supports the Volume Balance feature (see Section 3.1) and the HA # is a Banded Hearing Aid, the HA shall instantiate two instances of VOCS. diff --git a/samples/bluetooth/hap_ha/binaural.conf b/samples/bluetooth/hap_ha/binaural.conf index 28562c2778e..040966fb865 100644 --- a/samples/bluetooth/hap_ha/binaural.conf +++ b/samples/bluetooth/hap_ha/binaural.conf @@ -1,3 +1,3 @@ CONFIG_BT_CSIP_SET_MEMBER=y -CONFIG_BT_HAS_HEARING_AID_BINAURAL=y +CONFIG_HAP_HA_HEARING_AID_BINAURAL=y CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER=y diff --git a/samples/bluetooth/hap_ha/prj.conf b/samples/bluetooth/hap_ha/prj.conf index dfa34c6c167..ec2460bff1e 100644 --- a/samples/bluetooth/hap_ha/prj.conf +++ b/samples/bluetooth/hap_ha/prj.conf @@ -29,7 +29,7 @@ CONFIG_BT_PAC_SRC_LOC=y CONFIG_BT_VCP_VOL_REND=y CONFIG_BT_MICP_MIC_DEV=y CONFIG_BT_HAS=y -CONFIG_BT_HAS_HEARING_AID_MONAURAL=y +CONFIG_HAP_HA_HEARING_AID_MONAURAL=y CONFIG_BT_HAS_PRESET_COUNT=4 CONFIG_BT_HAS_PRESET_NAME_DYNAMIC=y CONFIG_BT_CAP_ACCEPTOR=y diff --git a/samples/bluetooth/hap_ha/src/bap_unicast_sr.c b/samples/bluetooth/hap_ha/src/bap_unicast_sr.c index e8465aac7d6..d544c137a21 100644 --- a/samples/bluetooth/hap_ha/src/bap_unicast_sr.c +++ b/samples/bluetooth/hap_ha/src/bap_unicast_sr.c @@ -425,6 +425,25 @@ int bap_unicast_sr_init(void) bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap_sink); + if (IS_ENABLED(CONFIG_BT_PAC_SNK_LOC)) { + if (IS_ENABLED(CONFIG_HAP_HA_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_HAP_HA_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); + } + } + if (IS_ENABLED(CONFIG_BT_ASCS_ASE_SRC)) { bt_pacs_cap_register(BT_AUDIO_DIR_SOURCE, &cap_source); } diff --git a/samples/bluetooth/hap_ha/src/has_server.c b/samples/bluetooth/hap_ha/src/has_server.c index f940c7be54e..344ae3ef2ba 100644 --- a/samples/bluetooth/hap_ha/src/has_server.c +++ b/samples/bluetooth/hap_ha/src/has_server.c @@ -34,7 +34,7 @@ static const struct bt_has_preset_ops ops = { .name_changed = name_changed_cb, }; -int has_server_init(void) +int has_server_preset_init(void) { int err; @@ -74,3 +74,25 @@ int has_server_init(void) return 0; } + +static struct bt_has_register_param param = { + .type = BT_HAS_HEARING_AID_TYPE_MONAURAL +}; + +int has_server_init(void) +{ + int err; + + if (IS_ENABLED(CONFIG_HAP_HA_HEARING_AID_BINAURAL)) { + param.type = BT_HAS_HEARING_AID_TYPE_BINAURAL; + } else if (IS_ENABLED(CONFIG_HAP_HA_HEARING_AID_BANDED)) { + param.type = BT_HAS_HEARING_AID_TYPE_BANDED; + } + + err = bt_has_register(¶m); + if (err) { + return err; + } + + return has_server_preset_init(); +} diff --git a/samples/bluetooth/hap_ha/src/main.c b/samples/bluetooth/hap_ha/src/main.c index 75d994e9afc..782095f875e 100644 --- a/samples/bluetooth/hap_ha/src/main.c +++ b/samples/bluetooth/hap_ha/src/main.c @@ -171,7 +171,7 @@ void main(void) return; } - if (IS_ENABLED(CONFIG_BT_HAS_HEARING_AID_BINAURAL)) { + if (IS_ENABLED(CONFIG_HAP_HA_HEARING_AID_BINAURAL)) { err = csip_set_member_init(); if (err != 0) { printk("CSIP Set Member init failed (err %d)\n", err); @@ -207,7 +207,7 @@ void main(void) } } - if (IS_ENABLED(CONFIG_BT_HAS_HEARING_AID_BANDED)) { + if (IS_ENABLED(CONFIG_HAP_HA_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 diff --git a/subsys/bluetooth/audio/Kconfig.has b/subsys/bluetooth/audio/Kconfig.has index 5d2bff60da0..37e4c2fc888 100644 --- a/subsys/bluetooth/audio/Kconfig.has +++ b/subsys/bluetooth/audio/Kconfig.has @@ -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 diff --git a/subsys/bluetooth/audio/has.c b/subsys/bluetooth/audio/has.c index 0a90f94a0f8..7e30bb43ca8 100644 --- a/subsys/bluetooth/audio/has.c +++ b/subsys/bluetooth/audio/has.c @@ -6,6 +6,7 @@ #include #include +#include #include @@ -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); diff --git a/subsys/bluetooth/shell/has.c b/subsys/bluetooth/shell/has.c index ed987f8cfb6..1e647792594 100644 --- a/subsys/bluetooth/shell/has.c +++ b/subsys/bluetooth/shell/has.c @@ -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(¶m); + 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 ", cmd_preset_reg, 4, 0), SHELL_CMD_ARG(preset-unreg, NULL, "Unregister preset ", cmd_preset_unreg, 2, 0), diff --git a/tests/bluetooth/bsim_bt/bsim_test_audio/prj.conf b/tests/bluetooth/bsim_bt/bsim_test_audio/prj.conf index 4d9a0371a22..d46a275cd56 100644 --- a/tests/bluetooth/bsim_bt/bsim_test_audio/prj.conf +++ b/tests/bluetooth/bsim_bt/bsim_test_audio/prj.conf @@ -107,7 +107,6 @@ CONFIG_BT_BAP_BROADCAST_ASSISTANT=y # Hearing Access CONFIG_BT_HAS=y CONFIG_BT_HAS_CLIENT=y -CONFIG_BT_HAS_HEARING_AID_MONAURAL=y # Common Audio Profile CONFIG_BT_CAP_ACCEPTOR=y diff --git a/tests/bluetooth/bsim_bt/bsim_test_audio/src/has_test.c b/tests/bluetooth/bsim_bt/bsim_test_audio/src/has_test.c index c9bfaa11e4e..7cf7509ad17 100644 --- a/tests/bluetooth/bsim_bt/bsim_test_audio/src/has_test.c +++ b/tests/bluetooth/bsim_bt/bsim_test_audio/src/has_test.c @@ -29,7 +29,9 @@ static const struct bt_has_preset_ops preset_ops = { static void test_main(void) { - struct bt_has_preset_register_param param; + struct bt_has_register_param has_param; + struct bt_has_preset_register_param preset_param; + int err; err = bt_enable(NULL); @@ -48,22 +50,30 @@ static void test_main(void) printk("Advertising successfully started\n"); - param.index = test_preset_index_5; - param.properties = test_preset_properties; - param.name = test_preset_name_5; - param.ops = &preset_ops, + has_param.type = BT_HAS_HEARING_AID_TYPE_MONAURAL; - err = bt_has_preset_register(¶m); + err = bt_has_register(&has_param); + if (err) { + FAIL("HAS register failed (err %d)\n", err); + return; + } + + preset_param.index = test_preset_index_5; + preset_param.properties = test_preset_properties; + preset_param.name = test_preset_name_5; + preset_param.ops = &preset_ops, + + err = bt_has_preset_register(&preset_param); if (err) { FAIL("Preset register failed (err %d)\n", err); return; } - param.index = test_preset_index_1; - param.properties = test_preset_properties; - param.name = test_preset_name_1; + preset_param.index = test_preset_index_1; + preset_param.properties = test_preset_properties; + preset_param.name = test_preset_name_1; - err = bt_has_preset_register(¶m); + err = bt_has_preset_register(&preset_param); if (err) { FAIL("Preset register failed (err %d)\n", err); return; diff --git a/tests/bluetooth/shell/audio.conf b/tests/bluetooth/shell/audio.conf index 773ec563792..847be03b1f8 100644 --- a/tests/bluetooth/shell/audio.conf +++ b/tests/bluetooth/shell/audio.conf @@ -132,7 +132,6 @@ CONFIG_BT_IAS=y CONFIG_BT_IAS_CLIENT=y CONFIG_BT_HAS=y -CONFIG_BT_HAS_HEARING_AID_MONAURAL=y CONFIG_BT_HAS_PRESET_NAME_DYNAMIC=y CONFIG_BT_HAS_PRESET_COUNT=4 CONFIG_BT_HAS_CLIENT=y