Rcv_Unvsl (ユニバーサル レシーバー)

Mono Wireless Inc.

Rcv_Unvsl (ユニバーサル レシーバー)

MWXライブラリの twe_twelite.networkNWK_LAYEREDtwe_twelite.network2NWK_SIMPLEを動作させることで、レイヤーツリーネット (TWELITE PAL, ARIAなど)のパケットを含む、さまざまな種類のパケットを受信、解釈できます。

ただし無線パケットは、同一チャネルであることと、同一アプリケーションIDであることが条件です。

main.cpp

setup(), loop()、受信パケットのコールバック関数 on_rx_packet()を記述しています。

setup()

これらのオブジェクトは pkt_handler.cpp で宣言され setup()中でpnew()により初期化されます。主にパケットのペイロード(データ)を解釈します。

    mwx::pnew(g_pkt_pal);
    mwx::pnew(g_pkt_apptwelite);
    mwx::pnew(g_pkt_actsamples);
    mwx::pnew(g_pkt_unknown);

2つのネットワークオブジェクトを生成しています。必ず the_twelite.networkNWK_LAYEREDにします。

    auto&& nwk_ly = the_twelite.network.use<NWK_LAYERED>();
    auto&& nwk_sm = the_twelite.network2.use<NWK_SIMPLE>();

loop()

このサンプルではloop()の処理で重要なのは約1秒おきに行っている .refresh() 処理です。g_pkt_apptwelite().refresh()のみ重複チェッカのタイムアウト処理を行っています。それ以外のオブジェクトは何もしません。

    if (TickTimer.available()) {
        static unsigned t;
        if (!(++t & 0x3FF)) {
            g_pkt_pal.refresh();
            g_pkt_apptwelite.refresh();
            g_pkt_actsamples.refresh();
            g_pkt_unknown.refresh();
        }
    }

on_rx_packet()

void on_rx_packet(packet_rx& rx, bool_t &handled) {
    auto type = rx.get_network_type();
    bool b_handled = false;

    // PAL
    if (!b_handled
        && type == mwx::NETWORK::LAYERED
        && g_pkt_pal.analyze(rx, b_handled)
    ) {
        g_pkt_pal.display(rx);
    }

    // Act samples
    if (!b_handled
        && type == mwx::NETWORK::SIMPLE
        && g_pkt_actsamples.analyze(rx, b_handled)
    ) {
        g_pkt_actsamples.display(rx);
    }

    // Standard application (e.g. App_Twelite)
    if (!b_handled
        && type == mwx::NETWORK::NONE
        && g_pkt_apptwelite.analyze(rx, b_handled)
    ) {
        g_pkt_apptwelite.display(rx);
    }

    // unknown
    if (!b_handled) {
        g_pkt_unknown.analyze(rx, b_handled);
        g_pkt_unknown.display(rx);
    }
}

このサンプルコードで最も重要な部分です。auto type = rx.get_network_type();によりパケットの種別を判定しています。

mwx::NETWORK::NONE の場合は、再送などで複数送信されうる同一パケットの重複チェッカ等の処理は MWX ライブラリ内部で行われません。これらの対応を記述する必要があります。本サンプルでは dup_checker.hpp, dup_checker.cpp を用意しています。

パケットの解釈はtsRxDataApp*をラップした packet_rx& オブジェクトを参照します。packet_rxクラス自体は特別な機能はなく、get_psRxDataApp()を用いてtsRxDataApp*から得られる一部の情報へのアクセス手段を定義しているのみです。

pkt_common.hpp

パケット解釈部分のインタフェースを統一する目的で定義しています。

template <class D>
struct pkt_handler {
    D& self() { return static_cast<D&>(*this); }
    bool analyze(packet_rx& rx, bool &b_handled) {
        return self().pkt.analyze(rx, b_handled);
    }
    void display(packet_rx& rx) {
        Serial
            << crlf
            << format("!PKT_%s(%03d-%08x/S=%d/L=%03d/V=%04d)"
                    , self().get_label_packet_type()
                    , self().pkt.data.u8addr_src
                    , self().pkt.data.u32addr_src
                    , rx.get_psRxDataApp()->u8Seq
                    , rx.get_lqi()
                    , self().pkt.data.u16volt
                    );

        self().disp_detail(rx);
    }
    void refresh() {
        self()._refresh();
    }
};

// packet analyzer for App_Twelite
class pkt_handler_apptwelite : public pkt_handler<pkt_handler_apptwelite> {
    friend class pkt_handler<pkt_handler_apptwelite>;
    pkt_apptwelite pkt;
    void disp_detail(packet_rx& rx);
    const char* get_label_packet_type() { return "AppTwelite"; }
    void _refresh() { pkt.refresh(); }
public:
    pkt_handler_apptwelite() : pkt() {}
};

さらにパケット解釈クラス(上記例 pkt_handler_apptwelite)には、メンバーオブジェクトの pkt が含まれます。実際のパケットの解釈部分は、pkt_???.cpp にある各々の analyze() の実装を参照してください。

pkt_???.hpp, pkt_???.cpp

パケット種別ごとのパケット解釈部 analyze() と、データ構造 data が定義されています。メンバーdataは、構造体ですがPktDataCommonの共通構造体を継承しています。この共通部を用いてパケットのデータのシリアル出力のコードを簡潔に記述しています。

pkt_pal

PAL関連のパケットに対応します。PALのパケット構造は複雑なデータ構造を持っています。ここでは EASTL のコンテナを用いた実装を行っています。

1パケット中の複数データに対して各々が追加されるたびに_vect_pal_sensors にエントリを確保して値を格納します。パケット中のすべてのデータを解釈した時点でセンサータイプをキーとした_map_pal_sensorsを構築します。

dup_checker

重複チェッカーを実装します。チェッカーの動作はテンプレート引数によってカスタマイズできます。

テンプレート引数

コンテナ

重複チェック

    bool check_dup(uint32_t u32ser, uint16_t u16val, uint32_t u32_timestamp) {
        // find entry by key:u32ser.
        auto r = _mmap_entries.equal_range(u32ser);

        ...
    }

マルチマップ構造からデータを検索するには .equal_range() を呼び出します。得られた r はイテレータで、同一のシリアル番号の要素を列挙します。

各要素(_dup_checker_entry)にはタイムスタンプやシーケンス番号が記録されています。この値に従い重複を確認します。