./demos/mota_basic_demo.c
協助裝置端使用MQTT協議,下載僅含單個升級檔案的OTA升級包,實現裝置的OTA升級。
背景資訊
步驟一:初始化OTA功能
- 添加標頭檔。
…… …… #include "aiot_ota_api.h" #include "aiot_mqtt_download_api.h" ……
/* 位於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; }
- 調用aiot_ota_init,建立OTA
ota_handle = aiot_ota_init(); if (NULL == ota_handle) { goto exit; }
步驟二:配置OTA功能
調用aiot_ota_setopt,配置以下功能。
關聯MQTT串連的控制代碼。
重要在配置OTA參數前,請確保已配置裝置認證資訊等相關參數。具體操作,請參見MQTT配置串連參數。
aiot_ota_setopt(ota_handle, AIOT_OTAOPT_MQTT_HANDLE, mqtt_handle);
配置項
樣本
說明
AIOT_OTAOPT_MQTT_HANDLE
mqtt_handle
OTA功能的請求基於MQTT串連,通過該配置項,關聯MQTT串連控制代碼。
- 配置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);
}
步驟四:接收升級指令
在物聯網平台添加升級包,並發起升級任務後,物聯網平台向裝置端下發升級指令。
具體操作,請參見添加升級包。
- 裝置端調用aiot_mqtt_recv接收訊息,當訊息被識別為OTA升級指令後,調用回呼函數
user_ota_recv_handler
,執行對應的處理邏輯。 - 編寫回呼函數的處理邏輯。您可以參考以下內容,編寫回呼函數的處理邏輯:
物聯網平台通過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升級。
- 初始化下載器。調用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(); …… …… }
- 配置下載參數。調用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_DESC ota_msg->task_desc 設定下載任務。 AIOT_DLOPT_DATA_REQUEST_SIZE request_size 每次向物聯網平台請求的單包資料大小。 AIOT_MDOPT_RANGE_START range_start 分段下載升級包,或僅下載升級包的片段時,每個分段的起始和終止位置的位元組序號。 如果不設定,表示一次下載全部檔案。
例如,一個1024位元組的升級包分兩次下載,兩次的參數可分別設定為:
第一次:
AIOT_DLOPT_RANGE_START=0
,AIOT_DLOPT_RANGE_END=511
第二次:
AIOT_DLOPT_RANGE_START=512
,AIOT_DLOPT_RANGE_END=1023
AIOT_MDOPT_RANGE_END range_end AIOT_MDOPT_RECV_HANDLE user_download_recv_handler 配置OTA升級包內容的回調。 裝置發起下載請求後,物聯網平台返回升級包內容的訊息時,觸發該回呼函數。
- 調用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); …… …… } }
- 物聯網平台接收下載請求後,向裝置返回升級包資訊,裝置接收訊息後,觸發回呼函數
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); }
- 升級包檔案下載完成後,調用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);