全部產品
Search
文件中心

:範例程式碼說明

更新時間:Jun 30, 2024

./demos/mota_basic_demo.c協助裝置端使用MQTT協議,下載僅含單個升級檔案的OTA升級包,實現裝置的OTA升級。

背景資訊

  • OTA升級功能的更多資訊,請參見OTA升級概述

  • OTA升級功能基於MQTT接入,開發過程中涉及MQTT接入的代碼說明,請參見MQTT接入

步驟一:初始化OTA功能

  1. 添加標頭檔。
    ……
    ……
    #include "aiot_ota_api.h"
    #include "aiot_mqtt_download_api.h"
    ……


  2. /* 位於portfiles/aiot_port檔案夾下的系統適配函數集合 */
    extern aiot_sysdep_portfile_t g_aiot_sysdep_portfile;
    
    /* TODO: 如果要關閉日誌, 則將該函數實現為空白, 如果要減少日誌, 可根據code選擇不列印
     * 例如: [1578463098.611][LK-0309] pub: /ota/device/upgrade/a13FN******/ota_demo
     * 上述該條日誌的code為0309(十六進位), code值的定義見core/aiot_state_api.h
     */
    
    /* 日誌回呼函數, SDK的日誌從此處輸出 */
    int32_t demo_state_logcb(int32_t code, char *message)
    {
        printf("%s", message);
        return 0;
    }

  3. 調用aiot_ota_init,建立OTA
        ota_handle = aiot_ota_init();
        if (NULL == ota_handle) {
            goto exit;
        }

步驟二:配置OTA功能

調用aiot_ota_setopt,配置以下功能。

  1. 關聯MQTT串連的控制代碼。

    重要

    在配置OTA參數前,請確保已配置裝置認證資訊等相關參數。具體操作,請參見MQTT配置串連參數

    •     aiot_ota_setopt(ota_handle, AIOT_OTAOPT_MQTT_HANDLE, mqtt_handle);
    • 配置項

      樣本

      說明

      AIOT_OTAOPT_MQTT_HANDLE

      mqtt_handle

      OTA功能的請求基於MQTT串連,通過該配置項,關聯MQTT串連控制代碼。

  2. 配置OTA升級指令訊息的回調。
    •     aiot_ota_setopt(ota_handle, AIOT_OTAOPT_RECV_HANDLER, user_ota_recv_handler);
    • 配置項樣本說明

      AIOT_OTAOPT_MQTT_HANDLER

      user_ota_recv_handler

      當裝置收到來自物聯網平台的OTA升級指令,調用該回呼函數。


步驟三:上報裝置目前的版本號

裝置建立MQTT串連後,調用aiot_ota_report_version,上報當前裝置的版本號碼。物聯網平台根據版本號碼,判斷是否需要升級。

以下範例程式碼中,OTA升級前裝置上報的版本號碼為1.0.0,在實際業務中,您需從裝置的配置區擷取實際的版本號碼,並執行編寫代碼。

重要

裝置進行OTA升級前,需至少上報一次版本號碼。

    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);
    }

步驟四:接收升級指令

  1. 在物聯網平台添加升級包,並發起升級任務後,物聯網平台向裝置端下發升級指令。

    具體操作,請參見添加升級包

  2. 裝置端調用aiot_mqtt_recv接收訊息,當訊息被識別為OTA升級指令後,調用回呼函數user_ota_recv_handler,執行對應的處理邏輯。
  3. 編寫回呼函數的處理邏輯。
    您可以參考以下內容,編寫回呼函數的處理邏輯:
    • 物聯網平台通過Topic /ota/device/upgrade/${ProductKey}/${DeviceName},向裝置下發OTA升級包指令。

      ${ProductKey}${DeviceName}的詳細說明,請參見擷取裝置認證資訊

    • OTA升級指令的類型為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;
              }
           ……
           ……
      
      }
    • OTA升級指令訊息的Alink資料格式說明,請參見物聯網平台推送OTA升級包資訊

    • OTA升級指令訊息的資料結構類型為aiot_ota_recv_t,Link SDK自動解析收到的升級指令訊息。

    • 您可以參考範例程式碼,編寫回呼函數的處理邏輯,請參見步驟五的步驟1至2。

步驟五:下載升級包,進行OTA升級

重要

裝置端收到物聯網平台推送的升級包訊息後,不會自動下載升級包,您需要調用Link SDK提供的API啟動下載。

觸發函數user_ota_recv_handler後,基於MQTT協議,下載器發起下載請求,然後接收物聯網平台返回的升級包,進行OTA升級。

  1. 初始化下載器。
    調用aiot_mqtt_download_init,建立download
    void 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();
    
         ……
         ……
    
    }

  2. 配置下載參數。
    調用aiot_mqtt_download_setopt,配置下載任務的相關參數。
    •         aiot_mqtt_download_setopt(md_handler, AIOT_MDOPT_TASK_DESC, ota_msg->task_desc);
              /* 設定下載一包的大小,對於資源受限裝置可以調整該值大小 */
              aiot_mqtt_download_setopt(md_handler, AIOT_DLOPT_DATA_REQUEST_SIZE, &request_size);
      
              /* 分段下載升級包,或僅下載升級包的片段時,每個分段的起始和終止位置的位元組序號。
               * 若設定範圍區間下載,單包報文的資料有CRC校正,但SDK將不進行完整檔案MD5校正,
               * 預設下載全部檔案,單包報文的資料有CRC校正,且SDK將進行完整檔案MD5校正 
               * 若取消下列代碼注釋,表示僅從檔案的第10位元組開始下載,下載至第50KB的第10位元組為止。/
              // 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;
    • 配置項樣本說明
      AIOT_MDOPT_TASK_DESCota_msg->task_desc設定下載任務。
      AIOT_DLOPT_DATA_REQUEST_SIZErequest_size每次向物聯網平台請求的單包資料大小。
      AIOT_MDOPT_RANGE_STARTrange_start分段下載升級包,或僅下載升級包的片段時,每個分段的起始和終止位置的位元組序號。

      如果不設定,表示一次下載全部檔案。

      例如,一個1024位元組的升級包分兩次下載,兩次的參數可分別設定為:

      • 第一次:AIOT_DLOPT_RANGE_START=0AIOT_DLOPT_RANGE_END=511

      • 第二次:AIOT_DLOPT_RANGE_START=512AIOT_DLOPT_RANGE_END=1023

      AIOT_MDOPT_RANGE_ENDrange_end
      AIOT_MDOPT_RECV_HANDLEuser_download_recv_handler配置OTA升級包內容的回調。

      裝置發起下載請求後,物聯網平台返回升級包內容的訊息時,觸發該回呼函數。


  3. 調用aiot_mqtt_download_process,向物聯網平台發送下載請求。
        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);
         ……
         ……
    
            }
        }
                            
  4. 物聯網平台接收下載請求後,向裝置返回升級包資訊,裝置接收訊息後,觸發回呼函數user_download_recv_handler
    您需編寫回呼函數的處理邏輯,將下載的升級包資料固化至本地。
    void user_download_recv_handler(void *handle, const aiot_mqtt_download_recv_t *packet, void *userdata)
    {
        uint32_t data_buffer_len = 0;
    
        /* 目前只支援packet->type為AIOT_MDRECV_DATA_RESP的情況 */
        if (!packet || AIOT_MDRECV_DATA_RESP != packet->type) {
            return;
        }
    
        /* 應在此實現檔案本地固化的操作 */
        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);
    }
  5. 升級包檔案下載完成後,調用aiot_mqtt_download_deinit退出程式。
        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) {
                    /* 升級成功,可在此處重啟並且上報新的版本號碼 */
                    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;
                }
            }
        }

步驟六:上報升級後版本號碼

上報版本號碼的範例程式碼,請參見步驟三:上報裝置目前的版本號

說明
  • 裝置完成OTA升級後,需上報最新版本號碼,否則物聯網平台視該OTA升級任務為失敗。

  • 如果裝置升級後需重啟,則裝置重啟後需上報最新的版本號碼。

  • 範例程式碼中不包含升級完成後重新上報版本號碼的過程,您需自行實現。

步驟七:中斷連線

調用aiot_mqtt_disconnect,向物聯網平台發送中斷連線的報文,然後斷開網路連接。

    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;
    }

步驟八:退出OTA程式

調用aiot_ota_deinit,銷毀OTA

    aiot_ota_deinit(&ota_handle);

後續步驟