forked from zmkfirmware/zmk
-
Notifications
You must be signed in to change notification settings - Fork 51
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(ble): Support perhipheral battery levels.
* Add ability to fetch and report peripheral battery levels on split centrals. * Add additional support for adding a new Battery Level service to split centrals that exposes fetched peripheral battery levels to connected hosts. Co-authored-by: Peter Johanson <[email protected]>
- Loading branch information
1 parent
c965e35
commit ede5f0c
Showing
9 changed files
with
299 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
/* | ||
* Copyright (c) 2020 The ZMK Contributors | ||
* | ||
* SPDX-License-Identifier: MIT | ||
*/ | ||
|
||
#include <zephyr/device.h> | ||
#include <zephyr/init.h> | ||
#include <sys/types.h> | ||
#include <zephyr/kernel.h> | ||
#include <zephyr/drivers/sensor.h> | ||
#include <zephyr/bluetooth/gatt.h> | ||
|
||
#include <zephyr/logging/log.h> | ||
|
||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); | ||
|
||
#include <zmk/event_manager.h> | ||
#include <zmk/battery.h> | ||
#include <zmk/events/battery_state_changed.h> | ||
#include <zmk/split/bluetooth/central.h> | ||
|
||
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) { | ||
const uint8_t source = (uint8_t)(uint32_t)attr->user_data; | ||
uint8_t level = 0; | ||
int rc = zmk_split_get_peripheral_battery_level(source, &level); | ||
|
||
if (rc == -EINVAL) { | ||
LOG_ERR("Invalid peripheral index requested for battery level read: %d", source); | ||
return 0; | ||
} | ||
|
||
return bt_gatt_attr_read(conn, attr, buf, len, offset, &level, sizeof(uint8_t)); | ||
} | ||
|
||
static const struct bt_gatt_cpf aux_level_cpf = { | ||
.format = 0x04, // uint8 | ||
.exponent = 0x0, | ||
.unit = 0x27AD, // Percentage | ||
.name_space = 0x01, // Bluetooth SIG | ||
.description = 0x0108, // "auxiliary" | ||
}; | ||
|
||
#define PERIPH_CUD_(x) "Peripheral " #x | ||
#define PERIPH_CUD(x) PERIPH_CUD_(x) | ||
|
||
// How many GATT attributes each battery level adds to our service | ||
#define PERIPH_BATT_LEVEL_ATTR_COUNT 5 | ||
// The second generated attribute is the one used to send GATT notifications | ||
#define PERIPH_BATT_LEVEL_ATTR_NOTIFY_IDX 1 | ||
|
||
#define PERIPH_BATT_LEVEL_ATTRS(i, _) \ | ||
BT_GATT_CHARACTERISTIC(BT_UUID_BAS_BATTERY_LEVEL, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, \ | ||
BT_GATT_PERM_READ, read_blvl, NULL, i), \ | ||
BT_GATT_CCC(blvl_ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE), \ | ||
BT_GATT_CPF(&aux_level_cpf), BT_GATT_CUD(PERIPH_CUD(i), BT_GATT_PERM_READ), | ||
|
||
BT_GATT_SERVICE_DEFINE(bas_aux, BT_GATT_PRIMARY_SERVICE(BT_UUID_BAS), | ||
LISTIFY(CONFIG_ZMK_SPLIT_BLE_CENTRAL_PERIPHERALS, PERIPH_BATT_LEVEL_ATTRS, | ||
())); | ||
|
||
int peripheral_batt_lvl_listener(const zmk_event_t *eh) { | ||
const struct zmk_peripheral_battery_state_changed *ev = | ||
as_zmk_peripheral_battery_state_changed(eh); | ||
if (ev == NULL) { | ||
return ZMK_EV_EVENT_BUBBLE; | ||
}; | ||
|
||
if (ev->source >= CONFIG_ZMK_SPLIT_BLE_CENTRAL_PERIPHERALS) { | ||
LOG_WRN("Got battery level event for an out of range peripheral index"); | ||
return ZMK_EV_EVENT_BUBBLE; | ||
} | ||
|
||
LOG_DBG("Peripheral battery level event: %u", ev->state_of_charge); | ||
|
||
// Offset by the index of the source plus the specific offset to find the attribute to notify | ||
// on. | ||
int index = (PERIPH_BATT_LEVEL_ATTR_COUNT * ev->source) + PERIPH_BATT_LEVEL_ATTR_NOTIFY_IDX; | ||
|
||
int rc = bt_gatt_notify(NULL, &bas_aux.attrs[index], &ev->state_of_charge, sizeof(uint8_t)); | ||
if (rc < 0 && rc != -ENOTCONN) { | ||
LOG_WRN("Failed to notify hosts of peripheral battery level: %d", rc); | ||
} | ||
|
||
return ZMK_EV_EVENT_BUBBLE; | ||
}; | ||
|
||
ZMK_LISTENER(peripheral_batt_lvl_listener, peripheral_batt_lvl_listener); | ||
ZMK_SUBSCRIPTION(peripheral_batt_lvl_listener, zmk_peripheral_battery_state_changed); |
Oops, something went wrong.