This commit is contained in:
Willy-JL
2023-09-30 19:25:50 +01:00
154 changed files with 3223 additions and 2939 deletions

View File

@@ -1,30 +1,4 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : app_common.h
* Description : App Common application configuration file for STM32WPAN Middleware.
*
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* 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
#pragma once
#include <stdint.h>
#include <string.h>
@@ -36,5 +10,3 @@ extern "C" {
#include <tl.h>
#include "app_conf.h"
#endif

View File

@@ -1,80 +1,32 @@
#pragma once
#include "hw_conf.h"
#include "hw_if.h"
#include <interface/patterns/ble_thread/hw.h>
#include <ble/core/ble_bufsize.h>
#include <ble/core/ble_defs.h>
#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_BONDING_MODE (1)
#define CFG_FIXED_PIN (111111)
#define CFG_USED_FIXED_PIN (1)
#define CFG_USED_FIXED_PIN USE_FIXED_PIN_FOR_PAIRING_FORBIDDEN
#define CFG_ENCRYPTION_KEY_SIZE_MAX (16)
#define CFG_ENCRYPTION_KEY_SIZE_MIN (8)
/**
* Define IO capabilities
*/
#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 CFG_IO_CAPABILITY IO_CAP_DISPLAY_YES_NO
/**
* Define MITM modes
*/
#define CFG_MITM_PROTECTION_NOT_REQUIRED (0x00)
#define CFG_MITM_PROTECTION_REQUIRED (0x01)
#define CFG_MITM_PROTECTION CFG_MITM_PROTECTION_REQUIRED
#define CFG_MITM_PROTECTION MITM_PROTECTION_REQUIRED
/**
* Define Secure Connections Support
*/
#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 CFG_SC_SUPPORT SC_PAIRING_OPTIONAL
/**
* Define PHY
@@ -87,42 +39,6 @@
#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
******************************************************************************/
@@ -203,7 +119,9 @@
* 1 : external high speed crystal HSE/32/32
* 0 : external low speed crystal ( no calibration )
*/
#define CFG_BLE_LSE_SOURCE 0
#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
/**
* Start up time of the high speed (16 or 32 MHz) crystal oscillator in units of 625/256 us (~2.44 us)
@@ -253,8 +171,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_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)
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)
/**
* Queue length of BLE Event
@@ -282,187 +200,3 @@
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

View File

@@ -6,6 +6,9 @@
#include <utilities/dbg_trace.h>
#include <utilities/utilities_common.h>
#include "stm32wbxx_ll_bus.h"
#include "stm32wbxx_ll_pwr.h"
#include <furi_hal.h>
typedef PACKED_STRUCT {
@@ -108,10 +111,6 @@ static void APPD_SetCPU2GpioConfig(void);
static void APPD_BleDtbCfg(void);
void APPD_Init() {
#if(CFG_DEBUG_TRACE != 0)
DbgTraceInit();
#endif
APPD_SetCPU2GpioConfig();
APPD_BleDtbCfg();
}
@@ -196,14 +195,14 @@ static void APPD_SetCPU2GpioConfig(void) {
gpio_config.Pin = gpiob_pin_list;
LL_C2_AHB2_GRP1_EnableClock(LL_C2_AHB2_GRP1_PERIPH_GPIOB);
LL_GPIO_Init(GPIOB, &gpio_config);
LL_GPIO_ResetOutputPin(GPIOB, gpioa_pin_list);
LL_GPIO_ResetOutputPin(GPIOB, gpiob_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, gpioa_pin_list);
LL_GPIO_ResetOutputPin(GPIOC, gpioc_pin_list);
}
}
@@ -252,13 +251,3 @@ 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

View File

@@ -1,26 +1,4 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : app_debug.h
* Description : Header for app_debug.c module
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* 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
#pragma once
#ifdef __cplusplus
extern "C" {
@@ -32,7 +10,3 @@ void APPD_EnableCPU2(void);
#ifdef __cplusplus
}
#endif
#endif /*__APP_DEBUG_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@@ -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) == 57,
"Ble stack config structure size mismatch (check new config options - last updated for v.1.15.0)");
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)");
typedef struct {
FuriMutex* hci_mtx;
@@ -33,6 +33,54 @@ 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));
@@ -44,58 +92,16 @@ 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
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);
status = SHCI_C2_Config((SHCI_C2_CONFIG_Cmd_Param_t*)&config_param);
if(status) {
FURI_LOG_E(TAG, "Failed to configure 2nd core: %d", status);
}
// Start ble stack on 2nd core
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);
status = SHCI_C2_BLE_Init((SHCI_C2_Ble_Init_Cmd_Packet_t*)&ble_init_cmd_packet);
if(status) {
FURI_LOG_E(TAG, "Failed to start ble stack: %d", status);
}
@@ -175,9 +181,11 @@ static void ble_app_hci_event_handler(void* pPayload) {
static void ble_app_hci_status_not_handler(HCI_TL_CmdStatus_t status) {
if(status == HCI_TL_CmdBusy) {
furi_hal_power_insomnia_enter();
furi_mutex_acquire(ble_app->hci_mtx, FuriWaitForever);
} else if(status == HCI_TL_CmdAvailable) {
furi_mutex_release(ble_app->hci_mtx);
furi_hal_power_insomnia_exit();
}
}

View File

@@ -1,12 +1,12 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdint.h>
bool ble_app_init();
void ble_app_get_key_storage_buff(uint8_t** addr, uint16_t* size);
void ble_app_thread_stop();

View File

@@ -1,51 +1,7 @@
/**
******************************************************************************
* File Name : App/ble_conf.h
* Description : Configuration file for BLE Middleware.
*
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* 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
#pragma once
#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
@@ -56,18 +12,3 @@
#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****/

View File

@@ -1,22 +1,4 @@
/*****************************************************************************
* @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__
#pragma once
#include <stdint.h>
#include <string.h>
@@ -115,5 +97,3 @@ 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__ */

View File

@@ -1,199 +1 @@
/**
******************************************************************************
* File Name : App/ble_dbg_conf.h
* Description : Debug configuration file for BLE Middleware.
*
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* 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****/
#pragma once

View File

@@ -32,7 +32,6 @@ 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;
@@ -104,7 +103,6 @@ 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);
@@ -393,7 +391,6 @@ 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;
@@ -427,22 +424,6 @@ 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;
}

View File

@@ -1,22 +1,4 @@
/*****************************************************************************
* @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__
#pragma once
#ifndef __PACKED_STRUCT
#define __PACKED_STRUCT PACKED(struct)
@@ -154,5 +136,3 @@
#endif
#endif
#endif
#endif /* COMPILER_H__ */

View File

@@ -1,220 +0,0 @@
#include "dev_info_service.h"
#include "app_common.h"
#include <ble/ble.h>
#include <furi.h>
#include <protobuf_version.h>
#include <lib/toolbox/version.h>
#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;
}

View File

@@ -1,416 +0,0 @@
#include "hid_service.h"
#include "app_common.h"
#include <ble/ble.h>
#include <furi.h>
#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;
}
}

View File

@@ -0,0 +1,81 @@
#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

View File

@@ -1,231 +0,0 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file hw_conf.h
* @author MCD Application Team
* @brief Configuration of hardware interface
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* 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****/

View File

@@ -1,102 +0,0 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file hw_if.h
* @author MCD Application Team
* @brief Hardware Interface
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* 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****/

View File

@@ -1,160 +1,52 @@
/**
******************************************************************************
* File Name : Target/hw_ipcc.c
* Description : Hardware IPCC source file for STM32WPAN Middleware.
*
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* 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 <interface/patterns/ble_thread/tl/mbox_def.h>
#include <interface/patterns/ble_thread/hw.h>
#include <furi_hal.h>
/* 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)))
#include <stm32wbxx_ll_ipcc.h>
#include <stm32wbxx_ll_pwr.h>
/* Private macros ------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static void (*FreeBufCb)(void);
#include <hsem_map.h>
/* 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);
#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))
#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
static void (*FreeBufCb)();
#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
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();
#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) {
void HW_IPCC_Rx_Handler() {
if(HW_IPCC_RX_PENDING(HW_IPCC_SYSTEM_EVENT_CHANNEL)) {
HW_IPCC_SYS_EvtHandler();
}
#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)) {
} 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) {
void HW_IPCC_Tx_Handler() {
if(HW_IPCC_TX_PENDING(HW_IPCC_SYSTEM_CMD_RSP_CHANNEL)) {
HW_IPCC_SYS_CmdEvtHandler();
}
#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)) {
} 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();
}
return;
}
/******************************************************************************
* GENERAL
******************************************************************************/
void HW_IPCC_Enable(void) {
void HW_IPCC_Enable() {
/**
* 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
@@ -177,11 +69,9 @@ void HW_IPCC_Enable(void) {
__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) {
void HW_IPCC_Init() {
LL_C1_IPCC_EnableIT_RXO(IPCC);
LL_C1_IPCC_EnableIT_TXF(IPCC);
@@ -189,366 +79,62 @@ void HW_IPCC_Init(void) {
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;
}
/******************************************************************************
* BLE
******************************************************************************/
void HW_IPCC_BLE_Init(void) {
void HW_IPCC_BLE_Init() {
LL_C1_IPCC_EnableReceiveChannel(IPCC, HW_IPCC_BLE_EVENT_CHANNEL);
return;
}
void HW_IPCC_BLE_SendCmd(void) {
void HW_IPCC_BLE_SendCmd() {
LL_C1_IPCC_SetFlag_CHx(IPCC, HW_IPCC_BLE_CMD_CHANNEL);
return;
}
static void HW_IPCC_BLE_EvtHandler(void) {
static void HW_IPCC_BLE_EvtHandler() {
HW_IPCC_BLE_RxEvtNot();
LL_C1_IPCC_ClearFlag_CHx(IPCC, HW_IPCC_BLE_EVENT_CHANNEL);
return;
}
void HW_IPCC_BLE_SendAclData(void) {
void HW_IPCC_BLE_SendAclData() {
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(void) {
static void HW_IPCC_BLE_AclDataEvtHandler() {
LL_C1_IPCC_DisableTransmitChannel(IPCC, HW_IPCC_HCI_ACL_DATA_CHANNEL);
HW_IPCC_BLE_AclDataAckNot();
return;
}
__weak void HW_IPCC_BLE_AclDataAckNot(void){};
__weak void HW_IPCC_BLE_RxEvtNot(void){};
/******************************************************************************
* SYSTEM
******************************************************************************/
void HW_IPCC_SYS_Init(void) {
void HW_IPCC_SYS_Init() {
LL_C1_IPCC_EnableReceiveChannel(IPCC, HW_IPCC_SYSTEM_EVENT_CHANNEL);
return;
}
void HW_IPCC_SYS_SendCmd(void) {
void HW_IPCC_SYS_SendCmd() {
LL_C1_IPCC_SetFlag_CHx(IPCC, HW_IPCC_SYSTEM_CMD_RSP_CHANNEL);
LL_C1_IPCC_EnableTransmitChannel(IPCC, HW_IPCC_SYSTEM_CMD_RSP_CHANNEL);
return;
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();
}
static void HW_IPCC_SYS_CmdEvtHandler(void) {
static void HW_IPCC_SYS_CmdEvtHandler() {
LL_C1_IPCC_DisableTransmitChannel(IPCC, HW_IPCC_SYSTEM_CMD_RSP_CHANNEL);
HW_IPCC_SYS_CmdEvtNot();
return;
}
static void HW_IPCC_SYS_EvtHandler(void) {
static void HW_IPCC_SYS_EvtHandler() {
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;
}
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)) {
void HW_IPCC_MM_SendFreeBuf(void (*cb)()) {
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);
@@ -557,37 +143,22 @@ void HW_IPCC_MM_SendFreeBuf(void (*cb)(void)) {
LL_C1_IPCC_SetFlag_CHx(IPCC, HW_IPCC_MM_RELEASE_BUFFER_CHANNEL);
}
return;
}
static void HW_IPCC_MM_FreeBufHandler(void) {
static void HW_IPCC_MM_FreeBufHandler() {
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;
}
/******************************************************************************
* TRACES
******************************************************************************/
void HW_IPCC_TRACES_Init(void) {
void HW_IPCC_TRACES_Init() {
LL_C1_IPCC_EnableReceiveChannel(IPCC, HW_IPCC_TRACES_CHANNEL);
return;
}
static void HW_IPCC_TRACES_EvtHandler(void) {
static void HW_IPCC_TRACES_EvtHandler() {
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****/

View File

@@ -1,25 +1,4 @@
/*****************************************************************************
* @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__
#pragma once
/**
* This function copies size number of bytes from a
@@ -59,5 +38,3 @@ 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__ */

View File

@@ -1,5 +1,7 @@
#include "battery_service.h"
#include "app_common.h"
#include "gatt_char.h"
#include <ble/ble.h>
#include <furi.h>
@@ -7,12 +9,6 @@
#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,
@@ -40,13 +36,44 @@ 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;
static const uint16_t battery_level_char_uuid = BATTERY_LEVEL_CHAR_UUID;
static const uint16_t power_state_char_uuid = BATTERY_POWER_STATE;
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;
void battery_svc_start() {
battery_svc = malloc(sizeof(BatterySvc));
@@ -58,53 +85,19 @@ void battery_svc_start() {
if(status) {
FURI_LOG_E(TAG, "Failed to add Battery service: %d", status);
}
// 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);
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 Power state characteristic
status = aci_gatt_add_char(
battery_svc->svc_handle,
UUID_TYPE_16,
(Char_UUID_t*)&power_state_char_uuid,
1,
CHAR_PROP_READ | CHAR_PROP_NOTIFY,
ATTR_PERMISSION_AUTHEN_READ,
GATT_DONT_NOTIFY_EVENTS,
10,
CHAR_VALUE_LEN_CONSTANT,
&battery_svc->power_state_char_handle);
if(status) {
FURI_LOG_E(TAG, "Failed to add Battery level characteristic: %d", status);
}
// Update power state charachteristic
battery_svc_update_power_state();
}
void battery_svc_stop() {
tBleStatus status;
if(battery_svc) {
// Delete Battery level characteristic
status =
aci_gatt_del_char(battery_svc->svc_handle, battery_svc->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);
for(size_t i = 0; i < BatterySvcGattCharacteristicCount; i++) {
flipper_gatt_characteristic_delete(battery_svc->svc_handle, &battery_svc->chars[i]);
}
// Delete Battery service
status = aci_gatt_del_service(battery_svc->svc_handle);
@@ -126,13 +119,10 @@ bool battery_svc_update_level(uint8_t battery_charge) {
return false;
}
// Update battery level characteristic
FURI_LOG_D(TAG, "Updating battery level characteristic");
tBleStatus result = aci_gatt_update_char_value(
battery_svc->svc_handle, battery_svc->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;
return flipper_gatt_characteristic_update(
battery_svc->svc_handle,
&battery_svc->chars[BatterySvcGattCharacteristicBatteryLevel],
&battery_charge);
}
bool battery_svc_update_power_state() {
@@ -152,15 +142,9 @@ bool battery_svc_update_power_state() {
power_state.charging = BatterySvcPowerStateNotCharging;
power_state.discharging = BatterySvcPowerStateDischarging;
}
FURI_LOG_D(TAG, "Updating power state characteristic");
tBleStatus result = aci_gatt_update_char_value(
return flipper_gatt_characteristic_update(
battery_svc->svc_handle,
battery_svc->power_state_char_handle,
0,
1,
(uint8_t*)&power_state);
if(result) {
FURI_LOG_E(TAG, "Failed updating Power state characteristic: %d", result);
}
return result != BLE_STATUS_SUCCESS;
&battery_svc->chars[BatterySvcGattCharacteristicPowerState],
&power_state);
}

View File

@@ -0,0 +1,176 @@
#include "dev_info_service.h"
#include "app_common.h"
#include "gatt_char.h"
#include <ble/ble.h>
#include <furi.h>
#include <protobuf_version.h>
#include <lib/toolbox/version.h>
#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;
}

View File

@@ -0,0 +1,3 @@
#define DEV_INVO_RPC_VERSION_UID \
{ 0x33, 0xa9, 0xb5, 0x3e, 0x87, 0x5d, 0x1a, 0x8e, 0xc8, 0x47, 0x5e, 0xae, 0x6d, 0x66, 0xf6, 0x03 }

View File

@@ -0,0 +1,122 @@
#include "gatt_char.h"
#include <furi.h>
#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;
}

View File

@@ -0,0 +1,96 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <ble/ble.h>
#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

View File

@@ -0,0 +1,366 @@
#include "hid_service.h"
#include "app_common.h"
#include <ble/ble.h>
#include "gatt_char.h"
#include <furi.h>
#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;
}
}

View File

@@ -27,6 +27,7 @@ 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);
bool hid_svc_update_info(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);
void hid_svc_register_led_state_callback(HidLedStateEventCallback callback, void* context);

View File

@@ -1,17 +1,67 @@
#include "serial_service.h"
#include "app_common.h"
#include <ble/ble.h>
#include "gatt_char.h"
#include <furi.h>
#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;
uint16_t rx_char_handle;
uint16_t tx_char_handle;
uint16_t flow_ctrl_char_handle;
uint16_t rpc_status_char_handle;
FlipperGattCharacteristicInstance chars[SerialSvcGattCharacteristicCount];
FuriMutex* buff_size_mtx;
uint32_t buff_size;
uint16_t bytes_ready_to_receive;
@@ -21,17 +71,6 @@ 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);
@@ -40,11 +79,14 @@ 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->rx_char_handle + 2) {
if(attribute_modified->Attr_Handle ==
serial_svc->chars[SerialSvcGattCharacteristicRx].handle + 2) {
// Descriptor handle
ret = SVCCTL_EvtAckFlowEnable;
FURI_LOG_D(TAG, "RX descriptor event");
} else if(attribute_modified->Attr_Handle == serial_svc->rx_char_handle + 1) {
} else if(
attribute_modified->Attr_Handle ==
serial_svc->chars[SerialSvcGattCharacteristicRx].handle + 1) {
FURI_LOG_D(TAG, "Received %d bytes", attribute_modified->Attr_Data_Length);
if(serial_svc->callback) {
furi_check(
@@ -70,7 +112,9 @@ 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->rpc_status_char_handle + 1) {
} else if(
attribute_modified->Attr_Handle ==
serial_svc->chars[SerialSvcGattCharacteristicStatus].handle + 1) {
SerialServiceRpcStatus* rpc_status =
(SerialServiceRpcStatus*)attribute_modified->Attr_Data;
if(*rpc_status == SerialServiceRpcStatusNotActive) {
@@ -97,18 +141,12 @@ static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void* event) {
}
static void serial_svc_update_rpc_char(SerialServiceRpcStatus 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);
}
flipper_gatt_characteristic_update(
serial_svc->svc_handle, &serial_svc->chars[SerialSvcGattCharacteristicStatus], &status);
}
void serial_svc_start() {
UNUSED(serial_svc_chars);
tBleStatus status;
serial_svc = malloc(sizeof(SerialSvc));
// Register event handler
@@ -116,72 +154,17 @@ void serial_svc_start() {
// Add service
status = aci_gatt_add_service(
UUID_TYPE_128, (Service_UUID_t*)service_uuid, PRIMARY_SERVICE, 12, &serial_svc->svc_handle);
UUID_TYPE_128, &service_uuid, PRIMARY_SERVICE, 12, &serial_svc->svc_handle);
if(status) {
FURI_LOG_E(TAG, "Failed to add Serial service: %d", status);
}
// 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 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 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);
@@ -196,13 +179,12 @@ 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);
aci_gatt_update_char_value(
flipper_gatt_characteristic_update(
serial_svc->svc_handle,
serial_svc->flow_ctrl_char_handle,
0,
sizeof(uint32_t),
(uint8_t*)&buff_size_reversed);
&serial_svc->chars[SerialSvcGattCharacteristicFlowCtrl],
&buff_size_reversed);
}
void serial_svc_notify_buffer_is_empty() {
@@ -213,13 +195,12 @@ 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);
aci_gatt_update_char_value(
flipper_gatt_characteristic_update(
serial_svc->svc_handle,
serial_svc->flow_ctrl_char_handle,
0,
sizeof(uint32_t),
(uint8_t*)&buff_size_reversed);
&serial_svc->chars[SerialSvcGattCharacteristicFlowCtrl],
&buff_size_reversed);
}
furi_check(furi_mutex_release(serial_svc->buff_size_mtx) == FuriStatusOk);
}
@@ -227,22 +208,8 @@ void serial_svc_notify_buffer_is_empty() {
void serial_svc_stop() {
tBleStatus status;
if(serial_svc) {
// 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);
for(uint8_t i = 0; i < SerialSvcGattCharacteristicCount; i++) {
flipper_gatt_characteristic_delete(serial_svc->svc_handle, &serial_svc->chars[i]);
}
// Delete service
status = aci_gatt_del_service(serial_svc->svc_handle);
@@ -273,7 +240,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->tx_char_handle,
serial_svc->chars[SerialSvcGattCharacteristicTx].handle,
remained ? 0x00 : 0x02,
data_len,
value_offset,

View File

@@ -0,0 +1,12 @@
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 }

View File

@@ -1,39 +1,12 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : App/tl_dbg_conf.h
* Description : Debug configuration file for stm32wpan transport layer interface.
*
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* 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 */
#pragma once
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __TL_DBG_CONF_H
#define __TL_DBG_CONF_H
#include "app_conf.h" /* required as some configuration used in dbg_trace.h are set there */
#include "dbg_trace.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 *
@@ -124,12 +97,6 @@ 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****/

View File

@@ -1,68 +0,0 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : utilities_conf.h
* Description : Configuration file for STM32 Utilities.
*
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* 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 <furi.h>
/******************************************************************************
* 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****/