Over The Air (OTA) Update Library
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
Over The Air(OTA) Library Overview

This library offers assistance for over-the-air (OTA) updates of the application code that is executed on a PSoC™ 6 Connectivity Device, a 20829(CYW920829M2EVK-02) Device, a 89829(CYW989829M2EVB-01) Device, or an XMC7200(KIT_XMC72_EVK) Device, using Wi-Fi, Bluetooth® or Ethernet Connectivity.

For simplification, this document may refer to an MQTT Broker or an HTTP Server as "server".

The library provides a number of combinations on how to get the OTA image:

Bluetooth®

  • We use a Push model with Bluetooth®. A Peer application running on a laptop or phone will connect and push an update to the Device.

MQTT and HTTP

  • MQTT and HTTP use a Pull model. One or two steps can be used to get the OTA image. The two steps are "get job" and "get data". The caller can skip the "get job" step and get the OTA image directly.

"Pull" Model using a Job file:

Step 1 - Get Job:

  • The OTA Agent downloads a JSON "Job" document (default name "ota_update.json").
  • The Job document has information about an update that is available, including its location.


Step 2: - Get Data:

  • The OTA Agent will download the OTA image and writes it to the configured upgrade slot using registered "upgrade image handling storage callback APIs".
    On the next reboot, Bootloader will take care of booting the new version of the application from the configured upgrade slot.

You can skip Step 1 by setting the use_get_job_flow field in cy_ota_network_params_t to CY_OTA_DIRECT_FLOW when calling cy_ota_agent_start().

The ModusToolbox OTA code examples import this OTA library automatically.

Features and Functionality

This library utilizes MQTT or HTTPS and TLS, or Bluetooth® to securely connect to and download an update for the users application.

Other features:

Server info, credentials, and other parameters are passed into cy_ota_agent_start().

MQTT and HTTP

  • Configuration to adjust multiple timing values to customize how often to check for updates, and other parameters for the MQTT Broker connection.
  • Runs in a separate background thread, only connecting to the server based on the parameters passed to cy_ota_agent_start().
  • Provides a callback mechanism to report stages of connect, download percentage, and errors.
  • Once the application starts the OTA Agent, the OTA Agent will contact the server at the defined intervals to see if there is an update available.
  • Upon receiving the upgrade image, OTA Agent gives a callback to the application for handling the upgrade image.

Bluetooth®

  • Runs in a separate thread with callbacks to the users application to handle the connection messages and download data.
  • When Bluetooth® is enabled in the compile flags, the Bluetooth® server will start automatically.

Integration Notes

Before enabling OTA in an application, the user must choose a suitable bootloader and program it on the chosen platform(s).
The required build environment for creating BOOT and UPGRADE images should be set up.

To add the required bootloader support at the application level itself, the OTA update library implements a callback mechanism and offloads handling of upgrade images including flash operations to application.

The application must implement these storage operation callbacks defined in ota-update/<version>/include/cy_ota_api.h to handle upgrade image based on bootloader choosen and must register callbacks during OTA agent start by giving a parameter of type 'cy_ota_storage_interface_t' in 'cy_ota_agent_start()'.

A pre-defined configuration file has been bundled with this library.
The user is expected to:

  • Copy the cy_ota_config.h file from the ota-update/<version>/configs
    directory to the top-level code example directory.

  • Copy FreeRTOSConfig.h configuration file for the CM4 (PSoC™ 6), CM33 (CYW920829M2EVK-02 and CYW989829M2EVB-01) or CM7 (KIT_XMC72_EVK) device used.
    Copy the ota-update/<version>/configs/FreeRTOS directory to the top-level code example directory.

  • Provide application version information in application makefile.
  • OTA library user is expected to provide application version(X.Y.Z) by adding values for APP_VERSION_MAJOR, APP_VERSION_MINOR, and APP_VERSION_BUILD.
    APP_VERSION_MAJOR=<X>
    APP_VERSION_MINOR=<Y>
    APP_VERSION_BUILD=<Z>
  • Please refer to the ota-update/<version>/OTA_MAKEFILE_INFO_README.md file for more details on OTA application makefile.

  • For HTTP support, add the following to the application Makefile:
    OTA_HTTP_SUPPORT=1

  • For MQTT support, add the following to the application Makefile:
    OTA_MQTT_SUPPORT=1

  • For Non-Secure Bluetooth® support, add the following to the application Makefile:
    OTA_BT_SUPPORT=1 OTA_BT_SECURE=0

  • For Secure Bluetooth® support, add the following to the application Makefile:
    OTA_BT_SUPPORT=1 OTA_BT_SECURE=1

    OTA_MQTT_SUPPORT, OTA_HTTP_SUPPORT and OTA_BT_SUPPORT can be used simultaneously, but will possibly be too large to fit in the FLASH slot available.

    There are other COMPONENTS that may be needed based on support. Please refer to the various README.md files in the root ota-update library directory.
    README.md
    OTA_MAKEFILE_INFO_README.md

General Concept

The OTA Agent downloads upgrade version of OTA applications and stores the update to the upgrade slot using user registered storage callbacks. Once after completing the download, OTA library verifies update image(checksum) and reboots device. When device reboots, programmed bootloader boots upgrade image of application.

The basic device boot sequence is as follows:

  1. ROM boot will start Bootloader.
  2. Bootloader runs the current application in the BOOT slot.
  3. The OTA Agent downloads the update and stores it in the UPGRADE slot.
  4. The OTA Agent marks the upgrade as ready.

    On the next system boot:
  1. ROM boot will start Bootloader
  2. If no update is downloaded, Bootloader starts the current application.
  3. Bootloader determines if there is an update in the UPGRADE Slot
  4. If there is an update available:
    a. Bootloader verifies the update.
    b. Bootloader starts the new (updated) application.
    c. The updated application must validate the update.

    For more general information, see the various README.md files in the ota-update/<version>/ directory:
    README.md
    OTA_MAKEFILE_INFO_README.md

API Overview

Start the OTA Agent

cy_ota_start_agent() is a non-blocking call, which returns a context pointer that is used in subsequent calls.
When using Bluetooth®, cy_ota_start_agent() is called after the Peer sends a PREPARE_DOWNLOAD message.
When using MQTT or HTTP, the OTA Agent uses callbacks to signal the application when events occur.

cy_rslt_t cy_ota_agent_start(cy_ota_network_params_t *network_params, cy_ota_agent_params_t *agent_params, cy_ota_storage_interface_t *storage_interface, cy_ota_context_ptr *ctx_ptr);

These defines determine when the checks happen. Between checks, the OTA Agent is not connected to a server, and not checking for updates.

  • CY_OTA_INITIAL_CHECK_SECS
  • CY_OTA_NEXT_CHECK_INTERVAL_SECS
  • CY_OTA_RETRY_INTERVAL_SECS
  • CY_OTA_CHECK_TIME_SECS

Stop the OTA Agent

When you want to stop the OTA Agent.

cy_rslt_t cy_ota_agent_stop(cy_ota_context_ptr *ctx_ptr);

Trigger a check right now.

Use this when you want to trigger a check for an OTA update earlier than
is currently scheduled. The OTA Agent must have been started already. For MQTT and HTTP only.

cy_rslt_t cy_ota_get_update_now(cy_ota_context_ptr ctx_ptr);

Override Default Settings

For MQTT and HTTP usage, copy the cy_ota_config.h file from the ota-update/<version>/configs
directory to the top-level code example directory in the project.
Change these values to your preferred settings.

#define CY_OTA_INITIAL_CHECK_SECS (10) /* 10 seconds */
#define CY_OTA_NEXT_CHECK_INTERVAL_SECS (24 * 60 * 60) /* 1 day between checks */
#define CY_OTA_RETRY_INTERVAL_SECS (5) /* 5 seconds between retries after an error */
#define CY_OTA_CHECK_TIME_SECS (10 * 60) /* 10 minutes */
#define CY_OTA_PACKET_INTERVAL_SECS (0) /* default disabled */
#define CY_OTA_JOB_CHECK_TIME_SECS (30) /* 30 seconds */
#define CY_OTA_DATA_CHECK_TIME_SECS (20 * 60) /* 20 minutes */
#define CY_OTA_RETRIES (3) /* retry entire process 3 times */
#define CY_OTA_CONNECT_RETRIES (3) /* 3 server connect retries */
#define CY_OTA_MAX_DOWNLOAD_TRIES (3) /* 3 download OTA Image retries */
#define CY_OTA_HTTP_TIMEOUT_SEND (3000) /* 3 second send timeout (ms). */
#define CY_OTA_HTTP_TIMEOUT_RECEIVE (3000) /* 3 second receive timeout. */
/**********************************************************************
* Message Defines
**********************************************************************/
#define PUBLISHER_LISTEN_TOPIC "publish_notify"
#define COMPANY_TOPIC_PREPEND "OTAUpdate"
#define PUBLISHER_DIRECT_TOPIC "OTAImage"
#define CY_OTA_RESULT_SUCCESS "Success"
#define CY_OTA_RESULT_FAILURE "Failure"
#define CY_OTA_HTTP_JOB_FILE "/ota_update.json"
#define CY_OTA_HTTP_DATA_FILE "/ota-update.bin"
#define CY_OTA_SUBSCRIBE_UPDATES_AVAIL \
"{\
\"Message\":\"Update Availability\", \
\"Manufacturer\": \"Express Widgits Corporation\", \
\"ManufacturerID\": \"EWCO\", \
\"ProductID\": \"Easy Widgit\", \
\"SerialNumber\": \"ABC213450001\", \
\"BoardName\": \"CY8CPROTO_062_4343W\", \
\"Version\": \"%d.%d.%d\", \
\"UniqueTopicName\": \"%s\"\
}"
#define CY_OTA_DOWNLOAD_REQUEST \
"{\
\"Message\":\"Request Update\", \
\"Manufacturer\": \"Express Widgits Corporation\", \
\"ManufacturerID\": \"EWCO\", \
\"ProductID\": \"Easy Widgit\", \
\"SerialNumber\": \"ABC213450001\", \
\"BoardName\": \"CY8CPROTO_062_4343W\", \
\"Version\": \"%d.%d.%d\", \
\"UniqueTopicName\": \"%s\" \
}"
#define CY_OTA_DOWNLOAD_CHUNK_REQUEST \
"{\
\"Message\":\"Request Data Chunk\", \
\"Manufacturer\": \"Express Widgits Corporation\", \
\"ManufacturerID\": \"EWCO\", \
\"ProductID\": \"Easy Widgit\", \
\"SerialNumber\": \"ABC213450001\", \
\"BoardName\": \"CY8CPROTO_062_4343W\", \
\"Version\": \"%d.%d.%d\", \
\"UniqueTopicName\": \"%s\", \
\"Filename\": \"%s\", \
\"Offset\": \"%ld\", \
\"Size\": \"%ld\"\
}"
#define CY_OTA_MQTT_RESULT_JSON \
"{\
\"Message\":\"%s\", \
\"UniqueTopicName\": \"%s\"\
}"
#define CY_OTA_HTTP_RESULT_JSON \
"{\
\"Message\":\"%s\", \
\"File\":\"%s\" \
}"
#ifndef CY_OTA_HTTP_GET_TEMPLATE
#define CY_OTA_HTTP_GET_TEMPLATE \
"GET %s HTTP/1.1\r\n" \
"Host: %s:%d \r\n" \
"\r\n"
#endif
#ifndef CY_OTA_HTTP_GET_RANGE_TEMPLATE
#define CY_OTA_HTTP_GET_RANGE_TEMPLATE \
"GET %s HTTP/1.1\r\n" \
"Host: %s:%d \r\n" \
"Range: bytes=%ld-%ld \r\n" \
"\r\n"
#endif
#ifndef CY_OTA_HTTP_POST_TEMPLATE
#define CY_OTA_HTTP_POST_TEMPLATE \
"POST %s HTTP/1.1\r\n" \
"Content-Length:%ld \r\n" \
"\r\n%s"
#endif
/**********************************************************************
* MQTT Defines
**********************************************************************/
#define CY_OTA_MQTT_KEEP_ALIVE_SECONDS (60) /* 60 second keepalive. */
#define CY_OTA_MQTT_MAX_TOPICS (2)
#define CY_OTA_MQTT_TOPIC_PREFIX "cy_ota_device"
#define CY_OTA_MQTT_CLIENT_ID_PREFIX "cy_device"

Bootloader Support


Starting from the 4.0 version of the ota-update library, the library is now fully separated from the MCUBootloader. This means that it can function independently and work with any bootloader, as long as the required OTA update handling storage APIs are implemented and registered with OTA agent by the user.
MCUBootloader Support:
MCUBootloader is a secure bootloader for 32-bits microcontrollers and users should build it outside of the user OTA application. It is programmed separately to the device before flashing the user OTA application and is not updated for the life of the device.
To support MCUBootloader based OTA using ota-update library, User can implement his own storage operation callbacks to handle upgrade image or can make use of ota-bootloader-abstraction library.
ota-bootloader-abstraction library has below support.

  1. Template flashmaps for PSoC6, 20829, 89829 and XMC7200 platforms.
  2. Template linker files for GCC_ARM, ARM, and IAR toolchains.
  3. Storage operation callback APIs to handle MCUBootloader based upgrade image.
  4. Prebuild and Postbuild scripts for generating and signing MCUBootloader based BOOT and UPGRADE image of an OTA Application.
    User needs to register storage operation callbacks available in ota-bootloader-abstraction during OTA agent start.
    For more information, see the various README.md files in the ota-bootloader-abstraction/<version>/ directory.

Code Snippets


MQTT and HTTP initialization:
The following code snippet demonstrates an example for initializing the cy_ota_network_params_t and ota_agent_params structures required to start the OTA Agent.

/* Macro to enable/disable TLS. */
#define ENABLE_TLS (false)
#define HTTP_SERVER "my.httpserver.com"
#define HTTP_SERVER_PORT (80) /* 443 for TLS. */
/* Number of MQTT topic filters. */
#define MQTT_TOPIC_FILTER_NUM (1)
#define MQTT_BROKER "mqtt.broker.com"
#define MQTT_BROKER_PORT (1883) /* (8883) for TLS support. */
/* MQTT topics. */
const char * mqtt_topics[ MQTT_TOPIC_FILTER_NUM ] =
{
"mtb/test/ota/image"
};
/* Root CA Certificate.
Must include the PEM header and footer:
"-----BEGIN CERTIFICATE-----\n" \
".........base64 data.......\n" \
"-----END CERTIFICATE-------\n"
*/
#define ROOT_CA_CERTIFICATE ""
/* Client Certificate.
Must include the PEM header and footer:
"-----BEGIN CERTIFICATE-----\n" \
".........base64 data.......\n" \
"-----END CERTIFICATE-------\n"
*/
#define CLIENT_CERTIFICATE ""
/* Private Key.
Must include the PEM header and footer:
"-----BEGIN RSA PRIVATE KEY-----\n" \
"...........base64 data.........\n" \
"-----END RSA PRIVATE KEY-------\n"
*/
#define CLIENT_KEY ""
/* OTA context. */
static cy_ota_context_ptr ota_context;
/* OTA callback function define. */
/* MQTT Credentials for OTA. */
cy_awsport_ssl_credentials_t mqtt_credentials;
/* HTTP Credentials for OTA. */
cy_awsport_ssl_credentials_t http_credentials;
/* network parameters for OTA. */
/* Parameters for the OTA Agent. */
cy_ota_agent_params_t ota_agent_params =
{
.cb_func = ota_callback, /* Set the value to NULL if the callback function is not used. */
.cb_arg = &ota_context, /* Set the value to NULL if the callback function is not used. */
.reboot_upon_completion = 1 /* Reboot after completing OTA with success. */
};
{
.ota_file_open = cy_ota_storage_open,
.ota_file_read = cy_ota_storage_read,
.ota_file_write = cy_ota_storage_write,
.ota_file_close = cy_ota_storage_close,
.ota_file_verify = cy_ota_storage_verify,
.ota_file_validate = cy_ota_storage_validated,
.ota_file_get_app_info = cy_ota_storage_get_app_info
};


OTA flash operations callback:
This example functions demonstrates the usage of the OTA storage operation callbacks to handle upgrade image(read/write/erase). Implementation of storage operation callbacks is mandatory because OTA Agent depends on these callbacks for handling upgrade images.

Note: You must initialize Flash before registering these callbacks.

/*******************************************************************************
* Function Name: cy_ota_storage_open()
*******************************************************************************
* Summary:
* Got a callback from OTA for opening and initializing storage area for download.
* Typically, this erases upgrade slot.
*
* @param[in] storage_ptr Pointer to the OTA Agent storage context @ref cy_ota_storage_context_t
*
* @return CY_RSLT_SUCCESS
* CY_RSLT_OTA_ERROR_OPEN_STORAGE
*
*******************************************************************************/
cy_rslt_t cy_ota_storage_open(cy_ota_storage_context_t *storage_ptr)
{
cy_rslt_t result = CY_RSLT_SUCCESS;
if(storage_ptr == NULL)
{
/* Parameter Error */
}
/* Add logic to open and erase storage area for writing upgrade */
return result;
}
/*******************************************************************************
* Function Name: cy_ota_storage_read()
*******************************************************************************
* Summary:
* Got a callback from OTA to read from storage area.
*
* @param[in] storage_ptr - Pointer to the OTA Agent storage context @ref cy_ota_storage_context_t
* @param[in][out] chunk_info - Pointer to chunk information, buffer pointer used for the read
*
* @return CY_RSLT_SUCCESS
* CY_RSLT_OTA_ERROR_READ_STORAGE
*
*******************************************************************************/
cy_rslt_t cy_ota_storage_read(cy_ota_storage_context_t *storage_ptr, cy_ota_storage_read_info_t *chunk_info)
{
cy_rslt_t result = CY_RSLT_SUCCESS;
if(storage_ptr == NULL)
{
/* Parameter Error */
}
/* Add logic to read from storage area */
return result;
}
/*******************************************************************************
* Function Name: cy_ota_storage_write()
*******************************************************************************
* Summary:
* Got a callback from OTA for writing to storage area.
*
* @param[in] storage_ptr Pointer to the OTA Agent storage context @ref cy_ota_storage_context_t
* @param[in] chunk_info Pointer to chunk information, buffer pointer used for the write
*
* @return CY_RSLT_SUCCESS
* CY_RSLT_OTA_ERROR_WRITE_STORAGE
*
*******************************************************************************/
cy_rslt_t cy_ota_storage_write(cy_ota_storage_context_t *storage_ptr, cy_ota_storage_write_info_t * const chunk_info)
{
cy_rslt_t result = CY_RSLT_SUCCESS;
if(storage_ptr == NULL)
{
/* Parameter Error */
}
/* Add logic to write upgrade image chunks/information to storage area */
return result;
}
/*******************************************************************************
* Function Name: cy_ota_storage_close()
*******************************************************************************
* Summary:
* Got a callback from OTA for closing storage area.
*
* @param[in] storage_ptr Pointer to the OTA Agent storage context @ref cy_ota_storage_context_t
*
* @return CY_RSLT_SUCCESS
* CY_RSLT_OTA_ERROR_CLOSE_STORAGE
*
*******************************************************************************/
cy_rslt_t cy_ota_storage_close(cy_ota_storage_context_t *storage_ptr)
{
cy_rslt_t result = CY_RSLT_SUCCESS;
if(storage_ptr == NULL)
{
/* Parameter Error */
}
/* Add logic to close storage area */
return result;
}
/*******************************************************************************
* Function Name: cy_ota_storage_verify()
*******************************************************************************
* Summary:
* Got a callback from OTA to verify the downloaded upgrade image.
*
* @param[in] storage_ptr Pointer to the OTA Agent storage context @ref cy_ota_storage_context_t
*
* @return CY_RSLT_SUCCESS
* CY_RSLT_OTA_ERROR_GENERAL
*
*******************************************************************************/
cy_rslt_t cy_ota_storage_verify(cy_ota_storage_context_t *storage_ptr)
{
cy_rslt_t result = CY_RSLT_SUCCESS;
if(storage_ptr == NULL)
{
/* Parameter Error */
}
/* Add logic to verify downloaded image and Activate if verification is successful. */
return result;
}
/*******************************************************************************
* Function Name: cy_ota_storage_validated()
*******************************************************************************
* Summary:
* This API needs to be called from application to make active image as permanent Image.
*
* @return CY_RSLT_SUCCESS
* CY_RSLT_OTA_ERROR_GENERAL
*
*******************************************************************************/
cy_rslt_t cy_ota_storage_validated(void)
{
cy_rslt_t result = CY_RSLT_SUCCESS;
if(storage_ptr == NULL)
{
/* Parameter Error */
}
/* Add logic to to make active image as permanent image. */
return result;
}
/*******************************************************************************
* Function Name: cy_ota_storage_verify()
*******************************************************************************
* Summary:
* Got a callback from OTA to read BOOT/UPGRADE image information.
*
* @param[in] file_des Pointer to the storage context.
* @param[in][out] app_info Pointer to store application image information.
*
* @return CY_RSLT_SUCCESS
* CY_RSLT_OTA_ERROR_GENERAL
*
*******************************************************************************/
cy_rslt_t cy_ota_storage_get_app_info(void* file_des, cy_ota_app_info_t *app_info)
{
cy_rslt_t result = CY_RSLT_SUCCESS;
if(storage_ptr == NULL)
{
/* Parameter Error */
}
/* Add logic to read BOOT/UPGRADE image information such as version and ID. */
return result;
}


OTA Application callback:
This example function demonstrates the usage of the OTA callback function to print the status of every OTA event. The callback feature is optional but be aware that the OTA library will not print the status of the OTA Agent on its own.

Note: You must initialize retarget-io to use the debug UART port.

/*******************************************************************************
* Function Name: ota_callback()
*******************************************************************************
* Summary:
* Got a callback from OTA.
*
* @param[in][out] cb_data - Structure holding the information for the application.
*
* Return:
* CY_OTA_CB_RSLT_OTA_CONTINUE - OTA Agent to continue with the function, using the modified data from the application.
* CY_OTA_CB_RSLT_OTA_STOP - OTA Agent to end the current update session (do not quit).
* CY_OTA_CB_RSLT_APP_SUCCESS - Application completed task; OTA Agent use success.
* CY_OTA_CB_RSLT_APP_FAILED - Application completed task; OTA Agent use failure.
*
*******************************************************************************/
static cy_ota_callback_results_t ota_callback(cy_ota_cb_struct_t *cb_data)
{
cy_ota_callback_results_t cb_result = CY_OTA_CB_RSLT_OTA_CONTINUE; /* OTA Agent to continue as normal. */
const char *state_string;
const char *error_string;
cy_ota_context_ptr ctx = NULL;
if (cb_data == NULL)
{
}
ctx = *((cy_ota_context_ptr *)cb_data->cb_arg);
if (ctx == NULL)
{
}
state_string = cy_ota_get_state_string(cb_data->state);
reason_string = cy_ota_get_callback_reason_string(cb_data->reason);
switch (cb_data->reason)
{
case CY_OTA_LAST_REASON: /* To keep linker happy. */
break;
printf("APP CB OTA SUCCESS state:%d %s last_error:%s\n", cb_data->state, state_string, error_string);
break;
printf("APP CB OTA FAILURE state:%d %s last_error:%s\n", cb_data->state, state_string, error_string);
break;
switch (cb_data->state)
{
/* Informational. */
printf("APP CB OTA STATE CHANGE state:%d %s last_error:%s\n", cb_data->state, state_string, error_string);
break;
printf("APP CB OTA STATE CHANGE CY_OTA_STATE_START_UPDATE\n");
break;
printf("APP CB OTA STORAGE OPEN\n");
break;
printf("APP CB OTA STORAGE WRITE %ld%% (%ld of %ld)\n", cb_data->percentage, cb_data->bytes_written, cb_data->total_size);
break;
printf("APP CB OTA STORAGE CLOSE\n");
break;
printf("APP CB OTA CONNECT FOR JOB using ");
/* NOTE:
* MQTT - json_doc holds the MQTT JSON request document.
* HTTP - json_doc holds the HTTP "GET" request.
*/
{
printf("MQTT: server:%s port: %d\n", cb_data->broker_server.pHostName, cb_data->broker_server.port);
}
else
{
printf("HTTP: server:%s port: %d\n", cb_data->broker_server.pHostName, cb_data->broker_server.port);
}
break;
printf("APP CB OTA JOB DOWNLOAD using ");
/* NOTE:
* MQTT - json_doc holds the MQTT JSON request document.
* HTTP - json_doc holds the HTTP "GET" request.
*/
{
printf("MQTT: '%s'", cb_data->json_doc);
printf(" topic: '%s' \n", cb_data->unique_topic);
}
else
{
printf("HTTP: '%s'", cb_data->file);
}
break;
printf("APP CB OTA JOB DISCONNECT\n");
break;
printf("APP CB OTA PARSE JOB: '%.*s' \n", strlen(cb_data->json_doc), cb_data->json_doc);
break;
printf("APP CB OTA JOB REDIRECT\n");
break;
printf("APP CB OTA CONNECT FOR DATA using ");
{
printf("MQTT: %s:%d \n", cb_data->broker_server.pHostName, cb_data->broker_server.port);
}
else
{
printf("HTTP: %s:%d \n", cb_data->broker_server.pHostName, cb_data->broker_server.port);
}
break;
printf("APP CB OTA DATA DOWNLOAD using ");
/* NOTE:
* MQTT - json_doc holds the MQTT JSON request document.
* HTTP - json_doc holds the HTTP "GET" request.
*/
{
printf("MQTT: '%s' \n", cb_data->json_doc);
printf(" topic: '%s' \n", cb_data->unique_topic);
}
else
{
printf("HTTP: '%s' \n", cb_data->json_doc);
printf(" file: '%s' \n", cb_data->file);
}
break;
printf("APP CB OTA DATA DISCONNECT\n");
break;
printf("APP CB OTA VERIFY\n");
break;
printf("APP CB OTA RESULT REDIRECT\n");
break;
printf("APP CB OTA SEND RESULT CONNECT using ");
/* NOTE:
* MQTT - json_doc holds the MQTT JSON request document.
* HTTP - json_doc holds the HTTP "GET" request.
*/
{
printf("MQTT: Broker:%s port: %d\n", cb_data->broker_server.pHostName, cb_data->broker_server.port);
printf(" topic: '%s' \n", cb_data->unique_topic);
}
else
{
printf("HTTP: Server:%s port: %d\n", cb_data->broker_server.pHostName, cb_data->broker_server.port);
}
break;
printf("APP CB OTA SENDING RESULT using ");
/* NOTE:
* MQTT - json_doc holds the MQTT JSON request document.
* HTTP - json_doc holds the HTTP "PUT".
*/
{
printf("MQTT: '%s' \n", cb_data->json_doc);
}
else
{
printf("HTTP: '%s' \n", cb_data->json_doc);
}
break;
printf("APP CB OTA Got Result response\n");
break;
printf("APP CB OTA Result Disconnect\n");
break;
printf("APP CB OTA Session Complete\n");
break;
case CY_OTA_NUM_STATES: /* To keep compiler happy. */
break;
} /* Switch state. */
break;
}
return cb_result;
}


OTA Initialization:
The following code snippet demonstrates the initialization of the OTA Agent.

/* Initialize and start the OTA Agent.
*
* The main application must:
* - In case of XMC7200 devices, disables and invalidate instruction cache and disable, clean and invalidate data cache.
* SCB_DisableICache(); // Disables and invalidates instruction cache
* SCB_DisableDCache(); // Disables, cleans and invalidates data cache
* - In case of CAT1C devices, like XMC7200 devices, initializa appropriate flash access apis.
* Cy_Flash_Init();
* Cy_Flashc_MainWriteEnable();
* Cy_Flashc_WorkWriteEnable();
* - Turn off the Watchdog Timer (if being used)
* cyhal_wdt_t wdt_obj;
* cyhal_wdt_init(&wdt_obj, cyhal_wdt_get_max_timeout_ms());
* cyhal_wdt_free(&wdt_obj);
* - Validate the application (if the update just happened)
* cy_ota_storage_validated();
* - In case of Wi-Fi enabled devices like PSoC62, PSoC63 or PSoC64 :
* Initialize Wi-Fi.
* Connect to the Wi-Fi AP.
* - In case of Ethernet enabled devices like XMC7200 :
* Initialize Ethernet Module.
* Bring up the interface and configure to corresponding Ethernet port.
*
*/
cy_rslt_t ota_setup(void)
{
cy_rslt_t result;
/*****************************************************************************
< Add code snippet here to initialize and connect to a Wi-Fi AP >
******************************************************************************/
/* Initialize the underlying support code that is needed for OTA and MQTT. */
if (cy_awsport_network_init() != CY_RSLT_SUCCESS)
{
printf("cy_awsport_network_init Failed.\n");
while(1)
{
cy_rtos_delay_milliseconds(10);
}
}
/* Initialize the MQTT subsystem. */
if (cy_mqtt_init() != CY_RSLT_SUCCESS )
{
printf("cy_mqtt_init() Failed.\n");
while(1)
{
cy_rtos_delay_milliseconds(10);
}
}
/* Set up parameters for starting the OTA Agent. */
memset(&network_params, 0, sizeof(network_params));
memset(&agent_params, 0, sizeof(agent_params));
/* Common network parameters. */
/* Server parameters. */
network_params.initial_connection = ota->connection_type;
/* Set all network parameters for both MQTT & HTTP in case of switching
* from Job Broker/server to data Broker/server.
*/
/* MQTT Connection values. */
network_params.mqtt.broker.host_name = MQTT_BROKER;
network_params.mqtt.broker.port = MQTT_BROKER_PORT;
network_params.use_get_job_flow = true; /* False for Direct flow. */
network_params.mqtt.numTopicFilters = MQTT_TOPIC_FILTER_NUM;
network_params.mqtt.pTopicFilters = mqtt_topics;
network_params.mqtt.pIdentifier = "MQTTClientUniqueIdentifier"; /* Create a unique identifier. */
network_params.mqtt.session_type = CY_OTA_MQTT_SESSION_CLEAN;
/* HTTP connection values. */
network_params.http.server.host_name = HTTP_SERVER; /* Must not be a local variable. */
network_params.http.server.port = HTTP_SERVER_PORT;
/* For HTTP, change the file with the GET when using a Job flow. */
network_params.use_get_job_flow = ota->update_flow;
if (network_params.use_get_job_flow == CY_OTA_JOB_FLOW)
{
/* For HTTP server to get the "Job" file. */
network_params.http.file = OTA_HTTP_JOB_FILE;
}
else
{
/* For HTTP server to get the "data" file directly. */
network_params.http.file = OTA_HTTP_DATA_FILE;
}
/* Set up MQTT credentials - only used if start_TLS is set. */
memset(&network_params.mqtt.credentials, 0x00, sizeof(network_params.mqtt.credentials) );
/* if service is AMAZON, for testing we need to set the username */
if (ota->mqtt_certificates == OTA_MQTT_SERVICE_AMAZON)
{
/* Only set this for Amazon testing. */
mqtt_credentials.username = "Test";
mqtt_credentials.username_size = strlen(mqtt_credentials.username);
mqtt_credentials.password = "";
mqtt_credentials.password_size = strlen(mqtt_credentials.password);
}
mqtt_credentials.alpnprotos = NULL;
mqtt_credentials.alpnprotoslen = 0;
mqtt_credentials.sni_host_name = NULL;
mqtt_credentials.sni_host_name_size = 0;
mqtt_credentials.root_ca = mqtt_root_ca_certificate_table[ota->mqtt_certificates];
mqtt_credentials.root_ca_size = strlen(mqtt_root_ca_certificate_table[ota->mqtt_certificates]) + 1;
mqtt_credentials.client_cert = mqtt_client_cert_table[ota->mqtt_certificates];
mqtt_credentials.client_cert_size = strlen(mqtt_client_cert_table[ota->mqtt_certificates]) + 1;
mqtt_credentials.private_key = mqtt_client_key_table[ota->mqtt_certificates];
mqtt_credentials.private_key_size = strlen(mqtt_client_key_table[ota->mqtt_certificates]) + 1;
if (ota->start_TLS)
{
network_params.mqtt.credentials = mqtt_credentials;
}
memset(&network_params.http.credentials, 0x00, sizeof(network_params.http.credentials ));
/* Set up HTTP credentials - only used if start_TLS is set. */
/* Only if the HTTP server needs this: */
//http_credentials.password = "";
//http_credentials.username_size = strlen(http_credentials.password);
//http_credentials.password = "";
//http_credentials.password_size = strlen(http_credentials.password);
http_credentials.alpnprotos = NULL;
http_credentials.alpnprotoslen = 0;
http_credentials.sni_host_name = NULL;
http_credentials.sni_host_name_size = 0;
http_credentials.root_ca = (const char *)root_ca_certificate_https;
http_credentials.root_ca_size = strlen(root_ca_certificate_https) + 1;
http_credentials.client_cert = (const char *)client_cert_https;
http_credentials.client_cert_size = strlen(client_cert_https) + 1;
http_credentials.private_key = (const char *)client_key_https;
http_credentials.private_key_size = strlen(client_key_https) + 1;
if (ota->start_TLS)
{
network_params.http.credentials = http_credentials;
}
/* OTA Agent parameters. */
agent_params.validate_after_reboot = 0; /* Validate after download so that you don't have to call
* cy_ota_validated() on reboot. */
agent_params.reboot_upon_completion = 1; /* 1 = Reboot when download is finished. */
agent_params.do_not_send_result = 0; /* 1 = Do not send the result info to the Broker/server. */
agent_params.cb_func = ota_callback;
agent_params.cb_arg = ota;
/* Initialize and start the OTA Agent. */
result = cy_ota_agent_start(&network_params, &agent_params, &ota_interfaces, &ota_context);
return result;
}


Application Bluetooth® initialization:
The following code snippet demonstrates and example for initializing the Bluetooth® Stack required before starting the OTA Agent. The next snippet shows the Bluetooth® GATT callback handler.

/*
* Function name:
* bt_app_init
*
* Function Description:
* @brief This function is executed if BTM_ENABLED_EVT event occurs in
* Bluetooth® management callback.
*
* @param void
*
* @return void
*/
static void bt_app_init(void)
{
wiced_result_t wiced_result;
wiced_bt_gatt_status_t status = WICED_BT_GATT_BUSY;
/* Initialising the HCI UART for Host contol */
cybt_platform_config_init(&app_bt_platform_cfg_settings);
/* Register with stack to receive GATT callback */
status = wiced_bt_gatt_register(app_bt_gatt_event_handler);
printf("wiced_bt_gatt_register() status (0x%lx) %s\n", status, app_get_gatt_status_name(status));
/* Initialize GATT Database */
status = wiced_bt_gatt_db_init(gatt_database, gatt_database_len, NULL);
if(status != WICED_BT_GATT_SUCCESS)
{
printf("%s() wiced_bt_gatt_db_init() FAILED 0x%lx !\n", __func__, status);
}
/* Allow peer to pair */
wiced_bt_set_pairable_mode(WICED_TRUE, 0);
/* Set Advertisement Data */
status = app_bt_set_advertisement_data();
if(status != WICED_SUCCESS)
{
printf("%s() app_bt_set_advertisement_data() FAILED 0x%lx !\n", __func__, status);
}
/* Start Undirected LE Advertisements on device startup. */
status = wiced_bt_start_advertisements(BTM_BLE_ADVERT_UNDIRECTED_HIGH, BLE_ADDR_PUBLIC, NULL);
if(status != WICED_SUCCESS)
{
printf("%s() wiced_bt_start_advertisements() FAILED 0x%lx\n", __func__, status);
}
/* Register call back and configuration with stack */
wiced_result = wiced_bt_stack_init(app_bt_management_callback , &wiced_bt_cfg_settings);
if( WICED_BT_SUCCESS == wiced_result)
{
printf("Bluetooth(r) Stack Initialization Successful \n");
}
else
{
printf("Bluetooth(r) Stack Initialization failed!!\n");
}
}


Application Bluetooth® Callback Handling:
The following code snippet demonstrates and example for initializing the Bluetooth® Stack required before starting the OTA Agent.

/*
* Function Name:
* app_bt_gatt_event_handler
*
* Function Description:
* @brief This Function handles the all the GATT events - GATT Event Handler
*
* @param event Bluetooth® GATT event type
* @param p_event_data Pointer to Bluetooth® GATT event data
*
* @return wiced_bt_gatt_status_t Bluetooth® GATT status
*/
static wiced_bt_gatt_status_t app_bt_gatt_event_handler(wiced_bt_gatt_evt_t event, wiced_bt_gatt_event_data_t *p_event_data)
{
wiced_bt_gatt_status_t status = WICED_BT_GATT_SUCCESS;
wiced_bt_gatt_attribute_request_t *p_attr_req = &p_event_data->attribute_request;
switch (event)
{
case GATT_CONNECTION_STATUS_EVT: /* GATT connection status change. Event data: #wiced_bt_gatt_connection_status_t */
printf("\n\n%s() GATT_CONNECTION_STATUS_EVT: %d\n", __func__, event);
status = app_bt_connect_callback(&p_event_data->connection_status);
break;
case GATT_ATTRIBUTE_REQUEST_EVT: /* GATT attribute request (from remote client). Event data: #wiced_bt_gatt_attribute_request_t */
printf("\n\n%s() GATT_ATTRIBUTE_REQUEST_EVT: %d type:%d\n", __func__, event, p_attr_req->opcode);
status = app_bt_server_callback(p_event_data);
break;
case GATT_GET_RESPONSE_BUFFER_EVT: /* GATT buffer request, typically sized to max of bearer mtu - 1 */
printf("\n\n%s() GATT_GET_RESPONSE_BUFFER_EVT\n", __func__);
p_event_data->buffer_request.buffer.p_app_rsp_buffer = app_bt_alloc_buffer (p_event_data->buffer_request.len_requested);
p_event_data->buffer_request.buffer.p_app_ctxt = (void*)app_bt_free_buffer;
status = WICED_BT_GATT_SUCCESS;
break;
case GATT_APP_BUFFER_TRANSMITTED_EVT: /* GATT buffer transmitted event, check \ref wiced_bt_gatt_buffer_transmitted_t*/
printf("\n\n%s() GATT_APP_BUFFER_TRANSMITTED_EVT.\n", __func__);
{
pfn_free_buffer_t pfn_free = (pfn_free_buffer_t)p_event_data->buffer_xmitted.p_app_ctxt;
/* If the buffer is dynamic, the context will point to a function to free it. */
if (pfn_free)
pfn_free(p_event_data->buffer_xmitted.p_app_data);
status = WICED_BT_GATT_SUCCESS;
}
break;
case GATT_OPERATION_CPLT_EVT: /* GATT operation complete. Event data: #wiced_bt_gatt_event_data_t */
printf("\n\n%s() GATT_OPERATION_CPLT_EVT: We are a server, nothing to do.\n", __func__);
break;
default:
printf("\n\n%s()------------------> Unhandled GATT event: %d\n\n", __func__, event);
status = WICED_BT_GATT_SUCCESS;
break;
}
return status;
}


OTA Agent Bluetooth® initialization:
The following code snippet demonstrates starting the OTA Agent for use with Bluetooth®.

/* Initialize and start the OTA Agent.
*
* The main application must:
* - Turn off the Watchdog Timer (if being used)
* cyhal_wdt_t wdt_obj;
* cyhal_wdt_init(&wdt_obj, cyhal_wdt_get_max_timeout_ms());
* cyhal_wdt_free(&wdt_obj);
* - Validate the application (if the update just happened)
* cy_ota_storage_validated();
* - Initialize Bluetooth®.
*
* */
/* Network parameters for OTA Agent. */
cy_ota_network_params_t network_params;
/* Parameters for the OTA Agent. */
cy_ota_agent_params_t ota_agent_params;
/* OTA Agent context pointer storage. */
cy_ota_context_ptr ota_context;
cy_rslt_t ota_setup(void)
{
cy_rslt_t result;
/*****************************************************************************
* This is called from the Bluetooth® callback
* Handle : HDLC_OTA_FW_UPGRADE_SERVICE_OTA_UPGRADE_CONTROL_POINT_VALUE
* Command: CY_OTA_UPGRADE_COMMAND_PREPARE_DOWNLOAD
******************************************************************************/
/* Set up parameters for starting the OTA Agent. */
memset(&network_params, 0, sizeof(network_params));
memset(&agent_params, 0, sizeof(agent_params));
/* Common network parameters. */
/* Server parameters. */
/* Initialize and start the OTA Agent. */
result = cy_ota_agent_start(&network_params, &agent_params, &ota_interfaces, &ota_context);
return result;
}


ModusToolbox OTA Code Examples

ModusToolbox OTA Example using MQTT: https://github.com/infineon/mtb-example-ota-mqtt
ModusToolbox OTA Example using HTTP: https://github.com/Infineon/mtb-example-ota-https
ModusToolbox OTA Update Bluetooth® example: https://github.com/infineon/mtb-example-btstack-freertos-cyw20829-keyboard
ModusToolbox OTA Update Bluetooth® example: https://github.com/Infineon/mtb-example-btstack-freertos-cyw20829-battery-server-ota