/******************************************************************************* * File Name: main_cm4.c * * Version: 1.30 * * Description: This file provides the source code for the DFU (App0) * running on the core CM4 (core1). * App0 core1 firmware does the following: * - Downloads App1 firmware image * - Switches to App1 if App1 image has successfully downloaded * and is valid * - Switches to existing App1 if button is pressed * - Turn on an LED depending on status * - Hibernates on timeout ******************************************************************************* * Related Document: CE216767.pdf * * Hardware Dependency: CY8CKIT-062-BLE PSoC 6 BLE Pioneer Kit * CY5677 CySmart USB Dongle * ****************************************************************************** * Copyright (2019), Cypress Semiconductor Corporation. ****************************************************************************** * This software is owned by Cypress Semiconductor Corporation (Cypress) and is * protected by and subject to worldwide patent protection (United States and * foreign), United States copyright laws and international treaty provisions. * Cypress hereby grants to licensee a personal, non-exclusive, non-transferable * license to copy, use, modify, create derivative works of, and compile the * Cypress Source Code and derivative works for the sole purpose of creating * custom software in support of licensee product to be used only in conjunction * with a Cypress integrated circuit as specified in the applicable agreement. * Any reproduction, modification, translation, compilation, or representation of * this software except as specified above is prohibited without the express * written permission of Cypress. * * Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH * REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * Cypress reserves the right to make changes without further notice to the * materials described herein. Cypress does not assume any liability arising out * of the application or use of any product or circuit described herein. Cypress * does not authorize its products for use as critical components in life-support * systems where a malfunction or failure may reasonably be expected to result in * significant injury to the user. The inclusion of Cypress' product in a life- * support systems application implies that the manufacturer assumes all risk of * such use and in doing so indemnifies Cypress against all charges. Use may be * limited by and subject to the applicable Cypress software license agreement. *******************************************************************************/ #include #include "project.h" #include "debug.h" #include "ias.h" #include "transport_ble.h" #if CY_DFU_OPT_CRYPTO_HW != 0 #define MY_CHAN_CRYPTO (uint32_t)(3u) /* IPC data channel for the Crypto */ #define MY_INTR_CRYPTO_SRV (uint32_t)(1u) /* IPC interrupt structure for the Crypto server */ #define MY_INTR_CRYPTO_CLI (uint32_t)(2u) /* IPC interrupt structure for the Crypto client */ #define MY_INTR_CRYPTO_SRV_MUX (IRQn_Type)(2u) /* CM0+ IPC interrupt mux number the Crypto server */ #define MY_INTR_CRYPTO_CLI_MUX (IRQn_Type)(3u) /* CM0+ IPC interrupt mux number the Crypto client */ #define MY_INTR_CRYPTO_ERR_MUX (IRQn_Type)(4u) /* CM0+ ERROR interrupt mux number the Crypto server */ const cy_stc_crypto_config_t cryptoConfig = { /* .ipcChannel */ MY_CHAN_CRYPTO, /* .acquireNotifierChannel */ MY_INTR_CRYPTO_SRV, /* .releaseNotifierChannel */ MY_INTR_CRYPTO_CLI, /* .releaseNotifierConfig */ { #if (CY_CPU_CORTEX_M0P) /* .intrSrc */ MY_INTR_CRYPTO_CLI_MUX, /* .cm0pSrc */ cpuss_interrupts_ipc_2_IRQn, /* depends on selected releaseNotifierChannel value */ #else /* .intrSrc */ cpuss_interrupts_ipc_2_IRQn, /* depends on selected releaseNotifierChannel value */ #endif /* .intrPriority */ 2u, }, /* .userCompleteCallback */ NULL, /* .userGetDataHandler */ NULL, /* .userErrorHandler */ NULL, /* .acquireNotifierConfig */ { #if (CY_CPU_CORTEX_M0P) /* .intrSrc */ MY_INTR_CRYPTO_SRV_MUX, /* to use with DeepSleep mode should be in DeepSleep capable muxer's range */ /* .cm0pSrc */ cpuss_interrupts_ipc_1_IRQn, /* depends on selected acquireNotifierChannel value */ #else /* .intrSrc */ cpuss_interrupts_ipc_1_IRQn, /* depends on selected acquireNotifierChannel value */ #endif /* .intrPriority */ 2u, }, /* .cryptoErrorIntrConfig */ { #if (CY_CPU_CORTEX_M0P) /* .intrSrc */ MY_INTR_CRYPTO_ERR_MUX, /* .cm0pSrc */ cpuss_interrupt_crypto_IRQn, #else /* .intrSrc */ cpuss_interrupt_crypto_IRQn, #endif /* .intrPriority */ 2u, } }; cy_stc_crypto_context_t cryptoContext; cy_en_crypto_status_t cryptoStatus; #endif /* BLE GAPP Connection Settings */ #define CYBLE_GAPP_CONNECTION_INTERVAL_MIN (0x000Cu) /* 15 ms - (N * 1,25)*/ #define CYBLE_GAPP_CONNECTION_INTERVAL_MAX (0x000Cu) /* 15 ms */ #define CYBLE_GAPP_CONNECTION_SLAVE_LATENCY (0x0000u) #define CYBLE_GAPP_CONNECTION_TIME_OUT (0x00C8u) /* 2000 ms */ /* BLE Callback function, defined in this file */ void AppCallBack(uint32 event, void* eventParam); /* Local functions */ static cy_en_dfu_status_t CopyRow(uint32_t dest, uint32_t src, uint32_t rowSize, cy_stc_dfu_params_t * params); static cy_en_dfu_status_t HandleMetadata(cy_stc_dfu_params_t *params); static bool IsButtonPressed(uint16_t timeoutInMilis); static uint32_t counterTimeoutSeconds(uint32_t seconds, uint32_t timeout); /* This section is used to verify an application signature For sha256 verification, set the number of elements in the array to 64, and in bootload_common.ld set __cy_boot_signature_size = 256. */ CY_SECTION(".cy_app_signature") __USED static const uint32_t cy_bootload_appSignature[64]; /******************************************************************************* * Function Name: main ******************************************************************************** * * Summary: * Main function of the DFU application (App0). * 1. If application started from non-software reset it validates App1 * 1.1. If App1 is valid it switches to App1, else goto #2. * 2. Start DFU communication. * 3. If updated application has been received it validates this app. * 4. If App1 is valid it switches to it, else wait for new application. * 5. If 300 seconds have passed and no new application has been received * then validate App1, if it is valid then switch to it, else hibernate * (Happens in the BLE AppCallBack). * *******************************************************************************/ int main(void) { /* timeout for Cy_DFU_Continue(), in milliseconds */ const uint32_t paramsTimeout = 20u; /* used to configure DFU */ static cy_stc_dfu_params_t dfuParams; /* Status codes from DFU SDK API */ cy_en_dfu_status_t status; /* SW2 released after deciding to stay in App0 */ bool buttonReleased = false; /* * DFU state, one of * - CY_DFU_STATE_NONE * - CY_DFU_STATE_UPDATING * - CY_DFU_STATE_FINISHED * - CY_DFU_STATE_FAILED */ uint32_t state = CY_DFU_STATE_NONE; cy_en_ble_api_result_t apiResult; cy_stc_ble_stack_lib_version_t stackVersion; /* * Used to count seconds, to convert counts to seconds use * counterTimeoutSeconds(SECONDS, paramsTimeout) */ uint32_t count = 0; uint32_t ledTimer = 0; #if CY_DFU_OPT_CRYPTO_HW != 0 cy_en_crypto_status_t cryptoStatus; #endif /* Buffer to store DFU commands */ CY_ALIGN(4) static uint8_t buffer[CY_DFU_SIZEOF_DATA_BUFFER]; /* Buffer for DFU packets for Transport API */ CY_ALIGN(4) static uint8_t packet[CY_DFU_SIZEOF_CMD_BUFFER]; /* Enable global interrupts */ __enable_irq(); /* Start UART Services */ UART_START(); /* Initializes LEDs */ InitLED(); #if CY_DFU_OPT_CRYPTO_HW != 0 /* Initialize the Crypto Client code */ cryptoStatus = Cy_Crypto_Init(&cryptoConfig, &cryptoContext); if (cryptoStatus != CY_CRYPTO_SUCCESS) { /* Crypto not initialized; debug what is the problem */ Cy_SysLib_Halt(0x00u); } cryptoStatus = Cy_Crypto_Enable(); if (cryptoStatus != CY_CRYPTO_SUCCESS) { /* Crypto not enabled; debug what is the problem */ Cy_SysLib_Halt(0x00u); } #endif /* CY_DFU_OPT_CRYPTO_HW != 0 */ /* Initialize dfuParams structure and DFU SDK state */ dfuParams.timeout = paramsTimeout; dfuParams.dataBuffer = &buffer[0]; dfuParams.packetBuffer = &packet[0]; status = Cy_DFU_Init(&state, &dfuParams); /* Ensure DFU Metadata is valid */ status = HandleMetadata(&dfuParams); if (status != CY_DFU_SUCCESS) { Cy_SysLib_Halt(0x00u); } /* * In the case of non-software reset and user does not * want to stay in App0, check if there is a valid app image. * If there is - switch to it. */ if ((Cy_SysLib_GetResetReason() != CY_SYSLIB_RESET_SOFT) && (IsButtonPressed(2000u) == false)) { status = Cy_DFU_ValidateApp(1u, &dfuParams); if (status == CY_DFU_SUCCESS) { /* * Clear reset reason because Cy_DFU_ExecuteApp() performs * a software reset. * Without clearing two reset reasons would be present. */ do { Cy_SysLib_ClearResetReason(); }while(Cy_SysLib_GetResetReason() != 0); /* Never returns */ Cy_DFU_ExecuteApp(1u); } } /* Initialize DFU communication */ Cy_DFU_TransportStart(); /* Initializes the Immediate Alert Service */ IasInit(); /* Output current stack version to UART */ apiResult = Cy_BLE_GetStackLibraryVersion(&stackVersion); if(apiResult != CY_BLE_SUCCESS) { DBG_PRINTF("CyBle_GetStackLibraryVersion API Error: 0x%2.2x \r\n", apiResult); } else { DBG_PRINTF("Stack Version: %d.%d.%d.%d \r\n", stackVersion.majorVersion, stackVersion.minorVersion, stackVersion.patch, stackVersion.buildNumber); } for(;;) { /* CyBle_ProcessEvents() allows BLE stack to process pending events */ Cy_BLE_ProcessEvents(); /* Process DFU commands */ status = Cy_DFU_Continue(&state, &dfuParams); ++count; switch(state) { case CY_DFU_STATE_FINISHED: /* Finished downloading the application image */ /* Validate downloaded application, if it is valid then switch to it */ status = Cy_DFU_ValidateApp(1u, &dfuParams); if (status == CY_DFU_SUCCESS) { Cy_DFU_TransportStop(); /* * Clear reset reason because Cy_DFU_ExecuteApp() performs * a software reset. * Without clearing two reset reasons would be present. */ do { Cy_SysLib_ClearResetReason(); }while(Cy_SysLib_GetResetReason() != 0); /* Never returns */ Cy_DFU_ExecuteApp(1u); } else if (status == CY_DFU_ERROR_VERIFY) { /* * Restarts DFU, alternatives are to Halt MCU here * or switch to the other app if it is valid. * Error code may be handled here, i.e. print to debug UART. */ status = Cy_DFU_Init(&state, &dfuParams); /* Reset LED */ ConnectedLED(); ledTimer = 0; Cy_DFU_TransportReset(); } break; case CY_DFU_STATE_FAILED: /* Handle error here */ DBG_PRINTF("Downloading has failed with error code 0x%x, try again\r\n", status); /* In this Code Example just restart DFU process */ status = Cy_DFU_Init(&state, &dfuParams); /* Reset LED */ ConnectedLED(); ledTimer = 0; Cy_DFU_TransportReset(); break; case CY_DFU_STATE_UPDATING: /* Reset timeout counter, if a command was correctly received */ if (status == CY_DFU_SUCCESS) { count = 0u; } else if (status == CY_DFU_ERROR_TIMEOUT) { /* * if no command has been received during 5 seconds when DFU * has started then restart DFU. */ if (count >= counterTimeoutSeconds(5u, paramsTimeout)) { count = 0u; Cy_DFU_Init(&state, &dfuParams); /* Reset LED */ ConnectedLED(); ledTimer = 0; Cy_DFU_TransportReset(); } } else { count = 0u; /* Delay because Transport still may be sending error response to a host */ Cy_SysLib_Delay(paramsTimeout); Cy_DFU_Init(&state, &dfuParams); Cy_DFU_TransportReset(); } break; } /* LED logic, constant values are optimized out. */ /* Reset timer after 2 seconds */ if(ledTimer == (2000u / paramsTimeout)) ledTimer = 0; /* Every 100 miliseconds */ if(!(ledTimer % (100u / paramsTimeout))) { /* Generates two 100 miliseconds pulses, every 2 seconds */ if((state == CY_DFU_STATE_UPDATING) && (ledTimer < (400u / paramsTimeout))) { BlinkLED(); } /* Generates one 100 miliseconds pulse, every 2 seconds */ else if ((Cy_BLE_GetAdvertisementState() == CY_BLE_ADV_STATE_ADVERTISING) && (ledTimer < (200u / paramsTimeout))) { BlinkLED(); } else { /* Remain OFF */ ConnectedLED(); } } ++ledTimer; /* Check if a switch to the other app is requested and perform the switch if it is */ if((buttonReleased == true) && (state == CY_DFU_STATE_NONE)) { bool switchRequested = false; if (alertLevel != 0) { switchRequested = true; } else if(IsButtonPressed(500u) == true) { switchRequested = true; buttonReleased = false; } if (switchRequested) { /* Validate and switch to App1 */ cy_en_dfu_status_t status = Cy_DFU_ValidateApp(1u, &dfuParams); if (status == CY_DFU_SUCCESS) { Cy_DFU_TransportStop(); /* * Clear reset reason because Cy_DFU_ExecuteApp() performs * a software reset. * Without clearing two reset reasons would be present. */ do { Cy_SysLib_ClearResetReason(); }while(Cy_SysLib_GetResetReason() != 0); /* Never returns */ Cy_DFU_ExecuteApp(1u); } } } else { buttonReleased = Cy_GPIO_Read(PIN_SW2_PORT, PIN_SW2_NUM); } } } /******************************************************************************* * Function Name: IsButtonPressed ******************************************************************************** * Checks if button is pressed for a 'timeoutInMilis' time. * * Params: * timeout: Amount of time to check if button was pressed. Broken into * 20 miliseconds steps. * Returns: * true if button is pressed for specified amount. * false otherwise. *******************************************************************************/ static bool IsButtonPressed(uint16_t timeoutInMilis) { uint16_t buttonTime = 0; bool buttonPressed = false; timeoutInMilis /= 20; while(Cy_GPIO_Read(PIN_SW2_PORT, PIN_SW2_NUM) == 0u) { Cy_SysLib_Delay(20u); if(++buttonTime == timeoutInMilis) { /* time has passed */ buttonPressed = true; break; } } return buttonPressed; } /******************************************************************************* * Function Name: counterTimeoutSeconds ******************************************************************************** * Returns number of counts that correspond to number of seconds passed as * a parameter. * E.g. comparing counter with 300 seconds is like this. * --- * uint32_t counter = 0u; * for (;;) * { * Cy_SysLib_Delay(UART_TIMEOUT); * ++count; * if (count >= counterTimeoutSeconds(seconds: 300u, timeout: UART_TIMEOUT)) * { * count = 0u; * DoSomething(); * } * } * --- * * Both parameters are required to be compile time constants, * so this function gets optimized out to single constant value. * * Parameters: * seconds Number of seconds to pass. Must be less that 4_294_967 seconds. * timeout Timeout for Cy_DFU_Continue() function, in milliseconds. * Must be greater than zero. * It is recommended to be a value that produces no reminder * for this function to be precise. * Return: * See description. *******************************************************************************/ static uint32_t counterTimeoutSeconds(uint32_t seconds, uint32_t timeout) { return (seconds * 1000ul) / timeout; } /******************************************************************************* * Function Name: CopyRow ******************************************************************************** * Copies data from a "src" address to a flash row with the address "dest". * If "src" data is the same as "dest" data then no copy is needed. * * Parameters: * dest Destination address. Has to be an address of the start of flash row. * src Source address. Has to be properly aligned. * rowSize Size of flash row. * * Returns: * CY_DFU_SUCCESS if operation is successful. * Error code in a case of failure. *******************************************************************************/ static cy_en_dfu_status_t CopyRow(uint32_t dest, uint32_t src, uint32_t rowSize, cy_stc_dfu_params_t * params) { cy_en_dfu_status_t status; /* Save params->dataBuffer value */ uint8_t *buffer = params->dataBuffer; /* Compare "dest" and "src" content */ params->dataBuffer = (uint8_t *)src; status = Cy_DFU_ReadData(dest, rowSize, CY_DFU_IOCTL_COMPARE, params); /* Restore params->dataBuffer */ params->dataBuffer = buffer; /* If "dest" differs from "src" then copy "src" to "dest" */ if (status != CY_DFU_SUCCESS) { (void) memcpy((void *) params->dataBuffer, (const void*)src, rowSize); status = Cy_DFU_WriteData(dest, rowSize, CY_DFU_IOCTL_WRITE, params); } /* Restore params->dataBuffer */ params->dataBuffer = buffer; return (status); } /******************************************************************************* * Function Name: HandleMetadata ******************************************************************************** * The goal of this function is to make DFU SDK metadata (MD) valid. * The following algorithm is used (in C-like pseudocode): * --- * if (isValid(MD) == true) * { if (MDC != MD) * MDC = MD; * } else * { if(isValid(MDC) ) * MD = MDC; * #if MD Writeable * else * MD = INITIAL_VALUE; * #endif * } * --- * Here MD is metadata flash row, MDC is flash row with metadata copy, * INITIAL_VALUE is known initial value. * * In this code example MDC is placed in the next flash row after the MD, and * INITIAL_VALUE is MD with only CRC, App0 start and size initialized, * all the other fields are not touched. This is only done if metadata is * writeable when downloading. * * Parameters: * params A pointer to a DFU SDK parameters structure. * * Returns: * - CY_DFU_SUCCESS when finished normally. * - Any other status code on error. *******************************************************************************/ static cy_en_dfu_status_t HandleMetadata(cy_stc_dfu_params_t *params) { const uint32_t MD = (uint32_t)(&__cy_boot_metadata_addr ); /* MD address */ const uint32_t mdSize = (uint32_t)(&__cy_boot_metadata_length ); /* MD size, assumed to be one flash row */ const uint32_t MDC = MD + mdSize; /* MDC address */ cy_en_dfu_status_t status = CY_DFU_SUCCESS; status = Cy_DFU_ValidateMetadata(MD, params); if (status == CY_DFU_SUCCESS) { /* Checks if MDC equals to DC, if no then copies MD to MDC */ status = CopyRow(MDC, MD, mdSize, params); } else { status = Cy_DFU_ValidateMetadata(MDC, params); if (status == CY_DFU_SUCCESS) { /* Copy MDC to MD */ status = CopyRow(MD, MDC, mdSize, params); } #if CY_DFU_METADATA_WRITABLE != 0 if (status != CY_DFU_SUCCESS) { const uint32_t elfStartAddress = 0x10000000; const uint32_t elfAppSize = 0x40000; /* Set MD to INITIAL_VALUE */ status = Cy_DFU_SetAppMetadata(0u, elfStartAddress, elfAppSize, params); } #endif /* CY_DFU_METADATA_WRITABLE != 0 */ } return (status); } /******************************************************************************* * Function Name: AppCallBack() ******************************************************************************** * * Summary: * This is an event callback function to receive events from the BLE Component. * Used in Cy_DFU_TransportStart() * * event - the event code * *eventParam - the event parameters * *******************************************************************************/ void AppCallBack(uint32 event, void* eventParam) { cy_en_ble_api_result_t apiResult; static cy_stc_ble_gap_sec_key_info_t keyInfo = { .localKeysFlag = CY_BLE_GAP_SMP_INIT_ENC_KEY_DIST | CY_BLE_GAP_SMP_INIT_IRK_KEY_DIST | CY_BLE_GAP_SMP_INIT_CSRK_KEY_DIST, .exchangeKeysFlag = CY_BLE_GAP_SMP_INIT_ENC_KEY_DIST | CY_BLE_GAP_SMP_INIT_IRK_KEY_DIST | CY_BLE_GAP_SMP_INIT_CSRK_KEY_DIST | CY_BLE_GAP_SMP_RESP_ENC_KEY_DIST | CY_BLE_GAP_SMP_RESP_IRK_KEY_DIST | CY_BLE_GAP_SMP_RESP_CSRK_KEY_DIST, }; switch (event) { /********************************************************** * General Events ***********************************************************/ /* This event received when BLE communication starts */ case CY_BLE_EVT_STACK_ON: /* Enter into discoverable mode so that remote can search it. */ apiResult = Cy_BLE_GAPP_StartAdvertisement(CY_BLE_ADVERTISING_FAST, 0u); if(apiResult != CY_BLE_SUCCESS) { } apiResult = Cy_BLE_GAP_GenerateKeys(&keyInfo); if(apiResult != CY_BLE_SUCCESS) { DBG_PRINTF("CyBle_GapGenerateKeys API Error: %d \r\n", apiResult); } break; /* This event indicates that some internal HW error has occurred. */ case CY_BLE_EVT_HARDWARE_ERROR: DBG_PRINTF("CYBLE_EVT_HARDWARE_ERROR\r\n"); break; /********************************************************** * GAP Events ***********************************************************/ case CY_BLE_EVT_GAP_AUTH_REQ: DBG_PRINTF("CYBLE_EVT_AUTH_REQ: security=%x, bonding=%x, ekeySize=%x, err=%x \r\n", (*(cy_stc_ble_gap_auth_info_t *)eventParam).security, (*(cy_stc_ble_gap_auth_info_t *)eventParam).bonding, (*(cy_stc_ble_gap_auth_info_t*)eventParam).ekeySize, (*(cy_stc_ble_gap_auth_info_t *)eventParam).authErr ); if ( cy_ble_configPtr->authInfo[CY_BLE_SECURITY_CONFIGURATION_0_INDEX].security == (CY_BLE_GAP_SEC_MODE_1 | CY_BLE_GAP_SEC_LEVEL_1) ) { cy_ble_configPtr->authInfo[CY_BLE_SECURITY_CONFIGURATION_0_INDEX].authErr = CY_BLE_GAP_AUTH_ERROR_PAIRING_NOT_SUPPORTED; } cy_ble_configPtr->authInfo[CY_BLE_SECURITY_CONFIGURATION_0_INDEX].bdHandle = ((cy_stc_ble_gap_auth_info_t *)eventParam)->bdHandle; apiResult = Cy_BLE_GAPP_AuthReqReply(&cy_ble_configPtr->authInfo[CY_BLE_SECURITY_CONFIGURATION_0_INDEX]); if(apiResult != CY_BLE_SUCCESS) { Cy_BLE_GAP_RemoveOldestDeviceFromBondedList(); apiResult = Cy_BLE_GAPP_AuthReqReply(&cy_ble_configPtr->authInfo[CY_BLE_SECURITY_CONFIGURATION_0_INDEX]); if(apiResult != CY_BLE_SUCCESS) { DBG_PRINTF("CyBle_GappAuthReqReply API Error: %d \r\n", apiResult); } } break; case CY_BLE_EVT_GAP_PASSKEY_ENTRY_REQUEST: DBG_PRINTF("CYBLE_EVT_PASSKEY_ENTRY_REQUEST press 'p' to enter passkey \r\n"); break; case CY_BLE_EVT_GAP_PASSKEY_DISPLAY_REQUEST: DBG_PRINTF("CYBLE_EVT_PASSKEY_DISPLAY_REQUEST %6.6d \r\n", *(int *)eventParam); break; case CY_BLE_EVT_GAP_KEYINFO_EXCHNGE_CMPLT: DBG_PRINTF("CYBLE_EVT_GAP_KEYINFO_EXCHNGE_CMPLT \r\n"); break; case CY_BLE_EVT_GAP_AUTH_COMPLETE: DBG_PRINTF("AUTH_COMPLETE \r\n"); break; case CY_BLE_EVT_GAP_AUTH_FAILED: DBG_PRINTF("CYBLE_EVT_AUTH_FAILED: %x \r\n", *(uint8 *)eventParam); break; case CY_BLE_EVT_GAP_DEVICE_CONNECTED: DBG_PRINTF("CYBLE_EVT_GAP_DEVICE_CONNECTED: %d \r\n", appConnHandle.bdHandle); if ( ((*(cy_stc_ble_gap_connected_param_t *)eventParam).connIntv < CYBLE_GAPP_CONNECTION_INTERVAL_MIN ) || ( (*(cy_stc_ble_gap_connected_param_t *)eventParam).connIntv > CYBLE_GAPP_CONNECTION_INTERVAL_MAX ) ) { cy_stc_ble_gap_conn_update_param_info_t connUpdateParam; /* If connection settings do not match expected ones - request parameter update */ connUpdateParam.connIntvMin = CYBLE_GAPP_CONNECTION_INTERVAL_MIN; connUpdateParam.connIntvMax = CYBLE_GAPP_CONNECTION_INTERVAL_MAX; connUpdateParam.connLatency = CYBLE_GAPP_CONNECTION_SLAVE_LATENCY; connUpdateParam.supervisionTO = CYBLE_GAPP_CONNECTION_TIME_OUT; connUpdateParam.bdHandle = appConnHandle.bdHandle; apiResult = Cy_BLE_L2CAP_LeConnectionParamUpdateRequest(&connUpdateParam); DBG_PRINTF("Cy_BLE_L2CAP_LeConnectionParamUpdateRequest API: 0x%2.2x \r\n", apiResult); } keyInfo.SecKeyParam.bdHandle = (*(cy_stc_ble_gap_connected_param_t *)eventParam).bdHandle; apiResult = Cy_BLE_GAP_SetSecurityKeys(&keyInfo); if(apiResult != CY_BLE_SUCCESS) { DBG_PRINTF("CyBle_GapSetSecurityKeys API Error: %d \r\n", apiResult); } break; case CY_BLE_EVT_L2CAP_CONN_PARAM_UPDATE_RSP: DBG_PRINTF("CY_BLE_EVT_L2CAP_CONN_PARAM_UPDATE_RSP, result = %d\r\n", (*(cy_stc_ble_l2cap_conn_update_rsp_param_t *)eventParam).result); break; case CY_BLE_EVT_GAP_KEYS_GEN_COMPLETE: DBG_PRINTF("CYBLE_EVT_GAP_KEYS_GEN_COMPLETE \r\n"); keyInfo.SecKeyParam = (*(cy_stc_ble_gap_sec_key_param_t *)eventParam); Cy_BLE_GAP_SetIdAddress(&cy_ble_deviceAddress); break; case CY_BLE_EVT_GAP_DEVICE_DISCONNECTED: DBG_PRINTF("CYBLE_EVT_GAP_DEVICE_DISCONNECTED\r\n"); /* Put the device into discoverable mode so that a remote can search it. */ apiResult = Cy_BLE_GAPP_StartAdvertisement(CY_BLE_ADVERTISING_FAST, CY_BLE_PERIPHERAL_CONFIGURATION_0_INDEX); if(apiResult != CY_BLE_SUCCESS) { DBG_PRINTF("StartAdvertisement API Error: %d \r\n", apiResult); } break; case CY_BLE_EVT_GAP_ENCRYPT_CHANGE: DBG_PRINTF("CYBLE_EVT_GAP_ENCRYPT_CHANGE: %x \r\n", *(uint8 *)eventParam); break; case CY_BLE_EVT_GAP_CONNECTION_UPDATE_COMPLETE: DBG_PRINTF("CYBLE_EVT_CONNECTION_UPDATE_COMPLETE: %x \r\n", *(uint8 *)eventParam); break; case CY_BLE_EVT_GAPP_ADVERTISEMENT_START_STOP: if(Cy_BLE_GetAdvertisementState() == CY_BLE_ADV_STATE_STOPPED) { /* Fast and slow advertising period complete, go to low power * mode (Hibernate mode) and wait for an external * user event to wake up the device again */ /* Stop DFU communication */ Cy_DFU_TransportStop(); /* Check if app is valid, if it is then switch to it */ uint32_t status = Cy_DFU_ValidateApp(1u, NULL); if (status == CY_DFU_SUCCESS) { /* * Clear reset reason because Cy_DFU_ExecuteApp() performs * a software reset. * Without clearing two reset reasons would be present. */ do { Cy_SysLib_ClearResetReason(); }while(Cy_SysLib_GetResetReason() != 0); /* Never returns */ Cy_DFU_ExecuteApp(1u); } /* 300 seconds has passed and App is invalid. Hibernate */ HibernateLED(); Cy_SysPm_Hibernate(); } break; /********************************************************** * GATT Events ***********************************************************/ case CY_BLE_EVT_GATT_CONNECT_IND: appConnHandle = *(cy_stc_ble_conn_handle_t *)eventParam; DBG_PRINTF("CYBLE_EVT_GATT_CONNECT_IND: %d \r\n", appConnHandle.bdHandle); break; case CY_BLE_EVT_GATT_DISCONNECT_IND: DBG_PRINTF("CYBLE_EVT_GATT_DISCONNECT_IND: %d \r\n", ((cy_stc_ble_conn_handle_t *)eventParam)->bdHandle); break; case CY_BLE_EVT_GATTS_WRITE_CMD_REQ: DBG_PRINTF("CYBLE_EVT_GATTS_WRITE_CMD_REQ\r\n"); break; default: break; } } /* [] END OF FILE */