Bluetooth: Tests: Check CCC Store

The first test check that if a bonded peer subscribe to a CCC, this
change is correctly stored to flash.

The second test, which is currently failing, is included to reproduce a
bug that occur when CCC or CF store on write is disabled and the other
one is enabled, leading to the delayed store being enabled. Causing the
value of the corresponding `n` selected option to not be stored at all.

Signed-off-by: Théo Battrel <theo.battrel@nordicsemi.no>
This commit is contained in:
Théo Battrel 2023-04-04 07:34:31 +02:00 committed by Carles Cufí
parent eb44414af9
commit f4ecc4e102
13 changed files with 981 additions and 0 deletions

View file

@ -41,6 +41,8 @@ app=tests/bsim/bluetooth/host/gatt/notify compile
app=tests/bsim/bluetooth/host/gatt/notify_multiple compile
app=tests/bsim/bluetooth/host/gatt/settings compile
app=tests/bsim/bluetooth/host/gatt/settings conf_file=prj_2.conf compile
app=tests/bsim/bluetooth/host/gatt/ccc_store compile
app=tests/bsim/bluetooth/host/gatt/ccc_store conf_file=prj_2.conf compile
app=tests/bsim/bluetooth/host/l2cap/general compile
app=tests/bsim/bluetooth/host/l2cap/userdata compile

View file

@ -0,0 +1,28 @@
# 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_ccc_store)
target_sources(app PRIVATE
src/main.c
src/common.c
src/central.c
src/peripheral.c
)
zephyr_include_directories(
$ENV{BSIM_COMPONENTS_PATH}/libUtilv1/src/
$ENV{BSIM_COMPONENTS_PATH}/libPhyComv1/src/
$ENV{ZEPHYR_BASE}/subsys/bluetooth/host/
)

View file

@ -0,0 +1,22 @@
CONFIG_BT=y
CONFIG_BT_CENTRAL=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_DEVICE_NAME="CCC Store Test"
CONFIG_LOG=y
CONFIG_BT_EXT_ADV=y
CONFIG_BT_MAX_CONN=3
CONFIG_BT_GATT_CLIENT=y
CONFIG_BT_SMP=y
CONFIG_SETTINGS=y
CONFIG_BT_SETTINGS=y
CONFIG_FLASH=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_NVS=y
CONFIG_FLASH_MAP=y
CONFIG_SETTINGS_NVS=y
CONFIG_ASSERT=y

View file

@ -0,0 +1,30 @@
CONFIG_BT=y
CONFIG_BT_CENTRAL=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_DEVICE_NAME="CCC Store Test"
CONFIG_LOG=y
CONFIG_BT_EXT_ADV=y
CONFIG_BT_MAX_CONN=3
CONFIG_BT_GATT_CLIENT=y
CONFIG_BT_SMP=y
CONFIG_SETTINGS=y
CONFIG_BT_SETTINGS=y
CONFIG_FLASH=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_NVS=y
CONFIG_FLASH_MAP=y
CONFIG_SETTINGS_NVS=y
CONFIG_ASSERT=y
# By doing so, BT_SETTINGS_DELAYED_STORE will be enabled because
# BT_SETTINGS_CF_STORE_ON_WRITE is enabled by default and selecting it.
# This cause the CCC to not be stored at all.
# If BT_SETTINGS_CCC_LAZY_LOADING is enabled, the test will pass because the
# CCC will not be cleared after the first disconnection and will then still be
# in RAM.
CONFIG_BT_SETTINGS_CCC_STORE_ON_WRITE=n

View file

@ -0,0 +1,310 @@
/* Copyright (c) 2023 Nordic Semiconductor ASA
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <zephyr/kernel.h>
#include <zephyr/bluetooth/att.h>
#include <zephyr/bluetooth/addr.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/hci_err.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/logging/log.h>
#include <zephyr/settings/settings.h>
#include "common.h"
#include "settings.h"
#include "argparse.h"
#include "bs_pc_backchannel.h"
#define SERVER_CHAN 0
CREATE_FLAG(connected_flag);
CREATE_FLAG(disconnected_flag);
CREATE_FLAG(security_updated_flag);
#define BT_UUID_DUMMY_SERVICE BT_UUID_DECLARE_128(DUMMY_SERVICE_TYPE)
#define BT_UUID_DUMMY_SERVICE_NOTIFY BT_UUID_DECLARE_128(DUMMY_SERVICE_NOTIFY_TYPE)
static struct bt_conn *default_conn;
static struct bt_conn_cb central_cb;
CREATE_FLAG(gatt_write_flag);
static uint8_t gatt_write_att_err;
static void gatt_write_cb(struct bt_conn *conn, uint8_t att_err,
struct bt_gatt_write_params *params)
{
gatt_write_att_err = att_err;
if (att_err) {
return;
}
SET_FLAG(gatt_write_flag);
}
static int gatt_write(struct bt_conn *conn, uint16_t handle, const uint8_t *write_buf,
size_t write_size)
{
int err;
struct bt_gatt_write_params params;
params.func = gatt_write_cb;
params.handle = handle;
params.offset = 0;
params.data = write_buf;
params.length = write_size;
UNSET_FLAG(gatt_write_flag);
/* `bt_gatt_write` is used instead of `bt_gatt_subscribe` and
* `bt_gatt_unsubscribe` to bypass subscribtion checks of GATT client
*/
err = bt_gatt_write(conn, &params);
if (err) {
FAIL("GATT write failed (err %d)", err);
}
WAIT_FOR_FLAG(gatt_write_flag);
return gatt_write_att_err;
}
static void ccc_subscribe(void)
{
int err;
uint8_t buf = 1;
err = gatt_write(default_conn, CCC_HANDLE, &buf, sizeof(buf));
if (err) {
FAIL("Failed to subscribe (att err %d)", err);
}
}
static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
struct net_buf_simple *ad)
{
int err;
char addr_str[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
LOG_DBG("Device found: %s (RSSI %d)", addr_str, rssi);
err = bt_le_scan_stop();
if (err) {
FAIL("Failed to stop scanner (err %d)\n", err);
}
err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT,
&default_conn);
if (err) {
FAIL("Could not connect to peer: %s (err %d)\n", addr_str, err);
}
}
static void connected(struct bt_conn *conn, uint8_t err)
{
const bt_addr_le_t *addr;
char addr_str[BT_ADDR_LE_STR_LEN];
addr = bt_conn_get_dst(conn);
bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
if (err) {
FAIL("Failed to connect to %s (err %d)\n", addr_str, err);
}
LOG_DBG("Connected: %s", addr_str);
if (conn == default_conn) {
SET_FLAG(connected_flag);
}
}
static void disconnected(struct bt_conn *conn, uint8_t reason)
{
char addr_str[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr_str, sizeof(addr_str));
LOG_DBG("Disconnected: %s (reason 0x%02x)", addr_str, reason);
SET_FLAG(disconnected_flag);
if (default_conn != conn) {
return;
}
bt_conn_unref(default_conn);
default_conn = NULL;
}
static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err)
{
char addr_str[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr_str, sizeof(addr_str));
if (!err) {
LOG_DBG("Security changed: %s level %u", addr_str, level);
SET_FLAG(security_updated_flag);
} else {
LOG_DBG("Security failed: %s level %u err %d", addr_str, level, err);
}
}
static void start_scan(void)
{
int err;
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
if (err) {
FAIL("Scanning failed to start (err %d)\n", err);
}
LOG_DBG("Scanning successfully started");
}
static void disconnect(void)
{
int err;
err = bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
if (err) {
FAIL("Disconnection failed (err %d)\n", err);
}
WAIT_FOR_FLAG(disconnected_flag);
UNSET_FLAG(disconnected_flag);
}
/* Test steps */
static void connect_pair_subscribe(void)
{
int err;
start_scan();
WAIT_FOR_FLAG(connected_flag);
UNSET_FLAG(connected_flag);
err = bt_conn_set_security(default_conn, BT_SECURITY_L2);
if (err != 0) {
FAIL("Failed to set security (err %d)\n", err);
}
WAIT_FOR_FLAG(security_updated_flag);
UNSET_FLAG(security_updated_flag);
/* subscribe while being paired */
ccc_subscribe();
/* confirm to server that we subscribed */
backchannel_sync_send(SERVER_CHAN, SERVER_ID);
/* wait for server to check that the subscribtion is well registered */
backchannel_sync_wait(SERVER_CHAN, SERVER_ID);
}
static void connect_restore_sec(void)
{
int err;
start_scan();
WAIT_FOR_FLAG(connected_flag);
UNSET_FLAG(connected_flag);
err = bt_conn_set_security(default_conn, BT_SECURITY_L2);
if (err != 0) {
FAIL("Failed to set security (err %d)\n", err);
}
WAIT_FOR_FLAG(security_updated_flag);
UNSET_FLAG(security_updated_flag);
/* notify the end of security update to server */
backchannel_sync_send(SERVER_CHAN, SERVER_ID);
/* wait for server to check that the subscribtion has been restored */
backchannel_sync_wait(SERVER_CHAN, SERVER_ID);
}
/* Util functions */
void central_backchannel_init(void)
{
uint device_number = get_device_nbr();
uint channel_numbers[1] = {
0,
};
uint device_numbers[1];
uint num_ch = 1;
uint *ch;
device_numbers[0] = SERVER_ID;
LOG_DBG("Opening back channels for device %d", device_number);
ch = bs_open_back_channel(device_number, device_numbers, channel_numbers, num_ch);
if (!ch) {
FAIL("Unable to open backchannel\n");
}
LOG_DBG("Back channels for device %d opened", device_number);
}
static void set_public_addr(void)
{
bt_addr_le_t addr = {BT_ADDR_LE_RANDOM, {{0x0A, 0x89, 0x67, 0x45, 0x23, 0xC1}}};
bt_id_create(&addr, NULL);
}
/* Main functions */
void run_central(void)
{
int err;
central_cb.connected = connected;
central_cb.disconnected = disconnected;
central_cb.security_changed = security_changed;
central_backchannel_init();
set_public_addr();
err = bt_enable(NULL);
if (err) {
FAIL("Bluetooth init failed (err %d)\n", err);
}
LOG_DBG("Bluetooth initialized");
bt_conn_cb_register(&central_cb);
err = settings_load();
if (err) {
FAIL("Settings load failed (err %d)\n", err);
}
err = bt_unpair(BT_ID_DEFAULT, BT_ADDR_LE_ANY);
if (err) {
FAIL("Unpairing failed (err %d)\n", err);
}
connect_pair_subscribe();
disconnect();
connect_restore_sec();
disconnect();
PASS("Central test passed\n");
}

View file

@ -0,0 +1,38 @@
/* Copyright (c) 2023 Nordic Semiconductor ASA
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include "common.h"
#include "argparse.h"
#include "bs_pc_backchannel.h"
void backchannel_sync_send(uint channel, uint device_nbr)
{
uint8_t sync_msg[BC_MSG_SIZE] = {get_device_nbr(), device_nbr}; /* src, dst */
bs_bc_send_msg(channel, sync_msg, ARRAY_SIZE(sync_msg));
}
void backchannel_sync_wait(uint channel, uint device_nbr)
{
uint8_t sync_msg[BC_MSG_SIZE];
LOG_DBG("Wait for %d on channel %d", device_nbr, channel);
while (true) {
if (bs_bc_is_msg_received(channel) > 0) {
bs_bc_receive_msg(channel, sync_msg, ARRAY_SIZE(sync_msg));
if (sync_msg[0] == device_nbr && sync_msg[1] == get_device_nbr()) {
break;
}
}
k_msleep(1);
}
LOG_DBG("Sync received");
}

View file

@ -0,0 +1,55 @@
/* Copyright (c) 2023 Nordic Semiconductor ASA
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/settings/settings.h>
#include <zephyr/logging/log.h>
#include "bs_tracing.h"
#include "bstests.h"
#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)
extern enum bst_result_t bst_result;
#define CREATE_FLAG(flag) static atomic_t flag = (atomic_t) false
#define SET_FLAG(flag) (void)atomic_set(&flag, (atomic_t) true)
#define GET_FLAG(flag) (bool)atomic_get(&flag)
#define UNSET_FLAG(flag) (void)atomic_set(&flag, (atomic_t) false)
#define WAIT_FOR_FLAG(flag) \
while (!(bool)atomic_get(&flag)) { \
(void)k_sleep(K_MSEC(1)); \
}
LOG_MODULE_DECLARE(bt_bsim_ccc_store, LOG_LEVEL_DBG);
#define DUMMY_SERVICE_TYPE BT_UUID_128_ENCODE(0x2e2b8dc3, 0x06e0, 0x4f93, 0x9bb2, 0x734091c356f0)
#define BT_UUID_DUMMY_SERVICE BT_UUID_DECLARE_128(DUMMY_SERVICE_TYPE)
#define DUMMY_SERVICE_NOTIFY_TYPE \
BT_UUID_128_ENCODE(0x2e2b8dc3, 0x06e0, 0x4f93, 0x9bb2, 0x734091c356f3)
#define BT_UUID_DUMMY_SERVICE_NOTIFY BT_UUID_DECLARE_128(DUMMY_SERVICE_NOTIFY_TYPE)
#define CCC_HANDLE 19
#define BC_MSG_SIZE 2
#define CLIENT_ID 0
#define SERVER_ID 1
void backchannel_sync_send(uint channel, uint device_nbr);
void backchannel_sync_wait(uint channel, uint device_nbr);

View file

@ -0,0 +1,87 @@
/* Copyright (c) 2023 Nordic Semiconductor ASA
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include "bs_types.h"
#include "bs_tracing.h"
#include "bstests.h"
#include <string.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(bt_bsim_ccc_store, LOG_LEVEL_DBG);
#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)
extern enum bst_result_t bst_result;
#define WAIT_TIME_S 60
#define WAIT_TIME (WAIT_TIME_S * 1e6)
extern void run_peripheral(void);
extern void run_central(void);
static void central_main(void)
{
run_central();
}
static void peripheral_main(void)
{
run_peripheral();
}
void test_tick(bs_time_t HW_device_time)
{
if (bst_result != Passed) {
bst_result = Failed;
bs_trace_error_time_line("Test failed (not passed after %d seconds)\n",
WAIT_TIME_S);
}
}
static void test_ccc_store_init(void)
{
bst_ticker_set_next_tick_absolute(WAIT_TIME);
}
static const struct bst_test_instance test_def[] = {
{
.test_id = "central",
.test_descr = "Central device",
.test_post_init_f = test_ccc_store_init,
.test_tick_f = test_tick,
.test_main_f = central_main,
},
{
.test_id = "peripheral",
.test_descr = "Peripheral device",
.test_post_init_f = test_ccc_store_init,
.test_tick_f = test_tick,
.test_main_f = peripheral_main,
},
BSTEST_END_MARKER};
struct bst_test_list *test_ccc_store_install(struct bst_test_list *tests)
{
return bst_add_tests(tests, test_def);
}
bst_test_install_t test_installers[] = {test_ccc_store_install, NULL};
void main(void)
{
bst_main();
}

View file

@ -0,0 +1,295 @@
/* Copyright (c) 2023 Nordic Semiconductor ASA
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <zephyr/kernel.h>
#include <zephyr/bluetooth/addr.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/logging/log.h>
#include <zephyr/settings/settings.h>
#include "common.h"
#include "settings.h"
#include "argparse.h"
#include "bs_pc_backchannel.h"
#define CLIENT_CHAN 0
CREATE_FLAG(connected_flag);
CREATE_FLAG(disconnected_flag);
CREATE_FLAG(security_updated_flag);
CREATE_FLAG(ccc_cfg_changed_flag);
static struct bt_uuid_128 dummy_service = BT_UUID_INIT_128(DUMMY_SERVICE_TYPE);
static struct bt_uuid_128 notify_characteristic_uuid = BT_UUID_INIT_128(DUMMY_SERVICE_NOTIFY_TYPE);
static struct bt_conn *default_conn;
static struct bt_conn_cb peripheral_cb;
static void ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
{
ARG_UNUSED(attr);
bool notif_enabled = (value == BT_GATT_CCC_NOTIFY);
LOG_INF("CCC Update: notification %s", notif_enabled ? "enabled" : "disabled");
SET_FLAG(ccc_cfg_changed_flag);
}
BT_GATT_SERVICE_DEFINE(dummy_svc, BT_GATT_PRIMARY_SERVICE(&dummy_service),
BT_GATT_CHARACTERISTIC(&notify_characteristic_uuid.uuid, BT_GATT_CHRC_NOTIFY,
BT_GATT_PERM_NONE, NULL, NULL, NULL),
BT_GATT_CCC(ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE));
static void create_adv(struct bt_le_ext_adv **adv)
{
int err;
struct bt_le_adv_param params;
memset(&params, 0, sizeof(struct bt_le_adv_param));
params.options |= BT_LE_ADV_OPT_CONNECTABLE;
params.id = BT_ID_DEFAULT;
params.sid = 0;
params.interval_min = BT_GAP_ADV_FAST_INT_MIN_2;
params.interval_max = BT_GAP_ADV_FAST_INT_MAX_2;
err = bt_le_ext_adv_create(&params, NULL, adv);
if (err) {
FAIL("Failed to create advertiser (%d)\n", err);
}
}
static void start_adv(struct bt_le_ext_adv *adv)
{
int err;
int32_t timeout = 0;
int8_t num_events = 0;
struct bt_le_ext_adv_start_param start_params;
start_params.timeout = timeout;
start_params.num_events = num_events;
err = bt_le_ext_adv_start(adv, &start_params);
if (err) {
FAIL("Failed to start advertiser (err %d)\n", err);
}
LOG_DBG("Advertiser started");
}
static void stop_adv(struct bt_le_ext_adv *adv)
{
int err;
err = bt_le_ext_adv_stop(adv);
if (err) {
FAIL("Failed to stop advertiser (err %d)\n", err);
}
}
static void connected(struct bt_conn *conn, uint8_t err)
{
char addr_str[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr_str, sizeof(addr_str));
if (err) {
FAIL("Failed to connect to %s (err %d)\n", addr_str, err);
}
LOG_DBG("Connected: %s", addr_str);
default_conn = bt_conn_ref(conn);
SET_FLAG(connected_flag);
UNSET_FLAG(disconnected_flag);
}
static void disconnected(struct bt_conn *conn, uint8_t reason)
{
char addr_str[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr_str, sizeof(addr_str));
LOG_DBG("Disconnected: %s (reason 0x%02x)", addr_str, reason);
bt_conn_unref(conn);
default_conn = NULL;
SET_FLAG(disconnected_flag);
UNSET_FLAG(connected_flag);
}
static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err)
{
char addr_str[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr_str, sizeof(addr_str));
if (!err) {
LOG_DBG("Security changed: %s level %u", addr_str, level);
SET_FLAG(security_updated_flag);
} else {
LOG_DBG("Security failed: %s level %u err %d", addr_str, level, err);
}
}
static bool is_peer_subscribed(struct bt_conn *conn)
{
struct bt_gatt_attr *attr = bt_gatt_find_by_uuid(NULL, 0, BT_UUID_DUMMY_SERVICE_NOTIFY);
bool is_subscribed = bt_gatt_is_subscribed(conn, attr, BT_GATT_CCC_NOTIFY);
return is_subscribed;
}
/* Test steps */
static void connect_pair_check_subscribtion(struct bt_le_ext_adv *adv)
{
start_adv(adv);
WAIT_FOR_FLAG(connected_flag);
WAIT_FOR_FLAG(security_updated_flag);
UNSET_FLAG(security_updated_flag);
/* wait for confirmation of subscribtion from good client */
backchannel_sync_wait(CLIENT_CHAN, CLIENT_ID);
/* check that subscribtion request did not fail */
if (!is_peer_subscribed(default_conn)) {
FAIL("Client did not subscribed\n");
}
stop_adv(adv);
/* confirm to client that the subscribtion has been well registered */
backchannel_sync_send(CLIENT_CHAN, CLIENT_ID);
}
static void connect_restore_sec_check_subscribtion(struct bt_le_ext_adv *adv)
{
start_adv(adv);
WAIT_FOR_FLAG(connected_flag);
WAIT_FOR_FLAG(security_updated_flag);
UNSET_FLAG(security_updated_flag);
/* wait for client end of security update */
backchannel_sync_wait(CLIENT_CHAN, CLIENT_ID);
/* check that subscribtion has been restored */
if (!is_peer_subscribed(default_conn)) {
if (!IS_ENABLED(CONFIG_BT_SETTINGS_CCC_STORE_ON_WRITE)) {
LOG_ERR("Expected failure: client is not subscribed. See issue #58471 for "
"more details.");
} else {
FAIL("Client is not subscribed\n");
}
} else {
LOG_DBG("Client is subscribed");
}
/* confirm to good client that the subscribtion has been well restored */
backchannel_sync_send(CLIENT_CHAN, CLIENT_ID);
}
/* Util functions */
void peripheral_backchannel_init(void)
{
uint device_number = get_device_nbr();
uint channel_numbers[1] = {
0,
};
uint device_numbers[1] = {
CLIENT_ID,
};
uint num_ch = 1;
uint *ch;
LOG_DBG("Opening back channels for device %d", device_number);
ch = bs_open_back_channel(device_number, device_numbers, channel_numbers, num_ch);
if (!ch) {
FAIL("Unable to open backchannel\n");
}
}
static void check_ccc_handle(void)
{
struct bt_gatt_attr *service_notify_attr =
bt_gatt_find_by_uuid(NULL, 0, &notify_characteristic_uuid.uuid);
struct bt_gatt_attr attr = {
.uuid = BT_UUID_GATT_CHRC,
.user_data = &(struct bt_gatt_chrc){
.value_handle = bt_gatt_attr_get_handle(service_notify_attr)}};
struct bt_gatt_attr *ccc_attr = bt_gatt_find_by_uuid(&attr, 0, BT_UUID_GATT_CCC);
uint16_t actual_ccc_handle = bt_gatt_attr_get_handle(ccc_attr);
__ASSERT(actual_ccc_handle == CCC_HANDLE,
"Please update the CCC_HANDLE define (actual_ccc_handle=%d)", actual_ccc_handle);
}
/* Main function */
void run_peripheral(void)
{
int err;
struct bt_le_ext_adv *adv = NULL;
peripheral_cb.connected = connected;
peripheral_cb.disconnected = disconnected;
peripheral_cb.security_changed = security_changed;
peripheral_backchannel_init();
err = bt_enable(NULL);
if (err) {
FAIL("Bluetooth init failed (err %d)\n", err);
}
LOG_DBG("Bluetooth initialized");
check_ccc_handle();
bt_conn_cb_register(&peripheral_cb);
err = settings_load();
if (err) {
FAIL("Settings load failed (err %d)\n", err);
}
err = bt_unpair(BT_ID_DEFAULT, BT_ADDR_LE_ANY);
if (err) {
FAIL("Unpairing failed (err %d)\n", err);
}
create_adv(&adv);
connect_pair_check_subscribtion(adv);
WAIT_FOR_FLAG(disconnected_flag);
connect_restore_sec_check_subscribtion(adv);
WAIT_FOR_FLAG(disconnected_flag);
PASS("Peripheral test passed\n");
}

View file

@ -0,0 +1,14 @@
#!/bin/env bash
# Copyright 2023 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0
set -eu
bash_source_dir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")"
source "${bash_source_dir}/_env.sh"
west build -b nrf52_bsim -d build_test && \
cp -v build_test/zephyr/zephyr.exe "${test_exe}"
west build -b nrf52_bsim -d build_test_2 -- -DCONF_FILE=prj_2.conf && \
cp -v build_test_2/zephyr/zephyr.exe "${test_exe_2}"

View file

@ -0,0 +1,16 @@
#!/bin/env bash
# Copyright 2023 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0
set -eu
bash_source_dir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")"
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
test_name="$(basename "$(realpath "$bash_source_dir/..")")"
bsim_bin="${BSIM_OUT_PATH}/bin"
verbosity_level=2
BOARD="${BOARD:-nrf52_bsim}"
simulation_id="$test_name"
test_exe="${bsim_bin}/bs_${BOARD}_tests_bsim_bluetooth_host_gatt_ccc_store_prj_conf"
test_exe_2="${bsim_bin}/bs_${BOARD}_tests_bsim_bluetooth_host_gatt_ccc_store_prj_2_conf"

View file

@ -0,0 +1,42 @@
#!/bin/env bash
# Copyright 2023 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0
source ${ZEPHYR_BASE}/tests/bsim/sh_common.source
test_name='ccc_store'
test_exe="bs_${BOARD}_tests_bsim_bluetooth_host_gatt_${test_name}_prj_conf"
simulation_id="${test_name}"
verbosity_level=2
EXECUTE_TIMEOUT=30
cd ${BSIM_OUT_PATH}/bin
if [ "${1}" != 'debug0' ]; then
Execute "./${test_exe}" \
-v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central \
-flash="${simulation_id}_client.log.bin" -flash_rm
fi
if [ "${1}" != 'debug1' ]; then
Execute "./${test_exe}" \
-v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral \
-flash="${simulation_id}_server.log.bin" -flash_rm
fi
Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \
-D=2 -sim_length=60e6
if [ "${1}" == 'debug0' ]; then
gdb --args "./${test_exe}" \
-v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central \
-flash="${simulation_id}_client.log.bin" -flash_rm
fi
if [ "${1}" == 'debug1' ]; then
gdb --args "./${test_exe}" \
-v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral \
-flash="${simulation_id}_server.log.bin" -flash_rm
fi
wait_for_background_jobs

View file

@ -0,0 +1,42 @@
#!/bin/env bash
# Copyright 2023 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0
source ${ZEPHYR_BASE}/tests/bsim/sh_common.source
test_name='ccc_store'
test_exe="bs_${BOARD}_tests_bsim_bluetooth_host_gatt_${test_name}_prj_2_conf"
simulation_id="${test_name}_2"
verbosity_level=2
EXECUTE_TIMEOUT=30
cd ${BSIM_OUT_PATH}/bin
if [ "${1}" != 'debug0' ]; then
Execute "./${test_exe}" \
-v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central \
-flash="${simulation_id}_client.log.bin" -flash_rm
fi
if [ "${1}" != 'debug1' ]; then
Execute "./${test_exe}" \
-v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral \
-flash="${simulation_id}_server.log.bin" -flash_rm
fi
Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \
-D=2 -sim_length=60e6
if [ "${1}" == 'debug0' ]; then
gdb --args "./${test_exe}" \
-v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central \
-flash="${simulation_id}_client.log.bin" -flash_rm
fi
if [ "${1}" == 'debug1' ]; then
gdb --args "./${test_exe}" \
-v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral \
-flash="${simulation_id}_server.log.bin" -flash_rm
fi
wait_for_background_jobs