[FL-2441] BLE add Power state, fix double connection (#1238)

* battery service: add power state charachteristic
* bt: update power state on charging / discharging events
* ble config: support only one connection
* bt: always update flow control characteristic
* bt: fix power state update
* bt: simplify updating power state
* bt: don't update flow control charachteristic
This commit is contained in:
gornekich 2022-05-24 16:42:02 +03:00 committed by GitHub
parent f90c9320d9
commit 2017baac48
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 115 additions and 11 deletions

View File

@ -91,11 +91,16 @@ static void bt_battery_level_changed_callback(const void* _event, void* context)
furi_assert(context); furi_assert(context);
Bt* bt = context; Bt* bt = context;
BtMessage message = {};
const PowerEvent* event = _event; const PowerEvent* event = _event;
if(event->type == PowerEventTypeBatteryLevelChanged) { if(event->type == PowerEventTypeBatteryLevelChanged) {
BtMessage message = { message.type = BtMessageTypeUpdateBatteryLevel;
.type = BtMessageTypeUpdateBatteryLevel, message.data.battery_level = event->data.battery_level;
.data.battery_level = event->data.battery_level}; furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
} else if(
event->type == PowerEventTypeStartCharging || event->type == PowerEventTypeFullyCharged ||
event->type == PowerEventTypeStopCharging) {
message.type = BtMessageTypeUpdatePowerState;
furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
} }
} }
@ -378,6 +383,8 @@ int32_t bt_srv() {
} else if(message.type == BtMessageTypeUpdateBatteryLevel) { } else if(message.type == BtMessageTypeUpdateBatteryLevel) {
// Update battery level // Update battery level
furi_hal_bt_update_battery_level(message.data.battery_level); furi_hal_bt_update_battery_level(message.data.battery_level);
} else if(message.type == BtMessageTypeUpdatePowerState) {
furi_hal_bt_update_power_state();
} else if(message.type == BtMessageTypePinCodeShow) { } else if(message.type == BtMessageTypePinCodeShow) {
// Display PIN code // Display PIN code
bt_pin_code_show(bt, message.data.pin_code); bt_pin_code_show(bt, message.data.pin_code);

View File

@ -21,6 +21,7 @@
typedef enum { typedef enum {
BtMessageTypeUpdateStatus, BtMessageTypeUpdateStatus,
BtMessageTypeUpdateBatteryLevel, BtMessageTypeUpdateBatteryLevel,
BtMessageTypeUpdatePowerState,
BtMessageTypePinCodeShow, BtMessageTypePinCodeShow,
BtMessageTypeKeysStorageUpdated, BtMessageTypeKeysStorageUpdated,
BtMessageTypeSetProfile, BtMessageTypeSetProfile,

View File

@ -127,7 +127,7 @@
* Maximum number of simultaneous connections that the device will support. * Maximum number of simultaneous connections that the device will support.
* Valid values are from 1 to 8 * Valid values are from 1 to 8
*/ */
#define CFG_BLE_NUM_LINK 2 #define CFG_BLE_NUM_LINK 1
/** /**
* Maximum number of Services that can be stored in the GATT database. * Maximum number of Services that can be stored in the GATT database.

View File

@ -3,18 +3,50 @@
#include "ble.h" #include "ble.h"
#include <furi.h> #include <furi.h>
#include <furi_hal_power.h>
#define TAG "BtBatterySvc" #define TAG "BtBatterySvc"
typedef struct { typedef struct {
uint16_t svc_handle; uint16_t svc_handle;
uint16_t char_level_handle; uint16_t battery_level_char_handle;
uint16_t power_state_char_handle;
} BatterySvc; } BatterySvc;
enum {
// Common states
BatterySvcPowerStateUnknown = 0b00,
BatterySvcPowerStateUnsupported = 0b01,
// Level states
BatterySvcPowerStateGoodLevel = 0b10,
BatterySvcPowerStateCriticallyLowLevel = 0b11,
// Charging states
BatterySvcPowerStateNotCharging = 0b10,
BatterySvcPowerStateCharging = 0b11,
// Discharging states
BatterySvcPowerStateNotDischarging = 0b10,
BatterySvcPowerStateDischarging = 0b11,
// Battery states
BatterySvcPowerStateBatteryNotPresent = 0b10,
BatterySvcPowerStateBatteryPresent = 0b11,
};
typedef struct {
uint8_t present : 2;
uint8_t discharging : 2;
uint8_t charging : 2;
uint8_t level : 2;
} BattrySvcPowerState;
_Static_assert(sizeof(BattrySvcPowerState) == 1, "Incorrect structure size");
static BatterySvc* battery_svc = NULL; static BatterySvc* battery_svc = NULL;
#define BATTERY_POWER_STATE (0x2A1A)
static const uint16_t service_uuid = BATTERY_SERVICE_UUID; static const uint16_t service_uuid = BATTERY_SERVICE_UUID;
static const uint16_t char_battery_level_uuid = BATTERY_LEVEL_CHAR_UUID; static const uint16_t battery_level_char_uuid = BATTERY_LEVEL_CHAR_UUID;
static const uint16_t power_state_char_uuid = BATTERY_POWER_STATE;
void battery_svc_start() { void battery_svc_start() {
battery_svc = malloc(sizeof(BatterySvc)); battery_svc = malloc(sizeof(BatterySvc));
@ -22,7 +54,7 @@ void battery_svc_start() {
// Add Battery service // Add Battery service
status = aci_gatt_add_service( status = aci_gatt_add_service(
UUID_TYPE_16, (Service_UUID_t*)&service_uuid, PRIMARY_SERVICE, 4, &battery_svc->svc_handle); UUID_TYPE_16, (Service_UUID_t*)&service_uuid, PRIMARY_SERVICE, 8, &battery_svc->svc_handle);
if(status) { if(status) {
FURI_LOG_E(TAG, "Failed to add Battery service: %d", status); FURI_LOG_E(TAG, "Failed to add Battery service: %d", status);
} }
@ -30,24 +62,47 @@ void battery_svc_start() {
status = aci_gatt_add_char( status = aci_gatt_add_char(
battery_svc->svc_handle, battery_svc->svc_handle,
UUID_TYPE_16, UUID_TYPE_16,
(Char_UUID_t*)&char_battery_level_uuid, (Char_UUID_t*)&battery_level_char_uuid,
1, 1,
CHAR_PROP_READ | CHAR_PROP_NOTIFY, CHAR_PROP_READ | CHAR_PROP_NOTIFY,
ATTR_PERMISSION_AUTHEN_READ, ATTR_PERMISSION_AUTHEN_READ,
GATT_DONT_NOTIFY_EVENTS, GATT_DONT_NOTIFY_EVENTS,
10, 10,
CHAR_VALUE_LEN_CONSTANT, CHAR_VALUE_LEN_CONSTANT,
&battery_svc->char_level_handle); &battery_svc->battery_level_char_handle);
if(status) { if(status) {
FURI_LOG_E(TAG, "Failed to add Battery level characteristic: %d", status); FURI_LOG_E(TAG, "Failed to add Battery level characteristic: %d", status);
} }
// Add Power state characteristic
status = aci_gatt_add_char(
battery_svc->svc_handle,
UUID_TYPE_16,
(Char_UUID_t*)&power_state_char_uuid,
1,
CHAR_PROP_READ | CHAR_PROP_NOTIFY,
ATTR_PERMISSION_AUTHEN_READ,
GATT_DONT_NOTIFY_EVENTS,
10,
CHAR_VALUE_LEN_CONSTANT,
&battery_svc->power_state_char_handle);
if(status) {
FURI_LOG_E(TAG, "Failed to add Battery level characteristic: %d", status);
}
// Update power state charachteristic
battery_svc_update_power_state();
} }
void battery_svc_stop() { void battery_svc_stop() {
tBleStatus status; tBleStatus status;
if(battery_svc) { if(battery_svc) {
// Delete Battery level characteristic // Delete Battery level characteristic
status = aci_gatt_del_char(battery_svc->svc_handle, battery_svc->char_level_handle); status =
aci_gatt_del_char(battery_svc->svc_handle, battery_svc->battery_level_char_handle);
if(status) {
FURI_LOG_E(TAG, "Failed to delete Battery level characteristic: %d", status);
}
// Delete Power state characteristic
status = aci_gatt_del_char(battery_svc->svc_handle, battery_svc->power_state_char_handle);
if(status) { if(status) {
FURI_LOG_E(TAG, "Failed to delete Battery level characteristic: %d", status); FURI_LOG_E(TAG, "Failed to delete Battery level characteristic: %d", status);
} }
@ -73,9 +128,39 @@ bool battery_svc_update_level(uint8_t battery_charge) {
// Update battery level characteristic // Update battery level characteristic
FURI_LOG_D(TAG, "Updating battery level characteristic"); FURI_LOG_D(TAG, "Updating battery level characteristic");
tBleStatus result = aci_gatt_update_char_value( tBleStatus result = aci_gatt_update_char_value(
battery_svc->svc_handle, battery_svc->char_level_handle, 0, 1, &battery_charge); battery_svc->svc_handle, battery_svc->battery_level_char_handle, 0, 1, &battery_charge);
if(result) { if(result) {
FURI_LOG_E(TAG, "Failed updating RX characteristic: %d", result); FURI_LOG_E(TAG, "Failed updating RX characteristic: %d", result);
} }
return result != BLE_STATUS_SUCCESS; return result != BLE_STATUS_SUCCESS;
} }
bool battery_svc_update_power_state() {
// Check if service was started
if(battery_svc == NULL) {
return false;
}
// Update power state characteristic
BattrySvcPowerState power_state = {
.level = BatterySvcPowerStateUnsupported,
.present = BatterySvcPowerStateBatteryPresent,
};
if(furi_hal_power_is_charging()) {
power_state.charging = BatterySvcPowerStateCharging;
power_state.discharging = BatterySvcPowerStateNotDischarging;
} else {
power_state.charging = BatterySvcPowerStateNotCharging;
power_state.discharging = BatterySvcPowerStateDischarging;
}
FURI_LOG_D(TAG, "Updating power state characteristic");
tBleStatus result = aci_gatt_update_char_value(
battery_svc->svc_handle,
battery_svc->power_state_char_handle,
0,
1,
(uint8_t*)&power_state);
if(result) {
FURI_LOG_E(TAG, "Failed updating Power state characteristic: %d", result);
}
return result != BLE_STATUS_SUCCESS;
}

View File

@ -15,6 +15,8 @@ bool battery_svc_is_started();
bool battery_svc_update_level(uint8_t battery_level); bool battery_svc_update_level(uint8_t battery_level);
bool battery_svc_update_power_state();
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -284,6 +284,12 @@ void furi_hal_bt_update_battery_level(uint8_t battery_level) {
} }
} }
void furi_hal_bt_update_power_state() {
if(battery_svc_is_started()) {
battery_svc_update_power_state();
}
}
void furi_hal_bt_get_key_storage_buff(uint8_t** key_buff_addr, uint16_t* key_buff_size) { void furi_hal_bt_get_key_storage_buff(uint8_t** key_buff_addr, uint16_t* key_buff_size) {
ble_app_get_key_storage_buff(key_buff_addr, key_buff_size); ble_app_get_key_storage_buff(key_buff_addr, key_buff_size);
} }

View File

@ -91,6 +91,9 @@ bool furi_hal_bt_change_app(FuriHalBtProfile profile, GapEventCallback event_cb,
*/ */
void furi_hal_bt_update_battery_level(uint8_t battery_level); void furi_hal_bt_update_battery_level(uint8_t battery_level);
/** Update battery power state */
void furi_hal_bt_update_power_state();
/** Checks if BLE state is active /** Checks if BLE state is active
* *
* @return true if device is connected or advertising, false otherwise * @return true if device is connected or advertising, false otherwise