Bluetooth: Audio: Add tests for the CAP cancel command
This adds unittests and babblesim tests for the CAP cancel command Signed-off-by: Andries Kruithof <andries.kruithof@nordicsemi.no>
This commit is contained in:
parent
1115cd5698
commit
c9a9f0ab08
7 changed files with 365 additions and 4 deletions
|
|
@ -20,4 +20,5 @@ target_sources(testbinary
|
|||
src/test_micp.c
|
||||
src/test_broadcast_reception.c
|
||||
src/test_distribute_broadcast_code.c
|
||||
src/test_cancel.c
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef UUT_BAP_BROADCAST_ASSISTANT_H_
|
||||
#define UUT_BAP_BROADCAST_ASSISTANT_H_
|
||||
|
||||
void set_skip_add_src(unsigned int nr_to_skip);
|
||||
|
||||
#endif /* UUT_BAP_BROADCAST_ASSISTANT_H_ */
|
||||
|
|
@ -129,7 +129,7 @@ static void test_start_param_init(void *f)
|
|||
fixture->start_param.count = ARRAY_SIZE(fixture->start_member_params);
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(fixture->subgroups); i++) {
|
||||
fixture->subgroups[i].bis_sync = 1 << i;
|
||||
fixture->subgroups[i].bis_sync = BIT(i);
|
||||
fixture->subgroups[i].metadata_len = 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
179
tests/bluetooth/audio/cap_commander/src/test_cancel.c
Normal file
179
tests/bluetooth/audio/cap_commander/src/test_cancel.c
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
/* test_cancel.c - unit test for cancel command */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <zephyr/bluetooth/audio/cap.h>
|
||||
#include <zephyr/fff.h>
|
||||
|
||||
#include "bluetooth.h"
|
||||
#include "cap_commander.h"
|
||||
#include "conn.h"
|
||||
#include "expects_util.h"
|
||||
#include "cap_mocks.h"
|
||||
#include "test_common.h"
|
||||
#include "bap_broadcast_assistant.h"
|
||||
|
||||
#define FFF_GLOBALS
|
||||
|
||||
struct cap_commander_test_cancel_fixture {
|
||||
struct bt_conn conns[CONFIG_BT_MAX_CONN];
|
||||
|
||||
struct bt_bap_bass_subgroup subgroups[CONFIG_BT_BAP_BASS_MAX_SUBGROUPS];
|
||||
struct bt_cap_commander_broadcast_reception_start_member_param
|
||||
start_member_params[CONFIG_BT_MAX_CONN];
|
||||
struct bt_cap_commander_broadcast_reception_start_param start_param;
|
||||
};
|
||||
|
||||
static void test_start_param_init(void *f)
|
||||
{
|
||||
struct cap_commander_test_cancel_fixture *fixture = f;
|
||||
int err;
|
||||
|
||||
fixture->start_param.type = BT_CAP_SET_TYPE_AD_HOC;
|
||||
fixture->start_param.param = fixture->start_member_params;
|
||||
|
||||
fixture->start_param.count = ARRAY_SIZE(fixture->start_member_params);
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(fixture->subgroups); i++) {
|
||||
fixture->subgroups[i].bis_sync = BIT(i);
|
||||
fixture->subgroups[i].metadata_len = 0;
|
||||
}
|
||||
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(fixture->start_member_params); i++) {
|
||||
fixture->start_member_params[i].member.member = &fixture->conns[i];
|
||||
bt_addr_le_copy(&fixture->start_member_params[i].addr, BT_ADDR_LE_ANY);
|
||||
fixture->start_member_params[i].adv_sid = 0;
|
||||
fixture->start_member_params[i].pa_interval = 10;
|
||||
fixture->start_member_params[i].broadcast_id = 0;
|
||||
memcpy(fixture->start_member_params[i].subgroups, &fixture->subgroups[0],
|
||||
sizeof(struct bt_bap_bass_subgroup) * CONFIG_BT_BAP_BASS_MAX_SUBGROUPS);
|
||||
fixture->start_member_params[i].num_subgroups = CONFIG_BT_BAP_BASS_MAX_SUBGROUPS;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) {
|
||||
err = bt_cap_commander_discover(&fixture->conns[i]);
|
||||
zassert_equal(0, err, "Unexpected return value %d", err);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cap_commander_test_cancel_fixture_init(struct cap_commander_test_cancel_fixture *fixture)
|
||||
{
|
||||
for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) {
|
||||
test_conn_init(&fixture->conns[i]);
|
||||
}
|
||||
|
||||
test_start_param_init(fixture);
|
||||
}
|
||||
|
||||
static void *cap_commander_test_cancel_setup(void)
|
||||
{
|
||||
struct cap_commander_test_cancel_fixture *fixture;
|
||||
|
||||
fixture = malloc(sizeof(*fixture));
|
||||
zassert_not_null(fixture);
|
||||
|
||||
return fixture;
|
||||
}
|
||||
|
||||
static void cap_commander_test_cancel_before(void *f)
|
||||
{
|
||||
struct cap_commander_test_cancel_fixture *fixture = f;
|
||||
|
||||
memset(f, 0, sizeof(struct cap_commander_test_cancel_fixture));
|
||||
cap_commander_test_cancel_fixture_init(fixture);
|
||||
}
|
||||
|
||||
static void cap_commander_test_cancel_after(void *f)
|
||||
{
|
||||
struct cap_commander_test_cancel_fixture *fixture = f;
|
||||
|
||||
bt_cap_commander_unregister_cb(&mock_cap_commander_cb);
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(fixture->conns); i++) {
|
||||
mock_bt_conn_disconnected(&fixture->conns[i], BT_HCI_ERR_REMOTE_USER_TERM_CONN);
|
||||
}
|
||||
}
|
||||
|
||||
static void cap_commander_test_cancel_teardown(void *f)
|
||||
{
|
||||
free(f);
|
||||
}
|
||||
|
||||
static void test_cancel(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_cap_commander_cancel();
|
||||
zassert_equal(0, err, "Unexpected return value %d", err);
|
||||
|
||||
zexpect_call_count("bt_cap_commander_cb.broadcast_reception_start", 1,
|
||||
mock_cap_commander_broadcast_reception_start_cb_fake.call_count);
|
||||
zassert_equal(-ECANCELED,
|
||||
mock_cap_commander_broadcast_reception_start_cb_fake.arg1_history[0]);
|
||||
}
|
||||
|
||||
ZTEST_SUITE(cap_commander_test_cancel, NULL, cap_commander_test_cancel_setup,
|
||||
cap_commander_test_cancel_before, cap_commander_test_cancel_after,
|
||||
cap_commander_test_cancel_teardown);
|
||||
|
||||
ZTEST_F(cap_commander_test_cancel, test_commander_cancel)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (CONFIG_BT_MAX_CONN == 1) {
|
||||
ztest_test_skip();
|
||||
}
|
||||
|
||||
err = bt_cap_commander_register_cb(&mock_cap_commander_cb);
|
||||
zassert_equal(0, err, "Unexpected return value %d", err);
|
||||
|
||||
/* Do not run the add_src callback, so that the broadcast reception start procedure does not
|
||||
* run until completion
|
||||
*/
|
||||
set_skip_add_src(1);
|
||||
|
||||
/* initiate a CAP procedure; for this test we use broadcast reception start*/
|
||||
err = bt_cap_commander_broadcast_reception_start(&fixture->start_param);
|
||||
zassert_equal(0, err, "Could not start CAP procedure: %d", err);
|
||||
|
||||
test_cancel();
|
||||
}
|
||||
|
||||
ZTEST_F(cap_commander_test_cancel, test_commander_cancel_double)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (CONFIG_BT_MAX_CONN == 1) {
|
||||
ztest_test_skip();
|
||||
}
|
||||
|
||||
err = bt_cap_commander_register_cb(&mock_cap_commander_cb);
|
||||
zassert_equal(0, err, "Unexpected return value %d", err);
|
||||
|
||||
set_skip_add_src(1);
|
||||
err = bt_cap_commander_broadcast_reception_start(&fixture->start_param);
|
||||
zassert_equal(0, err, "Could not start CAP procedure: %d", err);
|
||||
|
||||
test_cancel();
|
||||
|
||||
err = bt_cap_commander_cancel();
|
||||
zassert_equal(-EALREADY, err, "Unexpected return value %d", err);
|
||||
}
|
||||
|
||||
ZTEST_F(cap_commander_test_cancel, test_commander_cancel_no_proc_in_progress)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_cap_commander_register_cb(&mock_cap_commander_cb);
|
||||
zassert_equal(0, err, "Unexpected return value %d", err);
|
||||
|
||||
err = bt_cap_commander_cancel();
|
||||
zassert_equal(-EALREADY, err, "Unexpected return value %d", err);
|
||||
}
|
||||
|
|
@ -7,8 +7,25 @@
|
|||
#include "zephyr/bluetooth/audio/bap.h"
|
||||
#include "test_common.h"
|
||||
|
||||
#include "bap_broadcast_assistant.h"
|
||||
|
||||
static sys_slist_t broadcast_assistant_cbs = SYS_SLIST_STATIC_INIT(&broadcast_assistant_cbs);
|
||||
|
||||
/* when > 0 immediately return from the add_src callback the specified number of times
|
||||
* This allows us to test the CAP cancel command by not successfully sending all the
|
||||
* requests, so that we can cancel before the CAP commander implementation is done
|
||||
* with the procedure.
|
||||
* This is based on the fact that we are not actually sending any requests on air, and
|
||||
* that we are using this function as a synchronous function, rather than an asynchronous
|
||||
* function.
|
||||
*/
|
||||
static unsigned int add_src_skip;
|
||||
|
||||
void set_skip_add_src(unsigned int setting)
|
||||
{
|
||||
add_src_skip = setting;
|
||||
}
|
||||
|
||||
struct bap_broadcast_assistant_recv_state_info {
|
||||
uint8_t src_id;
|
||||
/** Cached PAST available */
|
||||
|
|
@ -83,6 +100,12 @@ int bt_bap_broadcast_assistant_add_src(struct bt_conn *conn,
|
|||
struct bt_bap_scan_delegator_recv_state state;
|
||||
struct bt_bap_broadcast_assistant_cb *listener, *next;
|
||||
|
||||
if (add_src_skip != 0) {
|
||||
add_src_skip--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Note that proper parameter checking is done in the caller */
|
||||
zassert_not_null(conn, "conn is NULL");
|
||||
zassert_not_null(param, "param is NULL");
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ static struct k_sem sem_mics_discovered;
|
|||
static struct k_sem sem_bass_discovered;
|
||||
|
||||
CREATE_FLAG(flag_mtu_exchanged);
|
||||
CREATE_FLAG(flag_cap_canceled);
|
||||
CREATE_FLAG(flag_volume_changed);
|
||||
CREATE_FLAG(flag_volume_mute_changed);
|
||||
CREATE_FLAG(flag_volume_offset_changed);
|
||||
|
|
@ -104,6 +105,12 @@ static void cap_discovery_complete_cb(struct bt_conn *conn, int err,
|
|||
#if defined(CONFIG_BT_VCP_VOL_CTLR)
|
||||
static void cap_volume_changed_cb(struct bt_conn *conn, int err)
|
||||
{
|
||||
if (err == -ECANCELED) {
|
||||
printk("CAP command cancelled for conn %p\n", conn);
|
||||
SET_FLAG(flag_cap_canceled);
|
||||
return;
|
||||
}
|
||||
|
||||
if (err != 0) {
|
||||
FAIL("Failed to change volume for conn %p: %d\n", conn, err);
|
||||
return;
|
||||
|
|
@ -114,6 +121,12 @@ static void cap_volume_changed_cb(struct bt_conn *conn, int err)
|
|||
|
||||
static void cap_volume_mute_changed_cb(struct bt_conn *conn, int err)
|
||||
{
|
||||
if (err == -ECANCELED) {
|
||||
printk("CAP command cancelled for conn %p\n", conn);
|
||||
SET_FLAG(flag_cap_canceled);
|
||||
return;
|
||||
}
|
||||
|
||||
if (err != 0) {
|
||||
FAIL("Failed to change volume mute for conn %p: %d\n", conn, err);
|
||||
return;
|
||||
|
|
@ -125,6 +138,12 @@ static void cap_volume_mute_changed_cb(struct bt_conn *conn, int err)
|
|||
#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS)
|
||||
static void cap_volume_offset_changed_cb(struct bt_conn *conn, int err)
|
||||
{
|
||||
if (err == -ECANCELED) {
|
||||
printk("CAP command cancelled for conn %p\n", conn);
|
||||
SET_FLAG(flag_cap_canceled);
|
||||
return;
|
||||
}
|
||||
|
||||
if (err != 0) {
|
||||
FAIL("Failed to change volume offset for conn %p: %d\n", conn, err);
|
||||
return;
|
||||
|
|
@ -138,6 +157,12 @@ static void cap_volume_offset_changed_cb(struct bt_conn *conn, int err)
|
|||
#if defined(CONFIG_BT_MICP_MIC_CTLR)
|
||||
static void cap_microphone_mute_changed_cb(struct bt_conn *conn, int err)
|
||||
{
|
||||
if (err == -ECANCELED) {
|
||||
printk("CAP command cancelled for conn %p\n", conn);
|
||||
SET_FLAG(flag_cap_canceled);
|
||||
return;
|
||||
}
|
||||
|
||||
if (err != 0) {
|
||||
FAIL("Failed to change microphone mute for conn %p: %d\n", conn, err);
|
||||
return;
|
||||
|
|
@ -149,6 +174,12 @@ static void cap_microphone_mute_changed_cb(struct bt_conn *conn, int err)
|
|||
#if defined(CONFIG_BT_MICP_MIC_CTLR_AICS)
|
||||
static void cap_microphone_gain_changed_cb(struct bt_conn *conn, int err)
|
||||
{
|
||||
if (err == -ECANCELED) {
|
||||
printk("CAP command cancelled for conn %p\n", conn);
|
||||
SET_FLAG(flag_cap_canceled);
|
||||
return;
|
||||
}
|
||||
|
||||
if (err != 0) {
|
||||
FAIL("Failed to change microphone gain for conn %p: %d\n", conn, err);
|
||||
return;
|
||||
|
|
@ -162,6 +193,12 @@ static void cap_microphone_gain_changed_cb(struct bt_conn *conn, int err)
|
|||
#if defined(CONFIG_BT_BAP_BROADCAST_ASSISTANT)
|
||||
static void cap_broadcast_reception_start_cb(struct bt_conn *conn, int err)
|
||||
{
|
||||
if (err == -ECANCELED) {
|
||||
printk("CAP command cancelled for conn %p\n", conn);
|
||||
SET_FLAG(flag_cap_canceled);
|
||||
return;
|
||||
}
|
||||
|
||||
if (err != 0) {
|
||||
FAIL("Failed to perform broadcast reception start for conn %p: %d\n", conn, err);
|
||||
return;
|
||||
|
|
@ -172,6 +209,12 @@ static void cap_broadcast_reception_start_cb(struct bt_conn *conn, int err)
|
|||
|
||||
static void cap_broadcast_reception_stop_cb(struct bt_conn *conn, int err)
|
||||
{
|
||||
if (err == -ECANCELED) {
|
||||
printk("CAP command cancelled for conn %p\n", conn);
|
||||
SET_FLAG(flag_cap_canceled);
|
||||
return;
|
||||
}
|
||||
|
||||
if (err != 0) {
|
||||
FAIL("Failed to perform broadcast reception stop for conn %p: %d\n", conn, err);
|
||||
return;
|
||||
|
|
@ -631,6 +674,7 @@ static void init(size_t acceptor_cnt)
|
|||
k_sem_init(&sem_mics_discovered, 0, acceptor_cnt);
|
||||
|
||||
UNSET_FLAG(flag_mtu_exchanged);
|
||||
UNSET_FLAG(flag_cap_canceled);
|
||||
UNSET_FLAG(flag_volume_changed);
|
||||
UNSET_FLAG(flag_volume_mute_changed);
|
||||
UNSET_FLAG(flag_volume_offset_changed);
|
||||
|
|
@ -843,7 +887,7 @@ static void discover_mics(size_t acceptor_cnt)
|
|||
}
|
||||
}
|
||||
|
||||
static void test_change_volume(void)
|
||||
static void init_change_volume(void)
|
||||
{
|
||||
union bt_cap_set_member members[CONFIG_BT_MAX_CONN];
|
||||
const struct bt_cap_commander_change_volume_param param = {
|
||||
|
|
@ -855,7 +899,6 @@ static void test_change_volume(void)
|
|||
int err;
|
||||
|
||||
printk("Changing volume to %u\n", param.volume);
|
||||
UNSET_FLAG(flag_volume_changed);
|
||||
|
||||
for (size_t i = 0U; i < param.count; i++) {
|
||||
param.members[i].member = connected_conns[i];
|
||||
|
|
@ -866,9 +909,13 @@ static void test_change_volume(void)
|
|||
FAIL("Failed to change volume: %d\n", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_change_volume(void)
|
||||
{
|
||||
UNSET_FLAG(flag_volume_changed);
|
||||
init_change_volume();
|
||||
WAIT_FOR_FLAG(flag_volume_changed);
|
||||
printk("Volume changed to %u\n", param.volume);
|
||||
}
|
||||
|
||||
static void test_change_volume_mute(bool mute)
|
||||
|
|
@ -1078,6 +1125,18 @@ static void test_distribute_broadcast_code(size_t acceptor_count)
|
|||
bt_cap_commander_distribute_broadcast_code(&distribute_broadcast_code_param);
|
||||
}
|
||||
|
||||
static void test_cancel(bool cap_in_progress)
|
||||
{
|
||||
const int expected_err = cap_in_progress ? 0 : -EALREADY;
|
||||
int err;
|
||||
|
||||
err = bt_cap_commander_cancel();
|
||||
if (err != expected_err) {
|
||||
FAIL("Could not cancel CAP command: %d\n", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_main_cap_commander_capture_and_render(void)
|
||||
{
|
||||
const size_t acceptor_cnt = get_dev_cnt() - 1; /* Assume all other devices are acceptors
|
||||
|
|
@ -1169,6 +1228,51 @@ static void test_main_cap_commander_broadcast_reception(void)
|
|||
PASS("Broadcast reception passed\n");
|
||||
}
|
||||
|
||||
static void test_main_cap_commander_cancel(void)
|
||||
{
|
||||
size_t acceptor_count;
|
||||
|
||||
/* The test consists of N devices
|
||||
* 1 device is the broadcast source
|
||||
* 1 device is the CAP commander
|
||||
* This leaves N - 2 devices for the acceptor
|
||||
*/
|
||||
acceptor_count = get_dev_cnt() - 1;
|
||||
printk("Acceptor count: %d\n", acceptor_count);
|
||||
|
||||
init(acceptor_count);
|
||||
|
||||
for (size_t i = 0U; i < acceptor_count; i++) {
|
||||
scan_and_connect();
|
||||
|
||||
WAIT_FOR_FLAG(flag_mtu_exchanged);
|
||||
}
|
||||
|
||||
/* TODO: We should use CSIP to find set members */
|
||||
discover_cas(acceptor_count);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_CSIP_SET_COORDINATOR)) {
|
||||
if (IS_ENABLED(CONFIG_BT_VCP_VOL_CTLR)) {
|
||||
discover_vcs(acceptor_count);
|
||||
|
||||
init_change_volume();
|
||||
|
||||
test_cancel(true);
|
||||
WAIT_FOR_FLAG(flag_cap_canceled);
|
||||
}
|
||||
}
|
||||
|
||||
test_cancel(false);
|
||||
|
||||
/* Disconnect all CAP acceptors */
|
||||
disconnect_acl(acceptor_count);
|
||||
|
||||
/* restore the default callback */
|
||||
cap_cb.volume_changed = cap_volume_changed_cb;
|
||||
|
||||
PASS("Broadcast reception passed\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_cap_commander[] = {
|
||||
{
|
||||
.test_id = "cap_commander_capture_and_render",
|
||||
|
|
@ -1182,6 +1286,12 @@ static const struct bst_test_instance test_cap_commander[] = {
|
|||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_main_cap_commander_broadcast_reception,
|
||||
},
|
||||
{
|
||||
.test_id = "cap_commander_cancel",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_main_cap_commander_cancel,
|
||||
},
|
||||
BSTEST_END_MARKER,
|
||||
};
|
||||
|
||||
|
|
|
|||
36
tests/bsim/bluetooth/audio/test_scripts/cap_cancel.sh
Executable file
36
tests/bsim/bluetooth/audio/test_scripts/cap_cancel.sh
Executable file
|
|
@ -0,0 +1,36 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
SIMULATION_ID="cap_cancel"
|
||||
VERBOSITY_LEVEL=2
|
||||
NR_OF_DEVICES=3
|
||||
EXECUTE_TIMEOUT=180
|
||||
|
||||
source ${ZEPHYR_BASE}/tests/bsim/sh_common.source
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin
|
||||
|
||||
printf "\n\n======== Running CAP commander cancel test =========\n\n"
|
||||
|
||||
Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=cap_commander_cancel \
|
||||
-RealEncryption=1 -rs=46 -D=${NR_OF_DEVICES}
|
||||
|
||||
Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=cap_acceptor_capture_and_render \
|
||||
-RealEncryption=1 -rs=23 -D=${NR_OF_DEVICES}
|
||||
|
||||
Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=2 --testid=cap_acceptor_capture_and_render \
|
||||
-RealEncryption=1 -rs=69 -D=${NR_OF_DEVICES}
|
||||
|
||||
# Simulation time should be larger than the WAIT_TIME in common.h
|
||||
Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \
|
||||
-D=${NR_OF_DEVICES} -sim_length=60e6 $@
|
||||
|
||||
|
||||
|
||||
wait_for_background_jobs
|
||||
Loading…
Reference in a new issue