Skip to content

Commit 6c95dab

Browse files
committed
tests: Bluetooth: bsim: Add test for auto connection parameter update
Add BabbleSim test to cover the automatic preferred peripheral connection parameter requests across multiple simultaneous connections. Signed-off-by: Vinayak Kariappa Chettimada <[email protected]>
1 parent 707604e commit 6c95dab

File tree

8 files changed

+431
-12
lines changed

8 files changed

+431
-12
lines changed

samples/bluetooth/central_multilink/src/central_multilink.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ static void start_scan(void);
3333

3434
static struct bt_conn *conn_connecting;
3535
static uint8_t volatile conn_count;
36+
static uint8_t volatile conn_param_count;
3637
static bool volatile is_disconnecting;
3738

3839
static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
@@ -215,6 +216,15 @@ static void le_param_updated(struct bt_conn *conn, uint16_t interval,
215216

216217
printk("LE conn param updated: %s int 0x%04x lat %d to %d\n",
217218
addr, interval, latency, timeout);
219+
220+
#if defined(CONFIG_TEST_BSIM_BT_CONN_PARAM)
221+
if ((interval >= CONFIG_BT_PERIPHERAL_PREF_MIN_INT) &&
222+
(interval <= CONFIG_BT_PERIPHERAL_PREF_MAX_INT) &&
223+
(latency == CONFIG_BT_PERIPHERAL_PREF_LATENCY) &&
224+
(timeout == CONFIG_BT_PERIPHERAL_PREF_TIMEOUT)) {
225+
conn_param_count++;
226+
}
227+
#endif /* CONFIG_TEST_BSIM_BT_CONN_PARAM */
218228
}
219229

220230
#if defined(CONFIG_BT_SMP)
@@ -316,6 +326,12 @@ int init_central(uint8_t iterations)
316326
k_sleep(K_MSEC(10));
317327
}
318328

329+
while (IS_ENABLED(CONFIG_TEST_BSIM_BT_CONN_PARAM) &&
330+
conn_param_count < CONFIG_BT_MAX_CONN) {
331+
k_sleep(K_MSEC(10));
332+
}
333+
conn_param_count = 0U;
334+
319335
k_sleep(K_SECONDS(60));
320336

321337
if (!iterations) {

samples/bluetooth/peripheral_identity/src/peripheral_identity.c

Lines changed: 167 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,7 @@
1212

1313
#include <zephyr/bluetooth/bluetooth.h>
1414
#include <zephyr/bluetooth/conn.h>
15-
16-
static struct k_work work_adv_start;
17-
static uint8_t volatile conn_count;
18-
static uint8_t id_current;
19-
static bool volatile is_disconnecting;
15+
#include <zephyr/bluetooth/gatt.h>
2016

2117
static const struct bt_data ad[] = {
2218
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
@@ -26,6 +22,116 @@ static const struct bt_data sd[] = {
2622
BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1),
2723
};
2824

25+
#if defined(CONFIG_BT_GATT_CLIENT)
26+
static void mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx)
27+
{
28+
printk("Updated MTU: TX: %d RX: %d bytes\n", tx, rx);
29+
}
30+
31+
static struct bt_gatt_cb gatt_callbacks = {
32+
.att_mtu_updated = mtu_updated
33+
};
34+
35+
static void mtu_exchange_cb(struct bt_conn *conn, uint8_t err,
36+
struct bt_gatt_exchange_params *params)
37+
{
38+
printk("%s: MTU exchange %s (%u)\n", __func__,
39+
err == 0U ? "successful" : "failed",
40+
bt_gatt_get_mtu(conn));
41+
}
42+
43+
static int mtu_exchange(struct bt_conn *conn)
44+
{
45+
static struct bt_gatt_exchange_params mtu_exchange_params;
46+
int err;
47+
48+
printk("%s: Current MTU = %u\n", __func__, bt_gatt_get_mtu(conn));
49+
50+
mtu_exchange_params.func = mtu_exchange_cb;
51+
52+
printk("%s: Exchange MTU...\n", __func__);
53+
err = bt_gatt_exchange_mtu(conn, &mtu_exchange_params);
54+
if (err) {
55+
printk("%s: MTU exchange failed (err %d)", __func__, err);
56+
}
57+
58+
return err;
59+
}
60+
61+
static uint32_t last_write_rate;
62+
63+
static void write_cmd_cb(struct bt_conn *conn, void *user_data)
64+
{
65+
static uint32_t cycle_stamp;
66+
static uint32_t write_count;
67+
static uint32_t write_rate;
68+
static uint32_t write_len;
69+
uint64_t delta;
70+
71+
delta = k_cycle_get_32() - cycle_stamp;
72+
delta = k_cyc_to_ns_floor64(delta);
73+
74+
if (delta == 0) {
75+
/* Skip division by zero */
76+
return;
77+
}
78+
79+
/* if last data rx-ed was greater than 1 second in the past,
80+
* reset the metrics.
81+
*/
82+
if (delta > (1U * NSEC_PER_SEC)) {
83+
printk("%s: count= %u, len= %u, rate= %u bps.\n", __func__,
84+
write_count, write_len, write_rate);
85+
86+
last_write_rate = write_rate;
87+
88+
write_count = 0U;
89+
write_len = 0U;
90+
write_rate = 0U;
91+
cycle_stamp = k_cycle_get_32();
92+
} else {
93+
uint16_t len;
94+
95+
write_count++;
96+
97+
/* Extract the 16-bit data length stored in user_data */
98+
len = (uint32_t)user_data & 0xFFFF;
99+
100+
write_len += len;
101+
write_rate = ((uint64_t)write_len << 3) * (1U * NSEC_PER_SEC) /
102+
delta;
103+
}
104+
}
105+
106+
int write_cmd(struct bt_conn *conn)
107+
{
108+
static uint8_t data[BT_ATT_MAX_ATTRIBUTE_LEN] = {0U, };
109+
static uint16_t data_len;
110+
int err;
111+
112+
data_len = bt_gatt_get_mtu(conn) - 3U;
113+
if (data_len > BT_ATT_MAX_ATTRIBUTE_LEN) {
114+
data_len = BT_ATT_MAX_ATTRIBUTE_LEN;
115+
}
116+
117+
/* Pass the 16-bit data length value (instead of reference) in
118+
* user_data so that unique value is pass for each write callback.
119+
* Using handle 0x0001, we do not care if it is writable, we just want
120+
* to transmit the data across.
121+
*/
122+
err = bt_gatt_write_without_response_cb(conn, 0x0001, data, data_len,
123+
false, write_cmd_cb,
124+
(void *)((uint32_t)data_len));
125+
if (err) {
126+
printk("%s: Write cmd failed (%d).\n", __func__, err);
127+
}
128+
129+
return err;
130+
}
131+
#endif /* CONFIG_BT_GATT_CLIENT */
132+
133+
static uint8_t id_current;
134+
29135
static void adv_start(struct k_work *work)
30136
{
31137
struct bt_le_adv_param adv_param = {
@@ -74,6 +180,10 @@ static void adv_start(struct k_work *work)
74180
printk("Advertising successfully started\n");
75181
}
76182

183+
static struct k_work work_adv_start;
184+
static uint8_t volatile conn_count;
185+
static struct bt_conn *conn_connected;
186+
77187
static void connected(struct bt_conn *conn, uint8_t err)
78188
{
79189
char addr[BT_ADDR_LE_STR_LEN];
@@ -91,8 +201,18 @@ static void connected(struct bt_conn *conn, uint8_t err)
91201
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
92202

93203
printk("Connected (%u): %s\n", conn_count, addr);
204+
205+
if (!conn_connected) {
206+
conn_connected = bt_conn_ref(conn);
207+
}
208+
209+
#if defined(CONFIG_BT_GATT_CLIENT)
210+
(void)mtu_exchange(conn);
211+
#endif /* CONFIG_BT_GATT_CLIENT */
94212
}
95213

214+
static bool volatile is_disconnecting;
215+
96216
static void disconnected(struct bt_conn *conn, uint8_t reason)
97217
{
98218
char addr[BT_ADDR_LE_STR_LEN];
@@ -101,6 +221,11 @@ static void disconnected(struct bt_conn *conn, uint8_t reason)
101221

102222
printk("Disconnected %s (reason 0x%02x)\n", addr, reason);
103223

224+
if (conn == conn_connected) {
225+
conn_connected = NULL;
226+
bt_conn_unref(conn);
227+
}
228+
104229
if ((conn_count == 1U) && is_disconnecting) {
105230
is_disconnecting = false;
106231
k_work_submit(&work_adv_start);
@@ -114,7 +239,7 @@ static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
114239

115240
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
116241

117-
printk("LE conn param req: %s int (0x%04x, 0x%04x) lat %d to %d\n",
242+
printk("LE conn param req: %s int (0x%04x, 0x%04x) lat %d to %d\n",
118243
addr, param->interval_min, param->interval_max, param->latency,
119244
param->timeout);
120245

@@ -208,8 +333,9 @@ static struct bt_conn_cb conn_callbacks = {
208333
#endif /* CONFIG_BT_USER_DATA_LEN_UPDATE */
209334
};
210335

211-
#if defined(CONFIG_BT_OBSERVER)
212-
#define BT_LE_SCAN_PASSIVE_ALLOW_DUPILCATES \
336+
#if defined(CONFIG_BT_OBSERVER) && \
337+
!defined(CONFIG_TEST_BSIM_BT_CONN_PARAM_OBSERVER_DISABLED)
338+
#define BT_LE_SCAN_PASSIVE_ALLOW_DUPLICATES \
213339
BT_LE_SCAN_PARAM(BT_LE_SCAN_TYPE_PASSIVE, \
214340
BT_LE_SCAN_OPT_NONE, \
215341
BT_GAP_SCAN_FAST_INTERVAL, \
@@ -223,7 +349,9 @@ static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
223349
bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
224350
printk("Device found: %s (RSSI %d)\n", addr_str, rssi);
225351
}
226-
#endif /* CONFIG_BT_OBSERVER */
352+
#endif /* CONFIG_BT_OBSERVER &&
353+
* !CONFIG_TEST_BSIM_BT_CONN_PARAM_OBSERVER_DISABLED
354+
*/
227355

228356
int init_peripheral(uint8_t iterations)
229357
{
@@ -242,18 +370,25 @@ int init_peripheral(uint8_t iterations)
242370
bt_conn_auth_cb_register(&auth_callbacks);
243371
#endif /* CONFIG_BT_SMP */
244372

373+
#if defined(CONFIG_BT_GATT_CLIENT)
374+
bt_gatt_cb_register(&gatt_callbacks);
375+
#endif /* CONFIG_BT_GATT_CLIENT */
376+
245377
printk("Bluetooth initialized\n");
246378

247-
#if defined(CONFIG_BT_OBSERVER)
379+
#if defined(CONFIG_BT_OBSERVER) && \
380+
!defined(CONFIG_TEST_BSIM_BT_CONN_PARAM_OBSERVER_DISABLED)
248381
printk("Start continuous passive scanning...");
249-
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE_ALLOW_DUPILCATES,
382+
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE_ALLOW_DUPLICATES,
250383
device_found);
251384
if (err) {
252385
printk("Scan start failed (%d).\n", err);
253386
return err;
254387
}
255388
printk("success.\n");
256-
#endif /* CONFIG_BT_OBSERVER */
389+
#endif /* CONFIG_BT_OBSERVER && \
390+
* !CONFIG_TEST_BSIM_BT_CONN_PARAM_OBSERVER_DISABLED
391+
*/
257392

258393
k_work_init(&work_adv_start, adv_start);
259394
k_work_submit(&work_adv_start);
@@ -284,6 +419,26 @@ int init_peripheral(uint8_t iterations)
284419
printk("Wait for disconnections...\n");
285420
is_disconnecting = true;
286421
while (is_disconnecting) {
422+
#if defined(CONFIG_BT_GATT_CLIENT)
423+
struct bt_conn *conn = NULL;
424+
425+
if (conn_connected) {
426+
/* Get a connection reference to ensure
427+
* that a reference is maintained in
428+
* case disconnected callback is called
429+
* while we perform GATT Write command.
430+
*/
431+
conn = bt_conn_ref(conn_connected);
432+
}
433+
434+
if (conn) {
435+
(void)write_cmd(conn);
436+
bt_conn_unref(conn);
437+
438+
continue;
439+
}
440+
#endif /* CONFIG_BT_GATT_CLIENT */
441+
287442
k_sleep(K_MSEC(10));
288443
}
289444
printk("All disconnected.\n");

tests/bsim/bluetooth/ll/compile.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,6 @@ app=tests/bsim/bluetooth/ll/edtt/gatt_test_app \
4242
app=tests/bsim/bluetooth/ll/multiple_id compile
4343
app=tests/bsim/bluetooth/ll/throughput compile
4444

45+
app=tests/bsim/bluetooth/ll/conn_param conf_file=prj-ll_sw_llcp_legacy.conf compile
46+
4547
wait_for_background_jobs
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
cmake_minimum_required(VERSION 3.20.0)
4+
5+
if (NOT DEFINED ENV{BSIM_COMPONENTS_PATH})
6+
message(FATAL_ERROR "This test requires the BabbleSim simulator. Please set \
7+
the environment variable BSIM_COMPONENTS_PATH to point to its \
8+
components folder. More information can be found in \
9+
https://babblesim.github.io/folder_structure_and_env.html")
10+
endif()
11+
12+
find_package(Zephyr HINTS $ENV{ZEPHYR_BASE})
13+
project(bsim_test_conn_param)
14+
15+
target_sources(app PRIVATE
16+
src/main.c
17+
${ZEPHYR_BASE}/samples/bluetooth/central_multilink/src/central_multilink.c
18+
${ZEPHYR_BASE}/samples/bluetooth/peripheral_identity/src/peripheral_identity.c
19+
)
20+
21+
zephyr_include_directories(
22+
$ENV{BSIM_COMPONENTS_PATH}/libUtilv1/src/
23+
$ENV{BSIM_COMPONENTS_PATH}/libPhyComv1/src/
24+
)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Copyright (c) 2022 Nordic Semiconductor ASA
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config TEST_BSIM_BT_CONN_PARAM
5+
bool "Test connection parameter requests on all connections"
6+
default y
7+
8+
config TEST_BSIM_BT_CONN_PARAM_OBSERVER_DISABLED
9+
bool "Disable Observer state simultaneous in Peripheral role"
10+
default y
11+
12+
menu "Zephyr Kernel"
13+
source "Kconfig.zephyr"
14+
endmenu

0 commit comments

Comments
 (0)