diff --git a/revert_gatt_char_refactor.patch b/revert_gatt_char_refactor.patch new file mode 100644 index 000000000..161830135 --- /dev/null +++ b/revert_gatt_char_refactor.patch @@ -0,0 +1,2181 @@ +diff --git a/applications/services/bt/bt_service/bt.c b/applications/services/bt/bt_service/bt.c +index 882fd11e85..b8cb09734d 100644 +--- a/applications/services/bt/bt_service/bt.c ++++ b/applications/services/bt/bt_service/bt.c +@@ -1,7 +1,7 @@ + #include "bt_i.h" ++#include "battery_service.h" + #include "bt_keys_storage.h" + +-#include + #include + #include + #include +diff --git a/firmware/targets/f7/ble_glue/app_debug.c b/firmware/targets/f7/ble_glue/app_debug.c +index 35f53ae22c..78e789ac30 100644 +--- a/firmware/targets/f7/ble_glue/app_debug.c ++++ b/firmware/targets/f7/ble_glue/app_debug.c +@@ -195,14 +195,14 @@ static void APPD_SetCPU2GpioConfig(void) { + gpio_config.Pin = gpiob_pin_list; + LL_C2_AHB2_GRP1_EnableClock(LL_C2_AHB2_GRP1_PERIPH_GPIOB); + LL_GPIO_Init(GPIOB, &gpio_config); +- LL_GPIO_ResetOutputPin(GPIOB, gpiob_pin_list); ++ LL_GPIO_ResetOutputPin(GPIOB, gpioa_pin_list); + } + + if(gpioc_pin_list != 0) { + gpio_config.Pin = gpioc_pin_list; + LL_C2_AHB2_GRP1_EnableClock(LL_C2_AHB2_GRP1_PERIPH_GPIOC); + LL_GPIO_Init(GPIOC, &gpio_config); +- LL_GPIO_ResetOutputPin(GPIOC, gpioc_pin_list); ++ LL_GPIO_ResetOutputPin(GPIOC, gpioa_pin_list); + } + } + +diff --git a/firmware/targets/f7/ble_glue/services/battery_service.c b/firmware/targets/f7/ble_glue/battery_service.c +similarity index 53% +rename from firmware/targets/f7/ble_glue/services/battery_service.c +rename to firmware/targets/f7/ble_glue/battery_service.c +index 63f736b3b7..8c371efadb 100644 +--- a/firmware/targets/f7/ble_glue/services/battery_service.c ++++ b/firmware/targets/f7/ble_glue/battery_service.c +@@ -1,7 +1,5 @@ + #include "battery_service.h" + #include "app_common.h" +-#include "gatt_char.h" +- + #include + + #include +@@ -9,6 +7,12 @@ + + #define TAG "BtBatterySvc" + ++typedef struct { ++ uint16_t svc_handle; ++ uint16_t battery_level_char_handle; ++ uint16_t power_state_char_handle; ++} BatterySvc; ++ + enum { + // Common states + BatterySvcPowerStateUnknown = 0b00, +@@ -36,44 +40,13 @@ typedef struct { + + _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; +- +-typedef enum { +- BatterySvcGattCharacteristicBatteryLevel = 0, +- BatterySvcGattCharacteristicPowerState, +- BatterySvcGattCharacteristicCount, +-} BatterySvcGattCharacteristicId; +- +-static const FlipperGattCharacteristicParams battery_svc_chars[BatterySvcGattCharacteristicCount] = +- {[BatterySvcGattCharacteristicBatteryLevel] = +- {.name = "Battery Level", +- .data_prop_type = FlipperGattCharacteristicDataFixed, +- .data.fixed.length = 1, +- .uuid.Char_UUID_16 = BATTERY_LEVEL_CHAR_UUID, +- .uuid_type = UUID_TYPE_16, +- .char_properties = CHAR_PROP_READ | CHAR_PROP_NOTIFY, +- .security_permissions = ATTR_PERMISSION_AUTHEN_READ, +- .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, +- .is_variable = CHAR_VALUE_LEN_CONSTANT}, +- [BatterySvcGattCharacteristicPowerState] = { +- .name = "Power State", +- .data_prop_type = FlipperGattCharacteristicDataFixed, +- .data.fixed.length = 1, +- .uuid.Char_UUID_16 = BATTERY_POWER_STATE, +- .uuid_type = UUID_TYPE_16, +- .char_properties = CHAR_PROP_READ | CHAR_PROP_NOTIFY, +- .security_permissions = ATTR_PERMISSION_AUTHEN_READ, +- .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, +- .is_variable = CHAR_VALUE_LEN_CONSTANT}}; +- +-typedef struct { +- uint16_t svc_handle; +- FlipperGattCharacteristicInstance chars[BatterySvcGattCharacteristicCount]; +-} BatterySvc; +- +-static BatterySvc* battery_svc = NULL; ++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)); +@@ -85,19 +58,53 @@ void battery_svc_start() { + if(status) { + FURI_LOG_E(TAG, "Failed to add Battery service: %d", status); + } +- for(size_t i = 0; i < BatterySvcGattCharacteristicCount; i++) { +- flipper_gatt_characteristic_init( +- battery_svc->svc_handle, &battery_svc_chars[i], &battery_svc->chars[i]); ++ // Add Battery level characteristic ++ status = aci_gatt_add_char( ++ battery_svc->svc_handle, ++ UUID_TYPE_16, ++ (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->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) { +- for(size_t i = 0; i < BatterySvcGattCharacteristicCount; i++) { +- flipper_gatt_characteristic_delete(battery_svc->svc_handle, &battery_svc->chars[i]); ++ // Delete Battery level characteristic ++ 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); + } + // Delete Battery service + status = aci_gatt_del_service(battery_svc->svc_handle); +@@ -119,10 +126,13 @@ bool battery_svc_update_level(uint8_t battery_charge) { + return false; + } + // Update battery level characteristic +- return flipper_gatt_characteristic_update( +- battery_svc->svc_handle, +- &battery_svc->chars[BatterySvcGattCharacteristicBatteryLevel], +- &battery_charge); ++ FURI_LOG_D(TAG, "Updating battery level characteristic"); ++ tBleStatus result = aci_gatt_update_char_value( ++ 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() { +@@ -142,9 +152,15 @@ bool battery_svc_update_power_state() { + power_state.charging = BatterySvcPowerStateNotCharging; + power_state.discharging = BatterySvcPowerStateDischarging; + } +- +- return flipper_gatt_characteristic_update( ++ FURI_LOG_D(TAG, "Updating power state characteristic"); ++ tBleStatus result = aci_gatt_update_char_value( + battery_svc->svc_handle, +- &battery_svc->chars[BatterySvcGattCharacteristicPowerState], +- &power_state); ++ 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/services/battery_service.h b/firmware/targets/f7/ble_glue/battery_service.h +similarity index 100% +rename from firmware/targets/f7/ble_glue/services/battery_service.h +rename to firmware/targets/f7/ble_glue/battery_service.h +diff --git a/firmware/targets/f7/ble_glue/ble_app.c b/firmware/targets/f7/ble_glue/ble_app.c +index 7a2148b6b8..4fc4d521be 100644 +--- a/firmware/targets/f7/ble_glue/ble_app.c ++++ b/firmware/targets/f7/ble_glue/ble_app.c +@@ -33,45 +33,6 @@ static int32_t ble_app_hci_thread(void* context); + static void ble_app_hci_event_handler(void* pPayload); + static void ble_app_hci_status_not_handler(HCI_TL_CmdStatus_t status); + +-static const HCI_TL_HciInitConf_t hci_tl_config = { +- .p_cmdbuffer = (uint8_t*)&ble_app_cmd_buffer, +- .StatusNotCallBack = ble_app_hci_status_not_handler, +-}; +- +-static const SHCI_C2_CONFIG_Cmd_Param_t config_param = { +- .PayloadCmdSize = SHCI_C2_CONFIG_PAYLOAD_CMD_SIZE, +- .Config1 = SHCI_C2_CONFIG_CONFIG1_BIT0_BLE_NVM_DATA_TO_SRAM, +- .BleNvmRamAddress = (uint32_t)ble_app_nvm, +- .EvtMask1 = SHCI_C2_CONFIG_EVTMASK1_BIT1_BLE_NVM_RAM_UPDATE_ENABLE, +-}; +- +-static const SHCI_C2_Ble_Init_Cmd_Packet_t ble_init_cmd_packet = { +- .Header = {{0, 0, 0}}, // Header unused +- .Param = { +- .pBleBufferAddress = 0, // pBleBufferAddress not used +- .BleBufferSize = 0, // BleBufferSize not used +- .NumAttrRecord = CFG_BLE_NUM_GATT_ATTRIBUTES, +- .NumAttrServ = CFG_BLE_NUM_GATT_SERVICES, +- .AttrValueArrSize = CFG_BLE_ATT_VALUE_ARRAY_SIZE, +- .NumOfLinks = CFG_BLE_NUM_LINK, +- .ExtendedPacketLengthEnable = CFG_BLE_DATA_LENGTH_EXTENSION, +- .PrWriteListSize = CFG_BLE_PREPARE_WRITE_LIST_SIZE, +- .MblockCount = CFG_BLE_MBLOCK_COUNT, +- .AttMtu = CFG_BLE_MAX_ATT_MTU, +- .SlaveSca = CFG_BLE_SLAVE_SCA, +- .MasterSca = CFG_BLE_MASTER_SCA, +- .LsSource = CFG_BLE_LSE_SOURCE, +- .MaxConnEventLength = CFG_BLE_MAX_CONN_EVENT_LENGTH, +- .HsStartupTime = CFG_BLE_HSE_STARTUP_TIME, +- .ViterbiEnable = CFG_BLE_VITERBI_MODE, +- .Options = CFG_BLE_OPTIONS, +- .HwVersion = 0, +- .max_coc_initiator_nbr = 32, +- .min_tx_power = 0, +- .max_tx_power = 0, +- .rx_model_config = 1, +- }}; +- + bool ble_app_init() { + SHCI_CmdStatus_t status; + ble_app = malloc(sizeof(BleApp)); +@@ -83,16 +44,52 @@ bool ble_app_init() { + furi_thread_start(ble_app->thread); + + // Initialize Ble Transport Layer ++ HCI_TL_HciInitConf_t hci_tl_config = { ++ .p_cmdbuffer = (uint8_t*)&ble_app_cmd_buffer, ++ .StatusNotCallBack = ble_app_hci_status_not_handler, ++ }; + hci_init(ble_app_hci_event_handler, (void*)&hci_tl_config); + + // Configure NVM store for pairing data +- status = SHCI_C2_Config((SHCI_C2_CONFIG_Cmd_Param_t*)&config_param); ++ SHCI_C2_CONFIG_Cmd_Param_t config_param = { ++ .PayloadCmdSize = SHCI_C2_CONFIG_PAYLOAD_CMD_SIZE, ++ .Config1 = SHCI_C2_CONFIG_CONFIG1_BIT0_BLE_NVM_DATA_TO_SRAM, ++ .BleNvmRamAddress = (uint32_t)ble_app_nvm, ++ .EvtMask1 = SHCI_C2_CONFIG_EVTMASK1_BIT1_BLE_NVM_RAM_UPDATE_ENABLE, ++ }; ++ status = SHCI_C2_Config(&config_param); + if(status) { + FURI_LOG_E(TAG, "Failed to configure 2nd core: %d", status); + } + + // Start ble stack on 2nd core +- status = SHCI_C2_BLE_Init((SHCI_C2_Ble_Init_Cmd_Packet_t*)&ble_init_cmd_packet); ++ SHCI_C2_Ble_Init_Cmd_Packet_t ble_init_cmd_packet = { ++ .Header = {{0, 0, 0}}, // Header unused ++ .Param = { ++ .pBleBufferAddress = 0, // pBleBufferAddress not used ++ .BleBufferSize = 0, // BleBufferSize not used ++ .NumAttrRecord = CFG_BLE_NUM_GATT_ATTRIBUTES, ++ .NumAttrServ = CFG_BLE_NUM_GATT_SERVICES, ++ .AttrValueArrSize = CFG_BLE_ATT_VALUE_ARRAY_SIZE, ++ .NumOfLinks = CFG_BLE_NUM_LINK, ++ .ExtendedPacketLengthEnable = CFG_BLE_DATA_LENGTH_EXTENSION, ++ .PrWriteListSize = CFG_BLE_PREPARE_WRITE_LIST_SIZE, ++ .MblockCount = CFG_BLE_MBLOCK_COUNT, ++ .AttMtu = CFG_BLE_MAX_ATT_MTU, ++ .SlaveSca = CFG_BLE_SLAVE_SCA, ++ .MasterSca = CFG_BLE_MASTER_SCA, ++ .LsSource = CFG_BLE_LSE_SOURCE, ++ .MaxConnEventLength = CFG_BLE_MAX_CONN_EVENT_LENGTH, ++ .HsStartupTime = CFG_BLE_HSE_STARTUP_TIME, ++ .ViterbiEnable = CFG_BLE_VITERBI_MODE, ++ .Options = CFG_BLE_OPTIONS, ++ .HwVersion = 0, ++ .max_coc_initiator_nbr = 32, ++ .min_tx_power = 0, ++ .max_tx_power = 0, ++ .rx_model_config = 1, ++ }}; ++ status = SHCI_C2_BLE_Init(&ble_init_cmd_packet); + if(status) { + FURI_LOG_E(TAG, "Failed to start ble stack: %d", status); + } +diff --git a/firmware/targets/f7/ble_glue/dev_info_service.c b/firmware/targets/f7/ble_glue/dev_info_service.c +new file mode 100644 +index 0000000000..d24058632f +--- /dev/null ++++ b/firmware/targets/f7/ble_glue/dev_info_service.c +@@ -0,0 +1,220 @@ ++#include "dev_info_service.h" ++#include "app_common.h" ++#include ++ ++#include ++#include ++#include ++ ++#define TAG "BtDevInfoSvc" ++ ++typedef struct { ++ uint16_t service_handle; ++ uint16_t man_name_char_handle; ++ uint16_t serial_num_char_handle; ++ uint16_t firmware_rev_char_handle; ++ uint16_t software_rev_char_handle; ++ uint16_t rpc_version_char_handle; ++ FuriString* version_string; ++ char hardware_revision[4]; ++} DevInfoSvc; ++ ++static DevInfoSvc* dev_info_svc = NULL; ++ ++static const char dev_info_man_name[] = "Flipper Devices Inc."; ++static const char dev_info_serial_num[] = "1.0"; ++static const char dev_info_rpc_version[] = TOSTRING(PROTOBUF_MAJOR_VERSION.PROTOBUF_MINOR_VERSION); ++ ++static const uint8_t dev_info_rpc_version_uuid[] = ++ {0x33, 0xa9, 0xb5, 0x3e, 0x87, 0x5d, 0x1a, 0x8e, 0xc8, 0x47, 0x5e, 0xae, 0x6d, 0x66, 0xf6, 0x03}; ++ ++void dev_info_svc_start() { ++ dev_info_svc = malloc(sizeof(DevInfoSvc)); ++ dev_info_svc->version_string = furi_string_alloc_printf( ++ "%s %s %s %s", ++ version_get_githash(NULL), ++ version_get_version(NULL), ++ version_get_gitbranchnum(NULL), ++ version_get_builddate(NULL)); ++ snprintf( ++ dev_info_svc->hardware_revision, ++ sizeof(dev_info_svc->hardware_revision), ++ "%d", ++ version_get_target(NULL)); ++ tBleStatus status; ++ ++ // Add Device Information Service ++ uint16_t uuid = DEVICE_INFORMATION_SERVICE_UUID; ++ status = aci_gatt_add_service( ++ UUID_TYPE_16, (Service_UUID_t*)&uuid, PRIMARY_SERVICE, 11, &dev_info_svc->service_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to add Device Information Service: %d", status); ++ } ++ ++ // Add characteristics ++ uuid = MANUFACTURER_NAME_UUID; ++ status = aci_gatt_add_char( ++ dev_info_svc->service_handle, ++ UUID_TYPE_16, ++ (Char_UUID_t*)&uuid, ++ strlen(dev_info_man_name), ++ CHAR_PROP_READ, ++ ATTR_PERMISSION_AUTHEN_READ, ++ GATT_DONT_NOTIFY_EVENTS, ++ 10, ++ CHAR_VALUE_LEN_CONSTANT, ++ &dev_info_svc->man_name_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to add manufacturer name char: %d", status); ++ } ++ uuid = SERIAL_NUMBER_UUID; ++ status = aci_gatt_add_char( ++ dev_info_svc->service_handle, ++ UUID_TYPE_16, ++ (Char_UUID_t*)&uuid, ++ strlen(dev_info_serial_num), ++ CHAR_PROP_READ, ++ ATTR_PERMISSION_AUTHEN_READ, ++ GATT_DONT_NOTIFY_EVENTS, ++ 10, ++ CHAR_VALUE_LEN_CONSTANT, ++ &dev_info_svc->serial_num_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to add serial number char: %d", status); ++ } ++ uuid = FIRMWARE_REVISION_UUID; ++ status = aci_gatt_add_char( ++ dev_info_svc->service_handle, ++ UUID_TYPE_16, ++ (Char_UUID_t*)&uuid, ++ strlen(dev_info_svc->hardware_revision), ++ CHAR_PROP_READ, ++ ATTR_PERMISSION_AUTHEN_READ, ++ GATT_DONT_NOTIFY_EVENTS, ++ 10, ++ CHAR_VALUE_LEN_CONSTANT, ++ &dev_info_svc->firmware_rev_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to add firmware revision char: %d", status); ++ } ++ uuid = SOFTWARE_REVISION_UUID; ++ status = aci_gatt_add_char( ++ dev_info_svc->service_handle, ++ UUID_TYPE_16, ++ (Char_UUID_t*)&uuid, ++ furi_string_size(dev_info_svc->version_string), ++ CHAR_PROP_READ, ++ ATTR_PERMISSION_AUTHEN_READ, ++ GATT_DONT_NOTIFY_EVENTS, ++ 10, ++ CHAR_VALUE_LEN_CONSTANT, ++ &dev_info_svc->software_rev_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to add software revision char: %d", status); ++ } ++ status = aci_gatt_add_char( ++ dev_info_svc->service_handle, ++ UUID_TYPE_128, ++ (const Char_UUID_t*)dev_info_rpc_version_uuid, ++ strlen(dev_info_rpc_version), ++ CHAR_PROP_READ, ++ ATTR_PERMISSION_AUTHEN_READ, ++ GATT_DONT_NOTIFY_EVENTS, ++ 10, ++ CHAR_VALUE_LEN_CONSTANT, ++ &dev_info_svc->rpc_version_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to add rpc version characteristic: %d", status); ++ } ++ ++ // Update characteristics ++ status = aci_gatt_update_char_value( ++ dev_info_svc->service_handle, ++ dev_info_svc->man_name_char_handle, ++ 0, ++ strlen(dev_info_man_name), ++ (uint8_t*)dev_info_man_name); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to update manufacturer name char: %d", status); ++ } ++ status = aci_gatt_update_char_value( ++ dev_info_svc->service_handle, ++ dev_info_svc->serial_num_char_handle, ++ 0, ++ strlen(dev_info_serial_num), ++ (uint8_t*)dev_info_serial_num); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to update serial number char: %d", status); ++ } ++ status = aci_gatt_update_char_value( ++ dev_info_svc->service_handle, ++ dev_info_svc->firmware_rev_char_handle, ++ 0, ++ strlen(dev_info_svc->hardware_revision), ++ (uint8_t*)dev_info_svc->hardware_revision); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to update firmware revision char: %d", status); ++ } ++ status = aci_gatt_update_char_value( ++ dev_info_svc->service_handle, ++ dev_info_svc->software_rev_char_handle, ++ 0, ++ furi_string_size(dev_info_svc->version_string), ++ (uint8_t*)furi_string_get_cstr(dev_info_svc->version_string)); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to update software revision char: %d", status); ++ } ++ status = aci_gatt_update_char_value( ++ dev_info_svc->service_handle, ++ dev_info_svc->rpc_version_char_handle, ++ 0, ++ strlen(dev_info_rpc_version), ++ (uint8_t*)dev_info_rpc_version); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to update rpc version char: %d", status); ++ } ++} ++ ++void dev_info_svc_stop() { ++ tBleStatus status; ++ if(dev_info_svc) { ++ furi_string_free(dev_info_svc->version_string); ++ // Delete service characteristics ++ status = ++ aci_gatt_del_char(dev_info_svc->service_handle, dev_info_svc->man_name_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to delete manufacturer name char: %d", status); ++ } ++ status = ++ aci_gatt_del_char(dev_info_svc->service_handle, dev_info_svc->serial_num_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to delete serial number char: %d", status); ++ } ++ status = aci_gatt_del_char( ++ dev_info_svc->service_handle, dev_info_svc->firmware_rev_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to delete firmware revision char: %d", status); ++ } ++ status = aci_gatt_del_char( ++ dev_info_svc->service_handle, dev_info_svc->software_rev_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to delete software revision char: %d", status); ++ } ++ status = ++ aci_gatt_del_char(dev_info_svc->service_handle, dev_info_svc->rpc_version_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to delete rpc version char: %d", status); ++ } ++ // Delete service ++ status = aci_gatt_del_service(dev_info_svc->service_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to delete device info service: %d", status); ++ } ++ free(dev_info_svc); ++ dev_info_svc = NULL; ++ } ++} ++ ++bool dev_info_svc_is_started() { ++ return dev_info_svc != NULL; ++} +diff --git a/firmware/targets/f7/ble_glue/services/dev_info_service.h b/firmware/targets/f7/ble_glue/dev_info_service.h +similarity index 100% +rename from firmware/targets/f7/ble_glue/services/dev_info_service.h +rename to firmware/targets/f7/ble_glue/dev_info_service.h +diff --git a/firmware/targets/f7/ble_glue/hid_service.c b/firmware/targets/f7/ble_glue/hid_service.c +new file mode 100644 +index 0000000000..a31d6015f5 +--- /dev/null ++++ b/firmware/targets/f7/ble_glue/hid_service.c +@@ -0,0 +1,416 @@ ++#include "hid_service.h" ++#include "app_common.h" ++#include ++ ++#include ++ ++#define TAG "BtHid" ++ ++typedef struct { ++ uint16_t svc_handle; ++ uint16_t protocol_mode_char_handle; ++ uint16_t report_char_handle[HID_SVC_REPORT_COUNT]; ++ uint16_t report_ref_desc_handle[HID_SVC_REPORT_COUNT]; ++ uint16_t report_map_char_handle; ++ uint16_t info_char_handle; ++ uint16_t ctrl_point_char_handle; ++ // led state ++ uint16_t led_state_char_handle; ++ uint16_t led_state_desc_handle; ++ HidLedStateEventCallback led_state_event_callback; ++ void* led_state_ctx; ++} HIDSvc; ++ ++static HIDSvc* hid_svc = NULL; ++ ++static SVCCTL_EvtAckStatus_t hid_svc_event_handler(void* event) { ++ SVCCTL_EvtAckStatus_t ret = SVCCTL_EvtNotAck; ++ hci_event_pckt* event_pckt = (hci_event_pckt*)(((hci_uart_pckt*)event)->data); ++ evt_blecore_aci* blecore_evt = (evt_blecore_aci*)event_pckt->data; ++ // aci_gatt_attribute_modified_event_rp0* attribute_modified; ++ if(event_pckt->evt == HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE) { ++ if(blecore_evt->ecode == ACI_GATT_ATTRIBUTE_MODIFIED_VSEVT_CODE) { ++ // Process modification events ++ ret = SVCCTL_EvtAckFlowEnable; ++ } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) { ++ // Process notification confirmation ++ ret = SVCCTL_EvtAckFlowEnable; ++ } else if(blecore_evt->ecode == ACI_GATT_WRITE_PERMIT_REQ_VSEVT_CODE) { ++ // Process write request ++ aci_gatt_write_permit_req_event_rp0* req = ++ (aci_gatt_write_permit_req_event_rp0*)blecore_evt->data; ++ ++ furi_check(hid_svc->led_state_event_callback && hid_svc->led_state_ctx); ++ ++ // this check is likely to be incorrect, it will actually work in our case ++ // but we need to investigate gatt api to see what is the rules ++ // that specify attibute handle value from char handle (or the reverse) ++ if(req->Attribute_Handle == (hid_svc->led_state_char_handle + 1)) { ++ hid_svc->led_state_event_callback(req->Data[0], hid_svc->led_state_ctx); ++ aci_gatt_write_resp( ++ req->Connection_Handle, ++ req->Attribute_Handle, ++ 0x00, /* write_status = 0 (no error))*/ ++ 0x00, /* err_code */ ++ req->Data_Length, ++ req->Data); ++ aci_gatt_write_char_value( ++ req->Connection_Handle, ++ hid_svc->led_state_char_handle, ++ req->Data_Length, ++ req->Data); ++ ret = SVCCTL_EvtAckFlowEnable; ++ } ++ } ++ } ++ return ret; ++} ++ ++void hid_svc_start() { ++ tBleStatus status; ++ hid_svc = malloc(sizeof(HIDSvc)); ++ Service_UUID_t svc_uuid = {}; ++ Char_Desc_Uuid_t desc_uuid = {}; ++ Char_UUID_t char_uuid = {}; ++ ++ // Register event handler ++ SVCCTL_RegisterSvcHandler(hid_svc_event_handler); ++ // Add service ++ svc_uuid.Service_UUID_16 = HUMAN_INTERFACE_DEVICE_SERVICE_UUID; ++ /** ++ * Add Human Interface Device Service ++ */ ++ status = aci_gatt_add_service( ++ UUID_TYPE_16, ++ &svc_uuid, ++ PRIMARY_SERVICE, ++ 2 + /* protocol mode */ ++ (4 * HID_SVC_INPUT_REPORT_COUNT) + (3 * HID_SVC_OUTPUT_REPORT_COUNT) + ++ (3 * HID_SVC_FEATURE_REPORT_COUNT) + 1 + 2 + 2 + 2 + ++ 4, /* Service + Report Map + HID Information + HID Control Point + LED state */ ++ &hid_svc->svc_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to add HID service: %d", status); ++ } ++ // Add Protocol mode characteristics ++ char_uuid.Char_UUID_16 = PROTOCOL_MODE_CHAR_UUID; ++ status = aci_gatt_add_char( ++ hid_svc->svc_handle, ++ UUID_TYPE_16, ++ &char_uuid, ++ 1, ++ CHAR_PROP_READ | CHAR_PROP_WRITE_WITHOUT_RESP, ++ ATTR_PERMISSION_NONE, ++ GATT_NOTIFY_ATTRIBUTE_WRITE, ++ 10, ++ CHAR_VALUE_LEN_CONSTANT, ++ &hid_svc->protocol_mode_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to add protocol mode characteristic: %d", status); ++ } ++ // Update Protocol mode characteristic ++ uint8_t protocol_mode = 1; ++ status = aci_gatt_update_char_value( ++ hid_svc->svc_handle, hid_svc->protocol_mode_char_handle, 0, 1, &protocol_mode); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to update protocol mode characteristic: %d", status); ++ } ++ ++#if(HID_SVC_REPORT_COUNT != 0) ++ for(uint8_t i = 0; i < HID_SVC_REPORT_COUNT; i++) { ++ if(i < HID_SVC_INPUT_REPORT_COUNT) { //-V547 ++ uint8_t buf[2] = {i + 1, 1}; // 1 input ++ char_uuid.Char_UUID_16 = REPORT_CHAR_UUID; ++ status = aci_gatt_add_char( ++ hid_svc->svc_handle, ++ UUID_TYPE_16, ++ &char_uuid, ++ HID_SVC_REPORT_MAX_LEN, ++ CHAR_PROP_READ | CHAR_PROP_NOTIFY, ++ ATTR_PERMISSION_NONE, ++ GATT_DONT_NOTIFY_EVENTS, ++ 10, ++ CHAR_VALUE_LEN_VARIABLE, ++ &(hid_svc->report_char_handle[i])); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to add report characteristic: %d", status); ++ } ++ ++ desc_uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID; ++ status = aci_gatt_add_char_desc( ++ hid_svc->svc_handle, ++ hid_svc->report_char_handle[i], ++ UUID_TYPE_16, ++ &desc_uuid, ++ HID_SVC_REPORT_REF_LEN, ++ HID_SVC_REPORT_REF_LEN, ++ buf, ++ ATTR_PERMISSION_NONE, ++ ATTR_ACCESS_READ_WRITE, ++ GATT_DONT_NOTIFY_EVENTS, ++ MIN_ENCRY_KEY_SIZE, ++ CHAR_VALUE_LEN_CONSTANT, ++ &(hid_svc->report_ref_desc_handle[i])); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to add report reference descriptor: %d", status); ++ } ++ } else if((i - HID_SVC_INPUT_REPORT_COUNT) < HID_SVC_OUTPUT_REPORT_COUNT) { ++ uint8_t buf[2] = {i + 1, 2}; // 2 output ++ char_uuid.Char_UUID_16 = REPORT_CHAR_UUID; ++ status = aci_gatt_add_char( ++ hid_svc->svc_handle, ++ UUID_TYPE_16, ++ &char_uuid, ++ HID_SVC_REPORT_MAX_LEN, ++ CHAR_PROP_READ | CHAR_PROP_NOTIFY, ++ ATTR_PERMISSION_NONE, ++ GATT_DONT_NOTIFY_EVENTS, ++ 10, ++ CHAR_VALUE_LEN_VARIABLE, ++ &(hid_svc->report_char_handle[i])); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to add report characteristic: %d", status); ++ } ++ ++ desc_uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID; ++ status = aci_gatt_add_char_desc( ++ hid_svc->svc_handle, ++ hid_svc->report_char_handle[i], ++ UUID_TYPE_16, ++ &desc_uuid, ++ HID_SVC_REPORT_REF_LEN, ++ HID_SVC_REPORT_REF_LEN, ++ buf, ++ ATTR_PERMISSION_NONE, ++ ATTR_ACCESS_READ_WRITE, ++ GATT_DONT_NOTIFY_EVENTS, ++ MIN_ENCRY_KEY_SIZE, ++ CHAR_VALUE_LEN_CONSTANT, ++ &(hid_svc->report_ref_desc_handle[i])); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to add report reference descriptor: %d", status); ++ } ++ } else { ++ uint8_t buf[2] = {i + 1, 3}; // 3 feature ++ char_uuid.Char_UUID_16 = REPORT_CHAR_UUID; ++ status = aci_gatt_add_char( ++ hid_svc->svc_handle, ++ UUID_TYPE_16, ++ &char_uuid, ++ HID_SVC_REPORT_MAX_LEN, ++ CHAR_PROP_READ | CHAR_PROP_NOTIFY, ++ ATTR_PERMISSION_NONE, ++ GATT_DONT_NOTIFY_EVENTS, ++ 10, ++ CHAR_VALUE_LEN_VARIABLE, ++ &(hid_svc->report_char_handle[i])); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to add report characteristic: %d", status); ++ } ++ ++ desc_uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID; ++ status = aci_gatt_add_char_desc( ++ hid_svc->svc_handle, ++ hid_svc->report_char_handle[i], ++ UUID_TYPE_16, ++ &desc_uuid, ++ HID_SVC_REPORT_REF_LEN, ++ HID_SVC_REPORT_REF_LEN, ++ buf, ++ ATTR_PERMISSION_NONE, ++ ATTR_ACCESS_READ_WRITE, ++ GATT_DONT_NOTIFY_EVENTS, ++ MIN_ENCRY_KEY_SIZE, ++ CHAR_VALUE_LEN_CONSTANT, ++ &(hid_svc->report_ref_desc_handle[i])); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to add report reference descriptor: %d", status); ++ } ++ } ++ } ++#endif ++ // Add led state output report ++ char_uuid.Char_UUID_16 = REPORT_CHAR_UUID; ++ status = aci_gatt_add_char( ++ hid_svc->svc_handle, ++ UUID_TYPE_16, ++ &char_uuid, ++ 1, ++ CHAR_PROP_READ | CHAR_PROP_WRITE_WITHOUT_RESP | CHAR_PROP_WRITE, ++ ATTR_PERMISSION_NONE, ++ GATT_NOTIFY_ATTRIBUTE_WRITE | GATT_NOTIFY_WRITE_REQ_AND_WAIT_FOR_APPL_RESP, ++ 10, ++ CHAR_VALUE_LEN_CONSTANT, ++ &(hid_svc->led_state_char_handle)); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to add led state characteristic: %d", status); ++ } ++ ++ // Add led state char descriptor specifying it is an output report ++ uint8_t buf[2] = {HID_SVC_REPORT_COUNT + 1, 2}; ++ desc_uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID; ++ status = aci_gatt_add_char_desc( ++ hid_svc->svc_handle, ++ hid_svc->led_state_char_handle, ++ UUID_TYPE_16, ++ &desc_uuid, ++ HID_SVC_REPORT_REF_LEN, ++ HID_SVC_REPORT_REF_LEN, ++ buf, ++ ATTR_PERMISSION_NONE, ++ ATTR_ACCESS_READ_WRITE, ++ GATT_DONT_NOTIFY_EVENTS, ++ MIN_ENCRY_KEY_SIZE, ++ CHAR_VALUE_LEN_CONSTANT, ++ &(hid_svc->led_state_desc_handle)); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to add led state descriptor: %d", status); ++ } ++ // Add Report Map characteristic ++ char_uuid.Char_UUID_16 = REPORT_MAP_CHAR_UUID; ++ status = aci_gatt_add_char( ++ hid_svc->svc_handle, ++ UUID_TYPE_16, ++ &char_uuid, ++ HID_SVC_REPORT_MAP_MAX_LEN, ++ CHAR_PROP_READ, ++ ATTR_PERMISSION_NONE, ++ GATT_DONT_NOTIFY_EVENTS, ++ 10, ++ CHAR_VALUE_LEN_VARIABLE, ++ &hid_svc->report_map_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to add report map characteristic: %d", status); ++ } ++ ++ // Add Information characteristic ++ char_uuid.Char_UUID_16 = HID_INFORMATION_CHAR_UUID; ++ status = aci_gatt_add_char( ++ hid_svc->svc_handle, ++ UUID_TYPE_16, ++ &char_uuid, ++ HID_SVC_INFO_LEN, ++ CHAR_PROP_READ, ++ ATTR_PERMISSION_NONE, ++ GATT_DONT_NOTIFY_EVENTS, ++ 10, ++ CHAR_VALUE_LEN_CONSTANT, ++ &hid_svc->info_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to add information characteristic: %d", status); ++ } ++ // Add Control Point characteristic ++ char_uuid.Char_UUID_16 = HID_CONTROL_POINT_CHAR_UUID; ++ status = aci_gatt_add_char( ++ hid_svc->svc_handle, ++ UUID_TYPE_16, ++ &char_uuid, ++ HID_SVC_CONTROL_POINT_LEN, ++ CHAR_PROP_WRITE_WITHOUT_RESP, ++ ATTR_PERMISSION_NONE, ++ GATT_NOTIFY_ATTRIBUTE_WRITE, ++ 10, ++ CHAR_VALUE_LEN_CONSTANT, ++ &hid_svc->ctrl_point_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to add control point characteristic: %d", status); ++ } ++ ++ hid_svc->led_state_event_callback = NULL; ++ hid_svc->led_state_ctx = NULL; ++} ++ ++bool hid_svc_update_report_map(const uint8_t* data, uint16_t len) { ++ furi_assert(data); ++ furi_assert(hid_svc); ++ ++ tBleStatus status = aci_gatt_update_char_value( ++ hid_svc->svc_handle, hid_svc->report_map_char_handle, 0, len, data); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed updating report map characteristic: %d", status); ++ return false; ++ } ++ return true; ++} ++ ++bool hid_svc_update_input_report(uint8_t input_report_num, uint8_t* data, uint16_t len) { ++ furi_assert(data); ++ furi_assert(hid_svc); ++ ++ tBleStatus status = aci_gatt_update_char_value( ++ hid_svc->svc_handle, hid_svc->report_char_handle[input_report_num], 0, len, data); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed updating report characteristic: %d", status); ++ return false; ++ } ++ return true; ++} ++ ++bool hid_svc_update_info(uint8_t* data, uint16_t len) { ++ furi_assert(data); ++ furi_assert(hid_svc); ++ ++ tBleStatus status = ++ aci_gatt_update_char_value(hid_svc->svc_handle, hid_svc->info_char_handle, 0, len, data); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed updating info characteristic: %d", status); ++ return false; ++ } ++ return true; ++} ++ ++void hid_svc_register_led_state_callback(HidLedStateEventCallback callback, void* context) { ++ furi_assert(hid_svc); ++ furi_assert(callback); ++ furi_assert(context); ++ ++ hid_svc->led_state_event_callback = callback; ++ hid_svc->led_state_ctx = context; ++} ++ ++bool hid_svc_is_started() { ++ return hid_svc != NULL; ++} ++ ++void hid_svc_stop() { ++ tBleStatus status; ++ if(hid_svc) { ++ // Delete characteristics ++ status = aci_gatt_del_char(hid_svc->svc_handle, hid_svc->report_map_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to delete Report Map characteristic: %d", status); ++ } ++#if(HID_SVC_INPUT_REPORT_COUNT != 0) ++ for(uint8_t i = 0; i < HID_SVC_REPORT_COUNT; i++) { ++ status = aci_gatt_del_char(hid_svc->svc_handle, hid_svc->report_char_handle[i]); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to delete Report characteristic: %d", status); ++ } ++ } ++#endif ++ status = aci_gatt_del_char(hid_svc->svc_handle, hid_svc->protocol_mode_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to delete Protocol Mode characteristic: %d", status); ++ } ++ status = aci_gatt_del_char(hid_svc->svc_handle, hid_svc->info_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to delete Information characteristic: %d", status); ++ } ++ status = aci_gatt_del_char(hid_svc->svc_handle, hid_svc->ctrl_point_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to delete Control Point characteristic: %d", status); ++ } ++ status = aci_gatt_del_char(hid_svc->svc_handle, hid_svc->led_state_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to delete led state characteristic: %d", status); ++ } ++ // Delete service ++ status = aci_gatt_del_service(hid_svc->svc_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to delete HID service: %d", status); ++ } ++ // Delete buffer size mutex ++ free(hid_svc); ++ hid_svc = NULL; ++ } ++} +diff --git a/firmware/targets/f7/ble_glue/services/hid_service.h b/firmware/targets/f7/ble_glue/hid_service.h +similarity index 89% +rename from firmware/targets/f7/ble_glue/services/hid_service.h +rename to firmware/targets/f7/ble_glue/hid_service.h +index 4d0ed4c4f9..b8f6b244d2 100644 +--- a/firmware/targets/f7/ble_glue/services/hid_service.h ++++ b/firmware/targets/f7/ble_glue/hid_service.h +@@ -27,7 +27,6 @@ bool hid_svc_update_report_map(const uint8_t* data, uint16_t len); + + bool hid_svc_update_input_report(uint8_t input_report_num, uint8_t* data, uint16_t len); + +-// Expects data to be of length HID_SVC_INFO_LEN (4 bytes) +-bool hid_svc_update_info(uint8_t* data); ++bool hid_svc_update_info(uint8_t* data, uint16_t len); + + void hid_svc_register_led_state_callback(HidLedStateEventCallback callback, void* context); +diff --git a/firmware/targets/f7/ble_glue/services/serial_service.c b/firmware/targets/f7/ble_glue/serial_service.c +similarity index 57% +rename from firmware/targets/f7/ble_glue/services/serial_service.c +rename to firmware/targets/f7/ble_glue/serial_service.c +index ab009bbfcb..c6421dc28f 100644 +--- a/firmware/targets/f7/ble_glue/services/serial_service.c ++++ b/firmware/targets/f7/ble_glue/serial_service.c +@@ -1,67 +1,17 @@ + #include "serial_service.h" + #include "app_common.h" + #include +-#include "gatt_char.h" + + #include + +-#include "serial_service_uuid.inc" +- + #define TAG "BtSerialSvc" + +-typedef enum { +- SerialSvcGattCharacteristicTx = 0, +- SerialSvcGattCharacteristicRx, +- SerialSvcGattCharacteristicFlowCtrl, +- SerialSvcGattCharacteristicStatus, +- SerialSvcGattCharacteristicCount, +-} SerialSvcGattCharacteristicId; +- +-static const FlipperGattCharacteristicParams serial_svc_chars[SerialSvcGattCharacteristicCount] = { +- [SerialSvcGattCharacteristicTx] = +- {.name = "TX", +- .data_prop_type = FlipperGattCharacteristicDataFixed, +- .data.fixed.length = SERIAL_SVC_DATA_LEN_MAX, +- .uuid.Char_UUID_128 = SERIAL_SVC_TX_CHAR_UUID, +- .uuid_type = UUID_TYPE_128, +- .char_properties = CHAR_PROP_READ | CHAR_PROP_INDICATE, +- .security_permissions = ATTR_PERMISSION_AUTHEN_READ, +- .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, +- .is_variable = CHAR_VALUE_LEN_VARIABLE}, +- [SerialSvcGattCharacteristicRx] = +- {.name = "RX", +- .data_prop_type = FlipperGattCharacteristicDataFixed, +- .data.fixed.length = SERIAL_SVC_DATA_LEN_MAX, +- .uuid.Char_UUID_128 = SERIAL_SVC_RX_CHAR_UUID, +- .uuid_type = UUID_TYPE_128, +- .char_properties = CHAR_PROP_WRITE_WITHOUT_RESP | CHAR_PROP_WRITE | CHAR_PROP_READ, +- .security_permissions = ATTR_PERMISSION_AUTHEN_READ | ATTR_PERMISSION_AUTHEN_WRITE, +- .gatt_evt_mask = GATT_NOTIFY_ATTRIBUTE_WRITE, +- .is_variable = CHAR_VALUE_LEN_VARIABLE}, +- [SerialSvcGattCharacteristicFlowCtrl] = +- {.name = "Flow control", +- .data_prop_type = FlipperGattCharacteristicDataFixed, +- .data.fixed.length = sizeof(uint32_t), +- .uuid.Char_UUID_128 = SERIAL_SVC_FLOW_CONTROL_UUID, +- .uuid_type = UUID_TYPE_128, +- .char_properties = CHAR_PROP_READ | CHAR_PROP_NOTIFY, +- .security_permissions = ATTR_PERMISSION_AUTHEN_READ, +- .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, +- .is_variable = CHAR_VALUE_LEN_CONSTANT}, +- [SerialSvcGattCharacteristicStatus] = { +- .name = "RPC status", +- .data_prop_type = FlipperGattCharacteristicDataFixed, +- .data.fixed.length = sizeof(SerialServiceRpcStatus), +- .uuid.Char_UUID_128 = SERIAL_SVC_RPC_STATUS_UUID, +- .uuid_type = UUID_TYPE_128, +- .char_properties = CHAR_PROP_READ | CHAR_PROP_WRITE | CHAR_PROP_NOTIFY, +- .security_permissions = ATTR_PERMISSION_AUTHEN_READ | ATTR_PERMISSION_AUTHEN_WRITE, +- .gatt_evt_mask = GATT_NOTIFY_ATTRIBUTE_WRITE, +- .is_variable = CHAR_VALUE_LEN_CONSTANT}}; +- + typedef struct { + uint16_t svc_handle; +- FlipperGattCharacteristicInstance chars[SerialSvcGattCharacteristicCount]; ++ uint16_t rx_char_handle; ++ uint16_t tx_char_handle; ++ uint16_t flow_ctrl_char_handle; ++ uint16_t rpc_status_char_handle; + FuriMutex* buff_size_mtx; + uint32_t buff_size; + uint16_t bytes_ready_to_receive; +@@ -71,6 +21,17 @@ typedef struct { + + static SerialSvc* serial_svc = NULL; + ++static const uint8_t service_uuid[] = ++ {0x00, 0x00, 0xfe, 0x60, 0xcc, 0x7a, 0x48, 0x2a, 0x98, 0x4a, 0x7f, 0x2e, 0xd5, 0xb3, 0xe5, 0x8f}; ++static const uint8_t char_tx_uuid[] = ++ {0x00, 0x00, 0xfe, 0x61, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19}; ++static const uint8_t char_rx_uuid[] = ++ {0x00, 0x00, 0xfe, 0x62, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19}; ++static const uint8_t flow_ctrl_uuid[] = ++ {0x00, 0x00, 0xfe, 0x63, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19}; ++static const uint8_t rpc_status_uuid[] = ++ {0x00, 0x00, 0xfe, 0x64, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19}; ++ + static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void* event) { + SVCCTL_EvtAckStatus_t ret = SVCCTL_EvtNotAck; + hci_event_pckt* event_pckt = (hci_event_pckt*)(((hci_uart_pckt*)event)->data); +@@ -79,14 +40,11 @@ static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void* event) { + if(event_pckt->evt == HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE) { + if(blecore_evt->ecode == ACI_GATT_ATTRIBUTE_MODIFIED_VSEVT_CODE) { + attribute_modified = (aci_gatt_attribute_modified_event_rp0*)blecore_evt->data; +- if(attribute_modified->Attr_Handle == +- serial_svc->chars[SerialSvcGattCharacteristicRx].handle + 2) { ++ if(attribute_modified->Attr_Handle == serial_svc->rx_char_handle + 2) { + // Descriptor handle + ret = SVCCTL_EvtAckFlowEnable; + FURI_LOG_D(TAG, "RX descriptor event"); +- } else if( +- attribute_modified->Attr_Handle == +- serial_svc->chars[SerialSvcGattCharacteristicRx].handle + 1) { ++ } else if(attribute_modified->Attr_Handle == serial_svc->rx_char_handle + 1) { + FURI_LOG_D(TAG, "Received %d bytes", attribute_modified->Attr_Data_Length); + if(serial_svc->callback) { + furi_check( +@@ -112,9 +70,7 @@ static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void* event) { + furi_check(furi_mutex_release(serial_svc->buff_size_mtx) == FuriStatusOk); + } + ret = SVCCTL_EvtAckFlowEnable; +- } else if( +- attribute_modified->Attr_Handle == +- serial_svc->chars[SerialSvcGattCharacteristicStatus].handle + 1) { ++ } else if(attribute_modified->Attr_Handle == serial_svc->rpc_status_char_handle + 1) { + SerialServiceRpcStatus* rpc_status = + (SerialServiceRpcStatus*)attribute_modified->Attr_Data; + if(*rpc_status == SerialServiceRpcStatusNotActive) { +@@ -141,12 +97,18 @@ static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void* event) { + } + + static void serial_svc_update_rpc_char(SerialServiceRpcStatus status) { +- flipper_gatt_characteristic_update( +- serial_svc->svc_handle, &serial_svc->chars[SerialSvcGattCharacteristicStatus], &status); ++ tBleStatus ble_status = aci_gatt_update_char_value( ++ serial_svc->svc_handle, ++ serial_svc->rpc_status_char_handle, ++ 0, ++ sizeof(SerialServiceRpcStatus), ++ (uint8_t*)&status); ++ if(ble_status) { ++ FURI_LOG_E(TAG, "Failed to update RPC status char: %d", ble_status); ++ } + } + + void serial_svc_start() { +- UNUSED(serial_svc_chars); + tBleStatus status; + serial_svc = malloc(sizeof(SerialSvc)); + // Register event handler +@@ -154,17 +116,72 @@ void serial_svc_start() { + + // Add service + status = aci_gatt_add_service( +- UUID_TYPE_128, &service_uuid, PRIMARY_SERVICE, 12, &serial_svc->svc_handle); ++ UUID_TYPE_128, (Service_UUID_t*)service_uuid, PRIMARY_SERVICE, 12, &serial_svc->svc_handle); + if(status) { + FURI_LOG_E(TAG, "Failed to add Serial service: %d", status); + } + +- // Add characteristics +- for(uint8_t i = 0; i < SerialSvcGattCharacteristicCount; i++) { +- flipper_gatt_characteristic_init( +- serial_svc->svc_handle, &serial_svc_chars[i], &serial_svc->chars[i]); ++ // Add RX characteristics ++ status = aci_gatt_add_char( ++ serial_svc->svc_handle, ++ UUID_TYPE_128, ++ (const Char_UUID_t*)char_rx_uuid, ++ SERIAL_SVC_DATA_LEN_MAX, ++ CHAR_PROP_WRITE_WITHOUT_RESP | CHAR_PROP_WRITE | CHAR_PROP_READ, ++ ATTR_PERMISSION_AUTHEN_READ | ATTR_PERMISSION_AUTHEN_WRITE, ++ GATT_NOTIFY_ATTRIBUTE_WRITE, ++ 10, ++ CHAR_VALUE_LEN_VARIABLE, ++ &serial_svc->rx_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to add RX characteristic: %d", status); + } + ++ // Add TX characteristic ++ status = aci_gatt_add_char( ++ serial_svc->svc_handle, ++ UUID_TYPE_128, ++ (const Char_UUID_t*)char_tx_uuid, ++ SERIAL_SVC_DATA_LEN_MAX, ++ CHAR_PROP_READ | CHAR_PROP_INDICATE, ++ ATTR_PERMISSION_AUTHEN_READ, ++ GATT_DONT_NOTIFY_EVENTS, ++ 10, ++ CHAR_VALUE_LEN_VARIABLE, ++ &serial_svc->tx_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to add TX characteristic: %d", status); ++ } ++ // Add Flow Control characteristic ++ status = aci_gatt_add_char( ++ serial_svc->svc_handle, ++ UUID_TYPE_128, ++ (const Char_UUID_t*)flow_ctrl_uuid, ++ sizeof(uint32_t), ++ CHAR_PROP_READ | CHAR_PROP_NOTIFY, ++ ATTR_PERMISSION_AUTHEN_READ, ++ GATT_DONT_NOTIFY_EVENTS, ++ 10, ++ CHAR_VALUE_LEN_CONSTANT, ++ &serial_svc->flow_ctrl_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to add Flow Control characteristic: %d", status); ++ } ++ // Add RPC status characteristic ++ status = aci_gatt_add_char( ++ serial_svc->svc_handle, ++ UUID_TYPE_128, ++ (const Char_UUID_t*)rpc_status_uuid, ++ sizeof(SerialServiceRpcStatus), ++ CHAR_PROP_READ | CHAR_PROP_WRITE | CHAR_PROP_NOTIFY, ++ ATTR_PERMISSION_AUTHEN_READ | ATTR_PERMISSION_AUTHEN_WRITE, ++ GATT_NOTIFY_ATTRIBUTE_WRITE, ++ 10, ++ CHAR_VALUE_LEN_CONSTANT, ++ &serial_svc->rpc_status_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to add RPC status characteristic: %d", status); ++ } + serial_svc_update_rpc_char(SerialServiceRpcStatusNotActive); + // Allocate buffer size mutex + serial_svc->buff_size_mtx = furi_mutex_alloc(FuriMutexTypeNormal); +@@ -179,12 +196,13 @@ void serial_svc_set_callbacks( + serial_svc->context = context; + serial_svc->buff_size = buff_size; + serial_svc->bytes_ready_to_receive = buff_size; +- + uint32_t buff_size_reversed = REVERSE_BYTES_U32(serial_svc->buff_size); +- flipper_gatt_characteristic_update( ++ aci_gatt_update_char_value( + serial_svc->svc_handle, +- &serial_svc->chars[SerialSvcGattCharacteristicFlowCtrl], +- &buff_size_reversed); ++ serial_svc->flow_ctrl_char_handle, ++ 0, ++ sizeof(uint32_t), ++ (uint8_t*)&buff_size_reversed); + } + + void serial_svc_notify_buffer_is_empty() { +@@ -195,12 +213,13 @@ void serial_svc_notify_buffer_is_empty() { + if(serial_svc->bytes_ready_to_receive == 0) { + FURI_LOG_D(TAG, "Buffer is empty. Notifying client"); + serial_svc->bytes_ready_to_receive = serial_svc->buff_size; +- + uint32_t buff_size_reversed = REVERSE_BYTES_U32(serial_svc->buff_size); +- flipper_gatt_characteristic_update( ++ aci_gatt_update_char_value( + serial_svc->svc_handle, +- &serial_svc->chars[SerialSvcGattCharacteristicFlowCtrl], +- &buff_size_reversed); ++ serial_svc->flow_ctrl_char_handle, ++ 0, ++ sizeof(uint32_t), ++ (uint8_t*)&buff_size_reversed); + } + furi_check(furi_mutex_release(serial_svc->buff_size_mtx) == FuriStatusOk); + } +@@ -208,8 +227,22 @@ void serial_svc_notify_buffer_is_empty() { + void serial_svc_stop() { + tBleStatus status; + if(serial_svc) { +- for(uint8_t i = 0; i < SerialSvcGattCharacteristicCount; i++) { +- flipper_gatt_characteristic_delete(serial_svc->svc_handle, &serial_svc->chars[i]); ++ // Delete characteristics ++ status = aci_gatt_del_char(serial_svc->svc_handle, serial_svc->tx_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to delete TX characteristic: %d", status); ++ } ++ status = aci_gatt_del_char(serial_svc->svc_handle, serial_svc->rx_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to delete RX characteristic: %d", status); ++ } ++ status = aci_gatt_del_char(serial_svc->svc_handle, serial_svc->flow_ctrl_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to delete Flow Control characteristic: %d", status); ++ } ++ status = aci_gatt_del_char(serial_svc->svc_handle, serial_svc->rpc_status_char_handle); ++ if(status) { ++ FURI_LOG_E(TAG, "Failed to delete RPC Status characteristic: %d", status); + } + // Delete service + status = aci_gatt_del_service(serial_svc->svc_handle); +@@ -240,7 +273,7 @@ bool serial_svc_update_tx(uint8_t* data, uint16_t data_len) { + tBleStatus result = aci_gatt_update_char_value_ext( + 0, + serial_svc->svc_handle, +- serial_svc->chars[SerialSvcGattCharacteristicTx].handle, ++ serial_svc->tx_char_handle, + remained ? 0x00 : 0x02, + data_len, + value_offset, +diff --git a/firmware/targets/f7/ble_glue/services/serial_service.h b/firmware/targets/f7/ble_glue/serial_service.h +similarity index 100% +rename from firmware/targets/f7/ble_glue/services/serial_service.h +rename to firmware/targets/f7/ble_glue/serial_service.h +diff --git a/firmware/targets/f7/ble_glue/services/dev_info_service.c b/firmware/targets/f7/ble_glue/services/dev_info_service.c +deleted file mode 100644 +index 5bee97b416..0000000000 +--- a/firmware/targets/f7/ble_glue/services/dev_info_service.c ++++ /dev/null +@@ -1,176 +0,0 @@ +-#include "dev_info_service.h" +-#include "app_common.h" +-#include "gatt_char.h" +-#include +- +-#include +-#include +-#include +- +-#include "dev_info_service_uuid.inc" +- +-#define TAG "BtDevInfoSvc" +- +-typedef enum { +- DevInfoSvcGattCharacteristicMfgName = 0, +- DevInfoSvcGattCharacteristicSerial, +- DevInfoSvcGattCharacteristicFirmwareRev, +- DevInfoSvcGattCharacteristicSoftwareRev, +- DevInfoSvcGattCharacteristicRpcVersion, +- DevInfoSvcGattCharacteristicCount, +-} DevInfoSvcGattCharacteristicId; +- +-#define DEVICE_INFO_HARDWARE_REV_SIZE 4 +-typedef struct { +- uint16_t service_handle; +- FlipperGattCharacteristicInstance characteristics[DevInfoSvcGattCharacteristicCount]; +- FuriString* version_string; +- char hardware_revision[DEVICE_INFO_HARDWARE_REV_SIZE]; +-} DevInfoSvc; +- +-static DevInfoSvc* dev_info_svc = NULL; +- +-static const char dev_info_man_name[] = "Flipper Devices Inc."; +-static const char dev_info_serial_num[] = "1.0"; +-static const char dev_info_rpc_version[] = TOSTRING(PROTOBUF_MAJOR_VERSION.PROTOBUF_MINOR_VERSION); +- +-static bool dev_info_char_firmware_rev_callback( +- const void* context, +- const uint8_t** data, +- uint16_t* data_len) { +- const DevInfoSvc* dev_info_svc = *(DevInfoSvc**)context; +- *data_len = sizeof(dev_info_svc->hardware_revision); +- if(data) { +- *data = (const uint8_t*)&dev_info_svc->hardware_revision; +- } +- return false; +-} +- +-static bool dev_info_char_software_rev_callback( +- const void* context, +- const uint8_t** data, +- uint16_t* data_len) { +- const DevInfoSvc* dev_info_svc = *(DevInfoSvc**)context; +- *data_len = furi_string_size(dev_info_svc->version_string); +- if(data) { +- *data = (const uint8_t*)furi_string_get_cstr(dev_info_svc->version_string); +- } +- return false; +-} +- +-static const FlipperGattCharacteristicParams dev_info_svc_chars[DevInfoSvcGattCharacteristicCount] = +- {[DevInfoSvcGattCharacteristicMfgName] = +- {.name = "Manufacturer Name", +- .data_prop_type = FlipperGattCharacteristicDataFixed, +- .data.fixed.length = sizeof(dev_info_man_name) - 1, +- .data.fixed.ptr = (const uint8_t*)&dev_info_man_name, +- .uuid.Char_UUID_16 = MANUFACTURER_NAME_UUID, +- .uuid_type = UUID_TYPE_16, +- .char_properties = CHAR_PROP_READ, +- .security_permissions = ATTR_PERMISSION_AUTHEN_READ, +- .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, +- .is_variable = CHAR_VALUE_LEN_CONSTANT}, +- [DevInfoSvcGattCharacteristicSerial] = +- {.name = "Serial Number", +- .data_prop_type = FlipperGattCharacteristicDataFixed, +- .data.fixed.length = sizeof(dev_info_serial_num) - 1, +- .data.fixed.ptr = (const uint8_t*)&dev_info_serial_num, +- .uuid.Char_UUID_16 = SERIAL_NUMBER_UUID, +- .uuid_type = UUID_TYPE_16, +- .char_properties = CHAR_PROP_READ, +- .security_permissions = ATTR_PERMISSION_AUTHEN_READ, +- .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, +- .is_variable = CHAR_VALUE_LEN_CONSTANT}, +- [DevInfoSvcGattCharacteristicFirmwareRev] = +- {.name = "Firmware Revision", +- .data_prop_type = FlipperGattCharacteristicDataCallback, +- .data.callback.context = &dev_info_svc, +- .data.callback.fn = dev_info_char_firmware_rev_callback, +- .uuid.Char_UUID_16 = FIRMWARE_REVISION_UUID, +- .uuid_type = UUID_TYPE_16, +- .char_properties = CHAR_PROP_READ, +- .security_permissions = ATTR_PERMISSION_AUTHEN_READ, +- .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, +- .is_variable = CHAR_VALUE_LEN_CONSTANT}, +- [DevInfoSvcGattCharacteristicSoftwareRev] = +- {.name = "Software Revision", +- .data_prop_type = FlipperGattCharacteristicDataCallback, +- .data.callback.context = &dev_info_svc, +- .data.callback.fn = dev_info_char_software_rev_callback, +- .uuid.Char_UUID_16 = SOFTWARE_REVISION_UUID, +- .uuid_type = UUID_TYPE_16, +- .char_properties = CHAR_PROP_READ, +- .security_permissions = ATTR_PERMISSION_AUTHEN_READ, +- .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, +- .is_variable = CHAR_VALUE_LEN_CONSTANT}, +- [DevInfoSvcGattCharacteristicRpcVersion] = { +- .name = "RPC Version", +- .data_prop_type = FlipperGattCharacteristicDataFixed, +- .data.fixed.length = sizeof(dev_info_rpc_version) - 1, +- .data.fixed.ptr = (const uint8_t*)&dev_info_rpc_version, +- .uuid.Char_UUID_128 = DEV_INVO_RPC_VERSION_UID, +- .uuid_type = UUID_TYPE_128, +- .char_properties = CHAR_PROP_READ, +- .security_permissions = ATTR_PERMISSION_AUTHEN_READ, +- .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, +- .is_variable = CHAR_VALUE_LEN_CONSTANT}}; +- +-void dev_info_svc_start() { +- dev_info_svc = malloc(sizeof(DevInfoSvc)); +- dev_info_svc->version_string = furi_string_alloc_printf( +- "%s %s %s %s", +- version_get_githash(NULL), +- version_get_version(NULL), +- version_get_gitbranchnum(NULL), +- version_get_builddate(NULL)); +- snprintf( +- dev_info_svc->hardware_revision, +- sizeof(dev_info_svc->hardware_revision), +- "%d", +- version_get_target(NULL)); +- tBleStatus status; +- +- // Add Device Information Service +- uint16_t uuid = DEVICE_INFORMATION_SERVICE_UUID; +- status = aci_gatt_add_service( +- UUID_TYPE_16, +- (Service_UUID_t*)&uuid, +- PRIMARY_SERVICE, +- 1 + 2 * DevInfoSvcGattCharacteristicCount, +- &dev_info_svc->service_handle); +- if(status) { +- FURI_LOG_E(TAG, "Failed to add Device Information Service: %d", status); +- } +- +- for(size_t i = 0; i < DevInfoSvcGattCharacteristicCount; i++) { +- flipper_gatt_characteristic_init( +- dev_info_svc->service_handle, +- &dev_info_svc_chars[i], +- &dev_info_svc->characteristics[i]); +- flipper_gatt_characteristic_update( +- dev_info_svc->service_handle, &dev_info_svc->characteristics[i], NULL); +- } +-} +- +-void dev_info_svc_stop() { +- tBleStatus status; +- if(dev_info_svc) { +- furi_string_free(dev_info_svc->version_string); +- // Delete service characteristics +- for(size_t i = 0; i < DevInfoSvcGattCharacteristicCount; i++) { +- flipper_gatt_characteristic_delete( +- dev_info_svc->service_handle, &dev_info_svc->characteristics[i]); +- } +- // Delete service +- status = aci_gatt_del_service(dev_info_svc->service_handle); +- if(status) { +- FURI_LOG_E(TAG, "Failed to delete device info service: %d", status); +- } +- free(dev_info_svc); +- dev_info_svc = NULL; +- } +-} +- +-bool dev_info_svc_is_started() { +- return dev_info_svc != NULL; +-} +diff --git a/firmware/targets/f7/ble_glue/services/dev_info_service_uuid.inc b/firmware/targets/f7/ble_glue/services/dev_info_service_uuid.inc +deleted file mode 100644 +index ad520f62e5..0000000000 +--- a/firmware/targets/f7/ble_glue/services/dev_info_service_uuid.inc ++++ /dev/null +@@ -1,3 +0,0 @@ +-#define DEV_INVO_RPC_VERSION_UID \ +- { 0x33, 0xa9, 0xb5, 0x3e, 0x87, 0x5d, 0x1a, 0x8e, 0xc8, 0x47, 0x5e, 0xae, 0x6d, 0x66, 0xf6, 0x03 } +- +diff --git a/firmware/targets/f7/ble_glue/services/gatt_char.c b/firmware/targets/f7/ble_glue/services/gatt_char.c +deleted file mode 100644 +index 9b6a44f61b..0000000000 +--- a/firmware/targets/f7/ble_glue/services/gatt_char.c ++++ /dev/null +@@ -1,123 +0,0 @@ +-#include "gatt_char.h" +- +-#include +- +-#define TAG "GattChar" +- +-#define GATT_MIN_READ_KEY_SIZE (10) +- +-void flipper_gatt_characteristic_init( +- uint16_t svc_handle, +- const FlipperGattCharacteristicParams* char_descriptor, +- FlipperGattCharacteristicInstance* char_instance) { +- furi_assert(char_descriptor); +- furi_assert(char_instance); +- +- // Copy the descriptor to the instance, since it may point to stack memory +- // TODO: only copy if really comes from stack +- char_instance->characteristic = malloc(sizeof(FlipperGattCharacteristicParams)); +- memcpy( +- (void*)char_instance->characteristic, +- char_descriptor, +- sizeof(FlipperGattCharacteristicParams)); +- +- uint16_t char_data_size = 0; +- if(char_descriptor->data_prop_type == FlipperGattCharacteristicDataFixed) { +- char_data_size = char_descriptor->data.fixed.length; +- } else if(char_descriptor->data_prop_type == FlipperGattCharacteristicDataCallback) { +- char_descriptor->data.callback.fn( +- char_descriptor->data.callback.context, NULL, &char_data_size); +- } +- +- tBleStatus status = aci_gatt_add_char( +- svc_handle, +- char_descriptor->uuid_type, +- &char_descriptor->uuid, +- char_data_size, +- char_descriptor->char_properties, +- char_descriptor->security_permissions, +- char_descriptor->gatt_evt_mask, +- GATT_MIN_READ_KEY_SIZE, +- char_descriptor->is_variable, +- &char_instance->handle); +- if(status) { +- FURI_LOG_E(TAG, "Failed to add %s char: %d", char_descriptor->name, status); +- } +- +- char_instance->descriptor_handle = 0; +- if((status == 0) && char_descriptor->descriptor_params) { +- uint8_t const* char_data = NULL; +- const FlipperGattCharacteristicDescriptorParams* char_data_descriptor = +- char_descriptor->descriptor_params; +- bool release_data = char_data_descriptor->data_callback.fn( +- char_data_descriptor->data_callback.context, &char_data, &char_data_size); +- +- status = aci_gatt_add_char_desc( +- svc_handle, +- char_instance->handle, +- char_data_descriptor->uuid_type, +- &char_data_descriptor->uuid, +- char_data_descriptor->max_length, +- char_data_size, +- char_data, +- char_data_descriptor->security_permissions, +- char_data_descriptor->access_permissions, +- char_data_descriptor->gatt_evt_mask, +- GATT_MIN_READ_KEY_SIZE, +- char_data_descriptor->is_variable, +- &char_instance->descriptor_handle); +- if(status) { +- FURI_LOG_E(TAG, "Failed to add %s char descriptor: %d", char_descriptor->name, status); +- } +- if(release_data) { +- free((void*)char_data); +- } +- } +-} +- +-void flipper_gatt_characteristic_delete( +- uint16_t svc_handle, +- FlipperGattCharacteristicInstance* char_instance) { +- tBleStatus status = aci_gatt_del_char(svc_handle, char_instance->handle); +- if(status) { +- FURI_LOG_E( +- TAG, "Failed to delete %s char: %d", char_instance->characteristic->name, status); +- } +- free((void*)char_instance->characteristic); +-} +- +-bool flipper_gatt_characteristic_update( +- uint16_t svc_handle, +- FlipperGattCharacteristicInstance* char_instance, +- const void* source) { +- furi_assert(char_instance); +- const FlipperGattCharacteristicParams* char_descriptor = char_instance->characteristic; +- FURI_LOG_D(TAG, "Updating %s char", char_descriptor->name); +- +- const uint8_t* char_data = NULL; +- uint16_t char_data_size = 0; +- bool release_data = false; +- if(char_descriptor->data_prop_type == FlipperGattCharacteristicDataFixed) { +- char_data = char_descriptor->data.fixed.ptr; +- if(source) { +- char_data = (uint8_t*)source; +- } +- char_data_size = char_descriptor->data.fixed.length; +- } else if(char_descriptor->data_prop_type == FlipperGattCharacteristicDataCallback) { +- const void* context = char_descriptor->data.callback.context; +- if(source) { +- context = source; +- } +- release_data = char_descriptor->data.callback.fn(context, &char_data, &char_data_size); +- } +- +- tBleStatus result = aci_gatt_update_char_value( +- svc_handle, char_instance->handle, 0, char_data_size, char_data); +- if(result) { +- FURI_LOG_E(TAG, "Failed updating %s characteristic: %d", char_descriptor->name, result); +- } +- if(release_data) { +- free((void*)char_data); +- } +- return result != BLE_STATUS_SUCCESS; +-} +\ No newline at end of file +diff --git a/firmware/targets/f7/ble_glue/services/gatt_char.h b/firmware/targets/f7/ble_glue/services/gatt_char.h +deleted file mode 100644 +index 959ab67a49..0000000000 +--- a/firmware/targets/f7/ble_glue/services/gatt_char.h ++++ /dev/null +@@ -1,96 +0,0 @@ +-#pragma once +- +-#include +-#include +-#include +- +-#include +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-// Callback signature for getting characteristic data +-// Is called when characteristic is created to get max data length. Data ptr is NULL in this case +-// The result is passed to aci_gatt_add_char as "Char_Value_Length" +-// For updates, called with a context - see flipper_gatt_characteristic_update +-// Returns true if *data ownership is transferred to the caller and will be freed +-typedef bool (*cbFlipperGattCharacteristicData)( +- const void* context, +- const uint8_t** data, +- uint16_t* data_len); +- +-typedef enum { +- FlipperGattCharacteristicDataFixed, +- FlipperGattCharacteristicDataCallback, +-} FlipperGattCharacteristicDataType; +- +-typedef struct { +- Char_Desc_Uuid_t uuid; +- struct { +- cbFlipperGattCharacteristicData fn; +- const void* context; +- } data_callback; +- uint8_t uuid_type; +- uint8_t max_length; +- uint8_t security_permissions; +- uint8_t access_permissions; +- uint8_t gatt_evt_mask; +- uint8_t is_variable; +-} FlipperGattCharacteristicDescriptorParams; +- +-typedef struct { +- const char* name; +- FlipperGattCharacteristicDescriptorParams* descriptor_params; +- union { +- struct { +- const uint8_t* ptr; +- uint16_t length; +- } fixed; +- struct { +- cbFlipperGattCharacteristicData fn; +- const void* context; +- } callback; +- } data; +- Char_UUID_t uuid; +- // Some packed bitfields to save space +- FlipperGattCharacteristicDataType data_prop_type : 2; +- uint8_t is_variable : 2; +- uint8_t uuid_type : 2; +- uint8_t char_properties; +- uint8_t security_permissions; +- uint8_t gatt_evt_mask; +-} FlipperGattCharacteristicParams; +- +-_Static_assert( +- sizeof(FlipperGattCharacteristicParams) == 36, +- "FlipperGattCharacteristicParams size must be 36 bytes"); +- +-typedef struct { +- const FlipperGattCharacteristicParams* characteristic; +- uint16_t handle; +- uint16_t descriptor_handle; +-} FlipperGattCharacteristicInstance; +- +-// Initialize a characteristic instance; copies the characteristic descriptor into the instance +-void flipper_gatt_characteristic_init( +- uint16_t svc_handle, +- const FlipperGattCharacteristicParams* char_descriptor, +- FlipperGattCharacteristicInstance* char_instance); +- +-// Delete a characteristic instance; frees the copied characteristic descriptor from the instance +-void flipper_gatt_characteristic_delete( +- uint16_t svc_handle, +- FlipperGattCharacteristicInstance* char_instance); +- +-// Update a characteristic instance; if source==NULL, uses the data from the characteristic +-// - For fixed data, fixed.ptr is used as the source if source==NULL +-// - For callback-based data, collback.context is passed as the context if source==NULL +-bool flipper_gatt_characteristic_update( +- uint16_t svc_handle, +- FlipperGattCharacteristicInstance* char_instance, +- const void* source); +- +-#ifdef __cplusplus +-} +-#endif +\ No newline at end of file +diff --git a/firmware/targets/f7/ble_glue/services/hid_service.c b/firmware/targets/f7/ble_glue/services/hid_service.c +deleted file mode 100644 +index 11f10b7b38..0000000000 +--- a/firmware/targets/f7/ble_glue/services/hid_service.c ++++ /dev/null +@@ -1,365 +0,0 @@ +-#include "hid_service.h" +-#include "app_common.h" +-#include +-#include "gatt_char.h" +- +-#include +- +-#define TAG "BtHid" +- +-typedef enum { +- HidSvcGattCharacteristicProtocolMode = 0, +- HidSvcGattCharacteristicReportMap, +- HidSvcGattCharacteristicInfo, +- HidSvcGattCharacteristicCtrlPoint, +- HidSvcGattCharacteristicLed, +- HidSvcGattCharacteristicCount, +-} HidSvcGattCharacteristicId; +- +-typedef struct { +- uint8_t report_idx; +- uint8_t report_type; +-} HidSvcReportId; +- +-static_assert(sizeof(HidSvcReportId) == sizeof(uint16_t), "HidSvcReportId must be 2 bytes"); +- +-static bool +- hid_svc_char_desc_data_callback(const void* context, const uint8_t** data, uint16_t* data_len) { +- const HidSvcReportId* report_id = context; +- *data_len = sizeof(HidSvcReportId); +- if(data) { +- *data = (const uint8_t*)report_id; +- } +- return false; +-} +- +-typedef struct { +- const void* data_ptr; +- uint16_t data_len; +-} HidSvcDataWrapper; +- +-static bool +- hid_svc_report_data_callback(const void* context, const uint8_t** data, uint16_t* data_len) { +- const HidSvcDataWrapper* report_data = context; +- if(data) { +- *data = report_data->data_ptr; +- *data_len = report_data->data_len; +- } else { +- *data_len = HID_SVC_REPORT_MAP_MAX_LEN; +- } +- return false; +-} +- +-// LED Descriptor params for BadBT +- +-static uint8_t led_desc_context_buf[2] = {HID_SVC_REPORT_COUNT + 1, 2}; +- +-static FlipperGattCharacteristicDescriptorParams hid_svc_char_descr_led = { +- .uuid_type = UUID_TYPE_16, +- .uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID, +- .max_length = HID_SVC_REPORT_REF_LEN, +- .data_callback.fn = hid_svc_char_desc_data_callback, +- .data_callback.context = led_desc_context_buf, +- .security_permissions = ATTR_PERMISSION_NONE, +- .access_permissions = ATTR_ACCESS_READ_WRITE, +- .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, +- .is_variable = CHAR_VALUE_LEN_CONSTANT, +-}; +- +-static const FlipperGattCharacteristicParams hid_svc_chars[HidSvcGattCharacteristicCount] = { +- [HidSvcGattCharacteristicProtocolMode] = +- {.name = "Protocol Mode", +- .data_prop_type = FlipperGattCharacteristicDataFixed, +- .data.fixed.length = 1, +- .uuid.Char_UUID_16 = PROTOCOL_MODE_CHAR_UUID, +- .uuid_type = UUID_TYPE_16, +- .char_properties = CHAR_PROP_READ | CHAR_PROP_WRITE_WITHOUT_RESP, +- .security_permissions = ATTR_PERMISSION_NONE, +- .gatt_evt_mask = GATT_NOTIFY_ATTRIBUTE_WRITE, +- .is_variable = CHAR_VALUE_LEN_CONSTANT}, +- [HidSvcGattCharacteristicReportMap] = +- {.name = "Report Map", +- .data_prop_type = FlipperGattCharacteristicDataCallback, +- .data.callback.fn = hid_svc_report_data_callback, +- .data.callback.context = NULL, +- .uuid.Char_UUID_16 = REPORT_MAP_CHAR_UUID, +- .uuid_type = UUID_TYPE_16, +- .char_properties = CHAR_PROP_READ, +- .security_permissions = ATTR_PERMISSION_NONE, +- .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, +- .is_variable = CHAR_VALUE_LEN_VARIABLE}, +- [HidSvcGattCharacteristicInfo] = +- {.name = "HID Information", +- .data_prop_type = FlipperGattCharacteristicDataFixed, +- .data.fixed.length = HID_SVC_INFO_LEN, +- .data.fixed.ptr = NULL, +- .uuid.Char_UUID_16 = HID_INFORMATION_CHAR_UUID, +- .uuid_type = UUID_TYPE_16, +- .char_properties = CHAR_PROP_READ, +- .security_permissions = ATTR_PERMISSION_NONE, +- .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, +- .is_variable = CHAR_VALUE_LEN_CONSTANT}, +- [HidSvcGattCharacteristicCtrlPoint] = +- {.name = "HID Control Point", +- .data_prop_type = FlipperGattCharacteristicDataFixed, +- .data.fixed.length = HID_SVC_CONTROL_POINT_LEN, +- .uuid.Char_UUID_16 = HID_CONTROL_POINT_CHAR_UUID, +- .uuid_type = UUID_TYPE_16, +- .char_properties = CHAR_PROP_WRITE_WITHOUT_RESP, +- .security_permissions = ATTR_PERMISSION_NONE, +- .gatt_evt_mask = GATT_NOTIFY_ATTRIBUTE_WRITE, +- .is_variable = CHAR_VALUE_LEN_CONSTANT}, +- [HidSvcGattCharacteristicLed] = +- { +- .name = +- "HID LED State", // LED Characteristic and descriptor for BadBT to get numlock state for altchars +- .data_prop_type = FlipperGattCharacteristicDataFixed, +- .data.fixed.length = 1, +- .uuid.Char_UUID_16 = REPORT_CHAR_UUID, +- .uuid_type = UUID_TYPE_16, +- .char_properties = CHAR_PROP_READ | CHAR_PROP_WRITE_WITHOUT_RESP | CHAR_PROP_WRITE, +- .security_permissions = ATTR_PERMISSION_NONE, +- .gatt_evt_mask = GATT_NOTIFY_ATTRIBUTE_WRITE | +- GATT_NOTIFY_WRITE_REQ_AND_WAIT_FOR_APPL_RESP, +- .is_variable = CHAR_VALUE_LEN_CONSTANT, +- .descriptor_params = &hid_svc_char_descr_led, +- }, +-}; +- +-static const FlipperGattCharacteristicDescriptorParams hid_svc_char_descr_template = { +- .uuid_type = UUID_TYPE_16, +- .uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID, +- .max_length = HID_SVC_REPORT_REF_LEN, +- .data_callback.fn = hid_svc_char_desc_data_callback, +- .security_permissions = ATTR_PERMISSION_NONE, +- .access_permissions = ATTR_ACCESS_READ_WRITE, +- .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, +- .is_variable = CHAR_VALUE_LEN_CONSTANT, +-}; +- +-static const FlipperGattCharacteristicParams hid_svc_report_template = { +- .name = "Report", +- .data_prop_type = FlipperGattCharacteristicDataCallback, +- .data.callback.fn = hid_svc_report_data_callback, +- .data.callback.context = NULL, +- .uuid.Char_UUID_16 = REPORT_CHAR_UUID, +- .uuid_type = UUID_TYPE_16, +- .char_properties = CHAR_PROP_READ | CHAR_PROP_NOTIFY, +- .security_permissions = ATTR_PERMISSION_NONE, +- .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, +- .is_variable = CHAR_VALUE_LEN_VARIABLE, +-}; +- +-typedef struct { +- uint16_t svc_handle; +- FlipperGattCharacteristicInstance chars[HidSvcGattCharacteristicCount]; +- FlipperGattCharacteristicInstance input_report_chars[HID_SVC_INPUT_REPORT_COUNT]; +- FlipperGattCharacteristicInstance output_report_chars[HID_SVC_OUTPUT_REPORT_COUNT]; +- FlipperGattCharacteristicInstance feature_report_chars[HID_SVC_FEATURE_REPORT_COUNT]; +- // led state +- HidLedStateEventCallback led_state_event_callback; +- void* led_state_ctx; +-} HIDSvc; +- +-static HIDSvc* hid_svc = NULL; +- +-static SVCCTL_EvtAckStatus_t hid_svc_event_handler(void* event) { +- SVCCTL_EvtAckStatus_t ret = SVCCTL_EvtNotAck; +- hci_event_pckt* event_pckt = (hci_event_pckt*)(((hci_uart_pckt*)event)->data); +- evt_blecore_aci* blecore_evt = (evt_blecore_aci*)event_pckt->data; +- // aci_gatt_attribute_modified_event_rp0* attribute_modified; +- if(event_pckt->evt == HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE) { +- if(blecore_evt->ecode == ACI_GATT_ATTRIBUTE_MODIFIED_VSEVT_CODE) { +- // Process modification events +- ret = SVCCTL_EvtAckFlowEnable; +- } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) { +- // Process notification confirmation +- ret = SVCCTL_EvtAckFlowEnable; +- } else if(blecore_evt->ecode == ACI_GATT_WRITE_PERMIT_REQ_VSEVT_CODE) { +- // LED Characteristic and descriptor for BadBT to get numlock state for altchars +- // +- // Process write request +- aci_gatt_write_permit_req_event_rp0* req = +- (aci_gatt_write_permit_req_event_rp0*)blecore_evt->data; +- +- furi_check(hid_svc->led_state_event_callback && hid_svc->led_state_ctx); +- +- // this check is likely to be incorrect, it will actually work in our case +- // but we need to investigate gatt api to see what is the rules +- // that specify attibute handle value from char handle (or the reverse) +- if(req->Attribute_Handle == (hid_svc->chars[HidSvcGattCharacteristicLed].handle + 1)) { +- hid_svc->led_state_event_callback(req->Data[0], hid_svc->led_state_ctx); +- aci_gatt_write_resp( +- req->Connection_Handle, +- req->Attribute_Handle, +- 0x00, /* write_status = 0 (no error))*/ +- 0x00, /* err_code */ +- req->Data_Length, +- req->Data); +- aci_gatt_write_char_value( +- req->Connection_Handle, +- hid_svc->chars[HidSvcGattCharacteristicLed].handle, +- req->Data_Length, +- req->Data); +- ret = SVCCTL_EvtAckFlowEnable; +- } +- } +- } +- return ret; +-} +- +-void hid_svc_start() { +- tBleStatus status; +- hid_svc = malloc(sizeof(HIDSvc)); +- Service_UUID_t svc_uuid = {}; +- +- // Register event handler +- SVCCTL_RegisterSvcHandler(hid_svc_event_handler); +- // Add service +- svc_uuid.Service_UUID_16 = HUMAN_INTERFACE_DEVICE_SERVICE_UUID; +- /** +- * Add Human Interface Device Service +- */ +- status = aci_gatt_add_service( +- UUID_TYPE_16, +- &svc_uuid, +- PRIMARY_SERVICE, +- 2 + /* protocol mode */ +- (4 * HID_SVC_INPUT_REPORT_COUNT) + (3 * HID_SVC_OUTPUT_REPORT_COUNT) + +- (3 * HID_SVC_FEATURE_REPORT_COUNT) + 1 + 2 + 2 + 2 + +- 4, /* Service + Report Map + HID Information + HID Control Point + LED state */ +- &hid_svc->svc_handle); +- if(status) { +- FURI_LOG_E(TAG, "Failed to add HID service: %d", status); +- } +- +- for(size_t i = 0; i < HidSvcGattCharacteristicCount; i++) { +- flipper_gatt_characteristic_init( +- hid_svc->svc_handle, &hid_svc_chars[i], &hid_svc->chars[i]); +- } +- uint8_t protocol_mode = 1; +- flipper_gatt_characteristic_update( +- hid_svc->svc_handle, +- &hid_svc->chars[HidSvcGattCharacteristicProtocolMode], +- &protocol_mode); +- +- // reports +- FlipperGattCharacteristicDescriptorParams hid_svc_char_descr; +- FlipperGattCharacteristicParams report_char; +- HidSvcReportId report_id; +- +- memcpy(&hid_svc_char_descr, &hid_svc_char_descr_template, sizeof(hid_svc_char_descr)); +- memcpy(&report_char, &hid_svc_report_template, sizeof(report_char)); +- +- hid_svc_char_descr.data_callback.context = &report_id; +- report_char.descriptor_params = &hid_svc_char_descr; +- +- typedef struct { +- uint8_t report_type; +- uint8_t report_count; +- FlipperGattCharacteristicInstance* chars; +- } HidSvcReportCharProps; +- +- HidSvcReportCharProps hid_report_chars[] = { +- {0x01, HID_SVC_INPUT_REPORT_COUNT, hid_svc->input_report_chars}, +- {0x02, HID_SVC_OUTPUT_REPORT_COUNT, hid_svc->output_report_chars}, +- {0x03, HID_SVC_FEATURE_REPORT_COUNT, hid_svc->feature_report_chars}, +- }; +- +- for(size_t report_type_idx = 0; report_type_idx < COUNT_OF(hid_report_chars); +- report_type_idx++) { +- report_id.report_type = hid_report_chars[report_type_idx].report_type; +- for(size_t report_idx = 0; report_idx < hid_report_chars[report_type_idx].report_count; +- report_idx++) { +- report_id.report_idx = report_idx + 1; +- flipper_gatt_characteristic_init( +- hid_svc->svc_handle, +- &report_char, +- &hid_report_chars[report_type_idx].chars[report_idx]); +- } +- } +-} +- +-bool hid_svc_update_report_map(const uint8_t* data, uint16_t len) { +- furi_assert(data); +- furi_assert(hid_svc); +- +- HidSvcDataWrapper report_data = { +- .data_ptr = data, +- .data_len = len, +- }; +- return flipper_gatt_characteristic_update( +- hid_svc->svc_handle, &hid_svc->chars[HidSvcGattCharacteristicReportMap], &report_data); +-} +- +-bool hid_svc_update_input_report(uint8_t input_report_num, uint8_t* data, uint16_t len) { +- furi_assert(data); +- furi_assert(hid_svc); +- furi_assert(input_report_num < HID_SVC_INPUT_REPORT_COUNT); +- +- HidSvcDataWrapper report_data = { +- .data_ptr = data, +- .data_len = len, +- }; +- return flipper_gatt_characteristic_update( +- hid_svc->svc_handle, &hid_svc->input_report_chars[input_report_num], &report_data); +-} +- +-bool hid_svc_update_info(uint8_t* data) { +- furi_assert(data); +- furi_assert(hid_svc); +- +- return flipper_gatt_characteristic_update( +- hid_svc->svc_handle, &hid_svc->chars[HidSvcGattCharacteristicInfo], &data); +-} +- +-void hid_svc_register_led_state_callback(HidLedStateEventCallback callback, void* context) { +- furi_assert(hid_svc); +- furi_assert(callback); +- furi_assert(context); +- +- hid_svc->led_state_event_callback = callback; +- hid_svc->led_state_ctx = context; +-} +- +-bool hid_svc_is_started() { +- return hid_svc != NULL; +-} +- +-void hid_svc_stop() { +- tBleStatus status; +- if(hid_svc) { +- // Delete characteristics +- for(size_t i = 0; i < HidSvcGattCharacteristicCount; i++) { +- flipper_gatt_characteristic_delete(hid_svc->svc_handle, &hid_svc->chars[i]); +- } +- +- typedef struct { +- uint8_t report_count; +- FlipperGattCharacteristicInstance* chars; +- } HidSvcReportCharProps; +- +- HidSvcReportCharProps hid_report_chars[] = { +- {HID_SVC_INPUT_REPORT_COUNT, hid_svc->input_report_chars}, +- {HID_SVC_OUTPUT_REPORT_COUNT, hid_svc->output_report_chars}, +- {HID_SVC_FEATURE_REPORT_COUNT, hid_svc->feature_report_chars}, +- }; +- +- for(size_t report_type_idx = 0; report_type_idx < COUNT_OF(hid_report_chars); +- report_type_idx++) { +- for(size_t report_idx = 0; report_idx < hid_report_chars[report_type_idx].report_count; +- report_idx++) { +- flipper_gatt_characteristic_delete( +- hid_svc->svc_handle, &hid_report_chars[report_type_idx].chars[report_idx]); +- } +- } +- +- // Delete service +- status = aci_gatt_del_service(hid_svc->svc_handle); +- if(status) { +- FURI_LOG_E(TAG, "Failed to delete HID service: %d", status); +- } +- free(hid_svc); +- hid_svc = NULL; +- } +-} +diff --git a/firmware/targets/f7/ble_glue/services/serial_service_uuid.inc b/firmware/targets/f7/ble_glue/services/serial_service_uuid.inc +deleted file mode 100644 +index a297d9ad60..0000000000 +--- a/firmware/targets/f7/ble_glue/services/serial_service_uuid.inc ++++ /dev/null +@@ -1,12 +0,0 @@ +- +-static const Service_UUID_t service_uuid = { .Service_UUID_128 = \ +- { 0x00, 0x00, 0xfe, 0x60, 0xcc, 0x7a, 0x48, 0x2a, 0x98, 0x4a, 0x7f, 0x2e, 0xd5, 0xb3, 0xe5, 0x8f }}; +- +-#define SERIAL_SVC_TX_CHAR_UUID \ +- { 0x00, 0x00, 0xfe, 0x61, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19 } +-#define SERIAL_SVC_RX_CHAR_UUID \ +- { 0x00, 0x00, 0xfe, 0x62, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19 } +-#define SERIAL_SVC_FLOW_CONTROL_UUID \ +- { 0x00, 0x00, 0xfe, 0x63, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19 } +-#define SERIAL_SVC_RPC_STATUS_UUID \ +- { 0x00, 0x00, 0xfe, 0x64, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19 } +diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt.c b/firmware/targets/f7/furi_hal/furi_hal_bt.c +index 22d286abd0..f71cd37762 100644 +--- a/firmware/targets/f7/furi_hal/furi_hal_bt.c ++++ b/firmware/targets/f7/furi_hal/furi_hal_bt.c +@@ -8,7 +8,8 @@ + #include + #include + #include +-#include ++#include "battery_service.h" ++ + #include + + #define TAG "FuriHalBt" +diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c b/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c +index 2bbfc15231..8e05a99049 100644 +--- a/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c ++++ b/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c +@@ -1,11 +1,11 @@ + #include + #include +-#include +-#include +-#include ++#include "usb_hid.h" ++#include "dev_info_service.h" ++#include "battery_service.h" ++#include "hid_service.h" + + #include +-#include + + #define FURI_HAL_BT_INFO_BASE_USB_SPECIFICATION (0x0101) + #define FURI_HAL_BT_INFO_COUNTRY_CODE (0x00) +@@ -221,7 +221,7 @@ void furi_hal_bt_hid_start() { + FURI_HAL_BT_HID_INFO_FLAG_REMOTE_WAKE_MSK | + FURI_HAL_BT_HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK, + }; +- hid_svc_update_info(hid_info_val); ++ hid_svc_update_info(hid_info_val, sizeof(hid_info_val)); + } + + void furi_hal_bt_hid_stop() { +diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt_serial.c b/firmware/targets/f7/furi_hal/furi_hal_bt_serial.c +index 2927d946f9..2539e6bd0e 100644 +--- a/firmware/targets/f7/furi_hal/furi_hal_bt_serial.c ++++ b/firmware/targets/f7/furi_hal/furi_hal_bt_serial.c +@@ -1,7 +1,7 @@ + #include +-#include +-#include +-#include ++#include "dev_info_service.h" ++#include "battery_service.h" ++#include "serial_service.h" + + #include + +diff --git a/firmware/targets/furi_hal_include/furi_hal_bt.h b/firmware/targets/furi_hal_include/furi_hal_bt.h +index d6a6e8c42b..bfe4a67c3c 100644 +--- a/firmware/targets/furi_hal_include/furi_hal_bt.h ++++ b/firmware/targets/furi_hal_include/furi_hal_bt.h +@@ -8,7 +8,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + +diff --git a/firmware/targets/furi_hal_include/furi_hal_bt_serial.h b/firmware/targets/furi_hal_include/furi_hal_bt_serial.h +index 0472d31d18..1b6e79ab07 100644 +--- a/firmware/targets/furi_hal_include/furi_hal_bt_serial.h ++++ b/firmware/targets/furi_hal_include/furi_hal_bt_serial.h +@@ -1,6 +1,6 @@ + #pragma once + +-#include ++#include "serial_service.h" + + #ifdef __cplusplus + extern "C" {