最適な出力のために、Google Chrome(15以降)または Microsoft Edge(79以降)を推奨いたします。
2024-11-14 現在pktparser
パケットパーサ
pktparser(parser_packet)は、
serparserで変換したバイト列に対して、内容の解釈を行います。
serparser_heap parser_ser;
void setup() {
// init ser parser (heap alloc)
parser_ser.begin(PARSER::ASCII, 256);
}
void loop() {
int c;
while ((c = Serial.read()) >= 0) {
parser_ser.parse(c);
if (parser_ser.available()) {
// get buffer object
auto&& payl = parser_ser.get_buf();
// identify packet type
auto&& typ = identify_packet_type(payl.begin(), payl.end());
// if packet type is TWELITE standard 0x81 message
if (typ == E_PKT::PKT_TWELITE) {
pktparser pkt; // packet parser object
// analyze packet data
typ = pkt.parse<TwePacketTwelite>(payl.begin(), payl.end());
if (typ != E_PKT::PKT_ERROR) { // success!
// get data object
auto&& atw = pkt.use<TwePacketTwelite>();
// display packet inforamtion
Serial << crlf << format("TWELITE: SRC=%08X LQI=%03d "
, app.u32addr_src, app.u8lqi);
Serial << " DI1..4="
<< atw.DI1 ? 'L' : 'H' << atw.DI2 ? 'L' : 'H'
<< atw.DI3 ? 'L' : 'H' << atw.DI4 ? 'L' : 'H';
}
}
}
}
}
上記の例は、標準アプリケーションの0x81メッセージの解釈を行っています。parser_serオブジェクトによりSerialより入力された電文をバイト列に変換します。このバイト列をまずidentify_packet_type()
により電文の種別E_PKT
を特定します。電文の種別が判定できたら次に.parse<TwePacketTwelite>()
により電文を解析します。解析結果はTwePacketTwelite
型になりますが、このオブジェクトを取り出す手続きが.use<TwePacketTwelite>()
です。TwePacketTwelite
型はクラスですが構造体として直接メンバー変数を参照します。
parse<T>
template <class T>
E_PKT parse(const uint8_t* p, const uint8_t* e)
バイト列を解析します。
T
には解析対象のパケット型を指定します。例えば標準アプリケーションの0x81メッセージならTwePacketTwelite
を指定します。
p
とe
はバイト列の先頭と終端の次を指定します。
戻り値はE_PKT
型です。エラーの場合はE_PKT::PKT_ERROR
が戻ります。
user<T>
template
T& use()
解釈したバイト列に対応するパケット型に対応するオブジェクトの参照を返します。事前にparse<T>を実行しエラーがなかった場合に呼び出すせます。
T
はparse<T>
で実行した型と同じもの、または基本的な情報のみ取得できるTwePacket
を指定します。
1 - E_PKT
パケット種別定義
以下のパケットに対応します。
App_Wings の親機で出力されるアスキー書式に対応します。
名前 | 解説 |
---|
PKT_ERROR | パケット解釈前やパケット種別が特定できないなど、TwePacketには意味のあるデータが格納されていない |
PKT_TWELITE | 標準アプリ App_Twelite の 0x81 コマンドを解釈したもの |
PKT_PAL | TWELITE PALのシリアル形式を解釈したもの |
PKT_APPIO | リモコンアプリ App_IO のUARTメッセージを解釈したもの |
PKT_APPUART | シリアル通信アプリ App_UART の拡張書式を解釈したもの。 |
PKT_APPTAG | 無線タグアプリApp_TagのUARTメッセージを解釈したもの。センサ固有部分は解釈されずpayloadとしてバイト列を報告します。 |
PKT_ACT_STD | アクト(Act)のサンプルなどで使用される出力書式。 |
2 - identify_packet_type()
パケット種別の判定
idenify_packet_type()
パケットデータのバイト列を入力として、パケットの種別を判定します。戻り値はE_PKT
です。
E_PKT identify_packet_type(uint8_t* p, uint8_t u8len)
特定のパケットであると解釈できなかった場合はE_PKT::PKT_ERROR
が戻ります。
3 - TwePacket
パケット型
パケット型の基底クラスですが、メンバー構造体common
にはアドレス情報など共通情報が含まれます。
class TwePacket {
public:
static const E_PKT _pkt_id = E_PKT::PKT_ERROR;
struct {
uint32_t tick; // 解釈実行時のシステム時刻[ms]
uint32_t src_addr; // 送信元アドレス(シリアル番号)
uint8_t src_lid; // 送信元アドレス(論理アドレス)
uint8_t lqi; // LQI
uint16_t volt; // 電圧[mV]
} common;
};
種別を混在してpktparser
型として配列等に格納するような場合に、アドレス情報などを最小限の情報を取得したい場合に使用します。
3.1 - TwePacketTwelite
App_Tweliteからのパケット
TwePacketTwelite
クラスは、標準アプリ
App_Tweliteの0x81コマンドを解釈したものです。
class TwePacketTwelite : public TwePacket, public DataTwelite { ... };
パケットデータ内の諸情報はparse<TwePacketTwelite>()
実行後にパケット情報がDataTwelite
に格納されます。
DataTwelite
構造体
struct DataTwelite {
//送信元のシリアル#
uint32_t u32addr_src;
// 送信元の論理ID
uint8_t u8addr_src;
// 宛先の論理ID
uint8_t u8addr_dst;
// 送信時のタイムスタンプ
uint16_t u16timestamp;
// 低レイテンシ送信時のフラグ
bool b_lowlatency_tx;
// リピート中継回数
uint16_t u8rpt_cnt;
// LQI値
uint16_t u8lqi;
// DIの状態 (true がアクティブ Lo,GND)
bool DI1, DI2, DI3, DI4;
// DIの状態ビットマップ (LSBから順にDI1,2,3,4)
uint8_t DI_mask;
// DIアクティブならtrue (過去にアクティブになったことがある)
bool DI1_active, DI2_active, DI3_active, DI4_active;
// DIのアクティブビットマップ(LSBから順にDI1,2,3,4)
uint8_t DI_active_mask;
// モジュールの電源電圧[mV]
uint16_t u16Volt;
// AD値 [mV]
uint16_t u16Adc1, u16Adc2, u16Adc3, u16Adc4;
// ADがアクティブ(有効)なら 1 になるビットマップ (LSBから順にAD1,2,3,4)
uint8_t Adc_active_mask;
};
3.2 - TwePacketIO
App_IOからのパケット
TwePacketAppIO
クラスは、標準アプリ
App_IOのシリアルメッセージ(0x81)を解釈したものです。
class TwePacketAppIO : public TwePacket, public DataAppIO { ... };
パケットデータ内の諸情報はparse<TwePacketIO>()
実行後にDataTwelite
に格納されます。
DataAppIO
構造体
struct DataAppIO {
//送信元のシリアル#
uint32_t u32addr_src;
// 送信元の論理ID
uint8_t u8addr_src;
// 宛先の論理ID
uint8_t u8addr_dst;
// 送信時のタイムスタンプ
uint16_t u16timestamp;
// 低レイテンシ送信時のフラグ
bool b_lowlatency_tx;
// リピート中継回数
uint16_t u8rpt_cnt;
// LQI値
uint16_t u8lqi;
// DIの状態ビットマップ (LSBから順にDI1,2,3,4,...)
uint8_t DI_mask;
// DIのアクティブ(使用なら1)ビットマップ(LSBから順にDI1,2,3,4,...)
uint8_t DI_active_mask;
// DIが割り込み由来かどうかのビットマップ(LSBから順にDI1,2,3,4,...)
uint16_t DI_int_mask;
};
3.3 - TwePacketUART
App_UARTからのパケット
TwePacketAppUart
クラスは、App_UARTの拡張書式を親機・中継機アプリApp_Wingsで受信したときの形式です。
class TwePacketAppUART : public TwePacket, public DataAppUART
パケットデータ内の諸情報はparse<TwePacketUART>()
実行後にDataAppUART
に格納されます。
簡易形式は解釈できません。parse<TwePacketUART>()
ではE_PKT::PKT_ERROR
を戻します。内容を確認するには元のバイト列を直接参照してください。
DataAppUART
構造体
struct DataAppUART {
/**
* source address (Serial ID)
*/
uint32_t u32addr_src;
/**
* source address (Serial ID)
*/
uint32_t u32addr_dst;
/**
* source address (logical ID)
*/
uint8_t u8addr_src;
/**
* destination address (logical ID)
*/
uint8_t u8addr_dst;
/**
* LQI value
*/
uint8_t u8lqi;
/**
* Response ID
*/
uint8_t u8response_id;
/**
* Payload length
*/
uint16_t u16paylen;
/**
* payload
*/
##if MWX_PARSER_PKT_APPUART_FIXED_BUF == 0
mwx::smplbuf_u8_attach payload;
##else
mwx::smplbuf_u8<MWX_PARSER_PKT_APPUART_FIXED_BUF> payload;
##endif
};
payload
はデータ部分ですが、マクロ定義によってデータ格納の方法が変わります。
MWX_PARSER_PKT_APPUART_FIXED_BUF
の値が0
としてコンパイルした場合は、payload
はパケット解析を行うバイト列を直接参照します。元のバイト列の値が変更されるとpayload
中のデータは破壊されます。
MWX_PARSER_PKT_APPUART_FIXED_BUF
の値を0
より大きい値として定義した場合は、payload
にはその値(バイト数)のバッファが確保されます。ただしシリアル電文のデータがバッファサイズを超えた場合はparse<TwePacketAppUART>()
は失敗しE_PKT::PKT_ERROR
を戻します。
3.4 - TwePacketPAL
App_PALからのパケット
TwePacketPal
クラスは、TWELITE PALのパケットデータを解釈したものです。このクラスはTWELITE PAL(センサーデータなど上り方向)共通に取り扱います。
class TwePacketPal : public TwePacket, public DataPal { ... };
PAL共通データはDataPal
に定義されています。
PALの各センサー基板特有のデータを取り出すためのジェネレータ関数を用意しています。
DataPal
構造体
PALは接続されるセンサーなどによってパケットデータ構造が異なりますが、DataPal
では共通部のデータ構造を保持します。
struct DataPal {
uint8_t u8lqi; // LQI値
uint32_t u32addr_rpt; // 中継器のアドレス
uint32_t u32addr_src; // 送信元のアドレス
uint8_t u8addr_src; // 送信元の論理アドレス
uint16_t u16seq; // シーケンス番号
E_PAL_PCB u8palpcb; // PAL基板の種別
uint8_t u8palpcb_rev; // PAL基板のレビジョン
uint8_t u8sensors; // データに含まれるセンサーデータの数 (MSB=1はエラー)
uint8_t u8snsdatalen; // センサーデータ長(バイト数)
union {
const uint8_t *au8snsdata; // センサーデータ部への参照
uint8_t _pobj[MWX_PARSER_PKT_APPPAL_FIXED_BUF]; // 各センサーオブジェクト
};
};
PALのパケットデータ構造は大まかに2つのブロックからなり、全てのPAL共通部と個別のデータ部になります。個別のデータ部は、パケットの解釈を行わずそのまま格納しています。取り扱いを単純化するため32バイトを超えるデータは動的に確保するuptr_snsdata
に格納します。
個別のデータ部は、PalBase
をベースクラスに持つ構造体に格納されます。この構造体は、TwePacketPal
に定義されるジェネレータ関数により生成されます。
parse<TwePacketPAL>()
実行時にMWX_PARSER_PKT_APPPAL_FIXED_BUF
に収まるサイズであれば、センサー個別のオブジェクトを生成します。
収まらない場合はau8snsdata
に解析時のバイト列の参照が保存されます。この場合、解析に用いたバイト列のデータが書き換えられた場合は、センサー個別のオブジェクトは生成できなくなります。
PalBase
PALの各センサーのデータ構造体はすべてPalBase
を継承します。センサーデータの格納状況u32StoredMask
が含まれます。
struct PalBase {
uint32_t u32StoredMask; // 内部的に利用されるデータ取得フラグ
};
PalEvent
PALイベントは、センサーなどの情報を直接送るのではなく、センサー情報を加工し一定の条件が成立したときに送信される情報です。例えば加速度センサーの静止状態から一定以上の加速度が検出された場合などです。
struct PalEvent {
uint8_t b_stored; // 格納されていたら true
uint8_t u8event_source; // 予備
uint8_t u8event_id; // イベントID
uint32_t u32event_param;// イベントパラメータ
};
イベントデータが存在する場合はTwePacketPal
の.is_PalEvent()
がtrue
になることで判定でき、.get_PalEvent()
によりPalEvent
データ構造を得られます。
ジェネレータ関数
センサーPALの各種データを取り出すためのジェネレータ関数です。
void print_pal(pktparser& pkt) {
auto&& pal = pkt.use<TwePacketPal>();
if (pal.is_PalEvent()) {
PalEvent obj = pal.get_PalEvent();
} else
switch(pal.u8palpcb) {
case E_PAL_PCB::MAG:
{
// generate pal board specific data structure.
PalMag obj = pal.get_PalMag();
} break;
case E_PAL_PCB::AMB:
{
// generate pal board specific data structure.
PalAmb obj = pal.get_PalAmb();
} break;
...
default: ;
}
}
ジェネレータ関数を利用するには、まずpkt
がイベントかどうか判定(.is_PalEvent()
)します。イベントの場合はget_PalEvent()
を持ちます。それ以外はu8palpcb
に応じてオブジェクトを生成します。
get_PalMag()
PalMag get_PalMag()
// MAG
struct PalMag : public PalBase {
uint16_t u16Volt; // モジュール電圧[mV]
uint8_t u8MagStat; // 磁気スイッチの状態 [0:磁石なし,1,2]
uint8_t bRegularTransmit; // MSB flag of u8MagStat
};
.u8palpcb==E_PAL_PCB::MAG
の場合、開閉センサーパルのデータPalMag
を取り出します。
get_PalAmb()
PalAmb get_PalAmb()
// AMB
struct PalAmb : public PalBase {
uint16_t u16Volt; // モジュール電圧[mV]
int16_t i16Temp; // 温度(100倍値)
uint16_t u16Humd; // 湿度(100倍値)
uint32_t u32Lumi; // 照度(Lux相当)
};
.u8palpcb==E_PAL_PCB::AMB
の場合、環境センサーパルのデータPalAmb
を取り出します。
get_PalMot()
PalMot get_PalMot()
// MOT
struct PalMot : public PalBase {
uint16_t u16Volt; // モジュール電圧[mV]
uint8_t u8samples; // サンプル数
uint8_t u8sample_rate_code; // サンプルレート (0: 25Hz, 4:100Hz)
int16_t i16X[16]; // X 軸
int16_t i16Y[16]; // Y 軸
int16_t i16Z[16]; // Z 軸
};
.u8palpcb==E_PAL_PCB::MOT
の場合、動作センサーパルのデータPalMot
を取り出します。
get_PalEvent()
PalEvent get_PalEvent()
// PAL event
struct PalEvent {
uint8_t b_stored; // trueならイベント情報あり
uint8_t u8event_source; // イベント源
uint8_t u8event_id; // イベントID
uint32_t u32event_param; // 24bit、イベントパラメータ
};
.is_PalEvent()
がtrue
の場合PalEvent
(PALイベント)を取り出します。