92 lines
2.2 KiB
C
92 lines
2.2 KiB
C
|
|
#include <errno.h>
|
||
|
|
|
||
|
|
#include <zephyr/kernel.h>
|
||
|
|
#include <zephyr/bluetooth/gatt.h>
|
||
|
|
|
||
|
|
#include <app_event_manager.h>
|
||
|
|
|
||
|
|
#define MODULE ble_battery
|
||
|
|
#include <caf/events/module_state_event.h>
|
||
|
|
|
||
|
|
#include "battery_status_event.h"
|
||
|
|
|
||
|
|
#include <zephyr/logging/log.h>
|
||
|
|
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
||
|
|
|
||
|
|
static bool notify_enabled;
|
||
|
|
static uint8_t battery_level = 100U;
|
||
|
|
|
||
|
|
static void bas_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
|
||
|
|
{
|
||
|
|
ARG_UNUSED(attr);
|
||
|
|
notify_enabled = (value == BT_GATT_CCC_NOTIFY);
|
||
|
|
}
|
||
|
|
|
||
|
|
static ssize_t read_battery_level(struct bt_conn *conn,
|
||
|
|
const struct bt_gatt_attr *attr,
|
||
|
|
void *buf,
|
||
|
|
uint16_t len,
|
||
|
|
uint16_t offset)
|
||
|
|
{
|
||
|
|
const uint8_t *value = attr->user_data;
|
||
|
|
|
||
|
|
return bt_gatt_attr_read(conn, attr, buf, len, offset, value, sizeof(*value));
|
||
|
|
}
|
||
|
|
|
||
|
|
BT_GATT_SERVICE_DEFINE(ble_battery_svc,
|
||
|
|
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_ENCRYPT,
|
||
|
|
read_battery_level, NULL, &battery_level),
|
||
|
|
BT_GATT_CCC(bas_ccc_cfg_changed,
|
||
|
|
BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT),
|
||
|
|
);
|
||
|
|
|
||
|
|
static bool handle_battery_status_event(const struct battery_status_event *event)
|
||
|
|
{
|
||
|
|
battery_level = event->soc;
|
||
|
|
|
||
|
|
if (!notify_enabled) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
int err = bt_gatt_notify(NULL, &ble_battery_svc.attrs[1], &battery_level, sizeof(battery_level));
|
||
|
|
|
||
|
|
if (err == -ENOTCONN) {
|
||
|
|
LOG_WRN("BAS notify skipped: peer disconnecting");
|
||
|
|
} else if (err) {
|
||
|
|
LOG_ERR("BAS notify failed: %d", err);
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
static bool handle_module_state_event(const struct module_state_event *event)
|
||
|
|
{
|
||
|
|
if (!check_state(event, MODULE_ID(ble_state), MODULE_STATE_READY)) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
module_set_state(MODULE_STATE_READY);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
static bool app_event_handler(const struct app_event_header *aeh)
|
||
|
|
{
|
||
|
|
if (is_battery_status_event(aeh)) {
|
||
|
|
return handle_battery_status_event(cast_battery_status_event(aeh));
|
||
|
|
}
|
||
|
|
|
||
|
|
if (is_module_state_event(aeh)) {
|
||
|
|
return handle_module_state_event(cast_module_state_event(aeh));
|
||
|
|
}
|
||
|
|
|
||
|
|
__ASSERT_NO_MSG(false);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
APP_EVENT_LISTENER(MODULE, app_event_handler);
|
||
|
|
APP_EVENT_SUBSCRIBE(MODULE, battery_status_event);
|
||
|
|
APP_EVENT_SUBSCRIBE(MODULE, module_state_event);
|