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

もとのページに戻る

2024-12-02 現在

serparser

シリアル書式入出力 (mwx::serial_parser)
    シリアル書式の入出力のために用います。内部に解釈済みのバイナリ系列を保持するバッファを持ち、入力時は1バイトずつ系列を読み出し書式に従い内部バッファに格納し、系列の解釈が完了した時点で完了状態になるものです。反対に出力時は内部バッファから所定の出力書式に従いバッファを出力します。

    メモリバッファ取り扱い方法(alloc)に応じて3種類のクラス名が定義されています。

    // serparser_attach : 既存のバッファを用いる
    serparser_attach
    
    // serparser : Nバイトのバッファを内部に確保する
    serparser_local<N>
    
    // serparser_heap : ヒープ領域にバッファを確保する
    serparser_heap

    定数(書式種別)

    begin()の初期化のパラメータで渡す書式の種別です。ここではアスキー形式とバイナリー形式の2種類があります。

    定数種別
    uint8_t PARSER::ASCII = 1アスキー形式
    uint8_t PARSER::BINARY = 2バイナリー形式

    形式について

    アスキー形式

    アスキー形式は、バイナリで構成されたデータ列を文字列で表現する方法です。

    例えばバイト列で 00A01301FF123456 をアスキー形式で表現すると、以下のようになります。先頭は :B1 がチェックサム、終端は [CR:0x0d][LF:0x0a] となります。

    :00A01301FF123456B1[CR][LF]
    

    終端のチェックサムを省略できます。チェックサムからCRLFの系列をXに置き換えます。文字化けによる誤ったデータ系列には弱くなりますが、実験などでデータを送付したいときに便利です。

    :00A01301FF123456X
    

    定義

    ======元データのバイト数バイト数解説
    ヘッダ1:(0x3A) コロンを指定します。
    データ部N2N元データの各バイトをアスキー文字列2文字(A-F は大文字)で表現します。
    例えば 0x1F は 1 (0x31) F (0x46) と表現します。
    チェックサム2データ部の各バイトの和を8ビット幅で計算し2の補数をとります。つまりデータ部の各バイトの総和+チェックサムバイトを8ビット幅で計算すると0になります。
    チェックサムバイトをアスキー文字列2文字で表現します。
    例えば 00A01301FF123456 では 0x00 + 0xA0 + … + 0x56 = 0x4F となり、この二の補数は0xB1 です。(つまり 0x4F + 0xB1 = 0x00)
    フッタ2[CR] (0x0D) [LF] (0x0A) を指定する。

    バイナリ形式

    バイナリ形式は、バイナリで構成されたデータ列にヘッダとチェックサムを付加して送付する方法です。

    例えば 00A01301FF123456をバイナリ形式で表現すると、以下のようになります。

    0xA5 0x5A 0x80 0x08 0x00 0xA0 0x13 0x01 0xFF 0x12 0x34 0x56 0x3D

    定義

    ======元データのバイト数形式におけるバイト数解説
    ヘッダ20xA5 0x5A を指定します。
    データ長2データ長はビッグエンディアン形式の2バイトで、MSB (0x8000) を設定した上、データ部の長さを指定します。
    例えばデータ部の長さが 8 バイトなら0x80 0x08 を指定します。
    データ部NN元データを指定します。
    チェックサム1データ部の各バイトの XOR を計算します。
    例えばデータ部が 00A01301FF123456なら 0x00 xor 0xA0 xor … 0x56 = 0x3D となります。
    フッタ(1)チェックサムが事実上の終端です。無線モジュールからの出力では 0x04 (EOT) が付加されます。

    メソッド

    宣言, begin()

    // serparser_attach : 既存のバッファを用いる
    serparser_attach p1;
    
    uint8_t buff[128];
    p1.begin(ARSER::ASCII, buff, 0, 128);
    
    
    // serparser : Nバイトのバッファを内部に確保する
    serparser p2<128>;
    p2.begin(PARSER::ASCII);
    
    
    // serparser_heap : ヒープ領域にバッファを確保する
    serparser_heap p3;
    p3.begin(PARSER::ASCII, 128);

    宣言にはメモリの確保クラスを指定します。この指定は煩雑であるため、上述のように別名定義を行っています。

    クラス名(別名定義)
    メモリ確保
    内容
    serparser_attachすでにあるバッファをbegin()にて指定する
    serparser_local<N>Nバイトのバッファを内部に確保する
    serparser_heapbegin()メソッドのパラメータで指定したサイズをヒープに確保する

    メモリ確保クラスに応じたbegin()メソッドを呼び出します。

    serparser_attach

    void begin(uint8_t ty, uint8_t *p, uint16_t siz, uint16_t max_siz)

    tyで指定する形式で、pで指定したバッファを用います。バッファの最大長はmax_sizで、バッファの有効データ長をsizで指定します。

    この定義は、特に、データ列を書式出力したい場合に用います(>> 演算子参照)

    serparser_local<N> - 内部にバッファを確保する

    void begin(uint8_t ty)

    tyで指定する形式で初期化を行います。

    serparser_heap - ヒープに確保

    void begin(uint8_t ty, uint16_t siz)

    tyで指定する形式で、sizで指定したサイズをヒープに確保して初期化します。

    get_buf()

    BUFTYPE& get_buf()

    内部バッファを返す。バッファは smplbuf<uint8_t, alloc> 型となります。

    parse()

    inline bool parse(uint8_t b)

    入力文字を処理する。書式入力の入力文字列を1バイト受け取り書式に従い解釈します。例えばASCII書式では:00112233Xのような系列を入力として受け取りますが : 0 0 ... X の順で1バイトずつ入力し、最後の X を入力した時点で書式の解釈を完了し、完了済みと報告します。

    parse()のパラメータは入力バイト、戻り値は解釈完了であればtrueを戻します。

    while (Serial.available()) {
        int c = Serial.read();
    
        if (SerialParser.parse(c)) {
            // 書式解釈完了、b に得られたデータ列(smplbuf<uint8_t>)
            auto&& b = SerialParser.get_buf();
    
            // 以下は得られたデータ列に対する処理を行う
            if (b[0] == 0xcc) {
              // ...
            }
        }
    }

    operator bool()

    operator bool()

    trueならparse()により読み出しが完了した状態で、falseなら解釈中となります。

    例 (parse()の例は以下のように書き換えられる)

    while (Serial.available()) {
        int c = Serial.read();
    
        SerialParser.parse(c);
    
        if(SerialParser) {
            // 書式解釈完了、b に得られたデータ列(smplbuf<uint8_t>)
            auto&& b = SerialParser.get_buf();
            // ...
        }
    }

    << 演算子

    内部バッファを書式形式でストリーム(Serial)に対して出力します。

    uint8_t u8buf[] = { 0x11, 0x22, 0x33, 0xaa, 0xbb, 0xcc };
    
    ser_parser pout;
    pout.begin(ARSER::ASCII, u8buf, 6, 6); // u8bufの6バイトを指定
    
    Serial << pout;// Serialに書式出力 -> :112233AABBCC??[CR][LF]