blob: 02d8759f34292fa77c9682eab54fd4bd4e6a92d8 [file] [log] [blame]
/*
* Copyright (c) 2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "common.h"
extern enum bst_result_t bst_result;
CREATE_FLAG(flag_is_connected);
CREATE_FLAG(flag_is_encrypted);
static struct bt_conn *g_conn;
static void connected(struct bt_conn *conn, uint8_t err)
{
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
if (err != 0) {
FAIL("Failed to connect to %s (%u)\n", addr, err);
return;
}
printk("Connected to %s\n", addr);
g_conn = bt_conn_ref(conn);
SET_FLAG(flag_is_connected);
}
static void disconnected(struct bt_conn *conn, uint8_t reason)
{
char addr[BT_ADDR_LE_STR_LEN];
if (conn != g_conn) {
return;
}
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
printk("Disconnected: %s (reason 0x%02x)\n", addr, reason);
bt_conn_unref(g_conn);
g_conn = NULL;
UNSET_FLAG(flag_is_connected);
}
static void security_changed(struct bt_conn *conn, bt_security_t level,
enum bt_security_err security_err)
{
if (security_err == BT_SECURITY_ERR_SUCCESS && level > BT_SECURITY_L1) {
SET_FLAG(flag_is_encrypted);
}
}
BT_CONN_CB_DEFINE(conn_callbacks) = {
.connected = connected,
.disconnected = disconnected,
.security_changed = security_changed,
};
#define ARRAY_ITEM(i, _) i
static const uint8_t chrc_data[] = { LISTIFY(CHRC_SIZE, ARRAY_ITEM, (,)) }; /* 1, 2, 3 ... */
static ssize_t read_test_chrc(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
uint16_t len, uint16_t offset)
{
printk("Characteristic read\n");
return bt_gatt_attr_read(conn, attr, buf, len, offset, (const void *)chrc_data, CHRC_SIZE);
}
BT_GATT_SERVICE_DEFINE(test_svc, BT_GATT_PRIMARY_SERVICE(TEST_SERVICE_UUID),
BT_GATT_CHARACTERISTIC(TEST_CHRC_UUID, BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
read_test_chrc, NULL, NULL));
static struct bt_gatt_attr additional_attributes[] = {
BT_GATT_CHARACTERISTIC(TEST_ADDITIONAL_CHRC_UUID, 0, BT_GATT_PERM_NONE, NULL, NULL, NULL),
};
static struct bt_gatt_service additional_gatt_service = BT_GATT_SERVICE(additional_attributes);
static void test_main_common(bool connect_eatt)
{
int err;
const struct bt_data ad[] = { BT_DATA_BYTES(BT_DATA_FLAGS,
(BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)) };
backchannel_init();
err = bt_enable(NULL);
if (err != 0) {
FAIL("Bluetooth init failed (err %d)\n", err);
return;
}
printk("Bluetooth initialized\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("Advertising successfully started\n");
WAIT_FOR_FLAG(flag_is_connected);
if (connect_eatt) {
WAIT_FOR_FLAG(flag_is_encrypted);
err = bt_eatt_connect(g_conn, CONFIG_BT_EATT_MAX);
if (err) {
FAIL("Failed to connect EATT channels (err %d)\n", err);
return;
}
}
/* Wait for client to do discovery and configuration */
backchannel_sync_wait();
printk("Registering additional service\n");
err = bt_gatt_service_register(&additional_gatt_service);
if (err < 0) {
FAIL("Registering additional service failed (err %d)\n", err);
}
/* Signal to client that additional service is registered */
backchannel_sync_send();
/* Wait for client to be done reading */
backchannel_sync_wait();
PASS("GATT server passed\n");
}
static void test_main_eatt(void)
{
test_main_common(true);
}
static void test_main_no_eatt(void)
{
test_main_common(false);
}
static const struct bst_test_instance test_gatt_server[] = {
{
.test_id = "gatt_server_eatt",
.test_post_init_f = test_init,
.test_tick_f = test_tick,
.test_main_f = test_main_eatt,
},
{
.test_id = "gatt_server_no_eatt",
.test_post_init_f = test_init,
.test_tick_f = test_tick,
.test_main_f = test_main_no_eatt,
},
BSTEST_END_MARKER,
};
struct bst_test_list *test_gatt_server_install(struct bst_test_list *tests)
{
return bst_add_tests(tests, test_gatt_server);
}