HTTPS経由で複数のファイルを含む無線 (OTA) 更新パッケージをダウンロードし、デバイスで更新を実行します。、。/demo/fota_multi_file_demo.c
サンプルコードファイルは使用されん。
背景情報
SDKの取得方法の詳細については、「SDKの取得」をご参照ください。
ステップ1: クライアントの初期化
ヘッダーファイルの追加
... …… # 「aiot_ota_api.h」を含む ……
基になる依存関係を追加し、ログ出力機能を設定します。
aiot_sysdep_set_portfile(&g_aiot_sysdep_portfile); aiot_state_set_logcb(demo_state_logcb);
aiot_ota_init操作を呼び出してOTAを作成
ota_handle = aiot_ota_init(); if (NULL == ota_handle) { printf("aiot_ota_init failed\r\n"); aiot_mqtt_deinit(&mqtt_handle); リターン-2; }
ステップ2: 必要な機能の設定
aiot_ota_setopt操作を呼び出して、次の項目を設定します。
MQTT接続ハンドルに関連付けます。
重要OTA更新固有のパラメーターを設定する前に、デバイス認証情報が指定されていることを確認してください。 詳細については、「例」をご参照ください。
aiot_ota_setopt(ota_handle, AIOT_OTAOPT_MQTT_HANDLE, mqtt_handle);
パラメーター
例
説明
AIOT_OTAOPT_MQTT_HANDLE
mqtt_handle
MQTT接続を確立する必要があります。 このパラメータは、MQTT接続ハンドルに関連付けるために使用されます。
OTA更新コマンドを処理するようにコールバックを設定します。
aiot_ota_setopt(ota_handle、AIOT_OTAOPT_RECV_HANDLER、demo_ota_recv_handler);
パラメーター
例
説明
AIOT_OTAOPT_MQTT_HANDLER
demo_ota_recv_handler
このコールバック関数は、デバイスがIoT PlatformからOTA更新コマンドを受信したときに呼び出されます。
ステップ3: デバイスのバージョン番号を送信する
デバイスがIoT PlatformとのMQTT接続を確立した後、aiot_ota_report_version操作を呼び出して、デバイスのバージョン番号を送信します。 IoT Platformは、バージョン番号に基づいて更新が必要かどうかを判断します。
この例では、送信されたバージョン番号は1.0.0
です。 実際のビジネスシナリオでは、デバイス設定からバージョン番号を取得し、バージョン番号を送信するロジックを指定する必要があります。
OTAアップデートを実行する前に、バージョン番号を少なくとも1回送信する必要があります。
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);
}
ステップ4: 更新コマンドの受信
IoT Platformに更新パッケージを追加して更新タスクを開始すると、IoT Platformは更新コマンドをデバイスに送信します。
詳細については、「アップデートパッケージの追加」をご参照ください。
デバイスは、aiot_mqtt_recv操作を呼び出してメッセージを受信します。 デバイスがメッセージをOTA更新コマンドとして認識した後、
demo_ota_recv_handler
コールバックが呼び出されます。- コールバックの処理ロジックを指定します。 コールバックの処理ロジックを指定する場合は、次の項目に注意してください。
IoT Platformは、
/ota/device/upgrade/${ProductKey}/${DeviceName}
トピックを使用して、OTA更新コマンドをデバイスに送信します。${ProductKey} および ${DeviceName} の詳細については、「デバイス検証情報の取得」をご参照ください。
- AIOT_OTARECV_FOTAはメッセージタイプを示します。
void demo_ota_recv_handler(void * ota_handle, aiot_ota_recv_t * ota_msg, void * userdata) { switch (ota_msg->type) { ケース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; } …… …… }
aiot_ota_recv_tはデータ形式を示します。 Link SDKは、受信したメッセージを自動的に解析します。
- サンプルコードに基づいて、コールバックの処理ロジックを指定できます。 詳細については、「手順5: アップデートパッケージをダウンロードしてOTAアップデートを実行する」をご参照ください。
ステップ5: アップデートパッケージをダウンロードしてOTAアップデートを実行する
デバイスがIoT Platformによってプッシュされた更新コマンドを受信した後、デバイスは更新パッケージを自動的にダウンロードしません。 パッケージをダウンロードするには、Link SDKのAPI操作を呼び出す必要があります。
demo_ota_recv_handler
コールバックが呼び出された後、ダウンローダーはOTA更新パッケージを受信するためのHTTPSリクエストを開始します。
- ダウンローダーを初期化します。 aiot_download_init操作を呼び出して、
ダウンロード
を作成します説明OTA更新パッケージには複数のファイルを含めることができます。 詳細については、「アップデートパッケージの追加」をご参照ください。
dl_handle = aiot_download_init(); if (NULL == dl_handle) { break; } if (NULL != ota_msg->task_desc->file_name) { printf("\r\n合計ファイル番号は % d、現在のファイルidは % d、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ターゲットファームウェアバージョン: % s、サイズ: % 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);
- パラメーターを設定します。 aiot_download_setopt操作を呼び出して、ダウンロードタスクに関連するパラメーターを設定します。説明
OTAアップデートパッケージに複数のファイルが含まれている場合は、パッケージのダウンロード時に各ファイルのID、サイズ、進行状況をメモしてください。
/* ダウンロード用のTLSプロトコルを設定します。 */ aiot_download_setopt(dl_handle、AIOT_DLOPT_NETWORK_CRED、(void *)(&cred)); /* アクセスするサーバのポート番号を設定します。 */ aiot_download_setopt(dl_handle、AIOT_DLOPT_NETWORK_PORT、(void *)(&port)); /* ダウンロードタスクの情報を指定します。これは、ota_msg入力パラメーターのtask_descメンバーから取得できます。 情報には、ダウンロードURL、ファームウェアサイズ、およびファームウェア署名が含まれます。 */ aiot_download_setopt(dl_handle, AIOT_DLOPT_TASK_DESC, (void *)(ota_msg->task_desc)); /* ダウンロードしたコンテンツを受信したときにSDKが呼び出すコールバックを設定します。 */ aiot_download_setopt(dl_handle、AIOT_DLOPT_RECV_HANDLER、(void *)(demo_download_recv_handler)); /* 1回のダウンロードの最大バッファ長を設定します。 制限に達すると、ユーザーに通知されます。 */ aiot_download_setopt(dl_handle, AIOT_DLOPT_BODY_BUFFER_MAX_LEN, (void *)(&max_buffer_len)); /* AIOT_DLOPT_RECV_HANDLERの異なる呼び出し間で共有される情報を指定します。 この例では、進捗情報が格納される。 */ 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); /* 最初のダウンロードタスクの進行状況0を送信します。 */ if (0 == ota_msg->task_desc->file_id) { aiot_download_report_progress(dl_handle、0); }
- ダウンロード要求を開始します。
- を開始します。Start the
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); 無料 (download_status); } else { /* デタッチするダウンロードスレッドのタイプを設定します。 ファームウェアが取得されると、ダウンロードスレッドは自動的に終了します。 */ pthread_detach(g_download_thread); }
- の後
demo_ota_download_thread
スレッドが有効になっている場合は、aiot_download_send_request操作を実行して、ストレージサーバーから更新パッケージをダウンロードするHTTPS GETリクエストを開始します。-
void * demo_ota_download_thread(void * dl_handle) { int32_t ret = 0; printf("\r\n 2秒でダウンロードスレッドを開始 ......\r\n"); 睡眠 (2); /* ストレージサーバーから更新パッケージをダウンロードする要求を開始します。 /* * TODO: 次の構文では、1つのリクエストを使用してすべてのファームウェアコンテンツを取得します。 * デバイスのリソースが限られている場合、またはネットワーク接続の状態が悪い場合は、セグメント化されたダウンロードを実装できます。 * * aiot_download_setopt(dl_handle、AIOT_DLOPT_RANGE_START、...); * aiot_download_setopt(dl_handle、AIOT_DLOPT_RANGE_END、...); * aiot_download_send_request(dl_handle); * * セグメント化されたダウンロードを実装する場合は、前の3つのステートメントをループで指定します。 この場合、複数の要求が送信され、複数の応答が受信される。 * */ …… …… }
セグメント化されたダウンロードを実装するには、AIOT_DLOPT_RANGE_STARTおよびAIOT_DLOPT_RANGE_ENDパラメーターを設定します。
たとえば、2つのセグメントを使用して1,024バイトの更新パッケージをダウンロードする場合は、パラメーターに次の値を指定します。
最初のセグメント:
AIOT_DLOPT_RANGE_START=0
、AIOT_DLOPT_RANGE_END=511
2番目のセグメント:
AIOT_DLOPT_RANGE_START=512
、AIOT_DLOPT_RANGE_END=1023
-
- を開始します。Start the
- 更新パッケージの受信
- ダウンロードリクエストの送信後、aiot_download_recv操作を呼び出して、
demo_ota_download_thread
ダウンロードスレッドを使用して更新パッケージを受信します。 デバイスがパッケージを受信すると、demo_download_recv_handler
コールバックが呼び出されます。 ダウンロードした更新パッケージをデバイスのローカルストレージまたはファイルシステムに保存する必要があります。void * demo_ota_download_thread(void * dl_handle) { …… …… aiot_download_send_request(dl_handle); // while (1) { while (should_stop == 0) { /* サーバーから送信されたファームウェアを受信します。 */ ret = aiot_download_recv(dl_handle); /* ファームウェアのダウンロード後、aiot_download_recv() の戻り値はSTATE_DOWNLOAD_FINISHEDです。 それ以外の場合、値は取得されたバイト数です。 */ if (STATE_DOWNLOAD_FINISHED == ret) { printf (「ダウンロード完了 \r\n」); break; } if (STATE_DOWNLOAD_RENEWAL_REQUEST_SENT == ret) { printf (「ダウンロード更新リクエストが正常に送信されました \r\n」); continue; } if (ret <= STATE_SUCCESS) { printf (「ダウンロードに失敗、エラーコードは % d、更新リクエストを送信しよう \r\n」、ret); continue; } } …… …… }
- を定義します。
demo_download_recv_handler
ダウンロードした更新パッケージを保存し、更新を実行するコールバック。説明 この例では、応答が印刷される。 更新パッケージを格納して書き込むロジックが指定されていません。 実際のビジネスシナリオでは、更新パッケージを保存し、パッケージをインストールしてOTA更新を完了する必要があります。- OTAアップデートパッケージに1つのファイルが含まれている場合は、ファイルを指定されたローカルストレージの場所に書き込むことができます。
- OTA更新パッケージに複数のファイルが含まれている場合、ファイルを異なるストレージロケーションに書き込むことができます。 各ファームウェアファイルの
file_name
フィールドを指定する必要があります。
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パーセント=0; multi_download_status_t * download_status = (multi_download_status_t *)userdata; /* packet->typeはAIOT_DLRECV_HTTPBODYにのみ設定できます。 */ if (!packet | | AIOT_DLRECV_HTTPBODY != packet->type) { return; } percent = packet->data.percent; /* userdataは、demo_download_recv_handler() の異なる呼び出し間で共有する必要があるデータを格納できます。 */ /* この例では、ファームウェアのダウンロードの進行状況の割合が保存されます。 */ if (userdata) { last_percent = (download_status->last_percent); } data_buffer_len = packet->data.len; /* パーセントの負の値は、データ受信中に例外が発生したか、ダイジェスト認証が失敗したことを示します。 */ if (パーセント <0) { printf("exception: パーセント=% d\r\n" 、パーセント); if (userdata) { 無料 (userdata); } return; } …… …… }
- ダウンロードリクエストの送信後、aiot_download_recv操作を呼び出して、
- ダウンロードの進行状況を送信します。
demo_download_recv_handler
コールバックが呼び出された後、aiot_download_report_progress操作を呼び出して、ダウンロードの進行状況と更新エラーをIoT Platformに送信します。 更新エラーには、書き込み障害やネットワークの切断が含まれます。送信された進捗状況を表示する:
進行状況がIoT Platformコンソールに表示されます。 詳細については、「更新ステータスの表示」をご参照ください。
進捗状況を正常または異常な状態で送信します。
ダウンロードが成功すると、進行状況を示す整数がIoT Platformに送信されます。 Link SDKは、percentパラメーターの値を自動的に計算し、コールバックを使用して値をIoT Platformに送信します。
ダウンロード中にエラーが発生した場合、またはダウンロードしたファームウェアの書き込みに失敗した場合、エラーはIoT Platformに送信されます。 エラーコードの詳細については、「aiot_ota_protocol_errcode_t」をご参照ください。
- 次の方法を使用して進行状況を送信します。
- 更新パッケージに1つのファイルが含まれている場合は、ファイルの進行状況を送信します。
- 更新パッケージに複数のファイルが含まれている場合は、混乱を防ぐために各ファイルのダウンロードの進行状況を送信しないでください。 合計ファイルサイズを分母、すべてのファイルのダウンロードバイト数を分子として使用して、パーセンテージを計算することをお勧めします。 次に、ダウンロードの進行状況を送信します。 ビジネスニーズに基づいて進行状況を送信するロジックを指定することもできます。 例:
- ダウンロード開始時に進行状況0% を送信します。 次に、ダウンロードが完了するまで進捗状況が10% 増加するたびに進捗状況を送信します。
- ダウンロードの開始時に進行状況0% を送信し、ダウンロードの完了時に100% します。
void demo_download_recv_handler(void * handle, const aiot_download_recv_t * packet, void * userdata) { …… …… /* * TODO: ファームウェアのセグメントがダウンロードされたら、次の操作を実行します。 * 更新パッケージをダウンロードした後、初期位置がpacket->data.bufferで、長さがpacket->data.lenであるメモリをローカルの保存場所に保存します。 * * 書き込みが失敗した場合は、aiot_download_report_progress(handle, -4) 操作を呼び出して、IoT Platformにエラーメッセージを送信する必要があります。 * プロトコルで定義されているエラーコードは、aiot_ota_protocol_errcode_t変数に含まれます。 例: * -1: 更新が失敗したことを示します。 * -2: ダウンロードが失敗したことを示します。 * -3: 検証が失敗したことを示します。 * -4: 燃焼が失敗したことを示します。 * */ /* percentパラメーターの値が100の場合、すべてのファームウェアコンテンツがダウンロードされます。 */ if (パーセント== 100) { g_finished_task_num ++; /* * TODO: ファームウェアを書き込み、設定を保存し、デバイスを再起動してから、新しいファームウェアに切り替えてデバイスを起動します。 次のコードを使用して、新しいファームウェアのバージョン番号をIoT Platformに送信します。 たとえば、バージョンが1.0.0から1.1.0に更新されている場合、new_versionの値は1.1.0であり、IoT Platformに送信する必要があります。 aiot_ota_report_version(ota_handle、new_version); IoT Platformは、新しいファームウェアのバージョン番号を受信した後、更新が成功したと判断します。 それ以外の場合、IoT Platformは更新が失敗したと判断します。 更新パッケージのダウンロード後に更新が失敗した場合は、aiot_download_report_progress(handle, -1) 操作を呼び出してエラータイプを送信します。 */ } /* 出力を簡素化します。 ダウンロードの進行状況が少なくとも5% 増加するたびに、進行状況が印刷され、IoT Platformに送信されます。 */ 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=パーセント; if (g_finished_task_num == download_status->file_num) { /* 更新パッケージのダウンロードに複数のスレッドが使用されている場合は、すべてのファイルがダウンロードされた後に進行状況100% を送信します。 */ aiot_download_report_progress (ハンドル、100); } } if (percent == 100 && userdata) { 無料 (userdata); } } }
ダウンローダーを終了します。
アップデートパッケージのダウンロード後、aiot_download_deinit操作を呼び出して
download
セッションを破棄します。 その後、ダウンロードスレッドが閉じられます。aiot_download_deinit(&dl_handle); printf (「ダウンロードスレッド出口 \n」);
ステップ6: 更新後にバージョン番号を送信する
- OTA更新パッケージに単一のファイルが含まれている場合、パッケージにはファームウェアバージョン番号が含まれます。 バージョン番号をIoT Platformに送信できます。
- 更新パッケージに複数のファイルが含まれている場合、ファイルは1つまたは複数のファームウェアバージョン番号に対応できます。 ファイルが
a1
、b1
、c1
などの異なるファームウェアバージョン番号に対応する場合、a1b1c1
などの更新パッケージの組み合わせバージョン番号を送信する必要があります。
バージョン番号を送信するサンプルコードの詳細については、「手順3: デバイスのバージョン番号を送信する」をご参照ください。
デバイスの更新後、最新のバージョン番号を送信する必要があります。 それ以外の場合、IoT PlatformはOTA更新タスクが失敗したと判断します。
デバイスは、更新後に再起動する必要があります。 この場合、デバイスの再起動後に最新のバージョン番号を送信してください。
この例では、更新後に最新のバージョン番号を送信するロジックは指定されていません。 ビジネス要件に基づいてロジックを指定する必要があります。
ステップ7: 接続を閉じる
MQTT接続は、永続的に接続されたままのデバイスに適用されます。 IoT Platformからデバイスを手動で切断できます。
この例では、メインスレッドを使用してパラメータを設定し、接続を確立します。 接続が確立されたら、メインスレッドを一時停止できます。
aiot_mqtt_disconnect操作を呼び出して、デバイスをIoT Platformから切断します。
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;
}
ステップ8: プログラムを終了する
aiot_ota_deinit操作を呼び出して、OTAを破棄します。
aiot_ota_deinit(&ota_handle);