Files
chest_strap/code/wb1mmc_code/STM32_WPAN/App/app_ble.c
T
2026-04-24 19:51:22 -07:00

696 lines
19 KiB
C

/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file App/app_ble.c
* @author MCD Application Team
* @brief BLE Application
*****************************************************************************
* @attention
*
* Copyright (c) 2026 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.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "app_common.h"
#include "dbg_trace.h"
#include "ble.h"
#include "tl.h"
#include "app_ble.h"
#include "stm32_seq.h"
#include "shci.h"
#include "stm32_lpm.h"
#include "otp.h"
#include "eddystone_beacon.h"
#include "eddystone_uid_service.h"
#include "eddystone_url_service.h"
#include "eddystone_tlm_service.h"
#include "ibeacon_service.h"
#include "ibeacon.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private defines -----------------------------------------------------------*/
#define APPBLE_GAP_DEVICE_NAME_LENGTH 7
/**
* Boot Mode: 1 (OTA)
* Sector Index: 6
* Nb Sectors : 1
*/
#define BOOT_MODE_AND_SECTOR 0x010601
#define APP_SECTORS 7
#define DATA_SECTOR 6
#define BD_ADDR_SIZE_LOCAL 6
#define BLE_DEFAULT_PIN (111111)
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
PLACE_IN_SECTION("MB_MEM1") ALIGN(4) static TL_CmdPacket_t BleCmdBuffer;
static const uint8_t a_MBdAddr[BD_ADDR_SIZE_LOCAL] =
{
(uint8_t)((CFG_ADV_BD_ADDRESS & 0x0000000000FF)),
(uint8_t)((CFG_ADV_BD_ADDRESS & 0x00000000FF00) >> 8),
(uint8_t)((CFG_ADV_BD_ADDRESS & 0x000000FF0000) >> 16),
(uint8_t)((CFG_ADV_BD_ADDRESS & 0x0000FF000000) >> 24),
(uint8_t)((CFG_ADV_BD_ADDRESS & 0x00FF00000000) >> 32),
(uint8_t)((CFG_ADV_BD_ADDRESS & 0xFF0000000000) >> 40)
};
static uint8_t a_BdAddrUdn[BD_ADDR_SIZE_LOCAL];
/**
* Identity root key used to derive IRK and DHK(Legacy)
*/
static const uint8_t a_BLE_CfgIrValue[16] = CFG_BLE_IR;
/**
* Encryption root key used to derive LTK(Legacy) and CSRK
*/
static const uint8_t a_BLE_CfgErValue[16] = CFG_BLE_ER;
static uint8_t sector_type;
/**
* These are the two tags used to manage a power failure during OTA
* The MagicKeywordAdress shall be mapped @0x140 from start of the binary image
* The MagicKeywordvalue is checked in the ble_ota application
*/
PLACE_IN_SECTION("TAG_OTA_END") const uint32_t MagicKeywordValue = 0x94448A29 ;
PLACE_IN_SECTION("TAG_OTA_START") const uint32_t MagicKeywordAddress = (uint32_t)&MagicKeywordValue;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
static void BLE_UserEvtRx(void *p_Payload);
static void BLE_StatusNot(HCI_TL_CmdStatus_t Status);
static void Ble_Tl_Init(void);
static void Ble_Hci_Gap_Gatt_Init(void);
static const uint8_t* BleGetBdAddress(void);
static void Beacon_Update(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* External variables --------------------------------------------------------*/
/* USER CODE BEGIN EV */
/* USER CODE END EV */
/* Functions Definition ------------------------------------------------------*/
void APP_BLE_Init(void)
{
SHCI_CmdStatus_t status;
/* USER CODE BEGIN APP_BLE_Init_1 */
/* USER CODE END APP_BLE_Init_1 */
SHCI_C2_Ble_Init_Cmd_Packet_t ble_init_cmd_packet =
{
{{0,0,0}}, /**< Header unused */
{0, /** pBleBufferAddress not used */
0, /** BleBufferSize not used */
CFG_BLE_NUM_GATT_ATTRIBUTES,
CFG_BLE_NUM_GATT_SERVICES,
CFG_BLE_ATT_VALUE_ARRAY_SIZE,
CFG_BLE_NUM_LINK,
CFG_BLE_DATA_LENGTH_EXTENSION,
CFG_BLE_PREPARE_WRITE_LIST_SIZE,
CFG_BLE_MBLOCK_COUNT,
CFG_BLE_MAX_ATT_MTU,
CFG_BLE_PERIPHERAL_SCA,
CFG_BLE_CENTRAL_SCA,
CFG_BLE_LS_SOURCE,
CFG_BLE_MAX_CONN_EVENT_LENGTH,
CFG_BLE_HSE_STARTUP_TIME,
CFG_BLE_VITERBI_MODE,
CFG_BLE_OPTIONS,
0,
CFG_BLE_MAX_COC_INITIATOR_NBR,
CFG_BLE_MIN_TX_POWER,
CFG_BLE_MAX_TX_POWER,
CFG_BLE_RX_MODEL_CONFIG,
CFG_BLE_MAX_ADV_SET_NBR,
CFG_BLE_MAX_ADV_DATA_LEN,
CFG_BLE_TX_PATH_COMPENS,
CFG_BLE_RX_PATH_COMPENS,
CFG_BLE_CORE_VERSION,
CFG_BLE_OPTIONS_EXT,
CFG_BLE_MAX_ADD_EATT_BEARERS
}
};
/**
* Initialize Ble Transport Layer
*/
Ble_Tl_Init();
#if (CFG_LPM_STANDBY_SUPPORTED == 0)
UTIL_LPM_SetOffMode(1U << CFG_LPM_APP_BLE, UTIL_LPM_DISABLE);
#endif /* CFG_LPM_STANDBY_SUPPORTED == 0 */
/**
* Register the hci transport layer to handle BLE User Asynchronous Events
*/
UTIL_SEQ_RegTask(1<<CFG_TASK_HCI_ASYNCH_EVT_ID, UTIL_SEQ_RFU, hci_user_evt_proc);
/**
* Starts the BLE Stack on CPU2
*/
status = SHCI_C2_BLE_Init(&ble_init_cmd_packet);
if (status != SHCI_Success)
{
APP_DBG_MSG(" Fail : SHCI_C2_BLE_Init command, result: 0x%02x\n\r", status);
/* if you are here, maybe CPU2 doesn't contain STM32WB_Copro_Wireless_Binaries, see Release_Notes.html */
Error_Handler();
}
else
{
APP_DBG_MSG(" Success: SHCI_C2_BLE_Init command\n\r");
}
/**
* Initialization of HCI & GATT & GAP layer
*/
Ble_Hci_Gap_Gatt_Init();
/**
* Initialization of the BLE Services
*/
SVCCTL_Init();
/**
* From here, all initialization are BLE application specific
*/
UTIL_SEQ_RegTask(1<<CFG_TASK_BEACON_UPDATE_REQ_ID, UTIL_SEQ_RFU, Beacon_Update);
/* USER CODE BEGIN APP_BLE_Init_3 */
/* USER CODE END APP_BLE_Init_3 */
/**
* Make device discoverable
*/
if (CFG_BEACON_TYPE & CFG_EDDYSTONE_UID_BEACON_TYPE)
{
APP_DBG_MSG("Eddystone UID beacon advertise\n\r");
EddystoneUID_Process();
}
else if (CFG_BEACON_TYPE & CFG_EDDYSTONE_URL_BEACON_TYPE)
{
APP_DBG_MSG("Eddystone URL beacon advertise\n\r");
EddystoneURL_Process();
}
else if (CFG_BEACON_TYPE & CFG_EDDYSTONE_TLM_BEACON_TYPE)
{
APP_DBG_MSG("Eddystone TLM beacon advertise\n\r");
EddystoneTLM_Process();
}
else if (CFG_BEACON_TYPE & CFG_IBEACON)
{
APP_DBG_MSG("Ibeacon advertise\n\r");
IBeacon_Process();
}
/* USER CODE BEGIN APP_BLE_Init_2 */
/* USER CODE END APP_BLE_Init_2 */
return;
}
SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void *p_Pckt)
{
hci_event_pckt *p_event_pckt;
evt_le_meta_event *p_meta_evt;
evt_blecore_aci *p_blecore_evt;
/* USER CODE BEGIN SVCCTL_App_Notification */
/* USER CODE END SVCCTL_App_Notification */
p_event_pckt = (hci_event_pckt*) ((hci_uart_pckt *) p_Pckt)->data;
switch (p_event_pckt->evt)
{
case HCI_DISCONNECTION_COMPLETE_EVT_CODE:
/* USER CODE BEGIN EVT_DISCONN_COMPLETE */
/* USER CODE END EVT_DISCONN_COMPLETE */
break; /* HCI_DISCONNECTION_COMPLETE_EVT_CODE */
case HCI_LE_META_EVT_CODE:
p_meta_evt = (evt_le_meta_event*) p_event_pckt->data;
/* USER CODE BEGIN EVT_LE_META_EVENT */
/* USER CODE END EVT_LE_META_EVENT */
switch (p_meta_evt->subevent)
{
case HCI_LE_CONNECTION_COMPLETE_SUBEVT_CODE:
/* USER CODE BEGIN SUBEVENT_DEFAULT */
/* USER CODE END SUBEVENT_DEFAULT */
break;
default:
/* USER CODE BEGIN SUBEVENT_DEFAULT */
/* USER CODE END SUBEVENT_DEFAULT */
break;
}
/* USER CODE BEGIN META_EVT */
/* USER CODE END META_EVT */
break; /* HCI_LE_META_EVT_CODE */
case HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE:
p_blecore_evt = (evt_blecore_aci*) p_event_pckt->data;
/* USER CODE BEGIN EVT_VENDOR */
/* USER CODE END EVT_VENDOR */
switch (p_blecore_evt->ecode)
{
/* USER CODE BEGIN ecode */
/* USER CODE END ecode */
case ACI_GAP_PROC_COMPLETE_VSEVT_CODE:
/* USER CODE BEGIN EVT_BLUE_GAP_PROCEDURE_COMPLETE */
/* USER CODE END EVT_BLUE_GAP_PROCEDURE_COMPLETE */
break; /* ACI_GAP_PROC_COMPLETE_VSEVT_CODE */
/* USER CODE BEGIN BLUE_EVT */
/* USER CODE END BLUE_EVT */
}
break; /* HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE */
/* USER CODE BEGIN EVENT_PCKT */
/* USER CODE END EVENT_PCKT */
default:
/* USER CODE BEGIN ECODE_DEFAULT*/
/* USER CODE END ECODE_DEFAULT*/
break;
}
return (SVCCTL_UserEvtFlowEnable);
}
/* USER CODE BEGIN FD*/
/* USER CODE END FD*/
/*************************************************************
*
* LOCAL FUNCTIONS
*
*************************************************************/
static void Ble_Tl_Init(void)
{
HCI_TL_HciInitConf_t Hci_Tl_Init_Conf;
Hci_Tl_Init_Conf.p_cmdbuffer = (uint8_t*)&BleCmdBuffer;
Hci_Tl_Init_Conf.StatusNotCallBack = BLE_StatusNot;
hci_init(BLE_UserEvtRx, (void*) &Hci_Tl_Init_Conf);
return;
}
static void Ble_Hci_Gap_Gatt_Init(void)
{
uint8_t role;
uint16_t gap_service_handle, gap_dev_name_char_handle, gap_appearance_char_handle;
const uint8_t *p_bd_addr;
uint16_t a_appearance[1] = {BLE_CFG_GAP_APPEARANCE};
tBleStatus ret = BLE_STATUS_INVALID_PARAMS;
/* USER CODE BEGIN Ble_Hci_Gap_Gatt_Init*/
/* USER CODE END Ble_Hci_Gap_Gatt_Init*/
APP_DBG_MSG("==>> Start Ble_Hci_Gap_Gatt_Init function\n");
/**
* Initialize HCI layer
*/
/*HCI Reset to synchronise BLE Stack*/
ret = hci_reset();
if (ret != BLE_STATUS_SUCCESS)
{
APP_DBG_MSG(" Fail : hci_reset command, result: 0x%x \n", ret);
}
else
{
APP_DBG_MSG(" Success: hci_reset command\n");
}
/**
* Write the BD Address
*/
p_bd_addr = BleGetBdAddress();
ret = aci_hal_write_config_data(CONFIG_DATA_PUBLIC_ADDRESS_OFFSET, CONFIG_DATA_PUBLIC_ADDRESS_LEN, (uint8_t*) p_bd_addr);
if (ret != BLE_STATUS_SUCCESS)
{
APP_DBG_MSG(" Fail : aci_hal_write_config_data command - CONFIG_DATA_PUBLIC_ADDRESS_OFFSET, result: 0x%x \n", ret);
}
else
{
APP_DBG_MSG(" Success: aci_hal_write_config_data command - CONFIG_DATA_PUBLIC_ADDRESS_OFFSET\n");
APP_DBG_MSG(" Public Bluetooth Address: %02x:%02x:%02x:%02x:%02x:%02x\n",p_bd_addr[5],p_bd_addr[4],p_bd_addr[3],p_bd_addr[2],p_bd_addr[1],p_bd_addr[0]);
}
/**
* Write Identity root key used to derive IRK and DHK(Legacy)
*/
ret = aci_hal_write_config_data(CONFIG_DATA_IR_OFFSET, CONFIG_DATA_IR_LEN, (uint8_t*)a_BLE_CfgIrValue);
if (ret != BLE_STATUS_SUCCESS)
{
APP_DBG_MSG(" Fail : aci_hal_write_config_data command - CONFIG_DATA_IR_OFFSET, result: 0x%x \n", ret);
}
else
{
APP_DBG_MSG(" Success: aci_hal_write_config_data command - CONFIG_DATA_IR_OFFSET\n");
}
/**
* Write Encryption root key used to derive LTK and CSRK
*/
ret = aci_hal_write_config_data(CONFIG_DATA_ER_OFFSET, CONFIG_DATA_ER_LEN, (uint8_t*)a_BLE_CfgErValue);
if (ret != BLE_STATUS_SUCCESS)
{
APP_DBG_MSG(" Fail : aci_hal_write_config_data command - CONFIG_DATA_ER_OFFSET, result: 0x%x \n", ret);
}
else
{
APP_DBG_MSG(" Success: aci_hal_write_config_data command - CONFIG_DATA_ER_OFFSET\n");
}
/**
* Set TX Power.
*/
ret = aci_hal_set_tx_power_level(1, CFG_TX_POWER);
if (ret != BLE_STATUS_SUCCESS)
{
APP_DBG_MSG(" Fail : aci_hal_set_tx_power_level command, result: 0x%x \n", ret);
}
else
{
APP_DBG_MSG(" Success: aci_hal_set_tx_power_level command\n");
}
/**
* Initialize GATT interface
*/
ret = aci_gatt_init();
if (ret != BLE_STATUS_SUCCESS)
{
APP_DBG_MSG(" Fail : aci_gatt_init command, result: 0x%x \n", ret);
}
else
{
APP_DBG_MSG(" Success: aci_gatt_init command\n");
}
/**
* Initialize GAP interface
*/
role = 0;
#if (BLE_CFG_PERIPHERAL == 1)
role |= GAP_PERIPHERAL_ROLE;
#endif /* BLE_CFG_PERIPHERAL == 1 */
#if (BLE_CFG_CENTRAL == 1)
role |= GAP_CENTRAL_ROLE;
#endif /* BLE_CFG_CENTRAL == 1 */
/* USER CODE BEGIN Role_Mngt*/
/* USER CODE END Role_Mngt */
if (role > 0)
{
const char *name = "STM32WB";
ret = aci_gap_init(role,
0,
APPBLE_GAP_DEVICE_NAME_LENGTH,
&gap_service_handle,
&gap_dev_name_char_handle,
&gap_appearance_char_handle);
if (ret != BLE_STATUS_SUCCESS)
{
APP_DBG_MSG(" Fail : aci_gap_init command, result: 0x%x \n", ret);
}
else
{
APP_DBG_MSG(" Success: aci_gap_init command\n");
}
ret = aci_gatt_update_char_value(gap_service_handle, gap_dev_name_char_handle, 0, strlen(name), (uint8_t *) name);
if (ret != BLE_STATUS_SUCCESS)
{
BLE_DBG_SVCCTL_MSG(" Fail : aci_gatt_update_char_value - Device Name\n");
}
else
{
BLE_DBG_SVCCTL_MSG(" Success: aci_gatt_update_char_value - Device Name\n");
}
}
ret = aci_gatt_update_char_value(gap_service_handle,
gap_appearance_char_handle,
0,
2,
(uint8_t *)&a_appearance);
if (ret != BLE_STATUS_SUCCESS)
{
BLE_DBG_SVCCTL_MSG(" Fail : aci_gatt_update_char_value - Appearance\n");
}
else
{
BLE_DBG_SVCCTL_MSG(" Success: aci_gatt_update_char_value - Appearance\n");
}
}
static void Beacon_Update(void)
{
FLASH_EraseInitTypeDef erase;
uint32_t pageError = 0;
if (sector_type != 0)
{
erase.TypeErase = FLASH_TYPEERASE_PAGES;
erase.Page = sector_type;
if (sector_type == APP_SECTORS)
{
erase.NbPages = 2; /* 2 sectors for beacon application */
}
else
{
erase.NbPages = 1; /* 1 sector for beacon user data */
}
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_OPTVERR);
HAL_FLASHEx_Erase(&erase, &pageError);
HAL_FLASH_Lock();
}
*(uint32_t*) SRAM1_BASE = BOOT_MODE_AND_SECTOR;
/**
* Boot Mode: 1 (OTA)
* Sector Index: 6
* Nb Sectors : 1
*/
NVIC_SystemReset();
}
const uint8_t* BleGetBdAddress(void)
{
uint8_t *p_otp_addr;
const uint8_t *p_bd_addr;
uint32_t udn;
uint32_t company_id;
uint32_t device_id;
udn = LL_FLASH_GetUDN();
if (udn != 0xFFFFFFFF)
{
company_id = LL_FLASH_GetSTCompanyID();
device_id = LL_FLASH_GetDeviceID();
/**
* Public Address with the ST company ID
* bit[47:24] : 24bits (OUI) equal to the company ID
* bit[23:16] : Device ID.
* bit[15:0] : The last 16bits from the UDN
* Note: In order to use the Public Address in a final product, a dedicated
* 24bits company ID (OUI) shall be bought.
*/
a_BdAddrUdn[0] = (uint8_t)(udn & 0x000000FF);
a_BdAddrUdn[1] = (uint8_t)((udn & 0x0000FF00) >> 8);
a_BdAddrUdn[2] = (uint8_t)device_id;
a_BdAddrUdn[3] = (uint8_t)(company_id & 0x000000FF);
a_BdAddrUdn[4] = (uint8_t)((company_id & 0x0000FF00) >> 8);
a_BdAddrUdn[5] = (uint8_t)((company_id & 0x00FF0000) >> 16);
p_bd_addr = (const uint8_t *)a_BdAddrUdn;
}
else
{
p_otp_addr = OTP_Read(0);
if (p_otp_addr)
{
p_bd_addr = ((OTP_ID0_t*)p_otp_addr)->bd_address;
}
else
{
p_bd_addr = a_MBdAddr;
}
}
return p_bd_addr;
}
/* USER CODE BEGIN FD_LOCAL_FUNCTION */
/* USER CODE END FD_LOCAL_FUNCTION */
/* USER CODE BEGIN FD_SPECIFIC_FUNCTIONS */
/* USER CODE END FD_SPECIFIC_FUNCTIONS */
/*************************************************************
*
* WRAP FUNCTIONS
*
*************************************************************/
void hci_notify_asynch_evt(void* p_Data)
{
UTIL_SEQ_SetTask(1 << CFG_TASK_HCI_ASYNCH_EVT_ID, CFG_SCH_PRIO_0);
return;
}
void hci_cmd_resp_release(uint32_t Flag)
{
UTIL_SEQ_SetEvt(1 << CFG_IDLEEVT_HCI_CMD_EVT_RSP_ID);
return;
}
void hci_cmd_resp_wait(uint32_t Timeout)
{
UTIL_SEQ_WaitEvt(1 << CFG_IDLEEVT_HCI_CMD_EVT_RSP_ID);
return;
}
static void BLE_UserEvtRx(void *p_Payload)
{
SVCCTL_UserEvtFlowStatus_t svctl_return_status;
tHCI_UserEvtRxParam *p_param;
p_param = (tHCI_UserEvtRxParam *)p_Payload;
svctl_return_status = SVCCTL_UserEvtRx((void *)&(p_param->pckt->evtserial));
if (svctl_return_status != SVCCTL_UserEvtFlowDisable)
{
p_param->status = HCI_TL_UserEventFlow_Enable;
}
else
{
p_param->status = HCI_TL_UserEventFlow_Disable;
}
return;
}
static void BLE_StatusNot(HCI_TL_CmdStatus_t Status)
{
uint32_t task_id_list;
switch (Status)
{
case HCI_TL_CmdBusy:
/**
* All tasks that may send an aci/hci commands shall be listed here
* This is to prevent a new command is sent while one is already pending
*/
task_id_list = (1 << CFG_LAST_TASK_ID_WITH_HCICMD) - 1;
UTIL_SEQ_PauseTask(task_id_list);
/* USER CODE BEGIN HCI_TL_CmdBusy */
/* USER CODE END HCI_TL_CmdBusy */
break;
case HCI_TL_CmdAvailable:
/**
* All tasks that may send an aci/hci commands shall be listed here
* This is to prevent a new command is sent while one is already pending
*/
task_id_list = (1 << CFG_LAST_TASK_ID_WITH_HCICMD) - 1;
UTIL_SEQ_ResumeTask(task_id_list);
/* USER CODE BEGIN HCI_TL_CmdAvailable */
/* USER CODE END HCI_TL_CmdAvailable */
break;
default:
/* USER CODE BEGIN Status */
/* USER CODE END Status */
break;
}
return;
}
void SVCCTL_ResumeUserEventFlow(void)
{
hci_resume_flow();
return;
}
/* USER CODE BEGIN FD_WRAP_FUNCTIONS */
/* USER CODE END FD_WRAP_FUNCTIONS */