Browse Source

tests: Bluetooth: Tester: VCP BSIM test

Adds BSIM testing of the VCP features of the BT Tester.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
pull/88157/merge
Emil Gydesen 4 months ago committed by Dan Kalowsky
parent
commit
e72e837971
  1. 2
      MAINTAINERS.yml
  2. 11
      tests/bluetooth/tester/testcase.yaml
  3. 2
      tests/bsim/bluetooth/tester/CMakeLists.txt
  4. 93
      tests/bsim/bluetooth/tester/src/audio/vcp_central.c
  5. 60
      tests/bsim/bluetooth/tester/src/audio/vcp_peripheral.c
  6. 2
      tests/bsim/bluetooth/tester/src/bsim_btp.c
  7. 205
      tests/bsim/bluetooth/tester/src/bsim_btp.h
  8. 4
      tests/bsim/bluetooth/tester/src/test_main.c
  9. 41
      tests/bsim/bluetooth/tester/tests_scripts/vcp.sh

2
MAINTAINERS.yml

@ -480,6 +480,7 @@ Bluetooth Host: @@ -480,6 +480,7 @@ Bluetooth Host:
- tests/bsim/bluetooth/hci_uart/
- tests/bsim/bluetooth/ll/
- tests/bsim/bluetooth/mesh/
- tests/bsim/bluetooth/tester/src/audio/
labels:
- "area: Bluetooth Host"
- "area: Bluetooth"
@ -534,6 +535,7 @@ Bluetooth Audio: @@ -534,6 +535,7 @@ Bluetooth Audio:
- tests/bluetooth/audio/
- tests/bsim/bluetooth/audio/
- tests/bsim/bluetooth/audio_samples/
- tests/bsim/bluetooth/tester/src/audio/
- tests/bluetooth/shell/audio.conf
- tests/bluetooth/tester/overlay-le-audio.conf
- tests/bluetooth/tester/overlay-bt_ll_sw_split.conf

11
tests/bluetooth/tester/testcase.yaml

@ -61,6 +61,17 @@ tests: @@ -61,6 +61,17 @@ tests:
tags: bluetooth
harness: bluetooth
sysbuild: true
bluetooth.general.tester_le_audio_bsim:
build_only: true
platform_allow:
- nrf52_bsim/native
- nrf5340bsim/nrf5340/cpuapp
extra_args:
- EXTRA_CONF_FILE="overlay-le-audio.conf"
harness: bsim
harness_config:
bsim_exe_name: tests_bluetooth_tester_le_audio_prj_conf
sysbuild: true
bluetooth.general.tester_mesh:
build_only: true
platform_allow:

2
tests/bsim/bluetooth/tester/CMakeLists.txt

@ -24,6 +24,8 @@ zephyr_include_directories( @@ -24,6 +24,8 @@ zephyr_include_directories(
target_sources(app PRIVATE
src/bsim_btp.c
src/test_main.c
src/audio/vcp_central.c
src/audio/vcp_peripheral.c
src/host/gap_central.c
src/host/gap_peripheral.c
)

93
tests/bsim/bluetooth/tester/src/audio/vcp_central.c

@ -0,0 +1,93 @@ @@ -0,0 +1,93 @@
/*
* Copyright (c) 2025 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <stdint.h>
#include <zephyr/bluetooth/addr.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/net_buf.h>
#include <zephyr/sys/util_macro.h>
#include "babblekit/testcase.h"
#include "bstests.h"
#include "btp/btp.h"
#include "bsim_btp.h"
LOG_MODULE_REGISTER(bsim_vcp_central, CONFIG_BSIM_BTTESTER_LOG_LEVEL);
static void test_vcp_central(void)
{
char addr_str[BT_ADDR_LE_STR_LEN];
bt_addr_le_t remote_addr;
bsim_btp_uart_init();
bsim_btp_wait_for_evt(BTP_SERVICE_ID_CORE, BTP_CORE_EV_IUT_READY, NULL);
bsim_btp_core_register(BTP_SERVICE_ID_GAP);
bsim_btp_core_register(BTP_SERVICE_ID_VCP);
bsim_btp_core_register(BTP_SERVICE_ID_VOCS);
bsim_btp_core_register(BTP_SERVICE_ID_AICS);
bsim_btp_gap_start_discovery(BTP_GAP_DISCOVERY_FLAG_LE);
bsim_btp_wait_for_gap_device_found(&remote_addr);
bt_addr_le_to_str(&remote_addr, addr_str, sizeof(addr_str));
LOG_INF("Found remote device %s", addr_str);
bsim_btp_gap_stop_discovery();
bsim_btp_gap_connect(&remote_addr, BTP_GAP_ADDR_TYPE_IDENTITY);
bsim_btp_wait_for_gap_device_connected(NULL);
LOG_INF("Device %s connected", addr_str);
bsim_btp_gap_pair(&remote_addr);
bsim_btp_wait_for_gap_sec_level_changed(NULL, NULL);
bsim_btp_vcp_discover(&remote_addr);
bsim_btp_wait_for_vcp_discovered(NULL);
const uint8_t new_vol = 123;
uint8_t ev_vol;
bsim_btp_vcp_ctlr_set_vol(&remote_addr, new_vol);
bsim_btp_wait_for_vcp_state(NULL, &ev_vol);
TEST_ASSERT(ev_vol == new_vol, "%u != %u", ev_vol, new_vol);
const int16_t new_offset = -5;
int16_t ev_offset;
bsim_btp_vocs_state_set(&remote_addr, new_offset);
bsim_btp_wait_for_vocs_state(NULL, &ev_offset);
TEST_ASSERT(ev_offset == new_offset, "%d != %d", ev_offset, new_offset);
const int8_t new_gain = 5;
int8_t ev_gain;
bsim_btp_aics_set_gain(&remote_addr, new_gain);
bsim_btp_wait_for_aics_state(NULL, &ev_gain);
TEST_ASSERT(ev_gain == new_gain, "%d != %d", ev_gain, new_gain);
bsim_btp_gap_disconnect(&remote_addr);
bsim_btp_wait_for_gap_device_disconnected(NULL);
LOG_INF("Device %s disconnected", addr_str);
TEST_PASS("PASSED\n");
}
static const struct bst_test_instance test_sample[] = {
{
.test_id = "vcp_central",
.test_descr = "Smoketest for the VCP central BT Tester behavior",
.test_main_f = test_vcp_central,
},
BSTEST_END_MARKER,
};
struct bst_test_list *test_vcp_central_install(struct bst_test_list *tests)
{
return bst_add_tests(tests, test_sample);
}

60
tests/bsim/bluetooth/tester/src/audio/vcp_peripheral.c

@ -0,0 +1,60 @@ @@ -0,0 +1,60 @@
/*
* Copyright (c) 2025 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <stdint.h>
#include <zephyr/bluetooth/addr.h>
#include <zephyr/bluetooth/gap.h>
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/util_macro.h>
#include "babblekit/testcase.h"
#include "bstests.h"
#include "btp/btp.h"
#include "bsim_btp.h"
LOG_MODULE_REGISTER(bsim_vcp_peripheral, CONFIG_BSIM_BTTESTER_LOG_LEVEL);
static void test_vcp_peripheral(void)
{
char addr_str[BT_ADDR_LE_STR_LEN];
bt_addr_le_t remote_addr;
bsim_btp_uart_init();
bsim_btp_wait_for_evt(BTP_SERVICE_ID_CORE, BTP_CORE_EV_IUT_READY, NULL);
bsim_btp_core_register(BTP_SERVICE_ID_GAP);
bsim_btp_core_register(BTP_SERVICE_ID_VCS);
bsim_btp_core_register(BTP_SERVICE_ID_VOCS);
bsim_btp_core_register(BTP_SERVICE_ID_AICS);
bsim_btp_gap_set_discoverable(BTP_GAP_GENERAL_DISCOVERABLE);
bsim_btp_gap_start_advertising(0U, 0U, NULL, BT_HCI_OWN_ADDR_PUBLIC);
bsim_btp_wait_for_gap_device_connected(&remote_addr);
bt_addr_le_to_str(&remote_addr, addr_str, sizeof(addr_str));
LOG_INF("Device %s connected", addr_str);
bsim_btp_wait_for_gap_device_disconnected(NULL);
LOG_INF("Device %s disconnected", addr_str);
TEST_PASS("PASSED\n");
}
static const struct bst_test_instance test_sample[] = {
{
.test_id = "vcp_peripheral",
.test_descr = "Smoketest for the VCP peripheral BT Tester behavior",
.test_main_f = test_vcp_peripheral,
},
BSTEST_END_MARKER,
};
struct bst_test_list *test_vcp_peripheral_install(struct bst_test_list *tests)
{
return bst_add_tests(tests, test_sample);
}

2
tests/bsim/bluetooth/tester/src/bsim_btp.c

@ -192,6 +192,8 @@ static bool is_valid_gap_packet_len(const struct btp_hdr *hdr, struct net_buf_si @@ -192,6 +192,8 @@ static bool is_valid_gap_packet_len(const struct btp_hdr *hdr, struct net_buf_si
}
case BTP_GAP_EV_PERIODIC_TRANSFER_RECEIVED:
return buf_simple->len == sizeof(struct btp_gap_ev_periodic_transfer_received_ev);
case BTP_GAP_EV_ENCRYPTION_CHANGE:
return buf_simple->len == sizeof(struct btp_gap_encryption_change_ev);
default:
LOG_ERR("Unhandled opcode 0x%02X", hdr->opcode);
return false;

205
tests/bsim/bluetooth/tester/src/bsim_btp.h

@ -3,10 +3,16 @@ @@ -3,10 +3,16 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef BSIM_BTP_H_
#define BSIM_BTP_H_
#include <stdint.h>
#include <string.h>
#include <zephyr/bluetooth/addr.h>
#include <zephyr/bluetooth/att.h>
#include <zephyr/net_buf.h>
#include <zephyr/sys/byteorder.h>
#include "babblekit/testcase.h"
@ -198,3 +204,202 @@ static inline void bsim_btp_wait_for_gap_device_disconnected(bt_addr_le_t *addre @@ -198,3 +204,202 @@ static inline void bsim_btp_wait_for_gap_device_disconnected(bt_addr_le_t *addre
net_buf_unref(buf);
}
static inline void bsim_btp_gap_pair(const bt_addr_le_t *address)
{
struct btp_gap_pair_cmd *cmd;
struct btp_hdr *cmd_hdr;
NET_BUF_SIMPLE_DEFINE(cmd_buffer, BTP_MTU);
cmd_hdr = net_buf_simple_add(&cmd_buffer, sizeof(*cmd_hdr));
cmd_hdr->service = BTP_SERVICE_ID_GAP;
cmd_hdr->opcode = BTP_GAP_PAIR;
cmd_hdr->index = BTP_INDEX;
cmd = net_buf_simple_add(&cmd_buffer, sizeof(*cmd));
bt_addr_le_copy(&cmd->address, address);
cmd_hdr->len = cmd_buffer.len - sizeof(*cmd_hdr);
bsim_btp_send_to_tester(cmd_buffer.data, cmd_buffer.len);
}
static inline void bsim_btp_wait_for_gap_sec_level_changed(bt_addr_le_t *address,
uint8_t *sec_level)
{
struct btp_gap_sec_level_changed_ev *ev;
struct net_buf *buf;
bsim_btp_wait_for_evt(BTP_SERVICE_ID_GAP, BTP_GAP_EV_SEC_LEVEL_CHANGED, &buf);
ev = net_buf_pull_mem(buf, sizeof(*ev));
if (address != NULL) {
bt_addr_le_copy(address, &ev->address);
}
if (sec_level != NULL) {
*sec_level = ev->sec_level;
}
net_buf_unref(buf);
}
static inline void bsim_btp_vcp_discover(const bt_addr_le_t *address)
{
struct btp_vcp_discover_cmd *cmd;
struct btp_hdr *cmd_hdr;
NET_BUF_SIMPLE_DEFINE(cmd_buffer, BTP_MTU);
cmd_hdr = net_buf_simple_add(&cmd_buffer, sizeof(*cmd_hdr));
cmd_hdr->service = BTP_SERVICE_ID_VCP;
cmd_hdr->opcode = BTP_VCP_VOL_CTLR_DISCOVER;
cmd_hdr->index = BTP_INDEX;
cmd = net_buf_simple_add(&cmd_buffer, sizeof(*cmd));
bt_addr_le_copy(&cmd->address, address);
cmd_hdr->len = cmd_buffer.len - sizeof(*cmd_hdr);
bsim_btp_send_to_tester(cmd_buffer.data, cmd_buffer.len);
}
static inline void bsim_btp_wait_for_vcp_discovered(bt_addr_le_t *address)
{
struct btp_vcp_discovered_ev *ev;
struct net_buf *buf;
bsim_btp_wait_for_evt(BTP_SERVICE_ID_VCP, BTP_VCP_DISCOVERED_EV, &buf);
ev = net_buf_pull_mem(buf, sizeof(*ev));
TEST_ASSERT(ev->att_status == BT_ATT_ERR_SUCCESS);
if (address != NULL) {
bt_addr_le_copy(address, &ev->address);
}
net_buf_unref(buf);
}
static inline void bsim_btp_vcp_ctlr_set_vol(const bt_addr_le_t *address, uint8_t volume)
{
struct btp_vcp_ctlr_set_vol_cmd *cmd;
struct btp_hdr *cmd_hdr;
NET_BUF_SIMPLE_DEFINE(cmd_buffer, BTP_MTU);
cmd_hdr = net_buf_simple_add(&cmd_buffer, sizeof(*cmd_hdr));
cmd_hdr->service = BTP_SERVICE_ID_VCP;
cmd_hdr->opcode = BTP_VCP_VOL_CTLR_SET_VOL;
cmd_hdr->index = BTP_INDEX;
cmd = net_buf_simple_add(&cmd_buffer, sizeof(*cmd));
bt_addr_le_copy(&cmd->address, address);
cmd->volume = volume;
cmd_hdr->len = cmd_buffer.len - sizeof(*cmd_hdr);
bsim_btp_send_to_tester(cmd_buffer.data, cmd_buffer.len);
}
static inline void bsim_btp_wait_for_vcp_state(bt_addr_le_t *address, uint8_t *volume)
{
struct btp_vcp_state_ev *ev;
struct net_buf *buf;
bsim_btp_wait_for_evt(BTP_SERVICE_ID_VCP, BTP_VCP_STATE_EV, &buf);
ev = net_buf_pull_mem(buf, sizeof(*ev));
TEST_ASSERT(ev->att_status == BT_ATT_ERR_SUCCESS);
if (address != NULL) {
bt_addr_le_copy(address, &ev->address);
}
if (volume != NULL) {
*volume = ev->volume;
}
net_buf_unref(buf);
}
static inline void bsim_btp_vocs_state_set(const bt_addr_le_t *address, int16_t offset)
{
struct btp_vocs_offset_set_cmd *cmd;
struct btp_hdr *cmd_hdr;
NET_BUF_SIMPLE_DEFINE(cmd_buffer, BTP_MTU);
cmd_hdr = net_buf_simple_add(&cmd_buffer, sizeof(*cmd_hdr));
cmd_hdr->service = BTP_SERVICE_ID_VOCS;
cmd_hdr->opcode = BTP_VOCS_OFFSET_STATE_SET;
cmd_hdr->index = BTP_INDEX;
cmd = net_buf_simple_add(&cmd_buffer, sizeof(*cmd));
bt_addr_le_copy(&cmd->address, address);
cmd->offset = sys_cpu_to_le16(offset);
cmd_hdr->len = cmd_buffer.len - sizeof(*cmd_hdr);
bsim_btp_send_to_tester(cmd_buffer.data, cmd_buffer.len);
}
static inline void bsim_btp_wait_for_vocs_state(bt_addr_le_t *address, int16_t *offset)
{
struct btp_vocs_offset_state_ev *ev;
struct net_buf *buf;
bsim_btp_wait_for_evt(BTP_SERVICE_ID_VOCS, BTP_VOCS_OFFSET_STATE_EV, &buf);
ev = net_buf_pull_mem(buf, sizeof(*ev));
TEST_ASSERT(ev->att_status == BT_ATT_ERR_SUCCESS);
if (address != NULL) {
bt_addr_le_copy(address, &ev->address);
}
if (offset != NULL) {
*offset = sys_le16_to_cpu(ev->offset);
}
net_buf_unref(buf);
}
static inline void bsim_btp_aics_set_gain(const bt_addr_le_t *address, int8_t gain)
{
struct btp_aics_set_gain_cmd *cmd;
struct btp_hdr *cmd_hdr;
NET_BUF_SIMPLE_DEFINE(cmd_buffer, BTP_MTU);
cmd_hdr = net_buf_simple_add(&cmd_buffer, sizeof(*cmd_hdr));
cmd_hdr->service = BTP_SERVICE_ID_AICS;
cmd_hdr->opcode = BTP_AICS_SET_GAIN;
cmd_hdr->index = BTP_INDEX;
cmd = net_buf_simple_add(&cmd_buffer, sizeof(*cmd));
bt_addr_le_copy(&cmd->address, address);
cmd->gain = gain;
cmd_hdr->len = cmd_buffer.len - sizeof(*cmd_hdr);
bsim_btp_send_to_tester(cmd_buffer.data, cmd_buffer.len);
}
static inline void bsim_btp_wait_for_aics_state(bt_addr_le_t *address, int8_t *gain)
{
struct btp_aics_state_ev *ev;
struct net_buf *buf;
bsim_btp_wait_for_evt(BTP_SERVICE_ID_AICS, BTP_AICS_STATE_EV, &buf);
ev = net_buf_pull_mem(buf, sizeof(*ev));
TEST_ASSERT(ev->att_status == BT_ATT_ERR_SUCCESS);
if (address != NULL) {
bt_addr_le_copy(address, &ev->address);
}
if (gain != NULL) {
*gain = ev->gain;
}
net_buf_unref(buf);
}
#endif /* BSIM_BTP_H_ */

4
tests/bsim/bluetooth/tester/src/test_main.c

@ -9,10 +9,14 @@ @@ -9,10 +9,14 @@
extern struct bst_test_list *test_gap_central_install(struct bst_test_list *tests);
extern struct bst_test_list *test_gap_peripheral_install(struct bst_test_list *tests);
extern struct bst_test_list *test_vcp_central_install(struct bst_test_list *tests);
extern struct bst_test_list *test_vcp_peripheral_install(struct bst_test_list *tests);
bst_test_install_t test_installers[] = {
test_gap_central_install,
test_gap_peripheral_install,
test_vcp_central_install,
test_vcp_peripheral_install,
NULL,
};

41
tests/bsim/bluetooth/tester/tests_scripts/vcp.sh

@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
#!/usr/bin/env bash
# Copyright 2025 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0
# Smoketest for VCP BTP commands with the BT tester
simulation_id="tester_vcp"
verbosity_level=2
EXECUTE_TIMEOUT=100
source ${ZEPHYR_BASE}/tests/bsim/sh_common.source
cd ${BSIM_OUT_PATH}/bin
UART_DIR=/tmp/bs_${USER}/${simulation_id}/
UART_PER=${UART_DIR}/peripheral
UART_CEN=${UART_DIR}/central
# Central BT Tester
Execute ./bs_${BOARD_TS}_tests_bluetooth_tester_le_audio_prj_conf \
-v=${verbosity_level} -s=${simulation_id} -rs=10 -d=0 -RealEncryption=1 \
-uart0_fifob_rxfile=${UART_CEN}.tx -uart0_fifob_txfile=${UART_CEN}.rx
# Central Upper Tester
Execute ./bs_nrf52_bsim_native_tests_bsim_bluetooth_tester_prj_conf \
-v=${verbosity_level} -s=${simulation_id} -rs=21 -d=10 -RealEncryption=1 -testid=vcp_central \
-nosim -uart0_fifob_rxfile=${UART_CEN}.rx -uart0_fifob_txfile=${UART_CEN}.tx
# Peripheral BT Tester
Execute ./bs_${BOARD_TS}_tests_bluetooth_tester_le_audio_prj_conf \
-v=${verbosity_level} -s=${simulation_id} -rs=32 -d=1 -RealEncryption=1 \
-uart0_fifob_rxfile=${UART_PER}.tx -uart0_fifob_txfile=${UART_PER}.rx
# Peripheral Upper Tester
Execute ./bs_nrf52_bsim_native_tests_bsim_bluetooth_tester_prj_conf \
-v=${verbosity_level} -s=${simulation_id} -rs=43 -d=11 -RealEncryption=1 -testid=vcp_peripheral \
-nosim -uart0_fifob_rxfile=${UART_PER}.rx -uart0_fifob_txfile=${UART_PER}.tx
Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} -D=2 -sim_length=20e6 $@
wait_for_background_jobs # Wait for all programs in background and return != 0 if any fails
Loading…
Cancel
Save