The device firmware can be downloaded through the OTA API. Device developers need to develop their own code to burn the firmware after downloading it. For more information about OTA, visit [OTA Service](https://iot.console.aliyun.com/service/ota). We will provide two examples to show how to implement OTA throughadvancedandbasic` APIs, respectively.

Background information

The following example uses the examples/linkkit/linkkit_example_solo.c routine to describe the procedure for implementing OTA firmware updates through advanced APIs.

Procedure

Define and register the callback function to be used after users receive a firmware update message.

Result

/* Define the callback function */
static int user_fota_event_handler(int type, const char *version)
{
    char buffer[128] = {0};
    int buffer_length = 128;
    user_example_ctx_t *user_example_ctx = user_example_get_ctx();

    if (type == 0) {
        EXAMPLE_TRACE("New Firmware Version: %s", version);

        IOT_Linkkit_Query(user_example_ctx->master_devid, ITM_MSG_QUERY_FOTA_DATA, (unsigned char *)buffer, buffer_length);
    }

    return 0;
}

/* Register the callback function */
int linkkit_main(void *paras)
{
...
IOT_RegisterCallback(ITE_FOTA, user_fota_event_handler);
...
}
  1. Configure the trituple
    memset(&master_meta_info, 0, sizeof(iotx_linkkit_dev_meta_info_t));
    memcpy(master_meta_info.product_key, PRODUCT_KEY, strlen(PRODUCT_KEY));
    memcpy(master_meta_info.product_secret, PRODUCT_SECRET, strlen(PRODUCT_SECRET));
    memcpy(master_meta_info.device_name, DEVICE_NAME, strlen(DEVICE_NAME));
    memcpy(master_meta_info.device_secret, DEVICE_SECRET, strlen(DEVICE_SECRET));
  1. Call the IOT_Ioctl() function to configure the connection to the cloud. For more information, see the corresponding API description.
/* Choose Logon Server, domain should be configured before IOT_Linkkit_Open() */
#if USE_CUSTOME_DOMAIN
    IOT_Ioctl(IOTX_IOCTL_SET_MQTT_DOMAIN, (void *)CUSTOME_DOMAIN_MQTT);
    IOT_Ioctl(IOTX_IOCTL_SET_HTTP_DOMAIN, (void *)CUSTOME_DOMAIN_HTTP);
#else
    int domain_type = IOTX_CLOUD_REGION_SHANGHAI;
    IOT_Ioctl(IOTX_IOCTL_SET_DOMAIN, (void *)&domain_type);
#endif

    /* Choose logon method */
    int dynamic_register = 0;
    IOT_Ioctl(IOTX_IOCTL_SET_DYNAMIC_REGISTER, (void *)&dynamic_register);
  1. Establish a connection.
user_example_ctx->master_devid = IOT_Linkkit_Open(IOTX_LINKKIT_DEV_TYPE_MASTER, &master_meta_info);
    if (user_example_ctx->master_devid < 0) {
        EXAMPLE_TRACE("IOT_Linkkit_Open Failed\n");
        return -1;
    }

    /* Start Connect Aliyun Server */
    res = IOT_Linkkit_Connect(user_example_ctx->master_devid);
    If (RES <0 ){
        EXAMPLE_TRACE("IOT_Linkkit_Connect Failed\n");
        return -1;
    }

Because IOT_Linkkit_Connect has subscribed to the topic related to firmware updates, the device side will receive firmware update messages published by the server, and OTA will be implemented.

  1. Wait for the server to publish a firmware update message. When the device side receives the firmware update message, the callback function user_fota_event_handler is triggered. You can view the logs printed for the function.
while (1) {
        IOT_Linkkit_Yield(USER_EXAMPLE_YIELD_TIMEOUT_MS);
        ...
    }
  1. Implement the firmware storage.

Before the download starts, the Link Kit SDK calls the HAL_Firmware_Persistence_Start function to open the firmware file and obtain a writable FD. When the download starts, the Link Kit SDK calls the HAL_Firmware_Persistence_Write function to store the firmware file. After the download is finished, the Link Kit SDK calls the HAL_Firmware_Persistence_Stop function to close the firmware file. To implement OTA through advanced APIs, you only need to implement these three HAL functions to implement the firmware storage. However, after the firmware is stored, you still need to develop code to implement how to use the new firmware (for example, specifying the time to initiate a restart to load the new firmware).

Routine used to implement OTA through basic APIs

The following example uses the examples/ota/ota_mqtt-example.c routine to describe the procedure for implementing OTA through basic APIs.Implementing OTA through basic APIs is more complicated than implementing OTA through advanced APIs. We recommend that you use advanced APIs for OTA implementation.

  1. Before establishing OTA, import the device trituple, and initialize the connection.
/**< get device info*/
    HAL_GetProductKey(g_product_key);
    HAL_GetDeviceName(g_device_name);
    HAL_GetDeviceSecret(g_device_secret);
    /**< end*/

    /* Device AUTH */
    if (0 != IOT_SetupConnInfo(g_product_key, g_device_name, g_device_secret, (void **)&pconn_info)) {
        EXAMPLE_TRACE("AUTH request failed!") ;
        rc = -1;
        goto do_exit;
    }
  1. Configure the MQTT parameters, create an MQTT session, and establish a connection to the cloud server.
/* Initialize MQTT parameter */
    memset(&mqtt_params, 0x0, sizeof(mqtt_params));

    mqtt_params.port = pconn_info->port;
    mqtt_params.host = pconn_info->host_name;
    mqtt_params.client_id = pconn_info->client_id;
    mqtt_params.username = pconn_info->username;
    mqtt_params.password = pconn_info->password;
    mqtt_params.pub_key = pconn_info->pub_key;

    mqtt_params.request_timeout_ms = 2000;
    mqtt_params.clean_session = 0;
    mqtt_params.keepalive_interval_ms = 60000;
    mqtt_params.read_buf_size = OTA_MQTT_MSGLEN;
    mqtt_params.write_buf_size = OTA_MQTT_MSGLEN;

    mqtt_params.handle_event.h_fp = event_handle;
    mqtt_params.handle_event.pcontext = NULL;


    /* Construct an MQTT client with specify parameter */
    pclient = IOT_MQTT_Construct(&mqtt_params);
    if (NULL == pclient) {
        EXAMPLE_TRACE("MQTT construct failed");
        rc = -1;
        goto do_exit;
    }
  1. Perform OTA initialization. The main purpose is to subscribe to the firmware update message related to the current device.
h_ota = IOT_OTA_Init(PRODUCT_KEY, DEVICE_NAME, pclient);
    if (NULL == h_ota) {
        rc = -1;
        EXAMPLE_TRACE("initialize OTA failed");
        goto do_exit;
    }
  1. Set up a loop to keep receiving an OTA firmware update message.
int ota_over = 0;
    do {
        uint32_t firmware_valid;

        EXAMPLE_TRACE("wait ota upgrade command....") ;

        /* Receive MQTT messages */
        IOT_MQTT_Yield(pclient, 200);

        /* Determine whether a firmware update message has been received */
        if (IOT_OTA_IsFetching(h_ota)) {
         /* Download the OTA content and report the download progress: See step 5 */
         /* Verify the MD5 value of the firmware: See step 6 */
        }

        } while (! ota_over);

The firmware update logic can only be triggered if the return value of the IOT_OTA_IsFetching function is 1. To achieve this, you need to configure the server to deliver a firmware update event as follows:Open the OTA Service and click “Add Firmware.”Click “Create Firmware” and then “Verify Firmware.”Click “Batch Upgrade” for the new firmware and select the product type of the current device. The product type is the same as that specified by the trituple in the examples/ota/ota_mqtt-example.c routine.To upgrade the version number, select the current version number from the drop-down list. Choose “Direct Upgrade” for “Upgrade Scope,” and select the device specified by the trituple for “Device Range.” Finally, click OK.

  1. Download the OTA content and report the download progress.
do {
        /* Download the OTA firmware */
        len = IOT_OTA_FetchYield(h_ota, buf_ota, OTA_BUF_LEN, 1);
        if (len > 0) {
            if (1 ! = fwrite(buf_ota, len, 1, fp)) {
                EXAMPLE_TRACE("write data to file failed");
                rc = -1;
                break;
            }
        } else {
            /* Report the download progress */
            IOT_OTA_ReportProgress(h_ota, IOT_OTAP_FETCH_FAILED, NULL);
            EXAMPLE_TRACE("ota fetch fail");
        }

        /* get OTA information */
        /* Obtain the amount of data downloaded, total file size, MD5 information, and version number */
        IOT_OTA_Ioctl(h_ota, IOT_OTAG_FETCHED_SIZE, &size_downloaded, 4);
        IOT_OTA_Ioctl(h_ota, IOT_OTAG_FILE_SIZE, &size_file, 4);
        IOT_OTA_Ioctl(h_ota, IOT_OTAG_MD5SUM, md5sum, 33);
        IOT_OTA_Ioctl(h_ota, IOT_OTAG_VERSION, version, 128);

        last_percent = percent;
        percent = (size_downloaded * 100) / size_file;
        if (percent - last_percent > 0) {
            /* Report the download progress */
            IOT_OTA_ReportProgress(h_ota, percent, NULL);
            IOT_OTA_ReportProgress(h_ota, percent, "hello");
        }
        IOT_MQTT_Yield(pclient, 100);
        /* Determine whether the download is complete */
    } while (! IOT_OTA_IsFetchFinish(h_ota));
  1. Verify the MD5 value.
IOT_OTA_Ioctl(h_ota, IOT_OTAG_CHECK_FIRMWARE, &firmware_valid, 4);
    if (0 == firmware_valid) {
        EXAMPLE_TRACE("The firmware is invalid");
    } else {
        EXAMPLE_TRACE("The firmware is valid");
    }

    ota_over = 1;
  1. Use the IOT_OTA_Deinit function to release all resources.
if (NULL ! = h_ota) {
        IOT_OTA_Deinit(h_ota);
    }

    if (NULL ! = pclient) {
        IOT_MQTT_Destroy(&pclient);
    }

    if (NULL ! = msg_buf) {
        HAL_Free(msg_buf);
    }

    if (NULL ! = msg_readbuf) {
        HAL_Free(msg_readbuf);
    }

    if (NULL ! = fp) {
        fclose(fp);
    }

    return rc;
  1. Implement the firmware storage.

Use the _ota_mqtt_client function to open, write, and close a file in the following way:

fp = fopen("ota.bin", "wb+")
...
if (1 ! = fwrite(buf_ota, len, 1, fp)) {
    EXAMPLE_TRACE("write data to file failed");
    rc = -1;
    break;
}
...
if (NULL ! = fp) {
    fclose(fp);
}

Basic APIs used to implement OTA

Function name Description
IOT_OTA_Init The constructor of an OTA instance. This API creates a handle for an OTA session and returns a value.
IOT_OTA_Deinit The destructor of an OTA instance. This API destroys all relevant data structures.
IOT_OTA_Ioctl The I/O function of an OTA instance. This API sets the properties of an OTA session based on different command words, or obtains the status of the OTA session.
IOT_OTA_GetLastError If an IOT_OTA_XXX() function returns an error within an OTA session, you can call this API to obtain the most recent error code.
IOT_OTA_ReportVersion Reports the version number of the specified firmware to the server.
IOT_OTA_FetchYield This API downloads a segment of firmware content from the firmware server within the specified timeout period and stores the firmware in the input parameter buffer during the OTA download.
IOT_OTA_IsFetchFinish This API checks whether the firmware download is completed by continually calling the IOT_OTA_FetchYield() function during the OTA download.
IOT_OTA_IsFetching Checks whether the firmware download is still in progress.
IOT_OTA_ReportProgress Reports the percentage of the firmware that has been downloaded to the server. This function is optional.

Advanced APIs used to implement OTA

Function name Description
IOT_Linkkit_Open This API is used to create local resources. This API must be called to obtain a session handle before messages can be exchanged over the network.
IOT_Linkkit_Connect For a primary device or gateway, this API connects the primary device to the cloud server. For a sub-device, this API registers the sub-device with the cloud server (if required) and adds the topological relationship between the primary device and the sub-device.
IOT_Linkkit_Yield If the SDK uses a detached thread, this API only distributes the received network messages to the callback function. Otherwise, the SDK uses CPU to receive network messages and distribute them to the callback function.
IOT_Linkkit_Close If the session handle in the input parameter indicates the primary device or gateway, this API closes the network connection and releases all resources occupied by the SDK for the session.
IOT_Linkkit_TriggerEvent This API sends event messages such as error codes and abnormal alarms to the cloud.
IOT_Linkkit_Report This API sends various uplink messages without cloud business data distribution to the cloud, including messages related to attribute values, device labels, binary transparent data, and sub-device management.
IOT_Linkkit_Query This API sends various query messages with cloud business data distribution to the cloud, including messages related to OTA status query, OTA firmware download, sub-device topology query, and NTP time query.

HAL functions to be implemented

HAL functions to be implemented when implementing OTA through basic APIs

None

HAL functions to be implemented when implementing OTA through advanced APIs

Function name Description
HAL_Firmware_Persistence_Start Starts firmware persistence. This function must be implemented to use OTA.
HAL_Firmware_Persistence_Stop Stops firmware persistence. This function must be implemented to use OTA.
HAL_Firmware_Persistence_Write Performs a firmware persistence write. This function must be implemented to use OTA.

HAL implementation example

static FILE *fp;
#define otafilename "/tmp/alinkota.bin"
void HAL_Firmware_Persistence_Start(void)
{
#ifdef __DEMO__
    fp = fopen(otafilename, "w");
    //    assert(fp);
#endif
    return;
}

int HAL_Firmware_Persistence_Stop(void)
{
#ifdef __DEMO__
    if (fp ! = NULL) {
        fclose(fp);
    }
#endif

    /* Check file md5 and burning it to flash, then reboot the system */

    return 0;
}

int HAL_Firmware_Persistence_Write(_IN_ char *buffer, _IN_ uint32_t length)
{
#ifdef __DEMO__
    unsigned int written_len = 0;
    written_len = fwrite(buffer, 1, length, fp);

    if (written_len ! = length) {
        return -1;
    }
#endif
    return 0;
}