> For the complete documentation index, see [llms.txt](https://palviewer.twelite.info/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://palviewer.twelite.info/1.0/source-code/format-parser.md).

# Format Parser

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

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

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

{% hint style="warning" %}
本プロジェクトに含まれる他のソースコードに依存している場合があります。
{% endhint %}

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

### 読み出し方法

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 = 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 = 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 |
