blob: 7068da7f06a974119994f6bc8bc3abf48b879f2e [file] [log] [blame]
/*
* 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"
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(pacs_notify_client_test, LOG_LEVEL_DBG);
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);
CREATE_FLAG(flag_available_contexts_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)
{
LOG_DBG("%p", params);
if (params == &pacs_instance.sink_pacs_sub) {
LOG_DBG("Received sink_pacs_sub notification");
pacs_instance.notify_received_mask |= BIT(0);
} else if (params == &pacs_instance.source_pacs_sub) {
LOG_DBG("Received source_pacs_sub notification");
pacs_instance.notify_received_mask |= BIT(1);
} else if (params == &pacs_instance.sink_loc_sub) {
LOG_DBG("Received sink_loc_sub notification");
pacs_instance.notify_received_mask |= BIT(2);
} else if (params == &pacs_instance.source_loc_sub) {
LOG_DBG("Received source_loc_sub notification");
pacs_instance.notify_received_mask |= BIT(3);
} else if (params == &pacs_instance.available_contexts_sub) {
LOG_DBG("Received available_contexts_sub notification");
pacs_instance.notify_received_mask |= BIT(4);
SET_FLAG(flag_available_contexts_received);
} else if (params == &pacs_instance.supported_contexts_sub) {
LOG_DBG("Received supported_contexts_sub notification");
pacs_instance.notify_received_mask |= BIT(5);
}
LOG_DBG("pacs_instance.notify_received_mask is %d", 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) {
LOG_DBG("Discover complete");
(void)memset(params, 0, sizeof(*params));
return BT_GATT_ITER_STOP;
}
if (!bt_uuid_cmp(params->uuid, BT_UUID_PACS_SUPPORTED_CONTEXT)) {
LOG_DBG("PACS Supported Contexts Characteristic handle at %d", 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) {
LOG_DBG("Discover failed (err %d)", err);
}
} else if (!bt_uuid_cmp(params->uuid, BT_UUID_GATT_CCC)) {
LOG_DBG("CCC handle at %d", 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) {
LOG_DBG("Subscribe failed (err %d)", err);
} else {
SET_FLAG(flag_supported_contexts_discovered);
LOG_DBG("[SUBSCRIBED]");
}
} else {
LOG_DBG("Unknown handle at %d", attr->handle);
return BT_GATT_ITER_CONTINUE;
}
return BT_GATT_ITER_STOP;
}
static void discover_and_subscribe_supported_contexts(void)
{
int err = 0;
LOG_DBG("");
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)", 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) {
LOG_DBG("Discover complete");
(void)memset(params, 0, sizeof(*params));
return BT_GATT_ITER_STOP;
}
if (!bt_uuid_cmp(params->uuid, BT_UUID_PACS_AVAILABLE_CONTEXT)) {
LOG_DBG("PACS Available Contexts Characteristic handle at %d", 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) {
LOG_DBG("Discover failed (err %d)", err);
}
} else if (!bt_uuid_cmp(params->uuid, BT_UUID_GATT_CCC)) {
LOG_DBG("CCC handle at %d", 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) {
LOG_DBG("Subscribe failed (err %d)", err);
} else {
SET_FLAG(flag_available_contexts_discovered);
LOG_DBG("[SUBSCRIBED]");
}
} else {
LOG_DBG("Unknown handle at %d", attr->handle);
return BT_GATT_ITER_CONTINUE;
}
return BT_GATT_ITER_STOP;
}
static void discover_and_subscribe_available_contexts(void)
{
int err = 0;
LOG_DBG("");
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)", 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) {
LOG_DBG("Discover complete");
(void)memset(params, 0, sizeof(*params));
return BT_GATT_ITER_STOP;
}
if (!bt_uuid_cmp(params->uuid, BT_UUID_PACS_SRC_LOC)) {
LOG_DBG("PACS Source Location Characteristic handle at %d", 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) {
LOG_DBG("Discover failed (err %d)", err);
}
} else if (!bt_uuid_cmp(params->uuid, BT_UUID_GATT_CCC)) {
LOG_DBG("CCC handle at %d", 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) {
LOG_DBG("Subscribe failed (err %d)", err);
} else {
SET_FLAG(flag_src_loc_discovered);
LOG_DBG("[SUBSCRIBED]");
}
} else {
LOG_DBG("Unknown handle at %d", attr->handle);
return BT_GATT_ITER_CONTINUE;
}
return BT_GATT_ITER_STOP;
}
static void discover_and_subscribe_src_loc(void)
{
int err = 0;
LOG_DBG("");
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)", 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) {
LOG_DBG("Discover complete");
(void)memset(params, 0, sizeof(*params));
return BT_GATT_ITER_STOP;
}
if (!bt_uuid_cmp(params->uuid, BT_UUID_PACS_SNK_LOC)) {
LOG_DBG("PACS Sink Location Characteristic handle at %d", 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) {
LOG_DBG("Discover failed (err %d)", err);
}
} else if (!bt_uuid_cmp(params->uuid, BT_UUID_GATT_CCC)) {
LOG_DBG("CCC handle at %d", 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) {
LOG_DBG("Subscribe failed (err %d)", err);
} else {
SET_FLAG(flag_snk_loc_discovered);
LOG_DBG("[SUBSCRIBED]");
}
} else {
LOG_DBG("Unknown handle at %d", attr->handle);
return BT_GATT_ITER_CONTINUE;
}
return BT_GATT_ITER_STOP;
}
static void discover_and_subscribe_snk_loc(void)
{
int err = 0;
LOG_DBG("");
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)", 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) {
LOG_DBG("Discover complete");
(void)memset(params, 0, sizeof(*params));
return BT_GATT_ITER_STOP;
}
if (!bt_uuid_cmp(params->uuid, BT_UUID_PACS_SRC)) {
LOG_DBG("PACS Source Characteristic handle at %d", 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) {
LOG_DBG("Discover failed (err %d)", err);
}
} else if (!bt_uuid_cmp(params->uuid, BT_UUID_GATT_CCC)) {
LOG_DBG("CCC handle at %d", 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) {
LOG_DBG("Subscribe failed (err %d)", err);
} else {
SET_FLAG(flag_pacs_src_discovered);
LOG_DBG("[SUBSCRIBED]");
}
} else {
LOG_DBG("Unknown handle at %d", attr->handle);
return BT_GATT_ITER_CONTINUE;
}
return BT_GATT_ITER_STOP;
}
static void discover_and_subscribe_src_pacs(void)
{
int err = 0;
LOG_DBG("");
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)", 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) {
LOG_DBG("Discover complete");
(void)memset(params, 0, sizeof(*params));
return BT_GATT_ITER_STOP;
}
if (!bt_uuid_cmp(params->uuid, BT_UUID_PACS_SNK)) {
LOG_DBG("PACS Sink Characteristic handle at %d", 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) {
LOG_DBG("Discover failed (err %d)", err);
}
} else if (!bt_uuid_cmp(params->uuid, BT_UUID_GATT_CCC)) {
LOG_DBG("CCC handle at %d", 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) {
LOG_DBG("Subscribe failed (err %d)", err);
} else {
SET_FLAG(flag_pacs_snk_discovered);
LOG_DBG("[SUBSCRIBED]");
}
} else {
LOG_DBG("Unknown handle at %d", attr->handle);
return BT_GATT_ITER_CONTINUE;
}
return BT_GATT_ITER_STOP;
}
static void discover_and_subscribe_snk_pacs(void)
{
int err = 0;
LOG_DBG("");
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)", err);
return;
}
}
static void test_main(void)
{
int err;
LOG_DBG("Enabling Bluetooth");
err = bt_enable(NULL);
if (err != 0) {
FAIL("Bluetooth enable failed (err %d)", err);
return;
}
bt_le_scan_cb_register(&common_scan_cb);
LOG_DBG("Starting scan");
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL);
if (err != 0) {
FAIL("Could not start scanning (err %d)", err);
return;
}
WAIT_FOR_FLAG(flag_connected);
LOG_DBG("Raising security");
err = bt_conn_set_security(default_conn, BT_SECURITY_L2);
if (err) {
FAIL("Failed to ser security level %d (err %d)", BT_SECURITY_L2, err);
return;
}
LOG_DBG("Starting Discovery");
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);
LOG_DBG("Waiting for all notifications to be received");
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);
err = bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
__ASSERT_NO_MSG(err == 0);
WAIT_FOR_UNSET_FLAG(flag_connected);
LOG_DBG("Starting scan");
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL);
if (err != 0) {
FAIL("Could not start scanning (err %d)", err);
return;
}
WAIT_FOR_FLAG(flag_connected);
LOG_DBG("Raising security");
err = bt_conn_set_security(default_conn, BT_SECURITY_L2);
if (err) {
FAIL("Failed to ser security level %d (err %d)", BT_SECURITY_L2, err);
return;
}
LOG_DBG("Waiting for all notifications to be received");
WAIT_FOR_FLAG(flag_all_notifications_received);
err = bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
__ASSERT_NO_MSG(err == 0);
WAIT_FOR_UNSET_FLAG(flag_connected);
UNSET_FLAG(flag_available_contexts_received);
LOG_DBG("Starting scan");
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL);
if (err != 0) {
FAIL("Could not start scanning (err %d)", err);
return;
}
WAIT_FOR_FLAG(flag_connected);
LOG_DBG("Raising security");
err = bt_conn_set_security(default_conn, BT_SECURITY_L2);
if (err) {
FAIL("Failed to ser security level %d (err %d)", BT_SECURITY_L2, err);
return;
}
LOG_DBG("Waiting for available contexts notification to be received");
WAIT_FOR_FLAG(flag_available_contexts_received);
err = bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
__ASSERT_NO_MSG(err == 0);
WAIT_FOR_UNSET_FLAG(flag_connected);
UNSET_FLAG(flag_available_contexts_received);
LOG_DBG("Starting scan");
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL);
if (err != 0) {
FAIL("Could not start scanning (err %d)", err);
return;
}
WAIT_FOR_FLAG(flag_connected);
LOG_DBG("Raising security");
err = bt_conn_set_security(default_conn, BT_SECURITY_L2);
if (err) {
FAIL("Failed to ser security level %d (err %d)", BT_SECURITY_L2, err);
return;
}
LOG_DBG("Waiting for available contexts notification to be received");
WAIT_FOR_FLAG(flag_available_contexts_received);
err = bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
__ASSERT_NO_MSG(err == 0);
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);
}