# Parent\_MONOSTICK

MONOSTICKを親機として使用するアクトです。子機からのパケットのデータペイロードをシリアルポートに出力します。

{% hint style="success" %}
このアクトの解説の前に[BRD\_APPTWELITEの解説](/v0.1.6/act_samples/brd_apptwelite.md)をご覧ください。
{% endhint %}

## アクトの機能

* サンプルアクトの子機からのパケットを受信して、アスキー形式で出力する。

## アクトの使い方

### 必要なTWELITEと配線

| 役割 | 例                                                                                                                                                                                                                                                           |
| -- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 親機 | [MONOSTICK BLUEまたはRED](https://mono-wireless.com/jp/products/MoNoStick/)                                                                                                                                                                                    |
| 子機 | サンプルアクトの子機設定 (例: [BLUE PAL または RED PAL](https://mono-wireless.com/jp/products/twelite-pal/BnR/index.html) +[AMBIENT SENSE PAL](https://mono-wireless.com/jp/products/twelite-pal/sense/amb-pal.html)に[PAL\_AMBアクト](/v0.1.6/act_samples/pal_amb.md)を書き込んだもの) |

## アクトの解説

### インクルード

```cpp
// use twelite mwx c++ template library
#include <TWELITE>
#include <NWK_SIMPLE>
#include <MONOSTICK>
```

MONOSTICK用のボードビヘイビア[`<MONOSTICK>`](/v0.1.6/boards/less-than-monostick-greater-than.md)をインクルードしています。このボードサポートには、LEDの制御、ウォッチドッグ対応が含まれます。

### setup()

```cpp
void setup() {
	/*** SETUP section */
	auto&& brd = the_twelite.board.use<MONOSTICK>();
	brd.set_led_red(LED_TIMER::ON_RX, 200); // RED (on receiving)
	brd.set_led_yellow(LED_TIMER::BLINK, 500); // YELLOW (blinking)

	// the twelite main class
	the_twelite
		<< TWENET::appid(APP_ID)    // set application ID (identify network group)
		<< TWENET::channel(CHANNEL) // set channel (pysical channel)
		<< TWENET::rx_when_idle();  // open receive circuit (if not set, it can't listen packts from others)

	// Register Network
	auto&& nwksmpl = the_twelite.network.use<NWK_SIMPLE>();
	nwksmpl << NWK_SIMPLE::logical_id(0x00); // set Logical ID. (0x00 means parent device)

	/*** BEGIN section */
	the_twelite.begin(); // start twelite!

	/*** INIT message */
	Serial << "--- MONOSTICK_Parent act ---" << mwx::crlf;
}
```

ボードサポートの使用とLEDの動作を設定しています。

```cpp
auto&& brd = the_twelite.board.use<MONOSTICK>();
brd.set_led_red(LED_TIMER::ON_RX, 200); // RED (on receiving)
brd.set_led_yellow(LED_TIMER::BLINK, 500); // YELLOW (blinking)
```

2行目では赤色のLEDを無線パケットを受信したら200ms点灯する設定をしています。最初のパラメータは`LED_TIMER::ON_RX`が無線パケット受信時を意味します。２番目は点灯時間をmsで指定します。

3行目はLEDの点滅指定です。１番目のパラメータは`LED_TIMER::BLINK`が点滅の指定で、２番目のパラメータは点滅のON/OFF切り替え時間です。500msごとにLEDが点灯、消灯(つまり１秒周期の点滅)を繰り返します。

```cpp
auto&& nwksmpl = the_twelite.network.use<NWK_SIMPLE>();
nwksmpl << NWK_SIMPLE::logical_id(0x00);
```

ここでは`NWK_SIMPLE::logical_id(0x00)`を設定し親機(論理ID=0x00)であることを指定します。

### loop()

パケットを受信したとき、その内容を表示します。ここでは２種類の表示を行っています。

```cpp
void loop() {
	// receive RF packet.
    while (the_twelite.receiver.available()) {
		auto&& rx = the_twelite.receiver.read();

		Serial << ".. coming packet (" << int(millis()&0xffff) << ')' << mwx::crlf;

		// output type1 (raw packet)
		//   uint8_t  : 0x01
		//   uint8_t  : src addr (LID)
		//   uint32_t : src addr (long)
		//   uint32_t : dst addr (LID/long)
		//   uint8_t  : repeat count
		//     total 11 bytes of header.
		//     
		//   N        : payload
		{
		  serparser_attach pout;
			pout.begin(PARSER::ASCII, rx.get_psRxDataApp()->auData, 
			    rx.get_psRxDataApp()->u8Len, rx.get_psRxDataApp()->u8Len);

			Serial << "RAW PACKET -> ";
			pout >> Serial;
			Serial << mwx::flush;
		}

		// output type2 
		{
			smplbuf_u8<128> buf;
			mwx::pack_bytes(buf
				, uint8_t(rx.get_addr_src_lid())		// src addr (LID)
				, uint8_t(0xCC)							        // cmd id (0xCC, fixed)
				, uint8_t(rx.get_psRxDataApp()->u8Seq)	// seqence number
				, uint32_t(rx.get_addr_src_long())	// src addr (long)
				, uint32_t(rx.get_addr_dst())			  // dst addr
				, uint8_t(rx.get_lqi())					    // LQI
				, uint16_t(rx.get_length())				  // payload length
				, rx.get_payload() 					      	// payload
			);

			serparser_attach pout;
			pout.begin(PARSER::ASCII, buf.begin(), buf.size(), buf.size());
			
			Serial << "FMT PACKET -> ";
			pout >> Serial;
			Serial << mwx::flush;
		}
	}
}
```

最初の出力は`<NWK_SIMPLE>`の制御データを含めたデータをすべて表示します。制御データは11バイトあります。通常は制御情報を直接参照することはありませんが、あくまでも参考です。

```cpp
serparser_attach pout;
pout.begin(PARSER::ASCII, rx.get_psRxDataApp()->auData, 
    rx.get_psRxDataApp()->u8Len, rx.get_psRxDataApp()->u8Len);

Serial << "RAW PACKET -> ";
pout >> Serial;
Serial << mwx::flush;

// 参考：制御部のパケット構造
// uint8_t  : 0x01 固定
// uint8_t  : 送信元のLID
// uint32_t : 送信元のロングアドレス(シリアル番号)
// uint32_t : 宛先アドレス
// uint8_t  : 中継回数
```

1行目は出力用のシリアルパーサをローカルオブジェクトとして宣言しています。内部にバッファを持たず、外部のバッファを流用し、パーサーの出力機能を用いて、バッファ内のバイト列を書式出力します。

２行目はシリアルパーサーのバッファを設定します。すでにあるデータ配列、つまり受信パケットのペイロード部を指定します。`serparser_attach pout`は、既にあるバッファを用いたシリアルパーサーの宣言です。`pout.begin()`の１番目のパラメータは、パーサーの対応書式を`PARSER::ASCII`つまりアスキー形式として指定しています。２番目はバッファの先頭アドレス。３番目はバッファ中の有効なデータ長、４番目はバッファの最大長を指定します。出力用で書式解釈に使わないため４番目のパラメータは３番目と同じ値を入れています。

6行目でシリアルポートへ`>>`演算子を用いて出力しています。

7行目の`Serial << mwx::flush`は、ここで出力が終わっていないデータの出力が終わるまで待ち処理を行う指定です。(`Serial.flush()`も同じ処理です)

２番目の出力はより実践的です。ユーザが定義した並び順で書式を構成します。

```cpp
smplbuf_u8<128> buf;
mwx::pack_bytes(buf
	, uint8_t(rx.get_addr_src_lid())		   // 送信元の論理ID
	, uint8_t(0xCC)											   // 0xCC
	, uint8_t(rx.get_psRxDataApp()->u8Seq) // パケットのシーケンス番号
	, uint32_t(rx.get_addr_src_long())		 // 送信元のシリアル番号
	, uint32_t(rx.get_addr_dst())			     // 宛先アドレス
	, uint8_t(rx.get_lqi())					       // LQI:受信品質
	, uint16_t(rx.get_length())				     // 以降のバイト数
	, rx.get_payload() 						         // データペイロード
);

serparser_attach pout;
pout.begin(PARSER::ASCII, buf.begin(), buf.size(), buf.size());

Serial << "FMT PACKET -> ";
pout >> Serial;
Serial << mwx::flush;
```

1行目はアスキー書式に変換する前のデータ列を格納するバッファをローカルオブジェクトとして宣言しています。

2行目は`pack_bytes()`を用いてデータ列を先ほどの`buf`に格納します。データ構造はソースコードのコメントを参照ください。`pack_bytes()`のパラメータには`smplbuf_u8 (smplbuf<uint8_t, ???>)`形式のコンテナを指定することもできます。

{% hint style="info" %}
パケットのシーケンス番号は、`<NWK_SIMPLE>`で自動設定され、送信パケット順に割り振られます。この値はパケットの重複検出に用いられます。

LQI (Link Quality Indicator)は受信時の電波強度に相当する値で、値が大きければ大きいほどより強い電界強度で受信できていることになります。ただしこの値と物理量との厳格な関連は定義されていませんし、環境のノイズと相対的なものでLQIがより大きな値であってもノイズも多ければ通信の成功率も低下することになります。
{% endhint %}

13,14,17行目は、シリアルパーサーの宣言と設定、出力です。


---

# 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://mwx.twelite.info/v0.1.6/act_samples/parent_monostick.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.
