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:
parent
b3ae323add
commit
baa5683e59
19 changed files with 1643 additions and 110 deletions
|
@ -1,4 +1,5 @@
|
||||||
/*
|
/*
|
||||||
|
* Copyright (c) 2024 Demant A/S
|
||||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||||
* Copyright (c) 2016 Intel Corporation
|
* Copyright (c) 2016 Intel Corporation
|
||||||
*
|
*
|
||||||
|
@ -19,11 +20,173 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <zephyr/sys/util.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Battery Level Status Characteristic flags.
|
||||||
|
*
|
||||||
|
* Enumeration for the flags indicating the presence
|
||||||
|
* of various fields in the Battery Level Status characteristic.
|
||||||
|
*/
|
||||||
|
enum bt_bas_bls_flags {
|
||||||
|
/** Bit indicating that the Battery Level Status identifier is present. */
|
||||||
|
BT_BAS_BLS_FLAG_IDENTIFIER_PRESENT = BIT(0),
|
||||||
|
|
||||||
|
/** Bit indicating that the Battery Level is present. */
|
||||||
|
BT_BAS_BLS_FLAG_BATTERY_LEVEL_PRESENT = BIT(1),
|
||||||
|
|
||||||
|
/** Bit indicating that additional status information is present. */
|
||||||
|
BT_BAS_BLS_FLAG_ADDITIONAL_STATUS_PRESENT = BIT(2),
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief Battery Present Status
|
||||||
|
*
|
||||||
|
* Enumeration for the presence of the battery.
|
||||||
|
*/
|
||||||
|
enum bt_bas_bls_battery_present {
|
||||||
|
/** Battery is not present. */
|
||||||
|
BT_BAS_BLS_BATTERY_NOT_PRESENT = 0,
|
||||||
|
|
||||||
|
/** Battery is present. */
|
||||||
|
BT_BAS_BLS_BATTERY_PRESENT = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief Wired External Power Source Status
|
||||||
|
*
|
||||||
|
* Enumeration for the status of the wired external power source.
|
||||||
|
*/
|
||||||
|
enum bt_bas_bls_wired_power_source {
|
||||||
|
/** Wired external power source is not connected. */
|
||||||
|
BT_BAS_BLS_WIRED_POWER_NOT_CONNECTED = 0,
|
||||||
|
|
||||||
|
/** Wired external power source is connected. */
|
||||||
|
BT_BAS_BLS_WIRED_POWER_CONNECTED = 1,
|
||||||
|
|
||||||
|
/** Wired external power source status is unknown. */
|
||||||
|
BT_BAS_BLS_WIRED_POWER_UNKNOWN = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief Wireless External Power Source Status
|
||||||
|
*
|
||||||
|
* Enumeration for the status of the wireless external power source.
|
||||||
|
*/
|
||||||
|
enum bt_bas_bls_wireless_power_source {
|
||||||
|
/** Wireless external power source is not connected. */
|
||||||
|
BT_BAS_BLS_WIRELESS_POWER_NOT_CONNECTED = 0,
|
||||||
|
|
||||||
|
/** Wireless external power source is connected. */
|
||||||
|
BT_BAS_BLS_WIRELESS_POWER_CONNECTED = 1,
|
||||||
|
|
||||||
|
/** Wireless external power source status is unknown. */
|
||||||
|
BT_BAS_BLS_WIRELESS_POWER_UNKNOWN = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief Battery Charge State
|
||||||
|
*
|
||||||
|
* Enumeration for the charge state of the battery.
|
||||||
|
*/
|
||||||
|
enum bt_bas_bls_battery_charge_state {
|
||||||
|
/** Battery charge state is unknown. */
|
||||||
|
BT_BAS_BLS_CHARGE_STATE_UNKNOWN = 0,
|
||||||
|
|
||||||
|
/** Battery is currently charging. */
|
||||||
|
BT_BAS_BLS_CHARGE_STATE_CHARGING = 1,
|
||||||
|
|
||||||
|
/** Battery is discharging actively. */
|
||||||
|
BT_BAS_BLS_CHARGE_STATE_DISCHARGING_ACTIVE = 2,
|
||||||
|
|
||||||
|
/** Battery is discharging but inactive. */
|
||||||
|
BT_BAS_BLS_CHARGE_STATE_DISCHARGING_INACTIVE = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief Battery Charge Level
|
||||||
|
*
|
||||||
|
* Enumeration for the level of charge in the battery.
|
||||||
|
*/
|
||||||
|
enum bt_bas_bls_battery_charge_level {
|
||||||
|
/** Battery charge level is unknown. */
|
||||||
|
BT_BAS_BLS_CHARGE_LEVEL_UNKNOWN = 0,
|
||||||
|
|
||||||
|
/** Battery charge level is good. */
|
||||||
|
BT_BAS_BLS_CHARGE_LEVEL_GOOD = 1,
|
||||||
|
|
||||||
|
/** Battery charge level is low. */
|
||||||
|
BT_BAS_BLS_CHARGE_LEVEL_LOW = 2,
|
||||||
|
|
||||||
|
/** Battery charge level is critical. */
|
||||||
|
BT_BAS_BLS_CHARGE_LEVEL_CRITICAL = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief Battery Charge Type
|
||||||
|
*
|
||||||
|
* Enumeration for the type of charging applied to the battery.
|
||||||
|
*/
|
||||||
|
enum bt_bas_bls_battery_charge_type {
|
||||||
|
/** Battery charge type is unknown or not charging. */
|
||||||
|
BT_BAS_BLS_CHARGE_TYPE_UNKNOWN = 0,
|
||||||
|
|
||||||
|
/** Battery is charged using constant current. */
|
||||||
|
BT_BAS_BLS_CHARGE_TYPE_CONSTANT_CURRENT = 1,
|
||||||
|
|
||||||
|
/** Battery is charged using constant voltage. */
|
||||||
|
BT_BAS_BLS_CHARGE_TYPE_CONSTANT_VOLTAGE = 2,
|
||||||
|
|
||||||
|
/** Battery is charged using trickle charge. */
|
||||||
|
BT_BAS_BLS_CHARGE_TYPE_TRICKLE = 3,
|
||||||
|
|
||||||
|
/** Battery is charged using float charge. */
|
||||||
|
BT_BAS_BLS_CHARGE_TYPE_FLOAT = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief Charging Fault Reason
|
||||||
|
*
|
||||||
|
* Enumeration for the reasons of charging faults.
|
||||||
|
*/
|
||||||
|
enum bt_bas_bls_charging_fault_reason {
|
||||||
|
/** No charging fault. */
|
||||||
|
BT_BAS_BLS_FAULT_REASON_NONE = 0,
|
||||||
|
|
||||||
|
/** Charging fault due to battery issue. */
|
||||||
|
BT_BAS_BLS_FAULT_REASON_BATTERY = BIT(0),
|
||||||
|
|
||||||
|
/** Charging fault due to external power source issue. */
|
||||||
|
BT_BAS_BLS_FAULT_REASON_EXTERNAL_POWER = BIT(1),
|
||||||
|
|
||||||
|
/** Charging fault for other reasons. */
|
||||||
|
BT_BAS_BLS_FAULT_REASON_OTHER = BIT(2)
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief Service Required Status
|
||||||
|
*
|
||||||
|
* Enumeration for whether the service is required.
|
||||||
|
*/
|
||||||
|
enum bt_bas_bls_service_required {
|
||||||
|
/** Service is not required. */
|
||||||
|
BT_BAS_BLS_SERVICE_REQUIRED_FALSE = 0,
|
||||||
|
|
||||||
|
/** Service is required. */
|
||||||
|
BT_BAS_BLS_SERVICE_REQUIRED_TRUE = 1,
|
||||||
|
|
||||||
|
/** Service requirement is unknown. */
|
||||||
|
BT_BAS_BLS_SERVICE_REQUIRED_UNKNOWN = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief Battery Fault Status
|
||||||
|
*
|
||||||
|
* Enumeration for the fault status of the battery.
|
||||||
|
*/
|
||||||
|
enum bt_bas_bls_battery_fault {
|
||||||
|
/** No battery fault. */
|
||||||
|
BT_BAS_BLS_BATTERY_FAULT_NO = 0,
|
||||||
|
|
||||||
|
/** Battery fault present. */
|
||||||
|
BT_BAS_BLS_BATTERY_FAULT_YES = 1
|
||||||
|
};
|
||||||
|
|
||||||
/** @brief Read battery level value.
|
/** @brief Read battery level value.
|
||||||
*
|
*
|
||||||
* Read the characteristic value of the battery level
|
* Read the characteristic value of the battery level
|
||||||
|
@ -43,6 +206,81 @@ uint8_t bt_bas_get_battery_level(void);
|
||||||
*/
|
*/
|
||||||
int bt_bas_set_battery_level(uint8_t level);
|
int bt_bas_set_battery_level(uint8_t level);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the battery present status.
|
||||||
|
*
|
||||||
|
* @param present The battery present status to set.
|
||||||
|
*/
|
||||||
|
void bt_bas_bls_set_battery_present(enum bt_bas_bls_battery_present present);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the wired external power source status.
|
||||||
|
*
|
||||||
|
* @param source The wired external power source status to set.
|
||||||
|
*/
|
||||||
|
void bt_bas_bls_set_wired_external_power_source(enum bt_bas_bls_wired_power_source source);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the wireless external power source status.
|
||||||
|
*
|
||||||
|
* @param source The wireless external power source status to set.
|
||||||
|
*/
|
||||||
|
void bt_bas_bls_set_wireless_external_power_source(enum bt_bas_bls_wireless_power_source source);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the battery charge state.
|
||||||
|
*
|
||||||
|
* @param state The battery charge state to set.
|
||||||
|
*/
|
||||||
|
void bt_bas_bls_set_battery_charge_state(enum bt_bas_bls_battery_charge_state state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the battery charge level.
|
||||||
|
*
|
||||||
|
* @param level The battery charge level to set.
|
||||||
|
*/
|
||||||
|
void bt_bas_bls_set_battery_charge_level(enum bt_bas_bls_battery_charge_level level);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the battery charge type.
|
||||||
|
*
|
||||||
|
* @param type The battery charge type to set.
|
||||||
|
*/
|
||||||
|
void bt_bas_bls_set_battery_charge_type(enum bt_bas_bls_battery_charge_type type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the charging fault reason.
|
||||||
|
*
|
||||||
|
* @param reason The charging fault reason to set.
|
||||||
|
*/
|
||||||
|
void bt_bas_bls_set_charging_fault_reason(enum bt_bas_bls_charging_fault_reason reason);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the identifier of the battery.
|
||||||
|
*
|
||||||
|
* kconfig_dep{CONFIG_BT_BAS_BLS_IDENTIFIER_PRESENT}
|
||||||
|
*
|
||||||
|
* @param identifier Identifier to set.
|
||||||
|
*/
|
||||||
|
void bt_bas_bls_set_identifier(uint16_t identifier);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the service required status.
|
||||||
|
*
|
||||||
|
* kconfig_dep{CONFIG_BT_BAS_BLS_ADDITIONAL_STATUS_PRESENT}
|
||||||
|
*
|
||||||
|
* @param value Service required status to set.
|
||||||
|
*/
|
||||||
|
void bt_bas_bls_set_service_required(enum bt_bas_bls_service_required value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the battery fault status.
|
||||||
|
*
|
||||||
|
* kconfig_dep{CONFIG_BT_BAS_BLS_ADDITIONAL_STATUS_PRESENT}
|
||||||
|
*
|
||||||
|
* @param value Battery fault status to set.
|
||||||
|
*/
|
||||||
|
void bt_bas_bls_set_battery_fault(enum bt_bas_bls_battery_fault value);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,4 +56,9 @@ CONFIG_BT_TBS_CLIENT_GTBS=y
|
||||||
CONFIG_BT_TBS_CLIENT_CCID=y
|
CONFIG_BT_TBS_CLIENT_CCID=y
|
||||||
CONFIG_BT_TBS_CLIENT_STATUS_FLAGS=y
|
CONFIG_BT_TBS_CLIENT_STATUS_FLAGS=y
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
CONFIG_LOG=y
|
CONFIG_LOG=y
|
||||||
|
|
|
@ -3,12 +3,14 @@
|
||||||
|
|
||||||
zephyr_sources_ifdef(CONFIG_BT_DIS dis.c)
|
zephyr_sources_ifdef(CONFIG_BT_DIS dis.c)
|
||||||
|
|
||||||
zephyr_sources_ifdef(CONFIG_BT_BAS bas.c)
|
|
||||||
|
|
||||||
zephyr_sources_ifdef(CONFIG_BT_HRS hrs.c)
|
zephyr_sources_ifdef(CONFIG_BT_HRS hrs.c)
|
||||||
|
|
||||||
zephyr_sources_ifdef(CONFIG_BT_TPS tps.c)
|
zephyr_sources_ifdef(CONFIG_BT_TPS tps.c)
|
||||||
|
|
||||||
|
if(CONFIG_BT_BAS)
|
||||||
|
add_subdirectory(bas)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(CONFIG_BT_OTS OR CONFIG_BT_OTS_CLIENT)
|
if(CONFIG_BT_OTS OR CONFIG_BT_OTS_CLIENT)
|
||||||
add_subdirectory(ots)
|
add_subdirectory(ots)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -8,8 +8,6 @@ menu "GATT Services"
|
||||||
|
|
||||||
rsource "Kconfig.dis"
|
rsource "Kconfig.dis"
|
||||||
|
|
||||||
rsource "Kconfig.bas"
|
|
||||||
|
|
||||||
rsource "Kconfig.hrs"
|
rsource "Kconfig.hrs"
|
||||||
|
|
||||||
rsource "Kconfig.tps"
|
rsource "Kconfig.tps"
|
||||||
|
@ -20,4 +18,6 @@ rsource "ias/Kconfig.ias"
|
||||||
|
|
||||||
rsource "ots/Kconfig"
|
rsource "ots/Kconfig"
|
||||||
|
|
||||||
|
rsource "bas/Kconfig.bas"
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
# Bluetooth GATT Battery service
|
|
||||||
|
|
||||||
# Copyright (c) 2018 Nordic Semiconductor ASA
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
config BT_BAS
|
|
||||||
bool "GATT Battery service"
|
|
|
@ -1,98 +0,0 @@
|
||||||
/** @file
|
|
||||||
* @brief GATT Battery Service
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
|
||||||
* Copyright (c) 2016 Intel Corporation
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <zephyr/init.h>
|
|
||||||
#include <zephyr/sys/__assert.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <zephyr/types.h>
|
|
||||||
|
|
||||||
#include <zephyr/bluetooth/bluetooth.h>
|
|
||||||
#include <zephyr/bluetooth/conn.h>
|
|
||||||
#include <zephyr/bluetooth/gatt.h>
|
|
||||||
#include <zephyr/bluetooth/uuid.h>
|
|
||||||
#include <zephyr/bluetooth/services/bas.h>
|
|
||||||
|
|
||||||
#define LOG_LEVEL CONFIG_BT_BAS_LOG_LEVEL
|
|
||||||
#include <zephyr/logging/log.h>
|
|
||||||
LOG_MODULE_REGISTER(bas);
|
|
||||||
|
|
||||||
static uint8_t battery_level = 100U;
|
|
||||||
|
|
||||||
static void blvl_ccc_cfg_changed(const struct bt_gatt_attr *attr,
|
|
||||||
uint16_t value)
|
|
||||||
{
|
|
||||||
ARG_UNUSED(attr);
|
|
||||||
|
|
||||||
bool notif_enabled = (value == BT_GATT_CCC_NOTIFY);
|
|
||||||
|
|
||||||
LOG_INF("BAS Notifications %s", notif_enabled ? "enabled" : "disabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t read_blvl(struct bt_conn *conn,
|
|
||||||
const struct bt_gatt_attr *attr, void *buf,
|
|
||||||
uint16_t len, uint16_t offset)
|
|
||||||
{
|
|
||||||
uint8_t lvl8 = battery_level;
|
|
||||||
|
|
||||||
return bt_gatt_attr_read(conn, attr, buf, len, offset, &lvl8,
|
|
||||||
sizeof(lvl8));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Constant values from the Assigned Numbers specification:
|
|
||||||
* https://www.bluetooth.com/wp-content/uploads/Files/Specification/Assigned_Numbers.pdf?id=89
|
|
||||||
*/
|
|
||||||
static const struct bt_gatt_cpf level_cpf = {
|
|
||||||
.format = 0x04, /* uint8 */
|
|
||||||
.exponent = 0x0,
|
|
||||||
.unit = 0x27AD, /* Percentage */
|
|
||||||
.name_space = 0x01, /* Bluetooth SIG */
|
|
||||||
.description = 0x0106, /* "main" */
|
|
||||||
};
|
|
||||||
|
|
||||||
BT_GATT_SERVICE_DEFINE(bas,
|
|
||||||
BT_GATT_PRIMARY_SERVICE(BT_UUID_BAS),
|
|
||||||
BT_GATT_CHARACTERISTIC(BT_UUID_BAS_BATTERY_LEVEL,
|
|
||||||
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
|
|
||||||
BT_GATT_PERM_READ, read_blvl, NULL,
|
|
||||||
&battery_level),
|
|
||||||
BT_GATT_CCC(blvl_ccc_cfg_changed,
|
|
||||||
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
|
|
||||||
BT_GATT_CPF(&level_cpf),
|
|
||||||
);
|
|
||||||
|
|
||||||
static int bas_init(void)
|
|
||||||
{
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t bt_bas_get_battery_level(void)
|
|
||||||
{
|
|
||||||
return battery_level;
|
|
||||||
}
|
|
||||||
|
|
||||||
int bt_bas_set_battery_level(uint8_t level)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (level > 100U) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
battery_level = level;
|
|
||||||
|
|
||||||
rc = bt_gatt_notify(NULL, &bas.attrs[1], &level, sizeof(level));
|
|
||||||
|
|
||||||
return rc == -ENOTCONN ? 0 : rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
SYS_INIT(bas_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
|
|
3
subsys/bluetooth/services/bas/CMakeLists.txt
Normal file
3
subsys/bluetooth/services/bas/CMakeLists.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
zephyr_sources_ifdef(CONFIG_BT_BAS bas.c)
|
||||||
|
zephyr_sources_ifdef(CONFIG_BT_BAS_BLS bas_bls.c)
|
30
subsys/bluetooth/services/bas/Kconfig.bas
Normal file
30
subsys/bluetooth/services/bas/Kconfig.bas
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# Bluetooth GATT Battery service
|
||||||
|
|
||||||
|
# Copyright (c) 2018 Nordic Semiconductor ASA
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
config BT_BAS
|
||||||
|
bool "GATT Battery service"
|
||||||
|
|
||||||
|
config BT_BAS_BLS
|
||||||
|
bool "Battery Level Status"
|
||||||
|
help
|
||||||
|
Enable this option to include Battery Level Status Characteristic.
|
||||||
|
|
||||||
|
if BT_BAS_BLS
|
||||||
|
|
||||||
|
config BT_BAS_BLS_IDENTIFIER_PRESENT
|
||||||
|
bool "Battery Level Identifier Present"
|
||||||
|
help
|
||||||
|
Enable this option if the Battery Level Identifier is present.
|
||||||
|
|
||||||
|
config BT_BAS_BLS_BATTERY_LEVEL_PRESENT
|
||||||
|
bool "Battery Level Present"
|
||||||
|
help
|
||||||
|
Enable this option if the Battery Level is present.
|
||||||
|
|
||||||
|
config BT_BAS_BLS_ADDITIONAL_STATUS_PRESENT
|
||||||
|
bool "Additional Battery Status Present"
|
||||||
|
help
|
||||||
|
Enable this option if Additional Battery Status information is present.
|
||||||
|
endif
|
134
subsys/bluetooth/services/bas/bas.c
Normal file
134
subsys/bluetooth/services/bas/bas.c
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
/** @file
|
||||||
|
* @brief GATT Battery Service
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Demant A/S
|
||||||
|
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||||
|
* Copyright (c) 2016 Intel Corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <zephyr/init.h>
|
||||||
|
#include <zephyr/sys/__assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <zephyr/types.h>
|
||||||
|
#include <zephyr/sys/util.h>
|
||||||
|
#include <zephyr/sys/util_macro.h>
|
||||||
|
|
||||||
|
#include <zephyr/bluetooth/bluetooth.h>
|
||||||
|
#include <zephyr/bluetooth/conn.h>
|
||||||
|
#include <zephyr/bluetooth/gatt.h>
|
||||||
|
#include <zephyr/bluetooth/uuid.h>
|
||||||
|
#include <zephyr/bluetooth/services/bas.h>
|
||||||
|
#include "bas_internal.h"
|
||||||
|
|
||||||
|
#define LOG_LEVEL CONFIG_BT_BAS_LOG_LEVEL
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
LOG_MODULE_REGISTER(bas, CONFIG_BT_BAS_LOG_LEVEL);
|
||||||
|
|
||||||
|
static uint8_t battery_level = 100U;
|
||||||
|
|
||||||
|
static void blvl_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(attr);
|
||||||
|
|
||||||
|
bool notif_enabled = (value == BT_GATT_CCC_NOTIFY);
|
||||||
|
|
||||||
|
LOG_INF("BAS Notifications %s", notif_enabled ? "enabled" : "disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_BAS_BLS)
|
||||||
|
static void blvl_status_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(attr);
|
||||||
|
|
||||||
|
bool notif_enabled = (value == BT_GATT_CCC_NOTIFY);
|
||||||
|
bool ind_enabled = (value == BT_GATT_CCC_INDICATE);
|
||||||
|
|
||||||
|
LOG_INF("BAS Notifications %s", notif_enabled ? "enabled" : "disabled");
|
||||||
|
LOG_INF("BAS Indications %s", ind_enabled ? "enabled" : "disabled");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static ssize_t read_blvl(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
|
||||||
|
uint16_t len, uint16_t offset)
|
||||||
|
{
|
||||||
|
uint8_t lvl8 = battery_level;
|
||||||
|
|
||||||
|
return bt_gatt_attr_read(conn, attr, buf, len, offset, &lvl8, sizeof(lvl8));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Constant values from the Assigned Numbers specification:
|
||||||
|
* https://www.bluetooth.com/wp-content/uploads/Files/Specification/Assigned_Numbers.pdf?id=89
|
||||||
|
*/
|
||||||
|
static const struct bt_gatt_cpf level_cpf = {
|
||||||
|
.format = 0x04, /* uint8 */
|
||||||
|
.exponent = 0x0,
|
||||||
|
.unit = 0x27AD, /* Percentage */
|
||||||
|
.name_space = 0x01, /* Bluetooth SIG */
|
||||||
|
.description = 0x0106, /* "main" */
|
||||||
|
};
|
||||||
|
|
||||||
|
BT_GATT_SERVICE_DEFINE(
|
||||||
|
bas, BT_GATT_PRIMARY_SERVICE(BT_UUID_BAS),
|
||||||
|
BT_GATT_CHARACTERISTIC(BT_UUID_BAS_BATTERY_LEVEL, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
|
||||||
|
BT_GATT_PERM_READ, read_blvl, NULL, NULL),
|
||||||
|
BT_GATT_CCC(blvl_ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
|
||||||
|
BT_GATT_CPF(&level_cpf),
|
||||||
|
#if defined(CONFIG_BT_BAS_BLS)
|
||||||
|
BT_GATT_CHARACTERISTIC(BT_UUID_BAS_BATTERY_LEVEL_STATUS,
|
||||||
|
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY | BT_GATT_CHRC_INDICATE,
|
||||||
|
BT_GATT_PERM_READ, bt_bas_bls_read_blvl_status, NULL, NULL),
|
||||||
|
BT_GATT_CCC(blvl_status_ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
|
||||||
|
static int bas_init(void)
|
||||||
|
{
|
||||||
|
if (IS_ENABLED(CONFIG_BT_BAS_BLS)) {
|
||||||
|
/* Initialize the Battery Level Status Module */
|
||||||
|
bt_bas_bls_init();
|
||||||
|
if (IS_ENABLED(CONFIG_BT_BAS_BLS_IDENTIFIER_PRESENT)) {
|
||||||
|
/* Set the identifier only if BT_BAS_BLS_IDENTIFIER_PRESENT is defined */
|
||||||
|
bt_bas_bls_set_identifier(level_cpf.description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t bt_bas_get_battery_level(void)
|
||||||
|
{
|
||||||
|
return battery_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bt_bas_set_battery_level(uint8_t level)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (level > 100U) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
battery_level = level;
|
||||||
|
|
||||||
|
rc = bt_gatt_notify(NULL, &bas.attrs[1], &level, sizeof(level));
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_BT_BAS_BLS_BATTERY_LEVEL_PRESENT)) {
|
||||||
|
bt_bas_bls_set_battery_level(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc == -ENOTCONN ? 0 : rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct bt_gatt_attr *bt_bas_get_bas_attr(uint16_t index)
|
||||||
|
{
|
||||||
|
if (index < bas.attr_count) {
|
||||||
|
return &bas.attrs[index];
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SYS_INIT(bas_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
|
236
subsys/bluetooth/services/bas/bas_bls.c
Normal file
236
subsys/bluetooth/services/bas/bas_bls.c
Normal file
|
@ -0,0 +1,236 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Demant A/S
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/sys/byteorder.h>
|
||||||
|
#include <zephyr/bluetooth/services/bas.h>
|
||||||
|
#include <zephyr/bluetooth/gatt.h>
|
||||||
|
#include "bas_internal.h"
|
||||||
|
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
LOG_MODULE_DECLARE(bas, CONFIG_BT_BAS_LOG_LEVEL);
|
||||||
|
|
||||||
|
/* The battery level status of a battery. */
|
||||||
|
static struct bt_bas_bls bls;
|
||||||
|
|
||||||
|
#define BT_BAS_IDX_BATT_LVL_STATUS_CHAR_VAL 6
|
||||||
|
|
||||||
|
/* Notify/Indicate all connections */
|
||||||
|
static struct bt_gatt_indicate_params ind_params;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bitfield structure: Power State
|
||||||
|
*
|
||||||
|
* - Bits 0: Battery Present
|
||||||
|
* - Bits 1–2: Wired External Power Source Connected
|
||||||
|
* - Bits 3–4: Wireless External Power Source Connected
|
||||||
|
* - Bits 5–6: Battery Charge State
|
||||||
|
* - Bits 7–8: Battery Charge Level
|
||||||
|
* - Bits 9–11: Charging Type
|
||||||
|
* - Bits 12–14: Charging Fault Reason
|
||||||
|
* - Bit 15: RFU
|
||||||
|
*
|
||||||
|
* For detailed specification, refer to:
|
||||||
|
* https://bitbucket.org/bluetooth-SIG/public/src/main/gss/
|
||||||
|
* org.bluetooth.characteristic.battery_level_status.yaml
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define BATTERY_SHIFT 0
|
||||||
|
#define WIRED_POWER_SHIFT 1
|
||||||
|
#define WIRELESS_POWER_SHIFT 3
|
||||||
|
#define BATTERY_CHARGE_STATE_SHIFT 5
|
||||||
|
#define BATTERY_CHARGE_LEVEL_SHIFT 7
|
||||||
|
#define BATTERY_CHARGE_TYPE_SHIFT 9
|
||||||
|
#define CHARGING_FAULT_SHIFT 12
|
||||||
|
|
||||||
|
#define BATTERY_MASK (BIT_MASK(1) << BATTERY_SHIFT)
|
||||||
|
#define WIRED_POWER_MASK (BIT_MASK(2) << WIRED_POWER_SHIFT)
|
||||||
|
#define WIRELESS_POWER_MASK (BIT_MASK(2) << WIRELESS_POWER_SHIFT)
|
||||||
|
#define BATTERY_CHARGE_STATE_MASK (BIT_MASK(2) << BATTERY_CHARGE_STATE_SHIFT)
|
||||||
|
#define BATTERY_CHARGE_LEVEL_MASK (BIT_MASK(2) << BATTERY_CHARGE_LEVEL_SHIFT)
|
||||||
|
#define BATTERY_CHARGE_TYPE_MASK (BIT_MASK(3) << BATTERY_CHARGE_TYPE_SHIFT)
|
||||||
|
#define CHARGING_FAULT_MASK (BIT_MASK(3) << CHARGING_FAULT_SHIFT)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bitfield structure: Additional Status
|
||||||
|
*
|
||||||
|
* - Bits 0–1: Service Required
|
||||||
|
* - Bit 2: Battery Fault
|
||||||
|
* - Bits 3–7: Reserved
|
||||||
|
*/
|
||||||
|
#define SERVICE_REQUIRED_SHIFT 0
|
||||||
|
#define BATTERY_FAULT_SHIFT 2
|
||||||
|
|
||||||
|
#define SERVICE_REQUIRED_MASK (BIT_MASK(2) << SERVICE_REQUIRED_SHIFT)
|
||||||
|
#define BATTERY_FAULT_MASK (BIT_MASK(1) << BATTERY_FAULT_SHIFT)
|
||||||
|
|
||||||
|
void bt_bas_bls_init(void)
|
||||||
|
{
|
||||||
|
LOG_DBG("Initialise BAS Battery Level Status Module");
|
||||||
|
|
||||||
|
bls.flags = 0;
|
||||||
|
bls.power_state = 0;
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_BAS_BLS_IDENTIFIER_PRESENT)
|
||||||
|
/* Set identifier flag */
|
||||||
|
bls.flags |= BT_BAS_BLS_FLAG_IDENTIFIER_PRESENT;
|
||||||
|
bls.identifier = 0;
|
||||||
|
#endif /* CONFIG_BT_BAS_BLS_IDENTIFIER_PRESENT */
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_BAS_BLS_BATTERY_LEVEL_PRESENT)
|
||||||
|
/* Set battery level flag */
|
||||||
|
bls.flags |= BT_BAS_BLS_FLAG_BATTERY_LEVEL_PRESENT;
|
||||||
|
bls.battery_level = bt_bas_get_battery_level();
|
||||||
|
#endif /* CONFIG_BT_BAS_BLS_BATTERY_LEVEL_PRESENT */
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_BAS_BLS_ADDITIONAL_STATUS_PRESENT)
|
||||||
|
/* Set additional status flag */
|
||||||
|
bls.flags |= BT_BAS_BLS_FLAG_ADDITIONAL_STATUS_PRESENT;
|
||||||
|
bls.additional_status = 0;
|
||||||
|
#endif /* CONFIG_BT_BAS_BLS_ADDITIONAL_STATUS_PRESENT */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void indicate_cb(struct bt_conn *conn, struct bt_gatt_indicate_params *params, uint8_t err)
|
||||||
|
{
|
||||||
|
if (err != 0) {
|
||||||
|
LOG_DBG("Indication failed with error %d\n", err);
|
||||||
|
} else {
|
||||||
|
LOG_DBG("Indication sent successfully\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bt_bas_bls_update_battery_level_status(void)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
const struct bt_gatt_attr *attr = bt_bas_get_bas_attr(BT_BAS_IDX_BATT_LVL_STATUS_CHAR_VAL);
|
||||||
|
|
||||||
|
if (attr) {
|
||||||
|
const struct bt_bas_bls le_battery_level_status = {
|
||||||
|
.flags = bls.flags,
|
||||||
|
.power_state = sys_cpu_to_le16(bls.power_state),
|
||||||
|
#if defined(CONFIG_BT_BAS_BLS_IDENTIFIER_PRESENT)
|
||||||
|
.identifier = sys_cpu_to_le16(bls.identifier),
|
||||||
|
#endif
|
||||||
|
#if defined(CONFIG_BT_BAS_BLS_BATTERY_LEVEL_PRESENT)
|
||||||
|
.battery_level = bls.battery_level,
|
||||||
|
#endif
|
||||||
|
#if defined(CONFIG_BT_BAS_BLS_ADDITIONAL_STATUS_PRESENT)
|
||||||
|
.additional_status = bls.additional_status,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Notify/Indicate all connections */
|
||||||
|
ind_params.attr = attr;
|
||||||
|
ind_params.data = &le_battery_level_status;
|
||||||
|
ind_params.len = sizeof(le_battery_level_status);
|
||||||
|
ind_params.func = indicate_cb;
|
||||||
|
err = bt_gatt_indicate(NULL, &ind_params);
|
||||||
|
if (err) {
|
||||||
|
LOG_DBG("Failed to send ntf/ind to all connections (err %d)\n", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t bt_bas_bls_read_blvl_status(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||||
|
void *buf, uint16_t len, uint16_t offset)
|
||||||
|
{
|
||||||
|
const struct bt_bas_bls le_battery_level_status = {
|
||||||
|
.flags = bls.flags,
|
||||||
|
.power_state = sys_cpu_to_le16(bls.power_state),
|
||||||
|
#if defined(CONFIG_BT_BAS_BLS_IDENTIFIER_PRESENT)
|
||||||
|
.identifier = sys_cpu_to_le16(bls.identifier),
|
||||||
|
#endif
|
||||||
|
#if defined(CONFIG_BT_BAS_BLS_BATTERY_LEVEL_PRESENT)
|
||||||
|
.battery_level = bls.battery_level,
|
||||||
|
#endif
|
||||||
|
#if defined(CONFIG_BT_BAS_BLS_ADDITIONAL_STATUS_PRESENT)
|
||||||
|
.additional_status = bls.additional_status,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
return bt_gatt_attr_read(conn, attr, buf, len, offset, &le_battery_level_status,
|
||||||
|
sizeof(le_battery_level_status));
|
||||||
|
}
|
||||||
|
|
||||||
|
void bt_bas_bls_set_battery_present(enum bt_bas_bls_battery_present present)
|
||||||
|
{
|
||||||
|
bls.power_state &= ~BATTERY_MASK;
|
||||||
|
bls.power_state |= (present << BATTERY_SHIFT) & BATTERY_MASK;
|
||||||
|
bt_bas_bls_update_battery_level_status();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bt_bas_bls_set_wired_external_power_source(enum bt_bas_bls_wired_power_source source)
|
||||||
|
{
|
||||||
|
bls.power_state &= ~WIRED_POWER_MASK;
|
||||||
|
bls.power_state |= (source << WIRED_POWER_SHIFT) & WIRED_POWER_MASK;
|
||||||
|
bt_bas_bls_update_battery_level_status();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bt_bas_bls_set_wireless_external_power_source(enum bt_bas_bls_wireless_power_source source)
|
||||||
|
{
|
||||||
|
bls.power_state &= ~WIRELESS_POWER_MASK;
|
||||||
|
bls.power_state |= (source << WIRELESS_POWER_SHIFT) & WIRELESS_POWER_MASK;
|
||||||
|
bt_bas_bls_update_battery_level_status();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bt_bas_bls_set_battery_charge_state(enum bt_bas_bls_battery_charge_state state)
|
||||||
|
{
|
||||||
|
bls.power_state &= ~BATTERY_CHARGE_STATE_MASK;
|
||||||
|
bls.power_state |= (state << BATTERY_CHARGE_STATE_SHIFT) & BATTERY_CHARGE_STATE_MASK;
|
||||||
|
bt_bas_bls_update_battery_level_status();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bt_bas_bls_set_battery_charge_level(enum bt_bas_bls_battery_charge_level level)
|
||||||
|
{
|
||||||
|
bls.power_state &= ~BATTERY_CHARGE_LEVEL_MASK;
|
||||||
|
bls.power_state |= (level << BATTERY_CHARGE_LEVEL_SHIFT) & BATTERY_CHARGE_LEVEL_MASK;
|
||||||
|
bt_bas_bls_update_battery_level_status();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bt_bas_bls_set_battery_charge_type(enum bt_bas_bls_battery_charge_type type)
|
||||||
|
{
|
||||||
|
bls.power_state &= ~BATTERY_CHARGE_TYPE_MASK;
|
||||||
|
bls.power_state |= (type << BATTERY_CHARGE_TYPE_SHIFT) & BATTERY_CHARGE_TYPE_MASK;
|
||||||
|
bt_bas_bls_update_battery_level_status();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bt_bas_bls_set_charging_fault_reason(enum bt_bas_bls_charging_fault_reason reason)
|
||||||
|
{
|
||||||
|
bls.power_state &= ~CHARGING_FAULT_MASK;
|
||||||
|
bls.power_state |= (reason << CHARGING_FAULT_SHIFT) & CHARGING_FAULT_MASK;
|
||||||
|
bt_bas_bls_update_battery_level_status();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_BAS_BLS_BATTERY_LEVEL_PRESENT)
|
||||||
|
void bt_bas_bls_set_battery_level(uint8_t level)
|
||||||
|
{
|
||||||
|
bls.battery_level = level;
|
||||||
|
bt_bas_bls_update_battery_level_status();
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_BT_BAS_BLS_BATTERY_LEVEL_PRESENT */
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_BAS_BLS_IDENTIFIER_PRESENT)
|
||||||
|
void bt_bas_bls_set_identifier(uint16_t identifier)
|
||||||
|
{
|
||||||
|
bls.identifier = sys_cpu_to_le16(identifier);
|
||||||
|
bt_bas_bls_update_battery_level_status();
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_BT_BAS_BLS_IDENTIFIER_PRESENT */
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_BAS_BLS_ADDITIONAL_STATUS_PRESENT)
|
||||||
|
void bt_bas_bls_set_service_required(enum bt_bas_bls_service_required value)
|
||||||
|
{
|
||||||
|
bls.additional_status &= ~SERVICE_REQUIRED_MASK;
|
||||||
|
bls.additional_status |= (value << SERVICE_REQUIRED_SHIFT) & SERVICE_REQUIRED_MASK;
|
||||||
|
bt_bas_bls_update_battery_level_status();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bt_bas_bls_set_battery_fault(enum bt_bas_bls_battery_fault value)
|
||||||
|
{
|
||||||
|
bls.additional_status &= ~BATTERY_FAULT_MASK;
|
||||||
|
bls.additional_status |= (value << BATTERY_FAULT_SHIFT) & BATTERY_FAULT_MASK;
|
||||||
|
bt_bas_bls_update_battery_level_status();
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_BT_BAS_BLS_ADDITIONAL_STATUS_PRESENT */
|
146
subsys/bluetooth/services/bas/bas_internal.h
Normal file
146
subsys/bluetooth/services/bas/bas_internal.h
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Demant A/S
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BT_BAS_INTERNAL_H_
|
||||||
|
#define BT_BAS_INTERNAL_H_
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <zephyr/sys/atomic.h>
|
||||||
|
#include <zephyr/types.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Battery level status structure definition.
|
||||||
|
*/
|
||||||
|
struct bt_bas_bls {
|
||||||
|
|
||||||
|
/** @brief Flags Field
|
||||||
|
*
|
||||||
|
* The values of this field are defined below.
|
||||||
|
*
|
||||||
|
* - bit 0: Identifier Present
|
||||||
|
* - Indicates whether the identifier field is present.
|
||||||
|
* - bit 1: Battery Level Present
|
||||||
|
* - Indicates whether the battery level field is present.
|
||||||
|
* - bit 2: Additional Status Present
|
||||||
|
* - Indicates whether the additional status field is present.
|
||||||
|
* - bit 3–7: RFU (Reserved for Future Use)
|
||||||
|
* - Reserved bits for future use; should be set to zero.
|
||||||
|
*/
|
||||||
|
uint8_t flags;
|
||||||
|
|
||||||
|
/** @brief Power State
|
||||||
|
*
|
||||||
|
* The values of this field are defined below.
|
||||||
|
*
|
||||||
|
* - bit 0: Battery Present
|
||||||
|
* - 0 = No
|
||||||
|
* - 1 = Yes
|
||||||
|
* - bit 1–2: Wired External Power Source Connected
|
||||||
|
* - 0 = No
|
||||||
|
* - 1 = Yes
|
||||||
|
* - 2 = Unknown
|
||||||
|
* - 3 = RFU
|
||||||
|
* - bit 3–4: Wireless External Power Source Connected
|
||||||
|
* - 0 = No
|
||||||
|
* - 1 = Yes
|
||||||
|
* - 2 = Unknown
|
||||||
|
* - 3 = RFU
|
||||||
|
* - bit 5–6: Battery Charge State
|
||||||
|
* - 0 = Unknown
|
||||||
|
* - 1 = Charging
|
||||||
|
* - 2 = Discharging: Active
|
||||||
|
* - 3 = Discharging: Inactive
|
||||||
|
* - bit 7–8: Battery Charge Level
|
||||||
|
* - 0 = Unknown
|
||||||
|
* - 1 = Good
|
||||||
|
* - 2 = Low
|
||||||
|
* - 3 = Critical
|
||||||
|
* - bit 9–11: Charging Type
|
||||||
|
* - 0 = Unknown or Not Charging
|
||||||
|
* - 1 = Constant Current
|
||||||
|
* - 2 = Constant Voltage
|
||||||
|
* - 3 = Trickle
|
||||||
|
* - 4 = Float
|
||||||
|
* - 5–7 = RFU
|
||||||
|
* - bit 12–14: Charging Fault Reason
|
||||||
|
* - Bit 12: Battery
|
||||||
|
* - Bit 13: External Power source
|
||||||
|
* - Bit 14: Other
|
||||||
|
* - bit 15: RFU
|
||||||
|
*/
|
||||||
|
uint16_t power_state;
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_BAS_BLS_IDENTIFIER_PRESENT)
|
||||||
|
/** Identifier for the battery, range 0x0000 to 0xFFFF.*/
|
||||||
|
uint16_t identifier;
|
||||||
|
#endif /* CONFIG_BT_BAS_BLS_IDENTIFIER_PRESENT */
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_BAS_BLS_BATTERY_LEVEL_PRESENT)
|
||||||
|
/** Current battery level */
|
||||||
|
uint8_t battery_level;
|
||||||
|
#endif /* CONFIG_BT_BAS_BLS_BATTERY_LEVEL_PRESENT */
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_BAS_BLS_ADDITIONAL_STATUS_PRESENT)
|
||||||
|
|
||||||
|
/** @brief Additional Status
|
||||||
|
*
|
||||||
|
* The values of this field are defined below.
|
||||||
|
*
|
||||||
|
* - bit 0–1: Service Required
|
||||||
|
* - 0 = False
|
||||||
|
* - 1 = True
|
||||||
|
* - 2 = Unknown
|
||||||
|
* - 3 = RFU
|
||||||
|
* - bit 2: Battery Fault
|
||||||
|
* - 0 = False or Unknown
|
||||||
|
* - 1 = Yes
|
||||||
|
* - bit 3–7: RFU
|
||||||
|
*/
|
||||||
|
uint8_t additional_status;
|
||||||
|
|
||||||
|
#endif /* CONFIG_BT_BAS_BLS_ADDITIONAL_STATUS_PRESENT */
|
||||||
|
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the Battery Level Status Module.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void bt_bas_bls_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the battery level characteristic value.
|
||||||
|
*
|
||||||
|
* @param battery_level The new battery level value in percent (0-100).
|
||||||
|
*/
|
||||||
|
void bt_bas_bls_set_battery_level(uint8_t battery_level);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read the Battery Level Status characteristic.
|
||||||
|
*
|
||||||
|
* @param conn Pointer to the Bluetooth connection object representing the client requesting
|
||||||
|
* the characteristic.
|
||||||
|
* @param attr Pointer to the GATT attribute representing the Battery Level Status characteristic.
|
||||||
|
* @param buf Buffer to store the read value.
|
||||||
|
* @param len Length of the buffer.
|
||||||
|
* @param offset Offset within the characteristic value to start reading.
|
||||||
|
*
|
||||||
|
* @return The number of bytes read and sent to the client, or a negative error code on failure.
|
||||||
|
*/
|
||||||
|
ssize_t bt_bas_bls_read_blvl_status(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||||
|
void *buf, uint16_t len, uint16_t offset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retrieve the Bluetooth GATT attribute for the BAS service by index.
|
||||||
|
*
|
||||||
|
* @param index The index of the attribute within the BAS service.
|
||||||
|
*
|
||||||
|
* @return Pointer to the Bluetooth GATT attribute if the index is valid,
|
||||||
|
* otherwise NULL if the index is out of bounds.
|
||||||
|
*/
|
||||||
|
const struct bt_gatt_attr *bt_bas_get_bas_attr(uint16_t index);
|
||||||
|
|
||||||
|
#endif /* BT_BAS_INTERNAL_H_ */
|
29
tests/bsim/bluetooth/samples/battery_service/CMakeLists.txt
Normal file
29
tests/bsim/bluetooth/samples/battery_service/CMakeLists.txt
Normal 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/
|
||||||
|
)
|
14
tests/bsim/bluetooth/samples/battery_service/prj.conf
Normal file
14
tests/bsim/bluetooth/samples/battery_service/prj.conf
Normal 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
|
562
tests/bsim/bluetooth/samples/battery_service/src/central_test.c
Normal file
562
tests/bsim/bluetooth/samples/battery_service/src/central_test.c
Normal 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;
|
||||||
|
}
|
22
tests/bsim/bluetooth/samples/battery_service/src/main.c
Normal file
22
tests/bsim/bluetooth/samples/battery_service/src/main.c
Normal 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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
29
tests/bsim/bluetooth/samples/battery_service/tests_scripts/bas.sh
Executable file
29
tests/bsim/bluetooth/samples/battery_service/tests_scripts/bas.sh
Executable 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
|
|
@ -37,5 +37,10 @@ app=tests/bsim/bluetooth/samples/central_hr_peripheral_hr \
|
||||||
extra_conf_file=${ZEPHYR_BASE}/samples/bluetooth/central_hr/prj.conf \
|
extra_conf_file=${ZEPHYR_BASE}/samples/bluetooth/central_hr/prj.conf \
|
||||||
conf_overlay=${ZEPHYR_BASE}/samples/bluetooth/central_hr/overlay-phy_coded.conf \
|
conf_overlay=${ZEPHYR_BASE}/samples/bluetooth/central_hr/overlay-phy_coded.conf \
|
||||||
compile
|
compile
|
||||||
|
if [ ${BOARD} == "nrf52_bsim" ]; then
|
||||||
|
app=tests/bsim/bluetooth/samples/battery_service \
|
||||||
|
conf_file=prj.conf \
|
||||||
|
compile
|
||||||
|
fi
|
||||||
|
|
||||||
wait_for_background_jobs
|
wait_for_background_jobs
|
||||||
|
|
|
@ -2,5 +2,5 @@
|
||||||
# This file is used in CI to select which tests are run
|
# 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/conn/tests_scripts/basic_conn_encrypted_split_privacy.sh
|
||||||
tests/bsim/bluetooth/ll/bis/tests_scripts/broadcast_iso.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/
|
tests/bsim/bluetooth/audio_samples/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue