/***************************************************************************//** * \file cy_ble_controller.c * \version 3.60 * * \brief * This file contains the source code for the API of the PSoC 6 BLE Middleware. * ******************************************************************************** * \copyright * Copyright 2017-2021, Cypress Semiconductor Corporation. All rights reserved. * You may use this file only in accordance with the license, terms, conditions, * disclaimers, and limitations in the end user license agreement accompanying * the software package with which this file was provided. *******************************************************************************/ #include "cy_ble_event_handler.h" #include "cy_ble_hal_pvt.h" #include "cy_ble.h" #include "cy_ble_stack_pvt.h" #if defined(CY_IP_MXBLESS) /******************************************************************************* * Private Function Prototypes *******************************************************************************/ static cy_en_syspm_status_t Cy_BLE_ControllerDeepSleepCallback(cy_stc_syspm_callback_params_t *callbackParams, cy_en_syspm_callback_mode_t mode); /******************************************************************************* * Global Variables *******************************************************************************/ /** Pointer to the global BLE configuration structures */ static const cy_stc_ble_config_t *cy_ble_controllerConfigPtr = NULL; /******************************************************************************* * Internal Defines *******************************************************************************/ #define CY_BLE_SEND_IPC_MESSAGE_TIMEOUT (2000u) #define CY_BLE_WAIT_CONTR_START_TIMEOUT (2000u) /****************************************************************************** * Function Name: Cy_BLE_InitController ***************************************************************************//** * * Initializes the PSoC 6 BLE Middleware (controller part). * * This function must used only in HCI or BLE dual CPU mode and called on CPU core, * where BLE controller is running. * * \param config: The configuration structure for the PSoC 6 BLE Middleware. * * \return * \ref cy_en_ble_api_result_t : Return value indicates whether the function succeeded or * failed. The following are possible error codes. * * Error codes | Description * ------------ | ----------- * CY_BLE_SUCCESS | The function completed successfully. * CY_BLE_ERROR_INVALID_PARAMETER | On specifying NULL as the input parameter. * ******************************************************************************/ cy_en_ble_api_result_t Cy_BLE_InitController(const cy_stc_ble_config_t *config) { cy_en_ble_api_result_t apiResult = CY_BLE_ERROR_INVALID_PARAMETER; if(config != NULL) { /* Register a pointer to the BLE controller configuration structure */ cy_ble_controllerConfigPtr = config; Cy_BLE_HAL_SetConfigStructure(cy_ble_controllerConfigPtr); apiResult = CY_BLE_SUCCESS; } return(apiResult); } /****************************************************************************** * Function Name: Cy_BLE_EnableController ***************************************************************************//** * * This function enables the BLE Stack controller. * * This function must used only in BLE dual CPU mode and called on CPU core, * where BLE controller is running. * * \return * \ref cy_en_ble_api_result_t : Return value indicates whether the function succeeded * or failed. The following are possible error codes. * * * * * * * * * * * * * * * * * * * * * * *
Error codesDescription
CY_BLE_SUCCESSOn successful operation.
CY_BLE_ERROR_REPEATED_ATTEMPTSOn invoking this function more than once without calling * Cy_BLE_Disable() function between calls to this function.
CY_BLE_ERROR_MEMORY_ALLOCATION_FAILEDThere is insufficient memory available.
CY_BLE_ERROR_INVALID_STATEThe PSoC 6 BLE Middleware was not initialized
* ******************************************************************************/ cy_en_ble_api_result_t Cy_BLE_EnableController(void) { cy_en_ble_api_result_t apiResult = CY_BLE_ERROR_INVALID_STATE; #if defined(COMPONENT_BLESS_CONTROLLER_IPC) if (cy_ble_controllerConfigPtr != NULL) { cy_stc_ble_stack_init_info_t stackInitParam; (void) memset(&stackInitParam, 0, sizeof(cy_stc_ble_stack_init_info_t)); /* BLE Stack memory heap size */ stackInitParam.memParam.totalHeapSz = cy_ble_controllerConfigPtr->stackParam->controllerTotalHeapSz; /* Configure DLE */ stackInitParam.stackConfig.dleConfig.dleMaxTxCapability = cy_ble_controllerConfigPtr->stackParam->dleMaxTxCapability; stackInitParam.stackConfig.dleConfig.dleMaxRxCapability = cy_ble_controllerConfigPtr->stackParam->dleMaxRxCapability; stackInitParam.stackConfig.dleConfig.dleNumTxBuffer = CY_BLE_LL_DEFAULT_NUM_ACL_TX_PACKETS; stackInitParam.stackConfig.dleConfig.dleNumRxBuffer = CY_BLE_LL_DEFAULT_NUM_ACL_RX_PACKETS; /* Configure BLE Stack features */ stackInitParam.stackConfig.featureMask = cy_ble_controllerConfigPtr->stackParam->featureMask; /* Configure maximum connection support */ stackInitParam.stackConfig.maxBleConnections = cy_ble_controllerConfigPtr->stackParam->maxConnCount; /* Configure bonded device list */ stackInitParam.stackConfig.bondListConfig.bondListSize = cy_ble_controllerConfigPtr->stackParam->maxBondedDevListSize; /* Configure white list */ stackInitParam.stackConfig.whiteListConfig.whiteListSize = cy_ble_controllerConfigPtr->stackParam->maxWhiteListSize; /* Configure LL Privacy */ stackInitParam.stackConfig.privacyConfig.resolvingListSize = cy_ble_controllerConfigPtr->stackParam->maxResolvableDevListSize; /* Configure BLE features */ /* Enable DLE code in the stack */ if((cy_ble_controllerConfigPtr->stackParam->featureMask & CY_BLE_DLE_FEATURE_MASK) != 0u) { Cy_BLE_EnableDleFeature(); } /* Enable LL Privacy code in the stack */ if((cy_ble_controllerConfigPtr->stackParam->featureMask & CY_BLE_PRIVACY_1_2_FEATURE_MASK) != 0u) { Cy_BLE_EnablePrivacyFeature(); } /* Enable PHY Update code in the stack */ if((cy_ble_controllerConfigPtr->stackParam->featureMask & CY_BLE_PHY_UPDATE_FEATURE_MASK) != 0u) { Cy_BLE_EnablePhyUpdateFeature(); } apiResult = Cy_BLE_StackSetFeatureConfig(&stackInitParam.stackConfig); if(apiResult == CY_BLE_SUCCESS) { /* Set pointer to memory RAM buffer */ stackInitParam.memParam.memoryHeapPtr = cy_ble_controllerConfigPtr->stackParam->controllerMemoryHeapPtr; /* Configure parameter for Radio PA calibration */ if(cy_ble_controllerConfigPtr->stackParam->paCalConfig != NULL) { stackInitParam.stackConfig.paCalConfig = *cy_ble_controllerConfigPtr->stackParam->paCalConfig; } /* Initialize the BLE Stack */ apiResult = Cy_BLE_StackInit(&stackInitParam); } } #endif /* defined(COMPONENT_BLESS_CONTROLLER_IPC) */ return(apiResult); } /****************************************************************************** * Function Name: Cy_BLE_EnableHCIModeController ***************************************************************************//** * * This function enables the BLE Stack controller in HCI only mode. * * This function must used only in HCI mode and called on CPU core, * where BLE controller is running. * * \return * \ref cy_en_ble_api_result_t : Return value indicates whether the function succeeded * or failed. The following are possible error codes. * * * * * * * * * * * * * * * * * * * * * * *
Error codesDescription
CY_BLE_SUCCESSOn successful operation.
CY_BLE_ERROR_REPEATED_ATTEMPTSOn invoking this function more than once without calling * Cy_BLE_Disable() function between calls to this function.
CY_BLE_ERROR_MEMORY_ALLOCATION_FAILEDThere is insufficient memory available.
CY_BLE_ERROR_INVALID_STATEThe PSoC 6 BLE Middleware was not initialized
* ******************************************************************************/ cy_en_ble_api_result_t Cy_BLE_EnableHCIModeController(void) { cy_en_ble_api_result_t apiResult = CY_BLE_ERROR_INVALID_STATE; #if defined(COMPONENT_BLESS_CONTROLLER) if (cy_ble_controllerConfigPtr != NULL) { cy_stc_ble_stack_init_info_t stackInitParam; (void) memset(&stackInitParam, 0, sizeof(cy_stc_ble_stack_init_info_t)); /* BLE Stack memory heap size */ stackInitParam.memParam.totalHeapSz = cy_ble_controllerConfigPtr->stackParam->totalHeapSz; /* Configure DLE */ stackInitParam.stackConfig.dleConfig.dleMaxTxCapability = cy_ble_controllerConfigPtr->stackParam->dleMaxTxCapability; stackInitParam.stackConfig.dleConfig.dleMaxRxCapability = cy_ble_controllerConfigPtr->stackParam->dleMaxRxCapability; stackInitParam.stackConfig.dleConfig.dleNumTxBuffer = CY_BLE_LL_DEFAULT_NUM_ACL_TX_PACKETS; stackInitParam.stackConfig.dleConfig.dleNumRxBuffer = CY_BLE_LL_DEFAULT_NUM_ACL_RX_PACKETS; /* Configure BLE Stack features */ stackInitParam.stackConfig.featureMask = cy_ble_controllerConfigPtr->stackParam->featureMask; /* Configure maximum connection support */ stackInitParam.stackConfig.maxBleConnections = cy_ble_controllerConfigPtr->stackParam->maxConnCount; /* Configure bonded device list */ stackInitParam.stackConfig.bondListConfig.bondListSize = cy_ble_controllerConfigPtr->stackParam->maxBondedDevListSize; /* Configure white list */ stackInitParam.stackConfig.whiteListConfig.whiteListSize = cy_ble_controllerConfigPtr->stackParam->maxWhiteListSize; /* Configure LL Privacy */ stackInitParam.stackConfig.privacyConfig.resolvingListSize = cy_ble_controllerConfigPtr->stackParam->maxResolvableDevListSize; /* Configure BLE features */ /* Enable DLE code in the stack */ if((cy_ble_controllerConfigPtr->stackParam->featureMask & CY_BLE_DLE_FEATURE_MASK) != 0u) { Cy_BLE_ControllerEnableDleFeature(); } /* Enable LL Privacy code in the stack */ if((cy_ble_controllerConfigPtr->stackParam->featureMask & CY_BLE_PRIVACY_1_2_FEATURE_MASK) != 0u) { Cy_BLE_ControllerEnablePrivacyFeature(); } /* Enable PHY Update code in the stack */ if((cy_ble_controllerConfigPtr->stackParam->featureMask & CY_BLE_PHY_UPDATE_FEATURE_MASK) != 0u) { Cy_BLE_ControllerEnablePhyUpdateFeature(); } apiResult = Cy_BLE_ControllerStackSetFeatureConfig(&stackInitParam.stackConfig); /* Application Callback Function */ stackInitParam.CyBleAppCbFunc = (cy_ble_app_ev_cb_t)&Cy_BLE_EventHandlerWrapper; if(apiResult == CY_BLE_SUCCESS) { /* Set pointer to memory RAM buffer */ stackInitParam.memParam.memoryHeapPtr = cy_ble_controllerConfigPtr->stackParam->memoryHeapPtr; /* Configure parameter for Radio PA calibration */ if(cy_ble_controllerConfigPtr->stackParam->paCalConfig != NULL) { stackInitParam.stackConfig.paCalConfig = *cy_ble_controllerConfigPtr->stackParam->paCalConfig; } /* Initialize the BLE Stack */ apiResult = Cy_BLE_ControllerStackInit(&stackInitParam); } } #endif /* defined(COMPONENT_BLESS_CONTROLLER) */ return(apiResult); } /****************************************************************************** * Function Name: Cy_BLE_EnableControllerFromHost ***************************************************************************//** * * This function sends an IPC message to enable the BLE Stack controller and * waits until the controller starts. * * \return * \ref cy_en_ble_api_result_t : Return value indicates whether the function succeeded * or failed. The following are possible error codes. * * * * * * * * * * * * * * * * * * * * * * * * * * *
Error codesDescription
CY_BLE_SUCCESSOn successful operation.
CY_BLE_ERROR_REPEATED_ATTEMPTSOn invoking this function more than once without calling * Cy_BLE_Disable() function between calls to this function.
CY_BLE_ERROR_MEMORY_ALLOCATION_FAILEDThere is insufficient memory available.
CY_BLE_ERROR_INVALID_STATEThe PSoC 6 BLE Middleware was not initialized
CY_BLE_ERROR_INVALID_OPERATIONThe timeout to enable the BLE controller (a problem with the IPC * communication, or other BLE controller's CPU core problem)
******************************************************************************/ cy_en_ble_api_result_t Cy_BLE_EnableControllerFromHost(void) { /** IPC mesage structure for enable controller */ static volatile cy_stc_ble_ipc_msg_t controllerMsg = { /* clientID */ CY_BLE_CYPIPE_MSG_CMD_ID, /* pktType */ CY_BLE_CYPIPE_ENABLE_CONTR_CMD, /* intrRelMask */ 0x00u, /* controllerStarted */ false, /* data */ 0x00u, /* dataLen */ 0x00u }; cy_en_ipc_pipe_status_t ipcStatus; uint32_t rTimeout = CY_BLE_SEND_IPC_MESSAGE_TIMEOUT; /* Check if controller is started */ if ( !controllerMsg.controllerStarted ) { /* Store pointer to stack param structure */ controllerMsg.data = (uint32_t) cy_ble_configPtr->stackParam; /* Send the address of the intrNotify structure to the controller core via CyPipe * The IPC Pipe can be busy. If so, try sending a message again. */ do { ipcStatus = Cy_IPC_Pipe_SendMessage(CY_BLE_IPC_CONTROLLER_ADDR, CY_BLE_IPC_HOST_ADDR, (void *)&controllerMsg, NULL); Cy_SysLib_DelayUs(1u); rTimeout--; }while((ipcStatus != CY_IPC_PIPE_SUCCESS) && (rTimeout != 0u)); /* Wait until controller starts */ rTimeout = CY_BLE_WAIT_CONTR_START_TIMEOUT; do { Cy_SysLib_Delay(1u); rTimeout--; } while ((!controllerMsg.controllerStarted) && (rTimeout != 0u)); } return ((rTimeout == 0u) ? CY_BLE_ERROR_INVALID_OPERATION : (cy_en_ble_api_result_t) controllerMsg.data); } /******************************************************************************* * BLE LPM (low power mode) *******************************************************************************/ /****************************************************************************** * Function Name: Cy_BLE_EnableControllerLowPowerMode ***************************************************************************//** * * This function enables BLE low power mode for Controller * * Register BLE callback for deep sleep / sleep * * This function must used only in BLE dual CPU mode and called on CPU core, * where BLE controller is running. * ******************************************************************************/ void Cy_BLE_EnableControllerLowPowerMode(void) { /* Structure with the SysPm callback parameters for BLESS deep sleep */ static cy_stc_syspm_callback_params_t bleDeepSleepCallbackParams = { /* base */ NULL, /* context */ NULL }; static cy_stc_syspm_callback_t bleDeepSleepCallback = { /* callback */ &Cy_BLE_ControllerDeepSleepCallback, /* type */ CY_SYSPM_DEEPSLEEP, /* skipMode */ CY_SYSPM_SKIP_BEFORE_TRANSITION | CY_SYSPM_SKIP_CHECK_FAIL, /* callbackParams */ &bleDeepSleepCallbackParams, /* prevItm */ NULL, /* nextItm */ NULL, /* order */ CY_BLE_LPM_SYSPM_CB_ORDER }; /* Register BLE callback for BLESS deep sleep support */ (void)Cy_SysPm_RegisterCallback(&bleDeepSleepCallback); } /******************************************************************************* * Function Name: Cy_BLE_ControllerDeepSleepCallback ****************************************************************************//** * * This function requests the BLE Stack to put Bluetooth Low Energy Sub-System * (BLESS) to deep sleep mode. * * It is registered to the system power mode by Cy_SysPm_RegisterCallback() * function with CY_SYSPM_DEEPSLEEP type. After registration it is called by * Cy_SysPm_DeepSleep() function prior entering the core into the CPU deep sleep * power mode. * * When it is called with the enMode parameter set to CY_SYSPM_CHECK_READY, * function enters BLESS to CY_BLE_BLESS_DEEPSLEEP mode. It also checks the * BLE Subsystem's current operational mode. When the * Cy_BLE_StackGetBleSsState() function returns CY_BLE_BLESS_STATE_ECO_ON or * CY_BLE_BLESS_STATE_DEEPSLEEP state, this function returns CY_SYSPM_PASS and * allows to put the core into the deep-sleep power mode. * At all other times, the function tries to enter core into sleep mode. * * This function is available only when BLE low power mode is enabled (called * Cy_BLE_EnableLowPowerMode() function). * * \param * callbackParams Pointer to the structure with the syspm callback parameters. * * \param * mode The associated syspm callback mode. See description of the * cy_en_syspm_callback_mode_t type. * * \return * * CY_SYSPM_SUCCESS - Entered and exited from CPU deep sleep * * CY_SYSPM_FAIL - CPU deep sleep not entered. * *******************************************************************************/ static cy_en_syspm_status_t Cy_BLE_ControllerDeepSleepCallback(cy_stc_syspm_callback_params_t *callbackParams, cy_en_syspm_callback_mode_t mode) { cy_en_syspm_status_t retVal; static uint32_t interruptState = 0u; cy_en_ble_bless_state_t blessState; /* Local variable to store the status of BLESS Hardware block */ cy_en_ble_lp_mode_t sleepMode; /* Suppress unused variable warning */ (void) callbackParams; switch(mode) { case (CY_SYSPM_CHECK_READY): if(Cy_IPC_Sema_Status(CY_BLE_SEMA) == CY_IPC_SEMA_STATUS_LOCKED) { /* System do not enter deep sleep if BLE Host start write operation */ retVal = CY_SYSPM_FAIL; } else if (Cy_BLE_HAL_IsEcoCpuClockSrc() == 1u) { /* System never enters deep sleep if BLE ECO is CPU source */ retVal = CY_SYSPM_FAIL; } else { cy_en_ble_api_result_t retIsControllerActive; /* Put BLESS into deep sleep and check the return status */ sleepMode = Cy_BLE_MappingStackEnterLPM(CY_BLE_BLESS_DEEPSLEEP); /* Disable global interrupt to prevent changes from any other interrupt ISR */ interruptState = Cy_SysLib_EnterCriticalSection(); /* Check the Status of BLESS */ blessState = Cy_BLE_StackGetBleSsState(); if(blessState == CY_BLE_BLESS_STATE_STOPPED) { retVal = CY_SYSPM_SUCCESS; } else if(sleepMode == CY_BLE_BLESS_DEEPSLEEP) { retIsControllerActive = Cy_BLE_MappingIsControllerActive(CY_BLE_CONTROLLER_SLEEP_MODE_DEEPSLEEP); if(((blessState == CY_BLE_BLESS_STATE_ECO_ON) || (blessState == CY_BLE_BLESS_STATE_DEEPSLEEP)) && (retIsControllerActive == CY_BLE_SUCCESS)) { /* Enter device deep sleep */ retVal = CY_SYSPM_SUCCESS; } else { /* The BLESS hardware block cannot go to deep sleep, try sleep mode */ retVal = CY_SYSPM_FAIL; } } else { retIsControllerActive = Cy_BLE_MappingIsControllerActive(CY_BLE_CONTROLLER_SLEEP_MODE_SLEEP); if((blessState != CY_BLE_BLESS_STATE_EVENT_CLOSE) && (retIsControllerActive == CY_BLE_SUCCESS)) { /* If the BLESS hardware block cannot go to deep sleep and BLE event has not * closed yet, then place CPU to sleep */ (void)Cy_SysPm_CpuEnterSleep(CY_SYSPM_WAIT_FOR_INTERRUPT); } retVal = CY_SYSPM_FAIL; } if(retVal == CY_SYSPM_FAIL) { /* Enable interrupts after failing check */ Cy_SysLib_ExitCriticalSection(interruptState); } } break; /* Enable interrupts after wakeup */ case (CY_SYSPM_AFTER_TRANSITION): Cy_SysLib_ExitCriticalSection(interruptState); retVal = CY_SYSPM_SUCCESS; break; default: retVal = CY_SYSPM_FAIL; break; } return(retVal); } /******************************************************************************* * Internal *******************************************************************************/ /****************************************************************************** * Function Name: Cy_BLE_EventHandlerWrapper ***************************************************************************//** * * This event handler is used in HCI Soft mode, and dirrect calls registered by * application Cy_BLE_ApplCallback callback. * ******************************************************************************/ void Cy_BLE_EventHandlerWrapper(cy_en_ble_event_t event, void *evParam) { /* Call Cy_BLE_ApplCallback */ Cy_BLE_ApplCallback((uint32_t)event, evParam); } #endif /* CY_IP_MXBLESS */ /* [] END OF FILE */