Bluetooth: Audio: Make BSIM tests for PACS notify functionality
Added a BSIM tests for PACS notification functionality. This test tests that all optional notifies are working, as well as verifying that a disconnected subscribed client will be notified on reconnect. Signed-off-by: Fredrik Danebjer <frdn@demant.com>
This commit is contained in:
parent
2ebbc7b130
commit
32b00dd6f4
8 changed files with 1024 additions and 190 deletions
|
@ -34,8 +34,8 @@ config BT_PACS_SNK_CONTEXT
|
||||||
config BT_PAC_SNK_NOTIFIABLE
|
config BT_PAC_SNK_NOTIFIABLE
|
||||||
bool "Sink PAC Notifiable Support"
|
bool "Sink PAC Notifiable Support"
|
||||||
help
|
help
|
||||||
This option enables support for clients to be notified of the Sink
|
This option enables support for clients to be notified on the Sink
|
||||||
PAC Characteristic.
|
PAC Characteristic changes.
|
||||||
|
|
||||||
config BT_PAC_SNK_LOC
|
config BT_PAC_SNK_LOC
|
||||||
bool "Sink PAC Location Support"
|
bool "Sink PAC Location Support"
|
||||||
|
@ -55,7 +55,7 @@ config BT_PAC_SNK_LOC_NOTIFIABLE
|
||||||
depends on BT_PAC_SNK_LOC
|
depends on BT_PAC_SNK_LOC
|
||||||
help
|
help
|
||||||
This option enables support for clients to be notified on the Sink
|
This option enables support for clients to be notified on the Sink
|
||||||
Audio Location Characteristic.
|
Audio Location Characteristic changes.
|
||||||
|
|
||||||
endif # BT_PACS_SNK
|
endif # BT_PACS_SNK
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ config BT_PAC_SRC_NOTIFIABLE
|
||||||
bool "Source PAC Notifiable Support"
|
bool "Source PAC Notifiable Support"
|
||||||
help
|
help
|
||||||
This option enables support for clients to be notified on the Source
|
This option enables support for clients to be notified on the Source
|
||||||
PAC Characteristic.
|
PAC Characteristic changes.
|
||||||
|
|
||||||
config BT_PAC_SRC_LOC
|
config BT_PAC_SRC_LOC
|
||||||
bool "Source PAC Location Support"
|
bool "Source PAC Location Support"
|
||||||
|
@ -107,7 +107,7 @@ config BT_PAC_SRC_LOC_NOTIFIABLE
|
||||||
depends on BT_PAC_SRC_LOC
|
depends on BT_PAC_SRC_LOC
|
||||||
help
|
help
|
||||||
This option enables support for clients to be notified on the Source
|
This option enables support for clients to be notified on the Source
|
||||||
Audio Location Characteristic.
|
Audio Location Characteristic changes.
|
||||||
|
|
||||||
endif # BT_PAC_SRC
|
endif # BT_PAC_SRC
|
||||||
|
|
||||||
|
@ -119,6 +119,6 @@ config BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE
|
||||||
depends on BT_PACS
|
depends on BT_PACS
|
||||||
help
|
help
|
||||||
This option enables support for clients to be notified on the
|
This option enables support for clients to be notified on the
|
||||||
Supported Audio Contexts Characteristic.
|
Supported Audio Contexts Characteristic changes.
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
|
@ -66,22 +66,12 @@ static uint16_t src_supported_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
FLAG_ACTIVE,
|
FLAG_ACTIVE,
|
||||||
#if defined(CONFIG_BT_PAC_SNK_NOTIFIABLE)
|
|
||||||
FLAG_SINK_PAC_CHANGED,
|
FLAG_SINK_PAC_CHANGED,
|
||||||
#endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE) */
|
|
||||||
#if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE)
|
|
||||||
FLAG_SINK_AUDIO_LOCATIONS_CHANGED,
|
FLAG_SINK_AUDIO_LOCATIONS_CHANGED,
|
||||||
#endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE */
|
|
||||||
#if defined(CONFIG_BT_PAC_SRC_NOTIFIABLE)
|
|
||||||
FLAG_SOURCE_PAC_CHANGED,
|
FLAG_SOURCE_PAC_CHANGED,
|
||||||
#endif /* CONFIG_BT_PAC_SRC_NOTIFIABLE */
|
|
||||||
#if defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE)
|
|
||||||
FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED,
|
FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED,
|
||||||
#endif
|
|
||||||
FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED,
|
FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED,
|
||||||
#if defined(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE)
|
|
||||||
FLAG_SUPPORTED_AUDIO_CONTEXT_CHANGED,
|
FLAG_SUPPORTED_AUDIO_CONTEXT_CHANGED,
|
||||||
#endif /* CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE */
|
|
||||||
FLAG_NUM,
|
FLAG_NUM,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -109,31 +99,6 @@ static void deferred_nfy_work_handler(struct k_work *work);
|
||||||
|
|
||||||
static K_WORK_DEFINE(deferred_nfy_work, deferred_nfy_work_handler);
|
static K_WORK_DEFINE(deferred_nfy_work, deferred_nfy_work_handler);
|
||||||
|
|
||||||
static ssize_t pac_data_add(struct net_buf_simple *buf, size_t count,
|
|
||||||
struct bt_audio_codec_data *data)
|
|
||||||
{
|
|
||||||
size_t len = 0;
|
|
||||||
|
|
||||||
for (size_t i = 0U; i < count; i++) {
|
|
||||||
struct bt_pac_ltv *ltv;
|
|
||||||
struct bt_data *d = &data[i].data;
|
|
||||||
const size_t ltv_len = sizeof(*ltv) + d->data_len;
|
|
||||||
|
|
||||||
if (net_buf_simple_tailroom(buf) < ltv_len) {
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
ltv = net_buf_simple_add(buf, sizeof(*ltv));
|
|
||||||
ltv->len = d->data_len + sizeof(ltv->type);
|
|
||||||
ltv->type = d->type;
|
|
||||||
net_buf_simple_add_mem(buf, d->data, d->data_len);
|
|
||||||
|
|
||||||
len += ltv_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct pac_records_build_data {
|
struct pac_records_build_data {
|
||||||
struct bt_pacs_read_rsp *rsp;
|
struct bt_pacs_read_rsp *rsp;
|
||||||
struct net_buf_simple *buf;
|
struct net_buf_simple *buf;
|
||||||
|
@ -308,10 +273,10 @@ static int set_supported_contexts(uint16_t contexts, uint16_t *supported,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE)
|
if (IS_ENABLED(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE)) {
|
||||||
pacs_set_notify_bit(FLAG_SUPPORTED_AUDIO_CONTEXT_CHANGED);
|
pacs_set_notify_bit(FLAG_SUPPORTED_AUDIO_CONTEXT_CHANGED);
|
||||||
k_work_submit(&deferred_nfy_work);
|
k_work_submit(&deferred_nfy_work);
|
||||||
#endif /* CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE */
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -400,10 +365,10 @@ static void set_snk_location(enum bt_audio_location audio_location)
|
||||||
|
|
||||||
pacs_snk_location = audio_location;
|
pacs_snk_location = audio_location;
|
||||||
|
|
||||||
#if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE)
|
if (IS_ENABLED(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE)) {
|
||||||
pacs_set_notify_bit(FLAG_SINK_AUDIO_LOCATIONS_CHANGED);
|
pacs_set_notify_bit(FLAG_SINK_AUDIO_LOCATIONS_CHANGED);
|
||||||
k_work_submit(&deferred_nfy_work);
|
k_work_submit(&deferred_nfy_work);
|
||||||
#endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE */
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static void set_snk_location(enum bt_audio_location location)
|
static void set_snk_location(enum bt_audio_location location)
|
||||||
|
@ -465,10 +430,12 @@ static ssize_t src_read(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||||
return ret_val;
|
return ret_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE)
|
||||||
static void src_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
|
static void src_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
|
||||||
{
|
{
|
||||||
LOG_DBG("attr %p value 0x%04x", attr, value);
|
LOG_DBG("attr %p value 0x%04x", attr, value);
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */
|
||||||
|
|
||||||
static inline int set_src_available_contexts(uint16_t contexts)
|
static inline int set_src_available_contexts(uint16_t contexts)
|
||||||
{
|
{
|
||||||
|
@ -521,10 +488,10 @@ static void set_src_location(enum bt_audio_location audio_location)
|
||||||
|
|
||||||
pacs_src_location = audio_location;
|
pacs_src_location = audio_location;
|
||||||
|
|
||||||
#if defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE)
|
if (IS_ENABLED(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE)) {
|
||||||
pacs_set_notify_bit(FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED);
|
pacs_set_notify_bit(FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED);
|
||||||
k_work_submit(&deferred_nfy_work);
|
k_work_submit(&deferred_nfy_work);
|
||||||
#endif /* CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static void set_src_location(enum bt_audio_location location)
|
static void set_src_location(enum bt_audio_location location)
|
||||||
|
@ -577,128 +544,122 @@ static sys_slist_t *pacs_get(enum bt_audio_dir dir)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define BT_PACS_SNK_PROP \
|
||||||
|
BT_GATT_CHRC_READ \
|
||||||
|
IF_ENABLED(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE, (|BT_GATT_CHRC_NOTIFY))
|
||||||
|
#define BT_PAC_SNK(_read) \
|
||||||
|
BT_AUDIO_CHRC(BT_UUID_PACS_SNK, \
|
||||||
|
BT_PACS_SNK_PROP, \
|
||||||
|
BT_GATT_PERM_READ_ENCRYPT, \
|
||||||
|
_read, NULL, NULL), \
|
||||||
|
IF_ENABLED(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE, (BT_AUDIO_CCC(snk_cfg_changed),))
|
||||||
|
|
||||||
|
#define BT_PACS_SNK_LOC_PROP \
|
||||||
|
BT_GATT_CHRC_READ \
|
||||||
|
IF_ENABLED(CONFIG_BT_PAC_SNK_LOC_WRITEABLE, (|BT_GATT_CHRC_WRITE)) \
|
||||||
|
IF_ENABLED(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE, (|BT_GATT_CHRC_NOTIFY))
|
||||||
|
#define BT_PACS_SNK_LOC_PERM \
|
||||||
|
BT_GATT_PERM_READ_ENCRYPT \
|
||||||
|
IF_ENABLED(CONFIG_BT_PAC_SNK_LOC_WRITEABLE, (|BT_GATT_PERM_WRITE_ENCRYPT))
|
||||||
|
#define BT_PACS_SNK_LOC(_read) \
|
||||||
|
BT_AUDIO_CHRC(BT_UUID_PACS_SNK_LOC, \
|
||||||
|
BT_PACS_SNK_LOC_PROP, \
|
||||||
|
BT_PACS_SNK_LOC_PERM, \
|
||||||
|
_read, \
|
||||||
|
COND_CODE_1(CONFIG_BT_PAC_SNK_LOC_WRITEABLE, (snk_loc_write), (NULL)), \
|
||||||
|
NULL), \
|
||||||
|
IF_ENABLED(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE, (BT_AUDIO_CCC(snk_loc_cfg_changed),))
|
||||||
|
|
||||||
|
#define BT_PACS_SRC_PROP \
|
||||||
|
BT_GATT_CHRC_READ \
|
||||||
|
IF_ENABLED(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE, (|BT_GATT_CHRC_NOTIFY))
|
||||||
|
#define BT_PAC_SRC(_read) \
|
||||||
|
BT_AUDIO_CHRC(BT_UUID_PACS_SRC, \
|
||||||
|
BT_PACS_SRC_PROP, \
|
||||||
|
BT_GATT_PERM_READ_ENCRYPT, \
|
||||||
|
_read, NULL, NULL), \
|
||||||
|
IF_ENABLED(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE, (BT_AUDIO_CCC(src_cfg_changed),))
|
||||||
|
|
||||||
|
#define BT_PACS_SRC_LOC_PROP \
|
||||||
|
BT_GATT_CHRC_READ \
|
||||||
|
IF_ENABLED(CONFIG_BT_PAC_SRC_LOC_WRITEABLE, (|BT_GATT_CHRC_WRITE)) \
|
||||||
|
IF_ENABLED(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE, (|BT_GATT_CHRC_NOTIFY))
|
||||||
|
#define BT_PACS_SRC_LOC_PERM \
|
||||||
|
BT_GATT_PERM_READ_ENCRYPT \
|
||||||
|
IF_ENABLED(CONFIG_BT_PAC_SRC_LOC_WRITEABLE, (|BT_GATT_PERM_WRITE_ENCRYPT))
|
||||||
|
#define BT_PACS_SRC_LOC(_read) \
|
||||||
|
BT_AUDIO_CHRC(BT_UUID_PACS_SRC_LOC, \
|
||||||
|
BT_PACS_SRC_LOC_PROP, \
|
||||||
|
BT_PACS_SRC_LOC_PERM, \
|
||||||
|
_read, \
|
||||||
|
COND_CODE_1(CONFIG_BT_PAC_SRC_LOC_WRITEABLE, (src_loc_write), (NULL)), \
|
||||||
|
NULL), \
|
||||||
|
IF_ENABLED(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE, (BT_AUDIO_CCC(src_loc_cfg_changed),))
|
||||||
|
|
||||||
|
#define BT_PAC_AVAILABLE_CONTEXT(_read) \
|
||||||
|
BT_AUDIO_CHRC(BT_UUID_PACS_AVAILABLE_CONTEXT, \
|
||||||
|
BT_GATT_CHRC_READ|BT_GATT_CHRC_NOTIFY, \
|
||||||
|
BT_GATT_PERM_READ_ENCRYPT, \
|
||||||
|
_read, NULL, NULL), \
|
||||||
|
BT_AUDIO_CCC(available_context_cfg_changed),
|
||||||
|
|
||||||
|
#define BT_PACS_SUPPORTED_CONTEXT_PROP \
|
||||||
|
BT_GATT_CHRC_READ \
|
||||||
|
IF_ENABLED(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE, (|BT_GATT_CHRC_NOTIFY))
|
||||||
|
#define BT_PAC_SUPPORTED_CONTEXT(_read) \
|
||||||
|
BT_AUDIO_CHRC(BT_UUID_PACS_SUPPORTED_CONTEXT, \
|
||||||
|
BT_PACS_SUPPORTED_CONTEXT_PROP, \
|
||||||
|
BT_GATT_PERM_READ_ENCRYPT, \
|
||||||
|
_read, NULL, NULL), \
|
||||||
|
IF_ENABLED(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE, \
|
||||||
|
(BT_AUDIO_CCC(supported_context_cfg_changed),))
|
||||||
|
|
||||||
BT_GATT_SERVICE_DEFINE(pacs_svc,
|
BT_GATT_SERVICE_DEFINE(pacs_svc,
|
||||||
BT_GATT_PRIMARY_SERVICE(BT_UUID_PACS),
|
BT_GATT_PRIMARY_SERVICE(BT_UUID_PACS),
|
||||||
#if defined(CONFIG_BT_PAC_SNK)
|
#if defined(CONFIG_BT_PAC_SNK)
|
||||||
#if defined(CONFIG_BT_PAC_SNK_NOTIFIABLE)
|
BT_PAC_SNK(snk_read)
|
||||||
BT_AUDIO_CHRC(BT_UUID_PACS_SNK,
|
|
||||||
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
|
|
||||||
BT_GATT_PERM_READ_ENCRYPT,
|
|
||||||
snk_read, NULL, NULL),
|
|
||||||
BT_AUDIO_CCC(snk_cfg_changed),
|
|
||||||
#else
|
|
||||||
BT_AUDIO_CHRC(BT_UUID_PACS_SNK,
|
|
||||||
BT_GATT_CHRC_READ,
|
|
||||||
BT_GATT_PERM_READ_ENCRYPT,
|
|
||||||
snk_read, NULL, NULL),
|
|
||||||
#endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE */
|
|
||||||
#if defined(CONFIG_BT_PAC_SNK_LOC)
|
#if defined(CONFIG_BT_PAC_SNK_LOC)
|
||||||
#if defined(CONFIG_BT_PAC_SNK_LOC_WRITEABLE) && defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE)
|
BT_PACS_SNK_LOC(snk_loc_read)
|
||||||
BT_AUDIO_CHRC(BT_UUID_PACS_SNK_LOC,
|
|
||||||
BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | BT_GATT_CHRC_NOTIFY,
|
|
||||||
BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT,
|
|
||||||
snk_loc_read, snk_loc_write, NULL),
|
|
||||||
BT_AUDIO_CCC(snk_loc_cfg_changed),
|
|
||||||
#elif defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE)
|
|
||||||
BT_AUDIO_CHRC(BT_UUID_PACS_SNK_LOC,
|
|
||||||
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
|
|
||||||
BT_GATT_PERM_READ_ENCRYPT,
|
|
||||||
snk_loc_read, NULL, NULL),
|
|
||||||
BT_AUDIO_CCC(snk_loc_cfg_changed),
|
|
||||||
#elif defined(CONFIG_BT_PAC_SNK_LOC_WRITEABLE)
|
|
||||||
BT_AUDIO_CHRC(BT_UUID_PACS_SNK_LOC,
|
|
||||||
BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
|
|
||||||
BT_GATT_PERM_READ_ENCRYPT,
|
|
||||||
snk_loc_read, snk_loc_write, NULL),
|
|
||||||
#else
|
|
||||||
BT_AUDIO_CHRC(BT_UUID_PACS_SNK_LOC,
|
|
||||||
BT_GATT_CHRC_READ,
|
|
||||||
BT_GATT_PERM_READ_ENCRYPT,
|
|
||||||
snk_loc_read, NULL, NULL),
|
|
||||||
#endif /* (CONFIG_BT_PAC_SNK_LOC_WRITEABLE && CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE) */
|
|
||||||
#endif /* CONFIG_BT_PAC_SNK_LOC */
|
#endif /* CONFIG_BT_PAC_SNK_LOC */
|
||||||
#endif /* CONFIG_BT_PAC_SNK */
|
#endif /* CONFIG_BT_PAC_SNK */
|
||||||
#if defined(CONFIG_BT_PAC_SRC)
|
#if defined(CONFIG_BT_PAC_SRC)
|
||||||
#if defined(CONFIG_BT_PAC_SRC_NOTIFIABLE)
|
BT_PAC_SRC(src_read)
|
||||||
BT_AUDIO_CHRC(BT_UUID_PACS_SRC,
|
|
||||||
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
|
|
||||||
BT_GATT_PERM_READ_ENCRYPT,
|
|
||||||
src_read, NULL, NULL),
|
|
||||||
BT_AUDIO_CCC(src_cfg_changed),
|
|
||||||
#else
|
|
||||||
BT_AUDIO_CHRC(BT_UUID_PACS_SRC,
|
|
||||||
BT_GATT_CHRC_READ,
|
|
||||||
BT_GATT_PERM_READ_ENCRYPT,
|
|
||||||
src_read, NULL, NULL),
|
|
||||||
BT_AUDIO_CCC(src_cfg_changed),
|
|
||||||
#endif /* CONFIG_BT_PAC_SRC_NOTIFIABLE */
|
|
||||||
#if defined(CONFIG_BT_PAC_SRC_LOC)
|
#if defined(CONFIG_BT_PAC_SRC_LOC)
|
||||||
#if defined(CONFIG_BT_PAC_SRC_LOC_WRITEABLE) && defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE)
|
BT_PACS_SRC_LOC(src_loc_read)
|
||||||
BT_AUDIO_CHRC(BT_UUID_PACS_SRC_LOC,
|
|
||||||
BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | BT_GATT_CHRC_NOTIFY,
|
|
||||||
BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT,
|
|
||||||
src_loc_read, src_loc_write, NULL),
|
|
||||||
BT_AUDIO_CCC(src_loc_cfg_changed),
|
|
||||||
#elif defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE)
|
|
||||||
BT_AUDIO_CHRC(BT_UUID_PACS_SRC_LOC,
|
|
||||||
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
|
|
||||||
BT_GATT_PERM_READ_ENCRYPT,
|
|
||||||
src_loc_read, NULL, NULL),
|
|
||||||
BT_AUDIO_CCC(src_loc_cfg_changed),
|
|
||||||
#elif defined(CONFIG_BT_PAC_SRC_LOC_WRITEABLE)
|
|
||||||
BT_AUDIO_CHRC(BT_UUID_PACS_SRC_LOC,
|
|
||||||
BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
|
|
||||||
BT_GATT_PERM_READ_ENCRYPT,
|
|
||||||
src_loc_read, src_loc_write, NULL),
|
|
||||||
#else
|
|
||||||
BT_AUDIO_CHRC(BT_UUID_PACS_SRC_LOC,
|
|
||||||
BT_GATT_CHRC_READ,
|
|
||||||
BT_GATT_PERM_READ_ENCRYPT,
|
|
||||||
src_loc_read, NULL, NULL),
|
|
||||||
#endif /* (CONFIG_BT_PAC_SRC_LOC_WRITEABLE && CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE) */
|
|
||||||
#endif /* CONFIG_BT_PAC_SRC_LOC */
|
#endif /* CONFIG_BT_PAC_SRC_LOC */
|
||||||
#endif /* CONFIG_BT_PAC_SRC */
|
#endif /* CONFIG_BT_PAC_SRC */
|
||||||
BT_AUDIO_CHRC(BT_UUID_PACS_AVAILABLE_CONTEXT,
|
BT_PAC_AVAILABLE_CONTEXT(available_contexts_read)
|
||||||
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
|
BT_PAC_SUPPORTED_CONTEXT(supported_context_read)
|
||||||
BT_GATT_PERM_READ_ENCRYPT,
|
|
||||||
available_contexts_read, NULL, NULL),
|
|
||||||
BT_AUDIO_CCC(available_context_cfg_changed),
|
|
||||||
#if defined(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE)
|
|
||||||
BT_AUDIO_CHRC(BT_UUID_PACS_SUPPORTED_CONTEXT,
|
|
||||||
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
|
|
||||||
BT_GATT_PERM_READ_ENCRYPT,
|
|
||||||
supported_context_read, NULL, NULL),
|
|
||||||
BT_AUDIO_CCC(supported_context_cfg_changed)
|
|
||||||
#else
|
|
||||||
BT_AUDIO_CHRC(BT_UUID_PACS_SUPPORTED_CONTEXT,
|
|
||||||
BT_GATT_CHRC_READ,
|
|
||||||
BT_GATT_PERM_READ_ENCRYPT,
|
|
||||||
supported_context_read, NULL, NULL),
|
|
||||||
#endif /* CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE */
|
|
||||||
);
|
);
|
||||||
|
|
||||||
#if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE) || defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE)
|
|
||||||
static int pac_notify_loc(struct bt_conn *conn, enum bt_audio_dir dir)
|
static int pac_notify_loc(struct bt_conn *conn, enum bt_audio_dir dir)
|
||||||
{
|
{
|
||||||
uint32_t location_le;
|
uint32_t location_le;
|
||||||
int err;
|
int err;
|
||||||
|
struct bt_uuid *uuid;
|
||||||
|
|
||||||
switch (dir) {
|
switch (dir) {
|
||||||
#if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE)
|
|
||||||
case BT_AUDIO_DIR_SINK:
|
case BT_AUDIO_DIR_SINK:
|
||||||
|
#if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE)
|
||||||
location_le = sys_cpu_to_le32(pacs_snk_location);
|
location_le = sys_cpu_to_le32(pacs_snk_location);
|
||||||
|
uuid = BT_UUID_PACS_SNK_LOC;
|
||||||
break;
|
break;
|
||||||
#endif /* CONFIG_BT_PAC_SNK */
|
#else
|
||||||
#if defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE)
|
return -ENOTSUP;
|
||||||
|
#endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE */
|
||||||
case BT_AUDIO_DIR_SOURCE:
|
case BT_AUDIO_DIR_SOURCE:
|
||||||
|
#if defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE)
|
||||||
location_le = sys_cpu_to_le32(pacs_src_location);
|
location_le = sys_cpu_to_le32(pacs_src_location);
|
||||||
|
uuid = BT_UUID_PACS_SRC_LOC;
|
||||||
break;
|
break;
|
||||||
#endif /* CONFIG_BT_PAC_SRC */
|
#else
|
||||||
|
return -ENOTSUP;
|
||||||
|
#endif /* CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = pacs_gatt_notify(conn, BT_UUID_PACS_SRC_LOC, pacs_svc.attrs, &location_le,
|
err = pacs_gatt_notify(conn, uuid, pacs_svc.attrs, &location_le,
|
||||||
sizeof(location_le));
|
sizeof(location_le));
|
||||||
if (err != 0 && err != -ENOTCONN) {
|
if (err != 0 && err != -ENOTCONN) {
|
||||||
LOG_WRN("PACS notify_loc failed: %d", err);
|
LOG_WRN("PACS notify_loc failed: %d", err);
|
||||||
|
@ -707,13 +668,25 @@ static int pac_notify_loc(struct bt_conn *conn, enum bt_audio_dir dir)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE || CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE*/
|
|
||||||
|
|
||||||
#if defined(CONFIG_BT_PAC_SRC_NOTIFIABLE) || defined(CONFIG_BT_PAC_SNK_NOTIFIABLE)
|
|
||||||
static int pac_notify(struct bt_conn *conn, enum bt_audio_dir dir)
|
static int pac_notify(struct bt_conn *conn, enum bt_audio_dir dir)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
sys_slist_t *pacs;
|
sys_slist_t *pacs;
|
||||||
|
struct bt_uuid *uuid;
|
||||||
|
|
||||||
|
switch (dir) {
|
||||||
|
case BT_AUDIO_DIR_SINK:
|
||||||
|
__ASSERT(IS_ENABLED(CONFIG_BT_PAC_SNK_NOTIFIABLE), "Sink PAC not notifiable.\n");
|
||||||
|
uuid = BT_UUID_PACS_SNK;
|
||||||
|
break;
|
||||||
|
case BT_AUDIO_DIR_SOURCE:
|
||||||
|
__ASSERT(IS_ENABLED(CONFIG_BT_PAC_SRC_NOTIFIABLE), "Source PAC not notifiable.\n");
|
||||||
|
uuid = BT_UUID_PACS_SRC;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
err = k_sem_take(&read_buf_sem, K_NO_WAIT);
|
err = k_sem_take(&read_buf_sem, K_NO_WAIT);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
|
@ -723,13 +696,10 @@ static int pac_notify(struct bt_conn *conn, enum bt_audio_dir dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
pacs = pacs_get(dir);
|
pacs = pacs_get(dir);
|
||||||
if (!pacs) {
|
__ASSERT(pacs, "Failed to get pacs.\n");
|
||||||
LOG_DBG("Failed to get pacs");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
get_pac_records(pacs, &read_buf);
|
get_pac_records(pacs, &read_buf);
|
||||||
|
|
||||||
err = pacs_gatt_notify(conn, BT_UUID_PACS_SNK, pacs_svc.attrs,
|
err = pacs_gatt_notify(conn, uuid, pacs_svc.attrs,
|
||||||
read_buf.data, read_buf.len);
|
read_buf.data, read_buf.len);
|
||||||
if (err != 0 && err != -ENOTCONN) {
|
if (err != 0 && err != -ENOTCONN) {
|
||||||
LOG_WRN("PACS notify failed: %d", err);
|
LOG_WRN("PACS notify failed: %d", err);
|
||||||
|
@ -743,7 +713,6 @@ static int pac_notify(struct bt_conn *conn, enum bt_audio_dir dir)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_BT_PAC_SRC_NOTIFIABLE|| CONFIG_BT_PAC_SNK_NOTIFIABLE */
|
|
||||||
|
|
||||||
static int available_contexts_notify(struct bt_conn *conn)
|
static int available_contexts_notify(struct bt_conn *conn)
|
||||||
{
|
{
|
||||||
|
@ -763,7 +732,6 @@ static int available_contexts_notify(struct bt_conn *conn)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE)
|
|
||||||
static int supported_contexts_notify(struct bt_conn *conn)
|
static int supported_contexts_notify(struct bt_conn *conn)
|
||||||
{
|
{
|
||||||
struct bt_pacs_context context = {
|
struct bt_pacs_context context = {
|
||||||
|
@ -781,7 +749,6 @@ static int supported_contexts_notify(struct bt_conn *conn)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE */
|
|
||||||
|
|
||||||
void pacs_gatt_notify_complete_cb(struct bt_conn *conn, void *user_data)
|
void pacs_gatt_notify_complete_cb(struct bt_conn *conn, void *user_data)
|
||||||
{
|
{
|
||||||
|
@ -827,7 +794,7 @@ static void notify_cb(struct bt_conn *conn, void *data)
|
||||||
struct bt_conn_info info;
|
struct bt_conn_info info;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
LOG_DBG("Notify cb");
|
LOG_DBG("");
|
||||||
|
|
||||||
err = bt_conn_get_info(conn, &info);
|
err = bt_conn_get_info(conn, &info);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
|
@ -845,40 +812,56 @@ static void notify_cb(struct bt_conn *conn, void *data)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_BT_PAC_SNK_NOTIFIABLE)
|
if (IS_ENABLED(CONFIG_BT_PAC_SNK_NOTIFIABLE) &&
|
||||||
if (atomic_test_and_clear_bit(client->flags, FLAG_SINK_PAC_CHANGED)) {
|
atomic_test_bit(client->flags, FLAG_SINK_PAC_CHANGED)) {
|
||||||
LOG_DBG("Notifying Sink PAC");
|
LOG_DBG("Notifying Sink PAC");
|
||||||
pac_notify(conn, BT_AUDIO_DIR_SINK);
|
err = pac_notify(conn, BT_AUDIO_DIR_SINK);
|
||||||
|
if (!err) {
|
||||||
|
atomic_clear_bit(client->flags, FLAG_SINK_PAC_CHANGED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE) */
|
|
||||||
#if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE)
|
if (IS_ENABLED(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE) &&
|
||||||
if (atomic_test_and_clear_bit(client->flags, FLAG_SINK_AUDIO_LOCATIONS_CHANGED)) {
|
atomic_test_bit(client->flags, FLAG_SINK_AUDIO_LOCATIONS_CHANGED)) {
|
||||||
LOG_DBG("Notifying Sink Audio Location");
|
LOG_DBG("Notifying Sink Audio Location");
|
||||||
pac_notify_loc(conn, BT_AUDIO_DIR_SINK);
|
err = pac_notify_loc(conn, BT_AUDIO_DIR_SINK);
|
||||||
|
if (!err) {
|
||||||
|
atomic_clear_bit(client->flags, FLAG_SINK_AUDIO_LOCATIONS_CHANGED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE */
|
if (IS_ENABLED(CONFIG_BT_PAC_SRC_NOTIFIABLE) &&
|
||||||
#if defined(CONFIG_BT_PAC_SRC_NOTIFIABLE)
|
atomic_test_bit(client->flags, FLAG_SOURCE_PAC_CHANGED)) {
|
||||||
if (atomic_test_and_clear_bit(client->flags, FLAG_SOURCE_PAC_CHANGED)) {
|
|
||||||
LOG_DBG("Notifying Source PAC");
|
LOG_DBG("Notifying Source PAC");
|
||||||
pac_notify(conn, BT_AUDIO_DIR_SOURCE);
|
err = pac_notify(conn, BT_AUDIO_DIR_SOURCE);
|
||||||
|
if (!err) {
|
||||||
|
atomic_clear_bit(client->flags, FLAG_SOURCE_PAC_CHANGED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_BT_PAC_SRC_NOTIFIABLE */
|
if (IS_ENABLED(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE) &&
|
||||||
#if defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE)
|
atomic_test_and_clear_bit(client->flags, FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED)) {
|
||||||
if (atomic_test_and_clear_bit(client->flags, FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED)) {
|
|
||||||
LOG_DBG("Notifying Source Audio Location");
|
LOG_DBG("Notifying Source Audio Location");
|
||||||
pac_notify_loc(conn, BT_AUDIO_DIR_SOURCE);
|
err = pac_notify_loc(conn, BT_AUDIO_DIR_SOURCE);
|
||||||
|
if (!err) {
|
||||||
|
atomic_clear_bit(client->flags, FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
if (atomic_test_and_clear_bit(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED)) {
|
if (atomic_test_bit(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED)) {
|
||||||
LOG_DBG("Notifying Available Contexts");
|
LOG_DBG("Notifying Available Contexts");
|
||||||
available_contexts_notify(conn);
|
err = available_contexts_notify(conn);
|
||||||
|
if (!err) {
|
||||||
|
atomic_clear_bit(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#if defined(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE)
|
|
||||||
if (atomic_test_and_clear_bit(client->flags, FLAG_SUPPORTED_AUDIO_CONTEXT_CHANGED)) {
|
if (IS_ENABLED(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE) &&
|
||||||
|
atomic_test_bit(client->flags, FLAG_SUPPORTED_AUDIO_CONTEXT_CHANGED)) {
|
||||||
LOG_DBG("Notifying Supported Contexts");
|
LOG_DBG("Notifying Supported Contexts");
|
||||||
supported_contexts_notify(conn);
|
err = supported_contexts_notify(conn);
|
||||||
|
if (!err) {
|
||||||
|
atomic_clear_bit(client->flags, FLAG_SUPPORTED_AUDIO_CONTEXT_CHANGED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void deferred_nfy_work_handler(struct k_work *work)
|
static void deferred_nfy_work_handler(struct k_work *work)
|
||||||
|
@ -946,7 +929,6 @@ static void pacs_security_changed(struct bt_conn *conn, bt_security_t level,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0U; i < ARRAY_SIZE(clients); i++) {
|
for (size_t i = 0U; i < ARRAY_SIZE(clients); i++) {
|
||||||
|
|
||||||
for (size_t j = 0U; j < FLAG_NUM; j++) {
|
for (size_t j = 0U; j < FLAG_NUM; j++) {
|
||||||
if (atomic_test_bit(clients[i].flags, j)) {
|
if (atomic_test_bit(clients[i].flags, j)) {
|
||||||
|
|
||||||
|
@ -1049,23 +1031,16 @@ int bt_pacs_cap_register(enum bt_audio_dir dir, struct bt_pacs_cap *cap)
|
||||||
callbacks_registered = true;
|
callbacks_registered = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_BT_PAC_SNK_NOTIFIABLE) && dir == BT_AUDIO_DIR_SINK) {
|
||||||
#if defined(CONFIG_BT_PAC_SNK_NOTIFIABLE)
|
|
||||||
if (dir == BT_AUDIO_DIR_SINK) {
|
|
||||||
pacs_set_notify_bit(FLAG_SINK_PAC_CHANGED);
|
pacs_set_notify_bit(FLAG_SINK_PAC_CHANGED);
|
||||||
k_work_submit(&deferred_nfy_work);
|
k_work_submit(&deferred_nfy_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE */
|
if (IS_ENABLED(CONFIG_BT_PAC_SRC_NOTIFIABLE) && dir == BT_AUDIO_DIR_SOURCE) {
|
||||||
|
|
||||||
#if defined(CONFIG_BT_PAC_SRC_NOTIFIABLE)
|
|
||||||
if (dir == BT_AUDIO_DIR_SOURCE) {
|
|
||||||
pacs_set_notify_bit(FLAG_SOURCE_PAC_CHANGED);
|
pacs_set_notify_bit(FLAG_SOURCE_PAC_CHANGED);
|
||||||
k_work_submit(&deferred_nfy_work);
|
k_work_submit(&deferred_nfy_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_BT_PAC_SRC_NOTIFIABLE */
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,6 +127,21 @@ CONFIG_BT_CAP_INITIATOR=y
|
||||||
# Telephony and Media Audio Profile
|
# Telephony and Media Audio Profile
|
||||||
CONFIG_BT_TMAP=y
|
CONFIG_BT_TMAP=y
|
||||||
|
|
||||||
|
# Publish Audio Capability configurations
|
||||||
|
CONFIG_BT_PAC_SNK=y
|
||||||
|
CONFIG_BT_PAC_SRC=y
|
||||||
|
CONFIG_BT_PAC_SNK_LOC=y
|
||||||
|
CONFIG_BT_PAC_SRC_LOC=y
|
||||||
|
|
||||||
|
CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE=y
|
||||||
|
CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE=y
|
||||||
|
CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE=y
|
||||||
|
CONFIG_BT_PAC_SRC_NOTIFIABLE=y
|
||||||
|
CONFIG_BT_PAC_SNK_NOTIFIABLE=y
|
||||||
|
CONFIG_BT_PAC_SNK_LOC_WRITEABLE=y
|
||||||
|
CONFIG_BT_PAC_SRC_LOC_WRITEABLE=y
|
||||||
|
CONFIG_BT_GATT_AUTO_DISCOVER_CCC=y
|
||||||
|
|
||||||
# DEBUGGING
|
# DEBUGGING
|
||||||
CONFIG_LOG=y
|
CONFIG_LOG=y
|
||||||
CONFIG_LOG_FUNC_NAME_PREFIX_ERR=y
|
CONFIG_LOG_FUNC_NAME_PREFIX_ERR=y
|
||||||
|
|
|
@ -41,6 +41,11 @@
|
||||||
while (!(bool)atomic_get(&flag)) { \
|
while (!(bool)atomic_get(&flag)) { \
|
||||||
(void)k_sleep(K_MSEC(1)); \
|
(void)k_sleep(K_MSEC(1)); \
|
||||||
}
|
}
|
||||||
|
#define WAIT_FOR_UNSET_FLAG(flag) \
|
||||||
|
while (atomic_get(&flag) != (atomic_t)false) { \
|
||||||
|
(void)k_sleep(K_MSEC(1)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#define FAIL(...) \
|
#define FAIL(...) \
|
||||||
do { \
|
do { \
|
||||||
|
|
|
@ -33,6 +33,8 @@ extern struct bst_test_list *test_ias_install(struct bst_test_list *tests);
|
||||||
extern struct bst_test_list *test_ias_client_install(struct bst_test_list *tests);
|
extern struct bst_test_list *test_ias_client_install(struct bst_test_list *tests);
|
||||||
extern struct bst_test_list *test_tmap_client_install(struct bst_test_list *tests);
|
extern struct bst_test_list *test_tmap_client_install(struct bst_test_list *tests);
|
||||||
extern struct bst_test_list *test_tmap_server_install(struct bst_test_list *tests);
|
extern struct bst_test_list *test_tmap_server_install(struct bst_test_list *tests);
|
||||||
|
extern struct bst_test_list *test_pacs_notify_client_install(struct bst_test_list *tests);
|
||||||
|
extern struct bst_test_list *test_pacs_notify_server_install(struct bst_test_list *tests);
|
||||||
|
|
||||||
bst_test_install_t test_installers[] = {
|
bst_test_install_t test_installers[] = {
|
||||||
test_vcp_install,
|
test_vcp_install,
|
||||||
|
@ -62,6 +64,8 @@ bst_test_install_t test_installers[] = {
|
||||||
test_ias_client_install,
|
test_ias_client_install,
|
||||||
test_tmap_server_install,
|
test_tmap_server_install,
|
||||||
test_tmap_client_install,
|
test_tmap_client_install,
|
||||||
|
test_pacs_notify_client_install,
|
||||||
|
test_pacs_notify_server_install,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
576
tests/bsim/bluetooth/audio/src/pacs_notify_client_test.c
Normal file
576
tests/bsim/bluetooth/audio/src/pacs_notify_client_test.c
Normal file
|
@ -0,0 +1,576 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Demant A/S
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/bluetooth/bluetooth.h>
|
||||||
|
#include <zephyr/bluetooth/gatt.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "common/bt_str.h"
|
||||||
|
|
||||||
|
struct pacs_instance_t {
|
||||||
|
uint16_t start_handle;
|
||||||
|
uint16_t end_handle;
|
||||||
|
|
||||||
|
struct bt_gatt_subscribe_params sink_pacs_sub;
|
||||||
|
struct bt_gatt_subscribe_params source_pacs_sub;
|
||||||
|
struct bt_gatt_subscribe_params sink_loc_sub;
|
||||||
|
struct bt_gatt_subscribe_params source_loc_sub;
|
||||||
|
struct bt_gatt_subscribe_params available_contexts_sub;
|
||||||
|
struct bt_gatt_subscribe_params supported_contexts_sub;
|
||||||
|
|
||||||
|
struct bt_gatt_discover_params discover_params;
|
||||||
|
|
||||||
|
int notify_received_mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern enum bst_result_t bst_result;
|
||||||
|
|
||||||
|
CREATE_FLAG(flag_pacs_snk_discovered);
|
||||||
|
CREATE_FLAG(flag_pacs_src_discovered);
|
||||||
|
CREATE_FLAG(flag_snk_loc_discovered);
|
||||||
|
CREATE_FLAG(flag_src_loc_discovered);
|
||||||
|
CREATE_FLAG(flag_available_contexts_discovered);
|
||||||
|
CREATE_FLAG(flag_supported_contexts_discovered);
|
||||||
|
CREATE_FLAG(flag_all_notifications_received);
|
||||||
|
|
||||||
|
static struct bt_uuid_16 uuid = BT_UUID_INIT_16(0);
|
||||||
|
|
||||||
|
static struct pacs_instance_t pacs_instance;
|
||||||
|
|
||||||
|
static uint8_t pacs_notify_handler(struct bt_conn *conn,
|
||||||
|
struct bt_gatt_subscribe_params *params,
|
||||||
|
const void *data, uint16_t length)
|
||||||
|
{
|
||||||
|
printk("%p\n", params);
|
||||||
|
|
||||||
|
if (params == &pacs_instance.sink_pacs_sub) {
|
||||||
|
printk("Received sink_pacs_sub notification\n");
|
||||||
|
pacs_instance.notify_received_mask |= BIT(0);
|
||||||
|
} else if (params == &pacs_instance.source_pacs_sub) {
|
||||||
|
printk("Received source_pacs_sub notification\n");
|
||||||
|
pacs_instance.notify_received_mask |= BIT(1);
|
||||||
|
} else if (params == &pacs_instance.sink_loc_sub) {
|
||||||
|
printk("Received sink_loc_sub notification\n");
|
||||||
|
pacs_instance.notify_received_mask |= BIT(2);
|
||||||
|
} else if (params == &pacs_instance.source_loc_sub) {
|
||||||
|
printk("Received source_loc_sub notification\n");
|
||||||
|
pacs_instance.notify_received_mask |= BIT(3);
|
||||||
|
} else if (params == &pacs_instance.available_contexts_sub) {
|
||||||
|
printk("Received available_contexts_sub notification\n");
|
||||||
|
pacs_instance.notify_received_mask |= BIT(4);
|
||||||
|
} else if (params == &pacs_instance.supported_contexts_sub) {
|
||||||
|
printk("Received supported_contexts_sub notification\n");
|
||||||
|
pacs_instance.notify_received_mask |= BIT(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
printk("pacs_instance.notify_received_mask is %d\n", pacs_instance.notify_received_mask);
|
||||||
|
|
||||||
|
if (pacs_instance.notify_received_mask ==
|
||||||
|
(BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5))) {
|
||||||
|
pacs_instance.notify_received_mask = 0;
|
||||||
|
SET_FLAG(flag_all_notifications_received);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BT_GATT_ITER_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t discover_supported_contexts(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||||
|
struct bt_gatt_discover_params *params)
|
||||||
|
{
|
||||||
|
struct bt_gatt_subscribe_params *subscribe_params;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!attr) {
|
||||||
|
printk("Discover complete\n");
|
||||||
|
(void)memset(params, 0, sizeof(*params));
|
||||||
|
return BT_GATT_ITER_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bt_uuid_cmp(params->uuid, BT_UUID_PACS_SUPPORTED_CONTEXT)) {
|
||||||
|
printk("PACS Supported Contexts Characteristic handle at %d\n", attr->handle);
|
||||||
|
subscribe_params = &pacs_instance.supported_contexts_sub;
|
||||||
|
memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid));
|
||||||
|
pacs_instance.discover_params.uuid = &uuid.uuid;
|
||||||
|
pacs_instance.discover_params.start_handle = attr->handle + 2;
|
||||||
|
pacs_instance.discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR;
|
||||||
|
subscribe_params->value_handle = bt_gatt_attr_value_handle(attr);
|
||||||
|
|
||||||
|
err = bt_gatt_discover(conn, &pacs_instance.discover_params);
|
||||||
|
if (err) {
|
||||||
|
printk("Discover failed (err %d)\n", err);
|
||||||
|
}
|
||||||
|
} else if (!bt_uuid_cmp(params->uuid, BT_UUID_GATT_CCC)) {
|
||||||
|
printk("CCC handle at %d\n", attr->handle);
|
||||||
|
subscribe_params = &pacs_instance.supported_contexts_sub;
|
||||||
|
subscribe_params->notify = pacs_notify_handler;
|
||||||
|
subscribe_params->value = BT_GATT_CCC_NOTIFY;
|
||||||
|
subscribe_params->ccc_handle = attr->handle;
|
||||||
|
|
||||||
|
err = bt_gatt_subscribe(conn, subscribe_params);
|
||||||
|
if (err && err != -EALREADY) {
|
||||||
|
printk("Subscribe failed (err %d)\n", err);
|
||||||
|
} else {
|
||||||
|
SET_FLAG(flag_supported_contexts_discovered);
|
||||||
|
printk("[SUBSCRIBED]\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printk("Unknown handle at %d\n", attr->handle);
|
||||||
|
return BT_GATT_ITER_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BT_GATT_ITER_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void discover_and_subscribe_supported_contexts(void)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
printk("%s\n", __func__);
|
||||||
|
|
||||||
|
memcpy(&uuid, BT_UUID_PACS_SUPPORTED_CONTEXT, sizeof(uuid));
|
||||||
|
pacs_instance.discover_params.uuid = &uuid.uuid;
|
||||||
|
pacs_instance.discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
|
||||||
|
pacs_instance.discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
|
||||||
|
pacs_instance.discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
|
||||||
|
pacs_instance.discover_params.func = discover_supported_contexts;
|
||||||
|
|
||||||
|
err = bt_gatt_discover(default_conn, &pacs_instance.discover_params);
|
||||||
|
if (err != 0) {
|
||||||
|
FAIL("Service Discovery failed (err %d)\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t discover_available_contexts(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||||
|
struct bt_gatt_discover_params *params)
|
||||||
|
{
|
||||||
|
struct bt_gatt_subscribe_params *subscribe_params;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!attr) {
|
||||||
|
printk("Discover complete\n");
|
||||||
|
(void)memset(params, 0, sizeof(*params));
|
||||||
|
return BT_GATT_ITER_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bt_uuid_cmp(params->uuid, BT_UUID_PACS_AVAILABLE_CONTEXT)) {
|
||||||
|
printk("PACS Available Contexts Characteristic handle at %d\n", attr->handle);
|
||||||
|
subscribe_params = &pacs_instance.available_contexts_sub;
|
||||||
|
memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid));
|
||||||
|
pacs_instance.discover_params.uuid = &uuid.uuid;
|
||||||
|
pacs_instance.discover_params.start_handle = attr->handle + 2;
|
||||||
|
pacs_instance.discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR;
|
||||||
|
subscribe_params->value_handle = bt_gatt_attr_value_handle(attr);
|
||||||
|
|
||||||
|
err = bt_gatt_discover(conn, &pacs_instance.discover_params);
|
||||||
|
if (err) {
|
||||||
|
printk("Discover failed (err %d)\n", err);
|
||||||
|
}
|
||||||
|
} else if (!bt_uuid_cmp(params->uuid, BT_UUID_GATT_CCC)) {
|
||||||
|
printk("CCC handle at %d\n", attr->handle);
|
||||||
|
subscribe_params = &pacs_instance.available_contexts_sub;
|
||||||
|
subscribe_params->notify = pacs_notify_handler;
|
||||||
|
subscribe_params->value = BT_GATT_CCC_NOTIFY;
|
||||||
|
subscribe_params->ccc_handle = attr->handle;
|
||||||
|
|
||||||
|
err = bt_gatt_subscribe(conn, subscribe_params);
|
||||||
|
if (err && err != -EALREADY) {
|
||||||
|
printk("Subscribe failed (err %d)\n", err);
|
||||||
|
} else {
|
||||||
|
SET_FLAG(flag_available_contexts_discovered);
|
||||||
|
printk("[SUBSCRIBED]\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printk("Unknown handle at %d\n", attr->handle);
|
||||||
|
return BT_GATT_ITER_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BT_GATT_ITER_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void discover_and_subscribe_available_contexts(void)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
printk("%s\n", __func__);
|
||||||
|
|
||||||
|
memcpy(&uuid, BT_UUID_PACS_AVAILABLE_CONTEXT, sizeof(uuid));
|
||||||
|
pacs_instance.discover_params.uuid = &uuid.uuid;
|
||||||
|
pacs_instance.discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
|
||||||
|
pacs_instance.discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
|
||||||
|
pacs_instance.discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
|
||||||
|
pacs_instance.discover_params.func = discover_available_contexts;
|
||||||
|
|
||||||
|
err = bt_gatt_discover(default_conn, &pacs_instance.discover_params);
|
||||||
|
if (err != 0) {
|
||||||
|
FAIL("Service Discovery failed (err %d)\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t discover_src_loc(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||||
|
struct bt_gatt_discover_params *params)
|
||||||
|
{
|
||||||
|
struct bt_gatt_subscribe_params *subscribe_params;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!attr) {
|
||||||
|
printk("Discover complete\n");
|
||||||
|
(void)memset(params, 0, sizeof(*params));
|
||||||
|
return BT_GATT_ITER_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bt_uuid_cmp(params->uuid, BT_UUID_PACS_SRC_LOC)) {
|
||||||
|
printk("PACS Source Location Characteristic handle at %d\n", attr->handle);
|
||||||
|
subscribe_params = &pacs_instance.source_loc_sub;
|
||||||
|
memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid));
|
||||||
|
pacs_instance.discover_params.uuid = &uuid.uuid;
|
||||||
|
pacs_instance.discover_params.start_handle = attr->handle + 2;
|
||||||
|
pacs_instance.discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR;
|
||||||
|
subscribe_params->value_handle = bt_gatt_attr_value_handle(attr);
|
||||||
|
|
||||||
|
err = bt_gatt_discover(conn, &pacs_instance.discover_params);
|
||||||
|
if (err) {
|
||||||
|
printk("Discover failed (err %d)\n", err);
|
||||||
|
}
|
||||||
|
} else if (!bt_uuid_cmp(params->uuid, BT_UUID_GATT_CCC)) {
|
||||||
|
printk("CCC handle at %d\n", attr->handle);
|
||||||
|
subscribe_params = &pacs_instance.source_loc_sub;
|
||||||
|
subscribe_params->notify = pacs_notify_handler;
|
||||||
|
subscribe_params->value = BT_GATT_CCC_NOTIFY;
|
||||||
|
subscribe_params->ccc_handle = attr->handle;
|
||||||
|
|
||||||
|
err = bt_gatt_subscribe(conn, subscribe_params);
|
||||||
|
if (err && err != -EALREADY) {
|
||||||
|
printk("Subscribe failed (err %d)\n", err);
|
||||||
|
} else {
|
||||||
|
SET_FLAG(flag_src_loc_discovered);
|
||||||
|
printk("[SUBSCRIBED]\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printk("Unknown handle at %d\n", attr->handle);
|
||||||
|
return BT_GATT_ITER_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BT_GATT_ITER_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void discover_and_subscribe_src_loc(void)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
printk("%s\n", __func__);
|
||||||
|
|
||||||
|
memcpy(&uuid, BT_UUID_PACS_SRC_LOC, sizeof(uuid));
|
||||||
|
pacs_instance.discover_params.uuid = &uuid.uuid;
|
||||||
|
pacs_instance.discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
|
||||||
|
pacs_instance.discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
|
||||||
|
pacs_instance.discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
|
||||||
|
pacs_instance.discover_params.func = discover_src_loc;
|
||||||
|
|
||||||
|
err = bt_gatt_discover(default_conn, &pacs_instance.discover_params);
|
||||||
|
if (err != 0) {
|
||||||
|
FAIL("Service Discovery failed (err %d)\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t discover_snk_loc(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||||
|
struct bt_gatt_discover_params *params)
|
||||||
|
{
|
||||||
|
struct bt_gatt_subscribe_params *subscribe_params;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!attr) {
|
||||||
|
printk("Discover complete\n");
|
||||||
|
(void)memset(params, 0, sizeof(*params));
|
||||||
|
return BT_GATT_ITER_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bt_uuid_cmp(params->uuid, BT_UUID_PACS_SNK_LOC)) {
|
||||||
|
printk("PACS Sink Location Characteristic handle at %d\n", attr->handle);
|
||||||
|
subscribe_params = &pacs_instance.sink_loc_sub;
|
||||||
|
memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid));
|
||||||
|
pacs_instance.discover_params.uuid = &uuid.uuid;
|
||||||
|
pacs_instance.discover_params.start_handle = attr->handle + 2;
|
||||||
|
pacs_instance.discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR;
|
||||||
|
subscribe_params->value_handle = bt_gatt_attr_value_handle(attr);
|
||||||
|
|
||||||
|
err = bt_gatt_discover(conn, &pacs_instance.discover_params);
|
||||||
|
if (err) {
|
||||||
|
printk("Discover failed (err %d)\n", err);
|
||||||
|
}
|
||||||
|
} else if (!bt_uuid_cmp(params->uuid, BT_UUID_GATT_CCC)) {
|
||||||
|
printk("CCC handle at %d\n", attr->handle);
|
||||||
|
subscribe_params = &pacs_instance.sink_loc_sub;
|
||||||
|
subscribe_params->notify = pacs_notify_handler;
|
||||||
|
subscribe_params->value = BT_GATT_CCC_NOTIFY;
|
||||||
|
subscribe_params->ccc_handle = attr->handle;
|
||||||
|
|
||||||
|
err = bt_gatt_subscribe(conn, subscribe_params);
|
||||||
|
if (err && err != -EALREADY) {
|
||||||
|
printk("Subscribe failed (err %d)\n", err);
|
||||||
|
} else {
|
||||||
|
SET_FLAG(flag_snk_loc_discovered);
|
||||||
|
printk("[SUBSCRIBED]\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printk("Unknown handle at %d\n", attr->handle);
|
||||||
|
return BT_GATT_ITER_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BT_GATT_ITER_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void discover_and_subscribe_snk_loc(void)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
printk("%s\n", __func__);
|
||||||
|
|
||||||
|
memcpy(&uuid, BT_UUID_PACS_SNK_LOC, sizeof(uuid));
|
||||||
|
pacs_instance.discover_params.uuid = &uuid.uuid;
|
||||||
|
pacs_instance.discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
|
||||||
|
pacs_instance.discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
|
||||||
|
pacs_instance.discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
|
||||||
|
pacs_instance.discover_params.func = discover_snk_loc;
|
||||||
|
|
||||||
|
err = bt_gatt_discover(default_conn, &pacs_instance.discover_params);
|
||||||
|
if (err != 0) {
|
||||||
|
FAIL("Service Discovery failed (err %d)\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t discover_pacs_src(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||||
|
struct bt_gatt_discover_params *params)
|
||||||
|
{
|
||||||
|
struct bt_gatt_subscribe_params *subscribe_params;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!attr) {
|
||||||
|
printk("Discover complete\n");
|
||||||
|
(void)memset(params, 0, sizeof(*params));
|
||||||
|
return BT_GATT_ITER_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bt_uuid_cmp(params->uuid, BT_UUID_PACS_SRC)) {
|
||||||
|
printk("PACS Source Characteristic handle at %d\n", attr->handle);
|
||||||
|
subscribe_params = &pacs_instance.source_pacs_sub;
|
||||||
|
memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid));
|
||||||
|
pacs_instance.discover_params.uuid = &uuid.uuid;
|
||||||
|
pacs_instance.discover_params.start_handle = attr->handle + 2;
|
||||||
|
pacs_instance.discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR;
|
||||||
|
subscribe_params->value_handle = bt_gatt_attr_value_handle(attr);
|
||||||
|
|
||||||
|
err = bt_gatt_discover(conn, &pacs_instance.discover_params);
|
||||||
|
if (err) {
|
||||||
|
printk("Discover failed (err %d)\n", err);
|
||||||
|
}
|
||||||
|
} else if (!bt_uuid_cmp(params->uuid, BT_UUID_GATT_CCC)) {
|
||||||
|
printk("CCC handle at %d\n", attr->handle);
|
||||||
|
subscribe_params = &pacs_instance.source_pacs_sub;
|
||||||
|
subscribe_params->notify = pacs_notify_handler;
|
||||||
|
subscribe_params->value = BT_GATT_CCC_NOTIFY;
|
||||||
|
subscribe_params->ccc_handle = attr->handle;
|
||||||
|
|
||||||
|
err = bt_gatt_subscribe(conn, subscribe_params);
|
||||||
|
if (err && err != -EALREADY) {
|
||||||
|
printk("Subscribe failed (err %d)\n", err);
|
||||||
|
} else {
|
||||||
|
SET_FLAG(flag_pacs_src_discovered);
|
||||||
|
printk("[SUBSCRIBED]\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printk("Unknown handle at %d\n", attr->handle);
|
||||||
|
return BT_GATT_ITER_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BT_GATT_ITER_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void discover_and_subscribe_src_pacs(void)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
printk("%s\n", __func__);
|
||||||
|
|
||||||
|
memcpy(&uuid, BT_UUID_PACS_SRC, sizeof(uuid));
|
||||||
|
pacs_instance.discover_params.uuid = &uuid.uuid;
|
||||||
|
pacs_instance.discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
|
||||||
|
pacs_instance.discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
|
||||||
|
pacs_instance.discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
|
||||||
|
pacs_instance.discover_params.func = discover_pacs_src;
|
||||||
|
|
||||||
|
err = bt_gatt_discover(default_conn, &pacs_instance.discover_params);
|
||||||
|
if (err != 0) {
|
||||||
|
FAIL("Service Discovery failed (err %d)\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t discover_pacs_snk(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||||
|
struct bt_gatt_discover_params *params)
|
||||||
|
{
|
||||||
|
struct bt_gatt_subscribe_params *subscribe_params;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!attr) {
|
||||||
|
printk("Discover complete\n");
|
||||||
|
(void)memset(params, 0, sizeof(*params));
|
||||||
|
return BT_GATT_ITER_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bt_uuid_cmp(params->uuid, BT_UUID_PACS_SNK)) {
|
||||||
|
printk("PACS Sink Characteristic handle at %d\n", attr->handle);
|
||||||
|
subscribe_params = &pacs_instance.sink_pacs_sub;
|
||||||
|
memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid));
|
||||||
|
pacs_instance.discover_params.uuid = &uuid.uuid;
|
||||||
|
pacs_instance.discover_params.start_handle = attr->handle + 2;
|
||||||
|
pacs_instance.discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR;
|
||||||
|
subscribe_params->value_handle = bt_gatt_attr_value_handle(attr);
|
||||||
|
|
||||||
|
err = bt_gatt_discover(conn, &pacs_instance.discover_params);
|
||||||
|
if (err) {
|
||||||
|
printk("Discover failed (err %d)\n", err);
|
||||||
|
}
|
||||||
|
} else if (!bt_uuid_cmp(params->uuid, BT_UUID_GATT_CCC)) {
|
||||||
|
printk("CCC handle at %d\n", attr->handle);
|
||||||
|
subscribe_params = &pacs_instance.sink_pacs_sub;
|
||||||
|
subscribe_params->notify = pacs_notify_handler;
|
||||||
|
subscribe_params->value = BT_GATT_CCC_NOTIFY;
|
||||||
|
subscribe_params->ccc_handle = attr->handle;
|
||||||
|
|
||||||
|
err = bt_gatt_subscribe(conn, subscribe_params);
|
||||||
|
if (err && err != -EALREADY) {
|
||||||
|
printk("Subscribe failed (err %d)\n", err);
|
||||||
|
} else {
|
||||||
|
SET_FLAG(flag_pacs_snk_discovered);
|
||||||
|
printk("[SUBSCRIBED]\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printk("Unknown handle at %d\n", attr->handle);
|
||||||
|
return BT_GATT_ITER_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BT_GATT_ITER_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void discover_and_subscribe_snk_pacs(void)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
printk("%s\n", __func__);
|
||||||
|
|
||||||
|
memcpy(&uuid, BT_UUID_PACS_SNK, sizeof(uuid));
|
||||||
|
pacs_instance.discover_params.uuid = &uuid.uuid;
|
||||||
|
pacs_instance.discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
|
||||||
|
pacs_instance.discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
|
||||||
|
pacs_instance.discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
|
||||||
|
pacs_instance.discover_params.func = discover_pacs_snk;
|
||||||
|
|
||||||
|
err = bt_gatt_discover(default_conn, &pacs_instance.discover_params);
|
||||||
|
if (err != 0) {
|
||||||
|
FAIL("Service Discovery failed (err %d)\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_main(void)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
printk("Enabling Bluetooth\n");
|
||||||
|
err = bt_enable(NULL);
|
||||||
|
if (err != 0) {
|
||||||
|
FAIL("Bluetooth enable failed (err %d)\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printk("Starting scan\n");
|
||||||
|
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
|
||||||
|
if (err != 0) {
|
||||||
|
FAIL("Could not start scanning (err %d)\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WAIT_FOR_FLAG(flag_connected);
|
||||||
|
|
||||||
|
printk("Raising security\n");
|
||||||
|
err = bt_conn_set_security(default_conn, BT_SECURITY_L2);
|
||||||
|
if (err) {
|
||||||
|
FAIL("Failed to ser security level %d (err %d)\n", BT_SECURITY_L2, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printk("Starting Discovery\n");
|
||||||
|
|
||||||
|
discover_and_subscribe_snk_pacs();
|
||||||
|
WAIT_FOR_FLAG(flag_pacs_snk_discovered);
|
||||||
|
|
||||||
|
discover_and_subscribe_snk_loc();
|
||||||
|
WAIT_FOR_FLAG(flag_snk_loc_discovered);
|
||||||
|
|
||||||
|
discover_and_subscribe_src_pacs();
|
||||||
|
WAIT_FOR_FLAG(flag_pacs_src_discovered);
|
||||||
|
|
||||||
|
discover_and_subscribe_src_loc();
|
||||||
|
WAIT_FOR_FLAG(flag_src_loc_discovered);
|
||||||
|
|
||||||
|
discover_and_subscribe_available_contexts();
|
||||||
|
WAIT_FOR_FLAG(flag_available_contexts_discovered);
|
||||||
|
|
||||||
|
discover_and_subscribe_supported_contexts();
|
||||||
|
WAIT_FOR_FLAG(flag_supported_contexts_discovered);
|
||||||
|
|
||||||
|
printk("Waiting for all notifications to be received\n");
|
||||||
|
|
||||||
|
WAIT_FOR_FLAG(flag_all_notifications_received);
|
||||||
|
|
||||||
|
/* Disconnect and wait for server to advertise again (after notifications are triggered) */
|
||||||
|
UNSET_FLAG(flag_all_notifications_received);
|
||||||
|
bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
|
||||||
|
WAIT_FOR_UNSET_FLAG(flag_connected);
|
||||||
|
|
||||||
|
printk("Starting scan\n");
|
||||||
|
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
|
||||||
|
if (err != 0) {
|
||||||
|
FAIL("Could not start scanning (err %d)\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WAIT_FOR_FLAG(flag_connected);
|
||||||
|
|
||||||
|
printk("Raising security\n");
|
||||||
|
err = bt_conn_set_security(default_conn, BT_SECURITY_L2);
|
||||||
|
if (err) {
|
||||||
|
FAIL("Failed to ser security level %d (err %d)\n", BT_SECURITY_L2, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printk("Waiting for all notifications to be received\n");
|
||||||
|
WAIT_FOR_FLAG(flag_all_notifications_received);
|
||||||
|
|
||||||
|
bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
|
||||||
|
WAIT_FOR_UNSET_FLAG(flag_connected);
|
||||||
|
|
||||||
|
PASS("GATT client Passed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct bst_test_instance test_pacs_notify_client[] = {
|
||||||
|
{
|
||||||
|
.test_id = "pacs_notify_client",
|
||||||
|
.test_post_init_f = test_init,
|
||||||
|
.test_tick_f = test_tick,
|
||||||
|
.test_main_f = test_main,
|
||||||
|
},
|
||||||
|
BSTEST_END_MARKER,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bst_test_list *test_pacs_notify_client_install(struct bst_test_list *tests)
|
||||||
|
{
|
||||||
|
return bst_add_tests(tests, test_pacs_notify_client);
|
||||||
|
}
|
233
tests/bsim/bluetooth/audio/src/pacs_notify_server_test.c
Normal file
233
tests/bsim/bluetooth/audio/src/pacs_notify_server_test.c
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Demant A/S
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/bluetooth/audio/pacs.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
extern enum bst_result_t bst_result;
|
||||||
|
|
||||||
|
static struct bt_audio_codec_cap lc3_codec_1 =
|
||||||
|
BT_AUDIO_CODEC_CAP_LC3(BT_AUDIO_CODEC_LC3_FREQ_16KHZ | BT_AUDIO_CODEC_LC3_FREQ_24KHZ,
|
||||||
|
BT_AUDIO_CODEC_LC3_DURATION_10,
|
||||||
|
BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1), 40u, 60u, 1u,
|
||||||
|
BT_AUDIO_CONTEXT_TYPE_ANY);
|
||||||
|
static struct bt_audio_codec_cap lc3_codec_2 =
|
||||||
|
BT_AUDIO_CODEC_CAP_LC3(BT_AUDIO_CODEC_LC3_FREQ_16KHZ,
|
||||||
|
BT_AUDIO_CODEC_LC3_DURATION_10,
|
||||||
|
BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1), 40u, 60u, 1u,
|
||||||
|
BT_AUDIO_CONTEXT_TYPE_ANY);
|
||||||
|
static struct bt_pacs_cap caps_1 = {
|
||||||
|
.codec_cap = &lc3_codec_1,
|
||||||
|
};
|
||||||
|
static struct bt_pacs_cap caps_2 = {
|
||||||
|
.codec_cap = &lc3_codec_2,
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool is_peer_subscribed(struct bt_conn *conn)
|
||||||
|
{
|
||||||
|
struct bt_gatt_attr *attr;
|
||||||
|
uint8_t nbr_subscribed = 0;
|
||||||
|
|
||||||
|
attr = bt_gatt_find_by_uuid(NULL, 0, BT_UUID_PACS_SNK);
|
||||||
|
if (!attr) {
|
||||||
|
printk("No BT_UUID_PACS_SNK attribute found\n");
|
||||||
|
}
|
||||||
|
if (bt_gatt_is_subscribed(conn, attr, BT_GATT_CCC_NOTIFY)) {
|
||||||
|
nbr_subscribed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
attr = bt_gatt_find_by_uuid(NULL, 0, BT_UUID_PACS_SNK_LOC);
|
||||||
|
if (!attr) {
|
||||||
|
printk("No BT_UUID_PACS_SNK_LOC attribute found\n");
|
||||||
|
}
|
||||||
|
if (bt_gatt_is_subscribed(conn, attr, BT_GATT_CCC_NOTIFY)) {
|
||||||
|
nbr_subscribed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
attr = bt_gatt_find_by_uuid(NULL, 0, BT_UUID_PACS_SRC);
|
||||||
|
if (!attr) {
|
||||||
|
printk("No BT_UUID_PACS_SRC attribute found\n");
|
||||||
|
}
|
||||||
|
if (bt_gatt_is_subscribed(conn, attr, BT_GATT_CCC_NOTIFY)) {
|
||||||
|
nbr_subscribed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
attr = bt_gatt_find_by_uuid(NULL, 0, BT_UUID_PACS_SRC_LOC);
|
||||||
|
if (!attr) {
|
||||||
|
printk("No BT_UUID_PACS_SRC_LOC attribute found\n");
|
||||||
|
}
|
||||||
|
if (bt_gatt_is_subscribed(conn, attr, BT_GATT_CCC_NOTIFY)) {
|
||||||
|
nbr_subscribed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
attr = bt_gatt_find_by_uuid(NULL, 0, BT_UUID_PACS_AVAILABLE_CONTEXT);
|
||||||
|
if (!attr) {
|
||||||
|
printk("No BT_UUID_PACS_AVAILABLE_CONTEXT attribute found\n");
|
||||||
|
}
|
||||||
|
if (bt_gatt_is_subscribed(conn, attr, BT_GATT_CCC_NOTIFY)) {
|
||||||
|
nbr_subscribed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
attr = bt_gatt_find_by_uuid(NULL, 0, BT_UUID_PACS_SUPPORTED_CONTEXT);
|
||||||
|
if (!attr) {
|
||||||
|
printk("No BT_UUID_PACS_SUPPORTED_CONTEXT attribute found\n");
|
||||||
|
}
|
||||||
|
if (bt_gatt_is_subscribed(conn, attr, BT_GATT_CCC_NOTIFY)) {
|
||||||
|
nbr_subscribed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nbr_subscribed != 6) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void trigger_notifications(void)
|
||||||
|
{
|
||||||
|
static enum bt_audio_context available = BT_AUDIO_CONTEXT_TYPE_ANY;
|
||||||
|
static enum bt_audio_context supported = BT_AUDIO_CONTEXT_TYPE_ANY;
|
||||||
|
static int i;
|
||||||
|
int err;
|
||||||
|
struct bt_pacs_cap *caps;
|
||||||
|
enum bt_audio_location snk_loc;
|
||||||
|
enum bt_audio_location src_loc;
|
||||||
|
|
||||||
|
printk("Triggering Notifications\n");
|
||||||
|
|
||||||
|
if (i) {
|
||||||
|
caps = &caps_1;
|
||||||
|
snk_loc = BT_AUDIO_LOCATION_FRONT_LEFT;
|
||||||
|
src_loc = BT_AUDIO_LOCATION_FRONT_RIGHT;
|
||||||
|
i = 0;
|
||||||
|
} else {
|
||||||
|
caps = &caps_2;
|
||||||
|
snk_loc = BT_AUDIO_LOCATION_FRONT_RIGHT;
|
||||||
|
src_loc = BT_AUDIO_LOCATION_FRONT_LEFT;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
printk("Changing Sink PACs\n");
|
||||||
|
bt_pacs_cap_register(BT_AUDIO_DIR_SINK, caps);
|
||||||
|
bt_pacs_cap_register(BT_AUDIO_DIR_SOURCE, caps);
|
||||||
|
|
||||||
|
printk("Changing Sink Location\n");
|
||||||
|
err = bt_pacs_set_location(BT_AUDIO_DIR_SINK, snk_loc);
|
||||||
|
if (err != 0) {
|
||||||
|
printk("Failed to set device sink location\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
printk("Changing Source Location\n");
|
||||||
|
err = bt_pacs_set_location(BT_AUDIO_DIR_SOURCE, src_loc);
|
||||||
|
if (err != 0) {
|
||||||
|
printk("Failed to set device source location\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
printk("Changing Supported Contexts Location\n");
|
||||||
|
supported = supported ^ BT_AUDIO_CONTEXT_TYPE_MEDIA;
|
||||||
|
bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SINK, supported);
|
||||||
|
|
||||||
|
printk("Changing Available Contexts\n");
|
||||||
|
available = available ^ BT_AUDIO_CONTEXT_TYPE_MEDIA;
|
||||||
|
bt_pacs_set_available_contexts(BT_AUDIO_DIR_SINK, available);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_main(void)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
const struct bt_data ad[] = {
|
||||||
|
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
|
||||||
|
};
|
||||||
|
|
||||||
|
printk("Enabling Bluetooth\n");
|
||||||
|
err = bt_enable(NULL);
|
||||||
|
if (err != 0) {
|
||||||
|
FAIL("Bluetooth enable failed (err %d)\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SINK, BT_AUDIO_CONTEXT_TYPE_ANY);
|
||||||
|
bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SOURCE, BT_AUDIO_CONTEXT_TYPE_ANY);
|
||||||
|
bt_pacs_set_available_contexts(BT_AUDIO_DIR_SINK, BT_AUDIO_CONTEXT_TYPE_ANY);
|
||||||
|
bt_pacs_set_available_contexts(BT_AUDIO_DIR_SOURCE, BT_AUDIO_CONTEXT_TYPE_ANY);
|
||||||
|
|
||||||
|
printk("Registereding PACS\n");
|
||||||
|
bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &caps_1);
|
||||||
|
bt_pacs_cap_register(BT_AUDIO_DIR_SOURCE, &caps_1);
|
||||||
|
|
||||||
|
err = bt_pacs_set_location(BT_AUDIO_DIR_SINK, BT_AUDIO_LOCATION_FRONT_LEFT);
|
||||||
|
if (err != 0) {
|
||||||
|
printk("Failed to set device sink location\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bt_pacs_set_location(BT_AUDIO_DIR_SOURCE, BT_AUDIO_LOCATION_FRONT_RIGHT);
|
||||||
|
if (err != 0) {
|
||||||
|
printk("Failed to set device source location\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printk("Start Advertising\n");
|
||||||
|
err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0);
|
||||||
|
if (err != 0) {
|
||||||
|
FAIL("Advertising failed to start (err %d)\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printk("Waiting to be connected\n");
|
||||||
|
WAIT_FOR_FLAG(flag_connected);
|
||||||
|
printk("Connected\n");
|
||||||
|
printk("Waiting to be subscribed\n");
|
||||||
|
|
||||||
|
while (!is_peer_subscribed(default_conn)) {
|
||||||
|
(void)k_sleep(K_MSEC(10));
|
||||||
|
}
|
||||||
|
printk("Subscribed\n");
|
||||||
|
|
||||||
|
trigger_notifications();
|
||||||
|
|
||||||
|
/* Now wait for client to disconnect, then stop adv so it does not reconnect */
|
||||||
|
printk("Wait for client disconnect\n");
|
||||||
|
WAIT_FOR_UNSET_FLAG(flag_connected);
|
||||||
|
printk("Client disconnected\n");
|
||||||
|
|
||||||
|
err = bt_le_adv_stop();
|
||||||
|
if (err != 0) {
|
||||||
|
FAIL("Advertising failed to stop (err %d)\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Trigger changes while device is disconnected */
|
||||||
|
trigger_notifications();
|
||||||
|
|
||||||
|
printk("Start Advertising\n");
|
||||||
|
err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0);
|
||||||
|
if (err != 0) {
|
||||||
|
FAIL("Advertising failed to start (err %d)\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WAIT_FOR_FLAG(flag_connected);
|
||||||
|
WAIT_FOR_UNSET_FLAG(flag_connected);
|
||||||
|
|
||||||
|
PASS("PACS Notify Server passed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct bst_test_instance test_pacs_notify_server[] = {
|
||||||
|
{
|
||||||
|
.test_id = "pacs_notify_server",
|
||||||
|
.test_post_init_f = test_init,
|
||||||
|
.test_tick_f = test_tick,
|
||||||
|
.test_main_f = test_main,
|
||||||
|
},
|
||||||
|
BSTEST_END_MARKER,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bst_test_list *test_pacs_notify_server_install(struct bst_test_list *tests)
|
||||||
|
{
|
||||||
|
return bst_add_tests(tests, test_pacs_notify_server);
|
||||||
|
}
|
26
tests/bsim/bluetooth/audio/test_scripts/pacs_notify.sh
Executable file
26
tests/bsim/bluetooth/audio/test_scripts/pacs_notify.sh
Executable file
|
@ -0,0 +1,26 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Copyright (c) 2023 Demant A/S
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
source ${ZEPHYR_BASE}/tests/bsim/sh_common.source
|
||||||
|
|
||||||
|
SIMULATION_ID="pacs_notify"
|
||||||
|
VERBOSITY_LEVEL=2
|
||||||
|
EXECUTE_TIMEOUT=200
|
||||||
|
|
||||||
|
cd ${BSIM_OUT_PATH}/bin
|
||||||
|
|
||||||
|
printf "\n\n======== Running PACS Notify test =========\n\n"
|
||||||
|
|
||||||
|
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||||
|
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=pacs_notify_server -rs=24
|
||||||
|
|
||||||
|
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||||
|
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=pacs_notify_client -rs=46
|
||||||
|
|
||||||
|
Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \
|
||||||
|
-D=2 -sim_length=60e6 $@
|
||||||
|
|
||||||
|
wait_for_background_jobs
|
Loading…
Add table
Add a link
Reference in a new issue