Skip to content

Commit 389192a

Browse files
jori-nordicnashif
authored andcommitted
tests: Bluetooth: Add common helpers for bsim
This code can be found (kinda) duplicated all over `tests/bsim/bluetooth`. Put it in a common place. Refactoring the current tests will be done in a future commit. Signed-off-by: Jonathan Rico <[email protected]>
1 parent 936598d commit 389192a

File tree

5 files changed

+296
-0
lines changed

5 files changed

+296
-0
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Copyright (c) 2024 Nordic Semiconductor ASA
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
# Helpers that can be used on bsim targets but don't have other
5+
# dependencies (e.g. on Bluetooth, etc).
6+
add_library(babblekit)
7+
8+
target_link_libraries(babblekit PUBLIC
9+
kernel
10+
zephyr_interface
11+
)
12+
13+
target_include_directories(babblekit PUBLIC
14+
include
15+
)
16+
17+
target_sources(babblekit PRIVATE
18+
src/sync.c
19+
)
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright (c) 2024 Nordic Semiconductor ASA
3+
*
4+
* Provides a way to set/clear and block on binary flags.
5+
*
6+
* These flags are often used to wait until the test has gotten in a particular
7+
* state, e.g. a connection is established or a message has been successfully
8+
* sent.
9+
*
10+
* These macros can only be called from Zephyr threads. They can't be called
11+
* from e.g. a bs_tests callback.
12+
*
13+
* SPDX-License-Identifier: Apache-2.0
14+
*/
15+
16+
#include <zephyr/sys/atomic.h>
17+
18+
/* Declare a flag that has been defined in another file */
19+
#define DECLARE_FLAG(flag) extern atomic_t flag
20+
21+
/* Define a new binary flag.
22+
* Declare them static if defining flags with the same name in multiple files.
23+
*
24+
* @param flag Name of the flag
25+
*/
26+
#define DEFINE_FLAG(flag) atomic_t flag = (atomic_t) false
27+
28+
#define SET_FLAG(flag) (void)atomic_set(&flag, (atomic_t) true)
29+
#define UNSET_FLAG(flag) (void)atomic_set(&flag, (atomic_t) false)
30+
31+
#define IS_FLAG_SET(flag) (atomic_get(&flag) != false)
32+
33+
/* Block until `flag` is equal to `val` */
34+
#define WAIT_FOR_VAL(var, val) \
35+
while (atomic_get(&var) != val) { \
36+
(void)k_sleep(K_MSEC(1)); \
37+
}
38+
39+
/* Block until `flag` is true */
40+
#define WAIT_FOR_FLAG(flag) \
41+
while (!(bool)atomic_get(&flag)) { \
42+
(void)k_sleep(K_MSEC(1)); \
43+
}
44+
45+
/* Block until `flag` is false */
46+
#define WAIT_FOR_FLAG_UNSET(flag) \
47+
while ((bool)atomic_get(&flag)) { \
48+
(void)k_sleep(K_MSEC(1)); \
49+
}
50+
51+
/* Block until `flag` is true and set it to false */
52+
#define TAKE_FLAG(flag) \
53+
while (!(bool)atomic_cas(&flag, true, false)) { \
54+
(void)k_sleep(K_MSEC(1)); \
55+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright (c) 2024 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* This file provides a synchronization mechanism between devices, for the
7+
* simple use-case when there are only two devices in the simulation.
8+
*/
9+
10+
11+
/*
12+
* @brief Initialize the sync library
13+
*
14+
* This initializes a simple synchronization library based on bsim backchannels.
15+
*
16+
* Calling `bk_sync_wait()` on device A will make it block until
17+
* `bk_sync_send()` is called on device B.
18+
*
19+
* @note Only works between two devices in a simulation, with IDs 0 and 1.
20+
*
21+
* @retval 0 Sync channel operational
22+
* @retval -1 Failed to open sync channel
23+
*
24+
*/
25+
int bk_sync_init(void);
26+
27+
/*
28+
* @brief Send a synchronization packet
29+
*
30+
* @note Only works between two devices in a simulation, with IDs 0 and 1.
31+
*
32+
*/
33+
void bk_sync_send(void);
34+
35+
/*
36+
* @brief Wait for a synchronization packet
37+
*
38+
* This blocks until the other device has called `bk_sync_send()`.
39+
*
40+
* @note Only works between two devices in a simulation, with IDs 0 and 1.
41+
*
42+
*/
43+
void bk_sync_wait(void);
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Copyright (c) 2024 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include "bs_tracing.h"
8+
#include "bs_types.h"
9+
#include "bstests.h"
10+
11+
extern enum bst_result_t bst_result;
12+
13+
/*
14+
* @brief Mark the test as in progress
15+
*
16+
* Call this at the start of the test entry point.
17+
*
18+
* @param ... format-string and arguments to print to console
19+
*
20+
*/
21+
#define TEST_START(msg, ...) \
22+
do { \
23+
bst_result = In_progress; \
24+
bs_trace_info_time(2, "Test start: " msg "\n", ##__VA_ARGS__); \
25+
} while (0)
26+
27+
/*
28+
* @brief Fail the test and exit
29+
*
30+
* Printf-like function that also terminates the device with an error code.
31+
*
32+
* @param ... format-string and arguments to print to console
33+
*
34+
*/
35+
#define TEST_FAIL(msg, ...) \
36+
do { \
37+
bst_result = Failed; \
38+
bs_trace_error_time_line(msg "\n", ##__VA_ARGS__); \
39+
} while (0)
40+
41+
/*
42+
* @brief Mark the currently-running test as "Passed"
43+
*
44+
* Mark the test as "passed". The execution continues after that point.
45+
*
46+
* @note Use this if you use backchannels (testlib/bsim/sync.h).
47+
*
48+
* After calling this, the executable will eventually return 0 when it exits.
49+
* Unless `TEST_FAIL` is called (e.g. in a callback).
50+
*
51+
* @param ... format-string and arguments to print to console
52+
*
53+
*/
54+
#define TEST_PASS(msg, ...) \
55+
do { \
56+
bst_result = Passed; \
57+
bs_trace_info_time(2, "Test end: " msg "\n", ##__VA_ARGS__); \
58+
} while (0)
59+
60+
/*
61+
* @brief Mark test case as passed and end execution
62+
*
63+
* Mark the role / test-case as "Passed" and return 0.
64+
*
65+
* @note DO NOT use this if you use backchannels (testlib/bsim/sync.h).
66+
*
67+
* @note This macro only ends execution for the current executable, not all
68+
* executables in a simulation.
69+
*
70+
* @param ... format-string and arguments to print to console
71+
*
72+
*/
73+
#define TEST_PASS_AND_EXIT(msg, ...) \
74+
do { \
75+
bst_result = Passed; \
76+
bs_trace_info_time(2, "Test end: " msg "\n", ##__VA_ARGS__); \
77+
bs_trace_silent_exit(0); \
78+
} while (0)
79+
80+
/*
81+
* @brief Assert `expr` is true
82+
*
83+
* Assert that `expr` is true. If assertion is false, print a printf-like
84+
* message to the console and fail the test. I.e. return non-zero.
85+
*
86+
* @note This is different than `sys/__assert.h`.
87+
*
88+
* @param message String to print to console
89+
*
90+
*/
91+
#define TEST_ASSERT(expr, ...) \
92+
do { \
93+
if (!(expr)) { \
94+
TEST_FAIL(__VA_ARGS__); \
95+
} \
96+
} while (0)
97+
98+
/*
99+
* @brief Print a value. Lower-level than `printk` or `LOG_xx`.
100+
*
101+
* Print a message to console.
102+
*
103+
* This can be safely called at any time in the execution of the device.
104+
* Use it to print when the logging subsystem is not available, e.g. early
105+
* startup or shutdown.
106+
*
107+
* @param ... format-string and arguments to print to console
108+
*
109+
*/
110+
#define TEST_PRINT(msg, ...) \
111+
bs_trace_print(BS_TRACE_INFO, __FILE__, __LINE__, 0, BS_TRACE_AUTOTIME, 0, \
112+
msg "\n", ##__VA_ARGS__)

tests/bsim/babblekit/src/sync.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright (c) 2024 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/kernel.h>
8+
#include <zephyr/sys/util.h>
9+
#include "argparse.h"
10+
#include "bs_types.h"
11+
#include "bs_tracing.h"
12+
#include "time_machine.h"
13+
#include "bs_pc_backchannel.h"
14+
15+
#include <zephyr/logging/log.h>
16+
LOG_MODULE_REGISTER(sync, CONFIG_LOG_DEFAULT_LEVEL);
17+
18+
#define CHANNEL_ID 0
19+
#define MSG_SIZE 1
20+
21+
int bk_sync_init(void)
22+
{
23+
uint device_number = get_device_nbr();
24+
uint peer_number = device_number ^ 1;
25+
uint device_numbers[] = { peer_number };
26+
uint channel_numbers[] = { CHANNEL_ID };
27+
uint *ch;
28+
29+
ch = bs_open_back_channel(device_number, device_numbers, channel_numbers,
30+
ARRAY_SIZE(channel_numbers));
31+
if (!ch) {
32+
return -1;
33+
}
34+
35+
LOG_DBG("Sync initialized");
36+
37+
return 0;
38+
}
39+
40+
void bk_sync_send(void)
41+
{
42+
uint8_t sync_msg[MSG_SIZE] = { get_device_nbr() };
43+
44+
LOG_DBG("Sending sync");
45+
bs_bc_send_msg(CHANNEL_ID, sync_msg, ARRAY_SIZE(sync_msg));
46+
}
47+
48+
void bk_sync_wait(void)
49+
{
50+
uint8_t sync_msg[MSG_SIZE];
51+
52+
LOG_DBG("Waiting for sync");
53+
54+
while (true) {
55+
if (bs_bc_is_msg_received(CHANNEL_ID) > 0) {
56+
bs_bc_receive_msg(CHANNEL_ID, sync_msg, ARRAY_SIZE(sync_msg));
57+
if (sync_msg[0] != get_device_nbr()) {
58+
/* Received a message from another device, exit */
59+
break;
60+
}
61+
}
62+
63+
k_sleep(K_MSEC(1));
64+
}
65+
66+
LOG_DBG("Sync received");
67+
}

0 commit comments

Comments
 (0)