812 lines
31 KiB
C
812 lines
31 KiB
C
/*******************************************************************************
|
|
* 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 <string.h>
|
|
#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 */
|