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 <jonathan.rico@nordicsemi.no>
This commit is contained in:
parent
936598ddf1
commit
389192a94d
5 changed files with 296 additions and 0 deletions
19
tests/bsim/babblekit/CMakeLists.txt
Normal file
19
tests/bsim/babblekit/CMakeLists.txt
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# Copyright (c) 2024 Nordic Semiconductor ASA
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
# Helpers that can be used on bsim targets but don't have other
|
||||||
|
# dependencies (e.g. on Bluetooth, etc).
|
||||||
|
add_library(babblekit)
|
||||||
|
|
||||||
|
target_link_libraries(babblekit PUBLIC
|
||||||
|
kernel
|
||||||
|
zephyr_interface
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(babblekit PUBLIC
|
||||||
|
include
|
||||||
|
)
|
||||||
|
|
||||||
|
target_sources(babblekit PRIVATE
|
||||||
|
src/sync.c
|
||||||
|
)
|
55
tests/bsim/babblekit/include/babblekit/flags.h
Normal file
55
tests/bsim/babblekit/include/babblekit/flags.h
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* Provides a way to set/clear and block on binary flags.
|
||||||
|
*
|
||||||
|
* These flags are often used to wait until the test has gotten in a particular
|
||||||
|
* state, e.g. a connection is established or a message has been successfully
|
||||||
|
* sent.
|
||||||
|
*
|
||||||
|
* These macros can only be called from Zephyr threads. They can't be called
|
||||||
|
* from e.g. a bs_tests callback.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/sys/atomic.h>
|
||||||
|
|
||||||
|
/* Declare a flag that has been defined in another file */
|
||||||
|
#define DECLARE_FLAG(flag) extern atomic_t flag
|
||||||
|
|
||||||
|
/* Define a new binary flag.
|
||||||
|
* Declare them static if defining flags with the same name in multiple files.
|
||||||
|
*
|
||||||
|
* @param flag Name of the flag
|
||||||
|
*/
|
||||||
|
#define DEFINE_FLAG(flag) 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 IS_FLAG_SET(flag) (atomic_get(&flag) != false)
|
||||||
|
|
||||||
|
/* Block until `flag` is equal to `val` */
|
||||||
|
#define WAIT_FOR_VAL(var, val) \
|
||||||
|
while (atomic_get(&var) != val) { \
|
||||||
|
(void)k_sleep(K_MSEC(1)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Block until `flag` is true */
|
||||||
|
#define WAIT_FOR_FLAG(flag) \
|
||||||
|
while (!(bool)atomic_get(&flag)) { \
|
||||||
|
(void)k_sleep(K_MSEC(1)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Block until `flag` is false */
|
||||||
|
#define WAIT_FOR_FLAG_UNSET(flag) \
|
||||||
|
while ((bool)atomic_get(&flag)) { \
|
||||||
|
(void)k_sleep(K_MSEC(1)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Block until `flag` is true and set it to false */
|
||||||
|
#define TAKE_FLAG(flag) \
|
||||||
|
while (!(bool)atomic_cas(&flag, true, false)) { \
|
||||||
|
(void)k_sleep(K_MSEC(1)); \
|
||||||
|
}
|
43
tests/bsim/babblekit/include/babblekit/sync.h
Normal file
43
tests/bsim/babblekit/include/babblekit/sync.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* This file provides a synchronization mechanism between devices, for the
|
||||||
|
* simple use-case when there are only two devices in the simulation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief Initialize the sync library
|
||||||
|
*
|
||||||
|
* This initializes a simple synchronization library based on bsim backchannels.
|
||||||
|
*
|
||||||
|
* Calling `bk_sync_wait()` on device A will make it block until
|
||||||
|
* `bk_sync_send()` is called on device B.
|
||||||
|
*
|
||||||
|
* @note Only works between two devices in a simulation, with IDs 0 and 1.
|
||||||
|
*
|
||||||
|
* @retval 0 Sync channel operational
|
||||||
|
* @retval -1 Failed to open sync channel
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int bk_sync_init(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief Send a synchronization packet
|
||||||
|
*
|
||||||
|
* @note Only works between two devices in a simulation, with IDs 0 and 1.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void bk_sync_send(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief Wait for a synchronization packet
|
||||||
|
*
|
||||||
|
* This blocks until the other device has called `bk_sync_send()`.
|
||||||
|
*
|
||||||
|
* @note Only works between two devices in a simulation, with IDs 0 and 1.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void bk_sync_wait(void);
|
112
tests/bsim/babblekit/include/babblekit/testcase.h
Normal file
112
tests/bsim/babblekit/include/babblekit/testcase.h
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "bs_tracing.h"
|
||||||
|
#include "bs_types.h"
|
||||||
|
#include "bstests.h"
|
||||||
|
|
||||||
|
extern enum bst_result_t bst_result;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief Mark the test as in progress
|
||||||
|
*
|
||||||
|
* Call this at the start of the test entry point.
|
||||||
|
*
|
||||||
|
* @param ... format-string and arguments to print to console
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define TEST_START(msg, ...) \
|
||||||
|
do { \
|
||||||
|
bst_result = In_progress; \
|
||||||
|
bs_trace_info_time(2, "Test start: " msg "\n", ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief Fail the test and exit
|
||||||
|
*
|
||||||
|
* Printf-like function that also terminates the device with an error code.
|
||||||
|
*
|
||||||
|
* @param ... format-string and arguments to print to console
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define TEST_FAIL(msg, ...) \
|
||||||
|
do { \
|
||||||
|
bst_result = Failed; \
|
||||||
|
bs_trace_error_time_line(msg "\n", ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief Mark the currently-running test as "Passed"
|
||||||
|
*
|
||||||
|
* Mark the test as "passed". The execution continues after that point.
|
||||||
|
*
|
||||||
|
* @note Use this if you use backchannels (testlib/bsim/sync.h).
|
||||||
|
*
|
||||||
|
* After calling this, the executable will eventually return 0 when it exits.
|
||||||
|
* Unless `TEST_FAIL` is called (e.g. in a callback).
|
||||||
|
*
|
||||||
|
* @param ... format-string and arguments to print to console
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define TEST_PASS(msg, ...) \
|
||||||
|
do { \
|
||||||
|
bst_result = Passed; \
|
||||||
|
bs_trace_info_time(2, "Test end: " msg "\n", ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief Mark test case as passed and end execution
|
||||||
|
*
|
||||||
|
* Mark the role / test-case as "Passed" and return 0.
|
||||||
|
*
|
||||||
|
* @note DO NOT use this if you use backchannels (testlib/bsim/sync.h).
|
||||||
|
*
|
||||||
|
* @note This macro only ends execution for the current executable, not all
|
||||||
|
* executables in a simulation.
|
||||||
|
*
|
||||||
|
* @param ... format-string and arguments to print to console
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define TEST_PASS_AND_EXIT(msg, ...) \
|
||||||
|
do { \
|
||||||
|
bst_result = Passed; \
|
||||||
|
bs_trace_info_time(2, "Test end: " msg "\n", ##__VA_ARGS__); \
|
||||||
|
bs_trace_silent_exit(0); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief Assert `expr` is true
|
||||||
|
*
|
||||||
|
* Assert that `expr` is true. If assertion is false, print a printf-like
|
||||||
|
* message to the console and fail the test. I.e. return non-zero.
|
||||||
|
*
|
||||||
|
* @note This is different than `sys/__assert.h`.
|
||||||
|
*
|
||||||
|
* @param message String to print to console
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define TEST_ASSERT(expr, ...) \
|
||||||
|
do { \
|
||||||
|
if (!(expr)) { \
|
||||||
|
TEST_FAIL(__VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief Print a value. Lower-level than `printk` or `LOG_xx`.
|
||||||
|
*
|
||||||
|
* Print a message to console.
|
||||||
|
*
|
||||||
|
* This can be safely called at any time in the execution of the device.
|
||||||
|
* Use it to print when the logging subsystem is not available, e.g. early
|
||||||
|
* startup or shutdown.
|
||||||
|
*
|
||||||
|
* @param ... format-string and arguments to print to console
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define TEST_PRINT(msg, ...) \
|
||||||
|
bs_trace_print(BS_TRACE_INFO, __FILE__, __LINE__, 0, BS_TRACE_AUTOTIME, 0, \
|
||||||
|
msg "\n", ##__VA_ARGS__)
|
67
tests/bsim/babblekit/src/sync.c
Normal file
67
tests/bsim/babblekit/src/sync.c
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/sys/util.h>
|
||||||
|
#include "argparse.h"
|
||||||
|
#include "bs_types.h"
|
||||||
|
#include "bs_tracing.h"
|
||||||
|
#include "time_machine.h"
|
||||||
|
#include "bs_pc_backchannel.h"
|
||||||
|
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
LOG_MODULE_REGISTER(sync, CONFIG_LOG_DEFAULT_LEVEL);
|
||||||
|
|
||||||
|
#define CHANNEL_ID 0
|
||||||
|
#define MSG_SIZE 1
|
||||||
|
|
||||||
|
int bk_sync_init(void)
|
||||||
|
{
|
||||||
|
uint device_number = get_device_nbr();
|
||||||
|
uint peer_number = device_number ^ 1;
|
||||||
|
uint device_numbers[] = { peer_number };
|
||||||
|
uint channel_numbers[] = { CHANNEL_ID };
|
||||||
|
uint *ch;
|
||||||
|
|
||||||
|
ch = bs_open_back_channel(device_number, device_numbers, channel_numbers,
|
||||||
|
ARRAY_SIZE(channel_numbers));
|
||||||
|
if (!ch) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DBG("Sync initialized");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bk_sync_send(void)
|
||||||
|
{
|
||||||
|
uint8_t sync_msg[MSG_SIZE] = { get_device_nbr() };
|
||||||
|
|
||||||
|
LOG_DBG("Sending sync");
|
||||||
|
bs_bc_send_msg(CHANNEL_ID, sync_msg, ARRAY_SIZE(sync_msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
void bk_sync_wait(void)
|
||||||
|
{
|
||||||
|
uint8_t sync_msg[MSG_SIZE];
|
||||||
|
|
||||||
|
LOG_DBG("Waiting for sync");
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (bs_bc_is_msg_received(CHANNEL_ID) > 0) {
|
||||||
|
bs_bc_receive_msg(CHANNEL_ID, sync_msg, ARRAY_SIZE(sync_msg));
|
||||||
|
if (sync_msg[0] != get_device_nbr()) {
|
||||||
|
/* Received a message from another device, exit */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
k_sleep(K_MSEC(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DBG("Sync received");
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue