# Format Parser

{% hint style="info" %}
[TWELITE PAL 親機の書式フォーマット ](https://wings.twelite.info/how-to-use/parent-mode/receive-message/app_pal)(ASCII形式のみ) を解釈しています。多くはその定義に従います。
{% endhint %}

{% hint style="warning" %}
Version 1.0 では書式フォーマットの解釈を VB.NET にて実装していましたが、v1.2 では C# による実装となりました。

当アプリのビルドでは PAL\_PARSER プロジェクト（ターゲットフレームワーク .NET Framework 4, クラスライブラリ）が該当し、VB.NET 側の PAL\_VIEWER プロジェクトから参照関係になっています。

本書では VB からの呼び出し例として記載します。
{% endhint %}

TWELITE PAL / ARIA / CUE の無線パケットは [App\_Wings ](https://wings.twelite.info/)を書き込んだ MONOSTICK などで受信します。この受信データは `:80000...<CR><LF>` といった電文で、データ量も多く複数の形式になるためデータの取り出しが容易では有りません。ここでは .NET 開発環境家で、この解釈処理を行うためのライブラリについて解説します。

PAL の書式フォーマットの構造は、大まかには、共通データ部とセンサーデータ部に分別されます。センサーデータ部は\[センサーデータ]のブロックが並んでいる構造で、PALの種別などによって数と種類は変わります。

```
[共通ヘッダ]{[センサーデータ1][センサーデータ2]...[センサーデータn]}
```

以下に挙げた関数とクラスを受信データ解釈に用います。

<table><thead><tr><th>関数とクラス</th><th>解説</th><th data-hidden></th></tr></thead><tbody><tr><td><code>PAL_Utils.genDataPresentation()</code></td><td>データ列の解釈を行う</td><td></td></tr><tr><td><code>ClsDataFormatPalApp</code></td><td>共通ヘッダ部の解釈データ</td><td></td></tr><tr><td><code>ClsDataPayloadPalSensors</code></td><td>センサーデータ部</td><td></td></tr></tbody></table>

### 関連ソースファイル

以下のソースコードにより PAL 親機より出力されるデータを解釈します。

※ ソースコードは[パルアプリビューアのサイト](https://mono-wireless.com/jp/products/TWE-APPS/App_pal/palviewer.html)より入手ください。

| ファイル名                       | 内容                                                                                       |
| --------------------------- | ---------------------------------------------------------------------------------------- |
| ITweDataPresentation.cs     | UART 電文のエンコード(ASCII 書式)を解釈する。解釈ができれば、ITweDataFormat による解釈も行う。                            |
| ClsDataPresentationAscii.cs | ASCII書式 `:800...<CR><LF>` の解釈。                                                           |
| ITweDataFormat.cs           | 上記 ASCII 書式で解釈されたデータ書式を表現する（アドレス情報など共通情報や、データ書式内のデータ構造など）。また書式を解釈後、ITweDataPayloadを生成する。 |
| ClsDataFormatPAL.cs         | PAL のデータ書式を解釈する。                                                                         |
| ITweDataPayload.cs          | センサー情報など各データを表現する。                                                                       |
| ClsDataPayloadPalSensors.cs | SENSE PAL の個別センサーの集約データ型。                                                                |
| ClsDataPalSenseElement.cs   | SENSE PAL の単独センサーのデータ型。                                                                  |
| MUtils.cs                   | ITWE??? 抽象型より、適切なクラスの生成を行うジェネレータや、諸ユーティリティ。                                              |

### プロジェクトへの組み込み方法

上記は Visual Studio (2019を想定) で、プロジェクト定義されたライブラリなどを参照する手順です。詳細はマニュアルや一般の情報を参照ください。

1. PAL\_PARSER ディレクトリを開発プロジェクト配下の適当な場所にコピーします。
2. Visual Studio の\[ソリューション]にPAL\_PARSER プロジェクトを追加します。
3. 開発プロジェクト中のプロジェクト\[プロパティ]>\[参照設定]にPARL\_PARSERを追加します。
4. 利用するソースコードの先頭部で Imports MONOW\_PAL\_PARSER を追加します。

上記参照設定を行えば、ソースコード中で PAL\_PARSER ライブラリのクラスなどが参照可能になります。

### 読み出し方法

TWELITE PAL Viewer では、`SerialPort1` の `.DataRecieved`イベントを起点として、書式の解釈が行われます。

以下のコード例(VB.NET)は、シリアルポートからのデータを String型の文字列 ( `:80000000CF0002` ) として受け取り、内容を解釈した後、解釈文字列として戻す関数です。（一例で、すべてのデータ要素やセンサーに対応したコードではありません）

* [VB.NET](https://palviewer.twelite.info/source-code/format-parser/sample-vb.net)
* [C#](https://palviewer.twelite.info/source-code/format-parser/sample-c)

以下は、VB.NET のコードを例に解説しています。

エラー処理は、*Try Catch* 構文で、まとめて例外処理しています。内部からのエラー時には `throw new Exception();` といった例外が発生します。

まず、解釈のために文字列をバイト列に変換して、`genDataPresentation()` により、データ解釈を行います。実行後、解釈済みの`ClsDataPresentationAscii`オブジェクトが生成されます。（末尾の改行コードが省略された場合を想定して`dataText & vbCr` と CR コードを追記した上、念の為末尾をCRの連続と変換しています。PAL\_PARSERは末尾 CR (\&H0D) を終端と処理しています）

```
' String -> Byte()
Dim b() As Byte = System.Text.Encoding.ASCII.GetBytes(dataText & vbCr)
' 末尾のコントロール文字を CR(&H0D) に書き換え
For i = b.Length - 1 To 0 Step -1 
    If b(i) < &H20 Then b(i) = &HD Else Exit For
Next
' :8000... を解釈しバイナリ列に[80 00 ...]に変換し、書式の解釈まで行う
Dim dataArrival = PAL_Utils.genDataPresentation(b)
```

続いて、データ書式、センサー情報を取り出します。`dataFmt` はデータ書式で、アドレス情報などを得ることができます。`dataPay`はセンサー情報で複数のセンサーの情報をひとまとめにしています。

```
Dim dataFmt As ClsDataFormatPalApp = dataArrival.objFormat 'データ形式、無線ノードの情報
Dim dataPay As ClsDataPayloadPalSensors = dataFmt.objPayload '各種センサー情報
```

データ書式(`ClsDataFormatPalApp`)で得られる情報を列挙します。

| 名前           |            | 内容                                                                                                           |
| ------------ | ---------- | ------------------------------------------------------------------------------------------------------------ |
| `BLQI`       | *Byte*     | LQI（受信感度相当）情報                                                                                                |
| `UsDataSer`  | *UShort*   | 続き番号                                                                                                         |
| `BBalPCB`    | *Byte*     | SENSE PAL 種別識別子                                                                                              |
| `BSrcAddr`   | *Byte*     | SENSE PAL の論理ID                                                                                              |
| `UiSrcAddr`  | *UInteger* | SENSE PAL のアドレス                                                                                              |
| `UiRepeater` | *UInteger* | <p>配送経路（<code>\&H80000000UI</code> なら直接、それ以外の場は最後に配送した中継器のアドレス）</p><p>※ PAL アプリの設定によって中継器のアドレスの定義は変化します。</p> |

次にセンサーの情報を得ます。`dataPay.SensoerCode()` により、センサーの種別を指定して情報を得ることができます。戻り型は`List(Of ClsDataPalSenseElement)`で、０個以上の要素が格納されます（Nothingにはならない）。ここでは電圧関連(`ClsDataPalSenseElement.E_SNSCD.VOLT`)のリストを探索します。

```
Dim l = dataPay.SensorCode(ClsDataPalSenseElement.E_SNSCD.VOLT)
```

ここでは、電源電圧(`ClsDataPalSenseElement.E_EXCD_VOLT.POWER`)の情報が欲しいので、リストの中にあるか探索します。見つかったらローカル変数 `iVolt`に値を格納します。

```
For Each m In l
    If m.Ex = ClsDataPalSenseElement.E_EXCD_VOLT.POWER Then
        iVolt = m.Data(0)
    End If
Next
```

#### ClsDataPalSenseElement クラス

このクラスは、各センサーの単一のデータを表現します。以下にデータの取り出しのためのプロパテを列挙します。

| 名前           | 型                      | 内容                                                                                                                                                                        |
| ------------ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `IsError`    | *Boolean*              | データエラーの場合は *True* となる。                                                                                                                                                    |
| `ErrorCode`  | *Byte*                 | エラーコードが入ります。                                                                                                                                                              |
| `Data`       | *Object(Byte,Shortなど)* | <p>センサーのデータを格納します。エラーなどで <em>Nothing</em> になる場合があります。データについては要素数が１つであっても配列型となります。<br>例えば <em>Byte</em>型のデータが一つだけ含まれる場合であっても <code>Byte(0)</code> で宣言された配列オブジェクトとなります。</p> |
| `SensorCode` | *Byte*                 | センサー種別が入ります。                                                                                                                                                              |
| `Ex`         | *Object(Byte)*         | 拡張データが入ります。主に電圧情報など、センサー種別が同じでも、複数ある場合に使われます。                                                                                                                             |
|              |                        |                                                                                                                                                                           |

センサーの種別を調べるための列挙型`ClsDataPalSenseElement.E_SNDCD`の定義は以下です。

| 名前     | 内容       |
| ------ | -------- |
| `HALL` | 開閉磁気センサー |
| `TEMP` | 温度センサー   |
| `HUMD` | 湿度センサー   |
| `LUMI` | 照度センサー   |
| `VOLT` | 電圧       |

電圧センサーの種別を特定するための列挙型`ClsDataPalSenseElement.E_EXCD_VOLT`は以下です。

| 名前      | 内容   |
| ------- | ---- |
| `POWER` | 電源電圧 |
| `ADC1`  | ADC1 |
