Tests: Bluetooth: Host: Added Test for extended Advertisements

Where extended advertising is restablished through the use of
recycled() callback, registers over bt_conn_cb_register().

Signed-off-by: Luis Ubieda <luisf@croxel.com>
This commit is contained in:
Luis Ubieda 2024-01-29 22:31:38 -05:00 committed by Fabio Baltieri
parent 56e2e7608d
commit 7e5b2a79fc
9 changed files with 610 additions and 0 deletions

View file

@ -0,0 +1,18 @@
# Copyright 2024 Croxel, Inc.
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(bsim_test_ext_adv)
target_sources(app PRIVATE
src/main.c
src/ext_adv_advertiser.c
src/ext_adv_scanner.c
)
zephyr_include_directories(
${BSIM_COMPONENTS_PATH}/libUtilv1/src/
${BSIM_COMPONENTS_PATH}/libPhyComv1/src/
)

View file

@ -0,0 +1,5 @@
CONFIG_BT=y
CONFIG_BT_DEVICE_NAME="test_ext_adv"
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_CENTRAL=y
CONFIG_BT_EXT_ADV=y

View file

@ -0,0 +1,53 @@
/**
* Copyright (c) 2024 Croxel, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_TEST_BSIM_BT_EXT_ADV_TEST_
#define ZEPHYR_TEST_BSIM_BT_EXT_ADV_TEST_
#include <zephyr/kernel.h>
#include "bs_types.h"
#include "bs_tracing.h"
#include "time_machine.h"
#include "bstests.h"
#define WAIT_SECONDS 30 /* seconds */
#define WAIT_TIME (WAIT_SECONDS * USEC_PER_SEC) /* microseconds*/
#define CREATE_FLAG(flag) static atomic_t flag = (atomic_t)false
#define SET_FLAG(flag) (void)atomic_set(&flag, (atomic_t) true)
#define TEST_FLAG(flag) (atomic_get(&flag) == (atomic_t)true)
#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)); \
}
#define WAIT_FOR_FLAG_UNSET(flag) \
while ((bool)atomic_get(&flag)) { \
(void)k_sleep(K_MSEC(1)); \
}
#define TAKE_FLAG(flag) \
while (!(bool)atomic_cas(&flag, true, false)) { \
(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, "PASSED: " __VA_ARGS__); \
} while (0)
void test_tick(bs_time_t HW_device_time);
void test_init(void);
#endif /* ZEPHYR_TEST_BSIM_BT_EXT_ADV_TEST_ */

View file

@ -0,0 +1,233 @@
/**
* Copyright (c) 2024 Croxel, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include "common.h"
#include "bs_types.h"
#include "bs_tracing.h"
#include "time_machine.h"
#include "bstests.h"
#include <zephyr/types.h>
#include <zephyr/sys/printk.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h>
extern enum bst_result_t bst_result;
static struct bt_conn *g_conn;
CREATE_FLAG(flag_connected);
CREATE_FLAG(flag_conn_recycled);
static void common_init(void)
{
int err;
err = bt_enable(NULL);
if (err) {
FAIL("Bluetooth init failed: %d\n", err);
return;
}
printk("Bluetooth initialized\n");
}
static void create_ext_adv_set(struct bt_le_ext_adv **adv, bool connectable)
{
int err;
printk("Creating extended advertising set...");
const struct bt_le_adv_param *adv_param = connectable ?
BT_LE_EXT_ADV_CONN_NAME : BT_LE_EXT_ADV_NCONN_NAME;
err = bt_le_ext_adv_create(adv_param, NULL, adv);
if (err) {
printk("Failed to create advertising set: %d\n", err);
return;
}
printk("done.\n");
}
static void start_ext_adv_set(struct bt_le_ext_adv *adv)
{
int err;
printk("Starting Extended Advertising...");
err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT);
if (err) {
printk("Failed to start extended advertising: %d\n", err);
return;
}
printk("done.\n");
}
static void stop_ext_adv_set(struct bt_le_ext_adv *adv)
{
int err;
printk("Stopping Extended Advertising...");
err = bt_le_ext_adv_stop(adv);
if (err) {
printk("Failed to stop extended advertising: %d\n",
err);
return;
}
printk("done.\n");
}
static void delete_adv_set(struct bt_le_ext_adv *adv)
{
int err;
printk("Delete extended advertising set...");
err = bt_le_ext_adv_delete(adv);
if (err) {
printk("Failed Delete extended advertising set: %d\n", err);
return;
}
printk("done.\n");
}
static void disconnect_from_target(void)
{
int err;
printk("Disconnecting...\n");
err = bt_conn_disconnect(g_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
if (err) {
FAIL("BT Disconnect failed: %d\n", err);
return;
}
}
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 != BT_HCI_ERR_SUCCESS) {
FAIL("Failed to connect to %s: %u\n", addr, err);
return;
}
printk("Connected to %s\n", addr);
if (g_conn != NULL) {
FAIL("Attempt to override connection object without clean-up\n");
return;
}
g_conn = bt_conn_ref(conn);
SET_FLAG(flag_connected);
}
static void disconnected(struct bt_conn *conn, uint8_t reason)
{
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
printk("Disconnected: %s (reason %u)\n", addr, reason);
bt_conn_unref(g_conn);
g_conn = NULL;
}
static void recycled(void)
{
SET_FLAG(flag_conn_recycled);
}
static struct bt_conn_cb conn_cbs = {
.connected = connected,
.disconnected = disconnected,
.recycled = recycled,
};
static void main_ext_adv_advertiser(void)
{
struct bt_le_ext_adv *ext_adv;
common_init();
create_ext_adv_set(&ext_adv, false);
start_ext_adv_set(ext_adv);
/* Advertise for a bit */
k_sleep(K_SECONDS(5));
stop_ext_adv_set(ext_adv);
delete_adv_set(ext_adv);
ext_adv = NULL;
PASS("Extended advertiser passed\n");
}
static void main_ext_conn_adv_advertiser(void)
{
struct bt_le_ext_adv *ext_adv;
common_init();
bt_conn_cb_register(&conn_cbs);
create_ext_adv_set(&ext_adv, true);
start_ext_adv_set(ext_adv);
printk("Waiting for connection...\n");
WAIT_FOR_FLAG(flag_connected);
disconnect_from_target();
printk("Waiting for Connection object to be recycled...\n");
WAIT_FOR_FLAG(flag_conn_recycled);
stop_ext_adv_set(ext_adv);
delete_adv_set(ext_adv);
create_ext_adv_set(&ext_adv, false);
start_ext_adv_set(ext_adv);
/* Advertise for a bit */
k_sleep(K_SECONDS(5));
stop_ext_adv_set(ext_adv);
delete_adv_set(ext_adv);
ext_adv = NULL;
PASS("Extended advertiser passed\n");
}
static const struct bst_test_instance ext_adv_advertiser[] = {
{
.test_id = "ext_adv_advertiser",
.test_descr = "Basic extended advertising test. "
"Will just start extended advertising.",
.test_post_init_f = test_init,
.test_tick_f = test_tick,
.test_main_f = main_ext_adv_advertiser
},
{
.test_id = "ext_adv_conn_advertiser",
.test_descr = "Basic connectable extended advertising test. "
"Starts extended advertising, and restarts it after disconnecting",
.test_post_init_f = test_init,
.test_tick_f = test_tick,
.test_main_f = main_ext_conn_adv_advertiser
},
BSTEST_END_MARKER
};
struct bst_test_list *test_ext_adv_advertiser(struct bst_test_list *tests)
{
return bst_add_tests(tests, ext_adv_advertiser);
}

View file

@ -0,0 +1,201 @@
/**
* Copyright (c) 2024 Croxel, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include "common.h"
#include "bs_types.h"
#include "bs_tracing.h"
#include "time_machine.h"
#include "bstests.h"
#include <zephyr/types.h>
#include <zephyr/sys/printk.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h>
extern enum bst_result_t bst_result;
static struct bt_conn *g_conn;
CREATE_FLAG(flag_ext_adv_seen);
CREATE_FLAG(flag_connected);
CREATE_FLAG(flag_conn_recycled);
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 != BT_HCI_ERR_SUCCESS) {
FAIL("Failed to connect to %s: %u\n", addr, err);
bt_conn_unref(g_conn);
g_conn = NULL;
return;
}
printk("Connected to %s\n", addr);
SET_FLAG(flag_connected);
}
static void disconnected(struct bt_conn *conn, uint8_t reason)
{
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
printk("Disconnected: %s (reason %u)\n", addr, reason);
bt_conn_unref(g_conn);
g_conn = NULL;
UNSET_FLAG(flag_connected);
}
static void recycled(void)
{
SET_FLAG(flag_conn_recycled);
}
static struct bt_conn_cb conn_cbs = {
.connected = connected,
.disconnected = disconnected,
.recycled = recycled,
};
static void scan_recv(const struct bt_le_scan_recv_info *info,
struct net_buf_simple *buf)
{
printk("Found advertisement. Adv-type: 0x%02x, Adv-prop: 0x%02x\n",
info->adv_type, info->adv_props);
if (info->adv_type & BT_GAP_ADV_TYPE_EXT_ADV &&
info->adv_props & BT_GAP_ADV_PROP_EXT_ADV) {
printk("Found extended advertisement!\n");
SET_FLAG(flag_ext_adv_seen);
}
if (!TEST_FLAG(flag_connected) &&
info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) {
int err;
printk("Stopping scan\n");
err = bt_le_scan_stop();
if (err) {
FAIL("Failed to stop scan: %d", err);
return;
}
err = bt_conn_le_create(info->addr, BT_CONN_LE_CREATE_CONN,
BT_LE_CONN_PARAM_DEFAULT, &g_conn);
if (err) {
FAIL("Could not connect to peer: %d", err);
return;
}
}
}
static struct bt_le_scan_cb scan_callbacks = {
.recv = scan_recv,
};
static void common_init(void)
{
int err = 0;
err = bt_enable(NULL);
if (err) {
FAIL("Bluetooth init failed: %d\n", err);
return;
}
bt_conn_cb_register(&conn_cbs);
bt_le_scan_cb_register(&scan_callbacks);
printk("Bluetooth initialized\n");
}
static void start_scan(void)
{
int err;
printk("Start scanning...");
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL);
if (err) {
FAIL("Failed to start scan: %d\n", err);
return;
}
printk("done.\n");
}
static void main_ext_adv_scanner(void)
{
common_init();
start_scan();
printk("Waiting for extended advertisements...\n");
WAIT_FOR_FLAG(flag_ext_adv_seen);
PASS("Extended adv scanner passed\n");
}
static void main_ext_adv_conn_scanner(void)
{
common_init();
start_scan();
printk("Waiting for extended advertisements...\n");
WAIT_FOR_FLAG(flag_ext_adv_seen);
printk("Waiting for connection with device...\n");
WAIT_FOR_FLAG(flag_connected);
printk("Waiting for device disconnection...\n");
WAIT_FOR_FLAG_UNSET(flag_connected);
printk("Waiting for Connection object to be recycled...\n");
WAIT_FOR_FLAG(flag_conn_recycled);
printk("Clearing flag for seen extended advertisements...\n");
UNSET_FLAG(flag_ext_adv_seen);
start_scan();
printk("Waiting to extended advertisements (again)...\n");
WAIT_FOR_FLAG(flag_ext_adv_seen);
PASS("Extended adv scanner passed\n");
}
static const struct bst_test_instance ext_adv_scanner[] = {
{
.test_id = "ext_adv_scanner",
.test_descr = "Basic extended advertising scanning test. "
"Will just scan an extended advertiser.",
.test_post_init_f = test_init,
.test_tick_f = test_tick,
.test_main_f = main_ext_adv_scanner
},
{
.test_id = "ext_adv_conn_scanner",
.test_descr = "Basic extended advertising scanning test. "
"Will just scan an extended advertiser.",
.test_post_init_f = test_init,
.test_tick_f = test_tick,
.test_main_f = main_ext_adv_conn_scanner
},
BSTEST_END_MARKER
};
struct bst_test_list *test_ext_adv_scanner(struct bst_test_list *tests)
{
return bst_add_tests(tests, ext_adv_scanner);
}

View file

@ -0,0 +1,39 @@
/**
* Copyright (c) 2024 Croxel, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include "bstests.h"
#include "common.h"
extern enum bst_result_t bst_result;
void test_tick(bs_time_t HW_device_time)
{
if (bst_result != Passed) {
FAIL("test failed (not passed after %i seconds)\n", WAIT_SECONDS);
}
}
void test_init(void)
{
bst_ticker_set_next_tick_absolute(WAIT_TIME);
bst_result = In_progress;
}
extern struct bst_test_list *test_ext_adv_advertiser(struct bst_test_list *tests);
extern struct bst_test_list *test_ext_adv_scanner(struct bst_test_list *tests);
bst_test_install_t test_installers[] = {
test_ext_adv_advertiser,
test_ext_adv_scanner,
NULL
};
int main(void)
{
bst_main();
return 0;
}

View file

@ -0,0 +1,29 @@
#!/usr/bin/env bash
# Copyright (c) 2024 Croxel, Inc.
# SPDX-License-Identifier: Apache-2.0
# Extended advertising test:
#
# - Broadcasting Only: a BLE broadcaster advertises with extended
# advertising, and a scanner scans the extended advertisement packets.
source ${ZEPHYR_BASE}/tests/bsim/sh_common.source
simulation_id="ext_adv"
verbosity_level=2
EXECUTE_TIMEOUT=10
cd ${BSIM_OUT_PATH}/bin
Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_adv_extended_prj_conf \
-v=${verbosity_level} -s=${simulation_id} -d=0 -RealEncryption=0 \
-testid=ext_adv_advertiser -rs=23
Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_adv_extended_prj_conf \
-v=${verbosity_level} -s=${simulation_id} -d=1 -RealEncryption=0 \
-testid=ext_adv_scanner -rs=6
Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \
-D=2 -sim_length=10e6 $@
wait_for_background_jobs

View file

@ -0,0 +1,31 @@
#!/usr/bin/env bash
# Copyright (c) 2024 Croxel, Inc.
# SPDX-License-Identifier: Apache-2.0
# Extended advertising test:
#
# - Connectable: In addition to broadcasting advertisements, it is connectable
# and restarts advertisements once disconnected. The scanner/central scans
# for the packets and establishes the connection, to then disconnect
# shortly-after.
source ${ZEPHYR_BASE}/tests/bsim/sh_common.source
simulation_id="ext_adv_conn"
verbosity_level=2
EXECUTE_TIMEOUT=10
cd ${BSIM_OUT_PATH}/bin
Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_adv_extended_prj_conf \
-v=${verbosity_level} -s=${simulation_id} -d=0 -RealEncryption=0 \
-testid=ext_adv_conn_advertiser -rs=23
Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_adv_extended_prj_conf \
-v=${verbosity_level} -s=${simulation_id} -d=1 -RealEncryption=0 \
-testid=ext_adv_conn_scanner -rs=6
Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \
-D=2 -sim_length=10e6 $@
wait_for_background_jobs

View file

@ -22,6 +22,7 @@ source ${ZEPHYR_BASE}/tests/bsim/compile.source
app=tests/bsim/bluetooth/host/adv/resume compile
app=tests/bsim/bluetooth/host/adv/resume conf_file=prj_2.conf compile
app=tests/bsim/bluetooth/host/adv/chain compile
app=tests/bsim/bluetooth/host/adv/extended compile
app=tests/bsim/bluetooth/host/adv/periodic compile
app=tests/bsim/bluetooth/host/adv/periodic conf_file=prj_long_data.conf compile
app=tests/bsim/bluetooth/host/adv/encrypted/css_sample_data compile