The ./demos/mota_basic_demo.c file shows how a device uses MQTT to download an OTA update package that contains a single update file and perform the update.
Background information
- For more information about the OTA update feature, see OTA update overview.
- The OTA update feature is based on an MQTT connection. For more information about the code for an MQTT connection, see MQTT connection.
Step 1: Initialize the OTA feature
- Add the header files.
…… …… #include "aiot_ota_api.h" #include "aiot_mqtt_download_api.h" ……
/* A collection of system adaptation functions in the portfiles/aiot_port directory */ extern aiot_sysdep_portfile_t g_aiot_sysdep_portfile; /* TODO: To disable logs, implement this function as an empty function. To reduce logs, you can choose not to print logs based on the code. * For example: [1578463098.611][LK-0309] pub: /ota/device/upgrade/a13FN******/ota_demo * The code for the preceding log is 0309 (hexadecimal). For more information about code values, see core/aiot_state_api.h. */ /* This is a log callback function. The SDK logs are output from here. */ int32_t demo_state_logcb(int32_t code, char *message) { printf("%s", message); return 0; }
- Call aiot_ota_init to create an OTA handle.
ota_handle = aiot_ota_init(); if (NULL == ota_handle) { goto exit; }
Step 2: Configure the OTA feature
Call aiot_ota_setopt to configure the following options.
- Associate the handle of the MQTT connection.Important Before you configure OTA parameters, you must configure parameters such as device credentials. For more information, see Configure connection parameters for MQTT.
aiot_ota_setopt(ota_handle, AIOT_OTAOPT_MQTT_HANDLE, mqtt_handle);Configuration item Example Description AIOT_OTAOPT_MQTT_HANDLE mqtt_handle OTA feature requests are based on MQTT connections. This configuration item associates the MQTT connection handle.
- Configure the callback for OTA update instruction messages.
aiot_ota_setopt(ota_handle, AIOT_OTAOPT_RECV_HANDLER, user_ota_recv_handler);-
Configuration item Example Description AIOT_OTAOPT_MQTT_HANDLERuser_ota_recv_handler When the device receives an OTA update instruction from IoT Platform, this callback function is called.
Step 3: Report the current device version
After the device establishes an MQTT connection, call aiot_ota_report_version to report the current version number of the device. IoT Platform determines whether an update is required based on the version number.
In the following sample code, the version number reported by the device before the OTA update is 1.0.0. In your application, you must obtain the actual version number from the device's configuration area and modify the code accordingly.
The device must report its version number at least once before an OTA update.
cur_version = "1.0.0";
res = aiot_ota_report_version(ota_handle, cur_version);
if (res < STATE_SUCCESS) {
printf("aiot_ota_report_version failed: -0x%04X\r\n", -res);
}Step 4: Receive the update instruction
- After you add an update package and start an update task in the IoT Platform console, IoT Platform sends an update instruction to the device.For more information, see Add an update package.
- The device calls aiot_mqtt_recv to receive messages. When a message is identified as an OTA update instruction, the
user_ota_recv_handlercallback is invoked to process the instruction. - Write the processing logic for the callback function.
Write the processing logic for the callback function based on the following information:- IoT Platform sends OTA update package instructions to the device over the topic
/ota/device/upgrade/${ProductKey}/${DeviceName}.For more information about ${ProductKey} and ${DeviceName}, see Obtain device credentials.
- The type of the OTA update instruction is AIOT_OTARECV_FOTA.
void user_ota_recv_handler(void *ota_handle, aiot_ota_recv_t *ota_msg, void *userdata) { uint32_t request_size = 10 * 1024; switch (ota_msg->type) { case AIOT_OTARECV_FOTA: { if (NULL == ota_msg->task_desc || ota_msg->task_desc->protocol_type != AIOT_OTA_PROTOCOL_MQTT) { break; } …… …… } - For information about the Alink data format of OTA update instruction messages, see IoT Platform pushes OTA update package information.
- The data structure type for OTA update instruction messages is aiot_ota_recv_t. Link SDK automatically parses the received update instruction messages.
- To write the processing logic for the callback function, seeStep 5.
- IoT Platform sends OTA update package instructions to the device over the topic
Step 5: Download the update package and perform the OTA update
After user_ota_recv_handler is triggered, the downloader sends an MQTT-based download request to receive the update package from IoT Platform and perform the OTA update.
- Initialize the downloader.
Call aiot_mqtt_download_init to create adownloadvoid user_ota_recv_handler(void *ota_handle, aiot_ota_recv_t *ota_msg, void *userdata) { …… …… printf("OTA target firmware version: %s, size: %u Bytes\r\n", ota_msg->task_desc->version, ota_msg->task_desc->size_total); void *md_handler = aiot_mqtt_download_init(); …… …… }
- Configure download parameters.
Call aiot_mqtt_download_setopt to configure parameters for the download task.aiot_mqtt_download_setopt(md_handler, AIOT_MDOPT_TASK_DESC, ota_msg->task_desc); /* Set the size of a download package. You can adjust this value for resource-constrained devices. */ aiot_mqtt_download_setopt(md_handler, AIOT_DLOPT_DATA_REQUEST_SIZE, &request_size); /* The start and end byte numbers for each segment when you download an update package in segments or download only a fragment of the package. * If you set a range for the download, the data in a single message has a cyclic redundancy check (CRC), but the SDK does not perform a full file MD5 validation. * By default, the entire file is downloaded. The data in a single message has a CRC, and the SDK performs a full file MD5 validation. * If you uncomment the following code, the download starts from the 10th byte of the file and ends at the 10th byte of the 50th kilobyte. */ // uint32_t range_start = 10, range_end = 50 * 1024 + 10; // aiot_mqtt_download_setopt(md_handler, AIOT_MDOPT_RANGE_START, &range_start); // aiot_mqtt_download_setopt(md_handler, AIOT_MDOPT_RANGE_END, &range_end); aiot_mqtt_download_setopt(md_handler, AIOT_MDOPT_RECV_HANDLE, user_download_recv_handler); g_dl_handle = md_handler;-
Configuration item Example Description AIOT_MDOPT_TASK_DESC ota_msg->task_desc Specifies the download task. AIOT_DLOPT_DATA_REQUEST_SIZE request_size The size of each data package requested from IoT Platform. AIOT_MDOPT_RANGE_START range_start The start and end byte numbers for each segment when you download an update package in segments or download only a fragment of the package. If this is not set, the entire file is downloaded at once.
For example, to download a 1024-byte update package in two parts, you can set the parameters as follows:- First part:
AIOT_DLOPT_RANGE_START=0,AIOT_DLOPT_RANGE_END=511 - Second part:
AIOT_DLOPT_RANGE_START=512,AIOT_DLOPT_RANGE_END=1023
AIOT_MDOPT_RANGE_END range_end AIOT_MDOPT_RECV_HANDLE user_download_recv_handler Specifies the callback for receiving OTA update package data. This callback is triggered when IoT Platform returns a message with the update package content after the device initiates a download request.
- First part:
- Call aiot_mqtt_download_process to send a download request to IoT Platform.
while (1) { aiot_mqtt_process(mqtt_handle); aiot_mqtt_recv(mqtt_handle); if(g_dl_handle != NULL) { int32_t res = aiot_mqtt_download_process(g_dl_handle); …… …… } } - After IoT Platform receives the download request, it returns the update package to the device. When the device receives the package data, the
user_download_recv_handlercallback is triggered.Write the processing logic for the callback function to save the downloaded update package data to a local file.void user_download_recv_handler(void *handle, const aiot_mqtt_download_recv_t *packet, void *userdata) { uint32_t data_buffer_len = 0; /* Currently, only the case where packet->type is AIOT_MDRECV_DATA_RESP is supported. */ if (!packet || AIOT_MDRECV_DATA_RESP != packet->type) { return; } /* The operation to persist the file locally should be implemented here. */ FILE *file = fopen("mota_demo.bin", "ab"); fwrite(packet->data.data_resp.data, packet->data.data_resp.data_size, sizeof(int8_t), file); fclose(file); data_buffer_len = packet->data.data_resp.data_size; printf("download %03d%% done, +%d bytes\r\n", packet->data.data_resp.percent, data_buffer_len); } - After the update package is downloaded, call aiot_mqtt_download_deinit to release the downloader resources.
while (1) { aiot_mqtt_process(mqtt_handle); aiot_mqtt_recv(mqtt_handle); if(g_dl_handle != NULL) { int32_t res = aiot_mqtt_download_process(g_dl_handle); if(STATE_MQTT_DOWNLOAD_SUCCESS == res) { /* The update is successful. You can restart the device and report the new version number here. */ printf("mqtt download ota success \r\n"); aiot_mqtt_download_deinit(&g_dl_handle); break; } else if(STATE_MQTT_DOWNLOAD_FAILED_RECVERROR == res || STATE_MQTT_DOWNLOAD_FAILED_TIMEOUT == res || STATE_MQTT_DOWNLOAD_FAILED_MISMATCH == res) { printf("mqtt download ota failed \r\n"); aiot_mqtt_download_deinit(&g_dl_handle); break; } } }
Step 6: Report the version number after the update
For sample code on how to report the version number, see Step 3: Report the current device version number.
After the device completes the OTA update, it must report the latest version number. Otherwise, IoT Platform considers the OTA update task to have failed.
If the device needs to be restarted after the update, it must report the latest version number after the restart.
- The sample code does not include the logic for reporting the version number after the update is complete. You must add this logic to your code.
Step 7: Disconnect
You can call aiot_mqtt_disconnect to send a disconnection message to IoT Platform and disconnect from the network.
res = aiot_mqtt_disconnect(mqtt_handle);
if (res < STATE_SUCCESS) {
aiot_mqtt_deinit(&mqtt_handle);
printf("aiot_mqtt_disconnect failed: -0x%04X\n", -res);
return -1;
}
Step 8: Exit the OTA program
Call aiot_ota_deinit to destroy the OTA instance.
aiot_ota_deinit(&ota_handle);What to do next
./demos/mota-basic-demodemo.For more information, see Compile and run.
- Operational logs.