1 /*
2 * Copyright (c) 2024 Demant A/S
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/bluetooth/services/bas.h>
8 #include <zephyr/bluetooth/gatt.h>
9 #include "bas_internal.h"
10
11 #include <zephyr/logging/log.h>
12 LOG_MODULE_DECLARE(bas, CONFIG_BT_BAS_LOG_LEVEL);
13
14 #define BATTERY_CRITICAL_STATUS_CHAR_IDX 9
15
16 static uint8_t battery_critical_status;
17
bt_bas_bcs_ccc_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)18 void bt_bas_bcs_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
19 {
20 ARG_UNUSED(attr);
21
22 bool ind_enabled = (value == BT_GATT_CCC_INDICATE);
23
24 LOG_DBG("BAS Critical status Indication %s", ind_enabled ? "enabled" : "disabled");
25 }
26
bt_bas_bcs_read_critical_status(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)27 ssize_t bt_bas_bcs_read_critical_status(struct bt_conn *conn, const struct bt_gatt_attr *attr,
28 void *buf, uint16_t len, uint16_t offset)
29 {
30
31 return bt_gatt_attr_read(conn, attr, buf, len, offset, &battery_critical_status,
32 sizeof(uint8_t));
33 }
34
bcs_indicate_cb(struct bt_conn * conn,struct bt_gatt_indicate_params * params,uint8_t err)35 static void bcs_indicate_cb(struct bt_conn *conn, struct bt_gatt_indicate_params *params,
36 uint8_t err)
37 {
38 if (err != 0) {
39 LOG_DBG("BCS Indication failed with error %u\n", err);
40 } else {
41 LOG_DBG("BCS Indication sent successfully\n");
42 }
43 }
44
bt_bas_bcs_update_battery_critical_status(void)45 static void bt_bas_bcs_update_battery_critical_status(void)
46 {
47 /* Indicate all connections */
48 const struct bt_gatt_attr *attr = bt_bas_get_bas_attr(BATTERY_CRITICAL_STATUS_CHAR_IDX);
49
50 if (attr) {
51 uint8_t err;
52 /* Indicate battery critical status to all connections */
53 static struct bt_gatt_indicate_params bcs_ind_params;
54
55 bcs_ind_params.attr = attr;
56 bcs_ind_params.data = &battery_critical_status;
57 bcs_ind_params.len = sizeof(battery_critical_status);
58 bcs_ind_params.func = bcs_indicate_cb;
59 err = bt_gatt_indicate(NULL, &bcs_ind_params);
60 if (err && err != -ENOTCONN) {
61 LOG_DBG("Failed to send critical status ind to all conns (err %d)\n", err);
62 }
63 }
64 }
65
bt_bas_bcs_set_battery_critical_state(bool critical_state)66 void bt_bas_bcs_set_battery_critical_state(bool critical_state)
67 {
68 bool current_state = (battery_critical_status & BT_BAS_BCS_BATTERY_CRITICAL_STATE) != 0;
69
70 if (current_state == critical_state) {
71 LOG_DBG("Already battery_critical_state is %d\n", critical_state);
72 return;
73 }
74
75 if (critical_state) {
76 battery_critical_status |= BT_BAS_BCS_BATTERY_CRITICAL_STATE;
77 } else {
78 battery_critical_status &= ~BT_BAS_BCS_BATTERY_CRITICAL_STATE;
79 }
80 bt_bas_bcs_update_battery_critical_status();
81 }
82
bt_bas_bcs_set_immediate_service_required(bool service_required)83 void bt_bas_bcs_set_immediate_service_required(bool service_required)
84 {
85 bool current_state = (battery_critical_status & BT_BAS_BCS_IMMEDIATE_SERVICE_REQUIRED) != 0;
86
87 if (current_state == service_required) {
88 LOG_DBG("Already immediate_service_required is %d\n", service_required);
89 return;
90 }
91
92 if (service_required) {
93 battery_critical_status |= BT_BAS_BCS_IMMEDIATE_SERVICE_REQUIRED;
94 } else {
95 battery_critical_status &= ~BT_BAS_BCS_IMMEDIATE_SERVICE_REQUIRED;
96 }
97 bt_bas_bcs_update_battery_critical_status();
98 }
99