bluetooth: BAS: add battery level status char to bas service

Added the battery level status char to bas service
as per bas_1.1 spec. Added BSIM test for BAS service
to test the NTF/INDs of BAS characteristics.

Signed-off-by: Nithin Ramesh Myliattil <niym@demant.com>
This commit is contained in:
Nithin Ramesh Myliattil 2024-08-08 17:49:46 +02:00 committed by Anas Nashif
commit baa5683e59
19 changed files with 1643 additions and 110 deletions

View file

@ -0,0 +1,29 @@
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(battery_service_test)
target_sources(app PRIVATE
src/main.c
src/central_test.c
src/peripheral_test.c
)
# This contains a variety of helper functions that abstract away common tasks,
# like scanning, setting up a connection, querying the peer for a given
# characteristic, etc..
add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/common/testlib testlib)
target_link_libraries(app PRIVATE testlib)
# This contains babblesim-specific helpers, e.g. device synchronization.
add_subdirectory(${ZEPHYR_BASE}/tests/bsim/babblekit babblekit)
target_link_libraries(app PRIVATE babblekit)
zephyr_library_include_directories(${ZEPHYR_BASE}/samples/bluetooth)
zephyr_include_directories(
${BSIM_COMPONENTS_PATH}/libUtilv1/src/
${BSIM_COMPONENTS_PATH}/libPhyComv1/src/
)

View file

@ -0,0 +1,14 @@
CONFIG_BT=y
CONFIG_LOG=y
CONFIG_BT_CENTRAL=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_SMP=y
CONFIG_BT_BAS=y
CONFIG_BT_GATT_CLIENT=y
CONFIG_BT_DEVICE_NAME="bsim_bas"
CONFIG_BT_ATT_TX_COUNT=5
CONFIG_BT_BAS_BLS=y
CONFIG_BT_BAS_BLS_IDENTIFIER_PRESENT=y
CONFIG_BT_BAS_BLS_BATTERY_LEVEL_PRESENT=y
CONFIG_BT_BAS_BLS_ADDITIONAL_STATUS_PRESENT=y

View file

@ -0,0 +1,562 @@
/*
* Copyright (c) 2024 Demant A/S
*
* 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 <argparse.h>
#include <zephyr/types.h>
#include <stddef.h>
#include <errno.h>
#include <zephyr/bluetooth/services/bas.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/sys/byteorder.h>
#include "testlib/conn.h"
#include "testlib/scan.h"
#include "testlib/log_utils.h"
#include "babblekit/flags.h"
#include "babblekit/sync.h"
#include "babblekit/testcase.h"
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(bt_bsim_bas, CONFIG_BT_BAS_LOG_LEVEL);
static struct bt_conn *default_conn;
static bt_addr_le_t peer = {};
static struct bt_uuid_16 uuid = BT_UUID_INIT_16(0);
static struct bt_gatt_discover_params discover_params;
static struct bt_gatt_subscribe_params battery_level_notify_params;
static struct bt_gatt_subscribe_params battery_level_status_sub_params;
/*
* Battery Service test:
* We expect to find a connectable peripheral to which we will
* connect and discover Battery Service
*
* Test the Read/Notify/Indicate Characteristics of BAS
*/
#define WAIT_TIME 10 /*seconds*/
#define BAS_BLS_IND_RECEIVED_COUNT 20
#define BAS_BLS_NTF_RECEIVED_COUNT 20
static DEFINE_FLAG(notification_count_reached);
static DEFINE_FLAG(indication_count_reached);
extern enum bst_result_t bst_result;
static void test_bas_central_init(void)
{
bst_ticker_set_next_tick_absolute(WAIT_TIME * 1e6);
bst_result = In_progress;
}
static void test_bas_central_tick(bs_time_t HW_device_time)
{
/*
* If in WAIT_TIME seconds the testcase did not already pass
* (and finish) we consider it failed
*/
if (bst_result != Passed) {
TEST_FAIL("test_bas_central failed (not passed after %i seconds)\n", WAIT_TIME);
}
}
/* Callback for handling Battery Level Notifications */
static uint8_t battery_level_notify_cb(struct bt_conn *conn,
struct bt_gatt_subscribe_params *params, const void *data,
uint16_t length)
{
if (data) {
LOG_INF("[NOTIFICATION] BAS Battery Level: %d%%", *(const uint8_t *)data);
} else {
LOG_INF("Battery Level Notifications disabled");
}
return BT_GATT_ITER_CONTINUE;
}
/* Callback for handling Battery Level Read Response */
static uint8_t battery_level_read_cb(struct bt_conn *conn, uint8_t err,
struct bt_gatt_read_params *params, const void *data,
uint16_t length)
{
TEST_ASSERT(err == 0, "Failed to read Battery Level (err %d)", err);
if (data) {
LOG_DBG("[READ] BAS Battery Level: %d%%\n", *(const uint8_t *)data);
}
return BT_GATT_ITER_STOP;
}
static bool parse_battery_level_status(const uint8_t *data, uint16_t length)
{
/* Check minimum length for parsing flags and power state */
if (length < 3) {
TEST_FAIL("Invalid data length: %d", length);
return false;
}
/* Parse flags (first byte) */
uint8_t flags = data[0];
LOG_INF("Parsed Flags: 0x%02x", flags);
if (flags & BT_BAS_BLS_FLAG_IDENTIFIER_PRESENT) {
LOG_INF(" Identifier Present");
} else {
LOG_INF(" Identifier Not Present");
}
if (flags & BT_BAS_BLS_FLAG_BATTERY_LEVEL_PRESENT) {
LOG_INF(" Battery Level Present");
} else {
LOG_INF(" Battery Level Not Present");
}
if (flags & BT_BAS_BLS_FLAG_ADDITIONAL_STATUS_PRESENT) {
LOG_INF(" Additional Status Present");
} else {
LOG_INF(" Additional Status Not Present");
}
/* Parse power state (next 2 bytes) */
uint16_t power_state = sys_get_le16(&data[1]);
LOG_INF("Parsed Power State: 0x%04x", power_state);
/* Print out each power state value */
LOG_INF(" Battery Present: %s", (power_state & BIT(0)) ? "Yes" : "No");
uint8_t wired_power = (power_state >> 1) & 0x03;
switch (wired_power) {
case 0:
LOG_INF(" Wired Power Source: No");
break;
case 1:
LOG_INF(" Wired Power Source: Yes");
break;
case 2:
LOG_INF(" Wired Power Source: Unknown");
break;
default:
LOG_INF(" Wired Power Source: RFU");
break;
}
uint8_t wireless_power = (power_state >> 3) & 0x03;
switch (wireless_power) {
case 0:
LOG_INF(" Wireless Power Source: No");
break;
case 1:
LOG_INF(" Wireless Power Source: Yes");
break;
case 2:
LOG_INF(" Wireless Power Source: Unknown");
break;
default:
LOG_INF(" Wireless Power Source: RFU");
break;
}
uint8_t charge_state = (power_state >> 5) & 0x03;
switch (charge_state) {
case 0:
LOG_INF(" Battery Charge State: Unknown");
break;
case 1:
LOG_INF(" Battery Charge State: Charging");
break;
case 2:
LOG_INF(" Battery Charge State: Discharging (Active)");
break;
case 3:
LOG_INF(" Battery Charge State: Discharging (Inactive)");
break;
}
uint8_t charge_level = (power_state >> 7) & 0x03;
switch (charge_level) {
case 0:
LOG_INF(" Battery Charge Level: Unknown");
break;
case 1:
LOG_INF(" Battery Charge Level: Good");
break;
case 2:
LOG_INF(" Battery Charge Level: Low");
break;
case 3:
LOG_INF(" Battery Charge Level: Critical");
break;
}
uint8_t charging_type = (power_state >> 9) & 0x07;
switch (charging_type) {
case 0:
LOG_INF(" Charging Type: Unknown or Not Charging");
break;
case 1:
LOG_INF(" Charging Type: Constant Current");
break;
case 2:
LOG_INF(" Charging Type: Constant Voltage");
break;
case 3:
LOG_INF(" Charging Type: Trickle");
break;
case 4:
LOG_INF(" Charging Type: Float");
break;
default:
LOG_INF(" Charging Type: RFU");
break;
}
uint8_t charging_fault = (power_state >> 12) & 0x07;
if (charging_fault) {
LOG_INF(" Charging Fault Reason: %s%s%s",
(charging_fault & BIT(0)) ? "Battery " : "",
(charging_fault & BIT(1)) ? "External Power Source " : "",
(charging_fault & BIT(2)) ? "Other " : "");
} else {
LOG_INF(" Charging Fault Reason: None");
}
/* Optional: Check if identifier is present */
if (IS_ENABLED(CONFIG_BT_BAS_BLS_IDENTIFIER_PRESENT)) {
/* Check if length is sufficient for identifier */
if (length < 5) {
TEST_FAIL("Invalid data length for identifier");
return false;
}
/* Parse identifier (next 2 bytes) */
uint16_t identifier = sys_get_le16(&data[3]);
LOG_INF("Parsed Identifier: 0x%04x", identifier);
}
/* Optional: Check if battery level is present */
if (IS_ENABLED(CONFIG_BT_BAS_BLS_BATTERY_LEVEL_PRESENT)) {
/* Check if length is sufficient for battery level */
if (length < 6) {
TEST_FAIL("Invalid data length for battery level");
return false;
}
/* Parse battery level (next byte) */
uint8_t battery_level = data[5];
LOG_INF("Parsed Battery Level: %d%%", battery_level);
}
/* Optional: Check if additional status is present */
if (IS_ENABLED(CONFIG_BT_BAS_BLS_ADDITIONAL_STATUS_PRESENT)) {
/* Check if length is sufficient for additional status */
if (length < 7) {
TEST_FAIL("Invalid data length for additional status");
return false;
}
/* Parse additional status (next byte) */
uint8_t additional_status = data[6];
LOG_INF("Parsed Additional Status: 0x%02x", additional_status);
/* Print out additional status values */
uint8_t service_required = additional_status & 0x03;
switch (service_required) {
case 0:
LOG_INF(" Service Required: False");
break;
case 1:
LOG_INF(" Service Required: True");
break;
case 2:
LOG_INF(" Service Required: Unknown");
break;
default:
LOG_INF(" Service Required: RFU");
break;
}
bool battery_fault = (additional_status & BIT(2)) ? true : false;
LOG_INF(" Battery Fault: %s", battery_fault ? "Yes" : "No");
}
return true;
}
static unsigned char battery_level_status_indicate_cb(struct bt_conn *conn,
struct bt_gatt_subscribe_params *params,
const void *data, uint16_t length)
{
if (!data) {
LOG_INF("bas level status indication disabled\n");
} else {
static int ind_received;
printk("[INDICATION] BAS Battery Level Status: ");
for (int i = 0; i < length; i++) {
printk("%02x ", ((uint8_t *)data)[i]);
}
printk("\n");
if (parse_battery_level_status(data, length)) {
LOG_INF("Notification parsed successfully");
} else {
LOG_ERR("Notification parsing failed");
}
if (ind_received++ > BAS_BLS_IND_RECEIVED_COUNT) {
SET_FLAG(indication_count_reached);
}
}
return BT_GATT_ITER_CONTINUE;
}
static uint8_t battery_level_status_notify_cb(struct bt_conn *conn,
struct bt_gatt_subscribe_params *params,
const void *data, uint16_t length)
{
if (!data) {
LOG_INF("bas level status notification disabled\n");
} else {
static int notify_count;
printk("[NOTIFICATION] BAS Battery Level Status: ");
for (int i = 0; i < length; i++) {
printk("%02x ", ((uint8_t *)data)[i]);
}
printk("\n");
if (parse_battery_level_status(data, length)) {
LOG_INF("Notification parsed successfully");
} else {
LOG_ERR("Notification parsing failed");
}
if (notify_count++ > BAS_BLS_NTF_RECEIVED_COUNT) {
SET_FLAG(notification_count_reached);
}
}
return BT_GATT_ITER_CONTINUE;
}
static void read_battery_level(const struct bt_gatt_attr *attr)
{
/* Read the battery level after subscribing */
static struct bt_gatt_read_params read_params;
read_params.func = battery_level_read_cb;
read_params.handle_count = 1;
read_params.single.handle = bt_gatt_attr_get_handle(attr);
read_params.single.offset = 0;
bt_gatt_read(default_conn, &read_params);
}
static void subscribe_battery_level(const struct bt_gatt_attr *attr)
{
int err;
battery_level_notify_params = (struct bt_gatt_subscribe_params){
/* In Zephyr, it is common practice for the CCC handle
* to be positioned two handles after the characteristic handle.
*/
.ccc_handle = bt_gatt_attr_get_handle(attr) + 2,
.value_handle = bt_gatt_attr_value_handle(attr),
.value = BT_GATT_CCC_NOTIFY,
.notify = battery_level_notify_cb,
};
err = bt_gatt_subscribe(default_conn, &battery_level_notify_params);
if (err && err != -EALREADY) {
TEST_FAIL("Subscribe failed (err %d)\n", err);
} else {
LOG_DBG("Battery level [SUBSCRIBED]\n");
}
read_battery_level(attr);
}
static void subscribe_battery_level_status(const struct bt_gatt_attr *attr)
{
int err;
if (get_device_nbr() == 1) { /* One device for Indication */
battery_level_status_sub_params = (struct bt_gatt_subscribe_params){
/* In Zephyr, it is common practice for the CCC handle
* to be positioned two handles after the characteristic handle.
*/
.ccc_handle = bt_gatt_attr_get_handle(attr) + 2,
.value_handle = bt_gatt_attr_value_handle(attr),
.value = BT_GATT_CCC_INDICATE,
.notify = battery_level_status_indicate_cb,
};
} else { /* Other device for Notification */
battery_level_status_sub_params = (struct bt_gatt_subscribe_params){
.ccc_handle = bt_gatt_attr_get_handle(attr) + 2,
.value_handle = bt_gatt_attr_value_handle(attr),
.value = BT_GATT_CCC_NOTIFY,
.notify = battery_level_status_notify_cb,
};
}
err = bt_gatt_subscribe(default_conn, &battery_level_status_sub_params);
if (err && err != -EALREADY) {
TEST_FAIL("Subscribe failed (err %d)\n", err);
} else {
LOG_DBG("Battery level status [SUBSCRIBED]\n");
}
}
static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr,
struct bt_gatt_discover_params *params)
{
int err;
if (!attr) {
LOG_DBG("Discover complete\n");
memset(params, 0, sizeof(*params));
return BT_GATT_ITER_STOP;
}
LOG_DBG("[ATTRIBUTE] handle %u\n", attr->handle);
if (!bt_uuid_cmp(discover_params.uuid, BT_UUID_BAS)) {
LOG_DBG("Battery Service\n");
memcpy(&uuid, BT_UUID_BAS_BATTERY_LEVEL, sizeof(uuid));
discover_params.uuid = &uuid.uuid;
discover_params.start_handle = attr->handle + 1;
discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
err = bt_gatt_discover(conn, &discover_params);
if (err) {
TEST_FAIL("Discover failed (err %d)\n", err);
}
} else if (!bt_uuid_cmp(discover_params.uuid, BT_UUID_BAS_BATTERY_LEVEL)) {
LOG_DBG("Subscribe Battery Level Char\n");
subscribe_battery_level(attr);
memcpy(&uuid, BT_UUID_BAS_BATTERY_LEVEL_STATUS, sizeof(uuid));
discover_params.uuid = &uuid.uuid;
discover_params.start_handle = attr->handle + 1;
discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
err = bt_gatt_discover(conn, &discover_params);
if (err) {
TEST_FAIL("Discover failed (err %d)\n", err);
}
} else if (!bt_uuid_cmp(discover_params.uuid, BT_UUID_BAS_BATTERY_LEVEL_STATUS)) {
LOG_DBG("Subscribe Batterry Level Status Char\n");
subscribe_battery_level_status(attr);
}
return BT_GATT_ITER_STOP;
}
static void discover_bas_service(struct bt_conn *conn)
{
int err;
LOG_DBG("%s\n", __func__);
memcpy(&uuid, BT_UUID_BAS, sizeof(uuid));
discover_params.uuid = &uuid.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;
err = bt_gatt_discover(conn, &discover_params);
if (err) {
TEST_FAIL("Discover failed(err %d)\n", err);
return;
}
}
static void test_bas_central_main(void)
{
int err;
/* Mark test as in progress. */
TEST_START("central");
/* bk_sync_init only works between two devices in a simulation, with IDs 0 and 1. */
if (get_device_nbr() == 1) {
/* Initialize device sync library */
bk_sync_init();
}
err = bt_enable(NULL);
TEST_ASSERT(err == 0, "Can't enable Bluetooth (err %d)", err);
LOG_DBG("Bluetooth initialized\n");
err = bt_testlib_scan_find_name(&peer, CONFIG_BT_DEVICE_NAME);
TEST_ASSERT(!err, "Failed to start scan (err %d)", err);
/* Create a connection using that address */
err = bt_testlib_connect(&peer, &default_conn);
TEST_ASSERT(!err, "Failed to initiate connection (err %d)", err);
LOG_DBG("Connected");
discover_bas_service(default_conn);
if (get_device_nbr() == 1) {
WAIT_FOR_FLAG(indication_count_reached);
LOG_INF("Indication Count Reached!");
} else {
WAIT_FOR_FLAG(notification_count_reached);
LOG_INF("Notification Count Reached!");
}
/* bk_sync_send only works between two devices in a simulation, with IDs 0 and 1. */
if (get_device_nbr() == 1) {
bk_sync_send();
}
bst_result = Passed;
TEST_PASS("Central Test Passed");
}
static const struct bst_test_instance test_bas_central[] = {
{
.test_id = "central",
.test_descr =
"Battery Service test. It expects that a peripheral device can be found. "
"The test will pass if it can receive notifications and indications more "
"than the threshold set within 15 sec. ",
.test_pre_init_f = test_bas_central_init,
.test_tick_f = test_bas_central_tick,
.test_main_f = test_bas_central_main,
},
BSTEST_END_MARKER,
};
struct bst_test_list *test_bas_central_install(struct bst_test_list *tests)
{
tests = bst_add_tests(tests, test_bas_central);
return tests;
}

View file

@ -0,0 +1,22 @@
/*
* Copyright (c) 2024 Demant A/S
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "bstests.h"
extern struct bst_test_list *test_bas_central_install(struct bst_test_list *tests);
extern struct bst_test_list *test_bas_peripheral_install(struct bst_test_list *tests);
bst_test_install_t test_installers[] = {
test_bas_central_install,
test_bas_peripheral_install,
NULL,
};
int main(void)
{
bst_main();
return 0;
}

View file

@ -0,0 +1,183 @@
/*
* Copyright (c) 2024 Demant A/S
*
* 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 <zephyr/bluetooth/services/bas.h>
#include <zephyr/sys/byteorder.h>
#include "testlib/conn.h"
#include "testlib/scan.h"
#include "testlib/log_utils.h"
#include "babblekit/flags.h"
#include "babblekit/sync.h"
#include "babblekit/testcase.h"
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(bt_bsim_bas, CONFIG_BT_BAS_LOG_LEVEL);
static struct bt_conn *default_conn;
static struct k_work_delayable update_bas_char_work;
/*
* Battery Service test:
* We expect a central to connect to us.
*/
#define WAIT_TIME 10 /*seconds*/
extern enum bst_result_t bst_result;
static void test_bas_peripheral_init(void)
{
bst_ticker_set_next_tick_absolute(WAIT_TIME * 1e6);
bst_result = In_progress;
}
static void test_bas_peripheral_tick(bs_time_t HW_device_time)
{
/*
* If in WAIT_TIME seconds the testcase did not already pass
* (and finish) we consider it failed
*/
if (bst_result != Passed) {
TEST_FAIL("test_bas_peripheral failed (not passed after %i seconds)\n", WAIT_TIME);
}
}
static const struct bt_data 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_BAS_VAL)),
BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1),
};
static void connected(struct bt_conn *conn, uint8_t err)
{
if (err) {
TEST_FAIL("Connection failed (err 0x%02x)\n", err);
} else {
default_conn = bt_conn_ref(conn);
LOG_DBG("Peripheral Connected\n");
}
}
static void disconnected(struct bt_conn *conn, uint8_t reason)
{
LOG_DBG("Peripheral %s (reason 0x%02x)\n", __func__, reason);
if (default_conn) {
bt_conn_unref(default_conn);
default_conn = NULL;
}
}
static struct bt_conn_cb conn_callbacks = {
.connected = connected,
.disconnected = disconnected,
};
static void bt_ready(void)
{
int err;
LOG_DBG("Peripheral Bluetooth initialized\n");
err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0);
if (err) {
TEST_FAIL("Advertising failed to start (err %d)\n", err);
return;
}
LOG_DBG("Advertising successfully started");
}
static void update_bas_char(void)
{
LOG_DBG("[PERIPHERAL] setting battery level");
bt_bas_set_battery_level(90);
LOG_DBG("[PERIPHERAL] setting battery present");
bt_bas_bls_set_battery_present(BT_BAS_BLS_BATTERY_PRESENT);
LOG_DBG("[PERIPHERAL] setting battery charge level");
bt_bas_bls_set_battery_charge_level(BT_BAS_BLS_CHARGE_LEVEL_CRITICAL);
LOG_DBG("[PERIPHERAL] setting battery service required true");
bt_bas_bls_set_service_required(BT_BAS_BLS_SERVICE_REQUIRED_TRUE);
LOG_DBG("[PERIPHERAL] setting battery service charge type ");
bt_bas_bls_set_battery_charge_type(BT_BAS_BLS_CHARGE_TYPE_FLOAT);
}
/* Work handler function */
void update_bas_char_work_handler(struct k_work *work)
{
update_bas_char();
k_work_reschedule(&update_bas_char_work, K_SECONDS(1));
}
static void test_bas_peripheral_main(void)
{
int err;
bt_conn_cb_register(&conn_callbacks);
/* Mark test as in progress. */
TEST_START("peripheral");
/* Initialize device sync library */
bk_sync_init();
/* Initialize Bluetooth */
err = bt_enable(NULL);
TEST_ASSERT(err == 0, "Can't enable Bluetooth (err %d)", err);
LOG_DBG("Bluetooth initialized");
bt_ready();
/* Initialize the update bas char work handler */
k_work_init_delayable(&update_bas_char_work, update_bas_char_work_handler);
/* Schedule the update bas char work for delayed execution */
k_work_schedule(&update_bas_char_work, K_SECONDS(1));
/* Main thread waits for the sync signal from other device */
bk_sync_wait();
bst_result = Passed;
TEST_PASS_AND_EXIT("Peripheral Test Passed");
}
static const struct bst_test_instance test_bas_peripheral[] = {
{
.test_id = "peripheral",
.test_descr = "Battery Service test. It expects that a central device can be found "
"The test will pass if ind/ntf can be sent without crash. ",
.test_pre_init_f = test_bas_peripheral_init,
.test_tick_f = test_bas_peripheral_tick,
.test_main_f = test_bas_peripheral_main,
},
BSTEST_END_MARKER,
};
struct bst_test_list *test_bas_peripheral_install(struct bst_test_list *tests)
{
tests = bst_add_tests(tests, test_bas_peripheral);
return tests;
}

View file

@ -0,0 +1,29 @@
#!/usr/bin/env bash
# Copyright 2024 Demant A/S
# SPDX-License-Identifier: Apache-2.0
source ${ZEPHYR_BASE}/tests/bsim/sh_common.source
# Battery service test: a central connects to a peripheral and expects a
# indication/notification of BAS chars from peripheral
simulation_id="battery_service_test"
verbosity_level=2
cd ${BSIM_OUT_PATH}/bin
Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_samples_battery_service_prj_conf \
-v=${verbosity_level} -s=${simulation_id} -d=0 \
-testid=peripheral -rs=23
Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_samples_battery_service_prj_conf\
-v=${verbosity_level} -s=${simulation_id} -d=1 \
-testid=central -rs=6
Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_samples_battery_service_prj_conf\
-v=${verbosity_level} -s=${simulation_id} -d=2 \
-testid=central -rs=6
Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \
-D=3 -sim_length=10e6 $@
wait_for_background_jobs

View file

@ -37,5 +37,10 @@ app=tests/bsim/bluetooth/samples/central_hr_peripheral_hr \
extra_conf_file=${ZEPHYR_BASE}/samples/bluetooth/central_hr/prj.conf \
conf_overlay=${ZEPHYR_BASE}/samples/bluetooth/central_hr/overlay-phy_coded.conf \
compile
if [ ${BOARD} == "nrf52_bsim" ]; then
app=tests/bsim/bluetooth/samples/battery_service \
conf_file=prj.conf \
compile
fi
wait_for_background_jobs

View file

@ -2,5 +2,5 @@
# This file is used in CI to select which tests are run
tests/bsim/bluetooth/ll/conn/tests_scripts/basic_conn_encrypted_split_privacy.sh
tests/bsim/bluetooth/ll/bis/tests_scripts/broadcast_iso.sh
tests/bsim/bluetooth/samples/
tests/bsim/bluetooth/samples/central_hr_peripheral_hr/
tests/bsim/bluetooth/audio_samples/