| /* |
| * Copyright (c) 2022 Codecoup |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/bluetooth/audio/has.h> |
| |
| #include "../../subsys/bluetooth/audio/has_internal.h" |
| |
| #include "common.h" |
| |
| #include <zephyr/logging/log.h> |
| LOG_MODULE_REGISTER(has_client_test, LOG_LEVEL_DBG); |
| |
| extern enum bst_result_t bst_result; |
| |
| extern const char *test_preset_name_1; |
| extern const char *test_preset_name_5; |
| extern const uint8_t test_preset_index_1; |
| extern const uint8_t test_preset_index_3; |
| extern const uint8_t test_preset_index_5; |
| extern const enum bt_has_properties test_preset_properties; |
| |
| CREATE_FLAG(g_service_discovered); |
| CREATE_FLAG(g_preset_switched); |
| CREATE_FLAG(g_preset_1_found); |
| CREATE_FLAG(g_preset_3_found); |
| CREATE_FLAG(g_preset_5_found); |
| |
| static struct bt_has *g_has; |
| static uint8_t g_active_index; |
| |
| static void discover_cb(struct bt_conn *conn, int err, struct bt_has *has, |
| enum bt_has_hearing_aid_type type, enum bt_has_capabilities caps) |
| { |
| if (err) { |
| FAIL("Failed to discover HAS (err %d)\n", err); |
| return; |
| } |
| |
| LOG_DBG("HAS discovered type %d caps %d", type, caps); |
| |
| g_has = has; |
| SET_FLAG(g_service_discovered); |
| } |
| |
| static void preset_switch_cb(struct bt_has *has, int err, uint8_t index) |
| { |
| if (err != 0) { |
| return; |
| } |
| |
| LOG_DBG("Active preset index %d", index); |
| |
| SET_FLAG(g_preset_switched); |
| g_active_index = index; |
| } |
| |
| static void check_preset_record(const struct bt_has_preset_record *record, |
| enum bt_has_properties expected_properties, |
| const char *expected_name) |
| { |
| if (record->properties != expected_properties || strcmp(record->name, expected_name)) { |
| FAIL("mismatch 0x%02x %s vs 0x%02x %s expected\n", |
| record->properties, record->name, expected_properties, expected_name); |
| } |
| } |
| |
| static void preset_read_rsp_cb(struct bt_has *has, int err, |
| const struct bt_has_preset_record *record, bool is_last) |
| { |
| if (err) { |
| FAIL("%s: err %d\n", __func__, err); |
| return; |
| } |
| |
| if (record->index == test_preset_index_1) { |
| SET_FLAG(g_preset_1_found); |
| |
| check_preset_record(record, test_preset_properties, test_preset_name_1); |
| } else if (record->index == test_preset_index_5) { |
| SET_FLAG(g_preset_5_found); |
| |
| check_preset_record(record, test_preset_properties, test_preset_name_5); |
| } else { |
| FAIL("unexpected index 0x%02x", record->index); |
| } |
| } |
| |
| static void preset_update_cb(struct bt_has *has, uint8_t index_prev, |
| const struct bt_has_preset_record *record, bool is_last) |
| { |
| if (record->index == test_preset_index_1) { |
| SET_FLAG(g_preset_1_found); |
| } else if (record->index == test_preset_index_3) { |
| SET_FLAG(g_preset_3_found); |
| } else if (record->index == test_preset_index_5) { |
| SET_FLAG(g_preset_5_found); |
| } |
| } |
| |
| static const struct bt_has_client_cb has_cb = { |
| .discover = discover_cb, |
| .preset_switch = preset_switch_cb, |
| .preset_read_rsp = preset_read_rsp_cb, |
| .preset_update = preset_update_cb, |
| }; |
| |
| static bool test_preset_switch(uint8_t index) |
| { |
| int err; |
| |
| UNSET_FLAG(g_preset_switched); |
| |
| err = bt_has_client_preset_set(g_has, index, false); |
| if (err < 0) { |
| LOG_DBG("%s (err %d)", __func__, err); |
| return false; |
| } |
| |
| WAIT_FOR_COND(g_preset_switched); |
| |
| return g_active_index == index; |
| } |
| |
| static bool test_preset_next(uint8_t active_index_expected) |
| { |
| int err; |
| |
| UNSET_FLAG(g_preset_switched); |
| |
| err = bt_has_client_preset_next(g_has, false); |
| if (err < 0) { |
| LOG_DBG("%s (err %d)", __func__, err); |
| return false; |
| } |
| |
| WAIT_FOR_COND(g_preset_switched); |
| |
| return g_active_index == active_index_expected; |
| } |
| |
| static bool test_preset_prev(uint8_t active_index_expected) |
| { |
| int err; |
| |
| UNSET_FLAG(g_preset_switched); |
| |
| err = bt_has_client_preset_prev(g_has, false); |
| if (err < 0) { |
| LOG_DBG("%s (err %d)", __func__, err); |
| return false; |
| } |
| |
| WAIT_FOR_COND(g_preset_switched); |
| |
| return g_active_index == active_index_expected; |
| } |
| |
| static void discover_has(void) |
| { |
| int err; |
| |
| g_service_discovered = false; |
| |
| err = bt_has_client_discover(default_conn); |
| if (err < 0) { |
| FAIL("Failed to discover HAS (err %d)\n", err); |
| return; |
| } |
| |
| WAIT_FOR_COND(g_service_discovered); |
| } |
| |
| static void test_main(void) |
| { |
| int err; |
| |
| err = bt_enable(NULL); |
| if (err < 0) { |
| FAIL("Bluetooth discover failed (err %d)\n", err); |
| return; |
| } |
| |
| LOG_DBG("Bluetooth initialized"); |
| |
| err = bt_has_client_cb_register(&has_cb); |
| if (err < 0) { |
| FAIL("Failed to register callbacks (err %d)\n", err); |
| return; |
| } |
| |
| bt_le_scan_cb_register(&common_scan_cb); |
| |
| err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL); |
| if (err < 0) { |
| FAIL("Scanning failed to start (err %d)\n", err); |
| return; |
| } |
| |
| LOG_DBG("Scanning successfully started"); |
| |
| WAIT_FOR_FLAG(flag_connected); |
| |
| discover_has(); |
| WAIT_FOR_COND(g_preset_switched); |
| |
| err = bt_has_client_presets_read(g_has, BT_HAS_PRESET_INDEX_FIRST, 255); |
| if (err < 0) { |
| FAIL("Failed to read presets (err %d)\n", err); |
| return; |
| } |
| |
| WAIT_FOR_COND(g_preset_1_found); |
| WAIT_FOR_COND(g_preset_5_found); |
| |
| if (!test_preset_switch(test_preset_index_1)) { |
| FAIL("Failed to switch preset %d\n", test_preset_index_1); |
| return; |
| } |
| |
| if (!test_preset_switch(test_preset_index_5)) { |
| FAIL("Failed to switch preset %d\n", test_preset_index_5); |
| return; |
| } |
| |
| if (!test_preset_next(test_preset_index_1)) { |
| FAIL("Failed to set next preset %d\n", test_preset_index_1); |
| return; |
| } |
| |
| if (!test_preset_next(test_preset_index_5)) { |
| FAIL("Failed to set next preset %d\n", test_preset_index_5); |
| return; |
| } |
| |
| if (!test_preset_next(test_preset_index_1)) { |
| FAIL("Failed to set next preset %d\n", test_preset_index_1); |
| return; |
| } |
| |
| if (!test_preset_prev(test_preset_index_5)) { |
| FAIL("Failed to set previous preset %d\n", test_preset_index_5); |
| return; |
| } |
| |
| if (!test_preset_prev(test_preset_index_1)) { |
| FAIL("Failed to set previous preset %d\n", test_preset_index_1); |
| return; |
| } |
| |
| if (!test_preset_prev(test_preset_index_5)) { |
| FAIL("Failed to set previous preset %d\n", test_preset_index_5); |
| return; |
| } |
| |
| PASS("HAS main PASS\n"); |
| } |
| |
| #define FEATURES_SUB_NTF BIT(0) |
| #define ACTIVE_INDEX_SUB_NTF BIT(1) |
| #define PRESET_CHANGED_SUB_NTF BIT(2) |
| #define SUB_NTF_ALL (FEATURES_SUB_NTF | ACTIVE_INDEX_SUB_NTF | PRESET_CHANGED_SUB_NTF) |
| |
| CREATE_FLAG(flag_features_discovered); |
| CREATE_FLAG(flag_active_preset_index_discovered); |
| CREATE_FLAG(flag_control_point_discovered); |
| CREATE_FLAG(flag_all_notifications_received); |
| |
| enum preset_state { |
| STATE_UNKNOWN, |
| STATE_AVAILABLE, |
| STATE_UNAVAILABLE, |
| STATE_DELETED, |
| }; |
| |
| static enum preset_state preset_state_1; |
| static enum preset_state preset_state_3; |
| static enum preset_state preset_state_5; |
| |
| static struct bt_uuid_16 uuid = BT_UUID_INIT_16(0); |
| static struct bt_gatt_discover_params discover_params; |
| static struct bt_gatt_subscribe_params features_sub; |
| static struct bt_gatt_subscribe_params active_preset_index_sub; |
| static struct bt_gatt_subscribe_params control_point_sub; |
| static uint8_t notify_received_mask; |
| |
| static void preset_availability_changed(uint8_t index, bool available) |
| { |
| enum preset_state state = available ? STATE_AVAILABLE : STATE_UNAVAILABLE; |
| |
| if (index == test_preset_index_1) { |
| preset_state_1 = state; |
| } else if (index == test_preset_index_3) { |
| preset_state_3 = state; |
| } else if (index == test_preset_index_5) { |
| preset_state_5 = state; |
| } else { |
| FAIL("invalid preset index 0x%02x", index); |
| } |
| } |
| |
| static uint8_t notify_handler(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, |
| const void *data, uint16_t length) |
| { |
| LOG_DBG("conn %p params %p data %p length %u", (void *)conn, params, data, length); |
| |
| if (params == &features_sub) { |
| if (data == NULL) { |
| LOG_DBG("features_sub [UNSUBSCRIBED]"); |
| return BT_GATT_ITER_STOP; |
| } |
| |
| LOG_DBG("Received features_sub notification"); |
| notify_received_mask |= FEATURES_SUB_NTF; |
| } else if (params == &active_preset_index_sub) { |
| if (data == NULL) { |
| LOG_DBG("active_preset_index_sub_sub [UNSUBSCRIBED]"); |
| return BT_GATT_ITER_STOP; |
| } |
| |
| LOG_DBG("Received active_preset_index_sub_sub notification"); |
| notify_received_mask |= ACTIVE_INDEX_SUB_NTF; |
| } else if (params == &control_point_sub) { |
| const struct bt_has_cp_hdr *hdr; |
| |
| if (data == NULL) { |
| LOG_DBG("control_point_sub [UNSUBSCRIBED]"); |
| return BT_GATT_ITER_STOP; |
| } |
| |
| if (length < sizeof(*hdr)) { |
| FAIL("malformed bt_has_cp_hdr"); |
| return BT_GATT_ITER_STOP; |
| } |
| |
| hdr = data; |
| |
| if (hdr->opcode == BT_HAS_OP_PRESET_CHANGED) { |
| const struct bt_has_cp_preset_changed *pc; |
| |
| if (length < (sizeof(*hdr) + sizeof(*pc))) { |
| FAIL("malformed bt_has_cp_preset_changed"); |
| return BT_GATT_ITER_STOP; |
| } |
| |
| pc = (const void *)hdr->data; |
| |
| switch (pc->change_id) { |
| case BT_HAS_CHANGE_ID_GENERIC_UPDATE: { |
| const struct bt_has_cp_generic_update *gu; |
| bool is_available; |
| |
| if (length < (sizeof(*hdr) + sizeof(*pc) + sizeof(*gu))) { |
| FAIL("malformed bt_has_cp_generic_update"); |
| return BT_GATT_ITER_STOP; |
| } |
| |
| gu = (const void *)pc->additional_params; |
| |
| LOG_DBG("Received generic update index 0x%02x props 0x%02x", |
| gu->index, gu->properties); |
| |
| is_available = (gu->properties & BT_HAS_PROP_AVAILABLE) != 0; |
| |
| preset_availability_changed(gu->index, is_available); |
| break; |
| } |
| default: |
| LOG_DBG("Unexpected Change ID 0x%02x", pc->change_id); |
| return BT_GATT_ITER_STOP; |
| } |
| |
| if (pc->is_last) { |
| notify_received_mask |= PRESET_CHANGED_SUB_NTF; |
| } |
| } else { |
| LOG_DBG("Unexpected opcode 0x%02x", hdr->opcode); |
| return BT_GATT_ITER_STOP; |
| } |
| } |
| |
| LOG_DBG("pacs_instance.notify_received_mask is %d", notify_received_mask); |
| |
| if (notify_received_mask == SUB_NTF_ALL) { |
| SET_FLAG(flag_all_notifications_received); |
| notify_received_mask = 0; |
| } |
| |
| return BT_GATT_ITER_CONTINUE; |
| } |
| |
| static void subscribe_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_subscribe_params *params) |
| { |
| if (err != BT_ATT_ERR_SUCCESS) { |
| return; |
| } |
| |
| LOG_DBG("[SUBSCRIBED]"); |
| |
| if (params == &features_sub) { |
| SET_FLAG(flag_features_discovered); |
| return; |
| } |
| |
| if (params == &control_point_sub) { |
| SET_FLAG(flag_control_point_discovered); |
| return; |
| } |
| |
| if (params == &active_preset_index_sub) { |
| SET_FLAG(flag_active_preset_index_discovered); |
| return; |
| } |
| } |
| |
| static uint8_t discover_features_cb(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_HAS_HEARING_AID_FEATURES)) { |
| LOG_DBG("HAS Hearing Aid Features handle at %d", attr->handle); |
| memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid)); |
| discover_params.uuid = &uuid.uuid; |
| discover_params.start_handle = attr->handle + 2; |
| discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR; |
| subscribe_params = &features_sub; |
| subscribe_params->value_handle = bt_gatt_attr_value_handle(attr); |
| |
| err = bt_gatt_discover(conn, &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 = &features_sub; |
| subscribe_params->notify = notify_handler; |
| subscribe_params->value = BT_GATT_CCC_NOTIFY; |
| subscribe_params->ccc_handle = attr->handle; |
| subscribe_params->subscribe = subscribe_cb; |
| |
| err = bt_gatt_subscribe(conn, subscribe_params); |
| if (err && err != -EALREADY) { |
| LOG_DBG("Subscribe failed (err %d)", err); |
| } |
| } else { |
| LOG_DBG("Unknown handle at %d", attr->handle); |
| return BT_GATT_ITER_CONTINUE; |
| } |
| |
| return BT_GATT_ITER_STOP; |
| } |
| |
| static void discover_and_subscribe_features(void) |
| { |
| int err = 0; |
| |
| LOG_DBG("%s", __func__); |
| |
| memcpy(&uuid, BT_UUID_HAS_HEARING_AID_FEATURES, sizeof(uuid)); |
| discover_params.uuid = &uuid.uuid; |
| discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; |
| discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; |
| discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; |
| discover_params.func = discover_features_cb; |
| |
| err = bt_gatt_discover(default_conn, &discover_params); |
| if (err != 0) { |
| FAIL("Service Discovery failed (err %d)\n", err); |
| return; |
| } |
| } |
| |
| static uint8_t discover_active_preset_index_cb(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_HAS_ACTIVE_PRESET_INDEX)) { |
| LOG_DBG("HAS Hearing Aid Features handle at %d", attr->handle); |
| memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid)); |
| discover_params.uuid = &uuid.uuid; |
| discover_params.start_handle = attr->handle + 2; |
| discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR; |
| subscribe_params = &active_preset_index_sub; |
| subscribe_params->value_handle = bt_gatt_attr_value_handle(attr); |
| |
| err = bt_gatt_discover(conn, &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 = &active_preset_index_sub; |
| subscribe_params->notify = notify_handler; |
| subscribe_params->value = BT_GATT_CCC_NOTIFY; |
| subscribe_params->ccc_handle = attr->handle; |
| subscribe_params->subscribe = subscribe_cb; |
| |
| err = bt_gatt_subscribe(conn, subscribe_params); |
| if (err && err != -EALREADY) { |
| LOG_DBG("Subscribe failed (err %d)", err); |
| } |
| } else { |
| LOG_DBG("Unknown handle at %d", attr->handle); |
| return BT_GATT_ITER_CONTINUE; |
| } |
| |
| return BT_GATT_ITER_STOP; |
| } |
| |
| static void discover_and_subscribe_active_preset_index(void) |
| { |
| int err = 0; |
| |
| LOG_DBG("%s", __func__); |
| |
| memcpy(&uuid, BT_UUID_HAS_ACTIVE_PRESET_INDEX, sizeof(uuid)); |
| discover_params.uuid = &uuid.uuid; |
| discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; |
| discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; |
| discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; |
| discover_params.func = discover_active_preset_index_cb; |
| |
| err = bt_gatt_discover(default_conn, &discover_params); |
| if (err != 0) { |
| FAIL("Service Discovery failed (err %d)\n", err); |
| return; |
| } |
| } |
| |
| static uint8_t discover_control_point_cb(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_HAS_PRESET_CONTROL_POINT)) { |
| LOG_DBG("HAS Control Point handle at %d", attr->handle); |
| memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid)); |
| discover_params.uuid = &uuid.uuid; |
| discover_params.start_handle = attr->handle + 2; |
| discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR; |
| subscribe_params = &control_point_sub; |
| subscribe_params->value_handle = bt_gatt_attr_value_handle(attr); |
| |
| err = bt_gatt_discover(conn, &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 = &control_point_sub; |
| subscribe_params->notify = notify_handler; |
| subscribe_params->value = BT_GATT_CCC_INDICATE; |
| subscribe_params->ccc_handle = attr->handle; |
| subscribe_params->subscribe = subscribe_cb; |
| |
| err = bt_gatt_subscribe(conn, subscribe_params); |
| if (err && err != -EALREADY) { |
| LOG_DBG("Subscribe failed (err %d)", err); |
| } |
| } else { |
| LOG_DBG("Unknown handle at %d", attr->handle); |
| return BT_GATT_ITER_CONTINUE; |
| } |
| |
| return BT_GATT_ITER_STOP; |
| } |
| |
| static void discover_and_subscribe_control_point(void) |
| { |
| int err = 0; |
| |
| LOG_DBG("%s", __func__); |
| |
| memcpy(&uuid, BT_UUID_HAS_PRESET_CONTROL_POINT, sizeof(uuid)); |
| discover_params.uuid = &uuid.uuid; |
| discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; |
| discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; |
| discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; |
| discover_params.func = discover_control_point_cb; |
| |
| err = bt_gatt_discover(default_conn, &discover_params); |
| if (err != 0) { |
| FAIL("Control Point failed (err %d)\n", err); |
| return; |
| } |
| } |
| |
| static void test_gatt_client(void) |
| { |
| int err; |
| |
| err = bt_enable(NULL); |
| if (err < 0) { |
| FAIL("Bluetooth discover failed (err %d)\n", err); |
| return; |
| } |
| |
| LOG_DBG("Bluetooth initialized"); |
| |
| bt_le_scan_cb_register(&common_scan_cb); |
| |
| err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL); |
| if (err < 0) { |
| FAIL("Scanning failed to start (err %d)\n", err); |
| return; |
| } |
| |
| LOG_DBG("Scanning successfully started"); |
| |
| WAIT_FOR_FLAG(flag_connected); |
| |
| err = bt_conn_set_security(default_conn, BT_SECURITY_L2); |
| if (err) { |
| FAIL("Failed to set security level %d (err %d)", BT_SECURITY_L2, err); |
| return; |
| } |
| |
| WAIT_FOR_COND(security_level == BT_SECURITY_L2); |
| |
| discover_and_subscribe_features(); |
| WAIT_FOR_FLAG(flag_features_discovered); |
| |
| discover_and_subscribe_active_preset_index(); |
| WAIT_FOR_FLAG(flag_active_preset_index_discovered); |
| |
| discover_and_subscribe_control_point(); |
| WAIT_FOR_FLAG(flag_control_point_discovered); |
| |
| bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); |
| WAIT_FOR_UNSET_FLAG(flag_connected); |
| |
| notify_received_mask = 0; |
| UNSET_FLAG(flag_all_notifications_received); |
| |
| err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL); |
| if (err < 0) { |
| FAIL("Scanning failed to start (err %d)\n", err); |
| return; |
| } |
| |
| LOG_DBG("Scanning successfully started"); |
| |
| WAIT_FOR_FLAG(flag_connected); |
| |
| err = bt_conn_set_security(default_conn, BT_SECURITY_L2); |
| if (err) { |
| FAIL("Failed to set security level %d (err %d)\n", BT_SECURITY_L2, err); |
| return; |
| } |
| |
| WAIT_FOR_FLAG(flag_all_notifications_received); |
| |
| PASS("HAS main PASS\n"); |
| } |
| |
| static const struct bst_test_instance test_has[] = { |
| { |
| .test_id = "has_client", |
| .test_post_init_f = test_init, |
| .test_tick_f = test_tick, |
| .test_main_f = test_main, |
| }, |
| { |
| .test_id = "has_client_offline_behavior", |
| .test_descr = "Test receiving notifications after reconnection", |
| .test_post_init_f = test_init, |
| .test_tick_f = test_tick, |
| .test_main_f = test_gatt_client, |
| }, |
| BSTEST_END_MARKER |
| }; |
| |
| struct bst_test_list *test_has_client_install(struct bst_test_list *tests) |
| { |
| if (IS_ENABLED(CONFIG_BT_HAS_CLIENT)) { |
| return bst_add_tests(tests, test_has); |
| } else { |
| return tests; |
| } |
| } |