diff --git a/revert_hardfault_fix_for_ios_hid.patch b/revert_hardfault_fix_for_ios_hid.patch new file mode 100644 index 000000000..6b904fc58 --- /dev/null +++ b/revert_hardfault_fix_for_ios_hid.patch @@ -0,0 +1,4889 @@ +diff --git a/SConstruct b/SConstruct +index 698ea85ec..8d389b70b 100644 +--- a/SConstruct ++++ b/SConstruct +@@ -77,8 +77,6 @@ if GetOption("fullenv") or any( + "${COPRO_DISCLAIMER}", + "--obdata", + '"${ROOT_DIR.abspath}/${COPRO_OB_DATA}"', +- "--stackversion", +- "${COPRO_CUBE_VERSION}", + ] + dist_resource_arguments = [ + "-r", +diff --git a/applications/services/bt/bt_service/bt.c b/applications/services/bt/bt_service/bt.c +index 31fa54161..d75a88888 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/fbt_options.py b/fbt_options.py +index 3f44bec3b..18b636822 100644 +--- a/fbt_options.py ++++ b/fbt_options.py +@@ -25,7 +25,7 @@ DIST_SUFFIX = f"XFW-DEV_@{subprocess.check_output(['git', 'rev-parse', '--short= + COPRO_OB_DATA = "scripts/ob.data" + + # Must match lib/stm32wb_copro version +-COPRO_CUBE_VERSION = "1.17.2" ++COPRO_CUBE_VERSION = "1.15.0" + + COPRO_CUBE_DIR = "lib/stm32wb_copro" + +diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv +index 338697ad7..30b63ca3a 100644 +--- a/firmware/targets/f18/api_symbols.csv ++++ b/firmware/targets/f18/api_symbols.csv +@@ -1025,10 +1025,8 @@ Function,+,furi_hal_clock_mco_disable,void, + Function,+,furi_hal_clock_mco_enable,void,"FuriHalClockMcoSourceId, FuriHalClockMcoDivisorId" + Function,-,furi_hal_clock_resume_tick,void, + Function,-,furi_hal_clock_suspend_tick,void, +-Function,-,furi_hal_clock_switch_hse2hsi,void, +-Function,-,furi_hal_clock_switch_hse2pll,_Bool, +-Function,-,furi_hal_clock_switch_hsi2hse,void, +-Function,-,furi_hal_clock_switch_pll2hse,_Bool, ++Function,-,furi_hal_clock_switch_to_hsi,void, ++Function,-,furi_hal_clock_switch_to_pll,void, + Function,+,furi_hal_console_disable,void, + Function,+,furi_hal_console_enable,void, + Function,+,furi_hal_console_init,void, +diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv +index 32646daef..01095b832 100644 +--- a/firmware/targets/f7/api_symbols.csv ++++ b/firmware/targets/f7/api_symbols.csv +@@ -1162,10 +1162,8 @@ Function,+,furi_hal_clock_mco_disable,void, + Function,+,furi_hal_clock_mco_enable,void,"FuriHalClockMcoSourceId, FuriHalClockMcoDivisorId" + Function,-,furi_hal_clock_resume_tick,void, + Function,-,furi_hal_clock_suspend_tick,void, +-Function,-,furi_hal_clock_switch_hse2hsi,void, +-Function,-,furi_hal_clock_switch_hse2pll,_Bool, +-Function,-,furi_hal_clock_switch_hsi2hse,void, +-Function,-,furi_hal_clock_switch_pll2hse,_Bool, ++Function,-,furi_hal_clock_switch_to_hsi,void, ++Function,-,furi_hal_clock_switch_to_pll,void, + Function,+,furi_hal_console_disable,void, + Function,+,furi_hal_console_enable,void, + Function,+,furi_hal_console_init,void, +diff --git a/firmware/targets/f7/ble_glue/app_common.h b/firmware/targets/f7/ble_glue/app_common.h +index e969636d2..8eaf23085 100644 +--- a/firmware/targets/f7/ble_glue/app_common.h ++++ b/firmware/targets/f7/ble_glue/app_common.h +@@ -1,4 +1,30 @@ +-#pragma once ++/* USER CODE BEGIN Header */ ++/** ++ ****************************************************************************** ++ * File Name : app_common.h ++ * Description : App Common application configuration file for STM32WPAN Middleware. ++ * ++ ****************************************************************************** ++ * @attention ++ * ++ *

© Copyright (c) 2020 STMicroelectronics. ++ * All rights reserved.

++ * ++ * This software component is licensed by ST under Ultimate Liberty license ++ * SLA0044, the "License"; You may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at: ++ * www.st.com/SLA0044 ++ * ++ ****************************************************************************** ++ */ ++/* USER CODE END Header */ ++/* Define to prevent recursive inclusion -------------------------------------*/ ++#ifndef APP_COMMON_H ++#define APP_COMMON_H ++ ++#ifdef __cplusplus ++extern "C" { ++#endif + + #include + #include +@@ -10,3 +36,5 @@ + #include + + #include "app_conf.h" ++ ++#endif +diff --git a/firmware/targets/f7/ble_glue/app_conf.h b/firmware/targets/f7/ble_glue/app_conf.h +index 25fa688c7..ee5115cfe 100644 +--- a/firmware/targets/f7/ble_glue/app_conf.h ++++ b/firmware/targets/f7/ble_glue/app_conf.h +@@ -1,32 +1,80 @@ + #pragma once + +-#include ++#include "hw_conf.h" ++#include "hw_if.h" ++ ++#include ++#include + + #define CFG_TX_POWER (0x19) /* +0dBm */ + + #define CFG_IDENTITY_ADDRESS GAP_PUBLIC_ADDR + ++/** ++ * Define Advertising parameters ++ */ ++#define CFG_ADV_BD_ADDRESS (0x7257acd87a6c) ++#define CFG_FAST_CONN_ADV_INTERVAL_MIN (0x80) /**< 80ms */ ++#define CFG_FAST_CONN_ADV_INTERVAL_MAX (0xa0) /**< 100ms */ ++#define CFG_LP_CONN_ADV_INTERVAL_MIN (0x640) /**< 1s */ ++#define CFG_LP_CONN_ADV_INTERVAL_MAX (0xfa0) /**< 2.5s */ ++ + /** + * Define IO Authentication + */ +-#define CFG_USED_FIXED_PIN USE_FIXED_PIN_FOR_PAIRING_FORBIDDEN ++#define CFG_BONDING_MODE (1) ++#define CFG_FIXED_PIN (111111) ++#define CFG_USED_FIXED_PIN (1) + #define CFG_ENCRYPTION_KEY_SIZE_MAX (16) + #define CFG_ENCRYPTION_KEY_SIZE_MIN (8) + + /** + * Define IO capabilities + */ +-#define CFG_IO_CAPABILITY IO_CAP_DISPLAY_YES_NO ++#define CFG_IO_CAPABILITY_DISPLAY_ONLY (0x00) ++#define CFG_IO_CAPABILITY_DISPLAY_YES_NO (0x01) ++#define CFG_IO_CAPABILITY_KEYBOARD_ONLY (0x02) ++#define CFG_IO_CAPABILITY_NO_INPUT_NO_OUTPUT (0x03) ++#define CFG_IO_CAPABILITY_KEYBOARD_DISPLAY (0x04) ++ ++#define CFG_IO_CAPABILITY CFG_IO_CAPABILITY_DISPLAY_YES_NO + + /** + * Define MITM modes + */ +-#define CFG_MITM_PROTECTION MITM_PROTECTION_REQUIRED ++#define CFG_MITM_PROTECTION_NOT_REQUIRED (0x00) ++#define CFG_MITM_PROTECTION_REQUIRED (0x01) ++ ++#define CFG_MITM_PROTECTION CFG_MITM_PROTECTION_REQUIRED + + /** + * Define Secure Connections Support + */ +-#define CFG_SC_SUPPORT SC_PAIRING_OPTIONAL ++#define CFG_SECURE_NOT_SUPPORTED (0x00) ++#define CFG_SECURE_OPTIONAL (0x01) ++#define CFG_SECURE_MANDATORY (0x02) ++ ++#define CFG_SC_SUPPORT CFG_SECURE_OPTIONAL ++ ++/** ++ * Define Keypress Notification Support ++ */ ++#define CFG_KEYPRESS_NOT_SUPPORTED (0x00) ++#define CFG_KEYPRESS_SUPPORTED (0x01) ++ ++#define CFG_KEYPRESS_NOTIFICATION_SUPPORT CFG_KEYPRESS_NOT_SUPPORTED ++ ++/** ++ * Numeric Comparison Answers ++ */ ++#define YES (0x01) ++#define NO (0x00) ++ ++/** ++ * Device name configuration for Generic Access Service ++ */ ++#define CFG_GAP_DEVICE_NAME "TEMPLATE" ++#define CFG_GAP_DEVICE_NAME_LENGTH (8) + + /** + * Define PHY +@@ -39,6 +87,42 @@ + #define RX_1M 0x01 + #define RX_2M 0x02 + ++/** ++* Identity root key used to derive LTK and CSRK ++*/ ++#define CFG_BLE_IRK \ ++ { \ ++ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, \ ++ 0xf0 \ ++ } ++ ++/** ++* Encryption root key used to derive LTK and CSRK ++*/ ++#define CFG_BLE_ERK \ ++ { \ ++ 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21, 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, \ ++ 0x21 \ ++ } ++ ++/* USER CODE BEGIN Generic_Parameters */ ++/** ++ * SMPS supply ++ * SMPS not used when Set to 0 ++ * SMPS used when Set to 1 ++ */ ++#define CFG_USE_SMPS 1 ++/* USER CODE END Generic_Parameters */ ++ ++/**< specific parameters */ ++/*****************************************************/ ++ ++/** ++* AD Element - Group B Feature ++*/ ++/* LSB - Second Byte */ ++#define CFG_FEATURE_OTA_REBOOT (0x20) ++ + /****************************************************************************** + * BLE Stack + ******************************************************************************/ +@@ -119,9 +203,7 @@ + * 1 : external high speed crystal HSE/32/32 + * 0 : external low speed crystal ( no calibration ) + */ +-#define CFG_BLE_LSE_SOURCE \ +- SHCI_C2_BLE_INIT_CFG_BLE_LS_CLK_LSE | SHCI_C2_BLE_INIT_CFG_BLE_LS_OTHER_DEV | \ +- SHCI_C2_BLE_INIT_CFG_BLE_LS_CALIB ++#define CFG_BLE_LSE_SOURCE 0 + + /** + * Start up time of the high speed (16 or 32 MHz) crystal oscillator in units of 625/256 us (~2.44 us) +@@ -171,8 +253,8 @@ + */ + #define CFG_BLE_OPTIONS \ + (SHCI_C2_BLE_INIT_OPTIONS_LL_HOST | SHCI_C2_BLE_INIT_OPTIONS_WITH_SVC_CHANGE_DESC | \ +- SHCI_C2_BLE_INIT_OPTIONS_DEVICE_NAME_RO | SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV | \ +- SHCI_C2_BLE_INIT_OPTIONS_CS_ALGO2 | SHCI_C2_BLE_INIT_OPTIONS_POWER_CLASS_2_3) ++ SHCI_C2_BLE_INIT_OPTIONS_DEVICE_NAME_RW | SHCI_C2_BLE_INIT_OPTIONS_NO_EXT_ADV | \ ++ SHCI_C2_BLE_INIT_OPTIONS_NO_CS_ALGO2 | SHCI_C2_BLE_INIT_OPTIONS_POWER_CLASS_2_3) + + /** + * Queue length of BLE Event +@@ -200,3 +282,187 @@ + 255 /**< Set to 255 with the memory manager and the mailbox */ + + #define TL_BLE_EVENT_FRAME_SIZE (TL_EVT_HDR_SIZE + CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE) ++/****************************************************************************** ++ * UART interfaces ++ ******************************************************************************/ ++ ++/** ++ * Select UART interfaces ++ */ ++#define CFG_DEBUG_TRACE_UART hw_uart1 ++#define CFG_CONSOLE_MENU 0 ++ ++/****************************************************************************** ++ * Low Power ++ ******************************************************************************/ ++/** ++ * When set to 1, the low power mode is enable ++ * When set to 0, the device stays in RUN mode ++ */ ++#define CFG_LPM_SUPPORTED 1 ++ ++/****************************************************************************** ++ * Timer Server ++ ******************************************************************************/ ++/** ++ * CFG_RTC_WUCKSEL_DIVIDER: This sets the RTCCLK divider to the wakeup timer. ++ * The lower is the value, the better is the power consumption and the accuracy of the timerserver ++ * The higher is the value, the finest is the granularity ++ * ++ * CFG_RTC_ASYNCH_PRESCALER: This sets the asynchronous prescaler of the RTC. It should as high as possible ( to ouput ++ * clock as low as possible) but the output clock should be equal or higher frequency compare to the clock feeding ++ * the wakeup timer. A lower clock speed would impact the accuracy of the timer server. ++ * ++ * CFG_RTC_SYNCH_PRESCALER: This sets the synchronous prescaler of the RTC. ++ * When the 1Hz calendar clock is required, it shall be sets according to other settings ++ * When the 1Hz calendar clock is not needed, CFG_RTC_SYNCH_PRESCALER should be set to 0x7FFF (MAX VALUE) ++ * ++ * CFG_RTCCLK_DIVIDER_CONF: ++ * Shall be set to either 0,2,4,8,16 ++ * When set to either 2,4,8,16, the 1Hhz calendar is supported ++ * When set to 0, the user sets its own configuration ++ * ++ * The following settings are computed with LSI as input to the RTC ++ */ ++#define CFG_RTCCLK_DIVIDER_CONF 0 ++ ++#if(CFG_RTCCLK_DIVIDER_CONF == 0) ++/** ++ * Custom configuration ++ * It does not support 1Hz calendar ++ * It divides the RTC CLK by 16 ++ */ ++#define CFG_RTCCLK_DIV (16) ++#define CFG_RTC_WUCKSEL_DIVIDER (0) ++#define CFG_RTC_ASYNCH_PRESCALER (CFG_RTCCLK_DIV - 1) ++#define CFG_RTC_SYNCH_PRESCALER (0x7FFF) ++ ++#else ++ ++#if(CFG_RTCCLK_DIVIDER_CONF == 2) ++/** ++ * It divides the RTC CLK by 2 ++ */ ++#define CFG_RTC_WUCKSEL_DIVIDER (3) ++#endif ++ ++#if(CFG_RTCCLK_DIVIDER_CONF == 4) ++/** ++ * It divides the RTC CLK by 4 ++ */ ++#define CFG_RTC_WUCKSEL_DIVIDER (2) ++#endif ++ ++#if(CFG_RTCCLK_DIVIDER_CONF == 8) ++/** ++ * It divides the RTC CLK by 8 ++ */ ++#define CFG_RTC_WUCKSEL_DIVIDER (1) ++#endif ++ ++#if(CFG_RTCCLK_DIVIDER_CONF == 16) ++/** ++ * It divides the RTC CLK by 16 ++ */ ++#define CFG_RTC_WUCKSEL_DIVIDER (0) ++#endif ++ ++#define CFG_RTCCLK_DIV CFG_RTCCLK_DIVIDER_CONF ++#define CFG_RTC_ASYNCH_PRESCALER (CFG_RTCCLK_DIV - 1) ++#define CFG_RTC_SYNCH_PRESCALER (DIVR(LSE_VALUE, (CFG_RTC_ASYNCH_PRESCALER + 1)) - 1) ++ ++#endif ++ ++/** tick timer value in us */ ++#define CFG_TS_TICK_VAL DIVR((CFG_RTCCLK_DIV * 1000000), LSE_VALUE) ++ ++typedef enum { ++ CFG_TIM_PROC_ID_ISR, ++ /* USER CODE BEGIN CFG_TimProcID_t */ ++ ++ /* USER CODE END CFG_TimProcID_t */ ++} CFG_TimProcID_t; ++ ++/****************************************************************************** ++ * Debug ++ ******************************************************************************/ ++/** ++ * When set, this resets some hw resources to set the device in the same state than the power up ++ * The FW resets only register that may prevent the FW to run properly ++ * ++ * This shall be set to 0 in a final product ++ * ++ */ ++#define CFG_HW_RESET_BY_FW 0 ++ ++/** ++ * keep debugger enabled while in any low power mode when set to 1 ++ * should be set to 0 in production ++ */ ++#define CFG_DEBUGGER_SUPPORTED 1 ++ ++/** ++ * When set to 1, the traces are enabled in the BLE services ++ */ ++#define CFG_DEBUG_BLE_TRACE 0 ++ ++/** ++ * Enable or Disable traces in application ++ */ ++#define CFG_DEBUG_APP_TRACE 0 ++ ++#if(CFG_DEBUG_APP_TRACE != 0) ++#define APP_DBG_MSG PRINT_MESG_DBG ++#else ++#define APP_DBG_MSG PRINT_NO_MESG ++#endif ++ ++#if((CFG_DEBUG_BLE_TRACE != 0) || (CFG_DEBUG_APP_TRACE != 0)) ++#define CFG_DEBUG_TRACE 1 ++#endif ++ ++#if(CFG_DEBUG_TRACE != 0) ++#undef CFG_LPM_SUPPORTED ++#undef CFG_DEBUGGER_SUPPORTED ++#define CFG_LPM_SUPPORTED 0 ++#define CFG_DEBUGGER_SUPPORTED 1 ++#endif ++ ++/** ++ * When CFG_DEBUG_TRACE_FULL is set to 1, the trace are output with the API name, the file name and the line number ++ * When CFG_DEBUG_TRACE_LIGHT is set to 1, only the debug message is output ++ * ++ * When both are set to 0, no trace are output ++ * When both are set to 1, CFG_DEBUG_TRACE_FULL is selected ++ */ ++#define CFG_DEBUG_TRACE_LIGHT 0 ++#define CFG_DEBUG_TRACE_FULL 0 ++ ++#if((CFG_DEBUG_TRACE != 0) && (CFG_DEBUG_TRACE_LIGHT == 0) && (CFG_DEBUG_TRACE_FULL == 0)) ++#undef CFG_DEBUG_TRACE_FULL ++#undef CFG_DEBUG_TRACE_LIGHT ++#define CFG_DEBUG_TRACE_FULL 0 ++#define CFG_DEBUG_TRACE_LIGHT 1 ++#endif ++ ++#if(CFG_DEBUG_TRACE == 0) ++#undef CFG_DEBUG_TRACE_FULL ++#undef CFG_DEBUG_TRACE_LIGHT ++#define CFG_DEBUG_TRACE_FULL 0 ++#define CFG_DEBUG_TRACE_LIGHT 0 ++#endif ++ ++/** ++ * When not set, the traces is looping on sending the trace over UART ++ */ ++#define DBG_TRACE_USE_CIRCULAR_QUEUE 0 ++ ++/** ++ * max buffer Size to queue data traces and max data trace allowed. ++ * Only Used if DBG_TRACE_USE_CIRCULAR_QUEUE is defined ++ */ ++#define DBG_TRACE_MSG_QUEUE_SIZE 4096 ++#define MAX_DBG_TRACE_MSG_SIZE 1024 ++ ++#define CFG_OTP_BASE_ADDRESS OTP_AREA_BASE ++#define CFG_OTP_END_ADRESS OTP_AREA_END_ADDR +diff --git a/firmware/targets/f7/ble_glue/app_debug.c b/firmware/targets/f7/ble_glue/app_debug.c +index fe76687b9..b443bee21 100644 +--- a/firmware/targets/f7/ble_glue/app_debug.c ++++ b/firmware/targets/f7/ble_glue/app_debug.c +@@ -6,9 +6,6 @@ + #include + #include + +-#include "stm32wbxx_ll_bus.h" +-#include "stm32wbxx_ll_pwr.h" +- + #include + + typedef PACKED_STRUCT { +@@ -111,6 +108,10 @@ static void APPD_SetCPU2GpioConfig(void); + static void APPD_BleDtbCfg(void); + + void APPD_Init() { ++#if(CFG_DEBUG_TRACE != 0) ++ DbgTraceInit(); ++#endif ++ + APPD_SetCPU2GpioConfig(); + APPD_BleDtbCfg(); + } +@@ -195,14 +196,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); + } + } + +@@ -251,3 +252,13 @@ static void APPD_BleDtbCfg(void) { + } + #endif + } ++ ++#if(CFG_DEBUG_TRACE != 0) ++void DbgOutputInit(void) { ++} ++ ++void DbgOutputTraces(uint8_t* p_data, uint16_t size, void (*cb)(void)) { ++ furi_hal_console_tx(p_data, size); ++ cb(); ++} ++#endif +diff --git a/firmware/targets/f7/ble_glue/app_debug.h b/firmware/targets/f7/ble_glue/app_debug.h +index 213470bed..92a54d75b 100644 +--- a/firmware/targets/f7/ble_glue/app_debug.h ++++ b/firmware/targets/f7/ble_glue/app_debug.h +@@ -1,4 +1,26 @@ +-#pragma once ++/* USER CODE BEGIN Header */ ++/** ++ ****************************************************************************** ++ * File Name : app_debug.h ++ * Description : Header for app_debug.c module ++ ****************************************************************************** ++ * @attention ++ * ++ *

© Copyright (c) 2020 STMicroelectronics. ++ * All rights reserved.

++ * ++ * This software component is licensed by ST under Ultimate Liberty license ++ * SLA0044, the "License"; You may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at: ++ * www.st.com/SLA0044 ++ * ++ ****************************************************************************** ++ */ ++/* USER CODE END Header */ ++ ++/* Define to prevent recursive inclusion -------------------------------------*/ ++#ifndef __APP_DEBUG_H ++#define __APP_DEBUG_H + + #ifdef __cplusplus + extern "C" { +@@ -10,3 +32,7 @@ void APPD_EnableCPU2(void); + #ifdef __cplusplus + } + #endif ++ ++#endif /*__APP_DEBUG_H */ ++ ++/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +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 63f736b3b..8c371efad 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 37ec3d0b9..ed62b1884 100644 +--- a/firmware/targets/f7/ble_glue/ble_app.c ++++ b/firmware/targets/f7/ble_glue/ble_app.c +@@ -18,8 +18,8 @@ PLACE_IN_SECTION("MB_MEM1") ALIGN(4) static TL_CmdPacket_t ble_app_cmd_buffer; + PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint32_t ble_app_nvm[BLE_NVM_SRAM_SIZE]; + + _Static_assert( +- sizeof(SHCI_C2_Ble_Init_Cmd_Packet_t) == 58, +- "Ble stack config structure size mismatch (check new config options - last updated for v.1.17.2)"); ++ sizeof(SHCI_C2_Ble_Init_Cmd_Packet_t) == 57, ++ "Ble stack config structure size mismatch (check new config options - last updated for v.1.15.0)"); + + typedef struct { + FuriMutex* hci_mtx; +@@ -33,54 +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, +- /* New stack (13.3->15.0) */ +- .max_adv_set_nbr = 1, // Only used if SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV is set +- .max_adv_data_len = 1650, // Only used if SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV is set +- .tx_path_compens = 0, // RF TX Path Compensation, * 0.1 dB +- .rx_path_compens = 0, // RF RX Path Compensation, * 0.1 dB +- .ble_core_version = SHCI_C2_BLE_INIT_BLE_CORE_5_4, +- /*15.0->17.0*/ +- .Options_extension = SHCI_C2_BLE_INIT_OPTIONS_ENHANCED_ATT_NOTSUPPORTED | +- SHCI_C2_BLE_INIT_OPTIONS_APPEARANCE_READONLY, +- }}; +- + bool ble_app_init() { + SHCI_CmdStatus_t status; + ble_app = malloc(sizeof(BleApp)); +@@ -92,16 +44,58 @@ 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, ++ /* New stack (13.3->15.0) */ ++ .max_adv_set_nbr = 1, // Only used if SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV is set ++ .max_adv_data_len = 31, // Only used if SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV is set ++ .tx_path_compens = 0, // RF TX Path Compensation, * 0.1 dB ++ .rx_path_compens = 0, // RF RX Path Compensation, * 0.1 dB ++ .ble_core_version = 11, // BLE Core Version: 11(5.2), 12(5.3) ++ }}; ++ 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/ble_app.h b/firmware/targets/f7/ble_glue/ble_app.h +index 2e6babab7..495005ec4 100644 +--- a/firmware/targets/f7/ble_glue/ble_app.h ++++ b/firmware/targets/f7/ble_glue/ble_app.h +@@ -1,12 +1,12 @@ + #pragma once + +-#include +-#include +- + #ifdef __cplusplus + extern "C" { + #endif + ++#include ++#include ++ + bool ble_app_init(); + void ble_app_get_key_storage_buff(uint8_t** addr, uint16_t* size); + void ble_app_thread_stop(); +diff --git a/firmware/targets/f7/ble_glue/ble_conf.h b/firmware/targets/f7/ble_glue/ble_conf.h +index 2b9c22dfe..a04d1def1 100644 +--- a/firmware/targets/f7/ble_glue/ble_conf.h ++++ b/firmware/targets/f7/ble_glue/ble_conf.h +@@ -1,7 +1,51 @@ +-#pragma once ++/** ++ ****************************************************************************** ++ * File Name : App/ble_conf.h ++ * Description : Configuration file for BLE Middleware. ++ * ++ ****************************************************************************** ++ * @attention ++ * ++ *

© Copyright (c) 2020 STMicroelectronics. ++ * All rights reserved.

++ * ++ * This software component is licensed by ST under Ultimate Liberty license ++ * SLA0044, the "License"; You may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at: ++ * www.st.com/SLA0044 ++ * ++ ****************************************************************************** ++ */ ++ ++/* Define to prevent recursive inclusion -------------------------------------*/ ++#ifndef BLE_CONF_H ++#define BLE_CONF_H + + #include "app_conf.h" + ++#ifndef __weak ++#define __weak __attribute__((weak)) ++#endif ++ ++/****************************************************************************** ++ * ++ * BLE SERVICES CONFIGURATION ++ * blesvc ++ * ++ ******************************************************************************/ ++ ++/** ++ * This setting shall be set to '1' if the device needs to support the Peripheral Role ++ * In the MS configuration, both BLE_CFG_PERIPHERAL and BLE_CFG_CENTRAL shall be set to '1' ++ */ ++#define BLE_CFG_PERIPHERAL 1 ++ ++/** ++ * This setting shall be set to '1' if the device needs to support the Central Role ++ * In the MS configuration, both BLE_CFG_PERIPHERAL and BLE_CFG_CENTRAL shall be set to '1' ++ */ ++#define BLE_CFG_CENTRAL 0 ++ + /** + * There is one handler per service enabled + * Note: There is no handler for the Device Information Service +@@ -12,3 +56,18 @@ + #define BLE_CFG_SVC_MAX_NBR_CB 7 + + #define BLE_CFG_CLT_MAX_NBR_CB 0 ++ ++/****************************************************************************** ++ * GAP Service - Apprearance ++ ******************************************************************************/ ++ ++#define BLE_CFG_UNKNOWN_APPEARANCE (0) ++#define BLE_CFG_GAP_APPEARANCE (0x0086) ++ ++/****************************************************************************** ++ * Over The Air Feature (OTA) - STM Proprietary ++ ******************************************************************************/ ++#define BLE_CFG_OTA_REBOOT_CHAR 0 /**< REBOOT OTA MODE CHARACTERISTIC */ ++ ++#endif /*BLE_CONF_H */ ++/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +diff --git a/firmware/targets/f7/ble_glue/ble_const.h b/firmware/targets/f7/ble_glue/ble_const.h +index 1e6647d90..85f734b62 100644 +--- a/firmware/targets/f7/ble_glue/ble_const.h ++++ b/firmware/targets/f7/ble_glue/ble_const.h +@@ -1,4 +1,22 @@ +-#pragma once ++/***************************************************************************** ++ * @file ble_const.h ++ * @author MDG ++ * @brief This file contains the definitions which are compiler dependent. ++ ***************************************************************************** ++ * @attention ++ * ++ * Copyright (c) 2018-2022 STMicroelectronics. ++ * All rights reserved. ++ * ++ * This software is licensed under terms that can be found in the LICENSE file ++ * in the root directory of this software component. ++ * If no LICENSE file comes with this software, it is provided AS-IS. ++ * ++ ***************************************************************************** ++ */ ++ ++#ifndef BLE_CONST_H__ ++#define BLE_CONST_H__ + + #include + #include +@@ -97,3 +115,5 @@ extern int hci_send_req(struct hci_request* req, uint8_t async); + #ifndef MAX + #define MAX(a, b) (((a) > (b)) ? (a) : (b)) + #endif ++ ++#endif /* BLE_CONST_H__ */ +diff --git a/firmware/targets/f7/ble_glue/ble_dbg_conf.h b/firmware/targets/f7/ble_glue/ble_dbg_conf.h +index 6f70f09be..8305f8106 100644 +--- a/firmware/targets/f7/ble_glue/ble_dbg_conf.h ++++ b/firmware/targets/f7/ble_glue/ble_dbg_conf.h +@@ -1 +1,199 @@ +-#pragma once ++/** ++ ****************************************************************************** ++ * File Name : App/ble_dbg_conf.h ++ * Description : Debug configuration file for BLE Middleware. ++ * ++ ****************************************************************************** ++ * @attention ++ * ++ *

© Copyright (c) 2020 STMicroelectronics. ++ * All rights reserved.

++ * ++ * This software component is licensed by ST under Ultimate Liberty license ++ * SLA0044, the "License"; You may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at: ++ * www.st.com/SLA0044 ++ * ++ ****************************************************************************** ++ */ ++ ++/* Define to prevent recursive inclusion -------------------------------------*/ ++#ifndef __BLE_DBG_CONF_H ++#define __BLE_DBG_CONF_H ++ ++/** ++ * Enable or Disable traces from BLE ++ */ ++ ++#define BLE_DBG_APP_EN 1 ++#define BLE_DBG_DIS_EN 1 ++#define BLE_DBG_HRS_EN 1 ++#define BLE_DBG_SVCCTL_EN 1 ++#define BLE_DBG_BLS_EN 1 ++#define BLE_DBG_HTS_EN 1 ++#define BLE_DBG_P2P_STM_EN 1 ++ ++/** ++ * Macro definition ++ */ ++#if(BLE_DBG_APP_EN != 0) ++#define BLE_DBG_APP_MSG PRINT_MESG_DBG ++#else ++#define BLE_DBG_APP_MSG PRINT_NO_MESG ++#endif ++ ++#if(BLE_DBG_DIS_EN != 0) ++#define BLE_DBG_DIS_MSG PRINT_MESG_DBG ++#else ++#define BLE_DBG_DIS_MSG PRINT_NO_MESG ++#endif ++ ++#if(BLE_DBG_HRS_EN != 0) ++#define BLE_DBG_HRS_MSG PRINT_MESG_DBG ++#else ++#define BLE_DBG_HRS_MSG PRINT_NO_MESG ++#endif ++ ++#if(BLE_DBG_P2P_STM_EN != 0) ++#define BLE_DBG_P2P_STM_MSG PRINT_MESG_DBG ++#else ++#define BLE_DBG_P2P_STM_MSG PRINT_NO_MESG ++#endif ++ ++#if(BLE_DBG_TEMPLATE_STM_EN != 0) ++#define BLE_DBG_TEMPLATE_STM_MSG PRINT_MESG_DBG ++#else ++#define BLE_DBG_TEMPLATE_STM_MSG PRINT_NO_MESG ++#endif ++ ++#if(BLE_DBG_EDS_STM_EN != 0) ++#define BLE_DBG_EDS_STM_MSG PRINT_MESG_DBG ++#else ++#define BLE_DBG_EDS_STM_MSG PRINT_NO_MESG ++#endif ++ ++#if(BLE_DBG_LBS_STM_EN != 0) ++#define BLE_DBG_LBS_STM_MSG PRINT_MESG_DBG ++#else ++#define BLE_DBG_LBS_STM_MSG PRINT_NO_MESG ++#endif ++ ++#if(BLE_DBG_SVCCTL_EN != 0) ++#define BLE_DBG_SVCCTL_MSG PRINT_MESG_DBG ++#else ++#define BLE_DBG_SVCCTL_MSG PRINT_NO_MESG ++#endif ++ ++#if(BLE_DBG_CTS_EN != 0) ++#define BLE_DBG_CTS_MSG PRINT_MESG_DBG ++#else ++#define BLE_DBG_CTS_MSG PRINT_NO_MESG ++#endif ++ ++#if(BLE_DBG_HIDS_EN != 0) ++#define BLE_DBG_HIDS_MSG PRINT_MESG_DBG ++#else ++#define BLE_DBG_HIDS_MSG PRINT_NO_MESG ++#endif ++ ++#if(BLE_DBG_PASS_EN != 0) ++#define BLE_DBG_PASS_MSG PRINT_MESG_DBG ++#else ++#define BLE_DBG_PASS_MSG PRINT_NO_MESG ++#endif ++ ++#if(BLE_DBG_BLS_EN != 0) ++#define BLE_DBG_BLS_MSG PRINT_MESG_DBG ++#else ++#define BLE_DBG_BLS_MSG PRINT_NO_MESG ++#endif ++ ++#if(BLE_DBG_HTS_EN != 0) ++#define BLE_DBG_HTS_MSG PRINT_MESG_DBG ++#else ++#define BLE_DBG_HTS_MSG PRINT_NO_MESG ++#endif ++ ++#if(BLE_DBG_ANS_EN != 0) ++#define BLE_DBG_ANS_MSG PRINT_MESG_DBG ++#else ++#define BLE_DBG_ANS_MSG PRINT_NO_MESG ++#endif ++ ++#if(BLE_DBG_ESS_EN != 0) ++#define BLE_DBG_ESS_MSG PRINT_MESG_DBG ++#else ++#define BLE_DBG_ESS_MSG PRINT_NO_MESG ++#endif ++ ++#if(BLE_DBG_GLS_EN != 0) ++#define BLE_DBG_GLS_MSG PRINT_MESG_DBG ++#else ++#define BLE_DBG_GLS_MSG PRINT_NO_MESG ++#endif ++ ++#if(BLE_DBG_BAS_EN != 0) ++#define BLE_DBG_BAS_MSG PRINT_MESG_DBG ++#else ++#define BLE_DBG_BAS_MSG PRINT_NO_MESG ++#endif ++ ++#if(BLE_DBG_RTUS_EN != 0) ++#define BLE_DBG_RTUS_MSG PRINT_MESG_DBG ++#else ++#define BLE_DBG_RTUS_MSG PRINT_NO_MESG ++#endif ++ ++#if(BLE_DBG_HPS_EN != 0) ++#define BLE_DBG_HPS_MSG PRINT_MESG_DBG ++#else ++#define BLE_DBG_HPS_MSG PRINT_NO_MESG ++#endif ++ ++#if(BLE_DBG_TPS_EN != 0) ++#define BLE_DBG_TPS_MSG PRINT_MESG_DBG ++#else ++#define BLE_DBG_TPS_MSG PRINT_NO_MESG ++#endif ++ ++#if(BLE_DBG_LLS_EN != 0) ++#define BLE_DBG_LLS_MSG PRINT_MESG_DBG ++#else ++#define BLE_DBG_LLS_MSG PRINT_NO_MESG ++#endif ++ ++#if(BLE_DBG_IAS_EN != 0) ++#define BLE_DBG_IAS_MSG PRINT_MESG_DBG ++#else ++#define BLE_DBG_IAS_MSG PRINT_NO_MESG ++#endif ++ ++#if(BLE_DBG_WSS_EN != 0) ++#define BLE_DBG_WSS_MSG PRINT_MESG_DBG ++#else ++#define BLE_DBG_WSS_MSG PRINT_NO_MESG ++#endif ++ ++#if(BLE_DBG_LNS_EN != 0) ++#define BLE_DBG_LNS_MSG PRINT_MESG_DBG ++#else ++#define BLE_DBG_LNS_MSG PRINT_NO_MESG ++#endif ++ ++#if(BLE_DBG_SCPS_EN != 0) ++#define BLE_DBG_SCPS_MSG PRINT_MESG_DBG ++#else ++#define BLE_DBG_SCPS_MSG PRINT_NO_MESG ++#endif ++ ++#if(BLE_DBG_DTS_EN != 0) ++#define BLE_DBG_DTS_MSG PRINT_MESG_DBG ++#define BLE_DBG_DTS_BUF PRINT_LOG_BUFF_DBG ++#else ++#define BLE_DBG_DTS_MSG PRINT_NO_MESG ++#define BLE_DBG_DTS_BUF PRINT_NO_MESG ++#endif ++ ++#endif /*__BLE_DBG_CONF_H */ ++ ++/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +diff --git a/firmware/targets/f7/ble_glue/ble_glue.c b/firmware/targets/f7/ble_glue/ble_glue.c +index 5f129ba8c..2c30612b5 100644 +--- a/firmware/targets/f7/ble_glue/ble_glue.c ++++ b/firmware/targets/f7/ble_glue/ble_glue.c +@@ -32,6 +32,7 @@ static uint8_t ble_glue_ble_spare_event_buff[sizeof(TL_PacketHeader_t) + TL_EVT_ + + typedef struct { + FuriMutex* shci_mtx; ++ FuriSemaphore* shci_sem; + FuriThread* thread; + BleGlueStatus status; + BleGlueKeyStorageChangedCallback callback; +@@ -103,6 +104,7 @@ void ble_glue_init() { + TL_Init(); + + ble_glue->shci_mtx = furi_mutex_alloc(FuriMutexTypeNormal); ++ ble_glue->shci_sem = furi_semaphore_alloc(1, 0); + + // FreeRTOS system task creation + ble_glue->thread = furi_thread_alloc_ex("BleShciDriver", 1024, ble_glue_shci_thread, ble_glue); +@@ -391,6 +393,7 @@ void ble_glue_thread_stop() { + furi_thread_free(ble_glue->thread); + // Free resources + furi_mutex_free(ble_glue->shci_mtx); ++ furi_semaphore_free(ble_glue->shci_sem); + ble_glue_clear_shared_memory(); + free(ble_glue); + ble_glue = NULL; +@@ -424,6 +427,22 @@ void shci_notify_asynch_evt(void* pdata) { + } + } + ++void shci_cmd_resp_release(uint32_t flag) { ++ UNUSED(flag); ++ if(ble_glue) { ++ furi_semaphore_release(ble_glue->shci_sem); ++ } ++} ++ ++void shci_cmd_resp_wait(uint32_t timeout) { ++ UNUSED(timeout); ++ if(ble_glue) { ++ furi_hal_power_insomnia_enter(); ++ furi_semaphore_acquire(ble_glue->shci_sem, FuriWaitForever); ++ furi_hal_power_insomnia_exit(); ++ } ++} ++ + bool ble_glue_reinit_c2() { + return SHCI_C2_Reinit() == SHCI_Success; + } +diff --git a/firmware/targets/f7/ble_glue/compiler.h b/firmware/targets/f7/ble_glue/compiler.h +index 1d32c2a2e..98a93d712 100644 +--- a/firmware/targets/f7/ble_glue/compiler.h ++++ b/firmware/targets/f7/ble_glue/compiler.h +@@ -1,4 +1,22 @@ +-#pragma once ++/***************************************************************************** ++ * @file compiler.h ++ * @author MDG ++ * @brief This file contains the definitions which are compiler dependent. ++ ***************************************************************************** ++ * @attention ++ * ++ * Copyright (c) 2018-2023 STMicroelectronics. ++ * All rights reserved. ++ * ++ * This software is licensed under terms that can be found in the LICENSE file ++ * in the root directory of this software component. ++ * If no LICENSE file comes with this software, it is provided AS-IS. ++ * ++ ***************************************************************************** ++ */ ++ ++#ifndef COMPILER_H__ ++#define COMPILER_H__ + + #ifndef __PACKED_STRUCT + #define __PACKED_STRUCT PACKED(struct) +@@ -136,3 +154,5 @@ + #endif + #endif + #endif ++ ++#endif /* COMPILER_H__ */ +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 000000000..d24058632 +--- /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 000000000..a31d6015f +--- /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 4d0ed4c4f..b8f6b244d 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/hsem_map.h b/firmware/targets/f7/ble_glue/hsem_map.h +deleted file mode 100644 +index 9a5f51d20..000000000 +--- a/firmware/targets/f7/ble_glue/hsem_map.h ++++ /dev/null +@@ -1,81 +0,0 @@ +-#pragma once +- +-/****************************************************************************** +- * Semaphores +- * THIS SHALL NO BE CHANGED AS THESE SEMAPHORES ARE USED AS WELL ON THE CM0+ +- *****************************************************************************/ +-/** +-* Index of the semaphore used the prevent conflicts after standby sleep. +-* Each CPUs takes this semaphore at standby wakeup until conflicting elements are restored. +-*/ +-#define CFG_HW_PWR_STANDBY_SEMID 10 +-/** +-* The CPU2 may be configured to store the Thread persistent data either in internal NVM storage on CPU2 or in +-* SRAM2 buffer provided by the user application. This can be configured with the system command SHCI_C2_Config() +-* When the CPU2 is requested to store persistent data in SRAM2, it can write data in this buffer at any time when needed. +-* In order to read consistent data with the CPU1 from the SRAM2 buffer, the flow should be: +-* + CPU1 takes CFG_HW_THREAD_NVM_SRAM_SEMID semaphore +-* + CPU1 reads all persistent data from SRAM2 (most of the time, the goal is to write these data into an NVM managed by CPU1) +-* + CPU1 releases CFG_HW_THREAD_NVM_SRAM_SEMID semaphore +-* CFG_HW_THREAD_NVM_SRAM_SEMID semaphore makes sure CPU2 does not update the persistent data in SRAM2 at the same time CPU1 is reading them. +-* There is no timing constraint on how long this semaphore can be kept. +-*/ +-#define CFG_HW_THREAD_NVM_SRAM_SEMID 9 +- +-/** +-* The CPU2 may be configured to store the BLE persistent data either in internal NVM storage on CPU2 or in +-* SRAM2 buffer provided by the user application. This can be configured with the system command SHCI_C2_Config() +-* When the CPU2 is requested to store persistent data in SRAM2, it can write data in this buffer at any time when needed. +-* In order to read consistent data with the CPU1 from the SRAM2 buffer, the flow should be: +-* + CPU1 takes CFG_HW_BLE_NVM_SRAM_SEMID semaphore +-* + CPU1 reads all persistent data from SRAM2 (most of the time, the goal is to write these data into an NVM managed by CPU1) +-* + CPU1 releases CFG_HW_BLE_NVM_SRAM_SEMID semaphore +-* CFG_HW_BLE_NVM_SRAM_SEMID semaphore makes sure CPU2 does not update the persistent data in SRAM2 at the same time CPU1 is reading them. +-* There is no timing constraint on how long this semaphore can be kept. +-*/ +-#define CFG_HW_BLE_NVM_SRAM_SEMID 8 +- +-/** +-* Index of the semaphore used by CPU2 to prevent the CPU1 to either write or erase data in flash +-* The CPU1 shall not either write or erase in flash when this semaphore is taken by the CPU2 +-* When the CPU1 needs to either write or erase in flash, it shall first get the semaphore and release it just +-* after writing a raw (64bits data) or erasing one sector. +-* Once the Semaphore has been released, there shall be at least 1us before it can be taken again. This is required +-* to give the opportunity to CPU2 to take it. +-* On v1.4.0 and older CPU2 wireless firmware, this semaphore is unused and CPU2 is using PES bit. +-* By default, CPU2 is using the PES bit to protect its timing. The CPU1 may request the CPU2 to use the semaphore +-* instead of the PES bit by sending the system command SHCI_C2_SetFlashActivityControl() +-*/ +-#define CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID 7 +- +-/** +-* Index of the semaphore used by CPU1 to prevent the CPU2 to either write or erase data in flash +-* In order to protect its timing, the CPU1 may get this semaphore to prevent the CPU2 to either +-* write or erase in flash (as this will stall both CPUs) +-* The PES bit shall not be used as this may stall the CPU2 in some cases. +-*/ +-#define CFG_HW_BLOCK_FLASH_REQ_BY_CPU1_SEMID 6 +- +-/** +-* Index of the semaphore used to manage the CLK48 clock configuration +-* When the USB is required, this semaphore shall be taken before configuring te CLK48 for USB +-* and should be released after the application switch OFF the clock when the USB is not used anymore +-* When using the RNG, it is good enough to use CFG_HW_RNG_SEMID to control CLK48. +-* More details in AN5289 +-*/ +-#define CFG_HW_CLK48_CONFIG_SEMID 5 +- +-/* Index of the semaphore used to manage the entry Stop Mode procedure */ +-#define CFG_HW_ENTRY_STOP_MODE_SEMID 4 +- +-/* Index of the semaphore used to access the RCC */ +-#define CFG_HW_RCC_SEMID 3 +- +-/* Index of the semaphore used to access the FLASH */ +-#define CFG_HW_FLASH_SEMID 2 +- +-/* Index of the semaphore used to access the PKA */ +-#define CFG_HW_PKA_SEMID 1 +- +-/* Index of the semaphore used to access the RNG */ +-#define CFG_HW_RNG_SEMID 0 +diff --git a/firmware/targets/f7/ble_glue/hw_conf.h b/firmware/targets/f7/ble_glue/hw_conf.h +new file mode 100644 +index 000000000..bf18a7d0e +--- /dev/null ++++ b/firmware/targets/f7/ble_glue/hw_conf.h +@@ -0,0 +1,231 @@ ++/* USER CODE BEGIN Header */ ++/** ++ ****************************************************************************** ++ * @file hw_conf.h ++ * @author MCD Application Team ++ * @brief Configuration of hardware interface ++ ****************************************************************************** ++ * @attention ++ * ++ *

© Copyright (c) 2019 STMicroelectronics. ++ * All rights reserved.

++ * ++ * This software component is licensed by ST under Ultimate Liberty license ++ * SLA0044, the "License"; You may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at: ++ * www.st.com/SLA0044 ++ * ++ ****************************************************************************** ++ */ ++/* USER CODE END Header */ ++ ++/* Define to prevent recursive inclusion -------------------------------------*/ ++#ifndef HW_CONF_H ++#define HW_CONF_H ++ ++#include "FreeRTOSConfig.h" ++ ++/****************************************************************************** ++ * Semaphores ++ * THIS SHALL NO BE CHANGED AS THESE SEMAPHORES ARE USED AS WELL ON THE CM0+ ++ *****************************************************************************/ ++/** ++* Index of the semaphore used the prevent conflicts after standby sleep. ++* Each CPUs takes this semaphore at standby wakeup until conclicting elements are restored. ++*/ ++#define CFG_HW_PWR_STANDBY_SEMID 10 ++/** ++* The CPU2 may be configured to store the Thread persistent data either in internal NVM storage on CPU2 or in ++* SRAM2 buffer provided by the user application. This can be configured with the system command SHCI_C2_Config() ++* When the CPU2 is requested to store persistent data in SRAM2, it can write data in this buffer at any time when needed. ++* In order to read consistent data with the CPU1 from the SRAM2 buffer, the flow should be: ++* + CPU1 takes CFG_HW_THREAD_NVM_SRAM_SEMID semaphore ++* + CPU1 reads all persistent data from SRAM2 (most of the time, the goal is to write these data into an NVM managed by CPU1) ++* + CPU1 releases CFG_HW_THREAD_NVM_SRAM_SEMID semaphore ++* CFG_HW_THREAD_NVM_SRAM_SEMID semaphore makes sure CPU2 does not update the persistent data in SRAM2 at the same time CPU1 is reading them. ++* There is no timing constraint on how long this semaphore can be kept. ++*/ ++#define CFG_HW_THREAD_NVM_SRAM_SEMID 9 ++ ++/** ++* The CPU2 may be configured to store the BLE persistent data either in internal NVM storage on CPU2 or in ++* SRAM2 buffer provided by the user application. This can be configured with the system command SHCI_C2_Config() ++* When the CPU2 is requested to store persistent data in SRAM2, it can write data in this buffer at any time when needed. ++* In order to read consistent data with the CPU1 from the SRAM2 buffer, the flow should be: ++* + CPU1 takes CFG_HW_BLE_NVM_SRAM_SEMID semaphore ++* + CPU1 reads all persistent data from SRAM2 (most of the time, the goal is to write these data into an NVM managed by CPU1) ++* + CPU1 releases CFG_HW_BLE_NVM_SRAM_SEMID semaphore ++* CFG_HW_BLE_NVM_SRAM_SEMID semaphore makes sure CPU2 does not update the persistent data in SRAM2 at the same time CPU1 is reading them. ++* There is no timing constraint on how long this semaphore can be kept. ++*/ ++#define CFG_HW_BLE_NVM_SRAM_SEMID 8 ++ ++/** ++* Index of the semaphore used by CPU2 to prevent the CPU1 to either write or erase data in flash ++* The CPU1 shall not either write or erase in flash when this semaphore is taken by the CPU2 ++* When the CPU1 needs to either write or erase in flash, it shall first get the semaphore and release it just ++* after writing a raw (64bits data) or erasing one sector. ++* Once the Semaphore has been released, there shall be at least 1us before it can be taken again. This is required ++* to give the opportunity to CPU2 to take it. ++* On v1.4.0 and older CPU2 wireless firmware, this semaphore is unused and CPU2 is using PES bit. ++* By default, CPU2 is using the PES bit to protect its timing. The CPU1 may request the CPU2 to use the semaphore ++* instead of the PES bit by sending the system command SHCI_C2_SetFlashActivityControl() ++*/ ++#define CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID 7 ++ ++/** ++* Index of the semaphore used by CPU1 to prevent the CPU2 to either write or erase data in flash ++* In order to protect its timing, the CPU1 may get this semaphore to prevent the CPU2 to either ++* write or erase in flash (as this will stall both CPUs) ++* The PES bit shall not be used as this may stall the CPU2 in some cases. ++*/ ++#define CFG_HW_BLOCK_FLASH_REQ_BY_CPU1_SEMID 6 ++ ++/** ++* Index of the semaphore used to manage the CLK48 clock configuration ++* When the USB is required, this semaphore shall be taken before configuring te CLK48 for USB ++* and should be released after the application switch OFF the clock when the USB is not used anymore ++* When using the RNG, it is good enough to use CFG_HW_RNG_SEMID to control CLK48. ++* More details in AN5289 ++*/ ++#define CFG_HW_CLK48_CONFIG_SEMID 5 ++ ++/* Index of the semaphore used to manage the entry Stop Mode procedure */ ++#define CFG_HW_ENTRY_STOP_MODE_SEMID 4 ++ ++/* Index of the semaphore used to access the RCC */ ++#define CFG_HW_RCC_SEMID 3 ++ ++/* Index of the semaphore used to access the FLASH */ ++#define CFG_HW_FLASH_SEMID 2 ++ ++/* Index of the semaphore used to access the PKA */ ++#define CFG_HW_PKA_SEMID 1 ++ ++/* Index of the semaphore used to access the RNG */ ++#define CFG_HW_RNG_SEMID 0 ++ ++/****************************************************************************** ++ * HW TIMER SERVER ++ *****************************************************************************/ ++/** ++ * The user may define the maximum number of virtual timers supported. ++ * It shall not exceed 255 ++ */ ++#define CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER 6 ++ ++/** ++ * The user may define the priority in the NVIC of the RTC_WKUP interrupt handler that is used to manage the ++ * wakeup timer. ++ * This setting is the preemptpriority part of the NVIC. ++ */ ++#define CFG_HW_TS_NVIC_RTC_WAKEUP_IT_PREEMPTPRIO \ ++ (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1) /* FreeRTOS requirement */ ++ ++/** ++ * The user may define the priority in the NVIC of the RTC_WKUP interrupt handler that is used to manage the ++ * wakeup timer. ++ * This setting is the subpriority part of the NVIC. It does not exist on all processors. When it is not supported ++ * on the CPU, the setting is ignored ++ */ ++#define CFG_HW_TS_NVIC_RTC_WAKEUP_IT_SUBPRIO 0 ++ ++/** ++ * Define a critical section in the Timer server ++ * The Timer server does not support the API to be nested ++ * The Application shall either: ++ * a) Ensure this will never happen ++ * b) Define the critical section ++ * The default implementations is masking all interrupts using the PRIMASK bit ++ * The TimerServer driver uses critical sections to avoid context corruption. This is achieved with the macro ++ * TIMER_ENTER_CRITICAL_SECTION and TIMER_EXIT_CRITICAL_SECTION. When CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION is set ++ * to 1, all STM32 interrupts are masked with the PRIMASK bit of the CortexM CPU. It is possible to use the BASEPRI ++ * register of the CortexM CPU to keep allowed some interrupts with high priority. In that case, the user shall ++ * re-implement TIMER_ENTER_CRITICAL_SECTION and TIMER_EXIT_CRITICAL_SECTION and shall make sure that no TimerServer ++ * API are called when the TIMER critical section is entered ++ */ ++#define CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION 1 ++ ++/** ++ * This value shall reflect the maximum delay there could be in the application between the time the RTC interrupt ++ * is generated by the Hardware and the time when the RTC interrupt handler is called. This time is measured in ++ * number of RTCCLK ticks. ++ * A relaxed timing would be 10ms ++ * When the value is too short, the timerserver will not be able to count properly and all timeout may be random. ++ * When the value is too long, the device may wake up more often than the most optimal configuration. However, the ++ * impact on power consumption would be marginal (unless the value selected is extremely too long). It is strongly ++ * recommended to select a value large enough to make sure it is not too short to ensure reliability of the system ++ * as this will have marginal impact on low power mode ++ */ ++#define CFG_HW_TS_RTC_HANDLER_MAX_DELAY (10 * (LSI_VALUE / 1000)) ++ ++/** ++ * Interrupt ID in the NVIC of the RTC Wakeup interrupt handler ++ * It shall be type of IRQn_Type ++ */ ++#define CFG_HW_TS_RTC_WAKEUP_HANDLER_ID RTC_WKUP_IRQn ++ ++/****************************************************************************** ++ * HW UART ++ *****************************************************************************/ ++#define CFG_HW_LPUART1_ENABLED 0 ++#define CFG_HW_LPUART1_DMA_TX_SUPPORTED 0 ++ ++#define CFG_HW_USART1_ENABLED 1 ++#define CFG_HW_USART1_DMA_TX_SUPPORTED 1 ++ ++/** ++ * UART1 ++ */ ++#define CFG_HW_USART1_PREEMPTPRIORITY 0x0F ++#define CFG_HW_USART1_SUBPRIORITY 0 ++ ++/** < The application shall check the selected source clock is enable */ ++#define CFG_HW_USART1_SOURCE_CLOCK RCC_USART1CLKSOURCE_SYSCLK ++ ++#define CFG_HW_USART1_BAUDRATE 115200 ++#define CFG_HW_USART1_WORDLENGTH UART_WORDLENGTH_8B ++#define CFG_HW_USART1_STOPBITS UART_STOPBITS_1 ++#define CFG_HW_USART1_PARITY UART_PARITY_NONE ++#define CFG_HW_USART1_HWFLOWCTL UART_HWCONTROL_NONE ++#define CFG_HW_USART1_MODE UART_MODE_TX_RX ++#define CFG_HW_USART1_ADVFEATUREINIT UART_ADVFEATURE_NO_INIT ++#define CFG_HW_USART1_OVERSAMPLING UART_OVERSAMPLING_8 ++ ++#define CFG_HW_USART1_TX_PORT_CLK_ENABLE __HAL_RCC_GPIOB_CLK_ENABLE ++#define CFG_HW_USART1_TX_PORT GPIOB ++#define CFG_HW_USART1_TX_PIN GPIO_PIN_6 ++#define CFG_HW_USART1_TX_MODE GPIO_MODE_AF_PP ++#define CFG_HW_USART1_TX_PULL GPIO_NOPULL ++#define CFG_HW_USART1_TX_SPEED GPIO_SPEED_FREQ_VERY_HIGH ++#define CFG_HW_USART1_TX_ALTERNATE GPIO_AF7_USART1 ++ ++#define CFG_HW_USART1_RX_PORT_CLK_ENABLE __HAL_RCC_GPIOB_CLK_ENABLE ++#define CFG_HW_USART1_RX_PORT GPIOB ++#define CFG_HW_USART1_RX_PIN GPIO_PIN_7 ++#define CFG_HW_USART1_RX_MODE GPIO_MODE_AF_PP ++#define CFG_HW_USART1_RX_PULL GPIO_NOPULL ++#define CFG_HW_USART1_RX_SPEED GPIO_SPEED_FREQ_VERY_HIGH ++#define CFG_HW_USART1_RX_ALTERNATE GPIO_AF7_USART1 ++ ++#define CFG_HW_USART1_CTS_PORT_CLK_ENABLE __HAL_RCC_GPIOA_CLK_ENABLE ++#define CFG_HW_USART1_CTS_PORT GPIOA ++#define CFG_HW_USART1_CTS_PIN GPIO_PIN_11 ++#define CFG_HW_USART1_CTS_MODE GPIO_MODE_AF_PP ++#define CFG_HW_USART1_CTS_PULL GPIO_PULLDOWN ++#define CFG_HW_USART1_CTS_SPEED GPIO_SPEED_FREQ_VERY_HIGH ++#define CFG_HW_USART1_CTS_ALTERNATE GPIO_AF7_USART1 ++ ++#define CFG_HW_USART1_DMA_TX_PREEMPTPRIORITY 0x0F ++#define CFG_HW_USART1_DMA_TX_SUBPRIORITY 0 ++ ++#define CFG_HW_USART1_DMAMUX_CLK_ENABLE __HAL_RCC_DMAMUX1_CLK_ENABLE ++#define CFG_HW_USART1_DMA_CLK_ENABLE __HAL_RCC_DMA2_CLK_ENABLE ++#define CFG_HW_USART1_TX_DMA_REQ DMA_REQUEST_USART1_TX ++#define CFG_HW_USART1_TX_DMA_CHANNEL DMA2_Channel4 ++#define CFG_HW_USART1_TX_DMA_IRQn DMA2_Channel4_IRQn ++#define CFG_HW_USART1_DMA_TX_IRQHandler DMA2_Channel4_IRQHandler ++ ++#endif /*HW_CONF_H */ ++ ++/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +diff --git a/firmware/targets/f7/ble_glue/hw_if.h b/firmware/targets/f7/ble_glue/hw_if.h +new file mode 100644 +index 000000000..a0ac23df3 +--- /dev/null ++++ b/firmware/targets/f7/ble_glue/hw_if.h +@@ -0,0 +1,102 @@ ++/* USER CODE BEGIN Header */ ++/** ++ ****************************************************************************** ++ * @file hw_if.h ++ * @author MCD Application Team ++ * @brief Hardware Interface ++ ****************************************************************************** ++ * @attention ++ * ++ *

© Copyright (c) 2019 STMicroelectronics. ++ * All rights reserved.

++ * ++ * This software component is licensed by ST under Ultimate Liberty license ++ * SLA0044, the "License"; You may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at: ++ * www.st.com/SLA0044 ++ * ++ ****************************************************************************** ++ */ ++/* USER CODE END Header */ ++ ++/* Define to prevent recursive inclusion -------------------------------------*/ ++#ifndef HW_IF_H ++#define HW_IF_H ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* Includes ------------------------------------------------------------------*/ ++#include "stm32wbxx.h" ++#include "stm32wbxx_ll_exti.h" ++#include "stm32wbxx_ll_system.h" ++#include "stm32wbxx_ll_rcc.h" ++#include "stm32wbxx_ll_ipcc.h" ++#include "stm32wbxx_ll_bus.h" ++#include "stm32wbxx_ll_pwr.h" ++#include "stm32wbxx_ll_cortex.h" ++#include "stm32wbxx_ll_utils.h" ++#include "stm32wbxx_ll_hsem.h" ++#include "stm32wbxx_ll_gpio.h" ++#include "stm32wbxx_ll_rtc.h" ++ ++#ifdef USE_STM32WBXX_USB_DONGLE ++#include "stm32wbxx_usb_dongle.h" ++#endif ++#ifdef USE_STM32WBXX_NUCLEO ++#include "stm32wbxx_nucleo.h" ++#endif ++#ifdef USE_X_NUCLEO_EPD ++#include "x_nucleo_epd.h" ++#endif ++ ++/* Private includes ----------------------------------------------------------*/ ++/* USER CODE BEGIN Includes */ ++ ++/* USER CODE END Includes */ ++ ++/****************************************************************************** ++ * HW UART ++ ******************************************************************************/ ++typedef enum { ++ hw_uart1, ++ hw_uart2, ++ hw_lpuart1, ++} hw_uart_id_t; ++ ++typedef enum { ++ hw_uart_ok, ++ hw_uart_error, ++ hw_uart_busy, ++ hw_uart_to, ++} hw_status_t; ++ ++void HW_UART_Init(hw_uart_id_t hw_uart_id); ++void HW_UART_Receive_IT( ++ hw_uart_id_t hw_uart_id, ++ uint8_t* pData, ++ uint16_t Size, ++ void (*Callback)(void)); ++void HW_UART_Transmit_IT( ++ hw_uart_id_t hw_uart_id, ++ uint8_t* pData, ++ uint16_t Size, ++ void (*Callback)(void)); ++hw_status_t ++ HW_UART_Transmit(hw_uart_id_t hw_uart_id, uint8_t* p_data, uint16_t size, uint32_t timeout); ++hw_status_t HW_UART_Transmit_DMA( ++ hw_uart_id_t hw_uart_id, ++ uint8_t* p_data, ++ uint16_t size, ++ void (*Callback)(void)); ++void HW_UART_Interrupt_Handler(hw_uart_id_t hw_uart_id); ++void HW_UART_DMA_Interrupt_Handler(hw_uart_id_t hw_uart_id); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /*HW_IF_H */ ++ ++/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +diff --git a/firmware/targets/f7/ble_glue/hw_ipcc.c b/firmware/targets/f7/ble_glue/hw_ipcc.c +index c2397f351..7c84df09f 100644 +--- a/firmware/targets/f7/ble_glue/hw_ipcc.c ++++ b/firmware/targets/f7/ble_glue/hw_ipcc.c +@@ -1,52 +1,160 @@ ++/** ++ ****************************************************************************** ++ * File Name : Target/hw_ipcc.c ++ * Description : Hardware IPCC source file for STM32WPAN Middleware. ++ * ++ ****************************************************************************** ++ * @attention ++ * ++ *

© Copyright (c) 2020 STMicroelectronics. ++ * All rights reserved.

++ * ++ * This software component is licensed by ST under Ultimate Liberty license ++ * SLA0044, the "License"; You may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at: ++ * www.st.com/SLA0044 ++ * ++ ****************************************************************************** ++ */ ++ ++/* Includes ------------------------------------------------------------------*/ + #include "app_common.h" + #include +-#include +-#include +- +-#include +-#include +- +-#include +- +-#define HW_IPCC_TX_PENDING(channel) \ +- ((!(LL_C1_IPCC_IsActiveFlag_CHx(IPCC, channel))) && \ +- LL_C1_IPCC_IsEnabledTransmitChannel(IPCC, channel)) +-#define HW_IPCC_RX_PENDING(channel) \ +- (LL_C2_IPCC_IsActiveFlag_CHx(IPCC, channel) && \ +- LL_C1_IPCC_IsEnabledReceiveChannel(IPCC, channel)) + +-static void (*FreeBufCb)(); +- +-static void HW_IPCC_BLE_EvtHandler(); +-static void HW_IPCC_BLE_AclDataEvtHandler(); +-static void HW_IPCC_MM_FreeBufHandler(); +-static void HW_IPCC_SYS_CmdEvtHandler(); +-static void HW_IPCC_SYS_EvtHandler(); +-static void HW_IPCC_TRACES_EvtHandler(); +- +-void HW_IPCC_Rx_Handler() { ++/* Global variables ---------------------------------------------------------*/ ++/* Private defines -----------------------------------------------------------*/ ++#define HW_IPCC_TX_PENDING(channel) \ ++ (!(LL_C1_IPCC_IsActiveFlag_CHx(IPCC, channel))) && (((~(IPCC->C1MR)) & ((channel) << 16U))) ++#define HW_IPCC_RX_PENDING(channel) \ ++ (LL_C2_IPCC_IsActiveFlag_CHx(IPCC, channel)) && (((~(IPCC->C1MR)) & ((channel) << 0U))) ++ ++/* Private macros ------------------------------------------------------------*/ ++/* Private typedef -----------------------------------------------------------*/ ++/* Private variables ---------------------------------------------------------*/ ++static void (*FreeBufCb)(void); ++ ++/* Private function prototypes -----------------------------------------------*/ ++static void HW_IPCC_BLE_EvtHandler(void); ++static void HW_IPCC_BLE_AclDataEvtHandler(void); ++static void HW_IPCC_MM_FreeBufHandler(void); ++static void HW_IPCC_SYS_CmdEvtHandler(void); ++static void HW_IPCC_SYS_EvtHandler(void); ++static void HW_IPCC_TRACES_EvtHandler(void); ++ ++#ifdef THREAD_WB ++static void HW_IPCC_OT_CmdEvtHandler(void); ++static void HW_IPCC_THREAD_NotEvtHandler(void); ++static void HW_IPCC_THREAD_CliNotEvtHandler(void); ++#endif ++ ++#ifdef LLD_TESTS_WB ++static void HW_IPCC_LLDTESTS_ReceiveCliRspHandler(void); ++static void HW_IPCC_LLDTESTS_ReceiveM0CmdHandler(void); ++#endif ++#ifdef LLD_BLE_WB ++/*static void HW_IPCC_LLD_BLE_ReceiveCliRspHandler( void );*/ ++static void HW_IPCC_LLD_BLE_ReceiveRspHandler(void); ++static void HW_IPCC_LLD_BLE_ReceiveM0CmdHandler(void); ++#endif ++ ++#ifdef MAC_802_15_4_WB ++static void HW_IPCC_MAC_802_15_4_CmdEvtHandler(void); ++static void HW_IPCC_MAC_802_15_4_NotEvtHandler(void); ++#endif ++ ++#ifdef ZIGBEE_WB ++static void HW_IPCC_ZIGBEE_CmdEvtHandler(void); ++static void HW_IPCC_ZIGBEE_StackNotifEvtHandler(void); ++static void HW_IPCC_ZIGBEE_StackM0RequestHandler(void); ++#endif ++ ++/* Public function definition -----------------------------------------------*/ ++ ++/****************************************************************************** ++ * INTERRUPT HANDLER ++ ******************************************************************************/ ++void HW_IPCC_Rx_Handler(void) { + if(HW_IPCC_RX_PENDING(HW_IPCC_SYSTEM_EVENT_CHANNEL)) { + HW_IPCC_SYS_EvtHandler(); +- } else if(HW_IPCC_RX_PENDING(HW_IPCC_BLE_EVENT_CHANNEL)) { ++ } ++#ifdef MAC_802_15_4_WB ++ else if(HW_IPCC_RX_PENDING(HW_IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL)) { ++ HW_IPCC_MAC_802_15_4_NotEvtHandler(); ++ } ++#endif /* MAC_802_15_4_WB */ ++#ifdef THREAD_WB ++ else if(HW_IPCC_RX_PENDING(HW_IPCC_THREAD_NOTIFICATION_ACK_CHANNEL)) { ++ HW_IPCC_THREAD_NotEvtHandler(); ++ } else if(HW_IPCC_RX_PENDING(HW_IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL)) { ++ HW_IPCC_THREAD_CliNotEvtHandler(); ++ } ++#endif /* THREAD_WB */ ++#ifdef LLD_TESTS_WB ++ else if(HW_IPCC_RX_PENDING(HW_IPCC_LLDTESTS_CLI_RSP_CHANNEL)) { ++ HW_IPCC_LLDTESTS_ReceiveCliRspHandler(); ++ } else if(HW_IPCC_RX_PENDING(HW_IPCC_LLDTESTS_M0_CMD_CHANNEL)) { ++ HW_IPCC_LLDTESTS_ReceiveM0CmdHandler(); ++ } ++#endif /* LLD_TESTS_WB */ ++#ifdef LLD_BLE_WB ++ else if(HW_IPCC_RX_PENDING(HW_IPCC_LLD_BLE_RSP_CHANNEL)) { ++ HW_IPCC_LLD_BLE_ReceiveRspHandler(); ++ } else if(HW_IPCC_RX_PENDING(HW_IPCC_LLD_BLE_M0_CMD_CHANNEL)) { ++ HW_IPCC_LLD_BLE_ReceiveM0CmdHandler(); ++ } ++#endif /* LLD_TESTS_WB */ ++#ifdef ZIGBEE_WB ++ else if(HW_IPCC_RX_PENDING(HW_IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL)) { ++ HW_IPCC_ZIGBEE_StackNotifEvtHandler(); ++ } else if(HW_IPCC_RX_PENDING(HW_IPCC_ZIGBEE_M0_REQUEST_CHANNEL)) { ++ HW_IPCC_ZIGBEE_StackM0RequestHandler(); ++ } ++#endif /* ZIGBEE_WB */ ++ else if(HW_IPCC_RX_PENDING(HW_IPCC_BLE_EVENT_CHANNEL)) { + HW_IPCC_BLE_EvtHandler(); + } else if(HW_IPCC_RX_PENDING(HW_IPCC_TRACES_CHANNEL)) { + HW_IPCC_TRACES_EvtHandler(); + } ++ ++ return; + } + +-void HW_IPCC_Tx_Handler() { ++void HW_IPCC_Tx_Handler(void) { + if(HW_IPCC_TX_PENDING(HW_IPCC_SYSTEM_CMD_RSP_CHANNEL)) { + HW_IPCC_SYS_CmdEvtHandler(); +- } else if(HW_IPCC_TX_PENDING(HW_IPCC_SYSTEM_CMD_RSP_CHANNEL)) { ++ } ++#ifdef MAC_802_15_4_WB ++ else if(HW_IPCC_TX_PENDING(HW_IPCC_MAC_802_15_4_CMD_RSP_CHANNEL)) { ++ HW_IPCC_MAC_802_15_4_CmdEvtHandler(); ++ } ++#endif /* MAC_802_15_4_WB */ ++#ifdef THREAD_WB ++ else if(HW_IPCC_TX_PENDING(HW_IPCC_THREAD_OT_CMD_RSP_CHANNEL)) { ++ HW_IPCC_OT_CmdEvtHandler(); ++ } ++#endif /* THREAD_WB */ ++#ifdef LLD_TESTS_WB ++// No TX handler for LLD tests ++#endif /* LLD_TESTS_WB */ ++#ifdef ZIGBEE_WB ++ if(HW_IPCC_TX_PENDING(HW_IPCC_ZIGBEE_CMD_APPLI_CHANNEL)) { ++ HW_IPCC_ZIGBEE_CmdEvtHandler(); ++ } ++#endif /* ZIGBEE_WB */ ++ else if(HW_IPCC_TX_PENDING(HW_IPCC_SYSTEM_CMD_RSP_CHANNEL)) { + HW_IPCC_SYS_CmdEvtHandler(); + } else if(HW_IPCC_TX_PENDING(HW_IPCC_MM_RELEASE_BUFFER_CHANNEL)) { + HW_IPCC_MM_FreeBufHandler(); + } else if(HW_IPCC_TX_PENDING(HW_IPCC_HCI_ACL_DATA_CHANNEL)) { + HW_IPCC_BLE_AclDataEvtHandler(); + } +-} + +-void HW_IPCC_Enable() { ++ return; ++} ++/****************************************************************************** ++ * GENERAL ++ ******************************************************************************/ ++void HW_IPCC_Enable(void) { + /** + * Such as IPCC IP available to the CPU2, it is required to keep the IPCC clock running + when FUS is running on CPU2 and CPU1 enters deep sleep mode +@@ -69,9 +177,11 @@ void HW_IPCC_Enable() { + __SEV(); /* Set the internal event flag and send an event to the CPU2 */ + __WFE(); /* Clear the internal event flag */ + LL_PWR_EnableBootC2(); ++ ++ return; + } + +-void HW_IPCC_Init() { ++void HW_IPCC_Init(void) { + LL_C1_IPCC_EnableIT_RXO(IPCC); + LL_C1_IPCC_EnableIT_TXF(IPCC); + +@@ -79,62 +189,366 @@ void HW_IPCC_Init() { + NVIC_EnableIRQ(IPCC_C1_RX_IRQn); + NVIC_SetPriority(IPCC_C1_TX_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 6, 0)); + NVIC_EnableIRQ(IPCC_C1_TX_IRQn); ++ ++ return; + } + +-void HW_IPCC_BLE_Init() { ++/****************************************************************************** ++ * BLE ++ ******************************************************************************/ ++void HW_IPCC_BLE_Init(void) { + LL_C1_IPCC_EnableReceiveChannel(IPCC, HW_IPCC_BLE_EVENT_CHANNEL); ++ ++ return; + } + +-void HW_IPCC_BLE_SendCmd() { ++void HW_IPCC_BLE_SendCmd(void) { + LL_C1_IPCC_SetFlag_CHx(IPCC, HW_IPCC_BLE_CMD_CHANNEL); ++ ++ return; + } + +-static void HW_IPCC_BLE_EvtHandler() { ++static void HW_IPCC_BLE_EvtHandler(void) { + HW_IPCC_BLE_RxEvtNot(); + + LL_C1_IPCC_ClearFlag_CHx(IPCC, HW_IPCC_BLE_EVENT_CHANNEL); ++ ++ return; + } + +-void HW_IPCC_BLE_SendAclData() { ++void HW_IPCC_BLE_SendAclData(void) { + LL_C1_IPCC_SetFlag_CHx(IPCC, HW_IPCC_HCI_ACL_DATA_CHANNEL); + LL_C1_IPCC_EnableTransmitChannel(IPCC, HW_IPCC_HCI_ACL_DATA_CHANNEL); ++ ++ return; + } + +-static void HW_IPCC_BLE_AclDataEvtHandler() { ++static void HW_IPCC_BLE_AclDataEvtHandler(void) { + LL_C1_IPCC_DisableTransmitChannel(IPCC, HW_IPCC_HCI_ACL_DATA_CHANNEL); + + HW_IPCC_BLE_AclDataAckNot(); ++ ++ return; + } + +-void HW_IPCC_SYS_Init() { ++__weak void HW_IPCC_BLE_AclDataAckNot(void){}; ++__weak void HW_IPCC_BLE_RxEvtNot(void){}; ++ ++/****************************************************************************** ++ * SYSTEM ++ ******************************************************************************/ ++void HW_IPCC_SYS_Init(void) { + LL_C1_IPCC_EnableReceiveChannel(IPCC, HW_IPCC_SYSTEM_EVENT_CHANNEL); ++ ++ return; + } + +-void HW_IPCC_SYS_SendCmd() { ++void HW_IPCC_SYS_SendCmd(void) { + LL_C1_IPCC_SetFlag_CHx(IPCC, HW_IPCC_SYSTEM_CMD_RSP_CHANNEL); ++ LL_C1_IPCC_EnableTransmitChannel(IPCC, HW_IPCC_SYSTEM_CMD_RSP_CHANNEL); + +- FuriHalCortexTimer timer = furi_hal_cortex_timer_get(33000000); +- +- while(LL_C1_IPCC_IsActiveFlag_CHx(IPCC, HW_IPCC_SYSTEM_CMD_RSP_CHANNEL)) { +- furi_check(!furi_hal_cortex_timer_is_expired(timer), "HW_IPCC_SYS_SendCmd timeout"); +- } +- +- HW_IPCC_SYS_CmdEvtHandler(); ++ return; + } + +-static void HW_IPCC_SYS_CmdEvtHandler() { ++static void HW_IPCC_SYS_CmdEvtHandler(void) { + LL_C1_IPCC_DisableTransmitChannel(IPCC, HW_IPCC_SYSTEM_CMD_RSP_CHANNEL); + + HW_IPCC_SYS_CmdEvtNot(); ++ ++ return; + } + +-static void HW_IPCC_SYS_EvtHandler() { ++static void HW_IPCC_SYS_EvtHandler(void) { + HW_IPCC_SYS_EvtNot(); + + LL_C1_IPCC_ClearFlag_CHx(IPCC, HW_IPCC_SYSTEM_EVENT_CHANNEL); ++ ++ return; ++} ++ ++__weak void HW_IPCC_SYS_CmdEvtNot(void){}; ++__weak void HW_IPCC_SYS_EvtNot(void){}; ++ ++/****************************************************************************** ++ * MAC 802.15.4 ++ ******************************************************************************/ ++#ifdef MAC_802_15_4_WB ++void HW_IPCC_MAC_802_15_4_Init(void) { ++ LL_C1_IPCC_EnableReceiveChannel(IPCC, HW_IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL); ++ ++ return; ++} ++ ++void HW_IPCC_MAC_802_15_4_SendCmd(void) { ++ LL_C1_IPCC_SetFlag_CHx(IPCC, HW_IPCC_MAC_802_15_4_CMD_RSP_CHANNEL); ++ LL_C1_IPCC_EnableTransmitChannel(IPCC, HW_IPCC_MAC_802_15_4_CMD_RSP_CHANNEL); ++ ++ return; ++} ++ ++void HW_IPCC_MAC_802_15_4_SendAck(void) { ++ LL_C1_IPCC_ClearFlag_CHx(IPCC, HW_IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL); ++ LL_C1_IPCC_EnableReceiveChannel(IPCC, HW_IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL); ++ ++ return; ++} ++ ++static void HW_IPCC_MAC_802_15_4_CmdEvtHandler(void) { ++ LL_C1_IPCC_DisableTransmitChannel(IPCC, HW_IPCC_MAC_802_15_4_CMD_RSP_CHANNEL); ++ ++ HW_IPCC_MAC_802_15_4_CmdEvtNot(); ++ ++ return; ++} ++ ++static void HW_IPCC_MAC_802_15_4_NotEvtHandler(void) { ++ LL_C1_IPCC_DisableReceiveChannel(IPCC, HW_IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL); ++ ++ HW_IPCC_MAC_802_15_4_EvtNot(); ++ ++ return; ++} ++__weak void HW_IPCC_MAC_802_15_4_CmdEvtNot(void){}; ++__weak void HW_IPCC_MAC_802_15_4_EvtNot(void){}; ++#endif ++ ++/****************************************************************************** ++ * THREAD ++ ******************************************************************************/ ++#ifdef THREAD_WB ++void HW_IPCC_THREAD_Init(void) { ++ LL_C1_IPCC_EnableReceiveChannel(IPCC, HW_IPCC_THREAD_NOTIFICATION_ACK_CHANNEL); ++ LL_C1_IPCC_EnableReceiveChannel(IPCC, HW_IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL); ++ ++ return; ++} ++ ++void HW_IPCC_OT_SendCmd(void) { ++ LL_C1_IPCC_SetFlag_CHx(IPCC, HW_IPCC_THREAD_OT_CMD_RSP_CHANNEL); ++ LL_C1_IPCC_EnableTransmitChannel(IPCC, HW_IPCC_THREAD_OT_CMD_RSP_CHANNEL); ++ ++ return; ++} ++ ++void HW_IPCC_CLI_SendCmd(void) { ++ LL_C1_IPCC_SetFlag_CHx(IPCC, HW_IPCC_THREAD_CLI_CMD_CHANNEL); ++ ++ return; ++} ++ ++void HW_IPCC_THREAD_SendAck(void) { ++ LL_C1_IPCC_ClearFlag_CHx(IPCC, HW_IPCC_THREAD_NOTIFICATION_ACK_CHANNEL); ++ LL_C1_IPCC_EnableReceiveChannel(IPCC, HW_IPCC_THREAD_NOTIFICATION_ACK_CHANNEL); ++ ++ return; ++} ++ ++void HW_IPCC_THREAD_CliSendAck(void) { ++ LL_C1_IPCC_ClearFlag_CHx(IPCC, HW_IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL); ++ LL_C1_IPCC_EnableReceiveChannel(IPCC, HW_IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL); ++ ++ return; ++} ++ ++static void HW_IPCC_OT_CmdEvtHandler(void) { ++ LL_C1_IPCC_DisableTransmitChannel(IPCC, HW_IPCC_THREAD_OT_CMD_RSP_CHANNEL); ++ ++ HW_IPCC_OT_CmdEvtNot(); ++ ++ return; + } + +-void HW_IPCC_MM_SendFreeBuf(void (*cb)()) { ++static void HW_IPCC_THREAD_NotEvtHandler(void) { ++ LL_C1_IPCC_DisableReceiveChannel(IPCC, HW_IPCC_THREAD_NOTIFICATION_ACK_CHANNEL); ++ ++ HW_IPCC_THREAD_EvtNot(); ++ ++ return; ++} ++ ++static void HW_IPCC_THREAD_CliNotEvtHandler(void) { ++ LL_C1_IPCC_DisableReceiveChannel(IPCC, HW_IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL); ++ ++ HW_IPCC_THREAD_CliEvtNot(); ++ ++ return; ++} ++ ++__weak void HW_IPCC_OT_CmdEvtNot(void){}; ++__weak void HW_IPCC_CLI_CmdEvtNot(void){}; ++__weak void HW_IPCC_THREAD_EvtNot(void){}; ++ ++#endif /* THREAD_WB */ ++ ++/****************************************************************************** ++ * LLD TESTS ++ ******************************************************************************/ ++#ifdef LLD_TESTS_WB ++void HW_IPCC_LLDTESTS_Init(void) { ++ LL_C1_IPCC_EnableReceiveChannel(IPCC, HW_IPCC_LLDTESTS_CLI_RSP_CHANNEL); ++ LL_C1_IPCC_EnableReceiveChannel(IPCC, HW_IPCC_LLDTESTS_M0_CMD_CHANNEL); ++ return; ++} ++ ++void HW_IPCC_LLDTESTS_SendCliCmd(void) { ++ LL_C1_IPCC_SetFlag_CHx(IPCC, HW_IPCC_LLDTESTS_CLI_CMD_CHANNEL); ++ return; ++} ++ ++static void HW_IPCC_LLDTESTS_ReceiveCliRspHandler(void) { ++ LL_C1_IPCC_DisableReceiveChannel(IPCC, HW_IPCC_LLDTESTS_CLI_RSP_CHANNEL); ++ HW_IPCC_LLDTESTS_ReceiveCliRsp(); ++ return; ++} ++ ++void HW_IPCC_LLDTESTS_SendCliRspAck(void) { ++ LL_C1_IPCC_ClearFlag_CHx(IPCC, HW_IPCC_LLDTESTS_CLI_RSP_CHANNEL); ++ LL_C1_IPCC_EnableReceiveChannel(IPCC, HW_IPCC_LLDTESTS_CLI_RSP_CHANNEL); ++ return; ++} ++ ++static void HW_IPCC_LLDTESTS_ReceiveM0CmdHandler(void) { ++ LL_C1_IPCC_DisableReceiveChannel(IPCC, HW_IPCC_LLDTESTS_M0_CMD_CHANNEL); ++ HW_IPCC_LLDTESTS_ReceiveM0Cmd(); ++ return; ++} ++ ++void HW_IPCC_LLDTESTS_SendM0CmdAck(void) { ++ LL_C1_IPCC_ClearFlag_CHx(IPCC, HW_IPCC_LLDTESTS_M0_CMD_CHANNEL); ++ LL_C1_IPCC_EnableReceiveChannel(IPCC, HW_IPCC_LLDTESTS_M0_CMD_CHANNEL); ++ return; ++} ++__weak void HW_IPCC_LLDTESTS_ReceiveCliRsp(void){}; ++__weak void HW_IPCC_LLDTESTS_ReceiveM0Cmd(void){}; ++#endif /* LLD_TESTS_WB */ ++ ++/****************************************************************************** ++ * LLD BLE ++ ******************************************************************************/ ++#ifdef LLD_BLE_WB ++void HW_IPCC_LLD_BLE_Init(void) { ++ LL_C1_IPCC_EnableReceiveChannel(IPCC, HW_IPCC_LLD_BLE_RSP_CHANNEL); ++ LL_C1_IPCC_EnableReceiveChannel(IPCC, HW_IPCC_LLD_BLE_M0_CMD_CHANNEL); ++ return; ++} ++ ++void HW_IPCC_LLD_BLE_SendCliCmd(void) { ++ LL_C1_IPCC_SetFlag_CHx(IPCC, HW_IPCC_LLD_BLE_CLI_CMD_CHANNEL); ++ return; ++} ++ ++/*static void HW_IPCC_LLD_BLE_ReceiveCliRspHandler( void ) ++{ ++ LL_C1_IPCC_DisableReceiveChannel( IPCC, HW_IPCC_LLD_BLE_CLI_RSP_CHANNEL ); ++ HW_IPCC_LLD_BLE_ReceiveCliRsp(); ++ return; ++}*/ ++ ++void HW_IPCC_LLD_BLE_SendCliRspAck(void) { ++ LL_C1_IPCC_ClearFlag_CHx(IPCC, HW_IPCC_LLD_BLE_CLI_RSP_CHANNEL); ++ LL_C1_IPCC_EnableReceiveChannel(IPCC, HW_IPCC_LLD_BLE_CLI_RSP_CHANNEL); ++ return; ++} ++ ++static void HW_IPCC_LLD_BLE_ReceiveM0CmdHandler(void) { ++ //LL_C1_IPCC_DisableReceiveChannel( IPCC, HW_IPCC_LLD_BLE_M0_CMD_CHANNEL ); ++ HW_IPCC_LLD_BLE_ReceiveM0Cmd(); ++ return; ++} ++ ++void HW_IPCC_LLD_BLE_SendM0CmdAck(void) { ++ LL_C1_IPCC_ClearFlag_CHx(IPCC, HW_IPCC_LLD_BLE_M0_CMD_CHANNEL); ++ //LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_LLD_BLE_M0_CMD_CHANNEL ); ++ return; ++} ++__weak void HW_IPCC_LLD_BLE_ReceiveCliRsp(void){}; ++__weak void HW_IPCC_LLD_BLE_ReceiveM0Cmd(void){}; ++ ++/* Transparent Mode */ ++void HW_IPCC_LLD_BLE_SendCmd(void) { ++ LL_C1_IPCC_SetFlag_CHx(IPCC, HW_IPCC_LLD_BLE_CMD_CHANNEL); ++ return; ++} ++ ++static void HW_IPCC_LLD_BLE_ReceiveRspHandler(void) { ++ LL_C1_IPCC_DisableReceiveChannel(IPCC, HW_IPCC_LLD_BLE_RSP_CHANNEL); ++ HW_IPCC_LLD_BLE_ReceiveRsp(); ++ return; ++} ++ ++void HW_IPCC_LLD_BLE_SendRspAck(void) { ++ LL_C1_IPCC_ClearFlag_CHx(IPCC, HW_IPCC_LLD_BLE_RSP_CHANNEL); ++ LL_C1_IPCC_EnableReceiveChannel(IPCC, HW_IPCC_LLD_BLE_RSP_CHANNEL); ++ return; ++} ++ ++#endif /* LLD_BLE_WB */ ++ ++/****************************************************************************** ++ * ZIGBEE ++ ******************************************************************************/ ++#ifdef ZIGBEE_WB ++void HW_IPCC_ZIGBEE_Init(void) { ++ LL_C1_IPCC_EnableReceiveChannel(IPCC, HW_IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL); ++ LL_C1_IPCC_EnableReceiveChannel(IPCC, HW_IPCC_ZIGBEE_M0_REQUEST_CHANNEL); ++ ++ return; ++} ++ ++void HW_IPCC_ZIGBEE_SendM4RequestToM0(void) { ++ LL_C1_IPCC_SetFlag_CHx(IPCC, HW_IPCC_ZIGBEE_CMD_APPLI_CHANNEL); ++ LL_C1_IPCC_EnableTransmitChannel(IPCC, HW_IPCC_ZIGBEE_CMD_APPLI_CHANNEL); ++ ++ return; ++} ++ ++void HW_IPCC_ZIGBEE_SendM4AckToM0Notify(void) { ++ LL_C1_IPCC_ClearFlag_CHx(IPCC, HW_IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL); ++ LL_C1_IPCC_EnableReceiveChannel(IPCC, HW_IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL); ++ ++ return; ++} ++ ++static void HW_IPCC_ZIGBEE_CmdEvtHandler(void) { ++ LL_C1_IPCC_DisableTransmitChannel(IPCC, HW_IPCC_ZIGBEE_CMD_APPLI_CHANNEL); ++ ++ HW_IPCC_ZIGBEE_RecvAppliAckFromM0(); ++ ++ return; ++} ++ ++static void HW_IPCC_ZIGBEE_StackNotifEvtHandler(void) { ++ LL_C1_IPCC_DisableReceiveChannel(IPCC, HW_IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL); ++ ++ HW_IPCC_ZIGBEE_RecvM0NotifyToM4(); ++ ++ return; ++} ++ ++static void HW_IPCC_ZIGBEE_StackM0RequestHandler(void) { ++ LL_C1_IPCC_DisableReceiveChannel(IPCC, HW_IPCC_ZIGBEE_M0_REQUEST_CHANNEL); ++ ++ HW_IPCC_ZIGBEE_RecvM0RequestToM4(); ++ ++ return; ++} ++ ++void HW_IPCC_ZIGBEE_SendM4AckToM0Request(void) { ++ LL_C1_IPCC_ClearFlag_CHx(IPCC, HW_IPCC_ZIGBEE_M0_REQUEST_CHANNEL); ++ LL_C1_IPCC_EnableReceiveChannel(IPCC, HW_IPCC_ZIGBEE_M0_REQUEST_CHANNEL); ++ ++ return; ++} ++ ++__weak void HW_IPCC_ZIGBEE_RecvAppliAckFromM0(void){}; ++__weak void HW_IPCC_ZIGBEE_RecvM0NotifyToM4(void){}; ++__weak void HW_IPCC_ZIGBEE_RecvM0RequestToM4(void){}; ++#endif /* ZIGBEE_WB */ ++ ++/****************************************************************************** ++ * MEMORY MANAGER ++ ******************************************************************************/ ++void HW_IPCC_MM_SendFreeBuf(void (*cb)(void)) { + if(LL_C1_IPCC_IsActiveFlag_CHx(IPCC, HW_IPCC_MM_RELEASE_BUFFER_CHANNEL)) { + FreeBufCb = cb; + LL_C1_IPCC_EnableTransmitChannel(IPCC, HW_IPCC_MM_RELEASE_BUFFER_CHANNEL); +@@ -143,22 +557,37 @@ void HW_IPCC_MM_SendFreeBuf(void (*cb)()) { + + LL_C1_IPCC_SetFlag_CHx(IPCC, HW_IPCC_MM_RELEASE_BUFFER_CHANNEL); + } ++ ++ return; + } + +-static void HW_IPCC_MM_FreeBufHandler() { ++static void HW_IPCC_MM_FreeBufHandler(void) { + LL_C1_IPCC_DisableTransmitChannel(IPCC, HW_IPCC_MM_RELEASE_BUFFER_CHANNEL); + + FreeBufCb(); + + LL_C1_IPCC_SetFlag_CHx(IPCC, HW_IPCC_MM_RELEASE_BUFFER_CHANNEL); ++ ++ return; + } + +-void HW_IPCC_TRACES_Init() { ++/****************************************************************************** ++ * TRACES ++ ******************************************************************************/ ++void HW_IPCC_TRACES_Init(void) { + LL_C1_IPCC_EnableReceiveChannel(IPCC, HW_IPCC_TRACES_CHANNEL); ++ ++ return; + } + +-static void HW_IPCC_TRACES_EvtHandler() { ++static void HW_IPCC_TRACES_EvtHandler(void) { + HW_IPCC_TRACES_EvtNot(); + + LL_C1_IPCC_ClearFlag_CHx(IPCC, HW_IPCC_TRACES_CHANNEL); ++ ++ return; + } ++ ++__weak void HW_IPCC_TRACES_EvtNot(void){}; ++ ++/******************* (C) COPYRIGHT 2019 STMicroelectronics *****END OF FILE****/ +diff --git a/firmware/targets/f7/ble_glue/osal.h b/firmware/targets/f7/ble_glue/osal.h +index 0cde06179..e5e0c4f68 100644 +--- a/firmware/targets/f7/ble_glue/osal.h ++++ b/firmware/targets/f7/ble_glue/osal.h +@@ -1,4 +1,25 @@ +-#pragma once ++/***************************************************************************** ++ * @file osal.h ++ * @author MDG ++ * @brief This header file defines the OS abstraction layer used by ++ * the BLE stack. OSAL defines the set of functions which needs to be ++ * ported to target operating system and target platform. ++ * Actually, only memset, memcpy and memcmp wrappers are defined. ++ ***************************************************************************** ++ * @attention ++ * ++ * Copyright (c) 2018-2022 STMicroelectronics. ++ * All rights reserved. ++ * ++ * This software is licensed under terms that can be found in the LICENSE file ++ * in the root directory of this software component. ++ * If no LICENSE file comes with this software, it is provided AS-IS. ++ * ++ ***************************************************************************** ++ */ ++ ++#ifndef OSAL_H__ ++#define OSAL_H__ + + /** + * This function copies size number of bytes from a +@@ -38,3 +59,5 @@ extern void* Osal_MemSet(void* ptr, int value, unsigned int size); + * @return 0 if the two buffers are equal, 1 otherwise + */ + extern int Osal_MemCmp(const void* s1, const void* s2, unsigned int size); ++ ++#endif /* OSAL_H__ */ +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 0db25b3d3..c6421dc28 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 { +- SerialSvcGattCharacteristicRx = 0, +- SerialSvcGattCharacteristicTx, +- SerialSvcGattCharacteristicFlowCtrl, +- SerialSvcGattCharacteristicStatus, +- SerialSvcGattCharacteristicCount, +-} SerialSvcGattCharacteristicId; +- +-static const FlipperGattCharacteristicParams serial_svc_chars[SerialSvcGattCharacteristicCount] = { +- [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}, +- [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}, +- [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 5bee97b41..000000000 +--- 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 ad520f62e..000000000 +--- 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 c06403f55..000000000 +--- a/firmware/targets/f7/ble_glue/services/gatt_char.c ++++ /dev/null +@@ -1,122 +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 +- 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, +- MIN_ENCRY_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 959ab67a4..000000000 +--- 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 d3fad0108..000000000 +--- a/firmware/targets/f7/ble_glue/services/hid_service.c ++++ /dev/null +@@ -1,366 +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 const Service_UUID_t hid_svc_uuid = { +- .Service_UUID_16 = HUMAN_INTERFACE_DEVICE_SERVICE_UUID, +-}; +- +-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)); +- +- // Register event handler +- SVCCTL_RegisterSvcHandler(hid_svc_event_handler); +- /** +- * Add Human Interface Device Service +- */ +- status = aci_gatt_add_service( +- UUID_TYPE_16, +- &hid_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 a297d9ad6..000000000 +--- 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/ble_glue/tl_dbg_conf.h b/firmware/targets/f7/ble_glue/tl_dbg_conf.h +index daaa9d82b..ce58af32b 100644 +--- a/firmware/targets/f7/ble_glue/tl_dbg_conf.h ++++ b/firmware/targets/f7/ble_glue/tl_dbg_conf.h +@@ -1,12 +1,39 @@ +-#pragma once ++/* USER CODE BEGIN Header */ ++/** ++ ****************************************************************************** ++ * File Name : App/tl_dbg_conf.h ++ * Description : Debug configuration file for stm32wpan transport layer interface. ++ * ++ ****************************************************************************** ++ * @attention ++ * ++ *

© Copyright (c) 2020 STMicroelectronics. ++ * All rights reserved.

++ * ++ * This software component is licensed by ST under Ultimate Liberty license ++ * SLA0044, the "License"; You may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at: ++ * www.st.com/SLA0044 ++ * ++ ****************************************************************************** ++ */ ++/* USER CODE END Header */ + +-#include "app_conf.h" /* required as some configuration used in dbg_trace.h are set there */ +-#include "dbg_trace.h" ++/* Define to prevent recursive inclusion -------------------------------------*/ ++#ifndef __TL_DBG_CONF_H ++#define __TL_DBG_CONF_H + + #ifdef __cplusplus + extern "C" { + #endif + ++/* USER CODE BEGIN Tl_Conf */ ++ ++/* Includes ------------------------------------------------------------------*/ ++#include "app_conf.h" /* required as some configuration used in dbg_trace.h are set there */ ++#include "dbg_trace.h" ++#include "hw_if.h" ++ + /** + * Enable or Disable traces + * The raw data output is the hci binary packet format as specified by the BT specification * +@@ -97,6 +124,12 @@ extern "C" { + #define TL_MM_DBG_MSG(...) + #endif + ++/* USER CODE END Tl_Conf */ ++ + #ifdef __cplusplus + } + #endif ++ ++#endif /*__TL_DBG_CONF_H */ ++ ++/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +diff --git a/firmware/targets/f7/ble_glue/utilities_conf.h b/firmware/targets/f7/ble_glue/utilities_conf.h +new file mode 100644 +index 000000000..9c15f2263 +--- /dev/null ++++ b/firmware/targets/f7/ble_glue/utilities_conf.h +@@ -0,0 +1,68 @@ ++/* USER CODE BEGIN Header */ ++/** ++ ****************************************************************************** ++ * File Name : utilities_conf.h ++ * Description : Configuration file for STM32 Utilities. ++ * ++ ****************************************************************************** ++ * @attention ++ * ++ *

© Copyright (c) 2019 STMicroelectronics. ++ * All rights reserved.

++ * ++ * This software component is licensed by ST under BSD 3-Clause license, ++ * the "License"; You may not use this file except in compliance with the ++ * License. You may obtain a copy of the License at: ++ * opensource.org/licenses/BSD-3-Clause ++ * ++ ****************************************************************************** ++ */ ++/* USER CODE END Header */ ++ ++/* Define to prevent recursive inclusion -------------------------------------*/ ++#ifndef UTILITIES_CONF_H ++#define UTILITIES_CONF_H ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#include "cmsis_compiler.h" ++#include "string.h" ++#include ++ ++/****************************************************************************** ++ * common ++ ******************************************************************************/ ++#define UTILS_ENTER_CRITICAL_SECTION() FURI_CRITICAL_ENTER() ++ ++#define UTILS_EXIT_CRITICAL_SECTION() FURI_CRITICAL_EXIT() ++ ++#define UTILS_MEMSET8(dest, value, size) memset(dest, value, size); ++ ++/****************************************************************************** ++ * tiny low power manager ++ * (any macro that does not need to be modified can be removed) ++ ******************************************************************************/ ++#define UTIL_LPM_INIT_CRITICAL_SECTION() ++#define UTIL_LPM_ENTER_CRITICAL_SECTION() UTILS_ENTER_CRITICAL_SECTION() ++#define UTIL_LPM_EXIT_CRITICAL_SECTION() UTILS_EXIT_CRITICAL_SECTION() ++ ++/****************************************************************************** ++ * sequencer ++ * (any macro that does not need to be modified can be removed) ++ ******************************************************************************/ ++#define UTIL_SEQ_INIT_CRITICAL_SECTION() ++#define UTIL_SEQ_ENTER_CRITICAL_SECTION() UTILS_ENTER_CRITICAL_SECTION() ++#define UTIL_SEQ_EXIT_CRITICAL_SECTION() UTILS_EXIT_CRITICAL_SECTION() ++#define UTIL_SEQ_CONF_TASK_NBR (32) ++#define UTIL_SEQ_CONF_PRIO_NBR (2) ++#define UTIL_SEQ_MEMSET8(dest, value, size) UTILS_MEMSET8(dest, value, size) ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /*UTILITIES_CONF_H */ ++ ++/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt.c b/firmware/targets/f7/furi_hal/furi_hal_bt.c +index 9defefbfe..ce6e9e291 100644 +--- a/firmware/targets/f7/furi_hal/furi_hal_bt.c ++++ b/firmware/targets/f7/furi_hal/furi_hal_bt.c +@@ -2,18 +2,15 @@ + + #include + #include +- + #include +-#include +- +-#include + + #include + #include + #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 2bbfc1523..8e05a9904 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 2927d946f..2539e6bd0 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/f7/furi_hal/furi_hal_clock.c b/firmware/targets/f7/furi_hal/furi_hal_clock.c +index 86c8fd467..736ad9f7c 100644 +--- a/firmware/targets/f7/furi_hal/furi_hal_clock.c ++++ b/firmware/targets/f7/furi_hal/furi_hal_clock.c +@@ -4,26 +4,19 @@ + + #include + #include +-#include + #include + #include + +-#include +-#include +- + #define TAG "FuriHalClock" + +-#define CPU_CLOCK_EARLY_HZ 4000000 +-#define CPU_CLOCK_HSI16_HZ 16000000 +-#define CPU_CLOCK_HSE_HZ 32000000 +-#define CPU_CLOCK_PLL_HZ 64000000 +- ++#define CPU_CLOCK_HZ_EARLY 4000000 ++#define CPU_CLOCK_HZ_MAIN 64000000 + #define TICK_INT_PRIORITY 15U + #define HS_CLOCK_IS_READY() (LL_RCC_HSE_IsReady() && LL_RCC_HSI_IsReady()) + #define LS_CLOCK_IS_READY() (LL_RCC_LSE_IsReady() && LL_RCC_LSI1_IsReady()) + + void furi_hal_clock_init_early() { +- LL_SetSystemCoreClock(CPU_CLOCK_EARLY_HZ); ++ LL_SetSystemCoreClock(CPU_CLOCK_HZ_EARLY); + LL_Init1msTick(SystemCoreClock); + } + +@@ -31,6 +24,11 @@ void furi_hal_clock_deinit_early() { + } + + void furi_hal_clock_init() { ++ /* Prepare Flash memory for 64MHz system clock */ ++ LL_FLASH_SetLatency(LL_FLASH_LATENCY_3); ++ while(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_3) ++ ; ++ + /* HSE and HSI configuration and activation */ + LL_RCC_HSE_SetCapacitorTuning(0x26); + LL_RCC_HSE_Enable(); +@@ -51,6 +49,9 @@ void furi_hal_clock_init() { + while(!LS_CLOCK_IS_READY()) + ; + ++ /* RF wakeup */ ++ LL_RCC_SetRFWKPClockSource(LL_RCC_RFWKP_CLKSOURCE_LSE); ++ + LL_EXTI_EnableIT_0_31( + LL_EXTI_LINE_18); /* Why? Because that's why. See RM0434, Table 61. CPU1 vector table. */ + LL_EXTI_EnableRisingTrig_0_31(LL_EXTI_LINE_18); +@@ -78,17 +79,12 @@ void furi_hal_clock_init() { + ; + + /* Sysclk activation on the main PLL */ +- /* Set CPU1 prescaler */ ++ /* Set CPU1 prescaler*/ + LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1); + +- /* Set CPU2 prescaler, from this point we are not allowed to touch it. */ ++ /* Set CPU2 prescaler*/ + LL_C2_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_2); + +- /* Prepare Flash memory for work on 64MHz system clock */ +- LL_FLASH_SetLatency(LL_FLASH_LATENCY_3); +- while(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_3) +- ; +- + LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL); + while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) + ; +@@ -108,7 +104,7 @@ void furi_hal_clock_init() { + ; + + /* Update CMSIS variable (which can be updated also through SystemCoreClockUpdate function) */ +- LL_SetSystemCoreClock(CPU_CLOCK_PLL_HZ); ++ LL_SetSystemCoreClock(CPU_CLOCK_HZ_MAIN); + + /* Update the time base */ + LL_Init1msTick(SystemCoreClock); +@@ -126,7 +122,7 @@ void furi_hal_clock_init() { + FURI_LOG_I(TAG, "Init OK"); + } + +-void furi_hal_clock_switch_hse2hsi() { ++void furi_hal_clock_switch_to_hsi() { + LL_RCC_HSI_Enable(); + + while(!LL_RCC_HSI_IsReady()) +@@ -138,77 +134,46 @@ void furi_hal_clock_switch_hse2hsi() { + while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSI) + ; + ++ LL_C2_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1); ++ + LL_FLASH_SetLatency(LL_FLASH_LATENCY_0); + while(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_0) + ; + } + +-void furi_hal_clock_switch_hsi2hse() { ++void furi_hal_clock_switch_to_pll() { + #ifdef FURI_HAL_CLOCK_TRACK_STARTUP + uint32_t clock_start_time = DWT->CYCCNT; + #endif + + LL_RCC_HSE_Enable(); +- while(!LL_RCC_HSE_IsReady()) +- ; +- +- LL_FLASH_SetLatency(LL_FLASH_LATENCY_1); +- while(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_1) +- ; +- +- LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSE); +- +- while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSE) +- ; +- +-#ifdef FURI_HAL_CLOCK_TRACK_STARTUP +- uint32_t total = DWT->CYCCNT - clock_start_time; +- if(total > (20 * 0x148)) { +- furi_crash("Slow HSE/PLL startup"); +- } +-#endif +-} +- +-bool furi_hal_clock_switch_hse2pll() { +- furi_assert(LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_HSE); +- + LL_RCC_PLL_Enable(); + LL_RCC_PLLSAI1_Enable(); + ++ while(!LL_RCC_HSE_IsReady()) ++ ; + while(!LL_RCC_PLL_IsReady()) + ; + while(!LL_RCC_PLLSAI1_IsReady()) + ; + +- if(SHCI_C2_SetSystemClock(SET_SYSTEM_CLOCK_HSE_TO_PLL) != SHCI_Success) { +- return false; +- } +- +- furi_check(LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_PLL); +- +- LL_SetSystemCoreClock(CPU_CLOCK_PLL_HZ); +- SysTick->LOAD = (uint32_t)((SystemCoreClock / 1000) - 1UL); ++ LL_C2_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_2); + +- return true; +-} ++ LL_FLASH_SetLatency(LL_FLASH_LATENCY_3); ++ while(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_3) ++ ; + +-bool furi_hal_clock_switch_pll2hse() { +- furi_assert(LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_PLL); ++ LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL); + +- LL_RCC_HSE_Enable(); +- while(!LL_RCC_HSE_IsReady()) ++ while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) + ; + +- if(SHCI_C2_SetSystemClock(SET_SYSTEM_CLOCK_PLL_ON_TO_HSE) != SHCI_Success) { +- return false; ++#ifdef FURI_HAL_CLOCK_TRACK_STARTUP ++ uint32_t total = DWT->CYCCNT - clock_start_time; ++ if(total > (20 * 0x148)) { ++ furi_crash("Slow HSE/PLL startup"); + } +- +- furi_check(LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_HSE); +- +- LL_SetSystemCoreClock(CPU_CLOCK_HSE_HZ); +- SysTick->LOAD = (uint32_t)((SystemCoreClock / 1000) - 1UL); +- +- return true; ++#endif + } + + void furi_hal_clock_suspend_tick() { +diff --git a/firmware/targets/f7/furi_hal/furi_hal_clock.h b/firmware/targets/f7/furi_hal/furi_hal_clock.h +index 3100b619f..5e651bbd3 100644 +--- a/firmware/targets/f7/furi_hal/furi_hal_clock.h ++++ b/firmware/targets/f7/furi_hal/furi_hal_clock.h +@@ -1,12 +1,11 @@ + #pragma once + +-#include +-#include +- + #ifdef __cplusplus + extern "C" { + #endif + ++#include ++ + typedef enum { + FuriHalClockMcoLse, + FuriHalClockMcoSysclk, +@@ -41,23 +40,11 @@ void furi_hal_clock_deinit_early(); + /** Initialize clocks */ + void furi_hal_clock_init(); + +-/** Switch clock from HSE to HSI */ +-void furi_hal_clock_switch_hse2hsi(); +- +-/** Switch clock from HSI to HSE */ +-void furi_hal_clock_switch_hsi2hse(); +- +-/** Switch clock from HSE to PLL +- * +- * @return true if changed, false if failed or not possible at this moment +- */ +-bool furi_hal_clock_switch_hse2pll(); ++/** Switch to HSI clock */ ++void furi_hal_clock_switch_to_hsi(); + +-/** Switch clock from PLL to HSE +- * +- * @return true if changed, false if failed or not possible at this moment +- */ +-bool furi_hal_clock_switch_pll2hse(); ++/** Switch to PLL clock */ ++void furi_hal_clock_switch_to_pll(); + + /** Stop SysTick counter without resetting */ + void furi_hal_clock_suspend_tick(); +diff --git a/firmware/targets/f7/furi_hal/furi_hal_console.c b/firmware/targets/f7/furi_hal/furi_hal_console.c +index 0b113d2da..2bdc57250 100644 +--- a/firmware/targets/f7/furi_hal/furi_hal_console.c ++++ b/firmware/targets/f7/furi_hal/furi_hal_console.c +@@ -5,6 +5,8 @@ + #include + #include + ++#include ++ + #include + + #define TAG "FuriHalConsole" +diff --git a/firmware/targets/f7/furi_hal/furi_hal_flash.c b/firmware/targets/f7/furi_hal/furi_hal_flash.c +index bc65b29eb..796d20b19 100644 +--- a/firmware/targets/f7/furi_hal/furi_hal_flash.c ++++ b/firmware/targets/f7/furi_hal/furi_hal_flash.c +@@ -7,9 +7,6 @@ + #include + + #include +-#include +- +-#include + + #define TAG "FuriHalFlash" + +diff --git a/firmware/targets/f7/furi_hal/furi_hal_memory.c b/firmware/targets/f7/furi_hal/furi_hal_memory.c +index 3f8df1f44..7f69b90ca 100644 +--- a/firmware/targets/f7/furi_hal/furi_hal_memory.c ++++ b/firmware/targets/f7/furi_hal/furi_hal_memory.c +@@ -4,6 +4,9 @@ + + #define TAG "FuriHalMemory" + ++// STM(TM) Copro(TM) bug(TM) workaround size ++#define RAM2B_COPRO_GAP_SIZE_KB 2 ++ + typedef enum { + SRAM_A, + SRAM_B, +@@ -35,20 +38,13 @@ void furi_hal_memory_init() { + uint32_t sbrsa = (FLASH->SRRVR & FLASH_SRRVR_SBRSA_Msk) >> FLASH_SRRVR_SBRSA_Pos; + uint32_t snbrsa = (FLASH->SRRVR & FLASH_SRRVR_SNBRSA_Msk) >> FLASH_SRRVR_SNBRSA_Pos; + +- // STM(TM) Copro(TM) bug(TM): SNBRSA is incorrect if stack version is higher than 1.13 and lower than 1.17.2+ +- // Radio core started, but not yet ready, so we'll try to guess +- // This will be true only if BLE light radio stack used, +- // 0x0D is known to be incorrect, 0x0B is known to be correct since 1.17.2+ +- // Lower value by 2 pages to match real memory layout +- if(snbrsa > 0x0B) { +- FURI_LOG_E(TAG, "SNBRSA workaround"); +- snbrsa -= 2; +- } +- + uint32_t sram2a_busy_size = (uint32_t)&__sram2a_free__ - (uint32_t)&__sram2a_start__; + uint32_t sram2a_unprotected_size = (sbrsa)*1024; + uint32_t sram2b_unprotected_size = (snbrsa)*1024; + ++ // STM(TM) Copro(TM) bug(TM) workaround ++ sram2b_unprotected_size -= 1024 * RAM2B_COPRO_GAP_SIZE_KB; ++ + memory->region[SRAM_A].start = (uint8_t*)&__sram2a_free__; + memory->region[SRAM_B].start = (uint8_t*)&__sram2b_start__; + +diff --git a/firmware/targets/f7/furi_hal/furi_hal_os.c b/firmware/targets/f7/furi_hal/furi_hal_os.c +index 046cf79dc..3fc1fbea8 100644 +--- a/firmware/targets/f7/furi_hal/furi_hal_os.c ++++ b/firmware/targets/f7/furi_hal/furi_hal_os.c +@@ -170,35 +170,27 @@ void vPortSuppressTicksAndSleep(TickType_t expected_idle_ticks) { + return; + } + +- // Core2 shenanigans takes extra time, so we want to compensate tick skew by reducing sleep duration by 1 tick +- TickType_t unexpected_idle_ticks = expected_idle_ticks - 1; +- + // Limit amount of ticks to maximum that timer can count +- if(unexpected_idle_ticks > FURI_HAL_OS_MAX_SLEEP) { +- unexpected_idle_ticks = FURI_HAL_OS_MAX_SLEEP; ++ if(expected_idle_ticks > FURI_HAL_OS_MAX_SLEEP) { ++ expected_idle_ticks = FURI_HAL_OS_MAX_SLEEP; + } + + // Stop IRQ handling, no one should disturb us till we finish + __disable_irq(); +- do { +- // Confirm OS that sleep is still possible +- if(eTaskConfirmSleepModeStatus() == eAbortSleep || furi_hal_os_is_pending_irq()) { +- break; +- } + +- // Sleep and track how much ticks we spent sleeping +- uint32_t completed_ticks = furi_hal_os_sleep(unexpected_idle_ticks); +- // Notify system about time spent in sleep +- if(completed_ticks > 0) { +- if(completed_ticks > expected_idle_ticks) { +-#ifdef FURI_HAL_OS_DEBUG +- furi_hal_console_printf(">%lu\r\n", completed_ticks - expected_idle_ticks); +-#endif +- completed_ticks = expected_idle_ticks; +- } +- vTaskStepTick(completed_ticks); +- } +- } while(0); ++ // Confirm OS that sleep is still possible ++ if(eTaskConfirmSleepModeStatus() == eAbortSleep || furi_hal_os_is_pending_irq()) { ++ __enable_irq(); ++ return; ++ } ++ ++ // Sleep and track how much ticks we spent sleeping ++ uint32_t completed_ticks = furi_hal_os_sleep(expected_idle_ticks); ++ // Notify system about time spent in sleep ++ if(completed_ticks > 0) { ++ vTaskStepTick(MIN(completed_ticks, expected_idle_ticks)); ++ } ++ + // Reenable IRQ + __enable_irq(); + } +diff --git a/firmware/targets/f7/furi_hal/furi_hal_power.c b/firmware/targets/f7/furi_hal/furi_hal_power.c +index c14de8569..035919d78 100644 +--- a/firmware/targets/f7/furi_hal/furi_hal_power.c ++++ b/firmware/targets/f7/furi_hal/furi_hal_power.c +@@ -13,7 +13,7 @@ + #include + #include + +-#include ++#include + #include + #include + #include +@@ -162,11 +162,6 @@ static inline void furi_hal_power_resume_aux_periphs() { + static inline void furi_hal_power_deep_sleep() { + furi_hal_power_suspend_aux_periphs(); + +- if(!furi_hal_clock_switch_pll2hse()) { +- // Hello core2 my old friend +- return; +- } +- + while(LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID)) + ; + +@@ -176,13 +171,13 @@ static inline void furi_hal_power_deep_sleep() { + LL_HSEM_ReleaseLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0); + + // The switch on HSI before entering Stop Mode is required +- furi_hal_clock_switch_hse2hsi(); ++ furi_hal_clock_switch_to_hsi(); + } + } else { + /** + * The switch on HSI before entering Stop Mode is required + */ +- furi_hal_clock_switch_hse2hsi(); ++ furi_hal_clock_switch_to_hsi(); + } + + /* Release RCC semaphore */ +@@ -206,14 +201,12 @@ static inline void furi_hal_power_deep_sleep() { + while(LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID)) + ; + +- if(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSE) { +- furi_hal_clock_switch_hsi2hse(); ++ if(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) { ++ furi_hal_clock_switch_to_pll(); + } + + LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0); + +- furi_check(furi_hal_clock_switch_hse2pll()); +- + furi_hal_power_resume_aux_periphs(); + furi_hal_rtc_sync_shadow(); + } +diff --git a/firmware/targets/f7/furi_hal/furi_hal_random.c b/firmware/targets/f7/furi_hal/furi_hal_random.c +index 225519303..cf4b552f6 100644 +--- a/firmware/targets/f7/furi_hal/furi_hal_random.c ++++ b/firmware/targets/f7/furi_hal/furi_hal_random.c +@@ -6,7 +6,7 @@ + #include + #include + +-#include ++#include + + #define TAG "FuriHalRandom" + +diff --git a/firmware/targets/furi_hal_include/furi_hal_bt.h b/firmware/targets/furi_hal_include/furi_hal_bt.h +index 25a20c4c3..b7d4eae1a 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 0472d31d1..1b6e79ab0 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" { +diff --git a/lib/stm32wb.scons b/lib/stm32wb.scons +index 8a8ad9644..94a1c7075 100644 +--- a/lib/stm32wb.scons ++++ b/lib/stm32wb.scons +@@ -64,6 +64,7 @@ sources += [ + "stm32wb_copro/wpan/ble/core/auto/ble_l2cap_aci.c", + "stm32wb_copro/wpan/ble/core/template/osal.c", + "stm32wb_copro/wpan/utilities/dbg_trace.c", ++ "stm32wb_copro/wpan/utilities/otp.c", + "stm32wb_copro/wpan/utilities/stm_list.c", + ] + +diff --git a/lib/stm32wb_copro b/lib/stm32wb_copro +index bbccbefae..6c9c54f05 160000 +--- a/lib/stm32wb_copro ++++ b/lib/stm32wb_copro +@@ -1 +1 @@ +-Subproject commit bbccbefae26a2301b8a4b58e57ebdeb93c08269b ++Subproject commit 6c9c54f05669b2c4d436df58bb691d3b0d7c86df +diff --git a/scripts/ob.data b/scripts/ob.data +index 9f6f1d081..605faccbf 100644 +--- a/scripts/ob.data ++++ b/scripts/ob.data +@@ -14,15 +14,15 @@ IWDGSTOP:0x1:rw + IWDGSW:0x1:rw + IPCCDBA:0x0:rw + ESE:0x1:r +-SFSA:0xD7:r ++SFSA:0xD5:r + FSD:0x0:r + DDS:0x1:r + C2OPT:0x1:r + NBRSD:0x0:r +-SNBRSA:0xB:r ++SNBRSA:0xD:r + BRSD:0x0:r + SBRSA:0x12:r +-SBRV:0x35C00:r ++SBRV:0x35400:r + PCROP1A_STRT:0x1FF:r + PCROP1A_END:0x0:r + PCROP_RDP:0x1:rw +diff --git a/scripts/update.py b/scripts/update.py +index da4a93aee..e6c69d35f 100755 +--- a/scripts/update.py ++++ b/scripts/update.py +@@ -74,9 +74,6 @@ class Main(App): + self.parser_generate.add_argument( + "--I-understand-what-I-am-doing", dest="disclaimer", required=False + ) +- self.parser_generate.add_argument( +- "--stackversion", dest="stack_version", required=False, default="" +- ) + + self.parser_generate.set_defaults(func=self.generate) + +@@ -97,13 +94,6 @@ class Main(App): + if not self.args.radiotype: + raise ValueError("Missing --radiotype") + radio_meta = CoproBinary(self.args.radiobin) +- if self.args.stack_version: +- actual_stack_version_str = f"{radio_meta.img_sig.version_major}.{radio_meta.img_sig.version_minor}.{radio_meta.img_sig.version_sub}" +- if actual_stack_version_str != self.args.stack_version: +- self.logger.error( +- f"Stack version mismatch: expected {self.args.stack_version}, actual {actual_stack_version_str}" +- ) +- return 1 + radio_version = self.copro_version_as_int(radio_meta, self.args.radiotype) + if ( + get_stack_type(self.args.radiotype) not in self.WHITELISTED_STACK_TYPES