diff --git a/applications/bt/bt_service/bt.c b/applications/bt/bt_service/bt.c index 4ea5d735..38aadc49 100644 --- a/applications/bt/bt_service/bt.c +++ b/applications/bt/bt_service/bt.c @@ -91,11 +91,16 @@ static void bt_battery_level_changed_callback(const void* _event, void* context) furi_assert(context); Bt* bt = context; + BtMessage message = {}; const PowerEvent* event = _event; if(event->type == PowerEventTypeBatteryLevelChanged) { - BtMessage message = { - .type = BtMessageTypeUpdateBatteryLevel, - .data.battery_level = event->data.battery_level}; + message.type = BtMessageTypeUpdateBatteryLevel; + message.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); } } @@ -378,6 +383,8 @@ int32_t bt_srv() { } else if(message.type == BtMessageTypeUpdateBatteryLevel) { // Update 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) { // Display PIN code bt_pin_code_show(bt, message.data.pin_code); diff --git a/applications/bt/bt_service/bt_i.h b/applications/bt/bt_service/bt_i.h index 610c0905..caa45360 100644 --- a/applications/bt/bt_service/bt_i.h +++ b/applications/bt/bt_service/bt_i.h @@ -21,6 +21,7 @@ typedef enum { BtMessageTypeUpdateStatus, BtMessageTypeUpdateBatteryLevel, + BtMessageTypeUpdatePowerState, BtMessageTypePinCodeShow, BtMessageTypeKeysStorageUpdated, BtMessageTypeSetProfile, diff --git a/firmware/targets/f7/ble_glue/app_conf.h b/firmware/targets/f7/ble_glue/app_conf.h index 1406f964..1d7474da 100644 --- a/firmware/targets/f7/ble_glue/app_conf.h +++ b/firmware/targets/f7/ble_glue/app_conf.h @@ -127,7 +127,7 @@ * Maximum number of simultaneous connections that the device will support. * 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. diff --git a/firmware/targets/f7/ble_glue/battery_service.c b/firmware/targets/f7/ble_glue/battery_service.c index 85f1eeea..a95f9187 100644 --- a/firmware/targets/f7/ble_glue/battery_service.c +++ b/firmware/targets/f7/ble_glue/battery_service.c @@ -3,18 +3,50 @@ #include "ble.h" #include +#include #define TAG "BtBatterySvc" typedef struct { uint16_t svc_handle; - uint16_t char_level_handle; + uint16_t battery_level_char_handle; + uint16_t power_state_char_handle; } 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; +#define BATTERY_POWER_STATE (0x2A1A) + 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() { battery_svc = malloc(sizeof(BatterySvc)); @@ -22,7 +54,7 @@ void battery_svc_start() { // Add Battery 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) { FURI_LOG_E(TAG, "Failed to add Battery service: %d", status); } @@ -30,24 +62,47 @@ void battery_svc_start() { status = aci_gatt_add_char( battery_svc->svc_handle, UUID_TYPE_16, - (Char_UUID_t*)&char_battery_level_uuid, + (Char_UUID_t*)&battery_level_char_uuid, 1, CHAR_PROP_READ | CHAR_PROP_NOTIFY, ATTR_PERMISSION_AUTHEN_READ, GATT_DONT_NOTIFY_EVENTS, 10, CHAR_VALUE_LEN_CONSTANT, - &battery_svc->char_level_handle); + &battery_svc->battery_level_char_handle); if(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() { tBleStatus status; if(battery_svc) { // 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) { 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 FURI_LOG_D(TAG, "Updating battery level characteristic"); 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) { FURI_LOG_E(TAG, "Failed updating RX characteristic: %d", result); } 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; +} diff --git a/firmware/targets/f7/ble_glue/battery_service.h b/firmware/targets/f7/ble_glue/battery_service.h index 2d35e252..f38bfc00 100644 --- a/firmware/targets/f7/ble_glue/battery_service.h +++ b/firmware/targets/f7/ble_glue/battery_service.h @@ -15,6 +15,8 @@ bool battery_svc_is_started(); bool battery_svc_update_level(uint8_t battery_level); +bool battery_svc_update_power_state(); + #ifdef __cplusplus } #endif diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt.c b/firmware/targets/f7/furi_hal/furi_hal_bt.c index 48d69844..1e869077 100755 --- a/firmware/targets/f7/furi_hal/furi_hal_bt.c +++ b/firmware/targets/f7/furi_hal/furi_hal_bt.c @@ -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) { ble_app_get_key_storage_buff(key_buff_addr, key_buff_size); } diff --git a/firmware/targets/furi_hal_include/furi_hal_bt.h b/firmware/targets/furi_hal_include/furi_hal_bt.h index 73b16bec..3a05081b 100644 --- a/firmware/targets/furi_hal_include/furi_hal_bt.h +++ b/firmware/targets/furi_hal_include/furi_hal_bt.h @@ -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); +/** Update battery power state */ +void furi_hal_bt_update_power_state(); + /** Checks if BLE state is active * * @return true if device is connected or advertising, false otherwise