セクションの複数ページをまとめています。 印刷またはPDF形式で保存...

もとのページに戻る

2024-05-08 現在

Parent_MONOSTICK

親機アプリケーション(MONOSTICK用)
    MONOSTICKを親機として使用するアクトです。子機からのパケットのデータペイロードをシリアルポートに出力します。サンプルアクトの多くのサンプルでのパケットを表示することが出来ます。

    アクトの機能

    • サンプルアクトの子機からのパケットを受信して、シリアルポートへ出力する。

    アクトの使い方

    必要なTWELITEと配線

    役割
    親機MONOSTICK BLUE/RED
    子機サンプルアクトの子機に設定したTWELITEシリーズ
    (例: Slp_Wk_and_Tx, PAL_AMB, PAL_MAG, PAL_MOT???など)

    最初は以下のデフォルトの設定にて確認してください。

    • アプリケーションID: 0x1234abcd
    • チャネル: 13

    アクトの解説

    宣言部

    インクルード

    // use twelite mwx c++ template library
    #include <TWELITE>
    #include <MONOSTICK>
    #include <NWK_SIMPLE>
    #include <STG_STD>

    MONOSTICK用のボードビヘイビア<MONOSTICK>をインクルードしています。このボードサポートには、LEDの制御、ウォッチドッグ対応が含まれます。

    • <NWK_SIMPLE> 簡易中継ネットの定義を読み込みます
    • <STG_STD> インタラクティブモードの定義を読み込みます。

    その他

    // application ID
    const uint32_t DEFAULT_APP_ID = 0x1234abcd;
    // channel
    const uint8_t DEFAULT_CHANNEL = 13;
    // option bits
    uint32_t OPT_BITS = 0;
    
    /*** function prototype */
    bool analyze_payload(packet_rx& rx);

    デフォルト値や関数プロトタイプなどの宣言をしています。

    setup()

    auto&& brd = the_twelite.board.use<MONOSTICK>();
    auto&& set = the_twelite.settings.use<STG_STD>();
    auto&& nwk = the_twelite.network.use<NWK_SIMPLE>();

    setup()では、まず<MONOSTICK>ボードビヘイビア、<STG_STD>インタラクティブモード ビヘイビア、<NWK_SIMPLE>ビヘイビアをuse<>を用い読み込みます。この手続きは必ずsetup()内で行います。

    set << SETTINGS::appname("PARENT"); // 設定画面中のタイトル
    set << SETTINGS::appid_default(DEFAULT_APP_ID); // アプリケーションIDデフォルト
    set << SETTINGS::ch_default(DEFAULT_CHANNEL); // チャネルデフォルト
    set << SETTINGS::lid_default(0x00); // LIDデフォルト
    set.hide_items(E_STGSTD_SETID::OPT_DWORD2, E_STGSTD_SETID::OPT_DWORD3, E_STGSTD_SETID::OPT_DWORD4, E_STGSTD_SETID::ENC_KEY_STRING, E_STGSTD_SETID::ENC_MODE);
    set.reload(); // 設定を不揮発性メモリから読み出す
    OPT_BITS = set.u32opt1(); // 読み込み例(オプションビット)
    

    続いてインタラクティブモードの設定と設定値の読み出しを行います。<STG_STD>インタラクティブモードでは、標準的な項目が用意されていますが、作成するアクトごとにいくつかのカスタマイズを行えるようになっています。

    • appname→ 設定画面中のタイトル行にでるアクト名称
    • appid_default→ デフォルトのアプリケーションID
    • ch_default→ デフォルトのチャネル
    • lid_default→ デバイスID(LID)のデフォルト値
    • .hide_items()→ 項目の非表示設定

    設定値を読み出す前には必ず.reload()を呼び出します。設定値は.u32opt1()のように設定値ごとに読み出し用のメソッドが用意されています。

    the_twelite
    	<< set                    // インタラクティブモードの設定を反映
    	<< TWENET::rx_when_idle() // 受信するように指定
    	;
    
    // Register Network
    nwk << set;							// インタラクティブモードの設定を反映
    nwk << NWK_SIMPLE::logical_id(0x00) // LIDだけは再設定
    	;

    いくつかの設定値は<STG_STD>オブジェクトを用いて直接反映することが出来ます。また、DIPスイッチの設定などにより特定の値を書き換えたいような場合などは、反映されたあとに別個に値を書き換えることも出来ます。上記の例ではthe_tweliteオブジェクトにアプリケーションID、チャネル、無線出力などを設定し、nwkオブジェクトに対してLIDと再送回数の設定をしてから、再度LIDを0に設定し直しています。

    brd.set_led_red(LED_TIMER::ON_RX, 200); // RED (on receiving)
    brd.set_led_yellow(LED_TIMER::BLINK, 500); // YELLOW (blinking)
    

    <MONOSTICK>ボードビヘイビアではLED点灯制御のための手続きを利用できます。

    1行目では赤色のLEDを無線パケットを受信したら200ms点灯する設定をしています。最初のパラメータはLED_TIMER::ON_RXが無線パケット受信時を意味します。2番目は点灯時間をmsで指定します。

    2行目はLEDの点滅指定です。1番目のパラメータはLED_TIMER::BLINKが点滅の指定で、2番目のパラメータは点滅のON/OFF切り替え時間です。500msごとにLEDが点灯、消灯(つまり1秒周期の点滅)を繰り返します。

    the_twelite.begin(); // start twelite!
    

    the_tweliteを開始するための手続きです。act0..4では出てきませんでしたがthe_tweliteの設定や各種ビヘイビアの登録を行った場合は、必ず呼び出すようにしてください。

    loop()

    このサンプルではloop()中の処理はありません。

    void loop() {
    }

    on_rx_packet()

    パケットを受信したときに呼び出されるコールバック関数です。この例では受信したパケットデータに対していくつかの出力を行っています。

    void on_rx_packet(packet_rx& rx, bool_t &handled) {
    	Serial << ".. coming packet (" << int(millis()&0xffff) << ')' << mwx::crlf;
    
      ...
    
    	// packet analyze
    	analyze_payload(rx);
    }
    analyze_payload

    関数の末尾で呼び出されるanalyze_payload()は、いくつかのサンプルアクトのパケットを解釈するコードが含まれています。サンプルアクト中のパケット生成部分と対応させてコードを参照してください。

    bool b_handled = false;
    
    uint8_t fourchars[4]{};
    auto&& np = expand_bytes(
    	    rx.get_payload().begin(), rx.get_payload().end()
    		, fourchars
        );
    
    if (np == nullptr) return;
    
    // display fourchars at first
    Serial
    	<< fourchars
    	<< format("(ID=%d/LQ=%d)", rx.get_addr_src_lid(), rx.get_lqi())
    	<< "-> ";

    この関数では最初に4文字識別データをfourchars[5]配列に読み込みます。

    読み込みはexpand_bytes()関数を用います。この関数の第1・第2パラメータはC++の標準ライブラリの作法に倣い、受信パケットのペイロード部の先頭ポインタ.begin()と末尾ポインタの次.end()を与えます。続くパラメータは可変引数として、読み込むデータ変数を与えます。戻り値はエラー時はnullptr、それ以外は次の解釈ポインタとなります。末尾まで解釈した場合は.end()が戻ります。ここでのパラメータはuint8_t fourchars[4]です。

    つづいて4バイトヘッダに対応した処理を行います。ここではサンプルアクトSlp_Wk_and_Txのパケットを解釈し内容を表示します。

    // Slp_Wk_and_Tx
    if (!b_handled && !strncmp(fourchars, "TXSP", 4)) {
    	b_handled = true;
    	uint32_t tick_ms;
    	uint16_t u16work_ct;
    
    	np = expand_bytes(np, rx.get_payload().end()
    		, tick_ms
    		, u16work_ct
    	);
    
    	if (np != nullptr) {
    		Serial << format("Tick=%d WkCt=%d", tick_ms, u16work_ct);
    	} else {
    		Serial << ".. error ..";
    	}
    }

    他の解釈部の判定をスキップするようにb_handledtrueに設定します。

    "TXSP"のパケットではuint32_t型のシステムタイマーカウントと、uint16_t型のダミーカウンタの値が格納されています。各々変数を宣言してexpand_bytes()関数を用い読み込みます。上述と違うのは、読み出しの最初のポインタとして第一パラメータがnpとなっている点です。tick_msu16work_ctをパラメータとして与え、ビッグエンディアン形式のバイト列としてペイロードに格納された値を読み出します。

    読み出しに成功すれば内容を出力して終了です。

    独自のアスキー書式を定義して出力する

    ユーザが定義した並び順でアスキー形式により構成します。

    smplbuf_u8<128> buf;
    mwx::pack_bytes(buf
    	, uint8_t(rx.get_addr_src_lid())		   // 送信元の論理ID
    	, uint8_t(0xCC)											   // 0xCC
    	, uint8_t(rx.get_psRxDataApp()->u8Seq) // パケットのシーケンス番号
    	, uint32_t(rx.get_addr_src_long())		 // 送信元のシリアル番号
    	, uint32_t(rx.get_addr_dst())			     // 宛先アドレス
    	, uint8_t(rx.get_lqi())					       // LQI:受信品質
    	, uint16_t(rx.get_length())				     // 以降のバイト数
    	, rx.get_payload() 						         // データペイロード
    );
    
    serparser_attach pout;
    pout.begin(PARSER::ASCII, buf.begin(), buf.size(), buf.size());
    
    Serial << "FMT PACKET -> ";
    pout >> Serial;
    Serial << mwx::flush;

    1行目はアスキー書式に変換する前のデータ列を格納するバッファをローカルオブジェクトとして宣言しています。

    2行目はpack_bytes()を用いてデータ列を先ほどのbufに格納します。データ構造はソースコードのコメントを参照ください。pack_bytes()のパラメータにはsmplbuf_u8 (smplbuf<uint8_t, ???>)形式のコンテナを指定することもできます。

    13,14,17行目は、シリアルパーサーの宣言と設定、出力です。

    NWK_SIMPLEのヘッダを含めてダンプ出力する

    最初の出力(if(0)により実行されないようになっています)は<NWK_SIMPLE>の制御データを含めたデータをすべて表示します。制御データは11バイトあります。通常は制御情報を直接参照することはありませんが、あくまでも参考です。

    serparser_attach pout;
    pout.begin(PARSER::ASCII, rx.get_psRxDataApp()->auData,
        rx.get_psRxDataApp()->u8Len, rx.get_psRxDataApp()->u8Len);
    
    Serial << "RAW PACKET -> ";
    pout >> Serial;
    Serial << mwx::flush;
    
    // 参考:制御部のパケット構造
    // uint8_t  : 0x01 固定
    // uint8_t  : 送信元のLID
    // uint32_t : 送信元のロングアドレス(シリアル番号)
    // uint32_t : 宛先アドレス
    // uint8_t  : 中継回数
    

    1行目は出力用のシリアルパーサをローカルオブジェクトとして宣言しています。内部にバッファを持たず、外部のバッファを流用し、パーサーの出力機能を用いて、バッファ内のバイト列をアスキー形式出力します。

    2行目はシリアルパーサーのバッファを設定します。すでにあるデータ配列、つまり受信パケットのペイロード部を指定します。serparser_attach poutは、既にあるバッファを用いたシリアルパーサーの宣言です。pout.begin()の1番目のパラメータは、パーサーの対応書式をPARSER::ASCIIつまりアスキー形式として指定しています。2番目はバッファの先頭アドレス。3番目はバッファ中の有効なデータ長、4番目はバッファの最大長を指定します。出力用で書式解釈に使わないため4番目のパラメータは3番目と同じ値を入れています。

    6行目でシリアルポートへ>>演算子を用いて出力しています。

    7行目のSerial << mwx::flushは、ここで出力が終わっていないデータの出力が終わるまで待ち処理を行う指定です。(Serial.flush()も同じ処理です)