Skip to content

Commit

Permalink
bluetooth: BAS: add battery critical status char to bas service
Browse files Browse the repository at this point in the history
Added the battery critical status char to bas service
as per bas_1.1 spec. Updated BSIM test for BAS service
to test the INDs of BAS critical characteristic.

Signed-off-by: Nithin Ramesh Myliattil <niym@demant.com>
  • Loading branch information
niym-ot committed Oct 21, 2024
1 parent 091c666 commit f22209d
Show file tree
Hide file tree
Showing 10 changed files with 319 additions and 28 deletions.
14 changes: 14 additions & 0 deletions include/zephyr/bluetooth/services/bas.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,20 @@
extern "C" {
#endif

/**
* @brief Battery Critical Status Characteristic flags.
*
* Enumeration for the flags indicating the presence
* of various fields in the Battery Critical Status characteristic.
*/
enum bt_bas_bcs_flags {
/** Battery Critical Status Bit 0: Critical Power State */
BT_BAS_BCS_BATTERY_CRITICAL_STATE = BIT(0),

/** Battery Critical Status Bit 1: Immediate Service Required */
BT_BAS_BCS_IMMEDIATE_SERVICE_REQUIRED = BIT(1),
};

/**
* @brief Battery Level Status Characteristic flags.
*
Expand Down
1 change: 1 addition & 0 deletions subsys/bluetooth/services/bas/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: Apache-2.0
zephyr_sources_ifdef(CONFIG_BT_BAS bas.c)
zephyr_sources_ifdef(CONFIG_BT_BAS_BLS bas_bls.c)
zephyr_sources_ifdef(CONFIG_BT_BAS_BCS bas_bcs.c)
5 changes: 5 additions & 0 deletions subsys/bluetooth/services/bas/Kconfig.bas
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,9 @@ config BT_BAS_BLS_ADDITIONAL_STATUS_PRESENT
bool "Additional Battery Status Present"
help
Enable this option if Additional Battery Status information is present.

config BT_BAS_BCS
bool "Battery Critical Status"
help
Enable this option to include Battery Critical Status Characteristic.
endif
6 changes: 6 additions & 0 deletions subsys/bluetooth/services/bas/bas.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ BT_GATT_SERVICE_DEFINE(
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
#if defined(CONFIG_BT_BAS_BCS)
BT_GATT_CHARACTERISTIC(BT_UUID_BAS_BATTERY_CRIT_STATUS,
BT_GATT_CHRC_READ | BT_GATT_CHRC_INDICATE, BT_GATT_PERM_READ,
bt_bas_bcs_read_critical_status, NULL, NULL),
BT_GATT_CCC(bt_bas_bcs_ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
#endif /* CONFIG_BT_BAS_BCS */
);

static int bas_init(void)
Expand Down
98 changes: 98 additions & 0 deletions subsys/bluetooth/services/bas/bas_bcs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* Copyright (c) 2024 Demant A/S
*
* SPDX-License-Identifier: Apache-2.0
*/

#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);

#define BATTERY_CRITICAL_STATUS_CHAR_IDX 9

static uint8_t battery_critical_status;

void bt_bas_bcs_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
{
ARG_UNUSED(attr);

bool ind_enabled = (value == BT_GATT_CCC_INDICATE);

LOG_DBG("BAS Critical status Indication %s", ind_enabled ? "enabled" : "disabled");
}

ssize_t bt_bas_bcs_read_critical_status(struct bt_conn *conn, const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset)
{

return bt_gatt_attr_read(conn, attr, buf, len, offset, &battery_critical_status,
sizeof(uint8_t));
}

static void bcs_indicate_cb(struct bt_conn *conn, struct bt_gatt_indicate_params *params,
uint8_t err)
{
if (err != 0) {
LOG_DBG("BCS Indication failed with error %u\n", err);
} else {
LOG_DBG("BCS Indication sent successfully\n");
}
}

static void bt_bas_bcs_update_battery_critical_status(void)
{
/* Indicate all connections */
const struct bt_gatt_attr *attr = bt_bas_get_bas_attr(BATTERY_CRITICAL_STATUS_CHAR_IDX);

if (attr) {
uint8_t err;
/* Indicate battery critical status to all connections */
static struct bt_gatt_indicate_params bcs_ind_params;

bcs_ind_params.attr = attr;
bcs_ind_params.data = &battery_critical_status;
bcs_ind_params.len = sizeof(battery_critical_status);
bcs_ind_params.func = bcs_indicate_cb;
err = bt_gatt_indicate(NULL, &bcs_ind_params);
if (err && err != -ENOTCONN) {
LOG_DBG("Failed to send critical status ind to all conns (err %d)\n", err);
}
}
}

void bt_bas_bcs_set_battery_critical_state(bool critical_state)
{
bool current_state = (battery_critical_status & BT_BAS_BCS_BATTERY_CRITICAL_STATE) != 0;

if (current_state == critical_state) {
LOG_DBG("Already battery_critical_state is %d\n", critical_state);
return;
}

if (critical_state) {
battery_critical_status |= BT_BAS_BCS_BATTERY_CRITICAL_STATE;
} else {
battery_critical_status &= ~BT_BAS_BCS_BATTERY_CRITICAL_STATE;
}
bt_bas_bcs_update_battery_critical_status();
}

void bt_bas_bcs_set_immediate_service_required(bool service_required)
{
bool current_state = (battery_critical_status & BT_BAS_BCS_IMMEDIATE_SERVICE_REQUIRED) != 0;

if (current_state == service_required) {
LOG_DBG("Already immediate_service_required is %d\n", service_required);
return;
}

if (service_required) {
battery_critical_status |= BT_BAS_BCS_IMMEDIATE_SERVICE_REQUIRED;
} else {
battery_critical_status &= ~BT_BAS_BCS_IMMEDIATE_SERVICE_REQUIRED;
}
bt_bas_bcs_update_battery_critical_status();
}
28 changes: 28 additions & 0 deletions subsys/bluetooth/services/bas/bas_bls.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,20 @@ void bt_bas_bls_set_battery_charge_level(enum bt_bas_bls_battery_charge_level le
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();

if (IS_ENABLED(CONFIG_BT_BAS_BCS)) {
/*
* Set the BCS Critical Power State bit as per BAS 1.1 specification
* section 3.4.1.1: The BCS Critical Power State bit should be set to true if the
* Battery Charge Level is set to Critical in the Power State field.
*/
if (level == BT_BAS_BLS_CHARGE_LEVEL_CRITICAL) {
bt_bas_bcs_set_battery_critical_state(true);
return;
}

bt_bas_bcs_set_battery_critical_state(false);
}
}

void bt_bas_bls_set_battery_charge_type(enum bt_bas_bls_battery_charge_type type)
Expand Down Expand Up @@ -232,6 +246,20 @@ 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();

if (IS_ENABLED(CONFIG_BT_BAS_BCS)) {
/*
* Set the BCS Immediate Service Required bit as per BAS 1.1 specification
* section 3.4.1.1: The BCS Immediate Service Required bit should be set to true if
* the service Required bit is set to true in the Additional Status field.
*/
if (value == BT_BAS_BLS_SERVICE_REQUIRED_TRUE) {
bt_bas_bcs_set_immediate_service_required(true);
return;
}

bt_bas_bcs_set_immediate_service_required(false);
}
}

void bt_bas_bls_set_battery_fault(enum bt_bas_bls_battery_fault value)
Expand Down
39 changes: 39 additions & 0 deletions subsys/bluetooth/services/bas/bas_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,52 @@ struct bt_bas_bls {
*/
void bt_bas_bls_init(void);

/**
* @brief Read the Battery Critical Status characteristic.
*
* @param conn Pointer to the Bluetooth connection object representing the client requesting
* the characteristic.
* @param attr Pointer to the GATT attribute of Battery Critical 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_bcs_read_critical_status(struct bt_conn *conn, const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset);

/**
* @brief Callback function for BCS Client Characteristic Configuration changes.
*
*
* @param attr Pointer to the GATT attribute of battery critical status char.
* @param value The new value of the CCC. This value indicates whether
* notifications or indications are enabled or disabled.
*/
void bt_bas_bcs_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value);

/**
* @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 Set the battery critical state flag.
*
* @param critical_state The battery critical state to set (true for critical, false otherwise).
*/
void bt_bas_bcs_set_battery_critical_state(bool critical_state);

/**
* @brief Set the immediate service required flag.
*
* @param service_required The immediate service required status to set.
*/
void bt_bas_bcs_set_immediate_service_required(bool service_required);

/**
* @brief Read the Battery Level Status characteristic.
*
Expand Down
3 changes: 2 additions & 1 deletion tests/bsim/bluetooth/samples/battery_service/prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ 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_ATT_TX_COUNT=10

CONFIG_BT_BAS_BLS=y
CONFIG_BT_BAS_BCS=y
CONFIG_BT_BAS_BLS_IDENTIFIER_PRESENT=y
CONFIG_BT_BAS_BLS_BATTERY_LEVEL_PRESENT=y
CONFIG_BT_BAS_BLS_ADDITIONAL_STATUS_PRESENT=y
Loading

0 comments on commit f22209d

Please sign in to comment.