From 59dd898c2b7ca1bb18440d8e3a7ac99f4f42f90e Mon Sep 17 00:00:00 2001 From: Alexandru Carbuneanu Date: Wed, 20 Apr 2022 15:48:59 +0200 Subject: [PATCH] test: bsim: Notification EATT test Increasing the test coverage of notification on EATT bearers. - test implementation Signed-off-by: Alexandru Carbuneanu --- .../bsim_test_eatt_notif/CMakeLists.txt | 21 ++ .../bsim_bt/bsim_test_eatt_notif/prj.conf | 15 ++ .../bsim_test_eatt_notif/src/client_test.c | 240 ++++++++++++++++++ .../bsim_bt/bsim_test_eatt_notif/src/common.c | 67 +++++ .../bsim_bt/bsim_test_eatt_notif/src/common.h | 76 ++++++ .../bsim_bt/bsim_test_eatt_notif/src/main.c | 21 ++ .../bsim_test_eatt_notif/src/server_test.c | 102 ++++++++ .../test_scripts/eatt_notif.sh | 39 +++ tests/bluetooth/bsim_bt/compile.sh | 1 + 9 files changed, 582 insertions(+) create mode 100644 tests/bluetooth/bsim_bt/bsim_test_eatt_notif/CMakeLists.txt create mode 100644 tests/bluetooth/bsim_bt/bsim_test_eatt_notif/prj.conf create mode 100644 tests/bluetooth/bsim_bt/bsim_test_eatt_notif/src/client_test.c create mode 100644 tests/bluetooth/bsim_bt/bsim_test_eatt_notif/src/common.c create mode 100644 tests/bluetooth/bsim_bt/bsim_test_eatt_notif/src/common.h create mode 100644 tests/bluetooth/bsim_bt/bsim_test_eatt_notif/src/main.c create mode 100644 tests/bluetooth/bsim_bt/bsim_test_eatt_notif/src/server_test.c create mode 100755 tests/bluetooth/bsim_bt/bsim_test_eatt_notif/test_scripts/eatt_notif.sh diff --git a/tests/bluetooth/bsim_bt/bsim_test_eatt_notif/CMakeLists.txt b/tests/bluetooth/bsim_bt/bsim_test_eatt_notif/CMakeLists.txt new file mode 100644 index 00000000000..038ff2a81ad --- /dev/null +++ b/tests/bluetooth/bsim_bt/bsim_test_eatt_notif/CMakeLists.txt @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +if (NOT DEFINED ENV{BSIM_COMPONENTS_PATH}) + message(FATAL_ERROR "This test requires the BabbleSim simulator. Please set\ + the environment variable BSIM_COMPONENTS_PATH to point to its components \ + folder. More information can be found in\ + https://babblesim.github.io/folder_structure_and_env.html") +endif() + +find_package(Zephyr HINTS $ENV{ZEPHYR_BASE}) +project(bsim_test_eatt_notif) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources} ) + +zephyr_include_directories( + $ENV{BSIM_COMPONENTS_PATH}/libUtilv1/src/ + $ENV{BSIM_COMPONENTS_PATH}/libPhyComv1/src/ + ) diff --git a/tests/bluetooth/bsim_bt/bsim_test_eatt_notif/prj.conf b/tests/bluetooth/bsim_bt/bsim_test_eatt_notif/prj.conf new file mode 100644 index 00000000000..bda959b81c6 --- /dev/null +++ b/tests/bluetooth/bsim_bt/bsim_test_eatt_notif/prj.conf @@ -0,0 +1,15 @@ +CONFIG_BT=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_SMP=y +CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y +CONFIG_BT_DEVICE_NAME="EATT test" +CONFIG_BT_EATT=y +CONFIG_BT_TESTING=y +CONFIG_BT_EATT_AUTO_CONNECT=n +CONFIG_BT_L2CAP_ECRED=y +CONFIG_BT_EATT_MAX=16 +CONFIG_BT_MAX_CONN=1 +CONFIG_BT_GATT_CLIENT=y +CONFIG_BT_ATT_PREPARE_COUNT=3 +CONFIG_ASSERT=y diff --git a/tests/bluetooth/bsim_bt/bsim_test_eatt_notif/src/client_test.c b/tests/bluetooth/bsim_bt/bsim_test_eatt_notif/src/client_test.c new file mode 100644 index 00000000000..ef981576e6d --- /dev/null +++ b/tests/bluetooth/bsim_bt/bsim_test_eatt_notif/src/client_test.c @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + * + * EATT notification reliability test: + * A central acting as a GATT client scans and connects + * to a peripheral acting as a GATT server. + * The GATT client will then attempt to connect a number of CONFIG_BT_EATT_MAX bearers + * over EATT, send notifications, disconnect all bearers and reconnect EATT_BEARERS_TEST + * and send start a transaction with a request, then send a lot of notifications + * before the response is received. + * The test might be expanded by checking that all the notifications all transmitted + * on EATT channels. + */ + +#include +#include +#include +#include + +#include "common.h" + +CREATE_FLAG(flag_is_connected); +CREATE_FLAG(flag_discover_complete); + +static struct bt_conn *g_conn; +static const struct bt_gatt_attr *local_attr; +static struct bt_uuid *test_svc_uuid = TEST_SERVICE_UUID; + +#define NUM_NOTIF 100 +#define SAMPLE_DATA 1 +#define EATT_BEARERS_TEST 1 + +volatile int num_eatt_channels; + +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); + 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); +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, +}; + +void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, + struct net_buf_simple *ad) +{ + char addr_str[BT_ADDR_LE_STR_LEN]; + int err; + + if (g_conn != NULL) { + return; + } + + /* We're only interested in connectable events */ + if (type != BT_HCI_ADV_IND && type != BT_HCI_ADV_DIRECT_IND) { + return; + } + + bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); + printk("Device found: %s (RSSI %d)\n", addr_str, rssi); + + printk("Stopping scan\n"); + err = bt_le_scan_stop(); + if (err != 0) { + FAIL("Could not stop scan: %d"); + return; + } + + err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, + BT_LE_CONN_PARAM_DEFAULT, &g_conn); + if (err != 0) { + FAIL("Could not connect to peer: %d", err); + } +} + +void send_notification(void) +{ + const uint8_t sample_dat = SAMPLE_DATA; + int err; + + do { + err = bt_gatt_notify(g_conn, local_attr, &sample_dat, sizeof(sample_dat)); + if (!err) { + return; + } else if (err != -ENOMEM) { + printk("GATT notify failed (err %d)\n", err); + return; + } + k_sleep(K_TICKS(1)); + } while (err == -ENOMEM); +} + +static uint8_t discover_func(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) +{ + SET_FLAG(flag_discover_complete); + printk("Discover complete\n"); + + return BT_GATT_ITER_STOP; +} + +static void gatt_discover(void) +{ + static struct bt_gatt_discover_params discover_params; + int err; + + printk("Discovering services and characteristics\n"); + + discover_params.uuid = test_svc_uuid; + discover_params.func = discover_func; + discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; + discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; + discover_params.type = BT_GATT_DISCOVER_PRIMARY; + + err = bt_gatt_discover(g_conn, &discover_params); + if (err != 0) { + FAIL("Discover failed(err %d)\n", err); + } +} + +BT_GATT_SERVICE_DEFINE(g_svc, + BT_GATT_PRIMARY_SERVICE(TEST_SERVICE_UUID), + BT_GATT_CHARACTERISTIC(TEST_CHRC_UUID, BT_GATT_CHRC_NOTIFY, + 0x00, NULL, NULL, NULL)); + +static void test_main(void) +{ + int err; + + device_sync_init(PERIPHERAL_ID); + + err = bt_enable(NULL); + if (err != 0) { + FAIL("Bluetooth enable failed (err %d)\n", err); + } + + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found); + if (err != 0) { + FAIL("Scanning failed to start (err %d)\n", err); + } + + printk("Scanning successfully started\n"); + + WAIT_FOR_FLAG(flag_is_connected); + + err = bt_eatt_connect(g_conn, CONFIG_BT_EATT_MAX); + if (err) { + FAIL("Sending credit based connection request failed (err %d)\n", err); + } + + /* Wait for the channels to be connected */ + while (bt_eatt_count(g_conn) < CONFIG_BT_EATT_MAX) { + k_sleep(K_TICKS(1)); + } + + local_attr = &g_svc.attrs[1]; + printk("############# Notification test\n"); + for (int idx = 0; idx < NUM_NOTIF; idx++) { + printk("Notification %d\n", idx); + send_notification(); + } + + printk("############# Disconnect and reconnect\n"); + for (int idx = 0; idx < CONFIG_BT_EATT_MAX; idx++) { + bt_eatt_disconnect_one(g_conn); + while (bt_eatt_count(g_conn) != (CONFIG_BT_EATT_MAX - idx)) { + k_sleep(K_TICKS(1)); + } + } + + printk("Connecting %d bearers\n", EATT_BEARERS_TEST); + err = bt_eatt_connect(g_conn, EATT_BEARERS_TEST); + if (err) { + FAIL("Sending credit based connection request failed (err %d)\n", err); + } + + /* Wait for the channels to be connected */ + while (bt_eatt_count(g_conn) < EATT_BEARERS_TEST) { + k_sleep(K_TICKS(1)); + } + + printk("############# Send notifications during discovery request\n"); + gatt_discover(); + while (!TEST_FLAG(flag_discover_complete)) { + printk("Notifying...\n"); + send_notification(); + } + + printk("Send sync to contine\n"); + device_sync_send(); + + PASS("Client Passed\n"); +} + +static const struct bst_test_instance test_vcs[] = { + { + .test_id = "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_client_install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_vcs); +} diff --git a/tests/bluetooth/bsim_bt/bsim_test_eatt_notif/src/common.c b/tests/bluetooth/bsim_bt/bsim_test_eatt_notif/src/common.c new file mode 100644 index 00000000000..5ed87daaacc --- /dev/null +++ b/tests/bluetooth/bsim_bt/bsim_test_eatt_notif/src/common.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "common.h" +#include + +#define LOG_MODULE_NAME common + +LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_DBG); + +void test_tick(bs_time_t HW_device_time) +{ + if (bst_result != Passed) { + FAIL("test failed (not passed after %i seconds)\n", WAIT_TIME); + } +} + +void test_init(void) +{ + bst_ticker_set_next_tick_absolute(WAIT_TIME); + bst_result = In_progress; +} + +/* Call in init functions*/ +void device_sync_init(uint device_nbr) +{ + uint peer; + + if (device_nbr == CENTRAL_ID) { + peer = PERIPHERAL_ID; + } else { + peer = CENTRAL_ID; + } + + uint dev_nbrs[BACK_CHANNELS] = { peer }; + uint channel_nbrs[BACK_CHANNELS] = { 0 }; + const uint *ch = bs_open_back_channel(device_nbr, dev_nbrs, channel_nbrs, BACK_CHANNELS); + + if (!ch) { + LOG_ERR("bs_open_back_channel failed!"); + } +} + +/* Call it to make peer to proceed.*/ +void device_sync_send(void) +{ + uint8_t msg[1] = "S"; + + bs_bc_send_msg(0, msg, sizeof(msg)); +} + +/* Wait until peer send sync*/ +void device_sync_wait(void) +{ + int size_msg_received = 0; + uint8_t msg; + + while (!size_msg_received) { + size_msg_received = bs_bc_is_msg_received(0); + k_sleep(K_MSEC(1)); + } + + bs_bc_receive_msg(0, &msg, size_msg_received); +} diff --git a/tests/bluetooth/bsim_bt/bsim_test_eatt_notif/src/common.h b/tests/bluetooth/bsim_bt/bsim_test_eatt_notif/src/common.h new file mode 100644 index 00000000000..6647dbd55d4 --- /dev/null +++ b/tests/bluetooth/bsim_bt/bsim_test_eatt_notif/src/common.h @@ -0,0 +1,76 @@ +/** + * Common functions and helpers for BSIM EATT notification tests + * + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "kernel.h" + +#include "bs_types.h" +#include "bs_tracing.h" +#include "time_machine.h" +#include "bstests.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "bs_pc_backchannel.h" + +extern enum bst_result_t bst_result; + +#define WAIT_TIME (30 * 1e6) /*seconds*/ + +#define CREATE_FLAG(flag) static atomic_t flag = (atomic_t)false +#define SET_FLAG(flag) (void)atomic_set(&flag, (atomic_t)true) +#define UNSET_FLAG(flag) (void)atomic_set(&flag, (atomic_t)false) +#define TEST_FLAG(flag) (atomic_get(&flag) == (atomic_t)true) +#define WAIT_FOR_FLAG(flag) \ + while (!(bool)atomic_get(&flag)) { \ + (void)k_sleep(K_MSEC(1)); \ + } + +#define FAIL(...) \ + do { \ + bst_result = Failed; \ + bs_trace_error_time_line(__VA_ARGS__); \ + } while (0) + +#define PASS(...) \ + do { \ + bst_result = Passed; \ + bs_trace_info_time(1, __VA_ARGS__); \ + } while (0) + +#define CHRC_SIZE 10 +#define LONG_CHRC_SIZE 40 + +#define TEST_SERVICE_UUID \ + BT_UUID_DECLARE_128(0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x02, 0x03, \ + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00) + +#define TEST_CHRC_UUID \ + BT_UUID_DECLARE_128(0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x02, 0x03, \ + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0x00) + +#define TEST_LONG_CHRC_UUID \ + BT_UUID_DECLARE_128(0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x02, 0x03, \ + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0x11) + +#define CENTRAL_ID 0 +#define PERIPHERAL_ID 1 +#define BACK_CHANNELS 1 + +void test_tick(bs_time_t HW_device_time); +void test_init(void); +void device_sync_init(uint device_nbr); +void device_sync_send(void); +void device_sync_wait(void); diff --git a/tests/bluetooth/bsim_bt/bsim_test_eatt_notif/src/main.c b/tests/bluetooth/bsim_bt/bsim_test_eatt_notif/src/main.c new file mode 100644 index 00000000000..2b8cd4054df --- /dev/null +++ b/tests/bluetooth/bsim_bt/bsim_test_eatt_notif/src/main.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bstests.h" + +extern struct bst_test_list *test_server_install(struct bst_test_list *tests); +extern struct bst_test_list *test_client_install(struct bst_test_list *tests); + +bst_test_install_t test_installers[] = { + test_server_install, + test_client_install, + NULL +}; + +void main(void) +{ + bst_main(); +} diff --git a/tests/bluetooth/bsim_bt/bsim_test_eatt_notif/src/server_test.c b/tests/bluetooth/bsim_bt/bsim_test_eatt_notif/src/server_test.c new file mode 100644 index 00000000000..1c4cf3fb01d --- /dev/null +++ b/tests/bluetooth/bsim_bt/bsim_test_eatt_notif/src/server_test.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "common.h" +#include +#include + +extern enum bst_result_t bst_result; + +CREATE_FLAG(flag_is_connected); + +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); +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, +}; + +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)) + }; + + device_sync_init(CENTRAL_ID); + + 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); + + printk("Wait for sync\n"); + device_sync_wait(); + + PASS("Server Passed\n"); +} + +static const struct bst_test_instance test_server[] = { + { + .test_id = "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_server_install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_server); +} diff --git a/tests/bluetooth/bsim_bt/bsim_test_eatt_notif/test_scripts/eatt_notif.sh b/tests/bluetooth/bsim_bt/bsim_test_eatt_notif/test_scripts/eatt_notif.sh new file mode 100755 index 00000000000..83585b95fe7 --- /dev/null +++ b/tests/bluetooth/bsim_bt/bsim_test_eatt_notif/test_scripts/eatt_notif.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# Copyright 2022 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# EATT notification reliability test + +simulation_id="eatt_notif" +verbosity_level=2 +process_ids=""; exit_code=0 + +function Execute(){ + if [ ! -f $1 ]; then + echo -e " \e[91m`pwd`/`basename $1` cannot be found (did you forget to\ + compile it?)\e[39m" + exit 1 + fi + timeout 120 $@ & process_ids="$process_ids $!" +} + +: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}" + +#Give a default value to BOARD if it does not have one yet: +BOARD="${BOARD:-nrf52_bsim}" + +cd ${BSIM_OUT_PATH}/bin + +Execute ./bs_${BOARD}_tests_bluetooth_bsim_bt_bsim_test_eatt_notif_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=client + +Execute ./bs_${BOARD}_tests_bluetooth_bsim_bt_bsim_test_eatt_notif_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=server + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=2 -sim_length=60e6 $@ + +for process_id in $process_ids; do + wait $process_id || let "exit_code=$?" +done +exit $exit_code #the last exit code != 0 diff --git a/tests/bluetooth/bsim_bt/compile.sh b/tests/bluetooth/bsim_bt/compile.sh index a6c11f70238..9732e9cb2cf 100755 --- a/tests/bluetooth/bsim_bt/compile.sh +++ b/tests/bluetooth/bsim_bt/compile.sh @@ -21,6 +21,7 @@ mkdir -p ${WORK_DIR} source ${ZEPHYR_BASE}/tests/bluetooth/bsim_bt/compile.source app=tests/bluetooth/bsim_bt/bsim_test_notify compile +app=tests/bluetooth/bsim_bt/bsim_test_eatt_notif conf_file=prj.conf compile app=tests/bluetooth/bsim_bt/bsim_test_gatt_caching compile app=tests/bluetooth/bsim_bt/bsim_test_eatt conf_file=prj_encryption.conf compile app=tests/bluetooth/bsim_bt/bsim_test_eatt conf_file=prj_collision.conf compile