こんにちは、ENGかぴです。
トワイライト(TWELITE)でMWSTAGEのライブラリであるNWK_SIMPLEを使用すると通信先を選択した無線通信ができます。親機と論理IDが異なる2つの子機を使ってブロードキャスト通信と個別の送信を行い動作確認を行いました。
トワイライトを太陽光パネルで動作させたことやMWSTAGEの環境でソフト開発して無線通信したことなどについてまとめています。
トワイライト(TWELITE)のソフト開発と無線通信でできること
共通の設定事項

モノワイヤレス社が提供しているNWK_SIMPLEのライブラリを使用することで通信先を指定した無線通信ができます。親局の論理IDは0x00になりますが、子機は0x01~0xEFまでの指定することができます。詳細は下記リンクを参考にしてください。
今回は論理IDを区別した無線通信と子機を対象としたブロードキャスト通信(0xFE)の動作についてまとめています。親機と子機でアプリケーションID・チャンネル番号・アプリ識別のための文字列を共通にする必要があります。
const uint32_t APP_ID = 0x1234abcd; // application ID
const uint8_t CHANNEL = 13; // channel
const char APP_CHAR[] = "COM";
TWENETに上記で定数宣言しているAPP_IDとCHANNELを指定して設定します。
the_twelite
    << TWENET::appid(APP_ID) //アプリケーションID
    << TWENET::channel(CHANNEL) //チャンネル設定
    << TWENET::rx_when_idle(); //無線通信を受信する場合は実装
無線通信を受信する場合はrx_when_idle()を実装する必要があります。子機は親機からの受信が必要なのでrx_when_idle()を実装する必要がありますが、親機で送信専用にする場合は実装の必要はありません。
PR:スキマ時間で自己啓発!スマホで学べる人気のオンライン資格講座【スタディング】まずは気になる講座を無料で体験しよう!
親機を実装する
auto&& nwksmpl = the_twelite.network.use<NWK_SIMPLE>();
       nwksmpl << NWK_SIMPLE::logical_id(0x00);
TWENETライブラリのnetwork関数を使用して論理IDの設定を行います。ネットワークのlogical_idに0x00をセットすることで親機として動作します。
MWX_APIRET transmit(void) {
    uint8_t txadrs;
    
    //送信先を選択する処理(省略)
    if (auto&& pkt = the_twelite.network.use<NWK_SIMPLE>().prepare_tx_packet()) {
	pkt << tx_addr(txadrs)  //送信先を指定
            << tx_retry(0x3) 
	    << tx_packet_delay(0,0,2);
        pack_bytes(pkt.get_payload(), make_pair(APP_CHAR, 3));//ヘッダー
        pack_bytes(pkt.get_payload(),do_out); //do_outをパッケージ化する
	return pkt.transmit(); //パケットを送信
    }
}
無線でデータを送信するためにはデータをペイロードに格納しネットワークオブジェクトのthe_twelite.network.use<MWK_SIMPLE>()のtransmit()関数を発行します。
tx_addr()に送信先の子機の論理IDを指定します。子機全体にブロードキャスト通信を行う場合は0xFEを指定します。tx_retryは送信失敗した時のリトライ回数です。
tx_packet_delay()の第1引数は送信開始までの最低待ち時間、第2引数が最長待ち時間です。2つとも0を指定しているので条件とタイミング次第で直ちに送信します。第3引数は再送間隔で最初のパケットを送って失敗した場合2ms間隔で再送を行います。
送信設定後はペイロードに自分が送りたいデータを格納します。ペイロードの準備が完了したら。ネットワークオブジェクトのtransmit()関数で通信がスタートします。
PR:スキマ時間で自己啓発!スマホで学べる人気のオンライン資格講座【スタディング】まずは気になる講座を無料で体験しよう!
子機を実装する
auto&& nwksmpl = the_twelite.network.use<NWK_SIMPLE>();
       nwksmpl << NWK_SIMPLE::logical_id(0x01);
TWENETライブラリのnetwork関数を使用して論理IDの設定を行います。ネットワークのlogical_idに0x01~0xEFもしくはFE(IDの区別がない)をセットすることで子機として動作します。
void receive() {
    char chk[4];
    uint8_t set;
    auto&& rx = the_twelite.receiver.read();
    auto&& np = expand_bytes(rx.get_payload().begin(), rx.get_payload().end()
		,make_pair(chk,3)); //文字列分を取得
		
    if( strncmp(chk, APP_CHAR, 3)){ return; } //文字列を判定
        np = expand_bytes(np,rx.get_payload().end(),set ); //残りのデータを取得
}
expand_bytes()は受信したペイロード(データのパケット)を指定したバイト数に分けて受信できるため使い勝手の良いAPIです。最初に3バイト受信しているのはアプリの文字列が一致するかのチェックを行うためです。
strncmp()で親機と子機の文字列が一致した場合は同一アプリのものと判断して文字列より先のペイロードのデータを取得する処理を行います。npはポインタで読み込んだデータ分より次のデータの位置を示すポインタになっています。例では変数であるsetに読み出したデータを格納しています。
PR:わからないを放置せず、あなたにあったスキルを身に着けるコツを教える テックジム 「書けるが先で、理解が後」を体験しよう!
動作確認

親機はSW1を押すと子機に対して無線通信を行います。下表のように親機の15、16をGNDに接続するパターンで送信先を切り替えています。子機は親機からの無線通信を受けてLEDを点灯/消灯します。
| DOのパターン DO(15):DO(16) | 子機の送信先 | 
|---|---|
| LOW:LOW | 0xFE | 
| HIGH:LOW | 0x01 | 
| LOW:HIGH | 0x02 | 
親機の送信先を0xFEにして送信すると子機(論理ID:0x01)と子機(論理ID:0x02)が動作することを確認しました。送信先を0x01に切り替えると子機(論理ID:0x01)のみLEDが点灯/消灯することが確認できました。同様に送信先を0x02に切り替えると子機(論理ID:0x02)のみのLEDが点灯/消灯することが確認できました。
ソースコード全体
ソースコードは記事作成時点において動作確認できていますが、使用しているライブラリの更新により動作が保証できなくなる可能性があります。また、ソースコードを使用したことによって生じた不利益などの一切の責任を負いかねます。参考資料としてお使いください。
TWELITE(子機)のソースコード:
#include <TWELITE>
#include <NWK_SIMPLE>
//#define CNG_ID
const uint8_t DO_COM = mwx::PIN_DIGITAL::DIO12;
const uint32_t APP_ID = 0x1234abcd; // application ID
const uint8_t CHANNEL = 13; // channel
const uint8_t LID
#ifdef CNG_ID
= 0x01
#else
= 0x02
#endif
;
const char APP_CHAR[] = "COM";
void receive();
/*** the setup procedure (called on boot) */
void setup() {
    pinMode(DO_COM,OUTPUT);
    the_twelite
	<< TWENET::appid(APP_ID)    
	<< TWENET::channel(CHANNEL) 
	<< TWENET::rx_when_idle();
    auto&& nwksmpl = the_twelite.network.use<NWK_SIMPLE>();
    nwksmpl << NWK_SIMPLE::logical_id(LID);
    the_twelite.begin(); // start twelite!
}
/*** the loop procedure (called every event) */
void loop() {
    while (the_twelite.receiver.available()) {
	receive();
    }
}
/* 無線通信を受信して処理する */
void receive() {
    char chk[4];
    uint8_t set;
    auto&& rx = the_twelite.receiver.read();
    auto&& np = expand_bytes(rx.get_payload().begin(), rx.get_payload().end()
		,make_pair(chk,3)); 
		
    if( strncmp(chk, APP_CHAR, 3)){ return; } // check header
        np = expand_bytes(np,rx.get_payload().end(),set );
    if( set == 1){
        digitalWrite(DO_COM,HIGH);
    }
    else{
        digitalWrite(DO_COM,LOW);
    }
}
TWELITE(親機)のソースコード:
#include <TWELITE>
#include <NWK_SIMPLE>
#define CNG_ID
#define TIME_UP 0
#define TIME_OFF -1
#define ZIG_WAIT_MAX 100
const uint8_t DI_SW = mwx::PIN_DIGITAL::DIO12;
const uint8_t DI_MD0 = mwx::PIN_DIGITAL::DIO15;
const uint8_t DI_MD1 = mwx::PIN_DIGITAL::DIO16;
const uint32_t APP_ID = 0x1234abcd; // application ID
const uint8_t CHANNEL = 13; // channel
const char APP_CHAR[] = "COM";
int16_t timzigwait = TIME_OFF;
uint8_t do_out;
/*** function prototype */
MWX_APIRET transmit(void);
/*** the setup procedure (called on boot) */
void setup() {
    pinMode(DI_SW,INPUT_PULLUP);
    pinMode(DI_MD0,INPUT_PULLUP);
    pinMode(DI_MD1,INPUT_PULLUP);
    the_twelite
	<< TWENET::appid(APP_ID)    
	<< TWENET::channel(CHANNEL) 
	<< TWENET::rx_when_idle();
    auto&& nwksmpl = the_twelite.network.use<NWK_SIMPLE>();
    nwksmpl << NWK_SIMPLE::logical_id(0x00);
    the_twelite.begin(); // start twelite!
}
/*** the loop procedure (called every event) */
void loop() {
    if( TickTimer.available()){
        if(timzigwait > TIME_UP){
            --timzigwait;
        }
    }
    if( timzigwait == TIME_UP ){
        timzigwait = TIME_OFF;
        transmit();
    }
    if( digitalRead(DI_SW) == LOW ){
	timzigwait = ZIG_WAIT_MAX;
    }
}
/* transmit a packet */
MWX_APIRET transmit(void) {
    uint8_t txadrs;
    if(digitalRead(DI_MD0) == LOW && digitalRead(DI_MD1) == LOW ){
	txadrs = 0xFE;
    }
    else if( digitalRead(DI_MD0) == HIGH && digitalRead(DI_MD1) == LOW){
	txadrs = 0x01;
    }
    else if( digitalRead(DI_MD0) == LOW && digitalRead(DI_MD1) == HIGH){
	txadrs = 0x02;
    }
    if (auto&& pkt = the_twelite.network.use<NWK_SIMPLE>().prepare_tx_packet()) {
	pkt << tx_addr(txadrs)  
            << tx_retry(0x3) 
	    << tx_packet_delay(0,0,2);
 
        if( do_out){
	    do_out = 0;
	}
	else{
            do_out = 1;
	}
        pack_bytes(pkt.get_payload(), make_pair(APP_CHAR, 3));//ヘッダー
        pack_bytes(pkt.get_payload(),do_out);
		
	return pkt.transmit();
    }
    return MWX_APIRET(false, 0);
}
TWELITEのソースコードはMWSTAGEのアクトに組み込んで使用してください。
関連リンク
トワイライトを太陽光パネルで動作させたことやMWSTAGEの環境でソフト開発して無線通信したことなどについてまとめています。
トワイライト(TWELITE)のソフト開発と無線通信でできること
PR:企業で求められる即戦力技術を身に付ける テックキャンプエンジニア転職 
最後まで、読んでいただきありがとうございました。
 


今回はACTを自作して送信先を切り替えて動作確認しましたが、標準アプリやシリアル通信アプリにおいては動作を確認してみるとブロードキャスト通信になっているようです。