zephyr/samples/bluetooth/hap_ha/src/main.c
Emil Gydesen 9d4cc4b49b Bluetooth: BAP: Add a set of suggested intervals to use with BAP
Add a selection of interval values that are suitable for BAP,
which will allow better coexistence between ISO and ACL,
for both broadcast and unicast. Some of these are defined
by the BAP spec, and some are defined by Zephyr, since they
do have a suggested value from BAP.

Samples and tests have been updated to use these new values.
Peripheral samples have also been updated with
CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS so that the connection
parameters from the centrals aren't updated to something else
shortly after.

The shell has also been updated to use the LE Audio (BAP) values
if audio is enabled, and the audio.conf file has disabled automatic
updating of the connection parameters as the peripheral, as we rarely
(if ever) want to do that.

Due to the connection interval change, CI hit an issue
with test_bass_broadcast_code in test_main_client_sync, where
the reading of the long receive state did not finish before we
attempted to do another procedure, so the function was updated to have
a retry.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
2025-03-11 08:58:51 +01:00

242 lines
6.2 KiB
C

/*
* Copyright (c) 2022 Codecoup
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <stdint.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/byteorder.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/audio/audio.h>
#include <zephyr/bluetooth/audio/bap.h>
#include <zephyr/bluetooth/audio/pacs.h>
#include <zephyr/bluetooth/audio/csip.h>
#include <zephyr/bluetooth/gap.h>
#include <zephyr/bluetooth/services/ias.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/__assert.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/util.h>
#include <zephyr/sys/util_macro.h>
#include "hap_ha.h"
#define MANDATORY_SINK_CONTEXT (BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED | \
BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | \
BT_AUDIO_CONTEXT_TYPE_MEDIA | \
BT_AUDIO_CONTEXT_TYPE_LIVE)
#define AVAILABLE_SINK_CONTEXT MANDATORY_SINK_CONTEXT
#define AVAILABLE_SOURCE_CONTEXT MANDATORY_SINK_CONTEXT
static uint8_t unicast_server_addata[] = {
BT_UUID_16_ENCODE(BT_UUID_ASCS_VAL), /* ASCS UUID */
BT_AUDIO_UNICAST_ANNOUNCEMENT_TARGETED, /* Target Announcement */
BT_BYTES_LIST_LE16(AVAILABLE_SINK_CONTEXT),
BT_BYTES_LIST_LE16(AVAILABLE_SOURCE_CONTEXT),
0x00, /* Metadata length */
};
static uint8_t csis_rsi_addata[BT_CSIP_RSI_SIZE];
/* TODO: Expand with BAP data */
static const struct bt_data ad[] = {
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(BT_UUID_ASCS_VAL)),
#if defined(CONFIG_BT_CSIP_SET_MEMBER)
BT_DATA(BT_DATA_CSIS_RSI, csis_rsi_addata, ARRAY_SIZE(csis_rsi_addata)),
#endif /* CONFIG_BT_CSIP_SET_MEMBER */
BT_DATA(BT_DATA_SVC_DATA16, unicast_server_addata, ARRAY_SIZE(unicast_server_addata)),
BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1),
};
static struct k_work_delayable adv_work;
static struct bt_le_ext_adv *ext_adv;
static void disconnected(struct bt_conn *conn, uint8_t reason)
{
/* Restart advertising after disconnection */
k_work_schedule(&adv_work, K_SECONDS(1));
}
BT_CONN_CB_DEFINE(conn_callbacks) = {
.disconnected = disconnected,
};
#if defined(CONFIG_BT_PRIVACY) && defined(CONFIG_BT_CSIP_SET_MEMBER)
static bool adv_rpa_expired_cb(struct bt_le_ext_adv *adv)
{
char rsi_str[13];
int err;
err = csip_generate_rsi(csis_rsi_addata);
if (err != 0) {
printk("Failed to generate RSI (err %d)\n", err);
return false;
}
snprintk(rsi_str, ARRAY_SIZE(rsi_str), "%02x%02x%02x%02x%02x%02x",
csis_rsi_addata[0], csis_rsi_addata[1], csis_rsi_addata[2],
csis_rsi_addata[3], csis_rsi_addata[4], csis_rsi_addata[5]);
printk("PRSI: 0x%s\n", rsi_str);
err = bt_le_ext_adv_set_data(adv, ad, ARRAY_SIZE(ad), NULL, 0);
if (err) {
printk("Failed to set advertising data (err %d)\n", err);
return false;
}
return true;
}
#endif /* CONFIG_BT_PRIVACY && CONFIG_BT_CSIP_SET_MEMBER */
static const struct bt_le_ext_adv_cb adv_cb = {
#if defined(CONFIG_BT_PRIVACY) && defined(CONFIG_BT_CSIP_SET_MEMBER)
.rpa_expired = adv_rpa_expired_cb,
#endif /* CONFIG_BT_PRIVACY && CONFIG_BT_CSIP_SET_MEMBER */
};
static void adv_work_handler(struct k_work *work)
{
int err;
if (ext_adv == NULL) {
/* Create a connectable advertising set */
err = bt_le_ext_adv_create(BT_BAP_ADV_PARAM_CONN_QUICK, &adv_cb, &ext_adv);
if (err) {
printk("Failed to create advertising set (err %d)\n", err);
}
err = bt_le_ext_adv_set_data(ext_adv, ad, ARRAY_SIZE(ad), NULL, 0);
if (err) {
printk("Failed to set advertising data (err %d)\n", err);
}
__ASSERT_NO_MSG(err == 0);
}
err = bt_le_ext_adv_start(ext_adv, BT_LE_EXT_ADV_START_DEFAULT);
if (err) {
printk("Failed to start advertising set (err %d)\n", err);
} else {
printk("Advertising successfully started\n");
}
}
#if defined(CONFIG_BT_IAS)
static void alert_stop(void)
{
printk("Alert stopped\n");
}
static void alert_start(void)
{
printk("Mild alert started\n");
}
static void alert_high_start(void)
{
printk("High alert started\n");
}
BT_IAS_CB_DEFINE(ias_callbacks) = {
.no_alert = alert_stop,
.mild_alert = alert_start,
.high_alert = alert_high_start,
};
#endif /* CONFIG_BT_IAS */
int main(void)
{
int err;
err = bt_enable(NULL);
if (err != 0) {
printk("Bluetooth init failed (err %d)\n", err);
return 0;
}
printk("Bluetooth initialized\n");
err = has_server_init();
if (err != 0) {
printk("HAS Server init failed (err %d)\n", err);
return 0;
}
err = bap_unicast_sr_init();
if (err != 0) {
printk("BAP Unicast Server init failed (err %d)\n", err);
return 0;
}
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);
return 0;
}
err = csip_generate_rsi(csis_rsi_addata);
if (err != 0) {
printk("Failed to generate RSI (err %d)\n", err);
return 0;
}
}
err = vcp_vol_renderer_init();
if (err != 0) {
printk("VCP Volume Renderer init failed (err %d)\n", err);
return 0;
}
if (IS_ENABLED(CONFIG_BT_ASCS_ASE_SRC)) {
err = micp_mic_dev_init();
if (err != 0) {
printk("MICP Microphone Device init failed (err %d)\n", err);
return 0;
}
}
if (IS_ENABLED(CONFIG_BT_TBS_CLIENT)) {
err = ccp_call_ctrl_init();
if (err != 0) {
printk("MICP Microphone Device init failed (err %d)\n", err);
return 0;
}
}
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 {
bt_pacs_set_location(BT_AUDIO_DIR_SINK,
BT_AUDIO_LOCATION_FRONT_LEFT);
}
bt_pacs_set_available_contexts(BT_AUDIO_DIR_SINK,
AVAILABLE_SINK_CONTEXT);
if (IS_ENABLED(CONFIG_BT_ASCS_ASE_SRC)) {
bt_pacs_set_location(BT_AUDIO_DIR_SOURCE,
BT_AUDIO_LOCATION_FRONT_LEFT);
bt_pacs_set_available_contexts(BT_AUDIO_DIR_SOURCE,
AVAILABLE_SOURCE_CONTEXT);
}
k_work_init_delayable(&adv_work, adv_work_handler);
k_work_schedule(&adv_work, K_NO_WAIT);
return 0;
}