# Format Parser

{% hint style="info" %}
[TWELITE PAL 親機の書式フォーマット](https://mono-wireless.com/jp/products/TWE-APPS/App_pal/parent.html) (ASCII形式のみ) を解釈しています。多くはその定義に従います。
{% endhint %}

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

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

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

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

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

| ファイル名                       | 内容                                                                                       |
| --------------------------- | ---------------------------------------------------------------------------------------- |
| 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??? 抽象型より、適切なクラスの生成を行うジェネレータや、諸ユーティリティ。                                              |

### 読み出し方法

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

以下のコード例では、`CSnsData`クラスにデータをコピーしています。

```
    ' event handler when got data from serial port
    Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
        Dim strDataReceived As String
        Dim bFlag As Boolean = True

        While SerialPort1.BytesToRead > 0
            Try
                strDataReceived = SerialPort1.ReadLine
            Catch ex As Exception
                strDataReceived = ex.Message
                bFlag = False
            End Try

            If bFlag Then
                Try
                    '' PAL 標準フォーマットを解釈する
                    Dim b() As Byte = System.Text.Encoding.ASCII.GetBytes(strDataReceived)
                    Dim dataArrival = PAL_Utils.genDataPresentation(b)

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

                    '' CSnsData 形式に変換
                    Dim snsdt As CSnsData = New CSnsData
                    snsdt.bStored = True
                    ' LQI
                    snsdt.iLQI = dataFmt.BLQI : snsdt.bLQI = True
                    ' 続き番号
                    snsdt.iSeq = dataFmt.UsDataSer
                    ' 名前ラベル
                    Dim iPalPcb_CD As UInteger = (dataFmt.BPalPcb And &HF)
                    Dim sPalPcb_Name As String
                    Select Case iPalPcb_CD
                        Case 0
                            sPalPcb_Name = "nc"
                        Case 1
                            sPalPcb_Name = "OnC"
                        Case 2
                            sPalPcb_Name = "AMB"
                        Case Else
                            sPalPcb_Name = "UNK"
                    End Select
                    snsdt.sID = sPalPcb_Name + dataFmt.BSrcAddr.ToString("_00")
                    ' 電圧
                    Dim l = dataPay.SensorCode(ClsDataPalSenseElement.E_SNSCD.VOLT)
                    For Each m In l
                        If m.Ex = ClsDataPalSenseElement.E_EXCD_VOLT.POWER Then
                            snsdt.iVolt = l(0).Data(0) : snsdt.bVolt = True
                        End If
                    Next
                    ' OpnCls状態
                    l = dataPay.SensorCode(ClsDataPalSenseElement.E_SNSCD.HALL)
                    If l.Count > 0 Then
                        snsdt.iPC = (l(0).Data(0) And &H7F) : snsdt.bPC = True
                    End If

                    ' TEMP
                    l = dataPay.SensorCode(ClsDataPalSenseElement.E_SNSCD.TEMP)
                    If l.Count > 0 Then
                        Try
                            snsdt.fTemp = CSng(l(0).Data(0)) / 100.0
                            snsdt.bTemp = True
                        Catch ex As Exception
                            snsdt.bTemp = False
                        End Try
                    End If

                    ' HUMD
                    l = dataPay.SensorCode(ClsDataPalSenseElement.E_SNSCD.HUMD)
                    If l.Count > 0 Then
                        Try
                            snsdt.fHumid = CSng(l(0).Data(0)) / 100.0
                            snsdt.bHumid = True
                        Catch ex As Exception
                            snsdt.bHumid = False
                        End Try
                    End If

                    ' LIGHT
                    l = dataPay.SensorCode(ClsDataPalSenseElement.E_SNSCD.LUMI)
                    If l.Count > 0 Then
                        Try
                            snsdt.iLight = CInt(l(0).Data(0))
                            snsdt.bLight = True
                        Catch ex As Exception
                            snsdt.bHumid = False
                        End Try
                    End If

                    ' データ
                    snsObjs.AddEntryTemporary(snsdt, thetime)
                    snsObjsLong.AddEntryTemporary(snsdt, thetime)
                    SaveRawLog(snsdt)

                Catch ex As Exception
                    bFlag = False
                End Try


            End If

        End While

    End Sub
```

まず、解釈のために文字列をバイト列に変換して、`genDataPresentation()` により、データ解釈を行います。実行後、解釈済みの`ClsDataPresentationAscii`オブジェクトが生成されます。

```
Dim b() As Byte = System.Text.Encoding.ASCII.GetBytes(strDataReceived)
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>配送経路（\&H80000000UI なら直接、それ以外の場は最後に配送した中継器のアドレス）</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`)の情報が欲しいので、リストの中にあるか探索します。

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

#### ClsDataPalSenseElement クラス

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

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

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

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

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

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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://palviewer.twelite.info/1.2/source-code/format-parser.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
