Kode contoh ./demos/fota_multi_file_demo.c menunjukkan cara perangkat mengunduh paket pembaruan OTA multi-file melalui HTTPS dan melakukan pembaruan OTA.
Informasi latar belakang
- Untuk informasi lebih lanjut tentang fitur pembaruan OTA, lihat Ikhtisar pembaruan OTA.
- Fitur pembaruan OTA didasarkan pada koneksi MQTT. Untuk informasi lebih lanjut tentang kode untuk koneksi MQTT, lihat Koneksi MQTT.
- Dibandingkan dengan Contoh 1
./demo/fota_posix_demo.c, contoh ini hanya berbeda pada bagian-bagian berikut:
Untuk informasi lebih lanjut tentang cara memperoleh SDK, lihat Memperoleh C Link SDK.
Langkah 1: Inisialisasi fitur OTA
- Tambahkan file header.
…… …… #include "aiot_ota_api.h" …… Konfigurasikan dependensi dasar dan output log.
aiot_sysdep_set_portfile(&g_aiot_sysdep_portfile); aiot_state_set_logcb(demo_state_logcb);- Panggil aiot_ota_init untuk membuat instans OTA.
ota_handle = aiot_ota_init(); if (NULL == ota_handle) { printf("aiot_ota_init failed\r\n"); aiot_mqtt_deinit(&mqtt_handle); return -2; }
Langkah 2: Konfigurasi fitur OTA
Panggil aiot_ota_setopt untuk mengonfigurasi opsi-opsi berikut.
- Asosiasikan handle koneksi MQTT.Penting Sebelum mengonfigurasi parameter OTA, Anda harus mengonfigurasi parameter seperti kredensial perangkat. Untuk informasi lebih lanjut, lihat Konfigurasi parameter koneksi untuk MQTT.
aiot_ota_setopt(ota_handle, AIOT_OTAOPT_MQTT_HANDLE, mqtt_handle);Item konfigurasi Contoh Deskripsi AIOT_OTAOPT_MQTT_HANDLE mqtt_handle Permintaan fitur OTA didasarkan pada koneksi MQTT. Item konfigurasi ini mengasosiasikan handle koneksi MQTT.
- Konfigurasikan callback untuk pesan instruksi pembaruan OTA.
aiot_ota_setopt(ota_handle, AIOT_OTAOPT_RECV_HANDLER, demo_ota_recv_handler);Item konfigurasi Contoh Deskripsi AIOT_OTAOPT_MQTT_HANDLER demo_ota_recv_handler Saat perangkat menerima instruksi pembaruan OTA dari IoT Platform, fungsi callback ini dipanggil.
Langkah 3: Laporkan versi perangkat saat ini
Setelah perangkat menjalin koneksi MQTT, panggil aiot_ota_report_version untuk melaporkan nomor versi saat ini dari perangkat. IoT Platform menentukan apakah pembaruan diperlukan berdasarkan nomor versi tersebut.
Dalam kode contoh berikut, nomor versi yang dilaporkan oleh perangkat sebelum pembaruan OTA adalah 1.0.0. Dalam aplikasi Anda, Anda harus memperoleh nomor versi aktual dari area konfigurasi perangkat dan memodifikasi kode sesuai kebutuhan.
Perangkat harus melaporkan nomor versinya setidaknya satu kali sebelum pembaruan 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);
}Langkah 4: Menerima instruksi pembaruan
- Setelah Anda menambahkan paket pembaruan dan memulai tugas pembaruan di Konsol IoT Platform, IoT Platform mengirim instruksi pembaruan ke perangkat.Untuk informasi lebih lanjut, lihat Menambahkan paket pembaruan.
- Perangkat memanggil aiot_mqtt_recv untuk menerima pesan. Saat sebuah pesan diidentifikasi sebagai instruksi pembaruan OTA, fungsi callback
demo_ota_recv_handlerdipanggil. - Tulis logika pemrosesan untuk fungsi callback.
Anda dapat menggunakan informasi berikut untuk menulis logika pemrosesan fungsi callback:- IoT Platform mengirim instruksi paket pembaruan OTA ke perangkat melalui topik
/ota/device/upgrade/${ProductKey}/${DeviceName}.Untuk informasi lebih lanjut tentang ${ProductKey} dan ${DeviceName}, lihat Memperoleh kredensial perangkat.
- Tipe instruksi pembaruan OTA adalah AIOT_OTARECV_FOTA.
void demo_ota_recv_handler(void *ota_handle, aiot_ota_recv_t *ota_msg, void *userdata) { switch (ota_msg->type) { case AIOT_OTARECV_FOTA: { uint32_t res = 0; uint16_t port = 443; uint32_t max_buffer_len = (8 * 1024); aiot_sysdep_network_cred_t cred; void *dl_handle = NULL; multi_download_status_t *download_status = NULL; if (NULL == ota_msg->task_desc) { break; } …… …… } - Tipe struktur data untuk pesan instruksi pembaruan OTA adalah aiot_ota_recv_t. Link SDK secara otomatis mengurai pesan instruksi pembaruan yang diterima.
- Anda dapat merujuk pada kode contoh untuk menulis logika pemrosesan fungsi callback. Untuk informasi lebih lanjut, lihat Langkah 5: Mengunduh paket pembaruan dan melakukan pembaruan OTA.
- IoT Platform mengirim instruksi paket pembaruan OTA ke perangkat melalui topik
Langkah 5: Mengunduh paket pembaruan dan melakukan pembaruan OTA
Saat fungsi demo_ota_recv_handler dipicu, downloader memulai permintaan unduh melalui HTTPS untuk mengunduh paket pembaruan dan melakukan pembaruan OTA.
- Inisialisasi downloader.
Panggil aiot_download_init untuk membuatdownloadCatatanPembaruan OTA mendukung paket pembaruan multi-file. Untuk informasi lebih lanjut, lihat Menambahkan paket pembaruan.
dl_handle = aiot_download_init(); if (NULL == dl_handle) { break; } if (NULL != ota_msg->task_desc->file_name) { printf("\r\nTotal file number is %d, current file id is %d, with file_name %s\r\n", ota_msg->task_desc->file_num, ota_msg->task_desc->file_id, ota_msg->task_desc->file_name); } printf("OTA target firmware version: %s, size: %u Bytes \r\n", ota_msg->task_desc->version, ota_msg->task_desc->size_total); if (NULL != ota_msg->task_desc->extra_data) { printf("extra data: %s\r\n", ota_msg->task_desc->extra_data); } memset(&cred, 0, sizeof(aiot_sysdep_network_cred_t)); cred.option = AIOT_SYSDEP_NETWORK_CRED_SVRCERT_CA; cred.max_tls_fragment = 16384; cred.x509_server_cert = ali_ca_cert; cred.x509_server_cert_len = strlen(ali_ca_cert);
- Konfigurasi parameter unduh.
Panggil aiot_download_setopt untuk mengonfigurasi parameter untuk tugas unduh.CatatanPembaruan OTA mendukung paket pembaruan multi-file. Saat Anda mengunduh paket, Anda harus membedakan ID, jumlah, dan progres unduh setiap file.
/* Set the download protocol to TLS. */ aiot_download_setopt(dl_handle, AIOT_DLOPT_NETWORK_CRED, (void *)(&cred)); /* Set the server port for the download. */ aiot_download_setopt(dl_handle, AIOT_DLOPT_NETWORK_PORT, (void *)(&port)); /* Set the download task information. This is obtained from the task_desc member of the ota_msg input parameter. It includes the download URL, firmware size, firmware signature, and more. */ aiot_download_setopt(dl_handle, AIOT_DLOPT_TASK_DESC, (void *)(ota_msg->task_desc)); /* Set the callback function that the SDK calls when the downloaded content arrives. */ aiot_download_setopt(dl_handle, AIOT_DLOPT_RECV_HANDLER, (void *)(demo_download_recv_handler)); /* Set the maximum cache length for a single download. The user is notified each time this memory buffer is full. */ aiot_download_setopt(dl_handle, AIOT_DLOPT_BODY_BUFFER_MAX_LEN, (void *)(&max_buffer_len)); /* Set the data to be shared between different calls of AIOT_DLOPT_RECV_HANDLER. For example, the sample stores the progress here. */ last_percent = malloc(sizeof(uint32_t)); if (NULL == last_percent) { aiot_download_deinit(&dl_handle); break; } memset(download_status, 0, sizeof(multi_download_status_t)); download_status->file_id = ota_msg->task_desc->file_id; download_status->file_num = ota_msg->task_desc->file_num; aiot_download_setopt(dl_handle, AIOT_DLOPT_USERDATA, (void *)download_status); /* If this is the first download task, report a progress of 0. */ if (0 == ota_msg->task_desc->file_id) { aiot_download_report_progress(dl_handle, 0); }
- Memulai permintaan unduh.
- Mulai thread unduh
demo_ota_download_thread.
res = pthread_create(&g_download_thread, NULL, demo_ota_download_thread, dl_handle); if (res != 0) { printf("pthread_create demo_ota_download_thread failed: %d\r\n", res); aiot_download_deinit(&dl_handle); free(download_status); } else { /* The download thread is set to the detach type. It can exit on its own after the firmware content is obtained. */ pthread_detach(g_download_thread); }
- Di dalam thread unduh
demo_ota_download_thread, panggil aiot_download_send_request untuk mengirim permintaan HTTPS GET ke server penyimpanan paket pembaruan yang ditentukan.
void *demo_ota_download_thread(void *dl_handle) { int32_t ret = 0; printf("\r\nstarting download thread in 2 seconds ......\r\n"); sleep(2); /* Request to download from the update package storage server. */ /* * TODO: The following code uses one request to get the entire firmware content. * For devices with limited resources or poor network conditions, you can also download in segments. To do this, combine the following statements: * * aiot_download_setopt(dl_handle, AIOT_DLOPT_RANGE_START, ...); * aiot_download_setopt(dl_handle, AIOT_DLOPT_RANGE_END, ...); * aiot_download_send_request(dl_handle); * * In this case, you need to place the combined statements in a loop and call send_request and recv multiple times. * */ …… …… }Anda dapat mengunduh paket pembaruan secara bertahap menggunakan AIOT_DLOPT_RANGE_START dan AIOT_DLOPT_RANGE_END.
Sebagai contoh, untuk mengunduh paket pembaruan berukuran 1024 byte dalam dua bagian, Anda dapat mengatur parameter sebagai berikut:- Bagian pertama:
AIOT_DLOPT_RANGE_START=0,AIOT_DLOPT_RANGE_END=511 - Bagian kedua:
AIOT_DLOPT_RANGE_START=512,AIOT_DLOPT_RANGE_END=1023
- Bagian pertama:
- Mulai thread unduh
- Menerima paket pembaruan.
- Setelah permintaan unduh dikirim, panggil aiot_download_recv di dalam thread unduh
demo_ota_download_threaduntuk menerima data paket pembaruan. Data yang diterima memicu fungsi callbackdemo_download_recv_handler. Di dalam fungsi callback, Anda harus menyimpan paket pembaruan yang telah diunduh ke penyimpanan lokal atau sistem file perangkat.
void *demo_ota_download_thread(void *dl_handle) { …… …… aiot_download_send_request(dl_handle); // while (1) { while (should_stop == 0) { /* Receive the firmware content from the server over the network. */ ret = aiot_download_recv(dl_handle); /* When the entire firmware is downloaded, the return value of aiot_download_recv() is STATE_DOWNLOAD_FINISHED. Otherwise, it is the number of bytes obtained in the current call. */ if (STATE_DOWNLOAD_FINISHED == ret) { printf("download completed\r\n"); break; } if (STATE_DOWNLOAD_RENEWAL_REQUEST_SENT == ret) { printf("download renewal request has been sent successfully\r\n"); continue; } if (ret <= STATE_SUCCESS) { printf("download failed, error code is %d, try to send renewal request\r\n", ret); continue; } } …… …… }
- Definisikan fungsi callback
demo_download_recv_handleruntuk menyertakan logika penyimpanan dan pembaruan paket setelah unduhan selesai.
Catatan Kode contoh hanya mencetak informasi dan tidak menyertakan logika untuk menyimpan serta membakar paket pembaruan. Anda harus menulis kode untuk menyimpan paket pembaruan berdasarkan lingkungan Anda, lalu membakar firmware untuk menyelesaikan pembaruan OTA.- Jika pembaruan OTA menggunakan paket satu file, Anda dapat membakar file tersebut ke lokasi penyimpanan lokal tertentu.
- Jika pembaruan OTA menggunakan paket multi-file, setiap file dapat sesuai dengan alamat penyimpanan yang berbeda. Anda harus mengidentifikasi bidang
file_namedari setiap firmware.
void demo_download_recv_handler(void *handle, const aiot_download_recv_t *packet, void *userdata) { uint32_t data_buffer_len = 0; int32_t last_percent = 0; int32_t percent = 0; multi_download_status_t *download_status = (multi_download_status_t *)userdata; /* Currently, only the case where packet->type is AIOT_DLRECV_HTTPBODY is supported. */ if (!packet || AIOT_DLRECV_HTTPBODY != packet->type) { return; } percent = packet->data.percent; /* userdata can store data that needs to be shared between different entries into demo_download_recv_handler(). */ /* Here, it is used to store the firmware download percentage from the last time this callback function was entered. */ if (userdata) { last_percent = (download_status->last_percent); } data_buffer_len = packet->data.len; /* If percent is negative, a packet reception exception or a digest verification error occurred. */ if (percent < 0) { printf("exception: percent = %d\r\n", percent); if (userdata) { free(userdata); } return; } …… …… }
- Setelah permintaan unduh dikirim, panggil aiot_download_recv di dalam thread unduh
- Laporkan progres unduhan.
Di dalam fungsi callback
demo_download_recv_handler, panggil aiot_download_report_progress untuk melaporkan progres unduhan dan pengecualian apa pun yang terjadi selama proses pembaruan, seperti kegagalan pembakaran atau pemutusan jaringan, ke IoT Platform.- Lihat progres yang dilaporkan:
Progres ditampilkan di Konsol IoT Platform. Untuk informasi lebih lanjut, lihat Melihat status pembaruan.
- Melaporkan progres untuk unduhan normal dan abnormal:
- Jika unduhan normal, progres unduhan dilaporkan ke IoT Platform sebagai persentase bilangan bulat. Link SDK secara otomatis menghitung nilai parameter percent dan melaporkannya ke IoT Platform.
- Jika unduhan abnormal atau terjadi pengecualian pembakaran firmware setelah unduhan, Anda harus melaporkan pengecualian tersebut ke IoT Platform. Untuk daftar kode kesalahan protokol antara perangkat dan IoT Platform, lihat aiot_ota_protocol_errcode_t.
- Metode pelaporan progres:
- Jika pembaruan OTA menggunakan paket satu file, progres yang dilaporkan adalah progres total.
- Jika pembaruan OTA menggunakan paket multi-file, jangan laporkan progres unduhan file individual karena hal ini dapat menimbulkan kebingungan. Saat melaporkan progres, kami menyarankan agar Anda menghitung persentase menggunakan ukuran total file sebagai penyebut dan jumlah total byte yang diunduh untuk semua file sebagai pembilang. Kemudian, Anda dapat melaporkan progres unduhan yang dihitung.Anda dapat mengembangkan skenario pelaporan progres paket pembaruan berdasarkan kebutuhan bisnis Anda. Sebagai contoh:
- Laporkan 0% saat unduhan dimulai. Lalu, laporkan progres hanya ketika progres unduhan total mencapai kelipatan bilangan bulat 10%, hingga 100%.
- Untuk menyederhanakan pelaporan progres, Anda dapat melaporkan 0% saat unduhan dimulai dan 100% setelah selesai. Artinya, Anda hanya melaporkan progres dua kali.
void demo_download_recv_handler(void *handle, const aiot_download_recv_t *packet, void *userdata) { …… …… /* * TODO: When a segment of firmware is successfully downloaded, the user should save the memory * starting at packet->data.buffer with a length of packet->data.len to a local storage location. * * If the burning fails, you should also call aiot_download_report_progress(handle, -4) to report the failure to IoT Platform. * Note: The error codes agreed upon with the cloud platform in the protocol are in the aiot_ota_protocol_errcode_t type. For example: * -1: indicates an update failure. * -2: indicates a download failure. * -3: indicates a verification failure. * -4: indicates a burning failure. * */ /* When the value of the percent input parameter is 100, it means the SDK has finished downloading the entire firmware content. */ if (percent == 100) { g_finished_task_num++; /* * TODO: At this point, all firmware burning should be complete. Save the current work, restart the device, and start with the new firmware. The new firmware must report the new version number to IoT Platform using the following code. For example, if updating from 1.0.0 to 1.1.0, the value of new_version is 1.1.0. aiot_ota_report_version(ota_handle, new_version); IoT Platform considers the update successful only after receiving the new version number. Otherwise, the update is considered failed. If the update fails after a successful download, you should also call aiot_download_report_progress(handle, -1) to report the failure type. */ } /* Simplified output. The progress is printed and reported to the server only when the download progress has increased by 5% or more since the last report. */ if (percent - last_percent >= 5 || percent == 100) { if (NULL != download_status) { printf("file_id %d, download %03d%% done, +%d bytes\r\n", download_status->file_id, percent, data_buffer_len); download_status->last_percent = percent; if (g_finished_task_num == download_status->file_num) { /* Considering concurrent downloads by multiple threads, report 100% progress only after all files are downloaded. */ aiot_download_report_progress(handle, 100); } } if (percent == 100 && userdata) { free(userdata); } } } - Lihat progres yang dilaporkan:
- Keluar dari downloader.
Setelah konten paket pembaruan diunduh, panggil aiot_download_deinit untuk menghapus sesi
download. Thread unduh kemudian keluar.aiot_download_deinit(&dl_handle); printf("download thread exit\n");
Langkah 6: Laporkan nomor versi setelah pembaruan
- Jika pembaruan OTA menggunakan paket satu file yang hanya berisi satu firmware, laporkan nomor versi firmware yang termasuk dalam paket tersebut ke IoT Platform untuk menyelesaikan pencocokan versi.
- Jika pembaruan OTA menggunakan paket multi-file, file-file tersebut dapat sesuai dengan satu atau beberapa firmware. Jika setiap file memiliki nomor versi firmware yang berbeda, seperti
a1,b1, danc1, laporkan nomor versi paket gabungan, sepertia1b1c1.
Untuk kode contoh pelaporan nomor versi, lihat Langkah 3: Laporkan nomor versi perangkat saat ini.
Setelah perangkat menyelesaikan pembaruan OTA, perangkat harus melaporkan nomor versi terbaru. Jika tidak, IoT Platform menganggap tugas pembaruan OTA gagal.
Jika perangkat perlu di-restart setelah pembaruan, perangkat harus melaporkan nomor versi terbaru setelah restart.
- Kode contoh tidak menyertakan logika untuk melaporkan nomor versi setelah pembaruan selesai. Anda harus menambahkan logika ini ke kode Anda.
Langkah 7: Putuskan koneksi
MQTT biasanya digunakan untuk perangkat yang memerlukan koneksi persisten. Oleh karena itu, program biasanya tidak mencapai titik ini.
Dalam program contoh, thread utama bertanggung jawab untuk mengonfigurasi parameter dan menjalin koneksi. Setelah koneksi terjalin, thread utama dapat masuk ke mode hibernasi.
Anda dapat memanggil aiot_mqtt_disconnect untuk mengirim pesan pemutusan koneksi ke IoT Platform dan memutuskan koneksi jaringan.
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;
}
Langkah 8: Keluar dari program OTA
Panggil aiot_ota_deinit untuk menghapus instans OTA.
aiot_ota_deinit(&ota_handle);Langkah selanjutnya
-
./output/fota-multi-file_demo.Untuk informasi lebih lanjut, lihat Kompilasi dan jalankan.
- Log operasi