tests bsim: Change folder structure
Bsim won't be limited anymore to BT tests. In preparation for adding more tests in network areas swap the tests/bluetooth/bsim with tests/bsim/bluetooth There is no other changes in this commit beyond that. Signed-off-by: Alberto Escolar Piedras <alberto.escolar.piedras@nordicsemi.no>
This commit is contained in:
parent
388d522c32
commit
f27c0b4905
500 changed files with 222 additions and 222 deletions
15
tests/bsim/bluetooth/README.txt
Normal file
15
tests/bsim/bluetooth/README.txt
Normal file
|
@ -0,0 +1,15 @@
|
|||
This folder contains tests meant to be run with BabbleSim's physical layer
|
||||
simulation, and therefore cannot be run directly from twister
|
||||
|
||||
The compile.sh and run_parallel.sh scripts are used by the CI system to build
|
||||
the needed images and execute these tests in batch.
|
||||
|
||||
You can also run them manually if desired, but be sure to call them setting
|
||||
the variables they expect. For example, from Zephyr's root folder, you can run:
|
||||
|
||||
WORK_DIR=${ZEPHYR_BASE}/bsim_bt_out tests/bsim/bluetooth/compile.sh
|
||||
RESULTS_FILE=${ZEPHYR_BASE}/myresults.xml SEARCH_PATH=tests/bsim/bluetooth tests/bsim/bluetooth/run_parallel.sh
|
||||
|
||||
Or to run only a specific subset, e.g. host advertising tests:
|
||||
WORK_DIR=${ZEPHYR_BASE}/bsim_bt_out tests/bsim/bluetooth/host/compile.sh
|
||||
RESULTS_FILE=${ZEPHYR_BASE}/myresults.xml SEARCH_PATH=tests/bsim/bluetooth/host/adv tests/bsim/bluetooth/run_parallel.sh
|
91
tests/bsim/bluetooth/_compile_permutate_kconfigs.sh
Executable file
91
tests/bsim/bluetooth/_compile_permutate_kconfigs.sh
Executable file
|
@ -0,0 +1,91 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright 2018 Oticon A/S
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Compile with all permutations of a given set of KConfigs
|
||||
# Specifically for going through possible combinations of
|
||||
# optional control procedures
|
||||
|
||||
#set -x #uncomment this line for debugging
|
||||
# set DEBUG_PERMUTATE to 'true' for extra debug output
|
||||
DEBUG_PERMUTATE=false
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
: "${BSIM_COMPONENTS_PATH:?BSIM_COMPONENTS_PATH must be defined}"
|
||||
: "${ZEPHYR_BASE:?ZEPHYR_BASE must be set to point to the zephyr root\
|
||||
directory}"
|
||||
|
||||
WORK_DIR="${WORK_DIR:-${ZEPHYR_BASE}/bsim_bt_out}"
|
||||
BOARD="${BOARD:-nrf52_bsim}"
|
||||
BOARD_ROOT="${BOARD_ROOT:-${ZEPHYR_BASE}}"
|
||||
|
||||
mkdir -p ${WORK_DIR}
|
||||
|
||||
source ${ZEPHYR_BASE}/tests/bsim/bluetooth/compile.source
|
||||
|
||||
|
||||
declare -a list=(
|
||||
"CONFIG_BT_CENTRAL="
|
||||
"CONFIG_BT_PERIPHERAL="
|
||||
"CONFIG_BT_CTLR_PER_INIT_FEAT_XCHG="
|
||||
"CONFIG_BT_DATA_LEN_UPDATE="
|
||||
"CONFIG_BT_PHY_UPDATE="
|
||||
"CONFIG_BT_CTLR_MIN_USED_CHAN="
|
||||
"CONFIG_BT_CTLR_LE_PING="
|
||||
"CONFIG_BT_CTLR_LE_ENC="
|
||||
"CONFIG_BT_CTLR_CONN_PARAM_REQ="
|
||||
)
|
||||
|
||||
perm_compile() {
|
||||
local -a results=()
|
||||
# We set a unique exe-name, so that we don't overwrite the executables
|
||||
# created by the compile scripts since that may mess up other tests
|
||||
# We also delete the executable to avoid having artifacts from
|
||||
# a previous run
|
||||
local exe_name="bs_nrf52_bsim_tests_kconfig_perm"
|
||||
local executable_name=${exe_name}
|
||||
local executable_name=${BSIM_OUT_PATH}/bin/$executable_name
|
||||
|
||||
rm -f ${executable_name}
|
||||
|
||||
let idx=$2
|
||||
for (( j = 0; j < $1; j++ )); do
|
||||
if (( idx % 2 )); then
|
||||
results=("${results[@]}" "${list[$j]}n")
|
||||
else
|
||||
results=("${results[@]}" "${list[$j]}y")
|
||||
fi
|
||||
let idx\>\>=1
|
||||
done
|
||||
printf '%s\n' "${results[@]}" > $3
|
||||
if test "$DEBUG_PERMUTATE" = "true"; then
|
||||
echo "Compile with config overlay:"
|
||||
cat $3
|
||||
fi
|
||||
local app=tests/bsim/bluetooth/edtt_ble_test_app/hci_test_app
|
||||
local conf_file=prj_dut_llcp.conf
|
||||
local conf_overlay=$3
|
||||
compile
|
||||
if [ ! -f ${executable_name} ]; then
|
||||
compile_failures=$(expr $compile_failures + 1)
|
||||
fi
|
||||
}
|
||||
let n=${#list[@]}
|
||||
temp_conf_file=$(mktemp -p ${WORK_DIR})
|
||||
# compile_failures will be equal to the number of failed compilations
|
||||
let compile_failures=0
|
||||
|
||||
for (( i = 0; i < 2**n; i++ )); do
|
||||
## don't compile for CENTRAL=n AND PERIPHERAL=n
|
||||
if (( (i & 0x3) != 0x3 )); then
|
||||
perm_compile $n $i ${temp_conf_file}
|
||||
fi
|
||||
done
|
||||
|
||||
# We set exit code based on type of failure
|
||||
# 0 means all configurations compiled w/o error
|
||||
|
||||
trap "{ rm "${temp_conf_file}" ; exit 255; }" SIGINT
|
||||
trap "{ rm "${temp_conf_file}" ; exit 254; }" SIGTERM
|
||||
trap "{ rm "${temp_conf_file}" ; exit 253; }" ERR
|
||||
trap "{ rm "${temp_conf_file}" ; exit ${compile_failures}; }" EXIT
|
22
tests/bsim/bluetooth/audio/CMakeLists.txt
Normal file
22
tests/bsim/bluetooth/audio/CMakeLists.txt
Normal file
|
@ -0,0 +1,22 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
if (NOT DEFINED ENV{BSIM_COMPONENTS_PATH})
|
||||
message(FATAL_ERROR "This test requires the BabbleSim simulator. Please set\
|
||||
the environment variable BSIM_COMPONENTS_PATH to point to its components \
|
||||
folder. More information can be found in\
|
||||
https://babblesim.github.io/folder_structure_and_env.html")
|
||||
endif()
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(bsim_test_audio)
|
||||
|
||||
FILE(GLOB app_sources src/*.c)
|
||||
target_sources(app PRIVATE ${app_sources} )
|
||||
|
||||
zephyr_include_directories(
|
||||
$ENV{BSIM_COMPONENTS_PATH}/libUtilv1/src/
|
||||
$ENV{BSIM_COMPONENTS_PATH}/libPhyComv1/src/
|
||||
${ZEPHYR_BASE}/subsys/bluetooth/host/audio/
|
||||
)
|
14
tests/bsim/bluetooth/audio/Kconfig
Normal file
14
tests/bsim/bluetooth/audio/Kconfig
Normal file
|
@ -0,0 +1,14 @@
|
|||
# Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Workaround for pretending that the controller
|
||||
# supports CIS as the host expects the controller
|
||||
# to support these features.
|
||||
|
||||
config BT_LL_SW_SPLIT
|
||||
select BT_CTLR_SYNC_TRANSFER_RECEIVER_SUPPORT
|
||||
select BT_CTLR_SYNC_TRANSFER_SENDER_SUPPORT
|
||||
|
||||
menu "Zephyr Kernel"
|
||||
source "Kconfig.zephyr"
|
||||
endmenu
|
5
tests/bsim/bluetooth/audio/README.txt
Normal file
5
tests/bsim/bluetooth/audio/README.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
Zephyr test application which uses the simulated boards test hooks.
|
||||
Can be compiled targeting the *_bsim boards.
|
||||
|
||||
This application will, based on the command line arguments, select one of
|
||||
testcases which are compiled with it.
|
25
tests/bsim/bluetooth/audio/compile.sh
Executable file
25
tests/bsim/bluetooth/audio/compile.sh
Executable file
|
@ -0,0 +1,25 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright 2023 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Compile all the applications needed by the bsim tests
|
||||
|
||||
#set -x #uncomment this line for debugging
|
||||
set -ue
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
: "${BSIM_COMPONENTS_PATH:?BSIM_COMPONENTS_PATH must be defined}"
|
||||
: "${ZEPHYR_BASE:?ZEPHYR_BASE must be set to point to the zephyr root\
|
||||
directory}"
|
||||
|
||||
WORK_DIR="${WORK_DIR:-${ZEPHYR_BASE}/bsim_out}"
|
||||
BOARD="${BOARD:-nrf52_bsim}"
|
||||
BOARD_ROOT="${BOARD_ROOT:-${ZEPHYR_BASE}}"
|
||||
|
||||
mkdir -p ${WORK_DIR}
|
||||
|
||||
source ${ZEPHYR_BASE}/tests/bsim/bluetooth/compile.source
|
||||
|
||||
app=tests/bsim/bluetooth/audio compile
|
||||
|
||||
wait_for_background_jobs
|
169
tests/bsim/bluetooth/audio/prj.conf
Normal file
169
tests/bsim/bluetooth/audio/prj.conf
Normal file
|
@ -0,0 +1,169 @@
|
|||
CONFIG_TEST=y
|
||||
CONFIG_BT_TESTING=y
|
||||
CONFIG_CONSOLE_HANDLER=y
|
||||
CONFIG_USERSPACE=n
|
||||
CONFIG_NO_OPTIMIZATIONS=y
|
||||
|
||||
CONFIG_BT=y
|
||||
CONFIG_BT_CENTRAL=y
|
||||
CONFIG_BT_PERIPHERAL=y
|
||||
CONFIG_BT_DEVICE_NAME="bsim_test_audio"
|
||||
CONFIG_BT_L2CAP_TX_BUF_COUNT=20
|
||||
CONFIG_BT_MAX_CONN=5
|
||||
CONFIG_BT_MAX_PAIRED=5
|
||||
CONFIG_BT_GATT_DYNAMIC_DB=y
|
||||
CONFIG_BT_SMP=y
|
||||
|
||||
# Needed for extended advertising
|
||||
CONFIG_BT_EXT_ADV_LEGACY_SUPPORT=y
|
||||
|
||||
CONFIG_BT_AUDIO=y
|
||||
CONFIG_BT_BAP_UNICAST_SERVER=y
|
||||
CONFIG_BT_BAP_UNICAST_CLIENT=y
|
||||
CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT=2
|
||||
CONFIG_BT_BAP_BROADCAST_SOURCE=y
|
||||
CONFIG_BT_BAP_BROADCAST_SINK=y
|
||||
# Only 1 stream support by controller at this point
|
||||
CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT=1
|
||||
CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT=1
|
||||
# Only 1 stream support by controller at this point
|
||||
CONFIG_BT_BAP_BROADCAST_SNK_SUBGROUP_COUNT=1
|
||||
CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT=1
|
||||
CONFIG_BT_ISO_TX_BUF_COUNT=4
|
||||
CONFIG_BT_ISO_MAX_CHAN=2
|
||||
|
||||
# Needed for Periodic Advertising Sync Transfer
|
||||
CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER=y
|
||||
CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER=y
|
||||
|
||||
# Volume Offset Control Service
|
||||
CONFIG_BT_VOCS_MAX_INSTANCE_COUNT=2
|
||||
CONFIG_BT_VOCS_CLIENT_MAX_INSTANCE_COUNT=2
|
||||
|
||||
# Audio Input Control Service
|
||||
CONFIG_BT_AICS_MAX_INSTANCE_COUNT=4
|
||||
CONFIG_BT_AICS_CLIENT_MAX_INSTANCE_COUNT=4
|
||||
|
||||
#Volume Control
|
||||
CONFIG_BT_VCP_VOL_REND=y
|
||||
CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT=2
|
||||
CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT=2
|
||||
CONFIG_BT_VCP_VOL_CTLR=y
|
||||
CONFIG_BT_VCP_VOL_CTLR_MAX_VOCS_INST=2
|
||||
CONFIG_BT_VCP_VOL_CTLR_MAX_AICS_INST=2
|
||||
|
||||
CONFIG_BT_MICP_MIC_DEV=y
|
||||
CONFIG_BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT=2
|
||||
CONFIG_BT_MICP_MIC_CTLR=y
|
||||
CONFIG_BT_MICP_MIC_CTLR_MAX_AICS_INST=2
|
||||
|
||||
# Coordinated Set Identification
|
||||
CONFIG_BT_CSIP_SET_MEMBER=y
|
||||
CONFIG_BT_CSIP_SET_MEMBER_TEST_SAMPLE_DATA=y
|
||||
CONFIG_BT_CSIP_SET_COORDINATOR=y
|
||||
CONFIG_BT_CSIP_SET_COORDINATOR_TEST_SAMPLE_DATA=y
|
||||
|
||||
# Telephone bearer service
|
||||
CONFIG_BT_TBS=y
|
||||
CONFIG_BT_TBS_CLIENT=y
|
||||
|
||||
# Media control
|
||||
CONFIG_MCTL=y
|
||||
CONFIG_MCTL_LOCAL_PLAYER_CONTROL=y
|
||||
CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL=y
|
||||
CONFIG_MCTL_LOCAL_PLAYER_REMOTE_CONTROL=y
|
||||
CONFIG_MCTL_REMOTE_PLAYER_CONTROL=y
|
||||
CONFIG_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS=y
|
||||
CONFIG_UTF8=y
|
||||
|
||||
# Media player
|
||||
CONFIG_BT_MPL=y
|
||||
CONFIG_BT_MPL_OBJECTS=y
|
||||
CONFIG_BT_MPL_MAX_OBJ_SIZE=600
|
||||
|
||||
# Media control
|
||||
CONFIG_BT_MCS=y
|
||||
CONFIG_BT_MCC=y
|
||||
CONFIG_BT_MCC_OTS=y
|
||||
CONFIG_BT_MCC_SHELL=y
|
||||
CONFIG_BT_MCC_TOTAL_OBJ_CONTENT_MEM=4096
|
||||
|
||||
# Immediate Alert
|
||||
CONFIG_BT_IAS=y
|
||||
CONFIG_BT_IAS_CLIENT=y
|
||||
|
||||
# Object Transfer
|
||||
CONFIG_BT_OTS=y
|
||||
CONFIG_BT_OTS_SECONDARY_SVC=y
|
||||
CONFIG_BT_OTS_MAX_OBJ_CNT=0x30
|
||||
CONFIG_BT_OTS_CLIENT=y
|
||||
|
||||
# Broadcast Audio Scan Service and client
|
||||
CONFIG_BT_BAP_SCAN_DELEGATOR=y
|
||||
CONFIG_BT_BAP_BROADCAST_ASSISTANT=y
|
||||
|
||||
# Hearing Access
|
||||
CONFIG_BT_HAS=y
|
||||
CONFIG_BT_HAS_CLIENT=y
|
||||
|
||||
# Common Audio Profile
|
||||
CONFIG_BT_CAP_ACCEPTOR=y
|
||||
CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER=y
|
||||
CONFIG_BT_CAP_INITIATOR=y
|
||||
|
||||
# DEBUGGING
|
||||
CONFIG_BT_DEBUG_LOG=y
|
||||
CONFIG_BT_VCP_VOL_REND_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_VCP_VOL_CTLR_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_AICS_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_AICS_CLIENT_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_VOCS_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_VOCS_CLIENT_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_MICP_MIC_DEV_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_MICP_MIC_CTLR_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_MPL_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_TBS_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_TBS_CLIENT_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_MCS_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_MCC_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_OTS_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_OTS_CLIENT_LOG_LEVEL_DBG=y
|
||||
CONFIG_MCTL_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_CSIP_SET_MEMBER_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_CSIP_SET_COORDINATOR_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_CSIP_SET_MEMBER_CRYPTO_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_BAP_UNICAST_CLIENT_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_BAP_UNICAST_SERVER_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_BAP_BROADCAST_SINK_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_BAP_BROADCAST_SOURCE_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_ASCS_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_PACS_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_BAP_STREAM_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_BAP_ISO_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_AUDIO_CODEC_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_BAP_SCAN_DELEGATOR_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_BAP_BROADCAST_ASSISTANT_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_HAS_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_HAS_CLIENT_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_CAP_ACCEPTOR_LOG_LEVEL_DBG=y
|
||||
CONFIG_BT_DEBUG_CAP_INITIATOR=y
|
||||
|
||||
# LOGGING
|
||||
CONFIG_TEST_LOGGING_DEFAULTS=n
|
||||
CONFIG_LOG_MODE_IMMEDIATE=y
|
||||
|
||||
# Controller Broadcast ISO configs
|
||||
CONFIG_BT_CTLR_ADV_ISO=y
|
||||
CONFIG_BT_CTLR_SYNC_ISO=y
|
||||
CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX=255
|
||||
# Supports the highest SDU size required by any BAP LC3 presets (155)
|
||||
CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=155
|
||||
CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=191
|
||||
CONFIG_BT_CTLR_ADV_ISO_STREAM_COUNT=1
|
||||
CONFIG_BT_CTLR_SYNC_ISO_STREAM_MAX=1
|
||||
|
||||
# Controller Connected ISO configs
|
||||
CONFIG_BT_CTLR_CENTRAL_ISO=y
|
||||
CONFIG_BT_CTLR_PERIPHERAL_ISO=y
|
||||
|
||||
CONFIG_BT_CTLR_ISO_TX_BUFFERS=3
|
492
tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c
Normal file
492
tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c
Normal file
|
@ -0,0 +1,492 @@
|
|||
/*
|
||||
* Copyright (c) 2021-2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_BT_BAP_BROADCAST_ASSISTANT
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/hci.h>
|
||||
#include <zephyr/bluetooth/audio/bap.h>
|
||||
#include "../../../../../subsys/bluetooth/host/hci_core.h"
|
||||
#include "common.h"
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
|
||||
/* BASS variables */
|
||||
static volatile bool g_mtu_exchanged;
|
||||
static volatile bool g_discovery_complete;
|
||||
static volatile bool g_write_complete;
|
||||
static volatile bool g_cb;
|
||||
static volatile bool g_broadcaster_found;
|
||||
static volatile bool g_pa_synced;
|
||||
static volatile bool g_state_synced;
|
||||
static volatile uint8_t g_src_id;
|
||||
static volatile uint32_t g_broadcast_id;
|
||||
|
||||
static volatile bool g_cb;
|
||||
|
||||
/* Broadcaster variables */
|
||||
static bt_addr_le_t g_broadcaster_addr;
|
||||
static struct bt_le_scan_recv_info g_broadcaster_info;
|
||||
static struct bt_le_per_adv_sync *g_pa_sync;
|
||||
|
||||
static const char *phy2str(uint8_t phy)
|
||||
{
|
||||
switch (phy) {
|
||||
case 0: return "No packets";
|
||||
case BT_GAP_LE_PHY_1M: return "LE 1M";
|
||||
case BT_GAP_LE_PHY_2M: return "LE 2M";
|
||||
case BT_GAP_LE_PHY_CODED: return "LE Coded";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static void bap_broadcast_assistant_discover_cb(struct bt_conn *conn, int err,
|
||||
uint8_t recv_state_count)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("BASS discover failed (%d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("BASS discover done with %u recv states\n", recv_state_count);
|
||||
g_discovery_complete = true;
|
||||
}
|
||||
|
||||
static void bap_broadcast_assistant_scan_cb(const struct bt_le_scan_recv_info *info,
|
||||
uint32_t broadcast_id)
|
||||
{
|
||||
char le_addr[BT_ADDR_LE_STR_LEN];
|
||||
|
||||
bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
|
||||
printk("Scan Recv: [DEVICE]: %s, broadcast_id %u, "
|
||||
"interval (ms) %u), SID 0x%x, RSSI %i\n",
|
||||
le_addr, broadcast_id, info->interval * 5 / 4,
|
||||
info->sid, info->rssi);
|
||||
|
||||
(void)memcpy(&g_broadcaster_info, info, sizeof(g_broadcaster_info));
|
||||
bt_addr_le_copy(&g_broadcaster_addr, info->addr);
|
||||
g_broadcast_id = broadcast_id;
|
||||
g_broadcaster_found = true;
|
||||
}
|
||||
|
||||
static bool metadata_entry(struct bt_data *data, void *user_data)
|
||||
{
|
||||
char metadata[512];
|
||||
|
||||
(void)bin2hex(data->data, data->data_len, metadata, sizeof(metadata));
|
||||
|
||||
printk("\t\tMetadata length %u, type %u, data: %s\n",
|
||||
data->data_len, data->type, metadata);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void bap_broadcast_assistant_recv_state_cb(
|
||||
struct bt_conn *conn, int err,
|
||||
const struct bt_bap_scan_delegator_recv_state *state)
|
||||
{
|
||||
char le_addr[BT_ADDR_LE_STR_LEN];
|
||||
char bad_code[33];
|
||||
|
||||
if (err != 0) {
|
||||
FAIL("BASS recv state read failed (%d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
bt_addr_le_to_str(&state->addr, le_addr, sizeof(le_addr));
|
||||
(void)bin2hex(state->bad_code, BT_AUDIO_BROADCAST_CODE_SIZE, bad_code,
|
||||
sizeof(bad_code));
|
||||
printk("BASS recv state: src_id %u, addr %s, sid %u, sync_state %u, "
|
||||
"encrypt_state %u%s%s\n", state->src_id, le_addr, state->adv_sid,
|
||||
state->pa_sync_state, state->encrypt_state,
|
||||
state->encrypt_state == BT_BAP_BIG_ENC_STATE_BAD_CODE ? ", bad code" : "",
|
||||
bad_code);
|
||||
|
||||
for (int i = 0; i < state->num_subgroups; i++) {
|
||||
const struct bt_bap_scan_delegator_subgroup *subgroup = &state->subgroups[i];
|
||||
struct net_buf_simple buf;
|
||||
|
||||
printk("\t[%d]: BIS sync %u, metadata_len %u\n",
|
||||
i, subgroup->bis_sync, subgroup->metadata_len);
|
||||
|
||||
net_buf_simple_init_with_data(&buf, (void *)subgroup->metadata,
|
||||
subgroup->metadata_len);
|
||||
bt_data_parse(&buf, metadata_entry, NULL);
|
||||
}
|
||||
|
||||
|
||||
if (state->pa_sync_state == BT_BAP_PA_STATE_INFO_REQ) {
|
||||
err = bt_le_per_adv_sync_transfer(g_pa_sync, conn,
|
||||
BT_UUID_BASS_VAL);
|
||||
if (err != 0) {
|
||||
FAIL("Could not transfer periodic adv sync: %d\n", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
g_state_synced = state->pa_sync_state == BT_BAP_PA_STATE_SYNCED;
|
||||
|
||||
g_src_id = state->src_id;
|
||||
g_cb = true;
|
||||
}
|
||||
|
||||
static void bap_broadcast_assistant_recv_state_removed_cb(struct bt_conn *conn, int err,
|
||||
uint8_t src_id)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("BASS recv state removed failed (%d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("BASS recv state %u removed\n", src_id);
|
||||
g_cb = true;
|
||||
}
|
||||
|
||||
static void bap_broadcast_assistant_scan_start_cb(struct bt_conn *conn, int err)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("BASS scan start failed (%d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("BASS scan start successful\n");
|
||||
g_write_complete = true;
|
||||
}
|
||||
|
||||
static void bap_broadcast_assistant_scan_stop_cb(struct bt_conn *conn, int err)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("BASS scan stop failed (%d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("BASS scan stop successful\n");
|
||||
g_write_complete = true;
|
||||
}
|
||||
|
||||
static void bap_broadcast_assistant_add_src_cb(struct bt_conn *conn, int err)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("BASS add source failed (%d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("BASS add source successful\n");
|
||||
g_write_complete = true;
|
||||
}
|
||||
|
||||
static void bap_broadcast_assistant_mod_src_cb(struct bt_conn *conn, int err)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("BASS modify source failed (%d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("BASS modify source successful\n");
|
||||
g_write_complete = true;
|
||||
}
|
||||
|
||||
static void bap_broadcast_assistant_broadcast_code_cb(struct bt_conn *conn, int err)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("BASS broadcast code failed (%d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("BASS broadcast code successful\n");
|
||||
g_write_complete = true;
|
||||
}
|
||||
|
||||
static void bap_broadcast_assistant_rem_src_cb(struct bt_conn *conn, int err)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("BASS remove source failed (%d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("BASS remove source successful\n");
|
||||
g_write_complete = true;
|
||||
}
|
||||
|
||||
static struct bt_bap_broadcast_assistant_cb broadcast_assistant_cbs = {
|
||||
.discover = bap_broadcast_assistant_discover_cb,
|
||||
.scan = bap_broadcast_assistant_scan_cb,
|
||||
.recv_state = bap_broadcast_assistant_recv_state_cb,
|
||||
.recv_state_removed = bap_broadcast_assistant_recv_state_removed_cb,
|
||||
.scan_start = bap_broadcast_assistant_scan_start_cb,
|
||||
.scan_stop = bap_broadcast_assistant_scan_stop_cb,
|
||||
.add_src = bap_broadcast_assistant_add_src_cb,
|
||||
.mod_src = bap_broadcast_assistant_mod_src_cb,
|
||||
.broadcast_code = bap_broadcast_assistant_broadcast_code_cb,
|
||||
.rem_src = bap_broadcast_assistant_rem_src_cb,
|
||||
};
|
||||
|
||||
static void att_mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx)
|
||||
{
|
||||
g_mtu_exchanged = true;
|
||||
}
|
||||
|
||||
static struct bt_gatt_cb gatt_callbacks = {
|
||||
.att_mtu_updated = att_mtu_updated,
|
||||
};
|
||||
|
||||
static void sync_cb(struct bt_le_per_adv_sync *sync,
|
||||
struct bt_le_per_adv_sync_synced_info *info)
|
||||
{
|
||||
char le_addr[BT_ADDR_LE_STR_LEN];
|
||||
|
||||
bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
|
||||
|
||||
printk("PER_ADV_SYNC[%u]: [DEVICE]: %s synced, "
|
||||
"Interval 0x%04x (%u ms), PHY %s\n",
|
||||
bt_le_per_adv_sync_get_index(sync), le_addr, info->interval,
|
||||
info->interval * 5 / 4, phy2str(info->phy));
|
||||
|
||||
g_pa_synced = true;
|
||||
}
|
||||
|
||||
static void term_cb(struct bt_le_per_adv_sync *sync,
|
||||
const struct bt_le_per_adv_sync_term_info *info)
|
||||
{
|
||||
char le_addr[BT_ADDR_LE_STR_LEN];
|
||||
|
||||
bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
|
||||
|
||||
printk("PER_ADV_SYNC[%u]: [DEVICE]: %s sync terminated\n",
|
||||
bt_le_per_adv_sync_get_index(sync), le_addr);
|
||||
|
||||
g_pa_synced = false;
|
||||
}
|
||||
|
||||
static struct bt_le_per_adv_sync_cb sync_callbacks = {
|
||||
.synced = sync_cb,
|
||||
.term = term_cb,
|
||||
};
|
||||
|
||||
static void test_exchange_mtu(void)
|
||||
{
|
||||
WAIT_FOR_COND(g_mtu_exchanged);
|
||||
printk("MTU exchanged\n");
|
||||
}
|
||||
|
||||
static void test_bass_discover(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
printk("Discovering BASS\n");
|
||||
err = bt_bap_broadcast_assistant_discover(default_conn);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to discover BASS %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_COND(g_discovery_complete);
|
||||
printk("Discovery complete\n");
|
||||
}
|
||||
|
||||
static void test_bass_scan_start(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
printk("Starting scan\n");
|
||||
g_write_complete = false;
|
||||
err = bt_bap_broadcast_assistant_scan_start(default_conn, true);
|
||||
if (err != 0) {
|
||||
FAIL("Could not write scan start to BASS (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_COND(g_write_complete && g_broadcaster_found);
|
||||
printk("Scan started\n");
|
||||
}
|
||||
|
||||
static void test_bass_scan_stop(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
printk("Stopping scan\n");
|
||||
g_write_complete = false;
|
||||
err = bt_bap_broadcast_assistant_scan_stop(default_conn);
|
||||
if (err != 0) {
|
||||
FAIL("Could not write scan stop to BASS (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_COND(g_write_complete);
|
||||
printk("Scan stopped\n");
|
||||
}
|
||||
|
||||
static void test_bass_create_pa_sync(void)
|
||||
{
|
||||
int err;
|
||||
struct bt_le_per_adv_sync_param sync_create_param = { 0 };
|
||||
|
||||
printk("Creating Periodic Advertising Sync...\n");
|
||||
bt_addr_le_copy(&sync_create_param.addr, &g_broadcaster_addr);
|
||||
sync_create_param.sid = g_broadcaster_info.sid;
|
||||
sync_create_param.timeout = 0xa;
|
||||
err = bt_le_per_adv_sync_create(&sync_create_param, &g_pa_sync);
|
||||
if (err != 0) {
|
||||
FAIL("Could not create PA syncs (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_COND(g_pa_synced);
|
||||
printk("PA synced\n");
|
||||
}
|
||||
|
||||
static void test_bass_add_source(void)
|
||||
{
|
||||
int err;
|
||||
struct bt_bap_broadcast_assistant_add_src_param add_src_param = { 0 };
|
||||
struct bt_bap_scan_delegator_subgroup subgroup = { 0 };
|
||||
|
||||
printk("Adding source\n");
|
||||
g_cb = g_write_complete = false;
|
||||
bt_addr_le_copy(&add_src_param.addr, &g_broadcaster_addr);
|
||||
add_src_param.adv_sid = g_broadcaster_info.sid;
|
||||
add_src_param.num_subgroups = 1;
|
||||
add_src_param.pa_interval = g_broadcaster_info.interval;
|
||||
add_src_param.pa_sync = false;
|
||||
add_src_param.broadcast_id = g_broadcast_id;
|
||||
add_src_param.subgroups = &subgroup;
|
||||
subgroup.bis_sync = 0;
|
||||
subgroup.metadata_len = 0;
|
||||
err = bt_bap_broadcast_assistant_add_src(default_conn, &add_src_param);
|
||||
if (err != 0) {
|
||||
FAIL("Could not add source (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_COND(g_cb && g_write_complete);
|
||||
printk("Source added\n");
|
||||
}
|
||||
|
||||
static void test_bass_mod_source(void)
|
||||
{
|
||||
int err;
|
||||
struct bt_bap_broadcast_assistant_mod_src_param mod_src_param = { 0 };
|
||||
struct bt_bap_scan_delegator_subgroup subgroup = { 0 };
|
||||
|
||||
printk("Modify source\n");
|
||||
g_cb = g_write_complete = false;
|
||||
mod_src_param.src_id = g_src_id;
|
||||
mod_src_param.num_subgroups = 1;
|
||||
mod_src_param.pa_sync = true;
|
||||
mod_src_param.subgroups = &subgroup;
|
||||
mod_src_param.pa_interval = g_broadcaster_info.interval;
|
||||
subgroup.bis_sync = 0;
|
||||
subgroup.metadata_len = 0;
|
||||
err = bt_bap_broadcast_assistant_mod_src(default_conn, &mod_src_param);
|
||||
if (err != 0) {
|
||||
FAIL("Could not modify source (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_COND(g_cb && g_write_complete);
|
||||
printk("Source added, waiting for server to PA sync\n");
|
||||
WAIT_FOR_COND(g_state_synced)
|
||||
printk("Server PA synced\n");
|
||||
}
|
||||
|
||||
static void test_bass_broadcast_code(void)
|
||||
{
|
||||
uint8_t broadcast_code[BT_AUDIO_BROADCAST_CODE_SIZE];
|
||||
int err;
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(broadcast_code); i++) {
|
||||
broadcast_code[i] = i;
|
||||
}
|
||||
|
||||
printk("Adding broadcast code\n");
|
||||
g_write_complete = false;
|
||||
err = bt_bap_broadcast_assistant_set_broadcast_code(default_conn, g_src_id, broadcast_code);
|
||||
if (err != 0) {
|
||||
FAIL("Could not add broadcast code (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_COND(g_write_complete);
|
||||
printk("Broadcast code added\n");
|
||||
}
|
||||
|
||||
static void test_bass_remove_source(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
printk("Removing source\n");
|
||||
g_cb = g_write_complete = false;
|
||||
err = bt_bap_broadcast_assistant_rem_src(default_conn, g_src_id);
|
||||
if (err != 0) {
|
||||
FAIL("Could not remove source (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
WAIT_FOR_COND(g_cb && g_write_complete);
|
||||
printk("Source removed\n");
|
||||
}
|
||||
|
||||
static void test_main(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_enable(NULL);
|
||||
|
||||
if (err != 0) {
|
||||
FAIL("Bluetooth enable failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
bt_gatt_cb_register(&gatt_callbacks);
|
||||
bt_bap_broadcast_assistant_register_cb(&broadcast_assistant_cbs);
|
||||
bt_le_per_adv_sync_cb_register(&sync_callbacks);
|
||||
|
||||
printk("Starting scan\n");
|
||||
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
|
||||
if (err != 0) {
|
||||
FAIL("Scanning failed to start (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Scanning successfully started\n");
|
||||
|
||||
WAIT_FOR_FLAG(flag_connected);
|
||||
|
||||
test_exchange_mtu();
|
||||
test_bass_discover();
|
||||
test_bass_scan_start();
|
||||
test_bass_scan_stop();
|
||||
test_bass_create_pa_sync();
|
||||
test_bass_add_source();
|
||||
test_bass_mod_source();
|
||||
test_bass_broadcast_code();
|
||||
test_bass_remove_source();
|
||||
|
||||
PASS("BAP broadcast assistant Passed\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_bass[] = {
|
||||
{
|
||||
.test_id = "bap_broadcast_assistant",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_main
|
||||
},
|
||||
BSTEST_END_MARKER
|
||||
};
|
||||
|
||||
struct bst_test_list *test_bap_broadcast_assistant_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_bass);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
struct bst_test_list *test_bap_broadcast_assistant_install(struct bst_test_list *tests)
|
||||
{
|
||||
return tests;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_BAP_BROADCAST_ASSISTANT */
|
92
tests/bsim/bluetooth/audio/src/bap_scan_delegator_test.c
Normal file
92
tests/bsim/bluetooth/audio/src/bap_scan_delegator_test.c
Normal file
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright (c) 2021-2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_BT_BAP_SCAN_DELEGATOR
|
||||
#include <zephyr/bluetooth/audio/bap.h>
|
||||
#include "common.h"
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
|
||||
static volatile bool g_cb;
|
||||
static volatile bool g_pa_synced;
|
||||
|
||||
static void pa_synced(struct bt_bap_scan_delegator_recv_state *recv_state,
|
||||
const struct bt_le_per_adv_sync_synced_info *info)
|
||||
{
|
||||
printk("Receive state %p synced\n", recv_state);
|
||||
g_pa_synced = true;
|
||||
}
|
||||
|
||||
static void pa_term(struct bt_bap_scan_delegator_recv_state *recv_state,
|
||||
const struct bt_le_per_adv_sync_term_info *info)
|
||||
{
|
||||
printk("Receive state %p sync terminated\n", recv_state);
|
||||
g_pa_synced = false;
|
||||
}
|
||||
|
||||
static void pa_recv(struct bt_bap_scan_delegator_recv_state *recv_state,
|
||||
const struct bt_le_per_adv_sync_recv_info *info,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
printk("Receive state %p received data\n", recv_state);
|
||||
}
|
||||
|
||||
static struct bt_bap_scan_delegator_cb scan_delegator_cb = {
|
||||
.pa_synced = pa_synced,
|
||||
.pa_term = pa_term,
|
||||
.pa_recv = pa_recv
|
||||
};
|
||||
|
||||
static void test_main(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_enable(NULL);
|
||||
if (err) {
|
||||
FAIL("Bluetooth init failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Bluetooth initialized\n");
|
||||
|
||||
bt_bap_scan_delegator_register_cb(&scan_delegator_cb);
|
||||
|
||||
err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, AD_SIZE, NULL, 0);
|
||||
if (err) {
|
||||
FAIL("Advertising failed to start (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Advertising successfully started\n");
|
||||
|
||||
WAIT_FOR_FLAG(flag_connected);
|
||||
|
||||
WAIT_FOR_COND(g_pa_synced);
|
||||
|
||||
PASS("BAP Scan Delegator passed\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_scan_delegator[] = {
|
||||
{
|
||||
.test_id = "bap_scan_delegator",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_main
|
||||
},
|
||||
BSTEST_END_MARKER
|
||||
};
|
||||
|
||||
struct bst_test_list *test_scan_delegator_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_scan_delegator);
|
||||
}
|
||||
#else
|
||||
struct bst_test_list *test_scan_delegator_install(struct bst_test_list *tests)
|
||||
{
|
||||
return tests;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR */
|
607
tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c
Normal file
607
tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c
Normal file
|
@ -0,0 +1,607 @@
|
|||
/*
|
||||
* Copyright (c) 2021-2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_BT_BAP_UNICAST_CLIENT)
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/audio/audio.h>
|
||||
#include <zephyr/bluetooth/audio/bap.h>
|
||||
#include <zephyr/bluetooth/audio/bap_lc3_preset.h>
|
||||
#include <zephyr/bluetooth/audio/pacs.h>
|
||||
#include "common.h"
|
||||
#include "bap_unicast_common.h"
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
|
||||
static struct bt_bap_stream g_streams[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT];
|
||||
static struct bt_bap_ep *g_sinks[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT];
|
||||
|
||||
/* Mandatory support preset by both client and server */
|
||||
static struct bt_bap_lc3_preset preset_16_2_1 = BT_BAP_LC3_UNICAST_PRESET_16_2_1(
|
||||
BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED);
|
||||
|
||||
CREATE_FLAG(flag_mtu_exchanged);
|
||||
CREATE_FLAG(flag_sink_discovered);
|
||||
CREATE_FLAG(flag_stream_codec_configured);
|
||||
static atomic_t flag_stream_qos_configured;
|
||||
CREATE_FLAG(flag_stream_enabled);
|
||||
CREATE_FLAG(flag_stream_started);
|
||||
CREATE_FLAG(flag_stream_released);
|
||||
CREATE_FLAG(flag_operation_success);
|
||||
|
||||
static void stream_configured(struct bt_bap_stream *stream,
|
||||
const struct bt_codec_qos_pref *pref)
|
||||
{
|
||||
printk("Configured stream %p\n", stream);
|
||||
|
||||
/* TODO: The preference should be used/taken into account when
|
||||
* setting the QoS
|
||||
*/
|
||||
|
||||
SET_FLAG(flag_stream_codec_configured);
|
||||
}
|
||||
|
||||
static void stream_qos_set(struct bt_bap_stream *stream)
|
||||
{
|
||||
printk("QoS set stream %p\n", stream);
|
||||
|
||||
atomic_inc(&flag_stream_qos_configured);
|
||||
}
|
||||
|
||||
static void stream_enabled(struct bt_bap_stream *stream)
|
||||
{
|
||||
printk("Enabled stream %p\n", stream);
|
||||
|
||||
SET_FLAG(flag_stream_enabled);
|
||||
}
|
||||
|
||||
static void stream_started(struct bt_bap_stream *stream)
|
||||
{
|
||||
printk("Started stream %p\n", stream);
|
||||
|
||||
SET_FLAG(flag_stream_started);
|
||||
}
|
||||
|
||||
static void stream_metadata_updated(struct bt_bap_stream *stream)
|
||||
{
|
||||
printk("Metadata updated stream %p\n", stream);
|
||||
}
|
||||
|
||||
static void stream_disabled(struct bt_bap_stream *stream)
|
||||
{
|
||||
printk("Disabled stream %p\n", stream);
|
||||
}
|
||||
|
||||
static void stream_stopped(struct bt_bap_stream *stream, uint8_t reason)
|
||||
{
|
||||
printk("Stopped stream %p with reason 0x%02X\n", stream, reason);
|
||||
}
|
||||
|
||||
static void stream_released(struct bt_bap_stream *stream)
|
||||
{
|
||||
printk("Released stream %p\n", stream);
|
||||
|
||||
SET_FLAG(flag_stream_released);
|
||||
}
|
||||
|
||||
static struct bt_bap_stream_ops stream_ops = {
|
||||
.configured = stream_configured,
|
||||
.qos_set = stream_qos_set,
|
||||
.enabled = stream_enabled,
|
||||
.started = stream_started,
|
||||
.metadata_updated = stream_metadata_updated,
|
||||
.disabled = stream_disabled,
|
||||
.stopped = stream_stopped,
|
||||
.released = stream_released,
|
||||
};
|
||||
|
||||
static void unicast_client_location_cb(struct bt_conn *conn,
|
||||
enum bt_audio_dir dir,
|
||||
enum bt_audio_location loc)
|
||||
{
|
||||
printk("dir %u loc %X\n", dir, loc);
|
||||
}
|
||||
|
||||
static void available_contexts_cb(struct bt_conn *conn,
|
||||
enum bt_audio_context snk_ctx,
|
||||
enum bt_audio_context src_ctx)
|
||||
{
|
||||
printk("snk ctx %u src ctx %u\n", snk_ctx, src_ctx);
|
||||
}
|
||||
|
||||
|
||||
static void config_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
|
||||
enum bt_bap_ascs_reason reason)
|
||||
{
|
||||
printk("stream %p config operation rsp_code %u reason %u\n", stream, rsp_code, reason);
|
||||
|
||||
if (rsp_code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
|
||||
SET_FLAG(flag_operation_success);
|
||||
}
|
||||
}
|
||||
|
||||
static void qos_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
|
||||
enum bt_bap_ascs_reason reason)
|
||||
{
|
||||
printk("stream %p qos operation rsp_code %u reason %u\n", stream, rsp_code, reason);
|
||||
|
||||
if (rsp_code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
|
||||
SET_FLAG(flag_operation_success);
|
||||
}
|
||||
}
|
||||
|
||||
static void enable_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
|
||||
enum bt_bap_ascs_reason reason)
|
||||
{
|
||||
printk("stream %p enable operation rsp_code %u reason %u\n", stream, rsp_code, reason);
|
||||
|
||||
if (rsp_code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
|
||||
SET_FLAG(flag_operation_success);
|
||||
}
|
||||
}
|
||||
|
||||
static void start_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
|
||||
enum bt_bap_ascs_reason reason)
|
||||
{
|
||||
printk("stream %p start operation rsp_code %u reason %u\n", stream, rsp_code, reason);
|
||||
|
||||
if (rsp_code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
|
||||
SET_FLAG(flag_operation_success);
|
||||
}
|
||||
}
|
||||
|
||||
static void stop_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
|
||||
enum bt_bap_ascs_reason reason)
|
||||
{
|
||||
printk("stream %p stop operation rsp_code %u reason %u\n", stream, rsp_code, reason);
|
||||
|
||||
if (rsp_code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
|
||||
SET_FLAG(flag_operation_success);
|
||||
}
|
||||
}
|
||||
|
||||
static void disable_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
|
||||
enum bt_bap_ascs_reason reason)
|
||||
{
|
||||
printk("stream %p disable operation rsp_code %u reason %u\n", stream, rsp_code, reason);
|
||||
|
||||
if (rsp_code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
|
||||
SET_FLAG(flag_operation_success);
|
||||
}
|
||||
}
|
||||
|
||||
static void metadata_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
|
||||
enum bt_bap_ascs_reason reason)
|
||||
{
|
||||
printk("stream %p metadata operation rsp_code %u reason %u\n", stream, rsp_code, reason);
|
||||
|
||||
if (rsp_code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
|
||||
SET_FLAG(flag_operation_success);
|
||||
}
|
||||
}
|
||||
|
||||
static void release_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
|
||||
enum bt_bap_ascs_reason reason)
|
||||
{
|
||||
printk("stream %p release operation rsp_code %u reason %u\n", stream, rsp_code, reason);
|
||||
|
||||
if (rsp_code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
|
||||
SET_FLAG(flag_operation_success);
|
||||
}
|
||||
}
|
||||
|
||||
const struct bt_bap_unicast_client_cb unicast_client_cbs = {
|
||||
.location = unicast_client_location_cb,
|
||||
.available_contexts = available_contexts_cb,
|
||||
.config = config_cb,
|
||||
.qos = qos_cb,
|
||||
.enable = enable_cb,
|
||||
.start = start_cb,
|
||||
.stop = stop_cb,
|
||||
.disable = disable_cb,
|
||||
.metadata = metadata_cb,
|
||||
.release = release_cb,
|
||||
};
|
||||
|
||||
static void add_remote_sink(struct bt_bap_ep *ep, uint8_t index)
|
||||
{
|
||||
printk("Sink #%u: ep %p\n", index, ep);
|
||||
|
||||
g_sinks[index] = ep;
|
||||
}
|
||||
|
||||
static void print_remote_codec(struct bt_codec *codec, int index, enum bt_audio_dir dir)
|
||||
{
|
||||
printk("#%u: codec %p dir 0x%02x\n", index, codec, dir);
|
||||
|
||||
print_codec(codec);
|
||||
}
|
||||
|
||||
static void discover_sink_cb(struct bt_conn *conn, struct bt_codec *codec, struct bt_bap_ep *ep,
|
||||
struct bt_bap_unicast_client_discover_params *params)
|
||||
{
|
||||
static bool codec_found;
|
||||
static bool endpoint_found;
|
||||
|
||||
if (params->err != 0) {
|
||||
FAIL("Discovery failed: %d\n", params->err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (codec != NULL) {
|
||||
print_remote_codec(codec, params->num_caps, params->dir);
|
||||
codec_found = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ep != NULL) {
|
||||
if (params->dir == BT_AUDIO_DIR_SINK) {
|
||||
add_remote_sink(ep, params->num_eps);
|
||||
endpoint_found = true;
|
||||
} else {
|
||||
FAIL("Invalid param dir: %u\n", params->dir);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Discover complete\n");
|
||||
|
||||
(void)memset(params, 0, sizeof(*params));
|
||||
|
||||
if (endpoint_found && codec_found) {
|
||||
SET_FLAG(flag_sink_discovered);
|
||||
} else {
|
||||
FAIL("Did not discover endpoint and codec\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void att_mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx)
|
||||
{
|
||||
printk("MTU exchanged\n");
|
||||
SET_FLAG(flag_mtu_exchanged);
|
||||
}
|
||||
|
||||
static struct bt_gatt_cb gatt_callbacks = {
|
||||
.att_mtu_updated = att_mtu_updated,
|
||||
};
|
||||
|
||||
static void init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_enable(NULL);
|
||||
if (err != 0) {
|
||||
FAIL("Bluetooth enable failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(g_streams); i++) {
|
||||
g_streams[i].ops = &stream_ops;
|
||||
}
|
||||
|
||||
bt_gatt_cb_register(&gatt_callbacks);
|
||||
|
||||
err = bt_bap_unicast_client_register_cb(&unicast_client_cbs);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to register client callbacks: %d", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void scan_and_connect(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
|
||||
if (err != 0) {
|
||||
FAIL("Scanning failed to start (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Scanning successfully started\n");
|
||||
WAIT_FOR_FLAG(flag_connected);
|
||||
}
|
||||
|
||||
static void exchange_mtu(void)
|
||||
{
|
||||
WAIT_FOR_FLAG(flag_mtu_exchanged);
|
||||
}
|
||||
|
||||
static void discover_sink(void)
|
||||
{
|
||||
static struct bt_bap_unicast_client_discover_params params;
|
||||
int err;
|
||||
|
||||
params.func = discover_sink_cb;
|
||||
params.dir = BT_AUDIO_DIR_SINK;
|
||||
|
||||
err = bt_bap_unicast_client_discover(default_conn, ¶ms);
|
||||
if (err != 0) {
|
||||
printk("Failed to discover sink: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_FLAG(flag_sink_discovered);
|
||||
}
|
||||
|
||||
static int codec_configure_stream(struct bt_bap_stream *stream, struct bt_bap_ep *ep)
|
||||
{
|
||||
int err;
|
||||
|
||||
UNSET_FLAG(flag_stream_codec_configured);
|
||||
UNSET_FLAG(flag_operation_success);
|
||||
|
||||
err = bt_bap_stream_config(default_conn, stream, ep,
|
||||
&preset_16_2_1.codec);
|
||||
if (err != 0) {
|
||||
FAIL("Could not configure stream: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
WAIT_FOR_FLAG(flag_stream_codec_configured);
|
||||
WAIT_FOR_FLAG(flag_operation_success);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void codec_configure_streams(size_t stream_cnt)
|
||||
{
|
||||
for (size_t i = 0U; i < stream_cnt; i++) {
|
||||
struct bt_bap_stream *stream = &g_streams[i];
|
||||
int err;
|
||||
|
||||
if (g_sinks[i] == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
err = codec_configure_stream(stream, g_sinks[i]);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to configure stream[%zu]: %d", i, err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void qos_configure_streams(struct bt_bap_unicast_group *unicast_group,
|
||||
size_t stream_cnt)
|
||||
{
|
||||
int err;
|
||||
|
||||
UNSET_FLAG(flag_stream_qos_configured);
|
||||
|
||||
err = bt_bap_stream_qos(default_conn, unicast_group);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to QoS configure streams: %d", err);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
while (atomic_get(&flag_stream_qos_configured) != stream_cnt) {
|
||||
(void)k_sleep(K_MSEC(1));
|
||||
}
|
||||
}
|
||||
|
||||
static int enable_stream(struct bt_bap_stream *stream)
|
||||
{
|
||||
int err;
|
||||
|
||||
UNSET_FLAG(flag_stream_enabled);
|
||||
|
||||
err = bt_bap_stream_enable(stream, NULL, 0);
|
||||
if (err != 0) {
|
||||
FAIL("Could not enable stream: %d\n", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
WAIT_FOR_FLAG(flag_stream_enabled);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void enable_streams(size_t stream_cnt)
|
||||
{
|
||||
for (size_t i = 0U; i < stream_cnt; i++) {
|
||||
struct bt_bap_stream *stream = &g_streams[i];
|
||||
int err;
|
||||
|
||||
err = enable_stream(stream);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to enable stream[%zu]: %d",
|
||||
i, err);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int start_stream(struct bt_bap_stream *stream)
|
||||
{
|
||||
int err;
|
||||
|
||||
UNSET_FLAG(flag_stream_started);
|
||||
|
||||
err = bt_bap_stream_start(stream);
|
||||
if (err != 0) {
|
||||
FAIL("Could not start stream: %d\n", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
WAIT_FOR_FLAG(flag_stream_started);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void start_streams(size_t stream_cnt)
|
||||
{
|
||||
for (size_t i = 0U; i < 1; i++) {
|
||||
struct bt_bap_stream *stream = &g_streams[i];
|
||||
int err;
|
||||
|
||||
err = start_stream(stream);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to start stream[%zu]: %d", i, err);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static size_t release_streams(size_t stream_cnt)
|
||||
{
|
||||
for (size_t i = 0; i < stream_cnt; i++) {
|
||||
int err;
|
||||
|
||||
if (g_sinks[i] == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
UNSET_FLAG(flag_operation_success);
|
||||
UNSET_FLAG(flag_stream_released);
|
||||
|
||||
err = bt_bap_stream_release(&g_streams[i]);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to release stream[%zu]: %d", i, err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
WAIT_FOR_FLAG(flag_operation_success);
|
||||
WAIT_FOR_FLAG(flag_stream_released);
|
||||
}
|
||||
|
||||
return stream_cnt;
|
||||
}
|
||||
|
||||
|
||||
static size_t create_unicast_group(struct bt_bap_unicast_group **unicast_group)
|
||||
{
|
||||
struct bt_bap_unicast_group_stream_pair_param pair_params[ARRAY_SIZE(g_streams)];
|
||||
struct bt_bap_unicast_group_stream_param stream_params[ARRAY_SIZE(g_streams)];
|
||||
struct bt_bap_unicast_group_param param;
|
||||
size_t stream_cnt = 0;
|
||||
int err;
|
||||
|
||||
for (stream_cnt = 0U;
|
||||
stream_cnt < MIN(ARRAY_SIZE(g_sinks), ARRAY_SIZE(g_streams));
|
||||
stream_cnt++) {
|
||||
if (g_sinks[stream_cnt] == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
stream_params[stream_cnt].stream = &g_streams[stream_cnt];
|
||||
stream_params[stream_cnt].qos = &preset_16_2_1.qos;
|
||||
pair_params[stream_cnt].rx_param = NULL;
|
||||
pair_params[stream_cnt].tx_param = &stream_params[stream_cnt];
|
||||
}
|
||||
|
||||
if (stream_cnt == 0U) {
|
||||
FAIL("No streams added to group");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
param.params = pair_params;
|
||||
param.params_count = stream_cnt;
|
||||
param.packing = BT_ISO_PACKING_SEQUENTIAL;
|
||||
|
||||
/* Require controller support for CIGs */
|
||||
printk("Creating unicast group\n");
|
||||
err = bt_bap_unicast_group_create(¶m, unicast_group);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to create unicast group: %d", err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return stream_cnt;
|
||||
}
|
||||
|
||||
static void delete_unicast_group(struct bt_bap_unicast_group *unicast_group)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Require controller support for CIGs */
|
||||
err = bt_bap_unicast_group_delete(unicast_group);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to delete unicast group: %d", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_main(void)
|
||||
{
|
||||
const unsigned int iterations = 3;
|
||||
|
||||
init();
|
||||
|
||||
scan_and_connect();
|
||||
|
||||
exchange_mtu();
|
||||
|
||||
discover_sink();
|
||||
|
||||
/* Run the stream setup multiple time to ensure states are properly
|
||||
* set and reset
|
||||
*/
|
||||
for (unsigned int i = 0U; i < iterations; i++) {
|
||||
struct bt_bap_unicast_group *unicast_group;
|
||||
size_t stream_cnt;
|
||||
|
||||
printk("\n########### Running iteration #%u\n\n", i);
|
||||
|
||||
printk("Creating unicast group\n");
|
||||
stream_cnt = create_unicast_group(&unicast_group);
|
||||
|
||||
printk("Codec configuring streams\n");
|
||||
codec_configure_streams(stream_cnt);
|
||||
|
||||
printk("QoS configuring streams\n");
|
||||
qos_configure_streams(unicast_group, stream_cnt);
|
||||
|
||||
printk("Enabling streams\n");
|
||||
enable_streams(stream_cnt);
|
||||
|
||||
printk("Starting streams\n");
|
||||
start_streams(stream_cnt);
|
||||
|
||||
printk("Releasing streams\n");
|
||||
release_streams(stream_cnt);
|
||||
|
||||
/* Test removing streams from group after creation */
|
||||
printk("Deleting unicast group\n");
|
||||
delete_unicast_group(unicast_group);
|
||||
unicast_group = NULL;
|
||||
}
|
||||
|
||||
|
||||
PASS("Unicast client passed\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_unicast_client[] = {
|
||||
{
|
||||
.test_id = "unicast_client",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_main
|
||||
},
|
||||
BSTEST_END_MARKER
|
||||
};
|
||||
|
||||
struct bst_test_list *test_unicast_client_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_unicast_client);
|
||||
}
|
||||
|
||||
#else /* !(CONFIG_BT_BAP_UNICAST_CLIENT) */
|
||||
|
||||
struct bst_test_list *test_unicast_client_install(struct bst_test_list *tests)
|
||||
{
|
||||
return tests;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
|
49
tests/bsim/bluetooth/audio/src/bap_unicast_common.c
Normal file
49
tests/bsim/bluetooth/audio/src/bap_unicast_common.c
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2021-2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "bap_unicast_common.h"
|
||||
|
||||
void print_hex(const uint8_t *ptr, size_t len)
|
||||
{
|
||||
while (len-- != 0) {
|
||||
printk("%02x", *ptr++);
|
||||
}
|
||||
}
|
||||
|
||||
void print_codec(const struct bt_codec *codec)
|
||||
{
|
||||
printk("codec 0x%02x cid 0x%04x vid 0x%04x count %u\n",
|
||||
codec->id, codec->cid, codec->vid, codec->data_count);
|
||||
|
||||
for (uint8_t i = 0; i < codec->data_count; i++) {
|
||||
printk("data #%u: type 0x%02x len %u\n",
|
||||
i, codec->data[i].data.type,
|
||||
codec->data[i].data.data_len);
|
||||
print_hex(codec->data[i].data.data,
|
||||
codec->data[i].data.data_len -
|
||||
sizeof(codec->data[i].data.type));
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < codec->meta_count; i++) {
|
||||
printk("meta #%u: type 0x%02x len %u\n",
|
||||
i, codec->meta[i].data.type,
|
||||
codec->meta[i].data.data_len);
|
||||
print_hex(codec->meta[i].data.data,
|
||||
codec->meta[i].data.data_len -
|
||||
sizeof(codec->meta[i].data.type));
|
||||
printk("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void print_qos(const struct bt_codec_qos *qos)
|
||||
{
|
||||
printk("QoS: interval %u framing 0x%02x phy 0x%02x sdu %u "
|
||||
"rtn %u latency %u pd %u\n",
|
||||
qos->interval, qos->framing, qos->phy, qos->sdu,
|
||||
qos->rtn, qos->latency, qos->pd);
|
||||
}
|
19
tests/bsim/bluetooth/audio/src/bap_unicast_common.h
Normal file
19
tests/bsim/bluetooth/audio/src/bap_unicast_common.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* Common functions and helpers for unicast audio BSIM audio tests
|
||||
*
|
||||
* Copyright (c) 2021-2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_TEST_BSIM_BT_AUDIO_TEST_UNICAST_COMMON_
|
||||
#define ZEPHYR_TEST_BSIM_BT_AUDIO_TEST_UNICAST_COMMON_
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/audio/audio.h>
|
||||
|
||||
void print_hex(const uint8_t *ptr, size_t len);
|
||||
void print_codec(const struct bt_codec *codec);
|
||||
void print_qos(const struct bt_codec_qos *qos);
|
||||
|
||||
#endif /* ZEPHYR_TEST_BSIM_BT_AUDIO_TEST_UNICAST_COMMON_ */
|
375
tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c
Normal file
375
tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c
Normal file
|
@ -0,0 +1,375 @@
|
|||
/*
|
||||
* Copyright (c) 2021-2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_BT_BAP_UNICAST_SERVER)
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/audio/audio.h>
|
||||
#include <zephyr/bluetooth/audio/bap.h>
|
||||
#include <zephyr/bluetooth/audio/pacs.h>
|
||||
#include "common.h"
|
||||
#include "bap_unicast_common.h"
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
|
||||
#define CHANNEL_COUNT_1 BIT(0)
|
||||
|
||||
static struct bt_codec lc3_codec =
|
||||
BT_CODEC_LC3(BT_CODEC_LC3_FREQ_16KHZ, BT_CODEC_LC3_DURATION_10, CHANNEL_COUNT_1, 40u, 40u,
|
||||
1u, (BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA));
|
||||
|
||||
static struct bt_bap_stream streams[CONFIG_BT_ASCS_ASE_SNK_COUNT + CONFIG_BT_ASCS_ASE_SRC_COUNT];
|
||||
|
||||
static const struct bt_codec_qos_pref qos_pref =
|
||||
BT_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, 0x02, 10, 40000, 40000, 40000, 40000);
|
||||
|
||||
/* TODO: Expand with BAP data */
|
||||
static const struct bt_data unicast_server_ad[] = {
|
||||
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
|
||||
BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(BT_UUID_ASCS_VAL)),
|
||||
};
|
||||
|
||||
CREATE_FLAG(flag_stream_configured);
|
||||
|
||||
static void print_ase_info(struct bt_bap_ep *ep, void *user_data)
|
||||
{
|
||||
struct bt_bap_ep_info info;
|
||||
|
||||
bt_bap_ep_get_info(ep, &info);
|
||||
printk("ASE info: id %u state %u dir %u\n", info.id, info.state, info.dir);
|
||||
}
|
||||
|
||||
static struct bt_bap_stream *stream_alloc(void)
|
||||
{
|
||||
for (size_t i = 0; i < ARRAY_SIZE(streams); i++) {
|
||||
struct bt_bap_stream *stream = &streams[i];
|
||||
|
||||
if (!stream->conn) {
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_audio_dir dir,
|
||||
const struct bt_codec *codec, struct bt_bap_stream **stream,
|
||||
struct bt_codec_qos_pref *const pref)
|
||||
{
|
||||
printk("ASE Codec Config: conn %p ep %p dir %u\n", conn, ep, dir);
|
||||
|
||||
print_codec(codec);
|
||||
|
||||
*stream = stream_alloc();
|
||||
if (*stream == NULL) {
|
||||
printk("No streams available\n");
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
printk("ASE Codec Config stream %p\n", *stream);
|
||||
|
||||
bt_bap_unicast_server_foreach_ep(conn, print_ase_info, NULL);
|
||||
|
||||
SET_FLAG(flag_stream_configured);
|
||||
|
||||
*pref = qos_pref;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lc3_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir,
|
||||
const struct bt_codec *codec, struct bt_codec_qos_pref *const pref)
|
||||
{
|
||||
printk("ASE Codec Reconfig: stream %p\n", stream);
|
||||
|
||||
print_codec(codec);
|
||||
|
||||
/* We only support one QoS at the moment, reject changes */
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
static int lc3_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos)
|
||||
{
|
||||
printk("QoS: stream %p qos %p\n", stream, qos);
|
||||
|
||||
print_qos(qos);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lc3_enable(struct bt_bap_stream *stream, const struct bt_codec_data *meta,
|
||||
size_t meta_count)
|
||||
{
|
||||
printk("Enable: stream %p meta_count %zu\n", stream, meta_count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lc3_start(struct bt_bap_stream *stream)
|
||||
{
|
||||
printk("Start: stream %p\n", stream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool valid_metadata_type(uint8_t type, uint8_t len)
|
||||
{
|
||||
switch (type) {
|
||||
case BT_AUDIO_METADATA_TYPE_PREF_CONTEXT:
|
||||
case BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT:
|
||||
if (len != 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
case BT_AUDIO_METADATA_TYPE_STREAM_LANG:
|
||||
if (len != 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
case BT_AUDIO_METADATA_TYPE_PARENTAL_RATING:
|
||||
if (len != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
case BT_AUDIO_METADATA_TYPE_EXTENDED: /* 1 - 255 octets */
|
||||
case BT_AUDIO_METADATA_TYPE_VENDOR: /* 1 - 255 octets */
|
||||
if (len < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
case BT_AUDIO_METADATA_TYPE_CCID_LIST: /* 2 - 254 octets */
|
||||
if (len < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
case BT_AUDIO_METADATA_TYPE_PROGRAM_INFO: /* 0 - 255 octets */
|
||||
case BT_AUDIO_METADATA_TYPE_PROGRAM_INFO_URI: /* 0 - 255 octets */
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_codec_data *meta,
|
||||
size_t meta_count)
|
||||
{
|
||||
printk("Metadata: stream %p meta_count %zu\n", stream, meta_count);
|
||||
|
||||
for (size_t i = 0; i < meta_count; i++) {
|
||||
if (!valid_metadata_type(meta->data.type, meta->data.data_len)) {
|
||||
printk("Invalid metadata type %u or length %u\n", meta->data.type,
|
||||
meta->data.data_len);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lc3_disable(struct bt_bap_stream *stream)
|
||||
{
|
||||
printk("Disable: stream %p\n", stream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lc3_stop(struct bt_bap_stream *stream)
|
||||
{
|
||||
printk("Stop: stream %p\n", stream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lc3_release(struct bt_bap_stream *stream)
|
||||
{
|
||||
printk("Release: stream %p\n", stream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct bt_bap_unicast_server_cb unicast_server_cb = {
|
||||
.config = lc3_config,
|
||||
.reconfig = lc3_reconfig,
|
||||
.qos = lc3_qos,
|
||||
.enable = lc3_enable,
|
||||
.start = lc3_start,
|
||||
.metadata = lc3_metadata,
|
||||
.disable = lc3_disable,
|
||||
.stop = lc3_stop,
|
||||
.release = lc3_release,
|
||||
};
|
||||
|
||||
static void stream_enabled_cb(struct bt_bap_stream *stream)
|
||||
{
|
||||
struct bt_bap_ep_info ep_info;
|
||||
int err;
|
||||
|
||||
printk("Enabled: stream %p\n", stream);
|
||||
|
||||
err = bt_bap_ep_get_info(stream->ep, &ep_info);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to get ep info: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ep_info.dir == BT_AUDIO_DIR_SINK) {
|
||||
/* Automatically do the receiver start ready operation */
|
||||
err = bt_bap_stream_start(stream);
|
||||
|
||||
if (err != 0) {
|
||||
FAIL("Failed to start stream: %d\n", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void stream_recv(struct bt_bap_stream *stream, const struct bt_iso_recv_info *info,
|
||||
struct net_buf *buf)
|
||||
{
|
||||
printk("Incoming audio on stream %p len %u\n", stream, buf->len);
|
||||
}
|
||||
|
||||
static struct bt_bap_stream_ops stream_ops = {
|
||||
.enabled = stream_enabled_cb,
|
||||
.recv = stream_recv
|
||||
};
|
||||
|
||||
static void init(void)
|
||||
{
|
||||
static struct bt_pacs_cap cap = {
|
||||
.codec = &lc3_codec,
|
||||
};
|
||||
int err;
|
||||
|
||||
err = bt_enable(NULL);
|
||||
if (err != 0) {
|
||||
FAIL("Bluetooth enable failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Bluetooth initialized\n");
|
||||
|
||||
bt_bap_unicast_server_register_cb(&unicast_server_cb);
|
||||
|
||||
err = bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to register capabilities: %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(streams); i++) {
|
||||
bt_bap_stream_cb_register(&streams[i], &stream_ops);
|
||||
}
|
||||
|
||||
err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, unicast_server_ad, ARRAY_SIZE(unicast_server_ad),
|
||||
NULL, 0);
|
||||
if (err != 0) {
|
||||
FAIL("Advertising failed to start (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_location(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_PAC_SNK_LOC)) {
|
||||
err = bt_pacs_set_location(BT_AUDIO_DIR_SINK, BT_AUDIO_LOCATION_FRONT_CENTER);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to set sink location (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_PAC_SRC_LOC)) {
|
||||
err = bt_pacs_set_location(BT_AUDIO_DIR_SOURCE, (BT_AUDIO_LOCATION_FRONT_LEFT |
|
||||
BT_AUDIO_LOCATION_FRONT_RIGHT));
|
||||
if (err != 0) {
|
||||
FAIL("Failed to set source location (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
printk("Location successfully set\n");
|
||||
}
|
||||
|
||||
static void set_available_contexts(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SINK,
|
||||
BT_AUDIO_CONTEXT_TYPE_MEDIA |
|
||||
BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL);
|
||||
if (IS_ENABLED(CONFIG_BT_PAC_SNK) && err != 0) {
|
||||
FAIL("Failed to set sink supported contexts (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_pacs_set_available_contexts(BT_AUDIO_DIR_SINK,
|
||||
BT_AUDIO_CONTEXT_TYPE_MEDIA |
|
||||
BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL);
|
||||
if (IS_ENABLED(CONFIG_BT_PAC_SNK) && err != 0) {
|
||||
FAIL("Failed to set sink available contexts (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SOURCE,
|
||||
BT_AUDIO_CONTEXT_TYPE_NOTIFICATIONS);
|
||||
if (IS_ENABLED(CONFIG_BT_PAC_SRC) && err != 0) {
|
||||
FAIL("Failed to set source supported contexts (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_pacs_set_available_contexts(BT_AUDIO_DIR_SOURCE,
|
||||
BT_AUDIO_CONTEXT_TYPE_NOTIFICATIONS);
|
||||
if (IS_ENABLED(CONFIG_BT_PAC_SRC) && err != 0) {
|
||||
FAIL("Failed to set source available contexts (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Available contexts successfully set\n");
|
||||
}
|
||||
|
||||
static void test_main(void)
|
||||
{
|
||||
init();
|
||||
|
||||
set_location();
|
||||
set_available_contexts();
|
||||
|
||||
/* TODO: When babblesim supports ISO, wait for audio stream to pass */
|
||||
|
||||
WAIT_FOR_FLAG(flag_connected);
|
||||
WAIT_FOR_FLAG(flag_stream_configured);
|
||||
PASS("Unicast server passed\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_unicast_server[] = {{.test_id = "unicast_server",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_main},
|
||||
BSTEST_END_MARKER};
|
||||
|
||||
struct bst_test_list *test_unicast_server_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_unicast_server);
|
||||
}
|
||||
|
||||
#else /* !(CONFIG_BT_BAP_UNICAST_SERVER) */
|
||||
|
||||
struct bst_test_list *test_unicast_server_install(struct bst_test_list *tests)
|
||||
{
|
||||
return tests;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_BAP_UNICAST_SERVER */
|
94
tests/bsim/bluetooth/audio/src/bass_broadcaster_test.c
Normal file
94
tests/bsim/bluetooth/audio/src/bass_broadcaster_test.c
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include "common.h"
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
|
||||
/* TODO: Deprecate in favor of broadcast_source_test */
|
||||
|
||||
#define BROADCAST_ID_ENCODE(broadcast_id) \
|
||||
(((broadcast_id) >> 0) & 0xFF), \
|
||||
(((broadcast_id) >> 8) & 0xFF), \
|
||||
(((broadcast_id) >> 16) & 0xFF)
|
||||
|
||||
static void test_main(void)
|
||||
{
|
||||
int err;
|
||||
uint32_t broadcast_id = 1234;
|
||||
struct bt_le_ext_adv *adv;
|
||||
struct bt_data ad[2] = {
|
||||
BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR),
|
||||
BT_DATA_BYTES(BT_DATA_SVC_DATA16,
|
||||
BT_UUID_16_ENCODE(BT_UUID_BROADCAST_AUDIO_VAL),
|
||||
BROADCAST_ID_ENCODE(broadcast_id))
|
||||
};
|
||||
|
||||
err = bt_enable(NULL);
|
||||
if (err) {
|
||||
FAIL("Bluetooth init failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Bluetooth initialized\n");
|
||||
|
||||
/* Create a non-connectable non-scannable advertising set */
|
||||
err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN_NAME, NULL, &adv);
|
||||
if (err) {
|
||||
FAIL("Failed to create advertising set (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set periodic advertising parameters */
|
||||
err = bt_le_per_adv_set_param(adv, BT_LE_PER_ADV_DEFAULT);
|
||||
if (err) {
|
||||
FAIL("Failed to set periodic advertising parameters (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set adv data */
|
||||
err = bt_le_ext_adv_set_data(adv, ad, ARRAY_SIZE(ad), NULL, 0);
|
||||
if (err) {
|
||||
FAIL("Failed to set advertising data (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Enable Periodic Advertising */
|
||||
err = bt_le_per_adv_start(adv);
|
||||
if (err) {
|
||||
FAIL("Failed to enable periodic advertising (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Start extended advertising */
|
||||
err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT);
|
||||
if (err) {
|
||||
FAIL("Failed to start extended advertising (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Advertising successfully started\n");
|
||||
|
||||
k_sleep(K_SECONDS(10));
|
||||
|
||||
PASS("BASS broadcaster passed\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_bass_broadcaster[] = {
|
||||
{
|
||||
.test_id = "bass_broadcaster",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_main
|
||||
},
|
||||
BSTEST_END_MARKER
|
||||
};
|
||||
|
||||
struct bst_test_list *test_bass_broadcaster_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_bass_broadcaster);
|
||||
}
|
332
tests/bsim/bluetooth/audio/src/broadcast_sink_test.c
Normal file
332
tests/bsim/bluetooth/audio/src/broadcast_sink_test.c
Normal file
|
@ -0,0 +1,332 @@
|
|||
/*
|
||||
* Copyright (c) 2021-2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_BT_BAP_BROADCAST_SINK)
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/audio/audio.h>
|
||||
#include <zephyr/bluetooth/audio/bap.h>
|
||||
#include <zephyr/bluetooth/audio/bap_lc3_preset.h>
|
||||
#include <zephyr/bluetooth/audio/pacs.h>
|
||||
#include "common.h"
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
|
||||
CREATE_FLAG(broadcaster_found);
|
||||
CREATE_FLAG(base_received);
|
||||
CREATE_FLAG(flag_base_metadata_updated);
|
||||
CREATE_FLAG(pa_synced);
|
||||
CREATE_FLAG(flag_syncable);
|
||||
CREATE_FLAG(pa_sync_lost);
|
||||
CREATE_FLAG(flag_received);
|
||||
|
||||
static struct bt_bap_broadcast_sink *g_sink;
|
||||
static struct bt_bap_stream broadcast_sink_streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT];
|
||||
static struct bt_bap_stream *streams[ARRAY_SIZE(broadcast_sink_streams)];
|
||||
static struct bt_bap_lc3_preset preset_16_2_1 = BT_BAP_LC3_BROADCAST_PRESET_16_2_1(
|
||||
BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED);
|
||||
|
||||
static K_SEM_DEFINE(sem_started, 0U, ARRAY_SIZE(streams));
|
||||
static K_SEM_DEFINE(sem_stopped, 0U, ARRAY_SIZE(streams));
|
||||
|
||||
static struct bt_codec_data metadata[CONFIG_BT_CODEC_MAX_METADATA_COUNT];
|
||||
|
||||
/* Create a mask for the maximum BIS we can sync to using the number of streams
|
||||
* we have. We add an additional 1 since the bis indexes start from 1 and not
|
||||
* 0.
|
||||
*/
|
||||
static const uint32_t bis_index_mask = BIT_MASK(ARRAY_SIZE(streams) + 1U);
|
||||
static uint32_t bis_index_bitfield;
|
||||
|
||||
static bool scan_recv_cb(const struct bt_le_scan_recv_info *info,
|
||||
struct net_buf_simple *ad,
|
||||
uint32_t broadcast_id)
|
||||
{
|
||||
SET_FLAG(broadcaster_found);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void scan_term_cb(int err)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("Scan terminated with error: %d", err);
|
||||
}
|
||||
}
|
||||
|
||||
static void pa_synced_cb(struct bt_bap_broadcast_sink *sink,
|
||||
struct bt_le_per_adv_sync *sync,
|
||||
uint32_t broadcast_id)
|
||||
{
|
||||
if (g_sink != NULL) {
|
||||
FAIL("Unexpected PA sync");
|
||||
return;
|
||||
}
|
||||
|
||||
printk("PA synced for broadcast sink %p with broadcast ID 0x%06X\n",
|
||||
sink, broadcast_id);
|
||||
|
||||
g_sink = sink;
|
||||
|
||||
SET_FLAG(pa_synced);
|
||||
}
|
||||
|
||||
static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base)
|
||||
{
|
||||
uint32_t base_bis_index_bitfield = 0U;
|
||||
|
||||
if (TEST_FLAG(base_received)) {
|
||||
|
||||
if (base->subgroup_count > 0 &&
|
||||
memcmp(metadata, base->subgroups[0].codec.meta,
|
||||
sizeof(base->subgroups[0].codec.meta)) != 0) {
|
||||
|
||||
(void)memcpy(metadata, base->subgroups[0].codec.meta,
|
||||
sizeof(base->subgroups[0].codec.meta));
|
||||
|
||||
SET_FLAG(flag_base_metadata_updated);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Received BASE with %u subgroups from broadcast sink %p\n",
|
||||
base->subgroup_count, sink);
|
||||
|
||||
|
||||
for (size_t i = 0U; i < base->subgroup_count; i++) {
|
||||
for (size_t j = 0U; j < base->subgroups[i].bis_count; j++) {
|
||||
const uint8_t index = base->subgroups[i].bis_data[j].index;
|
||||
|
||||
base_bis_index_bitfield |= BIT(index);
|
||||
}
|
||||
}
|
||||
|
||||
bis_index_bitfield = base_bis_index_bitfield & bis_index_mask;
|
||||
|
||||
SET_FLAG(base_received);
|
||||
}
|
||||
|
||||
static void syncable_cb(struct bt_bap_broadcast_sink *sink, bool encrypted)
|
||||
{
|
||||
printk("Broadcast sink %p syncable with%s encryption\n",
|
||||
sink, encrypted ? "" : "out");
|
||||
SET_FLAG(flag_syncable);
|
||||
}
|
||||
|
||||
static void pa_sync_lost_cb(struct bt_bap_broadcast_sink *sink)
|
||||
{
|
||||
if (g_sink == NULL) {
|
||||
FAIL("Unexpected PA sync lost");
|
||||
return;
|
||||
}
|
||||
|
||||
if (TEST_FLAG(pa_sync_lost)) {
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Sink %p disconnected\n", sink);
|
||||
|
||||
g_sink = NULL;
|
||||
|
||||
SET_FLAG(pa_sync_lost);
|
||||
}
|
||||
|
||||
static struct bt_bap_broadcast_sink_cb broadcast_sink_cbs = {
|
||||
.scan_recv = scan_recv_cb,
|
||||
.scan_term = scan_term_cb,
|
||||
.base_recv = base_recv_cb,
|
||||
.pa_synced = pa_synced_cb,
|
||||
.syncable = syncable_cb,
|
||||
.pa_sync_lost = pa_sync_lost_cb
|
||||
};
|
||||
|
||||
static struct bt_pacs_cap cap = {
|
||||
.codec = &preset_16_2_1.codec,
|
||||
};
|
||||
|
||||
static void started_cb(struct bt_bap_stream *stream)
|
||||
{
|
||||
printk("Stream %p started\n", stream);
|
||||
k_sem_give(&sem_started);
|
||||
}
|
||||
|
||||
static void stopped_cb(struct bt_bap_stream *stream, uint8_t reason)
|
||||
{
|
||||
printk("Stream %p stopped with reason 0x%02X\n", stream, reason);
|
||||
k_sem_give(&sem_stopped);
|
||||
}
|
||||
|
||||
static void recv_cb(struct bt_bap_stream *stream,
|
||||
const struct bt_iso_recv_info *info,
|
||||
struct net_buf *buf)
|
||||
{
|
||||
SET_FLAG(flag_received);
|
||||
}
|
||||
|
||||
static struct bt_bap_stream_ops stream_ops = {
|
||||
.started = started_cb,
|
||||
.stopped = stopped_cb,
|
||||
.recv = recv_cb
|
||||
};
|
||||
|
||||
static int init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_enable(NULL);
|
||||
if (err) {
|
||||
FAIL("Bluetooth enable failed (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
printk("Bluetooth initialized\n");
|
||||
|
||||
err = bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap);
|
||||
if (err) {
|
||||
FAIL("Capability register failed (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
bt_bap_broadcast_sink_register_cb(&broadcast_sink_cbs);
|
||||
|
||||
UNSET_FLAG(broadcaster_found);
|
||||
UNSET_FLAG(base_received);
|
||||
UNSET_FLAG(pa_synced);
|
||||
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
|
||||
streams[i] = &broadcast_sink_streams[i];
|
||||
bt_bap_stream_cb_register(streams[i], &stream_ops);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_common(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = init();
|
||||
if (err) {
|
||||
FAIL("Init failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Scanning for broadcast sources\n");
|
||||
err = bt_bap_broadcast_sink_scan_start(BT_LE_SCAN_ACTIVE);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to start scan for broadcast sources: %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_FLAG(broadcaster_found);
|
||||
printk("Broadcast source found, waiting for PA sync\n");
|
||||
WAIT_FOR_FLAG(pa_synced);
|
||||
printk("Broadcast source PA synced, waiting for BASE\n");
|
||||
WAIT_FOR_FLAG(base_received);
|
||||
printk("BASE received\n");
|
||||
|
||||
printk("Waiting for BIG syncable\n");
|
||||
WAIT_FOR_FLAG(flag_syncable);
|
||||
|
||||
printk("Syncing the sink\n");
|
||||
err = bt_bap_broadcast_sink_sync(g_sink, bis_index_bitfield, streams, NULL);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to sync the sink: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Wait for all to be started */
|
||||
printk("Waiting for streams to be started\n");
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
|
||||
k_sem_take(&sem_started, K_FOREVER);
|
||||
}
|
||||
|
||||
printk("Waiting for data\n");
|
||||
WAIT_FOR_FLAG(flag_received);
|
||||
|
||||
/* Ensure that we also see the metadata update */
|
||||
printk("Waiting for metadata update\n");
|
||||
WAIT_FOR_FLAG(flag_base_metadata_updated)
|
||||
|
||||
}
|
||||
|
||||
static void test_main(void)
|
||||
{
|
||||
test_common();
|
||||
|
||||
/* The order of PA sync lost and BIG Sync lost is irrelevant
|
||||
* and depend on timeout parameters. We just wait for PA first, but
|
||||
* either way will work.
|
||||
*/
|
||||
printk("Waiting for PA disconnected\n");
|
||||
WAIT_FOR_FLAG(pa_sync_lost);
|
||||
|
||||
printk("Waiting for streams to be stopped\n");
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
|
||||
k_sem_take(&sem_stopped, K_FOREVER);
|
||||
}
|
||||
|
||||
PASS("Broadcast sink passed\n");
|
||||
}
|
||||
|
||||
static void test_sink_disconnect(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
test_common();
|
||||
|
||||
err = bt_bap_broadcast_sink_stop(g_sink);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to stop sink: %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Waiting for streams to be stopped\n");
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
|
||||
k_sem_take(&sem_stopped, K_FOREVER);
|
||||
}
|
||||
|
||||
err = bt_bap_broadcast_sink_delete(g_sink);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to delete sink: %d", err);
|
||||
return;
|
||||
}
|
||||
/* No "sync lost" event is generated when we initialized the disconnect */
|
||||
g_sink = NULL;
|
||||
|
||||
PASS("Broadcast sink disconnect passed\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_broadcast_sink[] = {
|
||||
{
|
||||
.test_id = "broadcast_sink",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_main
|
||||
},
|
||||
{
|
||||
.test_id = "broadcast_sink_disconnect",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_sink_disconnect
|
||||
},
|
||||
BSTEST_END_MARKER
|
||||
};
|
||||
|
||||
struct bst_test_list *test_broadcast_sink_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_broadcast_sink);
|
||||
}
|
||||
|
||||
#else /* !CONFIG_BT_BAP_BROADCAST_SINK */
|
||||
|
||||
struct bst_test_list *test_broadcast_sink_install(struct bst_test_list *tests)
|
||||
{
|
||||
return tests;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_BAP_BROADCAST_SINK */
|
387
tests/bsim/bluetooth/audio/src/broadcast_source_test.c
Normal file
387
tests/bsim/bluetooth/audio/src/broadcast_source_test.c
Normal file
|
@ -0,0 +1,387 @@
|
|||
/*
|
||||
* Copyright (c) 2021-2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/audio/audio.h>
|
||||
#include <zephyr/bluetooth/audio/bap.h>
|
||||
#include <zephyr/bluetooth/audio/bap_lc3_preset.h>
|
||||
#include "common.h"
|
||||
|
||||
/* When BROADCAST_ENQUEUE_COUNT > 1 we can enqueue enough buffers to ensure that
|
||||
* the controller is never idle
|
||||
*/
|
||||
#define BROADCAST_ENQUEUE_COUNT 2U
|
||||
#define TOTAL_BUF_NEEDED (BROADCAST_ENQUEUE_COUNT * CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT)
|
||||
|
||||
BUILD_ASSERT(CONFIG_BT_ISO_TX_BUF_COUNT >= TOTAL_BUF_NEEDED,
|
||||
"CONFIG_BT_ISO_TX_BUF_COUNT should be at least "
|
||||
"BROADCAST_ENQUEUE_COUNT * CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT");
|
||||
|
||||
NET_BUF_POOL_FIXED_DEFINE(tx_pool,
|
||||
TOTAL_BUF_NEEDED,
|
||||
BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), 8, NULL);
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
static struct bt_bap_stream broadcast_source_streams[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT];
|
||||
static struct bt_bap_stream *streams[ARRAY_SIZE(broadcast_source_streams)];
|
||||
static struct bt_bap_lc3_preset preset_16_2_1 = BT_BAP_LC3_BROADCAST_PRESET_16_2_1(
|
||||
BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED);
|
||||
static struct bt_bap_lc3_preset preset_16_2_2 = BT_BAP_LC3_BROADCAST_PRESET_16_2_2(
|
||||
BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED);
|
||||
CREATE_FLAG(flag_stopping);
|
||||
|
||||
static K_SEM_DEFINE(sem_started, 0U, ARRAY_SIZE(streams));
|
||||
static K_SEM_DEFINE(sem_stopped, 0U, ARRAY_SIZE(streams));
|
||||
|
||||
static void started_cb(struct bt_bap_stream *stream)
|
||||
{
|
||||
printk("Stream %p started\n", stream);
|
||||
k_sem_give(&sem_started);
|
||||
}
|
||||
|
||||
static void stopped_cb(struct bt_bap_stream *stream, uint8_t reason)
|
||||
{
|
||||
printk("Stream %p stopped with reason 0x%02X\n", stream, reason);
|
||||
k_sem_give(&sem_stopped);
|
||||
}
|
||||
|
||||
static void sent_cb(struct bt_bap_stream *stream)
|
||||
{
|
||||
static uint8_t mock_data[CONFIG_BT_ISO_TX_MTU];
|
||||
static bool mock_data_initialized;
|
||||
static uint16_t seq_num;
|
||||
struct net_buf *buf;
|
||||
int ret;
|
||||
|
||||
if (TEST_FLAG(flag_stopping)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mock_data_initialized) {
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(mock_data); i++) {
|
||||
/* Initialize mock data */
|
||||
mock_data[i] = (uint8_t)i;
|
||||
}
|
||||
mock_data_initialized = true;
|
||||
}
|
||||
|
||||
buf = net_buf_alloc(&tx_pool, K_FOREVER);
|
||||
if (buf == NULL) {
|
||||
printk("Could not allocate buffer when sending on %p\n",
|
||||
stream);
|
||||
return;
|
||||
}
|
||||
|
||||
net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE);
|
||||
/* Use preset_16_2_1 as that is the config we end up using */
|
||||
net_buf_add_mem(buf, mock_data, preset_16_2_1.qos.sdu);
|
||||
ret = bt_bap_stream_send(stream, buf, seq_num++,
|
||||
BT_ISO_TIMESTAMP_NONE);
|
||||
if (ret < 0) {
|
||||
/* This will end broadcasting on this stream. */
|
||||
printk("Unable to broadcast data on %p: %d\n", stream, ret);
|
||||
net_buf_unref(buf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static struct bt_bap_stream_ops stream_ops = {
|
||||
.started = started_cb,
|
||||
.stopped = stopped_cb,
|
||||
.sent = sent_cb
|
||||
};
|
||||
|
||||
static int setup_broadcast_source(struct bt_bap_broadcast_source **source)
|
||||
{
|
||||
struct bt_codec_data bis_codec_data = BT_CODEC_DATA(BT_CODEC_CONFIG_LC3_FREQ,
|
||||
BT_CODEC_CONFIG_LC3_FREQ_16KHZ);
|
||||
struct bt_bap_broadcast_source_stream_param
|
||||
stream_params[ARRAY_SIZE(broadcast_source_streams)];
|
||||
struct bt_bap_broadcast_source_subgroup_param
|
||||
subgroup_params[CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT];
|
||||
struct bt_bap_broadcast_source_create_param create_param;
|
||||
int err;
|
||||
|
||||
(void)memset(broadcast_source_streams, 0,
|
||||
sizeof(broadcast_source_streams));
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(stream_params); i++) {
|
||||
stream_params[i].stream = &broadcast_source_streams[i];
|
||||
bt_bap_stream_cb_register(stream_params[i].stream,
|
||||
&stream_ops);
|
||||
stream_params[i].data_count = 1U;
|
||||
stream_params[i].data = &bis_codec_data;
|
||||
}
|
||||
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(subgroup_params); i++) {
|
||||
subgroup_params[i].params_count = 1U;
|
||||
subgroup_params[i].params = &stream_params[i];
|
||||
subgroup_params[i].codec = &preset_16_2_1.codec;
|
||||
}
|
||||
|
||||
create_param.params_count = ARRAY_SIZE(subgroup_params);
|
||||
create_param.params = subgroup_params;
|
||||
create_param.qos = &preset_16_2_2.qos;
|
||||
create_param.packing = BT_ISO_PACKING_SEQUENTIAL;
|
||||
create_param.encryption = false;
|
||||
|
||||
printk("Creating broadcast source with %zu subgroups and %zu streams\n",
|
||||
ARRAY_SIZE(subgroup_params), ARRAY_SIZE(stream_params));
|
||||
err = bt_bap_broadcast_source_create(&create_param, source);
|
||||
if (err != 0) {
|
||||
printk("Unable to create broadcast source: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_extended_adv(struct bt_bap_broadcast_source *source, struct bt_le_ext_adv **adv)
|
||||
{
|
||||
/* Broadcast Audio Streaming Endpoint advertising data */
|
||||
NET_BUF_SIMPLE_DEFINE(ad_buf,
|
||||
BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE);
|
||||
NET_BUF_SIMPLE_DEFINE(base_buf, 128);
|
||||
struct bt_data ext_ad;
|
||||
struct bt_data per_ad;
|
||||
uint32_t broadcast_id;
|
||||
int err;
|
||||
|
||||
/* Create a non-connectable non-scannable advertising set */
|
||||
err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN_NAME, NULL, adv);
|
||||
if (err != 0) {
|
||||
printk("Unable to create extended advertising set: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Set periodic advertising parameters */
|
||||
err = bt_le_per_adv_set_param(*adv, BT_LE_PER_ADV_DEFAULT);
|
||||
if (err) {
|
||||
printk("Failed to set periodic advertising parameters: %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = bt_bap_broadcast_source_get_id(source, &broadcast_id);
|
||||
if (err != 0) {
|
||||
printk("Unable to get broadcast ID: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Setup extended advertising data */
|
||||
net_buf_simple_add_le16(&ad_buf, BT_UUID_BROADCAST_AUDIO_VAL);
|
||||
net_buf_simple_add_le24(&ad_buf, broadcast_id);
|
||||
ext_ad.type = BT_DATA_SVC_DATA16;
|
||||
ext_ad.data_len = ad_buf.len;
|
||||
ext_ad.data = ad_buf.data;
|
||||
err = bt_le_ext_adv_set_data(*adv, &ext_ad, 1, NULL, 0);
|
||||
if (err != 0) {
|
||||
printk("Failed to set extended advertising data: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Setup periodic advertising data */
|
||||
err = bt_bap_broadcast_source_get_base(source, &base_buf);
|
||||
if (err != 0) {
|
||||
printk("Failed to get encoded BASE: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
per_ad.type = BT_DATA_SVC_DATA16;
|
||||
per_ad.data_len = base_buf.len;
|
||||
per_ad.data = base_buf.data;
|
||||
err = bt_le_per_adv_set_data(*adv, &per_ad, 1);
|
||||
if (err != 0) {
|
||||
printk("Failed to set periodic advertising data: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Start 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 err;
|
||||
}
|
||||
|
||||
/* Enable Periodic Advertising */
|
||||
err = bt_le_per_adv_start(*adv);
|
||||
if (err) {
|
||||
printk("Failed to enable periodic advertising: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stop_extended_adv(struct bt_le_ext_adv *adv)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_le_per_adv_stop(adv);
|
||||
if (err) {
|
||||
printk("Failed to stop periodic advertising: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = bt_le_ext_adv_stop(adv);
|
||||
if (err) {
|
||||
printk("Failed to stop extended advertising: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = bt_le_ext_adv_delete(adv);
|
||||
if (err) {
|
||||
printk("Failed to delete extended advertising: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_main(void)
|
||||
{
|
||||
struct bt_codec_data new_metadata[1] =
|
||||
BT_CODEC_LC3_CONFIG_META(BT_AUDIO_CONTEXT_TYPE_ALERTS);
|
||||
struct bt_bap_broadcast_source *source;
|
||||
struct bt_le_ext_adv *adv;
|
||||
int err;
|
||||
|
||||
err = bt_enable(NULL);
|
||||
if (err) {
|
||||
FAIL("Bluetooth init failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Bluetooth initialized\n");
|
||||
|
||||
err = setup_broadcast_source(&source);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to setup broadcast source: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = setup_extended_adv(source, &adv);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to setup extended advertising: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Reconfiguring broadcast source\n");
|
||||
err = bt_bap_broadcast_source_reconfig(source, &preset_16_2_1.codec, &preset_16_2_1.qos);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to reconfigure broadcast source: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Starting broadcast source\n");
|
||||
err = bt_bap_broadcast_source_start(source, adv);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to start broadcast source: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Wait for all to be started */
|
||||
printk("Waiting for streams to be started\n");
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
|
||||
k_sem_take(&sem_started, K_FOREVER);
|
||||
}
|
||||
|
||||
/* Initialize sending */
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
|
||||
for (unsigned int j = 0U; j < BROADCAST_ENQUEUE_COUNT; j++) {
|
||||
sent_cb(streams[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Keeping running for a little while */
|
||||
k_sleep(K_SECONDS(15));
|
||||
|
||||
/* Update metadata while streaming */
|
||||
printk("Updating metadata\n");
|
||||
err = bt_bap_broadcast_source_update_metadata(source, new_metadata,
|
||||
ARRAY_SIZE(new_metadata));
|
||||
if (err != 0) {
|
||||
FAIL("Failed to update metadata broadcast source: %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Keeping running for a little while */
|
||||
k_sleep(K_SECONDS(5));
|
||||
|
||||
printk("Stopping broadcast source\n");
|
||||
SET_FLAG(flag_stopping);
|
||||
err = bt_bap_broadcast_source_stop(source);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to stop broadcast source: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Wait for all to be stopped */
|
||||
printk("Waiting for streams to be stopped\n");
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
|
||||
k_sem_take(&sem_stopped, K_FOREVER);
|
||||
}
|
||||
|
||||
printk("Deleting broadcast source\n");
|
||||
err = bt_bap_broadcast_source_delete(source);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to delete broadcast source: %d\n", err);
|
||||
return;
|
||||
}
|
||||
source = NULL;
|
||||
|
||||
|
||||
err = stop_extended_adv(adv);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to stop extended advertising: %d\n", err);
|
||||
return;
|
||||
}
|
||||
adv = NULL;
|
||||
|
||||
/* Recreate broadcast source to verify that it's possible */
|
||||
printk("Recreating broadcast source\n");
|
||||
err = setup_broadcast_source(&source);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to setup broadcast source: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Deleting broadcast source\n");
|
||||
err = bt_bap_broadcast_source_delete(source);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to delete broadcast source: %d\n", err);
|
||||
return;
|
||||
}
|
||||
source = NULL;
|
||||
|
||||
PASS("Broadcast source passed\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_broadcast_source[] = {
|
||||
{
|
||||
.test_id = "broadcast_source",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_main
|
||||
},
|
||||
BSTEST_END_MARKER
|
||||
};
|
||||
|
||||
struct bst_test_list *test_broadcast_source_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_broadcast_source);
|
||||
}
|
||||
|
||||
#else /* CONFIG_BT_BAP_BROADCAST_SOURCE */
|
||||
|
||||
struct bst_test_list *test_broadcast_source_install(struct bst_test_list *tests)
|
||||
{
|
||||
return tests;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
|
359
tests/bsim/bluetooth/audio/src/cap_acceptor_test.c
Normal file
359
tests/bsim/bluetooth/audio/src/cap_acceptor_test.c
Normal file
|
@ -0,0 +1,359 @@
|
|||
/*
|
||||
* Copyright (c) 2022-2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_BT_CAP_ACCEPTOR)
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/audio/bap_lc3_preset.h>
|
||||
#include <zephyr/bluetooth/audio/cap.h>
|
||||
#include <zephyr/bluetooth/audio/pacs.h>
|
||||
#include "common.h"
|
||||
#include "bap_unicast_common.h"
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
|
||||
CREATE_FLAG(flag_broadcaster_found);
|
||||
CREATE_FLAG(flag_base_received);
|
||||
CREATE_FLAG(flag_pa_synced);
|
||||
CREATE_FLAG(flag_syncable);
|
||||
CREATE_FLAG(flag_received);
|
||||
CREATE_FLAG(flag_pa_sync_lost);
|
||||
|
||||
static struct bt_bap_broadcast_sink *g_broadcast_sink;
|
||||
static struct bt_cap_stream broadcast_sink_streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT];
|
||||
static struct bt_bap_lc3_preset broadcast_preset_16_2_1 = BT_BAP_LC3_BROADCAST_PRESET_16_2_1(
|
||||
BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED);
|
||||
|
||||
static K_SEM_DEFINE(sem_broadcast_started, 0U, ARRAY_SIZE(broadcast_sink_streams));
|
||||
static K_SEM_DEFINE(sem_broadcast_stopped, 0U, ARRAY_SIZE(broadcast_sink_streams));
|
||||
|
||||
/* Create a mask for the maximum BIS we can sync to using the number of
|
||||
* broadcast_sink_streams we have. We add an additional 1 since the bis indexes
|
||||
* start from 1 and not 0.
|
||||
*/
|
||||
static const uint32_t bis_index_mask = BIT_MASK(ARRAY_SIZE(broadcast_sink_streams) + 1U);
|
||||
static uint32_t bis_index_bitfield;
|
||||
|
||||
static bool scan_recv_cb(const struct bt_le_scan_recv_info *info,
|
||||
struct net_buf_simple *ad,
|
||||
uint32_t broadcast_id)
|
||||
{
|
||||
SET_FLAG(flag_broadcaster_found);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void scan_term_cb(int err)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("Scan terminated with error: %d", err);
|
||||
}
|
||||
}
|
||||
|
||||
static void pa_synced_cb(struct bt_bap_broadcast_sink *sink,
|
||||
struct bt_le_per_adv_sync *sync,
|
||||
uint32_t broadcast_id)
|
||||
{
|
||||
if (g_broadcast_sink != NULL) {
|
||||
FAIL("Unexpected PA sync");
|
||||
return;
|
||||
}
|
||||
|
||||
printk("PA synced for broadcast sink %p with broadcast ID 0x%06X\n",
|
||||
sink, broadcast_id);
|
||||
|
||||
g_broadcast_sink = sink;
|
||||
|
||||
SET_FLAG(flag_pa_synced);
|
||||
}
|
||||
|
||||
static bool valid_subgroup_metadata(const struct bt_bap_base_subgroup *subgroup)
|
||||
{
|
||||
bool stream_context_found = false;
|
||||
|
||||
for (size_t j = 0U; j < subgroup->codec.meta_count; j++) {
|
||||
const struct bt_data *metadata = &subgroup->codec.meta[j].data;
|
||||
|
||||
if (metadata->type == BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT) {
|
||||
if (metadata->data_len != 2) { /* Stream context size */
|
||||
printk("Subgroup has invalid streaming context length: %u\n",
|
||||
metadata->data_len);
|
||||
return false;
|
||||
}
|
||||
|
||||
stream_context_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!stream_context_found) {
|
||||
printk("Subgroup did not have streaming context\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base)
|
||||
{
|
||||
uint32_t base_bis_index_bitfield = 0U;
|
||||
|
||||
if (TEST_FLAG(flag_base_received)) {
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Received BASE with %u subgroups from broadcast sink %p\n",
|
||||
base->subgroup_count, sink);
|
||||
|
||||
if (base->subgroup_count == 0) {
|
||||
FAIL("base->subgroup_count was 0");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
for (size_t i = 0U; i < base->subgroup_count; i++) {
|
||||
const struct bt_bap_base_subgroup *subgroup = &base->subgroups[i];
|
||||
|
||||
for (size_t j = 0U; j < subgroup->bis_count; j++) {
|
||||
const uint8_t index = subgroup->bis_data[j].index;
|
||||
|
||||
base_bis_index_bitfield |= BIT(index);
|
||||
}
|
||||
|
||||
if (!valid_subgroup_metadata(subgroup)) {
|
||||
FAIL("Subgroup[%zu] has invalid metadata\n", i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bis_index_bitfield = base_bis_index_bitfield & bis_index_mask;
|
||||
|
||||
SET_FLAG(flag_base_received);
|
||||
}
|
||||
|
||||
static void syncable_cb(struct bt_bap_broadcast_sink *sink, bool encrypted)
|
||||
{
|
||||
printk("Broadcast sink %p syncable with%s encryption\n",
|
||||
sink, encrypted ? "" : "out");
|
||||
SET_FLAG(flag_syncable);
|
||||
}
|
||||
|
||||
static void pa_sync_lost_cb(struct bt_bap_broadcast_sink *sink)
|
||||
{
|
||||
if (g_broadcast_sink == NULL) {
|
||||
FAIL("Unexpected PA sync lost");
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Sink %p disconnected\n", sink);
|
||||
|
||||
SET_FLAG(flag_pa_sync_lost);
|
||||
|
||||
g_broadcast_sink = NULL;
|
||||
}
|
||||
|
||||
static struct bt_bap_broadcast_sink_cb broadcast_sink_cbs = {
|
||||
.scan_recv = scan_recv_cb,
|
||||
.scan_term = scan_term_cb,
|
||||
.base_recv = base_recv_cb,
|
||||
.pa_synced = pa_synced_cb,
|
||||
.syncable = syncable_cb,
|
||||
.pa_sync_lost = pa_sync_lost_cb
|
||||
};
|
||||
|
||||
static void started_cb(struct bt_bap_stream *stream)
|
||||
{
|
||||
printk("Stream %p started\n", stream);
|
||||
k_sem_give(&sem_broadcast_started);
|
||||
}
|
||||
|
||||
static void stopped_cb(struct bt_bap_stream *stream, uint8_t reason)
|
||||
{
|
||||
printk("Stream %p stopped with reason 0x%02X\n", stream, reason);
|
||||
k_sem_give(&sem_broadcast_stopped);
|
||||
}
|
||||
|
||||
static void recv_cb(struct bt_bap_stream *stream, const struct bt_iso_recv_info *info,
|
||||
struct net_buf *buf)
|
||||
{
|
||||
SET_FLAG(flag_received);
|
||||
}
|
||||
|
||||
static struct bt_bap_stream_ops broadcast_stream_ops = {
|
||||
.started = started_cb, .stopped = stopped_cb, .recv = recv_cb};
|
||||
|
||||
/* TODO: Expand with CAP service data */
|
||||
static const struct bt_data cap_acceptor_ad[] = {
|
||||
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
|
||||
BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(BT_UUID_CAS_VAL)),
|
||||
};
|
||||
|
||||
static struct bt_csip_set_member_svc_inst *csip_set_member;
|
||||
|
||||
static void init(void)
|
||||
{
|
||||
struct bt_csip_set_member_register_param csip_set_member_param = {
|
||||
.set_size = 3,
|
||||
.rank = 1,
|
||||
.lockable = true,
|
||||
/* Using the CSIP_SET_MEMBER test sample SIRK */
|
||||
.set_sirk = { 0xcd, 0xcc, 0x72, 0xdd, 0x86, 0x8c, 0xcd, 0xce,
|
||||
0x22, 0xfd, 0xa1, 0x21, 0x09, 0x7d, 0x7d, 0x45 },
|
||||
};
|
||||
|
||||
int err;
|
||||
|
||||
err = bt_enable(NULL);
|
||||
if (err != 0) {
|
||||
FAIL("Bluetooth enable failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Bluetooth initialized\n");
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER)) {
|
||||
err = bt_cap_acceptor_register(&csip_set_member_param,
|
||||
&csip_set_member);
|
||||
if (err != 0) {
|
||||
FAIL("CAP acceptor failed to register (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_SERVER)) {
|
||||
err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, cap_acceptor_ad,
|
||||
ARRAY_SIZE(cap_acceptor_ad), NULL, 0);
|
||||
if (err != 0) {
|
||||
FAIL("Advertising failed to start (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_BAP_BROADCAST_SINK)) {
|
||||
static struct bt_pacs_cap cap = {
|
||||
.codec = &broadcast_preset_16_2_1.codec,
|
||||
};
|
||||
|
||||
err = bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap);
|
||||
if (err != 0) {
|
||||
FAIL("Broadcast capability register failed (err %d)\n",
|
||||
err);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bt_bap_broadcast_sink_register_cb(&broadcast_sink_cbs);
|
||||
|
||||
UNSET_FLAG(flag_broadcaster_found);
|
||||
UNSET_FLAG(flag_base_received);
|
||||
UNSET_FLAG(flag_pa_synced);
|
||||
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(broadcast_sink_streams); i++) {
|
||||
bt_cap_stream_ops_register(&broadcast_sink_streams[i],
|
||||
&broadcast_stream_ops);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_cap_acceptor_unicast(void)
|
||||
{
|
||||
init();
|
||||
|
||||
/* TODO: When babblesim supports ISO, wait for audio stream to pass */
|
||||
|
||||
WAIT_FOR_FLAG(flag_connected);
|
||||
|
||||
PASS("CAP acceptor unicast passed\n");
|
||||
}
|
||||
|
||||
static void test_cap_acceptor_broadcast(void)
|
||||
{
|
||||
static struct bt_bap_stream *bap_streams[ARRAY_SIZE(broadcast_sink_streams)];
|
||||
int err;
|
||||
|
||||
init();
|
||||
|
||||
printk("Scanning for broadcast sources\n");
|
||||
err = bt_bap_broadcast_sink_scan_start(BT_LE_SCAN_ACTIVE);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to start scan for broadcast sources: %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_FLAG(flag_broadcaster_found);
|
||||
printk("Broadcast source found, waiting for PA sync\n");
|
||||
WAIT_FOR_FLAG(flag_pa_synced);
|
||||
printk("Broadcast source PA synced, waiting for BASE\n");
|
||||
WAIT_FOR_FLAG(flag_base_received);
|
||||
printk("BASE received\n");
|
||||
|
||||
printk("Waiting for BIG syncable\n");
|
||||
WAIT_FOR_FLAG(flag_syncable);
|
||||
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(broadcast_sink_streams); i++) {
|
||||
bap_streams[i] = &broadcast_sink_streams[i].bap_stream;
|
||||
}
|
||||
|
||||
printk("Syncing the sink\n");
|
||||
err = bt_bap_broadcast_sink_sync(g_broadcast_sink, bis_index_bitfield, bap_streams, NULL);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to sync the sink: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Wait for all to be started */
|
||||
printk("Waiting for broadcast_sink_streams to be started\n");
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(broadcast_sink_streams); i++) {
|
||||
k_sem_take(&sem_broadcast_started, K_FOREVER);
|
||||
}
|
||||
|
||||
printk("Waiting for data\n");
|
||||
WAIT_FOR_FLAG(flag_received);
|
||||
|
||||
/* The order of PA sync lost and BIG Sync lost is irrelevant
|
||||
* and depend on timeout parameters. We just wait for PA first, but
|
||||
* either way will work.
|
||||
*/
|
||||
printk("Waiting for PA disconnected\n");
|
||||
WAIT_FOR_FLAG(flag_pa_sync_lost);
|
||||
|
||||
printk("Waiting for streams to be stopped\n");
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(broadcast_sink_streams); i++) {
|
||||
k_sem_take(&sem_broadcast_stopped, K_FOREVER);
|
||||
}
|
||||
|
||||
PASS("CAP acceptor broadcast passed\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_cap_acceptor[] = {
|
||||
{
|
||||
.test_id = "cap_acceptor_unicast",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_cap_acceptor_unicast
|
||||
},
|
||||
{
|
||||
.test_id = "cap_acceptor_broadcast",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_cap_acceptor_broadcast
|
||||
},
|
||||
BSTEST_END_MARKER
|
||||
};
|
||||
|
||||
struct bst_test_list *test_cap_acceptor_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_cap_acceptor);
|
||||
}
|
||||
|
||||
#else /* !(CONFIG_BT_CAP_ACCEPTOR) */
|
||||
|
||||
struct bst_test_list *test_cap_acceptor_install(struct bst_test_list *tests)
|
||||
{
|
||||
return tests;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_CAP_ACCEPTOR */
|
486
tests/bsim/bluetooth/audio/src/cap_initiator_test.c
Normal file
486
tests/bsim/bluetooth/audio/src/cap_initiator_test.c
Normal file
|
@ -0,0 +1,486 @@
|
|||
/*
|
||||
* Copyright (c) 2022-2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_BT_CAP_INITIATOR)
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/audio/bap_lc3_preset.h>
|
||||
#include <zephyr/bluetooth/audio/cap.h>
|
||||
#include "common.h"
|
||||
#include "bap_unicast_common.h"
|
||||
|
||||
|
||||
/* When BROADCAST_ENQUEUE_COUNT > 1 we can enqueue enough buffers to ensure that
|
||||
* the controller is never idle
|
||||
*/
|
||||
#define BROADCAST_ENQUEUE_COUNT 2U
|
||||
#define TOTAL_BUF_NEEDED (BROADCAST_ENQUEUE_COUNT * CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT)
|
||||
|
||||
BUILD_ASSERT(CONFIG_BT_ISO_TX_BUF_COUNT >= TOTAL_BUF_NEEDED,
|
||||
"CONFIG_BT_ISO_TX_BUF_COUNT should be at least "
|
||||
"BROADCAST_ENQUEUE_COUNT * CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT");
|
||||
|
||||
NET_BUF_POOL_FIXED_DEFINE(tx_pool,
|
||||
TOTAL_BUF_NEEDED,
|
||||
BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), 8, NULL);
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
static struct bt_cap_stream broadcast_source_streams[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT];
|
||||
static struct bt_cap_stream *broadcast_streams[ARRAY_SIZE(broadcast_source_streams)];
|
||||
static struct bt_bap_lc3_preset broadcast_preset_16_2_1 = BT_BAP_LC3_BROADCAST_PRESET_16_2_1(
|
||||
BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_MEDIA);
|
||||
|
||||
static K_SEM_DEFINE(sem_broadcast_started, 0U, ARRAY_SIZE(broadcast_streams));
|
||||
static K_SEM_DEFINE(sem_broadcast_stopped, 0U, ARRAY_SIZE(broadcast_streams));
|
||||
|
||||
CREATE_FLAG(flag_discovered);
|
||||
CREATE_FLAG(flag_mtu_exchanged);
|
||||
CREATE_FLAG(flag_broadcast_stopping);
|
||||
|
||||
static void broadcast_started_cb(struct bt_bap_stream *stream)
|
||||
{
|
||||
printk("Stream %p started\n", stream);
|
||||
k_sem_give(&sem_broadcast_started);
|
||||
}
|
||||
|
||||
static void broadcast_stopped_cb(struct bt_bap_stream *stream, uint8_t reason)
|
||||
{
|
||||
printk("Stream %p stopped with reason 0x%02X\n", stream, reason);
|
||||
k_sem_give(&sem_broadcast_stopped);
|
||||
}
|
||||
|
||||
static void broadcast_sent_cb(struct bt_bap_stream *stream)
|
||||
{
|
||||
static uint8_t mock_data[CONFIG_BT_ISO_TX_MTU];
|
||||
static bool mock_data_initialized;
|
||||
static uint32_t seq_num;
|
||||
struct net_buf *buf;
|
||||
int ret;
|
||||
|
||||
if (broadcast_preset_16_2_1.qos.sdu > CONFIG_BT_ISO_TX_MTU) {
|
||||
FAIL("Invalid SDU %u for the MTU: %d",
|
||||
broadcast_preset_16_2_1.qos.sdu, CONFIG_BT_ISO_TX_MTU);
|
||||
return;
|
||||
}
|
||||
|
||||
if (TEST_FLAG(flag_broadcast_stopping)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mock_data_initialized) {
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(mock_data); i++) {
|
||||
/* Initialize mock data */
|
||||
mock_data[i] = (uint8_t)i;
|
||||
}
|
||||
mock_data_initialized = true;
|
||||
}
|
||||
|
||||
buf = net_buf_alloc(&tx_pool, K_FOREVER);
|
||||
if (buf == NULL) {
|
||||
printk("Could not allocate buffer when sending on %p\n",
|
||||
stream);
|
||||
return;
|
||||
}
|
||||
|
||||
net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE);
|
||||
net_buf_add_mem(buf, mock_data, broadcast_preset_16_2_1.qos.sdu);
|
||||
ret = bt_bap_stream_send(stream, buf, seq_num++, BT_ISO_TIMESTAMP_NONE);
|
||||
if (ret < 0) {
|
||||
/* This will end broadcasting on this stream. */
|
||||
printk("Unable to broadcast data on %p: %d\n", stream, ret);
|
||||
net_buf_unref(buf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static struct bt_bap_stream_ops broadcast_stream_ops = {.started = broadcast_started_cb,
|
||||
.stopped = broadcast_stopped_cb,
|
||||
.sent = broadcast_sent_cb};
|
||||
|
||||
static void cap_discovery_complete_cb(struct bt_conn *conn, int err,
|
||||
const struct bt_csip_set_coordinator_csis_inst *csis_inst)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("Failed to discover CAS: %d", err);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER)) {
|
||||
if (csis_inst == NULL) {
|
||||
FAIL("Failed to discover CAS CSIS");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Found CAS with CSIS %p\n", csis_inst);
|
||||
} else {
|
||||
printk("Found CAS\n");
|
||||
}
|
||||
|
||||
SET_FLAG(flag_discovered);
|
||||
}
|
||||
|
||||
static struct bt_cap_initiator_cb cap_cb = {
|
||||
.unicast_discovery_complete = cap_discovery_complete_cb
|
||||
};
|
||||
|
||||
static void att_mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx)
|
||||
{
|
||||
printk("MTU exchanged\n");
|
||||
SET_FLAG(flag_mtu_exchanged);
|
||||
}
|
||||
|
||||
static struct bt_gatt_cb gatt_callbacks = {
|
||||
.att_mtu_updated = att_mtu_updated,
|
||||
};
|
||||
|
||||
static void init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_enable(NULL);
|
||||
if (err != 0) {
|
||||
FAIL("Bluetooth enable failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT)) {
|
||||
bt_gatt_cb_register(&gatt_callbacks);
|
||||
|
||||
err = bt_cap_initiator_register_cb(&cap_cb);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to register CAP callbacks (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
(void)memset(broadcast_source_streams, 0,
|
||||
sizeof(broadcast_source_streams));
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(broadcast_streams); i++) {
|
||||
broadcast_streams[i] = &broadcast_source_streams[i];
|
||||
bt_cap_stream_ops_register(broadcast_streams[i],
|
||||
&broadcast_stream_ops);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void scan_and_connect(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
|
||||
if (err != 0) {
|
||||
FAIL("Scanning failed to start (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Scanning successfully started\n");
|
||||
WAIT_FOR_FLAG(flag_connected);
|
||||
}
|
||||
|
||||
static void discover_cas(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
UNSET_FLAG(flag_discovered);
|
||||
|
||||
err = bt_cap_initiator_unicast_discover(default_conn);
|
||||
if (err != 0) {
|
||||
printk("Failed to discover CAS: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_FLAG(flag_discovered);
|
||||
}
|
||||
|
||||
static void test_cap_initiator_unicast(void)
|
||||
{
|
||||
init();
|
||||
|
||||
scan_and_connect();
|
||||
|
||||
WAIT_FOR_FLAG(flag_mtu_exchanged);
|
||||
|
||||
discover_cas();
|
||||
|
||||
PASS("CAP initiator unicast passed\n");
|
||||
}
|
||||
|
||||
static int setup_extended_adv(struct bt_le_ext_adv **adv)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Create a non-connectable non-scannable advertising set */
|
||||
err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN_NAME, NULL, adv);
|
||||
if (err != 0) {
|
||||
printk("Unable to create extended advertising set: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Set periodic advertising parameters */
|
||||
err = bt_le_per_adv_set_param(*adv, BT_LE_PER_ADV_DEFAULT);
|
||||
if (err) {
|
||||
printk("Failed to set periodic advertising parameters: %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_extended_adv_data(struct bt_cap_broadcast_source *source,
|
||||
struct bt_le_ext_adv *adv)
|
||||
{
|
||||
/* Broadcast Audio Streaming Endpoint advertising data */
|
||||
NET_BUF_SIMPLE_DEFINE(ad_buf,
|
||||
BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE);
|
||||
NET_BUF_SIMPLE_DEFINE(base_buf, 128);
|
||||
struct bt_data ext_ad;
|
||||
struct bt_data per_ad;
|
||||
uint32_t broadcast_id;
|
||||
int err;
|
||||
|
||||
err = bt_cap_initiator_broadcast_get_id(source, &broadcast_id);
|
||||
if (err != 0) {
|
||||
printk("Unable to get broadcast ID: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Setup extended advertising data */
|
||||
net_buf_simple_add_le16(&ad_buf, BT_UUID_BROADCAST_AUDIO_VAL);
|
||||
net_buf_simple_add_le24(&ad_buf, broadcast_id);
|
||||
ext_ad.type = BT_DATA_SVC_DATA16;
|
||||
ext_ad.data_len = ad_buf.len + sizeof(ext_ad.type);
|
||||
ext_ad.data = ad_buf.data;
|
||||
err = bt_le_ext_adv_set_data(adv, &ext_ad, 1, NULL, 0);
|
||||
if (err != 0) {
|
||||
printk("Failed to set extended advertising data: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Setup periodic advertising data */
|
||||
err = bt_cap_initiator_broadcast_get_base(source, &base_buf);
|
||||
if (err != 0) {
|
||||
printk("Failed to get encoded BASE: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
per_ad.type = BT_DATA_SVC_DATA16;
|
||||
per_ad.data_len = base_buf.len;
|
||||
per_ad.data = base_buf.data;
|
||||
err = bt_le_per_adv_set_data(adv, &per_ad, 1);
|
||||
if (err != 0) {
|
||||
printk("Failed to set periodic advertising data: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int start_extended_adv(struct bt_le_ext_adv *adv)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Start 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 err;
|
||||
}
|
||||
|
||||
/* Enable Periodic Advertising */
|
||||
err = bt_le_per_adv_start(adv);
|
||||
if (err) {
|
||||
printk("Failed to enable periodic advertising: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stop_and_delete_extended_adv(struct bt_le_ext_adv *adv)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Stop extended advertising */
|
||||
err = bt_le_per_adv_stop(adv);
|
||||
if (err) {
|
||||
printk("Failed to stop periodic advertising: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = bt_le_ext_adv_stop(adv);
|
||||
if (err) {
|
||||
printk("Failed to stop extended advertising: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = bt_le_ext_adv_delete(adv);
|
||||
if (err) {
|
||||
printk("Failed to delete extended advertising: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_cap_initiator_broadcast(void)
|
||||
{
|
||||
struct bt_codec_data bis_codec_data = BT_CODEC_DATA(BT_CODEC_CONFIG_LC3_FREQ,
|
||||
BT_CODEC_CONFIG_LC3_FREQ_16KHZ);
|
||||
const uint16_t mock_ccid = 0x1234;
|
||||
const struct bt_codec_data new_metadata[] = {
|
||||
BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT,
|
||||
(BT_AUDIO_CONTEXT_TYPE_MEDIA & 0xFFU),
|
||||
((BT_AUDIO_CONTEXT_TYPE_MEDIA >> 8) & 0xFFU)),
|
||||
BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST,
|
||||
(mock_ccid & 0xFFU),
|
||||
((mock_ccid >> 8) & 0xFFU)),
|
||||
};
|
||||
struct bt_cap_initiator_broadcast_stream_param
|
||||
stream_params[ARRAY_SIZE(broadcast_source_streams)];
|
||||
struct bt_cap_initiator_broadcast_subgroup_param subgroup_param;
|
||||
struct bt_cap_initiator_broadcast_create_param create_param;
|
||||
struct bt_cap_broadcast_source *broadcast_source;
|
||||
struct bt_le_ext_adv *adv;
|
||||
int err;
|
||||
|
||||
(void)memset(broadcast_source_streams, 0,
|
||||
sizeof(broadcast_source_streams));
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(broadcast_streams); i++) {
|
||||
stream_params[i].stream = &broadcast_source_streams[i];
|
||||
bt_cap_stream_ops_register(stream_params[i].stream,
|
||||
&broadcast_stream_ops);
|
||||
stream_params[i].data_count = 1U;
|
||||
stream_params[i].data = &bis_codec_data;
|
||||
}
|
||||
|
||||
subgroup_param.stream_count = ARRAY_SIZE(broadcast_streams);
|
||||
subgroup_param.stream_params = stream_params;
|
||||
subgroup_param.codec = &broadcast_preset_16_2_1.codec;
|
||||
|
||||
create_param.subgroup_count = 1U;
|
||||
create_param.subgroup_params = &subgroup_param;
|
||||
create_param.qos = &broadcast_preset_16_2_1.qos;
|
||||
create_param.packing = BT_ISO_PACKING_SEQUENTIAL;
|
||||
create_param.encryption = false;
|
||||
|
||||
init();
|
||||
|
||||
printk("Creating broadcast source with %zu broadcast_streams\n",
|
||||
ARRAY_SIZE(broadcast_streams));
|
||||
|
||||
err = setup_extended_adv(&adv);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to setup extended advertiser: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_cap_initiator_broadcast_audio_start(&create_param, adv,
|
||||
&broadcast_source);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to start broadcast source: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = setup_extended_adv_data(broadcast_source, adv);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to setup extended advertising data: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = start_extended_adv(adv);
|
||||
if (err != 0) {
|
||||
FAIL("Unable to start extended advertiser: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Wait for all to be started */
|
||||
printk("Waiting for broadcast_streams to be started\n");
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(broadcast_streams); i++) {
|
||||
k_sem_take(&sem_broadcast_started, K_FOREVER);
|
||||
}
|
||||
|
||||
/* Initialize sending */
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(broadcast_streams); i++) {
|
||||
for (unsigned int j = 0U; j < BROADCAST_ENQUEUE_COUNT; j++) {
|
||||
broadcast_sent_cb(&broadcast_streams[i]->bap_stream);
|
||||
}
|
||||
}
|
||||
|
||||
/* Keeping running for a little while */
|
||||
k_sleep(K_SECONDS(5));
|
||||
|
||||
err = bt_cap_initiator_broadcast_audio_update(broadcast_source,
|
||||
new_metadata,
|
||||
ARRAY_SIZE(new_metadata));
|
||||
if (err != 0) {
|
||||
FAIL("Failed to update broadcast source metadata: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Keeping running for a little while */
|
||||
k_sleep(K_SECONDS(5));
|
||||
|
||||
err = bt_cap_initiator_broadcast_audio_stop(broadcast_source);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to stop broadcast source: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Wait for all to be stopped */
|
||||
printk("Waiting for broadcast_streams to be stopped\n");
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(broadcast_streams); i++) {
|
||||
k_sem_take(&sem_broadcast_stopped, K_FOREVER);
|
||||
}
|
||||
|
||||
err = bt_cap_initiator_broadcast_audio_delete(broadcast_source);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to stop broadcast source: %d\n", err);
|
||||
return;
|
||||
}
|
||||
broadcast_source = NULL;
|
||||
|
||||
err = stop_and_delete_extended_adv(adv);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to stop and delete extended advertising: %d\n", err);
|
||||
return;
|
||||
}
|
||||
adv = NULL;
|
||||
|
||||
PASS("CAP initiator broadcast passed\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_cap_initiator[] = {
|
||||
#if defined(CONFIG_BT_BAP_UNICAST_CLIENT)
|
||||
{.test_id = "cap_initiator_unicast",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_cap_initiator_unicast},
|
||||
#endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
|
||||
#if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
|
||||
{.test_id = "cap_initiator_broadcast",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_cap_initiator_broadcast},
|
||||
#endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
|
||||
BSTEST_END_MARKER};
|
||||
|
||||
struct bst_test_list *test_cap_initiator_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_cap_initiator);
|
||||
}
|
||||
|
||||
#else /* !(CONFIG_BT_CAP_INITIATOR) */
|
||||
|
||||
struct bst_test_list *test_cap_initiator_install(struct bst_test_list *tests)
|
||||
{
|
||||
return tests;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_CAP_INITIATOR */
|
110
tests/bsim/bluetooth/audio/src/common.c
Normal file
110
tests/bsim/bluetooth/audio/src/common.c
Normal file
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Bose Corporation
|
||||
* Copyright (c) 2020-2021 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
struct bt_conn *default_conn;
|
||||
atomic_t flag_connected;
|
||||
|
||||
const struct bt_data ad[AD_SIZE] = {
|
||||
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR))
|
||||
};
|
||||
|
||||
void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
|
||||
struct net_buf_simple *ad)
|
||||
{
|
||||
char addr_str[BT_ADDR_LE_STR_LEN];
|
||||
int err;
|
||||
|
||||
if (default_conn) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* We're only interested in connectable events */
|
||||
if (type != BT_HCI_ADV_IND && type != BT_HCI_ADV_DIRECT_IND) {
|
||||
return;
|
||||
}
|
||||
|
||||
bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
|
||||
printk("Device found: %s (RSSI %d)\n", addr_str, rssi);
|
||||
|
||||
/* connect only to devices in close proximity */
|
||||
if (rssi < -70) {
|
||||
FAIL("RSSI too low");
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Stopping scan\n");
|
||||
if (bt_le_scan_stop()) {
|
||||
FAIL("Could not stop scan");
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN,
|
||||
BT_LE_CONN_PARAM_DEFAULT, &default_conn);
|
||||
if (err) {
|
||||
FAIL("Could not connect to peer: %d", err);
|
||||
}
|
||||
}
|
||||
|
||||
static void connected(struct bt_conn *conn, uint8_t err)
|
||||
{
|
||||
char addr[BT_ADDR_LE_STR_LEN];
|
||||
|
||||
(void)bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
|
||||
|
||||
if (default_conn == NULL) {
|
||||
default_conn = bt_conn_ref(conn);
|
||||
}
|
||||
|
||||
if (err != 0) {
|
||||
bt_conn_unref(default_conn);
|
||||
default_conn = NULL;
|
||||
|
||||
FAIL("Failed to connect to %s (%u)\n", addr, err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Connected to %s\n", addr);
|
||||
SET_FLAG(flag_connected);
|
||||
}
|
||||
|
||||
void disconnected(struct bt_conn *conn, uint8_t reason)
|
||||
{
|
||||
char addr[BT_ADDR_LE_STR_LEN];
|
||||
|
||||
if (conn != default_conn) {
|
||||
return;
|
||||
}
|
||||
|
||||
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
|
||||
|
||||
printk("Disconnected: %s (reason %u)\n", addr, reason);
|
||||
|
||||
bt_conn_unref(default_conn);
|
||||
default_conn = NULL;
|
||||
UNSET_FLAG(flag_connected);
|
||||
}
|
||||
|
||||
BT_CONN_CB_DEFINE(conn_callbacks) = {
|
||||
.connected = connected,
|
||||
.disconnected = disconnected,
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
68
tests/bsim/bluetooth/audio/src/common.h
Normal file
68
tests/bsim/bluetooth/audio/src/common.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* Common functions and helpers for BSIM audio tests
|
||||
*
|
||||
* Copyright (c) 2019 Bose Corporation
|
||||
* Copyright (c) 2020-2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_TEST_BSIM_BT_AUDIO_TEST_
|
||||
#define ZEPHYR_TEST_BSIM_BT_AUDIO_TEST_
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
|
||||
#include "bs_types.h"
|
||||
#include "bs_tracing.h"
|
||||
#include "time_machine.h"
|
||||
#include "bstests.h"
|
||||
|
||||
#include <zephyr/types.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <zephyr/sys_clock.h>
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/hci.h>
|
||||
#include <zephyr/bluetooth/conn.h>
|
||||
#include <zephyr/bluetooth/uuid.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
|
||||
#define WAIT_SECONDS 30 /* seconds */
|
||||
#define WAIT_TIME (WAIT_SECONDS * USEC_PER_SEC) /* microseconds*/
|
||||
|
||||
#define WAIT_FOR_COND(cond) while (!(cond)) { k_sleep(K_MSEC(1)); }
|
||||
|
||||
#define CREATE_FLAG(flag) static atomic_t flag = (atomic_t)false
|
||||
#define SET_FLAG(flag) (void)atomic_set(&flag, (atomic_t)true)
|
||||
#define UNSET_FLAG(flag) (void)atomic_clear(&flag)
|
||||
#define TEST_FLAG(flag) (atomic_get(&flag) == (atomic_t)true)
|
||||
#define WAIT_FOR_FLAG(flag) \
|
||||
while (!(bool)atomic_get(&flag)) { \
|
||||
(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)
|
||||
|
||||
#define AD_SIZE 1
|
||||
extern const struct bt_data ad[AD_SIZE];
|
||||
extern struct bt_conn *default_conn;
|
||||
extern atomic_t flag_connected;
|
||||
|
||||
void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
|
||||
struct net_buf_simple *ad);
|
||||
void disconnected(struct bt_conn *conn, uint8_t reason);
|
||||
void test_tick(bs_time_t HW_device_time);
|
||||
void test_init(void);
|
||||
|
||||
#endif /* ZEPHYR_TEST_BSIM_BT_AUDIO_TEST_ */
|
411
tests/bsim/bluetooth/audio/src/csip_set_coordinator_test.c
Normal file
411
tests/bsim/bluetooth/audio/src/csip_set_coordinator_test.c
Normal file
|
@ -0,0 +1,411 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Bose Corporation
|
||||
* Copyright (c) 2020-2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifdef CONFIG_BT_CSIP_SET_COORDINATOR
|
||||
#include <zephyr/bluetooth/addr.h>
|
||||
#include <zephyr/bluetooth/audio/csip.h>
|
||||
#include "common.h"
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
static volatile bool discovered;
|
||||
static volatile bool members_discovered;
|
||||
static volatile bool set_locked;
|
||||
static volatile bool set_unlocked;
|
||||
static volatile bool ordered_access_locked;
|
||||
static volatile bool ordered_access_unlocked;
|
||||
static const struct bt_csip_set_coordinator_csis_inst *inst;
|
||||
|
||||
static uint8_t members_found;
|
||||
static struct k_work_delayable discover_members_timer;
|
||||
static bt_addr_le_t addr_found[CONFIG_BT_MAX_CONN];
|
||||
static struct bt_conn *conns[CONFIG_BT_MAX_CONN];
|
||||
static const struct bt_csip_set_coordinator_set_member *set_members[CONFIG_BT_MAX_CONN];
|
||||
|
||||
static void csip_set_coordinator_lock_set_cb(int err);
|
||||
|
||||
static void csip_set_coordinator_lock_release_cb(int err)
|
||||
{
|
||||
printk("%s\n", __func__);
|
||||
|
||||
if (err != 0) {
|
||||
FAIL("Release sets failed (%d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
set_unlocked = true;
|
||||
}
|
||||
|
||||
static void csip_set_coordinator_lock_set_cb(int err)
|
||||
{
|
||||
printk("%s\n", __func__);
|
||||
|
||||
if (err != 0) {
|
||||
FAIL("Lock sets failed (%d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
set_locked = true;
|
||||
}
|
||||
|
||||
static void csip_discover_cb(struct bt_conn *conn,
|
||||
const struct bt_csip_set_coordinator_set_member *member,
|
||||
int err, size_t set_count)
|
||||
{
|
||||
uint8_t conn_index;
|
||||
|
||||
printk("%s\n", __func__);
|
||||
|
||||
if (err != 0 || set_count == 0U) {
|
||||
FAIL("Discover failed (%d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
conn_index = bt_conn_index(conn);
|
||||
|
||||
inst = &member->insts[0];
|
||||
set_members[conn_index] = member;
|
||||
discovered = true;
|
||||
}
|
||||
|
||||
static void csip_lock_changed_cb(struct bt_csip_set_coordinator_csis_inst *inst,
|
||||
bool locked)
|
||||
{
|
||||
printk("Inst %p %s\n", inst, locked ? "locked" : "released");
|
||||
}
|
||||
|
||||
static void csip_set_coordinator_ordered_access_cb(
|
||||
const struct bt_csip_set_coordinator_set_info *set_info, int err,
|
||||
bool locked, struct bt_csip_set_coordinator_set_member *member)
|
||||
{
|
||||
if (err) {
|
||||
FAIL("Ordered access failed with err %d\n", err);
|
||||
} else if (locked) {
|
||||
printk("Ordered access procedure locked member %p\n", member);
|
||||
ordered_access_locked = true;
|
||||
} else {
|
||||
printk("Ordered access procedure finished\n");
|
||||
ordered_access_unlocked = true;
|
||||
}
|
||||
}
|
||||
|
||||
static struct bt_csip_set_coordinator_cb cbs = {
|
||||
.lock_set = csip_set_coordinator_lock_set_cb,
|
||||
.release_set = csip_set_coordinator_lock_release_cb,
|
||||
.discover = csip_discover_cb,
|
||||
.lock_changed = csip_lock_changed_cb,
|
||||
.ordered_access = csip_set_coordinator_ordered_access_cb
|
||||
};
|
||||
|
||||
static bool csip_set_coordinator_oap_cb(const struct bt_csip_set_coordinator_set_info *set_info,
|
||||
struct bt_csip_set_coordinator_set_member *members[],
|
||||
size_t count)
|
||||
{
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
printk("Ordered access for members[%zu]: %p\n", i, members[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool is_discovered(const bt_addr_le_t *addr)
|
||||
{
|
||||
for (int i = 0; i < members_found; i++) {
|
||||
if (bt_addr_le_eq(addr, &addr_found[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool csip_found(struct bt_data *data, void *user_data)
|
||||
{
|
||||
if (bt_csip_set_coordinator_is_set_member(inst->info.set_sirk, data)) {
|
||||
const bt_addr_le_t *addr = user_data;
|
||||
char addr_str[BT_ADDR_LE_STR_LEN];
|
||||
|
||||
bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
|
||||
printk("Found CSIP advertiser with address %s\n", addr_str);
|
||||
|
||||
if (is_discovered(addr)) {
|
||||
printk("Set member already found\n");
|
||||
/* Stop parsing */
|
||||
return false;
|
||||
}
|
||||
|
||||
bt_addr_le_copy(&addr_found[members_found++], addr);
|
||||
|
||||
printk("Found member (%u / %u)\n",
|
||||
members_found, inst->info.set_size);
|
||||
|
||||
/* Stop parsing */
|
||||
return false;
|
||||
}
|
||||
/* Continue parsing */
|
||||
return true;
|
||||
}
|
||||
|
||||
static void csip_set_coordinator_scan_recv(const struct bt_le_scan_recv_info *info,
|
||||
struct net_buf_simple *ad)
|
||||
{
|
||||
/* We're only interested in connectable events */
|
||||
if (info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) {
|
||||
if (inst == NULL) {
|
||||
/* Scanning for the first device */
|
||||
if (members_found == 0) {
|
||||
bt_addr_le_copy(&addr_found[members_found++],
|
||||
info->addr);
|
||||
}
|
||||
} else { /* Scanning for set members */
|
||||
bt_data_parse(ad, csip_found, (void *)info->addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct bt_le_scan_cb csip_set_coordinator_scan_callbacks = {
|
||||
.recv = csip_set_coordinator_scan_recv
|
||||
};
|
||||
|
||||
static void discover_members_timer_handler(struct k_work *work)
|
||||
{
|
||||
FAIL("Could not find all members (%u / %u)\n",
|
||||
members_found, inst->info.set_size);
|
||||
}
|
||||
|
||||
static void ordered_access(const struct bt_csip_set_coordinator_set_member **members,
|
||||
size_t count, bool expect_locked)
|
||||
{
|
||||
int err;
|
||||
|
||||
printk("Performing ordered access, expecting %s\n",
|
||||
expect_locked ? "locked" : "unlocked");
|
||||
|
||||
if (expect_locked) {
|
||||
ordered_access_locked = false;
|
||||
} else {
|
||||
ordered_access_unlocked = false;
|
||||
}
|
||||
|
||||
err = bt_csip_set_coordinator_ordered_access(members, count,
|
||||
&inst->info,
|
||||
csip_set_coordinator_oap_cb);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to do CSIP set coordinator ordered access (%d)",
|
||||
err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (expect_locked) {
|
||||
WAIT_FOR_COND(ordered_access_locked);
|
||||
} else {
|
||||
WAIT_FOR_COND(ordered_access_unlocked);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_main(void)
|
||||
{
|
||||
int err;
|
||||
char addr[BT_ADDR_LE_STR_LEN];
|
||||
const struct bt_csip_set_coordinator_set_member *locked_members[CONFIG_BT_MAX_CONN];
|
||||
uint8_t connected_member_count = 0;
|
||||
|
||||
err = bt_enable(NULL);
|
||||
if (err != 0) {
|
||||
FAIL("Bluetooth init failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Audio Client: Bluetooth initialized\n");
|
||||
|
||||
bt_csip_set_coordinator_register_cb(&cbs);
|
||||
k_work_init_delayable(&discover_members_timer,
|
||||
discover_members_timer_handler);
|
||||
bt_le_scan_cb_register(&csip_set_coordinator_scan_callbacks);
|
||||
|
||||
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL);
|
||||
if (err != 0) {
|
||||
FAIL("Scanning failed to start (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Scanning successfully started\n");
|
||||
|
||||
WAIT_FOR_COND(members_found == 1);
|
||||
|
||||
printk("Stopping scan\n");
|
||||
err = bt_le_scan_stop();
|
||||
if (err != 0) {
|
||||
FAIL("Could not stop scan");
|
||||
return;
|
||||
}
|
||||
|
||||
bt_addr_le_to_str(&addr_found[0], addr, sizeof(addr));
|
||||
err = bt_conn_le_create(&addr_found[0], BT_CONN_LE_CREATE_CONN,
|
||||
BT_LE_CONN_PARAM_DEFAULT, &conns[0]);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to connect to %s: %d\n", err);
|
||||
return;
|
||||
}
|
||||
printk("Connecting to %s\n", addr);
|
||||
|
||||
WAIT_FOR_FLAG(flag_connected);
|
||||
connected_member_count++;
|
||||
|
||||
err = bt_csip_set_coordinator_discover(conns[0]);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to initialize set coordinator for connection %d\n",
|
||||
err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_COND(discovered);
|
||||
|
||||
err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, NULL);
|
||||
if (err != 0) {
|
||||
FAIL("Could not start scan: %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = k_work_reschedule(&discover_members_timer,
|
||||
BT_CSIP_SET_COORDINATOR_DISCOVER_TIMER_VALUE);
|
||||
if (err < 0) { /* Can return 0, 1 and 2 for success */
|
||||
FAIL("Could not schedule discover_members_timer %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_COND(members_found == inst->info.set_size);
|
||||
|
||||
(void)k_work_cancel_delayable(&discover_members_timer);
|
||||
err = bt_le_scan_stop();
|
||||
if (err != 0) {
|
||||
FAIL("Scanning failed to stop (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint8_t i = 1; i < members_found; i++) {
|
||||
bt_addr_le_to_str(&addr_found[i], addr, sizeof(addr));
|
||||
|
||||
UNSET_FLAG(flag_connected);
|
||||
printk("Connecting to member[%d] (%s)", i, addr);
|
||||
err = bt_conn_le_create(&addr_found[i],
|
||||
BT_CONN_LE_CREATE_CONN,
|
||||
BT_LE_CONN_PARAM_DEFAULT,
|
||||
&conns[i]);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to connect to %s: %d\n", addr, err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Connected to %s\n", addr);
|
||||
WAIT_FOR_FLAG(flag_connected);
|
||||
connected_member_count++;
|
||||
|
||||
discovered = false;
|
||||
printk("Doing discovery on member[%u]", i);
|
||||
err = bt_csip_set_coordinator_discover(conns[i]);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to initialize set coordinator for connection %d\n",
|
||||
err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_COND(discovered);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(locked_members); i++) {
|
||||
locked_members[i] = set_members[i];
|
||||
}
|
||||
|
||||
ordered_access(locked_members, connected_member_count, false);
|
||||
|
||||
printk("Locking set\n");
|
||||
err = bt_csip_set_coordinator_lock(locked_members, connected_member_count,
|
||||
&inst->info);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to do set coordinator lock (%d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_COND(set_locked);
|
||||
|
||||
ordered_access(locked_members, connected_member_count, true);
|
||||
|
||||
k_sleep(K_MSEC(1000)); /* Simulate doing stuff */
|
||||
|
||||
printk("Releasing set\n");
|
||||
err = bt_csip_set_coordinator_release(locked_members, connected_member_count,
|
||||
&inst->info);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to do set coordinator release (%d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_COND(set_unlocked);
|
||||
|
||||
ordered_access(locked_members, connected_member_count, false);
|
||||
|
||||
/* Lock and unlock again */
|
||||
set_locked = false;
|
||||
set_unlocked = false;
|
||||
|
||||
printk("Locking set\n");
|
||||
err = bt_csip_set_coordinator_lock(locked_members, connected_member_count,
|
||||
&inst->info);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to do set coordinator lock (%d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_COND(set_locked);
|
||||
|
||||
k_sleep(K_MSEC(1000)); /* Simulate doing stuff */
|
||||
|
||||
printk("Releasing set\n");
|
||||
err = bt_csip_set_coordinator_release(locked_members, connected_member_count,
|
||||
&inst->info);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to do set coordinator release (%d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_COND(set_unlocked);
|
||||
|
||||
for (uint8_t i = 0; i < members_found; i++) {
|
||||
printk("Disconnecting member[%u] (%s)", i, addr);
|
||||
err = bt_conn_disconnect(conns[i],
|
||||
BT_HCI_ERR_REMOTE_USER_TERM_CONN);
|
||||
(void)memset(&set_members[i], 0, sizeof(set_members[i]));
|
||||
if (err != 0) {
|
||||
FAIL("Failed to do disconnect\n", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PASS("All members disconnected\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_connect[] = {
|
||||
|
||||
{
|
||||
.test_id = "csip_set_coordinator",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_main
|
||||
},
|
||||
|
||||
BSTEST_END_MARKER
|
||||
};
|
||||
|
||||
struct bst_test_list *test_csip_set_coordinator_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_connect);
|
||||
}
|
||||
#else
|
||||
struct bst_test_list *test_csip_set_coordinator_install(struct bst_test_list *tests)
|
||||
{
|
||||
return tests;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_CSIP_SET_COORDINATOR */
|
198
tests/bsim/bluetooth/audio/src/csip_set_member_test.c
Normal file
198
tests/bsim/bluetooth/audio/src/csip_set_member_test.c
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Bose Corporation
|
||||
* Copyright (c) 2020-2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifdef CONFIG_BT_CSIP_SET_MEMBER
|
||||
#include <zephyr/bluetooth/audio/csip.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
static struct bt_csip_set_member_svc_inst *svc_inst;
|
||||
extern enum bst_result_t bst_result;
|
||||
static volatile bool g_locked;
|
||||
static uint8_t sirk_read_req_rsp = BT_CSIP_READ_SIRK_REQ_RSP_ACCEPT;
|
||||
struct bt_csip_set_member_register_param param = {
|
||||
.set_size = 3,
|
||||
.rank = 1,
|
||||
.lockable = true,
|
||||
/* Using the CSIS test sample SIRK */
|
||||
.set_sirk = { 0xcd, 0xcc, 0x72, 0xdd, 0x86, 0x8c, 0xcd, 0xce,
|
||||
0x22, 0xfd, 0xa1, 0x21, 0x09, 0x7d, 0x7d, 0x45 },
|
||||
};
|
||||
|
||||
static void csip_disconnected(struct bt_conn *conn, uint8_t reason)
|
||||
{
|
||||
printk("Disconnected (reason %u)\n", reason);
|
||||
|
||||
if (reason == BT_HCI_ERR_REMOTE_USER_TERM_CONN) {
|
||||
PASS("Client successfully disconnected\n");
|
||||
} else {
|
||||
FAIL("Client disconnected unexpectedly (0x%02x)\n", reason);
|
||||
}
|
||||
}
|
||||
|
||||
static void csip_lock_changed_cb(struct bt_conn *conn,
|
||||
struct bt_csip_set_member_svc_inst *svc_inst,
|
||||
bool locked)
|
||||
{
|
||||
printk("Client %p %s the lock\n", conn, locked ? "locked" : "released");
|
||||
g_locked = locked;
|
||||
}
|
||||
|
||||
static uint8_t sirk_read_req_cb(struct bt_conn *conn,
|
||||
struct bt_csip_set_member_svc_inst *svc_inst)
|
||||
{
|
||||
return sirk_read_req_rsp;
|
||||
}
|
||||
|
||||
static struct bt_csip_set_member_cb csip_cbs = {
|
||||
.lock_changed = csip_lock_changed_cb,
|
||||
.sirk_read_req = sirk_read_req_cb,
|
||||
};
|
||||
|
||||
static void bt_ready(int err)
|
||||
{
|
||||
uint8_t rsi[BT_CSIP_RSI_SIZE];
|
||||
struct bt_data ad[] = {
|
||||
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
|
||||
BT_CSIP_DATA_RSI(rsi),
|
||||
};
|
||||
|
||||
if (err != 0) {
|
||||
FAIL("Bluetooth init failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Audio Server: Bluetooth initialized\n");
|
||||
|
||||
param.cb = &csip_cbs;
|
||||
|
||||
err = bt_csip_set_member_register(¶m, &svc_inst);
|
||||
if (err != 0) {
|
||||
FAIL("Could not register CSIP (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_csip_set_member_generate_rsi(svc_inst, rsi);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to generate RSI (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0);
|
||||
if (err != 0) {
|
||||
FAIL("Advertising failed to start (err %d)\n", err);
|
||||
}
|
||||
}
|
||||
|
||||
static struct bt_conn_cb conn_callbacks = {
|
||||
.disconnected = csip_disconnected,
|
||||
};
|
||||
|
||||
static void test_main(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_enable(bt_ready);
|
||||
|
||||
if (err != 0) {
|
||||
FAIL("Bluetooth init failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
bt_conn_cb_register(&conn_callbacks);
|
||||
}
|
||||
|
||||
static void test_force_release(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_enable(bt_ready);
|
||||
|
||||
if (err != 0) {
|
||||
FAIL("Bluetooth init failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
bt_conn_cb_register(&conn_callbacks);
|
||||
|
||||
WAIT_FOR_COND(g_locked);
|
||||
printk("Force releasing set\n");
|
||||
bt_csip_set_member_lock(svc_inst, false, true);
|
||||
}
|
||||
|
||||
static void test_csip_enc(void)
|
||||
{
|
||||
printk("Running %s\n", __func__);
|
||||
sirk_read_req_rsp = BT_CSIP_READ_SIRK_REQ_RSP_ACCEPT_ENC;
|
||||
test_main();
|
||||
}
|
||||
|
||||
static void test_args(int argc, char *argv[])
|
||||
{
|
||||
for (size_t argn = 0; argn < argc; argn++) {
|
||||
const char *arg = argv[argn];
|
||||
|
||||
if (strcmp(arg, "size") == 0) {
|
||||
param.set_size = strtol(argv[++argn], NULL, 10);
|
||||
} else if (strcmp(arg, "rank") == 0) {
|
||||
param.rank = strtol(argv[++argn], NULL, 10);
|
||||
} else if (strcmp(arg, "not-lockable") == 0) {
|
||||
param.lockable = false;
|
||||
} else if (strcmp(arg, "sirk") == 0) {
|
||||
size_t len;
|
||||
|
||||
argn++;
|
||||
|
||||
len = hex2bin(argv[argn], strlen(argv[argn]),
|
||||
param.set_sirk, sizeof(param.set_sirk));
|
||||
if (len == 0) {
|
||||
FAIL("Could not parse SIRK");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
FAIL("Invalid arg: %s", arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_connect[] = {
|
||||
{
|
||||
.test_id = "csip_set_member",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_main,
|
||||
.test_args_f = test_args,
|
||||
},
|
||||
{
|
||||
.test_id = "csip_set_member_release",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_force_release,
|
||||
.test_args_f = test_args,
|
||||
},
|
||||
{
|
||||
.test_id = "csip_set_member_enc",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_csip_enc,
|
||||
.test_args_f = test_args,
|
||||
},
|
||||
|
||||
BSTEST_END_MARKER
|
||||
};
|
||||
|
||||
struct bst_test_list *test_csip_set_member_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_connect);
|
||||
}
|
||||
#else
|
||||
|
||||
struct bst_test_list *test_csip_set_member_install(struct bst_test_list *tests)
|
||||
{
|
||||
return tests;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_CSIP_SET_MEMBER */
|
251
tests/bsim/bluetooth/audio/src/has_client_test.c
Normal file
251
tests/bsim/bluetooth/audio/src/has_client_test.c
Normal file
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Codecoup
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_BT_HAS_CLIENT
|
||||
#include <zephyr/bluetooth/audio/has.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
|
||||
extern const char *test_preset_name_1;
|
||||
extern const char *test_preset_name_5;
|
||||
extern const uint8_t test_preset_index_1;
|
||||
extern const uint8_t test_preset_index_5;
|
||||
extern const enum bt_has_properties test_preset_properties;
|
||||
|
||||
CREATE_FLAG(g_service_discovered);
|
||||
CREATE_FLAG(g_preset_switched);
|
||||
CREATE_FLAG(g_preset_1_found);
|
||||
CREATE_FLAG(g_preset_5_found);
|
||||
|
||||
static struct bt_has *g_has;
|
||||
static uint8_t g_active_index;
|
||||
|
||||
static void discover_cb(struct bt_conn *conn, int err, struct bt_has *has,
|
||||
enum bt_has_hearing_aid_type type, enum bt_has_capabilities caps)
|
||||
{
|
||||
if (err) {
|
||||
FAIL("Failed to discover HAS (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("HAS discovered type %d caps %d\n", type, caps);
|
||||
|
||||
g_has = has;
|
||||
SET_FLAG(g_service_discovered);
|
||||
}
|
||||
|
||||
static void preset_switch_cb(struct bt_has *has, int err, uint8_t index)
|
||||
{
|
||||
if (err != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Active preset index %d\n", index);
|
||||
|
||||
SET_FLAG(g_preset_switched);
|
||||
g_active_index = index;
|
||||
}
|
||||
|
||||
static void check_preset_record(const struct bt_has_preset_record *record,
|
||||
enum bt_has_properties expected_properties,
|
||||
const char *expected_name)
|
||||
{
|
||||
if (record->properties != expected_properties || strcmp(record->name, expected_name)) {
|
||||
FAIL("mismatch 0x%02x %s vs 0x%02x %s expected\n",
|
||||
record->properties, record->name, expected_properties, expected_name);
|
||||
}
|
||||
}
|
||||
|
||||
static void preset_read_rsp_cb(struct bt_has *has, int err,
|
||||
const struct bt_has_preset_record *record, bool is_last)
|
||||
{
|
||||
if (err) {
|
||||
FAIL("%s: err %d\n", __func__, err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (record->index == test_preset_index_1) {
|
||||
SET_FLAG(g_preset_1_found);
|
||||
|
||||
check_preset_record(record, test_preset_properties, test_preset_name_1);
|
||||
} else if (record->index == test_preset_index_5) {
|
||||
SET_FLAG(g_preset_5_found);
|
||||
|
||||
check_preset_record(record, test_preset_properties, test_preset_name_5);
|
||||
} else {
|
||||
FAIL("unexpected index 0x%02x", record->index);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct bt_has_client_cb has_cb = {
|
||||
.discover = discover_cb,
|
||||
.preset_switch = preset_switch_cb,
|
||||
.preset_read_rsp = preset_read_rsp_cb,
|
||||
};
|
||||
|
||||
static bool test_preset_switch(uint8_t index)
|
||||
{
|
||||
int err;
|
||||
|
||||
UNSET_FLAG(g_preset_switched);
|
||||
|
||||
err = bt_has_client_preset_set(g_has, index, false);
|
||||
if (err < 0) {
|
||||
printk("%s (err %d)\n", __func__, err);
|
||||
return false;
|
||||
}
|
||||
|
||||
WAIT_FOR_COND(g_preset_switched);
|
||||
|
||||
return g_active_index == index;
|
||||
}
|
||||
|
||||
static bool test_preset_next(uint8_t active_index_expected)
|
||||
{
|
||||
int err;
|
||||
|
||||
UNSET_FLAG(g_preset_switched);
|
||||
|
||||
err = bt_has_client_preset_next(g_has, false);
|
||||
if (err < 0) {
|
||||
printk("%s (err %d)\n", __func__, err);
|
||||
return false;
|
||||
}
|
||||
|
||||
WAIT_FOR_COND(g_preset_switched);
|
||||
|
||||
return g_active_index == active_index_expected;
|
||||
}
|
||||
|
||||
static bool test_preset_prev(uint8_t active_index_expected)
|
||||
{
|
||||
int err;
|
||||
|
||||
UNSET_FLAG(g_preset_switched);
|
||||
|
||||
err = bt_has_client_preset_prev(g_has, false);
|
||||
if (err < 0) {
|
||||
printk("%s (err %d)\n", __func__, err);
|
||||
return false;
|
||||
}
|
||||
|
||||
WAIT_FOR_COND(g_preset_switched);
|
||||
|
||||
return g_active_index == active_index_expected;
|
||||
}
|
||||
|
||||
static void test_main(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_enable(NULL);
|
||||
if (err < 0) {
|
||||
FAIL("Bluetooth discover failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Bluetooth initialized\n");
|
||||
|
||||
err = bt_has_client_cb_register(&has_cb);
|
||||
if (err < 0) {
|
||||
FAIL("Failed to register callbacks (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
|
||||
if (err < 0) {
|
||||
FAIL("Scanning failed to start (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Scanning successfully started\n");
|
||||
|
||||
WAIT_FOR_FLAG(flag_connected);
|
||||
|
||||
err = bt_has_client_discover(default_conn);
|
||||
if (err < 0) {
|
||||
FAIL("Failed to discover HAS (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_COND(g_service_discovered);
|
||||
WAIT_FOR_COND(g_preset_switched);
|
||||
|
||||
err = bt_has_client_presets_read(g_has, BT_HAS_PRESET_INDEX_FIRST, 255);
|
||||
if (err < 0) {
|
||||
FAIL("Failed to read presets (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_COND(g_preset_1_found);
|
||||
WAIT_FOR_COND(g_preset_5_found);
|
||||
|
||||
if (!test_preset_switch(test_preset_index_1)) {
|
||||
FAIL("Failed to switch preset %d\n", test_preset_index_1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!test_preset_switch(test_preset_index_5)) {
|
||||
FAIL("Failed to switch preset %d\n", test_preset_index_5);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!test_preset_next(test_preset_index_1)) {
|
||||
FAIL("Failed to set next preset %d\n", test_preset_index_1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!test_preset_next(test_preset_index_5)) {
|
||||
FAIL("Failed to set next preset %d\n", test_preset_index_5);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!test_preset_next(test_preset_index_1)) {
|
||||
FAIL("Failed to set next preset %d\n", test_preset_index_1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!test_preset_prev(test_preset_index_5)) {
|
||||
FAIL("Failed to set previous preset %d\n", test_preset_index_5);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!test_preset_prev(test_preset_index_1)) {
|
||||
FAIL("Failed to set previous preset %d\n", test_preset_index_1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!test_preset_prev(test_preset_index_5)) {
|
||||
FAIL("Failed to set previous preset %d\n", test_preset_index_5);
|
||||
return;
|
||||
}
|
||||
|
||||
PASS("HAS main PASS\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_has[] = {
|
||||
{
|
||||
.test_id = "has_client",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_main,
|
||||
},
|
||||
BSTEST_END_MARKER
|
||||
};
|
||||
|
||||
struct bst_test_list *test_has_client_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_has);
|
||||
}
|
||||
#else
|
||||
struct bst_test_list *test_has_client_install(struct bst_test_list *tests)
|
||||
{
|
||||
return tests;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_HAS_CLIENT */
|
107
tests/bsim/bluetooth/audio/src/has_test.c
Normal file
107
tests/bsim/bluetooth/audio/src/has_test.c
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Codecoup
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_BT_HAS
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
#include <zephyr/bluetooth/audio/has.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
|
||||
const uint8_t test_preset_index_1 = 0x01;
|
||||
const uint8_t test_preset_index_5 = 0x05;
|
||||
const char *test_preset_name_1 = "test_preset_name_1";
|
||||
const char *test_preset_name_5 = "test_preset_name_5";
|
||||
const enum bt_has_properties test_preset_properties = BT_HAS_PROP_AVAILABLE;
|
||||
|
||||
static int preset_select(uint8_t index, bool sync)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct bt_has_preset_ops preset_ops = {
|
||||
.select = preset_select,
|
||||
};
|
||||
|
||||
static void test_main(void)
|
||||
{
|
||||
struct bt_has_register_param has_param = {0};
|
||||
struct bt_has_preset_register_param preset_param;
|
||||
|
||||
int err;
|
||||
|
||||
err = bt_enable(NULL);
|
||||
if (err) {
|
||||
FAIL("Bluetooth enable failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Bluetooth initialized\n");
|
||||
|
||||
err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, AD_SIZE, NULL, 0);
|
||||
if (err) {
|
||||
FAIL("Advertising failed to start (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Advertising successfully started\n");
|
||||
|
||||
has_param.type = BT_HAS_HEARING_AID_TYPE_MONAURAL;
|
||||
|
||||
err = bt_has_register(&has_param);
|
||||
if (err) {
|
||||
FAIL("HAS register failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
preset_param.index = test_preset_index_5;
|
||||
preset_param.properties = test_preset_properties;
|
||||
preset_param.name = test_preset_name_5;
|
||||
preset_param.ops = &preset_ops,
|
||||
|
||||
err = bt_has_preset_register(&preset_param);
|
||||
if (err) {
|
||||
FAIL("Preset register failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
preset_param.index = test_preset_index_1;
|
||||
preset_param.properties = test_preset_properties;
|
||||
preset_param.name = test_preset_name_1;
|
||||
|
||||
err = bt_has_preset_register(&preset_param);
|
||||
if (err) {
|
||||
FAIL("Preset register failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Presets registered\n");
|
||||
|
||||
PASS("HAS passed\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_has[] = {
|
||||
{
|
||||
.test_id = "has",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_main,
|
||||
},
|
||||
BSTEST_END_MARKER,
|
||||
};
|
||||
|
||||
struct bst_test_list *test_has_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_has);
|
||||
}
|
||||
#else
|
||||
struct bst_test_list *test_has_install(struct bst_test_list *tests)
|
||||
{
|
||||
return tests;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_HAS */
|
137
tests/bsim/bluetooth/audio/src/ias_client_test.c
Normal file
137
tests/bsim/bluetooth/audio/src/ias_client_test.c
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Codecoup
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#ifdef CONFIG_BT_IAS_CLIENT
|
||||
|
||||
#include "zephyr/bluetooth/services/ias.h"
|
||||
#include "common.h"
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
|
||||
CREATE_FLAG(g_service_discovered);
|
||||
|
||||
static void discover_cb(struct bt_conn *conn, int err)
|
||||
{
|
||||
if (err) {
|
||||
FAIL("Failed to discover IAS (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("IAS discovered\n");
|
||||
SET_FLAG(g_service_discovered);
|
||||
}
|
||||
|
||||
static const struct bt_ias_client_cb ias_client_cb = {
|
||||
.discover = discover_cb,
|
||||
};
|
||||
|
||||
static void test_alert_high(struct bt_conn *conn)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_ias_client_alert_write(conn, BT_IAS_ALERT_LVL_HIGH_ALERT);
|
||||
if (err == 0) {
|
||||
printk("High alert sent\n");
|
||||
} else {
|
||||
FAIL("Failed to send high alert\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void test_alert_mild(struct bt_conn *conn)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_ias_client_alert_write(conn, BT_IAS_ALERT_LVL_MILD_ALERT);
|
||||
if (err == 0) {
|
||||
printk("Mild alert sent\n");
|
||||
} else {
|
||||
FAIL("Failed to send mild alert\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void test_alert_stop(struct bt_conn *conn)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_ias_client_alert_write(conn, BT_IAS_ALERT_LVL_NO_ALERT);
|
||||
if (err == 0) {
|
||||
printk("Stop alert sent\n");
|
||||
} else {
|
||||
FAIL("Failed to send no alert\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void test_main(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_enable(NULL);
|
||||
if (err < 0) {
|
||||
FAIL("Bluetooth discover failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Bluetooth initialized\n");
|
||||
|
||||
err = bt_ias_client_cb_register(&ias_client_cb);
|
||||
if (err < 0) {
|
||||
FAIL("Failed to register callbacks (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
|
||||
if (err < 0) {
|
||||
FAIL("Scanning failed to start (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Scanning successfully started\n");
|
||||
|
||||
WAIT_FOR_FLAG(flag_connected);
|
||||
|
||||
err = bt_ias_discover(default_conn);
|
||||
if (err < 0) {
|
||||
FAIL("Failed to discover IAS (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_FLAG(g_service_discovered);
|
||||
|
||||
/* Set alert levels with a delay to let the server handle any changes it want */
|
||||
test_alert_high(default_conn);
|
||||
k_sleep(K_SECONDS(1));
|
||||
|
||||
test_alert_mild(default_conn);
|
||||
k_sleep(K_SECONDS(1));
|
||||
|
||||
test_alert_stop(default_conn);
|
||||
k_sleep(K_SECONDS(1));
|
||||
|
||||
PASS("IAS client PASS\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_ias[] = {
|
||||
{
|
||||
.test_id = "ias_client",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_main,
|
||||
},
|
||||
BSTEST_END_MARKER
|
||||
};
|
||||
|
||||
struct bst_test_list *test_ias_client_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_ias);
|
||||
}
|
||||
#else
|
||||
struct bst_test_list *test_ias_client_install(struct bst_test_list *tests)
|
||||
{
|
||||
return tests;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_IAS_CLIENT */
|
106
tests/bsim/bluetooth/audio/src/ias_test.c
Normal file
106
tests/bsim/bluetooth/audio/src/ias_test.c
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Codecoup
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#ifdef CONFIG_BT_IAS
|
||||
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <zephyr/types.h>
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/hci.h>
|
||||
#include <zephyr/bluetooth/conn.h>
|
||||
#include <zephyr/bluetooth/uuid.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
|
||||
#include <zephyr/bluetooth/services/ias.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
|
||||
CREATE_FLAG(g_high_alert_received);
|
||||
CREATE_FLAG(g_mild_alert_received);
|
||||
CREATE_FLAG(g_stop_alert_received);
|
||||
|
||||
static void high_alert_cb(void)
|
||||
{
|
||||
SET_FLAG(g_high_alert_received);
|
||||
}
|
||||
|
||||
static void mild_alert_cb(void)
|
||||
{
|
||||
SET_FLAG(g_mild_alert_received);
|
||||
}
|
||||
|
||||
static void no_alert_cb(void)
|
||||
{
|
||||
SET_FLAG(g_stop_alert_received);
|
||||
}
|
||||
|
||||
BT_IAS_CB_DEFINE(ias_callbacks) = {
|
||||
.high_alert = high_alert_cb,
|
||||
.mild_alert = mild_alert_cb,
|
||||
.no_alert = no_alert_cb,
|
||||
};
|
||||
|
||||
static void test_main(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_enable(NULL);
|
||||
if (err != 0) {
|
||||
FAIL("Bluetooth init failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, AD_SIZE, NULL, 0);
|
||||
if (err) {
|
||||
FAIL("Advertising failed to start (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Advertising successfully started\n");
|
||||
|
||||
WAIT_FOR_FLAG(flag_connected);
|
||||
|
||||
WAIT_FOR_FLAG(g_high_alert_received);
|
||||
printk("High alert received\n");
|
||||
|
||||
err = bt_ias_local_alert_stop();
|
||||
if (err != 0) {
|
||||
FAIL("Failed to locally stop alert: %d\n", err);
|
||||
return;
|
||||
}
|
||||
WAIT_FOR_FLAG(g_stop_alert_received);
|
||||
|
||||
WAIT_FOR_FLAG(g_mild_alert_received);
|
||||
printk("Mild alert received\n");
|
||||
|
||||
WAIT_FOR_FLAG(g_stop_alert_received);
|
||||
printk("Stop alert received\n");
|
||||
|
||||
PASS("IAS test passed\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_ias[] = {
|
||||
{
|
||||
.test_id = "ias",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_main,
|
||||
|
||||
},
|
||||
BSTEST_END_MARKER
|
||||
};
|
||||
|
||||
struct bst_test_list *test_ias_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_ias);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_IAS */
|
65
tests/bsim/bluetooth/audio/src/main.c
Normal file
65
tests/bsim/bluetooth/audio/src/main.c
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "bstests.h"
|
||||
|
||||
extern struct bst_test_list *test_vcp_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_vcp_vol_ctlr_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_micp_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_micp_mic_ctlr_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_csip_set_member_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_csip_set_coordinator_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_tbs_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_tbs_client_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_mcs_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_mcc_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_media_controller_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_unicast_client_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_unicast_server_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_broadcast_source_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_broadcast_sink_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_scan_delegator_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_bap_broadcast_assistant_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_bass_broadcaster_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_cap_acceptor_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_cap_initiator_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_has_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_has_client_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_ias_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_ias_client_install(struct bst_test_list *tests);
|
||||
|
||||
bst_test_install_t test_installers[] = {
|
||||
test_vcp_install,
|
||||
test_vcp_vol_ctlr_install,
|
||||
test_micp_install,
|
||||
test_micp_mic_ctlr_install,
|
||||
test_csip_set_member_install,
|
||||
test_csip_set_coordinator_install,
|
||||
test_tbs_install,
|
||||
test_tbs_client_install,
|
||||
test_mcs_install,
|
||||
test_mcc_install,
|
||||
test_media_controller_install,
|
||||
test_unicast_client_install,
|
||||
test_unicast_server_install,
|
||||
test_broadcast_source_install,
|
||||
test_broadcast_sink_install,
|
||||
test_scan_delegator_install,
|
||||
test_bap_broadcast_assistant_install,
|
||||
test_bass_broadcaster_install,
|
||||
test_cap_acceptor_install,
|
||||
test_cap_initiator_install,
|
||||
test_has_install,
|
||||
test_has_client_install,
|
||||
test_ias_install,
|
||||
test_ias_client_install,
|
||||
NULL
|
||||
};
|
||||
|
||||
void main(void)
|
||||
{
|
||||
bst_main();
|
||||
}
|
1847
tests/bsim/bluetooth/audio/src/mcc_test.c
Normal file
1847
tests/bsim/bluetooth/audio/src/mcc_test.c
Normal file
File diff suppressed because it is too large
Load diff
81
tests/bsim/bluetooth/audio/src/mcs_test.c
Normal file
81
tests/bsim/bluetooth/audio/src/mcs_test.c
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright (c) 2019 - 2021 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_BT_MCS
|
||||
|
||||
#include <zephyr/bluetooth/audio/media_proxy.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
|
||||
/* Callback after Bluetoot initialization attempt */
|
||||
static void bt_ready(int err)
|
||||
{
|
||||
if (err) {
|
||||
FAIL("Bluetooth init failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Bluetooth initialized\n");
|
||||
|
||||
err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, AD_SIZE, NULL, 0);
|
||||
if (err) {
|
||||
FAIL("Advertising failed to start (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Advertising successfully started\n");
|
||||
}
|
||||
|
||||
static void test_main(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
printk("Media Control Server test application. Board: %s\n", CONFIG_BOARD);
|
||||
|
||||
/* Initialize media player */
|
||||
err = media_proxy_pl_init();
|
||||
if (err) {
|
||||
FAIL("Initializing MPL failed (err %d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Initialize Bluetooth, get connected */
|
||||
err = bt_enable(bt_ready);
|
||||
if (err) {
|
||||
FAIL("Bluetooth init failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_FLAG(flag_connected);
|
||||
|
||||
PASS("MCS passed\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_mcs[] = {
|
||||
{
|
||||
.test_id = "mcs",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_main
|
||||
},
|
||||
BSTEST_END_MARKER
|
||||
};
|
||||
|
||||
struct bst_test_list *test_mcs_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_mcs);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
struct bst_test_list *test_mcs_install(struct bst_test_list *tests)
|
||||
{
|
||||
return tests;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_MCS */
|
1719
tests/bsim/bluetooth/audio/src/media_controller_test.c
Normal file
1719
tests/bsim/bluetooth/audio/src/media_controller_test.c
Normal file
File diff suppressed because it is too large
Load diff
458
tests/bsim/bluetooth/audio/src/micp_mic_ctlr_test.c
Normal file
458
tests/bsim/bluetooth/audio/src/micp_mic_ctlr_test.c
Normal file
|
@ -0,0 +1,458 @@
|
|||
/*
|
||||
* Copyright (c) 2021-2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_BT_MICP_MIC_CTLR
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/audio/micp.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define AICS_DESC_SIZE 64
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
|
||||
static struct bt_micp_mic_ctlr *mic_ctlr;
|
||||
static struct bt_micp_included micp_included;
|
||||
static volatile bool g_bt_init;
|
||||
static volatile bool g_discovery_complete;
|
||||
static volatile bool g_write_complete;
|
||||
|
||||
static volatile uint8_t g_mute;
|
||||
static volatile uint8_t g_aics_count;
|
||||
static volatile int8_t g_aics_gain;
|
||||
static volatile uint8_t g_aics_input_mute;
|
||||
static volatile uint8_t g_aics_mode;
|
||||
static volatile uint8_t g_aics_input_type;
|
||||
static volatile uint8_t g_aics_units;
|
||||
static volatile uint8_t g_aics_gain_max;
|
||||
static volatile uint8_t g_aics_gain_min;
|
||||
static volatile bool g_aics_active = true;
|
||||
static char g_aics_desc[AICS_DESC_SIZE];
|
||||
static volatile bool g_cb;
|
||||
|
||||
static void aics_state_cb(struct bt_aics *inst, int err, int8_t gain,
|
||||
uint8_t mute, uint8_t mode)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("AICS state cb err (%d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
g_aics_gain = gain;
|
||||
g_aics_input_mute = mute;
|
||||
g_aics_mode = mode;
|
||||
|
||||
g_cb = true;
|
||||
}
|
||||
|
||||
static void aics_gain_setting_cb(struct bt_aics *inst, int err, uint8_t units,
|
||||
int8_t minimum, int8_t maximum)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("AICS gain setting cb err (%d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
g_aics_units = units;
|
||||
g_aics_gain_min = minimum;
|
||||
g_aics_gain_max = maximum;
|
||||
|
||||
g_cb = true;
|
||||
}
|
||||
|
||||
static void aics_input_type_cb(struct bt_aics *inst, int err,
|
||||
uint8_t input_type)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("AICS input type cb err (%d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
g_aics_input_type = input_type;
|
||||
|
||||
g_cb = true;
|
||||
}
|
||||
|
||||
static void aics_status_cb(struct bt_aics *inst, int err, bool active)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("AICS status cb err (%d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
g_aics_active = active;
|
||||
|
||||
g_cb = true;
|
||||
}
|
||||
|
||||
static void aics_description_cb(struct bt_aics *inst, int err,
|
||||
char *description)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("AICS description cb err (%d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strlen(description) > sizeof(g_aics_desc) - 1) {
|
||||
printk("Warning: AICS description (%zu) is larger than buffer (%zu)\n",
|
||||
strlen(description), sizeof(g_aics_desc) - 1);
|
||||
}
|
||||
|
||||
strncpy(g_aics_desc, description, sizeof(g_aics_desc) - 1);
|
||||
g_aics_desc[sizeof(g_aics_desc) - 1] = '\0';
|
||||
|
||||
g_cb = true;
|
||||
}
|
||||
|
||||
static void aics_write_cb(struct bt_aics *inst, int err)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("AICS write failed (%d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
g_write_complete = true;
|
||||
}
|
||||
|
||||
static void micp_mic_ctlr_discover_cb(struct bt_micp_mic_ctlr *mic_ctlr,
|
||||
int err,
|
||||
uint8_t aics_count)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("MICS could not be discovered (%d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
g_aics_count = aics_count;
|
||||
g_discovery_complete = true;
|
||||
}
|
||||
|
||||
static void micp_mic_ctlr_mute_written_cb(struct bt_micp_mic_ctlr *mic_ctlr,
|
||||
int err)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("mic_ctlr mute write failed (%d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
g_write_complete = true;
|
||||
}
|
||||
|
||||
static void micp_mic_ctlr_unmute_written_cb(struct bt_micp_mic_ctlr *mic_ctlr,
|
||||
int err)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("mic_ctlr unmute write failed (%d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
g_write_complete = true;
|
||||
}
|
||||
|
||||
static void micp_mic_ctlr_mute_cb(struct bt_micp_mic_ctlr *mic_ctlr, int err,
|
||||
uint8_t mute)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("mic_ctlr mute read failed (%d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
g_mute = mute;
|
||||
g_cb = true;
|
||||
}
|
||||
|
||||
static struct bt_micp_mic_ctlr_cb micp_mic_ctlr_cbs = {
|
||||
.discover = micp_mic_ctlr_discover_cb,
|
||||
.mute = micp_mic_ctlr_mute_cb,
|
||||
.mute_written = micp_mic_ctlr_mute_written_cb,
|
||||
.unmute_written = micp_mic_ctlr_unmute_written_cb,
|
||||
.aics_cb = {
|
||||
.state = aics_state_cb,
|
||||
.gain_setting = aics_gain_setting_cb,
|
||||
.type = aics_input_type_cb,
|
||||
.status = aics_status_cb,
|
||||
.description = aics_description_cb,
|
||||
.set_gain = aics_write_cb,
|
||||
.unmute = aics_write_cb,
|
||||
.mute = aics_write_cb,
|
||||
.set_manual_mode = aics_write_cb,
|
||||
.set_auto_mode = aics_write_cb,
|
||||
}
|
||||
};
|
||||
|
||||
static void bt_ready(int err)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("Bluetooth discover failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
g_bt_init = true;
|
||||
}
|
||||
|
||||
static int test_aics(void)
|
||||
{
|
||||
int err;
|
||||
int8_t expected_gain;
|
||||
uint8_t expected_input_mute;
|
||||
uint8_t expected_mode;
|
||||
uint8_t expected_input_type;
|
||||
char expected_aics_desc[AICS_DESC_SIZE];
|
||||
struct bt_conn *cached_conn;
|
||||
|
||||
printk("Getting AICS client conn\n");
|
||||
err = bt_aics_client_conn_get(micp_included.aics[0], &cached_conn);
|
||||
if (err != 0) {
|
||||
FAIL("Could not get AICS client conn (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
if (cached_conn != default_conn) {
|
||||
FAIL("Cached conn was not the conn used to discover");
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
printk("Getting AICS state\n");
|
||||
g_cb = false;
|
||||
err = bt_aics_state_get(micp_included.aics[0]);
|
||||
if (err != 0) {
|
||||
FAIL("Could not get AICS state (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
WAIT_FOR_COND(g_cb);
|
||||
printk("AICS state get\n");
|
||||
|
||||
printk("Getting AICS gain setting\n");
|
||||
g_cb = false;
|
||||
err = bt_aics_gain_setting_get(micp_included.aics[0]);
|
||||
if (err != 0) {
|
||||
FAIL("Could not get AICS gain setting (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
WAIT_FOR_COND(g_cb);
|
||||
printk("AICS gain setting get\n");
|
||||
|
||||
printk("Getting AICS input type\n");
|
||||
expected_input_type = BT_AICS_INPUT_TYPE_UNSPECIFIED;
|
||||
g_cb = false;
|
||||
err = bt_aics_type_get(micp_included.aics[0]);
|
||||
if (err != 0) {
|
||||
FAIL("Could not get AICS input type (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
/* Expect and wait for input_type from init */
|
||||
WAIT_FOR_COND(g_cb && expected_input_type == g_aics_input_type);
|
||||
printk("AICS input type get\n");
|
||||
|
||||
printk("Getting AICS status\n");
|
||||
g_cb = false;
|
||||
err = bt_aics_status_get(micp_included.aics[0]);
|
||||
if (err != 0) {
|
||||
FAIL("Could not get AICS status (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
WAIT_FOR_COND(g_cb);
|
||||
printk("AICS status get\n");
|
||||
|
||||
printk("Getting AICS description\n");
|
||||
g_cb = false;
|
||||
err = bt_aics_description_get(micp_included.aics[0]);
|
||||
if (err != 0) {
|
||||
FAIL("Could not get AICS description (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
WAIT_FOR_COND(g_cb);
|
||||
printk("AICS description get\n");
|
||||
|
||||
printk("Setting AICS mute\n");
|
||||
expected_input_mute = BT_AICS_STATE_MUTED;
|
||||
g_write_complete = g_cb = false;
|
||||
err = bt_aics_mute(micp_included.aics[0]);
|
||||
if (err != 0) {
|
||||
FAIL("Could not set AICS mute (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
WAIT_FOR_COND(g_aics_input_mute == expected_input_mute &&
|
||||
g_cb && g_write_complete);
|
||||
printk("AICS mute set\n");
|
||||
|
||||
printk("Setting AICS unmute\n");
|
||||
expected_input_mute = BT_AICS_STATE_UNMUTED;
|
||||
g_write_complete = g_cb = false;
|
||||
err = bt_aics_unmute(micp_included.aics[0]);
|
||||
if (err != 0) {
|
||||
FAIL("Could not set AICS unmute (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
WAIT_FOR_COND(g_aics_input_mute == expected_input_mute &&
|
||||
g_cb && g_write_complete);
|
||||
printk("AICS unmute set\n");
|
||||
|
||||
printk("Setting AICS auto mode\n");
|
||||
expected_mode = BT_AICS_MODE_AUTO;
|
||||
g_write_complete = g_cb = false;
|
||||
err = bt_aics_automatic_gain_set(micp_included.aics[0]);
|
||||
if (err != 0) {
|
||||
FAIL("Could not set AICS auto mode (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
WAIT_FOR_COND(g_aics_mode == expected_mode && g_cb && g_write_complete);
|
||||
printk("AICS auto mode set\n");
|
||||
|
||||
printk("Setting AICS manual mode\n");
|
||||
expected_mode = BT_AICS_MODE_MANUAL;
|
||||
g_write_complete = g_cb = false;
|
||||
err = bt_aics_manual_gain_set(micp_included.aics[0]);
|
||||
if (err != 0) {
|
||||
FAIL("Could not set AICS manual mode (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
WAIT_FOR_COND(g_aics_mode == expected_mode && g_cb && g_write_complete);
|
||||
printk("AICS manual mode set\n");
|
||||
|
||||
printk("Setting AICS gain\n");
|
||||
expected_gain = g_aics_gain_max - 1;
|
||||
g_write_complete = g_cb = false;
|
||||
err = bt_aics_gain_set(micp_included.aics[0], expected_gain);
|
||||
if (err != 0) {
|
||||
FAIL("Could not set AICS gain (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
WAIT_FOR_COND(g_aics_gain == expected_gain && g_cb && g_write_complete);
|
||||
printk("AICS gain set\n");
|
||||
|
||||
printk("Setting AICS Description\n");
|
||||
strncpy(expected_aics_desc, "New Input Description",
|
||||
sizeof(expected_aics_desc));
|
||||
expected_aics_desc[sizeof(expected_aics_desc) - 1] = '\0';
|
||||
g_cb = false;
|
||||
err = bt_aics_description_set(micp_included.aics[0],
|
||||
expected_aics_desc);
|
||||
if (err != 0) {
|
||||
FAIL("Could not set AICS Description (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
WAIT_FOR_COND(g_cb &&
|
||||
(strncmp(expected_aics_desc, g_aics_desc,
|
||||
sizeof(expected_aics_desc)) == 0));
|
||||
printk("AICS Description set\n");
|
||||
|
||||
printk("AICS passed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_main(void)
|
||||
{
|
||||
int err;
|
||||
uint8_t expected_mute;
|
||||
struct bt_conn *cached_conn;
|
||||
|
||||
err = bt_enable(bt_ready);
|
||||
|
||||
if (err != 0) {
|
||||
FAIL("Bluetooth discover failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
bt_micp_mic_ctlr_cb_register(&micp_mic_ctlr_cbs);
|
||||
|
||||
WAIT_FOR_COND(g_bt_init);
|
||||
|
||||
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
|
||||
if (err != 0) {
|
||||
FAIL("Scanning failed to start (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
printk("Scanning successfully started\n");
|
||||
WAIT_FOR_FLAG(flag_connected);
|
||||
|
||||
err = bt_micp_mic_ctlr_discover(default_conn, &mic_ctlr);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to discover MICS %d", err);
|
||||
}
|
||||
WAIT_FOR_COND(g_discovery_complete);
|
||||
|
||||
err = bt_micp_mic_ctlr_included_get(mic_ctlr, &micp_included);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to get mic_ctlr context (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Getting mic_ctlr conn\n");
|
||||
err = bt_micp_mic_ctlr_conn_get(mic_ctlr, &cached_conn);
|
||||
if (err != 0) {
|
||||
FAIL("Failed to get mic_ctlr conn (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
if (cached_conn != default_conn) {
|
||||
FAIL("Cached conn was not the conn used to discover");
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Getting mic_ctlr mute state\n");
|
||||
g_cb = false;
|
||||
err = bt_micp_mic_ctlr_mute_get(mic_ctlr);
|
||||
if (err != 0) {
|
||||
FAIL("Could not get mic_ctlr mute state (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
WAIT_FOR_COND(g_cb);
|
||||
printk("mic_ctlr mute state received\n");
|
||||
|
||||
printk("Muting mic_ctlr\n");
|
||||
expected_mute = 1;
|
||||
g_write_complete = g_cb = false;
|
||||
err = bt_micp_mic_ctlr_mute(mic_ctlr);
|
||||
if (err != 0) {
|
||||
FAIL("Could not mute mic_ctlr (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
WAIT_FOR_COND(g_mute == expected_mute && g_cb && g_write_complete);
|
||||
printk("mic_ctlr muted\n");
|
||||
|
||||
printk("Unmuting mic_ctlr\n");
|
||||
expected_mute = 0;
|
||||
g_write_complete = g_cb = false;
|
||||
err = bt_micp_mic_ctlr_unmute(mic_ctlr);
|
||||
if (err != 0) {
|
||||
FAIL("Could not unmute mic_ctlr (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
WAIT_FOR_COND(g_mute == expected_mute && g_cb && g_write_complete);
|
||||
printk("mic_ctlr unmuted\n");
|
||||
|
||||
if (CONFIG_BT_MICP_MIC_CTLR_MAX_AICS_INST > 0 && g_aics_count > 0) {
|
||||
if (test_aics()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PASS("mic_ctlr Passed\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_micp[] = {
|
||||
{
|
||||
.test_id = "micp_mic_ctlr",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_main
|
||||
},
|
||||
BSTEST_END_MARKER
|
||||
};
|
||||
|
||||
struct bst_test_list *test_micp_mic_ctlr_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_micp);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
struct bst_test_list *test_micp_mic_ctlr_install(struct bst_test_list *tests)
|
||||
{
|
||||
return tests;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_MICP_MIC_CTLR */
|
462
tests/bsim/bluetooth/audio/src/micp_mic_dev_test.c
Normal file
462
tests/bsim/bluetooth/audio/src/micp_mic_dev_test.c
Normal file
|
@ -0,0 +1,462 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_BT_MICP_MIC_DEV
|
||||
#include <zephyr/bluetooth/audio/micp.h>
|
||||
#include "common.h"
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
|
||||
#if defined(CONFIG_BT_AICS)
|
||||
#define AICS_DESC_SIZE CONFIG_BT_AICS_MAX_INPUT_DESCRIPTION_SIZE
|
||||
#else
|
||||
#define AICS_DESC_SIZE 0
|
||||
#endif /* CONFIG_BT_AICS */
|
||||
|
||||
static struct bt_micp_included micp_included;
|
||||
|
||||
static volatile uint8_t g_mute;
|
||||
static volatile int8_t g_aics_gain;
|
||||
static volatile uint8_t g_aics_input_mute;
|
||||
static volatile uint8_t g_aics_mode;
|
||||
static volatile uint8_t g_aics_input_type;
|
||||
static volatile uint8_t g_aics_units;
|
||||
static volatile uint8_t g_aics_gain_max;
|
||||
static volatile uint8_t g_aics_gain_min;
|
||||
static volatile bool g_aics_active = true;
|
||||
static char g_aics_desc[AICS_DESC_SIZE];
|
||||
static volatile bool g_cb;
|
||||
|
||||
static void micp_mute_cb(uint8_t mute)
|
||||
{
|
||||
g_mute = mute;
|
||||
g_cb = true;
|
||||
}
|
||||
|
||||
static struct bt_micp_mic_dev_cb micp_cb = {
|
||||
.mute = micp_mute_cb,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_BT_MICP_MIC_DEV_AICS)
|
||||
static void aics_state_cb(struct bt_aics *inst, int err, int8_t gain,
|
||||
uint8_t mute, uint8_t mode)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("AICS state cb err (%d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
g_aics_gain = gain;
|
||||
g_aics_input_mute = mute;
|
||||
g_aics_mode = mode;
|
||||
g_cb = true;
|
||||
}
|
||||
|
||||
static void aics_gain_setting_cb(struct bt_aics *inst, int err, uint8_t units,
|
||||
int8_t minimum, int8_t maximum)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("AICS gain setting cb err (%d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
g_aics_units = units;
|
||||
g_aics_gain_min = minimum;
|
||||
g_aics_gain_max = maximum;
|
||||
g_cb = true;
|
||||
}
|
||||
|
||||
static void aics_input_type_cb(struct bt_aics *inst, int err,
|
||||
uint8_t input_type)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("AICS input type cb err (%d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
g_aics_input_type = input_type;
|
||||
g_cb = true;
|
||||
}
|
||||
|
||||
static void aics_status_cb(struct bt_aics *inst, int err, bool active)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("AICS status cb err (%d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
g_aics_active = active;
|
||||
g_cb = true;
|
||||
}
|
||||
|
||||
static void aics_description_cb(struct bt_aics *inst, int err,
|
||||
char *description)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("AICS description cb err (%d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
strncpy(g_aics_desc, description, sizeof(g_aics_desc) - 1);
|
||||
g_aics_desc[sizeof(g_aics_desc) - 1] = '\0';
|
||||
g_cb = true;
|
||||
}
|
||||
|
||||
static struct bt_aics_cb aics_cb = {
|
||||
.state = aics_state_cb,
|
||||
.gain_setting = aics_gain_setting_cb,
|
||||
.type = aics_input_type_cb,
|
||||
.status = aics_status_cb,
|
||||
.description = aics_description_cb
|
||||
};
|
||||
#endif /* CONFIG_BT_MICP_MIC_DEV_AICS */
|
||||
|
||||
static int test_aics_server_only(void)
|
||||
{
|
||||
int err;
|
||||
int8_t expected_gain;
|
||||
uint8_t expected_input_mute;
|
||||
uint8_t expected_mode;
|
||||
uint8_t expected_input_type;
|
||||
bool expected_aics_active;
|
||||
char expected_aics_desc[AICS_DESC_SIZE];
|
||||
|
||||
printk("Deactivating AICS\n");
|
||||
expected_aics_active = false;
|
||||
err = bt_aics_deactivate(micp_included.aics[0]);
|
||||
if (err != 0) {
|
||||
FAIL("Could not deactivate AICS (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
WAIT_FOR_COND(expected_aics_active == g_aics_active);
|
||||
printk("AICS deactivated\n");
|
||||
|
||||
printk("Activating AICS\n");
|
||||
expected_aics_active = true;
|
||||
err = bt_aics_activate(micp_included.aics[0]);
|
||||
if (err != 0) {
|
||||
FAIL("Could not activate AICS (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
WAIT_FOR_COND(expected_aics_active == g_aics_active);
|
||||
printk("AICS activated\n");
|
||||
|
||||
printk("Getting AICS state\n");
|
||||
g_cb = false;
|
||||
err = bt_aics_state_get(micp_included.aics[0]);
|
||||
if (err != 0) {
|
||||
FAIL("Could not get AICS state (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
WAIT_FOR_COND(g_cb);
|
||||
printk("AICS state get\n");
|
||||
|
||||
printk("Getting AICS gain setting\n");
|
||||
g_cb = false;
|
||||
err = bt_aics_gain_setting_get(micp_included.aics[0]);
|
||||
if (err != 0) {
|
||||
FAIL("Could not get AICS gain setting (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
WAIT_FOR_COND(g_cb);
|
||||
printk("AICS gain setting get\n");
|
||||
|
||||
printk("Getting AICS input type\n");
|
||||
g_cb = false;
|
||||
expected_input_type = BT_AICS_INPUT_TYPE_DIGITAL;
|
||||
err = bt_aics_type_get(micp_included.aics[0]);
|
||||
if (err != 0) {
|
||||
FAIL("Could not get AICS input type (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
/* Expect and wait for input_type from init */
|
||||
WAIT_FOR_COND(g_cb && expected_input_type == g_aics_input_type);
|
||||
printk("AICS input type get\n");
|
||||
|
||||
printk("Getting AICS status\n");
|
||||
g_cb = false;
|
||||
err = bt_aics_status_get(micp_included.aics[0]);
|
||||
if (err != 0) {
|
||||
FAIL("Could not get AICS status (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
WAIT_FOR_COND(g_cb);
|
||||
printk("AICS status get\n");
|
||||
|
||||
printk("Getting AICS description\n");
|
||||
g_cb = false;
|
||||
err = bt_aics_description_get(micp_included.aics[0]);
|
||||
if (err != 0) {
|
||||
FAIL("Could not get AICS description (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
WAIT_FOR_COND(g_cb);
|
||||
printk("AICS description get\n");
|
||||
|
||||
printk("Setting AICS mute\n");
|
||||
g_cb = false;
|
||||
expected_input_mute = BT_AICS_STATE_MUTED;
|
||||
err = bt_aics_mute(micp_included.aics[0]);
|
||||
if (err != 0) {
|
||||
FAIL("Could not set AICS mute (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
WAIT_FOR_COND(g_cb && expected_input_mute == g_aics_input_mute);
|
||||
printk("AICS mute set\n");
|
||||
|
||||
printk("Setting AICS unmute\n");
|
||||
g_cb = false;
|
||||
expected_input_mute = BT_AICS_STATE_UNMUTED;
|
||||
err = bt_aics_unmute(micp_included.aics[0]);
|
||||
if (err != 0) {
|
||||
FAIL("Could not set AICS unmute (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
WAIT_FOR_COND(g_cb && expected_input_mute == g_aics_input_mute);
|
||||
printk("AICS unmute set\n");
|
||||
|
||||
printk("Setting AICS auto mode\n");
|
||||
g_cb = false;
|
||||
expected_mode = BT_AICS_MODE_AUTO;
|
||||
err = bt_aics_automatic_gain_set(micp_included.aics[0]);
|
||||
if (err != 0) {
|
||||
FAIL("Could not set AICS auto mode (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
WAIT_FOR_COND(g_cb && expected_mode == g_aics_mode);
|
||||
printk("AICS auto mode set\n");
|
||||
|
||||
printk("Setting AICS manual mode\n");
|
||||
g_cb = false;
|
||||
expected_mode = BT_AICS_MODE_MANUAL;
|
||||
err = bt_aics_manual_gain_set(micp_included.aics[0]);
|
||||
if (err != 0) {
|
||||
FAIL("Could not set AICS manual mode (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
WAIT_FOR_COND(g_cb && expected_mode == g_aics_mode);
|
||||
printk("AICS manual mode set\n");
|
||||
|
||||
printk("Setting AICS gain\n");
|
||||
g_cb = false;
|
||||
expected_gain = g_aics_gain_max - 1;
|
||||
err = bt_aics_gain_set(micp_included.aics[0], expected_gain);
|
||||
if (err != 0) {
|
||||
FAIL("Could not set AICS gain (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
WAIT_FOR_COND(g_cb && expected_gain == g_aics_gain);
|
||||
printk("AICS gain set\n");
|
||||
|
||||
printk("Setting AICS Description\n");
|
||||
g_cb = false;
|
||||
strncpy(expected_aics_desc, "New Input Description",
|
||||
sizeof(expected_aics_desc));
|
||||
expected_aics_desc[sizeof(expected_aics_desc) - 1] = '\0';
|
||||
err = bt_aics_description_set(micp_included.aics[0], expected_aics_desc);
|
||||
if (err != 0) {
|
||||
FAIL("Could not set AICS Description (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
WAIT_FOR_COND(g_cb && !strncmp(expected_aics_desc, g_aics_desc,
|
||||
sizeof(expected_aics_desc)));
|
||||
printk("AICS Description set\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_mic_dev_only(void)
|
||||
{
|
||||
int err;
|
||||
struct bt_micp_mic_dev_register_param micp_param;
|
||||
uint8_t expected_mute;
|
||||
|
||||
err = bt_enable(NULL);
|
||||
if (err != 0) {
|
||||
FAIL("Bluetooth init failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Bluetooth initialized\n");
|
||||
|
||||
(void)memset(&micp_param, 0, sizeof(micp_param));
|
||||
|
||||
#if defined(CONFIG_BT_MICP_MIC_DEV_AICS)
|
||||
char input_desc[CONFIG_BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT][16];
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(micp_param.aics_param); i++) {
|
||||
micp_param.aics_param[i].desc_writable = true;
|
||||
snprintf(input_desc[i], sizeof(input_desc[i]), "Input %d", i + 1);
|
||||
micp_param.aics_param[i].description = input_desc[i];
|
||||
micp_param.aics_param[i].type = BT_AICS_INPUT_TYPE_DIGITAL;
|
||||
micp_param.aics_param[i].status = g_aics_active;
|
||||
micp_param.aics_param[i].gain_mode = BT_AICS_MODE_MANUAL;
|
||||
micp_param.aics_param[i].units = 1;
|
||||
micp_param.aics_param[i].min_gain = 0;
|
||||
micp_param.aics_param[i].max_gain = 100;
|
||||
micp_param.aics_param[i].cb = &aics_cb;
|
||||
}
|
||||
#endif /* CONFIG_BT_MICP_MIC_DEV_AICS */
|
||||
|
||||
micp_param.cb = &micp_cb;
|
||||
|
||||
err = bt_micp_mic_dev_register(&micp_param);
|
||||
if (err != 0) {
|
||||
FAIL("MICP init failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MICP_MIC_DEV_AICS)) {
|
||||
err = bt_micp_mic_dev_included_get(&micp_included);
|
||||
if (err != 0) {
|
||||
FAIL("MICP get failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
printk("MICP initialized\n");
|
||||
|
||||
printk("Getting MICP mute\n");
|
||||
g_cb = false;
|
||||
err = bt_micp_mic_dev_mute_get();
|
||||
if (err != 0) {
|
||||
FAIL("Could not get MICP mute (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
WAIT_FOR_COND(g_cb);
|
||||
printk("MICP mute get\n");
|
||||
|
||||
printk("Setting MICP mute\n");
|
||||
expected_mute = BT_MICP_MUTE_MUTED;
|
||||
err = bt_micp_mic_dev_mute();
|
||||
if (err != 0) {
|
||||
FAIL("MICP mute failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
WAIT_FOR_COND(expected_mute == g_mute);
|
||||
printk("MICP mute set\n");
|
||||
|
||||
printk("Setting MICP unmute\n");
|
||||
expected_mute = BT_MICP_MUTE_UNMUTED;
|
||||
err = bt_micp_mic_dev_unmute();
|
||||
if (err != 0) {
|
||||
FAIL("MICP unmute failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
WAIT_FOR_COND(expected_mute == g_mute);
|
||||
printk("MICP unmute set\n");
|
||||
|
||||
printk("Setting MICP disable\n");
|
||||
expected_mute = BT_MICP_MUTE_DISABLED;
|
||||
err = bt_micp_mic_dev_mute_disable();
|
||||
if (err != 0) {
|
||||
FAIL("MICP disable failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
WAIT_FOR_COND(expected_mute == g_mute);
|
||||
printk("MICP disable set\n");
|
||||
|
||||
if (CONFIG_BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT > 0) {
|
||||
if (test_aics_server_only()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PASS("MICP mic_dev passed\n");
|
||||
}
|
||||
|
||||
static void test_main(void)
|
||||
{
|
||||
int err;
|
||||
struct bt_micp_mic_dev_register_param micp_param;
|
||||
|
||||
err = bt_enable(NULL);
|
||||
if (err != 0) {
|
||||
FAIL("Bluetooth init failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Bluetooth initialized\n");
|
||||
|
||||
(void)memset(&micp_param, 0, sizeof(micp_param));
|
||||
|
||||
#if defined(CONFIG_BT_MICP_MIC_DEV_AICS)
|
||||
char input_desc[CONFIG_BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT][16];
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(micp_param.aics_param); i++) {
|
||||
micp_param.aics_param[i].desc_writable = true;
|
||||
snprintf(input_desc[i], sizeof(input_desc[i]),
|
||||
"Input %d", i + 1);
|
||||
micp_param.aics_param[i].description = input_desc[i];
|
||||
micp_param.aics_param[i].type = BT_AICS_INPUT_TYPE_UNSPECIFIED;
|
||||
micp_param.aics_param[i].status = g_aics_active;
|
||||
micp_param.aics_param[i].gain_mode = BT_AICS_MODE_MANUAL;
|
||||
micp_param.aics_param[i].units = 1;
|
||||
micp_param.aics_param[i].min_gain = 0;
|
||||
micp_param.aics_param[i].max_gain = 100;
|
||||
micp_param.aics_param[i].cb = &aics_cb;
|
||||
}
|
||||
#endif /* CONFIG_BT_MICP_MIC_DEV_AICS */
|
||||
|
||||
micp_param.cb = &micp_cb;
|
||||
|
||||
err = bt_micp_mic_dev_register(&micp_param);
|
||||
if (err != 0) {
|
||||
FAIL("MICP init failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MICP_MIC_DEV_AICS)) {
|
||||
err = bt_micp_mic_dev_included_get(&micp_included);
|
||||
if (err != 0) {
|
||||
FAIL("MICP get failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
printk("MICP initialized\n");
|
||||
|
||||
err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, AD_SIZE, NULL, 0);
|
||||
if (err != 0) {
|
||||
FAIL("Advertising failed to start (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Advertising successfully started\n");
|
||||
|
||||
WAIT_FOR_FLAG(flag_connected);
|
||||
|
||||
PASS("MICP mic_dev passed\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_micp[] = {
|
||||
{
|
||||
.test_id = "micp_mic_dev_only",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_mic_dev_only
|
||||
},
|
||||
{
|
||||
.test_id = "micp_mic_dev",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_main
|
||||
},
|
||||
BSTEST_END_MARKER
|
||||
};
|
||||
|
||||
struct bst_test_list *test_micp_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_micp);
|
||||
}
|
||||
#else
|
||||
struct bst_test_list *test_micp_install(struct bst_test_list *tests)
|
||||
{
|
||||
return tests;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_MICP_MIC_DEV */
|
267
tests/bsim/bluetooth/audio/src/tbs_client_test.c
Normal file
267
tests/bsim/bluetooth/audio/src/tbs_client_test.c
Normal file
|
@ -0,0 +1,267 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Bose Corporation
|
||||
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_BT_TBS_CLIENT
|
||||
|
||||
#include <zephyr/bluetooth/audio/tbs.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
static volatile bool bt_init;
|
||||
static volatile bool discovery_complete;
|
||||
static volatile bool is_gtbs_found;
|
||||
static volatile bool read_complete;
|
||||
static volatile bool call_placed;
|
||||
static volatile uint8_t call_state;
|
||||
static volatile uint8_t call_index;
|
||||
static volatile uint8_t tbs_count;
|
||||
|
||||
CREATE_FLAG(ccid_read_flag);
|
||||
|
||||
static void tbs_client_call_states_cb(struct bt_conn *conn, int err,
|
||||
uint8_t index, uint8_t call_count,
|
||||
const struct bt_tbs_client_call_state *call_states)
|
||||
{
|
||||
if (index != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
printk("%s\n", __func__);
|
||||
printk("Index %u\n", index);
|
||||
if (err != 0) {
|
||||
FAIL("Call could not read call states (%d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
call_index = call_states[0].index;
|
||||
call_state = call_states[0].state;
|
||||
printk("call index %u - state %u\n", call_index, call_state);
|
||||
}
|
||||
|
||||
static void tbs_client_read_bearer_provider_name(struct bt_conn *conn, int err,
|
||||
uint8_t index,
|
||||
const char *value)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("Call could not read bearer name (%d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Index %u\n", index);
|
||||
printk("Bearer name pointer: %p\n", value);
|
||||
printk("Bearer name: %s\n", value);
|
||||
read_complete = true;
|
||||
}
|
||||
|
||||
static void tbs_client_discover_cb(struct bt_conn *conn, int err,
|
||||
uint8_t count, bool gtbs_found)
|
||||
{
|
||||
printk("%s\n", __func__);
|
||||
if (err != 0) {
|
||||
FAIL("TBS_CLIENT could not be discovered (%d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
tbs_count = count;
|
||||
is_gtbs_found = true;
|
||||
discovery_complete = true;
|
||||
}
|
||||
|
||||
static void tbs_client_read_ccid_cb(struct bt_conn *conn, int err,
|
||||
uint8_t inst_index, uint32_t value)
|
||||
{
|
||||
struct bt_tbs_instance *inst;
|
||||
|
||||
if (value > UINT8_MAX) {
|
||||
FAIL("Invalid CCID: %u", value);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Read CCID %u on index %u\n", value, inst_index);
|
||||
|
||||
inst = bt_tbs_client_get_by_ccid(conn, (uint8_t)value);
|
||||
if (inst == NULL) {
|
||||
FAIL("Could not get instance by CCID: %u", value);
|
||||
return;
|
||||
}
|
||||
|
||||
SET_FLAG(ccid_read_flag);
|
||||
}
|
||||
|
||||
static const struct bt_tbs_client_cb tbs_client_cbs = {
|
||||
.discover = tbs_client_discover_cb,
|
||||
.originate_call = NULL,
|
||||
.terminate_call = NULL,
|
||||
.hold_call = NULL,
|
||||
.accept_call = NULL,
|
||||
.retrieve_call = NULL,
|
||||
.bearer_provider_name = tbs_client_read_bearer_provider_name,
|
||||
.bearer_uci = NULL,
|
||||
.technology = NULL,
|
||||
.uri_list = NULL,
|
||||
.signal_strength = NULL,
|
||||
.signal_interval = NULL,
|
||||
.current_calls = NULL,
|
||||
.ccid = tbs_client_read_ccid_cb,
|
||||
.status_flags = NULL,
|
||||
.call_uri = NULL,
|
||||
.call_state = tbs_client_call_states_cb,
|
||||
.termination_reason = NULL
|
||||
};
|
||||
|
||||
static void bt_ready(int err)
|
||||
{
|
||||
if (err != 0) {
|
||||
FAIL("Bluetooth discover failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
bt_init = true;
|
||||
}
|
||||
|
||||
static void test_ccid(void)
|
||||
{
|
||||
if (is_gtbs_found) {
|
||||
int err;
|
||||
|
||||
UNSET_FLAG(ccid_read_flag);
|
||||
printk("Reading GTBS CCID\n");
|
||||
|
||||
err = bt_tbs_client_read_ccid(default_conn, BT_TBS_GTBS_INDEX);
|
||||
if (err != 0) {
|
||||
FAIL("Read GTBS CCID failed (%d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_FLAG(ccid_read_flag);
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < tbs_count; i++) {
|
||||
int err;
|
||||
|
||||
UNSET_FLAG(ccid_read_flag);
|
||||
printk("Reading bearer CCID on index %u\n", i);
|
||||
|
||||
err = bt_tbs_client_read_ccid(default_conn, i);
|
||||
if (err != 0) {
|
||||
FAIL("Read bearer CCID failed (%d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
WAIT_FOR_FLAG(ccid_read_flag);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_main(void)
|
||||
{
|
||||
int err;
|
||||
int index = 0;
|
||||
int tbs_client_err;
|
||||
|
||||
err = bt_enable(bt_ready);
|
||||
|
||||
if (err != 0) {
|
||||
FAIL("Bluetooth discover failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
bt_tbs_client_register_cb(&tbs_client_cbs);
|
||||
|
||||
WAIT_FOR_COND(bt_init);
|
||||
|
||||
printk("Audio Server: Bluetooth discovered\n");
|
||||
|
||||
err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, AD_SIZE, NULL, 0);
|
||||
if (err != 0) {
|
||||
FAIL("Advertising failed to start (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Advertising successfully started\n");
|
||||
|
||||
WAIT_FOR_COND(flag_connected);
|
||||
|
||||
tbs_client_err = bt_tbs_client_discover(default_conn, true);
|
||||
if (tbs_client_err) {
|
||||
FAIL("Failed to discover TBS_CLIENT for connection %d", tbs_client_err);
|
||||
}
|
||||
|
||||
WAIT_FOR_COND(discovery_complete);
|
||||
|
||||
printk("GTBS %sfound\n", is_gtbs_found ? "" : "not ");
|
||||
|
||||
printk("Placing call\n");
|
||||
err = bt_tbs_client_originate_call(default_conn, 0, "tel:123456789012");
|
||||
if (err != 0) {
|
||||
FAIL("Originate call failed (%d)\n", err);
|
||||
}
|
||||
|
||||
/* Call transitions:
|
||||
* 1) Dialing
|
||||
* 2) Alerting
|
||||
* 3) Active
|
||||
* 4) Remotely Held
|
||||
*/
|
||||
printk("Waiting for remotely held\n");
|
||||
WAIT_FOR_COND(call_state == BT_TBS_CALL_STATE_REMOTELY_HELD);
|
||||
|
||||
printk("Holding call\n");
|
||||
err = bt_tbs_client_hold_call(default_conn, index, call_index);
|
||||
if (err != 0) {
|
||||
FAIL("Hold call failed (%d)\n", err);
|
||||
}
|
||||
|
||||
/* Call transitions:
|
||||
* 1) Locally and remotely held
|
||||
* 2) Locally held
|
||||
*/
|
||||
WAIT_FOR_COND(call_state == BT_TBS_CALL_STATE_LOCALLY_HELD);
|
||||
|
||||
printk("Retrieving call\n");
|
||||
err = bt_tbs_client_retrieve_call(default_conn, index, call_index);
|
||||
if (err != 0) {
|
||||
FAIL("Retrieve call failed (%d)\n", err);
|
||||
}
|
||||
|
||||
WAIT_FOR_COND(call_state == BT_TBS_CALL_STATE_ACTIVE);
|
||||
|
||||
printk("Reading bearer provider name\n");
|
||||
err = bt_tbs_client_read_bearer_provider_name(default_conn, index);
|
||||
if (err != 0) {
|
||||
FAIL("Read bearer provider name failed (%d)\n", err);
|
||||
}
|
||||
|
||||
test_ccid();
|
||||
|
||||
WAIT_FOR_COND(read_complete);
|
||||
PASS("TBS_CLIENT Passed\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_tbs_client[] = {
|
||||
{
|
||||
.test_id = "tbs_client",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_main
|
||||
},
|
||||
BSTEST_END_MARKER
|
||||
};
|
||||
|
||||
struct bst_test_list *test_tbs_client_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_tbs_client);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
struct bst_test_list *test_tbs_client_install(struct bst_test_list *tests)
|
||||
{
|
||||
return tests;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_TBS_CLIENT */
|
120
tests/bsim/bluetooth/audio/src/tbs_test.c
Normal file
120
tests/bsim/bluetooth/audio/src/tbs_test.c
Normal file
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Bose Corporation
|
||||
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_BT_TBS
|
||||
#include <zephyr/bluetooth/audio/tbs.h>
|
||||
#include "common.h"
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
static volatile bool call_placed;
|
||||
static volatile bool call_held;
|
||||
static volatile bool call_id;
|
||||
|
||||
static void tbs_hold_call_cb(struct bt_conn *conn, uint8_t call_index)
|
||||
{
|
||||
if (call_index == call_id) {
|
||||
call_held = true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool tbs_originate_call_cb(struct bt_conn *conn, uint8_t call_index,
|
||||
const char *caller_id)
|
||||
{
|
||||
printk("Placing call to remote with id %u to %s\n",
|
||||
call_index, caller_id);
|
||||
call_id = call_index;
|
||||
call_placed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool tbs_authorize_cb(struct bt_conn *conn)
|
||||
{
|
||||
return conn == default_conn;
|
||||
}
|
||||
|
||||
static struct bt_tbs_cb tbs_cbs = {
|
||||
.originate_call = tbs_originate_call_cb,
|
||||
.terminate_call = NULL,
|
||||
.hold_call = tbs_hold_call_cb,
|
||||
.accept_call = NULL,
|
||||
.retrieve_call = NULL,
|
||||
.join_calls = NULL,
|
||||
.authorize = tbs_authorize_cb,
|
||||
};
|
||||
|
||||
static void test_main(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_enable(NULL);
|
||||
if (err != 0) {
|
||||
printk("Bluetooth init failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Audio Client: Bluetooth initialized\n");
|
||||
|
||||
bt_tbs_register_cb(&tbs_cbs);
|
||||
|
||||
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
|
||||
if (err != 0) {
|
||||
FAIL("Scanning failed to start (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Scanning successfully started\n");
|
||||
|
||||
WAIT_FOR_FLAG(flag_connected);
|
||||
|
||||
WAIT_FOR_COND(call_placed);
|
||||
|
||||
err = bt_tbs_remote_answer(call_id);
|
||||
if (err != BT_TBS_RESULT_CODE_SUCCESS) {
|
||||
FAIL("Remote could not answer call: %d\n", err);
|
||||
return;
|
||||
}
|
||||
printk("Remote answered %u\n", call_id);
|
||||
|
||||
err = bt_tbs_remote_hold(call_id);
|
||||
if (err != BT_TBS_RESULT_CODE_SUCCESS) {
|
||||
FAIL("Remote could not hold call: %d\n", err);
|
||||
}
|
||||
printk("Remote held %u\n", call_id);
|
||||
|
||||
WAIT_FOR_COND(call_held);
|
||||
|
||||
err = bt_tbs_remote_retrieve(call_id);
|
||||
if (err != BT_TBS_RESULT_CODE_SUCCESS) {
|
||||
FAIL("Remote could not answer call: %d\n", err);
|
||||
return;
|
||||
}
|
||||
printk("Remote retrieved %u\n", call_id);
|
||||
|
||||
PASS("TBS passed\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_tbs[] = {
|
||||
{
|
||||
.test_id = "tbs",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_main
|
||||
},
|
||||
BSTEST_END_MARKER
|
||||
};
|
||||
|
||||
struct bst_test_list *test_tbs_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_tbs);
|
||||
}
|
||||
#else
|
||||
struct bst_test_list *test_tbs_install(struct bst_test_list *tests)
|
||||
{
|
||||
return tests;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_TBS */
|
1216
tests/bsim/bluetooth/audio/src/vcp_vol_ctlr_test.c
Normal file
1216
tests/bsim/bluetooth/audio/src/vcp_vol_ctlr_test.c
Normal file
File diff suppressed because it is too large
Load diff
1082
tests/bsim/bluetooth/audio/src/vcp_vol_rend_test.c
Normal file
1082
tests/bsim/bluetooth/audio/src/vcp_vol_rend_test.c
Normal file
File diff suppressed because it is too large
Load diff
11
tests/bsim/bluetooth/audio/test_scripts/_cap.sh
Executable file
11
tests/bsim/bluetooth/audio/test_scripts/_cap.sh
Executable file
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
dir_path=$(dirname "$0")
|
||||
|
||||
$dir_path/cap_unicast.sh
|
||||
|
||||
$dir_path/cap_broadcast.sh
|
48
tests/bsim/bluetooth/audio/test_scripts/bap_bass.sh
Executable file
48
tests/bsim/bluetooth/audio/test_scripts/bap_bass.sh
Executable file
|
@ -0,0 +1,48 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (c) 2020-2022 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
SIMULATION_ID="bass"
|
||||
VERBOSITY_LEVEL=2
|
||||
PROCESS_IDS=""; EXIT_CODE=0
|
||||
|
||||
function Execute(){
|
||||
if [ ! -f $1 ]; then
|
||||
echo -e " \e[91m`pwd`/`basename $1` cannot be found (did you forget to\
|
||||
compile it?)\e[39m"
|
||||
exit 1
|
||||
fi
|
||||
timeout 20 $@ & PROCESS_IDS="$PROCESS_IDS $!"
|
||||
}
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
|
||||
#Give a default value to BOARD if it does not have one yet:
|
||||
BOARD="${BOARD:-nrf52_bsim}"
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin
|
||||
|
||||
printf "\n\n======== Running BASS and BASS client test =========\n\n"
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=bap_scan_delegator \
|
||||
-rs=24
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 \
|
||||
-testid=bap_broadcast_assistant -rs=46
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=2 -testid=bass_broadcaster -rs=69
|
||||
|
||||
# Simulation time should be larger than the WAIT_TIME in common.h
|
||||
Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -D=3 \
|
||||
-sim_length=60e6 $@
|
||||
|
||||
for PROCESS_ID in $PROCESS_IDS; do
|
||||
wait $PROCESS_ID || let "EXIT_CODE=$?"
|
||||
done
|
||||
|
||||
exit $EXIT_CODE #the last exit code != 0
|
65
tests/bsim/bluetooth/audio/test_scripts/bap_broadcast_audio.sh
Executable file
65
tests/bsim/bluetooth/audio/test_scripts/bap_broadcast_audio.sh
Executable file
|
@ -0,0 +1,65 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
VERBOSITY_LEVEL=2
|
||||
PROCESS_IDS=""; EXIT_CODE=0
|
||||
|
||||
function Execute(){
|
||||
if [ ! -f $1 ]; then
|
||||
echo -e " \e[91m`pwd`/`basename $1` cannot be found (did you forget to\
|
||||
compile it?)\e[39m"
|
||||
exit 1
|
||||
fi
|
||||
timeout 20 $@ & PROCESS_IDS="$PROCESS_IDS $!"
|
||||
}
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
|
||||
#Give a default value to BOARD if it does not have one yet:
|
||||
BOARD="${BOARD:-nrf52_bsim}"
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin
|
||||
|
||||
printf "\n\n======== Broadcaster test =========\n\n"
|
||||
|
||||
SIMULATION_ID="broadcaster"
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=broadcast_source -rs=23
|
||||
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=broadcast_sink -rs=27
|
||||
|
||||
# Simulation time should be larger than the WAIT_TIME in common.h
|
||||
Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \
|
||||
-D=2 -sim_length=60e6 $@
|
||||
|
||||
for PROCESS_ID in $PROCESS_IDS; do
|
||||
wait $PROCESS_ID || let "EXIT_CODE=$?"
|
||||
done
|
||||
|
||||
printf "\n\n======== Broadcaster sink disconnect test =========\n\n"
|
||||
|
||||
SIMULATION_ID="broadcaster_sink_disconnect"
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=broadcast_source -rs=23
|
||||
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 \
|
||||
-testid=broadcast_sink_disconnect -rs=27
|
||||
|
||||
# Simulation time should be larger than the WAIT_TIME in common.h
|
||||
Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \
|
||||
-D=2 -sim_length=60e6 $@
|
||||
|
||||
for PROCESS_ID in $PROCESS_IDS; do
|
||||
wait $PROCESS_ID || let "EXIT_CODE=$?"
|
||||
done
|
||||
|
||||
exit $EXIT_CODE #the last exit code != 0
|
44
tests/bsim/bluetooth/audio/test_scripts/bap_unicast_audio.sh
Executable file
44
tests/bsim/bluetooth/audio/test_scripts/bap_unicast_audio.sh
Executable file
|
@ -0,0 +1,44 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (c) 2021-2022 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
SIMULATION_ID="unicast_audio"
|
||||
VERBOSITY_LEVEL=2
|
||||
PROCESS_IDS=""; EXIT_CODE=0
|
||||
|
||||
function Execute(){
|
||||
if [ ! -f $1 ]; then
|
||||
echo -e " \e[91m`pwd`/`basename $1` cannot be found (did you forget to\
|
||||
compile it?)\e[39m"
|
||||
exit 1
|
||||
fi
|
||||
timeout 20 $@ & PROCESS_IDS="$PROCESS_IDS $!"
|
||||
}
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
|
||||
#Give a default value to BOARD if it does not have one yet:
|
||||
BOARD="${BOARD:-nrf52_bsim}"
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin
|
||||
|
||||
printf "\n\n======== Unicast Audio test =========\n\n"
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=unicast_client -rs=23
|
||||
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=unicast_server -rs=27
|
||||
|
||||
# Simulation time should be larger than the WAIT_TIME in common.h
|
||||
Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \
|
||||
-D=2 -sim_length=60e6 $@
|
||||
|
||||
for PROCESS_ID in $PROCESS_IDS; do
|
||||
wait $PROCESS_ID || let "EXIT_CODE=$?"
|
||||
done
|
||||
|
||||
exit $EXIT_CODE #the last exit code != 0
|
43
tests/bsim/bluetooth/audio/test_scripts/cap_broadcast.sh
Executable file
43
tests/bsim/bluetooth/audio/test_scripts/cap_broadcast.sh
Executable file
|
@ -0,0 +1,43 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
SIMULATION_ID="cap_broadcast"
|
||||
VERBOSITY_LEVEL=2
|
||||
PROCESS_IDS=""; EXIT_CODE=0
|
||||
|
||||
function Execute(){
|
||||
if [ ! -f $1 ]; then
|
||||
echo -e " \e[91m`pwd`/`basename $1` cannot be found (did you forget to\
|
||||
compile it?)\e[39m"
|
||||
exit 1
|
||||
fi
|
||||
timeout 20 $@ & PROCESS_IDS="$PROCESS_IDS $!"
|
||||
}
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
|
||||
#Give a default value to BOARD if it does not have one yet:
|
||||
BOARD="${BOARD:-nrf52_bsim}"
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin
|
||||
|
||||
printf "\n\n======== Running CAP broadcast test =========\n\n"
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=cap_acceptor_broadcast -rs=23
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=cap_initiator_broadcast -rs=46
|
||||
|
||||
# Simulation time should be larger than the WAIT_TIME in common.h
|
||||
Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \
|
||||
-D=2 -sim_length=60e6 $@
|
||||
|
||||
for PROCESS_ID in $PROCESS_IDS; do
|
||||
wait $PROCESS_ID || let "EXIT_CODE=$?"
|
||||
done
|
||||
|
||||
exit $EXIT_CODE #the last exit code != 0
|
43
tests/bsim/bluetooth/audio/test_scripts/cap_unicast.sh
Executable file
43
tests/bsim/bluetooth/audio/test_scripts/cap_unicast.sh
Executable file
|
@ -0,0 +1,43 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
SIMULATION_ID="cap_unicast"
|
||||
VERBOSITY_LEVEL=2
|
||||
PROCESS_IDS=""; EXIT_CODE=0
|
||||
|
||||
function Execute(){
|
||||
if [ ! -f $1 ]; then
|
||||
echo -e " \e[91m`pwd`/`basename $1` cannot be found (did you forget to\
|
||||
compile it?)\e[39m"
|
||||
exit 1
|
||||
fi
|
||||
timeout 20 $@ & PROCESS_IDS="$PROCESS_IDS $!"
|
||||
}
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
|
||||
#Give a default value to BOARD if it does not have one yet:
|
||||
BOARD="${BOARD:-nrf52_bsim}"
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin
|
||||
|
||||
printf "\n\n======== Running CAP unicast test =========\n\n"
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=cap_acceptor_unicast -rs=23
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=cap_initiator_unicast -rs=46
|
||||
|
||||
# Simulation time should be larger than the WAIT_TIME in common.h
|
||||
Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \
|
||||
-D=2 -sim_length=60e6 $@
|
||||
|
||||
for PROCESS_ID in $PROCESS_IDS; do
|
||||
wait $PROCESS_ID || let "EXIT_CODE=$?"
|
||||
done
|
||||
|
||||
exit $EXIT_CODE #the last exit code != 0
|
117
tests/bsim/bluetooth/audio/test_scripts/csip.sh
Executable file
117
tests/bsim/bluetooth/audio/test_scripts/csip.sh
Executable file
|
@ -0,0 +1,117 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (c) 2020-2022 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Basic CSIP test. A set coordinator connects to multiple set members
|
||||
# lock thems, unlocks them and disconnects.
|
||||
|
||||
VERBOSITY_LEVEL=2
|
||||
PROCESS_IDS=""; EXIT_CODE=0
|
||||
|
||||
function Execute(){
|
||||
if [ ! -f $1 ]; then
|
||||
echo -e " \e[91m`pwd`/`basename $1` cannot be found (did you forget to\
|
||||
compile it?)\e[39m"
|
||||
exit 1
|
||||
fi
|
||||
timeout 20 $@ & PROCESS_IDS="$PROCESS_IDS $!"
|
||||
}
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
|
||||
#Give a default value to BOARD if it does not have one yet:
|
||||
BOARD="${BOARD:-nrf52_bsim}"
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin
|
||||
|
||||
# NORMAL TEST
|
||||
printf "\n\n======== Running normal test ========\n\n"
|
||||
|
||||
SIMULATION_ID="csip"
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=csip_set_coordinator \
|
||||
-RealEncryption=1 -rs=1
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=csip_set_member \
|
||||
-RealEncryption=1 -rs=2 -argstest rank 1
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=2 -testid=csip_set_member \
|
||||
-RealEncryption=1 -rs=3 -argstest rank 2
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=3 -testid=csip_set_member \
|
||||
-RealEncryption=1 -rs=4 -argstest rank 3
|
||||
|
||||
# Simulation time should be larger than the WAIT_TIME in common.h
|
||||
Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \
|
||||
-D=4 -sim_length=60e6 $@
|
||||
|
||||
for PROCESS_ID in $PROCESS_IDS; do
|
||||
wait $PROCESS_ID || let "EXIT_CODE=$?"
|
||||
done
|
||||
|
||||
PROCESS_IDS="";
|
||||
|
||||
# TEST WITH FORCE RELEASE
|
||||
|
||||
SIMULATION_ID="csip_forced_release"
|
||||
|
||||
printf "\n\n======== Running test with forced release of lock ========\n\n"
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=csip_set_coordinator \
|
||||
-RealEncryption=1 -rs=1
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=csip_set_member \
|
||||
-RealEncryption=1 -rs=2 -argstest rank 1
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=2 -testid=csip_set_member \
|
||||
-RealEncryption=1 -rs=3 -argstest rank 2
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=3 -testid=csip_set_member_release \
|
||||
-RealEncryption=1 -rs=4 -argstest rank 3
|
||||
|
||||
# Simulation time should be larger than the WAIT_TIME in common.h
|
||||
Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \
|
||||
-D=4 -sim_length=60e6 $@
|
||||
|
||||
for PROCESS_ID in $PROCESS_IDS; do
|
||||
wait $PROCESS_ID || let "EXIT_CODE=$?"
|
||||
done
|
||||
|
||||
# TEST WITH SIRK ENC
|
||||
|
||||
SIMULATION_ID="csip_sirk_encrypted"
|
||||
|
||||
printf "\n\n======== Running test with SIRK encrypted ========\n\n"
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=csip_set_coordinator \
|
||||
-RealEncryption=1 -rs=1
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=csip_set_member_enc \
|
||||
-RealEncryption=1 -rs=2 -argstest rank 1
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=2 -testid=csip_set_member_enc \
|
||||
-RealEncryption=1 -rs=3 -argstest rank 2
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=3 -testid=csip_set_member_enc \
|
||||
-RealEncryption=1 -rs=4 -argstest rank 3
|
||||
|
||||
# Simulation time should be larger than the WAIT_TIME in common.h
|
||||
Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \
|
||||
-D=4 -sim_length=60e6 $@
|
||||
|
||||
for PROCESS_ID in $PROCESS_IDS; do
|
||||
wait $PROCESS_ID || let "EXIT_CODE=$?"
|
||||
done
|
||||
exit $EXIT_CODE #the last exit code != 0
|
42
tests/bsim/bluetooth/audio/test_scripts/has.sh
Executable file
42
tests/bsim/bluetooth/audio/test_scripts/has.sh
Executable file
|
@ -0,0 +1,42 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (c) 2022 Codecoup
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
SIMULATION_ID="has"
|
||||
VERBOSITY_LEVEL=2
|
||||
PROCESS_IDS=""; EXIT_CODE=0
|
||||
|
||||
function Execute(){
|
||||
if [ ! -f $1 ]; then
|
||||
echo -e " \e[91m`pwd`/`basename $1` cannot be found (did you forget to\
|
||||
compile it?)\e[39m"
|
||||
exit 1
|
||||
fi
|
||||
timeout 20 $@ & PROCESS_IDS="$PROCESS_IDS $!"
|
||||
}
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
|
||||
#Give a default value to BOARD if it does not have one yet:
|
||||
BOARD="${BOARD:-nrf52_bsim}"
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin
|
||||
|
||||
printf "\n\n======== Running HAS main (API) test =========\n\n"
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=has -rs=24
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=has_client -rs=46
|
||||
|
||||
Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \
|
||||
-D=2 -sim_length=60e6 $@
|
||||
|
||||
for PROCESS_ID in $PROCESS_IDS; do
|
||||
wait $PROCESS_ID || let "EXIT_CODE=$?"
|
||||
done
|
||||
|
||||
exit $EXIT_CODE #the last exit code != 0
|
43
tests/bsim/bluetooth/audio/test_scripts/ias.sh
Executable file
43
tests/bsim/bluetooth/audio/test_scripts/ias.sh
Executable file
|
@ -0,0 +1,43 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (c) 2022 Codecoup
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
SIMULATION_ID="ias"
|
||||
VERBOSITY_LEVEL=2
|
||||
PROCESS_IDS=""; EXIT_CODE=0
|
||||
|
||||
function Execute(){
|
||||
if [ ! -f $1 ]; then
|
||||
echo -e " \e[91m`pwd`/`basename $1` cannot be found (did you forget to\
|
||||
compile it?)\e[39m"
|
||||
exit 1
|
||||
fi
|
||||
timeout 20 $@ & PROCESS_IDS="$PROCESS_IDS $!"
|
||||
}
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
|
||||
#Give a default value to BOARD if it does not have one yet:
|
||||
BOARD="${BOARD:-nrf52_bsim}"
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin
|
||||
|
||||
printf "\n\n======== Running IAS main (API) test =========\n\n"
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=ias -rs=23
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=ias_client -rs=6
|
||||
|
||||
# Simulation time should be larger than the WAIT_TIME in common.h
|
||||
Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \
|
||||
-D=2 -sim_length=60e6 $@
|
||||
|
||||
for PROCESS_ID in $PROCESS_IDS; do
|
||||
wait $PROCESS_ID || let "EXIT_CODE=$?"
|
||||
done
|
||||
|
||||
exit $EXIT_CODE #the last exit code != 0
|
43
tests/bsim/bluetooth/audio/test_scripts/mcs_mcc.sh
Executable file
43
tests/bsim/bluetooth/audio/test_scripts/mcs_mcc.sh
Executable file
|
@ -0,0 +1,43 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
SIMULATION_ID="mcs_mcc"
|
||||
VERBOSITY_LEVEL=2
|
||||
PROCESS_IDS=""; EXIT_CODE=0
|
||||
|
||||
function Execute(){
|
||||
if [ ! -f $1 ]; then
|
||||
echo -e " \e[91m`pwd`/`basename $1` cannot be found (did you forget to\
|
||||
compile it?)\e[39m"
|
||||
exit 1
|
||||
fi
|
||||
timeout 20 $@ & PROCESS_IDS="$PROCESS_IDS $!"
|
||||
}
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
|
||||
#Give a default value to BOARD if it does not have one yet:
|
||||
BOARD="${BOARD:-nrf52_bsim}"
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin
|
||||
|
||||
printf "\n\n======== Running MCS and MCC test =========\n\n"
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=mcc -rs=46
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=mcs -rs=23
|
||||
|
||||
# Simulation time should be larger than the WAIT_TIME in common.h
|
||||
Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \
|
||||
-D=2 -sim_length=60e6 $@
|
||||
|
||||
for PROCESS_ID in $PROCESS_IDS; do
|
||||
wait $PROCESS_ID || let "EXIT_CODE=$?"
|
||||
done
|
||||
|
||||
exit $EXIT_CODE #the last exit code != 0
|
56
tests/bsim/bluetooth/audio/test_scripts/media_controller.sh
Executable file
56
tests/bsim/bluetooth/audio/test_scripts/media_controller.sh
Executable file
|
@ -0,0 +1,56 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
SIMULATION_ID="media_controller"
|
||||
VERBOSITY_LEVEL=2
|
||||
PROCESS_IDS=""; EXIT_CODE=0
|
||||
|
||||
function Execute(){
|
||||
if [ ! -f $1 ]; then
|
||||
echo -e " \e[91m`pwd`/`basename $1` cannot be found (did you forget to\
|
||||
compile it?)\e[39m"
|
||||
exit 1
|
||||
fi
|
||||
timeout 20 $@ & PROCESS_IDS="$PROCESS_IDS $!"
|
||||
}
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
|
||||
#Give a default value to BOARD if it does not have one yet:
|
||||
BOARD="${BOARD:-nrf52_bsim}"
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin
|
||||
|
||||
printf "\n\n======== Running media controller local_player test =========\n\n"
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=media_controller_local_player -rs=23
|
||||
|
||||
# Simulation time should be larger than the WAIT_TIME in common.h
|
||||
Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \
|
||||
-D=1 -sim_length=60e6 $@
|
||||
|
||||
for PROCESS_ID in $PROCESS_IDS; do
|
||||
wait $PROCESS_ID || let "EXIT_CODE=$?"
|
||||
done
|
||||
|
||||
printf "\n\n======== Running media controller remote_player test =========\n\n"
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=media_controller_remote_player -rs=46
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=media_controller_server -rs=23
|
||||
|
||||
# Simulation time should be larger than the WAIT_TIME in common.h
|
||||
Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \
|
||||
-D=2 -sim_length=60e6 $@
|
||||
|
||||
for PROCESS_ID in $PROCESS_IDS; do
|
||||
wait $PROCESS_ID || let "EXIT_CODE=$?"
|
||||
done
|
||||
|
||||
exit $EXIT_CODE #the last exit code != 0
|
56
tests/bsim/bluetooth/audio/test_scripts/micp.sh
Executable file
56
tests/bsim/bluetooth/audio/test_scripts/micp.sh
Executable file
|
@ -0,0 +1,56 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (c) 2020-2022 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
SIMULATION_ID="micp"
|
||||
VERBOSITY_LEVEL=2
|
||||
PROCESS_IDS=""; EXIT_CODE=0
|
||||
|
||||
function Execute(){
|
||||
if [ ! -f $1 ]; then
|
||||
echo -e " \e[91m`pwd`/`basename $1` cannot be found (did you forget to\
|
||||
compile it?)\e[39m"
|
||||
exit 1
|
||||
fi
|
||||
timeout 20 $@ & PROCESS_IDS="$PROCESS_IDS $!"
|
||||
}
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
|
||||
#Give a default value to BOARD if it does not have one yet:
|
||||
BOARD="${BOARD:-nrf52_bsim}"
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin
|
||||
|
||||
printf "\n\n==== Running MICP Microphone Device Only (API) test ====n\n"
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=micp_mic_dev_only -rs=23
|
||||
|
||||
# Simulation time should be larger than the WAIT_TIME in common.h
|
||||
Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \
|
||||
-D=1 -sim_length=60e6 $@
|
||||
|
||||
for PROCESS_ID in $PROCESS_IDS; do
|
||||
wait $PROCESS_ID || let "EXIT_CODE=$?"
|
||||
done
|
||||
|
||||
printf "\n\n==== Running MICP Microphone Device and MICP Microphone Controller test ====n\n"
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=micp_mic_dev -rs=23
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=micp_mic_ctlr -rs=46
|
||||
|
||||
# Simulation time should be larger than the WAIT_TIME in common.h
|
||||
Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \
|
||||
-D=2 -sim_length=60e6 $@
|
||||
|
||||
for PROCESS_ID in $PROCESS_IDS; do
|
||||
wait $PROCESS_ID || let "EXIT_CODE=$?"
|
||||
done
|
||||
|
||||
exit $EXIT_CODE #the last exit code != 0
|
41
tests/bsim/bluetooth/audio/test_scripts/tbs.sh
Executable file
41
tests/bsim/bluetooth/audio/test_scripts/tbs.sh
Executable file
|
@ -0,0 +1,41 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (c) 2019 Bose Corporation
|
||||
# Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
SIMULATION_ID="tbs_ccp"
|
||||
VERBOSITY_LEVEL=2
|
||||
PROCESS_IDS=""; EXIT_CODE=0
|
||||
|
||||
function Execute(){
|
||||
if [ ! -f $1 ]; then
|
||||
echo -e " \e[91m`pwd`/`basename $1` cannot be found (did you forget to\
|
||||
compile it?)\e[39m"
|
||||
exit 1
|
||||
fi
|
||||
timeout 20 $@ & PROCESS_IDS="$PROCESS_IDS $!"
|
||||
}
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
|
||||
#Give a default value to BOARD if it does not have one yet:
|
||||
BOARD="${BOARD:-nrf52_bsim}"
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=tbs -rs=23
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=tbs_client -rs=6
|
||||
|
||||
# Simulation time should be larger than the WAIT_TIME in common.h
|
||||
Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \
|
||||
-D=2 -sim_length=60e6 $@
|
||||
|
||||
for PROCESS_ID in $PROCESS_IDS; do
|
||||
wait $PROCESS_ID || let "EXIT_CODE=$?"
|
||||
done
|
||||
exit $EXIT_CODE #the last exit code != 0
|
56
tests/bsim/bluetooth/audio/test_scripts/vcp.sh
Executable file
56
tests/bsim/bluetooth/audio/test_scripts/vcp.sh
Executable file
|
@ -0,0 +1,56 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (c) 2020-2021 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
SIMULATION_ID="vcp"
|
||||
VERBOSITY_LEVEL=2
|
||||
PROCESS_IDS=""; EXIT_CODE=0
|
||||
|
||||
function Execute(){
|
||||
if [ ! -f $1 ]; then
|
||||
echo -e " \e[91m`pwd`/`basename $1` cannot be found (did you forget to\
|
||||
compile it?)\e[39m"
|
||||
exit 1
|
||||
fi
|
||||
timeout 20 $@ & PROCESS_IDS="$PROCESS_IDS $!"
|
||||
}
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
|
||||
#Give a default value to BOARD if it does not have one yet:
|
||||
BOARD="${BOARD:-nrf52_bsim}"
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin
|
||||
|
||||
printf "\n\n======== Running VCP Volume Renderer standalone (API) test =========\n\n"
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=vcp_vol_rend_standalone -rs=23
|
||||
|
||||
# Simulation time should be larger than the WAIT_TIME in common.h
|
||||
Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \
|
||||
-D=1 -sim_length=60e6 $@
|
||||
|
||||
for PROCESS_ID in $PROCESS_IDS; do
|
||||
wait $PROCESS_ID || let "EXIT_CODE=$?"
|
||||
done
|
||||
|
||||
printf "\n\n======== Running VCP Volume Renderer and VCP Volume Controller test =========\n\n"
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=vcp_vol_rend -rs=23
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \
|
||||
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=vcp_vol_ctlr -rs=46
|
||||
|
||||
# Simulation time should be larger than the WAIT_TIME in common.h
|
||||
Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \
|
||||
-D=2 -sim_length=60e6 $@
|
||||
|
||||
for PROCESS_ID in $PROCESS_IDS; do
|
||||
wait $PROCESS_ID || let "EXIT_CODE=$?"
|
||||
done
|
||||
|
||||
exit $EXIT_CODE #the last exit code != 0
|
28
tests/bsim/bluetooth/compile.sh
Executable file
28
tests/bsim/bluetooth/compile.sh
Executable file
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright 2018 Oticon A/S
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Compile all the applications needed by the bsim tests
|
||||
|
||||
#set -x #uncomment this line for debugging
|
||||
set -ue
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
: "${BSIM_COMPONENTS_PATH:?BSIM_COMPONENTS_PATH must be defined}"
|
||||
: "${ZEPHYR_BASE:?ZEPHYR_BASE must be set to point to the zephyr root\
|
||||
directory}"
|
||||
|
||||
WORK_DIR="${WORK_DIR:-${ZEPHYR_BASE}/bsim_out}"
|
||||
BOARD="${BOARD:-nrf52_bsim}"
|
||||
BOARD_ROOT="${BOARD_ROOT:-${ZEPHYR_BASE}}"
|
||||
|
||||
mkdir -p ${WORK_DIR}
|
||||
|
||||
source ${ZEPHYR_BASE}/tests/bsim/bluetooth/sh_common.source
|
||||
|
||||
run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/audio/compile.sh
|
||||
run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/host/compile.sh
|
||||
run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/ll/compile.sh
|
||||
run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/mesh/compile.sh
|
||||
|
||||
wait_for_background_jobs
|
71
tests/bsim/bluetooth/compile.source
Normal file
71
tests/bsim/bluetooth/compile.source
Normal file
|
@ -0,0 +1,71 @@
|
|||
# Copyright 2018 Oticon A/S
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
source ${ZEPHYR_BASE}/tests/bsim/bluetooth/sh_common.source
|
||||
|
||||
function print_error_info(){
|
||||
echo -e "\033[0;31mFailure building ${app} ${conf_file} for ${BOARD}\033[0m\n\
|
||||
You can rebuild it with\n\
|
||||
${cmake_cmd[@]} && ninja ${ninja_args}"
|
||||
}
|
||||
|
||||
function _compile(){
|
||||
: "${app:?app must be defined}"
|
||||
|
||||
local app_root="${app_root:-${ZEPHYR_BASE}}"
|
||||
local conf_file="${conf_file:-prj.conf}"
|
||||
local conf_overlay="${conf_overlay:-""}"
|
||||
|
||||
local cmake_args="${cmake_args:-"-DCONFIG_COVERAGE=y \
|
||||
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"}"
|
||||
local ninja_args="${ninja_args:-""}"
|
||||
local cc_flags="${cc_flags:-"-Werror"}"
|
||||
|
||||
if [ "${conf_overlay}" ]; then
|
||||
local exe_name="${exe_name:-bs_${BOARD}_${app}_${conf_file}_${conf_overlay}}"
|
||||
else
|
||||
local exe_name="${exe_name:-bs_${BOARD}_${app}_${conf_file}}"
|
||||
fi
|
||||
|
||||
local exe_name=${exe_name//\//_}
|
||||
local exe_name=${exe_name//./_}
|
||||
local exe_name=${BSIM_OUT_PATH}/bin/$exe_name
|
||||
local map_file_name=${exe_name}.Tsymbols
|
||||
|
||||
if [ "${conf_overlay}" ]; then
|
||||
local this_dir=${WORK_DIR}/${app}/${conf_file}_${conf_overlay}
|
||||
else
|
||||
local this_dir=${WORK_DIR}/${app}/${conf_file}
|
||||
fi
|
||||
|
||||
local modules_arg="${ZEPHYR_MODULES:+-DZEPHYR_MODULES=${ZEPHYR_MODULES}}"
|
||||
|
||||
echo "Building $exe_name"
|
||||
|
||||
local ret=0
|
||||
|
||||
local cmake_cmd=(cmake -GNinja -DBOARD_ROOT=${BOARD_ROOT} -DBOARD=${BOARD} \
|
||||
-DCONF_FILE=${conf_file} -DOVERLAY_CONFIG=${conf_overlay} \
|
||||
${modules_arg} \
|
||||
${cmake_args} -DCMAKE_C_FLAGS=\"${cc_flags}\" ${app_root}/${app})
|
||||
|
||||
# Set INCR_BUILD when calling to only do an incremental build
|
||||
if [ ! -v INCR_BUILD ] || [ ! -d "${this_dir}" ]; then
|
||||
[ -d "${this_dir}" ] && rm ${this_dir} -rf
|
||||
mkdir -p ${this_dir} && cd ${this_dir}
|
||||
${cmake_cmd[@]} &> cmake.out || \
|
||||
{ ret="$?"; print_error_info ; cat cmake.out && return $ret; }
|
||||
else
|
||||
cd ${this_dir}
|
||||
fi
|
||||
ninja ${ninja_args} &> ninja.out || \
|
||||
{ ret="$?"; print_error_info ; cat ninja.out && return $ret; }
|
||||
cp ${this_dir}/zephyr/zephyr.exe ${exe_name}
|
||||
|
||||
nm ${exe_name} | grep -v " [U|w] " | sort | cut -d" " -f1,3 > ${map_file_name}
|
||||
sed -i "1i $(wc -l ${map_file_name} | cut -d" " -f1)" ${map_file_name}
|
||||
}
|
||||
|
||||
function compile(){
|
||||
run_in_background _compile
|
||||
}
|
24
tests/bsim/bluetooth/host/adv/chain/CMakeLists.txt
Normal file
24
tests/bsim/bluetooth/host/adv/chain/CMakeLists.txt
Normal file
|
@ -0,0 +1,24 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
if (NOT DEFINED ENV{BSIM_COMPONENTS_PATH})
|
||||
message(FATAL_ERROR "This test requires the BabbleSim simulator. Please set \
|
||||
the environment variable BSIM_COMPONENTS_PATH to point to its \
|
||||
components folder. More information can be found in \
|
||||
https://babblesim.github.io/folder_structure_and_env.html")
|
||||
endif()
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(bsim_test_adv_chain)
|
||||
|
||||
target_sources(app PRIVATE
|
||||
src/main.c
|
||||
${ZEPHYR_BASE}/samples/bluetooth/broadcaster_multiple/src/broadcaster_multiple.c
|
||||
${ZEPHYR_BASE}/samples/bluetooth/observer/src/observer.c
|
||||
)
|
||||
|
||||
zephyr_include_directories(
|
||||
$ENV{BSIM_COMPONENTS_PATH}/libUtilv1/src/
|
||||
$ENV{BSIM_COMPONENTS_PATH}/libPhyComv1/src/
|
||||
)
|
39
tests/bsim/bluetooth/host/adv/chain/prj.conf
Normal file
39
tests/bsim/bluetooth/host/adv/chain/prj.conf
Normal file
|
@ -0,0 +1,39 @@
|
|||
CONFIG_BT=y
|
||||
CONFIG_BT_BROADCASTER=y
|
||||
CONFIG_BT_OBSERVER=y
|
||||
CONFIG_BT_EXT_ADV=y
|
||||
CONFIG_BT_EXT_ADV_MAX_ADV_SET=2
|
||||
CONFIG_BT_DEVICE_NAME="Broadcaster Multiple"
|
||||
|
||||
# Enable Advertising Data chaining in Zephyr Bluetooth LE Controller
|
||||
CONFIG_BT_CTLR_ADVANCED_FEATURES=y
|
||||
CONFIG_BT_CTLR_ADV_DATA_CHAIN=y
|
||||
|
||||
# Zephyr Bluetooth LE Controller will need to use chain PDUs when AD data
|
||||
# length > 191 bytes
|
||||
# - 31 bytes will use 22 bytes for the default name in this sample plus 9 bytes
|
||||
# for manufacturer data
|
||||
# - 191 bytes will use 22 bytes for the default name in this sample plus 169
|
||||
# bytes for manufacturer data
|
||||
# - 277 bytes will use 22 bytes for the default name in this sample plus 255
|
||||
# bytes for manufacturer data
|
||||
CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=1650
|
||||
|
||||
# Increase Advertising PDU buffers to number of advertising sets times the
|
||||
# number of chain PDUs per advertising set when using Zephyr Bluetooth LE
|
||||
# Controller
|
||||
CONFIG_BT_CTLR_ADV_DATA_BUF_MAX=2
|
||||
|
||||
# Maximum Extended Scanning buffer size
|
||||
CONFIG_BT_EXT_SCAN_BUF_SIZE=1650
|
||||
|
||||
# Set maximum scan data length for Extended Scanning in Bluetooth LE Controller
|
||||
CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX=1650
|
||||
|
||||
# Zephyr Bluetooth LE Controller needs 16 event buffers to generate Extended
|
||||
# Advertising Report for receiving the complete 1650 bytes of data
|
||||
CONFIG_BT_BUF_EVT_RX_COUNT=16
|
||||
|
||||
# Increase Zephyr Bluetooth LE Controller Rx buffer to receive complete chain
|
||||
# of PDUs
|
||||
CONFIG_BT_CTLR_RX_BUFFERS=9
|
208
tests/bsim/bluetooth/host/adv/chain/src/main.c
Normal file
208
tests/bsim/bluetooth/host/adv/chain/src/main.c
Normal file
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
|
||||
#include <zephyr/sys/printk.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/hci.h>
|
||||
|
||||
#include "bs_types.h"
|
||||
#include "bs_tracing.h"
|
||||
#include "time_machine.h"
|
||||
#include "bstests.h"
|
||||
|
||||
#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, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define NAME_LEN 30
|
||||
#define BT_AD_DATA_NAME_SIZE (sizeof(CONFIG_BT_DEVICE_NAME) - 1U + 2U)
|
||||
#define BT_AD_DATA_MFG_DATA_SIZE (254U + 2U)
|
||||
#define DATA_LEN MIN((BT_AD_DATA_NAME_SIZE + \
|
||||
BT_AD_DATA_MFG_DATA_SIZE), \
|
||||
CONFIG_BT_CTLR_ADV_DATA_LEN_MAX)
|
||||
|
||||
static K_SEM_DEFINE(sem_recv, 0, 1);
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
|
||||
static void test_adv_main(void)
|
||||
{
|
||||
extern int broadcaster_multiple(void);
|
||||
int err;
|
||||
|
||||
err = broadcaster_multiple();
|
||||
if (err) {
|
||||
FAIL("Adv tests failed\n");
|
||||
bs_trace_silent_exit(err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Successfully started advertising multiple sets */
|
||||
PASS("Adv tests passed\n");
|
||||
|
||||
/* Let the scanner receive the reports */
|
||||
k_sleep(K_SECONDS(10));
|
||||
}
|
||||
|
||||
static bool data_cb(struct bt_data *data, void *user_data)
|
||||
{
|
||||
char *name = user_data;
|
||||
uint8_t len;
|
||||
|
||||
switch (data->type) {
|
||||
case BT_DATA_NAME_SHORTENED:
|
||||
case BT_DATA_NAME_COMPLETE:
|
||||
len = MIN(data->data_len, NAME_LEN - 1);
|
||||
(void)memcpy(name, data->data, len);
|
||||
name[len] = '\0';
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static void scan_recv(const struct bt_le_scan_recv_info *info,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
static uint8_t sid[CONFIG_BT_EXT_ADV_MAX_ADV_SET];
|
||||
static uint8_t sid_count;
|
||||
char name[NAME_LEN];
|
||||
uint8_t data_status;
|
||||
uint16_t data_len;
|
||||
|
||||
data_status = BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS(info->adv_props);
|
||||
if (data_status) {
|
||||
return;
|
||||
}
|
||||
|
||||
data_len = buf->len;
|
||||
if (data_len != DATA_LEN) {
|
||||
return;
|
||||
}
|
||||
|
||||
(void)memset(name, 0, sizeof(name));
|
||||
bt_data_parse(buf, data_cb, name);
|
||||
|
||||
if (strcmp(name, CONFIG_BT_DEVICE_NAME)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < sid_count; i++) {
|
||||
if (sid[i] == info->sid) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
sid[sid_count++] = info->sid;
|
||||
|
||||
if (sid_count < CONFIG_BT_EXT_ADV_MAX_ADV_SET) {
|
||||
return;
|
||||
}
|
||||
|
||||
k_sem_give(&sem_recv);
|
||||
}
|
||||
|
||||
static struct bt_le_scan_cb scan_callbacks = {
|
||||
.recv = scan_recv,
|
||||
};
|
||||
|
||||
static void test_scan_main(void)
|
||||
{
|
||||
extern int observer_start(void);
|
||||
int err;
|
||||
|
||||
err = bt_enable(NULL);
|
||||
if (err) {
|
||||
FAIL("Bluetooth init failed\n");
|
||||
|
||||
bs_trace_silent_exit(err);
|
||||
return;
|
||||
}
|
||||
|
||||
bt_le_scan_cb_register(&scan_callbacks);
|
||||
|
||||
err = observer_start();
|
||||
if (err) {
|
||||
FAIL("Observer start failed\n");
|
||||
|
||||
bs_trace_silent_exit(err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Let the recv callback verify the reports */
|
||||
k_sleep(K_SECONDS(10));
|
||||
|
||||
err = k_sem_take(&sem_recv, K_NO_WAIT);
|
||||
if (err) {
|
||||
FAIL("Scan receive failed\n");
|
||||
|
||||
bs_trace_silent_exit(err);
|
||||
return;
|
||||
}
|
||||
|
||||
PASS("Scan tests passed\n");
|
||||
|
||||
bs_trace_silent_exit(0);
|
||||
}
|
||||
|
||||
static void test_adv_chain_init(void)
|
||||
{
|
||||
bst_ticker_set_next_tick_absolute(60e6);
|
||||
bst_result = In_progress;
|
||||
}
|
||||
|
||||
static void test_adv_chain_tick(bs_time_t HW_device_time)
|
||||
{
|
||||
bst_result = Failed;
|
||||
bs_trace_error_line("Test GATT Write finished.\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_def[] = {
|
||||
{
|
||||
.test_id = "adv",
|
||||
.test_descr = "Central GATT Write",
|
||||
.test_post_init_f = test_adv_chain_init,
|
||||
.test_tick_f = test_adv_chain_tick,
|
||||
.test_main_f = test_adv_main
|
||||
},
|
||||
{
|
||||
.test_id = "scan",
|
||||
.test_descr = "Peripheral GATT Write",
|
||||
.test_post_init_f = test_adv_chain_init,
|
||||
.test_tick_f = test_adv_chain_tick,
|
||||
.test_main_f = test_scan_main
|
||||
},
|
||||
BSTEST_END_MARKER
|
||||
};
|
||||
|
||||
struct bst_test_list *test_adv_chain_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_def);
|
||||
}
|
||||
|
||||
bst_test_install_t test_installers[] = {
|
||||
test_adv_chain_install,
|
||||
NULL
|
||||
};
|
||||
|
||||
void main(void)
|
||||
{
|
||||
bst_main();
|
||||
}
|
39
tests/bsim/bluetooth/host/adv/chain/tests_scripts/adv_chain.sh
Executable file
39
tests/bsim/bluetooth/host/adv/chain/tests_scripts/adv_chain.sh
Executable file
|
@ -0,0 +1,39 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright 2018 Oticon A/S
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Validate Extended Advertising AD Data fragment operation, PDU chaining and
|
||||
# Extended Scanning of chain PDUs
|
||||
simulation_id="adv_chain"
|
||||
verbosity_level=2
|
||||
process_ids=""; exit_code=0
|
||||
|
||||
function Execute(){
|
||||
if [ ! -f $1 ]; then
|
||||
echo -e " \e[91m`pwd`/`basename $1` cannot be found (did you forget to\
|
||||
compile it?)\e[39m"
|
||||
exit 1
|
||||
fi
|
||||
timeout 10 $@ & process_ids="$process_ids $!"
|
||||
}
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
|
||||
#Give a default value to BOARD if it does not have one yet:
|
||||
BOARD="${BOARD:-nrf52_bsim}"
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_adv_chain_prj_conf \
|
||||
-v=${verbosity_level} -s=${simulation_id} -d=0 -testid=adv
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_adv_chain_prj_conf\
|
||||
-v=${verbosity_level} -s=${simulation_id} -d=1 -testid=scan
|
||||
|
||||
Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \
|
||||
-D=2 -sim_length=10e6 $@
|
||||
|
||||
for process_id in $process_ids; do
|
||||
wait $process_id || let "exit_code=$?"
|
||||
done
|
||||
exit $exit_code #the last exit code != 0
|
26
tests/bsim/bluetooth/host/adv/periodic/CMakeLists.txt
Normal file
26
tests/bsim/bluetooth/host/adv/periodic/CMakeLists.txt
Normal file
|
@ -0,0 +1,26 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
if (NOT DEFINED ENV{BSIM_COMPONENTS_PATH})
|
||||
message(FATAL_ERROR "This test requires the BabbleSim simulator. Please set\
|
||||
the environment variable BSIM_COMPONENTS_PATH to point to its components \
|
||||
folder. More information can be found in\
|
||||
https://babblesim.github.io/folder_structure_and_env.html")
|
||||
endif()
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(bsim_test_audio)
|
||||
|
||||
target_sources(app PRIVATE
|
||||
src/common.c
|
||||
src/main.c
|
||||
src/per_adv_advertiser.c
|
||||
src/per_adv_syncer.c
|
||||
)
|
||||
|
||||
zephyr_include_directories(
|
||||
$ENV{BSIM_COMPONENTS_PATH}/libUtilv1/src/
|
||||
$ENV{BSIM_COMPONENTS_PATH}/libPhyComv1/src/
|
||||
${ZEPHYR_BASE}/subsys/bluetooth/host/audio/
|
||||
)
|
14
tests/bsim/bluetooth/host/adv/periodic/prj.conf
Normal file
14
tests/bsim/bluetooth/host/adv/periodic/prj.conf
Normal file
|
@ -0,0 +1,14 @@
|
|||
CONFIG_BT=y
|
||||
CONFIG_BT_DEVICE_NAME="test_per_adv"
|
||||
CONFIG_BT_PERIPHERAL=y
|
||||
CONFIG_BT_CENTRAL=y
|
||||
CONFIG_BT_SMP=y
|
||||
CONFIG_BT_PRIVACY=y
|
||||
|
||||
CONFIG_BT_EXT_ADV=y
|
||||
CONFIG_BT_EXT_ADV_MAX_ADV_SET=2
|
||||
CONFIG_BT_CTLR_ADVANCED_FEATURES=y
|
||||
CONFIG_BT_CTLR_ADV_AUX_SET=2
|
||||
CONFIG_BT_CTLR_ADV_DATA_BUF_MAX=2
|
||||
CONFIG_BT_PER_ADV=y
|
||||
CONFIG_BT_PER_ADV_SYNC=y
|
21
tests/bsim/bluetooth/host/adv/periodic/prj_long_data.conf
Normal file
21
tests/bsim/bluetooth/host/adv/periodic/prj_long_data.conf
Normal file
|
@ -0,0 +1,21 @@
|
|||
CONFIG_BT=y
|
||||
CONFIG_BT_DEVICE_NAME="test_per_adv"
|
||||
CONFIG_BT_PERIPHERAL=y
|
||||
CONFIG_BT_CENTRAL=y
|
||||
CONFIG_BT_SMP=y
|
||||
CONFIG_BT_PRIVACY=y
|
||||
|
||||
CONFIG_BT_EXT_ADV=y
|
||||
CONFIG_BT_EXT_ADV_MAX_ADV_SET=2
|
||||
CONFIG_BT_CTLR_ADVANCED_FEATURES=y
|
||||
CONFIG_BT_CTLR_ADV_AUX_SET=2
|
||||
CONFIG_BT_CTLR_ADV_DATA_BUF_MAX=2
|
||||
CONFIG_BT_CTLR_ADV_AUX_PDU_BACK2BACK=y
|
||||
CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK=y
|
||||
CONFIG_BT_PER_ADV=y
|
||||
CONFIG_BT_PER_ADV_SYNC=y
|
||||
CONFIG_BT_PER_ADV_SYNC_BUF_SIZE=1650
|
||||
|
||||
CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=1650
|
||||
CONFIG_BT_CTLR_ADV_DATA_CHAIN=y
|
||||
CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX=1650
|
41
tests/bsim/bluetooth/host/adv/periodic/src/common.c
Normal file
41
tests/bsim/bluetooth/host/adv/periodic/src/common.c
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
uint8_t mfg_data[254] = {
|
||||
0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
|
||||
0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
|
||||
0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A,
|
||||
0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
|
||||
0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
|
||||
0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
|
||||
0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
|
||||
0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
|
||||
0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84,
|
||||
0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93,
|
||||
0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2,
|
||||
0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1,
|
||||
0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0,
|
||||
0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
|
||||
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE,
|
||||
0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED,
|
||||
0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB};
|
59
tests/bsim/bluetooth/host/adv/periodic/src/common.h
Normal file
59
tests/bsim/bluetooth/host/adv/periodic/src/common.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
* Common functions and helpers
|
||||
*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_TEST_BSIM_BT_AUDIO_TEST_
|
||||
#define ZEPHYR_TEST_BSIM_BT_AUDIO_TEST_
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
|
||||
#include "bs_types.h"
|
||||
#include "bs_tracing.h"
|
||||
#include "time_machine.h"
|
||||
#include "bstests.h"
|
||||
|
||||
#include <zephyr/types.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <zephyr/sys_clock.h>
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/hci.h>
|
||||
#include <zephyr/bluetooth/conn.h>
|
||||
#include <zephyr/bluetooth/uuid.h>
|
||||
#include <zephyr/bluetooth/gatt.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 UNSET_FLAG(flag) (void)atomic_set(&flag, (atomic_t)false)
|
||||
#define TEST_FLAG(flag) (atomic_get(&flag) == (atomic_t)true)
|
||||
#define WAIT_FOR_FLAG(flag) \
|
||||
while (!(bool)atomic_get(&flag)) { \
|
||||
(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);
|
||||
|
||||
extern uint8_t mfg_data[254];
|
||||
|
||||
#endif /* ZEPHYR_TEST_BSIM_BT_AUDIO_TEST_ */
|
21
tests/bsim/bluetooth/host/adv/periodic/src/main.c
Normal file
21
tests/bsim/bluetooth/host/adv/periodic/src/main.c
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "bstests.h"
|
||||
|
||||
extern struct bst_test_list *test_per_adv_syncer(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_per_adv_advertiser(struct bst_test_list *tests);
|
||||
|
||||
bst_test_install_t test_installers[] = {
|
||||
test_per_adv_syncer,
|
||||
test_per_adv_advertiser,
|
||||
NULL
|
||||
};
|
||||
|
||||
void main(void)
|
||||
{
|
||||
bst_main();
|
||||
}
|
362
tests/bsim/bluetooth/host/adv/periodic/src/per_adv_advertiser.c
Normal file
362
tests/bsim/bluetooth/host/adv/periodic/src/per_adv_advertiser.c
Normal file
|
@ -0,0 +1,362 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <zephyr/kernel.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 "common.h"
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
|
||||
static struct bt_conn *g_conn;
|
||||
|
||||
CREATE_FLAG(flag_connected);
|
||||
CREATE_FLAG(flag_bonded);
|
||||
|
||||
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);
|
||||
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 struct bt_conn_cb conn_cbs = {
|
||||
.connected = connected,
|
||||
.disconnected = disconnected,
|
||||
};
|
||||
|
||||
static void pairing_complete_cb(struct bt_conn *conn, bool bonded)
|
||||
{
|
||||
if (conn == g_conn && bonded) {
|
||||
SET_FLAG(flag_bonded);
|
||||
}
|
||||
}
|
||||
|
||||
static struct bt_conn_auth_info_cb auto_info_cbs = {
|
||||
.pairing_complete = pairing_complete_cb,
|
||||
};
|
||||
|
||||
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");
|
||||
|
||||
bt_conn_cb_register(&conn_cbs);
|
||||
bt_conn_auth_info_cb_register(&auto_info_cbs);
|
||||
}
|
||||
|
||||
static void create_per_adv_set(struct bt_le_ext_adv **adv)
|
||||
{
|
||||
int err;
|
||||
|
||||
printk("Creating extended advertising set...");
|
||||
err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN_NAME, NULL, adv);
|
||||
if (err) {
|
||||
printk("Failed to create advertising set: %d\n", err);
|
||||
return;
|
||||
}
|
||||
printk("done.\n");
|
||||
|
||||
printk("Setting periodic advertising parameters...");
|
||||
err = bt_le_per_adv_set_param(*adv, BT_LE_PER_ADV_DEFAULT);
|
||||
if (err) {
|
||||
printk("Failed to set periodic advertising parameters: %d\n",
|
||||
err);
|
||||
return;
|
||||
}
|
||||
printk("done.\n");
|
||||
}
|
||||
|
||||
static void create_conn_adv_set(struct bt_le_ext_adv **adv)
|
||||
{
|
||||
int err;
|
||||
|
||||
printk("Creating connectable extended advertising set...");
|
||||
err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN_NAME, 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 start_per_adv_set(struct bt_le_ext_adv *adv)
|
||||
{
|
||||
int err;
|
||||
|
||||
printk("Starting periodic advertising...");
|
||||
err = bt_le_per_adv_start(adv);
|
||||
if (err) {
|
||||
printk("Failed to start periodic advertising: %d\n", err);
|
||||
return;
|
||||
}
|
||||
printk("done.\n");
|
||||
}
|
||||
|
||||
#if (CONFIG_BT_CTLR_ADV_DATA_CHAIN)
|
||||
static void set_per_adv_data(struct bt_le_ext_adv *adv)
|
||||
{
|
||||
int err;
|
||||
const struct bt_data ad[] = {
|
||||
BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, ARRAY_SIZE(mfg_data)),
|
||||
BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, ARRAY_SIZE(mfg_data))};
|
||||
|
||||
printk("Setting Periodic Advertising Data...");
|
||||
err = bt_le_per_adv_set_data(adv, ad, ARRAY_SIZE(ad));
|
||||
if (err) {
|
||||
printk("Failed to set periodic advertising data: %d\n",
|
||||
err);
|
||||
return;
|
||||
}
|
||||
printk("done.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
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 stop_per_adv_set(struct bt_le_ext_adv *adv)
|
||||
{
|
||||
int err;
|
||||
|
||||
printk("Stopping Periodic Advertising...");
|
||||
err = bt_le_per_adv_stop(adv);
|
||||
if (err) {
|
||||
printk("Failed to stop periodic 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 main_per_adv_advertiser(void)
|
||||
{
|
||||
struct bt_le_ext_adv *per_adv;
|
||||
|
||||
common_init();
|
||||
|
||||
create_per_adv_set(&per_adv);
|
||||
|
||||
start_per_adv_set(per_adv);
|
||||
start_ext_adv_set(per_adv);
|
||||
|
||||
/* Advertise for a bit */
|
||||
k_sleep(K_SECONDS(10));
|
||||
|
||||
stop_per_adv_set(per_adv);
|
||||
stop_ext_adv_set(per_adv);
|
||||
|
||||
delete_adv_set(per_adv);
|
||||
per_adv = NULL;
|
||||
|
||||
PASS("Periodic advertiser passed\n");
|
||||
}
|
||||
|
||||
static void main_per_adv_conn_advertiser(void)
|
||||
{
|
||||
struct bt_le_ext_adv *conn_adv;
|
||||
struct bt_le_ext_adv *per_adv;
|
||||
|
||||
common_init();
|
||||
|
||||
create_per_adv_set(&per_adv);
|
||||
create_conn_adv_set(&conn_adv);
|
||||
|
||||
start_per_adv_set(per_adv);
|
||||
start_ext_adv_set(per_adv);
|
||||
start_ext_adv_set(conn_adv);
|
||||
|
||||
WAIT_FOR_FLAG(flag_connected);
|
||||
|
||||
/* Advertise for a bit */
|
||||
k_sleep(K_SECONDS(10));
|
||||
|
||||
stop_per_adv_set(per_adv);
|
||||
stop_ext_adv_set(per_adv);
|
||||
stop_ext_adv_set(conn_adv);
|
||||
|
||||
delete_adv_set(per_adv);
|
||||
per_adv = NULL;
|
||||
delete_adv_set(conn_adv);
|
||||
conn_adv = NULL;
|
||||
|
||||
PASS("Periodic advertiser passed\n");
|
||||
}
|
||||
|
||||
static void main_per_adv_conn_privacy_advertiser(void)
|
||||
{
|
||||
struct bt_le_ext_adv *conn_adv;
|
||||
struct bt_le_ext_adv *per_adv;
|
||||
|
||||
common_init();
|
||||
|
||||
create_conn_adv_set(&conn_adv);
|
||||
|
||||
start_ext_adv_set(conn_adv);
|
||||
|
||||
WAIT_FOR_FLAG(flag_connected);
|
||||
WAIT_FOR_FLAG(flag_bonded);
|
||||
|
||||
/* Start periodic advertising after bonding so that the scanner gets
|
||||
* the resolved address
|
||||
*/
|
||||
create_per_adv_set(&per_adv);
|
||||
start_per_adv_set(per_adv);
|
||||
start_ext_adv_set(per_adv);
|
||||
|
||||
/* Advertise for a bit */
|
||||
k_sleep(K_SECONDS(10));
|
||||
|
||||
stop_per_adv_set(per_adv);
|
||||
stop_ext_adv_set(per_adv);
|
||||
stop_ext_adv_set(conn_adv);
|
||||
|
||||
delete_adv_set(per_adv);
|
||||
per_adv = NULL;
|
||||
delete_adv_set(conn_adv);
|
||||
conn_adv = NULL;
|
||||
|
||||
PASS("Periodic advertiser passed\n");
|
||||
}
|
||||
|
||||
static void main_per_adv_long_data_advertiser(void)
|
||||
{
|
||||
#if (CONFIG_BT_CTLR_ADV_DATA_CHAIN)
|
||||
struct bt_le_ext_adv *per_adv;
|
||||
|
||||
common_init();
|
||||
|
||||
create_per_adv_set(&per_adv);
|
||||
|
||||
set_per_adv_data(per_adv);
|
||||
start_per_adv_set(per_adv);
|
||||
start_ext_adv_set(per_adv);
|
||||
|
||||
/* Advertise for a bit */
|
||||
k_sleep(K_SECONDS(10));
|
||||
|
||||
stop_per_adv_set(per_adv);
|
||||
stop_ext_adv_set(per_adv);
|
||||
|
||||
delete_adv_set(per_adv);
|
||||
per_adv = NULL;
|
||||
#endif
|
||||
PASS("Periodic long data advertiser passed\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance per_adv_advertiser[] = {
|
||||
{
|
||||
.test_id = "per_adv_advertiser",
|
||||
.test_descr = "Basic periodic advertising test. "
|
||||
"Will just start periodic advertising.",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = main_per_adv_advertiser
|
||||
},
|
||||
{
|
||||
.test_id = "per_adv_conn_advertiser",
|
||||
.test_descr = "Periodic advertising test with concurrent ACL "
|
||||
"and PA sync.",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = main_per_adv_conn_advertiser
|
||||
},
|
||||
{
|
||||
.test_id = "per_adv_conn_privacy_advertiser",
|
||||
.test_descr = "Periodic advertising test with concurrent ACL "
|
||||
"with bonding and PA sync.",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = main_per_adv_conn_privacy_advertiser
|
||||
},
|
||||
{
|
||||
.test_id = "per_adv_long_data_advertiser",
|
||||
.test_descr = "Periodic advertising test with a longer data length. "
|
||||
"To test the syncers reassembly of large data packets",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = main_per_adv_long_data_advertiser
|
||||
},
|
||||
BSTEST_END_MARKER
|
||||
};
|
||||
|
||||
struct bst_test_list *test_per_adv_advertiser(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, per_adv_advertiser);
|
||||
}
|
377
tests/bsim/bluetooth/host/adv/periodic/src/per_adv_syncer.c
Normal file
377
tests/bsim/bluetooth/host/adv/periodic/src/per_adv_syncer.c
Normal file
|
@ -0,0 +1,377 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <zephyr/kernel.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 "common.h"
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
|
||||
static struct bt_conn *g_conn;
|
||||
static bt_addr_le_t per_addr;
|
||||
static uint8_t per_sid;
|
||||
|
||||
CREATE_FLAG(flag_connected);
|
||||
CREATE_FLAG(flag_bonded);
|
||||
CREATE_FLAG(flag_per_adv);
|
||||
CREATE_FLAG(flag_per_adv_sync);
|
||||
CREATE_FLAG(flag_per_adv_sync_lost);
|
||||
CREATE_FLAG(flag_per_adv_recv);
|
||||
|
||||
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);
|
||||
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 struct bt_conn_cb conn_cbs = {
|
||||
.connected = connected,
|
||||
.disconnected = disconnected,
|
||||
};
|
||||
|
||||
static void pairing_complete_cb(struct bt_conn *conn, bool bonded)
|
||||
{
|
||||
if (conn == g_conn && bonded) {
|
||||
SET_FLAG(flag_bonded);
|
||||
}
|
||||
}
|
||||
|
||||
static struct bt_conn_auth_info_cb auto_info_cbs = {
|
||||
.pairing_complete = pairing_complete_cb,
|
||||
};
|
||||
|
||||
static void scan_recv(const struct bt_le_scan_recv_info *info,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
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 != 0) {
|
||||
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 != 0) {
|
||||
FAIL("Could not connect to peer: %d", err);
|
||||
return;
|
||||
}
|
||||
} else if (!TEST_FLAG(flag_per_adv) && info->interval != 0U) {
|
||||
|
||||
per_sid = info->sid;
|
||||
bt_addr_le_copy(&per_addr, info->addr);
|
||||
|
||||
SET_FLAG(flag_per_adv);
|
||||
}
|
||||
}
|
||||
|
||||
static struct bt_le_scan_cb scan_callbacks = {
|
||||
.recv = scan_recv,
|
||||
};
|
||||
|
||||
static void sync_cb(struct bt_le_per_adv_sync *sync,
|
||||
struct bt_le_per_adv_sync_synced_info *info)
|
||||
{
|
||||
char le_addr[BT_ADDR_LE_STR_LEN];
|
||||
|
||||
bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
|
||||
|
||||
printk("PER_ADV_SYNC[%u]: [DEVICE]: %s synced, "
|
||||
"Interval 0x%04x (%u us)\n",
|
||||
bt_le_per_adv_sync_get_index(sync), le_addr,
|
||||
info->interval, BT_CONN_INTERVAL_TO_US(info->interval));
|
||||
|
||||
SET_FLAG(flag_per_adv_sync);
|
||||
}
|
||||
|
||||
static void term_cb(struct bt_le_per_adv_sync *sync,
|
||||
const struct bt_le_per_adv_sync_term_info *info)
|
||||
{
|
||||
char le_addr[BT_ADDR_LE_STR_LEN];
|
||||
|
||||
bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
|
||||
|
||||
printk("PER_ADV_SYNC[%u]: [DEVICE]: %s sync terminated\n",
|
||||
bt_le_per_adv_sync_get_index(sync), le_addr);
|
||||
|
||||
SET_FLAG(flag_per_adv_sync_lost);
|
||||
}
|
||||
|
||||
static void recv_cb(struct bt_le_per_adv_sync *recv_sync,
|
||||
const struct bt_le_per_adv_sync_recv_info *info,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
char le_addr[BT_ADDR_LE_STR_LEN];
|
||||
uint8_t buf_data_len;
|
||||
|
||||
if (TEST_FLAG(flag_per_adv_recv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
|
||||
printk("PER_ADV_SYNC[%u]: [DEVICE]: %s advertisment received\n",
|
||||
bt_le_per_adv_sync_get_index(recv_sync), le_addr);
|
||||
|
||||
while (buf->len > 0) {
|
||||
buf_data_len = (uint8_t)net_buf_simple_pull_le16(buf);
|
||||
if (buf->data[0] - 1 != sizeof(mfg_data) ||
|
||||
memcmp(buf->data, mfg_data, sizeof(mfg_data))) {
|
||||
FAIL("Unexpected adv data received\n");
|
||||
}
|
||||
net_buf_simple_pull(buf, ARRAY_SIZE(mfg_data));
|
||||
}
|
||||
|
||||
SET_FLAG(flag_per_adv_recv);
|
||||
}
|
||||
|
||||
static struct bt_le_per_adv_sync_cb sync_callbacks = {
|
||||
.synced = sync_cb,
|
||||
.term = term_cb,
|
||||
.recv = recv_cb,
|
||||
};
|
||||
|
||||
static void common_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_enable(NULL);
|
||||
|
||||
if (err) {
|
||||
FAIL("Bluetooth init failed: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
bt_le_scan_cb_register(&scan_callbacks);
|
||||
bt_le_per_adv_sync_cb_register(&sync_callbacks);
|
||||
bt_conn_cb_register(&conn_cbs);
|
||||
bt_conn_auth_info_cb_register(&auto_info_cbs);
|
||||
}
|
||||
|
||||
static void start_scan(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
printk("Start scanning...");
|
||||
err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, NULL);
|
||||
if (err) {
|
||||
FAIL("Failed to start scan: %d\n", err);
|
||||
return;
|
||||
}
|
||||
printk("done.\n");
|
||||
}
|
||||
|
||||
static void create_pa_sync(struct bt_le_per_adv_sync **sync)
|
||||
{
|
||||
struct bt_le_per_adv_sync_param sync_create_param = { 0 };
|
||||
int err;
|
||||
|
||||
printk("Creating periodic advertising sync...");
|
||||
bt_addr_le_copy(&sync_create_param.addr, &per_addr);
|
||||
sync_create_param.options = 0;
|
||||
sync_create_param.sid = per_sid;
|
||||
sync_create_param.skip = 0;
|
||||
sync_create_param.timeout = 0x0a;
|
||||
err = bt_le_per_adv_sync_create(&sync_create_param, sync);
|
||||
if (err) {
|
||||
FAIL("Failed to create periodic advertising sync: %d\n", err);
|
||||
return;
|
||||
}
|
||||
printk("done.\n");
|
||||
|
||||
printk("Waiting for periodic sync...\n");
|
||||
WAIT_FOR_FLAG(flag_per_adv_sync);
|
||||
printk("Periodic sync established.\n");
|
||||
}
|
||||
|
||||
static void start_bonding(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
printk("Setting security...");
|
||||
err = bt_conn_set_security(g_conn, BT_SECURITY_L2);
|
||||
if (err) {
|
||||
FAIL("Failed to set security: %d\n", err);
|
||||
return;
|
||||
}
|
||||
printk("done.\n");
|
||||
}
|
||||
|
||||
static void main_per_adv_syncer(void)
|
||||
{
|
||||
struct bt_le_per_adv_sync *sync = NULL;
|
||||
|
||||
common_init();
|
||||
start_scan();
|
||||
|
||||
printk("Waiting for periodic advertising...\n");
|
||||
WAIT_FOR_FLAG(flag_per_adv);
|
||||
printk("Found periodic advertising.\n");
|
||||
|
||||
create_pa_sync(&sync);
|
||||
|
||||
printk("Waiting for periodic sync lost...\n");
|
||||
WAIT_FOR_FLAG(flag_per_adv_sync_lost);
|
||||
|
||||
PASS("Periodic advertising syncer passed\n");
|
||||
}
|
||||
|
||||
static void main_per_adv_conn_syncer(void)
|
||||
{
|
||||
struct bt_le_per_adv_sync *sync = NULL;
|
||||
|
||||
common_init();
|
||||
start_scan();
|
||||
|
||||
printk("Waiting for connection...");
|
||||
WAIT_FOR_FLAG(flag_connected);
|
||||
printk("done.\n");
|
||||
|
||||
start_scan();
|
||||
|
||||
printk("Waiting for periodic advertising...\n");
|
||||
WAIT_FOR_FLAG(flag_per_adv);
|
||||
printk("Found periodic advertising.\n");
|
||||
|
||||
create_pa_sync(&sync);
|
||||
|
||||
printk("Waiting for periodic sync lost...\n");
|
||||
WAIT_FOR_FLAG(flag_per_adv_sync_lost);
|
||||
|
||||
PASS("Periodic advertising syncer passed\n");
|
||||
}
|
||||
|
||||
static void main_per_adv_conn_privacy_syncer(void)
|
||||
{
|
||||
struct bt_le_per_adv_sync *sync = NULL;
|
||||
|
||||
common_init();
|
||||
start_scan();
|
||||
|
||||
printk("Waiting for connection...");
|
||||
WAIT_FOR_FLAG(flag_connected);
|
||||
printk("done.\n");
|
||||
|
||||
start_bonding();
|
||||
|
||||
printk("Waiting for bonding...");
|
||||
WAIT_FOR_FLAG(flag_bonded);
|
||||
printk("done.\n");
|
||||
|
||||
start_scan();
|
||||
|
||||
printk("Waiting for periodic advertising...\n");
|
||||
WAIT_FOR_FLAG(flag_per_adv);
|
||||
printk("Found periodic advertising.\n");
|
||||
|
||||
create_pa_sync(&sync);
|
||||
|
||||
printk("Waiting for periodic sync lost...\n");
|
||||
WAIT_FOR_FLAG(flag_per_adv_sync_lost);
|
||||
|
||||
PASS("Periodic advertising syncer passed\n");
|
||||
}
|
||||
|
||||
static void main_per_adv_long_data_syncer(void)
|
||||
{
|
||||
#if (CONFIG_BT_PER_ADV_SYNC_BUF_SIZE > 0)
|
||||
struct bt_le_per_adv_sync *sync = NULL;
|
||||
|
||||
common_init();
|
||||
start_scan();
|
||||
|
||||
printk("Waiting for periodic advertising...\n");
|
||||
WAIT_FOR_FLAG(flag_per_adv);
|
||||
printk("Found periodic advertising.\n");
|
||||
|
||||
create_pa_sync(&sync);
|
||||
|
||||
printk("Waiting to receive periodic advertisment...\n");
|
||||
WAIT_FOR_FLAG(flag_per_adv_recv);
|
||||
|
||||
printk("Waiting for periodic sync lost...\n");
|
||||
WAIT_FOR_FLAG(flag_per_adv_sync_lost);
|
||||
#endif
|
||||
PASS("Periodic advertising long data syncer passed\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance per_adv_syncer[] = {
|
||||
{
|
||||
.test_id = "per_adv_syncer",
|
||||
.test_descr = "Basic periodic advertising sync test. "
|
||||
"Will just sync to a periodic advertiser.",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = main_per_adv_syncer
|
||||
},
|
||||
{
|
||||
.test_id = "per_adv_conn_syncer",
|
||||
.test_descr = "Periodic advertising sync test, but where there "
|
||||
"is a connection between the advertiser and the "
|
||||
"syncer.",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = main_per_adv_conn_syncer
|
||||
},
|
||||
{
|
||||
.test_id = "per_adv_conn_privacy_syncer",
|
||||
.test_descr = "Periodic advertising sync test, but where "
|
||||
"advertiser and syncer are bonded and using "
|
||||
"privacy",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = main_per_adv_conn_privacy_syncer
|
||||
},
|
||||
{
|
||||
.test_id = "per_adv_long_data_syncer",
|
||||
.test_descr = "Periodic advertising sync test with larger "
|
||||
"data length. Test is used to verify that "
|
||||
"reassembly of long data is handeled correctly.",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = main_per_adv_long_data_syncer
|
||||
},
|
||||
BSTEST_END_MARKER
|
||||
};
|
||||
|
||||
struct bst_test_list *test_per_adv_syncer(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, per_adv_syncer);
|
||||
}
|
41
tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv.sh
Executable file
41
tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv.sh
Executable file
|
@ -0,0 +1,41 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Basic periodic advertising sync test: an advertiser advertises with periodic
|
||||
# advertising, and a scanner scans for and syncs to the periodic advertising.
|
||||
simulation_id="per_adv"
|
||||
verbosity_level=2
|
||||
process_ids=""; exit_code=0
|
||||
|
||||
function Execute(){
|
||||
if [ ! -f $1 ]; then
|
||||
echo -e " \e[91m`pwd`/`basename $1` cannot be found (did you forget to\
|
||||
compile it?)\e[39m"
|
||||
exit 1
|
||||
fi
|
||||
timeout 10 $@ & process_ids="$process_ids $!"
|
||||
}
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
|
||||
#Give a default value to BOARD if it does not have one yet:
|
||||
BOARD="${BOARD:-nrf52_bsim}"
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_adv_periodic_prj_conf \
|
||||
-v=${verbosity_level} -s=${simulation_id} -d=0 -RealEncryption=0 \
|
||||
-testid=per_adv_advertiser -rs=23
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_adv_periodic_prj_conf \
|
||||
-v=${verbosity_level} -s=${simulation_id} -d=1 -RealEncryption=0 \
|
||||
-testid=per_adv_syncer -rs=6
|
||||
|
||||
Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \
|
||||
-D=2 -sim_length=20e6 $@
|
||||
|
||||
for process_id in $process_ids; do
|
||||
wait $process_id || let "exit_code=$?"
|
||||
done
|
||||
exit $exit_code #the last exit code != 0
|
41
tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv_conn.sh
Executable file
41
tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv_conn.sh
Executable file
|
@ -0,0 +1,41 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Basic periodic advertising sync test: an advertiser advertises with periodic
|
||||
# advertising, and a scanner scans for and syncs to the periodic advertising.
|
||||
simulation_id="per_adv_conn"
|
||||
verbosity_level=2
|
||||
process_ids=""; exit_code=0
|
||||
|
||||
function Execute(){
|
||||
if [ ! -f $1 ]; then
|
||||
echo -e " \e[91m`pwd`/`basename $1` cannot be found (did you forget to\
|
||||
compile it?)\e[39m"
|
||||
exit 1
|
||||
fi
|
||||
timeout 10 $@ & process_ids="$process_ids $!"
|
||||
}
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
|
||||
#Give a default value to BOARD if it does not have one yet:
|
||||
BOARD="${BOARD:-nrf52_bsim}"
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_adv_periodic_prj_conf \
|
||||
-v=${verbosity_level} -s=${simulation_id} -d=0 -RealEncryption=0 \
|
||||
-testid=per_adv_conn_advertiser -rs=23
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_adv_periodic_prj_conf \
|
||||
-v=${verbosity_level} -s=${simulation_id} -d=1 -RealEncryption=0 \
|
||||
-testid=per_adv_conn_syncer -rs=6
|
||||
|
||||
Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \
|
||||
-D=2 -sim_length=20e6 $@
|
||||
|
||||
for process_id in $process_ids; do
|
||||
wait $process_id || let "exit_code=$?"
|
||||
done
|
||||
exit $exit_code #the last exit code != 0
|
41
tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv_conn_privacy.sh
Executable file
41
tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv_conn_privacy.sh
Executable file
|
@ -0,0 +1,41 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Basic periodic advertising sync test: an advertiser advertises with periodic
|
||||
# advertising, and a scanner scans for and syncs to the periodic advertising.
|
||||
simulation_id="per_adv_conn_privacy"
|
||||
verbosity_level=2
|
||||
process_ids=""; exit_code=0
|
||||
|
||||
function Execute(){
|
||||
if [ ! -f $1 ]; then
|
||||
echo -e " \e[91m`pwd`/`basename $1` cannot be found (did you forget to\
|
||||
compile it?)\e[39m"
|
||||
exit 1
|
||||
fi
|
||||
timeout 10 $@ & process_ids="$process_ids $!"
|
||||
}
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
|
||||
#Give a default value to BOARD if it does not have one yet:
|
||||
BOARD="${BOARD:-nrf52_bsim}"
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_adv_periodic_prj_conf \
|
||||
-v=${verbosity_level} -s=${simulation_id} -d=0 -RealEncryption=0 \
|
||||
-testid=per_adv_conn_privacy_advertiser -rs=23
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_adv_periodic_prj_conf \
|
||||
-v=${verbosity_level} -s=${simulation_id} -d=1 -RealEncryption=0 \
|
||||
-testid=per_adv_conn_privacy_syncer -rs=6
|
||||
|
||||
Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \
|
||||
-D=2 -sim_length=20e6 $@
|
||||
|
||||
for process_id in $process_ids; do
|
||||
wait $process_id || let "exit_code=$?"
|
||||
done
|
||||
exit $exit_code #the last exit code != 0
|
41
tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv_long_data.sh
Executable file
41
tests/bsim/bluetooth/host/adv/periodic/tests_scripts/per_adv_long_data.sh
Executable file
|
@ -0,0 +1,41 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Basic periodic advertising sync test: an advertiser advertises with periodic
|
||||
# advertising, and a scanner scans for and syncs to the periodic advertising.
|
||||
simulation_id="per_adv_long_data"
|
||||
verbosity_level=2
|
||||
process_ids=""; exit_code=0
|
||||
|
||||
function Execute(){
|
||||
if [ ! -f $1 ]; then
|
||||
echo -e " \e[91m`pwd`/`basename $1` cannot be found (did you forget to\
|
||||
compile it?)\e[39m"
|
||||
exit 1
|
||||
fi
|
||||
timeout 10 $@ & process_ids="$process_ids $!"
|
||||
}
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
|
||||
#Give a default value to BOARD if it does not have one yet:
|
||||
BOARD="${BOARD:-nrf52_bsim}"
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_adv_periodic_prj_long_data_conf \
|
||||
-v=${verbosity_level} -s=${simulation_id} -d=0 -RealEncryption=0 \
|
||||
-testid=per_adv_long_data_advertiser -rs=23
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_adv_periodic_prj_long_data_conf \
|
||||
-v=${verbosity_level} -s=${simulation_id} -d=1 -RealEncryption=0 \
|
||||
-testid=per_adv_long_data_syncer -rs=6
|
||||
|
||||
Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \
|
||||
-D=2 -sim_length=20e6 $@
|
||||
|
||||
for process_id in $process_ids; do
|
||||
wait $process_id || let "exit_code=$?"
|
||||
done
|
||||
exit $exit_code #the last exit code != 0
|
25
tests/bsim/bluetooth/host/adv/resume/CMakeLists.txt
Normal file
25
tests/bsim/bluetooth/host/adv/resume/CMakeLists.txt
Normal file
|
@ -0,0 +1,25 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
if (NOT DEFINED ENV{BSIM_COMPONENTS_PATH})
|
||||
message(FATAL_ERROR "This test requires the BabbleSim simulator. Please set\
|
||||
the environment variable BSIM_COMPONENTS_PATH to point to its components \
|
||||
folder. More information can be found in\
|
||||
https://babblesim.github.io/folder_structure_and_env.html")
|
||||
endif()
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(bsim_test_adv_resume)
|
||||
|
||||
target_sources(app PRIVATE
|
||||
src/bs_bt_utils.c
|
||||
src/dut.c
|
||||
src/main.c
|
||||
src/tester.c
|
||||
)
|
||||
|
||||
zephyr_include_directories(
|
||||
$ENV{BSIM_COMPONENTS_PATH}/libUtilv1/src/
|
||||
$ENV{BSIM_COMPONENTS_PATH}/libPhyComv1/src/
|
||||
)
|
20
tests/bsim/bluetooth/host/adv/resume/prj.conf
Normal file
20
tests/bsim/bluetooth/host/adv/resume/prj.conf
Normal file
|
@ -0,0 +1,20 @@
|
|||
CONFIG_BT=y
|
||||
CONFIG_BT_PERIPHERAL=y
|
||||
CONFIG_BT_CENTRAL=y
|
||||
|
||||
CONFIG_ASSERT=y
|
||||
CONFIG_BT_TESTING=y
|
||||
CONFIG_BT_DEBUG_LOG=y
|
||||
|
||||
CONFIG_BT_EXT_ADV=n
|
||||
CONFIG_BT_PRIVACY=n
|
||||
CONFIG_BT_SCAN_WITH_IDENTITY=n
|
||||
CONFIG_BT_LOG_SNIFFER_INFO=y
|
||||
|
||||
CONFIG_BT_AUTO_PHY_UPDATE=n
|
||||
CONFIG_BT_AUTO_DATA_LEN_UPDATE=n
|
||||
CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n
|
||||
|
||||
CONFIG_BT_MAX_CONN=2
|
||||
CONFIG_BT_MAX_PAIRED=2
|
||||
CONFIG_BT_ID_MAX=2
|
18
tests/bsim/bluetooth/host/adv/resume/prj_2.conf
Normal file
18
tests/bsim/bluetooth/host/adv/resume/prj_2.conf
Normal file
|
@ -0,0 +1,18 @@
|
|||
CONFIG_BT=y
|
||||
CONFIG_BT_PERIPHERAL=y
|
||||
CONFIG_BT_CENTRAL=y
|
||||
|
||||
CONFIG_ASSERT=y
|
||||
CONFIG_BT_TESTING=y
|
||||
CONFIG_BT_DEBUG_LOG=y
|
||||
|
||||
CONFIG_BT_EXT_ADV=y
|
||||
CONFIG_BT_PRIVACY=n
|
||||
|
||||
CONFIG_BT_AUTO_PHY_UPDATE=n
|
||||
CONFIG_BT_AUTO_DATA_LEN_UPDATE=n
|
||||
CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n
|
||||
|
||||
CONFIG_BT_MAX_CONN=2
|
||||
CONFIG_BT_MAX_PAIRED=2
|
||||
CONFIG_BT_ID_MAX=2
|
233
tests/bsim/bluetooth/host/adv/resume/src/bs_bt_utils.c
Normal file
233
tests/bsim/bluetooth/host/adv/resume/src/bs_bt_utils.c
Normal file
|
@ -0,0 +1,233 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "bs_bt_utils.h"
|
||||
#include "argparse.h"
|
||||
#include "bs_pc_backchannel.h"
|
||||
|
||||
BUILD_ASSERT(CONFIG_BT_MAX_PAIRED >= 2, "CONFIG_BT_MAX_PAIRED is too small.");
|
||||
BUILD_ASSERT(CONFIG_BT_ID_MAX == 2, "CONFIG_BT_ID_MAX should be 2.");
|
||||
|
||||
#define BS_SECONDS(dur_sec) ((bs_time_t)dur_sec * USEC_PER_SEC)
|
||||
#define TEST_TIMEOUT_SIMULATED BS_SECONDS(60)
|
||||
|
||||
DEFINE_FLAG(flag_is_connected);
|
||||
DEFINE_FLAG(flag_test_end);
|
||||
|
||||
void test_tick(bs_time_t HW_device_time)
|
||||
{
|
||||
bs_trace_debug_time(0, "Simulation ends now.\n");
|
||||
if (bst_result != Passed) {
|
||||
bst_result = Failed;
|
||||
bs_trace_error("Test did not pass before simulation ended.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void test_init(void)
|
||||
{
|
||||
bst_ticker_set_next_tick_absolute(TEST_TIMEOUT_SIMULATED);
|
||||
bst_result = In_progress;
|
||||
}
|
||||
|
||||
void wait_connected(void)
|
||||
{
|
||||
UNSET_FLAG(flag_is_connected);
|
||||
WAIT_FOR_FLAG(flag_is_connected);
|
||||
printk("connected\n");
|
||||
}
|
||||
|
||||
void wait_disconnected(void)
|
||||
{
|
||||
SET_FLAG(flag_is_connected);
|
||||
WAIT_FOR_FLAG_UNSET(flag_is_connected);
|
||||
printk("disconnected\n");
|
||||
}
|
||||
|
||||
static void disconnected(struct bt_conn *conn, uint8_t reason)
|
||||
{
|
||||
UNSET_FLAG(flag_is_connected);
|
||||
}
|
||||
|
||||
static void connected(struct bt_conn *conn, uint8_t err)
|
||||
{
|
||||
if (err != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
SET_FLAG(flag_is_connected);
|
||||
}
|
||||
|
||||
BT_CONN_CB_DEFINE(conn_callbacks) = {
|
||||
.connected = connected,
|
||||
.disconnected = disconnected,
|
||||
};
|
||||
|
||||
void bs_bt_utils_setup(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
UNSET_FLAG(flag_test_end);
|
||||
|
||||
err = bt_enable(NULL);
|
||||
ASSERT(!err, "bt_enable failed.\n");
|
||||
}
|
||||
|
||||
static bt_addr_le_t last_scanned_addr;
|
||||
|
||||
static void scan_connect_to_first_result_device_found(const bt_addr_le_t *addr, int8_t rssi,
|
||||
uint8_t type, struct net_buf_simple *ad)
|
||||
{
|
||||
struct bt_conn *conn;
|
||||
char addr_str[BT_ADDR_LE_STR_LEN];
|
||||
int err;
|
||||
|
||||
/* We're only interested in connectable events */
|
||||
if (type != BT_HCI_ADV_IND && type != BT_HCI_ADV_DIRECT_IND) {
|
||||
FAIL("Unexpected advertisement type.");
|
||||
}
|
||||
|
||||
bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
|
||||
printk("Got scan result, connecting.. dst %s, RSSI %d\n",
|
||||
addr_str, rssi);
|
||||
|
||||
err = bt_le_scan_stop();
|
||||
ASSERT(!err, "Err bt_le_scan_stop %d", err);
|
||||
|
||||
err = bt_conn_le_create(addr,
|
||||
BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT,
|
||||
&conn);
|
||||
ASSERT(!err, "Err bt_conn_le_create %d", err);
|
||||
|
||||
/* Save address for later comparison */
|
||||
memcpy(&last_scanned_addr, addr, sizeof(last_scanned_addr));
|
||||
}
|
||||
|
||||
void scan_connect_to_first_result(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
printk("start scanner\n");
|
||||
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE,
|
||||
scan_connect_to_first_result_device_found);
|
||||
ASSERT(!err, "Err bt_le_scan_start %d", err);
|
||||
}
|
||||
|
||||
static void scan_expect_same_address_device_found(const bt_addr_le_t *addr, int8_t rssi,
|
||||
uint8_t type, struct net_buf_simple *ad)
|
||||
{
|
||||
char addr_str[BT_ADDR_LE_STR_LEN];
|
||||
char expected_addr_str[BT_ADDR_LE_STR_LEN];
|
||||
|
||||
/* We're only interested in connectable events */
|
||||
if (type != BT_HCI_ADV_IND && type != BT_HCI_ADV_DIRECT_IND) {
|
||||
FAIL("Unexpected advertisement type.");
|
||||
}
|
||||
|
||||
if (!bt_addr_le_eq(&last_scanned_addr, addr)) {
|
||||
bt_addr_le_to_str(&last_scanned_addr,
|
||||
expected_addr_str,
|
||||
sizeof(expected_addr_str));
|
||||
bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
|
||||
|
||||
FAIL("Expected advertiser with addr %s, got %s\n",
|
||||
expected_addr_str, addr_str);
|
||||
}
|
||||
|
||||
PASS("Advertiser used correct address on resume\n");
|
||||
}
|
||||
|
||||
void scan_expect_same_address(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
printk("start scanner\n");
|
||||
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE,
|
||||
scan_expect_same_address_device_found);
|
||||
ASSERT(!err, "Err bt_le_scan_start %d", err);
|
||||
}
|
||||
|
||||
static void disconnect_device(struct bt_conn *conn, void *data)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* We only use a single flag to indicate connections. Since this
|
||||
* function will be called multiple times in a row, we have to set it
|
||||
* back after it has been unset (in the `disconnected` callback).
|
||||
*/
|
||||
SET_FLAG(flag_is_connected);
|
||||
|
||||
err = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
|
||||
ASSERT(!err, "Failed to initate disconnect (err %d)", err);
|
||||
|
||||
printk("Waiting for disconnection...\n");
|
||||
WAIT_FOR_FLAG_UNSET(flag_is_connected);
|
||||
}
|
||||
|
||||
void disconnect(void)
|
||||
{
|
||||
bt_conn_foreach(BT_CONN_TYPE_LE, disconnect_device, NULL);
|
||||
}
|
||||
|
||||
void advertise_connectable(int id, bool persist)
|
||||
{
|
||||
printk("start advertiser\n");
|
||||
int err;
|
||||
struct bt_le_adv_param param = {};
|
||||
|
||||
param.id = id;
|
||||
param.interval_min = 0x0020;
|
||||
param.interval_max = 0x4000;
|
||||
param.options |= persist ? 0 : BT_LE_ADV_OPT_ONE_TIME;
|
||||
param.options |= BT_LE_ADV_OPT_CONNECTABLE;
|
||||
|
||||
err = bt_le_adv_start(¶m, NULL, 0, NULL, 0);
|
||||
ASSERT(err == 0, "Advertising failed to start (err %d)\n", err);
|
||||
}
|
||||
|
||||
#define CHANNEL_ID 0
|
||||
#define MSG_SIZE 1
|
||||
|
||||
void backchannel_init(uint peer)
|
||||
{
|
||||
uint device_number = get_device_nbr();
|
||||
uint device_numbers[] = { peer };
|
||||
uint channel_numbers[] = { CHANNEL_ID };
|
||||
uint *ch;
|
||||
|
||||
ch = bs_open_back_channel(device_number, device_numbers,
|
||||
channel_numbers, ARRAY_SIZE(channel_numbers));
|
||||
if (!ch) {
|
||||
FAIL("Unable to open backchannel\n");
|
||||
}
|
||||
}
|
||||
|
||||
void backchannel_sync_send(void)
|
||||
{
|
||||
uint8_t sync_msg[MSG_SIZE] = { get_device_nbr() };
|
||||
|
||||
printk("Sending sync\n");
|
||||
bs_bc_send_msg(CHANNEL_ID, sync_msg, ARRAY_SIZE(sync_msg));
|
||||
}
|
||||
|
||||
void backchannel_sync_wait(void)
|
||||
{
|
||||
uint8_t sync_msg[MSG_SIZE];
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
printk("Sync received\n");
|
||||
}
|
79
tests/bsim/bluetooth/host/adv/resume/src/bs_bt_utils.h
Normal file
79
tests/bsim/bluetooth/host/adv/resume/src/bs_bt_utils.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
/**
|
||||
* Common functions and helpers for BSIM ADV tests
|
||||
*
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "bs_tracing.h"
|
||||
#include "bs_types.h"
|
||||
#include "bstests.h"
|
||||
#include "time_machine.h"
|
||||
#include "zephyr/sys/__assert.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/conn.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
#include <zephyr/bluetooth/hci.h>
|
||||
#include <zephyr/bluetooth/uuid.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/types.h>
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
|
||||
#define DECLARE_FLAG(flag) extern atomic_t 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 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 ASSERT(expr, ...) \
|
||||
do { \
|
||||
if (!(expr)) { \
|
||||
FAIL(__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
DECLARE_FLAG(flag_test_end);
|
||||
|
||||
#define FAIL(...) \
|
||||
SET_FLAG(flag_test_end); \
|
||||
do { \
|
||||
bst_result = Failed; \
|
||||
bs_trace_error_time_line(__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define PASS(...) \
|
||||
SET_FLAG(flag_test_end); \
|
||||
do { \
|
||||
bst_result = Passed; \
|
||||
bs_trace_info_time(1, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
void test_tick(bs_time_t HW_device_time);
|
||||
void test_init(void);
|
||||
void backchannel_init(uint peer);
|
||||
void backchannel_sync_send(void);
|
||||
void backchannel_sync_wait(void);
|
||||
|
||||
void bs_bt_utils_setup(void);
|
||||
void wait_connected(void);
|
||||
void wait_disconnected(void);
|
||||
void scan_connect_to_first_result(void);
|
||||
void disconnect(void);
|
||||
void advertise_connectable(int id, bool persist);
|
||||
void scan_expect_same_address(void);
|
66
tests/bsim/bluetooth/host/adv/resume/src/dut.c
Normal file
66
tests/bsim/bluetooth/host/adv/resume/src/dut.c
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "bs_bt_utils.h"
|
||||
#include "zephyr/bluetooth/addr.h"
|
||||
#include "zephyr/bluetooth/bluetooth.h"
|
||||
#include "zephyr/bluetooth/conn.h"
|
||||
#include "zephyr/toolchain/gcc.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
void dut_procedure(void)
|
||||
{
|
||||
bs_bt_utils_setup();
|
||||
|
||||
printk("DUT start\n");
|
||||
|
||||
/* start scanning (using NRPA) */
|
||||
scan_connect_to_first_result();
|
||||
|
||||
advertise_connectable(0, 0);
|
||||
wait_connected();
|
||||
printk("DUT is peripheral\n");
|
||||
|
||||
/* tester advertises using a new identity
|
||||
* -> will get detected and connected to by DUT
|
||||
*/
|
||||
wait_connected();
|
||||
printk("DUT is central & peripheral\n");
|
||||
|
||||
/* restart advertiser: it will fail because we have run out of contexts.
|
||||
* But since we pass the `persist` flag, it will start up as soon as a
|
||||
* peripheral role is disconnected.
|
||||
*
|
||||
* We can't start it with the `persist` flag the first time, because adv
|
||||
* will resume straight after the peripheral's connection completes,
|
||||
* 'stealing' the last conn context and preventing the scanner from
|
||||
* establishing a connection.
|
||||
*/
|
||||
advertise_connectable(0, 1);
|
||||
|
||||
wait_disconnected();
|
||||
printk("DUT is central\n");
|
||||
scan_connect_to_first_result();
|
||||
|
||||
wait_disconnected();
|
||||
printk("DUT has no connections\n");
|
||||
|
||||
PASS("PASS\n");
|
||||
}
|
||||
|
||||
void dut_procedure_2(void)
|
||||
{
|
||||
bs_bt_utils_setup();
|
||||
|
||||
printk("DUT start\n");
|
||||
|
||||
/* Start a resumable advertiser. */
|
||||
advertise_connectable(0, true);
|
||||
|
||||
PASS("DUT done\n");
|
||||
}
|
61
tests/bsim/bluetooth/host/adv/resume/src/main.c
Normal file
61
tests/bsim/bluetooth/host/adv/resume/src/main.c
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "bs_bt_utils.h"
|
||||
#include "bstests.h"
|
||||
|
||||
void dut_procedure(void);
|
||||
void tester_peripheral_procedure(void);
|
||||
void tester_central_procedure(void);
|
||||
|
||||
void dut_procedure_2(void);
|
||||
void tester_procedure_2(void);
|
||||
|
||||
static const struct bst_test_instance test_to_add[] = {
|
||||
{
|
||||
.test_id = "dut",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = dut_procedure,
|
||||
},
|
||||
{
|
||||
.test_id = "tester_peripheral",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = tester_peripheral_procedure,
|
||||
},
|
||||
{
|
||||
.test_id = "tester_central",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = tester_central_procedure,
|
||||
},
|
||||
{
|
||||
.test_id = "dut_2",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = dut_procedure_2,
|
||||
},
|
||||
{
|
||||
.test_id = "tester_2",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = tester_procedure_2,
|
||||
},
|
||||
BSTEST_END_MARKER,
|
||||
};
|
||||
|
||||
static struct bst_test_list *install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_to_add);
|
||||
};
|
||||
|
||||
bst_test_install_t test_installers[] = { install, NULL };
|
||||
|
||||
void main(void)
|
||||
{
|
||||
bst_main();
|
||||
}
|
83
tests/bsim/bluetooth/host/adv/resume/src/tester.c
Normal file
83
tests/bsim/bluetooth/host/adv/resume/src/tester.c
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "bs_bt_utils.h"
|
||||
#include "zephyr/bluetooth/addr.h"
|
||||
#include "zephyr/bluetooth/conn.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
|
||||
#define TESTER_CENTRAL_ID 1
|
||||
#define TESTER_PERIPHERAL_ID 2
|
||||
|
||||
void tester_central_procedure(void)
|
||||
{
|
||||
bs_bt_utils_setup();
|
||||
backchannel_init(TESTER_PERIPHERAL_ID);
|
||||
printk("central tester start\n");
|
||||
|
||||
/* connect to DUT as central */
|
||||
scan_connect_to_first_result();
|
||||
wait_connected();
|
||||
backchannel_sync_send();
|
||||
/* DUT is peripheral */
|
||||
|
||||
/* wait until DUT connects to peripheral, and that it has disconnected
|
||||
* from it afterwards.
|
||||
*/
|
||||
backchannel_sync_wait();
|
||||
|
||||
printk("disconnect central\n");
|
||||
disconnect();
|
||||
|
||||
/* DUT starts advertising again (with scanner's NRPA)
|
||||
* should give wrong address
|
||||
*/
|
||||
scan_expect_same_address();
|
||||
|
||||
/* PASS/FAIL is called in the `device_found` callback. */
|
||||
}
|
||||
|
||||
void tester_peripheral_procedure(void)
|
||||
{
|
||||
bs_bt_utils_setup();
|
||||
backchannel_init(TESTER_CENTRAL_ID);
|
||||
printk("peripheral tester start\n");
|
||||
|
||||
/* wait for central to connect to DUT */
|
||||
backchannel_sync_wait();
|
||||
|
||||
/* connect to DUT as peripheral */
|
||||
advertise_connectable(0, 0);
|
||||
wait_connected();
|
||||
/* DUT is central & peripheral */
|
||||
|
||||
printk("disconnect peripheral\n");
|
||||
disconnect();
|
||||
/* DUT starts scanning again (using NRPA) */
|
||||
backchannel_sync_send();
|
||||
|
||||
PASS("PASS\n");
|
||||
}
|
||||
|
||||
void tester_procedure_2(void)
|
||||
{
|
||||
bs_bt_utils_setup();
|
||||
|
||||
printk("Tester start\n");
|
||||
|
||||
scan_connect_to_first_result();
|
||||
wait_connected();
|
||||
|
||||
/* Verify DUT advertiser was able to resume after the connection was
|
||||
* established.
|
||||
*/
|
||||
scan_expect_same_address();
|
||||
|
||||
WAIT_FOR_FLAG(flag_test_end);
|
||||
}
|
16
tests/bsim/bluetooth/host/adv/resume/test_scripts/_compile.sh
Executable file
16
tests/bsim/bluetooth/host/adv/resume/test_scripts/_compile.sh
Executable file
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright 2022 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
set -eu
|
||||
bash_source_dir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")"
|
||||
|
||||
# Read variable definitions output by _env.sh
|
||||
source "${bash_source_dir}/_env.sh"
|
||||
|
||||
# Place yourself in the test's root (i.e. ./../)
|
||||
west build -b nrf52_bsim -d build_test && \
|
||||
cp build_test/zephyr/zephyr.exe "${test_exe}"
|
||||
|
||||
west build -b nrf52_bsim -d build_test_2 -- -DCONF_FILE=prj_2.conf && \
|
||||
cp build_test_2/zephyr/zephyr.exe "${test_2_exe}"
|
13
tests/bsim/bluetooth/host/adv/resume/test_scripts/_env.sh
Executable file
13
tests/bsim/bluetooth/host/adv/resume/test_scripts/_env.sh
Executable file
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright 2022 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
set -eu
|
||||
bash_source_dir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")"
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
|
||||
test_name="$(basename "$(realpath "$bash_source_dir/..")")"
|
||||
bsim_bin="${BSIM_OUT_PATH}/bin"
|
||||
BOARD="${BOARD:-nrf52_bsim}"
|
||||
test_exe="${bsim_bin}/bs_${BOARD}_tests_bsim_bluetooth_host_adv_resume_prj_conf"
|
||||
test_2_exe="${bsim_bin}/bs_${BOARD}_tests_bsim_bluetooth_host_adv_resume_prj_2_conf"
|
49
tests/bsim/bluetooth/host/adv/resume/test_scripts/run_adv_resume.sh
Executable file
49
tests/bsim/bluetooth/host/adv/resume/test_scripts/run_adv_resume.sh
Executable file
|
@ -0,0 +1,49 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright 2022 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
set -eu
|
||||
bash_source_dir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")"
|
||||
|
||||
# Read variable definitions output by _env.sh
|
||||
source "${bash_source_dir}/_env.sh"
|
||||
|
||||
simulation_id="${test_name}"
|
||||
verbosity_level=2
|
||||
process_ids=""
|
||||
exit_code=0
|
||||
|
||||
function Execute() {
|
||||
if [ ! -f $1 ]; then
|
||||
echo -e " \e[91m$(pwd)/$(basename $1) cannot be found (did you forget to\
|
||||
compile it?)\e[39m"
|
||||
exit 1
|
||||
fi
|
||||
timeout 30 $@ &
|
||||
process_ids="$process_ids $!"
|
||||
}
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin
|
||||
|
||||
Execute "$test_exe" \
|
||||
-v=${verbosity_level} -s=${simulation_id} -d=0 -testid=dut -RealEncryption=1
|
||||
|
||||
Execute "$test_exe" \
|
||||
-v=${verbosity_level} -s=${simulation_id} -d=1 -testid=tester_central -RealEncryption=1
|
||||
|
||||
Execute "$test_exe" \
|
||||
-v=${verbosity_level} -s=${simulation_id} -d=2 -testid=tester_peripheral -RealEncryption=1
|
||||
|
||||
Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \
|
||||
-D=3 -sim_length=10e6 $@
|
||||
|
||||
# Uncomment (and comment the other peripheral line) to run DUT under a debugger
|
||||
# gdb --args "$test_exe" \
|
||||
# -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral -RealEncryption=1
|
||||
|
||||
for process_id in $process_ids; do
|
||||
wait $process_id || let "exit_code=$?"
|
||||
done
|
||||
exit $exit_code #the last exit code != 0
|
42
tests/bsim/bluetooth/host/adv/resume/test_scripts/run_adv_resume_2.sh
Executable file
42
tests/bsim/bluetooth/host/adv/resume/test_scripts/run_adv_resume_2.sh
Executable file
|
@ -0,0 +1,42 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright 2022 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
set -eu
|
||||
bash_source_dir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")"
|
||||
|
||||
# Read variable definitions output by _env.sh
|
||||
source "${bash_source_dir}/_env.sh"
|
||||
|
||||
simulation_id="${test_name}_2"
|
||||
verbosity_level=2
|
||||
process_ids=""
|
||||
exit_code=0
|
||||
|
||||
function Execute() {
|
||||
if [ ! -f $1 ]; then
|
||||
echo -e " \e[91m$(pwd)/$(basename $1) cannot be found (did you forget to\
|
||||
compile it?)\e[39m"
|
||||
exit 1
|
||||
fi
|
||||
timeout 30 $@ &
|
||||
process_ids="$process_ids $!"
|
||||
}
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin
|
||||
|
||||
Execute "$test_2_exe" \
|
||||
-v=${verbosity_level} -s="${simulation_id}" -d=0 -testid=dut_2 -RealEncryption=1
|
||||
|
||||
Execute "$test_2_exe" \
|
||||
-v=${verbosity_level} -s="${simulation_id}" -d=1 -testid=tester_2 -RealEncryption=1
|
||||
|
||||
Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s="${simulation_id}" \
|
||||
-D=2 -sim_length=10e6 $@
|
||||
|
||||
for process_id in $process_ids; do
|
||||
wait $process_id || let "exit_code=$?"
|
||||
done
|
||||
exit $exit_code #the last exit code != 0
|
28
tests/bsim/bluetooth/host/att/eatt/CMakeLists.txt
Normal file
28
tests/bsim/bluetooth/host/att/eatt/CMakeLists.txt
Normal file
|
@ -0,0 +1,28 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
if (NOT DEFINED ENV{BSIM_COMPONENTS_PATH})
|
||||
message(FATAL_ERROR "This test requires the BabbleSim simulator. Please set\
|
||||
the environment variable BSIM_COMPONENTS_PATH to point to its components \
|
||||
folder. More information can be found in\
|
||||
https://babblesim.github.io/folder_structure_and_env.html")
|
||||
endif()
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(bsim_test_host)
|
||||
|
||||
|
||||
target_sources(app PRIVATE
|
||||
src/common.c
|
||||
src/main_collision.c
|
||||
src/main_autoconnect.c
|
||||
src/main_reconfigure.c
|
||||
src/main.c
|
||||
)
|
||||
|
||||
|
||||
zephyr_include_directories(
|
||||
$ENV{BSIM_COMPONENTS_PATH}/libUtilv1/src/
|
||||
$ENV{BSIM_COMPONENTS_PATH}/libPhyComv1/src/
|
||||
)
|
16
tests/bsim/bluetooth/host/att/eatt/prj_autoconnect.conf
Normal file
16
tests/bsim/bluetooth/host/att/eatt/prj_autoconnect.conf
Normal file
|
@ -0,0 +1,16 @@
|
|||
CONFIG_BT=y
|
||||
CONFIG_BT_CENTRAL=y
|
||||
CONFIG_BT_PERIPHERAL=y
|
||||
CONFIG_BT_SMP=y
|
||||
CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y
|
||||
CONFIG_BT_DEVICE_NAME="EATT test"
|
||||
CONFIG_BT_EATT=y
|
||||
CONFIG_BT_L2CAP_ECRED=y
|
||||
CONFIG_BT_EATT_MAX=5
|
||||
CONFIG_BT_MAX_CONN=1
|
||||
|
||||
CONFIG_BT_TESTING=y
|
||||
CONFIG_BT_DEBUG_LOG=y
|
||||
CONFIG_ASSERT=y
|
||||
|
||||
CONFIG_BT_L2CAP_TX_MTU=200
|
15
tests/bsim/bluetooth/host/att/eatt/prj_collision.conf
Normal file
15
tests/bsim/bluetooth/host/att/eatt/prj_collision.conf
Normal file
|
@ -0,0 +1,15 @@
|
|||
CONFIG_BT=y
|
||||
CONFIG_BT_CENTRAL=y
|
||||
CONFIG_BT_PERIPHERAL=y
|
||||
CONFIG_BT_SMP=y
|
||||
CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y
|
||||
CONFIG_BT_DEVICE_NAME="EATT test"
|
||||
CONFIG_BT_EATT=y
|
||||
CONFIG_BT_L2CAP_ECRED=y
|
||||
CONFIG_BT_EATT_MAX=5
|
||||
CONFIG_BT_MAX_CONN=1
|
||||
CONFIG_BT_EATT_AUTO_CONNECT=n
|
||||
|
||||
CONFIG_BT_TESTING=y
|
||||
CONFIG_BT_DEBUG_LOG=y
|
||||
CONFIG_ASSERT=y
|
15
tests/bsim/bluetooth/host/att/eatt/prj_multiple_conn.conf
Normal file
15
tests/bsim/bluetooth/host/att/eatt/prj_multiple_conn.conf
Normal file
|
@ -0,0 +1,15 @@
|
|||
CONFIG_BT=y
|
||||
CONFIG_BT_CENTRAL=y
|
||||
CONFIG_BT_PERIPHERAL=y
|
||||
CONFIG_BT_SMP=y
|
||||
CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y
|
||||
CONFIG_BT_DEVICE_NAME="EATT test"
|
||||
CONFIG_BT_EATT=y
|
||||
CONFIG_BT_L2CAP_ECRED=y
|
||||
CONFIG_BT_EATT_MAX=5
|
||||
CONFIG_BT_MAX_CONN=2
|
||||
CONFIG_BT_EATT_AUTO_CONNECT=n
|
||||
|
||||
CONFIG_BT_TESTING=y
|
||||
CONFIG_BT_DEBUG_LOG=y
|
||||
CONFIG_ASSERT=y
|
223
tests/bsim/bluetooth/host/att/eatt/src/common.c
Normal file
223
tests/bsim/bluetooth/host/att/eatt/src/common.c
Normal file
|
@ -0,0 +1,223 @@
|
|||
/* common.c - Common test code */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "argparse.h"
|
||||
|
||||
struct bt_conn *default_conn;
|
||||
|
||||
static const struct bt_data ad[] = {
|
||||
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
|
||||
};
|
||||
|
||||
static volatile bool is_connected;
|
||||
static volatile bool is_encrypted;
|
||||
|
||||
static void connected(struct bt_conn *conn, uint8_t conn_err)
|
||||
{
|
||||
char addr[BT_ADDR_LE_STR_LEN];
|
||||
|
||||
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
|
||||
|
||||
if (conn_err) {
|
||||
if (default_conn) {
|
||||
bt_conn_unref(default_conn);
|
||||
default_conn = NULL;
|
||||
}
|
||||
|
||||
FAIL("Failed to connect to %s (%u)\n", addr, conn_err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!default_conn) {
|
||||
default_conn = bt_conn_ref(conn);
|
||||
}
|
||||
|
||||
printk("Connected: %s\n", addr);
|
||||
is_connected = true;
|
||||
}
|
||||
|
||||
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 0x%02x)\n", addr, reason);
|
||||
|
||||
bt_conn_unref(default_conn);
|
||||
default_conn = NULL;
|
||||
is_connected = false;
|
||||
is_encrypted = false;
|
||||
}
|
||||
|
||||
static void security_changed(struct bt_conn *conn, bt_security_t level,
|
||||
enum bt_security_err security_err)
|
||||
{
|
||||
if (security_err == BT_SECURITY_ERR_SUCCESS && level > BT_SECURITY_L1) {
|
||||
is_encrypted = true;
|
||||
}
|
||||
}
|
||||
|
||||
BT_CONN_CB_DEFINE(conn_callbacks) = {
|
||||
.connected = connected,
|
||||
.disconnected = disconnected,
|
||||
.security_changed = security_changed,
|
||||
};
|
||||
|
||||
static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
|
||||
struct net_buf_simple *ad)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_le_scan_stop();
|
||||
if (err) {
|
||||
FAIL("Stop LE scan failed (err %d)\n", err);
|
||||
}
|
||||
|
||||
err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT,
|
||||
&default_conn);
|
||||
if (err) {
|
||||
FAIL("Create conn failed (err %d)\n", err);
|
||||
}
|
||||
|
||||
printk("Device connected\n");
|
||||
}
|
||||
|
||||
void test_init(void)
|
||||
{
|
||||
bst_ticker_set_next_tick_absolute(60e6); /* 60 seconds */
|
||||
bst_result = In_progress;
|
||||
}
|
||||
|
||||
void test_tick(bs_time_t HW_device_time)
|
||||
{
|
||||
if (bst_result != Passed) {
|
||||
bst_result = Failed;
|
||||
bs_trace_error_time_line("Test eatt finished.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void central_setup_and_connect(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_enable(NULL);
|
||||
if (err) {
|
||||
FAIL("Can't enable Bluetooth (err %d)\n", err);
|
||||
}
|
||||
|
||||
err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, device_found);
|
||||
if (err) {
|
||||
FAIL("Scanning failed to start (err %d)\n", err);
|
||||
}
|
||||
|
||||
while (!is_connected) {
|
||||
k_sleep(K_MSEC(100));
|
||||
}
|
||||
|
||||
err = bt_conn_set_security(default_conn, BT_SECURITY_L2);
|
||||
if (err) {
|
||||
FAIL("Failed to start encryption procedure\n");
|
||||
}
|
||||
|
||||
while (!is_encrypted) {
|
||||
k_sleep(K_MSEC(100));
|
||||
}
|
||||
}
|
||||
|
||||
void peripheral_setup_and_connect(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_enable(NULL);
|
||||
if (err) {
|
||||
FAIL("Can't enable Bluetooth (err %d)\n", err);
|
||||
}
|
||||
|
||||
err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0);
|
||||
if (err) {
|
||||
FAIL("Advertising failed to start (err %d)\n", err);
|
||||
}
|
||||
|
||||
while (!is_connected) {
|
||||
k_sleep(K_MSEC(100));
|
||||
}
|
||||
|
||||
/* Wait for central to start encryption */
|
||||
while (!is_encrypted) {
|
||||
k_sleep(K_MSEC(100));
|
||||
}
|
||||
}
|
||||
|
||||
void wait_for_disconnect(void)
|
||||
{
|
||||
while (is_connected) {
|
||||
k_sleep(K_MSEC(100));
|
||||
}
|
||||
}
|
||||
|
||||
void disconnect(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
|
||||
if (err) {
|
||||
FAIL("Disconnection failed (err %d)\n", err);
|
||||
}
|
||||
|
||||
while (is_connected) {
|
||||
k_sleep(K_MSEC(100));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define CHANNEL_ID 0
|
||||
#define MSG_SIZE 1
|
||||
|
||||
void backchannel_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) {
|
||||
FAIL("Unable to open backchannel\n");
|
||||
}
|
||||
}
|
||||
|
||||
void backchannel_sync_send(void)
|
||||
{
|
||||
uint8_t sync_msg[MSG_SIZE] = { get_device_nbr() };
|
||||
|
||||
printk("Sending sync\n");
|
||||
bs_bc_send_msg(CHANNEL_ID, sync_msg, ARRAY_SIZE(sync_msg));
|
||||
}
|
||||
|
||||
void backchannel_sync_wait(void)
|
||||
{
|
||||
uint8_t sync_msg[MSG_SIZE];
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
printk("Sync received\n");
|
||||
}
|
57
tests/bsim/bluetooth/host/att/eatt/src/common.h
Normal file
57
tests/bsim/bluetooth/host/att/eatt/src/common.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
/* common.h - Common test code */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <zephyr/types.h>
|
||||
#include <zephyr/sys/printk.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/conn.h>
|
||||
#include <zephyr/bluetooth/att.h>
|
||||
|
||||
#include "bs_types.h"
|
||||
#include "bs_tracing.h"
|
||||
#include "bstests.h"
|
||||
#include "bs_pc_backchannel.h"
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
|
||||
#define CREATE_FLAG(flag) static atomic_t flag = (atomic_t)false
|
||||
#define SET_FLAG(flag) (void)atomic_set(&flag, (atomic_t)true)
|
||||
#define WAIT_FOR_FLAG(flag) \
|
||||
while (!(bool)atomic_get(&flag)) { \
|
||||
(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, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
extern volatile int num_eatt_channels;
|
||||
extern struct bt_conn *default_conn;
|
||||
|
||||
void central_setup_and_connect(void);
|
||||
void peripheral_setup_and_connect(void);
|
||||
void wait_for_disconnect(void);
|
||||
void disconnect(void);
|
||||
void test_init(void);
|
||||
void test_tick(bs_time_t HW_device_time);
|
||||
void backchannel_init(void);
|
||||
void backchannel_sync_send(void);
|
||||
void backchannel_sync_wait(void);
|
23
tests/bsim/bluetooth/host/att/eatt/src/main.c
Normal file
23
tests/bsim/bluetooth/host/att/eatt/src/main.c
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "bstests.h"
|
||||
|
||||
extern struct bst_test_list *test_main_collision_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_main_autoconnect_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_main_reconfigure_install(struct bst_test_list *tests);
|
||||
|
||||
bst_test_install_t test_installers[] = {
|
||||
test_main_collision_install,
|
||||
test_main_autoconnect_install,
|
||||
test_main_reconfigure_install,
|
||||
NULL,
|
||||
};
|
||||
|
||||
void main(void)
|
||||
{
|
||||
bst_main();
|
||||
}
|
61
tests/bsim/bluetooth/host/att/eatt/src/main_autoconnect.c
Normal file
61
tests/bsim/bluetooth/host/att/eatt/src/main_autoconnect.c
Normal file
|
@ -0,0 +1,61 @@
|
|||
/* main_connect.c - Application main entry point */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
static void test_peripheral_main(void)
|
||||
{
|
||||
peripheral_setup_and_connect();
|
||||
|
||||
while (bt_eatt_count(default_conn) < CONFIG_BT_EATT_MAX) {
|
||||
k_sleep(K_MSEC(10));
|
||||
}
|
||||
|
||||
/* Do not disconnect until the central also has connected all channels */
|
||||
k_sleep(K_MSEC(1000));
|
||||
|
||||
disconnect();
|
||||
|
||||
PASS("EATT Peripheral tests Passed\n");
|
||||
}
|
||||
|
||||
static void test_central_main(void)
|
||||
{
|
||||
central_setup_and_connect();
|
||||
|
||||
while (bt_eatt_count(default_conn) < CONFIG_BT_EATT_MAX) {
|
||||
k_sleep(K_MSEC(10));
|
||||
}
|
||||
|
||||
wait_for_disconnect();
|
||||
|
||||
PASS("EATT Central tests Passed\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_def[] = {
|
||||
{
|
||||
.test_id = "peripheral_autoconnect",
|
||||
.test_descr = "Peripheral autoconnect",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_peripheral_main,
|
||||
},
|
||||
{
|
||||
.test_id = "central_autoconnect",
|
||||
.test_descr = "Central autoconnect",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_central_main,
|
||||
},
|
||||
BSTEST_END_MARKER,
|
||||
};
|
||||
|
||||
struct bst_test_list *test_main_autoconnect_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_def);
|
||||
}
|
88
tests/bsim/bluetooth/host/att/eatt/src/main_collision.c
Normal file
88
tests/bsim/bluetooth/host/att/eatt/src/main_collision.c
Normal file
|
@ -0,0 +1,88 @@
|
|||
/* main_collision.c - Application main entry point */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
static void test_peripheral_main(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
backchannel_init();
|
||||
|
||||
peripheral_setup_and_connect();
|
||||
|
||||
/*
|
||||
* we need to sync with peer to ensure that we get collisions
|
||||
*/
|
||||
backchannel_sync_send();
|
||||
backchannel_sync_wait();
|
||||
|
||||
err = bt_eatt_connect(default_conn, CONFIG_BT_EATT_MAX);
|
||||
if (err) {
|
||||
FAIL("Sending credit based connection request failed (err %d)\n", err);
|
||||
}
|
||||
|
||||
while (bt_eatt_count(default_conn) < CONFIG_BT_EATT_MAX) {
|
||||
k_sleep(K_MSEC(10));
|
||||
}
|
||||
|
||||
/* Do not disconnect until the central also has connected all channels */
|
||||
k_sleep(K_MSEC(1000));
|
||||
|
||||
disconnect();
|
||||
|
||||
PASS("EATT Peripheral tests Passed\n");
|
||||
}
|
||||
|
||||
static void test_central_main(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
backchannel_init();
|
||||
|
||||
central_setup_and_connect();
|
||||
|
||||
backchannel_sync_wait();
|
||||
backchannel_sync_send();
|
||||
|
||||
err = bt_eatt_connect(default_conn, CONFIG_BT_EATT_MAX);
|
||||
if (err) {
|
||||
FAIL("Sending credit based connection request failed (err %d)\n", err);
|
||||
}
|
||||
|
||||
while (bt_eatt_count(default_conn) < CONFIG_BT_EATT_MAX) {
|
||||
k_sleep(K_MSEC(10));
|
||||
}
|
||||
|
||||
wait_for_disconnect();
|
||||
|
||||
PASS("EATT Central tests Passed\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_def[] = {
|
||||
{
|
||||
.test_id = "peripheral",
|
||||
.test_descr = "Peripheral Collision",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_peripheral_main,
|
||||
},
|
||||
{
|
||||
.test_id = "central",
|
||||
.test_descr = "Central Collision",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_central_main,
|
||||
},
|
||||
BSTEST_END_MARKER,
|
||||
};
|
||||
|
||||
struct bst_test_list *test_main_collision_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_def);
|
||||
}
|
91
tests/bsim/bluetooth/host/att/eatt/src/main_reconfigure.c
Normal file
91
tests/bsim/bluetooth/host/att/eatt/src/main_reconfigure.c
Normal file
|
@ -0,0 +1,91 @@
|
|||
/* main_reconfigure.c - Application main entry point */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
|
||||
#define NEW_MTU 100
|
||||
|
||||
CREATE_FLAG(flag_reconfigured);
|
||||
|
||||
void att_mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx)
|
||||
{
|
||||
printk("MTU Updated: tx %d, rx %d\n", tx, rx);
|
||||
if (rx == NEW_MTU || tx == NEW_MTU) {
|
||||
SET_FLAG(flag_reconfigured);
|
||||
}
|
||||
}
|
||||
|
||||
static struct bt_gatt_cb cb = {
|
||||
.att_mtu_updated = att_mtu_updated,
|
||||
};
|
||||
|
||||
static void test_peripheral_main(void)
|
||||
{
|
||||
peripheral_setup_and_connect();
|
||||
|
||||
bt_gatt_cb_register(&cb);
|
||||
|
||||
while (bt_eatt_count(default_conn) < CONFIG_BT_EATT_MAX) {
|
||||
k_sleep(K_MSEC(10));
|
||||
}
|
||||
|
||||
WAIT_FOR_FLAG(flag_reconfigured);
|
||||
|
||||
disconnect();
|
||||
|
||||
PASS("EATT Peripheral tests Passed\n");
|
||||
}
|
||||
|
||||
static void test_central_main(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
central_setup_and_connect();
|
||||
|
||||
bt_gatt_cb_register(&cb);
|
||||
|
||||
while (bt_eatt_count(default_conn) < CONFIG_BT_EATT_MAX) {
|
||||
k_sleep(K_MSEC(10));
|
||||
}
|
||||
|
||||
err = bt_eatt_reconfigure(default_conn, NEW_MTU);
|
||||
if (err < 0) {
|
||||
FAIL("Reconfigure failed (%d)\n", err);
|
||||
}
|
||||
|
||||
WAIT_FOR_FLAG(flag_reconfigured);
|
||||
|
||||
wait_for_disconnect();
|
||||
|
||||
PASS("EATT Central tests Passed\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_def[] = {
|
||||
{
|
||||
.test_id = "peripheral_reconfigure",
|
||||
.test_descr = "Peripheral reconfigure",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_peripheral_main,
|
||||
},
|
||||
{
|
||||
.test_id = "central_reconfigure",
|
||||
.test_descr = "Central reconfigure",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_central_main,
|
||||
},
|
||||
BSTEST_END_MARKER,
|
||||
};
|
||||
|
||||
struct bst_test_list *test_main_reconfigure_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_def);
|
||||
}
|
37
tests/bsim/bluetooth/host/att/eatt/tests_scripts/autoconnect.sh
Executable file
37
tests/bsim/bluetooth/host/att/eatt/tests_scripts/autoconnect.sh
Executable file
|
@ -0,0 +1,37 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright (c) 2022 Nordic Semiconductor
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
simulation_id="connection"
|
||||
verbosity_level=2
|
||||
process_ids=""; exit_code=0
|
||||
|
||||
function Execute(){
|
||||
if [ ! -f $1 ]; then
|
||||
echo -e " \e[91m`pwd`/`basename $1` cannot be found (did you forget to\
|
||||
compile it?)\e[39m"
|
||||
exit 1
|
||||
fi
|
||||
timeout 120 $@ & process_ids="$process_ids $!"
|
||||
}
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
|
||||
#Give a default value to BOARD if it does not have one yet:
|
||||
BOARD="${BOARD:-nrf52_bsim}"
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_att_eatt_prj_autoconnect_conf \
|
||||
-v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central_autoconnect
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_att_eatt_prj_autoconnect_conf \
|
||||
-v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral_autoconnect
|
||||
|
||||
Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \
|
||||
-D=2 -sim_length=200e6 $@
|
||||
|
||||
for process_id in $process_ids; do
|
||||
wait $process_id || let "exit_code=$?"
|
||||
done
|
||||
exit $exit_code #the last exit code != 0
|
37
tests/bsim/bluetooth/host/att/eatt/tests_scripts/collision.sh
Executable file
37
tests/bsim/bluetooth/host/att/eatt/tests_scripts/collision.sh
Executable file
|
@ -0,0 +1,37 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright (c) 2022 Nordic Semiconductor
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
simulation_id="collision"
|
||||
verbosity_level=2
|
||||
process_ids=""; exit_code=0
|
||||
|
||||
function Execute(){
|
||||
if [ ! -f $1 ]; then
|
||||
echo -e " \e[91m`pwd`/`basename $1` cannot be found (did you forget to\
|
||||
compile it?)\e[39m"
|
||||
exit 1
|
||||
fi
|
||||
timeout 120 $@ & process_ids="$process_ids $!"
|
||||
}
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
|
||||
#Give a default value to BOARD if it does not have one yet:
|
||||
BOARD="${BOARD:-nrf52_bsim}"
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_att_eatt_prj_collision_conf \
|
||||
-v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_att_eatt_prj_collision_conf \
|
||||
-v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral
|
||||
|
||||
Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \
|
||||
-D=2 -sim_length=200e6 $@
|
||||
|
||||
for process_id in $process_ids; do
|
||||
wait $process_id || let "exit_code=$?"
|
||||
done
|
||||
exit $exit_code #the last exit code != 0
|
37
tests/bsim/bluetooth/host/att/eatt/tests_scripts/multiple_conn.sh
Executable file
37
tests/bsim/bluetooth/host/att/eatt/tests_scripts/multiple_conn.sh
Executable file
|
@ -0,0 +1,37 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright (c) 2022 Nordic Semiconductor
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
simulation_id="multiple_conn"
|
||||
verbosity_level=2
|
||||
process_ids=""; exit_code=0
|
||||
|
||||
function Execute(){
|
||||
if [ ! -f $1 ]; then
|
||||
echo -e " \e[91m`pwd`/`basename $1` cannot be found (did you forget to\
|
||||
compile it?)\e[39m"
|
||||
exit 1
|
||||
fi
|
||||
timeout 120 $@ & process_ids="$process_ids $!"
|
||||
}
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
|
||||
#Give a default value to BOARD if it does not have one yet:
|
||||
BOARD="${BOARD:-nrf52_bsim}"
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_att_eatt_prj_multiple_conn_conf \
|
||||
-v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_att_eatt_prj_multiple_conn_conf \
|
||||
-v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral
|
||||
|
||||
Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \
|
||||
-D=2 -sim_length=200e6 $@
|
||||
|
||||
for process_id in $process_ids; do
|
||||
wait $process_id || let "exit_code=$?"
|
||||
done
|
||||
exit $exit_code #the last exit code != 0
|
37
tests/bsim/bluetooth/host/att/eatt/tests_scripts/reconfigure.sh
Executable file
37
tests/bsim/bluetooth/host/att/eatt/tests_scripts/reconfigure.sh
Executable file
|
@ -0,0 +1,37 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright (c) 2022 Nordic Semiconductor
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
simulation_id="reconfigure"
|
||||
verbosity_level=2
|
||||
process_ids=""; exit_code=0
|
||||
|
||||
function Execute(){
|
||||
if [ ! -f $1 ]; then
|
||||
echo -e " \e[91m`pwd`/`basename $1` cannot be found (did you forget to\
|
||||
compile it?)\e[39m"
|
||||
exit 1
|
||||
fi
|
||||
timeout 120 $@ & process_ids="$process_ids $!"
|
||||
}
|
||||
|
||||
: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"
|
||||
|
||||
#Give a default value to BOARD if it does not have one yet:
|
||||
BOARD="${BOARD:-nrf52_bsim}"
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_att_eatt_prj_autoconnect_conf \
|
||||
-v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central_reconfigure
|
||||
|
||||
Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_att_eatt_prj_autoconnect_conf \
|
||||
-v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral_reconfigure
|
||||
|
||||
Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \
|
||||
-D=2 -sim_length=60e6 $@
|
||||
|
||||
for process_id in $process_ids; do
|
||||
wait $process_id || let "exit_code=$?"
|
||||
done
|
||||
exit $exit_code #the last exit code != 0
|
21
tests/bsim/bluetooth/host/att/eatt_notif/CMakeLists.txt
Normal file
21
tests/bsim/bluetooth/host/att/eatt_notif/CMakeLists.txt
Normal file
|
@ -0,0 +1,21 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
if (NOT DEFINED ENV{BSIM_COMPONENTS_PATH})
|
||||
message(FATAL_ERROR "This test requires the BabbleSim simulator. Please set\
|
||||
the environment variable BSIM_COMPONENTS_PATH to point to its components \
|
||||
folder. More information can be found in\
|
||||
https://babblesim.github.io/folder_structure_and_env.html")
|
||||
endif()
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(bsim_test_eatt_notif)
|
||||
|
||||
FILE(GLOB app_sources src/*.c)
|
||||
target_sources(app PRIVATE ${app_sources} )
|
||||
|
||||
zephyr_include_directories(
|
||||
$ENV{BSIM_COMPONENTS_PATH}/libUtilv1/src/
|
||||
$ENV{BSIM_COMPONENTS_PATH}/libPhyComv1/src/
|
||||
)
|
16
tests/bsim/bluetooth/host/att/eatt_notif/prj.conf
Normal file
16
tests/bsim/bluetooth/host/att/eatt_notif/prj.conf
Normal file
|
@ -0,0 +1,16 @@
|
|||
CONFIG_BT=y
|
||||
CONFIG_BT_CENTRAL=y
|
||||
CONFIG_BT_PERIPHERAL=y
|
||||
CONFIG_BT_SMP=y
|
||||
CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y
|
||||
CONFIG_BT_DEVICE_NAME="EATT test"
|
||||
CONFIG_BT_EATT=y
|
||||
CONFIG_BT_TESTING=y
|
||||
CONFIG_BT_EATT_AUTO_CONNECT=n
|
||||
CONFIG_BT_L2CAP_ECRED=y
|
||||
CONFIG_BT_EATT_MAX=16
|
||||
CONFIG_BT_MAX_CONN=1
|
||||
CONFIG_BT_GATT_CLIENT=y
|
||||
CONFIG_BT_GATT_AUTO_DISCOVER_CCC=y
|
||||
CONFIG_BT_ATT_PREPARE_COUNT=3
|
||||
CONFIG_ASSERT=y
|
264
tests/bsim/bluetooth/host/att/eatt_notif/src/client_test.c
Normal file
264
tests/bsim/bluetooth/host/att/eatt_notif/src/client_test.c
Normal file
|
@ -0,0 +1,264 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* EATT notification reliability test:
|
||||
* A central acting as a GATT client scans and connects
|
||||
* to a peripheral acting as a GATT server.
|
||||
* The GATT client will then attempt to connect a number of CONFIG_BT_EATT_MAX bearers
|
||||
* over EATT, send notifications, disconnect all bearers and reconnect EATT_BEARERS_TEST
|
||||
* and send start a transaction with a request, then send a lot of notifications
|
||||
* before the response is received.
|
||||
* The test might be expanded by checking that all the notifications all transmitted
|
||||
* on EATT channels.
|
||||
*/
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
#include <zephyr/bluetooth/conn.h>
|
||||
#include <zephyr/bluetooth/att.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
CREATE_FLAG(flag_is_connected);
|
||||
CREATE_FLAG(flag_discover_complete);
|
||||
CREATE_FLAG(flag_is_encrypted);
|
||||
|
||||
static struct bt_conn *g_conn;
|
||||
static const struct bt_gatt_attr *local_attr;
|
||||
static struct bt_uuid *test_svc_uuid = TEST_SERVICE_UUID;
|
||||
|
||||
#define NUM_NOTIF 100
|
||||
#define SAMPLE_DATA 1
|
||||
#define EATT_BEARERS_TEST 1
|
||||
|
||||
volatile int num_eatt_channels;
|
||||
|
||||
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 != 0) {
|
||||
FAIL("Failed to connect to %s (%u)\n", addr, err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Connected to %s\n", addr);
|
||||
SET_FLAG(flag_is_connected);
|
||||
}
|
||||
|
||||
static void disconnected(struct bt_conn *conn, uint8_t reason)
|
||||
{
|
||||
char addr[BT_ADDR_LE_STR_LEN];
|
||||
|
||||
if (conn != g_conn) {
|
||||
return;
|
||||
}
|
||||
|
||||
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
|
||||
|
||||
printk("Disconnected: %s (reason 0x%02x)\n", addr, reason);
|
||||
|
||||
bt_conn_unref(g_conn);
|
||||
|
||||
g_conn = NULL;
|
||||
UNSET_FLAG(flag_is_connected);
|
||||
}
|
||||
|
||||
static void security_changed(struct bt_conn *conn, bt_security_t level,
|
||||
enum bt_security_err security_err)
|
||||
{
|
||||
if (security_err == BT_SECURITY_ERR_SUCCESS && level > BT_SECURITY_L1) {
|
||||
SET_FLAG(flag_is_encrypted);
|
||||
}
|
||||
}
|
||||
|
||||
BT_CONN_CB_DEFINE(conn_callbacks) = {
|
||||
.connected = connected,
|
||||
.disconnected = disconnected,
|
||||
.security_changed = security_changed,
|
||||
};
|
||||
|
||||
void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
|
||||
struct net_buf_simple *ad)
|
||||
{
|
||||
char addr_str[BT_ADDR_LE_STR_LEN];
|
||||
int err;
|
||||
|
||||
if (g_conn != NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* We're only interested in connectable events */
|
||||
if (type != BT_HCI_ADV_IND && type != BT_HCI_ADV_DIRECT_IND) {
|
||||
return;
|
||||
}
|
||||
|
||||
bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
|
||||
printk("Device found: %s (RSSI %d)\n", addr_str, rssi);
|
||||
|
||||
printk("Stopping scan\n");
|
||||
err = bt_le_scan_stop();
|
||||
if (err != 0) {
|
||||
FAIL("Could not stop scan: %d");
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN,
|
||||
BT_LE_CONN_PARAM_DEFAULT, &g_conn);
|
||||
if (err != 0) {
|
||||
FAIL("Could not connect to peer: %d", err);
|
||||
}
|
||||
}
|
||||
|
||||
void send_notification(void)
|
||||
{
|
||||
const uint8_t sample_dat = SAMPLE_DATA;
|
||||
int err;
|
||||
|
||||
do {
|
||||
err = bt_gatt_notify(g_conn, local_attr, &sample_dat, sizeof(sample_dat));
|
||||
if (!err) {
|
||||
return;
|
||||
} else if (err != -ENOMEM) {
|
||||
printk("GATT notify failed (err %d)\n", err);
|
||||
return;
|
||||
}
|
||||
k_sleep(K_TICKS(1));
|
||||
} while (err == -ENOMEM);
|
||||
}
|
||||
|
||||
static uint8_t discover_func(struct bt_conn *conn,
|
||||
const struct bt_gatt_attr *attr,
|
||||
struct bt_gatt_discover_params *params)
|
||||
{
|
||||
SET_FLAG(flag_discover_complete);
|
||||
printk("Discover complete\n");
|
||||
|
||||
return BT_GATT_ITER_STOP;
|
||||
}
|
||||
|
||||
static void gatt_discover(void)
|
||||
{
|
||||
static struct bt_gatt_discover_params discover_params;
|
||||
int err;
|
||||
|
||||
printk("Discovering services and characteristics\n");
|
||||
|
||||
discover_params.uuid = test_svc_uuid;
|
||||
discover_params.func = discover_func;
|
||||
discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
|
||||
discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
|
||||
discover_params.type = BT_GATT_DISCOVER_PRIMARY;
|
||||
discover_params.chan_opt = BT_ATT_CHAN_OPT_NONE;
|
||||
|
||||
err = bt_gatt_discover(g_conn, &discover_params);
|
||||
if (err != 0) {
|
||||
FAIL("Discover failed(err %d)\n", err);
|
||||
}
|
||||
}
|
||||
|
||||
BT_GATT_SERVICE_DEFINE(g_svc,
|
||||
BT_GATT_PRIMARY_SERVICE(TEST_SERVICE_UUID),
|
||||
BT_GATT_CHARACTERISTIC(TEST_CHRC_UUID, BT_GATT_CHRC_NOTIFY,
|
||||
BT_GATT_PERM_READ, NULL, NULL, NULL),
|
||||
BT_GATT_CCC(NULL,
|
||||
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE));
|
||||
|
||||
static void test_main(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
device_sync_init(PERIPHERAL_ID);
|
||||
|
||||
err = bt_enable(NULL);
|
||||
if (err != 0) {
|
||||
FAIL("Bluetooth enable failed (err %d)\n", err);
|
||||
}
|
||||
|
||||
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
|
||||
if (err != 0) {
|
||||
FAIL("Scanning failed to start (err %d)\n", err);
|
||||
}
|
||||
|
||||
printk("Scanning successfully started\n");
|
||||
|
||||
WAIT_FOR_FLAG(flag_is_connected);
|
||||
|
||||
err = bt_conn_set_security(g_conn, BT_SECURITY_L2);
|
||||
if (err) {
|
||||
FAIL("Failed to start encryption procedure\n");
|
||||
}
|
||||
|
||||
WAIT_FOR_FLAG(flag_is_encrypted);
|
||||
|
||||
err = bt_eatt_connect(g_conn, CONFIG_BT_EATT_MAX);
|
||||
if (err) {
|
||||
FAIL("Sending credit based connection request failed (err %d)\n", err);
|
||||
}
|
||||
|
||||
/* Wait for the channels to be connected */
|
||||
while (bt_eatt_count(g_conn) < CONFIG_BT_EATT_MAX) {
|
||||
k_sleep(K_TICKS(1));
|
||||
}
|
||||
|
||||
printk("Waiting for sync\n");
|
||||
device_sync_wait();
|
||||
|
||||
local_attr = &g_svc.attrs[1];
|
||||
|
||||
printk("############# Notification test\n");
|
||||
for (int idx = 0; idx < NUM_NOTIF; idx++) {
|
||||
printk("Notification %d\n", idx);
|
||||
send_notification();
|
||||
}
|
||||
|
||||
printk("############# Disconnect and reconnect\n");
|
||||
for (int idx = 0; idx < CONFIG_BT_EATT_MAX; idx++) {
|
||||
bt_eatt_disconnect_one(g_conn);
|
||||
while (bt_eatt_count(g_conn) != (CONFIG_BT_EATT_MAX - idx)) {
|
||||
k_sleep(K_TICKS(1));
|
||||
}
|
||||
}
|
||||
|
||||
printk("Connecting %d bearers\n", EATT_BEARERS_TEST);
|
||||
err = bt_eatt_connect(g_conn, EATT_BEARERS_TEST);
|
||||
if (err) {
|
||||
FAIL("Sending credit based connection request failed (err %d)\n", err);
|
||||
}
|
||||
|
||||
/* Wait for the channels to be connected */
|
||||
while (bt_eatt_count(g_conn) < EATT_BEARERS_TEST) {
|
||||
k_sleep(K_TICKS(1));
|
||||
}
|
||||
|
||||
printk("############# Send notifications during discovery request\n");
|
||||
gatt_discover();
|
||||
while (!TEST_FLAG(flag_discover_complete)) {
|
||||
printk("Notifying...\n");
|
||||
send_notification();
|
||||
}
|
||||
|
||||
printk("Sending final sync\n");
|
||||
device_sync_send();
|
||||
|
||||
PASS("Client Passed\n");
|
||||
}
|
||||
|
||||
static const struct bst_test_instance test_vcs[] = {
|
||||
{
|
||||
.test_id = "client",
|
||||
.test_post_init_f = test_init,
|
||||
.test_tick_f = test_tick,
|
||||
.test_main_f = test_main
|
||||
},
|
||||
BSTEST_END_MARKER
|
||||
};
|
||||
|
||||
struct bst_test_list *test_client_install(struct bst_test_list *tests)
|
||||
{
|
||||
return bst_add_tests(tests, test_vcs);
|
||||
}
|
67
tests/bsim/bluetooth/host/att/eatt_notif/src/common.c
Normal file
67
tests/bsim/bluetooth/host/att/eatt_notif/src/common.c
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#define LOG_MODULE_NAME common
|
||||
|
||||
LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_DBG);
|
||||
|
||||
void test_tick(bs_time_t HW_device_time)
|
||||
{
|
||||
if (bst_result != Passed) {
|
||||
FAIL("test failed (not passed after %i seconds)\n", WAIT_TIME);
|
||||
}
|
||||
}
|
||||
|
||||
void test_init(void)
|
||||
{
|
||||
bst_ticker_set_next_tick_absolute(WAIT_TIME);
|
||||
bst_result = In_progress;
|
||||
}
|
||||
|
||||
/* Call in init functions*/
|
||||
void device_sync_init(uint device_nbr)
|
||||
{
|
||||
uint peer;
|
||||
|
||||
if (device_nbr == CENTRAL_ID) {
|
||||
peer = PERIPHERAL_ID;
|
||||
} else {
|
||||
peer = CENTRAL_ID;
|
||||
}
|
||||
|
||||
uint dev_nbrs[BACK_CHANNELS] = { peer };
|
||||
uint channel_nbrs[BACK_CHANNELS] = { 0 };
|
||||
const uint *ch = bs_open_back_channel(device_nbr, dev_nbrs, channel_nbrs, BACK_CHANNELS);
|
||||
|
||||
if (!ch) {
|
||||
LOG_ERR("bs_open_back_channel failed!");
|
||||
}
|
||||
}
|
||||
|
||||
/* Call it to make peer to proceed.*/
|
||||
void device_sync_send(void)
|
||||
{
|
||||
uint8_t msg[1] = "S";
|
||||
|
||||
bs_bc_send_msg(0, msg, sizeof(msg));
|
||||
}
|
||||
|
||||
/* Wait until peer send sync*/
|
||||
void device_sync_wait(void)
|
||||
{
|
||||
int size_msg_received = 0;
|
||||
uint8_t msg;
|
||||
|
||||
while (!size_msg_received) {
|
||||
size_msg_received = bs_bc_is_msg_received(0);
|
||||
k_sleep(K_MSEC(1));
|
||||
}
|
||||
|
||||
bs_bc_receive_msg(0, &msg, size_msg_received);
|
||||
}
|
75
tests/bsim/bluetooth/host/att/eatt_notif/src/common.h
Normal file
75
tests/bsim/bluetooth/host/att/eatt_notif/src/common.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* Common functions and helpers for BSIM EATT notification tests
|
||||
*
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
|
||||
#include "bs_types.h"
|
||||
#include "bs_tracing.h"
|
||||
#include "time_machine.h"
|
||||
#include "bstests.h"
|
||||
|
||||
#include <zephyr/types.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/hci.h>
|
||||
#include <zephyr/bluetooth/conn.h>
|
||||
#include <zephyr/bluetooth/uuid.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
#include "bs_pc_backchannel.h"
|
||||
|
||||
extern enum bst_result_t bst_result;
|
||||
|
||||
#define WAIT_TIME (30 * 1e6) /*seconds*/
|
||||
|
||||
#define CREATE_FLAG(flag) static 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 TEST_FLAG(flag) (atomic_get(&flag) == (atomic_t)true)
|
||||
#define WAIT_FOR_FLAG(flag) \
|
||||
while (!(bool)atomic_get(&flag)) { \
|
||||
(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, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define CHRC_SIZE 10
|
||||
#define LONG_CHRC_SIZE 40
|
||||
|
||||
#define TEST_SERVICE_UUID \
|
||||
BT_UUID_DECLARE_128(0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x02, 0x03, \
|
||||
0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00)
|
||||
|
||||
#define TEST_CHRC_UUID \
|
||||
BT_UUID_DECLARE_128(0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x02, 0x03, \
|
||||
0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0x00)
|
||||
|
||||
#define TEST_LONG_CHRC_UUID \
|
||||
BT_UUID_DECLARE_128(0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x02, 0x03, \
|
||||
0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0x11)
|
||||
|
||||
#define CENTRAL_ID 0
|
||||
#define PERIPHERAL_ID 1
|
||||
#define BACK_CHANNELS 1
|
||||
|
||||
void test_tick(bs_time_t HW_device_time);
|
||||
void test_init(void);
|
||||
void device_sync_init(uint device_nbr);
|
||||
void device_sync_send(void);
|
||||
void device_sync_wait(void);
|
21
tests/bsim/bluetooth/host/att/eatt_notif/src/main.c
Normal file
21
tests/bsim/bluetooth/host/att/eatt_notif/src/main.c
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "bstests.h"
|
||||
|
||||
extern struct bst_test_list *test_server_install(struct bst_test_list *tests);
|
||||
extern struct bst_test_list *test_client_install(struct bst_test_list *tests);
|
||||
|
||||
bst_test_install_t test_installers[] = {
|
||||
test_server_install,
|
||||
test_client_install,
|
||||
NULL
|
||||
};
|
||||
|
||||
void main(void)
|
||||
{
|
||||
bst_main();
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue