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) コロンを指定します。

データ部

N

2N

元データの各バイトをアスキー文字列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

定義

======

元データのバイト数

形式におけるバイト数

解説

ヘッダ

2

0xA5 0x5A を指定します。

データ長

2

データ長はビッグエンディアン形式の2バイトで、MSB (0x8000) を設定した上、データ部の長さを指定します。 例えばデータ部の長さが 8 バイトなら0x80 0x08 を指定します。

データ部

N

N

元データを指定します。

チェックサム

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_heap

begin()メソッドのパラメータで指定したサイズをヒープに確保する

メモリ確保クラスに応じた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を戻します。

parse()で読み出し完了になったとき、次のparse()を実行すると読み出し中のステータスに戻ります。

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] 

最終更新