レシピOTA

概要

本製品に書込まれているレシピ実行ファイルを、LTE通信により遠隔から変更する仕組み(Over The Air)をレシピで作成する方法を紹介します。
レシピをOver The Air(OTA)で更新することをROTAと示します。

ROTA_front

※ROTA機能はベータ版リリースとなります。

ROTAの特徴

ROTA機能の特徴を以下に示します。

ROTA機能

ROTA機能を実行するには、本製品に書込まれたレシピ実行ファイル内にROTAの仕組みが含まれていること、変更するレシピ実行ファイル、及びレシピ実行ファイルを配信するためのROTAサーバが必要です。

ROTAサーバの仕様

本製品とROTAサーバとはHTTP GETコマンドで通信を行います。そのため、HTTP GETコマンドに対応したWebサーバである必要があります。
HTTP GETコマンドによる通信はHTTPおよびHTTPSでの通信に対応していますが、セキュリティリスクの観点から閉域網の通信で無い場合は、HTTPSによる暗号化通信を行うことを推奨します。

ROTA_folder

[配置するファイルについて]

ROTAサーバに配置するファイル(rcp_info.bin, rcp_prog.bin)は、レシピ言語をビルドして作成された、「rcp_compress.zip」を展開した中身となります。

ROTA_zipfile

この2つのファイルをクラウドストレージに保存します。

[ROTA抑制について]

ROTAの実行を抑制したい場合は、ROTA用のファイル(rcp_info.bin, rcp_prog.bin)を削除することに加えて、「NO_UPDATE」というファイルを置いておくことでROTAの実行を抑制することが出来ます。

ROTA_noupdate


ROTA制御のAPI

ROTAを実行するAPIは以下となります。

API 内容
1 rcplib_KCS_RcpOTA() ROTAを実行する

rcplib_KCS_RcpOTA ()

本APIの実⾏により、ROTAが開始されます。
レシピ実行ファイルのダウンロードが完了すると⾃動的に本製品が再起動し、レシピ実行ファイルの更新が実行されます。ダウンロードしたレシピ実行ファイルのタイムスタンプを確認し、現在動作させているものと同じであれば更新は実⾏されません。

rcplib_KCS_RcpOTA(int32 timeout, uint8 sync, uint8 ex_result, str hosturl, uint8 rcv_event_id, str http_header, uint8 protocol, uint8 sni, uint8 auth_mode, uint8 auth_index) 
      timeout      タイムアウト値[msec] <0:EAPI_TIMEOUT_ZERO>
      sync         同期実行 <0:EAPI_SYNC_RESULT>
      ex_result    API実行結果 <戻り値>
      hosturl      接続先サーバのURL <最大127文字>
      rcv_event_id コールバックを受ける任意のイベントID <1254>
      http_header  HTTPヘッダ指定 <非サポート(NULL)>
      protocol     利用する通信プロトコル <MMG_PROTOCOL_HTTPS(HTTP/HTTPS)のみ>
      sni          TLS通信利用時のSNI設定 <MMG_SNI_ENABLE(有効)のみ>
      auth_mode    TLS通信利用時のmode設定 <MMG_AUTH_SRV(サーバー認証)のみ>
      auth_index   認証ID(TLS接続や証明書設定の管理ID) <非サポート("1")>

timeout, sync
APIのタイムアウト設定と実行方法の指定ですが、ここでは両方とも「0」を指定します。

ex_result
ex_resultの戻り値は以下の定義です。
0:成功 (KCS_RCPOTA_RESULT_NO_ERROR)
1:失敗 - 無効なURL (KCS_RCPOTA_RESULT_ERR_INVALID_URL)
2:失敗 - 開始不可 (KCS_RCPOTA_RESULT_ERR_CANNOT_START)

hosturl
接続先のサーバのURL文字列を指定します。HTTP GETでレシピ実行ファイルを取得する際の該当ファイルが保存されているフォルダまでの指定となります。

ex) "http://xxxx.xxxx.com/KC4C-recipe/0001"

※機器ごとに更新するレシピ実行ファイルを変えたい場合などは、URLに特殊なリプレイス文字(*rp_imei*)を付与することで自動的に機器のユニーク番号であるIMEIに置き換える機能を利用する事ができます。

ex) "http://xxxx.xxxx.com/KC4C-recipe/*rp_imei*******/"
             
    "http://xxxx.xxxx.com/KC4C-recipe/012345678901234/"

このAPIではHTTP/HTTPSの区別はurlの先頭部分で行います。このため、http:// 又は、 https:// の指定を意識する必要があります。

rcv_event_id
ROTAのAPIを実行した結果、エラーなど発生した場合の通知を受け取るイベントIDとなります。正しく書き換えが実行された場合は機器がリセットしますので、このイベントは発行されません。
イベントが通知された場合、該当イベントの第一引数(rcplib_TASK_GetArg(0)で取得)には以下の定義のコードが入ります。

resp_code   ROTA開始後に更新完了しない詳細理由 
    0成功 - タイムスタンプが同一 (KCS_RCPOTA_RESP_OK)
    1失敗 - 通信エラー/ファイル無しなど (KCS_RCPOTA_RESP_ERR)
    2終了 - NO_UPDATEファイル有 (KCS_RCPOTA_RESP_NO_UPDATE)
    3中断 - FOTA中の中断 (KCS_RCPOTA_RESP_SUSPEND)
    4再開 - FOTA後の再開 (KCS_RCPOTA_RESP_RESUME)

http_header (ベータ版非対応)
非サポートとなるためNULL指定「""」を入力してください。

protocol (ベータ版固定)
プロトコルはHTTP/HTTPSが利用できますがここは「MMG_PROTOCOL_HTTPS」固定で指定してください。HTTP/HTTPSの指定はurlの「http://, https://」で区別します。

sni (ベータ版固定)
TLS通信利用時のSNI設定ですが、MMG_SNI_ENABLEのみ指定可能です。

auth_mode (ベータ版固定)
TLS通信利用時の認証方式はサーバ認証のみ対応です。MMG_AUTH_SRVを指定。

auth_index (ベータ版固定)
TLS接続にかかわる証明書設定してある認証IDを指定しますが、「1」のみ指定可能です。証明書はキッティングツールで書込む「FOTA」用の証明書を利用します。


[コード例]
#incliude "modemMgrTask.h"
#incliude "eventLib.h"
#incliude "bufferLib.h"
   
// 内部非同期イベント
#define UNSYNC_EVENT_INIT 0
#define UNSYNC_EVENT_RECIPE_OTA_RECEIVE 1

// 接続先サーバ設定
#define USER_SETTING_HOST_NAME     "http://xxxx.xxxx.com"
#define USER_SETTING_HOST_SUB_URL  "/KC4C_test/*rp_imei*******/"
   
// mainループ処理
void main_loop() {
   
    // レシピOTAの応答イベント受信時の処理
    else if(event_id == UNSYNC_EVENT_RECIPE_OTA_RECEIVE) {
        event_recipe_ota_event_receive(rcplib_TASK_GetArg(0));
    }
   

// ROTA実行関数
func any_func() {
    rcplib_LOG_Print("uapp_1 recipe_ota_exe_proc start");

    str ex_result_msg[32];
    uint8 ex_result; ex_result = 0;
    uint8 ret; ret = 0;

    // 接続先URLの文字列 "http://xxxx.xxxx.com/KC4C_test/*rp_imei*******/" を生成
    str hosturl[MMG_URL_MAX];
    hosturl = USER_SETTING_HOST_NAME;
    rcplib_STR_Cat(hosturl, USER_SETTING_HOST_SUB_URL);

    // レシピOTAを実行
    ret = rcplib_KCS_RcpOTA(
                 EAPI_TIMEOUT_ZERO,
                 EAPI_UNSYNC_NORESULT,
                 ex_result,
                 hosturl,
                 UNSYNC_EVENT_RECIPE_OTA_RECEIVE,
                 "",
                 MMG_PROTOCOL_HTTPS,
                 MMG_SNI_ENABLE,
                 MMG_AUTH_SRV,
                 1
                 );

    if(ret != 0) {
        rcplib_LOG_Print("rcplib_KCS_RcpOTA execute Error!!");
        rcplib_FORMAT_String(ex_result_msg, "ex_result:%d", ex_result);
        rcplib_LOG_Print(ex_result_msg);

        if(ex_result == KCS_RCPOTA_RESULT_NO_ERROR) {
            // ret!=0の時、ex_result=0になることはなく、ここに入ることはありません。
            rcplib_LOG_Print("KCS_RCPOTA_RESULT_NO_ERROR");
        } else if(ex_result == KCS_RCPOTA_RESULT_ERR_INVALID_URL) {
            // 接続先サーバのURLの文字列の長さが128文字以上になっている場合のエラー
            rcplib_LOG_Print("KCS_RCPOTA_RESULT_ERR_INVALID_URL");
        } else if(ex_result == KCS_RCPOTA_RESULT_ERR_CANNOT_START) {
            // レシピOTAの実行要求が既に入って、実行中である(多重実行された時)、
            // または端末のFirmwareのOTAを実行中であり、レシピOTAの実行が出来ないことを示すエラー
            rcplib_LOG_Print("KCS_RCPOTA_RESULT_ERR_CANNOT_START");
        }
    } else {
        rcplib_LOG_Print("rcplib_KCS_RcpOTA execute OK!!");
    }

    return(0); 
}

// レシピOTAの応答イベント
// ※レシピバイナリの更新処理を実行した場合は、このイベントが通知されることなく更新のために端末が再起動されます。
func event_recipe_ota_event_receive(uint16 resp_code) {
    str resp_msg[32];
    rcplib_LOG_Print("***** RECIPE OTA response event received *****");
    rcplib_FORMAT_String(resp_msg, "resp_code:%d", resp_code);
    rcplib_LOG_Print(resp_msg);

    if(resp_code == KCS_RCPOTA_RESP_OK) {
        // 接続先サーバ上からダウンロードしたレシピバイナリのタイムスタンプを確認した結果、現在動作させているものと同じであり、
        // 更新処理が必要ないため実行しなかった場合に通知されるイベント
        rcplib_LOG_Print("KCS_RCPOTA_RESP_OK");
    } else if(resp_code == KCS_RCPOTA_RESP_ERR) {
        // 何らかの理由によりレシピOTAの実行に失敗したことを通知されるイベント(通信に失敗した/接続先サーバにファイルが見つからない等)
        rcplib_LOG_Print("KCS_RCPOTA_RESP_ERR");
    } else if(resp_code == KCS_RCPOTA_RESP_NO_UPDATE) {
        // 接続先サーバ上に"NO_UPDATE"ファイルが配置されており、更新処理を実行しなかったことを通知するイベント
        rcplib_LOG_Print("KCS_RCPOTA_RESP_NO_UPDATE");
    } else if(resp_code == KCS_RCPOTA_RESP_SUSPEND) {
        // 端末のFirmwareのOTAが実行され、レシピOTAの処理が中断したことを通知するイベント
        rcplib_LOG_Print("KCS_RCPOTA_RESP_SUSPEND");
    } else if(resp_code == KCS_RCPOTA_RESP_RESUME) {
        // 端末のFirmwareのOTAの実行が終了し、レシピOTAの処理が再開したことを通知するイベント
        rcplib_LOG_Print("KCS_RCPOTA_RESP_RESUME");
    }

    return(0);
}

TLSの利用

HTTPSでクラウドストレージにアクセスを行うためには、サーバー証明書(CA証明書)を設定する必要があります。ROTAで利用するサーバー証明書はキッティングツールで書き込むFOTAのサーバ証明書を利用します。ここでは、キッティングツールでの書き込み方を示します。(本リリース版ではFOTAの証明書とROTAの証明書を分ける予定です。)

[証明書の書込み]

証明書の書込みは、キッティングツールから行います。
以下の手順でサーバー証明書の書込みをしてください。

ROTA_kitting1

ROTA_kitting2

設定した証明書は、サンプルコード上の接続先のサーバー設定にて「https://」を指定することで、ここの証明書を使って指定のサーバに接続に行きます。


サンプルコードの解説

「1201_ボタン長押しでレシピOTAを実行する」

ボタン押下(1秒以上4秒未満)の契機でROTAの実行をします。利用にあたりいくつかの修正と準備が必要となります。

クラウドストレージ側準備
クラウドストレージには以下のフォルダ構成でファイルを準備しておきます。

/KC4C_test/012345678901234/
  - rcp_info.bin
  - ucp_prog.bin
  ※012345678901234の所には、利用機器のIMEIが入ります。

サンプルコード変更
以下のxxxx.xxxx.comの部分をご利用のクラウドストレージのアドレスに変更します。

// 接続先サーバ設定
#define USER_SETTING_HOST_NAME     "http://xxxx.xxxx.com"
#define USER_SETTING_HOST_SUB_URL  "/KC4C_test/*rp_imei*******/"

上記準備とサンプルコードの変更を行なった後に、ボタン押下(1秒以上4秒未満)を行うことで、ROTAが動きます。成功した場合はレシピが書き変わった後にリセットを行い、書き換えた後のレシピが実行されます。
エラーが発生した場合は、内容がログに出力されますので、ご確認ください。

サンプルコードではボタン押下をトリガーとしていますが、運用の契機としては、MQTTでROTAサーバURLを受信したら受信したURL向けにROTAを実行する等、が考えられます。

関連情報

各サンプルコードについて動作確認を行っておりますが、全ての環境において動作を保証するものではありません。正しく動作することを確認の上でご利用ください。

対応機種:KC4-C-100A/KC4-C-101A