最適な出力のために、Google Chrome(15以降)または Microsoft Edge(79以降)を推奨いたします。
2024-11-14 現在 マニュアル ここでは、製品使用における詳細情報を掲載しています。
TWELITE BLUE / RED シリーズ向けファームウェア(TWELITE APPS)の資料はこちら
1 - TWELITE STAGE SDK TWELITE の設定やデータ表示、ファームウェア開発を行うためのパッケージ
1.1 - 導入方法 TWELITE STAGE SDK のインストール方法
動作環境によっては、本アプリケーションの動作に各種設定が必要です。問題が生じた場合には、本資料の記述を参考にして環境を整備してください。
開発環境を構築するためには、ソフトウェア群のインストール、またこれらの利用許諾に同意する必要があります。また、セキュリティ設定等が必要になる場合があります。
配布時に十分注意しておりますが、お客さまの側でもウィルスやマルウェアが含まれていないことを確認いただくようお願いします。 セキュリティの運用(外部アプリケーションのインストールの可否など)については、お客さまの環境の管理者にご確認ください。 「アプリケーションの配布と実行について」 も併せてご覧ください。以下の内容を含みます。
本来のファイルとダウンロードしたファイルの同一性の確認について macOS/Windowsにおけるコード署名の取り扱いについて TWELITE STAGE SDK のインストール手順 ① アーカイブを取得 各プラットフォーム (Windows / macOS / Linux) 用の TWELITE STAGE SDK を ダウンロード します。
macOSの場合はHomebrewを使用できます
brew install twelite-stage
インストール先は ~/MWSTAGE
です。
② アーカイブを展開 ダウンロードしたZipアーカイブを展開します。
展開先のファイルパスには、半角数字 0..9、半角アルファベットa..zA..Z、一部の記号 -_. 以外の空白や漢字・ひらがな等を含めないでください。
Windows の場合の例
NG : C:\work\作業\
NG : C:\Users\user1\work dir\
OK : C:\Work\Work1
③ ファイルを確認 展開先のフォルダを確認します。
通常 C:\Work
上に配置したアーカイブは C:\Work\MWSTAGE
に展開されますが、展開ソフトによってはフォルダ名が異なる可能性があります。 必要に応じて変更してください。
文中では展開したフォルダ (例 C:\Work\MWSTAGE
) を {MWSTAGE インストール}
のように表記する場合があります。
展開先のフォルダ {MWSTAGE インストール}
には、以下が含まれます。
TWELITE STAGE APPWindows の場合:TWELITE_Stage.exe
(通常版)、TWELITE_Stage_VSCode.exe
(VSCode対応版) macOS の場合:TWELITE_Stage.command
(通常版)、TWELITE_Stage_VSCode.command
(VSCode対応版) Linux の場合:TWELITE_Stage.run
(通常版)、TWELITE_Stage_VSCode.run
(VSCode対応版) TWELITE_STAGE
- TWELITE STAGE APP の関連ファイルMWSDK
- ライブラリ、ソースコードなどTools
- ビルドするためのツールチェインなどBIN
- TWELITE STAGE APP の [BINから選択]メニューで参照されるTWELITE 向け.BINファイルlog
- TWELITE STAGE APP のログ機能やデータベースファイルの保存先flask_wsns_db
- Python, Flask, sqlite3 による簡易的なサーバ詳細は「フォルダ構成 」をご覧ください。
1.1.1 - フォルダ構成 TWELITE STAGE APP のフォルダ構成について
TWELITE STAGE APP は、TWELITE STAGE SDK のフロントエンドアプリケーションとして動作します。
ここでは、そのフォルダ構成について解説します。
MWSTAGE/ : TWELITE STAGE SDK インストール
TWELITE_Stage.??? : 実行形式 (Windwows .exe, macOS .command, Linux .run)
TWELITE_Stage.sav : 設定ファイル
TWELITE_Stage.ini : その他設定
TWELITE_Stage/ : TWELITE STAGE APP の関連ファイル
MWSDK/ : MWSDKのライブラリなど
BIN/ : [BINファイル選択]時の格納先
log/ : ログ・データベース格納先
Tools/ : gcc コンパイラなどのツール一式
flask_wsns_db/ : Python, Flask, sqlite3 による簡易的なサーバ
MWSDK
フォルダ
MWSDK/
Act_samples/ : mwx ライブラリによるサンプルコード
Wks_TweApps/ : TWELITE APPS のソースコード
Act_extras/ : mwx ライブラリによるより専門的なサンプル、他のライブラリを引用したもの
TWENET/ : TWENET ライブラリ (mwx ライブラリなど)
ChipLib/ : 半導体ライブラリ
MkFiles/ : Makefile の本体処理部分
docs/ : ライブラリマニュアルなど
LICENSE : MWSDKのライセンス記述
000manifest : MWSDKのバージョン情報
ReleaseNotes.md : 更新履歴(トップページ)
ReleaseNotes_en.md : 更新履歴(英語)
ReleaseNotes_jp.md : 更新履歴(日本語)
MWSDK フォルダには、TWELITE のソフトウェアを構築するためのライブラリや、サンプル、TWELITE APPS のソースコードが含まれます。
TWELITE_Stage.sav
TWELITE STAGE APPの設定情報を記録します。
ファイル名は TWELITE STAGE APP 実行形式名 + .sav
です。
TWELITE_Stage.ini
.ini
ファイルの詳細はこちら 。
MWSDK=
MWSDK/
フォルダの替わりに別のフォルダを指定したいときに編集します。複数のライブラリバージョンを混在させる場合に便利です。上記の例では MWSDK2020_10
フォルダを利用します。LANG=
TWELITE STAGE APP の表示言語を英語にする場合は LANG=en
を指定します。設定の異なる TWELITE STAGE APP を実行する TWELITE_Stage.exe
(Windows の場合) を別のファイル名でコピーします。 例えば TWS1.exe
と変更した場合は、TRS1.sav
, TRS1.ini
という設定ファイルを参照します。
BIN
フォルダTWELITE STAGE APP の [BINから選択] メニューを選択したときには、このフォルダにある ファームウェアファイル (.BIN
) を利用します。
log
フォルダTWELITE STAGE APP でシリアルポートのログ機能を実行したときには、このフォルダにログファイルを格納します。
グラフ機能を用いた場合のデータベースファイルの格納先や、csvファイルの出力先もこのフォルダです。
gcc
, g++
など、クロスコンパイラの toolchain 等が含まれます。
プラットフォームに固有のユーティリティもこのフォルダに格納されます。詳しくは Tools/readme.txt
を参照してください。
flask_wsns_db
フォルダTWELITE STAGE APP のセンサーグラフビューアで作成したデータベースにアクセスするためのPythonのサンプルスクリプトです。
本サンプルでは表やグラフでデータをWebブラウザで閲覧することができます。
詳しくは flask_wsns_db/README.html
を参照してください。
ビルドプロジェクトフォルダ
本機能は標準的に提供する機能ではないものとして紹介します。記載の内容と異なった動作になる場合もあります。
フォルダの検索順 TWELITE STAGE APP は、以下の順でビルドプロジェクトフォルダ (Act_samples
など) を検索します。
TWELITE STAGE APP が起動したときのフォルダ TWELITE STAGE APP の実行形式があるフォルダ {MWSDKフォルダ}/..
{MWSDKフォルダ}
MWSDK は TWELITE STAGE APP の実行形式があるフォルダを起点に検索します。
Wks_Acts Wks_Acts
フォルダを作成した場合には、Act_samples
フォルダの替わりに、このフォルダをメニューの[actビルド&書換]メニューから参照します。
Wks_Acts
は、自身で作成したプロジェクトを格納する用途を想定しています。
1.1.2 - プラットフォーム別の注意事項 インストールにおけるプラットフォーム別の注意事項
TWELITE STAGE APP を各プラットフォームにインストールする際の注意事項を記載しています。
1.1.2.1 - Windowsへインストールする際の注意事項 TWELITE STAGE APP を Windows へインストールする際の注意事項
Windows 環境 以下の環境で開発・動作確認しています。
Windows10 バージョン 1903 VisualStudio 2019 (32bit ビルド) シリアルポートの取り扱い MONOSTICK や TWELITE R シリーズには、 FTDI社の USBシリアル変換IC(FT230/FT232 シリーズ)を搭載しています。これらを利用するために、デバイスドライバのインストールが必要となる場合があります。
PC がMONOSTICK や TWELITE R を認識しない場合には、 https://www.ftdichip.com より D2XX ドライバをインストールしてください。
Visual C++ ランタイムライブラリの追加インストール 場合によっては、Visual Studio 2019 の Visual C++ 頒布可能コード(ランタイムライブラリ)が必要です。
アプリケーションの起動時にエラーが出て起動しない場合は、本パッケージで再配布している TWELITE_Stage¥INSTALL¥VC_redist.x86.exe
を実行するか、マイクロソフト社のウェブサイトから入手してください。なお、再配布バイナリは 32bit です。
1.1.2.2 - macOSインストールする際の注意事項 TWELITE STAGE APP を macOS へインストールする際の注意事項
macOS 環境 以下の環境で開発・動作確認しています。
macOS 10.14 (Mojave, Intel) macOS 12 (Monterey, Apple Silicon) 依存するソフトウェアや警告ダイアログについて 下記の事象が発生した場合には、 TWELITE_Stage.command
の動作のために、実行の許可やインストールが必要です。
ツールチェインにはコード署名がなされていますが、コード署名が正しく認証されない場合は、ビルドツールチェイン (ba-elf-gcc
など) の実行形式一つずつについて、動作許可を求められる場合があります。 ダウンロードアーカイブには署名しておりません。実行時には、インターネットからダウンロードされたアプリケーションとしてセキュリティ警告が出る場合があります。 TWELITE_Stage.command
をインストールしたパスからの実行許可を要求される場合があります。ビルド実行時に make ユーティリティのインストールダイアログが出る場合があります。 make ユーティリティの追加インストール 場合によっては、make ユーティリティをインストールしなくてはなりません。
macOSバージョンの違いなどにより、別の手順で行う必要があるかもしれません。
コマンドライン (zsh) から make を実行したときに、エラーが出る場合には Command Line Tools をインストールします。
インストールが完了したら、make を入力して以下のメッセージの出力を確認します。
make
make: *** No targets specified and no makefile found. Stop.
シリアルポートの取り扱い MONOSTICK や TWELITE R シリーズには、 FTDI社 (https://www.ftdichip.com ) の USBシリアル変換IC(FT230/FT232 シリーズ)を搭載しています。これらを利用するために、デバイスドライバのインストールが必要となる場合があります。
TWELITE_Stage.command
を起動してもシリアルポートが表示されない場合は、FTDI社のドライバをアンロード(無効化)してください。
このユーティリティは MONOSTICK や TWELITE R を挿入した際にOS標準のデバイスドライバのロードを抑制するだけでなく、同じ USB の ID を持つそれ以外のデバイスについてもデバイスドライバのロードを抑制します。
https://www.ftdichip.com/Drivers/D2XX.htm より D2xxHelper をダウンロードできます。 なお、TWELITE STAGE SDKの TWELITE_Stage/INSTALL
フォルダにも同じものを収録しています。
参考:FTDI社デバイスドライバの手動アンロード FTDI 関連のドライバをアンロードするには、以下のコマンドを実行します。
sudo kextunload -b com.apple.driver.AppleUSBFTDI
1.1.2.3 - Linuxへインストールする際の注意事項 TWELITE STAGE APP を Linux へインストールする際の注意事項
Linux
TWELITE R2 のUSBデバイスIDが従来の0403:6001から0403:6015に変わっています。udevの設定追加が必要です。
Linux環境はディストリビューションやバージョンによって、用意されているパッケージの種類が異なります。個別にパッケージ等のインストールや設定が必要になる場合があります。
エラーメッセージ等を手がかりに一般の情報を参照いただくようお願いいたします。
環境 以下の環境で開発・動作確認しています。
Ubuntu 16.04, 18.04, 20.04 NNLinux Beta8 64bit CentOS 7 シリアルポートの取り扱い TWELITE STAGE から MONOSTICK や TWELITE-R を認識するには、ftdi_sioモジュールをアンロードし、USBデバイスに対して読み書き権限を与える必要があります。
USBデバイスのIDを以下に示します。
ベンダーID 0x0403
プロダクトID 0x6001
(MONOSTICK,TWELITE R) または 0x6015
(TWELITE R2) なお、この設定を自動化するための udev
の設定スクリプト(Ubuntu, CentOS) を用意しています。
/etc/udev/rules.d
に定義をコピーして、設定をリロードします。 設定後は USB デバイスを抜き差ししてから TWELITE_Stage.run
を実行してください。起動直後の画面で USB デバイスが表示されたなら、設定が反映されています。
Ubuntu 16.04, 18.04, 20.04
cd ./MWSTAGE/TWELITE_Stage/INSTALL/ubuntu/
sudo ./set_udev_sudo.sh
定義ファイル(読みやすいように改行しています)
ACTION=="add",
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001",
MODE="0666",
RUN+="/bin/sh -c 'rmmod ftdi_sio && rmmod usbserial'"
ACTION=="add",
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015",
MODE="0666",
RUN+="/bin/sh -c 'rmmod ftdi_sio && rmmod usbserial'"
Centos 7
cd ./MWSTAGE/TWELITE_Stage/INSTALL/centos/
sudo ./set_udev_sudo.sh
定義ファイル(読みやすいように改行しています)
ACTION=="add",
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001",
MODE="0666",
RUN+="/bin/sh -c '/usr/sbin/rmmod ftdi_sio'"
ACTION=="add",
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015",
MODE="0666",
RUN+="/bin/sh -c '/usr/sbin/rmmod ftdi_sio'"
アプリケーションの登録 必要に応じて、お使いのデスクトップ環境に合った方法でアプリケーションを登録してください。
デスクトップ上のファイルアイコンから、TWELITE_Stage.run を実行できない場合があります。 これは、システムが TWELITE_Stage.run
を実行形式として認識できない場合があるためです。
Ubuntu 16.04, 18.04, 20.04 Ubuntu用の定義ファイル生成スクリプトを用意しています。
cd ./MWSTAGE/TWELITE_Stage/INSTALL/ubuntu/
./make_launch_icon.sh
このスクリプトは .desktop
ファイル(アプリ定義)を $HOME/.local/share/applications
に作成します。
スクリプト実行後に、アプリケーション一覧に TWELITE STAGE のアイコンが追加されます。
1.1.2.4 - Raspberry Piへインストールする際の注意事項 TWELITE STAGE APP を Raspberry Pi へインストールする際の注意事項
RasPi TWELITE STAGE APPは、一部を除く Raspberry Pi で動作します。
マウスとタッチスクリーンに対応します。 ビルドツールチェインが付属しており、コンパイルもできます。 実行形式には、X11版のほかにフレームバッファ版(nox
)があるほか、半透明エフェクトなどを省略した軽量版があります。
お使いの Raspberry Pi の OS 種別、バージョン、インストール状況によっては動作しない場合や、再コンパイル等が必要になる場合があります。
環境 以下の環境で開発・動作確認しています。
ハードウェア Raspberry Pi 3 Model B LCD Screen: Raspberry Pi Touch Display (7") ソフトウェア Raspberry PI OS (32bit) Lite (Version:August 2020) 既知の問題・制限事項 1回目の起動で /dev/serial0
の動作に失敗することがあります。 Raspberry Pi 4B では /dev/serial0
の動作は未検証です。 Raspberry Pi 4B ではタッチスクリーンの動作は未検証です。 TWELITE STAGE への入力文字列が/dev/tty1
上で動作してるシェルやgetty
へ入力文字列がそのまま渡されます。/dev/tty1
から起動することを推奨します。 他のインストールや動作のプログラム(X11など)に影響を受けることがあります。 アーカイブの展開 ダウンロードしたアーカイブファイルは、パス名に空白や日本語などが含まれないフォルダに展開します。
以下ではRaspberry Piのホームフォルダに展開しています。
cd /home/pi
unzip MWSTAGE2020_XX_YYYY.zip
フォルダ構成
../MWSTAGE
TWELITE_Stage.run TWELITE_Stage アプリ
BIN/ ファームウェアBINファイル
MWSDK/ MWSDK ライブラリなど
TWELITE_Stage/ TWELITE_Stage アプリ関連ファイル
デバイスドライバ TWELITE STAGE から MONOSTICK や TWELITE R を認識するためには、ftdi_sio
モジュールのアンロードや、USBデバイスに対する読み書き権限の付与が必要です。
USBデバイスのIDを以下に示します。
ベンダーID 0x0403
プロダクトID 0x6001
(MONOSTICK,TWELITE R) または 0x6015
(TWELITE R2) この設定を自動化するための udev
の設定スクリプトを用意しています。/etc/udev/rules.d
に定義をコピーして、設定をリロードしています。設定後は USB デバイスを抜き差ししてから TWELITE_Stage.run
を実行してください。起動直後の画面で USB デバイスが表示されたなら、設定が反映されています。
cd ./MWSTAGE/TWELITE_Stage/INSTALL/ubuntu/
sudo ./set_udev_sudo.sh
定義ファイル(読みやすいように改行しています)
ACTION=="add",
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001",
MODE="0666",
RUN+="/bin/sh -c 'rmmod ftdi_sio && rmmod usbserial'"
ACTION=="add",
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015",
MODE="0666",
RUN+="/bin/sh -c 'rmmod ftdi_sio && rmmod usbserial'"
シリアルポートの取り扱い 上述の環境では、raspi-config
よりシリアルポートの設定をすることで /dev/serial0
が利用できます。
メニューより
"3 Interface Options Configure connections to peripherals"
→"P6 Serial Port Enable/disable shell messages on the serial connection"
以下のようにログインシェルとしては利用しない、ハードウェアを有効化するを選択します。
"Would you like a login shell to be accessible over serial?" ->
"Would you like the serial port hardware to be enabled?" →
配線例
[TWELITE] [Raspberry Pi]
GND ------------------ Gound (#6,#9,#14,#20,#25,#30,#34,#39のいずれか)
TXD(DIO6,DIP#10) ------ GPIO15/UART0 RXD (#10)
PRG(SPIMISO,DIP#7) ---- GPIO23 (#16)
RXD(DIO7,DIP#3) ------- GPIO14/UART0 TXD (#8)
RST(RESETN,DIP#21) ---- GPIO22 (#15)
VCC ------------------ 3V3 (#1,#17のいずれか)
SET(DIO12,DIP#15) ----- GPIO12 (#32)
TWELITE, Raspberry Pi それぞれのマニュアルを参照してください。 DIP# は TWELITE DIP のピン番号です。 上記の配線は TWELITEが安定稼働することを保証するものではありません。 TWELITE STAGE APPの起動 フレームバッファ版(nox
)はX11のデスクトップ上では動作しません。X11を終了しておきます。 TWELITE_Stage.run
を実行します。スクリーン画面上のTWELITE STAGE APPが表示されます。留意事項 マウスとタッチパネルに対応します。 TWELITE STAGE APP中で、入力した文字はコンソール画面にも表示される場合があります。 その他 /dev/dri
エラーTWELITE_Stage.run
の起動時に以下のエラーが出る場合がありますが、無視して構いません。
"The path /dev/dri/ cannot be opened or is not available"
メモリ不足 CPU数が4以上の場合、ビルド時はCPU数を一つ引いた値の並列コンパイルを実行します(4コアなら3並列)。 場合によってはメモリ不足が発生するかもしれません。その場合は並列数を変更してください。
Raspberry Pi 4
busterにおける注意事項 OpenGL関連のドライバを有効とする必要があります。
raspi-config の Advanced Settings → A2 GL Driver → G2 GL (Fake KMS) を選択します libgles-dev パッケージを導入しておきます
2024年6月現在、Raspberry Pi OS (32bit, bookworm)では、Linuxカーネルの更新に伴いピンの制御を行えず、モジュールを認識・操作できない不具合が発生しております。
また、bookworm では libccm 等に関するエラーにより起動できない不具合も確認されていますが、次のコマンドを実行することで解消できる場合があります。
sudo apt update
sudo apt install --reinstall libraspberrypi0 libraspberrypi-dev libraspberrypi-doc libraspberrypi-bin
このとき、再起動すると lightdm の起動に失敗してしまう場合があります。
その際は raspberrypi-ui-mods
の導入をお試しください。
sudo apt update
sudo apt install raspberrypi-ui-mods
お手数ですが、当分は Raspberry Pi OS (32bit, bullseye) をご利用ください。
追記:Raspberry Pi OS (bookworm) に対応した TWELITE STAGE アプリのベータ版 を作成しました。
【32bit版パッチの導入方法】
cd MWSTAGE
wget https://twelite.net/files/TWELITE_Stage_Wayland.run.zip
unzip TWELITE_Stage_Wayland.run.zip
./TWELITE_Stage_Wayland.run
【64bit版パッチの導入方法】
cd MWSTAGE
wget https://twelite.net/files/TWELITE_Stage_Wayland_64.run.zip
unzip TWELITE_Stage_Wayland_64.run.zip
mv Tools/ba-elf-ba2-r36379 Tools/ba-elf-ba2-r36379-bkup32
wget https://twelite.net/files/ba-elf-ba2-r36379_aarch64.tgz
tar -xzf ba-elf-ba2-r36379_aarch64.tgz
mv ba-elf-ba2-r36379 Tools/
./TWELITE_Stage_Wayland_64.run
1.2 - TWELITE STAGE APP ビルドや書き換え、設定やデータ表示を行うアプリケーション
TWELITE STAGE APP は、ファームウェアのビルドや書き換え、TWELITE APPSの設定やデータ表示を行うアプリケーションです。評価開発環境 TWELITE STAGE で使用します。
1.2.1 - TWELITE STAGE APP マニュアル ビルドや書き換え、設定やデータ表示を行うアプリケーション
TWELITE STAGE APP は、ファームウェアのビルドや書き換え、TWELITE APPSの設定やデータ表示を行うアプリケーションです。評価開発環境 TWELITE STAGE で使用します。
資料の取り扱いについて をご参照ください。
お気付きの点がありましたら、当サポート窓口にご連絡いただければ幸いです。
本資料の表示例(ボタン名や画面キャプチャ)は、資料作成時のバージョンのものとなっています。一部、入手されたバージョンと差異がある場合があります。
Windows/macOS/Linux ではコンパイラ・サンプルコードなどを格納した MWSDK が含まれます。これらに関する詳細は、以下を参照ください。
様々なプラットフォームで動作します。
Windows10 macOS (High Sierra 以降、Intel および Apple Silicon Mac に対応) Linux (Ubuntu18.04) Raspberry Pi (Raspberry Pi 3 Model B, Lcd Touch Screen, Raspberry Pi OS August-2020) (M5stack : バージョン1.0 まで対応。v1.3以降はソースレベルで非対応です。) ※ プラットフォームによって、動作条件や配布形式、また機能が異なります。
ルートメニュー
加速度リアルタイムグラフ
本資料について 対象のプラットフォームを示すため、一部のページでは以下を記載しています。Windows
– Windows 10macOS
– Mac OS X, OS X, macOSLinux
– Ubuntuなど(64bit)RasPi
– Raspberry Pi 1.2.1.1 - パッケージの取得 TWELITE STAGE APP の取得方法
最新版のTWELITE STAGE アプリは、以下のいずれかの方法で取得できます。
TWELITE STAGE SDK 全体(公式サイト) モノワイヤレス公式サイトでは、TWELITE STAGE アプリを含む開発ツール一式(Windows/macOS/Linux用)を配布しています。
TWELITE STAGE-トワイライトステージ - MONO-WIRELESS.COM
TWELITE STAGE アプリのみ(GitHub) モノワイヤレス公式リポジトリでは、TWELITE STAGE アプリ単体のバイナリを配布しています。 TWELITE STAGE アプリだけを更新する場合や、M5Stack版を取得する際にはこちらをご利用ください。 各バイナリのバージョンはGitHub上のtagから識別できます。
TWELITE STAGEアプリは、安定板として配布された最新のTWELITE STAGE SDKにおける動作を目的としています。 したがって、古いSDKでは、新しいTWELITE STAGEアプリが正常に動作しない恐れがあります。
Windows monowireless/TWELITE_Stage_BIN_Win: Binary Distribution of TWELITE Stage.
macOS monowireless/TWELITE_Stage_BIN_macOS: Binary distribution of TWELITE Stage for macOS
Linux Linux 版のバイナリは個別に配布しておりません。 バイナリは TWELITE STAGE SDK パッケージから取得してください。 もしくは、ソースコードからビルドしてください。
Raspberry Pi Raspberry Pi 版のバイナリは個別に配布しておりません。 バイナリは TWELITE STAGE SDK パッケージから取得してください。 もしくは、ソースコードからビルドしてください。
M5Stack バージョン 1.0.3a までを以下のページで配布しております。
monowireless/TWELITE_STAGE_Bin_M5Stack
ソースコード (MWM5ライブラリ) TWELITE STAGE のソースコードを含む MWM5 ライブラリは以下のページで公開しています。
monowireless/mwm5
TWELITE STAGE アプリのソースコードは、examples/TWELITE_Stageに配置しています。
1.2.1.2 - 使用方法 TWELITE STAGE APP の使用方法
TWELITE STAGE APP の画面・操作方法を解説します。
アプリの起動方法 TWELITE STAGE アプリを起動するには、{MWSTAGE インストール}
にある実行形式を実行します。
アップデートなどでTWELITE STAGE アプリの実行形式を差し替える場合には、必ず、指定フォルダ {MWSTAGE インストール} にコピーしてください。 それ以外のパスに実行形式を配置した場合の動作は未定義です。
実行はプラットフォーム(Windows, macOS, Linux)によって方法が異なります。
システム 拡張子 備考 Windows .exe
エクスプローラで実行形式をダブルクリック macOS .command
Finder で実行形式をダブルクリック Linux
RasPi .run
ディストリビューションやインストール環境に依存します。Xウインドウシステム上のターミナル画面(xtermなど)から、コマンドとして実行します
アプリの実行形式 TWELITE STAGE APP には、2種類の実行形式があります。
TWELITE_Stage.{拡張子} - 標準設定で起動します。 TWELITE_Stage_VSCode.{拡張子} - 「VSCode を使う」設定済みです(設定はTWELITE_Stage_VSCode.ini
に保存)。VSCodeを使う設定を有効にすると、VSCodeを用いた開発作業に適した動作を行うようになります。
TWELITE STAGE APP は複数起動してもエラーになりませんが、複数起動すると不都合のある機能(センサーグラフ機能など)が存在します。
したがって、複数のアプリを同時に起動する際には、実行形式を複製して、別々のファイルを立ち上げる必要があります。 各種設定ファイルや入出力ファイルが分離されるため、互いの干渉を避けることができます。
アプリの実行画面 アプリを起動すると、以下の2種類のウィンドウが表示されます。
メイン画面TWELITE STAGE APPのユーザインタフェースを表示します。 TWELITE STAGE APPの操作はこの中で行います。 コマンド画面通常は使用しませんが、補助情報を表示します。シリアル通信の内容が表示されるため、ログを確認する用途に最適です。 コマンドラインから実行した場合には、実行元のターミナルがコマンド画面となります。 TWELITE STAGE APP 画面例
アプリの終了 いずれかの方法で終了してください。
実行画面上の右上にマウスポインタを移動し、画面内に表示された終了ボタンを押します。 実行画面のウインドウを閉じます(macOSの場合は⌘Q
も使用できます)。
ごくまれに、終了操作をしても実行画面が残る場合があります。その場合には、以下をお試しください。
TWELTIE STAGE APPのコマンドライン画面を閉じる。 強制終了を行う(強制終了の操作方法はお使いのシステムの解説を参照してください)。 1.2.1.2.1 - キーとマウスの操作 TWELITE STAGE APP に使用するキーとマウスの操作説明
Windows
macOS
Linux
RasPi
TWELITE STAGE APP に使用するキーとマウスの操作を解説します。
キー操作 Windows
macOS
Linux
RasPi
Alt(⌘)
を押しながら行うキー入力は、TWELITE STAGE APP の設定を変える操作等に割り当てられています。その他のキー操作は、通常は文字入力として機能します。
共通のキー Windows
macOS
Linux
RasPi
キー 意味 ESC
ESC
素早く2回ESC
を押す。キャンセル、または前画面に戻る。画面によっては1回の押下で前画面に戻ります。 ENTER
入力、選択 BS
一文字削除 カーソルキー↑
↓
項目の選択
ヘルプ画面 Windows
macOS
Linux
RasPi
Alt(⌘)
を押し続ける ことでヘルプ画面を表示します。ヘルプ画面ではAlt(⌘)
と一緒に操作できるキーの説明や一部動作状況を表示します。
ヘルプ画面は画面の左上部分にマウスポインタを移動する ことでも表示できます。
ヘルプ画面
Alt(⌘)+操作 Windows
macOS
Linux
RasPi
Alt(⌘)
を押しながら行う操作について解説します。
表中ではAlt(⌘)
+の表記は省略しています。上記のヘルプ画面から使用可能なキーを確認できますが、下表に補足説明を示します。
Alt(⌘)
+キー意味 I
+ + + を入力します。インタラクティブモードに入るキーシーケンスです。※ スリープによる間欠動作を行うアプリは非対応。 R
モジュールをリセットします。TWELITE R や MONOSTICK の機能を用いてリセットピンの制御を行います。 A
, S
, D
A, B, C ボタンを押します。 Shift
+A
, S
, D
A, B, C ボタンを長押しします。 C
表示されている画面の文字列をクリップボードにコピーします。(画面によって範囲は異なります) V
クリップボードからキーボード入力としてペーストします。 F
フルスクリーン表示に遷移します。Shift+Fの場合、可能であればより拡大します。 G
画面の描画方法を変更します。640x480の液晶画面をエミュレートしていますが、拡大時の描画方式として(1. 液晶モニタ風の描画 / 2. ブラウン管風の描画 / 3. ドットを目立たせた拡大 / 4. ドットをぼやかせた拡大)の4種類が選択できます。※ 設定メニューで起動時の設定を変更できます。 J
画面サイズを選択します。選択可能な画面サイズは {640,480}, {1280, 720}, {1280,960}, {1920,1440}, {2560,1440}, {320,240} です。※ 設定メニューで起動時設定にできます。 Q
TWELITE STAGE APPを終了します。 0
シリアルポートを切断し、再度シリアルポートの一覧を表示します。 1
, 2
, …シリアルポートを選択します。 L
, Shift
+L
シリアルポートの入出力のログを開始します。終了時にはログファイルが Windows であればメモ帳、macOS であれば ログビューア で開かれます。Shift
+L
でログ格納フォルダを開きます。
その他の操作 キー 意味 Alt(⌘)
+Shift
+Ctrl
+m
MWX ライブラリコードのフォルダを開きます。 Alt(⌘)
+Shift
+l
log
フォルダを開きます。
マウス操作 Windows
macOS
Linux
RasPi
マウス操作は左クリックが中心ですが、右クリック、右ダブルクリック、ホイールを使う場合があります。
マウス操作 意味 左クリック 選択 左クリックしながらドラッグ 画面によっては利用(グラフ画面でのドラッグ) 左ダブルクリック 使用しない 右クリック 画面によっては使用する 右ダブルクリック 画面から脱出する(ESC
ESC
と同様) ホイール 画面によって利用する(グラフ画面で拡大縮小)
マウスによるA,B,Cボタン Windows
macOS
Linux
RasPi
画面下部のメニュー表示にマウスポインタを移動すると、[ A ]
, [ B ]
, [ C ]
という表記のボタンが表示されます。 TWELITE STAGE APPは、この3つ並びのハードウェアボタンを模したメニューに画面ごとの機能を割り当てています。 このボタンを左クリックまたは左長押しクリックすることで、機能を呼び出しできます。(Alt(⌘)
+a
,s
,d`` または
Alt(⌘)+
Shift+
a,
s,
d`でも選択可能)
画面下部の仮想[ B ]ボタンの表示例
マウスによる画面操作 Windows
macOS
Linux
RasPi
Windows/macOS/Linuxでは、TWELITE STAGE APP の画面を原則文字列のみで構成しますが、メニューやボタン、タブについてはマウスによる操作が可能です。
コマンダー画面例
画面はテキストのみの構成ですが、画面上部のタブや、反転表示の文字はマウスの左クリックで選択可能です。
1.2.1.2.2 - 画面の操作 TWELITE STAGE APP の各画面における操作説明
Windows
macOS
Linux
RasPi
メニュー画面の例
Windows / macOS / Linux / Raspberry Pi TWELITE STAGE APPはコンソール画面(コマンドライン)から起動するアプリケーションです。コンソール画面とウインドウ画面の両方に情報を出力します。
コンソール画面には、ターミナルと同様にUART出力を表示します。
一部の環境でコンソール画面の入力を受け付ることがありますが、確認済みの正式機能という位置づけではありません。
Raspberry Pi (nox) X11 を使わず、フレームバッファに表示します。
通常(フレームバッファ上のシェル画面から起動した場合)はコンソール画面を表示しません。
1.2.1.2.2.1 - シリアルポート選択 シリアルポート選択画面の操作説明
Windows
macOS
Linux
RasPi
概要 Windows / macOS / Linux では、始動時にTWELITEが接続されたシリアルポートを選択する画面を表示します。 ただし、シリアルポートは、あとから接続することもできます。
シリアルポート選択画面の例
TWELITE STAGEアプリでは、シリアルポートの選択と各画面の処理は連携しません。 例えば、シリアルポートの選択をしていない状態で、ビューアを起動しても表示は更新されません。この状態でシリアルポートを選択すると、ビューワの表示が更新されます。
なお、シリアルポートは Alt(⌘)
+0
, 1
, 2
, … のキー操作でいつでも切り替えできます。
Windows c
キーを押すと、リストで反転中のシリアルポートのCOMポート名が表示されます。
Raspberry Pi Raspberry Pi ではUSBデバイスに加えて/dev/serial0
/dev/serial1
があれば serial0
, serial1
を表示します。なお、通常はserial0
を使用します。
1.2.1.2.2.2 - メインメニュー メインメニュー画面の操作説明
Windows
macOS
Linux
RasPi
階層化されたメニューの最上位に位置します。
メインメニュー画面の例
この画面では、メニュー選択を行います。メニューを反転すると、下部緑色文字部分に簡易的な解説を表示します。
ビューア : TWELITE から受信した電文を解釈して表示するビューアです。多くの場合、受信側の TWELITE には App_Wings を書き込んでおきます。 アプリ書き換え : ファームウェアをビルドし、接続した TWELITE に書き込みます。 インタラクティブモード : 接続した TWELITE 設定を、インタラクティブモードによって行います。 TWELITE STAGEの設定 : TWELITE STAGE アプリの各種設定を行います。 シリアルポートの選択 : シリアルポートを選択します。 説明書 : 説明書を表示するメニューです。以下の説明書をブラウザで開きます。TWELITE STAGE アプリ(この文書) MWX ライブラリ TWENET_C ライブラリ 1.2.1.2.2.2.1 - ビューア ビューアについて
Windows
macOS
Linux
RasPi
ビューアは、接続した TWELITE から受信した情報を表示したり、コマンドを送ったりするための機能です。
各々のビューアは、比較的小規模なプログラムで mwm5 ライブラリの使用方法のサンプルを兼ねています。
1.2.1.2.2.2.1.1 - ターミナル ターミナル画面の操作説明
Windows
macOS
Linux
RasPi
ターミナル画面の例
概要 一般的なVT100系のシリアルターミナルです。
TWELITE のインタラクティブモードやリセット制御をサポートしています。
操作 操作 説明 [ A ] + + +
シーケンスの入力(インタラクティブモード)[ A ]長押し この画面を抜けて、前のメニューに戻ります。 [ B ] 大きなフォントで最初の画面の部分領域を表示します。カーソルが画面中に表示されるように領域を選びますが、画面出力によっては見たい部分が見えない場合もあります。 [ B ]長押し 折返し制御のON/OFFを変更します。標準では折返し表示を行うようになっていますが、折り返ししないように表示することもできます。画面右端以降の文字列は表示されません。 [ C ] ファーム書換画面に移動します。ファームウェアの開発中には頻繁にソースコードの修正、動作確認、ビルド&書き込みを行うため、ショートカットを用意しています。 [ C ]長押し TWELITE のリセットピンを制御し、リセットします。 ESC
ESC
ESC
キーを2回素早く入力することで、この画面を抜けます。※ 殆どの画面ではESC
キーを1回押すことで画面から抜ける操作となっていますが、ターミナルではESC
キーの単独入力を使用する場合があるため、2回連続入力の割当になっています。
1.2.1.2.2.2.1.2 - 標準アプリ ビューア 標準アプリビューア画面の操作説明
Windows
macOS
Linux
RasPi
標準アプリビューア画面の例
概要 通信相手の TWELITE には App_Twelite
(標準アプリ)を書き込んでおきます。標準アプリのボタンやアナログ入力の状態のメッセージ (0x81
メッセージ) を受信すると、その内容を mwm5
のパーサーライブラリにより解釈して表示します。
PC に接続する TWELITE に App_Twelite(標準アプリ) または App_Wings(親機・中継機アプリ)を書き込んでおき、通信相手のTWELITEから受信したデータがターミナルに表示されることを確認してから使用してください。
操作 操作 説明 [ A ] 割当なし [ A ]長押し この画面を抜けて、前のメニューに戻ります。 [ B ] フォントを変更します。 [ B ]長押し テスト用のダミーデータによる画面表示を行います。 [ C ] 割当なし [ C ]長押し TWELITE のリセットピンを制御し、リセットします。 ESC
ESC
ESC
キーを入力することで、この画面を抜けます。
1.2.1.2.2.2.1.3 - グラフ グラフ画面の一覧
加速度リアルタイムグラフ:加速度センサーのパケットをリアルタイムで表示します。周波数領域の表示や CSV ファイルの保存ができます。 センサーグラフ:TWELITE 各種センサーのデータを sqlite3 データベースに保存し、グラフを表示します。 1.2.1.2.2.2.1.3.1 - 加速度リアルタイムグラフ 加速度リアルタイムグラフ画面の操作説明
Windows
macOS
Linux
RasPi
デモデータの表示例
概要 TWELITE CUE や TWELITE 動作センサーPAL から受信したパケットを参照します。加速度データをリアルタイムで表示できるほか、周波数解析や CSV 出力の機能があります。
加速度リアルタイムグラフでは、各サンプルデータを別々に処理します。
一方、
センサーグラフ では、1パケットに複数サンプルが含まれるような連続計測を行う場合であっても、1パケットを1サンプルとして記録します。
CUE モード、MOTモード、2525 FIFO モードの3種類に対応しています。
連続したサンプルが一定数(解析窓)以上になると、XYZ軸を周波数解析した表示を行います。ただし 2525 FIFO モードでは常に連続していると仮定します。
パケットの区切りが明示的である場合(直前のパケットから3秒以上経過したとき、CUEモードは1パケットごと、MOTモードはパケットのシーケンス番号が不連続になった場合)には、4サンプル分のダミーデータを挿入しピンク色の背景色を表示します。
先着順に最大4ノードまでのデータを格納します。
複数ノード運用時には、互いのパケット衝突により通信の失敗が多くなります 。特に FIFO モードでは、送信周期がほぼ一定で互いにほぼ同時期にパケット送信を試み、干渉により送信が失敗するといったことが長時間続く場合があります。原則として無線チャネル1つにつき、1ノードという運用を行ってください。
工場出荷時の TWELITE CUE は TWELITE CUE モード に設定されています。
連続したデータを計測する場合は動作センサーパルモード に変更してください。
加速度リアルタイムグラフを使用する場合における動作センサーパルモードの代表的な設定を以下に記します。
連続的に約 25Hz で計測したいときt: set Transmission Interval (0)
p: set Sensor Parameter (03000000)
連続的に約 50Hz で計測したいときt: set Transmission Interval (0)
p: set Sensor Parameter (03000100)
連続的に約 100Hz で計測したいときt: set Transmission Interval (0)
p: set Sensor Parameter (03000200)
約10秒おきに 約 100Hz で128サンプル分計測したいときt: set Transmission Interval (10)
p: set Sensor Parameter (03000208)
約10秒おきに 約 100Hz で256サンプル分計測したいときt: set Transmission Interval (10)
p: set Sensor Parameter (03000210)
約10秒おきに 約 50Hz で64サンプル分計測したいときt: set Transmission Interval (10)
p: set Sensor Parameter (03000104)
約10秒おきに 約 200Hz で128サンプル分計測したいときt: set Transmission Interval (10)
p: set Sensor Parameter (03000308)
操作 操作 説明 右上部(i)ID#
ボタン クリックするごとにIDの切り替えを行います。(注:FIFOモードによる連続サンプルデータは、複数IDによる運用に向きません) 右上部(f)SMP#
ボタン クリックするごとに解析窓サイズを 64,128,256 と変更します。 右下部(c)表示データ保存
ボタン log
フォルダにCSV形式のデータ出力を行います。バッファにある最も古いサンプルから、画面右端の最新のサンプルまでを出力します。(注:出力数は常に 5120 サンプルであり、末尾のデータが最新です)右下部PAUSE( )
ボタン 表示更新を中断します。(注:サンプルの取得は内部の一時サンプルバッファが一杯になるまで行います) マウスドラッグ(グラフ部分) 表示サンプルの位置を移動します。 マウスドラッグ(下部スクロールバー) より大きなステップで表示サンプルの位置を移動します。 カーソルキー→
←
サンプルの表示領域を移動させます。 カーソルキー↑
↓
サンプルの横軸を拡大・縮小(等倍 / 2倍 / 3倍 / 4倍)します。(注:解析サンプル数 256 の場合は2倍まで)
サンプルレートの推定 サンプリングレートは、パケットの受信時間から計算しています。過去複数サンプルの受信時間を平均して1サンプル分としているため、パケットの飛びなどがある場合は誤差が大きくなります。
また、関連するログ記録のタイムスタンプ(T_SMPL
)も同様に推測値であり、パケット取得時と比較して遅れたタイムスタンプになります。
なお、サンプルレートの推定が終わると、グラフ表示のスクロールをスムーズにします。
CUEグラフモードの起動時に開く [STAGE 共通設定→起動アプリ指定]にて31
を指定してください。
ログ出力(表示データ保存) (c)表示データ保存
ボタンを押すことで、画面上の表示位置(右端サンプル)を起点とした最大 512 サンプル分のデータを出力できます。
最新のサンプルが末尾に記録されるため、冒頭には何もデータが無い場合がある点に注意してください。
ログファイル名は {logフォルダ}/acc_snap_{タイムスタンプ}.csv
です。
データは、画面右端の一番新しいサンプルが 512 番目(ファイルの末尾)です。 周波数解析実行時は、最後のサンプルから 周波数解析サンプル数分が対象です。 周波数解析対象サンプルが記録されている行に周波数解析結果を追加しています(64 サンプルの場合は 449 番目から 32 行が結果で DC 成分から高周波成分までが並びます)。 ラベル 項目名 説明 #
サンプル番号 T_PKT[ms]
パケット受信時刻 1パケットに複数のサンプルが含まれるため、同じタイムスタンプのサンプルが並びます。 SEQ
パケット続き番号 各パケットに付与されており、連続していればパケットの欠落がないと考えられます。 T_SMPL[ms]
サンプル時刻(仮想・推定) パケットの受信時刻から生成した各サンプルのタイムスタンプです。実際にサンプルが行われた時刻とは一致しません。(注:サンプルレートをパケット受信間隔から推定しているため誤差が大きくなるほか、サンプル周期を都度加算しているため実際のサンプル時刻よりも1パケット周期分遅れたタイムスタンプを記録します) X[G]
X軸のサンプル値 単位はG
です。センサーの値に基づいています。 Y[G]
Y軸のサンプル値 単位はG
です。センサーの値に基づいています。 Z[G]
Z軸のサンプル値 単位はG
です。センサーの値に基づいています。 FD#
周波数解析計算値の番号 周波数解析サンプル数が 64 の場合は DC,1,2,...,31
の順で並びます。 Hz
周波数解析計算結果の周波数軸の値 推定の周波数です。(FD# / FD_Len) * FD_Freq
のように計算しています。 X
X軸の周波数解析計算値 Y
Y軸の周波数解析計算値 Z
Z軸の周波数解析計算値 Label
追加情報名 下表 参照Info
追加情報 下表 参照
追加情報 情報名 解説 ModuleSID
送信側のシリアル番号 Tick[ms]
ログファイルを開いたときのシステム時間(注:TWELITE STAGEアプリ側) Date
ログファイルを開いたときの日付 Time
ログファイルを開いたときの時刻 Time_Msec_part
ログファイルを開いたときの秒未満部分 [ms] Samples
有効サンプルデータ FD_Len
周波数解析サンプル数 FD_Start#
周波数解析開始サンプル番号 FD_Freq
周波数解析範囲の周波数推定値[Hz](注:サンプル受信間隔からの推定)
ログ出力(自動保存) 加速度リアルタイムグラフ画面を開き、データが入力された時点から自動的にログファイルを出力します。
ログファイル名は logフォルダ/accel_{シリアル番号}_{タイムスタンプ}.csv
です。
画面を開いている間はファイルの書き出しを行うため、その間には読み出し用に開けない、またはすべてのデータが読み出せない場合があります。
ラベル 項目名 説明 #
サンプル番号 T_PKT[ms]
パケット受信時刻 1パケットに複数のサンプルが含まれるため、同じタイムスタンプのサンプルが並びます。 SEQ
パケット続き番号 各パケットに付与されており、連続していればパケットの欠落がないと考えられます。 T_SMPL[ms]
サンプル時刻(仮想・推定) パケットの受信時刻から生成した各サンプルのタイムスタンプです。実際にサンプルが行われた時刻とは一致しません。(注:サンプルレートをパケット受信間隔から推定しているため誤差が大きくなるほか、サンプル周期を都度加算しているため実際のサンプル時刻よりも1パケット周期分遅れたタイムスタンプを記録します) X[G]
X軸のサンプル値 単位はG
です。センサーの値に基づいています。 Y[G]
Y軸のサンプル値 単位はG
です。センサーの値に基づいています。 Z[G]
Z軸のサンプル値 単位はG
です。センサーの値に基づいています。 Label
追加情報名 下表 参照Info
追加情報 下表 参照
追加情報 情報名 解説 ModuleSID
送信側のシリアル番号 Tick[ms]
ログファイルを開いたときのシステム時間(注:TWELITE STAGEアプリ側) Date
ログファイルを開いたときの日付 Time
ログファイルを開いたときの時刻 Time_Msec_part
ログファイルを開いたときの秒未満部分 [ms]
1.2.1.2.2.2.1.3.2 - センサーグラフ センサーグラフ画面の操作説明
Windows
macOS
Linux
RasPi
データの表示例
概要 各種センサーデータを SQLite データベースに記録し、画面上にグラフ形式で表示します。データベースファイルは外部のアプリケーションから参照することも可能です。
同一実行形式名の TWELITE STAGE APP を複数起動して、センサーグラフを同時に使用することはできません。
データベースファイルは {MWSTAGEインストール}/log
フォルダに格納され、TWELITE STAGE APP の実行形式名をもとにファイル名が決まります。同一の実行形式名である場合は、同じデータベースファイルを参照してしまいます。TWELITE STAGE APP の実装では、複数のアプリが同時に同一のデータベースにデータを追加することを想定していません。また、場合によってはデータベースファイルのアクセスエラーとなり、TWELITE STAGE APP がクラッシュすることもあります。
例えば、MONOSTICK を PC に2台接続して、同時に複数の「センサーグラフ」を動作させたい場合には、別の実行形式名 (TWELITE_Stage_a.exe
, TWELITE_Stage_b.exe
) とした TWELITE STAGE アプリを複数実行します。このときのデータベースファイル名はそれぞれ log/TWELITE_Stage_a_WSns.sqlite
, log/TWELITE_Stage_b_WSns.sqlite
です。
データベースには SQLite (sqlite3) を使用しており、{MW_STAGE Install}/log/{実行形式名}_WSns.sqlite
というファイルに格納されます。 画面遷移は [一覧(グラフプレビューあり)]
>[24時間データ]
>[ライブビュー]
です。[24時間データ]
から更に [年]
[月]
[日(グラフプレビューあり)]
選択画面に遷移できます。 [ライブ]
表示画面について一覧から特定のノードを選択します。 1秒おきのリアルタイム表示を行い、過去 450 秒間のデータを表示します。 [24時間データ]
表示画面について特定の日のデータを表示します。 1秒おきの更新とし、その間に複数のデータがあった場合は間引かれます。 最大拡大時(1ピクセル1秒)以外は、各ピクセルの範囲における取得値の平均を表示します。 値が画面よりはみ出す場合は、上下端に測定点を表示します。 現在時刻が含まれる場合には、新着データで表示を更新します。 マウスホイールやカーソルキー↑
↓
の入力:時間軸の拡大・縮小 マウスポインタの移動:マウスポインタに対応した時間軸にある取得データを簡易表示します。 マウスクリック&ドラッグ:スクロール(拡大時のみ) 拡大時はスクロールバーによる操作も可能です。 [CSV出力]
機能では、データベースに含まれるすべての取得値を表示します。操作 操作 説明 マウスドラッグ(グラフ部分) 拡大時に表示サンプルの位置を移動します。 マウスドラッグ(下部スクロールバー) 表示サンプルの位置を移動します。 カーソルキー→
←
サンプルの表示領域を移動させます。 カーソルキー↑
↓
サンプルの横軸を拡大・縮小します。 [ライブ]
1秒刻みで最新のデータを表示するビューに移動します。 [24時間データ]
1日単位のグラフに移動します。 [<<一覧]
一覧選択画面に移動します。 [年]
[月]
[日]
年月日で、特定の日を選択します。 [最新]
今日のデータに移動します。 [CSV出力]
1日分のデータをCSVファイルに出力します。 一覧で[表示]
リストの表示方式を変更します。 一覧で[ソート]
リストの並び順を変更します。 一覧で[↑]
リストの並び順を反転します。
センサーノードのメモ(補助情報)の編集 v1.3.9+ 「24時間データ画面」で、画面右上のセンサーノードのメモ部分を左クリックすると、メモを編集するためのプロンプトを使用できます。
センサーノードのメモを編集する様子(IMEオン)
キー 説明 通常の半角文字 通常の半角英数文字列を直接入力した場合は画面上にも表示されます。 IME による入力 IMEからの入力は画面左上部分に入力途上の文字列が表示されます。ENTER
キーで入力中の文字列を確定します。 BS
表示されている末尾の文字を削除します。 ENTER
入力した文字列をデータベースに反映します。
IME入力時の操作方法は、システム環境に依存する場合があります。
また、IME入力時の操作によっては期待しない文字列が入力される場合があります。不要な文字列が入力エリアに表示された場合は BS
キーで不要部分を削除してください。
画面遷移 基本の画面は一覧、24時間、ライブの3種類に分けられます。
[一覧] <--> [24時間] <--> [ライブ]
↓↑
[年月日選択]
センサーグラフモードの起動時に開く [STAGE 共通設定 → 起動アプリ指定] にて 32
を指定してください。
DBのテーブルについて sensor_data
受信したデータを格納します。
カラム名 型 解説 _uqid
INTEGER データベースで使用する続き番号 sid
INTEGERint32_t
int32_t
型で格納しているシリアル番号です。例えば “8123abcd” というシリアル番号の場合は整数値で -2,128,368,691 の値が格納されます。ts
INTEGERint64_t
システムがパケットを受信した時刻で、int64_t
型で格納されるタイムスタンプ値です。UNIX epoch (エポック、1970年からの経過秒) です。 ts_msec
INTEGER タイムスタンプのミリ秒部分です。 year
INTEGER タイムスタンプよりローカル時間の年部分です。 month
INTEGER タイムスタンプよりローカル時間の月部分です。 day
INTEGER タイムスタンプよりローカル時間の日部分です。 hour
INTEGER タイムスタンプよりローカル時間の時部分です。 lid
INTEGER ユーザにより割り当てられた LID などの識別値です。 lqi
INTEGER 受信強度の目安値です (Link Quality Indicator) 。 pkt_seq
INTEGER パケットの続き番号です。どのような値を取りうるのかはファームウェアによって異なります。 pkt_type
INTEGER 無線パケットの種別です。2 PAL AMB
6 ARIA
1 PAL MAG
*3 PAL MOT
5 CUE
0x101 App_Twelite
*0x103 App_IO
*現時点で非対応 value
REAL 計測値です(パケット種別によって定義が異なります)。pkt_type->
2,6: 温度[°C]
1: 磁石の判定有無 (00->磁石なし, 01->N極, 02->S極)
3,5: X軸加速度(パケット中に複数サンプル含まれる場合は平均値)[G]
0x101,103: 入力IOのビットマップ(val_dioの下位8ビットと同値)
value1
REAL 計測値です(パケット種別によって定義が異なります)。pkt_type->
2,6: 湿度[%]
1: 未使用
3,5: Y軸加速度(パケット中に複数サンプル含まれる場合は平均値)[G]
0x101: ADC1[V]
103: 未使用
value2
REAL 計測値です(パケット種別によって定義が異なります)。pkt_type->
2: 照度[lx]
6: 未使用
1: 未使用
3,5: Z軸加速度(パケット中に複数サンプル含まれる場合は平均値)[G]
0x101: ADC2[V]
103: 未使用
value3
REAL 計測値です(パケット種別によって定義が異なります)。pkt_type->
2: 未使用
6: 未使用
1: 未使用
3,5: 未使用
0x101: ADC3[V]
103: 未使用
val_vcc_mv
INTEGER 電源電圧[mV] val_dio
INTEGERint32_t
b0..b7
: DI1..DI8
の値 (1
はLOW, 0
はHIGHレベル)b24..b25
: マグネット値 (b28
が1
の場合) 00
->磁石なし, 01
->N極, 10
->S極b28
: 1
の場合マグネットデータがb24..b25
に格納されるb31
: 定期送信ビット(マグネットのみ)val_adc1_mv
INTEGER pkt_type->
1,2,3,0x101
: ADC1の計測値val_adc2_mv
INTEGER pkt_type->
0x101
: ADC4の計測値val_aux
INTEGER その他データ格納目的 ev_src
INTEGER イベント発生元 ev_id
INTEGER イベントIDpal_type->
5: サイコロ(1...6)
16→MOVE他
資料参照 ev_param
INTEGER イベントパラメータ
sensor_node
センサーノードにテキストメモ(付加情報)を格納します。
カラム名 型 解説 sid
INTEGER 上述のSID sid_text
TEXT 可読性のためにSIDを16進数に変換した文字列 desc
TEXTUTF-8
SIDに対応するメモ(補助情報)。一覧などで表示する
sensor_last
最後に受信したタイムスタンプを管理します。
カラム名 型 解説 sid
INTEGER 上述のSID ts
INTEGER 最後の受信したときのタイムスタンプ lid
以下、最後に受信時のデータの抜粋 lqi
pkt_type
value
value1
value2
value3
val_vcc_mv
val_dio
ev_id
1.2.1.2.2.2.1.4 - 簡易モニタ 簡易モニタの一覧
CUEビューア : TWELITE CUE からのパケットを解釈して簡易表示します ARIAビューア : TWELITE ARIA からのパケットを解釈して簡易表示します Glancer : TWELITE の多くの形式に対応した簡易モニタです 1.2.1.2.2.2.1.4.1 - CUE ビューア CUE ビューア画面の操作説明
Windows
macOS
Linux
RasPi
このページには旧バージョンのキャプチャ画像が含まれます。
サイコロ面の検出例
概要 TWELITE CUE から受信したメッセージを解釈して表示します。
TWELITE CUE の動作 工場出荷時の TWELITE CUE は、TWELITE CUEモード に設定されています。
TWELITE CUEモードでは、コイン電池で駆動できるように間欠駆動をしながら、いくつかの要因によってスリープから起床して、様々なデータを送信します。
CUEモードは TWELITE CUE の動作確認を想定しているため、搭載するセンサーやLEDのすべてを動作させます。
起床要因 TWELITE CUE がスリープから起床するには、以下のうちいずれかの要因を必要とします。
タイマーによる起床(定期的な起床) 加速度の検出による起床 磁気センサーによる起床(磁石が近づいたことを検出した場合) 送信するデータの種類 TWELITE CUE は、以下のデータをパケットに収めて送信します。
検出イベント(後述 ) モジュール電源電圧 磁気センサーの検出値 加速度データ パケットの属性 受信したパケットの属性からは、その基本情報を得ることができます。
属性 解説 #???? これまでの受信パケット数です。 種別 mwm5
ライブラリにおけるE_PKT
の値で、パケット種別です。TWELITE CUEからのパケットは通常PKT_PAL=02
です。ID 送信元の論理IDです。通常は0..100
の値になります。 AD 送信元のシリアル番号です。 LQ 受信強度の目安値です (Link Quality Indicator) 。 SQ パケットの続き番号です。
イベント TWELITE CUEモードでは、必ず加速度イベントを出力します。
起床要因に関わらず、起床後には一定サンプル数の加速度を計測します。このとき、加速度の計測結果に応じてイベントを判定します。
イベント 番号 解説 ダイス 1(0x00) .. 6(0x06)
定期起床と磁気センサー検出起床を起点に判定します。起床後に大きな加速度が検出される場合は、判定不可としたイベント(0xFF
)を検出する場合があります。 ムーブ 16(0x10)
加速度センサーが一定以上の加速度を検出したときに、ムーブまたはシェイクのイベントが発生します。ムーブは、計測した加速度の変化が比較的小さい場合(加速度の変化は検出したが、連続的な加速度の変化がなかった場合)に発生します。 シェイク 0x08
加速度センサーが一定以上の加速度を検出したときに、ムーブまたはシェイクのイベントが発生します。シェイクは、計測した加速度の変化が比較的大きい場合(連続的な加速度の変化を検出した場合)に発生します。
加速度のしきい値やイベントの検出条件について、定量的な定義は案内しておりません。
電圧 モジュールの電源電圧[mV]です。
磁石 検出された磁石の極または未検出を表示します。
磁気センサーの検出による起床であるかどうかを表示する機能はありません。
加速度 起床後に計測された加速度を表示します。
サンプル:加速度のサンプル数を表示しています。10サンプル固定です。 レートID:加速度のサンプルレートです。04固定で100Hzです。 X,Y,Z:3つの軸の加速度です。8サンプル分の平均値として求めています。単位はミリG (1000mG=1G=9.8m/s2)です。 画面の表示例 ムーブイベントの検出例
シェイクイベントの検出例
1.2.1.2.2.2.1.4.2 - ARIA ビューア ARIA ビューア画面の操作説明
Windows
macOS
Linux
RasPi
このページには旧バージョンのキャプチャ画像が含まれます。
温湿度データ表の表示例
概要 TWELITE ARIA から受信したメッセージを解釈して表示します。
TWELITE ARIA の動作 工場出荷時の TWELITE ARIA は、TWELITE ARIAモード に設定されています。
TWELITE ARIAモードでは、コイン電池で駆動できるように間欠駆動をしながら、いくつかの要因によってスリープから起床して、様々なデータを送信します。
起床要因 TWELITE ARIA がスリープから起床するには、以下のうちいずれかの要因を必要とします。
タイマーによる起床(定期的な起床) 磁気センサーによる起床(磁石が近づいたことを検出した場合) 送信するデータの種類 TWELITE ARIA は、以下のデータをパケットに収めて送信します。
モジュール電源電圧 磁気センサーの検出値 温湿度データ パケットの属性 受信したパケットの属性からは、その基本情報を得ることができます。
属性 解説 #???? これまでの受信パケット数です。 種別 mwm5
ライブラリにおけるE_PKT
の値で、パケット種別です。TWELITE ARIAからのパケットは通常PKT_PAL=02
です。ID 送信元の論理IDです。通常は0..100
の値になります。 AD 送信元のシリアル番号です。 LQ 受信強度の目安値です (Link Quality Indicator) 。 SQ パケットの続き番号です。
温湿度データ表 TWELITE ARIAから受信した過去9回分のデータの履歴を表示します。最新のデータが最上部に表示されます。
時間[s] TWELITE STAGE APPが起動してからデータを受信するまでの時間[秒]です。
ID モジュールの論理デバイスIDです。
VCC(mV) モジュールの電源電圧[mV]です。
温度(C) モジュールが計測した温度(°C)です。
湿度(%) モジュールが計測した湿度(%)です。
磁石 検出された磁石の極または未検出を表示します。
磁気センサーの検出による起床であるかどうかを表示する機能はありません。
1.2.1.2.2.2.1.4.3 - グランサー グランサー画面の操作説明
Windows
macOS
Linux
RasPi
概要 Glancer は、受信メッセージ中の情報 を簡易的に表示します。
接続する TWELITE には App_Wings
を書き込んでおくことで、通信相手のTWELITE (App_Twelite
, TWELITE PAL, … アプリケーションIDと周波数チャネルを一致させれば混在も可) から受信した情報を表示できます。
Glancer は、glance(=ちらりと見る、一瞥)する人という意味の英単語です。
操作 一覧表示の画面と選択表示の画面を切り替えて使用します。
一覧表示 一覧表示の例
通信相手からの情報を列挙します。
表示内容は(メッセージの種別、論理デバイスID、シリアルID、LQI (Lq)、電源電圧(情報に含まれている場合)、タイムスタンプ)です。
操作 説明 [ A ] リストの前項目に移動します。 [ A ]長押し この画面を抜けて、前メニューに戻ります。 [ B ] 選択表示に移行します。 [ B ]長押し 項目をソートします。ソートを実行するたびに、ソートキーは順に変わります。 [ C ] リストの次項目に移動します。 [ C ]長押し TWELITE のリセットピンを制御し、リセットします。 ESC
この画面を抜けます。
選択表示 選択表示の例
一覧表示で項目を移動し反転表示になったところで選択操作を行うことで、この画面に遷移します。特定の通信相手に関する情報を到着順に表示します。
選択されてからの受信パケット数と LQI の平均値が表示されます。
操作 説明 [ A ] 割当なし [ A ]長押し この画面を抜けて、前メニューに戻ります。 [ B ] 割当なし [ B ]長押し 割当なし [ C ] 割当なし [ C ]長押し TWELITE のリセットピンを制御し、リセットします。 ESC
選択画面に戻ります。
1.2.1.2.2.2.1.5 - コマンダー コマンダー画面の操作説明
Windows
macOS
Linux
RasPi
概要 コマンダーは、TWELITE にシリアルメッセージを送信する機能です。
操作 コマンダーの最初の画面は留意事項について記載しています。
画面上部にはテキストで表現されたタブがあり、これをマウスでクリックすることでタブ中の画面に移動できます。
操作 説明 [ A ] タブの移動(左) [ A ]長押し この画面を抜けて、選択画面に戻ります。 [ B ] 割当なし [ B ]長押し 割当なし [ C ] タブの移動(右) [ C ]長押し TWELITE のリセットピンを制御し、リセットします。 ESC
この画面を抜けて、選択画面に戻ります。
タブ:TWELITE この画面では、 標準アプリ(App_Twelite) の 0x80コマンド を生成し、送信します。
接続する TWELITE には App_Twelite または 親機・中継機アプリ(App_Wings) を書き込んでおき、アプリケーションID・チャネルを設定した上で、通信相手からメッセージが受信されていることを確認してください。
TWELITEタブの表示例
項目 内容 宛先 送信先の TWELITE を指定します。自身が子機の場合は「親機:0」宛を指定してください。自身が親機の場合は「全子機=0x78」または特定の子機ID(1..8まで指定可能)を指定します。 DI1..DI4 DI1からDI4までの設定状態です。■は選択(LOW=GNDレベル)、□は(HIGH=VCCレベル)を意味します。下項目のSELを指定してください。 SEL 各DIの選択ビットです。(0ならDIの指定を無視し、1なら指定を有効化します。) PWM1..4 PWMのデューティ比を設定します。0はGNDレベル相当、1024(100%)はVCCレベル相当です。N.A.にしたPWMポートは変更しません。(注:MW-STA-KIT-0/MW-STA-SOLO-0基板のPWM1はVCCからの吸い込みとなっているため、 LEDは0のときに最も明るく点灯し、100%で消灯します。)
各項目を変更するたびにコマンドが生成されます。送信ボタンを押すと、現在の設定のコマンドを再度送信します。
タブ:NOTICE この画面では、通知PAL(NOTICE PAL) の LED制御コマンド を生成します。
接続する TWELITE には App_Wings を書き込んでおき、アプリケーションID・チャネルを設定した上で、通信相手からメッセージが受信されていることを確認します。
TWELITEタブの表示例
項目 内容 宛先 送信先の TWELITE PAL の ID を指定します。値の範囲は 1..8 です。 色 点灯色を7色から指定します。白は2種類ありますが、一方はRGBの混色でもう一方は白色LED単体が点灯します。 明るさ 0..15で指定します。0は消灯です。 点灯点滅 点灯または点滅パターンを選択します。 点灯時間 コマンド発行後、一定時間経過すると自動的に消灯する機能です。 消灯(x) 消灯メッセージを生成し、LEDを消灯させます。 点灯(SPACE) 現在の設定を送信し、LEDを点灯させます。
各項目を変更するたびにコマンドが生成されます。送信ボタンを押すと、現在の設定のコマンドを再度送信します。
画面下部の表示 画面下部には、コマンドが生成されたタイムスタンプと :で始まるコマンドが表示されます。クリップボードにはこの画面の内容がコピーされます。
1.2.1.2.2.2.2 - アプリ書換 アプリ書換の機能について
Windows
macOS
Linux
RasPi
アプリ書換機能では、TWELITE のアプリ(ファームウェア)を書き込むことができます。
ビルド済みの.BIN
ファイルを書き込む アクト(act)などのソースファイルからビルドして書き込む ソースファイルのビルド、ターミナル切断、書き込みユーティリティ起動、ターミナル接続といった煩雑さを解消できます。
TWELITE を自動で認識する 書き込み終了後にリセットしてからインタラクティブモードまたはターミナルに遷移する 各プロジェクトのリストから、プロジェクトフォルダまたはVSCode等の環境を起動する (Raspberry Pi版を除く) 各プロジェクトのリストから、関連情報のウェブページを開く (Linux版、Raspberry Pi版を除く) 1.2.1.2.2.2.2.1 - BINから選択 BINから選択の画面の操作説明
Windows
macOS
Linux
RasPi
概要 ビルド済みのアプリ(.BIN
ファイル)を書き込むことができます。
BINから選択画面の例
メニューを選択すると、.BIN
ファイルの一覧が表示されます。書き込むファームウェアを選択してください。
あらかじめ用意されている.BIN
ファイルとは別のファイルを使用する際は、メニューを選択する前に書き込むファイルを以下に格納してください。
プラットフォーム 場所 Windows, macOS, Linux, Raspberry Pi {MWSTAGEフォルダ}/BIN
BIN
フォルダには、ファイル名を変更せずに TWELITE STAGE でビルドした .BIN
ファイル(各プロジェクトのbuild
フォルダ以下に格納されています)を格納してください。
../BIN/App_Wings_MONOSTICK_BLUE_L1304_V1-1-3.bin
App_Wings_MONOSTICK_RED_L1304_V1-1-3.bin
App_Twelite_BLUE_L1304_V1-9-1.bin
App_Twelite_RED_L1304_V1-9-1.bin
...
この機能では、ファイル名から TWELITE(BLUE/REDなど) の識別を行っています。
1.2.1.2.2.2.2.2 - actビルド&書換 actビルド&書換の画面の操作説明
Windows
macOS
Linux
RasPi
概要 MWX ライブラリによって記述されたアクト(act)のビルドと書き換えを行うことができます。
サンプルアクト選択画面の例
この画面では、以下のパスに配置されたアクトによるプロジェクトの一覧を表示します。
{MWSTAGEインストールフォルダ}/MWSTAGE/Act_samples
デフォルトでは、サンプルとしてご利用いただくことを想定した比較的小規模なプロジェクトを収録しています。
操作 一覧から書き込むプロジェクトを選択することで、ビルド~書き込みを行えます。
なお、書き込み終了後に ENTER
または[ B ]ボタンを押すことで、TWELITE をリセットしてインタラクティブモード画面(もしくはターミナル画面、要設定)に遷移できます。
ビルド~書き込み画面
VSCodeを利用する設定(アプリ書換>codeでフォルダを開く)を有効化している場合は、ビルドは行わずに
build/
以下の
.BIN
ファイルを書き込む
画面 を開きます。
操作 説明 [ A ] メニュー選択↑ [ A ]長押し この画面を抜けて、選択画面に戻ります。 [ B ] 選択 [ B ]長押し 関連ウェブサイトをOS標準のブラウザで開きます。(プロジェクトフォルダの000desc.txt
に登録されている場合) [ C ] メニュー選択↓ [ C ]長押し フォルダ(プロジェクト、関連フォルダ)を開きます。設定メニューでVS Codeで開くように設定できます。 ESC
この画面を抜けて、アプリ書換メニューに戻ります。 マウスクリック[ヘルプ] 関連ウェブサイトを開きます。 マウスクリック[フォルダ] または [VSCode] 関連フォルダを開きます。 マウスクリック [▽] または [△] 次ページ、前ページに移動します。
1.2.1.2.2.2.2.3 - TWELITE APPSビルド&書換 TWELITE APPSビルド&書換の画面の操作説明
Windows
macOS
Linux
RasPi
概要 TWENET C ライブラリによって記述された TWELITE APPS のビルドと書き換えを行うことができます。
アプリ選択画面の例
この画面では、以下のパスに配置されたプロジェクトの一覧を表示します。
{MWSTAGEインストールフォルダ}/MWSTAGE/Wks_TweApps
デフォルトでは、そのままご利用いただくことを想定した比較的大規模なプロジェクトを収録しています。
操作 一覧から書き込むプロジェクトを選択することで、ビルド~書き込みを行えます。
なお、書き込み終了後に ENTER
または[ B ]ボタンを押すことで、TWELITE をリセットしてインタラクティブモード画面(もしくはターミナル画面、要設定)に遷移できます。
ビルド~書き込み画面
VSCodeを利用する設定(アプリ書換>codeでフォルダを開く)を有効化している場合は、ビルドは行わずに
build/
以下の
.BIN
ファイルを書き込む
画面 を開きます。
操作 説明 [ A ] メニュー選択↑ [ A ]長押し この画面を抜けて、選択画面に戻ります。 [ B ] 選択 [ B ]長押し 関連ウェブサイトをOS標準のブラウザで開きます。(プロジェクトフォルダの000desc.txt
に登録されている場合) [ C ] メニュー選択↓ [ C ]長押し フォルダ(プロジェクト、関連フォルダ)を開きます。設定メニューでVS Codeで開くように設定できます。 ESC
この画面を抜けて、アプリ書換メニューに戻ります。 マウスクリック[ヘルプ] 関連ウェブサイトを開きます。 マウスクリック[フォルダ] または [VSCode] 関連フォルダを開きます。 マウスクリック [▽] または [△] 次ページ、前ページに移動します。
1.2.1.2.2.2.2.4 - Act_extras Act_extras画面の操作説明
Windows
macOS
Linux
RasPi
概要 MWX ライブラリによって記述されたアクト(act)のビルドと書き換えを行うことができます。
アクト選択画面の例
この画面では、以下のパスに配置されたアクトによるプロジェクトの一覧を表示します。
{MWSTAGEインストールフォルダ}/MWSTAGE/Act_extras
actビルド&書換 とは異なり、サンプルとしてご利用いただくことを想定した比較的複雑な処理を行うプロジェクトや、外部のオープンソースライブラリを利用したプロジェクトを収録しています。
操作 一覧から書き込むプロジェクトを選択することで、ビルド~書き込みを行えます。
なお、書き込み終了後に ENTER
または[ B ]ボタンを押すことで、TWELITE をリセットしてインタラクティブモード画面(もしくはターミナル画面、要設定)に遷移できます。
ビルド~書き込み画面
VSCodeを利用する設定(アプリ書換>codeでフォルダを開く)を有効化している場合は、ビルドは行わずに
build/
以下の
.BIN
ファイルを書き込む
画面 を開きます。
操作 説明 [ A ] メニュー選択↑ [ A ]長押し この画面を抜けて、選択画面に戻ります。 [ B ] 選択 [ B ]長押し 関連ウェブサイトをOS標準のブラウザで開きます。(プロジェクトフォルダの000desc.txt
に登録されている場合) [ C ] メニュー選択↓ [ C ]長押し フォルダ(プロジェクト、関連フォルダ)を開きます。設定メニューでVS Codeで開くように設定できます。 ESC
この画面を抜けて、アプリ書換メニューに戻ります。 マウスクリック[ヘルプ] 関連ウェブサイトを開きます。 マウスクリック[フォルダ] または [VSCode] 関連フォルダを開きます。 マウスクリック [▽] または [△] 次ページ、前ページに移動します。
1.2.1.2.2.2.2.5 - 指定 プロジェクトを指定した書き込み
Windows
macOS
Linux
フォルダまたは.BIN
ファイルを TWELITE STAGE APP の画面にドラッグ&ドロップすることで、特定のプロジェクトを書き込むことができます。 ドロップした対象のビルドや書き込みを行うときに選択します。
.BIN
ファイルをドロップしたときは、そのファイルが格納されるフォルダをドロップした場合と同様に、そのフォルダにあるファームウェアの一覧を表示します。
1.2.1.2.2.2.2.6 - 再書換 直前に書き込んだプロジェクトの再書き込み
Windows
macOS
Linux
RasPi
直前に書き換え・指定したプロジェクトを再選択します。
項目によって、以下のいずれかを行います。
選択したプロジェクトの再書換 直前に選択したプロジェクト一覧の再表示 1.2.1.2.2.2.2.7 - ビルド・書換画面 ビルド・書換画面の操作説明
Windows
macOS
Linux
RasPi
ここでは、プロジェクトのビルドや書換を行うときに表示される画面の操作説明を行います。
ビルド中 ビルド(コンパイル)中の画面です。ビルドコマンドの内容は、コンソール画面に出力されます。画面中の ...
はビルドしたファイル数、下部の暗い色の表示はビルドしているファイル名です。
コンパイル中の画面の例
ビルドエラー ビルドエラーが発生した場合は、上記のような画面を表示します。再ビルドの実行やエラーログの表示を行うことができます。また、一定時間でタイムアウトして直前のメニューに戻ります。
エラー表示画面の例
画面上のエラーメッセージは、代表的なものだけが表示されます。ビルドが失敗したとき、エラー内容のメッセージが表示されないこともあります。
操作 説明 [ A ] 割当なし [ A ]長押し この画面を抜けて、前のメニューに戻ります。 [ B ] エラー時に再ビルドします。 [ B ]長押し 割当なし [ C ] [ C ]長押し エラーログを表示します(Windows/macOS)。保存場所は{プロジェクトフォルダ}/build/builderr.log
です。 ESC
この画面を抜けて、書換メニューに戻ります。 ENTER
エラー時に再ビルドします。
書換中 ビルドが成功すると、ファームウェアを書き込む画面を表示します。
書換中画面の例
書換失敗 書換がエラーの場合は、下記のような画面を表示します。
書換失敗画面の例
操作 説明 [ A ]長押し この画面を抜けて、選択画面に戻ります。 [ B ] 再度書換を行う(直前の書き換えメニューに戻ります。 自動的にメニュー項目が選択されるため、 もう一度[ B ]を押すことで再書換できます) ESC
この画面を抜けて、書換メニューに戻ります。
書換完了 書換が無事に成功すると、下記のような画面を表示します。
書換完了画面の例
v1.0.2以降では、ファームウェア書き換え後に、書き換え内容を読み出して確認するベリファイ処理を行います。
操作 説明 [ A ]長押し この画面を抜けて、選択画面に戻ります。 [ B ] TWELITE をリセットして、インタラクティブモード画面(または設定によりターミナル)画面に移動します。 ESC
この画面を抜けて、書換メニューに戻ります。
1.2.1.2.2.2.3 - インタラクティブモード インタラクティブモードの利用
Windows
macOS
Linux
RasPi
概要 この画面から、接続した TWELITE のインタラクティブモードを利用できます。
インタラクティブモード画面の例
この画面はターミナルとほぼ同じ振る舞いをしますが、インタラクティブモードに遷移するための操作と離脱の検出を行うなど、インタラクティブモードに固有の機能を追加しています。
接続する TWELITE には、インタラクティブモードに対応したファームウェアをあらかじめ書き込んでおく必要があります。 TWELITE の入出力を使用するため、シリアル通信に文字化けなどが発生した場合など、期待通りにインタラクティブモードへの遷移や離脱ができない場合もあります。 マウス操作には対応しておりません。キーボード(カーソル ↑
↓
での操作は可能)操作を行ってください。
ターミナル によるインタラクティブモードへの遷移と操作もできます。
ターミナルでは、自動的にSETピンの操作を行いません。手動でSETピンをLOに設定する必要があります。 ターミナルにおいても、+ + +
入力Alt(⌘)+I
やモジュールリセットAlt(⌘)+R
を行う操作を定義しています。 インタラクティブモード画面の動作フロー 以下に大まかな処理の流れを記載します。
[画面黒背景にする]
↓
[TWELITEのリセット (制御可能ならSET=LO)]
↓
<間欠動作アプリのインタラクティブモードメッセージを検出?> --YES--> [操作画面]へ
↓タイムアウト
['+' を3回入力]
↓
<通常アプリのインタラクティブモードメッセージを検出?> --YES--> [操作画面]へ
↓タイムアウト
[操作画面へ] ※ この状態はインタラクティブモードではない
[操作画面]
↓
<インタラクティブモード脱出メッセージ?> --> [終了]
↓
<画面離脱操作 [ A ] 長押しなど> --> [終了]
↓
-> <入力中判定> --NO-> [終了]
↓ ↓
[入力文字列をTWELITEへ送信]
↓
[操作画面]へ戻る
[終了]
↓
[TWELITEのリセット]
↓
[画面離脱] インタラクティブモード画面を終了し前の画面へ戻る
1.2.1.2.2.2.4 - TWELITE STAGE の設定 TWELITE STAGE APP の設定
Windows
macOS
Linux
RasPi
概要 この画面から、TWELITE STAGE APP の各種設定を行います。
設定画面の例
この画面のメニューはマウス操作できません。
また、画面の色を変更した場合に見づらくなる場合があります。
以下の解説のメニュー中には、プラットフォームによっては存在しない項目がありますが、全てを列挙して解説します。
共通メニュー以外の色設定については、解説を省略します。
ルートメニュー
共通設定
ターミナル
標準アプリ ビューア
グラフ表示 (加速度リアルタイム/センサー)
簡易モニター (CUA/ARIA/Glancer)
グランサー(簡易モニタ)
コマンダー
アプリ書換
インタラクティブモード
セーブデータ ユーティリティ(ダンプ/消去)
情報
共通設定
a: ( 0x00) 起動アプリ指定
G: ( 0x00) 画面サイズ・描画方法
F: ( ) シリアルデバイスID
f: (0x00FFFFFF) 文字色
b: (0x005A0032) 背景色
B: ( 115200) ボーレート
設定 内容 起動アプリ指定 TWELITE STAGE始動時にビューアアプリに移動する設定です。設定値は1..{ビューアアプリメニューで列挙されている数}
です。注:シリアルデバイスIDを設定しておかないと、始動時に接続するシリアルデバイス選択画面で入力待ちになります。 画面サイズ・描画方法 (M5Stack版を除く)XY
の2桁の文字で指定します(X
:画面サイズ Y
:描画方法)。X
0
:640x480 1
:1280x720 2
:1280x960 3
:1920x1440 4
:2560x1440 5
:320x240Y
0
:LCD風 1
:CRT風 2
:ぼやけ 3
:ブロック シリアルデバイスID (M5Stack版を除く)設定はシリアルデバイス名または数値の1..9
を指定します。注:数値の場合はデバイス列挙順になります。 文字色・背景色 文字色、背景色を指定します。共通設定の色設定値は他の画面の設定にも継承されます。他の画面で未設定の場合は共通設定の色設定が採用されます。色はRGB 24bitを16進数で指定しますが、内部的には16bit 565形式に値が丸められます。 ボーレート TWELITE 側のボーレートが 115200
ではない場合に、ターミナルなどの表示が化けないように設定します。
アプリ書換
f: (0x00FFFFFF) 文字色
b: (0x005A0032) 背景色
j: ( 0) ビルド時のmakeジョブ数
v: ( 0) codeでフォルダを開く(VSCode)
l: ( 0) LTOを行わない
n: ( 0) 書換完了後の画面
設定 内容 ビルド時のmakeジョブ数 (M5Stack版を除く)ビルドを行う際の並列ジョブ数です。適切な数を設定することでビルド時間の短縮を期待できます。規定値0
は(物理プロセッサ数-1)でジョブ数を計算しています。目安としては論理プロセッサ数を上限とすると良いでしょう。 codeでフォルダを開く (VSCode) (VSCodeのインストールが必要)1
を設定することでOS標準のフォルダウインドウの代わりにcodeコマンド(VSCode)でフォルダを開きます。実行ファイルTWELITE_Stage_VSCode
ではデフォルトで1
に設定されています。 書換完了後の画面 (M5Stack版を除く)1
を設定することでインタラクティブモード画面の代わりにターミナルを開きます。2
を設定することで、書換メニューに戻ります。TWELITE_Stage_VSCode
では2
に設定されています。 LTOを行わない (Windowsのみ)1
を設定すると、WindowsのコンパイラでLTOを行いません。LTOは比較的小さなバイナリを生成できる一方でリンクに時間を要します。LTOを省略することでより高速なリンクが実現できます。
セーブデータユーティリティ
r: Read sector.
R: Read ALL sectors.
e: Erase sector.
E: Erase ALL sectors.
この画面は、データセーブ領域のメンテナンスを行うユーティリティです。EEPROM(64バイトを1セクタとして最大60セクタ、3840バイト)をエミュレートします。
設定 内容 r
セクタを読み出します。0..59
を入力すると、入力したセクタ番号のセクタの内容を表示します。 R
YES
を入力すると全セクタの読み出しを行いますが、末尾の部分のみを表示します。e
セクタを消去(0xFF
)します。0..59
を入力すると、入力したセクタ番号のセクタが消去されます。 E
YES
を入力すると全セクタを消去します。
Windows, macOS, Linux, Raspberry Pi では、 {実行形式名}.sav
(デフォルトでは TWELITE_Stage.sav
ファイル)に保存されます。
1.2.1.2.2.2.5 - シリアルポートの選択 シリアルポートの選択
Windows
macOS
Linux
RasPi
概要 この画面では、シリアルポートを再選択できます。
シリアルポート選択画面の例
この画面を使用せず、Alt(⌘)+0
, Alt(⌘)+1,2,..
でシリアルポートを切り替えることもできます。
1.2.1.2.3 - ログ機能 TWELITE と PC 間のログ機能
Windows
macOS
Linux
RasPi
TWELITE と PC 間のシリアル通信のログを記録できます。
操作 記録開始 Alt(⌘)+L
を押します。
ログの開始画面の例
記録終了 記録中に再度 Alt(⌘)+L
キーを押します。
ログの終了画面の例
ログの記録が終了し、その時点のログファイルをOS標準の方法(Windowsはメモ帳、macOSはコンソール.app)で開きます。
Raspberry Pi では、ログファイルの保存のみ行います。自動的にログファイルを開く機能はありません。
仕様 ログの記録 TWELITE から受信した文字列は、そのまま記録されます。
TWELITE に送信した文字列は、1文字ずつ記録されます。
Windowsの場合は 「 」
、 macOS / Linux / RaspBerryPi は « »
で囲われます。
例えば«t»
とある場合は、キーボードからt
を入力したことを意味します。
ログ記録のフォルダとファイル名 {TWELITE STAGE APP の実行形式のあるフォルダ}/log
にログ開始時の日時を元にしたファイル名で保存されます。
Alt(⌘)+Shift+L
を押すことで、そのフォルダを開きます。
ログ出力フォルダの例
1.2.1.3 - 詳細な仕様 TWELITE STAGE APP の詳細な仕様
1.2.1.3.1 - コマンドライン引数とiniファイルによる詳細設定 コマンドライン引数とiniファイルによる TWELITE STAGE APP の詳細設定
コマンドライン引数 コマンドライン引数は、TWELITE STAGE APPのいくつかの細かい設定を行います。
コマンドライン引数 内容 -E 0 フェードアウトのようなグラフィカルな効果を無効にする。 -R {type} {type} 値でレンダリングタイプを設定します。0: デフォルト1: OpenGL2: DirectX(Windows) Metal(macOS)3: ソフトウェア -J ゲームコントローラーを有効にします。 -x {x_pos},-y {y_pos} 起動時のTWELITE STAGE Appのグラフィカルウィンドウの位置を設定します。{x_pos}と{y_pos}はウィンドウの左上のスクリーン座標です。
iniファイル iniファイルはTWELITE STAGE APPの基本的な設定(MWSDKのフォルダを参照するなど)を行うために使用されます。
iniファイル名は{TWELITE STAGE APPの実行ファイルのベース名} + .ini
です。 通常は TWELITE_Stage.ini
となります。
;;; MWSDKの参照を変更します。
; MWSDK=MWSDK
mwsdk=mwsdk2020_10
;;; インターフェース言語
; LANG=en
;;; ウィンドウのジオメトリ
GEOM_X=200
GEOM_Y=100
シンタックス ini ファイルはプレーンテキストファイルとして記述される。 キーと値は =
で区切られた1行に格納される (例: KEY=value
)。 キーと値の文字列は行頭から始まる(キーの前に空白や他の文字は許されない)。 キーと値の間にスペースを入れてはならない。 コメント行は ;
または #
を行頭に追加する。 設定 キー 値 MWSDK MWSDKのフォルダを変更する。デフォルトのフォルダは、TWELITE STAGE APPの実行ファイルが置かれているのと同じフォルダにある MWSDK です。古いMWSDKやカスタムMWSDKを使用する必要がある場合は、そのフォルダの名前を指定することができます。 LANG LANG=en は、ユーザーインターフェースの言語をデフォルト(日本語)から英語に変更します。 GEOM_X, GEOM_Y TWELITE STAGEアプリのウィンドウが表示される場所を変更する。
異なる設定の TWELITE STAGE APP を実行する 異なる設定の TWELITE STAGE APP が必要な場合は、TWELITE STAGE APPと同じフォルダに実行ファイルをコピーして、同じ名前の .ini
ファイルを作成します。
例えば、英語のインターフェースを使用する場合、TWELITE_Stage.exe
(注: .exe はWindowsの実行ファイルの拡張子)を TWELITE_Stage_en.exe
にコピーして、 LANG=en
の設定を TWELITE_Stage_en.ini
に書き込むことで、英語のインターフェースを有効化した実行ファイルを作成できます。
TWELITE_Stage.exe
TWELITE_Stage.ini | 特別な設定なし
TWELITE_Stage_ja.exe | TWELITE_Stage.exe のコピー
TWELITE_Stage_en.ini | LANG=en が設定されている。
1.2.1.3.2 - 環境変数 TWELITE STAGE APP が使用する環境変数
TWELITE STAGE APP では、内部的に環境変数を設定して make などのビルドプログラムの動作を行います。事前に環境変数の設定は不要です。
内部的に設定される環境変数 環境変数 解説 MWSDK_ROOT
標準では TWELITE STAGE APP の実行形式が格納されるフォルダにある MWSDK
フォルダ(つまり../MWSTAGE/MWSDK
)が指定されます。 MWSDK.ini
が指定される場合は、指定されたフォルダ名を採用します。 MWSDK_TWENET_LIBSRC
サンプルコードやTWELITE APPSのソースコードフォルダには、Microsoft社の Visual Studio Code (VS Code) 用の定義ファイルを予め作成しています。この定義ファイル中にVS Codeエディタ中でコード解釈を行う目的でライブラリソースコードの参照先を指定しますが、この環境変数を用いています。MWSDK_TWENET_LIBSRC
環境変数が適切に指定されると、MWSDK
以下ではないプロジェクトフォルダでもコード解釈が行われ、ライブラリ関数名の補完などが機能します。(参考 ) LANG=C
ツールチェインのメッセージを規定の言語(英語)にするため、明示的に設定しています。 PATH
Windowsでは、SDK添付のmsysユーティリティへのPATHを追加します。 MWSDK_MAKE_JOBS
MWSDK_MAKE_DISABLE_LTO
VS Codeの設定定義で利用します。JOBS
: STAGE APPで設定された並列ビルド数を渡しますDISABLE_LTO
: LTOを無効化します(
Windows
)
参考 .vscode/settings.json
の設定例(抜粋)
"C_Cpp.default.includePath" : [
"${env:MWSDK_TWENET_LIBSRC}/include/**" ,
"${env:MWSDK_TWENET_LIBSRC}/src/**"
],
"C_Cpp.default.browse.path" : [
"${env:MWSDK_TWENET_LIBSRC}/include/**" ,
"${env:MWSDK_TWENET_LIBSRC}/src/**"
],
"../../"
で始まる定義は、TWELITE STAGEアプリからプロジェクトを開く場合は不要です。環境変数MWSDK_TWENET_LIBSRC
を設定しない場合に、既定のフォルダ構成の時にソース参照先を指定しています。
1.2.1.3.3 - 000desc.txt によるプロジェクト説明の追加 000desc.txt によるプロジェクト説明の追加方法について
プロジェクトフォルダに000desc.txt
を作成した場合には、TWELITE STAGE APP が、プロジェクトフォルダの一覧にその内容を表示します。
000desc.txtの表示例
ファイルは UTF-8 形式のプレーンテキストで記述します。書式は以下の2種類があります。
書式1
スイッチを押した時にLEDを点灯
act4はTWELITE DIPに接続されたスイッチを押した時にLEDを点灯させるactを動作させます。
https://mono-wireless.com/jp/products/act/index.html
1行目はタイトル行です。 2行目以降は詳細の記述です。 最終行が http で始まる場合は、ウェブサイトへのリンクになります。 書式2
[JAPANESE]
TITLE = actのテンプレート
DESC = 中身が何もない setup(), loop() のみのファイルです。
新しく act を記述するのに利用してください。
URL = jp/MWX/content/Act_samples/README.html
[ENGLISH]
TITLE = act empty template
DESC = This act file only contains empty setup() and loop(),
which is intended to write a new act.
URL = en/MWX/content/Act_samples/README.html
iniファイルのような書式です。行頭から始まる項目名と=
文字までを項目の定義として=
以降が項目の内容です。
項目定義 詳細 [JAPANESE]
, [ENGLISH]
ブロックの区切り TITLE=
タイトル行 DESC=
詳細の記述。改行を含めて複数行にすることもできます。 URL=
ウェブサイトまたはファイルへのリンク
URL 指定について URL= 詳細 https:
, http:
で始まるそのアドレスを開きます それ以外 {MWSDK_ROOT}/docs/
を起点とした相対フォルダを指定します。a/b/c.html
とした場合は {MWSDK_ROOT}/docs/a/b/c.html
に変換されます。
1.2.1.4 - ライセンス ライセンスについて
モノワイヤレス 株式会社が配布するTWELITE_Stageの実行形式は MW-SLA-1J,1E が適用されます。
ソースコードについてはMW-OSSLA-1J,1E が適用されます。概要はリンク先を参照ください。
お客様がソースコードからビルドした場合は、非商用目的でより制限の緩和されたMW-OSSLA-1J,1Eによる運用が可能です。
一部の配布パッケージ(2020/10/9現在では M5Stack用 0.8.9a パッケージのみ)ではMW-SLA-1J,1E と MW-OSSLA-1J,1E とのデュアルライセンスを適用しているものもあります。パッケージ内のライセンス記述を確認してください。
商用利用ではMW-SLA-1J,1Eを選択いただくことになりますのでご注意ください。
利用したオープンソース成果物 高品質なソースコードを提供いただいたオープンソースプロジェクトに感謝いたします。
名前 記述 SDL2 Simple DirectMedia Layer Copyright (C) 1997-2020 Sam Lantinga getopt Copyright (c) 1987, 1993, 1994The Regents of the University of California. All rights reserved. regex regex - Regular expression pattern matching and replacementBy: Ozan S. Yigit (oz) Dept. of Computer Science York University printf Copyright (c) 2014 Marco Paland 東雲フォント 2001 The Electronic Font Open Laboratory http://openlab.ring.gr.jp/efont/ M+ BITMAP FONTS Copyright 2002-2005 COZ coz@users.sourceforge.jp SQLiteC++ Copyright (c) 2012-2021 Sebastien Rombauts (sebastien.rombauts@gmail.com ) sqlite3 All of the code and documentation in SQLite has been dedicated to the public domain by the authors.
1.2.1.5 - 改訂履歴 TWELITE STAGE APPの改訂履歴
ソースコードの変更履歴は https://mwm5.twelite.info/changes および https://github.com/monowireless/mwm5 を参照してください。
プラットフォームによっては、配布中の最新バージョンと改訂履歴の最新バージョンが一致しない場合があります。
1.3.8 MWSTAGE2022_08収録版 メジャーバージョンアップ。
内部描画解像度を320x240から640x480ピクセルに変更 加速度センサーのリアルタイムグラフの追加 センサーデータの保存とグラフ表示を行うセンサーグラフを追加 英語表示に対応 主要マニュアルをローカルhtmlファイルに変更 1.0.8 MWSTAGE2021_09収録版 [ A ] [ B ] [ C ]ボタンで、ポインタから外れたボタンが残ってしまう場合があった STAGE APPでEnter入力の際にTWELITEに対してCRLFを送信するようにした MacのFTDIライブラリを更新しApple Silicon(M1)でもシリアル仲介プログラムを利用しなくても、動作できるようになった Windowsでmsysツール群のPATHを内部設定し、期待しないmakeが呼び出されないようにした TWELITE未接続でも書き込み画面に移動できるようにした(B,Rキーを入力し、対象のTWELITEモデルを指定する) VSCodeを利用する設定を行った場合は、actやTweAppsを選択したときに、ビルドを実行せず、build/以下の.binファイルを書き込む画面を開くようにした。(ビルドはVSCodeから実施します) いくつかの環境変数を内部的に設定し、TWELITE STAGEから起動したVSCodeにこれらを参照させることで、VSCodeから適切なビルドを実行、VSCodeのコード解釈に対して適切なライブラリソースを参照できるようにした MWSDKフォルダ以下にサンプルコードが格納されているが、ビルド対象のフォルダをドロップすることで、MWSDK以外のフォルダでもビルドや書き込み作業をできるようにした(フォルダ名に空白や日本語文字などが含まれてはいけません) 始動時のコンソール画面に、内部のフォルダ設定や環境変数の設定内容を表示するようにした 終了時は1秒待ってからSTAGE APPを終了するようにした 1.0.7pre2 Raspberry Pi の対応を強化 (1.0.7pre2)serial0 の対応(TWELITE STAGE HAT) Zero 向けビルドを追加(対応ライブラリでビルド&描画フェード機能を無効化) X11 デスクトップ向けビルドを追加 一般のFTDIデバイス(FT232,FT230)でも利用できるようにした。ファームウェア書き込みモードは手動で行う必要があります Windowsで、シリアルポート選択画面でcキーを押すことでWindowsで割り当てられているCOMポートを表示する機能を追加した ボーレートを115200bpsから変更できるようにした 描画フェード機能を無効にするコマンドラインオプション(-E 0)を追加。 1.0.3 MWSTAGE2020_12収録版 TWELITE CUE対応(パーサー・CUEビューア) 書換メニューで、書き込み時にベリファイ(比較)を行うようにした。 Apple Silicon暫定対応(TWELITE_Stage.command はユニバーサルアプリ、シリアル処理用の外部コマンドsersrv_ftdi.command、Toolsは Rosetta2 で動作可能な intel バイナリを再ビルド、シリアル通信は外部コマンド経由のため遅くなります) フォルダ構成で MWSTAGE/MWSDK/Tools を MWSTAGE/Toolsに移動した。(MWSDKをMWSDK_COMMONレポジトリをそのまま利用できるようにするため) TWELITE_Stage.ini (起動ファイル名から拡張子を取り除き .ini を付加) を、起動時に読み込みMWSDKフォルダを選択できるようにした。(古い版のライブラリ一式を簡単に切り替えられるようにした) 画面描画用のSDL2ライブラリを 2.0.12 に変更した (Windows, MacOS, RaspberryPi)。 Windows では static ビルドとして DLL ファイル不要とした。 make -j による並列ビルド数を(物理CPU数 - 1)とした。 書換メニューのいくつかの場所で、シリアルポートの再オープンを明示的に行うようにした。デバイスの抜き差しを行ったときなどにUSB接続が切断した場合などに、復帰しやすいようにした。 Alt(Cmd)+Shift+m, t で mwx, twesettings を開くとき TWENET/usever.mk 記載のフォルダを 開くようにした。 [Raspberry Pi] 初回起動時に /dev/serial0 での書込メニュー遷移が失敗する問題を修正。 既知の問題 起動時にAlt(Cmd)押し下げ時のヘルプメッセージが出現しない場合がある。Alt(Cmd)+0を入力することで表示されます。 書換メニューでファイル名が長すぎる場合に、行の行事が乱れる場合がある。 Apple Siliconでの動作については十分な検証を行っていません。 0.9.11 MWSTAGE2020_10, Raspberry Pi 版 (暫定版) (※包括的な検証を実施しないバージョンです)
Raspberry Pi での動作 その他、機能調整 0.9.9 - MWSTAGE2020_10収録版 最上位メニューにも [ウェブ] ボタンを追加し、関連リンクをブラウザで開けるようにした。 Linux版のフォルダ、ウェブ、VS Code で開く機能を実装した。 TWELITE が頻繁に UART 出力している場合に、書き込みメニューへ遷移しづらいことがあった 0.9.8a https://github.com/monowireless/TWELITE_STAGE_Bin_M5Stack/releases/tag/0.9.8a
M5Stack版で MW-SLA-1J,E / MW-OSSLA-1J,E のデュアルライセンスとし、readme-j.txt を更新した。
0.9.8 ビューア一覧表示に[ウェブ]ボタンを追加し、関連サイトを開く機能を追加など。
改定内容 ビューア>コマンダーの追加標準アプリ 0x80 コマンド NOTICE PALのLED制御 (App_Wingsにコマンドを送付) ビューア>PALビューアのNOTICE PAL対応。 Act_extrasのメニューを追加Act_samplesより高度なもの 外部のオープンソースライブラリ(センサー手続きなど)を利用したもの マウスによる操作を拡大 (リスト、ボタン、タブ)マウス移動でフォーカス、左クリックで確定、右クリックは[ESC]キー入力 画面表示負荷の低減アプリケーションがバックグラウンドの時はスクリーンセーバーを無効にした アプリケーションがバックグラウンドの時は、描画回数を減らして CPU 負荷を減らした ビルドプロジェクト(act, TWE_Apps, Act_extras)の一覧の機能強化項目選択時に下部に概要を表示 (000desc.txtを読み込む。TWE_Descクラスにより処理) プロジェクトフォルダを開く(またはVSCodeで開く)機能 関連ウェブサイトを開く機能 ALt+Shift+m mwxライブラリ、Alt+Shift+t twesettingsライブラリを開く機能 ビルドメニュー中で選択中のフォルダやビルドエラーファイルを開けるようにした。 ログ(シリアルポート入出力)機能の追加(Alt/Cmd+L)でログの開始・終了 ログファイルを {TWELITE_Stage 実行形式のあるフォルダ}/log に格納 ファイル名は twestage_{日付-時刻}.log Shift+Alt/Cmd+L でログファイルフォルダを開く その他、変更・修正などシリアル(FTDI)デバイス名、IDの表示方法を変更 App_UARTでインタラクティブモードに遷移しなかった問題を修正 フォルダドロップ時の挙動を変更した (これまではバイナリ書き込みになる場合があったが、メニュー遷移とした) ターミナル長押し時[C]でリセットに加え、画面クリアするようにした。 既知の問題 M5Stack で設定を保存するときにハングアップし、設定内容が初期化される場合があります。 0.8.9 2020_05 リリース版
ウインドウアイコンの追加 BINファイル一覧画面での最大リスト数の制約を緩和 (win/linux/mac) Glancerビューアの追加 解説文面等の調整 コンソール画面の描画の調整 ファーム書き込み後の移動先画面(インタラクティブモードかターミナルか)の設定が動作していなかった Alt(or Cmd)+W の割り当てを変更 その他不具合の修正 0.8.6 Linux 版リリース初版
0.8.5 リリース初版
1.3 - TWELITE APPS 信号伝達やシリアル通信など、すぐに使える専用ファームウェア
TWELITE APPS - トワイライトアプリはTWELITEのソフトウエア開発を行わずにそのまま使えるレディメイドソフトウエアです。
インタラクティブモードとは インタラクティブモードは、 TWELITE APPS の詳細設定を行うモードです。
複数のグループで通信したい場合や、通信エラーを減らしたい場合等に必要な設定を行うことができます。
PC との接続 TWELITE の場合 MONOSTICK の場合 親基板へ用意した7Pインターフェイスに TWELITE R シリーズを装着し、USBケーブルを使ってパソコンと接続してください。 MONOSTICK をパソコンの USB ポートに接続してください。 TWELITE R シリーズ は必要ありません。 TWELITE (SMD) と PC の接続
MONOSTICK と PC の接続
TWELITE DIP (BLUE/RED) の場合 その他の場合 TWELITE R シリーズ へ装着し、USBケーブルを使ってパソコンと接続してください。7Pインターフェイスを備える TWELITE シリーズには TWELITE R シリーズ を装着し、USBケーブルを使ってパソコンと接続してください。 TWELITE DIP (BLUE/RED) と PC の接続
その他の TWELITE シリーズ と PC の接続
インタラクティブモードの切り替え
TWELITE がスリープしている間はインタラクティブモードを使用できません。
TWELITE STAGE を使用する場合 TWELITE STAGE APP は TWELITE のファームウェアの書き込みと設定、および受信したデータの表示機能を統合した開発ツールです。
TWELITE STAGE APP を起動する TWELITE STAGE APP のメインメニュー
TWELITE STAGE APP のメニューから「インタラクティブモード」を選択 する ターミナルソフトを使用する場合 一般のターミナルソフトを使用することもできます。
パソコン側でターミナルソフトを起動する(通信条件:115200bps/8-N-1) TWELITEをリセットする。 パソコンのキーボードの+
をゆっくり(0.2~1秒間隔)で3回押下する。上手くいかない場合は、繰り返し + を入力する。 インタラクティブモードを終了するには、もう一度+
を3回押下してください。
テンキーから+
キーを入力すると失敗する場合があります。本体の+
を使用してください。
インタラクティブモードの操作 インタラクティブモードでは、以下のような画面を表示します。
--- CONFIG/TWELITE APP V1-00-2/SID=0x81000038/LID=0x78 ---
a: set Application ID (0x67720102)
i: set Device ID (--)
c: set Channels (18)
t: set mode4 sleep dur (1000ms)
y: set mode7 sleep dur (10s)
f: set mode3 fps (32)
---
S: save Configuration
R: reset to Defaults
表示内容は、ファームウェアの種類やバージョンによって異なります。
エスケープシーケンスに対応しないターミナルソフトウェアでは、表示が崩れる場合があります。
手順
値を選択:先頭のアルファベットを押下 値を指定:値を入力 値を確定:Enter
キーを押下 値を保存:S
(大文字)を押下 値を適用:TWELITE を再起動 ()
内の値は設定値です。
R
(大文字)を押下することで、初期値へリセットできます(S
で適用)。
操作例 アプリケーションIDを 0xBEEFCAFE
へ設定する場合の入力は次のようになります。
Input Application ID (HEX:32bit): BEEFCAFE
設定を適用するには、S
コマンドで内容を保存したのち、本体を再起動してください。
TWELITE APPS に共通する設定 周波数チャネル、アプリケーションID、デバイスID、再送回数と送信出力の設定は、TWELITE APPS に共通しています。
アプリケーションIDと周波数チャネル グループ化のイメージ
同一のアプリケーションIDと周波数チャネルをもつ端末でないと通信できません。
a
:アプリケーションID通信を行うすべての端末へ同一の値を設定すると、論理的にネットワークを分離 できます。
TWELITE は、自身と異なるアプリケーションIDをもつ端末から受信したパケットを破棄します。したがって、同一の周波数チャネル内へ複数のグループを設けることができます。
アプリケーションIDが同一であっても、周波数チャネルが同一であった場合はパケットの干渉を避けることはできません。可能な限り周波数チャネルを分けるようにしてください。
グループ数が16以下の場合は、周波数チャネルとアプリケーションIDの双方をグループごとに分けることを推奨いたします。
上位または下位の2バイトに0
またはF
が連続する値は設定できません(0xFFFF????
/0x0000????
/0x????FFFF
/0x????0000
)。
0x80000001
以上の値を設定する場合は、必ずお客さまのお手元にある TWELITE へ刻印されたシリアル番号を使用してください。
皆さんがこのルールを守る限り、誰もがユニークなアプリケーションIDを得ることができます。
c
:周波数チャネル通信を行うすべての端末へ同一の値を設定すると、物理的にネットワークを分離 できます。
TWELITE は IEEE802.15.4 規格へ準拠しており、2.4GHz帯を16チャネルに分割して使用します。
周波数チャネルの一覧
周波数チャネルを変更する場合は、c
(小文字)を押下してください。
チャネルアジリティーの使用(通常は非推奨) 動作イメージ
カンマ区切りで複数のチャネルを指定することで、チャネルアジリティを有効化できます。
チャネルアジリティは、複数の周波数チャネルを一定の間隔で切り替えながら通信することにより、劣悪な通信環境における通信の成功率を改善する仕組みです。
同時に3チャネルまで指定できます。指定されたチャネルを一定の間隔で順番に切り替えて送信します。受信側においても、チャネルを一定の間隔で順番に切り替えて受信します。
なお、チャネルの切り替え中は受信できません。通常の通信環境では、1チャネルを指定するよりも通信の信頼性は低下します 。
各 TWELITE APPS の初期値 TWELITE APPS アプリケーションID 周波数チャネル 超簡単!標準アプリ(App_Twelite) 0x67720102
18
リモコンアプリ(App_IO) 0x67720107
16
シリアル通信アプリ(App_Uart) 0x67720103
18
無線タグアプリ(App_Tag) 0x67726305
15
パルアプリ(App_PAL) 0x67726305
15
キューアプリ(App_CUE) 0x67720102
18
アリアアプリ(App_ARIA) 0x67720102
18
親機・中継機アプリ(App_Wings) 0x67720102
18
i
:論理デバイスID論理デバイス ID は各端末を識別するために使用します。各端末に論理的なIDを割り振ることができます。
論理デバイスIDを付与するイメージ
1つの親機に対して複数の子機を使用する場合は、各子機へ異なる ID(1
~100
)を付与してください。
x
:送信出力と再送回数送信出力を弱めることで電波の有効伝達範囲を狭くすることができます。ただし消費電力は変わりませんから、通常は最大出力でお使いください。
出力を弱めてしまうと、届いてほしいときに届かないことがあります。
出力を弱めることで到達範囲を狭くしなくてはならないとき、多くの場合はシステムの設計に問題があるといえます。周波数チャネルとアプリケーションIDにより、ネットワークを適切に分離してください。
再送回数は、1回の送信リクエストにつき追加で送信する回数 を指します。通信環境が悪い場合は、再送回数を設定するとデータの到達率が向上する場合があります。ただし、通信時間と消費電力は再送に応じて増加します。
インタラクティブモードでは2桁の数値を入力します。
十の位:再送回数 一の位:送信出力3
が最強2
/1
/0
と1段階小さくなるたびに -11.5dB
の出力低下 例
32
→ 再送3回、出力1段階弱める93
→ 再送9回、出力最大
理論上の伝達距離は6dB
です。設定値を小さくするたびに半分となりますから、1段階小さくした場合の伝達距離は約4分の1になるものと予想されます。ただし、実際の距離はノイズや遮蔽物の有無に依存します。
設定の初期化 設定内容によっては、操作へ支障をきたす場合があります(ボーレート変更など)。
次の手順で初期化できます。
他のアプリへ書き換え インタラクティブモードへ切り替え 元のアプリへ書き戻す 各 TWELITE APPS に固有の設定 各アプリによって異なる設定については、以下のページをご覧ください。
1.3.1 - 超簡単!標準アプリ マニュアル デジタル・アナログ信号伝送
親機と子機の入出力状態がシンクロ(同期)します。デジタル4ポート、アナログ4ポート、シリアル、I2Cを使用出来るオールインパッケージです。多彩な機能を単純化してわかりやすい反面、処理速度や応答性、省電力性は追求していません。
1.3.1.1 - 超簡単!標準アプリ マニュアル 最新版
工場出荷時の TWELITE や TWELITE DIP へインストールされています。
ダウンロード 超簡単!標準アプリ(App_Twelite
)を導入するには TWELITE STAGE SDK をインストールして、TWELITE STAGE アプリを使って書き換え てください。
1.3.1.1.1 - 超簡単!標準アプリのピン配置 超簡単!標準アプリが使用するピンの機能
超簡単!標準アプリ(App_Twelite)が使用するピンの機能とその配置
ピン配置 ピン配置表
x
は任意の数字を表します。例えば、M1
M2
M3
の総称を Mx
と表しています。
電源入力 VCC
/GND
には、3.3V(2.3-3.6V)の電源を接続します。
デジタル・アナログ入出力 DIx
/DOx
, AIx
/PWMx
ピンは、対応する番号のピンが同期して信号伝送を行います。
デジタル アナログ DIx
の入力→DOx
の出力AIx
の入力→PWMx
の出力
超簡単!標準アプリでは、アナログ入力の電圧範囲を 0-2V としています。
VCC
へ接続するなど、2V以上の電圧を入力した際は未使用扱いとなります。
シリアル通信 UART TX
/RX
は、UART 通信の送信と受信に使用します。具体的には、次のような場面で使用します。
無線による信号伝送 外部デバイスとの有線通信 ファームウェアの管理 I2C SCL
/SDA
ピンは、I2C のターゲットデバイスを接続する際に使用します。
設定入力 Mx
ピンを未接続またはGND
へ接続することで、親機、子機、中継機といった動作モードを切り替える ことができます。
BPS
ピンを未接続またはGND
へ接続することで、UART のボーレート(通信速度)を 115200bps 以外の値へ変更 できます。
リセット入力 リセット入力ピン RST
と GND
との間にプッシュボタンを接続することで、リセットボタンを実装できます。RST
は内部プルアップされています。
1.3.1.1.2 - 超簡単!標準アプリの動作モード 各動作モードの説明
超簡単!標準アプリ(App_Twelite)には、7つの動作モードがあります。
動作モードの一覧 各モードは、Mx
ピンを未接続または GND
へ接続することで設定します。
M3
M2
M1
モード 機能 省電力動作 LID初期値 O O O 子機:連続 入力状態を親機へ送信するほか、常に受信データを待機して出力へ反映します 120
O O G 親機:連続 入力状態を子機へ送信するほか、常に受信データを待機して出力へ反映します 0
O G O 中継機:連続 常に受信データを待機して中継します 122
O G G 子機:連続0.03秒 頻繁に入力状態を親機へ送信するほか、常に受信データを待機して出力へ反映します 123
G O O 子機:間欠1秒 1秒おきに入力状態を親機へ送信するほか、受信を無効化して常に節電モードへ入ります ✅ 124
G O G 子機:間欠受信1秒 1秒おきに入力状態を親機へ送信するほか、同時に受信を行い常に節電モードへ入ります ✅ 125
G G O - 未使用 - - G G G 子機:間欠10秒 10秒おきに入力状態を親機へ送信するほか、受信を無効化して常に節電モードへ入ります ✅ 127
O:未接続(OPEN)、G:GND
へ接続
初期状態は子機:連続モードです。
モードによって端末を識別するための論理デバイスID(LID)の初期値は異なります。
親機または中継機モードに限り、インタラクティブモード で切り替えできます。
親機は121
、中継機は122
としてください。
未使用のAIx
ポートの扱い 子機:連続/子機:連続0.03秒/親機:連続 モードでは、未使用の AIx
ポートを VCC
へ接続してください。
未使用の AIx
ポートは不定の値を報告します。これらのモードは入力信号に変化が生じた際にデータ送信を行いますから、不要なデータ送信を引き起こす場合があります。
親機 連続モード 親機:連続モード 信号入力の変化を検知したとき、また1秒おきに、すべての子機へデータを送信します。
また子機から送信されるデータを常時待機しており、反応がよいものの、常に電力を消費します。
定期送信の無効化 インタラクティブモードでオプションビット 0x00000002
を設定することで、1秒おきの定期送信を無効化できます。
子機 連続モード 子機:連続モード 信号入力の変化を検知したとき、また1秒おきに、すべての親機へデータを送信します。
また親機から送信されるデータを常時待機しており、反応がよいものの、常に電力を消費します。
親機との通信のイメージ
定期送信の無効化 インタラクティブモードでオプションビット 0x00000002
を設定することで、1秒おきの定期送信を無効化できます。
子機:連続0.03秒モード 子機:連続モードの定期送信の間隔は1秒ですが、これを0.03秒に短縮するモードです。
親機から送信されるデータを常時待機しているものの、子機から親機への通信で帯域を占有してしまうため、親機の入力に対する反応は鈍くなってしまいます。常に電力を消費します。
親機との通信のイメージ
1台の子機だけでほとんどの帯域を占有してしまうため、同時に複数の子機を使用することはなるべく避けてください。
間欠モード 子機:間欠1秒モード 信号入力の変化を検知したとき、また1秒おきに節電モードを解除し、すべての親機へデータを送信します。
受信機能を無効とするため、親機の制御を受けることはできません。省電力性能に優れたモードです。
親機との通信のイメージ
子機:間欠10秒モード 信号入力の変化を検知したとき、また10秒おきに節電モードを解除し、すべての親機へデータを送信します。
受信機能を無効とするため、親機の制御を受けることはできません。省電力性能に優れたモードです。
親機との通信のイメージ
子機:間欠受信1秒モード 信号入力の変化を検知したとき、また1秒おきに節電モードを解除し、すべての親機へデータを送信します。
1秒おきに受信処理も合わせて行います。省電力性能に優れていますが、子機:間欠1秒モードには劣ります。
親機との通信のイメージ
間欠して受信するため、親機側を連続して動作させる必要があります。
中継機 連続モード 中継機:連続モード 中継機は、受信したパケットを送信します。
親機と子機の間に3つまで設置できますが、中継機を増やすとパケットの数が増大するため、干渉しやすくなることに注意してください。
中継のイメージ
子機に中継機能を付与することもできます。インタラクティブモードのオプションビットに
0x00008000
を指定してください。
1.3.1.1.3 - 超簡単!標準アプリの代替ボーレート設定 UART 通信に使用するボーレート設定の変更
超簡単!標準アプリ(App_Twelite)はデフォルトで 115200 bps のボーレートを UART 通信に使用しますが、これを変更できます。
代替ボーレート設定の有効化 BPS
ピンを GND
へ接続することで、代替ボーレート設定を有効化できます。
BPS
内容 ボーレート 備考 O デフォルト 115200bps G 上書き設定 38400bps 変更 可
O:未接続(OPEN)、G:GND
へ接続
インタラクティブモードのボーレート設定は、代替ボーレートの値を示しています。BPS
ピンが GND
に接続されていないと、インタラクティブモードの設定値は適用されません。
インタラクティブモードは、UART 通信を利用します。TWELTIE のボーレートを切り替えた際は、インタラクティブモードを使用する前に PC 側のボーレートを合わせなくてはなりません(
TWELITE STAGE アプリの設定変更 )。
1.3.1.1.4 - 超簡単!標準アプリのUART機能 UART機能で利用するデータ形式
超簡単!標準アプリ(App_Twelite)の UART 機能で使用するデータ形式を解説します。
デジタル・アナログ入出力 0x81
:相手端末からの状態通知受信した入力信号の状態を出力します。
データ形式 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信元の論理デバイスID 1 uint8
コマンド番号 0x81
のみ2 uint8
パケット識別子 アプリケーションIDより生成 3 uint8
プロトコルバージョン 0x01
のみ4 uint8
LQI 0
-255
5 uint32
送信元のシリアルID 0x8???????
9 uint8
送信先の論理デバイスID 10 uint16
タイムスタンプ 1秒で64カウント 12 uint8
中継回数 13 uint16
電源電圧 単位はmV 15 int8
- (未使用) 16 uint8
デジタル信号 LSBから順にDIx
へ対応、0
がHigh MSBが1
なら定期送信 17 uint8
デジタル信号マスク LSBから順にDIx
へ対応、1
が有効 18 uint8
AI1
の変換値アナログ信号の計算 を参照、0xFF
で未使用19 uint8
AI2
の変換値アナログ信号の計算 を参照、0xFF
で未使用20 uint8
AI3
の変換値アナログ信号の計算 を参照、0xFF
で未使用21 uint8
AI4
の変換値アナログ信号の計算 を参照、0xFF
で未使用22 uint8
AIx
の補正値LSBから2ビットずつ順にAIx
へ対応 uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
アナログ信号の計算 AIx
の入力電圧 \(V\)は、受信した変換値\(e_{r}\)および補正値\(e_{fr}\)を使って次のように表すことができます。
$$\begin{align*}
V &= e+e_f \\
\text{where} \\
e &= 16e_r \\
e_f &= 4e_{fr} \\
\end{align*}$$
単位は mV
出力データの例
:78811501C98201015A000391000C2E00810301FFFFFFFFFB
上記データの解釈 # データ 内容 値 :
char
ヘッダ :
78
0 uint8
送信元の論理デバイスID 0x78
81
1 uint8
コマンド番号 0x81
15
2 uint8
パケット識別子 0x15
01
3 uint8
プロトコルバージョン 0x01
C9
4 uint8
LQI 201/255
8201015A
5 uint32
送信元のシリアルID 0x201015A
00
9 uint8
送信先の論理デバイスID 0x00
0391
10 uint16
タイムスタンプ 約14.27
秒 00
12 uint8
中継回数 0
0C2E
13 uint16
電源電圧 3118
mV00
15 int8
- 81
16 uint8
デジタル信号 DI1
L
DI2
H
DI3
H
DI4
H
(定期送信)03
17 uint8
デジタル信号マスク DI1
DI2
01
18 uint8
AI1
の変換値16
mVFF
19 uint8
AI2
の変換値未使用 FF
20 uint8
AI3
の変換値未使用 FF
21 uint8
AI4
の変換値未使用 FF
22 uint8
AIx
の補正値AI1
0x03
FB
uint8
チェックサム 0xFB
char
フッタ \r
char
フッタ \n
0x80
:相手端末の出力変更相手端末の出力信号を制御します。
データ形式 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信先の論理デバイスID 親機0x00
,子機0x01
-0x64
,全子機0x78
1 uint8
コマンド番号 0x80
のみ2 uint8
書式バージョン 0x01
のみ3 uint8
デジタル信号 LSBからDOx
に対応、0
でHigh 4 uint8
デジタル信号マスク LSBからDOx
に対応、1
で有効 5 uint16
PWM1
信号0
-1024
,0xFFFF
で無効7 uint16
PWM2
信号0
-1024
,0xFFFF
で無効9 uint16
PWM3
信号0
-1024
,0xFFFF
で無効11 uint16
PWM4
信号0
-1024
,0xFFFF
で無効uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
UART 入出力 0x01
:任意のデータの送信データ形式 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信先の論理デバイスID 親機0x00
,子機0x01
-0x64
,全子機0x78
1 uint8
コマンド番号 0x01
のみ2 [uint8]
任意のデータ 長さ\(N\)のバイト列(\(N\leqq80\)を推奨) uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
0x01
:任意のデータの受信データ形式 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信元の論理デバイスID 親機0x00
,子機0x01
-0x64
,未設定子機0x78
1 uint8
コマンド番号 0x01
のみ2 [uint8]
任意のデータ 長さ\(N\)のバイト列 uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
I2C 入出力 0x88
:I2C 入力データ形式 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信先の論理デバイスID 親機0x00
,子機0
-0x7F
,全子機0x78
,自身0xDB
1 uint8
パケット識別子 0x88
のみ2 uint8
応答番号 応答メッセージへ出力する番号 3 uint8
コマンド番号 書き込み0x1
,読み出し0x2
,読み書き0x4
4 uint8
I2Cアドレス 7ビット 5 uint8
I2Cコマンド 最初のコマンドバイト 6 uint8
データサイズ 0
はなし7 [uint8]
データ 長さ\(N\)のバイト列 uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
コマンド番号0x4
では、データサイズに読み出すデータのサイズを指定したうえで、データを省略してください。指定されたI2Cコマンドを書き込み、データサイズの分だけ読み出しを行います。
0x89
:I2C 出力データ形式 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信元の論理デバイスID 親機0x00
,子機0
-0x7F
,全子機0x78
,自身0xDB
1 uint8
パケット識別子 0x89
のみ2 uint8
応答番号 応答メッセージへ出力する番号 3 uint8
コマンド番号 書き込み0x1
,読み出し0x2
,読み書き0x4
4 uint8
結果 失敗0
、成功1
5 uint8
データサイズ 0
はなし6 [uint8]
データ 長さ\(N\)のバイト列 uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
1.3.1.1.5 - インタラクティブモード(超簡単!標準アプリ) インタラクティブモードによる詳細な設定変更
インタラクティブモードでアプリの詳細設定を行うことができます。
ここでは超簡単!標準アプリ(App_Twelite)に固有の機能を説明します。共通機能については、TWELITE APPS マニュアル のトップページ を参照してください。
TWELITE がスリープしている間はインタラクティブモードを使用できません。
Mx
ピンの設定 を子機連続モードあるいは親機・中継機モードとしてください。
表示例 次のような画面を表示します。
--- CONFIG/TWELITE APP V1-01-1/SID=0x8201001f/LID=0x78 ---
a: set Application ID (0x67720102)
i: set Device ID (--)
c: set Channels (18)
x: set Tx Power (03)
t: set mode4 sleep dur (1000ms)
y: set mode7 sleep dur (10s)
f: set mode3 fps (32)
z: set PWM HZ (1000,1000,1000,1000)
o: set Option Bits (0x00000000)
b: set UART baud (38400)
p: set UART parity (N)
---
S: save Configuration
R: reset to Defaults
コマンド 各コマンドの詳細を次に示します。
a
:アプリケーションID通信を行う端末はすべて同一の値とします。論理的にネットワークを分離します。
i
:論理デバイスID複数の子機を識別する必要がある場合に設定します。
子機の場合は1
-100
の任意の値へ、親機の場合は121
へ、中継機の場合は122
へ設定してください。
121
または122
へ設定すると、親機または中継機モードへ切り替えできます。このときMx
ピンの設定は必要ありません。
超簡単!標準アプリでは、動作モードによって論理デバイスIDの初期値が異なります。
動作モードの一覧
c
:周波数チャネル通信を行う端末はすべて同一の値とします。物理的にネットワークを分離します。
x
:送信出力と再送回数電波の送信出力と、パケットを追加で送信する回数を指定します。
t
:子機間欠1秒モードの間隔子機間欠1秒モードの間欠時間を1秒から他の値へ上書きします。単位はミリ秒です。
0
を設定した場合は、タイマによる定期的な起床を無効化します。このときDIx
の立ち下がりエッジにより起床しますが、立ち上がりエッジでは起床しません。
y
:子機間欠10秒モードの間隔子機間欠10秒モードの間欠時間を10秒から他の値へ上書きします。単位は秒です。
0
を設定した場合は、タイマによる定期的な起床を無効化します。このときDIx
の立ち下がりエッジにより起床しますが、立ち上がりエッジでは起床しません。
f
:子機連続0.03秒モードのサイクル毎秒の送信リクエストの数を32回から4
/8
/16
回へ上書きします。再送回数は含みません。
z
:PWMx
の周波数値を一つ指定した場合は、すべてのPWMポートの周波数を上書きします。カンマ区切りで指定した場合は、PWM1
-PWM4
に個別の値を上書きできます。
o
:オプションビット32bit の数値を指定します。各ビットに紐付いた設定を有効化できます。
b
:UART代替ボーレートBPS
ピンをGND
へ接続して起動した場合に選択される代替ボーレートを38400
bpsから上書きします。
値は9600
/19200
/38400
/57600
/115200
/230400
から選択できます。他の値を指定すると、誤差が生じる可能性があります。
BPS
ピンを開放して起動した場合、この設定は適用されません。115200
bpsに固定されます。
ボーレート変更によってインタラクティブモードが使用できない事態を防ぐための仕様です。
p
:UARTパリティN
はパリティ無し、O
は奇数、E
:は偶数を示します。
データビットは8、ストップビットは1で固定されます。ハードウェアフローは設定できません。
オプションビットの詳細 オプションビットの値の各ビットに紐付いた設定を解説します。
00000001
:低レイテンシモード低レイテンシモードは、DIx
の変化を検知してから速やかに送信を行うことで、受信側の遅延を短縮します。
低レイテンシモードの動作 初期状態ではDIx
がDOx
へ反映されるまでに30-70ms程度の遅延が生じます。低レイテンシモードでは、チャタリングや無線パケットの干渉を避けるための処理を簡略化することで、遅延を3-10ms程度に短縮します。
立ち下がりエッジの検出には割り込みを利用します 立ち上がりエッジの検出には定期的な判定を利用します1msおきに5回連続でHighである場合に送信します (初期状態では4msおきに5回連続でHighである場合に送信します) 検出時は送信および再送の遅延を設定しません。直ちに無線パケットを送信します 代表的な遅延は、DIx
の立ち下がりの場合に約3-5ms、立ち上がりの場合に約10msです 実際の遅延は送受信の失敗などを理由に変化します 間欠モードにおいても、本体の起床から送信までの時間を短縮します 00000002
:定期送信の無効化連続モードにおける1秒おきの定期送信を無効化します。
00000004
:定期送信とUART出力の無効化子機:連続モードにおける1秒おきの定期送信を無効化するほか、受信データのUART出力を停止します。
00000010
:AIx
の変化による送信の無効化子機:連続モードにおいて、AIx
の入力が変化した際の送信を無効化します。
開放されたAIx
ポートは不定の値を報告するため、正気状態でアナログ入力を利用しない場合はVCC
へ接続する必要があります。このオプションを設定すると、VCC
への接続を省略できます。
00000020
:AIx
の値の無効化ADCの計測値を使用せず、未使用ポート(0xFFFF
)扱いとしてパケットを送信します
00000040
:PWMx
の計算式を変更初期状態ではボリューム用に調節した出力を PWMx
へ適用します。
このオプションはこれを無効化し、1.8V 以下の入力に対してフルスケールの出力を行います。
デューティ比の計算式 デューティ比 \(duty\)は、入力電圧\(V_{input}\)と電源電圧\(V_{cc}\)を使って、(1) のように表すことができます。
$$\begin{align}
duty &= min(230\frac{V_{input}}{V_{cc}}-5, 100) \\
duty &= 100\frac{min(V_{input}, 1.8)}{1.8}
\end{align}$$
このオプションを有効化すると、代わりに (2) を適用します。
なお、2.0V 以上の入力は未使用扱いとなります。
00000100
:ボタン押下時のみ送信DIx
の入力が Low であるときにパケットを連続送信します。
例えば、モータを遠隔制御する際に利用します。リモコンのボタンを押している間にモータを回転させ、電波が途切れた場合に停止させることができます。
連続送信の動作 DIx
のいずれかが Low のときは、1秒につき32回送信しますDIx
のすべてが High へ遷移してから1秒間は引き続き32回送信しますDOx
のいずれかが Low へ遷移してから0.5秒間パケットを受信しなかった場合は、DOx
をすべて High へ戻します。PWMx
は保持します00000800
:DIx
の内部プルアップを停止DIx
の内部プルアップ(約50kΩ)をすべて停止します。
起動してからハードウェアの初期化を完了するまでの約1msの期間はプルアップされます。
00008000
:子機へ中継機能を付与子機:連続モードにおいて中継機能を付与します。最大中継段数は1です。
00001000
:子機中継時の最大中継段数を2とする00008000
:子機へ中継機能を付与 の設定時に、最大中継段数を2へ変更します。
00002000
:子機中継時の最大中継段数を3とする00008000
:子機へ中継機能を付与 の設定時に、最大中継段数を3へ変更します。
00010000
:PWMx
の波形を反転PWMx
の出力波形を反転します。
AIx
へ最大値を入力すると PWMx
は Low となります。
00020000
:起動後PWMx
を落とす起動後またはリセット後にPWMx
の出力を Low 状態とします。
起動してからハードウェアの初期化を完了するまでの約1msの期間は High 状態となります。
00080000
:代替ポート割り当て代替ポート割り当てを有効化します。
PWM2
/PWM3
へトランジスタ等を接続すると、動作が不安定となる場合があります(詳細 )そうした場合に利用してください。
代替ポート割り当ての内容 PWMx
の割り当て変更DI3
→PWM1
DI1
→PWM2
DI2
→PWM3
BPS
→PWM4
DIx
の割り当て変更PWM1
→DI1
PWM4
→DI2
SDA
→DI3
DI4
→DI4
(変更なし)BPS
の割り当て変更SCL
/SDA
を無効化00100000
:起動後2秒間DOx
を落とす起動後またはリセット後にDOx
を2秒間 Low 状態とします。
DOx
へ接続した LED を起動時に点灯させることができます。
起動してからハードウェアの初期化を完了するまでの約1msの期間は High 状態となります。
00400000
:DOx
の出力を反転DOx
の出力を反転します。
初期状態とは異なり、片方の DI が Low レベルになると、もう片方の DO も Low レベルとなります。
起動してからハードウェアの初期化を完了するまでの約1msの期間は High 状態となります。
00800000
:DOx
の内部プルアップを停止DOx
の内部プルアップ(約50kΩ)をすべて停止します。
1.3.2 - 親機・中継機アプリ マニュアル データ集約と通信範囲拡張に。
超簡単!標準アプリやパルアプリなどの TWELITE APPS やact のパケットを受信と中継をするアプリです。
1.3.2.1 - 親機・中継機アプリ マニュアル 最新版
TWELITE APPS や act の子機に対する親機や中継機として働きます。
機能 TWELITE APPSとactの全てのデータパケットを処理することができ、共通の親機または中継機として使用できます。
超簡単!標準アプリやパル専用アプリなどの TWELITE APPS や act のデータを1つの MONOSTICK で収集可能 16チャンネルで複数システムを個別に運用可能 アプリケーションIDの設定することで、同一チャネルに複数システムを混在可能 中継機能で通信範囲拡大 1.3.2.1.1 - 親機・中継機アプリの動作モード 親機・中継機アプリの動作モード
親機モードと中継機モードの2つのモードがあります。
1.3.2.1.1.1 - 親機・中継機アプリの親機モード 子機からデータを受信、子機へデータを送信する
子機から送信されたデータを受信し、シリアルポートから出力します。また、シリアルポートへ入力されたコマンドを子機へ送信します。
1.3.2.1.1.1.1 - 親機・中継機アプリの受信メッセージ 子機からデータを受信した際の出力
子機から送信されたデータを受信し、既定の書式でシリアルポートから出力します。
1.3.2.1.1.1.1.1 - 超簡単!標準アプリからの出力(親機・中継機アプリ) 超簡単!標準アプリからデータを受信した際の出力書式
0x81
:相手端末からの状態通知受信した入力信号の状態を出力します。
データ形式 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信元の論理デバイスID 1 uint8
コマンド番号 0x81
のみ2 uint8
パケット識別子 アプリケーションIDより生成 3 uint8
プロトコルバージョン 0x01
のみ4 uint8
LQI 0
-255
5 uint32
送信元のシリアルID 0x8???????
9 uint8
送信先の論理デバイスID 10 uint16
タイムスタンプ 1秒で64カウント 12 uint8
中継回数 13 uint16
電源電圧 単位はmV 15 int8
- (未使用) 16 uint8
デジタル信号 LSBから順にDIx
へ対応、0
がHigh MSBが1
なら定期送信 17 uint8
デジタル信号マスク LSBから順にDIx
へ対応、1
が有効 18 uint8
AI1
の変換値アナログ信号の計算 を参照、0xFF
で未使用19 uint8
AI2
の変換値アナログ信号の計算 を参照、0xFF
で未使用20 uint8
AI3
の変換値アナログ信号の計算 を参照、0xFF
で未使用21 uint8
AI4
の変換値アナログ信号の計算 を参照、0xFF
で未使用22 uint8
AIx
の補正値LSBから2ビットずつ順にAIx
へ対応 uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
アナログ信号の計算 AIx
の入力電圧 \(V\)は、受信した変換値\(e_{r}\)および補正値\(e_{fr}\)を使って次のように表すことができます。
$$\begin{align*}
V &= e+e_f \\
\text{where} \\
e &= 16e_r \\
e_f &= 4e_{fr} \\
\end{align*}$$
単位は mV
出力データの例
:78811501C98201015A000391000C2E00810301FFFFFFFFFB
# データ 内容 値 :
char
ヘッダ :
78
0 uint8
送信元の論理デバイスID 0x78
81
1 uint8
コマンド番号 0x81
15
2 uint8
パケット識別子 0x15
01
3 uint8
プロトコルバージョン 0x01
C9
4 uint8
LQI 201/255
8201015A
5 uint32
送信元のシリアルID 0x201015A
00
9 uint8
送信先の論理デバイスID 0x00
0391
10 uint16
タイムスタンプ 約14.27
秒 00
12 uint8
中継回数 0
0C2E
13 uint16
電源電圧 3118
mV00
15 int8
- 81
16 uint8
デジタル信号 DI1
L
DI2
H
DI3
H
DI4
H
(定期送信)03
17 uint8
デジタル信号マスク DI1
DI2
01
18 uint8
AI1
の変換値16
mVFF
19 uint8
AI2
の変換値未使用 FF
20 uint8
AI3
の変換値未使用 FF
21 uint8
AI4
の変換値未使用 FF
22 uint8
AIx
の補正値AI1
0x03
FB
uint8
チェックサム 0xFB
char
フッタ \r
char
フッタ \n
データの判別条件 親機・中継機アプリは、さまざまな種類の子機からデータを受信することができます。
出力されたデータが超簡単!標準アプリのものであるかを確認するには、次の箇所を参照してください。
# データ 項目 条件 1 uint8
コマンド番号 0x81
であること3 uint8
プロトコルバージョン 0x01
であること5 uint32
送信元のシリアルID MSBが1であること(0x8???????
) - - ペイロードのサイズ 23バイトであること(:
とチェックサムの間)
パーサの実装例 0x01
:任意のデータの受信データ形式 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信元の論理デバイスID 親機0x00
,子機0x01
-0x64
,未設定子機0x78
1 uint8
コマンド番号 0x01
のみ2 [uint8]
任意のデータ 長さ\(N\)のバイト列 uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
1.3.2.1.1.1.1.2 - リモコンアプリからの出力(親機・中継機アプリ) リモコンアプリからデータを受信した際の出力書式
0x81
:相手端末からの状態通知受信した入力信号の状態を出力します。
データ形式 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信元の論理デバイスID 1 uint8
コマンド番号 0x81
のみ2 uint8
パケット識別子 0x0F
のみ3 uint8
プロトコルバージョン 0x01
のみ4 uint8
LQI 0
-255
5 uint32
送信元のシリアルID 0x8???????
9 uint8
送信先の論理デバイスID 10 uint16
タイムスタンプ 1秒で64カウント、MSBは内部フラグ 12 uint8
中継回数 13 uint16
デジタル信号 LSBから順にIx
へ対応、0
がHigh 15 uint16
デジタル信号マスク LSBから順にIx
へ対応、1
なら有効 17 uint16
デジタル信号フラグ LSBから順にIx
へ対応、1
なら割り込み 19 uint8
未使用 内部管理用 uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
出力データの例
:01810F01DB8630000200645F000040004F00400049
# データ 内容 値 :
char
ヘッダ :
01
0 uint8
送信元の論理デバイスID 0x78
81
1 uint8
コマンド番号 0x81
0F
2 uint8
パケット識別子 0x15
01
3 uint8
プロトコルバージョン 0x01
DB
4 uint8
LQI 219/255
86300002
5 uint32
送信元のシリアルID 0x6300002
00
9 uint8
送信先の論理デバイスID 0x00
645F
10 uint16
タイムスタンプ 約401
秒 00
12 uint8
中継回数 0
0040
13 uint16
デジタル信号 I7
がLo004F
15 uint16
デジタル信号マスク I7
,I1
-I4
が有効0040
17 uint16
デジタル信号フラグ I7
は割り込みにより変化00
19 uint8
未使用 49
uint8
チェックサム 0x49
char
フッタ \r
char
フッタ \n
データの判別条件 親機・中継機アプリは、さまざまな種類の子機からデータを受信することができます。
出力されたデータがリモコンアプリのものであるかを確認するには、次の箇所を参照してください。
# データ 項目 条件 1 uint8
コマンド番号 0x81
であること3 uint8
プロトコルバージョン 0x02
であること5 uint32
送信元のシリアルID MSBが1であること(0x8???????
) - - ペイロードのサイズ 20バイトであること(:
とチェックサムの間)
パーサの実装例 1.3.2.1.1.1.1.3 - シリアル通信アプリからの出力(親機・中継機アプリ) シリアル通信アプリからデータを受信した際の出力書式
本アプリでは、書式モードの電文のみ受信できます。
透過モードやチャットモードのパケットを受信した場合の出力は未定義ですから、ご注意ください。
書式モード:簡易形式 データ形式 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信元の論理デバイスID 親機0x00
,子機0x01
-0x64
,未設定子機0x78
1 uint8
コマンド番号 送信側で指定した0x80
未満の値 2 [uint8]
任意のデータ 長さ\(N\)のバイト列 uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
出力データの例
# データ 内容 値 :
char
ヘッダ :
78
0 uint8
送信元の論理デバイスID ID未設定子機 01
1 uint8
コマンド番号 0x01
00112233AABBCCDD
2 [uint8]
任意のデータ そのまま 13
uint8
チェックサム 0x13
char
フッタ \r
char
フッタ \n
データの判別条件 親機・中継機アプリは、さまざまな種類の子機からデータを受信することができます。
出力されたデータがシリアル通信アプリ(書式モード:簡易形式)のものであるかを確認するには、次の箇所を参照してください。
# データ 項目 条件 0 uint8
送信元の論理デバイスID 0x64
以下もしくは0x78
であること1 uint8
コマンド番号 0x80
未満であること- - ペイロードのサイズ 3バイト以上82バイト以下であること
緩い条件のため、超簡単!標準アプリなど他のパケットの条件に続けて確認してください。
パーサの実装例 書式モード:拡張書式 データ形式 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信元の論理デバイスID 親機0x00
,子機0x01
-0x64
,未設定子機0x78
1 uint8
コマンド番号 0xA0
のみ2 uint8
応答ID 送信側で指定した値 3 uint32
送信元の拡張アドレス シリアルIDの先頭へ0x8
を加えた値 7 uint32
送信先の拡張アドレス 論理デバイスID使用時は0xFFFFFFFF
11 uint8
LQI 受信時の電波通信品質 12 uint16
続くバイト列の長さ バイト数\(M\)を表す 14 [uint8]
任意のデータ 長さ\(M\)のバイト列 uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
出力データの例
:78A0028201015AFFFFFFFFA8000700112233AABBCCC6
# データ 内容 備考 :
char
ヘッダ :
78
0 uint8
送信元の論理デバイスID ID未設定子機 A0
1 uint8
コマンド番号 0xA0
02
2 uint8
応答ID 0x02
8201015A
3 uint32
送信元の拡張アドレス 0x201015A
FFFFFFFF
7 uint32
送信先の拡張アドレス 論理デバイスID指定 A8
11 uint8
LQI 168/255
0007
12 uint16
続くバイト列の長さ 7
バイト00112233AABBCC
14 [uint8]
任意のデータ そのまま C6
uint8
チェックサム 0xC6
char
フッタ char
フッタ
データの判別条件 親機・中継機アプリは、さまざまな種類の子機からデータを受信することができます。
出力されたデータがシリアル通信アプリ(書式モード:拡張形式)のものであるかを確認するには、次の箇所を参照してください。
# データ 項目 条件 0 uint8
送信元の論理デバイスID 0x64
以下もしくは0x78
であること1 uint8
コマンド番号 0xA0
であること2 uint8
応答ID 0x80
未満であること3 uint32
送信元の拡張アドレス MSBが1であること(0x8???????
) 12 uint16
続くバイト列の長さ ペイロードのサイズ - 14
バイトであること
パーサの実装例 1.3.2.1.1.1.1.4 - パル/キュー/アリアアプリからの出力(親機・中継機アプリ) パル/キュー/アリアアプリからデータを受信した際の出力書式
1.3.2.1.1.1.1.4.1 - パルアプリからの出力(親機・中継機アプリ) パルアプリからデータを受信した際の出力書式
全般 パルアプリから受信したデータは、センサ種別とその値からなるセンサーデータの羅列によって表現します。
パルアプリに共通する書式の詳細については、
共通書式の詳細 をご覧ください。
以降では、製品の種別に応じた具体的な例を取り上げます。
開閉センサーパル データ形式 # データ 内容 備考 char
ヘッダ :
のみ0 uint32
中継機のシリアルID 中継なしの場合80000000
4 uint8
LQI 0
-255
5 uint16
続き番号 7 uint32
送信元のシリアルID 0x8???????
11 uint8
送信元の論理デバイスID 12 uint8
センサー種別 0x80
のみ13 uint8
PAL基板バージョンとPAL基板ID 0x81
のみ14 uint8
センサーデータ の数3
のみセンサーデータ1 15 uint8
情報ビット 0x11
のみ16 uint8
データソース 0x30
のみ17 uint8
拡張バイト 0x08
のみ18 uint8
データ長 2
のみ19 uint16
データ 電源電圧(mV) センサーデータ2 21 uint8
情報ビット 0x11
のみ22 uint8
データソース 0x30
のみ23 uint8
拡張バイト 0x01
のみ24 uint8
データ長 2
のみ25 uint16
データ ADC1の電圧(mV) センサーデータ3 27 uint8
情報ビット 0x00
のみ28 uint8
データソース 0x00
のみ29 uint8
拡張バイト 0x00
のみ30 uint8
データ長 1
のみ31 uint8
データ 磁気データ センサーデータの末端 32 uint8
チェックサム1 直前までのCRC8 uint8
チェックサム2 チェックサム1までのLRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
出力データの例
:80000000A8001C82012B1E01808103113008020D0C1130010203E40000000101EC6E
# データ 内容 値 :
char
ヘッダ :
80000000
0 uint32
中継機のシリアルID 中継なし A8
4 uint8
LQI 168
/255
001C
5 uint16
続き番号 28
82012B1E
7 uint32
送信元のシリアルID 0x2012B1E
01
11 uint8
送信元の論理デバイスID 0x01
80
12 uint8
センサー種別 81
13 uint8
PAL基板バージョンとPAL基板ID 開閉パルV1 03
14 uint8
センサーデータ の数3
つセンサーデータ1 11
15 uint8
情報ビット 拡張バイトありuint16
30
16 uint8
データソース 電圧 08
17 uint8
拡張バイト 電源 02
18 uint8
データ長 2
バイト0D0C
19 uint16
データ 3340
mVセンサーデータ2 11
21 uint8
情報ビット 拡張バイトありuint16
30
22 uint8
データソース 電圧 01
23 uint8
拡張バイト ADC1 02
24 uint8
データ長 2
バイト03E4
25 uint16
データ 996
mVセンサーデータ3 00
27 uint8
情報ビット 拡張バイトなしuint8
00
28 uint8
データソース 磁気 00
29 uint8
拡張バイト なし 01
30 uint8
データ長 1
バイト01
31 uint8
データ N極が近づいた センサーデータの末端 EC
32 uint8
チェックサム1 0xEC
6E
uint8
チェックサム2 0x6E
char
フッタ '\r'
char
フッタ '\n'
データの判別条件 親機・中継機アプリは、さまざまな種類の子機からデータを受信することができます。
出力されたデータがパルアプリ(開閉センサーパル)のものであるかを確認するには、次の箇所を参照してください。
# データ 項目 条件 0 uint32
中継機のシリアルID MSBが1であること 7 uint32
送信元のシリアルID MSBが1であること 12 uint8
センサー種別 0x80
であること13 uint8
PAL基板バージョンとPAL基板ID 0x81
であること- - ペイロードのサイズ 33バイトであること
パーサの実装例 環境センサーパル データ形式 # データ 内容 備考 char
ヘッダ :
のみ0 uint32
中継機のシリアルID 中継なしの場合80000000
4 uint8
LQI 0
-255
5 uint16
続き番号 7 uint32
送信元のシリアルID 0x8???????
11 uint8
送信元の論理デバイスID 12 uint8
センサー種別 0x80
のみ13 uint8
PAL基板バージョンとPAL基板ID 0x82
のみ14 uint8
センサーデータ の数5
のみセンサーデータ1 15 uint8
情報ビット 0x11
のみ16 uint8
データソース 0x30
のみ17 uint8
拡張バイト 0x08
のみ18 uint8
データ長 2
のみ19 uint16
データ 電源電圧(mV) センサーデータ2 21 uint8
情報ビット 0x11
のみ22 uint8
データソース 0x30
のみ23 uint8
拡張バイト 0x01
のみ24 uint8
データ長 2
のみ25 uint16
データ ADC1の電圧(mV) センサーデータ3 27 uint8
情報ビット 0x05
のみ28 uint8
データソース 0x01
のみ29 uint8
拡張バイト 0x00
のみ30 uint8
データ長 2
のみ31 int16
データ 温度データ センサーデータ4 33 uint8
情報ビット 0x01
のみ34 uint8
データソース 0x02
のみ35 uint8
拡張バイト 0x00
のみ36 uint8
データ長 2
のみ37 uint16
データ 湿度データ センサーデータ5 39 uint8
情報ビット 0x02
のみ40 uint8
データソース 0x03
のみ41 uint8
拡張バイト 0x00
のみ42 uint8
データ長 4
のみ43 uint32
データ 照度データ センサーデータの末端 47 uint8
チェックサム1 直前までのCRC8 uint8
チェックサム2 チェックサム1までのLRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
出力データの例
:8000000084811F810EFF6D04808205113008020AEB11300102035A0501000209E3010200020E3A02030004000001BE6C00
# データ 内容 値 :
char
ヘッダ :
80000000
0 uint32
中継機のシリアルID 中継なし 84
4 uint8
LQI 132
/255
811F
5 uint16
続き番号 33055
810EFF6D
7 uint32
送信元のシリアルID 0x10EFF6D
04
11 uint8
送信元の論理デバイスID 0x04
80
12 uint8
センサー種別 82
13 uint8
PAL基板バージョンとPAL基板ID 環境パルV1 05
14 uint8
センサーデータ の数5
つセンサーデータ1 11
15 uint8
情報ビット 拡張バイトありuint16
30
16 uint8
データソース 電圧 08
17 uint8
拡張バイト 電源 02
18 uint8
データ長 2
バイト0AEB
19 uint16
データ 2795
mVセンサーデータ2 11
21 uint8
情報ビット 拡張バイトありuint16
30
22 uint8
データソース 電圧 01
23 uint8
拡張バイト ADC1 02
24 uint8
データ長 2
バイト035A
25 uint16
データ 858
mVセンサーデータ3 05
27 uint8
情報ビット 拡張バイトなしint16
01
28 uint8
データソース 温度 00
29 uint8
拡張バイト なし 02
30 uint8
データ長 2
バイト09E3
31 int16
データ 25.31°C センサーデータ4 01
33 uint8
情報ビット 拡張バイトなしuint16
02
34 uint8
データソース 湿度 00
35 uint8
拡張バイト なし 02
36 uint8
データ長 2
バイト0E3A
37 uint16
データ 36.42% センサーデータ5 02
39 uint8
情報ビット 拡張バイトなしuint32
03
40 uint8
データソース 照度 00
41 uint8
拡張バイト なし 04
42 uint8
データ長 4
バイト000001BE
43 uint32
データ 446
lxセンサーデータの末端 6C
47 uint8
チェックサム1 0x6C
00
uint8
チェックサム2 0x00
char
フッタ '\r'
char
フッタ '\n'
データの判別条件 親機・中継機アプリは、さまざまな種類の子機からデータを受信することができます。
出力されたデータがパルアプリ(環境センサーパル)のものであるかを確認するには、次の箇所を参照してください。
# データ 項目 条件 0 uint32
中継機のシリアルID MSBが1であること 7 uint32
送信元のシリアルID MSBが1であること 12 uint8
センサー種別 0x80
であること13 uint8
PAL基板バージョンとPAL基板ID 0x82
であること- - ペイロードのサイズ 48バイトであること
パーサの実装例 動作センサーパル データ形式 出力データの例
:80000000BA002382011CEF01808312113008020D0211300102055C1504400600100010045015044106000800100430150442060000001004381504430600080018043015044406000000180458150445060000002004381504460600080018042815044706FFE80010042015044806FFF00010043815044906FFE80018043015044A06FFF80018044015044B06FFF80018041815044C0600000010042015044D0600000028045015044E0600000008043815044F0600000018043828A5
# データ 内容 値 :
char
ヘッダ :
80000000
0 uint32
中継機のシリアルID 中継なし BA
4 uint8
LQI 186
/255
0023
5 uint16
続き番号 35
82011CEF
7 uint32
送信元のシリアルID 0x2011CEF
01
11 uint8
送信元の論理デバイスID 0x01
80
12 uint8
センサー種別 83
13 uint8
PAL基板バージョンとPAL基板ID 動作パルV1 12
14 uint8
センサーデータ の数18
個センサーデータ1 11
15 uint8
情報ビット 拡張バイトありuint16
30
16 uint8
データソース 電圧 08
17 uint8
拡張バイト 電源 02
18 uint8
データ長 2
バイト0D02
19 uint16
データ 3330
mVセンサーデータ2 11
21 uint8
情報ビット 拡張バイトありuint16
30
22 uint8
データソース 電圧 01
23 uint8
拡張バイト ADC1 02
24 uint8
データ長 2
バイト055C
25 uint16
データ 1372
mVセンサーデータ3 15
27 uint8
情報ビット 拡張バイトありint16
04
28 uint8
データソース 加速度 40
29 uint8
拡張バイト 100Hz, 0番サンプル 06
30 uint8
データ長 6
バイト001000100450
31 int16
データ X16
mG/Y16
mG/Z1104
mG センサーデータ4 15
37 uint8
情報ビット 拡張バイトありint16
04
38 uint8
データソース 加速度 41
39 uint8
拡張バイト 100Hz, 1番サンプル 06
40 uint8
データ長 6
バイト000800100430
41 uint16
データ X8
mG/Y16
mG/Z1072
mG センサーデータ5 <省略> センサデータ15 15
177 uint8
情報ビット 拡張バイトありint16
04
178 uint8
データソース 加速度 4F
179 uint8
拡張バイト 100Hz, 15番サンプル 06
180 uint8
データ長 6
バイト000000180438
181 uint32
データ X0
mG/Y24
mG/Z1080
mG センサーデータの末端 28
187 uint8
チェックサム1 0x28
A5
uint8
チェックサム2 0xA5
char
フッタ '\r'
char
フッタ '\n'
データの判別条件 親機・中継機アプリは、さまざまな種類の子機からデータを受信することができます。
出力されたデータがパルアプリ(動作センサーパル)のものであるかを確認するには、次の箇所を参照してください。
# データ 項目 条件 0 uint32
中継機のシリアルID MSBが1であること 7 uint32
送信元のシリアルID MSBが1であること 12 uint8
センサー種別 0x80
であること13 uint8
PAL基板バージョンとPAL基板ID 0x83
であること- - ペイロードのサイズ 188バイトであること
パーサの実装例 通知パル データ形式 # データ 内容 備考 char
ヘッダ :
のみ0 uint32
中継機のシリアルID 中継なしの場合80000000
4 uint8
LQI 0
-255
5 uint16
続き番号 7 uint32
送信元のシリアルID 0x8???????
11 uint8
送信元の論理デバイスID 12 uint8
センサー種別 0x80
のみ13 uint8
PAL基板バージョンとPAL基板ID 0x84
のみ14 uint8
センサーデータ の数3
のみセンサーデータ1 15 uint8
情報ビット 0x11
のみ16 uint8
データソース 0x30
のみ17 uint8
拡張バイト 0x08
のみ18 uint8
データ長 2
のみ19 uint16
データ 電源電圧(mV) センサーデータ2 21 uint8
情報ビット 0x11
のみ22 uint8
データソース 0x30
のみ23 uint8
拡張バイト 0x01
のみ24 uint8
データ長 2
のみ25 uint16
データ ADC1の電圧(mV) センサーデータ3 27 uint8
情報ビット 0x12
のみ28 uint8
データソース 0x05
のみ29 uint8
拡張バイト 0x04
のみ30 uint8
データ長 4
のみ31 uint8
データ 加速度イベントデータ 32 [uint8]
未使用 センサーデータの末端 35 uint8
チェックサム1 直前までのCRC8 uint8
チェックサム2 チェックサム1までのLRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
出力データの例
:80000000C9BBC082014C3501808403 113008020D0C 1130010203F9 1205040410000000 97C6
# データ 内容 値 :
char
ヘッダ :
80000000
0 uint32
中継機のシリアルID 中継なし C9
4 uint8
LQI 201
/255
BBC0
5 uint16
続き番号 48064
82014C35
7 uint32
送信元のシリアルID 0x2014C35
01
11 uint8
送信元の論理デバイスID 0x01
80
12 uint8
センサー種別 84
13 uint8
PAL基板バージョンとPAL基板ID 通知パルV1 03
14 uint8
センサーデータ の数3
つセンサーデータ1 11
15 uint8
情報ビット 拡張バイトありuint16
30
16 uint8
データソース 電圧 08
17 uint8
拡張バイト 電源 02
18 uint8
データ長 2
バイト0D0C
19 uint16
データ 3340
mVセンサーデータ2 11
21 uint8
情報ビット 拡張バイトありuint16
30
22 uint8
データソース 電圧 01
23 uint8
拡張バイト ADC1 02
24 uint8
データ長 2
バイト03F9
25 uint16
データ 1017
mVセンサーデータ3 12
27 uint8
情報ビット 拡張バイトありuint32
05
28 uint8
データソース イベント 04
29 uint8
拡張バイト 加速度イベント 04
30 uint8
データ長 4
バイト10
31 uint8
データ ムーブ 000000
32 [uint8]
センサーデータの末端 97
35 uint8
チェックサム1 0x97
C6
uint8
チェックサム2 0xC6
char
フッタ '\r'
char
フッタ '\n'
データの判別条件 親機・中継機アプリは、さまざまな種類の子機からデータを受信することができます。
出力されたデータがパルアプリ(通知パル)のものであるかを確認するには、次の箇所を参照してください。
# データ 項目 条件 0 uint32
中継機のシリアルID MSBが1であること 7 uint32
送信元のシリアルID MSBが1であること 12 uint8
センサー種別 0x80
であること13 uint8
PAL基板バージョンとPAL基板ID 0x84
であること- - ペイロードのサイズ 36バイトであること
1.3.2.1.1.1.1.4.2 - キューアプリからの出力(親機・中継機アプリ) キューアプリからデータを受信した際の出力書式
TWELITE CUE モード データ形式 出力データの例
:80000000CF7F7382019E3B0180050F003400038135001205040406000000113008020B8611300102042E000000018015044006FFF00010FC1815044106FFF00018FC1815044206FFF00010FC0015044306FFF80000FC1015044406FFF00010FC1815044506FFE00018FBF815044606FFE80000FC0015044706FFE80010FBF815044806FFE80010FC0815044906FFE80010FC080C0E
# データ 内容 値 :
char
ヘッダ :
80000000
0 uint32
中継機のシリアルID 中継なし CF
4 uint8
LQI 207
/255
7F73
5 uint16
続き番号 32627 82019E3B
7 uint32
送信元のシリアルID 0x2019E3B
01
11 uint8
送信元の論理デバイスID 0x01
80
12 uint8
センサー種別 05
13 uint8
PAL基板バージョンとPAL基板ID TWELITE CUE 0F
14 uint8
センサーデータ の数15
個センサーデータ1 00
15 uint8
情報ビット 拡張バイトなしuint8
34
16 uint8
データソース パケットプロパティ 00
17 uint8
拡張バイト なし 03
18 uint8
データ長 3
バイト813500
19 [uint8]
データ ID129
、タイマイベント発生 センサーデータ2 12
22 uint8
情報ビット 拡張バイトありuint32
05
23 uint8
データソース イベント 04
24 uint8
拡張バイト 加速度イベント 04
25 uint8
データ長 4
バイト06000000
26 uint32
データ サイコロ:6 センサーデータ3 11
30 uint8
情報ビット 拡張バイトありuint16
30
31 uint8
データソース 電圧 08
32 uint8
拡張バイト 電源電圧 02
33 uint8
データ長 2
バイト0B86
34 uint16
データ 2950
mVセンサーデータ4 11
36 uint8
情報ビット 拡張バイトありuint16
30
37 uint8
データソース 電圧 01
38 uint8
拡張バイト ADC1の電圧 02
39 uint8
データ長 2
バイト042E
40 uint16
データ 1070
mVセンサーデータ5 00
42 uint8
情報ビット 拡張バイトなしuint8
00
43 uint8
データソース 磁気 00
44 uint8
拡張バイト なし 01
45 uint8
データ長 1
バイト80
46 uint8
データ 磁石なし(定期送信) センサーデータ6 15
47 uint8
情報ビット 拡張バイトありint16
04
48 uint8
データソース 加速度データ 40
49 uint8
拡張バイト 100Hz, 0番サンプル 06
50 uint8
データ長 6
バイトFFF00010FC18
51 [int16]
データ X-16
mG/Y16
mG/Z-1000
mG センサーデータ7 15
57 uint8
情報ビット 拡張バイトありint16
04
58 uint8
データソース 加速度データ 41
59 uint8
拡張バイト 100Hz, 1番サンプル 06
60 uint8
データ長 6
バイトFFF00018FC18
61 [int16]
データ X-16
mG/Y24
mG/Z-1000
mG センサーデータ8 <省略> センサーデータ15 15
137 uint8
情報ビット 拡張バイトありint16
04
138 uint8
データソース 加速度データ 49
139 uint8
拡張バイト 100Hz, 9番サンプル 06
140 uint8
データ長 6
バイトFFE80010FC08
141 int16
データ X-24
mG/Y16
mG/Z-1016
mG センサーデータの末端 0C
147 uint8
チェックサム1 0x0C
0E
uint8
チェックサム2 0x0E
char
フッタ '\r'
char
フッタ '\n'
データの判別条件 親機・中継機アプリは、さまざまな種類の子機からデータを受信することができます。
出力されたデータがキューアプリ(TWELITE CUEモード)のものであるかを確認するには、次の箇所を参照してください。
# データ 項目 条件 0 uint32
中継機のシリアルID MSBが1であること 7 uint32
送信元のシリアルID MSBが1であること 12 uint8
センサー種別 0x80
であること13 uint8
PAL基板バージョンとPAL基板ID 0x05
であること- - ペイロードのサイズ 148バイトであること
パーサの実装例 開閉センサーパルモード 動作センサーパルモード(加速度計測モード) 動作センサーパルモード(ムーブ/ダイスモード) データ形式 # データ 内容 備考 char
ヘッダ :
のみ0 uint32
中継機のシリアルID 中継なしの場合80000000
4 uint8
LQI 0
-255
5 uint16
続き番号 7 uint32
送信元のシリアルID 0x8???????
11 uint8
送信元の論理デバイスID 12 uint8
センサー種別 0x80
のみ13 uint8
PAL基板バージョンとPAL基板ID 0x03
のみ14 uint8
センサーデータ の数04
のみセンサーデータ1 15 uint8
情報ビット 0x00
のみ16 uint8
データソース 0x34
のみ17 uint8
拡張バイト 0x00
のみ18 uint8
データ長 3
のみ19 [uint8]
データ パケットプロパティデータ センサーデータ2 22 uint8
情報ビット 0x12
のみ23 uint8
データソース 0x05
のみ24 uint8
拡張バイト 0x04
のみ25 uint8
データ長 4
のみ26 uint32
データ イベントデータ センサーデータ3 30 uint8
情報ビット 0x11
のみ31 uint8
データソース 0x30
のみ32 uint8
拡張バイト 0x08
のみ33 uint8
データ長 2
のみ34 uint16
データ 電源電圧(mV) センサーデータ4 36 uint8
情報ビット 0x11
のみ37 uint8
データソース 0x30
のみ38 uint8
拡張バイト 0x01
のみ39 uint8
データ長 2
のみ40 uint16
データ ADC1の電圧(mV) センサーデータの末端 42 uint8
チェックサム1 直前までのCRC8 uint8
チェックサム2 チェックサム1までのLRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
出力データの例 ダイスモードの例を示します。ムーブモードの場合は、センサーデータ2
のイベント が異なります。
:80000000B400048106664801800304003400038035001205040403000000113008020D2011300102052C59B7
# データ 内容 値 :
char
ヘッダ :
80000000
0 uint32
中継機のシリアルID 中継なし B1
4 uint8
LQI 177
/255
0008
5 uint16
続き番号 8 81066648
7 uint32
送信元のシリアルID 0x2019E3B
01
11 uint8
送信元の論理デバイスID 0x1066648
80
12 uint8
センサー種別 03
13 uint8
PAL基板バージョンとPAL基板ID TWELITE CUE ダイス/ムーブ 04
14 uint8
センサーデータ の数4
つセンサーデータ1 00
15 uint8
情報ビット 拡張バイトなしuint8
34
16 uint8
データソース パケットプロパティ 00
17 uint8
拡張バイト なし 03
18 uint8
データ長 3
バイト803500
19 [uint8]
データ ID128
、イベント発生(他ADC1と電源のみ) センサーデータ2 12
22 uint8
情報ビット 拡張バイトありuint32
05
23 uint8
データソース イベント 04
24 uint8
拡張バイト 加速度イベント 04
25 uint8
データ長 4
バイト03000000
26 uint32
データ ダイスモード、サイコロ:3 センサーデータ3 11
30 uint8
情報ビット 拡張バイトありuint16
30
31 uint8
データソース 電圧 08
32 uint8
拡張バイト 電源電圧 02
33 uint8
データ長 2
バイト0D20
34 uint16
データ 3360
mVセンサーデータ4 11
36 uint8
情報ビット 拡張バイトありuint16
30
37 uint8
データソース 電圧 01
38 uint8
拡張バイト ADC1の電圧 02
39 uint8
データ長 2
バイト052C
40 uint16
データ 1324
mVセンサーデータの末端 59
42 uint8
チェックサム1 0x0C
B7
uint8
チェックサム2 0x0E
char
フッタ '\r'
char
フッタ '\n'
データの判別条件 親機・中継機アプリは、さまざまな種類の子機からデータを受信することができます。
出力されたデータがキューアプリ(動作センサーパルモードのムーブあるいはダイスモード)のものであるかを確認するには、次の箇所を参照してください。
# データ 項目 条件 0 uint32
中継機のシリアルID MSBが1であること 7 uint32
送信元のシリアルID MSBが1であること 12 uint8
センサー種別 0x80
であること13 uint8
PAL基板バージョンとPAL基板ID 0x03
であること- - ペイロードのサイズ 43バイトであること
パーサの実装例 1.3.2.1.1.1.1.4.3 - アリアアプリからの出力(親機・中継機アプリ) アリアアプリからデータを受信した際の出力書式
TWELITE ARIA モード データ形式 出力データの例
:80000000CF00028201BAA201800607003400038135001205350401000000113008020D201130010204ED00000001800501000209D0010200020F347934[CR][LF]
# データ 内容 値 :
char
ヘッダ :
80000000
0 uint32
中継機のシリアルID 中継なし CF
4 uint8
LQI 207
/255
0002
5 uint16
続き番号 2 8201BAA2
7 uint32
送信元のシリアルID 0x201BAA2
01
11 uint8
送信元の論理デバイスID 0x01
80
12 uint8
センサー種別 06
13 uint8
PAL基板バージョンとPAL基板ID TWELITE ARIA 07
14 uint8
センサーデータ の数7
つセンサーデータ1 00
15 uint8
情報ビット 拡張バイトなしuint8
34
16 uint8
データソース パケットプロパティ 00
17 uint8
拡張バイト なし 03
18 uint8
データ長 3
バイト813500
19 [uint8]
データ ID129
、タイマイベント発生 センサーデータ2 12
22 uint8
情報ビット 拡張バイトありuint32
05
23 uint8
データソース イベント 35
24 uint8
拡張バイト タイマイベント 04
25 uint8
データ長 4
バイト01000000
26 uint32
データ タイマによる起床 センサーデータ3 11
30 uint8
情報ビット 拡張バイトありuint16
30
31 uint8
データソース 電圧 08
32 uint8
拡張バイト 電源電圧 02
33 uint8
データ長 2
バイト0D20
34 uint16
データ 3360
mVセンサーデータ4 11
36 uint8
情報ビット 拡張バイトありuint16
30
37 uint8
データソース 電圧 01
38 uint8
拡張バイト ADC1の電圧 02
39 uint8
データ長 2
バイト04ED
40 uint16
データ 1261
mVセンサーデータ5 00
42 uint8
情報ビット 拡張バイトなしuint8
00
43 uint8
データソース 磁気 00
44 uint8
拡張バイト なし 01
45 uint8
データ長 1
バイト80
46 uint8
データ 磁石なし(定期送信) センサーデータ6 05
47 uint8
情報ビット 拡張バイトなしint16
01
48 uint8
データソース 温度 00
49 uint8
拡張バイト なし 02
50 uint8
データ長 2
バイト09D0
51 int16
データ 25.12
°Cセンサーデータ7 01
53 uint8
情報ビット 拡張バイトなしuint16
02
54 uint8
データソース 湿度 00
55 uint8
拡張バイト なし 02
56 uint8
データ長 2
バイト0F34
57 uint16
データ 38.92
%センサーデータの末端 79
59 uint8
チェックサム1 0x79
34
uint8
チェックサム2 0x34
char
フッタ '\r'
char
フッタ '\n'
データの判別条件 親機・中継機アプリは、さまざまな種類の子機からデータを受信することができます。
出力されたデータがアリアアプリ(TWELITE ARIAモード)のものであるかを確認するには、次の箇所を参照してください。
# データ 項目 条件 0 uint32
中継機のシリアルID MSBが1であること 7 uint32
送信元のシリアルID MSBが1であること 12 uint8
センサー種別 0x80
であること13 uint8
PAL基板バージョンとPAL基板ID 0x06
であること- - ペイロードのサイズ 60バイトであること
パーサの実装例 開閉センサーパルモード 1.3.2.1.1.1.1.4.4 - パル・キュー・アリアアプリからの出力の詳細(親機・中継機アプリ) パル・キュー・アリアアプリに共通する出力書式の詳細
パル・キュー・アリアアプリの子機から受信したデータは、共通の書式に沿って出力されます。ここには、その詳細を記しています。それぞれの具体的な出力例は、
各アプリのページ をご覧ください。
全体 データ形式 # データ 内容 備考 char
ヘッダ :
のみ0 uint32
中継機のシリアルID 中継なしの場合80000000
4 uint8
LQI 0
-255
5 uint16
続き番号 7 uint32
送信元のシリアルID 0x8???????
11 uint8
送信元の論理デバイスID 12 uint8
センサー種別 0x80
のみ13 uint8
PAL基板バージョンとPAL基板ID 0x81
など14 uint8
センサーデータ の数15 [uint8]
センサーデータ の羅列長さ\(N\)のバイト列 15+\(N\) uint8
チェックサム1 直前までのCRC8 uint8
チェックサム2 チェックサム1までのLRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
出力データの例
:80000000A8001C82012B1E01808103113008020D0C1130010203E40000000101EC6E
# データ 内容 値 :
char
ヘッダ :
80000000
0 uint32
中継機のシリアルID 中継なし A8
4 uint8
LQI 168/255
001C
5 uint16
続き番号 28
82012B1E
7 uint32
送信元のシリアルID 0x2012B1E
01
11 uint8
送信元の論理デバイスID 0x01
80
12 uint8
センサー種別 - 81
13 uint8
PAL基板バージョンとPAL基板ID 0x81
03
14 uint8
センサーデータ の数3
つ1130...0101
15 [uint8]
センサーデータ の羅列長さ17のバイト列 EC
15+17 uint8
チェックサム1 0xEC
6E
uint8
チェックサム2 0x6E
char
フッタ '\r'
char
フッタ '\n'
センサーデータ データ形式 # データ 内容 備考 0 uint8
情報ビット データの型や拡張バイトの有無 1 uint8
データソース センサー値の種類 2 uint8
拡張バイト センサー値の付加情報 3 uint8
データ長 センサー値の長さ 4 [uint8]
データ センサー値
出力データの例
情報ビット センサー値のデータ型や拡張バイトの有無、読み込みエラーの有無を示します。
bit 7 6 5 4 3 2 1 0 機能 ERR - - EXT - TYP:2 TYP:1 TYP:0
各機能は次の内容を示します。
機能 説明 値 内容 ERR 読み込みエラーの有無 0
正常 1
エラーあり EXT 拡張バイトの有無 0
拡張バイトなし 1
拡張バイトあり TYP データ型 000
uint8
001
uint16
010
uint32
011
N/A 100
int8
101
int16
110
int32
111
[uint8]
データソース センサー値の種類を示します。
値 内容 0x00
磁気 0x01
温度 0x02
湿度 0x03
照度 0x04
加速度 0x05
イベント 0x30
電圧 0x34
パケットプロパティ
拡張バイト 連続データのインデックスなど、センサー値の付加情報を示します。
データソースが磁気/温度/湿度/照度/パケットプロパティの場合 なし
データソースが加速度の場合 加速度サンプルデータの属性を示します。
bit 7 6 5 4 3 2 1 0 機能 SFQ:2 SFQ:1 SFQ:0 SNM:4 SNM:3 SNM:2 SNM:1 SNM:0
各機能は次の内容を示します。
機能 説明 値 内容 SFQ サンプリング周波数 000
(0x00|SNM
)25Hz 001
(0x20|SNM
)50Hz 010
(0x40|SNM
)100Hz 011
(0x60|SNM
)190Hz 100
以上未定義 SNM サンプル番号 0
-31
古い順
データソースがイベントの場合 イベントの発生要因を示します。
値 内容 0x00
磁気 0x01
温度 0x02
湿度 0x03
照度 0x04
加速度 0x31
デジタル入力 0x35
タイマ
データソースが電圧の場合 対象を示します。
値 内容 0x01
ADC1 0x02
ADC2 0x03
ADC3 0x04
ADC4 0x08
電源
データ長 続くデータのバイト数を示します。
データ センサー値を表します。
データソースが磁気の場合 データ型はuint8
です。
値 内容 0x00
磁石なし 0x01
N極が近づいた 0x02
S極が近づいた 0x80
磁石なし(定期送信) 0x81
N極が近くにある(定期送信) 0x82
S極が近くにある(定期送信)
データソースが温度の場合 データ型はint16
です。
100倍されたセ氏の温度を表します。
データソースが湿度の場合 データ型はuint16
です。
100倍された相対湿度を表します。
データソースが照度の場合 データ型はuint32
です。
ルクスの値を表します。
データソースが加速度の場合 int16
のデータが3つ続きます。
X,Y,Z軸の値(mG)の合計は6バイトです。
byte 0 1 2 3 4 5 内容 X:15-8 X:7-0 Y:15-8 Y:7-0 Z:15-8 Z:7-0
データソースがイベントの場合 uint8
のデータが4つ続きます。
先頭のデータがイベントの内容を表し、残りは未使用です。
拡張バイトが磁気の場合 先頭の値 内容 0x00
磁石なし 0x01
N極が近くにある 0x02
S極が近くにある
拡張バイトが加速度の場合 先頭の値 内容 0x01
サイコロ:1 0x02
サイコロ:2 0x03
サイコロ:3 0x04
サイコロ:4 0x05
サイコロ:5 0x06
サイコロ:6 0x08
シェイク 0x10
ムーブ
拡張バイトがタイマの場合 データソースが電圧の場合 データ型はuint16
です。
mV単位の電圧を表します。
データソースがパケットプロパティの場合 uint8
のデータが3つ続きます。
byte 0 1 2 データ パケットID 起床要因の根源 起床要因の条件
各データは次の内容を表します。
データ 値 内容 パケットID 0
イベントなし、ADC1と電源の電圧のみ 1
-127
イベントなし、その他のデータあり 128
イベントあり、ADC1と電源の電圧のみ 129
-255
イベントあり、その他のデータあり 起床要因の根源 0x00
磁気 0x01
温度 0x02
湿度 0x03
照度 0x04
加速度 0x31
デジタル入力 0x35
タイマ 起床要因の条件 0x00
イベントが発生した 0x01
値が変化した 0x02
値がしきい値を上回った 0x03
値がしきい値を下回った 0x04
値が範囲を満たした
1.3.2.1.1.1.1.5 - actからの出力(親機・中継機アプリ) act からデータを受信した際の出力書式
act から受信したデータ データ形式 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信元の論理デバイスID 1 uint8
コマンド種別 0xAA
のみ2 uint8
応答ID 0x00
-0x7F
3 uint32
送信元のシリアルID 7 uint32
送信先のシリアルID 論理デバイスID指定時は00000000
11 uint8
LQI 0
-255
12 uint16
データのバイト数 14 [uint8]
任意のデータ 長さ\(N\)のバイト列 uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
出力データの例
:FEAA008201015A00000000B7000F424154310F0CEE000B03FF03FF03FF92
# データ 内容 値 :
char
ヘッダ :
FE
0 uint8
送信元の論理デバイスID 0xFE
AA
1 uint8
コマンド種別 0xAA
00
2 uint8
応答ID 0x00
8201015A
3 uint32
送信元のシリアルID 0x201015A
00000000
7 uint32
送信先のシリアルID 論理デバイスID指定 B7
11 uint8
LQI 183/255
000F
12 uint16
データのバイト数 15
バイト424154310F0CEE000B03FF03FF03FF
14 [uint8]
任意のデータ そのまま 92
uint8
チェックサム 0x92
char
フッタ \r
char
フッタ \n
1.3.2.1.1.1.1.6 - 無線タグアプリからの出力(親機・中継機アプリ) 無線タグアプリからデータを受信した際の出力書式
子機へ主なセンサーを接続した際の出力を記載します。
アナログセンサー データ形式 # データ 内容 備考 char
ヘッダ :
のみ0 uint32
中継機のシリアルID 中継なしは80000000
4 uint8
LQI 0
-255
5 uint16
続き番号 7 uint32
送信元のシリアルID 11 uint8
送信元の論理デバイスID 12 uint8
センサー種別 13 uint8
電源電圧(mV) 電源電圧の計算 を参照14 uint16
ADC1の電圧 16 uint16
ADC2の電圧 18 uint32
未使用 22 uint8
チェックサム
出力データの例
:80000000B700628201015A0010DF08FD09A300000000E9
# データ 内容 値 :
char
ヘッダ :
80000000
0 uint32
中継機のシリアルID 中継なし B7
4 uint8
LQI 183/255
0062
5 uint16
続き番号 98
8201015A
7 uint32
送信元のシリアルID 0x201015A
00
11 uint8
送信元の論理デバイスID 0x00
10
12 uint8
センサー種別 アナログセンサー DF
13 uint8
電源電圧(mV) 3330
mV08FD
14 uint16
ADC1の電圧 2301
mV09A3
16 uint16
ADC2の電圧 2467
mV00000000
18 uint32
未使用 E9
22 uint8
チェックサム 0xE9
char
フッタ \r
char
フッタ \n
加速度センサー(ADXL34x / TWELITE 2525A) データ形式 # データ 内容 備考 char
ヘッダ :
のみ0 uint32
中継機のシリアルID 中継なしは80000000
4 uint8
LQI 0
-255
5 uint16
続き番号 7 uint32
送信元のシリアルID 11 uint8
送信元の論理デバイスID 12 uint8
センサー種別 13 uint8
電源電圧(mV) 電源電圧の計算 を参照14 uint16
ADC1の電圧 16 uint16
ADC2の電圧 18 uint8
センサーモード番号 19 int16
X軸の加速度 単位はmG*10
21 int16
Y軸の加速度 単位はmG*10
23 int16
Z軸の加速度 単位はmG*10
25 uint8
チェックサム
出力データの例
:8000000063001781013C850035DF057702F2000000FF96FFF0BB
# データ 内容 値 :
char
ヘッダ :
80000000
0 uint32
中継機のシリアルID 中継なし 63
4 uint8
LQI 99/255
0017
5 uint16
続き番号 23
81013C85
7 uint32
送信元のシリアルID 0x1013C85
00
11 uint8
送信元の論理デバイスID 0x00
35
12 uint8
センサー種別 加速度センサー(ADXL34x) DF
13 uint8
電源電圧(mV) 3330
mV0577
14 uint16
ADC1の電圧 1399
mV02F2
16 uint16
ADC2の電圧 754
mV00
18 uint8
センサーモード番号 通常 0000
19 int16
X軸の加速度 0
mGFF96
21 int16
Y軸の加速度 -1060
mGFFF0
23 int16
Z軸の加速度 -160
mGBB
25 uint8
チェックサム 0xBB
char
フッタ \r
char
フッタ \n
スイッチ データ形式 # データ 内容 備考 char
ヘッダ :
のみ0 uint32
中継機のシリアルID 中継なしは80000000
4 uint8
LQI 0
-255
5 uint16
続き番号 7 uint32
送信元のシリアルID 11 uint8
送信元の論理デバイスID 12 uint8
センサー種別 13 uint8
電源電圧(mV) 電源電圧の計算 を参照14 uint16
ADC1の電圧 16 uint16
ADC2の電圧 18 uint8
センサーモード番号 0
がHi→Lo、1
がLo→Hi19 uint8
DI1
の状態1
がLo20 uint8
未使用 21 uint8
チェックサム
出力データの例
:800000009C00118201015A00FEDF000709A300010064
# データ 内容 値 :
char
ヘッダ 80000000
0 uint32
中継機のシリアルID 中継なし 9C
4 uint8
LQI 156/255
0062
5 uint16
続き番号 98
8201015A
7 uint32
送信元のシリアルID 0x201015A
00
11 uint8
送信元の論理デバイスID 0x00
FE
12 uint8
センサー種別 スイッチ DF
13 uint8
電源電圧(mV) 3330
mV0007
14 uint16
ADC1の電圧 7
mV09A3
16 uint16
ADC2の電圧 2467
mV00
18 uint8
センサーモード番号 Hi→Lo 01
19 uint8
DI1
の状態Lo 00
20 uint8
未使用 64
21 uint8
チェックサム 0x64
char
フッタ \r
char
フッタ \n
電源電圧の計算 電源電圧 \(V_{cc}\) は、受信した値 \(e_{cc}\) を使って次のように表すことができます。
$$\begin{cases}
V_{cc} = 1950+5e_{cc} & (e_{cc} <= 170) \\
V_{cc} = 2800+10(e_{cc}-170) & (e_{cc} > 170)
\end{cases}$$
単位は mV
1.3.2.1.1.1.2 - 親機・中継機アプリの送信コマンド 子機へデータを送信する際の入力
既定の書式でシリアルポートから入力されたコマンドを子機へ送信します。
1.3.2.1.1.1.2.1 - 超簡単!標準アプリへの入力(親機・中継機アプリ) 超簡単!標準アプリの出力を制御するためのコマンド
超簡単!標準アプリの出力を制御できます。
デジタル・アナログ入出力 0x80
:相手端末の出力変更相手端末の出力信号を制御します。
データ形式 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信先の論理デバイスID 親機0x00
,子機0x01
-0x64
,全子機0x78
1 uint8
コマンド番号 0x80
のみ2 uint8
書式バージョン 0x01
のみ3 uint8
デジタル信号 LSBからDOx
に対応、0
でHigh 4 uint8
デジタル信号マスク LSBからDOx
に対応、1
で有効 5 uint16
PWM1
信号0
-1024
,0xFFFF
で無効7 uint16
PWM2
信号0
-1024
,0xFFFF
で無効9 uint16
PWM3
信号0
-1024
,0xFFFF
で無効11 uint16
PWM4
信号0
-1024
,0xFFFF
で無効uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
1.3.2.1.1.1.2.2 - シリアル通信アプリへの入力(親機・中継機アプリ) シリアル通信アプリへデータを送信するコマンド
シリアル通信アプリの子機へデータを送信できます(書式モード、簡易形式)
UART 書式モード:アスキー・簡易形式 App_Wings v1.3 以降では、書式モード(A)の簡易形式に対応しています。
2024年9月現在、公開中の SDK に App_Wings v1.3 は含まれていません。
次のリンクから App_Wings v1.3 をダウンロードし、ファイルを指定して書き込む ことで使用できます。
データ形式 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信先の論理デバイスID 親機0x00
,子機0x01
-0x64
,全子機0x78
1 uint8
コマンド番号 0x80
未満の任意の値2 [uint8]
任意のデータ 長さ\(N\)のバイト列(\(N\leqq80\)を推奨) uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
1.3.2.1.1.1.2.3 - パルアプリ(通知パル)への入力(親機・中継機アプリ) 通知パルのLEDを制御するためのコマンド
通知パルのLEDを制御できます。
:0190010004000169[CR][LF]
^1^2^3^^^^^^^4^5
番号 バイト数 意味 データ例 備考 1 1 送信先の論理デバイスID 01 送信先のTWELITE PALの論理デバイスIDを指定します。 0x01から0x64まで指定可能です。
2 1 コマンド種別 90 3 1 コマンドパラメータ数 01 コマンドパラメータの数を指定します。例えば、コマンドパラメータを1つだけ指定するなら1に、2つ指定するには2にします。 4 コマンド数x4 コマンドパラメータ 00040001 イベントやLEDの色などを指定するためのパラメータを指定します。 詳細はコマンドパラメータを参照してください。
5 1 チェックサム 69 1~4の各バイトの和を8ビット幅で計算し2の補数をとります。つまりデータ部の各バイトの総和+チェックサムバイトを8ビット幅で計算すると0になります。 チェックサムバイトをアスキー文字列2文字で表現します。 例えば 00A01301FF123456 では 0x00 + 0xA0 + … + 0x56 = 0x4F となり、この二の補数は0xB1 です。(つまり 0x4F + 0xB1 = 0) チェックサムをXにすることでチェックサムを省略可能です。
6 2 フッター [CR][LF] [CR] (0x0D) [LF] (0x0A) を指定します。ただし、チェックサムをXで省略する場合はフッターも省略可能です。
コマンドパラメータ 4バイトのコマンドパラメータを組み合わせてコマンドを指定します。
0x00:イベントIDを送信する TWELITE PALは受信したイベントIDごとの振る舞いが設定されております。 本パラメータでは送信先のTWELITE PALにイベントIDを送信し、設定した動作を行います。
イベント毎の振る舞いを変更するにはTWELITE PALの設定を変更してください。
番号 バイト数 内容 備考 1 1 コマンドパラメータID 0x00 2 1 送信先PAL ID 送信先のPAL IDを指定します。 0x04:通知パル 0xFF:すべてのTWELITE PAL
3 1 未使用領域 0x00固定 4 1 イベントID 0~16までのイベントIDを指定します。
0x01 : LEDの色、点滅パターン、明るさを送信する 送信先の通知パルにLEDの色、点滅パターン、明るさを送信します。
番号 バイト数 内容 備考 1 1 コマンドパラメータID 0x01 2 1 色
0:赤 1:緑 2:青 3:黄色 4:紫 5:水色 6:白 7:暖かい白
3 1 点滅パターン 0:常時点灯 1~3:点滅パターン(数値が大きくなるほど点滅が早くなる。)
4 1 明るさ 0:消灯 0x01~0x0F:明るさ(数値が大きいほど明るくなる。)
0x02 : 点灯時間を送信する 通知パルのLEDの点灯時間を送信します。
本コマンドパラメータは、LEDの色、点滅パターン、明るさのパラメータが含まれないので、コマンドパラメータ0x01または0x03と組み合わせて使用します。
本コマンドパラメータを使用する場合は、送信間隔を必ず点灯時間より大きく設定してご使用ください。
番号 バイト数 内容 備考 1 1 コマンドパラメータID 0x02 2 1 未使用領域
0xFF固定 3 1 未使用領域 0x00固定 4 1 点灯時間 秒で指定(0は常時点灯)
0x03:LEDの色をRGBWで指定する 通知パルのLEDの点灯色をRGBWで送信します。
コマンドパラメータ0x00および0x01とは同時に使用できません。
番号 バイト数 内容 備考 1 1 コマンドパラメータID 0x03 2 1 未使用領域
0xFF固定 3 2 LEDの点灯色 LSBからRGBWの順番で4ビットずつ指定する。
数値が大きいほど明るい
0x04:点滅パラメータを指定する。 通知パルのLEDの点滅周期と点滅Dutyを送信します。
本コマンドパラメータは、LEDの色のパラメータが含まれないので、コマンドパラメータ0x03と組み合わせて使用します。
コマンドパラメータ0x00および0x01とは同時に使用できません。
番号 バイト数 内容 備考 1 1 コマンドパラメータID 0x04 2 1 未使用領域
0xFF固定 3 1 点滅時間の割合 0x00~0xFFで指定する。
数値が大きいほど1周期当たりの点灯時間が長くなる。
1周期の半分だけ点灯させるには0x7Fを指定する。
4 1 点滅周期 0x00~0xFFで指定する。
設定値が1大きくなるごとに点滅の周期が約0.04sずつ増える。
1周期1秒にするには0x17を指定する。
コマンド例 例1:イベントを送信する 論理デバイスIDが1のNOTICE PALに対してイベント1を送信するコマンド例です。
:0190010004000169
^1^2^3^4^5^6^7^8
番号 バイト数 意味 データ例 データ例の内容 備考 1 1 送信先の論理デバイスID 01 送信先の論理デバイスIDは0x01 2 1 コマンド種別 90 0x90コマンド 90固定 3 1 コマンド数 01 コマンドは1個 4 1 コマンドID 00 コマンド00 5 1 送信先PAL ID 04 通知パルに対して送信する 6 1 未使用領域 00 7 1 イベントID 01 イベント1 0x00~0x10まで 8 1 チェックサム 69
例2:通知パルのLEDの点灯色を送信する 論理デバイスIDが1のNOTICE PALに対して明るさ8で白色にゆっくり点滅させるためのコマンドです。
:019001010601085E
^1^2^3^4^5^6^7^8
番号 バイト数 意味 データ例 データ例の内容 備考 1 1 送信先の論理デバイスID 01 送信先の論理デバイスIDは0x01 2 1 コマンド種別 90 0x90コマンド 90固定 3 1 コマンド数 01 コマンドは1個 4 1 コマンドパラメータID 01 コマンドパラメータID 0x01 5 1 色 06 白 6 1 点滅パターン 01 点滅 7 1 明るさ 08 明るさ8 0x00~0x0Fまで 8 1 チェックサム 5E
例3:通知パルのLEDの点灯色と点灯時間を送信する 論理デバイスIDが1のNOTICE PALに対して紫に点灯させ、点灯後1秒で消灯させるコマンドです。
本コマンドを試す場合、送信間隔を必ず点灯時間より大きく設定してご使用ください。
:0190020104000802FF00015E
^1^2^3^4^5^6^7^8^9^a^b^c
番号 バイト数 意味 データ例 データ例の内容 備考 1 1 送信先の論理デバイスID 01 送信先の論理デバイスIDは0x01 2 1 コマンド種別 90 0x90コマンド 90固定 3 1 コマンド数 02 コマンドは2個 4 1 コマンドパラメータID 01 コマンドパラメータID 0x01 5 1 色 04 紫 6 1 点滅パターン 00 点灯 7 1 明るさ 08 明るさ8 0x00~0x0Fまで 8 1 コマンドパラメータID 02 コマンドパラメータID 0x02 9 1 未使用領域 FF a 1 未使用領域 00 b 1 点灯時間 01 点灯後1秒で消える c 1 チェックサム 5E
例4:通知パルに詳細な点灯色を送信する 論理デバイスIDが1のNOTICE PALに対して紫に点灯させるコマンドです。
:01900103FF0F0459
^1^2^3^4^5^^^6^7
番号 バイト数 意味 データ例 データ例の内容 備考 1 1 送信先の論理デバイスID 01 送信先の論理デバイスIDは0x01 2 1 コマンド種別 90 0x90コマンド 90固定 3 1 コマンド数 01 コマンドは2個 4 1 コマンドパラメータID 03 コマンドパラメータID 0x03 5 1 未使用 FF 6 2 LEDの点灯色 0F04 青:15、赤4の明るさで点灯させる。 LSBからRGBWの順番で各色4bitずつ(0~15)で指定する。
数値が大きいほど明るい
7 1 チェックサム 59
例5:通知パルのLEDの点灯色と点灯時間を送信する 論理デバイスIDが1のNOTICE PALに対して紫に点灯させ、点灯後1秒で消灯させるコマンドです。
本コマンドを試す場合、送信間隔を必ず点灯時間より大きく設定してご使用ください。
:0190020104000802FF00015E
^1^2^3^4^5^6^7^8^9^a^b^c
番号 バイト数 意味 データ例 データ例の内容 備考 1 1 送信先の論理デバイスID 01 送信先の論理デバイスIDは0x01 2 1 コマンド種別 90 0x90コマンド 90固定 3 1 コマンド数 02 コマンドは2個 4 1 コマンドパラメータID 01 コマンドパラメータID 0x01 5 1 色 04 紫 6 1 点滅パターン 00 点灯 7 1 明るさ 08 明るさ8 0x00~0x0Fまで 8 1 コマンドパラメータID 02 コマンドパラメータID 0x02 9 1 未使用領域 FF a 1 未使用領域 00 b 1 点灯時間 01 点灯後1秒で消える c 1 チェックサム 5E
1.3.2.1.1.2 - 親機・中継機アプリの中継機モード 子機や親機から受信したデータを再送信する
中継機モードでは、受信したパケットを再送信することで、子機と親機の通信距離を延ばすことができます。
中継したとき、親機が受信するパケットの順番が入れ替わってしまうことがあります。
100ms程度など短い間隔で連続的に送信する子機がいる際には、中継が間に合わない場合があります。本番環境でよく検証のうえご利用ください。
設定例 中継機として使用するには、インタラクティブモードの動作モード を1
以上としてください。
中継方式 TWELITE NETでは無線パケットの中継配送について、大きく分けて下表で示す2つの方式を用意しており、アプリケーションごとに異なります。本アプリでは下表で示すアプリケーションのパケットを識別し、中継することができます。
中継方式 対応アプリ 単純ネット 超簡単!標準アプリ、リモコンアプリ、シリアル通信アプリ、アクト 中継ネット 無線タグアプリ、パルアプリ、キューアプリ
単純ネットを使用した中継 単純ネットを使用するアプリの中継を行う場合、動作モードの値を1以上に設定することで3回まで中継することができます。
例えば、1. のように親機と子機の間に中継機が3台以内であれば親機にデータが届きますが、2. ように中継機が4台以上ある場合は親機にデータが届きません。
1. 子機 ---> 中継機 ---> 中継機 ---> 中継機 ---> 親機
→ 親機が子機のデータを3回中継して受信できる。
2. 子機 ---> 中継機 ---> 中継機 ---> 中継機 ---> 中継機 -x-> 親機\
→ 中継4回目で中継することをやめる。
単純ネットによる中継は、基本的に同報通信を使用して通信を行い、受信したパケットをすべて中継を行います。そのため、中継ネットワークを形成、維持するための通信が必要ないという利点がありますが、中継機が増えるほど爆発的に通信量が多くなることがあるという欠点もあります。
詳しくは こちら を参照ください。
中継ネットを使用した中継 中継ネットを使用するアプリのデータを1段の中継を行う場合、動作モードの値を1に設定してしてください。
複数回の中継を行う場合は、親機から遠くなるにつれて動作モードの設定値を大きくしてください。(設定値が昇順になっていれば設定値が飛んでもかまいません。)
本方式の最大中継回数は63回までです。
例1:1回の中継を行う場合\
子機 ---> 中継機(動作モード:1) ---> 親機
例2:2回の中継を行う場合\
子機 ---> 中継機(動作モード:2) ---> 中継機(動作モード:**1**) ---> 親機
例3:3回の中継を行う場合\
子機 ---> 中継機(動作モード:6) ---> 中継機(動作モード:3) ---> 中継機(動作モード:1) ---> 親機
中継ネットは上り方向の配送を効率的に実施する目的を持って設計されたツリー型ネットワークで、中継機は上位レイヤ(より動作モードの設定値が小さい親機もしくは中継機)を探索し、発見した上位レイヤ1台に対して中継を行います。
そのため、中継機の台数が増えても単純ネットほどは通信量が多くなりにくいですが、接続先を探索、維持するための通信が発生します。
詳しくは こちら をご覧ください。
静的ルーティング(中継先を直接指定)をする場合 中継ネットでの中継を行うときに、下図のような配置を考えた場合、中継機2の接続先は親機もしくは中継機1のどちらかを自動的に選択します。
基本的には、中継する回数が少ない方が親機への配送率が高くなる場合が多いですが、中継機2の接続先として親機が選択されてしまった場合、親機と中継機2の間に障害物があるため、通信品質が悪くなり、親機への配送率が中継機1を経由するときより低くなる可能性が高くなります。
そのため、本アプリには中継機の接続先を TWELITE のシリアル番号で指定する機能 (静的ルーティング機能) があります。
静的ルーティングを行う場合は、中継機2→中継機1への経路を静的にする、または全ての経路を静的に設定します。
すべての経路の設定にはその分だけ設定が多くなり、また、中継機の故障や電波状況の変化といった状況を想定した冗長化に対応できない点がありますが、上位通信先を確定するまでの時間をなくし、速やかに中継動作に移行できる利点があります。
静的ルーティングをするには下表のように中継機1には親機のSID、中継機2には中継機1のSIDになるように接続先を設定してください。
例: 2段中継の場合 (親機 ← 中継機1 ← 中継機2 ← 子機)
TWELITEのSID例 接続先(A: Access Point Address)の設定例 動作モード(l:Mode)の設定例 親機 810F155E - 0 中継機1 810E18E8 810F155E (親機のSID)※ 1 中継機2 810F17FF 810E18E8 (中継機1のSID) 2
※上図の壁による影響のみに対処したい場合は設定不要です。
1.3.2.1.2 - インタラクティブモード(親機・中継機アプリ) インタラクティブモードによる詳細な設定変更
インタラクティブモードでアプリの詳細設定を行うことができます。
ここでは親機・中継機アプリ(App_Wings)に固有の機能を説明します。共通機能については、TWELITE APPS マニュアル のトップページ を参照してください。
表示例 次のような画面を表示します。
[CONFIG MENU/App_Wings:0/v1-02-1/SID=820163B2]
a: (0x67720102) Application ID [HEX:32bit]
c: (18 ) Channels Set
x: ( 0x03) RF Power/Retry [HEX:8bit]
b: (38400,8N1 ) UART Baud [9600-230400]
o: (0x00000000) Option Bits [HEX:32bit]
k: (0xA5A5A5A5) Encryption Key [HEX:32bit]
m: ( 0) Mode (Parent or Router)
A: (0x00000000) Access point address [HEX:32bit]
[ESC]:Back [!]:Reset System [M]:Extr Menu
コマンド 各コマンドの詳細を次に示します。
a
:アプリケーションID通信を行う端末はすべて同一の値とします。論理的にネットワークを分離します。
c
:周波数チャネル通信を行う端末はすべて同一の値とします。物理的にネットワークを分離します。
x
:送信出力と再送回数電波の送信出力と、パケットを追加で送信する回数を指定します。
b
:UART代替設定オプションビットのUART代替設定の有効化 を設定した場合のUARTオプションを指定します。
値にはボーレートとパリティの設定をカンマで区切って指定します。
ボーレートは、9600
/19200
/38400
/57600
/115200
/230400
から選択できます。他の値を指定すると、誤差が生じる可能性があります。
パリティはN
: 無し、O
: Odd(奇数)、E
: Even(偶数)を設定します。ハードウェアフローは設定できません。8N1, 7E2 などと設定できますが、8N1 以外の設定は未検証です。事前に動作をご確認ください。
o
:オプションビット32bit の数値を指定します。各ビットに紐付いた設定を有効化できます。
k
:暗号化鍵オプションビットの暗号化通信の有効化 を設定した場合の暗号化鍵を32bitの16進数で指定します。
m
:動作モード0
は親機モード、1
は中継機モードへ設定します。
中継機モードで多段中継を行う ときには、2
-63
とすることで中継機のレイヤを指定できます。
A
:中継先中継機モードで静的ルーティングを行う ときに接続する上位段の端末のシリアルID(0x8???????
)を指定します。このとき、0x00000000
とした場合は自動検索します。
オプションビットの詳細 オプションビットの値の各ビットに紐付いた設定を解説します。
00000200
:UART代替設定の有効化b
:UART代替設定 を有効とします。
00000400
:定期送信パケットの出力を停止超簡単!標準アプリとリモコンアプリの1秒毎の定期送信と連続モード時のUART出力を停止します。
00001000
:暗号化通信の有効化暗号化通信を有効にします。相手側の暗号化通信も有効化する必要があります。
00002000
:暗号化通信時の平文受信を有効化暗号化通信を有効とした際に、暗号化していないパケットも受信するようにします。
1.3.3 - リモコンアプリ マニュアル デジタル信号の伝送
デジタル信号の伝送に特化したファームウェアです。超簡単!標準アプリと比較して豊富な機能を備えています。
1.3.3.1 - リモコンアプリ マニュアル 最新版
導入方法 リモコンアプリ(App_IO
)を導入するには TWELITE STAGE SDK をインストールして、TWELITE STAGE アプリを使って書き換え てください。[アプリ書換] → [TWELITE APPSビルド&書換] → [App_IO]を選択します。
機能 12個までのスイッチ等の接点入力を無線送信できます。
超簡単!標準アプリ(App_Twelite
)との違いは次の通りです。
ポート数が増加し、最大12ポートを使用できる 入出力の割り当ては4種類(12:0, 8:4, 6:6, 0:12) 外部配線で周波数チャネルを4種類から選択できる。 通信を暗号化できる 特定の相手とのみ通信できる(アプリケーションIDの自動設定) 1.3.3.1.1 - リモコンアプリのピン配置 リモコンアプリが使用するピンの機能
TWELITE / TWELITE DIP リモコンアプリが使用するピンの機能を、下図の超簡単!標準アプリのピン 名を使って表します。
超簡単!標準アプリのピン配置表
電源入力 VCC
/GND
には、3.3V(2.0-3.6V)の電源を接続します。
デジタル入出力 子機:12入力0出力/親機:12出力0入力 デフォルトの入出力の割り当て。
名称 子機 親機 標準 DIP # I1
/O5
I1
O5
DI1
15 I2
/O6
I2
O6
DI2
16 I3
/O7
I3
O7
DI3
17 I4
/O8
I4
O8
DI4
18 I5
/O1
I5
O1
DO1
5 I6
/O2
I6
O2
DO2
8 I7
/O3
I7
O3
DO3
9 I8
/O4
I8
O4
DO4
12 I9
/O9
I9
O9
SCL
2 I10
/O10
I10
O10
SDA
19 I11
/O11
I11
O11
PWM1
4 I12
/O12
I12
O12
PWM4
11
子機:8入力4出力/親機:8出力4入力 オプションビット:0x00001000
の設定を有効とした場合の入出力の割り当て。
名称 子機 親機 標準 DIP # I1
/O5
I1
I1
DI1
15 I2
/O6
I2
I2
DI2
16 I3
/O7
I3
I3
DI3
17 I4
/O8
I4
I4
DI4
18 I5
/O1
O1
O1
DO1
5 I6
/O2
O2
O2
DO2
8 I7
/O3
O3
O3
DO3
9 I8
/O4
O4
O4
DO4
12 I9
/O9
I5
O5
SCL
2 I10
/O10
I6
O6
SDA
19 I11
/O11
I7
O7
PWM1
4 I12
/O12
I8
O8
PWM4
11
子機:6入力6出力/親機:6出力6入力 オプションビット:0x00002000
の設定を有効とした場合の入出力の割り当て。
名称 子機 親機 標準 DIP # I1
/O5
I1
I1
DI1
15 I2
/O6
I2
I2
DI2
16 I3
/O7
I3
I3
DI3
17 I4
/O8
I4
I4
DI4
18 I5
/O1
O1
O1
DO1
5 I6
/O2
O2
O2
DO2
8 I7
/O3
O3
O3
DO3
9 I8
/O4
O4
O4
DO4
12 I9
/O9
O5
I5
SCL
2 I10
/O10
O6
I6
SDA
19 I11
/O11
I5
O5
PWM1
4 I12
/O12
I6
O6
PWM4
11
子機:0入力12出力/親機:0出力12入力 オプションビット:0x00003000
の設定を有効とした場合の入出力の割り当て。
名称 子機 親機 標準 DIP # I1
/O5
O5
I1
DI1
15 I2
/O6
O6
I2
DI2
16 I3
/O7
O7
I3
DI3
17 I4
/O8
O8
I4
DI4
18 I5
/O1
O1
I5
DO1
5 I6
/O2
O2
I6
DO2
8 I7
/O3
O3
I7
DO3
9 I8
/O4
O4
I8
DO4
12 I9
/O9
O9
I9
SCL
2 I10
/O10
O10
I10
SDA
19 I11
/O11
O11
I11
PWM1
4 I12
/O12
O12
I12
PWM4
11
シリアル入出力 TX
/RX
は、リモコン(UART)の送信と受信に使用します。
3.3V レベルのため、Arduino など 5V レベルで動作するマイコン等と接続する場合はレベル変換を行ってください。
ステータスLED出力 アプリケーションID自動設定時のステータス出力を行う際に使用します。
出力が Lo のとき光るようにしてください(吸い込み方式)。
設定入力 モード設定入力 Mx
ピンを未接続またはGND
へ接続することで、親機、子機、中継機といった動作モードを切り替える ことができます。
代替ボーレート設定入力 BPS
ピンを未接続またはGND
へ接続することで、UART のボーレート(通信速度)を 115200bps 以外の値へ変更 できます。
チャネル設定入力 一時的に周波数チャネルを上書きします。
間欠モードでは、これらのピンをプルアップするか、
無効化 してください。暗電流が発生するおそれがあります。
リセット入力 RST
とGND
との間にプッシュボタンを接続することで、リセットボタンを実装できます。RST
は内部プルアップされています。
1.3.3.1.2 - リモコンアプリの動作モード 各動作モードの説明
リモコンアプリ(App_IO)には、6つの動作モードがあります。
動作モードの一覧 各モードは、Mx
ピンを未接続または GND
へ接続することで設定します。
M3
M2
M1
モード 機能 省電力動作 LID初期値 O O O 子機:連続 入力状態を親機へ送信するほか、常に受信データを待機して出力へ反映します 120
O O G 親機:連続 入力状態を子機へ送信するほか、常に受信データを待機して出力へ反映します 0
O G O 中継機:連続 常に受信データを待機して中継します 122
O G G 子機:連続0.03秒 頻繁に入力状態を親機へ送信するほか、常に受信データを待機して出力へ反映します 123
G O O 子機:間欠1秒 1秒おきに入力状態を親機へ送信するほか、受信を無効化して常に節電モードへ入ります ✅ 124
G G O (ペアリングモード) 詳細 G G G 子機:間欠10秒 10秒おきに入力状態を親機へ送信するほか、受信を無効化して常に節電モードへ入ります ✅ 127
O:未接続(OPEN)、G:GND
へ接続
初期状態は子機:連続モードです。
モードによって端末を識別するための論理デバイスID(LID)の初期値は異なります。
親機または中継機モードに限り、インタラクティブモード で切り替えできます。
親機は121
、中継機は122
としてください。
親機 連続モード 親機:連続モード 信号入力の変化を検知したとき、また1秒おきに、すべての子機へデータを送信します。
また子機から送信されるデータを常時待機しており、反応がよいものの、常に電力を消費します。
子機 連続モード 子機:連続モード 信号入力の変化を検知したとき、また1秒おきに、すべての親機へデータを送信します。
また親機から送信されるデータを常時待機しており、反応がよいものの、常に電力を消費します。
親機との通信のイメージ
定期送信の無効化 インタラクティブモードでオプションビット 0x00000020
を設定することで、1秒おきの定期送信を無効化できます。
子機:連続0.03秒モード 子機:連続モードの定期送信の間隔は1秒ですが、これを0.03秒に短縮するモードです。
親機から送信されるデータを常時待機しているものの、子機から親機への通信で帯域を占有してしまうため、親機の入力に対する反応は鈍くなってしまいます。常に電力を消費します。
親機との通信のイメージ
1台の子機だけでほとんどの帯域を占有してしまうため、同時に複数の子機を使用することはなるべく避けてください。
間欠モード 子機:間欠1秒モード 信号入力の変化を検知したとき、また1秒おきに節電モードを解除し、すべての親機へデータを送信します。
受信機能を無効とするため、親機の制御を受けることはできません。省電力性能に優れたモードです。
親機との通信のイメージ
子機:間欠10秒モード 信号入力の変化を検知したとき、また10秒おきに節電モードを解除し、すべての親機へデータを送信します。
受信機能を無効とするため、親機の制御を受けることはできません。省電力性能に優れたモードです。
親機との通信のイメージ
中継機 連続モード 中継機:連続モード 中継機は、受信したパケットを送信します。
親機と子機の間に3つまで設置できますが、中継機を増やすとパケットの数が増大するため、干渉しやすくなることに注意してください。
中継のイメージ
1.3.3.1.3 - リモコンアプリの代替ボーレート設定 UART 通信に使用するボーレート設定の変更
リモコンアプリ(App_IO)はデフォルトで 115200 bps のボーレートを UART 通信に使用しますが、これを変更できます。
代替ボーレート設定の有効化 BPS
ピンを GND
へ接続することで、代替ボーレート設定を有効化できます。
BPS
内容 ボーレート 備考 O デフォルト 115200bps G 上書き設定 38400bps 変更 可
O:未接続(OPEN)、G:GND
へ接続
インタラクティブモードのボーレート設定は、代替ボーレートの値を示しています。BPS
ピンが GND
に接続されていないと、インタラクティブモードの設定値は適用されません。
インタラクティブモードは、UART 通信を利用します。TWELTIE のボーレートを切り替えた際は、インタラクティブモードを使用する前に PC 側のボーレートを合わせなくてはなりません(
TWELITE STAGE アプリの設定変更 )。
1.3.3.1.4 - リモコンアプリのUART機能 UART機能で利用するデータ形式
リモコンアプリ(App_IO)の UART 機能で使用するデータ形式を解説します。
デジタル入出力 0x81
:相手端末からの状態通知受信した入力信号の状態を出力します。
データ形式 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信元の論理デバイスID 1 uint8
コマンド番号 0x81
のみ2 uint8
パケット識別子 0x0F
のみ3 uint8
プロトコルバージョン 0x01
のみ4 uint8
LQI 0
-255
5 uint32
送信元のシリアルID 0x8???????
9 uint8
送信先の論理デバイスID 10 uint16
タイムスタンプ 1秒で64カウント、MSBは内部フラグ 12 uint8
中継回数 13 uint16
デジタル信号 LSBから順にIx
へ対応、0
がHigh 15 uint16
デジタル信号マスク LSBから順にIx
へ対応、1
なら有効 17 uint16
デジタル信号フラグ LSBから順にIx
へ対応、1
なら割り込み 19 uint8
未使用 内部管理用 uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
出力データの例
:01810F01DB8630000200645F000040004F00400049
上記データの解釈 # データ 内容 値 :
char
ヘッダ :
01
0 uint8
送信元の論理デバイスID 0x78
81
1 uint8
コマンド番号 0x81
0F
2 uint8
パケット識別子 0x15
01
3 uint8
プロトコルバージョン 0x01
DB
4 uint8
LQI 219/255
86300002
5 uint32
送信元のシリアルID 0x6300002
00
9 uint8
送信先の論理デバイスID 0x00
645F
10 uint16
タイムスタンプ 約401
秒 00
12 uint8
中継回数 0
0040
13 uint16
デジタル信号 I7
がLo004F
15 uint16
デジタル信号マスク I7
,I1
-I4
が有効0040
17 uint16
デジタル信号フラグ I7
は割り込みにより変化00
19 uint8
未使用 49
uint8
チェックサム 0x49
char
フッタ \r
char
フッタ \n
0x80
:相手端末の出力変更相手端末の出力信号を制御します。
データ形式 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信先の論理デバイスID 親機0x00
,子機0x01
-0x64
,全子機0x78
1 uint8
コマンド番号 0x80
のみ2 uint8
書式バージョン 0x01
のみ3 uint16
デジタル信号 LSBからOx
に対応、0
でHigh 5 uint16
デジタル信号マスク LSBからOx
に対応、1
で有効 7 uint16
未使用 0
9 uint16
未使用 0
11 uint16
未使用 0
13 uint16
未使用 0
uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
親機・中継機アプリはこの書式に対応していません。リモコンアプリの親機のみ対応しています。
UART 入出力 1.3.3.1.5 - リモコンアプリのカスタムデフォルト機能 デフォルトの設定を変更したファームウェアの作成
カスタムデフォルト機能によって、ファームウェアに含まれるデフォルトのパラメータを変更できます。
例えば、ボーレートを 115200bps から 9600bps へ変更したファームウェアを作成しておけば、最初から 9600bps で使用できます。
設定手順 1. 設定を適用 インタラクティブモード の設定を変更し、S
を押下して保存します。
2. 設定内容をダウンロード xmodem プロトコルのデータをダウンロードできるソフトウェアを用意します。
xmodem の仕様はチェックサム/128バイトパケットです。拡張された 1KB や CRC の形式は使用しません。
再度インタラクティブモードへ入った状態(項目を選ぶ前の状態)として、xmodem のダウンロードを要求します。
TeraTerm では、次の操作を行います。
ファイル > 転送 > XMODEM > 受信...
を選択Option > Checksum, Binary
を選択ファイル名を指定(例:conf.bin
) 開く
ボタンを押下
macOS や Linux 等では、lrzsz
を利用できます。
lrx --binary --xmodem /path/to/conf.bin
通常は screen
でインタラクティブモードへ入り、Ctrl+A
の押下後 :exec !! lrx -b -X /path/to/conf.bin
を実行します
ダウンロードに成功すると、128バイトのファイルを生成します(xmodem の実装によっては、小さいサイズになることもあります)。
3. カスタムバイナリの作成 ダウンロードしたファイルをファームウェアのバイナリファイルの末尾へ連結し、カスタムバイナリを作成します。
連結には、コマンドラインツールや汎用のファイル連結ツールを使用してください。
実行例 ダウンロードした xmodem のファイルを conf.bin
、元のバイナリファイルをApp_IO_BLUE_L1305_V1-3-X.bin
、作成するカスタムバイナリをApp_IO_custom_V1-3-X.bin
とした場合の例を示します。
【Windows】
copy App_IO_BLUE_L1305_V1-3 -X.bin App_IO_custom_V1-3 -X.bin
type conf.bin >> App_IO_custom_V1-3 -X.bin
【macOS / Linux】
cat App_IO_BLUE_L1305_V1-3-X.bin conf.bin > App_IO_custom_V1-3-X.bin
4. カスタムバイナリの書き込み 連結したカスタムバイナリを TWELITE へ書き込みます。
カスタムバイナリを書き込んでからインタラクティブモードへ入ると、最初の行の末尾に C-
を表示します。
--- CONFIG/APP_IO V1-04-2/SID=0x81001f1c/LID=0x78 C- ---
カスタムバイナリに対してインタラクティブモードから設定を上書きして保存すると、C-
の代わりにCE
と表示します。
--- CONFIG/APP_IO V1-04-2/SID=0x81001f1c/LID=0x78 CE ---
1.3.3.1.6 - リモコンアプリのペアリング機能 アプリケーションIDの自動設定による親機と子機のグループ化
リモコンアプリ(App_IO)には、インタラクティブモードを使わずに親機と子機のグループを作成する機能があります。
「ペアリング」といっても、Bluetooth のペアリングとは異なります。
あくまでもアプリケーションIDを共有するだけであり、同報通信の仕組み は変わりません。
設定方法 親機のシリアルIDに基づいたアプリケーションIDを生成し、それを子機へ流し込むことでグループを作成します。LED
ピンへ LED を接続すると、設定の成否を確認できます。
接続の様子
親機と子機の LED
へ LED と 電流制限抵抗(680Ω)を接続する(吸い込み) M1
を開放したまま、M2
とM3
をGND
へ接続する親機の電源を入れて、LED の点滅を確認する 5秒以内に親機の近くで子機の電源を入れ、LED が消灯することを確認する(失敗すると点灯) 1.3.3.1.7 - インタラクティブモード(リモコンアプリ) インタラクティブモードによる設定変更
インタラクティブモードでアプリの詳細設定を行うことができます。
ここではリモコンアプリ(App_IO)に固有の機能を説明します。共通機能については、TWELITE APPS マニュアル のトップページ を参照してください。
TWELITE がスリープしている間はインタラクティブモードを使用できません。
M3
ピン をGND
へ接続していないことを確認してください。
表示例 次のような画面を表示します。
--- CONFIG/APP_IO V1-03-2/SID=0x86300001/LID=0x00 ---
a: set Application ID (0x67720107)
i: set Device ID (--)
c: set Channels (16)
x: set Tx Power (3)
t: set mode4 sleep dur (1000ms)
y: set mode7 sleep dur (0s)
f: set mode3 fps (16)
d: set hold mask (000000000000)
D: set hold dur (1000ms)
o: set Option Bits (0x00000000)
b: set UART baud (38400)
p: set UART parity (N)
C: set crypt mode (0)
K: set crypt key []
---
S: save Configuration
R: reset to Defaults
コマンド 各コマンドの詳細を次に示します。
a
:アプリケーションID通信を行う端末はすべて同一の値とします。論理的にネットワークを分離します。
i
:論理デバイスID複数の子機を識別する必要がある場合に設定します。
識別の必要がない、できない場合は120
としてください。識別の必要がある場合は、子機は1
-100
の任意の値に、親機は0
あるいは121
としてください。
c
:周波数チャネル通信を行う端末はすべて同一の値とします。物理的にネットワークを分離します。
x
:送信出力と再送回数電波の送信出力と、透過モードおよびヘッダ付き透過モードにおいてパケットを追加で送信する回数を指定します。
t
:子機間欠1秒モードの間隔子機間欠1秒モードの間欠時間を1秒から他の値へ上書きします。単位はミリ秒です。
0
を設定した場合は、タイマによる定期的な起床を無効化します。このときIx
の立ち下がりエッジにより起床しますが、立ち上がりエッジでは起床しません。
y
:子機間欠10秒モードの間隔子機間欠10秒モードの間欠時間を10秒から他の値へ上書きします。単位は秒です。
0
を設定した場合は、タイマによる定期的な起床を無効化します。このときIx
の立ち下がりエッジにより起床しますが、立ち上がりエッジでは起床しません。
f
:子機連続0.03秒モードのサイクル毎秒の送信リクエストの数を32回から4
/8
/16
回へ上書きします。再送回数は含みません。
d
:ホールド/長押しモードの対象初期状態ではホールドモードの、オプションビット0x00000100
を有効としたときはリモコン長押しモードの対象とするポートを選択します。
設定値には、対象とするIx
またはOx
のビットマスクを指定します。値は12文字までの0
または1
で構成します。LSBから順に I1
I2
… I12
と並びます。
例えば 000000001010
を指定すると、I2
とI4
にホールドモードを適用できます。任意のピンを対象とした場合、対象としていないポートからは50msのパルスを出力します。
ホールドモード ホールドモードの場合、対象としたポートは次のように振るまいます。
入力(送信)側:Ix
すべての入力がLoからHiへ戻ったあと、設定した時間 にわたり連続して送信します(ホールド解除のため) 出力(受信)側:Ox
受信した入力のうち、Loであるものに対しては、設定した時間 にわたり出力をLoのままホールドします いずれかの出力のホールド中に再び入力がLoの信号を受信した際は、ホールドする期間を延長します リモコン長押しモード リモコン長押しモードの場合、対象としたポートは次のように振るまいます。
入力(送信)側:Ix
いずれかの入力がLoである間、連続して送信します すべての入力がLoからHiへ戻ったあと、設定した時間 にわたり連続して送信します 出力(受信)側:Ox
いずれかの入力がLoであるパケットが断絶してから設定した時間 が経過すると、出力をHiへ戻します D
:ホールド/長押しモードの時間初期状態ではホールドモードを、オプションビット0x00000100
を有効としたときはリモコン長押しモードのホールド時間や送信間隔といった値を指定することができます。
20
-64000
ms の値を指定できます。
ホールドモード ホールドモードの場合、設定した時間は次のように適用されます。
入力(送信)側:Ix
連続モードでは、すべての入力がLoからHiへ戻ったあとに連続して送信する時間を指定します。
間欠モードでは、いずれかの入力がLoである間の送信間隔を指定します。
出力(受信)側:Ox
出力を維持する時間を指定します。
リモコン長押しモード リモコン長押しモードの場合、設定した時間は次のように適用されます。
入力(送信)側:Ix
すべての入力がLoからHiへ戻ったあとに連続して送信する時間を指定します。
出力(受信)側:Ox
いずれかの入力がLoのパケットが断絶してからすべての出力をHiへ戻すまでの時間を指定します。
o
:オプションビット32bit の数値を指定します。各ビットに紐付いた設定を有効化できます。
b
:UART代替ボーレートBPS
ピンをGND
へ接続して起動した場合に選択される代替ボーレートを38400
bpsから上書きします。
値は9600
/19200
/38400
/57600
/115200
/230400
から選択できます。他の値を指定すると、誤差が生じる可能性があります。
BPS
ピンを開放して起動した場合、この設定は適用されません。115200
bpsに固定されます。
B
:UARTパリティN
: 無し、O
: Odd(奇数)、E
: Even(偶数)のいずれかを設定します。ストップビットは1
のみ、ハードウェアフローは設定不可です。
C
:暗号化暗号化機能の有無を指定します。
AES128bitの暗号化を有効とするには、1
を指定してください。
K
:暗号鍵暗号化に用いる鍵を入力します。16文字のテキストを指定します(バイナリ列は指定できません)。
オプションビットの詳細 オプションビットの値の各ビットに紐付いた設定を解説します。
0x00000001
:低レイテンシモード低レイテンシモードで入力状態の監視と無線送信を行います。
ボタン監視の時間を短縮し、送信遅延を最小にします。また、連続モードでは入力の判定に割り込みを使用しますが、チャタリングの影響を受けやすくなります。間欠モードでは、入力状態の確定までの時間を短縮します。
子機のみ有効です。
0x00000002
:低レイテンシモード(スリープ割り込み)間欠モード時にスリープ復帰要因がIx
のHiからLoへの割り込みであったとき、割り込み要因のポート情報を速やかに送信します。
特に子機間欠10秒モードにおいて、定期起床を無効としたとき、ボタンの押し下げを検出するためにホールドモードと合わせて利用します。
子機のみ有効です。
0x00000010
:ACKつき送信の有効化子機から ACK を有効とした通信を行います。親機が ACK を返した時点で送信は終了します。
複数台の親機やすべての中継機は利用できませんが、親機と安定して通信できる環境では効率のよい通信を実現できます。
子機間欠10秒モードの場合、BPS
ピンが出力ピンとして設定されるため、子機側のボーレートの上書きはできません。
0x00000020
:定期送信の無効化子機連続モードにおける1秒おきの定期送信を無効化します。
0x00000100
:リモコン長押しモードの有効化ホールドモードの代わりに、リモコン長押しモードを適用します。
0x00000200
:C1
/C2
チャネル切り替えの無効化C1
/C2
ピンによるチャネル切り替え機能を停止します。
0x00000400
:Ix
の入力を反転入力が Hi のとき1
を、Lo のとき0
を送信します。
デフォルトでは、プルアップを想定しているため、入力が Hi のとき0
を、 Lo のとき1
を送信します。
0x00000800
:Ix
の内部プルアップを停止Ix
の内部プルアップ(約50kΩ)をすべて停止します。
起動してからハードウェアの初期化を完了するまでの約1msの期間はプルアップされます。
0x00001000
:子機:8入力4出力/親機:8出力4入力入出力ポートの割り当てを「子機:12入力0出力/親機:12出力0入力」から変更します。間欠モードでは間欠受信を行います。
0x00002000
:子機:6入力6出力/親機:6出力6入力入出力ポートの割り当てを「子機:12入力0出力/親機:12出力0入力」から変更します。間欠モードでは間欠受信を行います。
0x00003000
:子機:0入力12出力/親機:0出力12入力入出力ポートの割り当てを「子機:12入力0出力/親機:12出力0入力」から変更します。間欠モードでは間欠受信を行います。
0x00010000
:子機の受信を強制的に有効化連続モードのとき、出力ポートの有無に関わらず強制的に受信を有効化します。
他の端末から受信したデータのUART出力を実現できます。
0x00020000
:入出力変化時のUART出力の停止入出力変化時のメッセージ出力を停止します
0x00040000
:C2
のウォッチドッグ出力を有効化C2
ポートからウォッチドッグ出力を行います。
アプリケーションループでIOを制御し、約32Hzの矩形波を出力します。
モジュールのハングアップに備えて、自動復帰のために外部のリセット回路を接続し、モジュールを強制的にリセットする際に使用します。
0x00400000
:Ox
の出力を反転受信した入力ポートの状態が 0
のとき Lo を、1
のとき Hi を出力します。
デフォルトでは、プルアップを想定しているため、受信した入力ポートの状態が 0
のとき Hi を、1
のとき Lo を出力します。
1.3.4 - シリアル通信アプリ マニュアル シリアル通信の無線化
シリアル通信(UART)の無線伝送に特化したファームウェアです。超簡単!標準アプリと比較して豊富な機能を備えています。
1.3.4.1 - シリアル通信アプリ マニュアル 最新版
工場出荷時の TWELITE UART へインストールされています。
ダウンロード シリアル通信アプリ(App_Uart
)を導入するには TWELITE STAGE SDK をインストールして、TWELITE STAGE アプリを使って書き換え てください。
1.3.4.1.1 - シリアル通信アプリのピン配置 シリアル通信アプリが使用するピンの機能
以下の情報は、App_Uart v1.2 以降を対象としています。
TWELITE / TWELITE DIP シリアル通信アプリが使用するピンの機能を、下図の超簡単!標準アプリのピン 名を使って表します。
超簡単!標準アプリのピン配置表
電源入力 VCC
/GND
には、3.3V(2.0-3.6V)の電源を接続します。
シリアル入出力 TX
/RX
は、シリアル通信(UART)の送信と受信に使用します。
3.3V レベルのため、Arduino など 5V レベルで動作するマイコン等と接続する場合はレベル変換を行ってください。
シリアル副入出力 TX_SUB
(SCL
)/RX_SUB
(SDA
)は、シリアル入出力の副ポートとして利用できます。
シリアル入力許可 RTS
(PWM1
)が Low レベルのときは、RX
へのシリアル入力を受け付けていることを示します。
Hi レベルのときにRX
への入力を抑制することで、取りこぼしを防ぐことが期待されます。
親機/子機の選択 M1
をGND
へ接続すると親機、開放またはVCC
へ接続すると子機として使用できます。
インタラクティブモードによる設定 この接続を省略し、インタラクティブモードから設定することもできます。
子機へ中継機能を付与 M2
を子機設定のときにGND
へ接続することで、中継機能を付与できます。
インタラクティブモードによる設定 この接続を省略し、インタラクティブモードから設定することもできます。
スリープ M3
をGND
へ接続すると、本体をスリープさせることができます。
動作モードの上書き EX1
を起動時に GND
へ接続しておくことで、動作モードを書式モード(バイナリ)へ上書きできます。
代替ボーレート設定の有効化 BPS
をGND
へ接続することで、インタラクティブモードで指定した代替ボーレート設定を有効化できます。
リセット入力 RST
とGND
との間にプッシュボタンを接続することで、リセットボタンを実装できます。RST
は内部プルアップされています。
TWELITE UART シリアル通信アプリが使用するピンの機能を、基板に記載された7Pインタフェース(下図の②)のピン名を使って表します。
基板アンテナタイプ
同軸コネクタタイプ
電源入力 VCC
/GND
には、3.3V(2.0-3.6V)の電源を接続します。
シリアル入出力 TX
/RX
は、シリアル通信(UART)の送信と受信に使用します。
Arduino など 5V レベルで動作するマイコンと接続する場合は、レベル変換してください。
動作モードの上書き SET
を起動時に GND
へ接続することで、動作モードを書式モード(アスキー)へ上書きできます。
リセット入力 RST
とGND
との間にプッシュボタンを接続することで、リセットボタンを実装できます。RST
は内部プルアップされています。
1.3.4.1.2 - シリアル通信アプリの通信モード 各通信モードの説明
シリアル通信アプリ(App_Uart)には、5つの通信モードがあります。
通信モードの一覧 各モードは、インタラクティブモードによって切り替えます(一部のモードはピン入力にて設定可能)。
初期状態はヘッダ付き透過モード です。
モードに関わらず、送信データは80バイト以内としてください パケットサイズの制約から、一度に送るデータはバイナリ換算で80バイト以内に収めてください。
TWELITE が採用する IEEE 802.15.4 のパケットの最大長は128バイトであり、オーバーヘッドを考慮するとシリアル通信アプリのペイロードに使用できる領域は80バイトに限られます。
大量のデータを送信する場合は、Wi-Fi などを利用した他社製品をご検討ください。TWELITE は少ないデータを効率よく送る用途に適しています。
A
:書式モード(アスキー)送信側の端末へ特定の書式に従ったデータを入力すると、受信側の端末も特定の書式に従ったデータを出力します。
16進数で表すデータはアスキー文字列で表現します。
送信側の入力 受信側の出力 簡易形式/拡張形式のデータ → 簡易形式/拡張形式のデータ
TWELITE UART では、SET
ピンを GND
へ接続して起動すると本モードが有効となります。
データを表現する形式は2種類あります。
簡易形式:論理デバイスIDだけを使用。超簡単!標準アプリのUART伝送機能と互換性あり 拡張形式:論理デバイスIDに加えて、シリアルIDや再送回数などの送信オプションを使用できる 例えば、5バイトのバイナリデータ 0x48 0x45 0x4C 0x4C 0x4F
は、簡易形式を使って次のように送信できます。
【送信側】
:000148454C4C4F8B <- 入力
:DBA1800103 <- 出力
【受信側】
書式モードでは、アプリケーションIDなどの設定をインタラクティブモードだけでなく UART によるコマンド(アスキー形式 )によって動的に適用できます。
B
:書式モード(バイナリ)送信側の端末へ特定の書式に従ったデータを入力すると、受信側の端末も特定の書式に従ったデータを出力します。
16進数で表すデータはそのままバイナリ形式で表現します。
送信側の入力 受信側の出力 簡易形式/拡張形式のデータ → 簡易形式/拡張形式のデータ
TWELITE / TWELITE DIP では、EX1
ピンを GND
へ接続して起動すると本モードが有効となります。
書式モード(アスキー)と同様に、データを表現する形式は2種類あります。
例えば、5バイトのバイナリデータ 0x48 0x45 0x4C 0x4C 0x4F
は、簡易形式を使って次のように送信できます。
【送信側】
0xA5 0x5A 0x00 0x07 0x00 0x01 0x48 0x45 0x4C 0x4C 0x4F 0x43 0x04 <- 入力
0xA5 0x5A 0x00 0x04 0xDB 0xA1 0x80 0x01 0xFB 0x04 <- 出力
【受信側】
0xA5 0x5A 0x00 0x07 0x78 0x01 0x48 0x45 0x4C 0x4C 0x4F 0x3B 0x04 <- 出力
書式モードでは、アプリケーションIDなどの設定をインタラクティブモードだけでなく UART によるコマンド(バイナリ形式 )によって動的に適用できます。
C
:チャットモードテキストチャットを実現します。
送信側の入力 受信側の出力 任意の文字列 → 補助情報+任意の文字列
プロンプトの表示とエコーバック(入力した文字の出力)を行います。すべての端末は子機として、同報通信を行います。
例えば、ある端末から他の端末へ Hello
という文字列を送信する場合は、次のように振る舞います。
【送信側】
810A4778:0> Hello <- 入力
810A4778:1> <- 出力
【受信側】
[810A4778:0] Hello <- 出力
82018CA0:0> <- 出力
上記の例ではプロンプトにシリアルIDを表示していますが、任意のハンドル名を使用することもできます。
D
:透過モード送信側の端末へ任意のデータを入力すると、受信側の端末は受信したデータをそのまま出力します。
送信側の入力 受信側の出力 任意のデータ → 任意のデータ
書式を必要としないため、既存の UART 通信を簡単に無線化できます。
一方で、データの区切りがあいまいになってしまうほか、受信側の出力から送信元を判別できないといった欠点があります。
初期状態では、送信側へ入力されたデータをCRLFで区切り、CRLF よりも前のデータを送信します。
例えば、送信側の端末へ Hello<Enter>
と入力すると、受信側の端末はそのまま Hello
を出力します。
【送信側】
【受信側】
E
:ヘッダ付き透過モード送信側の端末へ任意のデータを入力すると、受信側の端末は受信した内容に特定の書式で補助情報を付加したデータを出力します。
送信側の入力 受信側の出力 任意のデータ → 任意のデータ+補助情報
初期状態では、送信側へ入力されたデータをCRLFで区切り、CRLF よりも前のデータを送信します。
例えば、送信側の端末へ Hello<Enter>
と入力すると、受信側の端末は補助情報を含んだ書式で Hello
を出力します。送信側の端末も送信完了といったメッセージを伝える書式を出力します。
【送信側】
Hello <- 入力
;U;00004;219;0x820163B2;000;000;0,1,Hel...;6E; <- 出力
【受信側】
;U;00003;000;0x820163B2;255;000;Hello;42; <- 出力
受信側が出力する補助情報は、送信元のアドレスや受信時の電波強度、チェックサム等を含みます。補助情報の書式はカスタマイズできます。
1.3.4.1.2.1 - シリアル通信アプリの書式モード(アスキー形式) 送受信双方の出力にヘッダを付加するモード(アスキー形式)
書式モードは、送受信双方の出力にヘッダを付加します。アスキー形式では、データを16進数の文字列で表します。
概要 送信側の端末へ特定の書式に従ったデータを入力すると、受信側の端末も特定の書式に従ったデータを出力します。
データは16進数のアスキー文字列で表現します。
送信側の入力 受信側の出力 簡易形式/拡張形式のデータ → 簡易形式/拡張形式のデータ
TWELITE UART では、SET
ピンを GND
へ接続して起動すると書式モード(アスキー)が有効となります。 TWELITE / TWELITE DIP では、EX1
ピンを GND
へ接続して起動すると書式モード(バイナリ)が有効となります。 扱うことのできる書式の形式は2種類あります。
簡易形式:論理デバイスIDだけを使用する。超簡単!標準アプリのUART伝送機能と互換性あり 拡張形式:論理デバイスIDに加えて、シリアルIDや再送回数などの送信オプションを使用できる 例えば、5バイトのバイナリデータ 0x48 0x45 0x4C 0x4C 0x4F
は、簡易形式を使って次のように送信できます。
【送信側】
:000148454C4C4F8B <- 入力
:DBA1800103 <- 出力
【受信側】
基本の書式 基本形式や拡張形式で表現したデータ列を送信するときは、アスキー文字列(0-9,A-F)へ変換します。
書式は超簡単!標準アプリ(App_Twelite)や親機・中継機アプリ(App_Wings)の親機の出力と同様に、:
で始まりCRLFで終わります。
ヘッダ ペイロード チェックサム フッタ :
00
-FF
の繰り返しペイロードのLRC8 CRLF
すべて ASCII 文字 先頭は :
(0x3A
) チェックサムはペイロードの合計の2の補数 末端は CRLF (\r\n
/0x0D 0x0A
) ビッグエンディアン 例えば、バイナリデータ 0x00 0x11 0x22 0x33 0xAA 0xBB 0xCC
は次のように表現します。
:00112233AABBCC69<CR><LF>
親機と子機の区別 書式モードは、親機と子機を区別します。
親子間では、アプリケーションIDと周波数チャネル を合わせる必要があります。
送信元の判別 書式モードでは、受信したデータから送信元を判別できます。
簡易形式の書式では論理デバイスIDを、拡張形式の書式では論理デバイスIDに加えて拡張アドレスを利用します。
拡張アドレスは、TWELITE 本体に記載された7ビットのシリアルIDの先頭へ0x8
を付加したものです。
簡易形式の書式 書式モードの簡易形式を利用する場合は、次の書式に従います。
送信側の入力 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信先の論理デバイスID 親機0x00
,子機0x01
-0x64
,全子機0x78
1 uint8
コマンド番号 0x80
未満の任意の値2 [uint8]
任意のデータ 長さ\(N\)のバイト列(\(N\leqq80\)を推奨) uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
受信側の出力 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信元の論理デバイスID 親機0x00
,子機0x01
-0x64
,未設定子機0x78
1 uint8
コマンド番号 送信側で指定した0x80
未満の値 2 [uint8]
任意のデータ 長さ\(N\)のバイト列 uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
送信側の出力(応答メッセージ) # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信元の論理デバイスID 0xDB
のみ:自身を示す1 uint8
コマンド番号 0xA1
のみ2 uint8
応答ID 128
-255
(0x80
-0xFF
)の範囲で続き番号を示す3 uint8
処理結果 成功1
,失敗0
uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
使用例 親機から全子機に対してバイト列 0x11 0x22 0x33 0xAA 0xBB 0xCC
を送信する例を示します。
【送信側:親機】
:7801112233AABBCCF0<CR><LF> <- 入力
:DBA1800103<CR><LF> <- 出力
末尾の0xF0
はチェックサム:0x78
から0xCC
までの合計の2の補数のLSBから8ビット。
【受信側:全子機】
:0001112233AABBCC68<CR><LF> <- 出力
末尾の0x68
はチェックサム:0x00
から0xCC
までの合計の2の補数のLSBから8ビット。
拡張形式の書式 書式モードの拡張形式を利用する場合は、次の書式に従います。
送信側の入力 送信先の指定に論理デバイスIDを使用する場合 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信先の論理デバイスID 親機0x00
,子機0x01
-0x64
,全子機0x78
1 uint8
コマンド番号 0xA0
のみ2 uint8
応答ID 任意の値 3 [uint8]
オプション 長さ\(N\)のオプション列 3+\(N\) [uint8]
任意のデータ 長さ\(M\)のバイト列(\(M\leqq80\)を推奨) uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
送信先の指定に拡張アドレスを使用する場合 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
拡張アドレスの指定 0x80
のみ1 uint8
コマンド番号 0xA0
のみ2 uint8
応答ID 任意の値 3 uint32
送信先の拡張アドレス シリアルIDの先頭へ0x8
を加えた値 7 [uint8]
オプション 長さ\(N\)のオプション列 7+\(N\) [uint8]
任意のデータ 長さ\(M\)のバイト列(\(M\leqq80\)を推奨) uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
オプション列の詳細 拡張形式では、オプション列を指定することで細かな設定を行うことができます。
オプション列は、オプションのIDと引数の繰り返しで表現します。終端は 0xFF
とします。
オプションを指定しない場合は0xFF
の1バイトだけを指定します。
入力後1秒が経過すると、送信処理はタイムアウトします。また、内部のバッファが処理待ちで埋まってしまい、新しい要求を受け付けることができない場合があります。アプリケーション再送や遅延を設定する場合は、極端な値に設定しないように注意してください。
0x01
:MAC ACKの有効化MAC層のACK(確認応答)を有効化します。
頻繁にデータを送信する場合には適しませんが、信頼性を向上できる場合があります。
中継機は利用できません。また、送信先を全子機(0x78
)とするときは利用できません。
0x02
:アプリケーション再送の有効化MAC ACK を使用するときは、0x00
-0x0F
を指定します。送信に成功するまで、それぞれ0-16回の再送を行います。
MAC ACK を使用しないときは、0x81
-0x8F
を指定します。必ず1-16回の再送を行います。
応答メッセージは、すべての再送が終了してから出力します。
0x03
:初回送信の遅延の最小値初回送信までの遅延の最小値をミリ秒で指定できます。
0x04
:初回送信の遅延の最大値初回送信までの遅延の最大値をミリ秒で指定できます。
0x05
:アプリケーション再送の間隔アプリケーション再送を有効化した際の再送間隔をミリ秒で指定します。
0x06
:平行要求の許可平行要求を許可します。
平行要求を許可すると、要求を完了するまでブロックせず、次の要求処理を受け付けることができるようになります。
例えば 0.5 秒の遅延を設定した要求を3回連続して入力した場合、初期状態では 0.5 秒後、1.0秒後、1.5秒後と順番に処理します。ところが、平行要求を許可した場合は、0.5秒後に順不同で送信要求を処理します。なおパケット分割を必要とする場合は使用できません。
受信側の端末は、常に新しいデータを採用します。平行要求を許可していると、新しいデータのあとに古いデータが届き、古いデータが無視されてしまうことがあります。
0x07
:応答メッセージの無効化送信側へデータを入力した際に出力される応答メッセージを無効とします。
0x08
:送信後スリープ送信後、速やかに本体をスリープさせます。
RX
が立ち上がりエッジを検知すると、スリープから復帰します。何か1バイトのデータを入力してください。
スリープ復帰後、UART の初期化が終わると入力を受け付けます。
受信側の出力 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信元の論理デバイスID 親機0x00
,子機0x01
-0x64
,未設定子機0x78
1 uint8
コマンド番号 0xA0
のみ2 uint8
応答ID 送信側で指定した値 3 uint32
送信元の拡張アドレス シリアルIDの先頭へ0x8
を加えた値 7 uint32
送信先の拡張アドレス 論理デバイスID使用時は0xFFFFFFFF
11 uint8
LQI 受信時の電波通信品質 12 uint16
続くバイト列の長さ バイト数\(M\)を表す 14 [uint8]
任意のデータ 長さ\(M\)のバイト列 uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
送信側の出力(応答メッセージ) # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信元の論理デバイスID 0xDB
のみ:自身を示す1 uint8
コマンド番号 0xA1
のみ2 uint8
応答ID 入力時に指定した値 3 uint8
処理結果 成功1
,失敗0
uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
使用例 親機から子機に対してバイト列 0x11 0x22 0x33 0xAA 0xBB 0xCC
を送信する例を示します。
論理デバイスIDを指定する例 親機から論理デバイスID0x42
の子機へ送信する例を示します。
応答IDは0x01
オプションなし 親機の拡張アドレスは0x81000000
(シリアルID0x1000000
) 【送信側:親機】
:42A001FF112233AABBCC87<CR><LF> <- 入力
:DBA1010182<CR><LF> <- 出力
末尾の0x87
はチェックサム:0x42
から0xCC
までの合計の2の補数のLSBから8ビット。
【受信側:子機】
:00A00181000000FFFFFFFFC80006112233AABBCC7D<CR><LF> <- 出力
末尾の0x7D
はチェックサム:最初の0x00
から0xCC
までの合計の2の補数のLSBから8ビット。
拡張アドレスを指定する例 親機から拡張アドレス0x81000001
(シリアルID0x1000001
)の子機へ送信する例を示します。
応答IDは0x01
オプションなし 親機の拡張アドレスは0x81000000
(シリアルID0x1000000
) 【送信側:親機】
:80A00181000001FF112233AABBCCC7<CR><LF> <- 入力
:DBA1010182<CR><LF> <- 出力
末尾の0xC7
はチェックサム:0x80
から0xCC
までの合計の2の補数のLSBから8ビット。
【受信側:子機】
:00A0018100000081000001C80006112233AABBCCF7<CR><LF> <- 出力
末尾の0xF7
はチェックサム:最初の0x00
から0xCC
までの合計の2の補数のLSBから8ビット。
MAC ACKを使用する例 親機から論理デバイスID0x42
の子機へ MAC ACK を使用して送信する例を示します。
【送信側:親機】
:42A00101FF112233AABBCC86<CR><LF> <- 入力
:DBA1010182<CR><LF> <- 出力
末尾の0x86
はチェックサム:0x42
から0xCC
までの合計の2の補数のLSBから8ビット。
【受信側:子機】
:00A00181000000FFFFFFFFC80006112233AABBCC7D<CR><LF> <- 出力
末尾の0x7D
はチェックサム:0x00
から0xCC
までの合計の2の補数のLSBから8ビット。
遅延を設ける例 親機から論理デバイスID0x42
の子機へ 768ms の遅延を設けて送信する例を示します。
【送信側:親機】
:42A001030300FF112233AABBCC81<CR><LF> <- 入力
:DBA1010182<CR><LF> <- 出力
末尾の0x81
はチェックサム:0x42
から0xCC
までの合計の2の補数のLSBから8ビット。
【受信側:子機】
:00A00181000000FFFFFFFFC80006112233AABBCC7D<CR><LF> <- 出力
末尾の0x7D
はチェックサム:0x00
から0xCC
までの合計の2の補数のLSBから8ビット。
0xDB
コマンドインタラクティブモードの設定を行う代わりに、UART から 0xDB
コマンドを入力することでモジュールの操作や設定を行うことができます。
1.3.4.1.2.1.1 - シリアル通信アプリ 書式モード(アスキー)の 0xDB コマンド 書式モード(アスキー)におけるインタラクティブモードを使用しない設定機能
書式モードでは、インタラクティブモードの代わりに0xDB
コマンドを使うことで、UART接続されたデバイスから動的に設定を行えます。
入力の書式 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信先の論理デバイスID 自身を示す0xDB
のみ 1 uint8
コマンド番号 後述の値 から選択2 [uint8]
パラメータ 設定値を示す長さ\(N\)のバイト列(オプション) uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
コマンド番号の一覧 0xF0
:ACKの有効化ACK 応答の要求を行います。
パラメータはありません。
応答の書式 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信先の論理デバイスID 0xDB
のみ1 uint8
コマンド番号 0xF0
のみ2 uint8
データ 0x01
のみuint8
チェックサム 0x34
:LRC8char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
0xF1
:端末情報の取得アドレス等の情報を表示します。起動時にも出力されます。
パラメータはありません。
応答の書式 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信先の論理デバイスID 0xDB
のみ1 uint8
コマンド番号 0xF1
のみ2 uint32
アプリケーションID 6 uint32
バージョン番号 1.4.7
なら00010407
10 uint8
論理デバイスID 11 uint32
シリアルID 15 uint8
サイレントモードの状態 有効1
, 無効0
16 uint8
ネットワークの状態 UP1
, DOWN0
uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
0xF2
:端末設定の適用設定を適用します。
適用するパラメータは、
下記に記載 の識別子とデータの組み合わせで構成します。
応答の書式 成功した場合 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信先の論理デバイスID 0xDB
のみ1 uint8
コマンド番号 0xF3
のみ2 [uint8]
設定内容 長さ\(N\)の識別子とデータ の繰り返し uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
失敗した場合 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信先の論理デバイスID 0xDB
のみ1 uint8
コマンド番号 0xF3
のみ2 uint8
エラー 0xFF
のみuint8
チェックサム 0x33
:LRC8char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
0xF3
:端末設定の取得設定を取得します。
取得するパラメータは、
下記に記載 の識別子で構成します。
応答の書式 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信先の論理デバイスID 0xDB
のみ1 uint8
コマンド番号 0xF3
のみ2 [uint8]
設定内容 識別子とデータ の繰り返しuint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
0xF8
:端末の制御起動時にサイレントモードを有効としていた場合に、これを解除します。
応答の書式 # データ 内容 備考 char
ヘッダ :
のみ0 uint8
送信先の論理デバイスID 0xDB
のみ1 uint8
コマンド番号 0xF8
のみ2 uint8
データ 0x11
のみ3 uint8
状態 解除済み1
, 未解除0
uint8
チェックサム LRC8 char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
0xFD
:端末設定の消去設定を初期化し、本体をリセットします。
パラメータおよび応答はありません。
0xFE
:端末設定の保存適用した設定を保存し、本体をリセットします。
パラメータおよび応答はありません。
0xFF
:端末のリセット適用した設定を破棄し、本体をリセットします。
パラメータおよび応答はありません。
パラメータの一覧(0xF2
/0xF3
) 0xF2
:端末設定の適用 および 0xF3
:端末設定の取得 のパラメータは、識別子とデータ(ビッグエンディアン)の繰り返しで表現します。
0x00
:アプリケーションIDアプリケーションIDを指定します。
0x01
:周波数チャネルマスク周波数チャネルのビットマスクを指定します。
使用するチャネルのビットを立てます。例えば、11チャネルを使う場合は1<<11
です。
0x02
:再送回数と出力電波の送信出力と、透過モードおよびヘッダ付き透過モードにおいてパケットを追加で送信する回数を指定します。
下位の1バイトのみを使用します。そのうち上位の4ビットが再送回数(0
-9
)、下位の4ビットが送信出力(0
-3
)です。例えば、8回再送/出力3 であれば 0x0083
です。
0x03
:論理デバイスID論理デバイスIDを指定します。
0x04
:役割子機のみ有効です。以下の値を指定します。通常はネットワーク層を利用しない配送方式を選択してください。
ネットワーク層を利用しない配送方式 0
:通常の指定(親機または子機)1
-3
:中継子機(論理デバイスIDを1
-100
または 120
とします)1
-3
の数値は最大中継段数を指します。最大中継段数まで再送を繰り返す方式のため、中継機の配置や数によっては重複したパケットを中継します。ネットワーク層を利用する配送方式
サイレントモードを有効化するには、上記の数値に80
を足してください。例えば 93
は「ネットワーク層利用かつサイレントモード」です。
0x05
:中継レイヤ中継レイヤの番号です。中継機は中継レイヤ数の上位(より小さい値)の中継機・親機への接続を試みます。役割 を12
としているときにだけ有効です。
0x06
:通信モード0
:透過モード1
:書式モード(アスキー)2
:書式モード(バイナリ)3
:チャットモード4
:ヘッダ付き透過モード0x07
:ボーレートUART ボーレートを指定します。
0x08
:パリティ以下の設定の組み合わせにおいて、設定値の総和を指定します。
例えば、7-E-1 なら 8+2+0=10(0xA)
を指定します。
0x09
:暗号化機能暗号化機能の有無を指定します。
0x0A
:暗号化キー16バイトの暗号化キーを指定します。
インタラクティブモードでは設定できないバイナリ列を格納できます。この場合、インタラクティブモードの表示が崩れる場合があります。
0x0C
:区切り文字区切り文字列の指定を行います(0x00
-0xFF
)。
サイレントモード
サイレントモードでは、起動後に受信回路を動作させず、解除するまでパケットを受信しません。起動後に外部へ接続したマイコンから0xDB
コマンドによる設定を完了してから受信を始める際に利用します。
設定方法 インタラクティブモードで以下の設定を行います。
r: Role
に 80
を足しておく。例えば、通常の親機や子機なら80
とする。m: UART mode
を書式モード(A
/B
)としておく。動作確認 起動直後に出力される DB F1 応答 の内容を確認します。
解除方法 DB F8 要求 を行います(アスキー形式::DBF8101D<CR><LF>
)。
注意点 サイレントモードの再設定はできません。 サイレントモードが有効のときに送信コマンドを入力した場合の動作は未定義です。 1.3.4.1.2.2 - シリアル通信アプリの書式モード(バイナリ形式) 送受信双方の出力にヘッダを付加するモード(バイナリ形式)
書式モードは、送受信双方の出力にヘッダを付加します。バイナリ形式では、データをそのまま表現します。
概要 送信側の端末へ特定の書式に従ったデータを入力すると、受信側の端末も特定の書式に従ったデータを出力します。
16進数で表すデータは、バイナリデータのまま表現します。
送信側の入力 受信側の出力 簡易形式/拡張形式のデータ → 簡易形式/拡張形式のデータ
TWELITE UART では、SET
ピンを GND
へ接続して起動すると書式モード(アスキー)が有効となります。 TWELITE / TWELITE DIP では、EX1
ピンを GND
へ接続して起動すると書式モード(バイナリ)が有効となります。 扱うことのできる書式の形式は2種類あります。
簡易形式:論理デバイスIDだけを使用。超簡単!標準アプリのUART伝送機能と互換性あり 拡張形式:論理デバイスIDに加えて、シリアルIDや再送回数などの送信オプションを使用できる 例えば、5バイトのバイナリデータ 0x48 0x45 0x4C 0x4C 0x4F
は、簡易形式を使って次のように送信できます。
以降、バイナリデータ表現の 0x
を省略します。
例えば、0x48 0x45 0x4C 0x4C 0x4F
は 48 45 4C 4C 4F
と表します。
【送信側】
A5 5A 80 07 00 01 48 45 4C 4C 4F 43 04 <- 入力
A5 5A 80 04 DB A1 80 01 FB 04 <- 出力
【受信側】
A5 5A 80 07 78 01 48 45 4C 4C 4F 3B 04 <- 出力
基本の書式 基本形式や拡張形式で表現したデータ列を送信するときは、バイナリデータのまま扱います。
ヘッダ 長さ ペイロード チェックサム フッタ A5 5A
ペイロード長 00
-FF
の繰り返しペイロードのXOR EOT
すべてバイナリ 先頭は A5 5A
の2バイト ペイロード長はバイト数を2バイトで表現、0x8000
とORをとる チェックサムはペイロードのXOR 末端は EOT を表す 0x04
(入力時は省略可) ビッグエンディアン 例えば、バイナリデータ 00 11 22 33 AA BB CC
は次のように表現します。
A5 5A 80 07 00 11 22 33 AA BB CC DD 04
デバッグが面倒ですが、マイコン間の通信では高い効率を誇ります。
親機と子機の区別 書式モードは、親機と子機を区別します。
親子間では、アプリケーションIDと周波数チャネル を合わせる必要があります。
送信元の判別 書式モードでは、受信したデータから送信元を判別できます。
簡易形式の書式では論理デバイスIDを、拡張形式の書式では論理デバイスIDに加えて拡張アドレスを利用します。
拡張アドレスは、TWELITE 本体に記載された7ビットのシリアルIDの先頭へ0x8
を付加したものです。
簡易形式の書式 書式モードの簡易形式を利用する場合は、次の書式に従います。
送信側の入力 # データ 内容 備考 uint8
ヘッダ 0xA5
のみuint8
ヘッダ 0x5A
のみuint16
データ長 \(N\)+2 0 uint8
送信先の論理デバイスID 親機0x00
,子機0x01
-0x64
,全子機0x78
1 uint8
コマンド番号 0x80
未満の任意の値2 [uint8]
任意のデータ 長さ\(N\)のバイト列(\(N\leqq80\)を推奨) uint8
チェックサム XOR uint8
フッタ EOT (0x04
)
受信側の出力 # データ 内容 備考 uint8
ヘッダ 0xA5
のみuint8
ヘッダ 0x5A
のみuint16
データ長 \(N\)+2 0 uint8
送信元の論理デバイスID 親機0x00
,子機0x01
-0x64
,未設定子機0x78
1 uint8
コマンド番号 送信側で指定した0x80
未満の値 2 [uint8]
任意のデータ 長さ\(N\)のバイト列 uint8
チェックサム XOR uint8
フッタ EOT (0x04
)
送信側の出力(応答メッセージ) # データ 内容 備考 uint8
ヘッダ 0xA5
のみuint8
ヘッダ 0x5A
のみuint16
データ長 4 0 uint8
送信元の論理デバイスID 0xDB
のみ:自身を示す1 uint8
コマンド番号 0xA1
のみ2 uint8
応答ID 128
-255
(0x80
-0xFF
)の範囲で続き番号を示す3 uint8
処理結果 成功1
,失敗0
uint8
チェックサム XOR uint8
フッタ EOT (0x04
)
使用例 親機から全子機に対してバイト列 11 22 33 AA BB CC
を送信する例を示します。
【送信側:親機】
A5 5A 80 08 78 01 11 22 33 AA BB CC A4 04 <- 入力
A5 5A 80 04 DB A1 80 01 FB 04 <- 出力
末尾の0xA4
はチェックサム:0x78
から0xCC
までのXOR。
【受信側:全子機】
A5 5A 80 08 00 01 11 22 33 AA BB CC DC 04 <- 出力
末尾の0xDC
はチェックサム:0x00
から0xCC
までのXOR。
拡張形式の書式 書式モードの拡張形式を利用する場合は、次の書式に従います。
送信側の入力 送信先の指定に論理デバイスIDを使用する場合 # データ 内容 備考 uint8
ヘッダ 0xA5
のみuint8
ヘッダ 0x5A
のみuint16
データ長 \(N\)+\(M\)+3 0 uint8
送信先の論理デバイスID 親機0x00
,子機0x01
-0x64
,全子機0x78
1 uint8
コマンド番号 0xA0
のみ2 uint8
応答ID 任意の値 3 [uint8]
オプション 長さ\(N\)のオプション列 3+\(N\) [uint8]
任意のデータ 長さ\(M\)のバイト列(\(M\leqq80\)を推奨) uint8
チェックサム XOR uint8
フッタ EOT (0x04
)
送信先の指定に拡張アドレスを使用する場合 # データ 内容 備考 uint8
ヘッダ 0xA5
のみuint8
ヘッダ 0x5A
のみuint16
データ長 \(N\)+\(M\)+7 0 uint8
拡張アドレスの指定 0x80
のみ1 uint8
コマンド番号 0xA0
のみ2 uint8
応答ID 任意の値 3 uint32
送信先の拡張アドレス シリアルIDの先頭へ0x8
を加えた値 7 [uint8]
オプション 長さ\(N\)のオプション列 7+\(N\) [uint8]
任意のデータ 長さ\(M\)のバイト列(\(M\leqq80\)を推奨) uint8
チェックサム XOR uint8
フッタ EOT (0x04
)
オプション列の詳細 拡張形式では、オプション列を指定することで細かな設定を行うことができます。
オプション列は、オプションのIDと引数の繰り返しで表現します。終端は 0xFF
とします。
オプションを指定しない場合は0xFF
の1バイトだけを指定します。
入力後1秒が経過すると、送信処理はタイムアウトします。また、内部のバッファが処理待ちで埋まってしまい、新しい要求を受け付けることができない場合があります。アプリケーション再送や遅延を設定する場合は、極端な値に設定しないように注意してください。
0x01
:MAC ACKの有効化MAC層のACK(確認応答)を有効化します。
頻繁にデータを送信する場合には適しませんが、信頼性を向上できる場合があります。
中継機は利用できません。また、送信先を全子機(0x78
)とするときは利用できません。
0x02
:アプリケーション再送の有効化MAC ACK を使用するときは、0x00
-0x0F
を指定します。送信に成功するまで、それぞれ0-16回の再送を行います。
MAC ACK を使用しないときは、0x81
-0x8F
を指定します。必ず1-16回の再送を行います。
応答メッセージは、すべての再送が終了してから出力します。
0x03
:初回送信の遅延の最小値初回送信までの遅延の最小値をミリ秒で指定できます。
0x04
:初回送信の遅延の最大値初回送信までの遅延の最大値をミリ秒で指定できます。
0x05
:アプリケーション再送の間隔アプリケーション再送を有効化した際の再送間隔をミリ秒で指定します。
0x06
:平行要求の許可平行要求を許可します。
平行要求を許可すると、要求を完了するまでブロックせず、次の要求処理を受け付けることができるようになります。
例えば 0.5 秒の遅延を設定した要求を3回連続して入力した場合、初期状態では 0.5 秒後、1.0秒後、1.5秒後と順番に処理します。ところが、平行要求を許可した場合は、0.5秒後に順不同で送信要求を処理します。なおパケット分割を必要とする場合は使用できません。
受信側の端末は、常に新しいデータを採用します。平行要求を許可していると、新しいデータのあとに古いデータが届き、古いデータが無視されてしまうことがあります。
0x07
:応答メッセージの無効化送信側へデータを入力した際に出力される応答メッセージを無効とします。
0x08
:送信後スリープ送信後、速やかに本体をスリープさせます。
RX
が立ち上がりエッジを検知すると、スリープから復帰します。何か1バイトのデータを入力してください。
スリープ復帰後、UART の初期化が終わると入力を受け付けます。
受信側の出力 # データ 内容 備考 uint8
ヘッダ 0xA5
のみuint8
ヘッダ 0x5A
のみuint16
データ長 \(M\)+14 0 uint8
送信元の論理デバイスID 親機0x00
,子機0x01
-0x64
,未設定子機0x78
1 uint8
コマンド番号 0xA0
のみ2 uint8
応答ID 送信側で指定した値 3 uint32
送信元の拡張アドレス シリアルIDの先頭へ0x8
を加えた値 7 uint32
送信先の拡張アドレス 論理デバイスID使用時は0xFFFFFFFF
11 uint8
LQI 受信時の電波通信品質 12 uint16
続くバイト列の長さ バイト数\(M\)を表す 14 [uint8]
任意のデータ 長さ\(M\)のバイト列 uint8
チェックサム XOR uint8
フッタ EOT (0x04
)
送信側の出力(応答メッセージ) # データ 内容 備考 uint8
ヘッダ 0xA5
のみuint8
ヘッダ 0x5A
のみuint16
データ長 4 0 uint8
送信元の論理デバイスID 0xDB
のみ:自身を示す1 uint8
コマンド番号 0xA1
のみ2 uint8
応答ID 入力時に指定した値 3 uint8
処理結果 成功1
,失敗0
uint8
チェックサム XOR uint8
フッタ EOT (0x04
)
使用例 親機から子機に対してバイト列 11 22 33 AA BB CC
を送信する例を示します。
論理デバイスIDを指定する例 親機から論理デバイスID0x01
の子機へ送信する例を示します。
【送信側:親機】
A5 5A 80 0A 01 A0 01 FF 11 22 33 AA BB CC 82 04 <- 入力
A5 5A 80 04 DB A1 01 01 7A 04 <- 出力
末尾の0xC1
はチェックサム:0x42
から0xCC
までのXOR。
【受信側:子機】
A5 5A 80 14 00 A0 01 82 03 68 41 FF FF FF FF FF 00 06 11 22 33 AA BB CC 2D 04 <- 出力
末尾の0x2D
はチェックサム:0x00
から0xCC
までのXOR。
拡張アドレスを指定する例 親機から拡張アドレス0x820163B2
(シリアルID0x20163B2
)の子機へ送信する例を示します。
【送信側:親機】
A5 5A 80 0E 80 A0 01 82 01 63 B2 FF 11 22 33 AA BB CC 51 04 <- 入力
A5 5A 80 04 DB A1 01 01 7A 04 <- 出力
末尾の0x51
はチェックサム:0x80
から0xCC
までのXOR。
【受信側:子機】
A5 5A 80 14 00 A0 01 82 03 68 41 82 01 63 B2 FF 00 06 11 22 33 AA BB CC 7F 04 <- 出力
末尾の0x7F
はチェックサム:0x00
から0xCC
までのXOR。
MAC ACKを使用する例 親機から論理デバイスID0x01
の子機へ MAC ACK を使用して送信する例を示します。
【送信側:親機】
A5 5A 80 0B 01 A0 01 01 FF 11 22 33 AA BB CC 83 04 <- 入力
A5 5A 80 04 DB A1 01 01 7A 04 <- 出力
末尾の0x83
はチェックサム:0x01
から0xCC
までのXOR。
【受信側:子機】
A5 5A 80 14 00 A0 01 82 03 68 41 00 00 01 01 FF 00 06 11 22 33 AA BB CC 2D 04 <- 出力
末尾の0x2D
はチェックサム:0x00
から0xCC
までのXOR。
遅延を設ける例 親機から論理デバイスID0x01
の子機へ 768ms の遅延を設けて送信する例を示します。
【送信側:親機】
A5 5A 80 0D 01 A0 01 03 03 00 FF 11 22 33 AA BB CC 82 04 <- 入力
A5 5A 80 04 DB A1 01 01 7A 04 <- 出力
末尾の0x82
はチェックサム:0x01
から0xCC
までのXOR。
【受信側:子機】
A5 5A 80 14 00 A0 01 82 03 68 41 FF FF FF FF FF 00 06 11 22 33 AA BB CC 2D 04 <- 出力
末尾の0x2D
はチェックサム:0x00
から0xCC
までのXOR。
0xDB
コマンドインタラクティブモードの設定を行う代わりに、UART から 0xDB
コマンドを入力することでモジュールの操作や設定を行うことができます。
1.3.4.1.2.2.1 - シリアル通信アプリ 書式モード(バイナリ)の 0xDB コマンド 書式モード(バイナリ)におけるインタラクティブモードを使用しない設定機能
書式モードでは、インタラクティブモードの代わりに0xDB
コマンドを使うことで、UART接続されたデバイスから動的に設定を行えます。
入力の書式 # データ 内容 備考 uint8
ヘッダ 0xA5
のみuint8
ヘッダ 0x5A
のみuint16
データ長 \(N\)+2 0 uint8
送信先の論理デバイスID 自身を示す0xDB
のみ 1 uint8
コマンド番号 後述の値 から選択2 [uint8]
パラメータ 設定値を示す長さ\(N\)のバイト列(オプション) uint8
チェックサム XOR uint8
フッタ EOT (0x04
)
コマンド番号の一覧 0xF0
:ACKの有効化ACK 応答の要求を行います。
パラメータはありません。
応答の書式 # データ 内容 備考 uint8
ヘッダ 0xA5
のみuint8
ヘッダ 0x5A
のみuint16
データ長 3 0 uint8
送信先の論理デバイスID 0xDB
のみ1 uint8
コマンド番号 0xF0
のみ2 uint8
データ 0x01
のみuint8
チェックサム XOR uint8
フッタ EOT (0x04
)
0xF1
:端末情報の取得アドレス等の情報を表示します。起動時にも出力されます。
パラメータはありません。
応答の書式 # データ 内容 備考 uint8
ヘッダ 0xA5
のみuint8
ヘッダ 0x5A
のみuint16
データ長 17 0 uint8
送信先の論理デバイスID 0xDB
のみ1 uint8
コマンド番号 0xF1
のみ2 uint32
アプリケーションID 6 uint32
バージョン番号 1.4.7
なら00010407
10 uint8
論理デバイスID 11 uint32
シリアルID 15 uint8
サイレントモードの状態 有効1
, 無効0
16 uint8
ネットワークの状態 UP1
, DOWN0
uint8
チェックサム XOR uint8
フッタ EOT (0x04
)
0xF2
:端末設定の適用設定を適用します。
適用するパラメータは、
下記に記載 の識別子とデータの組み合わせで構成します。
応答の書式 成功した場合 # データ 内容 備考 uint8
ヘッダ 0xA5
のみuint8
ヘッダ 0x5A
のみuint16
データ長 \(N\)+2 0 uint8
送信先の論理デバイスID 0xDB
のみ1 uint8
コマンド番号 0xF3
のみ2 [uint8]
設定内容 長さ\(N\)の識別子とデータ の繰り返し uint8
チェックサム XOR uint8
フッタ EOT (0x04
)
失敗した場合 # データ 内容 備考 uint8
ヘッダ 0xA5
のみuint8
ヘッダ 0x5A
のみuint16
データ長 3 0 uint8
送信先の論理デバイスID 0xDB
のみ1 uint8
コマンド番号 0xF3
のみ2 uint8
エラー 0xFF
のみuint8
チェックサム XOR uint8
フッタ EOT (0x04
)
0xF3
:端末設定の取得設定を取得します。
取得するパラメータは、
下記に記載 の識別子で構成します。
応答の書式 # データ 内容 備考 uint8
ヘッダ 0xA5
のみuint8
ヘッダ 0x5A
のみuint16
データ長 \(N\)+2 0 uint8
送信先の論理デバイスID 0xDB
のみ1 uint8
コマンド番号 0xF3
のみ2 [uint8]
設定内容 長さ\(N\)の識別子とデータ の繰り返し uint8
チェックサム XOR uint8
フッタ EOT (0x04
)
0xF8
:端末の制御起動時にサイレントモードを有効としていた場合に、これを解除します。
応答の書式 # データ 内容 備考 uint8
ヘッダ 0xA5
のみuint8
ヘッダ 0x5A
のみuint16
データ長 4 0 uint8
送信先の論理デバイスID 0xDB
のみ1 uint8
コマンド番号 0xF8
のみ2 uint8
データ 0x11
のみ3 uint8
状態 解除済み1
, 未解除0
uint8
チェックサム XOR uint8
フッタ EOT (0x04
)
0xFD
:端末設定の消去設定を初期化し、本体をリセットします。
パラメータおよび応答はありません。
0xFE
:端末設定の保存適用した設定を保存し、本体をリセットします。
パラメータおよび応答はありません。
0xFF
:端末のリセット適用した設定を破棄し、本体をリセットします。
パラメータおよび応答はありません。
パラメータの一覧(0xF2
/0xF3
) 0xF2
:端末設定の適用 および 0xF3
:端末設定の取得 のパラメータは、識別子とデータ(ビッグエンディアン)の繰り返しで表現します。
0x00
:アプリケーションIDアプリケーションIDを指定します。
0x01
:周波数チャネルマスク周波数チャネルのビットマスクを指定します。
使用するチャネルのビットを立てます。例えば、11チャネルを使う場合は1<<11
です。
0x02
:再送回数と出力電波の送信出力と、透過モードおよびヘッダ付き透過モードにおいてパケットを追加で送信する回数を指定します。
下位の1バイトのみを使用します。そのうち上位の4ビットが再送回数(0
-9
)、下位の4ビットが送信出力(0
-3
)です。例えば、8回再送/出力3 であれば 0x0083
です。
0x03
:論理デバイスID論理デバイスIDを指定します。
0x04
:役割子機のみ有効です。以下の値を指定します。通常はネットワーク層を利用しない配送方式を選択してください。
ネットワーク層を利用しない配送方式 0
:通常の指定(親機または子機)1
-3
:中継子機(論理デバイスIDを1
-100
または 120
とします)1
-3
の数値は最大中継段数を指します。最大中継段数まで再送を繰り返す方式のため、中継機の配置や数によっては重複したパケットを中継します。ネットワーク層を利用する配送方式
サイレントモードを有効化するには、上記の数値に80
を足してください。例えば 93
は「ネットワーク層利用かつサイレントモード」です。
0x05
:中継レイヤ中継レイヤの番号です。中継機は中継レイヤ数の上位(より小さい値)の中継機・親機への接続を試みます。役割 を12
としているときにだけ有効です。
0x06
:通信モード0
:透過モード1
:書式モード(バイナリ)2
:書式モード(バイナリ)3
:チャットモード4
:ヘッダ付き透過モード0x07
:ボーレートUART ボーレートを指定します。
0x08
:パリティ以下の設定の組み合わせにおいて、設定値の総和を指定します。
例えば、7-E-1 なら 8+2+0=10(0xA)
を指定します。
0x09
:暗号化機能暗号化機能の有無を指定します。
0x0A
:暗号化キー16バイトの暗号化キーを指定します。
インタラクティブモードでは設定できないバイナリ列を格納できます。この場合、インタラクティブモードの表示が崩れる場合があります。
0x0C
:区切り文字区切り文字列の指定を行います(0x00
-0xFF
)。
サイレントモード
サイレントモードでは、起動後に受信回路を動作させず、解除するまでパケットを受信しません。起動後に外部へ接続したマイコンから0xDB
コマンドによる設定を完了してから受信を始める際に利用します。
設定方法 インタラクティブモードで以下の設定を行います。
r: Role
に 80
を足しておく。例えば、通常の親機や子機なら80
とする。m: UART mode
を書式モード(A
/B
)としておく。動作確認 起動直後に出力される DB F1 応答 の内容を確認します。
解除方法 DB F8 要求 を行います(バイナリ形式:A5 5A 80 03 DB F8 10 33 04
)。
注意点 サイレントモードの再設定はできません。 サイレントモードが有効のときに送信コマンドを入力した場合の動作は未定義です。 1.3.4.1.2.3 - シリアル通信アプリのチャットモード プロンプト表示とエコーバックを行うモード
チャットモードは、プロンプト表示とエコーバックによりテキストチャットを実現します。
MONOSTICK を PC 等へ接続することで、複数の端末同士のチャットを行うことができます。
概要 テキストチャットを実現します。
送信側の入力 受信側の出力 任意の文字列 → 任意の文字列+補助情報
プロンプトの表示とエコーバック(入力した文字の出力)を行います。すべての端末は子機として、同報通信を行います。
例えば、ある端末から他の端末へ Hello
という文字列を送信する場合は、次のように振る舞います。
【送信側】
810A4778:0> Hello <- 入力
810A4778:1> <- 出力
【受信側】
[810A4778:0] Hello <- 出力
82018CA0:0> <- 出力
チャットモードは、プロンプトの表示とエコーバック(自身へ入力された文字の出力)を行います。
全ての端末は子機としたうえで、送信内容はブロードキャストします。すべての端末と通信できますが宛て先は指定できません。またバイナリデータは送れません。文字列のみ対応しています(0x00
-0x1F
, 0x7F
は送信不可)。
中継は3段(3ホップ)まで対応しています。初期設定では中継しません。
親機と子機の区別 チャットモードは、親機と子機を区別しません。
アプリケーションIDと周波数チャネル が同一であれば、どの端末へ入力したデータもほかの端末へと送信されます。
ネットワークの構成イメージ
送信元の判別 受信側に出力される補助情報の識別情報から送信元を判別できます。
インタラクティブモードのh: Header format
を空欄としたときは、7桁のシリアルIDの先頭へ0x8
を付与した拡張アドレスを使用します。例えば、以下の出力では送信元のシリアルIDが0x10A4778
であったと分かります。
インタラクティブモードのh: Header format
へ任意の文字列を設定したときは、それをハンドル名として利用します。ただし、ハンドル名は無線パケットに格納するデータを消費します。
送信側の入力書式 プロンプトに続けて、メッセージと改行文字を入力します。
データ 内容 備考 [char]
メッセージ 0x00
-0x1F
, 0x7F
は不可char
CR (0x0D
/'\r'
) 単体でも可 char
LF (0x0A
/'\n'
) 単体でも可
受信側の出力書式 補助情報に続けて、受信したメッセージを出力します。
補助情報は、モジュールの拡張アドレスまたはハンドル名と、続き番号を含みます。
データ 内容 備考 char
補助情報のヘッダ [
のみ[char]
識別情報 8桁の拡張アドレスまたはハンドル名 char
補助情報の区切り文字 :
のみ[char]
続き番号 0
から開始char
補助情報のフッタ ]
のみchar
区切り文字 半角スペースのみ [char]
メッセージ char
フッタ CR (0x0D
/'\r'
) char
フッタ LF (0x0A
/'\n'
)
エラー等の場合は、(err)
(canceled)
といった ()
書きのメッセージを出力します。
その他の入力 エスケープシーケンスに対応したターミナルでは、以下の制御コマンドを使用できます。
Ctrl-L
:画面のクリアCtrl-C
:入力のキャンセルBS
/DEL
:カーソルを戻す1.3.4.1.2.4 - シリアル通信アプリの透過モード 純粋にUARTを無線化するモード
透過モードは、ヘッダの付加やエコーバック、プロンプト表示を行わず、有線接続された UART と同じような振る舞いを実現します。
外部マイコン同士を簡単に接続できますが、書式を用いて通信を最適化するには書式モード(アスキー /バイナリ )が適しています。
概要 純粋にUARTを無線化します。
送信側の入力 受信側の出力 任意のデータ → 任意のデータ
書式を必要としないため、既存の UART 通信を簡単に無線化できます。
一方で、データの区切りがあいまいになってしまうほか、受信側の出力から送信元を判別できないといった欠点があります。
初期状態では、送信トリガ文字にCRLFを指定しています。したがって、送信側へ入力されたデータをCRLFで区切り、CRLF よりも前のデータを送信します。
例えば、送信側の端末へ Hello<Enter>
と入力すると、受信側の端末はそのまま Hello
を出力します。
【送信側】
【受信側】
連続して入力された文字列を80バイトごとに分割して送信します。トリガ文字までのデータは通常80バイト以下としてください。
全ての端末は子機としたうえで、送信内容はブロードキャストします。すべての端末と通信できますが宛て先は指定できません。アスキー文字だけでなく、バイナリデータも送信できます。
中継は3段(3ホップ)まで対応しています。初期設定では中継しません。
親機と子機の区別 透過モードは、親機と子機を区別しません。
アプリケーションIDと周波数チャネル が同一であれば、どの端末へ入力したデータもほかの端末へと送信されます。
ネットワークの構成イメージ
送信元の判別 透過モードでは、送信元を判別できません。
送信元を判別するには、送信側へ入力するデータそのものに送信元の情報を含める必要があります。
送信トリガ 送信側の入力に書式はありませんが、データはある時点で分割されたのち、パケットごとに無線で送信されます。
したがって、次に挙げる送信トリガを意識しなくてはなりません。
データ入力後のタイムアウトを迎えたとき 入力データが最小データサイズを満たしたとき 送信トリガ文字を受け取ったとき
送信トリガの優先順位 タイムアウトを迎えたときは、強制的に送信します。また、最小データサイズを設定している場合は、そのサイズを満たしていないと送信トリガ文字は無効となります。
送信トリガの設定は、インタラクティブモードのk
:送信トリガ 項目から指定します。
設定例 送信トリガ文字をLF、最小データサイズを8バイト、タイムアウトを30msとする場合は次のように設定します。
m: set UART mode (D)
k: set Tx Trigger (sep=0x0a, min_bytes=8 dly=30[ms])
o: set option bits (0x00000100)
1.3.4.1.2.5 - シリアル通信アプリのヘッダ付き透過モード 受信側の出力にだけヘッダを付加するモード
ヘッダ付き透過モードは、受信側の出力にだけ補助情報を付加します。
概要 初期状態で有効となっています。
送信側の端末へ任意のデータを入力すると、受信側の端末は受信した内容に特定の書式で補助情報を付加したデータを出力します。
送信側の入力 受信側の出力 任意のデータ → 任意のデータ+補助情報
初期状態では、送信側へ入力されたデータをCRLFで区切り、CRLF よりも前のデータを送信します。
例えば、送信側の端末へ Hello<Enter>
と入力すると、受信側の端末は補助情報を含んだ書式で Hello
を出力します。送信側の端末も送信完了といったメッセージを伝える書式を出力します。
【送信側】
Hello <- 入力
;U;00004;219;0x820163B2;000;000;0,1,Hel...;6E; <- 出力
【受信側】
;U;00003;000;0x820163B2;255;000;Hello;42; <- 出力
受信側が出力する補助情報は、送信元のアドレスや受信時の電波強度、チェックサム等を含みます。補助情報の書式はカスタマイズできます。
親機と子機の区別 ヘッダ付き透過モードは、親機と子機を区別しません。
アプリケーションIDと周波数チャネル が同一であれば、どの端末へ入力したデータもほかの端末へと送信されます。
ネットワークの構成イメージ
送信元の判別 ヘッダ付き透過モードで受信したデータからは、送信元を判別できます。
受信側が出力する補助情報を表すヘッダに含むことのできる論理デバイスID やシリアルIDのデータを利用します。
宛先を指定することはできません。受信側へ接続されたデバイスが判別しなくてはなりません。
受信側の出力書式 出力書式はセミコロン(;
)区切りとして表現されます。
【初期状態における出力例】
;U;00777;120;0x81025A17;120;013;HELLO;79;
この出力例は、次のように解釈できます。
データ 内容 値 U
char
固定値 U
00777
uint16
出力時のタイムスタンプ 777
秒120
uint8
送信元の論理デバイスID 120
IDなし子機0x81025A17
uint32
送信元の拡張アドレス 81025A17
120
uint8
LQI(電波通信品質) 120/255
013
uint8
送信元の続き番号 13
HELLO
[uint8]
入力データ HELLO
79
uint8
XORチェックサム 0x79
送信元の論理デバイスIDは、自身の応答メッセージのとき219
となります。
拡張アドレスは、TWELITE 本体に記載された7ビットのシリアルIDの先頭へ0x8
を付加したものです。
ヘッダフォーマットによるカスタマイズ 受信側の出力書式は、ヘッダフォーマットに従います。
ヘッダフォーマットを変更することで、受信側が出力する補助情報の内容やチェックサムの計算範囲をカスタマイズできます。
初期状態では、ヘッダフォーマットを ;U;%t;%i;0x%A;%q;%s;<*;%X;\n
としています。
ヘッダフォーマットの変更は、インタラクティブモードの h: set header format
から行います。
最も簡単な書式 最も簡単な書式を表すヘッダフォーマットは *\n
です。受信したデータへ CRLF の改行文字を付与して出力します。
h: set header format [*\n]
この場合にHELLO
を送信すると、次のように振る舞います。
【受信側】
HELLO<CR><LF> または HELLO<LF>
【送信側】
フォーマットを構成する特殊文字 ヘッダフォーマットに次の特殊文字を含めることで、出力内容をカスタマイズできます。
全般 内容 *
受信したデータ &hl
任意の文字(アスキー)(例:&20
は空白) <
チェックサム計算の開始位置(未設定で先頭から) >
チェックサム計算の終了位置(v1.4.6以降のみ)
\
(バックスラッシュ・¥)に続くもの内容 \n
CRLF (0x0D
0x0A
) \t
TAB \*
*
\%
%
\<
<
\>
>
\&
&
%
に続くもの内容 長さ データ %A
送信元アドレス(32bit) 8桁 16進数 %a
送信元アドレス(32bit) 10桁 16進数 %I
送信元論理アドレス(8bit) 2桁 16進数 %i
送信元論理アドレス(8bit) 3桁 10進数 %T
現在のシステム時間(秒) 4桁 16進数 %t
現在のシステム時間(秒) 5桁 10進数 %S
送信元が設定した続き番号 2桁 16進数 %s
送信元が設定した続き番号 3桁 16進数 %Q
受信時の電波強度 2桁 16進数 %q
受信時の電波強度 3桁 10進数 %X
チェックサム 2桁 16進数 %x
チェックサム 3桁 10進数
チェックサムの計算 チェックサムはデータの先頭あるいはヘッダフォーマットの<
を指定した箇所から%X
,%x
の直前までを XOR(排他的論理和)にて計算します。
初期状態の例 初期状態ではヘッダフォーマットを ;U;%t;%i;0x%A;%q;%s;<*;%X;\n
としており、チェックサムの計算範囲は*;
です。
すなわち、HELLO
を送信した場合は HELLO;
のバイナリデータを対象とするため、チェックサムは0x79
です。
【Python による検証コード】
from functools import reduce
def main ():
data = "HELLO;"
checksum = reduce(lambda x, y: x ^ y, data. encode("ascii" ))
print(f " { data} -> { hex(checksum)} " )
if __name__ == "__main__" :
main() # HELLO; -> 0x79
その他の例 例えば、ヘッダフォーマットを ;%I;*;%X
とした場合を考えます。
<
を指定していないため、チェックサムの計算範囲は;%I;*;
です。
すなわち、HELLO
を送信した場合は ;000;HELLO;
のバイナリデータを対象とするため、チェックサムは 0x49
です。
【Python による検証コード】
from functools import reduce
def main ():
data = ";000;HELLO;"
checksum = reduce(lambda x, y: x ^ y, data. encode("ascii" ))
print(f " { data} -> { hex(checksum)} " )
if __name__ == "__main__" :
main() # ;000;HELLO; -> 0x49
送信トリガ 送信側の入力に書式はありませんが、データはある時点で分割されたのち、パケットごとに無線で送信されます。
したがって、次に挙げる送信トリガを意識しなくてはなりません。
データ入力後のタイムアウトを迎えたとき 入力データが最小データサイズを満たしたとき 送信トリガ文字を受け取ったとき
送信トリガの優先順位 タイムアウトを迎えたときは、強制的に送信します。また、最小データサイズを設定している場合は、そのサイズを満たしていないと送信トリガ文字は無効となります。
送信トリガの設定は、インタラクティブモードのk
:送信トリガ 項目から指定します。
設定例 送信トリガ文字をLF、最小データサイズを8バイト、タイムアウトを30msとする場合は次のように設定します。
m: set UART mode (E)
k: set Tx Trigger (sep=0x0a, min_bytes=8 dly=30[ms])
o: set option bits (0x00000100)
1.3.4.1.3 - シリアル通信アプリのカスタムデフォルト機能 デフォルトの設定を変更したファームウェアの作成
カスタムデフォルト機能によって、ファームウェアに含まれるデフォルトのパラメータを変更できます。
例えば、ボーレートを 115200bps から 9600bps へ変更したファームウェアを作成しておけば、最初から 9600bps で使用できます。
設定手順 1. 設定を適用 インタラクティブモード の設定を変更し、S
を押下して保存します。
2. 設定内容をダウンロード xmodem プロトコルのデータをダウンロードできるソフトウェアを用意します。
xmodem の仕様はチェックサム/128バイトパケットです。拡張された 1KB や CRC の形式は使用しません。
再度インタラクティブモードへ入った状態(項目を選ぶ前の状態)として、xmodem のダウンロードを要求します。
TeraTerm では、次の操作を行います。
ファイル > 転送 > XMODEM > 受信...
を選択Option > Checksum, Binary
を選択ファイル名を指定(例:conf.bin
) 開く
ボタンを押下
macOS や Linux 等では、lrzsz
を利用できます。
lrx --binary --xmodem /path/to/conf.bin
通常は screen
でインタラクティブモードへ入り、Ctrl+A
の押下後 :exec !! lrx -b -X /path/to/conf.bin
を実行します
ダウンロードに成功すると、128バイトのファイルを生成します(xmodem の実装によっては、小さいサイズになることもあります)。
3. カスタムバイナリの作成 ダウンロードしたファイルをファームウェアのバイナリファイルの末尾へ連結し、カスタムバイナリを作成します。
連結には、コマンドラインツールや汎用のファイル連結ツールを使用してください。
実行例 ダウンロードした xmodem のファイルを conf.bin
、元のバイナリファイルをApp_Uart_BLUE_L1305_V1-4-X.bin
、作成するカスタムバイナリをApp_Uart_custom_V1-4-X.bin
とした場合の例を示します。
【Windows】
copy App_Uart_BLUE_L1305_V1-4 -X.bin App_Uart_custom_V1-4 -X.bin
type conf.bin >> App_Uart_custom_V1-4 -X.bin
【macOS / Linux】
cat App_Uart_BLUE_L1305_V1-4-X.bin conf.bin > App_Uart_custom_V1-4-X.bin
4. カスタムバイナリの書き込み 連結したカスタムバイナリを TWELITE へ書き込みます。
カスタムバイナリを書き込んでからインタラクティブモードへ入ると、最初の行の末尾に C-
を表示します。
--- CONFIG/TWE UART APP V1-04-2/SID=0x81001f1c/LID=0x78 C- ---
カスタムバイナリに対してインタラクティブモードから設定を上書きして保存すると、C-
の代わりにCE
と表示します。
--- CONFIG/TWE UART APP V1-04-2/SID=0x81001f1c/LID=0x78 CE ---
1.3.4.1.4 - シリアル通信アプリの通信における注意点 安定した通信を実現するための注意点
安定した通信を実現するための注意点を記載しています。
UART のデータ入出力 UART の入力には、入力側に 4KB、出力側に 4KB のバッファを確保しています。2系統のUARTを出力する場合は、各系統の入力に 2KB、出力に 2KB を利用します。
書式モードやチャットモードでバッファのサイズを意識する場面は多くありませんが、ヘッダ付き透過モードや透過モードで連続的に系列を入力する場合や、書式モードであっても多数の系列を一度に入力する場合は、バッファサイズの上限を意識する必要があります。出力においても、遅いボーレートを設定した場合には、無線で受信したデータの出力が間に合わない可能性があります。
バッファの上限を超えた場合は、その境界でのデータは保護されません。データ抜けが発生します。特に入力側では後述のフロー制御ピンを参照することを検討してください。
UART のフロー制御 入力側のフロー制御については、 RTS ピン同様の振る舞いをするように実装しています。使用するピンは PWM1
(DIO5
) であり、その対象は主UARTポートです。入力を受け付けないときに High、入力を受け付けるときに Low 状態となります。なお出力側のフロー制御には対応していません。受信側のデバイスでは、十分なボーレートと処理速度を確保してください。
電源投入・リセット直後は High です。UART が初期化されると Low。 UART の入力バッファが 7/8 を超えたときに High となります。下回ると Low。 透過モードでは、パケット送信中は High となります。 無線通信エラーの対策 受信側にデータ抜けが発生する場合は、無線の再送回数を増やしてください。
追加送信するパケットの数を増やすことで、受信の成功率を向上できる場合があります。
再送回数はインタラクティブモード で設定できます(x: set RF Conf
)。
1.3.4.1.5 - インタラクティブモード(シリアル通信アプリ) インタラクティブモードによる設定変更
インタラクティブモードでアプリの詳細設定を行うことができます。
ここではシリアル通信アプリ(App_Uart)に固有の機能を説明します。共通機能については、TWELITE APPS マニュアル のトップページ を参照してください。
TWELITE がスリープしている間はインタラクティブモードを使用できません。
M3
ピン をGND
へ接続していないことを確認してください。
表示例 次のような画面を表示します。
--- CONFIG/TWE UART APP V1-04-5/SID=0x82018ca0/LID=0x78 -- ---
a: set Application ID (0x67720103)
i: set Device ID (120=0x78)
c: set Channels (18)
x: set RF Conf (3)
r: set Role (0x0)
l: set Layer (0x1)
b: set UART baud (38400)
B: set UART option (8N1)
m: set UART mode (E)
k: set Tx Trigger (sep=0x0d0a, min_bytes=0 dly=0[ms])
h: set header format [;U;%t;%i;0x%A;%q;%s;<*>;%X;\n]
C: set crypt mode (0)
o: set option bits (0x00000100)
---
S: save Configuration
R: reset to Defaults
コマンド 各コマンドの詳細を次に示します。
a
:アプリケーションID通信を行う端末はすべて同一の値とします。論理的にネットワークを分離します。
i
:論理デバイスID複数の子機を識別する必要がある場合に設定します。
識別の必要がない、できない場合は120
としてください。識別の必要がある場合は、子機は1
-100
の任意の値に、親機は0
あるいは121
としてください。
c
:周波数チャネル通信を行う端末はすべて同一の値とします。物理的にネットワークを分離します。
x
:送信出力と再送回数電波の送信出力と、透過モードおよびヘッダ付き透過モードにおいてパケットを追加で送信する回数を指定します。
r
:役割子機のみ有効です。以下の値を指定します。通常はネットワーク層を利用しない配送方式を選択してください。
ネットワーク層を利用しない配送方式 0
:通常の指定(親機または子機)1
-3
:中継子機(論理デバイスIDを1
-100
または 120
とします)1
-3
の数値は最大中継段数を指します。最大中継段数まで再送を繰り返す方式のため、中継機の配置や数によっては重複したパケットを中継します。ネットワーク層を利用する配送方式 書式モードのみ対応しています。
サイレントモードを有効化するには、上記の数値に80
を足してください。例えば 93
は「ネットワーク層利用かつサイレントモード」です。
l
:中継レイヤ中継レイヤの番号です。中継機は中継レイヤ数の上位(より小さい値)の中継機・親機への接続を試みます。役割 を12
としているときにだけ有効です。
m
:通信モードA
:書式モード(アスキー)B
:書式モード(バイナリ)C
:チャットモードD
:透過モードE
:ヘッダ付き透過モードb
:UART代替ボーレートBPS
ピンをGND
へ接続して起動した場合に選択される代替ボーレートを38400
bpsから上書きします。
値は9600
/19200
/38400
/57600
/115200
/230400
から選択できます。他の値を指定すると、誤差が生じる可能性があります。
BPS
ピンを開放して起動した場合、この設定は適用されません。115200
bpsに固定されます。
BPS
ピンの状態を無視して強制的に代替ボーレート設定を適用するには、オプションビットの強制的に代替ボーレートを適用 を有効とします。
B
:UARTオプションBit-Parity-Stop
の順で3文字を指定します。
k
:送信トリガ透過モードとヘッダ付き透過モードの入力へ適用する送信トリガを設定します。
カンマ,
で区切り、以下の順で入力してください。
送信トリガ文字 最小データサイズ タイムアウト 送信トリガ文字 この文字が入力されたときにパケットを送信します(最小データサイズを満たしていない場合を除く)。
インタラクティブモードでは、16進数のASCIIコードを指定します。先頭の0x
は無視されます。初期状態ではCRLFとしています。
送信されるデータには送信トリガ文字も含まれます。送信トリガ文字を有効とするには、オプションビット 0x00000100
を指定する必要があります(デフォルト指定済み)。
最小データサイズ 連続して扱うデータの最小サイズを指定します。最小データサイズを満たすまでのデータに送信トリガ文字が含まれていても、これは無効となります。
インタラクティブモードでは、バイト数として1
-80
の数値を指定します。0
で無効となります。初期状態では無効です。
タイムアウト 最後の入力からパケットを送信するまでの待ち時間を示します。
インタラクティブモードでは、ミリ秒単位で10
-200
の数値を指定します。0
で無効となります。初期状態では無効
すべての設定を有効とした場合の優先順位は次の通りです。
タイムアウト 最小データサイズ 送信トリガ文字 タイムアウトが設定されていれば、常に優先します。送信トリガ文字が設定されていても、最小データサイズに達するまでは送信されません。
h
:ヘッダ/ハンドル名ヘッダ付き透過モードに対してはヘッダのフォーマットを、チャットモードに対してはハンドル名を示します。
ヘッダ(ヘッダ付き透過モード) ヘッダ付き透過モードに対しては、ヘッダのフォーマット書式 を指定します。
ハンドル名(チャットモード) 相手端末に表示するハンドル名を指定します。
最大23文字です。送信するデータ(80バイト)の領域を消費します。
C
:暗号化暗号化機能の有無を指定します。
AES128bitの暗号化を有効とするには、1
を指定してください。
暗号化機能を有効とした端末は平文のメッセージも受信できますが、Ack 応答は利用できません。
o
:オプションビット32bit の数値を指定します。各ビットに紐付いた設定を有効化できます。
オプションビットの詳細 オプションビットの値の各ビットに紐付いた設定を解説します。
00000001
:M3
の内部プルアップを停止TWELITE DIP におけるスリープ設定用のピン M3
の内部プルアップを停止します。
プルアップ停止時には、オープン状態で起動しないでください。意図せずスリープしてしまう場合があります。
00000100
:送信トリガの有効化透過モードまたはヘッダ付き透過モードにおいて、送信トリガの設定 を有効とします。
00000200
:新たな入力系列を優先書式モード(アスキー・バイナリ)、透過モード、ヘッダ付き透過モードにおいて、送信完了前に複数の系列が入力された際、新しいものを優先します。
制御値や計測値を連続的に送信し、常に最新のデータを反映させたい場合に有効です。
00001000
:応答メッセージを停止書式モード(アスキー・バイナリ)、ヘッダ付き透過モードにおいて、送信完了時の応答メッセージを停止します。
00004000
:重複チェッカの緩和受信側において、重複チェッカの条件を緩和します。
重複チェッカは、中継などにより重複して届いてしまったパケットを排除するための仕組みです。
100ms以下など短い間隔で送信を行うと、異なるパケットであっても同一のものであると見なされてしまう場合があります(続き番号が異なる場合も含む)。
送信間隔を短く設定する場合や、たくさんの送信機を同時に使用する際は、この設定を有効としてください。
00010000
:強制的に代替ボーレートを適用起動時にBPS
ピンの入力が Low でなくとも、代替ボーレートの設定 を適用します。
インタラクティブモードも UART を使用するため、インタラクティブモードを使用するにはPC側のボーレートを合わせる必要があります。
00020000
:副ポートへ同時出力シリアル出力TX
の内容をシリアル副出力TX_SUB
にも適用します。
入出力用のバッファ(入力4KB,出力4KB)は、主ポート・副ポートで半々(入力2KB,出力2KB)の割り当てとなります。
00040000
:主ポートの切り替えシリアル入出力TX
/RX
とシリアル副入出力TX_SUB
/RX_SUB
を入れ替えます。
00100000
:中継レイヤを制限書式モード(アスキー・バイナリ)において、ネットワーク層を利用する配送方式 を指定した場合に、必ず1階層上位に位置する中継機や親機へ送信させます。通常、ネットワーク層を利用する配送方式では、上位層で最も電波通信品質の高い中継機や親機へ送信します。
中継機能について 通信距離が足りない場合や、障害物があって通信できない場合には、中継機を使用することが有用です。
中継機能を持った端末は、自身が受信したパケットを他の端末へ送信します。
中継機能の設定 通常は、インタラクティブモードへ入った状態で役割 の値を1
-3
へ変更します。初期値は0
で、中継機能を持ちません。
1
-3
の数値は最大中継段数を指します。例えば3
を指定すると最大3段まで中継されます。
親機子機の区別をする場合、子機のみ有効です。
中継段数や中継機を増やすと、送信されるパケットも増加します。同一の周波数チャネル内の通信が不安定となってしまう場合があります。
設定例 次のネットワーク構成は、赤色の端末の役割 を0
、青色の端末の役割 を3
とした場合を示します。
役割の設定による中継の例
赤色の端末を追加すると、赤色の端末同士で最大3段の中継を伴う通信を実現できます。
送信機や受信機を追加する例
1.3.5 - キューアプリ マニュアル モノの動きを無線でお知らせ。
キューアプリ(App_CUE)は磁気・加速度センサータグ TWELITE CUE専用のアプリです。
1.3.5.1 - キューアプリ マニュアル 最新版
機能 モノに装着することで動きや状態を無線で送信できます。
複数の無線タグからのデータを親機で収集可能 複数の無線タグを親機で制御可能 16チャネルで複数システムを個別に運用可能 グループ毎に異なるアプリケーションIDを設定することで、同一チャネルに複数システムを混在可能 暗号化と暗号化鍵の設定 1.3.5.1.1 - キューアプリの動作モード キューアプリの動作モード
1.3.5.1.1.1 - キューアプリのTWELITE CUEモード 衝撃の検知やドアの開閉、加速度の計測のすべてを行うことができるオールインワンモード
加速度の計測、衝撃の検知、姿勢の検知、磁石の検知といった機能をすべて利用できるオールインワンモードです。
工場出荷時は本モードに設定されております。
設定 本モードを使用する場合は以下の項目を設定してください。
設定コマンド 設定項目 設定値 備考 p センサ固有パラメータの設定 00000000
親機の出力 代表的な電池寿命 5秒に1度の定期送信のみの場合、約80日 5秒に1度の定期送信 + 1分に1度TWELITE CUEを動かした場合、約80日 1分に1度の定期送信のみの場合、約700日 1分に1度の定期送信 + 1分に1度TWELITE CUEを動かした場合、約565日
消費電流は試験用のサンプル個体の実測に基づき、CR2032の容量を220mAhとして計算しています。電池寿命は参考値であり、保証値ではありません。電池の性能や使用温度等の使用環境で変化します。
1.3.5.1.1.2 - キューアプリの動作センサーパルモード 動作センサーパルとして動作するモード
動作センサーパルと同等の機能を使用できるモードです。
連続で加速度を計測する際や衝撃の検知を行う際は本モードを使用します。
本モードは次の3つのモードに分けられます。
加速度計測モード 加速度を間欠もしくは連続で計測し、送信するモードです。
設定 TWELITE2525Aモードフラグ TWELITE 2525Aモードフラグを1(センサ固有パラメータを13000000)に設定すると、TWELITE 2525A のFIFO(通常)モード として動作します。TWELITE 2525Aの代替として使用したい場合にはこのモードをご使用ください。
加速度センサープロパティ 加速度センサープロパティで連続送信サンプル数やサンプリング周波数を変更できます。
これらの設定は足し合わせることで機能を組み合わせて使用できます。
設定値(16進) 説明 0x?3????00~0x?3????FF 間欠送信モード時に送信するサンプル数を設定できます。 送信するサンプル数は16サンプル(1パケット)単位で設定できます。 サンプル数=16+16x設定値 0x00000000 の場合:16サンプル(初期設定) 0x00000001 の場合:32サンプル : 0x00000007 の場合:128サンプル : 0x000000FF の場合:4096サンプル 0x?3???0??~0x?3???F?? 加速度のサンプリング周波数を変更できます。設定値毎のサンプリング周波数は下記の通りです。 0x00000000:25Hz(初期設定) 0x00000100:50Hz 0x00000200:100Hz 0x00000300:190Hz 0x00000400~0x00000F00:未定義
サンプル数を32以上に設定した場合、データは16サンプルごとに別のパケットへ分割されます。
例えば、サンプル数を32とした場合には、16サンプルのパケットが2回届きます 。32サンプルのパケットが1回届くのではないことに注意してください。
親機の出力 ムーブモード 動き出し(Move)やシェイク(Shake)を検出することができます。
通知パルのLEDを制御することができます。
設定 設定コマンド 設定項目 設定値 備考 p センサ固有パラメータの設定 01100000
親機の出力 使用上の注意 本モードは動きを検知してしてデータを送信します。 そのため、ゆっくり動かしたときは動きを検知できず、出力が変化しない場合があります。 その際は少し強めに動かしてください。
また、センサー固有パラメータ(p)を01000000にすると、動作検知の感度が厳しくなります。 もし、意図しないタイミングで電波を送信する場合は、センサー固有パラメータを01000000に設定してください。
ダイスモード TWELITE CUEが上に向いている面を検出することができます。
イベント検出モードと同様に通知パルのLEDを制御することができます。
設定 設定コマンド 設定項目 設定値 備考 p センサ固有パラメータの設定 02100000
親機の出力 使用上の注意 本モードは動きを検知して面の判定を行います。 そのため、ゆっくり動かしたときは面が判定できず、出力が変化しない場合があります。 その際は机に置く、軽く衝撃を与えるなどをしてください。
また、センサー固有パラメータ(p)を02000000にすると、動作検知の感度が厳しくなります。 もし、意図しないタイミングで電波を送信する場合は、センサー固有パラメータを02000000に設定してください。
代表的な電池寿命 加速度計測モード(間欠送信)で1分に1度送信した場合、約3.5年 加速度計測モード(連続送信)でサンプリング周波数が25Hzの場合、約20日 イベント検出モードもしくはダイスモードで1分に1度、TWELITE CUEを動かした場合、約3年
消費電流は試験用のサンプル個体の実測に基づき、CR2032の容量を220mAhとして計算しています。電池寿命は参考値であり、保証値ではありません。電池の性能や使用温度等の使用環境で変化します。
1.3.5.1.1.3 - キューアプリの開閉センサーパルモード 開閉センサーパルとして動作するモード
モノに装着し、磁石の有無によってその開閉を知ることができるモードです。
ドアの開閉や工場設備の稼働状況を計測する場合は本モードを使用します。
設定 本モードを使用する場合は以下の項目を設定してください。
設定コマンド 設定項目 設定値 備考 p センサ固有パラメータの設定 04000000
親機の出力 代表的な電池寿命 1日に200回の開閉を行なった場合、約4年です。(含1分毎の定期送信) 1日に0回の開閉を行なった場合、約4.5年です。(含1分毎の定期送信)
消費電流は試験用のサンプル個体の実測に基づき、CR2032の容量を220mAhとして計算しています。電池寿命は参考値であり、保証値ではありません。電池の性能や使用温度等の使用環境で変化します。
1.3.5.1.2 - キューアプリの設定方法 キューアプリの設定方法
TWELITE CUEを設定する方法には、有線と無線の2種類があります。
1.3.5.1.2.1 - キューアプリのOTAによる設定 無線による設定の方法
OTA設定は、インタラクティブモードの設定を無線経由で行う機能です。
OTAによる設定手順 以下の手順でOTAによる設定を行います。
1. TWELITE STAGE APPを起動する パソコンへTWELITE STAGE SDK をインストール し、MWSTAGEフォルダ内のTWELITE_Stage
を起動する。
2. MONOSTICKへOTA設定用のアプリを書き込む 2: アプリ書換 > 1: BINから選択 を開き、App_CUE_OTA_...
を選択する。
3. インタラクティブモードで設定値を入力する 3: インタラクティブモード を選択し、値を編集・保存する。
4. OTA設定を実行する MONOSTICKから約20cm以内の距離に TWELITE CUE を置く。本体の電源を投入するか、または磁石を磁気センサーへ5回以上接近させて、TWELITE CUE の LED が点滅することを確認する。
5. MONOSTICKの出力を確認する 次のようなメッセージの出力を確認する。
出力されない場合はこちら
6. MONOSTICKのアプリを書き戻す 2: アプリ書換 > 1: BINから選択 を開き、App_Wings_MONOSTICK_...
を選択する。
OTAに失敗した場合 距離が遠い 次のようなメッセージは、距離が遠いことを示します。
OTA FAILURE
OTA request TS=20515[ms]
LQI:63 (RF strength, >= 100)
SID:810BA765
TWELITE CUE:v1.1.1
Protocol Version:0x11
--— LQI is small. Please make TWELITE CUE closer. —--
この場合は、MONOSTICK と TWELITE CUE の距離を近づけてください。
対象が異なる 次のようなメッセージは、TWELITE CUE のファームウェアが異なっているか、間違って TWELITE CUE を近づけていることを示します。
OTA FAILURE
OTA request TS=20515[ms]
LQI:180 (RF strength, >= 100)
SID:810BA765
TWELITE CUE:v1.1.1
Protocol Version:0x13
--— Different protocol version. Please update TWELITE CUE. —--
この場合は、間違って TWELITE CUE を近づけていないか確認してください。
また、TWELITE CUE のファームウェアを書き換えていた場合は、TWELITE R2/R3を使って App_CUE
へ書き戻してください。
1.3.5.1.2.2 - キューアプリのTWELITE R2/R3による設定 TWELITE R2/R3を使う設定の方法
TWELITE CUEの7PインターフェイスへTWELITE R2/R3 を接続することで設定できます。
TWELITE R2との接続例
TWELITE R2/R3を逆向きに接続するとTWELITE CUEが破損します。
TWELITE R2/R3を使用して設定する場合は以下の手順で設定してください。
1. TWELITE STAGE APPを起動する パソコンへTWELITE STAGE SDK をインストール し、MWSTAGEフォルダ内のTWELITE_Stage
を起動する。
2. インタラクティブモードで設定値を入力する 3: インタラクティブモード を選択し、値を編集・保存する。
1.3.5.1.2.3 - インタラクティブモード(キューアプリ) インタラクティブモードによる詳細な設定変更
本アプリでは、インタラクティブモードからアプリの詳細設定を行うことができます。
ここではキューアプリ(App_CUE)に固有の機能を説明します。共通機能については、TWELITE APPS マニュアル のトップページ を参照してください。
インタラクティブモードに入ると以下の画面が表示されます。
--- CONFIG/App_CUE V1-00-2/SID=0x810ba765/LID=0x01 ---
a: set Application ID (0x67720102)
i: set Device ID (--)
c: set Channels (18)
x: set Tx Power (13)
b: set UART baud (38400)
B: set UART option (8N1)
k: set Enc Key (0xA5A5A5A5)
o: set Option Bits (0x00000001)
t: set Transmission Interval (5)
p: set Senser Parameter (0x00000000)
---
S: save Configuration
R: reset to Defaults
設定コマンド一覧 コマンド 設定項目 初期値 説明 a アプリケーションID 0x67720102 同一の周波数チャネルを複数のグループで使用することが可能です。値は32ビットで設定します。 i 論理デバイスID – 子機の論理デバイスIDを設定します。1~100までの値を設定できます。 設定値が “–” の場合は、論理デバイスIDは内部で1に設定されます。 c 周波数チャネルの設定 18 チャネル(11~26)を選択します。省電力動作を優先する観点から、複数チャネルの指定は無効としています。 x 送信出力の設定 13 1桁、または2桁の数字を指定します。2桁目は省略可能です。 1桁目は、送信出力を設定します。3が最強で2,1,0と1段階小さくなるたびに -11.5db 出力が低下します。出力を制限し電波の有効伝達範囲を小さくしたい場合に使用します。ただし、伝達可能距離は環境(ノイズ・遮蔽物など)に影響を受けます。 ※ 理論上の伝達距離は 6db 出力が小さくなるたびに 1/2 になりますので、1段階小さくすることで伝達距離は約1/4になります。 2桁目は再送回数を設定します。2桁目は 0~9を指定し、0はデフォルトで再送なし、1~9は再送回数に対応します。 例: 3 -> 再送なし・最強出力(デフォルト、省略時) 42 -> 再送4回・出力は2(1段階弱める) b UARTボーレートの設定 38400 入力値にかかわらず115200bps固定です。 B UARTパリティの設定 8N1 入力値にかかわらず8N1で固定です。 k 暗号化鍵の設定 0xA5A5A5A5 暗号化鍵を入力します。32bitの16進数を設定します。通信グループ内は全て同一の値に設定してください。 o オプションビットの設定 0x00000001 各種詳細設定ができます。 t 送信間隔の設定 5 定期送信パケットの送信間隔を秒単位で設定します。1〜4095の値で指定可能です。範囲外の設定をした場合の動作は不定です。 p センサ固有パラメータの設定 0 モードの切り替えやパラメータの設定をします。0以上の16進数で指定できます。詳細は、各種モード のページを参照ください。 S 設定値の保存 設定を保存し、モジュールを再起動します。 R 初期値に設定を戻す 設定を初期化します。他の操作を行わず、続けてS キーによる設定の保存を行うとセーブ領域のクリアを行います。
オプションビットの設定 オプションビット設定値を各ビットごとに解説します。
ビット(16進) 説明 0x00000001 各中継機または親機宛に送信し、受信した中継機すべての情報が親機に転送され、シリアル出力されます。 この場合、複数の受信パケットを分析する事で一番近くで受信したルータを特定することができます。 0x00000040 OTAを無効にする。 0x00001000 暗号化通信を有効にします。(相手側の暗号化設定もしてください。) 0x00010000 UART通信でのメッセージ出力を有効にします。
1.3.6 - アリアアプリ マニュアル 温度・湿度を無線でお知らせ。
アリアアプリ(App_ARIA)は磁気・湿度・温度センサータグ TWELITE ARIA専用のアプリです。
1.3.6.1 - アリアアプリ マニュアル 最新版
1.3.6.1.1 - アリアアプリの使用方法 アリアアプリの使用方法
アリアアプリの使用方法を2つのステップに分けて説明します。
1.3.6.1.1.1 - アリアアプリの動作確認 MONOSTICKとPCを使用して、TWELITE ARIAの動作確認を行う
TWELITE CUEとMONOSTICKを使用して温度を計測してみましょう。
必要なもの TWELITE CUE MONOSTICK 電池を入れる CR2032電池の+側を電池ホルダー(+)の向きで差し込みます。TWELITE CUEのLEDが3回点滅すれば正常です。 起動後は5秒毎に送信をし、送信時にLEDが1回点滅します。
電池の装着
電池の向きに注意してください。逆に入れた場合、発熱し故障の原因になります。
また、TWELITE ARIAの電池ホルダーは構造上、半田付け部が外れやすいため、以下に注意して電池を挿入してください。
コイン電池の取り外し時には電池ホルダーの半田付け部に力がかかりにくくなるように、電池ホルダーを上から軽く指で押さえながらコイン電池を取り外すことを推奨します。 TWELITE ARIAの運用時は、専用ケースで電池ホルダーを上から押さえながら使用することを推奨します。 固定用磁石を取り付ける 図の位置の窪みに磁石を取り付けると、TWELITE ARIAを金属面に貼り付けることができます。必要に応じてお使いください。
磁石の設置箇所
ケースに入れる 丸印で示したようにケースの縁にある爪に引っ掛けて収めてください。
基板の挿入
必要に応じてねじ止めをしてください。ねじ穴はストラップを通したり、対象物への固定用にも使用できます。
ケースを開ける ケースの切り込みにコインを差し込みこじ開けてください。
コインを差し込む場所
親機・中継機の準備 通信相手として親機が必要です。通信距離を延長する場合は中継機 が使用できます。親機、中継機にはMONOSTCK - モノスティック を使用することができます。
MONOSTCK - モノスティックのアプリは親機・中継機アプリ Wings-ウイングス のバージョンv1-01-4以上を書き込んでください。
動作確認をする TWELITE ARIAを動かしたり、磁石を近づけたりして、パソコンに接続したMONOSTICKで受信したデータを確認してみましょう。
TWELITE STAGE SDKの準備 まず最初にTWELITE STAGE SDK の最新版をパソコンにインストールします。
TWELITE STAGE APPを起動する MONOSTICKをパソコンのUSBポートに接続します。 インストールしたTWELITE STAGE SDKのMWSTAGEフォルダ内の以下のファイルをダブルクリックしてください。 ・TWELITE_stage.exe(Windows) ・TWELITE_stage.command(macOS) ・TWELITE_stage.run(Linux) 起動するとUSBに接続されたMONOSTICKが画面上に表示されます。 シリアルポート選択画面から1: MONOSTICKを選択してください。 デバイスを選択するとTWELITE STAGE APPのトップメニュー画面が表示されます。 親機の準備 通信相手として親機が必要です。親機にはMONOSTCK - モノスティック を使用することができます。 以下の手順で親機・中継機アプリ Wings-ウイングス をMONOSTICK - モノスティックに書き込んでください。
トップメニューから 2:アプリの書換 > 1:BINから選択を選択してください。 MONOSTICK BLUE を使用している場合はApp_Wings_MONOSTICK_BLUE_… を選択し、MONOSTICK RED を使用している場合はApp_Wings_MONOSTICK_RED_… を選択してください。 書き込み完了後はインタラクティブモードに入らずにESCキーを長押ししてトップメニューに戻ってください。 ビューアを選択する トップメニューから 1:ビューア > 4: CUE/ARIAビューア を選択します。 TWELITE ARIA タブをクリックします。 TWELITE ARIAビューア
TWELITE ARIAの動作確認をする 温度、湿度を計測する 5秒ごとに温湿度の値が更新されます。
磁石を検出させる 磁石のN極を磁気センサーに近づけると「[N極]」と表示されます。 磁石のS極を磁気センサーに近づけると「[S極]」と表示されます。 磁石を磁気センサーから遠ざけると「 —- 」と表示されます。 モードを変更する モードを変更することで、TWELITE ARIAの振る舞いを変更することができます。
詳しくは以下のページをご確認ください。
モード選択
設定を変更する グループ分けや送信頻度の変更などはインタラクティブモードで設定できます。
インタラクティブモードへの移行方法は以下のページをご確認ください。
設定方法
また、設定できる項目については以下のページをご確認ください。
インタラクティブモード
ログを出力する パルスクリプトで温湿度などのデータをCSV形式でログに出力することができます。
詳しくは以下のページをご確認ください。
パルスクリプト
グラフを描画する パルビューアで温湿度や磁気センサーの値をグラフで見ることができます。
詳しくは以下のページをご確認ください。
パルビューア
1.3.6.1.1.2 - アリアアプリの動作モード アリアアプリの動作モード
アリアアプリには、TWELITE ARIAモードと開閉センサーパルモードの2種類の動作モードがあります。
TWELITE ARIAモード TWELITE ARIAの初期モードです。
温湿度計測とドアの開閉の検知を同時に行うことができるオールインワンモードです。
開閉センサーパルモード 開閉センサーパルとして動作するモードです。
ドアの開閉や工場設備の稼働状況を計測する場合は本モードを使用します。
1.3.6.1.1.2.1 - アリアアプリのTWELITE ARIAモード 初期設定のモード
温湿度の計測、磁石の有無のすべてを試すことができるオールインワンモードです。
工場出荷時は本モードに設定されております。
設定 本モードを使用する場合は以下の項目を設定してください。
設定コマンド 設定項目 設定値 備考 p センサ固有パラメータの設定 00000000
親機の出力 代表的な電池寿命 5秒に1度の定期送信のみの場合、約340日 5秒に1度の定期送信 + 1分に1度磁石を近づけた場合、約300日 1分に1度の定期送信のみの場合、約4年 1分に1度の定期送信 + 1分に1度磁石を近づけた場合、約2.5年
消費電流は試験用のサンプル個体の実測に基づき、CR2032の容量を220mAhとして計算しています。電池寿命は参考値であり、保証値ではありません。電池の性能や使用温度等の使用環境で変化します。
1.3.6.1.1.2.2 - アリアアプリの開閉センサーパルモード 開閉センサーパルとして動作するモード
モノに装着し、磁石の有無で開閉を知ることができるモードです。
設定 本モードを使用する場合は以下の項目を設定してください。
設定コマンド 設定項目 設定値 備考 p センサ固有パラメータの設定 04000000
親機の出力 代表的な電池寿命 1日に200回の開閉を行なった場合、約4年です。(含1分毎の定期送信) 1日に0回の開閉を行なった場合、約4.5年です。(含1分毎の定期送信)
消費電流は試験用のサンプル個体の実測に基づき、CR2032の容量を220mAhとして計算しています。電池寿命は参考値であり、保証値ではありません。電池の性能や使用温度等の使用環境で変化します。
1.3.6.1.2 - アリアアプリの設定方法 アリアアプリの設定方法
アリアアプリを設定する方法は以下の2種類あります。
設定できる内容に関してはインタラクティブモードをご確認ください。
OTAによる設定 OTAとはOver the Airの略です。非接触での通信を意味します。OTA設定はインタラクティブモード の設定をケーブル接続不要で行う機能です。
OTAを実行するには MONOSTICK-モノスティック が必要です。
TWELITE R2を使用する設定 TWELITE CUEの7PインターフェイスにTWELITE R2/R3 を接続し、インタラクティブモードで設定を行うことも可能です。
1.3.6.1.2.1 - アリアアプリのOTAによる設定 TWELITE ARIAとMONOSTICKとの無線通信による設定
OTA設定は、インタラクティブモードの設定を無線経由で行う機能です。
OTAによる設定手順 以下の手順でOTAによる設定を行います。
1. TWELITE STAGE APPを起動する パソコンにTWELITE STAGE SDK をインストール し、MWSTAGEフォルダ内のTWELITE_Stage
を起動する。
2. MONOSTICKにOTA設定用のアプリを書き込む 2: アプリ書換 > 1: BINから選択 を開き、App_ARIA_OTA_...
を選択する。
3. インタラクティブモードで設定値を入力する 3: インタラクティブモード を選択し、値を編集・保存する。
4. OTA設定を実行する MONOSTICKから約20cm以内の距離に TWELITE ARIA を置く。本体の電源を投入するか、または磁石を磁気センサーへ5回以上接近させて、TWELITE ARIA の LED が点滅することを確認する。
5. MONOSTICKの出力を確認する 次のようなメッセージの出力を確認する。
出力されない場合はこちら
6. MONOSTICKのアプリを書き戻す 2: アプリ書換 > 1: BINから選択 を開き、App_Wings_MONOSTICK_...
を選択する。
OTAに失敗した場合 距離が遠い 次のようなメッセージは、距離が遠いことを示します。
OTA FAILURE
OTA request TS=20515[ms]
LQI:63 (RF strength, >= 100)
SID:810BA765
TWELITE ARIA:v1.1.1
Protocol Version:0x13
--— LQI is small. Please make TWELITE ARIA closer. —--
この場合は、MONOSTICK と TWELITE ARIA の距離を近づけてください。
対象が異なる 次のようなメッセージは、TWELITE ARIA のファームウェアが異なっているか、間違って TWELITE CUE を近づけていることを示します。
OTA FAILURE
OTA request TS=20515[ms]
LQI:180 (RF strength, >= 100)
SID:810BA765
TWELITE ARIA:v1.1.1
Protocol Version:0x11
--— Different protocol version. Please update TWELITE ARIA. —--
この場合は、間違って TWELITE CUE を近づけていないか確認してください。
また、TWELITE ARIA のファームウェアを書き換えていた場合は、TWELITE R2/R3を使って App_ARIA
へ書き戻してください。
1.3.6.1.2.2 - アリアアプリのTWELITE R2/R3による設定 TWELITE ARIAとTWELITE R2/R3を有線で接続して行う設定
TWELITE ARIAの7PインターフェイスへTWELITE R2/R3 を接続することで設定できます。
TWELITE R2との接続例
TWELITE R2/R3を逆向きに接続するとTWELITE ARIAが破損します。
TWELITE R2/R3を使用して設定する場合は以下の手順で設定してください。
1. TWELITE STAGE APPを起動する パソコンへTWELITE STAGE SDK をインストール し、MWSTAGEフォルダ内のTWELITE_Stage
を起動する。
2. インタラクティブモードで設定値を入力する 3: インタラクティブモード を選択し、値を編集・保存する。
1.3.6.1.3 - インタラクティブモード(アリアアプリ) アリアアプリのインタラクティブモード
インタラクティブモードでアプリの詳細設定を行うことができます。
ここではアリアアプリ(App_ARIA)に固有の機能を説明します。共通機能については、TWELITE APPS マニュアル のトップページ を参照してください。
TWELITE がスリープしている間はインタラクティブモードを使用できません。
SET
ピンをGND
へ接続した状態で起動してください。TWELITE STAGE アプリと TWELITE R2/R3 は、自動的にこの操作を行います。
表示例 次のような画面を表示します。
--- CONFIG/App_ARIA V1-01-0/SID=0x810a7817/LID=0x01 ---
a: set Application ID (0x67720102)
i: set Device ID (--)
c: set Channels (18)
x: set Tx Power (13)
b: set UART baud (38400)
B: set UART option (8N1)
k: set Enc Key (0xA5A5A5A5)
o: set Option Bits (0x00000001)
t: set Transmission Interval (5)
p: set Senser Parameter (0x00000000)
d: set Temperature Coefficient (0)
D: set Temperature Offset (0)
f: set Humidity Coefficient (0)
F: set Humidity Offset (0)
---
S: save Configuration
R: reset to Defaults
コマンド 各コマンドの詳細を次に示します。
a
:アプリケーションID通信を行う端末はすべて同一の値とします。論理的にネットワークを分離します。
i
:論理デバイスID複数の子機を識別する必要がある場合に設定します。
1
-100
の任意の値を設定できます。
c
:周波数チャネル通信を行う端末はすべて同一の値とします。物理的にネットワークを分離します。
x
:送信出力と再送回数電波の送信出力と、透過モードおよびヘッダ付き透過モードにおいてパケットを追加で送信する回数を指定します。
b
:UART代替ボーレート適用できません。TWELITE DIP 等の製品とは異なり BPS
ピンがないからです。
B
:UARTオプション適用できません。TWELITE DIP 等の製品とは異なり BPS
ピンがないからです。
k
:暗号鍵オプションビットの暗号化通信の有効化 を設定した場合の暗号化鍵を32bitの16進数で指定します。
o
:オプションビット32bit の数値を指定します。各ビットに紐付いた設定を有効化できます。
t
:送信間隔データの送信間隔を指定します。
p
:センサ固有パラメータ動作モード の切り替えに使用します。
d
:温度係数環境センサーパル 0
-60000
の範囲で温度データの係数\(d\)を指定します。
0
の場合は無効です。それ以外の値では、最終的な温度を\(\frac{d}{1024}\)倍とします。
D
:温度オフセット環境センサーパル -2000
-2000
の範囲で温度データのオフセット\(D\)を指定します。
100倍された温度に\(D\)を加算します。最終的な温度は \(\frac{D}{100}\)°C 変化します。
f
:湿度係数環境センサーパル 0
-60000
の範囲で湿度データの係数\(f\)を指定します。
0
の場合は無効です。それ以外の値では、最終的な湿度を\(\frac{f}{1024}\)倍とします。
F
:湿度オフセット環境センサーパル -2000
-2000
の範囲で湿度データのオフセット\(F\)を指定します。
100倍された湿度に\(F\)を加算します。最終的な湿度は \(\frac{F}{100}\)% 変化します。
オプションビットの詳細 オプションビットの値の各ビットに紐付く設定を解説します。
00000001
:中継機への送信を有効化親機だけでなく、中継機へ向けた送信を有効化します。
このオプションを設定していない場合にも中継機を使用できますが、親機は重複して届いたパケットを排除します。このとき、パケットがどの中継機を通して伝わったのか、あるいは中継されていないのかを確かめる術はありません。
このオプションを設定していると、親機は複数の端末から受信した一つのパケットを別々に出力することができます。親機に接続されたデバイスが出力を分析することで、子機がどの端末の近くにあったのかを調べることができます。
00000040
:OTA設定機能を無効化OTA設定の機能を無効化します。
00001000
:暗号化通信の有効化暗号化通信を有効にします。相手側の暗号化通信も有効化する必要があります。
00010000
:子機のUART出力を有効化子機のメッセージ出力を有効化します。
1.3.7 - パルアプリ マニュアル TWELITE PAL シリーズ用
パルアプリ(App_PAL)は、無線タグシステム TWELITE PAL シリーズ専用のアプリです。
工場出荷時の TWELITE BLUE / RED PAL へインストールしています。
1.3.7.1 - パルアプリ マニュアル 最新版
導入方法 パルアプリ(App_PAL
)を書き込むには TWELITE STAGE SDK をインストールして、TWELITE STAGE アプリを使って書き換え てください。
App_PAL_EndDevice
が子機用です。
以前は親機用として App_PAL_Parent
を同梱していましたが、現在は App_Wings
へ統合されています。
対応するハードウェア 開閉センサーパル を装着した TWELITE BLUE / RED PAL 環境センサーパル を装着した TWELITE BLUE / RED PAL 動作センサーパル を装着した TWELITE BLUE / RED PAL 通知パル を装着した TWELITE BLUE / RED PAL
子機の使用上限 1つの親機と通信できる子機の数は、親機へ届くパケットの数によって決まります。
例えば、1つの子機が連続で加速度を送信する場合は、1対1通信を推奨します。
子機が間欠動作をする場合には、すべての子機に対して 0.1*送信機の台数
秒 以上の送信間隔を空けるように推奨しております。例えば、送信を行う子機が10台あるのなら、各子機の送信間隔は1秒以上空けてください。
1.3.7.1.1 - インタラクティブモード(パルアプリ) パルアプリのインタラクティブモード
インタラクティブモードでアプリの詳細設定を行うことができます。
ここではパルアプリ(App_PAL)に固有の機能を説明します。共通機能については、TWELITE APPS マニュアル のトップページ を参照してください。
TWELITE がスリープしている間はインタラクティブモードを使用できません。
SET
ピンをGND
へ接続した状態で起動してください。TWELITE STAGE アプリと TWELITE R2/R3 は、自動的にこの操作を行います。
表示例 次のような画面を表示します。
--- CONFIG/App_PAL V1-05-2/SID=0x810e0e23/LID=0x01 ---
a: set Application ID (0x67726305)
i: set Device ID (--)
c: set Channels (15)
x: set Tx Power (13)
b: set UART baud (38400)
B: set UART option (8N1)
k: set Enc Key (0xA5A5A5A5)
o: set Option Bits (0x00000001)
t: set Transmission Interval (60)
p: set Senser Parameter (0x00000000)
e: set Event Parameter(s) (0180002A0208002A0300802A0488002A0580802A0608802A0880000A1008000A)
d: set Temperature Coefficient (0)
D: set Temperature Offset (0)
f: set Humidity Coefficient (0)
F: set Humidity Offset (0)
---
S: save Configuration
R: reset to Defaults
コマンド 各コマンドの詳細を次に示します。
a
:アプリケーションID通信を行う端末はすべて同一の値とします。論理的にネットワークを分離します。
i
:論理デバイスID複数の子機を識別する必要がある場合に設定します。
識別の必要がない、できない場合は120
としてください。識別の必要がある場合は、子機は1
-100
の任意の値に、親機は0
あるいは121
としてください。
c
:周波数チャネル通信を行う端末はすべて同一の値とします。物理的にネットワークを分離します。
x
:送信出力と再送回数電波の送信出力と、透過モードおよびヘッダ付き透過モードにおいてパケットを追加で送信する回数を指定します。
b
:UART代替ボーレートBPS
ピンをGND
へ接続して起動した場合に選択される代替ボーレートを38400
bpsから上書きします。
値は9600
/19200
/38400
/57600
/115200
/230400
から選択できます。他の値を指定すると、誤差が生じる可能性があります。
BPS
ピンを開放して起動した場合、この設定は適用されません。115200
bpsに固定されます。
B
:UARTオプションBPS
ピンをGND
へ接続して起動した場合に選択される代替設定を8N1
から上書きします。
パリティはN
: 無し、O
: Odd(奇数)、E
: Even(偶数)を設定します。ハードウェアフローは設定できません。8N1, 7E2 などと設定できますが、8N1 以外の設定は未検証です。事前に動作をご確認ください。
BPS
ピンを開放して起動した場合、この設定は適用されません。115200
bpsに固定されます。
k
:暗号鍵オプションビットの暗号化通信の有効化 を設定した場合の暗号化鍵を32bitの16進数で指定します。
o
:オプションビット32bit の数値を指定します。各ビットに紐付いた設定を有効化できます。
t
:送信間隔データの送信間隔を指定します。通知パルの場合は、親機へ制御情報を問い合わせて、それをLEDの出力へ反映する間隔を示します。
p
:センサ固有パラメータハードウェアによって異なります。
e
:通知イベント通知パル イベント番号を受信した際の動作を指定します。
詳しくは通知イベントの詳細 をご覧ください。
d
:温度係数環境センサーパル 0
-60000
の範囲で温度データの係数\(d\)を指定します。
0
の場合は無効です。それ以外の値では、最終的な温度を\(\frac{d}{1024}\)倍とします。
D
:温度オフセット環境センサーパル -2000
-2000
の範囲で温度データのオフセット\(D\)を指定します。
100倍された温度に\(D\)を加算します。最終的な温度は \(\frac{D}{100}\)°C 変化します。
f
:湿度係数環境センサーパル 0
-60000
の範囲で湿度データの係数\(f\)を指定します。
0
の場合は無効です。それ以外の値では、最終的な湿度を\(\frac{f}{1024}\)倍とします。
F
:湿度オフセット環境センサーパル -2000
-2000
の範囲で湿度データのオフセット\(F\)を指定します。
100倍された湿度に\(F\)を加算します。最終的な湿度は \(\frac{F}{100}\)% 変化します。
オプションビットの詳細 オプションビットの値の各ビットに紐付く設定を解説します。
00000001
:中継機への送信を有効化親機だけでなく、中継機へ向けた送信を有効化します。
このオプションを設定していない場合にも中継機を使用できますが、親機は重複して届いたパケットを排除します。このとき、パケットがどの中継機を通して伝わったのか、あるいは中継されていないのかを確かめる術はありません。
このオプションを設定していると、親機は複数の端末から受信した一つのパケットを別々に出力することができます。親機に接続されたデバイスが出力を分析することで、子機がどの端末の近くにあったのかを調べることができます。
00001000
:暗号化通信の有効化暗号化通信を有効にします。相手側の暗号化通信も有効化する必要があります。
00010000
:子機のUART出力を有効化子機のメッセージ出力を有効化します。
センサ固有パラメータの詳細 センサ固有パラメータの値に紐付く設定を解説します。
開閉センサーパル 使用しません。
環境センサーパル 使用しません。
動作センサーパル 32bitの数値を指定します。
bit 31-28 27-24 23-20 19-16 15-12 11-8 7-4 3-0 機能 - - - - ATH
SFQ
SCT:7-4
SCT:3-0
初期値 0
0
0
0
0
0
0
0
各機能は次の内容を示します。
SCT
:サンプル数SCT
は送信するサンプル数に影響します。
間欠送信モード ATH
を0
かつt
:送信間隔 を0
以外とした場合は、間欠送信モードとなります。
SCT
の値を\(C_i\)としたとき、サンプル数は\(16C_i+16\)と表すことができます。
p
SCT
サンプル数 0x??????00
0x00
16サンプル(初期設定) 0x??????01
0x01
32サンプル … 0x??????07
0x07
128サンプル … 0x??????FF
0xFF
4096サンプル
アクティブ検出モード ATH
とt
:送信間隔 を0
以外とした場合は、アクティブ検出モードとなります。
アクティブ検出モードでは、ATH
によって与えられる加速度のしきい値を超えたとき、直前の30サンプルに加えて 直後のサンプルを送信します。
SCT
の値を\(C_a\)としたとき、直後のサンプル数は\(30C_a+30\)と表すことができます。
p
SCT
直後のサンプル数 0x??????00
0x00
30サンプル(初期設定) 0x??????01
0x01
60サンプル … 0x??????07
0x07
240サンプル … 0x??????FF
0xFF
7680サンプル
SFQ
:サンプリング周波数SFQ
は加速度データのサンプリング周波数に影響します。
p
SFQ
サンプリング周波数 0x?????0??
0x0
25Hz(初期設定) 0x?????1??
0x1
50Hz 0x?????2??
0x2
100Hz 0x?????3??
0x3
190Hz
ATH
:アクティブ検出モードATH
はアクティブ検出モードの振る舞いに影響します。
0
の場合は無効となり、1
-F
の場合はその値をしきい値として有効となります。
p
ATH
内容 0x????0???
0x0
無効(初期設定) 0x????1???
0x1
1G(非推奨) 0x????2???
0x2
2G … 0x????F???
0xF
15G
ATH
を1
とした場合、定置していても常にアクティブ状態となってしまいます。
通知パル 32bitの数値を指定します。
00000000
:タップ&シェイクモードタップ(軽く叩く)やシェイク(振る)をした時にデータを送信します。
00000001
:サイコロモード6通りの上面を検出し、データを送信します。
通知イベントの詳細 値は最大68バイトのバイナリデータであり、16進数の文字列で表現します。
一つのイベントは4バイトで構成します。イベントの最大数は17です。
# データ 内容 備考 1番目のイベント 0 uint8
イベントID 0x00
-0x10
1 uint8
赤と緑の輝度 赤0x0?
-0xF?
, 緑0x?0
-0x?F
2 uint8
青と白の輝度 青0x0?
-0xF?
, 白0x?0
-0x?F
3 uint8
点滅パターンと点灯時間 点滅パターン 常時点灯0x0?
, 遅0x1?
, 並0x2?
, 早0x3?
点灯時間 消灯しない0x?0
, 秒指定0x?1
-0x?F
2番目のイベント 4 uint8
イベントID 0x01
-0x10
5 uint8
赤と緑の輝度 赤0x0?
-0xF?
, 緑0x?0
-0x?F
6 uint8
青と白の輝度 青0x0?
-0xF?
, 白0x?0
-0x?F
7 uint8
点滅パターンと点灯時間 点滅パターン 常時点灯0x0?
, 遅0x1?
, 並0x2?
, 早0x3?
点灯時間 消灯しない0x?0
, 秒指定0x?1
-0x?F
3番目のイベント <省略> 17番目のイベント 64 uint8
イベントID 0x01
-0x10
65 uint8
赤と緑の輝度 赤0x0?
-0xF?
, 緑0x?0
-0x?F
66 uint8
青と白の輝度 青0x0?
-0xF?
, 白0x?0
-0x?F
67 uint8
点滅パターンと点灯時間 点滅パターン 常時点灯0x0?
, 遅0x1?
, 並0x2?
, 早0x3?
点灯時間 消灯しない0x?0
, 秒指定0x?1
-0x?F
設定データの例 初期設定の例を示します。
0180002A0208002A0300802A0488002A0580802A0608802A0880000A1008000A
# データ 内容 値 1番目のイベント 01
0 uint8
イベントID 0x01
80
1 uint8
赤と緑の輝度 赤8
/15
, 緑0
/15
00
2 uint8
青と白の輝度 青0
/15
, 白0
/15
2A
3 uint8
点滅パターンと点灯時間 並, 10
秒 2番目のイベント 02
4 uint8
イベントID 0x02
08
5 uint8
赤と緑の輝度 赤0
/15
, 緑8
/15
00
6 uint8
青と白の輝度 青0
/15
, 白0
/15
2A
7 uint8
点滅パターンと点灯時間 並, 10
秒 3番目のイベント <省略> 8番目のイベント 10
28 uint8
イベントID 0x10
08
29 uint8
赤と緑の輝度 赤0
/15
, 緑8
/15
00
30 uint8
青と白の輝度 青0
/15
, 白0
/15
0A
31 uint8
点滅パターンと点灯時間 常時点灯, 10
秒
1.4 - act サンプル act のサンプルプログラム
MWSDK/Act_Samples
ディレクトリには、actのサンプルプログラムを格納しています。
1.4.1 - act サンプル 最新版
MWSDK/Act_Samples
ディレクトリには、actのサンプルプログラムを格納しています。
サンプルの紹介 以下には、目的別のアクトを紹介します。
無線通信を行わなず、マイコン機能のみの短いアクト act0..4
無線機能などを使わないごくシンプルな例です。actの基本構造が理解できます。
I2C センサーを用いたアクトの記述例 I2Cセンサーを接続し、スリープによる簡潔動作を行いながら無線パケットを送信する、無線センサーの実装例です。
比較的簡潔的かつ代表的な構造ですので、act0からact4を確認してから参照することを推奨します。
BRD_I2C_TEMPHUMID
TWELITE で無線センサーを実装するための代表的な要素(シンプル中継ネット <NWK_SIMPLE>
の利用・インタラクティブモード <STG_STD>
、I2Cセンサーの取り扱い Wire
、スリープによる間欠動作など)が含まれます。
無線通信を行う基本的なアクト 無線パケットを送信、または送受信するサンプルですが、各々少し違った視点で実装されています。
Scratch
UARTから1バイトコマンドを受けて、送信などを行うシンプルなコードです。
Slp_Wk_and_Tx
ステートマシンを用い、スリープを用いた間欠動作で、スリープ復帰→無線送信→スリープを繰り返します。
PingPong
一方から他方にパケットを送信し、受信した他方がパケットを送り返すサンプルです。送信と受信についての基本的な手続きが含まれます。
WirelessUART
UART入力をserparser
を用いてアスキー形式を解釈してから、これを送信します。
親機側のアクト
注:このサンプルに含まれるアクトの無線パケットの受信には、
App_Wings を利用することもできます。
独自の受信側親機アプリケーションを実装するときに参照してください。
Parent-MONOSTICK
専ら受信のみを行い、シリアルポートへ受信結果を出力します。このサンプルの無線パケットで、親機向け(0x00
)や子機ブロードキャスト(0xFE
)とアドレス設定しているものは受信できます。またインタラクティブモード<STG_STD>
をactに追加するための手続きが含まれます。
Rcv_Univsl
ユニバーサルパケットレシーバ (TWENETレイヤーツリーネットワーク, App_Twelite
, act
, … など) のサンプルコードです。また、コンテナやアルゴリズムにEASTLライブラリを使用しています。
インタラクティブモードを追加するためのアクト インタラクティブモードを使用するアクトの解説には大まかな流れを記しています(ここでは上述の BRD_I2C_TEMPHUMID
を引用します)。どのサンプルの解説も大きな差はありません。
BRD_I2C_TEMPHUMID
I2Cセンサーデバイスの読み書きコマンドを実行し I2C センサーから得られた計測値を無線送信します。またインタラクティブモード<STG_STD>
をactに追加するための手続きが含まれます。
Settings
インタラクティブモード<STG_STD>
のより高度なカスタマイズを行います。詳細はコードを参照ください。
センサーなどのデバイスを動作させるためのアクト 内蔵ペリフェラルや外部センサーデバイスからセンサー情報を得るサンプルです。
BRD_APPTWELITE
ディジタル入力、アナログ入力、ディジタル出力、アナログ出力を用いた双方向通信を行っています。またインタラクティブモード<STG_STD>
をactに追加するための手続きが含まれます。
BRD_I2C_TEMPHUMID
I2Cセンサーデバイスの読み書きコマンドを実行し I2C センサーから得られた計測値を無線送信します。またインタラクティブモード<STG_STD>
をactに追加するための手続きが含まれます。
PulseCounter
パルスカウンター機能を用い、スリープ中も含め入力ポートで検出したパルス数を計数し、これを無線送信します。
PAL_AMB_behavior
ビヘイビアを用いた例です。PAL_AMBでは温湿度センサーはライブラリ内部のコードが呼ばれますが、このサンプルでは温湿度センサーのアクセスのための独自の手続きも含まれます。
TWELITE PAL を使用するためのアクト TWELITE PAL には標準的なPALアプリが書き込まれていますが、PALアプリを用いずアクトによる記述を行うことができます。MWXライブラリには、PALで使用するセンサーを動作させるための標準的な手続きが用意されています。
各種PAL基板用のサンプルです。PAL基板上のセンサー値を取得し、送信し、スリープします。
PAL_AMB
PAL_MOT-single
PAL_MAG
以下は応用例で、上記のアクトより少し複雑な記述になっています。
PAL_AMB_usenap
は、数十msかかるセンサーの動作時間にTWELITEマイコンを短くスリープさせ、より省電力を目指すサンプルです。PAL_AMB_behavior
は、ビヘイビアを用いた例です。PAL_AMBでは温湿度センサーはライブラリ内部のコードが呼ばれますが、このサンプルでは温湿度センサーのアクセスのための独自の手続きも含まれます。PAL_MOT_fifo
は、加速度センサーのFIFOおよびFIFOの割り込みを用いて、サンプルを中断することなく、連続的に取得し無線送信するためのサンプルです。TWELITE CUE を使用するためのアクト PAL_MOT
アクトが利用できます。軽微な修整が必要となる場合があります。
PAL_MOT-single
PAL_MOT_fifo
は、加速度センサーのFIFOおよびFIFOの割り込みを用いて、サンプルを中断することなく、連続的に取得し無線送信するためのサンプルです。TWELITE ARIA を使用するためのアクト BRD_ARIA
は、TWELITE ARIA を動作させるためのアクトです。BRD_I2C_TEMPHUMID
は、I2C センサー利用のためのテンプレートですが、実装例として TWELITE ARIA で利用する SHT40 センサー用のコードが含まれます。PAL_AMB
用のアクトを修整することで利用できます。単体機能を紹介したアクト Unit-*
は機能やAPIの紹介を目的としています。
最新版の入手 共通の記述 アクトのサンプル中で以下の項目は共通の設定項目になり、以下で解説します。
const uint32_t APP_ID = 0x1234abcd ;
const uint8_t CHANNEL = 13 ;
const char APP_FOURCHAR[] = "BAT1" ;
サンプルアクト共通として以下の設定をしています。
アプリケーションID 0x1234abcd チャネル 13 アプリケーションIDとチャネルはともに他のネットワークと混在しないようにする仕組みです。
アプリケーションIDが異なる者同士は、チャネルが同じであっても混信することはありません 。ただし、別のアプリケーションIDのシステムが頻繁に無線送信しているような場合はその無線送信が妨害となりますので影響が認められます。
チャネルは通信に使う周波数を決めます。TWELITE無線モジュールでは原則として16個のチャネルが利用でき 、通常のシステムでは実施しないような極めて例外的な場合を除いて、他のチャネルとは通信できません。
サンプルアクト共通の仕様として、パケットのペイロード(データ部)の先頭には4バイトの文字列(APP_FOURCHAR[]
)を格納しています。種別の識別性には1バイトで十分ですが、解説のための記述です。こういったシステム特有の識別子やデータ構造を含める ことも混信対策の一つであるといえます。
1.4.1.1 - act0..4 最初に試すシンプルなact(アクト)
act0 から始まるアクト(act)は、actを始める - Opening act で紹介されたものを収録しています。LEDやボタンの動作のみの単純なものですが、最初にお試しいただくことをお勧めします。
act0
処理の記述がないテンプレート
act1
Lチカ(LEDの点滅)
act2
タイマーを用いたLチカ
act3
2つのタイマーを用いたLチカ
act4
ボタン(スイッチ)を用いたLED点灯
1.4.1.2 - Scratch テンプレートコード
テンプレートとなるアクトです。
このアクトには以下が含まれます。
無線パケットの送信 (’t’ キー) スリープ (’s’キー) シリアルポートからの入力 - Serial
ディジタル(ボタン)入力 - Buttons
setup()
void setup () {
/*** SETUP section */
tx_busy = false;
// 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 && nwk = the_twelite.network.use< NWK_SIMPLE> ();
nwk << NWK_SIMPLE:: logical_id(0xFE ); // set Logical ID. (0xFE means a child device with no ID)
/*** BEGIN section */
Buttons.begin(pack_bits(PIN_BTN), 5 , 10 ); // check every 10ms, a change is reported by 5 consequent values.
the_twelite.begin(); // start twelite!
/*** INIT message */
Serial << "--- Scratch act ---" << mwx:: crlf;
}
the_twelite
を設定してアプリケーションID APP_ID
, 無線チャネル CHANNEL
、受信有を設定します。
またnwk
を生成し、子機アドレス0xFE
を指定しています。このアドレスは子機でアドレスを指定していない名無しの子機という意味です。
設定できるアドレスは0x00
: 親機,0x01
~0xEF
: 子機, 0xFE
:子機アドレス未指定の範囲です。
送信先として指定するアドレスは0x00
は親機宛、0x01
~0xEF
は指定の親機アドレス、0xFE
は任意の子機アドレス、0xFF
は親機を含む任意のアドレスです。
またButtons
オブジェクトを初期化します。連続参照によるチャタリング抑制アルゴリズムです。10msごとに5回連続同じ値になれば対象のポート(PIN_BTN
のみ)のHIGH
またはLOW
を確定します。pack_bits(N1, N2, ..)
は1UL<<N1 | 1UL << N2 | ...
を行いビットマップを生成します。
the_twelite.begin(); // start twelite!
the_twelite
を開始するための手続きです。act0..4
では出てきませんでしたがthe_twelite
の設定や各種ビヘイビアの登録を行った場合は、必ず呼び出すようにしてください。
begin()
void begin () {
Serial << "..begin (run once at boot)" << mwx:: crlf;
}
始動時setup()
の後に1回だけ呼び出されます。メッセージの表示のみ。
loop()
ボタン(スイッチ)の入力検出
if (Buttons.available()) {
uint32_t bm, cm;
Buttons.read(bm, cm);
if (cm & 0x80000000 ) {
// the first capture.
}
Serial << int (millis()) << ":BTN" << format("%b" ) << mwx:: crlf;
}
Buttons
による連続参照により状態を確定します。ボタン状態が変化したらシリアルに出力します。
シリアルからの入力
while (Serial.available()) {
int c = Serial.read();
Serial << '[' << char (c) << ']' ;
switch (c) {
case 'p' : ... // millis() を表示
case 't' : ... // 無線パケットを送信 (vTransmit)
if (! tx_busy) {
tx_busy = Transmit();
if (tx_busy) {
Serial << int (millis()) << ":tx request success! ("
<< int (tx_busy.get_value()) << ')' << mwx:: crlf;
} else {
Serial << int (millis()) << ":tx request failed" << mwx:: crlf;;
}
}
case 's' : ... // スリープする
Serial << int (millis()) << ":sleeping for " << 5000 << "ms" << mwx:: crlf << mwx:: flush;
the_twelite.sleep(5000 );
break ;
}
}
Serial.available()
がtrue
の場合は、シリアルポートからの入力が保存されています。シリアルから1文字読み込んで、入力文字に応じた処理をします。
’t’を入力して無線送信 ’t’を入力したときは送信を行います。このサンプルではtx_busy
フラグを用い連続的に入力は行わないようにしています。
送信要求は一定数までキューに保存されるため、キューの範囲(3パケット)で要求を積むことは可能です。
以下はif(!tx_busy)
の判定をしないようにして ’tttt’と連続的に入力した場合の処理例です。4つ目の要求でキューが一杯になって要求は失敗しています。
Transmit()
の.prepare_tx_packet()
で得られたpktオブジェクトが false
になります。
送信タイミングはランダム化されるため、送信完了は送信要求順にはなりません。
--- Scratch act ---
..begin (run once at boot)
[t]11591:Transmit()
11592:tx request success! (1)
[t]11593:Transmit()
11593:tx request success! (2)
[t]11594:Transmit()
11595:tx request success! (3)
[t]11595:Transmit()
TX QUEUE is FULL
11596:tx request failed
11654:tx completed!(id=2, stat=1)
11719:tx completed!(id=3, stat=1)
11745:tx completed!(id=1, stat=1)
’s’を入力してスリープ
5000ms=5秒のスリープを実施します。復帰後はwakeup()
が実行されます。
wakeup()
void wakeup () {
Serial << int (millis()) << ":wake up!" << mwx:: crlf;
}
スリープ起床時に最初に呼び出されます。メッセージの表示のみ。
Transmit()
MWX_APIRET Transmit () {
Serial << int (millis()) << ":Transmit()" << mwx:: crlf;
if (auto && pkt = the_twelite.network.use< NWK_SIMPLE> ().prepare_tx_packet()) {
// set tx packet behavior
pkt << tx_addr(0xFF ) // 同報通信=ブロードキャスト
<< tx_retry(0x1 ) // 再送1回
<< tx_packet_delay(100 ,200 ,20 ); // 送信時遅延100-200msの間に送信、再送間隔20ms
// 送信データの指定(アプリケーションごとに決める)
pack_bytes(pkt.get_payload()
, make_pair("SCRT" , 4 ) // 4文字識別子
, uint32_t (millis()) // タイムスタンプ
);
// 送信要求を行う
return pkt.transmit();
} else {
// .prepare_tx_packet() 時点で失敗している(送信キューが一杯)
Serial << "TX QUEUE is FULL" << mwx:: crlf;
return MWX_APIRET(false, 0 );
}
}
送信要求を行う最小限の手続きです。
この関数を抜けた時点では、まだ要求は実行されていません。しばらく待つ必要があります。この例では100-200msの送信開始の遅延を設定しているため、送信が開始されるのは早くて100ms後です。
on_tx_comp()
void on_tx_comp (mwx:: packet_ev_tx& ev, bool_t & b_handled) {
Serial << int (millis()) << ":tx completed!"
<< format("(id=%d, stat=%d)" , ev.u8CbId, ev.bStatus) << mwx:: crlf;
tx_busy = false; // clear tx busy flag.
}
送信完了時に呼び出されます。ev
には送信IDと完了ステータスが含まれます。
on_rx_packet()
void on_rx_packet (packet_rx& rx, bool_t & handled) {
Serial << format("rx from %08x/%d" ,
rx.get_addr_src_long(), rx.get_addr_src_lid()) << mwx:: crlf;
}
パケットを受信したら、送信元のアドレス情報を表示します。
1.4.1.3 - Slp_Wk_and_Tx スリープ起床時にパケットを送信する
Slp_Wk_and_Tx
は、定期起床後、何か実行(センサーデータの取得など)を行って、その結果を無線パケットとして送信するようなアプリケーションを想定した、テンプレートソースコードです。
setup()
, loop()
の形式では、どうしても loop()
中が判読しづらい条件分岐が発生しがちです。本actでは、loop()
中をSM_SIMPLE
ステートマシンを用いて _switch_
構文による単純な状態遷移を用いることで、コードの見通しを良くしています。
このアクトには以下が含まれます。
代表的な間欠動作(スリープ→起床→計測→無線送信→スリープ)の制御構造 送信パケットの生成と送信手続き、完了待ち アクトの機能 起動後、初期化処理を経て、一旦スリープするsetup()
初期化するbegin()
スリープ実行する スリープ起床後、状態変数を初期化し、以下の順に動作を行うwakeup()
スリープからの起床、各初期化を行うloop()
状態INIT
->WORK_JOB
に遷移: 何らかの処理を行う(このactでは 1ms ごとの TickCount
ごとにカウンタを更新し乱数で決めたカウント後にTX
状態に進む)loop()
状態TX
送信要求を行うloop()
状態WAIT_TX
送信完了待ちを行うloop()
状態EXIT_NORMAL
スリープする (1. に戻る) loop()
状態EXIT_FATAL
エラーが発生した場合は、モジュールリセットするアクトの解説 宣言部 インクルード
#include <TWELITE>
#include <NWK_SIMPLE>
#include <SM_SIMPLE>
#include "Common.h"
パケット送信を行うため <NWK_SIMPLE>
をインクルードしています。また、アプリケーションIDなど基本的な定義は "Common.h"
に記述しています。
状態定義 loop()
内の順次処理を記述うするため、このサンプルではステートマシン(状態遷移)の考え方を用います。ごく単純な状態遷移の処理をまとめた<SM_SIMPLE>
を用います。
Common.h
に以下の状態に対応する列挙体 STATE
が定義されています。
enum class STATE {
INIT = 0 , // INIT STATE
WORK_JOB, // do some job (e.g sensor capture)
TX, // reuest transmit
WAIT_TX, // wait its completion
EXIT_NORMAL, // normal exiting.
EXIT_FATAL // has a fatal error (will do system reset)
};
状態を示す列挙体STATE
を用いてSM_SIMPLE
ステートマシン(状態遷移)を宣言します。
ここで宣言されたstep
は、状態の管理、タイムアウト、処理待ちを行うための機能が含まれています。
センサーデータ このサンプルではセンサーデーターの処理は行いませんが、ダミーデータを用意しておきます。
struct {
uint16_t dummy_work_ct_now;
uint16_t dummy_work_ct_max; // counter for dummy work job.
} sensor;
setup()
void setup () {
/*** SETUP section */
step.setup(); // init state machine
// 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(false); // open receive circuit (if not set, it can't listen packts from others)
// Register Network
auto && nwk = the_twelite.network.use< NWK_SIMPLE> ();
nwk << NWK_SIMPLE:: logical_id(DEVICE_ID); // set Logical ID.
/*** BEGIN section */
the_twelite.begin(); // start twelite!
/*** INIT message */
Serial << "--- Sleep an Tx Act ---" << crlf;
}
変数やクラスオブジェクトの初期化を行います。
step
ステートマシンの初期化the_twelite
クラスオブジェクトの初期化ネットワーク <NWK_SIMPLE>
の登録と初期化(DEVICE_ID
の登録)を行います。 つづいてクラスオブジェクトやハードウェアなどの開始処理を行います。
the_twelite.begin(); // start twelite!
the_twelite
を開始するための手続きです。act0..4
では出てきませんでしたがthe_twelite
の設定や各種ビヘイビアの登録を行った場合は、必ず呼び出すようにしてください。
begin()
void begin () {
Serial << "..begin (run once at boot)" << crlf;
SleepNow();
}
setup()
の直後に一度だけ呼び出されます。SleepNow()
関数を呼び出して初回のスリープ手続きを行います。
wakeup()
void wakeup () {
memset(& sensor, 0 , sizeof (sensor));
Serial << crlf << int (millis()) << ":wake up!" << crlf;
}
起床直後に呼び出されます。ここではセンサーデータ領域の初期化と、起床時のメッセージを出力しています。
loop()
void loop () {
do {
switch (step.state()) {
case STATE:: INIT:
sensor.dummy_work_ct_now = 0 ;
sensor.dummy_work_ct_max = random(10 ,1000 );
step.next(STATE:: WORK_JOB);
break ;
...
}
} while (step.b_more_loop());
}
上記のコードは、実際のコードを簡略化したものです。
この制御構造はSM_SIMPLE
ステートマシンを利用しています。do..while()
構文のループになっています。ループの中はswitch case
節となっていて、.state()
で得られた状態により処理を分岐しています。状態の遷移は.next()
を呼び出しステートマシン内の内部変数を新しい状態値に書き換えます。
step.b_more_loop()
は、.next()
により状態遷移があった場合 true
に設定されます。これは状態遷移が発生したときloop()
を脱出せずに次の状態のコード(case
節)を実行する目的です。
以下に各状態の解説を行います。
STATE::INIT
sensor.dummy_work_ct_now = 0 ;
sensor.dummy_work_ct_max = random(10 ,1000 );
step.next(STATE:: WORK_JOB);
ダミーーのセンサー値を初期化します。一つは加算カウンタ、一つはカウンター停止値でランダムに決定しています。
STATE::WORK_JOB
if (TickTimer.available()) {
Serial << '.' ;
sensor.dummy_work_ct_now++ ;
if (sensor.dummy_work_ct_now >= sensor.dummy_work_ct_max) {
Serial << crlf;
step.next(STATE:: TX);
}
}
WORK_JOB
状態では1msごとのタイマー単位で処理します。TickタイマーごとにTickTimer.available()
になります。Tickタイマーごとにカウンタを加算しdummy_work_ct_max
になったら、次の状態STATE::TX
に遷移します。
STATE::TX
if (Transmit()) {
Serial << int (millis()) << ":tx request success!" << crlf;
step.set_timeout(100 );
step.clear_flag();
step.next(STATE:: WAIT_TX);
} else {
// normall it should not be here.
Serial << int (millis()) << "!FATAL: tx request failed." << crlf;
step.next(STATE:: EXIT_FATAL);
}
Transmit()
関数を呼び出しパケット送信要求を行います。送信要求が成功した場合はSTATE::WAIT_TXEVENT
に遷移して送信完了を待つことになります。ここでは完了待ちとしてSM_SIMPLE
ステートマシンのタイムアウトとフラッグ機能を用います(待ちループ中での変数値の変化により判定する単純なものです)。
単一の送信要求が失敗することは通常想定しませんが、失敗時はSTATE::EXIT_FATAL
として例外処理する状態に遷移します。
この時点ではまだパケットが送信されていないため、この時点でスリープをしてはいけません。多くの場合、送信完了を待ってから、続く処理を行います。
Transmit()
関数はMWX_APIRET
オブジェクトを返しますが、このオブジェクトはbool
型の成功の可否と、最大31ビットの値を保持しています。bool
型として評価できますから、if
文の判定は送信要求が成功したら true
、失敗したらfalse
を返します。
STATE::WAIT_TX
if (step.is_flag_ready()) {
Serial << int (millis()) << ":tx completed!" << crlf;
step.next(STATE:: EXIT_NORMAL);
} else if (step.is_timeout()) {
Serial << int (millis()) << "!FATAL: tx timeout." << crlf;
step.next(STATE:: EXIT_FATAL);
}
送信完了待ちは後述のon_tx_comp()
によりステートマシン機能のフラッグをセットすることで判定しています。タイムアウトは.is_timeout()
を呼び出すことで.set_timeout()
を行ったときからの経過時間により判定します。
送信が成功しても失敗しても通常は完了通知がありますが、タイムアウトを設け例外処理のための状態STATE::EXIT_FATAL
に遷移します。
STATE::EXIT_NORMAL
SleepNow()
を呼び出して、スリープ処理に入ります。
STATE::EXIT_FATAL
Serial << crlf << "!FATAL: RESET THE SYSTEM." ;
delay(1000 ); // wait a while.
the_twelite.reset_system();
重大なエラーとして、システムリセットを行います。
SleepNow()
void SleepNow () {
uint16_t u16dur = SLEEP_DUR;
u16dur = random(SLEEP_DUR - SLEEP_DUR_TERMOR, SLEEP_DUR + SLEEP_DUR_TERMOR);
Serial << int (millis()) << ":sleeping for " << int (u16dur) << "ms" << crlf;
Serial.flush();
step.on_sleep(); // reset status of statemachine to INIT state.
the_twelite.sleep(u16dur, false);
}
周期スリープを行います。スリープ時間はrandom()
関数を用いて、一定の時間ブレを作っています。これは複数のデバイスの送信周期が同期した場合、著しく失敗率が上がる場合があるためです。
スリープ前にはSM_SIMPLE
ステートマシンの状態を.on_sleep()
を呼び出してセットしておきます。
Transmit()
MWX_APIRET vTransmit () {
Serial << int (millis()) << ":vTransmit()" << crlf;
if (auto && pkt = the_twelite.network.use< NWK_SIMPLE> ().prepare_tx_packet()) {
// set tx packet behavior
pkt << tx_addr(0x00 ) // 0..0xFF (LID 0:parent, FE:child w/ no id, FF:LID broad cast), 0x8XXXXXXX (long address)
<< tx_retry(0x1 ) // set retry (0x3 send four times in total)
<< tx_packet_delay(0 ,0 ,2 ); // send packet w/ delay (send first packet with randomized delay from 0 to 0ms, repeat every 2ms)
// prepare packet payload
pack_bytes(pkt.get_payload() // set payload data objects.
, make_pair(FOURCC, 4 ) // string should be paired with length explicitly.
, uint32_t (millis()) // put timestamp here.
, uint16_t (sensor.dummy_work_ct_now) // put dummy sensor information.
);
// do transmit
//return nwksmpl.transmit(pkt);
return pkt.transmit();
}
return MWX_APIRET(false, 0 );
}
ID=0x00
の親機宛に無線パケットの送信要求を行います。格納されるデータはActサンプルで共通に使われている4文字識別子(FOURCC
)に加え、システム時間[ms]とダミーセンサー値(sensor.dummy_work_ct_now
)を格納します。
まず最初に送信パケットを格納するオブジェクトを取得します。このオブジェクトを操作し、送信データや条件を設定します。
if (auto && pkt = the_twelite.network.use< NWK_SIMPLE> ().prepare_tx_packet()) {
MWX ライブラリでは、if
文中でオブジェクトを取得し、そのオブジェクトのbool
判定でtrue
の場合に処理を行う記述を採用しています。
ここではthe_twelite.network.use<NWK_SIMPLE>()
によりボードオブジェクトを取得し、ボードオブジェクトの.prepare_tx_packet()
によりパケットオブジェクトを取得しています。パケットオブジェクトの取得失敗は通常想定しませんが、失敗時は送信キューが一杯で送信要求が受け付けられない場合です。このサンプルは単一の送信のみですから、エラーは想定外の重大な問題に限られます。
pkt << tx_addr(0x00 ) // 宛先
<< tx_retry(0x1 ) // 再送回数
<< tx_packet_delay(0 ,0 ,2 ); // 送信遅延
得られたpkt
オブジェクトに対して、送信条件(宛先や再送など)を<<
演算子を用いて設定します。
tx_addr
はパケットの宛先を指定します。tx_retry
は再送回数、tx_packet_delay
は送信遅延の指定です。
pack_bytes(pkt.get_payload() // set payload data objects.
, make_pair(FOURCC, 4 ) // string should be paired with length explicitly.
, uint32_t (millis()) // put timestamp here.
, uint16_t (sensor.dummy_work_ct_now) // put dummy sensor information.
);
パケットのペイロード(データ部分)はpkt.get_payload()
により得られるsmblbuf<uint8_t>
派生の配列です。この配列に対して直接値を設定しても構いませんが、ここではpack_bytes()
を用いた値の設定を行います。
ペイロードの最大長は上記の例では91バイトですが、詳しくはNWK_SIMPLE
パケット構造と最大長を参照ください。
この関数は可変数引数により指定できます。一番最初のパラメータは.get_payload()
より得られた配列オブジェクトです。
make_pair(FOURCC,4)
: make_pair
はC++標準ライブラリのもので、std::pair
オブジェクトを生成します。文字列型に対して先頭から4バイト分を書き出すという意味になります。(文字列型の配列は終端を含める、含めないといった話題が混乱を生むため、明示的に書き出すバイト数を指定するために、このような指定をします)uint32_t
型のデータを指定するとビッグエンディアン並びで4バイト分のデータを書き込みます。uint16_t
型のデータについても同様です。
uint8_t
型のポインタを用いてデータの書き込みを行うことも出来ます。
auto && pay = pkt.get_payload(); // get buffer object.
// the following code will write data directly to internal buffer of `pay' object.
uint8_t * p = pay.begin(); // get the pointer of buffer head.
S_OCTET(p, FOURCC[0 ]); // store byte at pointer `p' and increment the pointer.
S_OCTET(p, FOURCC[1 ]);
S_OCTET(p, FOURCC[2 ]);
S_OCTET(p, FOURCC[3 ]);
S_DWORD(p, millis()); // store uint32_t data.
S_WORD(p, sensor.dummy_work_ct_now); // store uint16_t data.
pay.redim(p - pay.begin());
.get_payload()
から得られた配列オブジェクトは、何も格納されていないサイズ0の配列ですが、この配列にデータを書き込むことでサイズが拡張され(実際は内部の固定長のバッファに対してデータを書き込み、内部管理のデータサイズを更新します)、最終的なサイズがペイロードのデータサイズです。
ここでは.begin()
を用いてuint8_t*
のポインタを得て、このポインタを用いてデータを書き込み、最後に書き込んだサイズを.redim()
で設定します。
S_OCTET()
, S_WORD()
, S_DWORD()
といった関数を書き込みに用いていますが、例えばS_OCTET(p, 'H')
は *p = 'H'; p++;
と同じ処理を行うポインタを用いたデータ書き込みです。
最後の.redim()
は配列のサイズをバッファの初期化をせずに 変更する手続きです。.resize()
を呼び出すとすべて0クリアされます。
最後に.transmit()
を呼び出して、送信要求を行います。戻り値はMWX_APIRET
型です。要求後、実際の送信が行われますが、送信パラメータや送信サイズにもよりますが、完了まで数ms~数十ms程度はかかります。完了時にはon_tx_comp()
が呼び出されます。
MWX_APIRET
はuint32_t
型をラップしたクラスで、MSBを失敗成功のフラグとし、以下31ビットをデータとして用いています。pkt.transmit()
の戻り型になっており、送信要求の成功と失敗(bool
型へのキャスト)ならびに送信IDをデータ部(.get_value()
)に格納しています。
on_tx_comp()
void on_tx_comp (mwx:: packet_ev_tx& ev, bool_t & b_handled) {
step.set_flag(ev.bStatus);
}
送信完了時に呼び出されるシステムイベントです。ここでは.set_flag()
により完了としています。
1.4.1.4 - Parent_MONOSTICK 親機アプリケーション(MONOSTICK用)
MONOSTICKを親機として使用するアクトです。子機からのパケットのデータペイロードをシリアルポートに出力します。サンプルアクトの多くのサンプルでのパケットを表示することが出来ます。
このアクトには以下が含まれます。
無線パケットの受信 受信したパケットのデータ解釈 インタラクティブモードの設定 - <STG_STD>
バイト列のアスキー形式への変換 - serparser
アクトの機能 サンプルアクトの子機からのパケットを受信して、シリアルポートへ出力する。 アクトの使い方 必要なTWELITEと配線 役割 例 親機 MONOSTICK BLUE/RED 子機 サンプルアクトの子機に設定したTWELITEシリーズ(例: Slp_Wk_and_Tx
, PAL_AMB
, PAL_MAG
, PAL_MOT???
など)
最初は以下のデフォルトの設定にて確認してください。
アプリケーションID: 0x1234abcd
チャネル: 13
アクトの解説 宣言部 インクルード
// use twelite mwx c++ template library
#include <TWELITE>
#include <MONOSTICK>
#include <NWK_SIMPLE>
#include <STG_STD>
MONOSTICK用のボードビヘイビア<MONOSTICK>
をインクルードしています。このボードサポートには、LEDの制御、ウォッチドッグ対応が含まれます。
<NWK_SIMPLE>
簡易中継ネットの定義を読み込みます<STG_STD>
インタラクティブモードの定義を読み込みます。その他
// application ID
const uint32_t DEFAULT_APP_ID = 0x1234abcd ;
// channel
const uint8_t DEFAULT_CHANNEL = 13 ;
// option bits
uint32_t OPT_BITS = 0 ;
/*** function prototype */
bool analyze_payload (packet_rx& rx);
デフォルト値や関数プロトタイプなどの宣言をしています。
setup()
auto && brd = the_twelite.board.use< MONOSTICK> ();
auto && set = the_twelite.settings.use< STG_STD> ();
auto && nwk = the_twelite.network.use< NWK_SIMPLE> ();
setup()
では、まず<MONOSTICK>
ボードビヘイビア、<STG_STD>
インタラクティブモード ビヘイビア、<NWK_SIMPLE>
ビヘイビアをuse<>
を用い読み込みます。この手続きは必ずsetup()
内で行います。
set << SETTINGS:: appname("PARENT" ); // 設定画面中のタイトル
set << SETTINGS:: appid_default(DEFAULT_APP_ID); // アプリケーションIDデフォルト
set << SETTINGS:: ch_default(DEFAULT_CHANNEL); // チャネルデフォルト
set << SETTINGS:: lid_default(0x00 ); // LIDデフォルト
set.hide_items(E_STGSTD_SETID:: OPT_DWORD2, E_STGSTD_SETID:: OPT_DWORD3, E_STGSTD_SETID:: OPT_DWORD4, E_STGSTD_SETID:: ENC_KEY_STRING, E_STGSTD_SETID:: ENC_MODE);
set.reload(); // 設定を不揮発性メモリから読み出す
OPT_BITS = set.u32opt1(); // 読み込み例(オプションビット)
続いてインタラクティブモードの設定と設定値の読み出しを行います。<STG_STD>
インタラクティブモードでは、標準的な項目が用意されていますが、作成するアクトごとにいくつかのカスタマイズを行えるようになっています。
appname
→ 設定画面中のタイトル行にでるアクト名称appid_default
→ デフォルトのアプリケーションIDch_default
→ デフォルトのチャネルlid_default
→ デバイスID(LID)のデフォルト値.hide_items()
→ 項目の非表示設定設定値を読み出す前には必ず.reload()
を呼び出します。設定値は.u32opt1()
のように設定値ごとに読み出し用のメソッドが用意されています。
the_twelite
<< set // インタラクティブモードの設定を反映
<< TWENET:: rx_when_idle() // 受信するように指定
;
// Register Network
nwk << set; // インタラクティブモードの設定を反映
nwk << NWK_SIMPLE:: logical_id(0x00 ) // LIDだけは再設定
;
いくつかの設定値は<STG_STD>
オブジェクトを用いて直接反映することが出来ます。また、DIPスイッチの設定などにより特定の値を書き換えたいような場合などは、反映されたあとに別個に値を書き換えることも出来ます。上記の例ではthe_twelite
オブジェクトにアプリケーションID、チャネル、無線出力などを設定し、nwk
オブジェクトに対してLIDと再送回数の設定をしてから、再度LIDを0
に設定し直しています。
brd.set_led_red(LED_TIMER:: ON_RX, 200 ); // RED (on receiving)
brd.set_led_yellow(LED_TIMER:: BLINK, 500 ); // YELLOW (blinking)
<MONOSTICK>
ボードビヘイビアではLED点灯制御のための手続きを利用できます。
1行目では赤色のLEDを無線パケットを受信したら200ms点灯する設定をしています。最初のパラメータはLED_TIMER::ON_RX
が無線パケット受信時を意味します。2番目は点灯時間をmsで指定します。
2行目はLEDの点滅指定です。1番目のパラメータはLED_TIMER::BLINK
が点滅の指定で、2番目のパラメータは点滅のON/OFF切り替え時間です。500msごとにLEDが点灯、消灯(つまり1秒周期の点滅)を繰り返します。
the_twelite.begin(); // start twelite!
the_twelite
を開始するための手続きです。act0..4
では出てきませんでしたがthe_twelite
の設定や各種ビヘイビアの登録を行った場合は、必ず呼び出すようにしてください。
loop()
このサンプルではloop()
中の処理はありません。
on_rx_packet()
パケットを受信したときに呼び出されるコールバック関数です。この例では受信したパケットデータに対していくつかの出力を行っています。
void on_rx_packet (packet_rx& rx, bool_t & handled) {
Serial << ".. coming packet (" << int (millis()& 0xffff ) << ')' << mwx:: crlf;
...
// packet analyze
analyze_payload(rx);
}
analyze_payload
関数の末尾で呼び出されるanalyze_payload()
は、いくつかのサンプルアクトのパケットを解釈するコードが含まれています。サンプルアクト中のパケット生成部分と対応させてコードを参照してください。
bool b_handled = false;
uint8_t fourchars[4 ]{};
auto && np = expand_bytes(
rx.get_payload().begin(), rx.get_payload().end()
, fourchars
);
if (np == nullptr ) return ;
// display fourchars at first
Serial
<< fourchars
<< format("(ID=%d/LQ=%d)" , rx.get_addr_src_lid(), rx.get_lqi())
<< "-> " ;
この関数では最初に4文字識別データをfourchars[5]
配列に読み込みます。
読み込みはexpand_bytes()
関数を用います。この関数の第1・第2パラメータはC++の標準ライブラリの作法に倣い、受信パケットのペイロード部の先頭ポインタ.begin()
と末尾ポインタの次.end()
を与えます。続くパラメータは可変引数として、読み込むデータ変数を与えます。戻り値はエラー時はnullptr
、それ以外は次の解釈ポインタとなります。末尾まで解釈した場合は.end()
が戻ります。ここでのパラメータはuint8_t fourchars[4]
です。
この記述で対応するのは配列長さNが指定されるuint8_t[N]
型のみで、uint8*
型、char*
型、char[]
型などを用いる場合は、make_pair(char*,int)
を用いた指定が必要になります。
char fourchars[5 ]{}; // 終端文字\0も含め5バイト確保する
auto && np = expand_bytes(
rx.get_payload().begin(), rx.get_payload().end()
, make_pair((char * )fourchars, 4 )
);
つづいて4バイトヘッダに対応した処理を行います。ここではサンプルアクトSlp_Wk_and_Tx
のパケットを解釈し内容を表示します。
// Slp_Wk_and_Tx
if (! b_handled && ! strncmp(fourchars, "TXSP" , 4 )) {
b_handled = true;
uint32_t tick_ms;
uint16_t u16work_ct;
np = expand_bytes(np, rx.get_payload().end()
, tick_ms
, u16work_ct
);
if (np != nullptr ) {
Serial << format("Tick=%d WkCt=%d" , tick_ms, u16work_ct);
} else {
Serial << ".. error .." ;
}
}
他の解釈部の判定をスキップするようにb_handled
をtrue
に設定します。
"TXSP"
のパケットではuint32_t
型のシステムタイマーカウントと、uint16_t
型のダミーカウンタの値が格納されています。各々変数を宣言してexpand_bytes()
関数を用い読み込みます。上述と違うのは、読み出しの最初のポインタとして第一パラメータがnp
となっている点です。tick_ms
とu16work_ct
をパラメータとして与え、ビッグエンディアン形式のバイト列としてペイロードに格納された値を読み出します。
読み出しに成功すれば内容を出力して終了です。
独自のアスキー書式を定義して出力する ユーザが定義した並び順でアスキー形式により構成します。
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, ???>)
形式のコンテナを指定することもできます。
パケットのシーケンス番号は、<NWK_SIMPLE>
で自動設定され、送信パケット順に割り振られます。この値はパケットの重複検出に用いられます。
LQI (Link Quality Indicator)は受信時の電波強度に相当する値で、値が大きければ大きいほどより強い電界強度で受信できていることになります。ただしこの値と物理量との厳格な関連は定義されていませんし、環境のノイズと相対的なものでLQIがより大きな値であってもノイズも多ければ通信の成功率も低下することになります。
13,14,17行目は、シリアルパーサーの宣言と設定、出力です。
NWK_SIMPLEのヘッダを含めてダンプ出力する 最初の出力(if(0)
により実行されないようになっています)は<NWK_SIMPLE>
の制御データを含めたデータをすべて表示します。制御データは11バイトあります。通常は制御情報を直接参照することはありませんが、あくまでも参考です。
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行目は出力用のシリアルパーサをローカルオブジェクトとして宣言しています。内部にバッファを持たず、外部のバッファを流用し、パーサーの出力機能を用いて、バッファ内のバイト列をアスキー形式出力します。
2行目はシリアルパーサーのバッファを設定します。すでにあるデータ配列、つまり受信パケットのペイロード部を指定します。serparser_attach pout
は、既にあるバッファを用いたシリアルパーサーの宣言です。pout.begin()
の1番目のパラメータは、パーサーの対応書式をPARSER::ASCII
つまりアスキー形式として指定しています。2番目はバッファの先頭アドレス。3番目はバッファ中の有効なデータ長、4番目はバッファの最大長を指定します。出力用で書式解釈に使わないため4番目のパラメータは3番目と同じ値を入れています。
6行目でシリアルポートへ>>
演算子を用いて出力しています。
7行目のSerial << mwx::flush
は、ここで出力が終わっていないデータの出力が終わるまで待ち処理を行う指定です。(Serial.flush()
も同じ処理です)
1.4.1.5 - PingPong パケットを打ち返す
2台のシリアル接続しているTWELITEの片方からPING(ピン)の無線パケットを送信すると、他方からPONG(ポン)の無線パケットが返ってきます。
このアクトには以下が含まれます。
無線パケットの受信からの速やかな応答送信 相手のアドレスを直接指定した送信 シリアルポートからの入力 - Serial
ディジタル(ボタン)入力 - Buttons
アナログ入力 - Analogue
アクトの使い方 必要なTWELITE いずれかを2台用意します。
MONOSTICK BLUE / RED TWELITE R シリーズ でUART接続した TWELITE DIP など アクトの解説 宣言部 インクルード
// use twelite mwx c++ template library
#include <TWELITE>
#include <NWK_SIMPLE>
全てのアクトで<TWELITE>
をインクルードします。ここでは、シンプルネットワーク <NWK_SIMPLE>
をインクルードしておきます。
その他
// application ID
const uint32_t APP_ID = 0x1234abcd ;
// channel
const uint8_t CHANNEL = 13 ;
// DIO pins
const uint8_t PIN_BTN = 12 ;
/*** function prototype */
void vTransmit (const char * msg, uint32_t addr);
/*** application defs */
// packet message
const int MSG_LEN = 4 ;
const char MSG_PING[] = "PING" ;
const char MSG_PONG[] = "PONG" ;
サンプルアクト共通宣言 長めの処理を関数化しているため、そのプロトタイプ宣言(送信と受信) アプリケーション中のデータ保持するための変数 setup()
void setup () {
/*** SETUP section */
Buttons.setup(5 ); // init button manager with 5 history table.
Analogue.setup(true, 50 ); // setup analogue read (check every 50ms)
// 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(0xFE ) // set Logical ID. (0xFE means a child device with no ID)
<< NWK_SIMPLE:: repeat_max(3 ); // can repeat a packet up to three times. (being kind of a router)
/*** BEGIN section */
Buttons.begin(pack_bits(PIN_BTN), 5 , 10 ); // check every 10ms, a change is reported by 5 consequent values.
Analogue.begin(pack_bits(PIN_ANALOGUE:: A1, PIN_ANALOGUE:: VCC)); // _start continuous adc capture.
the_twelite.begin(); // start twelite!
/*** INIT message */
Serial << "--- PingPong sample (press 't' to transmit) ---" << mwx:: crlf;
}
大まかな流れは、各部の初期設定、各部の開始となっています。
the_twelite
このオブジェクトはTWENETを操作するための中核クラスオブジェクトです。
// 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)
the_twelite
に設定を反映するには <<
を用います。
TWENET::appid(APP_ID)
アプリケーションIDの指定TWENET::channel(CHANNEL)
チャネルの指定TWENET::rx_when_idle()
受信回路をオープンにする指定
<<
, >>
演算子はC言語におけるビットシフト演算子ですが、ここではその意味合いとは異なる挿入演算子(stream insertion operator)として使用しています。MWXライブラリでは、C++標準ライブラリの入出力利用にならって上記のような設定やシリアルポートの入出力等で利用します。
ただし、以下の記述は MWX ライブラリでは利用できません。
#include <iostream>
std:: cout << "hello world" << std:: endl;
次にネットワークを登録します。
auto && nwksmpl = the_twelite.network.use< NWK_SIMPLE> ();
nwksmpl << NWK_SIMPLE:: logical_id(0xFE );
<< NWK_SIMPLE:: repeat_max(3 );
1行目は、ボードの登録と同じ書き方で <>
には <NWK_SIMPLE>
を指定します。
2行目は、<NWK_SIMPLE>
の設定で、0xFE
(ID未設定の子機)という指定を行います。
3行目は、中継回数の最大値を指定しています。この解説では中継には触れませんが、複数台で動作させたときにパケットの中継が行われます。
the_twelite.begin(); // start twelite!
setup()
関数の末尾で the_twelite.begin()
を実行しています。
Analogue
ADC(アナログディジタルコンバータ)を取り扱うクラスオブジェクトです。
初期化Analogue.setup()
で行います。パラメータのtrue
はADC回路の安定までその場で待つ指定です。
Analogue.begin(pack_bits(PIN_ANALOGUE:: A1, PIN_ANALOGUE:: VCC), 50 );
ADCを開始するにはAnalogue.begin()
を呼びます。パラメータはADC対象のピンに対応するビットマップです。
ビットマップを指定するのにpack_bits()
関数を用います。可変数引数の関数で、各引数には1を設定するビット位置を指定します。例えばpack_bits(1,3,5)
なら2進数で 101010
の値が戻ります。この関数はconstexpr
指定があるため、パラメータが定数のみであれば定数に展開されます。
パラメータにはPIN_ANALOGUE::A1
(ADC0)とPIN_ANALOGUE::VCC
(モジュール電源電圧)が指定されています。
2番目のパラメータには50
が指定されています。ADCの動作はデフォルトではTickTimerで開始されていて、初回を除き ADC の開始は、割り込みハンドラ内で行います。
DIO (ディジタル入力) の値の変化を検出します。Buttons
では、メカ式のボタンのチャタリング(摺動)の影響を軽減するため、一定回数同じ値が検出されてから、値の変化とします。
初期化は Buttons.setup()
で行います。パラメータの 5
は、値の確定に必要な検出回数ですが、設定可能な最大値を指定します。内部的にはこの数値をもとに内部メモリの確保を行っています。
Buttons.begin(pack_bits(PIN_BTN),
5 , // history count
10 ); // tick delta
開始は Buttons.begin()
で行います。1番目のパラメータは検出対象のDIOです。BRD_APPTWELITE::
に定義されるPIN_BTN
(12) を指定しています。2番めのパラメータは状態を確定するのに必要な検出回数です。3番めのパラメータは検出間隔です。10
を指定しているので10msごとに5回連続で同じ値が検出できた時点で、HIGH
, LOW
の状態が確定します。
Buttons
でのDIO状態の検出はイベントハンドラで行います。イベントハンドラは、割り込み発生後にアプリケーションループで呼ばれるため割り込みハンドラに比べ遅延が発生します。
Serial
Serial
オブジェクトは、初期化や開始手続きなく利用できます。
Serial << "--- PingPong sample (press 't' to transmit) ---" << mwx:: crlf;
シリアルポートへの文字列出力を行います。mwx::crlf
は改行文字です。
loop()
ループ関数は TWENET ライブラリのメインループからコールバック関数として呼び出されます。ここでは、利用するオブジェクトが available になるのを待って、その処理を行うのが基本的な記述です。ここではアクトで使用されているいくつかのオブジェクトの利用について解説します。
TWENET ライブラリのメインループは、事前にFIFOキューに格納された受信パケットや割り込み情報などをイベントとして処理し、そののちloop()
が呼び出されます。loop()
を抜けた後は CPU が DOZE モードに入り、低消費電流で新たな割り込みが発生するまでは待機します。
したがってCPUが常に稼働していることを前提としたコードはうまく動作しません。
void loop () {
// read from serial
while (Serial.available()) {
int c = Serial.read();
Serial << mwx:: crlf << char (c) << ':' ;
switch (c) {
case 't' :
vTransmit(MSG_PING, 0xFF );
break ;
default :
break ;
}
}
// Button press
if (Buttons.available()) {
uint32_t btn_state, change_mask;
Buttons.read(btn_state, change_mask);
// Serial << fmt("<BTN %b:%b>", btn_state, change_mask);
if (! (change_mask & 0x80000000 ) && (btn_state && (1UL << PIN_BTN))) {
// PIN_BTN pressed
vTransmit(MSG_PING, 0xFF );
}
}
}
Serial
while (Serial.available()) {
int c = Serial.read();
Serial << mwx:: crlf << char (c) << ':' ;
switch (c) {
case 't' :
vTransmit(MSG_PING, 0xFF );
break ;
default :
break ;
}
}
Serial.available()
がtrue
の間はシリアルポートからの入力があります。内部のFIFOキューに格納されるためある程度の余裕はありますが、速やかに読み出すようにします。データの読み出しはSerial.read()
を呼びます。
ここでは't'
キーの入力に対応してvTransmit()
関数を呼び出しPINGパケットを送信します。
DIO(ディジタルIO)の入力変化を検出したタイミングで available になり、Buttons.read()
により読み出します。
if (Buttons.available()) {
uint32_t btn_state, change_mask;
Buttons.read(btn_state, change_mask);
1番目のパラメータは、現在のDIOのHIGH/LOWのビットマップで、bit0から順番にDIO0,1,2,.. と並びます。例えば DIO12 であれば btn_state & (1UL << 12)
を評価すれば HIGH / LOW が判定できます。ビットが1になっているものがHIGHになります。
初回のIO状態確定時は MSB (bit31) に1がセットされます。スリープ復帰時も初回の確定処理を行います。
// Serial « fmt("<BTN %b:%b>", btn_state, change_mask);
if (!(change_mask & 0x80000000) && (btn_state && (1UL « PIN_BTN))) {
// PIN_BTN pressed
vTransmit(MSG_PING, 0xFF);
初回確定以外の場合かつPIN_BTN
のボタンが離された タイミングでvTransmit()
を呼び出しています。押したタイミングにするには(!(btn_state && (1UL << PIN_BTN)))
のように条件を論理反転します。
transmit()
無線パケットの送信要求をTWENETに行う関数です。本関数が終了した時点では、まだ無線パケットの処理は行われません。実際に送信が完了するのは、送信パラメータ次第ですが、数ms後以降になります。ここでは代表的な送信要求方法について解説します。
void vTransmit (const char * msg, uint32_t addr) {
Serial << "vTransmit()" << mwx:: crlf;
if (auto && pkt = the_twelite.network.use< NWK_SIMPLE> ().prepare_tx_packet()) {
// set tx packet behavior
pkt << tx_addr(addr) // 0..0xFF (LID 0:parent, FE:child w/ no id, FF:LID broad cast), 0x8XXXXXXX (long address)
<< tx_retry(0x3 ) // set retry (0x3 send four times in total)
<< tx_packet_delay(100 ,200 ,20 ); // send packet w/ delay (send first packet with randomized delay from 100 to 200ms, repeat every 20ms)
// prepare packet payload
pack_bytes(pkt.get_payload() // set payload data objects.
, make_pair(msg, MSG_LEN) // string should be paired with length explicitly.
, uint16_t (analogRead(PIN_ANALOGUE:: A1)) // possible numerical values types are uint8_t, uint16_t, uint32_t. (do not put other types)
, uint16_t (analogRead_mv(PIN_ANALOGUE:: VCC)) // A1 and VCC values (note: alalog read is valid after the first (Analogue.available() == true).)
, uint32_t (millis()) // put timestamp here.
);
// do transmit
pkt.transmit();
}
}
ネットワークオブジェクトとパケットオブジェクトの取得
if (auto && pkt = the_twelite.network.use< NWK_SIMPLE> ().prepare_tx_packet()) {
ネットワークオブジェクトをthe_twelite.network.use<NWK_SIMPLE>()
で取得します。そのオブジェクトを用いて.prepare_tx_packet()
によりpkt
オブジェクトを取得します。
ここではif
文の条件判定式の中で宣言しています。宣言したpkt
オブジェクトはif
節の終わりまで有効です。pkt
オブジェクトはbool
型の応答をし、ここではTWENETの送信要求キューに空きがあって送信要求を受け付ける場合にtrue
、空きがない場合にfalse
となります。
パケットの送信設定
pkt << tx_addr(addr) // 0..0xFF (LID 0:parent, FE:child w/ no id, FF:LID broad cast), 0x8XXXXXXX (long address)
<< tx_retry(0x3 ) // set retry (0x3 send four times in total)
<< tx_packet_delay(100 ,200 ,20 ); // send packet w/ delay (send first packet with randomized delay from 100 to 200ms, repeat every 20ms)
パケットの設定はthe_twelite
の初期化設定のように<<
演算子を用いて行います。
tx_addr()
パラメータに送信先アドレスを指定します。0x00
なら自分が子機で親機宛に、0xFE
なら自分が親機で任意の子機宛のブロードキャストという意味です。tx_retry()
パラメータに再送回数を指定します。例の3は再送回数が3回、つまり合計4回パケットを送ります。無線パケット1回のみの送信では条件が良くても数%程度の失敗はあります。tx_packet_delay()
送信遅延を設定します。一つ目のパラメータは、送信開始までの最低待ち時間、2番目が最長の待ち時間です。この場合は送信要求を発行後におよそ100msから200msの間で送信を開始します。3番目が再送間隔です。最初のパケットが送信されてから20ms置きに再送を行うという意味です。パケットのデータペイロード ペイロードは積載物という意味ですが、無線パケットでは「送りたいデータ本体」という意味でよく使われます。無線パケットのデータにはデータ本体以外にもアドレス情報などいくつかの補助情報が含まれます。
送受信を正しく行うために、データペイロードのデータ並び順を意識するようにしてください。ここでは以下のようなデータ順とします。このデータ順に合わせてデータペイロードを構築します。
# 先頭バイトのインデックス: データ型 : バイト数 : 内容
00: uint8_t[4] : 4 : 4文字識別子
08: uint16_t : 2 : AI1のADC値 (0..1023)
06: uint16_t : 2 : Vccの電圧値 (2000..3600)
10: uint32_t : 4 : millis()システム時間
データペイロードには90バイト格納できます(実際にはあと数バイト格納できます)。
IEEE802.15.4の無線パケットの1バイトは貴重です。できるだけ節約して使用することを推奨します。1パケットで送信できるデータ量に限りがあります。パケットを分割する場合は分割パケットの送信失敗などを考慮する必要がありコストは大きくつきます。また1バイト余分に送信するのに、およそ16μ秒×送信時の電流に相当するエネルギーが消費され、特に電池駆動のアプリケーションには大きく影響します。
上記のデータペイロードのデータ構造を実際に構築してみます。データペイロードは pkt.get_payload()
により simplbuf<uint8_t>
型のコンテナとして参照できます。このコンテナに上記の仕様に基づいてデータを構築します。
上記のように記述できますがMWXライブラリでは、データペイロード構築のための補助関数pack_bytes()
を用意しています。
// prepare packet payload
pack_bytes(pkt.get_payload() // set payload data objects.
, make_pair(msg, MSG_LEN) // string should be paired with length explicitly.
, uint16_t (analogRead(PIN_ANALOGUE:: A1)) // possible numerical values types are uint8_t, uint16_t, uint32_t. (do not put other types)
, uint16_t (analogRead_mv(PIN_ANALOGUE:: VCC)) // A1 and VCC values (note: alalog read is valid after the first (Analogue.available() == true).)
, uint32_t (millis()) // put timestamp here.
);
pack_bytes
の最初のパラメータはコンテナを指定します。この場合はpkt.get_payload()
です。
そのあとのパラメータは可変数引数でpack_bytes
で対応する型の値を必要な数だけ指定します。pack_bytes
は内部で.push_back()
メソッドを呼び出して末尾に指定した値を追記していきます。
3行目のmake_pair()
は標準ライブラリの関数でstd::pair
を生成します。文字列型の混乱(具体的にはペイロードの格納時にヌル文字を含めるか含めないか)を避けるための指定です。make_pair()
の1番目のパラメータに文字列型(char*
やuint8_t*
型、uint8_t[]
など)を指定します。2番目のパラメータはペイロードへの格納バイト数です。
4,5,6行目は、数値型の値 (uint8_t
, uint16_t
, uint32_t
)を格納します。符号付などの数値型、char
型など同じ数値型であっても左記の3つの型にキャストして投入します。
analogRead()
とanalogRead_mv()
は、ADCの結果を取得するものです。前者はADC値(0..1023
)、後者は電圧(mV, 0..2470
)となります。モジュールの電源電圧は内部的に分圧抵抗の値を読んでいるためその変換を行うadalogRead_mv()
を利用しています。
これでパケットの準備は終わりです。最後に、送信要求を行います。
パケットを送信するにはpkt
オブジェクトのpkt.transmit()
メソッドを用います。
このアクトでは使用しませんが、戻り値には、要求の成功失敗の情報と要求に対応する番号が格納されています。送信完了まで待つ処理を行う場合は、この戻り値の値を利用します。
on_rx_packet()
受信パケットがある場合の処理です。
void on_rx_packet (packet_rx& rx, bool_t & handled) {
uint8_t msg[MSG_LEN];
uint16_t adcval, volt;
uint32_t timestamp;
// expand packet payload (shall match with sent packet data structure, see pack_bytes())
expand_bytes(rx.get_payload().begin(), rx.get_payload().end()
, msg // 4bytes of msg
// also can be -> std::make_pair(&msg[0], MSG_LEN)
, adcval // 2bytes, A1 value [0..1023]
, volt // 2bytes, Module VCC[mV]
, timestamp // 4bytes of timestamp
);
// if PING packet, respond pong!
if (! strncmp((const char * )msg, "PING" , MSG_LEN)) {
// transmit a PONG packet with specifying the address.
vTransmit(MSG_PONG, rx.get_psRxDataApp()-> u32SrcAddr);
}
// display the packet
Serial << format("<RX ad=%x/lq=%d/ln=%d/sq=%d:" // note: up to 4 args!
, rx.get_psRxDataApp()-> u32SrcAddr
, rx.get_lqi()
, rx.get_length()
, rx.get_psRxDataApp()-> u8Seq
)
<< format(" %s AD=%d V=%d TS=%dms>" // note: up to 4 args!
, msg
, adcval
, volt
, timestamp
)
<< mwx:: crlf
<< mwx:: flush;
}
まず受信パケットのデータはパラメータrx
として渡されます。rx
から無線パケットのアドレス情報やデータペイロードにアクセスします。
while (the_twelite.receiver.available()) {
auto && rx = the_twelite.receiver.read();
次の行では、受信パケットデータには、送信元のアドレス(32bitのロングアドレスと8bitの論理アドレス)などの情報を参照しています。
Serial << format("..receive(%08x/%d) : " ,
rx.get_addr_src_long(), rx.get_addr_src_lid());
<NWK_SIMPLE>
では、8bitの論理IDと32bitのロングアドレスの2種類が常にやり取りされます。送り先を指定する場合はロングアドレスか論理アドレスのいずれかを指定します。受信時には両方のアドレスが含まれます。
MWXライブラリにはtransmit()
のときに使ったpack_bytes()
の対になる関数expand_bytes()
が用意されています。
uint8_t msg[MSG_LEN];
uint16_t adcval, volt;
uint32_t timestamp;
// expand packet payload (shall match with sent packet data structure, see pack_bytes())
expand_bytes(rx.get_payload().begin(), rx.get_payload().end()
, msg // 4bytes of msg
// also can be -> std::make_pair(&msg[0], MSG_LEN)
, adcval // 2bytes, A1 value [0..1023]
, volt // 2bytes, Module VCC[mV]
, timestamp // 4bytes of timestamp
);
1行目から3行目までは、データを格納する変数を指定しています。
6行目でexpand_bytes()
によりパケットのペイロードのデータを変数に格納します。1番目のパラメータでコンテナの先頭イテレータ(uint8_t*
ポインタ)を指定します。.begin()
メソッドにより取得できます。2番目のパラメータはコンテナの末尾の次を指すイテレータで.end()
メソッドで取得できます。2番目はコンテナの末尾を超えた読み出しを行わないようにするためです。
3番目以降のパラメータに変数を列挙します。列挙した順番にペイロードの読み出しとデータ格納が行われます。
このアクトでは、パケット長が間違っていた場合などのエラーチェックを省いています。チェックを厳格にしたい場合は、expand_bytes()
の戻り値により判定してください。
expand_bytes()
の戻り値は uint8_t*
ですが、末尾を超えたアクセスの場合はnullptr
(ヌルポインタ)を戻します。
msg
に読み出した4バイト文字列の識別子が"PING"
の場合はPONGメッセージを送信する処理です。
if (! strncmp((const char * )msg, "PING" , MSG_LEN)) {
vTransmit(MSG_PONG, rx.get_psRxDataApp()-> u32SrcAddr);
}
続いて到着したパケット情報を表示します。
Serial << format("<RX ad=%x/lq=%d/ln=%d/sq=%d:" // note: up to 4 args!
, rx.get_psRxDataApp()-> u32SrcAddr
, rx.get_lqi()
, rx.get_length()
, rx.get_psRxDataApp()-> u8Seq
)
<< format(" %s AD=%d V=%d TS=%dms>" // note: up to 4 args!
, msg
, adcval
, volt
, timestamp
)
<< mwx:: crlf
<< mwx:: flush;
数値のフォーマット出力が必要になるのでformat()
を用いています。>>
演算子向けにprintf()
と同じ構文を利用できるようにしたヘルパークラスですが、引数の数は最大8つまで(32bitパラメータの場合)に制限されています。(制限を超えるとコンパイルエラーが出ます。なおSerial.printfmt()
には引数の数の制限がありません。)
mwx::crlf
は改行文字(CRLF)を、mwx::flush
は出力完了待ちを指定します(mwx::flush
はSerial.flush()
と記述しても構いません)。
1.4.1.6 - BRD_APPTWELITE デジタル・アナログ信号伝送
App_Twelite と同じ配線を想定したボードサポート <BRD_APPTWELITE>
を用いたサンプルです。
このサンプルは App_Twelite と通信できません。
このアクトには以下が含まれます。
無線パケットの送受信 インタラクティブモードによる設定 - <STG_STD>
ディジタル(ボタン)入力 - Buttons
アナログ入力 - Analogue
アクトの機能 M1を読み取り、親機か子機かを決めます。 DI1-DI4 の値を読み取ります。Buttons
クラスにより、チャタリングの影響を小さくするため、連続で同じ値になったときにはじめて変化が通知されます。変化があったときには通信を行います。 AI1-AI4 の値を読み取ります。 DIの変化または1秒おきに、DI1-4, AI1-4, VCC の値を、自身が親機の場合は子機へ、子機の場合は親機宛に送信します。 受信したパケットの値に応じで DO1-4, PWM1-4 に設定します。 アクトの使い方 必要なTWELITEと配線例 役割 例 親機 TWELITE DIP最低限 M1=GND, DI1:ボタン, DO1:LEDの配線をしておく。 子機 TWELITE DIP最低限 M1=オープン, DI1:ボタン, DO1:LEDの配線をしておく。
配線例 (AI1-AI4は省略可)
アクトの解説 宣言部 インクルード
// use twelite mwx c++ template library
#include <TWELITE>
#include <NWK_SIMPLE>
#include <BRD_APPTWELITE>
#include <STG_STD>
全てのアクトで<TWELITE>
をインクルードします。ここでは、シンプルネットワーク <NWK_SIMPLE>
とボードサポート <BRD_APPTWELITE>
をインクルードしておきます。
またインタラクティブモードを追加するために <STG_STD>
をインクルードしています。
その他
/*** Config part */
// application ID
const uint32_t DEFAULT_APP_ID = 0x1234abcd ;
// channel
const uint8_t DEFAULT_CHANNEL = 13 ;
// option bits
uint32_t OPT_BITS = 0 ;
// logical id
uint8_t LID = 0 ;
/*** function prototype */
MWX_APIRET transmit ();
void receive ();
/*** application defs */
const char APP_FOURCHAR[] = "BAT1" ;
// sensor values
uint16_t au16AI[5 ];
uint8_t u8DI_BM;
サンプルアクト共通宣言 長めの処理を関数化しているため、そのプロトタイプ宣言(送信と受信) アプリケーション中のデータ保持するための変数 setup()
void setup () {
/*** SETUP section */
// init vars
for (auto && x : au16AI) x = 0xFFFF ;
u8DI_BM = 0xFF ;
// load board and settings
auto && set = the_twelite.settings.use< STG_STD> ();
auto && brd = the_twelite.board.use< BRD_APPTWELITE> ();
auto && nwk = the_twelite.network.use< NWK_SIMPLE> ();
// settings: configure items
set << SETTINGS:: appname("BRD_APPTWELITE" );
set << SETTINGS:: appid_default(DEFAULT_APP_ID); // set default appID
set << SETTINGS:: ch_default(DEFAULT_CHANNEL); // set default channel
set.hide_items(E_STGSTD_SETID:: OPT_DWORD2, E_STGSTD_SETID:: OPT_DWORD3, E_STGSTD_SETID:: OPT_DWORD4, E_STGSTD_SETID:: ENC_KEY_STRING, E_STGSTD_SETID:: ENC_MODE);
set.reload(); // load from EEPROM.
OPT_BITS = set.u32opt1(); // this value is not used in this example.
LID = set.u8devid(); // logical ID
// the twelite main class
the_twelite
<< set // apply settings (appid, ch, power)
<< TWENET:: rx_when_idle(); // open receive circuit (if not set, it can't listen packts from others)
if (brd.get_M1()) { LID = 0 ; }
// Register Network
nwk << set // apply settings (LID and retry)
;
// if M1 pin is set, force parent device (LID=0)
nwk << NWK_SIMPLE:: logical_id(LID); // write logical id again.
/*** BEGIN section */
// start ADC capture
Analogue.setup(true, ANALOGUE:: KICK_BY_TIMER0); // setup analogue read (check every 16ms)
Analogue.begin(pack_bits(
BRD_APPTWELITE:: PIN_AI1,
BRD_APPTWELITE:: PIN_AI2,
BRD_APPTWELITE:: PIN_AI3,
BRD_APPTWELITE:: PIN_AI4,
PIN_ANALOGUE:: VCC)); // _start continuous adc capture.
// Timer setup
Timer0.begin(32 , true); // 32hz timer
// start button check
Buttons.setup(5 ); // init button manager with 5 history table.
Buttons.begin(pack_bits(
BRD_APPTWELITE:: PIN_DI1,
BRD_APPTWELITE:: PIN_DI2,
BRD_APPTWELITE:: PIN_DI3,
BRD_APPTWELITE:: PIN_DI4),
5 , // history count
4 ); // tick delta (change is detected by 5*4=20ms consequtive same values)
the_twelite.begin(); // start twelite!
/*** INIT message */
Serial << "--- BRD_APPTWELITE ---" << mwx:: crlf;
Serial << format("-- app:x%08x/ch:%d/lid:%d"
, the_twelite.get_appid()
, the_twelite.get_channel()
, nwk.get_config().u8Lid
)
<< mwx:: crlf;
Serial << format("-- pw:%d/retry:%d/opt:x%08x"
, the_twelite.get_tx_power()
, nwk.get_config().u8RetryDefault
, OPT_BITS
)
<< mwx:: crlf;
}
大まかな流れは、各部の初期設定、各部の開始となっています。
各種ビヘイビアオブジェクトの登録
auto && set = the_twelite.settings.use< STG_STD> ();
auto && brd = the_twelite.board.use< BRD_APPTWELITE> ();
auto && nwk = the_twelite.network.use< NWK_SIMPLE> ();
システムの振る舞いを決めるためのビヘイビアオブジェクトを登録します。インタラクティブモードの設定管理で合ったり、ボードサポート、また無線パケットのネットワーク記述です。
インタラクティブモードの設定
// インタラクティブモードの初期化
auto && set = the_twelite.settings.use< STG_STD> ();
set << SETTINGS:: appname("BRD_APPTWELITE" );
set << SETTINGS:: appid_default(DEFAULT_APP_ID); // set default appID
set << SETTINGS:: ch_default(DEFAULT_CHANNEL); // set default channel
set.hide_items(E_STGSTD_SETID:: OPT_DWORD2, E_STGSTD_SETID:: OPT_DWORD3, E_STGSTD_SETID:: OPT_DWORD4, E_STGSTD_SETID:: ENC_KEY_STRING, E_STGSTD_SETID:: ENC_MODE);
set.reload(); // load from EEPROM.
OPT_BITS = set.u32opt1(); // this value is not used in this example.
LID = set.u8devid(); // logical ID;
インタラクティブモードの初期化を行います。まずsetオブジェクトを取得しています。続いて以下の処理を行っています。
アプリケーション名を"BRD_APPTWELITE"
に設定(メニューで利用される) デフォルトのアプリケーションIDとチャネル値を書き換える 不要な項目を削除する set.reload()
により保存された設定値を読み出すOPT_BITS
とLID
の値を変数にコピーする
読み出したインタラクティブモードの設定の反映については後述します。
以下は画面例です。+ + + と + を3回、0.2 秒から 1 秒の間をあけて入力するとインタラクティブモード画面を出すことが出来ます。
[CONFIG/BRD_APPTWELITE:0/SID=8XXYYYYY]
a: (0x1234ABCD) Application ID [HEX:32bit]
i: ( 13) Device ID [1-100,etc]
c: ( 13) Channel [11-26]
x: ( 0x03) RF Power/Retry [HEX:8bit]
o: (0x00000000) Option Bits [HEX:32bit]
[ESC]:Back [!]:Reset System [M]:Extr Menu
Option Bits をメニューに表示していますが、このサンプルでは使用していません。
the_twelite
このオブジェクトはTWENETの中核としてふるまいます。
auto && brd = the_twelite.board.use< BRD_APPTWELITE> ();
ボードの登録(このアクトでは<BRD_APPTWELITE>
を登録しています)。以下のように use
の後に <>
で登録したいボードの名前を指定します。
ユニバーサル参照(auto&&
)にて得られた戻り値として、参照型でのボードオブジェクトが得られます。このオブジェクトにはボード特有の操作や定義が含まれます。以下ではボードオブジェクトを用い、M1ピンの状態を確認しています。M1ピンがLOWであれば、LID
=0、つまり親機アドレスと設定します。
if (brd.get_M1()) { LID = 0 ; }
the_twelite
を動作させるには初期設定が必要です。アプリケーションIDや無線チャネルの設定は必須といえます。
// the twelite main class
the_twelite
<< set
<< TWENET:: rx_when_idle(); // open receive circuit (if not set, it can't listen packts from others)
the_twelite
に設定を反映するには <<
を用います。
set
はインタラクティブモードから読み出した設定の一部(アプリケーションIDや無線チャネルなど)反映させます。反映される項目は<STG_STD>
の解説を参照してください。TWENET::rx_when_idle()
受信回路をオープンにする指定です。
<<
, >>
演算子はC言語におけるビットシフト演算子ですが、ここではその意味合いとは異なる挿入演算子(stream insertion operator)として使用しています。MWXライブラリでは、C++標準ライブラリの入出力利用にならって上記のような設定やシリアルポートの入出力等で利用します。
ただし、以下の記述は MWX ライブラリでは利用できません。
#include <iostream>
std:: cout << "hello world" << std:: endl;
次にネットワークを登録します。
auto && nwk = the_twelite.network.use< NWK_SIMPLE> ();
nwk << set;
nwk << NWK_SIMPLE:: logical_id(LID);
1行目は、ボードの登録と同じ書き方で <>
には <NWK_SIMPLE>
を指定します。
2,3行目は、<NWK_SIMPLE>
の設定です。先にインタラクティブモードの設定値を反映させます。反映される項目はLID
と再送回数です。このアプリケーションではM1ピンの状態によってLID=0
にする場合があるため、3行目で再度LID
を設定しています。
Analogue
ADC(アナログディジタルコンバータ)を取り扱うクラスオブジェクトです。
Analogue.setup(true, ANALOGUE:: KICK_BY_TIMER0);
初期化Analogue.setup()
で行います。パラメータのtrue
はADC回路の安定までその場で待つ指定です。2番目のパラメータは、ADCの開始をTimer0
に同期して行う指定です。
Analogue.begin(pack_bits(
BRD_APPTWELITE:: PIN_AI1,
BRD_APPTWELITE:: PIN_AI2,
BRD_APPTWELITE:: PIN_AI3,
BRD_APPTWELITE:: PIN_AI4,
PIN_ANALOGUE:: VCC));
ADCを開始するにはAnalogue.begin()
を呼びます。パラメータはADC対象のピンに対応するビットマップです。
ビットマップを指定するのにpack_bits()
関数を用います。可変数引数の関数で、各引数には1を設定するビット位置を指定します。例えばpack_bits(1,3,5)
なら2進数で 101010
の値が戻ります。この関数はconstexpr
指定があるため、パラメータが定数のみであれば定数に展開されます。
パラメータと指定されるBRD_APPTWELITE::
にはPIN_AI1..4
が定義されています。App_Tweliteで用いるAI1..AI4に対応します。AI1=ADC1, AI2=DIO0, AI3=ADC2, AI4=DIO2 と割り当てられています。PIN_ANALOGUE::
にはADCで利用できるピンの一覧が定義されています。
初回を除き ADC の開始は、割り込みハンドラ内で行います。
DIO (ディジタル入力) の値の変化を検出します。Buttons
では、メカ式のボタンのチャタリング(摺動)の影響を軽減するため、一定回数同じ値が検出されてから、値の変化とします。
初期化は Buttons.setup()
で行います。パラメータの 5
は、値の確定に必要な検出回数ですが、設定可能な最大値を指定します。内部的にはこの数値をもとに内部メモリの確保を行っています。
Buttons.begin(pack_bits(
BRD_APPTWELITE:: PIN_DI1,
BRD_APPTWELITE:: PIN_DI2,
BRD_APPTWELITE:: PIN_DI3,
BRD_APPTWELITE:: PIN_DI4),
5 , // history count
4 ); // tick delta
開始は Buttons.begin()
で行います。1番目のパラメータは検出対象のDIOです。BRD_APPTWELITE::
に定義されるPIN_DI1-4 (DI1-DI4) を指定しています。2番めのパラメータは状態を確定するのに必要な検出回数です。3番めのパラメータは検出間隔です。4を指定しているので4msごとに5回連続で同じ値が検出できた時点で、HIGH, LOWの状態が確定します。
Buttons
でのDIO状態の検出はイベントハンドラで行います。イベントハンドラは、割り込み発生後にアプリケーションループで呼ばれるため割り込みハンドラに比べ遅延が発生します。
Timer0
Timer0.begin(32 , true); // 32hz timer
App_Twelite ではアプリケーションの制御をタイマー起点で行っているため、このアクトでも同じようにタイマー割り込み・イベントを動作させます。もちろん1msごとに動作しているシステムのTickTimerを用いても構いません。
上記の例の1番目のパラメータはタイマーの周波数で32Hzを指定しています。2番目のパラメータをtrue
にするとソフトウェア割り込みが有効になります。
Timer0.begin()
を呼び出したあと、タイマーが稼働します。
the_twelite
の動作開始
the_twelite.begin(); // start twelite!
setup()
関数の末尾で the_twelite.begin()
を実行しています。
Serial
Serial
オブジェクトは、初期化や開始手続きなく利用できます。
Serial << "--- BRD_APPTWELITE ---" << mwx:: crlf;
Serial << format("-- app:x%08x/ch:%d/lid:%d"
, the_twelite.get_appid()
, the_twelite.get_channel()
, nwk.get_config().u8Lid
)
<< mwx:: crlf;
Serial << format("-- pw:%d/retry:%d/opt:x%08x"
, the_twelite.get_tx_power()
, nwk.get_config().u8RetryDefault
, OPT_BITS
)
<< mwx:: crlf;
このサンプルでは始動時のメッセージとしていくつかのシステム設定値を表示しています。Serial
オブジェクトには const char*
型の文字列や、int
型(他の整数型はNG)、printf()
とほぼ同じ振る舞いをするformat()
、改行文字を出力するcrlf
などを<<
演算子に与えます。
サンプル中では名前空間mwx::
を省略している場合もあります。上記ではmwx::crlf
と記載していますがcrlf
と記載しても構いません。mwx::
名前空間は、一部を省略可能とするように設計しています。
loop()
ループ関数は TWENET ライブラリのメインループからコールバック関数として呼び出されます。ここでは、利用するオブジェクトが available になるのを待って、その処理を行うのが基本的な記述です。ここではアクトで使用されているいくつかのオブジェクトの利用について解説します。
TWENET ライブラリのメインループは、事前にFIFOキューに格納された受信パケットや割り込み情報などをイベントとして処理し、そののちloop()
が呼び出されます。loop()
を抜けた後は CPU が DOZE モードに入り、低消費電流で新たな割り込みが発生するまでは待機します。
したがってCPUが常に稼働していることを前提としたコードはうまく動作しません。
/*** loop procedure (called every event) */
void loop () {
if (Buttons.available()) {
uint32_t bp, bc;
Buttons.read(bp, bc);
u8DI_BM = uint8_t (collect_bits(bp,
BRD_APPTWELITE:: PIN_DI4, // bit3
BRD_APPTWELITE:: PIN_DI3, // bit2
BRD_APPTWELITE:: PIN_DI2, // bit1
BRD_APPTWELITE:: PIN_DI1)); // bit0
transmit();
}
if (Analogue.available()) {
au16AI[0 ] = Analogue.read(PIN_ANALOGUE:: VCC);
au16AI[1 ] = Analogue.read_raw(BRD_APPTWELITE:: PIN_AI1);
au16AI[2 ] = Analogue.read_raw(BRD_APPTWELITE:: PIN_AI2);
au16AI[3 ] = Analogue.read_raw(BRD_APPTWELITE:: PIN_AI3);
au16AI[4 ] = Analogue.read_raw(BRD_APPTWELITE:: PIN_AI4);
}
if (Timer0.available()) {
static uint8_t u16ct;
u16ct++ ;
if (u8DI_BM != 0xFF && au16AI[0 ] != 0xFFFF ) { // finished the first capture
if ((u16ct % 32 ) == 0 ) { // every 32ticks of Timer0
transmit();
}
}
}
}
DIO(ディジタルIO)の入力変化を検出したタイミングで available になり、Buttons.read()
により読み出します。
if (Buttons.available()) {
uint32_t bp, bc;
Buttons.read(bp, bc);
1番目のパラメータは、現在のDIOのHIGH/LOWのビットマップで、bit0から順番にDIO0,1,2,.. と並びます。例えば DIO12 であれば bp & (1UL << 12)
を評価すれば HIGH / LOW が判定できます。ビットが1になっているものがHIGHになります。
初回のIO状態確定時は MSB (bit31) に1がセットされます。スリープ復帰時も初回の確定処理を行います。
次にビットマップから値を取り出してu8DI_BM
に格納しています。ここではMWXライブラリで用意したcollect_bits()
関数を用いています。
u8DI_BM = uint8_t (collect_bits(bp,
BRD_APPTWELITE:: PIN_DI4, // bit3
BRD_APPTWELITE:: PIN_DI3, // bit2
BRD_APPTWELITE:: PIN_DI2, // bit1
BRD_APPTWELITE:: PIN_DI1)); // bit0
/* collect_bits は以下の処理を行います。
u8DI_BM = 0;
if (bp & (1UL << BRD_APPTWELITE::PIN_DI1)) u8DI_BM |= 1;
if (bp & (1UL << BRD_APPTWELITE::PIN_DI2)) u8DI_BM |= 2;
if (bp & (1UL << BRD_APPTWELITE::PIN_DI3)) u8DI_BM |= 4;
if (bp & (1UL << BRD_APPTWELITE::PIN_DI4)) u8DI_BM |= 8;
*/
collect_bits()
は、上述のpack_bits()
と同様のビット位置の整数値を引数とします。可変数引数の関数で、必要な数だけパラメータを並べます。上記の処理では bit0 は DI1、bit1 は DI2、bit2 は DI3、bit3 は DI4の値としてu8DI_BM
に格納しています。
App_Twelite では、DI1から4に変化があった場合に無線送信しますので、Buttons.available()
を起点に送信処理を行います。transmit()
処理の内容は後述します。
Analogue
ADCのアナログディジタル変換が終了した直後のloop()
で available になります。次の ADC が開始するまでは、データは直前に取得されたものとして読み出すことが出来ます。
ADCのアナログディジタル変換が終了した直後のloop()で available になります。次の ADC が開始するまでは、データは直前に取得されたものとして読み出すことが出来ます。
ADC値を読むには Analogue.read()
または Analogue.read_raw()
メソッドを用います。read()
はmVに変換した値、read_raw()
は 0..1023
のADC値となります。パラメータにはADCのピン番号を指定します。ADCのピン番号はPIN_ANALOGUE::
やBRD_APPTWELITE::
に定義されているので、こちらを利用しています。
周期的に実行されるADCの値は、タイミングによってはavailable通知前のより新しい値が読み出されることがあります。
このアクトでは32Hzと比較的ゆっくりの周期で処理しているため、available判定直後に処理すれば問題にはなりませんが、変換周期が短い場合、loop()
中で比較的長い時間のかかる処理をしている場合は注意が必要です。
Analogue
には、変換終了後に割り込みハンドラ内から呼び出されるコールバック関数を指定することが出来ます。例えば、このコールバック関数からFIFOキューに値を格納する処理を行い、アプリケーションループ内ではキューの値を逐次読み出すといった非同期処理を行います。
Timer0
Timer0は32Hzで動作しています。タイマー割り込みが発生直後の loop()
で available になります。つまり、秒32回の処理をします。ここでは、ちょうど1秒になったところで送信処理をしています。
if (Timer0.available()) {
static uint8_t u16ct;
u16ct++ ;
if (u8DI_BM != 0xFF && au16AI[0 ] != 0xFFFF ) { // finished the first capture
if ((u16ct % 32 ) == 0 ) { // every 32ticks of Timer0
transmit();
}
}
}
AppTweliteでは約1秒おきに定期送信を行っています。Timer0
がavailableになったときにu16ctをインクリメントします。このカウンタ値をもとに、32回カウントが終わればtransmit()
を呼び出し無線パケットを送信しています。
u8DI_BM
とau16AI[]
の値判定は、初期化直後かどうかの判定です。まだDI1..DI4やAI1..AI4の値が格納されていない場合は何もしません。
transmit()
無線パケットの送信要求をTWENETに行う関数です。本関数が終了した時点では、まだ無線パケットの処理は行われません。実際に送信が完了するのは、送信パラメータ次第ですが、数ms後以降になります。ここでは代表的な送信要求方法について解説します。
MWX_APIRET transmit () {
if (auto && pkt = the_twelite.network.use< NWK_SIMPLE> ().prepare_tx_packet()) {
auto && set = the_twelite.settings.use< STG_STD> ();
if (! set.is_screen_opened()) {
Serial << "..DI=" << format("%04b " , u8DI_BM);
Serial << format("ADC=%04d/%04d/%04d/%04d " , au16AI[1 ], au16AI[2 ], au16AI[3 ], au16AI[4 ]);
Serial << "Vcc=" << format("%04d " , au16AI[0 ]);
Serial << " --> transmit" << mwx:: crlf;
}
// set tx packet behavior
pkt << tx_addr(u8devid == 0 ? 0xFE : 0x00 ) // 0..0xFF (LID 0:parent, FE:child w/ no id, FF:LID broad cast), 0x8XXXXXXX (long address)
<< tx_retry(0x1 ) // set retry (0x1 send two times in total)
<< tx_packet_delay(0 ,50 ,10 ); // send packet w/ delay (send first packet with randomized delay from 100 to 200ms, repeat every 20ms)
// prepare packet payload
pack_bytes(pkt.get_payload() // set payload data objects.
, make_pair(APP_FOURCHAR, 4 ) // string should be paired with length explicitly.
, uint8_t (u8DI_BM)
);
for (auto && x : au16AI) {
pack_bytes(pkt.get_payload(), uint16_t (x)); // adc values
}
// do transmit
return pkt.transmit();
}
return MWX_APIRET(false, 0 );
}
関数プロトタイプ
MWX_APIRET
はuint32_t
型のデータメンバを持つ戻り値を取り扱うクラスです。MSB(bit31)が成功失敗、それ以外が戻り値として利用するものです。
ネットワークオブジェクトとパケットオブジェクトの取得
if (auto && pkt = the_twelite.network.use< NWK_SIMPLE> ().prepare_tx_packet()) {
ネットワークオブジェクトをthe_twelite.network.use<NWK_SIMPLE>()
で取得します。そのオブジェクトを用いて.prepare_tx_packet()
によりpkt
オブジェクトを取得します。
ここではif
文の条件判定式の中で宣言しています。宣言したpkt
オブジェクトはif
節の終わりまで有効です。pkt
オブジェクトはbool
型の応答をし、ここではTWENETの送信要求キューに空きがあって送信要求を受け付ける場合にtrue
、空きがない場合にfalse
となります。
インタラクティブモード画面表示中の表示抑制
auto && set = the_twelite.settings.use< STG_STD> ();
if (! set.is_screen_opened()) {
//インタラクティブモード画面中ではない!
}
インタラクティブモードの画面が表示されているときは、画面出力を抑制します。
パケットの送信設定
pkt << tx_addr(u8devid == 0 ? 0xFE : 0x00 ) // 0..0xFF (LID 0:parent, FE:child w/ no id, FF:LID broad cast), 0x8XXXXXXX (long address)
<< tx_retry(0x1 ) // set retry (0x3 send four times in total)
<< tx_packet_delay(0 ,50 ,10 ); // send packet w/ delay (send first packet with randomized delay from 100 to 200ms, repeat every 20ms)
パケットの設定はthe_twelite
の初期化設定のように<<
演算子を用いて行います。
tx_addr()
パラメータに送信先アドレスを指定します。0x00
なら自分が子機で親機宛に、0xFE
なら自分が親機で任意の子機宛のブロードキャストという意味です。tx_retry()
パラメータに再送回数を指定します。例の1は再送回数が1回、つまり合計2回パケットを送ります。無線パケット1回のみの送信では条件が良くても数%程度の失敗はあります。tx_packet_delay()
送信遅延を設定します。一つ目のパラメータは、送信開始までの最低待ち時間、2番目が最長の待ち時間です。この場合は送信要求を発行後におよそ0msから50msの間で送信を開始します。3番目が再送間隔です。最初のパケットが送信されてから10ms置きに再送を行うという意味です。パケットのデータペイロード ペイロードは積載物という意味ですが、無線パケットでは「送りたいデータ本体」という意味でよく使われます。無線パケットのデータにはデータ本体以外にもアドレス情報などいくつかの補助情報が含まれます。
送受信を正しく行うために、データペイロードのデータ並び順を意識するようにしてください。ここでは以下のようなデータ順とします。このデータ順に合わせてデータペイロードを構築します。
# 先頭バイトのインデックス: データ型 : バイト数 : 内容
00: uint8_t[4] : 4 : 4文字識別子
04: uint8_t : 1 : DI1..4のビットマップ
06: uint16_t : 2 : Vccの電圧値
08: uint16_t : 2 : AI1のADC値 (0..1023)
10: uint16_t : 2 : AI2のADC値 (0..1023)
12: uint16_t : 2 : AI3のADC値 (0..1023)
14: uint16_t : 2 : AI4のADC値 (0..1023)
データペイロードには90バイト格納できます(実際にはあと数バイト格納できます)。
IEEE802.15.4の無線パケットの1バイトは貴重です。できるだけ節約して使用することを推奨します。1パケットで送信できるデータ量に限りがあります。パケットを分割する場合は分割パケットの送信失敗などを考慮する必要がありコストは大きくつきます。また1バイト余分に送信するのに、およそ16μ秒×送信時の電流に相当するエネルギーが消費され、特に電池駆動のアプリケーションには大きく影響します。
上記の例は、解説のためある程度の妥協をしています。節約を考える場合 00: の識別子は1バイトの簡単なものにすべきですし、VCCの電圧値は8ビットに丸めてもかまわないでしょう。また各AI1..AI4の値は10bitで、合計40bit=5バイトに対して6バイト使用しています。
上記のデータペイロードのデータ構造を実際に構築してみます。データペイロードは pkt.get_payload()
により simplbuf<uint8_t>
型のコンテナとして参照できます。このコンテナに上記の仕様に基づいてデータを構築します。
auto && payl = pkt.get_payload();
payl.reserve(16 ); // 16バイトにリサイズ
payl[00 ] = APP_FOURCHAR[0 ];
payl[01 ] = APP_FOURCHAR[1 ];
...
payl[08 ] = (au16AI[0 ] & 0xFF00 ) >> 8 ; //Vcc
payl[09 ] = (au16AI[0 ] & 0xFF );
...
payl[14 ] = (au16AI[4 ] & 0xFF00 ) >> 8 ; // AI4
payl[15 ] = (au16AI[4 ] & 0xFF );
上記のように記述できますがMWXライブラリでは、データペイロード構築のための補助関数pack_bytes()
を用意しています。
// prepare packet payload
pack_bytes(pkt.get_payload() // set payload data objects.
, make_pair(APP_FOURCHAR, 4 ) // string should be paired with length explicitly.
, uint8_t (u8DI_BM)
);
for (auto && x : au16AI) {
pack_bytes(pkt.get_payload(), uint16_t (x)); // adc values
}
pack_bytes()
の最初のパラメータはコンテナを指定します。この場合はpkt.get_payload()
です。
そのあとのパラメータは可変数引数でpack_bytes()
で対応する型の値を必要な数だけ指定します。pack_bytes()
は内部で.push_back()
メソッドを呼び出して末尾に指定した値を追記していきます。
3行目のmake_pair()
は標準ライブラリの関数でstd::pair
を生成します。文字列型の混乱(具体的にはペイロードの格納時にヌル文字を含めるか含めないか)を避けるための指定です。make_pair()
の1番目のパラメータに文字列型(char*
やuint8_t*
型、uint8_t[]
など)を指定します。2番目のパラメータはペイロードへの格納バイト数です。
4行目はuint8_t
型でDI1..DI4のビットマップを書き込みます。
7-9行目ではau16AI
配列の値を順に書き込んでいます。この値はuint16_t
型で2バイトですが、ビッグエンディアンの並びで書き込みます。
7行目のfor
文はC++で導入された範囲for 文です。サイズのわかっている配列やbegin()
, end()
によるイテレータによるアクセスが可能なコンテナクラスなどは、この構文が使用できます。au16AI
の型もコンパイル時に判定できるため auto&&
(ユニバーサル参照)で型の指定も省略してます。
通常のfor
文に書き換えると以下のようになります。
for (int i = 0 ; i < sizeof (au16AI)/ sizeof (uint16_t )); i++ ) {
pack_bytes(pkt.get_payload(), au16AI[i]);
}
これでパケットの準備は終わりです。あとは、送信要求を行います。
パケットを送信するにはpkt
オブジェクトのpkt.transmit()
メソッドを用います。戻り値としてMWX_APIRET型を返していますが、このアクトでは使っていません。
戻り値には、要求の成功失敗の情報と要求に対応する番号が格納されています。送信完了まで待つ処理を行う場合は、この戻り値の値を利用します。
on_rx_packet()
無線パケットが受信できたときは、受信イベントとしてon_rx_packet()
が呼び出されます。
the_twelite.receiver
による手続きでは一旦受信パケットを内部キュー(2パケットまで格納)に格納してからの処理でしたが、on_rx_packet()
ではTWENETライブラリからのコールバックから直接呼び出され、より取りこぼし等が発生しにくい手続きです。ただしloop()
文中で長時間処理を止めてしまうような記述を行うと、同じように取りこぼしの原因となります。
ここでは、相手方から伝えられたDI1..DI4の値とAI1..AI4の値を、自身のDO1..DO4とPWM1..PWM4に設定します。
void on_rx_packet (packet_rx& rx, bool_t & handled) {
auto && set = the_twelite.settings.use< STG_STD> ();
Serial << format("..receive(%08x/%d) : " , rx.get_addr_src_long(), rx.get_addr_src_lid());
// expand the packet payload
char fourchars[5 ]{};
auto && np = expand_bytes(rx.get_payload().begin(), rx.get_payload().end()
, make_pair((uint8_t * )fourchars, 4 ) // 4bytes of msg
);
// check header
if (strncmp(APP_FOURCHAR, fourchars, 4 )) { return ; }
// read rest of payload
uint8_t u8DI_BM_remote = 0xff ;
uint16_t au16AI_remote[5 ];
expand_bytes(np, rx.get_payload().end()
, u8DI_BM_remote
, au16AI_remote[0 ]
, au16AI_remote[1 ]
, au16AI_remote[2 ]
, au16AI_remote[3 ]
, au16AI_remote[4 ]
);
Serial << format("DI:%04b" , u8DI_BM_remote & 0x0F );
for (auto && x : au16AI_remote) {
Serial << format("/%04d" , x);
}
Serial << mwx:: crlf;
// set local DO
digitalWrite(BRD_APPTWELITE:: PIN_DO1, (u8DI_BM_remote & 1 ) ? HIGH : LOW);
digitalWrite(BRD_APPTWELITE:: PIN_DO2, (u8DI_BM_remote & 2 ) ? HIGH : LOW);
digitalWrite(BRD_APPTWELITE:: PIN_DO3, (u8DI_BM_remote & 4 ) ? HIGH : LOW);
digitalWrite(BRD_APPTWELITE:: PIN_DO4, (u8DI_BM_remote & 8 ) ? HIGH : LOW);
// set local PWM : duty is set 0..1024, so 1023 is set 1024.
Timer1.change_duty(au16AI_remote[1 ] == 1023 ? 1024 : au16AI_remote[1 ]);
Timer2.change_duty(au16AI_remote[2 ] == 1023 ? 1024 : au16AI_remote[2 ]);
Timer3.change_duty(au16AI_remote[3 ] == 1023 ? 1024 : au16AI_remote[3 ]);
Timer4.change_duty(au16AI_remote[4 ] == 1023 ? 1024 : au16AI_remote[4 ]);
}
関数プロトタイプ
void on_rx_packet(packet_rx& rx, bool_t & handled)
受信パケットのデータrx
をパラメータとして渡されます。rx
から無線パケットのアドレス情報やデータペイロードにアクセスします。パラメータhandled
は通常利用しません。
送信元アドレスの表示
if (! set.is_screen_opened()) {
Serial << format("..receive(%08x/%d) : " ,
rx.get_addr_src_long(), rx.get_addr_src_lid());
}
受信パケットデータには、送信元のアドレス(32bitのロングアドレスと8bitの論理アドレス)などの情報を参照しています。インタラクティブモード画面が表示されているときは出力を抑制します。
<NWK_SIMPLE>
では、8bitの論理IDと32bitのロングアドレスの2種類が常にやり取りされます。送り先を指定する場合はロングアドレスか論理アドレスのいずれかを指定します。受信時には両方のアドレスが含まれます。
パケットの識別 MWXライブラリにはtransmit()
の時に使ったpack_bytes()
の対になる関数expand_bytes()
が用意されています。
char fourchars[5 ]{};
auto && np = expand_bytes(rx.get_payload().begin(), rx.get_payload().end()
, make_pair((uint8_t * )fourchars, 4 ) // 4bytes of msg
);
1行目ではデータ格納のためのchar
型の配列を宣言しています。サイズが5バイトなのは末尾にヌル文字を含め、文字出力などでの利便性を挙げるためです。末尾の{}
は初期化の指定で、5バイト目を0
にすれば良いのですが、ここでは配列全体をデフォルトの方法で初期化、つまり0
にしています。
2行目でexpand_bytes()
により4バイト文字列を取り出しています。パラメータにコンテナ型を指定しない理由は、この続きを読み出すための読み出し位置を把握する必要があるためです。1番目のパラメータでコンテナの先頭イテレータ(uint8_t*
ポインタ)を指定します。.begin()
メソッドにより取得できます。2番目のパラメータはコンテナの末尾の次を指すイテレータで.end()
メソッドで取得できます。2番目はコンテナの末尾を超えた読み出しを行わないようにするためです。
3番目に読み出す変数を指定しますが、ここでもmake_pair()
によって文字列配列とサイズのペアを指定します。
このアクトでは、パケット長が間違っていた場合などのエラーチェックを省いています。チェックを厳格にしたい場合は、expand_bytes()
の戻り値により判定してください。
expand_bytes()
の戻り値は uint8_t*
ですが、末尾を超えたアクセスの場合はnullptr
(ヌルポインタ)を戻します。
読み出した4バイト文字列の識別子が、このアクトで指定した識別子と異なる場合は、このパケットを処理しません。
if (strncmp(APP_FOURCHAR, fourchars, 4 )) { return ; }
TWENETではアプリケーションIDと物理的な無線チャネルが合致する場合は、どのアプリケーションもたとえ種別が違ったとしても、受信することが出来ます。他のアプリケーションで作成したパケットを意図しない形で受信しない目的で、このような識別子やデータペイロードの構造などのチェックを行い、偶然の一致が起きないように対処することを推奨します。
シンプルネットワーク<NWK_SIMPLE>
でのパケット構造の要件も満足する必要があるため、シンプルネットワークを使用しない他のアプリケーションが同じ構造のパケットを定義しない限り(非常にまれと思われます)、パケットの混在受信は発生しません。
データペイロードの取得 DI1..DI4の値とAI1..AI4の値を別の変数に格納します。
// read rest of payload
uint8_t u8DI_BM_remote = 0xff ;
uint16_t au16AI_remote[5 ];
expand_bytes(np, rx.get_payload().end()
, u8DI_BM_remote
, au16AI_remote[0 ]
, au16AI_remote[1 ]
, au16AI_remote[2 ]
, au16AI_remote[3 ]
, au16AI_remote[4 ]
);
先ほどのexpand_bytes()
の戻り値np
を1番目のパラメータにしています。先に読み取った4バイト文字列識別子の次から読み出す指定です。2番目のパラメータは同様です。
3番目以降のパラメータはデータペイロードの並びに一致した型の変数を、送り側のデータ構造と同じ順番で並べています。この処理が終われば、指定した変数にペイロードから読み出した値が格納されます。
取得したデータの表示 確認のためシリアルポートへ出力します。インタラクティブモード画面が表示されているときは出力は抑制します。
auto && set = the_twelite.settings.use< STG_STD> ();
...
Serial << format("DI:%04b" , u8DI_BM_remote & 0x0F );
for (auto && x : au16AI_remote) {
Serial << format("/%04d" , x);
}
Serial << mwx:: crlf;
数値のフォーマット出力が必要になるのでformat()
を用いています。>>
演算子向けにprintf()
と同じ構文を利用できるようにしたヘルパークラスですが、引数の数が4つまでに制限されています。(Serial.printfmt()
には引数の数の制限がありません。)
3行目の "DI:%04b"
は"DI:0010"のようにDI1..DI4のビットマップを4桁で表示します。
5行目の"/%04d"
は"/3280/0010/0512/1023/1023"のように Vcc/AI1..AI4の値を順に整数で出力します。
7行目のmwx::crlf
は改行文字列を出力します。
信号の出力 これで必要なデータの展開が終わったので、あとはボード上のDO1..DO4とPWM1..PWM4の値を変更します。
// set local DO
digitalWrite(BRD_APPTWELITE:: PIN_DO1, (u8DI_BM_remote & 1 ) ? HIGH : LOW);
digitalWrite(BRD_APPTWELITE:: PIN_DO2, (u8DI_BM_remote & 2 ) ? HIGH : LOW);
digitalWrite(BRD_APPTWELITE:: PIN_DO3, (u8DI_BM_remote & 4 ) ? HIGH : LOW);
digitalWrite(BRD_APPTWELITE:: PIN_DO4, (u8DI_BM_remote & 8 ) ? HIGH : LOW);
// set local PWM : duty is set 0..1024, so 1023 is set 1024.
Timer1.change_duty(au16AI_remote[1 ] == 1023 ? 1024 : au16AI_remote[1 ]);
Timer2.change_duty(au16AI_remote[2 ] == 1023 ? 1024 : au16AI_remote[2 ]);
Timer3.change_duty(au16AI_remote[3 ] == 1023 ? 1024 : au16AI_remote[3 ]);
Timer4.change_duty(au16AI_remote[4 ] == 1023 ? 1024 : au16AI_remote[4 ]);
digitalWrite()
はディジタル出力の値を変更します。1番目のパラメータはピン番号で、2番目はHIGH(VCCレベル)かLOW(GNDレベル)を指定します。
Timer?.change_duty()
はPWM出力のデューティ比を変更します。パラメータにデューティ比 0..1024
を指定します。最大値が1023
でないことに注意してください。ライブラリ内で実行される割り算のコストが大きいため、2のべき乗である1024
を最大値としています。0
にするとGNDレベル、1024
にするとVCCレベル相当の出力になります。
1.4.1.7 - BRD_I2C_TEMPHUMID I2Cセンサーデバイスによるデータ送信
I2C センサーデバイスを用いて、定期起床からの計測および送信を行うサンプルです。
このサンプルでは、当社の 環境センサーパル AMBIENT SENSE PAL あるいは TWELITE ARIA BLUE / RED に搭載の I2C センサーデバイスを利用しています。しかし、I2Cコマンド送受信部分を書き換えることで、その他の一般的な I2C センサーデバイス(図中 Generic I2C Sensor Module
) を利用することもできます。その場合には、以下のように配線してください。
一般的なI2Cデバイスの接続
このアクトには以下が含まれます。
無線パケットの送受信 インタラクティブモードによる設定 - <STG_STD>
ステートマシンによる状態遷移制御 - <SM_SIMPLE>
アクトの機能 I2C デバイスのコマンド送受信を行います。 コイン電池で動作させるための、スリープ機能を利用します。 アクトの使い方 必要なTWELITE アクトの解説 インクルード
#include <TWELITE>
#include <NWK_SIMPLE> // ネットワークサポート
#include <STG_STD> // インタラクティブモード
#include <SM_SIMPLE> // 簡易ステートマシン
無線送受信に必要な <NWK_SIMPLE>
、インタラクティブモードを追加するための <STG_STD>
、アプリケーションループの記述を簡素化するための <SM_SIMPLE>
をインクルードしています。
センサードライバ この例では SHTC3 (TWELITE AMB PAL) と、SHT40 (TWELITE ARIA) の2種類のコードがあり #ifdef
により切り替えています(USE_SHTC3
またはUSE_SHT40
のどちらかを #define
してください)。コードの移植性のため2種類は同じ関数インタフェースとして定義しています。2種類のコードは同メーカ、同系列のセンサーであるため似通っています。
/*** sensor select, define either of USE_SHTC3 or USE_SHT40 */
// use SHTC3 (TWELITE PAL)
#define USE_SHTC3
// use SHT40 (TWELITE ARIA)
#undef USE_SHT40
以下では SHTC3 の例を示します。
#if defined(USE_SHTC3)
// for SHTC3
struct SHTC3 {
uint8_t I2C_ADDR;
uint8_t CONV_TIME;
bool setup () { ... }
bool begin () { ... }
int get_convtime () { return CONV_TIME; }
bool read (int16_t & i16Temp, int16_t & i16Humd) { ... }
} sensor_device;
ここではソースコードを整理するため I2C センサー関連の手続きを構造体(クラス) SHTC3 にまとめています。この構造体には I2C アドレス I2C_ADDR
と、値取得のための待ち時間 CONV_TIME
をメンバー変数として持っており、sensor_device
という実体名で宣言しています。
この構造体(クラス)は以下のメンバー関数を持っています。
関数名 解説 setup()
構造体の初期化を行う。 begin()
センサー値の取得を開始する。開始後、適切なセンサー値が得られるまで一定時間待つ必要がある。 get_convtime()
センサー値の取得待ち時間を返す。 read(int&, int&)
センサー値を取得する。
コンパイラの制約により、グローバル宣言した場合はコンストラクタが呼び出されないため、コンストラクタの代わりにsetup()
を呼び出します。
処理を一つ一つ見ていきます。
setup()
bool setup () {
// here, initialize some member vars instead of constructor.
I2C_ADDR = 0x70 ;
CONV_TIME = 10 ; // wait time [ms]
return true;
}
メンバー変数に I2C アドレスと、センサー値取得待ち時間(上記は10ms)を設定します。
これらの値は原則として固定値ですので変数設定する必要はありません。変数として扱う有効な例として、設定によってより高精度なセンサー稼働をさせるような場合に必要な変換時間を管理する、設定によって I2C の副アドレスを選択するような場合などが考えられます。
begin()
bool begin () {
// send start trigger command
if (auto && wrt = Wire.get_writer(I2C_ADDR)) {
wrt << 0x60 ; // SHTC3_TRIG_H
wrt << 0x9C ; // SHTC3_TRIG_L
} else {
return false;
}
return true;
}
センサーを動作させるために指令を書き込みます。
MWXライブラリでは、Wire
クラスオブジェクトを用いたI2Cバスへの読み書きに2種類の異なった記述方法がありますが、こちらはヘルパー関数を用いる方法です。
if
文中で Wire.get_writer(I2C_ADDR)
は、アドレスI2C_ADDR
に対応するI2Cデバイスを開き、その読み書き用のオブジェクトを生成します。読み書きオブジェクト wrt
は if
節の (bool)
評価により、デバイスのオープンに失敗したときなどには false
を返します。true
が戻った時は無事にオープンできたことになり if
節内の処理を行います。
ここでは wrt << 0x60;
のように、ストリーム演算子 <<
を用いて1バイト I2C デバイスに書き込んでいます。このストリーム演算子は原則 uint8_t
型の1バイトを書き込むためのものです。
get_convtime()
int get_convtime () {
return CONV_TIME;
}
CONV_TIME
の値を返すための関数です。
read()
bool read (int16_t & i16Temp, int16_t & i16Humd) {
// read result
uint16_t u16temp, u16humd;
uint8_t u8temp_csum, u8humd_csum;
if (auto && rdr = Wire.get_reader(I2C_ADDR, 6 )) {
rdr >> u16temp; // read two bytes (MSB first)
rdr >> u8temp_csum; // check sum (crc8)
rdr >> u16humd; // read two bytes (MSB first)
rdr >> u8humd_csum; // check sum (crc8)
} else {
return false;
}
// check CRC and save the values
if ( (CRC8_u8CalcU16(u16temp, 0xff ) == u8temp_csum)
&& (CRC8_u8CalcU16(u16humd, 0xff ) == u8humd_csum))
{
i16Temp = (int16_t )(- 4500 + ((17500 * int32_t (u16temp)) >> 16 ));
i16Humd = (int16_t )((int32_t (u16humd) * 10000 ) >> 16 );
} else {
return false;
}
return true;
}
センサーデータを読み出します。
SHTC3では、begin()
によりセンサー読み出しを開始してから、数ms待ち時間をおいてセンサー値を読み出します。 センサー値の並びは以下のようになっています。
バイト 解説 0 温度センサー値(上位バイト) 1 温度センサー値(下位バイト) 2 バイト0,1のCRC8値 3 湿度センサー値(上位バイト) 4 湿度センサー値(下位バイト) 5 バイト3,4のCRC8値
SHTC3では、センサー取得開始時に与えるパラメータによってデータの並び順も変化しますが、上記begin()
で書き込んだ0x609C
コマンドで開始した場合は、温度データが先に到着します。
begin()
ではデータを書き出していましたが、ここではデータを読み込みます。データを読み込むには同様に Wire.get_reader()
により、ヘルパーオブジェクト rdr
を生成します。エラーがなければ rdr
は if
節中で true
を返します。ここで get_reader(I2C_ADDR, 6)
の2番目に与えたパラメータ 6
は、読み出しバイト数です。このバイト数を読みだした時点で I2C バスの読出しを終了する手続きを行います。(デバイスによっては、こういった手続きを省略しても動作するものもありますが、通常は適切な値を与えるようにしてください)
読み出しはストリーム演算子 >>
により行っています。読み出し方法にはほかにもいくつかあります。詳しくは ヘルパー関数 を参照してください。ストリーム演算子を用いる場合は、事前に宣言した uint8_t
, uint16_t
, uint32_t
型の変数に値を入力します。rdr >> u16temp
は、uint16_t
型の変数に対して2バイトI2Cバスから読み出し**ビッグエンディアン形式(1バイト目は上位バイト)**で格納します。
最終的に i16Temp ・ i16Humd
に温度[℃]の100倍値、および湿度[%]の100倍値を計算して格納しています。計算式について I2C デバイスのデータシートを参照してください。
setup()
setup()
関数は TWELITE が始動したときに1度だけ呼び出される関数です。この関数では、各種初期化を行います。
void setup () {
/*** SETUP section */
...
}
ステートマシン SM_SIMPLE
の初期化
// application state defs
enum class STATE : uint8_t {
INTERACTIVE = 255 ,
INIT = 0 ,
SENSOR,
TX,
TX_WAIT_COMP,
GO_SLEEP
};
// simple state machine.
SM_SIMPLE< STATE> step;
void setup () {
...
/// init vars or objects
step.setup(); // initialize state machine
...
}
ステートマシン(状態遷移マシン)は、都度呼び出される loop()
文中の記述を簡素化するために用います。もちろん、アプリケーションの記述を行うのに、この例で使用する SM_SIMPLE
を使用しなくても構いません。
SM_SIMPLE
は、ごく短いコードで実装されており、状態への遷移と、タイムアウトの管理、フラグの管理を簡易的に行えます。状態はあらかじめ列挙体で定義しておきます。上記の例では enum class STATE
です。ステートマシンの実体は定義済みの列挙体 STATE
をパラメータとして SM_SMPLE<STATE> step
のように宣言します。
ビヘイビアの登録
void setup () {
...
/// load board and settings objects
auto && set = the_twelite.settings.use< STG_STD> (); // load save/load settings(interactive mode) support
auto && nwk = the_twelite.network.use< NWK_SIMPLE> (); // load network support
...
}
ビヘイビアは、プログラム中で利用する機能のまとまりです。各種イベントが発生したときの振る舞いが記述されています。
ここでは、インタラクティブモード画面 <STG_STD>
と、シンプル中継ネットワーク <NWK_SMPLE>
の2種類のビヘイビアを利用します。
インタラクティブモードの設定 STG_STD
...
/// configure settings
// configure settings
set << SETTINGS:: appname(FOURCHARS);
set << SETTINGS:: appid_default(DEFAULT_APP_ID); // set default appID
set << SETTINGS:: ch_default(DEFAULT_CHANNEL); // set default channel
set.hide_items(E_STGSTD_SETID:: OPT_DWORD2, E_STGSTD_SETID:: OPT_DWORD3, E_STGSTD_SETID:: OPT_DWORD4, E_STGSTD_SETID:: ENC_KEY_STRING, E_STGSTD_SETID:: ENC_MODE);
記述するアプリケーションに合わせたインタラクティブモードの設定項目にするため、 STG_STD に対して初期設定を行います。
SETTINGS::appname
: アプリケーション名(文字列)を指定します。インタラクティブモード画面上で先頭行に表示されます。画面上の文字数には余裕がないので最小限の文字列にします。SETTINGS::appid_default
: アプリケーションIDの規定値です。独自のアプリケーションで独自の規定アプリケーションIDを持たせたい場合に実行します。SETTINGS::ch_default
: チャネルの規定値です。独自のアプリケーションで既定のチャネルを持たせたい場合に実行します。続いて set.hide_items()
では、既定のインタラクティブモードの画面上で不要な設定項目を削除しています。すべて表示しても構わない場合は、この呼び出しを行う必要はありません。
// if SET(DIO12)=LOW is detected, start with intaractive mode.
if (digitalRead(PIN_DIGITAL:: DIO12) == PIN_STATE:: LOW) {
set << SETTINGS:: open_at_start();
step.next(STATE:: INTERACTIVE);
return ;
}
DIO12 のピンが LOW (GNDレベル) で、電源投入またはリセットされた場合は、インタラクティブモードで起動する記述です。digitalRead()
でピンの状態を読み取り、SETTINGS::open_at_start()
を反映させます。
インタラクティブモード中に通常のアプリケーション処理が行われてしまうと不都合であるため、ステートマシンの状態を STATE::INTERACTIVE
に設定します。この状態では、一切の入力等の処理を行わず同じ状態にとどまります。
// load values
set.reload(); // load from EEPROM.
OPT_BITS = set.u32opt1(); // this value is not used in this example.
// LID is configured DIP or settings.
LID = set.u8devid(); // 2nd is setting.
if (LID == 0 ) LID = 0xFE ; // if still 0, set 0xFE (anonymous child)
最後にインタラクティブモードのデータを読み込みます。set.reload()
を呼び出すことで、EEPROM に書き込まれたデータを読み込みます。設定が行われず EEPROM に何も情報がない場合は、規定値として読みだせます。
ここではオプションビット set.u32opt1()
と、8ビットの論理ID set.u8devid()
を読み出します。LID が 0
の場合は、通常親機として運用されるため、この値が記録されている場合は 0xFE
(IDを割り振らない子機) としています。
/// configure system basics
the_twelite << set; // apply settings (from interactive mode)
nwk << set; // apply settings (from interactive mode)
nwk << NWK_SIMPLE:: logical_id(LID); // set LID again (LID can also be configured by DIP-SW.)
...
最後に the_twelite
と nwk
に設定情報(の一部)を反映させています。アプリケーションIDやチャネルといった無線通信に必須の情報が反映されます。上記ではこれらの設定に対する明示的な読み出しコードは存在しませんが set.reload()
で、設定がなければ規定値に、あれば設定値が読み出されます。
ペリフェラルの初期化
/*** BEGIN section */
Wire.begin(); // start two wire serial bus.
I2C センサーの初期化設定を行っています。
MWX の開始
// let the TWELITE begin!
the_twelite.begin();
/*** INIT message */
Serial << "--- TEMP&HUMID:" << FOURCHARS << " ---" << mwx:: crlf;
Serial << format("-- app:x%08x/ch:%d/lid:%d"
, the_twelite.get_appid()
, the_twelite.get_channel()
, nwk.get_config().u8Lid
)
<< mwx:: crlf;
Serial << format("-- pw:%d/retry:%d/opt:x%08x"
, the_twelite.get_tx_power()
, nwk.get_config().u8RetryDefault
, OPT_BITS
)
<< mwx:: crlf;
the_twelite.begin()
は MWX ライブラリの初期化完了を宣言する手続きです。この処理を行わないと、MWX ライブラリは適切に動作しません。
起動時のメッセージなどもここで表示します。
loop()
void loop () {
do {
switch (step.state()) {
// 各状態の振る舞い
case STATE:: INIT:
...
break ;
...
}
while (step.b_more_loop());
}
loop()
は、SM_SIMPLE
ステートマシンstep
を用いた制御を行っています。スリープ復帰からセンサー値取得、無線パケット送信、送信完了待ち、スリープといった一連の流れを簡潔に表現するためです。
ステートマシン図
上記の do while
文の制御構造を記述しておきます。ステート(状態)は step.state()
で判定します。while
の条件式は step.b_more_loop()
となっています。これは、ある状態からさらに別の状態に遷移したときに、loop()
を抜けずに連続的に処理したい場合があるためです。つまり、別の状態に遷移して switch
節を抜けた場合、次の状態の case
節が呼び出されます。この動作には注意してください。
case STATE::INTERACTIVE:
インタラクティブモード中にメインループが動作するのは都合が悪いため、この状態に固定します。
case STATE::INIT:
// start sensor capture
sensor_device.begin();
step.set_timeout(sensor_device.get_convtime()); // set timeout
step.next(STATE:: SENSOR);
センサーのデータ取得を開始します。set_timeout()
で、センサー取得の時間待ちを行います。
時間待ちの非常に長いセンサーなどは、ここでいったんスリープを行うといった処理を記述すると電池寿命を延ばすことができますが、構造が複雑になるためこの例では割愛します。必要な場合はスリープ待ちの例を参照してください。
case STATE::SENSOR:
if (step.is_timeout()) {
// the sensor data should be ready (wait some)
sensor_device.read(sensor.i16temp, sensor.i16humid);
Serial << "..finish sensor capture." << mwx:: crlf
<< " : temp=" << div100(sensor.i16temp) << 'C' << mwx:: crlf
<< " humd=" << div100(sensor.i16humid) << '%' << mwx:: crlf
;
Serial.flush();
step.next(STATE:: TX);
}
センサーの値を sensor_device.read()
により取得して sensor
構造体に値を格納します。
最初に step.is_timeout()
によるタイムアウトチェックを行います。タイムアウトの起点は先ほどの step.set_timeout()
です。タイムアウトしない場合は、if
節は実行されず、そのまま loop()
を抜けます。次のハードウェアイベント(多くの場合はシステムタイマーである1ms ごとに割り込みを発生するTickTimerの割り込み)が来るまではTWELITE マイコンは低電力でCPUが待機するDOZE(ドーズ)モードになります。
無線センサーとしてセンサー側の TWELITE のシリアルポートに結果を出力する必要はありませんが、動作確認を容易にするためシリアルポートに取得値を表示しています。ここで Serial.flush()
を行い出力待ちを行っていますが、これは TWELITE がスリープするまでにシリアルポート出力が終わらないことを想定した記述です。この処理も、電池消耗の原因になるためSerial.flush()
を行わないようにするか、シリアルポートへの出力をしないようにします。
ここで使用する div100()
は、低コストで100の除算を行う関数です。TWELITE には除算回路がありませんので、除算処理は極力行わないことを推奨します。
case STATE::TX:
step.next(STATE:: GO_SLEEP); // set default next state (for error handling.)
// get new packet instance.
if (auto && pkt = the_twelite.network.use< NWK_SIMPLE> ().prepare_tx_packet()) {
...
}
通信手続きを記述します。この状態で待ち処理などを行うことはなく、処理を実行したら速やかに次の状態に遷移します。あらかじめ step.next(STATE::GO_SLEEP)
と記述しているのは、エラーなどの検出は複数個所で行われるため、すべての場所で同じ記述を行うことを避けるためです。
if (auto&& pkt = the_twelite.network.use<NWK_SIMPLE>().prepare_tx_packet())
では、送信パケットのオブジェクトを生成し、オブジェクトの生成に成功したら if
節を実行するという処理です。
// set tx packet behavior
pkt << tx_addr(0x00 ) // 0..0xFF (LID 0:parent, FE:child w/ no id, FF:LID broad cast), 0x8XXXXXXX (long address)
<< tx_retry(0x1 ) // set retry (0x1 send two times in total)
<< tx_packet_delay(0 , 0 , 2 ); // send packet w/ delay
最初に送信の設定を行います。宛先 tx_addr(0x00)
を親機 0x00
に設定し、再送回数 tx_retry(0x1)
を1回にし、パケットの遅延の設定 tx_packet_delay(0, 0, 2)
を初回送信までの遅延は 0、再送間隔を 2ms と設定しています。
pack_bytes(pkt.get_payload()
, make_pair(FOURCHARS, 4 )
, uint16_t (sensor.i16temp)
, uint16_t (sensor.i16humid)
);
パケットのペイロード部に識別子のFOURCHARS
とセンサーデータを格納します。得られた値のうち温度値は int16_t
ですが、送信パケットのデータ構造は符号なしで格納するため、uint16_t
にキャストしています。
// do transmit
MWX_APIRET ret = pkt.transmit();
if (ret) {
step.clear_flag(); // waiting for flag is set.
step.set_timeout(100 ); // set timeout
step.next(STATE:: TX_WAIT_COMP);}
pkt.transmit()
を呼び送信要求を行います。この時点ではまだ送信処理は始らず、送信要求を内部のキューに設定しただけです。MWXライブラリ内で適切なタイミングで送信要求が処理されます。
送信要求に成功した場合 ret
は true
になります。完了を判定するためのフラグの初期化 step.clear_flag()
、送信失敗時など予期しないエラーを処理するためのタイムアウト step.set_timeout(100)
を設定し、次の状態を STATE::TX_WAIT_COMP
にします(STATE::GO_SLEEP
の指定は上書きされます)。
case STATE::TX_WAIT_COMP:
ここでは送信の完了待ちを行います。タイムアウトの判定(エラー時)または送信完了イベントの判定を行います。
if (step.is_timeout()) { // maybe fatal error.
the_twelite.reset_system();
}
if (step.is_flag_ready()) { // when tx is performed
Serial << "..transmit complete." << mwx:: crlf;
Serial.flush();
step.next(STATE:: GO_SLEEP);
}
STATE::GO_SLEEP:
sleepNow()
の処理を行います。この関数を呼び出すことで TWELITE はスリープ状態になります。
on_tx_comp()
void on_tx_comp (mwx:: packet_ev_tx& ev, bool_t & b_handled) {
step.set_flag(ev.bStatus);
}
送信完了時に呼び出されるシステムイベントです。ここでは.set_flag()
を呼び出しstep
のフラグをセットします。
sleepNow()
void sleepNow () {
step.on_sleep(false); // reset state machine.
// randomize sleep duration.
uint32_t u32ct = 1750 + random(0 ,500 );
// output message
Serial << "..sleeping " << int (u32ct) << "ms." << mwx:: crlf;
Serial.flush(); // wait until all message printed.
// do sleep.
the_twelite.sleep(u32ct);
}
スリープ前に.on_sleep(false)
によりステートマシンの状態を初期化します。パラメータのfalse
はスリープ復帰後STATE::INIT(=0)
から始めます。
ここでは、起床までの時間を乱数により 1750ms から 2250ms の間に設定しています。これにより他の同じような周期で送信するデバイスのパケットとの連続的な衝突を避けます。
周期が完全に一致すると、互いのパケットで衝突が起き通信が困難になります。通常は時間の経過とともにタイマー周期が互いにずれるため、しばらくすると通信が回復し、また時間がたつと衝突が起きるという繰り返しになります。
8,9行目、この例ではシリアルポートからの出力を待ってスリープに入ります。通常は消費エネルギーを最小化したいため、スリープ前のシリアルポートの出力は最小限(または無し)にします。
12行目、スリープに入るには the_twelite.sleep()
を呼びます。この呼び出しの中で、ボード上のハードウェアのスリープ前の手続きなどが行われます。パラメータとしてスリープ時間をmsで指定しています。
TWELITE PAL では、必ず60秒以内に一度起床し、ウォッチドッグタイマーをリセットしなければなりません。スリープ時間は60000
を超えないように指定してください。
wakeup()
void wakeup () {
Serial << mwx:: crlf
<< "--- PAL_AMB:" << FOURCHARS << " wake up ---"
<< mwx:: crlf
<< "..start sensor capture again."
<< mwx:: crlf;
...
}
スリープから復帰し起床すると wakeup()
が呼び出されます。そのあとloop()
が都度呼び出されます。wakeup()
の前に、UARTなどの各ペリフェラルやボード上のデバイスのウェイクアップ処理が行われます。例えばLEDの点灯制御を再始動します。
1.4.1.8 - BRD_ARIA TWELITE ARIAを使ったサンプル
TWELITE ARIA - トワイライトアリア を用い、センサー値の取得を行います。
このアクトには以下が含まれます。
無線パケットの送受信 インタラクティブモードによる設定 - <STG_STD>
ステートマシンによる状態遷移制御 - <SM_SIMPLE>
<ARIA>
ボードビヘイビアによるボード操作アクトの機能 TWELITE ARIA - トワイライトアリア を用い、センサー値の取得を行います。 コイン電池で動作させるための、スリープ機能を利用します。 アクトの使い方 必要なTWELITE アクトの解説 インクルード
#include <TWELITE>
#include <NWK_SIMPLE> // ネットワークサポート
#include <ARIA> // TWELITE ARIA
#include <STG_STD> // インタラクティブモード
#include <SM_SIMPLE> // 簡易ステートマシン
TWELITE ARIA<ARIA>
のボードビヘイビアをインクルードします。
setup()
void setup (){
/*** SETUP section */
/// init vars or objects
step.setup(); // initialize state machine
/// load board and settings objects
auto && brd = the_twelite.board.use< ARIA> (); // load board support
auto && set = the_twelite.settings.use< STG_STD> (); // load save/load settings(interactive mode) support
auto && nwk = the_twelite.network.use< NWK_SIMPLE> (); // load network support
/// configure settings
// configure settings
set << SETTINGS:: appname("ARIA" );
set << SETTINGS:: appid_default(DEFAULT_APP_ID); // set default appID
set << SETTINGS:: ch_default(DEFAULT_CHANNEL); // set default channel
set.hide_items(E_STGSTD_SETID:: OPT_DWORD2, E_STGSTD_SETID:: OPT_DWORD3, E_STGSTD_SETID:: OPT_DWORD4, E_STGSTD_SETID:: ENC_KEY_STRING, E_STGSTD_SETID:: ENC_MODE);
// if SET=LOW is detected, start with intaractive mode.
if (digitalRead(brd.PIN_SET) == PIN_STATE:: LOW) {
set << SETTINGS:: open_at_start();
step.next(STATE:: INTERACTIVE);
return ;
}
// load values
set.reload(); // load from EEPROM.
OPT_BITS = set.u32opt1(); // this value is not used in this example.
LID = set.u8devid(); // set logical ID
/// configure system basics
the_twelite << set; // apply settings (from interactive mode)
/// configure network
nwk << set; // apply settings (from interactive mode)
nwk << NWK_SIMPLE:: logical_id(LID); // set LID again (LID can also be configured by DIP-SW.)
/// configure hardware
// LED setup (use periph_led_timer, which will re-start on wakeup() automatically)
brd.set_led(LED_TIMER:: BLINK, 10 ); // blink (on 10ms/ off 10ms)
// let the TWELITE begin!
the_twelite.begin();
/*** INIT message */
Serial << "--- ARIA:" << FOURCHARS << " ---" << mwx:: crlf;
Serial << format("-- app:x%08x/ch:%d/lid:%d"
, the_twelite.get_appid()
, the_twelite.get_channel()
, nwk.get_config().u8Lid
)
<< mwx:: crlf;
Serial << format("-- pw:%d/retry:%d/opt:x%08x"
, the_twelite.get_tx_power()
, nwk.get_config().u8RetryDefault
, OPT_BITS
)
<< mwx:: crlf;
}
最初に変数などの初期化を行います。ここではステートマシンstep
の初期化を行っています。
最初にボードサポート <ARIA>
を登録します。ボードサポートの初期化時にセンサーやDIOの初期化が行われます。
auto && brd = the_twelite.board.use< ARIA> ();
つづいて、インタラクティブモード関連の初期化と読出しを行います。
// configure settings
set << SETTINGS:: appname("ARIA" );
set << SETTINGS:: appid_default(DEFAULT_APP_ID); // set default appID
set << SETTINGS:: ch_default(DEFAULT_CHANNEL); // set default channel
set.hide_items(E_STGSTD_SETID:: OPT_DWORD2, E_STGSTD_SETID:: OPT_DWORD3, E_STGSTD_SETID:: OPT_DWORD4, E_STGSTD_SETID:: ENC_KEY_STRING, E_STGSTD_SETID:: ENC_MODE);
// if SET=LOW is detected, start with intaractive mode.
if (digitalRead(brd.PIN_SET) == PIN_STATE:: LOW) {
set << SETTINGS:: open_at_start();
step.next(STATE:: INTERACTIVE);
return ;
}
// load values
set.reload(); // load from EEPROM.
OPT_BITS = set.u32opt1(); // this value is not used in this example.
LID = set.u8devid(); // set logical ID
ここではset
オブジェクトの取得、アプリ名の反映、デフォルトのアプリケーションIDと通信チャネルの反映、設定メニューで不要項目の削除を行います。
次にSETピンの状態を読み出します。このサンプルはスリープによる間欠動作を行うため、+++
入力によるインタラクティブモード遷移は出来ません。替わりに起動時のSETピン=LO状態でインタラクティブモードに遷移します。このときSETTINGS::open_at_start()
を指定していますが、これはsetup()
を終了後速やかにインタラクティブモード画面に遷移する指定です。
最後に.reload()
を実行して設定値をEEPROMから読み出します。設定値を各変数にコピーしています。
このアクトではもっぱら無線パケットを送信しますので、TWENET の設定では動作中に受信回路をオープンにする指定(TWENET::rx_when_idle()
)は含めません。
the_twelite << set; // apply settings (from interactive mode)
続いてLEDの設定を行います。ここでは 10ms おきに ON/OFF の点滅の設定をします(スリープを行い起床時間が短いアプリケーションでは、起床中は点灯するという設定とほぼ同じ意味合いになります)。
brd.set_led(LED_TIMER:: BLINK, 10 ); // blink (on 10ms/ off 10ms)
loop()
void loop () {
auto && brd = the_twelite.board.use< ARIA> ();
do {
switch (step.state()) {
// 各状態の振る舞い
case STATE:: INIT:
...
break ;
...
}
while (step.b_more_loop());
}
loop()
は、SM_SIMPLE
ステートマシンstep
を用いた制御を行っています。スリープ復帰からセンサー値取得、無線パケット送信、送信完了待ち、スリープといった一連の流れを簡潔に表現するためです。ループの戦闘ではbrd
オブジェクトを取得しています。
case STATE::INTERACTIVE:
インタラクティブモード中にメインループが動作するのは都合が悪いため、この状態に固定します。
case STATE::INIT:
brd.sns_SHT4x.begin();
step.next(STATE:: SENSOR);
センサーのデータ取得を開始します。
case STATE::SENSOR:
// wait until sensor capture finish
if (! brd.sns_SHT4x.available()) {
brd.sns_SHT4x.process_ev(E_EVENT_TICK_TIMER);
}else { // now sensor data is ready.
sensor.i16temp = brd.sns_SHT4x.get_temp_cent();
sensor.i16humid = brd.sns_SHT4x.get_humid_per_dmil();
// read magnet sensor
sensor.b_north = digitalRead(ARIA:: PIN_SNS_NORTH);
sensor.b_south = digitalRead(ARIA:: PIN_SNS_SOUTH);
Serial << "..finish sensor capture." << mwx:: crlf
<< " MAGnet : north=" << int (sensor.b_north) << mwx:: crlf
<< " south=" << int (sensor.b_south) << mwx:: crlf
<< " SHT4x : temp=" << div100(sensor.i16temp) << 'C' << mwx:: crlf
<< " humd=" << div100(sensor.i16humid) << '%' << mwx:: crlf
;
Serial.flush();
step.next(STATE:: TX);
}
ボード上のセンサーは .sns_SHT4x
という名前でアクセスでき、このオブジェクトに操作を行います。センサーの完了待ちを行います。まだセンサーの取得が終わっていない場合(.available()
がfalse
)はセンサーに対して時間経過のイベント(.process_ev(E_EVENT_TICK_TIMER)
)を送付します。
センサーがavailableになった時点で、センサー値を取得し、STATE_TX
に遷移します。
温湿度センサーは以下のように取得できます。
.get_temp_cent()
: int16_t
: 1℃を100とした温度 (25.6 ℃なら 2560).get_temp()
: float
: float値 (25.6 ℃なら 25.6).get_humid_dmil()
: int16_t
: 1%を100とした湿度 (56.8%なら 5680).get_temp()
: float
: float値 (56.8%なら 56.8)case STATE::TX:
送信手続きについては他のアクトのサンプルと同様です。ここでは、再送1回、再送遅延を最小にする設定になっています。
pkt << tx_addr(0x00 ) // 親機0x00宛
<< tx_retry(0x1 ) // リトライ1回
<< tx_packet_delay(0 , 0 , 2 ); // 遅延は最小限
パケットのペイロード部に識別子のFOURCHARS
とセンサーデータを格納します。得られた値のうち温度値は int16_t
ですが、送信パケットのデータ構造は符号なしで格納するため、uint16_t
にキャストしています。
pack_bytes(pkt.get_payload() // set payload data objects.
, make_pair(FOURCHARS, 4 ) // just to see packet identification, you can design in any.
, uint8_t (sensor.b_north)
, uint8_t (sensor.b_south)
, uint16_t (sensor.i16temp)
, uint16_t (sensor.i16humid)
);
送信要求を行います。送信要求が成功したら送信完了街の準備を行います。完了イベントを待つために.clear_flag()
、万が一のときのタイムアウトをset_timeout(100)
を指定します。パラメータの100
の単位はミリ秒[ms]です。
// do transmit
MWX_APIRET ret = pkt.transmit();
if (ret) {
step.clear_flag(); // waiting for flag is set.
step.set_timeout(100 ); // set timeout
step.next(STATE:: TX_WAIT_COMP);
}
case STATE::TX_WAIT_COMP:
ここではタイムアウトの判定、送信完了イベントの判定を行います。
if (step.is_timeout()) { // maybe fatal error.
the_twelite.reset_system();
}
if (step.is_flag_ready()) { // when tx is performed
Serial << "..transmit complete." << mwx:: crlf;
Serial.flush();
step.next(STATE:: GO_SLEEP);
}
STATE::GO_SLEEP:
sleepNow()
の処理を行います。
on_tx_comp()
void on_tx_comp (mwx:: packet_ev_tx& ev, bool_t & b_handled) {
step.set_flag(ev.bStatus);
}
送信完了時に呼び出されるシステムイベントです。ここでは.set_flag()
により完了としています。
sleepNow()
スリープに入る手続きをまとめています。
void sleepNow () {
step.on_sleep(false); // reset state machine.
// randomize sleep duration.
uint32_t u32ct = 1750 + random(0 ,500 );
// set an interrupt for MAGnet sensor.
pinMode(ARIA:: PIN_SNS_OUT1, PIN_MODE:: WAKE_FALLING);
pinMode(ARIA:: PIN_SNS_OUT2, PIN_MODE:: WAKE_FALLING);
// output message
Serial << "..sleeping " << int (u32ct) << "ms." << mwx:: crlf;
Serial.flush(); // wait until all message printed.
// do sleep.
the_twelite.sleep(u32ct);
}
スリープ前に.on_sleep(false)
によりステートマシンの状態を初期化します。パラメータのfalse
はスリープ復帰後STATE::INIT(=0)
から始めます。
ここでは、起床までの時間を乱数により 1750ms から 2250ms の間に設定しています。これにより他の同じような周期で送信するデバイスのパケットとの連続的な衝突を避けます。
周期が完全に一致すると、互いのパケットで衝突が起き通信が困難になります。通常は時間の経過とともにタイマー周期が互いにずれるため、しばらくすると通信が回復し、また時間がたつと衝突が起きるという繰り返しになります。
8,9行目では、スリープに入るまえに磁気センサーのDIOピンの割り込み設定をします。pinMode()
を用います。2番めのパラメータはPIN_MODE::WAKE_FALLING
を指定しています。これはHIGHからLOWへピンの状態が変化したときに起床する設定です。
12,13行目、この例ではシリアルポートからの出力を待ってスリープに入ります。通常は消費エネルギーを最小化したいため、スリープ前のシリアルポートの出力は最小限(または無し)にします。
16行目、スリープに入るには the_twelite.sleep()
を呼びます。この呼び出しの中で、ボード上のハードウェアのスリープ前の手続きなどが行われます。たとえばLEDは消灯します。
パラメータとしてスリープ時間をmsで指定しています。
TWELITE ARIA では、必ず60秒以内に一度起床し、ウォッチドッグタイマーをリセットしなければなりません。スリープ時間は60000を超えないように指定してください。
wakeup()
スリープから復帰し起床すると wakeup()
が呼び出されます。そのあとloop()
が都度呼び出されます。wakeup()
の前に、UARTなどの各ペリフェラルやボード上のデバイスのウェイクアップ処理が行われます。例えばLEDの点灯制御を再始動します。
void wakeup () {
Serial << mwx:: crlf
<< "--- ARIA:" << FOURCHARS << " wake up " ;
if (the_twelite.is_wokeup_by_wktimer()) {
Serial << "(WakeTimer) ---" ;
} else
if (the_twelite.is_wokeup_by_dio(ARIA:: PIN_SNS_NORTH)) {
Serial << "(MAGnet INT [N]) ---" ;
} else
if (the_twelite.is_wokeup_by_dio(ARIA:: PIN_SNS_SOUTH)) {
Serial << "(MAGnet INT [S]) ---" ;
} else {
Serial << "(unknown source) ---" ;
}
Serial << mwx:: crlf
<< "..start sensor capture again."
<< mwx:: crlf;
}
1.4.1.9 - PAL_AMB 環境センサーパルを使ったサンプル
このアクトには以下が含まれます。
無線パケットの送受信 インタラクティブモードによる設定 - <STG_STD>
ステートマシンによる状態遷移制御 - <SM_SIMPLE>
<PAL_AMB>
ボードビヘイビアによるボード操作アクトの機能 環境センサーパル AMPIENT SENSE PAL を用い、センサー値の取得を行います。 コイン電池で動作させるための、スリープ機能を利用します。 アクトの使い方 必要なTWELITE アクトの解説 インクルード
#include <TWELITE>
#include <NWK_SIMPLE> // ネットワークサポート
#include <PAL_AMB> // PAL_AMB
#include <STG_STD> // インタラクティブモード
#include <SM_SIMPLE> // 簡易ステートマシン
環境センサーパル <PAL_AMB>
のボードビヘイビアをインクルードします。
setup()
void setup () {
/*** SETUP section */
step.setup(); // ステートマシンの初期化
// PAL_AMBのボードビヘイビアを読み込む
auto && brd = the_twelite.board.use< PAL_AMB> ();
// インタラクティブモードを読み込む
auto && set = the_twelite.settings.use< STG_STD> ();
set << SETTINGS:: appname(FOURCHARS);
set << SETTINGS:: appid_default(APP_ID); // set default appID
set.hide_items(E_STGSTD_SETID:: POWER_N_RETRY, E_STGSTD_SETID:: OPT_DWORD2, E_STGSTD_SETID:: OPT_DWORD3, E_STGSTD_SETID:: OPT_DWORD4, E_STGSTD_SETID:: ENC_KEY_STRING, E_STGSTD_SETID:: ENC_MODE);
// SET ピンを検出した場合は、インタラクティブモードを起動する
if (digitalRead(brd.PIN_BTN) == PIN_STATE:: LOW) {
set << SETTINGS:: open_at_start();
step.next(STATE:: INTERACTIVE);
return ;
}
// インタラクティブモードのデータを読み出す
set.reload();
APP_ID = set.u32appid();
CHANNEL = set.u8ch();
OPT_BITS = set.u32opt1();
// DIPスイッチとインタラクティブモードの設定からLIDを決める
LID = (brd.get_DIPSW_BM() & 0x07 ); // 1st priority is DIP SW
if (LID == 0 ) LID = set.u8devid(); // 2nd is setting.
if (LID == 0 ) LID = 0xFE ; // if still 0, set 0xFE (anonymous child)
// LED初期化
brd.set_led(LED_TIMER:: BLINK, 10 ); // blink (on 10ms/ off 10ms)
// the twelite main object.
the_twelite
<< TWENET:: appid(APP_ID) // set application ID (identify network group)
<< TWENET:: channel(CHANNEL); // set channel (pysical channel)
// Register Network
auto && nwk = the_twelite.network.use< NWK_SIMPLE> ();
nwk << NWK_SIMPLE:: logical_id(u8ID); // set Logical ID. (0xFE means a child device with no ID)
/*** BEGIN section */
Wire.begin(); // start two wire serial bus.
Analogue.begin(pack_bits(PIN_ANALOGUE:: A1, PIN_ANALOGUE:: VCC)); // _start continuous adc capture.
the_twelite.begin(); // start twelite!
startSensorCapture(); // start sensor capture!
/*** INIT message */
Serial << "--- PAL_AMB:" << FOURCHARS << " ---" << mwx:: crlf;
}
最初に変数などの初期化を行います。ここではステートマシンstep
の初期化を行っています。
最初にボードサポート <PAL_AMB>
を登録します。ボードサポートの初期化時にセンサーやDIOの初期化が行われます。最初に行うのは、ボードのDIP SWなどの状態を確認してから、ネットワークの設定などを行うといった処理が一般的だからです。
auto && brd = the_twelite.board.use< PAL_AMB> ();
つづいて、インタラクティブモード関連の初期化と読出しを行います。
// インタラクティブモードを読み込む
auto && set = the_twelite.settings.use< STG_STD> ();
set << SETTINGS:: appname(FOURCHARS);
set << SETTINGS:: appid_default(APP_ID); // set default appID
set.hide_items(E_STGSTD_SETID:: POWER_N_RETRY, E_STGSTD_SETID:: OPT_DWORD2, E_STGSTD_SETID:: OPT_DWORD3, E_STGSTD_SETID:: OPT_DWORD4, E_STGSTD_SETID:: ENC_KEY_STRING, E_STGSTD_SETID:: ENC_MODE);
// SET ピンを検出した場合は、インタラクティブモードを起動する
if (digitalRead(brd.PIN_BTN) == PIN_STATE:: LOW) {
set << SETTINGS:: open_at_start();
step.next(STATE:: INTERACTIVE);
return ;
}
// インタラクティブモードのデータを読み出す
set.reload();
APP_ID = set.u32appid();
CHANNEL = set.u8ch();
OPT_BITS = set.u32opt1();
// DIPスイッチとインタラクティブモードの設定からLIDを決める
LID = (brd.get_DIPSW_BM() & 0x07 ); // 1st priority is DIP SW
if (LID == 0 ) LID = set.u8devid(); // 2nd is setting.
if (LID == 0 ) LID = 0xFE ; // if still 0, set 0xFE (anonymous child)
ここではset
オブジェクトの取得、アプリ名の反映、デフォルトのアプリケーションIDと通信チャネルの反映、設定メニューで不要項目の削除を行います。
次にSETピンの状態を読み出します。このサンプルはスリープによる間欠動作を行うため、+++
入力によるインタラクティブモード遷移は出来ません。替わりに起動時のSETピン=LO状態でインタラクティブモードに遷移します。このときSETTINGS::open_at_start()
を指定していますが、これはsetup()
を終了後速やかにインタラクティブモード画面に遷移する指定です。
最後に.reload()
を実行して設定値をEEPROMから読み出します。設定値を各変数にコピーしています。
続いてLEDの設定を行います。ここでは 10ms おきに ON/OFF の点滅の設定をします(スリープを行い起床時間が短いアプリケーションでは、起床中は点灯するという設定とほぼ同じ意味合いになります)。
brd.set_led(LED_TIMER:: BLINK, 10 ); // blink (on 10ms/ off 10ms)
このアクトではもっぱら無線パケットを送信しますので、TWENET の設定では動作中に受信回路をオープンにする指定(TWENET::rx_when_idle()
)は含めません。
the_twelite
<< TWENET:: appid(APP_ID) // set application ID (identify network group)
<< TWENET:: channel(CHANNEL); // set channel (pysical channel)
ボード上のセンサーはI2Cバスを用いますので、バスを利用開始しておきます。
Wire.begin(); // start two wire serial bus.
ボード上のセンサーの取得を開始します。startSensorCapture()の解説を参照ください。
loop()
void loop () {
auto && brd = the_twelite.board.use< PAL_AMB> ();
do {
switch (step.state()) {
// 各状態の振る舞い
case STATE:: INIT:
...
break ;
...
}
while (step.b_more_loop());
}
loop()
は、SM_SIMPLE
ステートマシンstep
を用いた制御を行っています。スリープ復帰からセンサー値取得、無線パケット送信、送信完了待ち、スリープといった一連の流れを簡潔に表現するためです。ループの戦闘ではbrd
オブジェクトを取得しています。
case STATE::INTERACTIVE:
インタラクティブモード中にメインループが動作するのは都合が悪いため、この状態に固定します。
case STATE::INIT:
brd.sns_SHTC3.begin();
brd.sns_LTR308ALS.begin();
step.next(STATE:: SENSOR);
センサーのデータ取得を開始します。
case STATE::SENSOR:
if (! brd.sns_LTR308ALS.available()) {
brd.sns_LTR308ALS.process_ev(E_EVENT_TICK_TIMER);
}
if (! brd.sns_SHTC3.available()) {
brd.sns_SHTC3.process_ev(E_EVENT_TICK_TIMER);
}
ボード上のセンサーは .sns_LTR308ALS
または .sns_SHTC3
という名前でアクセスでき、このオブジェクトに操作を行います。センサーの完了待ちを行います。まだセンサーの取得が終わっていない場合(.available()
がfalse
)はセンサーに対して時間経過のイベント(.process_ev(E_EVENT_TICK_TIMER)
)を送付します。
センサーがavailableになった時点で、センサー値を取得し、STATE_TX
に遷移します。
// now sensor data is ready.
if (brd.sns_LTR308ALS.available() && brd.sns_SHTC3.available()) {
sensor.u32luminance = brd.sns_LTR308ALS.get_luminance();
sensor.i16temp = brd.sns_SHTC3.get_temp_cent();
sensor.i16humid = brd.sns_SHTC3.get_humid_per_dmil();
Serial << "..finish sensor capture." << mwx:: crlf
<< " LTR308ALS: lumi=" << int (sensor.u32luminance) << mwx:: crlf
<< " SHTC3 : temp=" << div100(sensor.i16temp) << 'C' << mwx:: crlf
<< " humd=" << div100(sensor.i16humid) << '%' << mwx:: crlf
;
Serial.flush();
step.next(STATE:: TX);
}
照度センサーは.get_luminance()
: uint32_t
で得られます。
温湿度センサーは以下のように取得できます。
.get_temp_cent()
: int16_t
: 1℃を100とした温度 (25.6 ℃なら 2560).get_temp()
: float
: float値 (25.6 ℃なら 25.6).get_humid_dmil()
: int16_t
: 1%を100とした湿度 (56.8%なら 5680).get_temp()
: float
: float値 (56.8%なら 56.8)case STATE::TX:
送信手続きについては他のアクトのサンプルと同様です。ここでは、再送1回、再送遅延を最小にする設定になっています。
pkt << tx_addr(0x00 ) // 親機0x00宛
<< tx_retry(0x1 ) // リトライ1回
<< tx_packet_delay(0 , 0 , 2 ); // 遅延は最小限
パケットのペイロード部に識別子のFOURCHARS
とセンサーデータを格納します。得られた値のうち温度値は int16_t
ですが、送信パケットのデータ構造は符号なしで格納するため、uint16_t
にキャストしています。
pack_bytes(pkt.get_payload()
, make_pair(FOURCHARS, 4 )
, uint32_t (sensor.u32luminance)
, uint16_t (sensor.i16temp)
, uint16_t (sensor.i16humid)
);
送信要求を行います。送信要求が成功したら送信完了街の準備を行います。完了イベントを待つために.clear_flag()
、万が一のときのタイムアウトをset_timeout(100)
を指定します。パラメータの100
の単位はミリ秒[ms]です。
// do transmit
MWX_APIRET ret = pkt.transmit();
if (ret) {
step.clear_flag(); // waiting for flag is set.
step.set_timeout(100 ); // set timeout
step.next(STATE:: TX_WAIT_COMP);
}
case STATE::TX_WAIT_COMP:
ここではタイムアウトの判定、送信完了イベントの判定を行います。
if (step.is_timeout()) { // maybe fatal error.
the_twelite.reset_system();
}
if (step.is_flag_ready()) { // when tx is performed
Serial << "..transmit complete." << mwx:: crlf;
Serial.flush();
step.next(STATE:: GO_SLEEP);
}
STATE::GO_SLEEP:
sleepNow()
の処理を行います。
on_tx_comp()
void on_tx_comp (mwx:: packet_ev_tx& ev, bool_t & b_handled) {
step.set_flag(ev.bStatus);
}
送信完了時に呼び出されるシステムイベントです。ここでは.set_flag()
により完了としています。
sleepNow()
スリープに入る手続きをまとめています。
void sleepNow () {
step.on_sleep(false); // reset state machine.
// randomize sleep duration.
uint32_t u32ct = 1750 + random(0 ,500 );
// output message
Serial << "..sleeping " << int (u32ct) << "ms." << mwx:: crlf;
Serial.flush(); // wait until all message printed.
// do sleep.
the_twelite.sleep(u32ct);
}
スリープ前に.on_sleep(false)
によりステートマシンの状態を初期化します。パラメータのfalse
はスリープ復帰後STATE::INIT(=0)
から始めます。
ここでは、起床までの時間を乱数により 1750ms から 2250ms の間に設定しています。これにより他の同じような周期で送信するデバイスのパケットとの連続的な衝突を避けます。
周期が完全に一致すると、互いのパケットで衝突が起き通信が困難になります。通常は時間の経過とともにタイマー周期が互いにずれるため、しばらくすると通信が回復し、また時間がたつと衝突が起きるという繰り返しになります。
8,9行目、この例ではシリアルポートからの出力を待ってスリープに入ります。通常は消費エネルギーを最小化したいため、スリープ前のシリアルポートの出力は最小限(または無し)にします。
12行目、スリープに入るには the_twelite.sleep()
を呼びます。この呼び出しの中で、ボード上のハードウェアのスリープ前の手続きなどが行われます。たとえばLEDは消灯します。
パラメータとしてスリープ時間をmsで指定しています。
TWELITE PAL では、必ず60秒以内に一度起床し、ウォッチドッグタイマーをリセットしなければなりません。スリープ時間は60000を超えないように指定してください。
wakeup()
スリープから復帰し起床すると wakeup()
が呼び出されます。そのあとloop()
が都度呼び出されます。wakeup()
の前に、UARTなどの各ペリフェラルやボード上のデバイスのウェイクアップ処理が行われます。例えばLEDの点灯制御を再始動します。
void wakeup () {
Serial << mwx:: crlf
<< "--- PAL_AMB:" << FOURCHARS << " wake up ---"
<< mwx:: crlf
<< "..start sensor capture again."
<< mwx:: crlf;
応用編 消費エネルギーの削減 アクト PAL_AMB-UseNap は、センサーのデータ取得待ちをスリープで行い、より低消費エネルギーで動作できます。
1.4.1.10 - PAL_AMB-usenap 環境センサーパルを使ったサンプル
環境センサーパル AMBIENT SENSE PAL を用いて、センサー値の取得を行います。
PAL_AMB サンプルを改良し、センサーデータ取得中の待ち時間(約50ms)を、スリープで待つようにします。
このアクトには以下が含まれます。
無線パケットの送受信 インタラクティブモードによる設定 - <STG_STD>
ステートマシンによる状態遷移制御 - <SM_SIMPLE>
<PAL_AMB>
ボードビヘイビアによるボード操作アクトの機能 環境センサーパル AMPIENT SENSE PAL を用い、センサー値の取得を行います。 コイン電池で動作させるための、スリープ機能を利用します。 センサデータ取得中にもスリープ機能を利用します。 アクトの解説 begin()
begin()
関数はsetup()
関数を終了し(そのあとTWENETの初期化が行われる)一番最初のloop()
の直前で呼ばれます。
void begin () {
sleepNow(); // the first time is just sleeping.
}
setup()
終了後に初回スリープを実行します。setup()
中にセンサーデータ取得を開始していますが、この結果は評価せず、センサーを事前に一度は動かしておくという意味あいで、必ずしも必要な手続きではありません。
wakeup()
起床後の手続きです。以下の処理を行います。
まだセンサーデータの取得開始をしていない場合、センサーデータ取得を行い、短いスリープに入る。 直前にセンサーデータ取得開始を行ったので、データを確認して無線送信する。
void wakeup () {
if (! b_senser_started) {
// delete/make shorter this message if power requirement is harder.
Serial << mwx:: crlf
<< "--- PAL_AMB:" << FOURCHARS << " wake up ---"
<< mwx:: crlf
<< "..start sensor capture again."
<< mwx:: crlf;
startSensorCapture();
b_senser_started = true;
napNow(); // short period sleep.
} else {
Serial << "..wake up from short nap.." << mwx:: crlf;
auto && brd = the_twelite.board.use< PAL_AMB> ();
b_senser_started = false;
// tell sensors waking up.
brd.sns_LTR308ALS.process_ev(E_EVENT_START_UP);
brd.sns_SHTC3.process_ev(E_EVENT_START_UP);
}
}
上記の分岐をグローバル変数のb_sensor_started
により制御しています。!b_sensor_started
の場合はセンサー取得開始(startSensorCapture()
)を行い、napNow()
により短いスリープに入ります。時間は100msです。
napNow()
によるスリープ復帰後、b_sensor_started==true
の節が実行されます。ここでは、2つのセンサーに対してE_EVENT_START_UP
イベントを通知しています。このイベントは、センサーの取得が終了するのに十分な時間が経過したことを意味します。この通知をもとにsns_LTR308ALS
とsns_SHTC3
はavailableになります。この後loop()
に移行し、無線パケットが送信されます。
センサーに通知するイベントは必要な時間待ちが終わったかどうかを判定するために使われます。実際時間が経過しているかどうかはnapNow()
で正しい時間を設定したかどうかで決まります。短い時間で起床した場合は、必要とされる時間経過に足りないため、続く処理でセンサーデータが得られないなどのエラーが出ることが想定されます。
napNow()
ごく短いスリープを実行する。
void napNow () {
uint32_t u32ct = 100 ;
Serial << "..nap " << int (u32ct) << "ms." << mwx:: crlf;
the_twelite.sleep(u32ct, false, false, TWENET:: SLEEP_WAKETIMER_SECONDARY);
}
sleepのパラメータの2番目をtrueにすると前回のスリープ復帰時刻をもとに次の復帰時間を調整します。常に5秒おきに起床したいような場合設定します。
3番目をtrueにするとメモリーを保持しないスリープになります。復帰後はwakeup()は呼び出されじ、電源再投入と同じ処理になります。
4番目はウェイクアップタイマーの2番目を使う指定です。ここでは1番目は通常のスリープに使用して、2番目を短いスリープに用いています。このアクトでは2番目を使う強い理由はありませんが、例えば上述の5秒おきに起床したいような場合、短いスリープに1番目のタイマーを用いてしまうとカウンター値がリセットされてしまい、経過時間の補正計算が煩雑になるため2番目のタイマーを使用します。
あまり短いスリープ時間を設定してもスリープ復帰後のシステムの再初期化などのエネルギーコストと釣り合いません。目安として最小時間を30-50ms程度とお考え下さい。
1.4.1.11 - PAL_AMB-behavior 環境センサーパルを使ったサンプル
このサンプルは
ビヘイビア の記述方法のサンプルです。ビヘイビアはより複雑なアプリケーションを記述する際に用います。
アクトの機能 環境センサーパル AMBIENT SENSE PAL を用い、センサー値の取得を行います。 コイン電池で動作させるための、スリープ機能を利用します。 アクトの使い方 TWELITEの準備
親機にPALを使用する場合は、コイン電池での動作はできません。目安として50mA以上の電流を安定して得られるような電源環境を用意してください。
ファイル構成 PAL_AMB-behavior.hpp : setup()
のみの定義です。DIP-SWを読み出し、D1..D3が上位置の場合は親機として動作し、それ以外は子機としてDIP SWに対応するIDをセットします。 Parent/myAppBhvParent.hpp : 親機用のビヘイビアクラス定義 Parent/myAppBhvParent.cpp : 実装 Parent/myAppBhvParent-handlers.cpp : ハンドラーの実装 Parent/myAppBhvParent.hpp : 子機用のビヘイビアクラス定義 Parent/myAppBhvParent.cpp : 実装 Parent/myAppBhvParent-handlers.cpp : ハンドラーの実装 親機のビヘイビア名は<MY_APP_PARENT>
、子機は<MY_APP_CHILD>
です。
setup()
// now read DIP sw status can be read.
u8ID = (brd.get_DIPSW_BM() & 0x07 );
// Register App Behavior (set differnt Application by DIP SW settings)
if (u8ID == 0 ) {
// put settings to the twelite main object.
the_twelite
<< TWENET:: appid(APP_ID) // set application ID (identify network group)
<< TWENET:: channel(CHANNEL) // set channel (pysical channel)
<< TWENET:: rx_when_idle(); // open RX channel
the_twelite.app.use< MY_APP_PARENT> ();
} else {
// put settings to the twelite main object.
the_twelite
<< TWENET:: appid(APP_ID) // set application ID (identify network group)
<< TWENET:: channel(CHANNEL); // set channel (pysical channel)
the_twelite.app.use< MY_APP_CHILD> ();
}
DIP SWの読み値が0の場合は親機用のビヘイビア<MY_APP_PARENT>
を、それ以外の場合は子機用のビヘイビア<MY_APP_CHILD>
を登録します。
親機がMONOSTICKの場合は、PAL用のDIP SWの読み値は0となり、親機としてふるまいます。ただしこの動作はMONOSTICKの仕様として定義されているものではありません。
親機のビヘイビア 親機はスリープをしない受信機としてふるまい、子機からのパケットを受信したときにシリアルポートにパケットの情報を出力します。
MY_APP_PARENT::receive()
void MY_APP_PARENT:: receive(mwx:: packet_rx& rx) {
uint8_t msg[4 ];
uint32_t lumi;
uint16_t u16temp, u16humid;
// expand packet payload (shall match with sent packet data structure, see pack_bytes())
auto && np = expand_bytes(rx.get_payload().begin(), rx.get_payload().end(), msg);
// if PING packet, respond pong!
if (! strncmp((const char * )msg, (const char * )FOURCHARS, 4 )) {
// get rest of data
expand_bytes(np, rx.get_payload().end(), lumi, u16temp, u16humid);
// print them
Serial << format("Packet(%x:%d/lq=%d/sq=%d): " ,
rx.get_addr_src_long(), rx.get_addr_src_lid(),
rx.get_lqi(), rx.get_psRxDataApp()-> u8Seq)
<< "temp=" << double (int16_t (u16temp)/ 100.0 )
<< "C humid=" << double (int16_t (u16humid)/ 100.0 )
<< "% lumi=" << int (lumi)
<< mwx:: crlf << mwx:: flush;
}
}
親機用がパケットを受信したときは、パケットの先頭4文字が照合(FOURCHARS
)できれば、そのパケット内容を表示します。
MY_APP_PARENT::MWX_TICKTIMER_INT()
MWX_TICKTIMER_INT(uint32_t arg, uint8_t & handled) {
// blink LED
digitalWrite(PAL_AMB:: PIN_LED,
((millis() >> 9 ) & 1 ) ? PIN_STATE:: HIGH : PIN_STATE:: LOW);
}
親機の割り込みハンドラはLEDの点滅を行います。
MY_APP_PARENT::MWX_DIO_EVENT(PAL_AMB::PIN_BTN)
MWX_DIO_EVENT(PAL_AMB:: PIN_BTN, uint32_t arg) {
Serial << "Button Pressed" << mwx:: crlf;
static uint32_t u32tick_last;
uint32_t tick = millis();
if (tick - u32tick_last > 100 ) {
PEV_Process(E_ORDER_KICK, 0UL );
}
u32tick_last = tick;
}
PAL上のボタン(5)が押されたときには、状態マシンに対してE_ORDER_KICK
イベントを発行します。
MY_APP_PARENT::MWX_STATE(E_MWX::STATE_0 .. 3)
状態マシンは、状態遷移の参考として記述したもので、アプリケーションの動作上意味のあるものではありません。ボタンから送付されるE_ORDER_KICK
イベントによる状態遷移や、タイムアウトなどを実行しています。
子機のビヘイビア 子機の動作の流れはPAL_AMB-usenap
と同じです。初回スリープから「起床→センサー動作開始→短いスリープ→起床→センサー値取得→無線送信→無線送信完了待ち→スリープ」を繰り返します。
MY_APP_CHILD::on_begin()
void _begin () {
// sleep immediately.
Serial << "..go into first sleep (1000ms)" << mwx:: flush;
the_twelite.sleep(1000 );
}
on_begin()
から呼び出される_begin()
関数では、初回スリープを実行しています。
(※_begin()
関数で本処理を記述せずon_begin()
に直接記述してもかまいません)
MY_APP_CHILD::wakeup()
void wakeup (uint32_t & val) {
Serial << mwx:: crlf << "..wakeup" << mwx:: crlf;
// init wire device.
Wire.begin();
// turn on LED
digitalWrite(PAL_AMB:: PIN_LED, PIN_STATE:: LOW);
// KICK it!
PEV_Process(E_ORDER_KICK, 0 ); // pass the event to state machine
}
スリープからの起床処理を記述しています。
ここで初回のWire.begin()
を実行しています。2回目以降のスリープ起床時では冗長な記述です。この処理はon_begin()
に移動してもかまいません。
MY_APP_CHILD::transmit_complete()
void transmit_complete (mwx:: packet_ev_tx& txev) {
Serial << "..txcomp=" << int (txev.u8CbId) << mwx:: crlf;
PEV_Process(E_ORDER_KICK, txev.u8CbId); // pass the event to state machine
}
送信完了時に状態マシンに対してE_ORDER_KICK
メッセージを処理します。
MY_APP_CHILD::transmit_complete()
static const uint8_t STATE_IDLE = E_MWX:: STATE_0;
static const uint8_t STATE_SENSOR = E_MWX:: STATE_1;
static const uint8_t STATE_TX = E_MWX:: STATE_2;
static const uint8_t STATE_SLEEP = E_MWX:: STATE_3;
状態名を定義しています。
MY_APP_CHILD::shtc3_???()
MWX_APIRET MY_APP_CHILD:: shtc3_start()
MWX_APIRET MY_APP_CHILD:: shtc3_read()
SHTC3用のセンサー取得実装例です。送付コマンド等の詳細はSHTC3のデータシートなどを参考にしてください。
MY_APP_CHILD::ltr308als_???()
MWX_APIRET MY_APP_CHILD:: ltr308als_read()
MWX_APIRET MY_APP_CHILD:: ltr308als_start()
static MWX_APIRET WireWriteAngGet(uint8_t addr, uint8_t cmd)
LTR308ALSのセンサー取得実装例です。送付コマンド等の詳細はLTR308ALSのデータシートなどを参考にしてください。
WireWriteAndGet()
はaddr
のデバイスに対してcmd
を1バイト送信してから、1バイト受信して値を返します。
MY_APP_CHILD::STATE_IDLE (0)
MWX_STATE(MY_APP_CHILD:: STATE_IDLE, uint32_t ev, uint32_t evarg) {
if (PEV_is_coldboot(ev,evarg)) {
Serial << "[STATE_IDLE:START_UP(" << int (evarg) << ")]" << mwx:: crlf;
// then perform the first sleep at on_begin().
} else
if (PEV_is_warmboot(ev,evarg)) {
Serial << "[STATE_IDLE:START_UP(" << int (evarg) << ")]" << mwx:: crlf;
PEV_SetState(STATE_SENSOR);
}
}
0番の状態は特別な意味を持ちます。起動直後またはスリープ復帰後の状態です。
起動直後PEV_is_coldboot(ev,evarg)
判定がtrue
になって呼び出されます。on_begin()
から、そのままスリープしてしまうため、状態遷移するようなコードも含まれません。**この時点では主要な初期化がまだ終わっていませんので、無線パケットの送信など複雑な処理を行うことが出来ません。**そのような処理を行うための最初の状態遷移を行うためにはon_begin()
からイベントを送り、そのイベントに従って状態遷移を行います。
スリープ復帰後はPEV_is_warmboot(ev,evarg)
がtrue
になる呼び出しが最初にあります。PEV_SetState()
を呼び出しSTATE_SENSOR
状態に遷移します。
MY_APP_CHILD::STATE_SENSOR
MWX_STATE(MY_APP_CHILD:: STATE_SENSOR, uint32_t ev, uint32_t evarg) {
if (ev == E_EVENT_NEW_STATE) {
Serial << "[STATE_SENSOR:NEW] Start Sensor." << mwx:: crlf;
// start sensor capture
shtc3_start();
ltr308als_start();
// take a nap waiting finish of capture.
Serial << "..nap for 66ms" << mwx:: crlf;
Serial.flush();
PEV_KeepStateOnWakeup(); // stay this state on waking up.
the_twelite.sleep(66 , false, false, TWENET:: SLEEP_WAKETIMER_SECONDARY);
} else
if (PEV_is_warmboot(ev,evarg)) {
// on wakeup, code starts here.
Serial << "[STATE_SENSOR:START_UP] Wakeup." << mwx:: crlf;
PEV_SetState(STATE_TX);
}
}
スリープ復帰後STATE_IDLE
から遷移したとき、STATE_SENSOR
の状態ハンドラが続けて呼び出されます。この時のイベントev
はE_EVENT_NEW_STATE
です。
ここではSHTC3, LTR308ALSの2センサーの動作開始を行います。一定時間経過すれば、センサーはデータ取得可能な状態になります。この時間待ちを66
ms設定のスリープで行います。スリープ前にPEV_KeepStateOnWakeup()
が呼ばれている点に注意してください。この呼び出しを行うと、スリープ復帰後の状態はSTATE_IDLE
ではなく、スリープしたときの状態、つまりSTATE_SENSOR
となります。
短いスリープから復帰するとPEV_is_warmboot(ev,evarg)
判定がtrue
となる呼び出しが最初に発生します。この呼び出し時点で、無線パケットの送信などを行うことが出来ます。STATE_TX
に遷移します。
MY_APP_CHILD::STATE_TX
MWX_STATE(MY_APP_CHILD:: STATE_TX, uint32_t ev, uint32_t evarg)
static int u8txid;
if (ev == E_EVENT_NEW_STATE) {
Serial << "[STATE_TX:NEW]" << mwx:: crlf;
u8txid = - 1 ;
auto && r1 = shtc3_read();
auto && r2 = ltr308als_read();
Serial << "..shtc3 t=" << int (i16Temp) << ", h=" << int (i16Humd) << mwx:: crlf;
Serial << "..ltr308als l=" << int (u32Lumi) << mwx:: crlf;
if (r1 && r2) {
if (auto && pkt = the_twelite.network.use< NWK_SIMPLE> ().prepare_tx_packet()) {
ここではE_EVENT_NEW_STATE
イベントの時に、センサーデータ読み出し、無線パケットの送信手続きに入ります。送信手続きの詳細は他のアクトサンプル例を参考にしてください。
void transmit_complete (mwx:: packet_ev_tx& txev) {
Serial << "..txcomp=" << int (txev.u8CbId) << mwx:: crlf;
PEV_Process(E_ORDER_KICK, txev.u8CbId); // pass the event to state machine
}
// ↓ ↓ ↓ メッセージ送付
} else if (ev == E_ORDER_KICK && evarg == uint32_t (u8txid)) {
Serial << "[STATE_TX] SUCCESS TX(" << int (evarg) << ')' << mwx:: crlf;
PEV_SetState(STATE_SLEEP);
}
送信完了まちの処理はループでのアクト記述と違い、transmit_complete()
からのPEV_Process()
によるメッセージを待つことで完了確認としています。メッセージを受け取った時点でスリープします。スリープ処理はSTATE_SLEEP
に遷移することで行っています。
if (PEV_u32Elaspsed_ms() > 100 ) {
// does not finish TX!
Serial << "[STATE_TX] FATAL, TX does not finish!" << mwx:: crlf << mwx:: flush;
the_twelite.reset_system();
}
最後にタイムアウト処理を行っています。万が一送信パケットの完了メッセージが戻ってこなかった場合を想定します。PEV_u32Elaspsed_ms()
はその状態に遷移してからの経過時間を[ms]で返します。時間経過した場合は、上記では(このタイムアウトは余程のことだとして)システムリセットthe_twelite.reset_system()
を行います。
MY_APP_CHILD::STATE_SLEEP
MWX_STATE(MY_APP_CHILD:: STATE_SLEEP, uint32_t ev, uint32_t evarg) {
if (ev == E_EVENT_NEW_STATE) {
Serial << "..sleep for 5000ms" << mwx:: crlf;
pinMode(PAL_AMB:: PIN_BTN, PIN_MODE:: WAKE_FALLING_PULLUP);
digitalWrite(PAL_AMB:: PIN_LED, PIN_STATE:: HIGH);
Serial.flush();
the_twelite.sleep(5000 ); // regular sleep
}
}
スリープを行います。前の状態から遷移した直後のE_EVENT_NEW_STATE
に記述します。スリープ直前に他のイベントが呼ばれる可能性がありますので、必ず1回だけ実行される判定式の中でthe_twelite.sleep()
を実行してください。
1.4.1.12 - PAL_MAG 磁気センサーパルを使ったサンプル
アクトの機能 開閉センサーパル OPEN-CLOSE SENSE PAL を用い、磁気センサーの検出時に割り込み起床し、無線送信します。 コイン電池で動作させるための、スリープ機能を利用します。 アクトの使い方 必要なTWELITE アクトの解説 インクルード
##include <TWELITE>
##include <NWK_SIMPLE>
##include <PAL_MAG>
開閉センサーパルのボード ビヘイビア<PAL_MAG>
をインクルードします。
setup()
void setup () {
/*** SETUP section */
// use PAL_AMB board support.
auto && brd = the_twelite.board.use< PAL_MAG> ();
// now it can read DIP sw status.
u8ID = (brd.get_DIPSW_BM() & 0x07 ) + 1 ;
if (u8ID == 0 ) u8ID = 0xFE ; // 0 is to 0xFE
// LED setup (use periph_led_timer, which will re-start on wakeup() automatically)
brd.set_led(LED_TIMER:: BLINK, 10 ); // blink (on 10ms/ off 10ms)
// the twelite main object.
the_twelite
<< TWENET:: appid(APP_ID) // set application ID (identify network group)
<< TWENET:: channel(CHANNEL); // set channel (pysical channel)
// Register Network
auto && nwk = the_twelite.network.use< NWK_SIMPLE> ();
nwk << NWK_SIMPLE:: logical_id(u8ID); // set Logical ID. (0xFE means a child device with no ID)
/*** BEGIN section */
the_twelite.begin(); // start twelite!
/*** INIT message */
Serial << "--- PAL_MAG:" << FOURCHARS << " ---" << mwx:: crlf;
}
最初にボードビヘイビア<PAL_MAG>
を登録します。ボードビヘイビアの初期化時にセンサーやDIOの初期化が行われます。最初に行うのは、ボードのDIP SWなどの状態を確認してから、ネットワークの設定などを行うといった処理が一般的だからです。
auto && brd = the_twelite.board.use< PAL_MAG> ();
u8ID = (brd.get_DIPSW_BM() & 0x07 ) + 1 ;
if (u8ID == 0 ) u8ID = 0xFE ; // 0 is to 0xFE
ここでは、ボード上の4ビットDIP SWのうち3ビットを読み出して子機のIDとして設定しています。0の場合は、ID無しの子機(0xFE
)とします。
LEDの設定を行います。ここでは 10ms おきに ON/OFF の点滅の設定をします(スリープを行い起床時間が短いアプリケーションでは、起床中は点灯するという設定とほぼ同じ意味合いになります)。
brd.set_led(LED_TIMER:: BLINK, 10 ); // blink (on 10ms/ off 10ms)
begin()
begin()
関数はsetup()
関数を終了し(そのあとTWENETの初期化が行われる)一番最初のloop()
の直前で呼ばれます。
void begin () {
sleepNow(); // the first time is just sleeping.
}
setup()
終了後にsleepNow()
を呼び出し初回スリープを実行します。
sleepNow()
void sleepNow () {
uint32_t u32ct = 60000 ;
pinMode(PAL_MAG:: PIN_SNS_OUT1, PIN_MODE:: WAKE_FALLING);
pinMode(PAL_MAG:: PIN_SNS_OUT2, PIN_MODE:: WAKE_FALLING);
the_twelite.sleep(u32ct);
}
スリープに入るまえに磁気センサーのDIOピンの割り込み設定をします。pinMode()
を用います。2番めのパラメータはPIN_MODE::WAKE_FALLING
を指定しています。これはHIGHからLOWへピンの状態が変化したときに起床する設定です。
7行目でthe_twelite.sleep()
でスリープを実行します。パラメータの60000は、TWELITE PAL ボードのウォッチドッグをリセットするために必要な起床設定です。リセットしないと60秒経過後にハードリセットがかかります。
wakeup()
スリープから復帰し起床すると wakeup()
が呼び出されます。そのあとloop()
が都度呼び出されます。wakeup()
の前に、UARTなどの各ペリフェラルやボード上のデバイスのウェイクアップ処理(ウォッチドッグタイマーのリセットなど)が行われます。例えばLEDの点灯制御を再始動します。
void wakeup () {
if (the_twelite.is_wokeup_by_wktimer()) {
sleepNow();
}
}
ここではウェイクアップタイマーからの起床の場合(the_twelite.is_wokeup_by_wktimer()
)は再びスリープを実行します。これは上述のウォッチドッグタイマーのリセットを行う目的のみの起床です。
磁気センサーの検出時の起床の場合は、このままloop()
処理に移行します。
loop()
ここでは、検出された磁気センサーのDIOの確認を行い、パケットの送信を行い、パケット送信完了後に再びスリープを実行します。
void loop () {
if (! b_transmit) {
if (auto && pkt =
the_twelite.network.use< NWK_SIMPLE> ().prepare_tx_packet())
uint8_t b_north =
the_twelite.is_wokeup_by_dio(PAL_MAG:: PIN_SNS_NORTH);
uint8_t b_south =
the_twelite.is_wokeup_by_dio(PAL_MAG:: PIN_SNS_SOUTH);
Serial << "..sensor north=" << int (b_north)
<< " south=" << int (b_south) << mwx:: crlf;
// set tx packet behavior
pkt << tx_addr(0x00 )
<< tx_retry(0x1 )
<< tx_packet_delay(0 , 0 , 2 );
// prepare packet payload
pack_bytes(pkt.get_payload()
, make_pair(FOURCHARS, 4 )
, b_north
, b_south
);
// do transmit
MWX_APIRET ret = pkt.transmit();
if (ret) {
u8txid = ret.get_value() & 0xFF ;
b_transmit = true;
}
else {
// fail to request
sleepNow();
}
} else {
sleepNow();
}
} else {
if (the_twelite.tx_status.is_complete(u8txid)) {
b_transmit = 0 ;
sleepNow();
}
}
}
b_transmit
変数によってloop()
内の振る舞いを制御しています。送信要求が成功した後、この値を1にセットしパケット送信完了待ちを行います。
磁気センサーの検出DIOピンの確認を行います。検出ピンは二種類あります。N極検知とS極検知です。単に磁石が近づいたことだけを知りたいならいずれかのピンの検出されたことが条件となります。
uint8_t b_north =
the_twelite.is_wokeup_by_dio(PAL_MAG:: PIN_SNS_NORTH);
uint8_t b_south =
the_twelite.is_wokeup_by_dio(PAL_MAG:: PIN_SNS_SOUTH);
起床要因のピンを確認するにはthe_twelite.is_wokeup_by_dio()
を用います。パラメータはピン番号です。戻り値をuint8_t
に格納しているのはパケットのペイロードに格納するためです。
通信条件の設定やペイロードにデータを格納後、送信を行います。
// do transmit
MWX_APIRET ret = pkt.transmit();
その後、loop()
中 b_transmit
が true
になっている場合は、完了チェックを行い、完了すれば sleepNow()
によりスリープします。
if (the_twelite.tx_status.is_complete(u8txid)) {
b_transmit = 0 ;
sleepNow();
}
送信完了に確認は the_twelite.tx_status.is_complete(u8txid)
で行っています。u8txid
は送信時に戻り値として戻されたID値です。
1.4.1.13 - PAL_MOT-single 加速度センサーパルを使ったサンプル
このアクトでは、スリープ復帰後に数サンプル加速度データを取得しそのデータを送ります。
アクトの解説 起床→加速度センサーの取得開始→加速度センサーのFIFO割り込み待ち→加速度センサーのデータの取り出し→無線送信→スリープという流れになります。
加速度センサーは、FIFOキューが一杯になるとFIFOキューへのデータ追加を停止します。
宣言部 インクルード
##include <TWELITE> // MWXライブラリ基本
##include <NWK_SIMPLE> // ネットワーク
##include <SM_SIMPLE> // ステートマシン(状態遷移)
##include <STG_STD> // インタラクティブモード
/*** board selection (choose one) */
##define USE_PAL_MOT
//#define USE_CUE
// board dependend definitions.
##if defined(USE_PAL_MOT)
##define BRDN PAL_MOT
##define BRDC <PAL_MOT>
##elif defined(USE_CUE)
##define BRDN CUE
##define BRDC <CUE>
##endif
// include board support
##include BRDC
MOT PALまたはTWELITE CUEに対応するため、インクルード部分はマクロになっています。USE_PAL_MOT
または、USE_CUE
のいずれかを定義します。
USE_PAL_MOT
が定義されている場合は動作センサーパルのボードビヘイビア<PAL_MOT>
をインクルードしています。
状態定義
enum class E_STATE : uint8_t {
INTERACTIVE = 255 ,
INIT = 0 ,
START_CAPTURE,
WAIT_CAPTURE,
REQUEST_TX,
WAIT_TX,
EXIT_NORMAL,
EXIT_FATAL
};
SM_SIMPLE< E_STATE> step;
loop()
中の順次処理を行うために状態を定義し、またステートマシン step
を宣言します。
センサーデータ格納
struct {
int32_t x_ave, y_ave, z_ave;
int32_t x_min, y_min, z_min;
int32_t x_max, y_max, z_max;
uint16_t n_seq;
uint8_t n_samples;
} sensor;
センサーデータを格納するためのデータ構造です。
setup()
/// load board and settings objects
auto && brd = the_twelite.board.use BRDC (); // load board support
auto && set = the_twelite.settings.use< STG_STD> (); // load save/load settings(interactive mode) support
auto && nwk = the_twelite.network.use< NWK_SIMPLE> (); // load network support
ボード、設定、ネットワークの各ビヘイビアオブジェクトの登録を行います。
インタラクティブモード
// settings: configure items
set << SETTINGS:: appname("MOT" );
set << SETTINGS:: appid_default(DEFAULT_APP_ID); // set default appID
set << SETTINGS:: ch_default(DEFAULT_CHANNEL); // set default channel
set << SETTINGS:: lid_default(0x1 ); // set default LID
set.hide_items(E_STGSTD_SETID:: OPT_DWORD2, E_STGSTD_SETID:: OPT_DWORD3, E_STGSTD_SETID:: OPT_DWORD4, E_STGSTD_SETID:: ENC_KEY_STRING, E_STGSTD_SETID:: ENC_MODE);
// if SET=LOW is detected, start with intaractive mode.
if (digitalRead(brd.PIN_SET) == PIN_STATE:: LOW) {
set << SETTINGS:: open_at_start();
brd.set_led(LED_TIMER:: BLINK, 300 ); // slower blink
step.next(STATE:: INTERACTIVE);
return ;
}
// load settings
set.reload(); // load from EEPROM.
OPT_BITS = set.u32opt1(); // this value is not used in this example.
インタラクティブモードの初期化を行います。
まず、設定項目の調整を行います。ここでは、メニュー項目で表示されるタイトル名SETTINGS::appname
、アプリケーションIDのデフォルト値の設定SETTINGS::appid_default
、チャネルのデフォルトSETTINGS::ch_default
、論理デバイスIDのデフォルトSETTINGS::lid_default
、非表示項目の設定.hide_items()
を行います。
このサンプルでは起動時にSETピンがLOである場合にインタラクティブモードに遷移します。digitalRead(brd.PIN_SET)
によりピンがLOであることを確認できた場合は、SETTINGS::open_at_start()
を指定します。この指定によりsetup()
を抜けた後に速やかにインタラクティブモード画面が表示されます。画面が表示されてもbegin()
やloop()
が実行されます。このサンプルでは状態STATE::INTERACTIVE
としてloop()
中ではスリープなどの動作はせず何もしないようにします。
続いて設定値を読み出します。設定値を読むには必ず.reload()
を実行します。このサンプルではオプションビット設定.u32opt1()
を読み出します。
the_twelite
the_twelite
は、システムの基本的な振る舞いを管理するクラスオブジェクトです。このオブジェクトは、setup()
内でアプリケーションIDやチャネルなど様々な初期化を行います。
ここではインタラクティブモードの設定値の一部 を反映しています。
インタラクティブモード設定で反映した項目を別の設定に変更したい場合は、続いて上書きしたい設定を行います。
the_twelite << set;// インタラクティブモード
the_twelite << twenet:: channel(19 ); // chを19に上書き設定
NWK_SIMPLE
オブジェクト
ネットワークビヘイビアオブジェクトに対しても設定を行います。インタラクティブモードの論理デバイスID(LID)と再送設定が反映されます。
その他、ハードウェアの初期化など
brd.set_led(LED_TIMER:: BLINK, 100 );
LEDのブリンク設定などを行います。
begin()
void begin () {
auto && set = the_twelite.settings.use< STG_STD> ();
if (! set.is_screen_opened()) {
// sleep immediately, waiting for the first capture.
sleepNow();
}
}
setup()
を終了した後に呼ばれます。ここでは初回スリープを実行しています。ただしインタラクティブモードの画面が表示される場合はスリープしません。
wakeup()
void wakeup () {
Serial << crlf << "--- PAL_MOT(OneShot):"
<< FOURCHARS << " wake up ---" << crlf;
eState = E_STATE:: INIT;
}
起床後は状態変数eState
を初期状態INITにセットしています。この後loop()
が実行されます。
loop()
void loop () {
auto && brd = the_twelite.board.use< PAL_MOT> ();
do {
switch (step.state()) {
case STATE:: INTERACTIVE:
break ;
...
} while (step.b_more_loop());
}
loop()
の基本構造は<SM_STATE>
ステートマシンstate
を用い_switch … case_節での制御です。初期状態はSTATE::INIT
またはSTATE::INTERACTIVE
です。
STATE::INTERACTIVE
インタラクティブモード画面が表示されているときの状態です。何もしません。この画面ではSerialの入出力はインタラクティブモードが利用します。
STATE::INIT
初期状態のINITです。
case STATE:: INIT:
brd.sns_MC3630.get_que().clear(); // clear queue in advance (just in case).
memset(& sensor, 0 , sizeof (sensor)); // clear sensor data
step.next(STATE:: START_CAPTURE);
break ;
状態INITでは、初期化(結果格納用のキューのクリア)や結果格納用のデータ構造の初期化を行います。STATE::START_CAPTUREに遷移します。この遷移設定後、もう一度_while_ループが実行されます。
STATE::CAPTURE
case STATE:: START_CAPTURE:
brd.sns_MC3630.begin(
// 400Hz, +/-4G range, get four samples and will average them.
SnsMC3630:: Settings(
SnsMC3630:: MODE_LP_400HZ, SnsMC3630:: RANGE_PLUS_MINUS_4G, N_SAMPLES));
step.set_timeout(100 );
step.next(STATE:: WAIT_CAPTURE);
break ;
状態START_CAPTURE
では、MC3630センサーのFIFO取得を開始します。ここでは400Hzで4サンプル取得できた時点でFIFO割り込みが発生する設定にしています。
例外処理のためのタイムアウトの設定と、次の状態STATE::WAIT_CAPTURE
に遷移します。
STATE::WAIT_CAPTURE
case STATE:: WAIT_CAPTURE:
if (brd.sns_MC3630.available()) {
brd.sns_MC3630.end(); // stop now!
状態WAIT_CAPTURE
では、FIFO割り込みを待ちます。割り込みが発生し結果格納用のキューにデータが格納されるとsns_MC3630.available()
がtrue
になります。sns_MC3630.end()
を呼び出し処理を終了します。
sensor.n_samples = brd.sns_MC3630.get_que().size();
if (sensor.n_samples) sensor.n_seq = brd.sns_MC3630.get_que()[0 ].get_t();
...
サンプル数とサンプルのシーケンス番号を取得します。
// get all samples and average them.
for (auto && v: brd.sns_MC3630.get_que()) {
sensor.x_ave += v.x;
sensor.y_ave += v.y;
sensor.z_ave += v.z;
}
if (sensor.n_samples == N_SAMPLES) {
// if N_SAMPLES == 2^n, division is much faster.
sensor.x_ave /= N_SAMPLES;
sensor.y_ave /= N_SAMPLES;
sensor.z_ave /= N_SAMPLES;
}
...
すべてのサンプルデータに対して読み出し、平均値をとる処理をします。
// can also be:
// int32_t x_max = -999999, x_min = 999999;
// for (auto&& v: brd.sns_MC3630.get_que()) {
// if (v.x >= x_max) x_max = v.x;
// if (v.y <= x_min) x_min = v.x;
// ...
// }
auto && x_minmax = std:: minmax_element(
get_axis_x_iter(brd.sns_MC3630.get_que().begin()),
get_axis_x_iter(brd.sns_MC3630.get_que().end()));
sensor.x_min = * x_minmax.first;
sensor.x_max = * x_minmax.second;
...
ここでは取得されたサンプルに対して、各軸に対応するイテレータを用い最大・最小を得ています。
C++ Standard Template Library のアルゴリズムを使用する例としてstd::mimmax_element
紹介していますが、コメント内のようにforループ内で最大、最小を求めても構いません。
if (brd.sns_MC3630.available()) {
...
brd.sns_MC3630.get_que().clear(); // clean up the queue
step.next(STATE:: REQUEST_TX); // next state
} else if (step.is_timeout()) {
Serial << crlf << "!!!FATAL: SENSOR CAPTURE TIMEOUT." ;
step.next(STATE:: EXIT_FATAL);
}
break ;
.sns_MC3630.get_que().clear()
を呼び出し、キューにあるデータをクリアします。これを呼び出さないと続くサンプル取得ができません。その後STATE::REQUEST_TX
状態に遷移します。
.is_timeout()
はタイムアウトをチェックします。タイムアウト時は異常としてSTATE::EXIT_FATAL
に遷移します。
STATE::REQUEST_TX
case STATE:: REQUEST_TX:
if (TxReq()) {
step.set_timeout(100 );
step.clear_flag();
step.next(STATE:: WAIT_TX);
} else {
Serial << crlf << "!!!FATAL: TX REQUEST FAILS." ;
step.next(STATE:: EXIT_FATAL);
}
break ;
状態REQUEST_TX
ではローカル定義関数TxReq()
を呼び出し、得られたセンサーデータの処理と送信パケットの生成・送信を行います。送信要求は送信キューの状態などで失敗することがあります。送信要求が成功した場合、TxReq()はtrueとして戻りますが、まだ送信は行われません。送信完了はon_tx_comp()
コールバックが呼び出されます。
また.clear_flag()
により送信完了を知らせるためのフラグをクリアしておきます。同時にタイムアウトも設定します。
E_STATE::WAIT_TX
case STATE:: WAIT_TX:
if (step.is_flag_ready()) {
step.next(STATE:: EXIT_NORMAL);
}
if (step.is_timeout()) {
Serial << crlf << "!!!FATAL: TX TIMEOUT." ;
step.next(STATE:: EXIT_FATAL);
}
break ;
状態STATE::WAIT_TX
では、無線パケットの送信完了を待ちます。フラグはon_tx_comp()
コールバック関数でセットされ、セット後に.is_flag_ready()
が_true_になります。
E_STATE::EXIT_NORMAL
, E_STATE::EXIT_FATAL
case STATE:: EXIT_NORMAL:
sleepNow();
break ;
case STATE:: EXIT_FATAL:
Serial << flush;
the_twelite.reset_system();
break ;
一連の動作が完了したときは状態STATE::EXIT_NORMAL
に遷移しローカル定義の関数sleepNow()
を呼び出しスリープを実行します。またエラーを検出した場合は状態STATE::EXIT_FATAL
に遷移し、システムリセットを行います。
MWX_APIRET TxReq()
MWX_APIRET TxReq () {
auto && brd = the_twelite.board.use< PAL_MOT> ();
MWX_APIRET ret = false;
// prepare tx packet
if (auto && pkt = the_twelite.network.use< NWK_SIMPLE> ().prepare_tx_packet()) {
// set tx packet behavior
pkt << tx_addr(0x00 ) // 0..0xFF (LID 0:parent, FE:child w/ no id, FF:LID broad cast), 0x8XXXXXXX (long address)
<< tx_retry(0x1 ) // set retry (0x1 send two times in total)
<< tx_packet_delay(0 , 0 , 2 ); // send packet w/ delay
// prepare packet (first)
pack_bytes(pkt.get_payload() // set payload data objects.
, make_pair(FOURCHARS, 4 ) // just to see packet identification, you can design in any.
, uint16_t (sensor.n_seq)
, uint8_t (sensor.n_samples)
, uint16_t (sensor.x_ave)
, uint16_t (sensor.y_ave)
, uint16_t (sensor.z_ave)
, uint16_t (sensor.x_min)
, uint16_t (sensor.y_min)
, uint16_t (sensor.z_min)
, uint16_t (sensor.x_max)
, uint16_t (sensor.y_max)
, uint16_t (sensor.z_max)
);
// perform transmit
ret = pkt.transmit();
if (ret) {
Serial << "..txreq(" << int (ret.get_value()) << ')' ;
}
}
return ret;
}
最期にパケットの生成と送信を要求を行います。パケットには続き番号、サンプル数、XYZの平均値、XYZの最小サンプル値、XYZの最大サンプル値を含めます。
sleepNow()
void sleepNow () {
Serial << crlf << "..sleeping now.." << crlf;
Serial.flush();
step.on_sleep(false); // reset state machine.
the_twelite.sleep(3000 , false); // set longer sleep (PAL must wakeup less than 60sec.)
}
スリープの手続きです。
シリアルポートはスリープ前にSerial.flush()
を呼び出してすべて出力しておきます。 <SM_SIMPLE>
ステートマシンはon_sleep()
を行う必要があります。1.4.1.14 - PAL_MOT-fifo 加速度センサーパルを使ったサンプル
アクトの機能 動作センサーパル MOTION SENSE PAL を用い、加速度センサーの加速度を連続的に計測し、無線送信します。 コイン電池で動作させるための、スリープ機能を利用します。 アクトの使い方 必要なTWELITE アクトの解説 インクルード
##include <TWELITE>
##include <NWK_SIMPLE>
##include <PAL_MOT>
動作センサーパルのボードビヘイビア<PAL_MOT>
をインクルードします。
setup()
void setup () {
/*** SETUP section */
// board
auto && brd = the_twelite.board.use< PAL_MOT> ();
brd.set_led(LED_TIMER:: BLINK, 100 );
// the twelite main class
the_twelite
<< TWENET:: appid(APP_ID)
<< TWENET:: channel(CHANNEL);
// Register Network
auto && nwk = the_twelite.network.use< NWK_SIMPLE> ();
nwk << NWK_SIMPLE:: logical_id(0xFE );
/*** BEGIN section */
the_twelite.begin(); // start twelite!
brd.sns_MC3630.begin(SnsMC3630:: Settings(
SnsMC3630:: MODE_LP_14HZ, SnsMC3630:: RANGE_PLUS_MINUS_4G));
/*** INIT message */
Serial << "--- PAL_MOT(Cont):" << FOURCHARS
<< " ---" << mwx:: crlf;
}
最初にボードビヘイビア<PAL_MOT>
を登録します。ボードビヘイビアの初期化時にセンサーやDIOの初期化が行われます。最初に行うのは、ボードのDIP SWなどの状態を確認してから、ネットワークの設定などを行うといった処理が一般的だからです。
auto && brd = the_twelite.board.use< PAL_MOT> ();
u8ID = (brd.get_DIPSW_BM() & 0x07 ) + 1 ;
if (u8ID == 0 ) u8ID = 0xFE ; // 0 is to 0xFE
ここでは、ボード上の4ビットDIP SWのうち3ビットを読み出して子機のIDとして設定しています。0の場合は、ID無しの子機(0xFE
)とします。
LEDの設定を行います。ここでは 10ms おきに ON/OFF の点滅の設定をします(スリープを行い起床時間が短いアプリケーションでは、起床中は点灯するという設定とほぼ同じ意味合いになります)。
brd.set_led(LED_TIMER:: BLINK, 10 ); // blink (on 10ms/ off 10ms)
加速度センサーの初期化
brd.sns_MC3630.begin(SnsMC3630:: Settings(
SnsMC3630:: MODE_LP_14HZ, SnsMC3630:: RANGE_PLUS_MINUS_4G));
加速度センサーの計測を開始します。加速度センサーの設定(SnsMC3630::Settings
)には計測周波数と測定レンジを指定します。ここでは14HZの計測(SnsMC3630::MODE_LP_14HZ
)で、±4Gのレンジ(SnsMC3630::RANGE_PLUS_MINUS_4G
)で計測します。
開始後は加速度センサーの計測が秒14回行われ、その値はセンサー内部のFIFOキューに保存されます。センサーに28回分の計測が終わった時点で通知されます。
begin()
begin()
関数はsetup()
関数を終了し(そのあとTWENETの初期化が行われる)一番最初のloop()
の直前で呼ばれます。
void begin () {
sleepNow(); // the first time is just sleeping.
}
setup()
終了後にsleepNow()
を呼び出し初回スリープを実行します。
sleepNow()
void sleepNow () {
pinMode(PAL_MOT:: PIN_SNS_INT, WAKE_FALLING);
the_twelite.sleep(60000 , false);
}
スリープに入るまえに加速度センサーのDIOピンの割り込み設定をします。FIFOキューが一定数まで到達したときに発生する割り込みです。pinMode()
を用います。2番めのパラメータはPIN_MODE::WAKE_FALLING
を指定しています。これはHIGHからLOWへピンの状態が変化したときに起床する設定です。
3行目でthe_twelite.sleep()
でスリープを実行します。パラメータの60000は、TWELITE PAL ボードのウォッチドッグをリセットするために必要な起床設定です。リセットしないと60秒経過後にハードリセットがかかります。
wakeup()
加速度センサーのFIFO割り込みにより、スリープから復帰し起床すると wakeup()
が呼び出されます。そのあとloop()
が都度呼び出されます。wakeup()
の前に、UARTなどの各ペリフェラルやボード上のデバイスのウェイクアップ処理(ウォッチドッグタイマーのリセットなど)が行われます。例えばLEDの点灯制御を再始動します。
void wakeup () {
Serial << "--- PAL_MOT(Cont):" << FOURCHARS
<< " wake up ---" << mwx:: crlf;
b_transmit = false;
txid[0 ] = 0xFFFF ;
txid[1 ] = 0xFFFF ;
}
ここではloop()
で使用する変数の初期化を行っています。
loop()
ここでは、加速度センサー内のFIFOキューに格納された加速度情報を取り出し、これをもとにパケット送信を行います。パケット送信完了後に再びスリープを実行します。
void loop () {
auto && brd = the_twelite.board.use< PAL_MOT> ();
if (! b_transmit) {
if (! brd.sns_MC3630.available()) {
Serial << "..sensor is not available."
<< mwx:: crlf << mwx:: flush;
sleepNow();
}
// send a packet
Serial << "..finish sensor capture." << mwx:: crlf
<< " seq=" << int (brd.sns_MC3630.get_que().back().t)
<< "/ct=" << int (brd.sns_MC3630.get_que().size());
// calc average in the queue.
{
int32_t x = 0 , y = 0 , z = 0 ;
for (auto && v: brd.sns_MC3630.get_que()) {
x += v.x;
y += v.y;
z += v.z;
}
x /= brd.sns_MC3630.get_que().size();
y /= brd.sns_MC3630.get_que().size();
z /= brd.sns_MC3630.get_que().size();
Serial << format("/ave=%d,%d,%d" , x, y, z) << mwx:: crlf;
}
for (int ip = 0 ; ip < 2 ; ip++ ) {
if (auto && pkt =
the_twelite.network.use< NWK_SIMPLE> ().prepare_tx_packet())
// set tx packet behavior
pkt << tx_addr(0x00 )
<< tx_retry(0x1 )
<< tx_packet_delay(0 , 0 , 2 );
// prepare packet (first)
uint8_t siz = (brd.sns_MC3630.get_que().size() >= MAX_SAMP_IN_PKT)
? MAX_SAMP_IN_PKT : brd.sns_MC3630.get_que().size();
uint16_t seq = brd.sns_MC3630.get_que().front().t;
pack_bytes(pkt.get_payload()
, make_pair(FOURCHARS, 4 )
, seq
, siz
);
// store sensor data (36bits into 5byts, alas 4bits are not used...)
for (int i = 0 ; i < siz; i++ ) {
auto && v = brd.sns_MC3630.get_que().front();
uint32_t v1;
v1 = ((uint16_t (v.x/ 2 ) & 4095 ) << 20 ) // X:12bits
| ((uint16_t (v.y/ 2 ) & 4095 ) << 8 ) // Y:12bits
| ((uint16_t (v.z/ 2 ) & 4095 ) >> 4 ); // Z:8bits from MSB
uint8_t v2 = (uint16_t (v.z/ 2 ) & 255 ); // Z:4bits from LSB
pack_bytes(pkt.get_payload(), v1, v2); // add into pacekt entry.
brd.sns_MC3630.get_que().pop(); // pop an entry from queue.
}
// perform transmit
MWX_APIRET ret = pkt.transmit();
if (ret) {
Serial << "..txreq(" << int (ret.get_value()) << ')' ;
txid[ip] = ret.get_value() & 0xFF ;
} else {
sleepNow();
}
}
}
// finished tx request
b_transmit = true;
} else {
if ( the_twelite.tx_status.is_complete(txid[0 ])
&& the_twelite.tx_status.is_complete(txid[1 ]) ) {
sleepNow();
}
}
}
b_transmit
変数によってloop()
内の振る舞いを制御しています。送信要求が成功した後、この値を1にセットしパケット送信完了待ちを行います。
最初にセンサーがavailableかどうかを確認します。割り込み起床後であるため、availableでないのは通常ではなく、そのままスリープします。
if (! brd.sns_MC3630.available()) {
Serial << "..sensor is not available."
<< mwx:: crlf << mwx:: flush;
sleepNow();
}
無線送信パケットでは使用しないのですが、取り出した加速度の情報を確認してみます。
Serial << "..finish sensor capture." << mwx:: crlf
<< " seq=" << int (brd.sns_MC3630.get_que().front().t)
<< "/ct=" << int (brd.sns_MC3630.get_que().size());
// calc average in the queue.
{
int32_t x = 0 , y = 0 , z = 0 ;
for (auto && v: brd.sns_MC3630.get_que()) {
x += v.x;
y += v.y;
z += v.z;
}
x /= brd.sns_MC3630.get_que().size();
y /= brd.sns_MC3630.get_que().size();
z /= brd.sns_MC3630.get_que().size();
Serial << format("/ave=%d,%d,%d" , x, y, z) << mwx:: crlf;
}
加速度センサーの計測結果はbrd.sns_MC3630.get_que()
で得られるFIFOキューに格納されます。
加速度センサーの計測結果を格納している構造体 axis_xyzt
は x, y, z の三軸の情報に加え、続き番号 t が格納されています。
格納されているサンプル数はキューのサイズ(brd.sns_MC3630.get_que().size()
)を読み出すことで確認できます。通常は28サンプルですが処理の遅延等によりもう少し進む場合もあります。最初のサンプルはfront()
で取得することができます。その続き番号はfront().t
になります。
ここでは、サンプルをキューから取り出す前にサンプルの平均をとってみます。キューの各要素にはfor文(for (auto&& v: brd.sns_MC3630.get_que()) { ... }
) でアクセスできます。for文内の v.x, v.y, v.z
が各要素になります。ここでは各要素の合計を計算しています。for文終了後は要素数で割ることで平均を計算しています。
次にパケットを生成して送信要求を行いますが、データ量が大きいため2回に分けて送信します。そのため送信処理がfor文で2回行われます。
for (int ip = 0 ; ip < 2 ; ip++ ) {
送信するパケットに含めるサンプル数とサンプル最初の続き番号をパケットのペイロードの先頭部分に格納します。
// prepare packet (first)
uint8_t siz = (brd.sns_MC3630.get_que().size() >= MAX_SAMP_IN_PKT)
? MAX_SAMP_IN_PKT : brd.sns_MC3630.get_que().size();
uint16_t seq = brd.sns_MC3630.get_que().front().t;
pack_bytes(pkt.get_payload()
, make_pair(FOURCHARS, 4 )
, seq
, siz
);
最後に加速度データを格納します。先程は平均値の計算のためにキューの各要素を参照のみしましたが、ここではキューから1サンプルずつ読み出してパケットのペイロードに格納します。
for (int i = 0 ; i < siz; i++ ) {
auto && v = brd.sns_MC3630.get_que().front();
uint32_t v1;
v1 = ((uint16_t (v.x/ 2 ) & 4095 ) << 20 ) // X:12bits
| ((uint16_t (v.y/ 2 ) & 4095 ) << 8 ) // Y:12bits
| ((uint16_t (v.z/ 2 ) & 4095 ) >> 4 ); // Z:8bits from MSB
uint8_t v2 = (uint16_t (v.z/ 2 ) & 255 ); // Z:4bits from LSB
pack_bytes(pkt.get_payload(), v1, v2); // add into pacekt entry.
brd.sns_MC3630.get_que().pop(); // pop an entry from queue.
}
加速度センサーからのデータキューの先頭を読み出すのは.front()
を用います。読みだした後.pop()
を用いて先頭キューを開放します。
加速度センサーから取得されるデータは1Gを1000としたミリGの単位です。レンジを±4Gとしているため、12bitの範囲に入るように2で割って格納します。データ数を節約するため最初の4バイトにX,Y軸とZ軸の上位8bitを格納し、次の1バイトにZ軸の下位4bitの合計5バイトを生成します。
2回分の送信待ちを行うため送信IDはtxid[]
配列に格納します。
MWX_APIRET ret = pkt.transmit();
if (ret) {
Serial << "..txreq(" << int (ret.get_value()) << ')' ;
txid[ip] = ret.get_value() & 0xFF ;
} else {
sleepNow();
}
その後、loop()
中 b_transmit
が true
になっている場合は、完了チェックを行い、完了すれば sleepNow()
によりスリープします。
} else {
if ( the_twelite.tx_status.is_complete(txid[0 ])
&& the_twelite.tx_status.is_complete(txid[1 ]) ) {
sleepNow();
}
}
送信完了に確認は the_twelite.tx_status.is_complete()
で行っています。txid[]
は送信時に戻り値として戻されたID値です。
1.4.1.15 - PulseCounter パルスカウンターを使ったサンプル
パルスカウンターは、マイコンを介在せず信号の立ち上がりまたは立ち下りの回数を計数するものです。不定期のパルスを計数し一定回数までカウントが進んだ時点で無線パケットで回数を送信するといった使用方法が考えられます。
アクトの機能 子機側のDIO8に接続したパルスを計数し、一定時間経過後または一定数のカウントを検出した時点で無線送信する。 子機側はスリープしながら動作する。 アクトの使い方 必要なTWELITE アクトの解説 setup()
// Pulse Counter setup
PulseCounter.setup();
パルスカウンターの初期化を行います。
begin()
void begin () {
// start the pulse counter capturing
PulseCounter.begin(
100 // 100 count to wakeup
, PIN_INT_MODE:: FALLING // falling edge
);
sleepNow();
}
パルスカウンターの動作を開始し、初回スリープを実行します。PulseCounter.begin()
の最初のパラメータは、起床割り込みを発生させるためのカウント数100
で、2番目は立ち下がり検出PIN_INT_MODE::FALLING
を指定しています。
wakeup()
void wakeup () {
Serial << mwx:: crlf
<< "--- Pulse Counter:" << FOURCHARS << " wake up ---"
<< mwx:: crlf;
if (! PulseCounter.available()) {
Serial << "..pulse counter does not reach the reference value." << mwx:: crlf;
sleepNow();
}
}
起床時にPulseCounter.available()
を確認しています。availableつまりtrue
になっていると、指定したカウント数以上のカウントになっていることを示します。ここではfalse
の場合再スリープしています。
カウント数が指定以上の場合はloop()
で送信処理と送信完了待ちを行います。
loop()
uint16_t u16ct = PulseCounter.read();
パルスカウント値の読み出しを行います。読み出した後カウンタはリセットされます。
1.4.1.16 - WirelessUART シリアル通信を行います。
WirelessUARTはシリアル通信を行います。
アクトの機能 2台のUART接続の TWELITE 同士をアスキー書式で通信する。 アクトの使い方 必要なTWELITE PCにシリアル接続されている以下のデバイスを2台使います。
アクトの解説 setup()
void setup () {
auto && set = the_twelite.settings.use< STG_STD> ();
auto && nwk = the_twelite.network.use< NWK_SIMPLE> ();
/*** INTERACTIE MODE */
// settings: configure items
set << SETTINGS:: appname("WirelessUART" );
set << SETTINGS:: appid_default(DEFAULT_APP_ID); // set default appID
set << SETTINGS:: ch_default(DEFAULT_CHANNEL); // set default channel
set << SETTINGS:: lid_default(DEFAULT_LID); // set default lid
set.hide_items(E_STGSTD_SETID:: OPT_DWORD2, E_STGSTD_SETID:: OPT_DWORD3, E_STGSTD_SETID:: OPT_DWORD4, E_STGSTD_SETID:: ENC_KEY_STRING, E_STGSTD_SETID:: ENC_MODE);
set.reload(); // load from EEPROM.
/*** SETUP section */
// the twelite main class
the_twelite
<< set // from iteractive mode (APPID/CH/POWER)
<< TWENET:: rx_when_idle(); // open receive circuit (if not set, it can't listen packts from others)
// Register Network
nwk << set; // from interactive mode (LID/REPEAT)
/*** BEGIN section */
SerialParser.begin(PARSER:: ASCII, 128 ); // Initialize the serial parser
the_twelite.begin(); // start twelite!
/*** INIT message */
Serial << "--- WirelessUart (id=" << int (nwk.get_config().u8Lid) << ") ---" << mwx:: crlf;
}
インタラクティブモードを初期化しています。このサンプルでは互いに論理デバイスID(LID)が異なるデバイスを2台以上用意します。
SerialParser.begin(PARSER:: ASCII, 128 );
シリアルパーサー を初期化します。
loop()
while (Serial.available()) {
if (SerialParser.parse(Serial.read())) {
Serial << ".." << SerialParser;
const uint8_t * b = SerialParser.get_buf().begin();
uint8_t addr = * b; ++ b; // the first byte is destination address.
transmit(addr, b, SerialParser.get_buf().end());
}
}
シリアルからのデータ入力があった時点で、シリアルパーサーに1バイト入力します。アスキー形式が最後まで受け付けられた時点でSerialParser.parse()
はtrue
を戻します。
SerialParser
は内部バッファに対してsmplbuf
でアクセスできます。上の例ではバッファの1バイト目を送信先のアドレスとして取り出し、2バイト目から末尾までをtransmit()
関数に渡します。
on_rx_packet()
パケットを受信したときには、送信元を先頭バイトにし続くペイロードを格納したバッファsmplbuf_u8<128> buf
を生成し、出力用のシリアルパーサーserparser_attach pout
からシリアルに出力しています。
void on_rx_packet (packet_rx& rx, bool_t & handled) {
// check the packet header.
const uint8_t * p = rx.get_payload().begin();
if (rx.get_length() > 4 && ! strncmp((const char * )p, (const char * )FOURCHARS, 4 )) {
Serial << format("..rx from %08x/%d" , rx.get_addr_src_long(), rx.get_addr_src_lid()) << mwx:: crlf;
smplbuf_u8< 128 > buf;
mwx:: pack_bytes(buf
, uint8_t (rx.get_addr_src_lid()) // src addr (LID)
, make_pair(p+ 4 , rx.get_payload().end()) ); // data body
serparser_attach pout;
pout.begin(PARSER:: ASCII, buf.begin(), buf.size(), buf.size());
Serial << pout;
}
}
テスト用のコマンド
テストデータは必ずペースト機能 を用いてターミナルに入力してください。入力にはタイムアウトがあるためです。
参考: TWE ProgrammerやTeraTermでのペーストはAlt+Vを用います。
入力の末尾にCR LFが必要です。
最初はCR LFが省略できるXで終わる系列を試してください。終端文字列が入力されない場合は、その系列は無視されます。
例
:FE00112233X
:FE001122339C
任意の子機宛に00112233
を送付します。
例
:03AABBCC00112233X
:03AABBCC0011223366
子機3番に対してAABBCC00112233
を送付します。
例
:FF00112233X
:00112233X
任意の親機または子機宛(0xFF
)、親機宛(0x00
)に送付します。
1.4.1.17 - ユニバーサル レシーバー 様々なパケットを受信します
MWXライブラリの twe_twelite.network
に NWK_LAYERED
、 twe_twelite.network2
に NWK_SIMPLE
を動作させることで、レイヤーツリーネット (TWELITE PAL, ARIAなど)のパケットを含む、さまざまな種類のパケットを受信、解釈できます。
ただし無線パケットは、同一チャネルであることと、同一アプリケーションIDであることが条件です。
main.cpp
setup()
, loop()
、受信パケットのコールバック関数 on_rx_packet()
を記述しています。
setup()
これらのオブジェクトは pkt_handler.cpp
で宣言され setup()
中でpnew()
により初期化されます。主にパケットのペイロード(データ)を解釈します。
mwx:: pnew(g_pkt_pal);
mwx:: pnew(g_pkt_apptwelite);
mwx:: pnew(g_pkt_actsamples);
mwx:: pnew(g_pkt_unknown);
2つのネットワークオブジェクトを生成しています。必ず the_twelite.network
にNWK_LAYERED
にします。
auto && nwk_ly = the_twelite.network.use< NWK_LAYERED> ();
auto && nwk_sm = the_twelite.network2.use< NWK_SIMPLE> ();
loop()
このサンプルではloop()
の処理で重要なのは約1秒おきに行っている .refresh()
処理です。g_pkt_apptwelite().refresh()
のみ重複チェッカのタイムアウト処理を行っています。それ以外のオブジェクトは何もしません。
if (TickTimer.available()) {
static unsigned t;
if (! (++ t & 0x3FF )) {
g_pkt_pal.refresh();
g_pkt_apptwelite.refresh();
g_pkt_actsamples.refresh();
g_pkt_unknown.refresh();
}
}
on_rx_packet()
void on_rx_packet (packet_rx& rx, bool_t & handled) {
auto type = rx.get_network_type();
bool b_handled = false;
// PAL
if (! b_handled
&& type == mwx:: NETWORK:: LAYERED
&& g_pkt_pal.analyze(rx, b_handled)
) {
g_pkt_pal.display(rx);
}
// Act samples
if (! b_handled
&& type == mwx:: NETWORK:: SIMPLE
&& g_pkt_actsamples.analyze(rx, b_handled)
) {
g_pkt_actsamples.display(rx);
}
// Standard application (e.g. App_Twelite)
if (! b_handled
&& type == mwx:: NETWORK:: NONE
&& g_pkt_apptwelite.analyze(rx, b_handled)
) {
g_pkt_apptwelite.display(rx);
}
// unknown
if (! b_handled) {
g_pkt_unknown.analyze(rx, b_handled);
g_pkt_unknown.display(rx);
}
}
このサンプルコードで最も重要な部分です。auto type = rx.get_network_type();
によりパケットの種別を判定しています。
mwx::NETWORK::LAYERED
: NWK_LAYERED
レイヤーツリーネットのケットmwx::NETWORK::SIMPLE
: NWK_SIMPLE
のパケットmwx::NETWORK::NONE
: ネットワークなし(App_Tweliteなど)その他 : エラーまたは未対応のパケット mwx::NETWORK::NONE
の場合は、再送などで複数送信されうる同一パケットの重複チェッカ等の処理は MWX ライブラリ内部で行われません。これらの対応を記述する必要があります。本サンプルでは dup_checker.hpp
, dup_checker.cpp
を用意しています。
パケットの解釈はtsRxDataApp*
をラップした packet_rx&
オブジェクトを参照します。packet_rx
クラス自体は特別な機能はなく、get_psRxDataApp()
を用いてtsRxDataApp*
から得られる一部の情報へのアクセス手段を定義しているのみです。
pkt_common.hpp
パケット解釈部分のインタフェースを統一する目的で定義しています。
template < class D >
struct pkt_handler {
D& self() { return static_cast < D&> (* this ); }
bool analyze (packet_rx& rx, bool & b_handled) {
return self().pkt.analyze(rx, b_handled);
}
void display (packet_rx& rx) {
Serial
<< crlf
<< format("!PKT_%s(%03d-%08x/S=%d/L=%03d/V=%04d)"
, self().get_label_packet_type()
, self().pkt.data.u8addr_src
, self().pkt.data.u32addr_src
, rx.get_psRxDataApp()-> u8Seq
, rx.get_lqi()
, self().pkt.data.u16volt
);
self().disp_detail(rx);
}
void refresh () {
self()._refresh();
}
};
// packet analyzer for App_Twelite
class pkt_handler_apptwelite : public pkt_handler< pkt_handler_apptwelite> {
friend class pkt_handler < pkt_handler_apptwelite> ;
pkt_apptwelite pkt;
void disp_detail (packet_rx& rx);
const char * get_label_packet_type () { return "AppTwelite" ; }
void _refresh () { pkt.refresh(); }
public :
pkt_handler_apptwelite() : pkt() {}
};
analyze()
: パケットのペイロードを解釈する。display()
: パケット情報を表示する。refresh()
: 1秒おきの処理を記述します。self()
: 派生クラスD
にキャストします。さらにパケット解釈クラス(上記例 pkt_handler_apptwelite
)には、メンバーオブジェクトの pkt
が含まれます。実際のパケットの解釈部分は、pkt_???.cpp
にある各々の analyze()
の実装を参照してください。
pkt_???.hpp
, pkt_???.cpp
パケット種別ごとのパケット解釈部 analyze()
と、データ構造 data
が定義されています。メンバーdata
は、構造体ですがPktDataCommon
の共通構造体を継承しています。この共通部を用いてパケットのデータのシリアル出力のコードを簡潔に記述しています。
pkt_pal
PAL関連のパケットに対応します。PALのパケット構造は複雑なデータ構造を持っています。ここでは EASTL のコンテナを用いた実装を行っています。
_vect_pal_sensors
: _pal_sensor
オブジェクトのプール。このオブジェクトは instusive map で使用するための専用クラスです。_map_pal_sensors
: センサーデータを効率よく検索するための intrusive map 構造。1パケット中の複数データに対して各々が追加されるたびに_vect_pal_sensors
にエントリを確保して値を格納します。パケット中のすべてのデータを解釈した時点でセンサータイプをキーとした_map_pal_sensors
を構築します。
dup_checker
重複チェッカーを実装します。チェッカーの動作はテンプレート引数によってカスタマイズできます。
テンプレート引数 MODE
: MODE_REJECT_SAME_SEQ
を指定すると、同じシーケンス番号のパケットを除外します。パケット順が並び変わるような場合に使用します。MODE_REJECT_OLDER_SEQ
はより新しい番号を採用します。TIMEOUT_ms
: 重複データベースの初期化を行う間隔です。1000
と指定すると1秒経過したデータは抹消されます。直前では除外されていたパケットも、重複データベースの初期化されると再び採用されることになります。N_ENTRIES
: データ構造に最大確保される要素数です。N_BUCKET_HASH
: ハッシュ値の最大数です。素数を指定します。受信される無線ノードの種類をもとに決めます。コンテナ _mmap_entries
: intrusive ハッシュ マルチ マップ構造です。検索キーは無線ノードのシリアル番号です。_vect_pool
: マップ構造で用いられる要素を固定数(N_ENTRIES
)を確保します。_ring_vecant_idx
: _mmap_entries
に利用されていない_vect_pool
の要素を配列インデックス番号で管理します。リングバッファの構造で、要素を追加するときはリングバッファから値を一つ取り出し、削除するときはリングバッファに値を返します。重複チェック
bool check_dup (uint32_t u32ser, uint16_t u16val, uint32_t u32_timestamp) {
// find entry by key:u32ser.
auto r = _mmap_entries.equal_range(u32ser);
...
}
マルチマップ構造からデータを検索するには .equal_range()
を呼び出します。得られた r
はイテレータで、同一のシリアル番号の要素を列挙します。
各要素(_dup_checker_entry
)にはタイムスタンプやシーケンス番号が記録されています。この値に従い重複を確認します。
1.4.1.18 - Unit_??? 単機能の動作確認サンプル
Unit_
で始まるアクト(act)は、ごく単機能の記述や動作を確認するためのものです。
名前 内容 Unit_ADC
ADCを動作させるサンプルです。100msごとにADCを連続実行しつつ約1秒おきに読み出し表示します。[s]
キーでスリープします。 Unit_I2Cprobe
I2Cバスをスキャンして、応答のあるデバイス番号を表示します(この手順で応答しないデバイスもあります)。 Unit_delayMicoroseconds
delayMicroseconds()
の動作を確認します。16MhzのTickTimerのカウントとの比較をします。Unit_brd_CUE
TWELITE CUE の加速度センサー,磁気センサー,LEDの動作確認を行います。ターミナルから[a]
,[s]
,[l]
キーを入力します。Unit_brd_ARIA
TWELITE ARIAの温湿度センサー、磁気センサー、LEDの動作確認を行います。ターミナルから[t]
,[s]
,[l]
キーを入力します。 Unit_brd_PAL_NOTICE
通知パル(NOTICE PAL)のLED点灯 を試します。起動時に全灯フラッシュ、その後はシリアル入力で操作します。 - r
,g
,b
,w
: 各色の点灯モードをトグルする - R
,G
,B
,W
: 各色の明るさを変更する(消灯・全灯時は無効) - c
: 周期を変化させる(点滅時) - C
: 点滅時のデューティを変化させる(点滅時)Unit_div100
10,100,1000の割り算と商を求めるdiv10()
,div100()
,div1000()
の動作確認を行います。-99999~99999まで計算を行い通常の/
,%
による除算との経過時間の比較をします。 Unit_div_format
div10()
,div100()
,div1000()
の結果を文字列出力します。Unit_UART1
UART1 (Serial1
) の使用サンプルです。UART0からの入力をUART1に出力し、UART1からの入力をUART0に出力します。 Unit_Pkt_Parser
パケット情報のパーサーpktparser
の使用サンプルです。App_Wingsの出力を解釈することが出来ます。 ※ TWELITE無線モジュール同士をシリアル接続して、一方をApp_Wings
として他方でその出力を解釈したいような場合です。他方をTWELITE無線モジュール以外に接続したい場合は他のプラットフォーム を参照ください。 Unit_EEPROM
EEPROMの読み書きテストコードです。 Unit_Cue_MagBuz
TWELITE CUEの磁石センサーとSETピン(圧電ブザーを接続)を用いた、磁石を離すとブザーが鳴るプログラムです。 Unit_doint-bhv
IO割り込みを処理するビヘイビア記述例です。 Unit_EASTL
EASTL ライブラリを用いた断片コード集です。
1.5 - 改版履歴 TWELITE STAGE SDK の改版履歴
軽微な修正にあたるものは、本改版履歴には記載を行わずGitHub上の改版のみとなります。必要に応じて修正を引用ください。
更新方法 TWELITE STAGE の配布パッケージリリース後の修正・追加分などはGitHubレポジトリに格納しております。必要に応じて配布パッケージの位置を差し替えて利用いただくようお願いいたします。
MWSDKの他の更新が必要になる場合があります。更新時のリリース記述を参照してください。MWSDKの更新についてはこちらを参照ください。
MWXライブラリコードの更新方法 ライブラリのソースコードは GitHubリポジトリ にて公開しています。ライブラリのソースコードの差し替えは、以下の手順で行ってください。
各リリースのリンクよりGitのクローンを行うか zip 形式でソースコードをダウンロードします。
以下のフォルダの内容を差し替えます。
.../MWSTAGE/ --- TWELITE STAGE 配布フォルダ
.../MWSDK --- MWSDKフォルダ
.../TWENET/current/src/mwx <-- このフォルダを差し替える
リリース前の更新 リリース前の更新については下記に掲載する場合があります。
https://github.com/monowireless/mwx/wiki
履歴 0.2.0 - 2022-03-01 ライブラリ名 依存バージョン mwx 0.2.0 twesettings 0.2.6 TWENET C 1.3.5
主な改定内容
ヒープ領域へのメモリ確保を行う Wire オブジェクトを変更した。 utils.hでの名前の衝突を避けるため、関数名をG_OCTET()
からG_BYTE()
に変更した。 attachIntDio()
において、vAHI_DioInterruptEnable()
の順番を変更した。ユニバーサルレシーバ (NWK_LAYERED
, NWK_SIMPLE
またはネットワークレスパケットを同一実行コードで受信する) をサポートするために the_twelite.network2
を追加した。 NWK_LAYERED
を追加 (現時点では親機受信のみ対応)MWXの初期化時にアプリケーションのバージョンを設定する MWX_Set_Usder_App_Ver()
関数を導入した。 mwx::pnew()
を追加し配置newの記述を簡素化した。EASTLのサポート追加 MWXのソースコードのほとんどをプリコンパイルし、コンパイルの高速化を図った。 DIOイベントが無関係なポートに引き渡されていたのを修正。 0.1.9 - 2021-12-15 ライブラリ名 依存バージョン mwx 0.1.9 twesettings 0.2.6 TWENET C 1.3.5
主な改定内容
TWELITE ARIA向けのボードサポート BRD_ARIA
とセンサー定義 SHT4x
を追加 インタラクティブモード中で Serial
クラスオブジェクトを用いた出力を可能とする内部手続きを追加 (Serial._force_Serial_out_during_intaractive_mode()
) 0.1.8 - 2021-09-09 ライブラリ名 依存バージョン mwx 0.1.8 twesettings 0.2.6 TWENET C 1.3.5
主な改定内容
Serial1
のポート、代替ポートの定義が適切でなかったSerial
(UART0)のボーレートを変更できるようにした受信パケット(on_rx_packet()
)、送信完了(on_tx_comp()
)を知らせるイベントコールバックを追加コールバック関数の定義をしなければ従前の手続きも利用可能 <STG_STD>
インタラクティブモード設定の定義ID間違いや一部デフォルト値の変更など<STG_STD>
インタラクティブモード設定でAppIDに加えて、チャネルと論理デバイスIDのデフォルト値を変更できるようにしたthe_twelite
と <NWK_SIMPLE>
オブジェクトの設定を、一部の設定についてインタラクティブモード<STG_STD>
オブジェクトで行えるようにした<NWK_SIMPLE>
で再送回数のデフォルト値を設定できるようにした<STG_STD>
インタラクティブモードの画面が出ている間はアプリケーションからのSerial(UART0)の入出力を行わないようにしたCUE::PIN_SET
, PAL???"":PIN_SET
を追加 (PIN_BTN
はボタンのないCUEでPIN_BTN
を用いるのは不自然であるため)random()
の名前空間をmwx::に移動 (グローバル名にエリアス)MONOSTICKのウォッチドッグ設定を32ms単位で行うようにした BRD_TWELITE
を用いスリープを行うと、復帰時にピンが正しく初期化されなかった0.1.7 - 2020-12-03 ライブラリ名 依存バージョン mwx 0.1.7 twesettings 0.2.6 TWENET C 1.3.4
主な改定内容
0.1.6 - 2020-10-09 ライブラリ名 依存バージョン mwx 0.1.6 twesettings 0.2.5 TWENET C 1.3.4
主な改定内容
0.1.5 - 2020-08-05 ライブラリ名 依存バージョン mwx 0.1.5 twesettings 0.2.5 TWENET C 1.3.4
主な改定内容
設定ビヘイビア(インタラクティブモード機能)を追加 チャネルマネージャ chmgr
の実装 0.1.4 - 2020-07-29 ライブラリ名 依存バージョン mwx 0.1.4 twesettings 0.2.4 TWENET C 1.3.3
一括ダウンロード
MWSDK2020_07_UNOFFICIAL
(ReadMe )
主な改定内容
delayMilliseconds()
の追加digitalReadBitmap()
の追加delay()
の精度向上Serial1
インスタンスが定義されていない問題を修正Analogue
の割り込みハンドラが呼び出されない問題を修正0.1.3 - 2020-05-29 MWSDK2020_05 に対応
主な改定内容
重複チェッカ duplicate_checker
の初期化等に不備があり期待通りの除去を行っていなかった format()
の実装を機種依存の少ないものとした。また、引数を最大8までとした。64bit引数が含まれる場合は引数の数は制限される。https://github.com/monowireless/mwx/releases/tag/0.1.3
修正は MWSDK2020_05 を前提としています。本修正については、更新を推奨します。
0.1.2 - 2020-04-24 MWSDK2020_04 に対応
主な改定内容
Timer0..4
の初期化の問題を修正mwx::format()
の内部処理を変更インタラクティブモード対応のための実験的なコードの追加 https://github.com/monowireless/mwx/releases/tag/0.1.2
修正は MWSDK2020_04 を前提としています。本修正については、更新を推奨します。
0.1.1 - 2020-02-28 主な改定内容
https://github.com/monowireless/mwx/releases/tag/0.1.1
0.1.0 - 2019-12-23 初版リリース (SDL 2019/12月号収録)
https://github.com/monowireless/mwx/releases/tag/0.1.0
2 - TWELITE SPOT / ESP32 無線 LAN ゲートウェイを試作するためのキット
TWELITE SPOT は TWELITE 親機と ESP32 を搭載した、無線 LAN ゲートウェイを手軽に試作するためのキットです。
2.1 - 導入済みアプリケーションの概要 TWELITE SPOT にプリインストールされたアプリケーションの機能説明
TWELITE SPOT にプリインストールされたアプリケーション(spot-server)は、無線 LAN アクセスポイントとして振る舞い、Web ページ上に子機からのデータを表示します。
動作イメージ
使用方法 TWELITE SPOT スタートガイド まずは使ってみる をご覧ください。
ビューア画面 それぞれのビューアを選択すると、対応した TWELITE 子機 から受信したデータを表示します。
Signal Viewer TWELITE DIP (超簡単!標準アプリ) から受信したデータを表示します。
AI1-4 に入力した電圧や、DI1-4 の入力状態を確認できます。
Signal Viewer
CUE Viewer TWELITE CUE (キューアプリ、TWELITE CUE モード) から受信したデータを表示します。
加速度センサや磁気センサのデータを確認できます。
CUE Viewer
ARIA Viewer TWELITE ARIA (アリアアプリ、TWELITE ARIA モード) から受信したデータを表示します。
温湿度センサや磁気センサのデータを確認できます。
ARIA Viewer
閲覧環境によっては、グラフの X 軸ラベルが重なって見えることがあります。
Serial Viewer TWELITE SPOT が受信したパケットの電文を表示します。
Serial Viewer
親機・中継機アプリの ASCII 形式の出力を表示します。
工場出荷時のアプリの詳細 ESP32 ESP32 に書き込んでいるスケッチは、spot-server
です。
GitHub
TWELITE TWELITE に書き込んでいるアプリは、App_Wings_SPOT_BLUE
です。
親機・中継機アプリ (App_Wings)
2.2 - 無線性能に配慮した設置方法 無線性能に配慮した TWELITE SPOT の設置方法
TWELITE SPOT の無線性能に配慮した設置方法や、壁面への設置方法をご案内します。
TWELITE 専用アンテナに関する詳しい説明は
こちら を参照してください。
無線性能に配慮した設置 アンテナ方向マークを天地方向にする TWELITE SPOT で使用しているアンテナは、アンテナ方向マークを天地方向に向けると、TWELITE SPOT を上面から見たときに、TWELITE SPOT を中心に円状に電波が放射されるため、広い範囲の電波を受信することができます。
TWELITE SPOT と TWELITE 子機のアンテナ方向マークを同じ方向にする 電波には波の振動方向があり、この方向を偏波と呼びます。
送信側と受信側の偏波が同一でない場合感度が低くなり、通信距離が短くなります。
TWELITE SPOT に表記されているアンテナ方向マークはこの偏波の向きを示しており、通信するアンテナ同士のアンテナ方向マークを合わせることにより通信感度が良くなります。
周辺に障害物がない場所に設置する TWELITE SPOT の周辺に障害物があると電波が減衰するため、通信距離が短くなるため、この特性をご理解の上、設置場所を決めてください。
特に金属が TWELITE SPOT の周辺にあると著しく通信距離が短くなるため、TWELITE SPOT の周辺には金属を含む障害物を置かないようにしてください。
目安として TWELITE SPOT から半径 10cm 以内に金属を配置しないようにしてください。
壁面への設置 M3 ビスを 2 本使用しますが、金属製の部品は無線性能に影響を与える可能性があることに注意してください。
2.3 - ファームウェア開発環境の構築方法 TWELITE SPOT のファームウェア開発に向けた環境の構築方法
TWELITE SPOT のファームウェア開発を行うための環境構築の手順をご案内します。
2.3.1 - Arduino IDE 1.x による開発環境の構築方法 Arduino IDE 1.x を使用した開発環境の構築手順
Arduino IDE 1.x を使用した開発環境の構築手順をご案内します。
2.3.1.1 - Arduino IDE 1.x の導入 統合開発環境 (IDE) の導入手順
Arduino IDE 1.x の導入手順をご案内します。
すでに Arduino IDE 1.x がインストールされている場合は、本稿を無視してください。
ダウンロード Web ブラウザで Arduino 公式ダウンロードページ を開き、Legacy IDE (1.8.X) をダウンロードしてください 。
Software | Arduino
例えば、Windows のインストーラは “Windows Win 7 and newer” です。
インストール ダウンロードしたファイルを実行して指示に従い、Arduino IDE 1.x をインストールしてください。
2.3.1.2 - Arduino core for the ESP32 の導入 ESP32 向けツールチェインの導入手順
Arduino に対応した ESP32 専用のコンパイラやライブラリを導入する手順をご案内します。
インストール方法の詳細は
公式資料 をご覧ください(英語)。
ボード情報の追加 Arduino IDE 1.x を起動し、ツールバーの ファイル -> 環境設定 を開いてください。
環境設定の場所
追加のボードマネージャーのURL
に下記の URL を入力し、OKボタンを押してください。
https://espressif.github.io/arduino-esp32/package_esp32_index.json
環境設定ウィンドウ
インストール ツールバーの ツール -> ボード: “Arduino Uno” -> ボードマネージャ を開いてください。
選択されているボードが “Arduino Uno” ではない場合もありますが、同様に操作してください。
ボードマネージャの場所
検索ボックスに “ESP32” と入力して、esp32
ボード定義をインストールしてください。
ボードマネージャ
バージョン 2.0.5
以降で動作確認しています。
2.3.1.3 - Arduino core for the ESP32 の設定 ESP32 向けツールチェインの設定方法
TWELITE SPOT のファームウェア開発において必要となる Arduino core for the ESP32 の設定をご案内します。
ここからは TWELITE SPOT に固有の内容です。
ボード種別の選択 ツールバーの ツール ―> ボード -> ESP32 Arduino -> ESP32 Dev Module を選択してください。
ESP32 Dev Module の場所
ボード設定 以下の画像のように設定してください。
設定後の内容
デフォルトでは Flash size
が 4MB (32Mb)
となっています。
これを 16MB (128Mb)
に変更してください。
2.3.1.4 - MWings ライブラリの導入 TWELITE を使用するためのライブラリ MWings のインストール手順
TWELITE を使用するためのライブラリ MWings の導入手順をご案内します。
インストール スケッチ -> ライブラリをインクルード -> ライブラリを管理… を開いてください。
ライブラリマネージャの場所
検索ボックスに MWings
と入力し、MWings をインストールしてください。
ライブラリマネージャ
2.4 - ファームウェアの書き込み方法 TWELITE SPOT に対するファームウェアの書き込み方法
TWELITE SPOT に搭載された ESP32 および TWELITE へのファームウェアの書き込み方法をご案内します。
2.4.1 - ESP32 へのファームウェアの書き込み方法 TWELITE SPOT に搭載された ESP32 に対するファームウェアの書き込み方法
TWELITE SPOT に搭載された ESP32 へのファームウェアの書き込み方法をご案内します。
2.4.1.1 - ESP32 へのスケッチの書き込み方法 TWELITE SPOT に搭載された ESP32 に対するスケッチの書き込み方法
TWELITE SPOT に搭載された ESP32 への Arduino スケッチの書き込み方法をご案内します。
ホストとの接続 TWELITE R3 / R2 を接続 7P インターフェイス(ESP32
と記載のある側)に TWELITE R3 / R2 を接続してください。
電源を接続 側面の USB-C コネクタ に 5V 電源を供給してください。
接続例 (ESP32)
TWELITE R3 / R2 は、必ず上図と同じ向きで TWELITE SPOT に接続してください。誤った向きで接続すると、 TWELITE SPOT や TWELITE R3 / R2 が破損する恐れがあります。
Arduino IDE の操作 スケッチを開く Arduino IDE を起動して、書き込むスケッチを開いてください。
シリアルポートを選択 ツール -> シリアルポート メニューから、 TWELITE R3 / R2 のポートを選択してください。
シリアルポート選択
シリアルポートは、Windows では COM?
といった名称に、macOS / Linux では /dev/tty?
といった名称になります。
ESP32 をプログラムモードで起動 TWELITE SPOT の ESP32 リセットスイッチ EN(RST)
と ESP32 ブートスイッチ BOOT
を押し、EN(RST)
-> BOOT
の順で離してください。
ボタンの位置
BOOT
を押した状態でリセットすることで、ESP32 をプログラムモードに移行できます。
書き込みを実行 Arduino IDEの マイコンボードに書き込む ボタンをクリックしてください。
マイコンボードに書き込む
書き込みが完了すると、画面下部に Hard resetting via RTS pin...
と表示されます。
書き込みに失敗し、下記のメッセージが表示された場合は、使用する USB ポートや USB ケーブルを変えてみてください。
A serial exception error occurred: Could not configure port: (6, 'Device not configured')
ESP32 をリセット 書き込みが完了したら、TWELITE SPOT の ESP32 リセットスイッチ EN(RST)
を押して離し、ESP32 をリセットしてください。
リセットスイッチの位置
書き込み完了画面
リセットを行わないと、プログラムモードから抜け出せません。
2.4.1.2 - ESP32 へのファイルの書き込み方法 TWELITE SPOT に搭載された ESP32 に対するファイルの書き込み方法
TWELITE SPOT に搭載された ESP32 へファイル(data/
フォルダ以下のファイル群)を書き込む方法をご案内します。
本稿では、応用的な内容(TWELITE SPOT に搭載された ESP32 のフラッシュ領域をファイルシステムとして扱い、HTML などのファイルを書き込む方法)を紹介しております。
例えば TWELITE SPOT に HTML ファイルを書き込んでWebサーバとして振る舞わせたい(spot-server サンプルで実現しています)、TWELITE SPOT に暗号鍵ファイルを書き込んでおきたいといった要求がない場合には、本稿の内容を無視していただいて構いません。
本稿では、サードパーティのオープンソースソフトウェアを使用します。
サードパーティのソフトウェアについて、その詳しい使用方法を弊社からご案内することはいたしかねます。また、サードパーティのソフトウェアを使用されたことによるいかなる損害についても、弊社は一切の責任を負いません。
プラグインの導入 ESP32 のフラッシュ領域へファイルを書き込むための Arduino プラグイン (arduino-esp32fs-plugin) をインストールします。
プラグインのダウンロード 以下のページから、esp32fs.zip
を入手します。
Release Update to support Big Sur · lorol/arduino-esp32fs-plugin
プラグインのインストール ダウンロードした esp32fs.zip
を展開してください。
Arduino のスケッチブックの保存場所(Arduino IDE 環境設定に記載。例:C:\Users\foo\Documents\Arduino
)に tools
フォルダがない場合は、これを作成してください。
tools
フォルダに ESP32FS/tool
フォルダを作成し、zipファイルから得た esp32ffs.jar
ファイルを配置してください。(配置例:C:\Users\foo\Documents\Arduino\tools\ESP32FS\tool\esp32fs.jar
)。
Arduino IDE を次に起動した際にプラグインが使用できるようになります。
ホストとの接続 TWELITE R3 / R2 を接続 7P インターフェイス(ESP32
と記載のある側)に TWELITE R3 / R2 を接続してください。
電源を接続 側面の USB-C コネクタ に 5V 電源を供給してください。
接続例 (ESP32)
TWELITE R3 / R2 は、必ず上図と同じ向きで TWELITE SPOT に接続してください。誤った向きで接続すると、 TWELITE SPOT や TWELITE R3 / R2 が破損する恐れがあります。
Arduino IDE の操作 スケッチを開く Arduino IDE を起動して、スケッチを開いてください。
書き込むファイルの配置 スケッチ -> スケッチのフォルダを表示 から、スケッチのフォルダを開いてください。
スケッチファイル(.ino
)と同じ階層に、data
フォルダを作成してください。
data
フォルダ内に、書き込むファイルを配置してください。
フラッシュ領域においても、data
フォルダ内の階層構造は維持されます。
シリアルポートを選択 ツール -> シリアルポート メニューから、 TWELITE R3 / R2 のポートを選択してください。
シリアルポート選択
シリアルポートは、Windows では COM?
といった名称に、macOS / Linux では /dev/tty?
といった名称になります。
ESP32 をプログラムモードで起動 TWELITE SPOT の ESP32 リセットスイッチ EN(RST)
と ESP32 ブートスイッチ BOOT
を押し、EN(RST)
-> BOOT
の順で離してください。
ボタンの位置
BOOT
を押した状態でリセットすることで、ESP32 をプログラムモードに移行できます。
書き込みを実行 ツール -> ESP32 Sketch Data Upload をクリックしてください。
Select FS for <スケッチ名> /data folder にて、LittleFS を選択してください。
ファイルシステムの選択画面
OK を押してください。
書き込みが完了すると、画面下部に Hard resetting via RTS pin...
と表示されます。
環境によっては、以下のように表示されて書き込みに失敗することがあります(macOS で確認)。
`Error: esptool not found!`
その際には、esptool.py を Arduino15フォルダ
/packages/esp32/tools/esptool_py/<バージョン>/esptool.py
へ配置することで解決できるかもしれません。
例えば、macOS の場合には、下記のようにして esptool.py を取得し、シンボリックリンクを作成します。
/usr/bin/pip3 install esptool
ln -s ~/Library/Python/3.9/bin/esptool.py ~/Library/Arduino15/packages/esp32/tools/esptool_py/4.5.1/esptool.py
注:/usr/bin/pip3
と指定しないと、Homebrew のディレクトリにインストールされてしまうことがあります
ESP32 をリセット 書き込みが完了したら、TWELITE SPOT の ESP32 リセットスイッチ EN(RST)
を押して離し、ESP32 をリセットしてください。
リセットスイッチの位置
2.4.1.3 - ESP32 のパーティションテーブルを指定した書き込み方法 TWELITE SPOT に搭載された ESP32 に対する書き込みにおいて、任意のパーティションテーブルを適用する方法
TWELITE SPOT に搭載された ESP32 へスケッチやファイルを書き込む際に、任意のパーティションテーブルを適用する方法をご案内します。
本稿では、応用的な内容(フラッシュ領域のパーティションテーブルを指定する方法)を紹介しております。
ESP32 Arduino Core に最初から含まれているパーティションテーブルの設定(例:Default 4MB with spiffs)を使用される場合は、本稿を無視していただいて構いません。
本稿の設定を行ったことによるいかなる損害についても、弊社は一切の責任を負いません。
定義ファイルの作成 パーティションテーブルの定義は、csv ファイルに記述します。
下記の例では、16MB のフラッシュ領域のうち、8MB をファイルシステムで使うように指定しています。
# TWELITE SPOT 16MB with 8MB LittleFS
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xE000, 0x2000,
app0, app, ota_0, 0x10000, 0x7F0000,
spiffs, data, spiffs, 0x800000, 0x800000,
TWELITE SPOT 16MB with 8MB LittleFS
Arduino IDE に表示される名前です。nvs
システムで使用する領域です。変更しません。otadata
OTA を使う際に使用する領域です。変更しません。app0
ファームウェアを書き込む領域です。spiffs
LittleFS ファイルシステムで使用する領域です。csv ファイル中の Offset
および Size
列の単位はバイトで、16進数です。
したがって、上記の例では、ファームウェアとファイルシステムが使えるサイズは下記のように計算できます。
app0
のサイズ:0x7F0000 = 8323072
より、7.875MB
spiffs
のサイズ:0x800000 = 8388608
より、8MB
定義ファイルの登録 Arduino15フォルダ を開き、下記のパスに csv ファイルを追加します。
Arduino15/packages/esp32/hardware/esp32/x.x.x/tools/partitions
x.x.x
は Arduino core for the ESP32 のバージョン
パーティションテーブルの適用 Arduino IDE のツールバーから ツール -> Partition Scheme を開き、追加したパーティションテーブルを選びます。
選択したパーティションテーブルが次回以降のファームウェアの書き込みやファイルシステムの書き込みに反映されます。
スケッチファイルと同じ場所に partitions.csv
という名前で設定ファイルを置くと、そちらが優先されます。ただし、Arduino IDE 上の表記は変わらないため、紛らわしい場合があります。
2.4.2 - TWELITE へのファームウェアの書き込み方法 TWELITE SPOT に搭載された TWELITE に対するファームウェアの書き込み方法
TWELITE SPOT に搭載された TWELITE へのファームウェアの書き込み方法をご案内します。
工場出荷時の TWELITE SPOT では、TWELITE に親機・中継機アプリ(App_Wings_SPOT)をあらかじめ書き込んでいます。工場出荷状態の場合は、TWELITE のファームウェアを書き換える必要はありません。
TWELITE SPOT に搭載される TWELITE では、インタラクティブモードによる設定変更ができません。
TWELITE の周波数チャネルやアプリケーションIDを設定するには、ESP32 からシリアル通信でコマンドを送信します。Arduino 環境では、Twelite.begin()
を使用してください。
TWELITE STAGE APP をインストール TWELITE STAGE SDK をダウンロードし、ダウンロードしたファイルをCドライブ直下に展開してください。
ホストとの接続 TWELITE R3 / R2 を接続 7P インターフェイス(TWELITE
と記載のある側)に TWELITE R3 / R2 を接続してください。
電源を接続 側面の USB-C コネクタ に 5V 電源を供給してください。
接続例 (TWELITE)
TWELITE R3 / R2 は、必ず上図と同じ向きで TWELITE SPOT に接続してください。誤った向きで接続すると、 TWELITE SPOT や TWELITE R3 / R2 が破損する恐れがあります。
TWELITE STAGE APP の操作 TWELITE STAGE APP (TWELITE_Stage.exe
) を起動してください。
シリアルポート選択画面で TWELITE R3 / TWELITE R2 を選択してください。
メインメニュー -> アプリ書換 を選択し、書換えたいアプリを選択してください。
2.4.3 - ファームウェアの初期化方法 TWELITE SPOT のファームウェアを工場出荷時に戻す方法
TWELITE SPOT に搭載された ESP32 および TWELITE へ書き込まれたファームウェアを工場出荷時の状態に初期化する方法をご案内します。
2.4.3.1 - ESP32 のファームウェアの初期化方法 TWELITE SPOT に搭載された ESP32 に書き込まれたファームウェアを工場出荷時に戻す方法
esptool によって、TWELITE SPOT に搭載された ESP32 へ書き込まれたファームウェアを手動で工場出荷時の状態に戻す方法をご案内します。
esptool は、ESP32 にバイナリファイルを書き込むための公式ユーティリティです。
Python をインストール Python 3.7 以降がインストールされていない場合は、Python 3.7 以降をインストールしてください。
https://www.python.org/downloads/
PyPI から esptool をインストールしてください。
既存のPython環境に影響を与えたくない場合は、pipx の使用を推奨します。
ホストとの接続 TWELITE R3 / R2 を接続 7P インターフェイス(ESP32
と記載のある側)に TWELITE R3 / R2 を接続してください。
電源を接続 側面の USB-C コネクタ に 5V 電源を供給してください。
TWELITE R3 / R2 は、必ず上図と同じ向きで TWELITE SPOT に接続してください。誤った向きで接続すると、 TWELITE SPOT や TWELITE R3 / R2 が破損する恐れがあります。
バイナリファイルの取得 下記のリンクから、spot-server-2023-05-bin.zip
をダウンロードしてください。
spot-server-2023-05-bin.zip
ダウンロードしたら、zipファイルを展開してください。
ESP32 をプログラムモードで起動 TWELITE SPOT の ESP32 リセットスイッチ EN(RST)
と ESP32 ブートスイッチ BOOT
を押し、EN(RST)
-> BOOT
の順で離してください。
ボタンの位置
BOOT
を押した状態でリセットすることで、ESP32 をプログラムモードに移行できます。
esptool をインストールした端末でspot-server-2023-05-bin.zip
を展開したフォルダに移動し、下記を実行してください。
esptool --chip esp32 --port <シリアルポート> --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode qio --flash_freq 80m --flash_size 16MB 0x1000 spot-server.ino.bootloader.bin 0x8000 spot-server.ino.partitions.bin 0xe000 boot_app0.bin 0x10000 spot-server.ino.bin 0x100000 spot-server.littlefs.bin
<シリアルポート> には、COM?
や /dev/tty?
といったポート名を入力します。
もし失敗する場合は、下記をお試しください。
--flash_mode qio
を --flash_mode dio
に変更--flash_freq 80m
を --flash_freq 40m
に変更--baud 921600
を --baud 460800
に変更ESP32 をリセット 書き込みが完了したら、TWELITE SPOT の ESP32 リセットスイッチ EN(RST)
を押して離し、ESP32 をリセットしてください。
リセットスイッチの位置
リセットを行わないと、プログラムモードから抜け出せません。
2.4.3.2 - TWELITE のファームウェアの初期化方法 TWELITE SPOT に搭載された TWELITE へ書き込まれたファームウェアを工場出荷時に戻す方法
TWELITE STAGE APP によって、TWELITE SPOT に搭載された TWELITE へ書き込まれたファームウェアを工場出荷時の状態に戻す方法をご案内します。
TWELITE SPOT に搭載される TWELITE では、インタラクティブモードによる設定変更ができません。
TWELITE の周波数チャネルやアプリケーションIDを設定するには、ESP32 からシリアル通信でコマンドを送信します。Arduino 環境では、Twelite.begin()
を使用してください。
TWELITE STAGE APP をインストール TWELITE STAGE SDK をダウンロードし、ダウンロードしたファイルをCドライブ直下に展開(Windowsの場合)してください。
ファームウェアの入手 下記のリンクからバイナリファイルをダウンロードし、MWSTAGE
フォルダ内の BIN
フォルダに配置してください。
ホストとの接続 TWELITE R3 / R2 を接続 7P インターフェイス(TWELITE
と記載のある側)に TWELITE R3 / R2 を接続してください。
電源を接続 側面の USB-C コネクタ に 5V 電源を供給してください。
TWELITE R3 / R2 は、必ず上図と同じ向きで TWELITE SPOT に接続してください。誤った向きで接続すると、 TWELITE SPOT や TWELITE R3 / R2 が破損する恐れがあります。
TWELITE STAGE APP の操作 TWELITE STAGE APP (TWELITE_Stage.exe
) を起動してください。
シリアルポート選択画面で TWELITE R3 / TWELITE R2 を選択してください。
メインメニュー -> アプリ書換 -> BIN から選択 を選び、先ほど入手したバイナリ(App_Wings_TWELITESPOT_BLUE_L1305_V1-3-0.bin
)を書き込んでください。
2.5 - サンプルスケッチの解説 TWELITE SPOT 向けサンプルスケッチの解説
TWELITE SPOT 向けサンプルスケッチの内容を解説します。
2.5.1 - TWELITE と通信するスケッチの解説 MWings ライブラリに同梱された TWELITE SPOT の基本的なサンプルスケッチの解説
TWELITE NET だけを使用し、無線 LAN を使わない簡単なサンプルスケッチを解説します。
2.5.1.1 - 超簡単!標準アプリのデータを取得・操作 超簡単!標準アプリのデータを取得・表示するサンプルスケッチ monitor_spot_app_twelite
の解説
超簡単!標準アプリ (App_Twelite) のデータを取得・表示するサンプルスケッチ
monitor_spot_app_twelite
の解説です。最後に、相手先の出力ポートを操作する改変を行います。
2.5.1.1.1 - 超簡単!標準アプリのデータを取得・操作 最新版
超簡単!標準アプリ (App_Twelite) のデータを取得・表示するサンプルスケッチ
monitor_spot_app_twelite
の解説です。最後に、相手先の出力ポートを操作する改変を行います。
サンプルスケッチの保存場所 MWings ライブラリを導入 していれば、Arduino IDE の ファイル -> スケッチ例 -> MWings -> TWELITE SPOT -> Receive -> monitor_spot_app_twelite からスケッチを開くことができます。
保存場所の表示例
スケッチ 以下はソースコード本体です。
// Monitor example for TWELITE SPOT: Receive data from App_Twelite
#include <Arduino.h>
#include "MWings.h"
const int RST_PIN = 5 ;
const int PRG_PIN = 4 ;
const int LED_PIN = 18 ;
const int8_t RX1_PIN = 16 ;
const int8_t TX1_PIN = 17 ;
const uint8_t TWE_CHANNEL = 18 ;
const uint32_t TWE_APP_ID = 0x67720102 ;
void setup ()
{
// Initialize serial ports
Serial.begin(115200 );
Serial.println("Monitor example for TWELITE SPOT: App_Twelite" );
Serial2.begin(115200 , SERIAL_8N1, RX1_PIN, TX1_PIN);
// Initialize TWELITE
Twelite.begin(Serial2,
LED_PIN, RST_PIN, PRG_PIN,
TWE_CHANNEL, TWE_APP_ID);
// Attach an event handler to process packets from App_Twelite
Twelite.on([](const ParsedAppTwelitePacket& packet) {
Serial.println("" );
Serial.print("Packet Timestamp: " );
Serial.print(packet.u16SequenceNumber / 64.0f , 1 ); Serial.println(" sec" );
Serial.print("Source Logical ID: 0x" );
Serial.println(packet.u8SourceLogicalId, HEX);
Serial.print("LQI: " );
Serial.println(packet.u8Lqi, DEC);
Serial.print("Supply Voltage: " );
Serial.print(packet.u16SupplyVoltage, DEC); Serial.println(" mV" );
Serial.print("Digital Input: " );
Serial.print(packet.bDiState[0 ] ? " DI1:Lo" : " DI1:Hi" );
Serial.print(packet.bDiState[1 ] ? " DI2:Lo" : " DI2:Hi" );
Serial.print(packet.bDiState[2 ] ? " DI3:Lo" : " DI3:Hi" );
Serial.println(packet.bDiState[3 ] ? " DI4:Lo" : " DI4:Hi" );
Serial.print("Analog Input: " );
Serial.print(" AI1:" ); Serial.print(packet.u16AiVoltage[0 ]); Serial.print(" mV" );
Serial.print(" AI2:" ); Serial.print(packet.u16AiVoltage[1 ]); Serial.print(" mV" );
Serial.print(" AI3:" ); Serial.print(packet.u16AiVoltage[2 ]); Serial.print(" mV" );
Serial.print(" AI4:" ); Serial.print(packet.u16AiVoltage[3 ]); Serial.println(" mV" );
});
}
void loop ()
{
// Update TWELITE
Twelite.update();
}
ライブラリのインクルード 4行目では、MWings ライブラリ をインクルードしています。
ピン番号の定義 6-11行目では、ピン番号を定義しています。
const int RST_PIN = 5 ;
const int PRG_PIN = 4 ;
const int LED_PIN = 18 ;
const int8_t RX1_PIN = 16 ;
const int8_t TX1_PIN = 17 ;
名称 内容 RST_PIN
TWELITE の RST ピンが接続されているピンの番号 PRG_PIN
TWELITE の PRG ピンが接続されているピンの番号 LED_PIN
基板上の ESP32 用 LED が接続されているピンの番号 RX1_PIN
TWELITE の RX1 ピンが接続されているピンの番号 TX1_PIN
TWELITE の TX1 ピンが接続されているピンの番号
TWELITE 設定の定義 13-14行目では、TWELITE SPOT に搭載された TWELITE 親機に適用する設定を定義しています。
const uint8_t TWE_CHANNEL = 18 ;
const uint32_t TWE_APP_ID = 0x67720102 ;
名称 内容 TWE_CHANNEL
TWELITE の 周波数チャネル TWE_APP_ID
TWELITE の アプリケーション ID
スケッチ中の値は、超簡単!標準アプリの初期値です。
シリアルポートの設定 19-21行目では、使用するシリアルポートを初期化するとともに、シリアルモニタへ起動メッセージを出力しています。
Serial.begin(115200 );
Serial.println("Monitor example for TWELITE SPOT: App_Twelite" );
Serial2.begin(115200 , SERIAL_8N1, RX1_PIN, TX1_PIN);
Serial
は、Arduino IDE の シリアルモニタとの通信に使います。シリアルモニタの設定に合わせて、ボーレートを 115200
bps としています。
一方、Serial2
は、TWELITE SPOT に搭載された TWELITE 親機との通信に使います。こちらも TWELITE 親機の初期設定に合わせて、ボーレートを 115200
bps としています。
TWELITE の設定 24-27行目では、Twelite.begin()
を呼び出し、TWELITE SPOT に搭載された TWELITE 親機の設定と起動を行っています。
Twelite.begin(Serial2,
LED_PIN, RST_PIN, PRG_PIN,
TWE_CHANNEL, TWE_APP_ID);
パケット受信時のイベントの登録 29-49行目では、Twelite.on()
を呼び出し、送られたデータに対して行う処理を登録しています。
ここでは、受信したパケットの内容をシリアルモニタに出力しています。
Twelite.on([](const ParsedAppTwelitePacket& packet) {
Serial.println("" );
Serial.print("Packet Timestamp: " );
Serial.print(packet.u16SequenceNumber / 64.0f , 1 ); Serial.println(" sec" );
Serial.print("Source Logical ID: 0x" );
Serial.println(packet.u8SourceLogicalId, HEX);
Serial.print("LQI: " );
Serial.println(packet.u8Lqi, DEC);
Serial.print("Supply Voltage: " );
Serial.print(packet.u16SupplyVoltage, DEC); Serial.println(" mV" );
Serial.print("Digital Input: " );
Serial.print(packet.bDiState[0 ] ? " DI1:Lo" : " DI1:Hi" );
Serial.print(packet.bDiState[1 ] ? " DI2:Lo" : " DI2:Hi" );
Serial.print(packet.bDiState[2 ] ? " DI3:Lo" : " DI3:Hi" );
Serial.println(packet.bDiState[3 ] ? " DI4:Lo" : " DI4:Hi" );
Serial.print("Analog Input: " );
Serial.print(" AI1:" ); Serial.print(packet.u16AiVoltage[0 ]); Serial.print(" mV" );
Serial.print(" AI2:" ); Serial.print(packet.u16AiVoltage[1 ]); Serial.print(" mV" );
Serial.print(" AI3:" ); Serial.print(packet.u16AiVoltage[2 ]); Serial.print(" mV" );
Serial.print(" AI4:" ); Serial.print(packet.u16AiVoltage[3 ]); Serial.println(" mV" );
});
上記のイベントは、超簡単!標準アプリからのパケットを受信したときにだけ呼び出されます。
受信したパケットの内容は ParsedAppTwelitePacket
型の引数 packet
に格納されています。
メッセージの内容 メッセージ 内容 Packet Timestamp
パケットのタイムスタンプ Source Logical ID
送信元 TWELITE の論理デバイスID LQI
無線通信品質(0~255) Supply Voltage
電源電圧 (mV) Digital Input
デジタル入力の状態 Analog Input
アナログ入力の状態
TWELITE のデータの更新 55行目では、Twelite.update()
を呼び出しています。
相手先の出力ポートの操作 超簡単!標準アプリの入力ポートの状態を取得するだけでなく、超簡単!標準アプリの出力ポートを操作してみましょう。
ここでは、TWELITE SPOT が受信した際の LQI(無線通信品質)に基づき、相手端末が TWELITE SPOT に近づいた際に、相手端末のデジタル出力ポートを点灯させてみます。
スケッチの改変 改変内容 はじめに、16行目へ下記のコードを追加します。
AppTweliteCommand command;
上記のコードでは、送信するコマンドの内容を格納する AppTweliteCommand
を作成しています。
次に、52-54行目へ下記のコードを追加します。
command.u8DestinationLogicalId = packet.u8SourceLogicalId; // LID
command.bDiState[0 ] = (packet.u8Lqi >= 100 ) ? true : false; // DI1
Twelite.send(command);
上記のコードでは、AppTweliteCommand
を操作し、Twelite.send()
でコマンドを送信しています。
これでスケッチの改変は終了です。改変後のコードを示します。
// Monitor example for TWELITE SPOT: Receive data from and send data to App_Twelite
#include <Arduino.h>
#include "MWings.h"
const int RST_PIN = 5 ;
const int PRG_PIN = 4 ;
const int LED_PIN = 18 ;
const int8_t RX1_PIN = 16 ;
const int8_t TX1_PIN = 17 ;
const uint8_t TWE_CHANNEL = 18 ;
const uint32_t TWE_APP_ID = 0x67720102 ;
AppTweliteCommand command;
void setup ()
{
// Initialize serial ports
Serial.begin(115200 );
Serial.println("Monitor example for TWELITE SPOT: App_Twelite" );
Serial2.begin(115200 , SERIAL_8N1, RX1_PIN, TX1_PIN);
// Initialize TWELITE
Twelite.begin(Serial2,
LED_PIN, RST_PIN, PRG_PIN,
TWE_CHANNEL, TWE_APP_ID);
// Attach an event handler to process packets from App_Twelite
Twelite.on([](const ParsedAppTwelitePacket& packet) {
Serial.println("" );
Serial.print("Packet Timestamp: " );
Serial.print(packet.u16SequenceNumber / 64.0f , 1 ); Serial.println(" sec" );
Serial.print("Source Logical ID: 0x" );
Serial.println(packet.u8SourceLogicalId, HEX);
Serial.print("LQI: " );
Serial.println(packet.u8Lqi, DEC);
Serial.print("Supply Voltage: " );
Serial.print(packet.u16SupplyVoltage, DEC); Serial.println(" mV" );
Serial.print("Digital Input: " );
Serial.print(packet.bDiState[0 ] ? " DI1:Lo" : " DI1:Hi" );
Serial.print(packet.bDiState[1 ] ? " DI2:Lo" : " DI2:Hi" );
Serial.print(packet.bDiState[2 ] ? " DI3:Lo" : " DI3:Hi" );
Serial.println(packet.bDiState[3 ] ? " DI4:Lo" : " DI4:Hi" );
Serial.print("Analog Input: " );
Serial.print(" AI1:" ); Serial.print(packet.u16AiVoltage[0 ]); Serial.print(" mV" );
Serial.print(" AI2:" ); Serial.print(packet.u16AiVoltage[1 ]); Serial.print(" mV" );
Serial.print(" AI3:" ); Serial.print(packet.u16AiVoltage[2 ]); Serial.print(" mV" );
Serial.print(" AI4:" ); Serial.print(packet.u16AiVoltage[3 ]); Serial.println(" mV" );
command.u8DestinationLogicalId = packet.u8SourceLogicalId; // LID
command.bDiState[0 ] = (packet.u8Lqi >= 100 ) ? true : false; // DI1
Twelite.send(command);
});
}
void loop ()
{
// Update TWELITE
Twelite.update();
}
動作確認 子機の TWELITE DIP の DO1 ピンと VCC ピンの間に LED と電流制限抵抗を接続してください。
改変したスケッチを書き込むと、TWELITE DIP が TWELITE SPOT に近づいた際(=通信品質がよいとき)に LED が点灯します。
TWELITE SPOT から子機を操作することができました!
2.5.1.1.2 - 超簡単!標準アプリのデータを取得・操作 v1.0.1
超簡単!標準アプリ (App_Twelite) のデータを取得・表示するサンプルスケッチ
monitor_spot_app_twelite
の解説です。最後に、相手先の出力ポートを操作する改変を行います。
サンプルスケッチの保存場所 MWings ライブラリを導入 していれば、Arduino IDE の ファイル -> スケッチ例 -> MWings -> monitor_spot_app_twelite からスケッチを開くことができます。
保存場所
スケッチ 以下はソースコード本体です。
// Monitor example for TWELITE SPOT: Receive data from App_Twelite
#include <Arduino.h>
#include "MWings.h"
const int RST_PIN = 5 ;
const int PRG_PIN = 4 ;
const int LED_PIN = 18 ;
const uint8_t TWE_CHANNEL = 18 ;
const uint32_t TWE_APP_ID = 0x67720102 ;
void setup ()
{
// Initialize serial ports
Serial.begin(115200 );
Serial.println("Monitor example for TWELITE SPOT: App_Twelite" );
Serial2.begin(115200 , SERIAL_8N1);
// Initialize TWELITE
Twelite.begin(Serial2,
LED_PIN, RST_PIN, PRG_PIN,
TWE_CHANNEL, TWE_APP_ID);
// Attach an event handler to process packets from App_Twelite
Twelite.on([](const ParsedAppTwelitePacket& packet) {
Serial.println("" );
Serial.print("Packet Timestamp: " );
Serial.print(packet.u16SequenceNumber / 64.0f , 1 ); Serial.println(" sec" );
Serial.print("Source Logical ID: 0x" );
Serial.println(packet.u8SourceLogicalId, HEX);
Serial.print("LQI: " );
Serial.println(packet.u8Lqi, DEC);
Serial.print("Supply Voltage: " );
Serial.print(packet.u16SupplyVoltage, DEC); Serial.println(" mV" );
Serial.print("Digital Input: " );
Serial.print(packet.bDiState[0 ] ? " DI1:Lo" : " DI1:Hi" );
Serial.print(packet.bDiState[1 ] ? " DI2:Lo" : " DI2:Hi" );
Serial.print(packet.bDiState[2 ] ? " DI3:Lo" : " DI3:Hi" );
Serial.println(packet.bDiState[3 ] ? " DI4:Lo" : " DI4:Hi" );
Serial.print("Analog Input: " );
Serial.print(" AI1:" ); Serial.print(packet.u16AiVoltage[0 ]); Serial.print(" mV" );
Serial.print(" AI2:" ); Serial.print(packet.u16AiVoltage[1 ]); Serial.print(" mV" );
Serial.print(" AI3:" ); Serial.print(packet.u16AiVoltage[2 ]); Serial.print(" mV" );
Serial.print(" AI4:" ); Serial.print(packet.u16AiVoltage[3 ]); Serial.println(" mV" );
});
}
void loop ()
{
// Update TWELITE
Twelite.update();
}
ライブラリのインクルード 4行目では、MWings ライブラリ をインクルードしています。
ピン番号の定義 6-8行目では、ピン番号を定義しています。
const int RST_PIN = 5 ;
const int PRG_PIN = 4 ;
const int LED_PIN = 18 ;
名称 内容 RST_PIN
TWELITE の RST ピンが接続されているピンの番号 PRG_PIN
TWELITE の PRG ピンが接続されているピンの番号 LED_PIN
基板上の ESP32 用 LED が接続されているピンの番号
TWELITE 設定の定義 10-11行目では、TWELITE SPOT に搭載された TWELITE 親機に適用する設定を定義しています。
const uint8_t TWE_CHANNEL = 18 ;
const uint32_t TWE_APP_ID = 0x67720102 ;
名称 内容 TWE_CHANNEL
TWELITE の 周波数チャネル TWE_APP_ID
TWELITE の アプリケーション ID
スケッチ中の値は、超簡単!標準アプリの初期値です。
シリアルポートの設定 16-18行目では、使用するシリアルポートを初期化するとともに、シリアルモニタへ起動メッセージを出力しています。
Serial.begin(115200 );
Serial.println("Monitor example for TWELITE SPOT: App_Twelite" );
Serial2.begin(115200 , SERIAL_8N1);
Serial
は、Arduino IDE の シリアルモニタとの通信に使います。シリアルモニタの設定に合わせて、ボーレートを 115200
bps としています。
一方、Serial2
は、TWELITE SPOT に搭載された TWELITE 親機との通信に使います。こちらも TWELITE 親機の初期設定に合わせて、ボーレートを 115200
bps としています。
TWELITE の設定 21-23行目では、Twelite.begin()
を呼び出し、TWELITE SPOT に搭載された TWELITE 親機の設定と起動を行っています。
Twelite.begin(Serial2,
LED_PIN, RST_PIN, PRG_PIN,
TWE_CHANNEL, TWE_APP_ID);
パケット受信時のイベントの登録 26-46行目では、Twelite.on()
を呼び出し、送られたデータに対して行う処理を登録しています。
ここでは、受信したパケットの内容をシリアルモニタに出力しています。
Twelite.on([](const ParsedAppTwelitePacket& packet) {
Serial.println("" );
Serial.print("Packet Timestamp: " );
Serial.print(packet.u16SequenceNumber / 64.0f , 1 ); Serial.println(" sec" );
Serial.print("Source Logical ID: 0x" );
Serial.println(packet.u8SourceLogicalId, HEX);
Serial.print("LQI: " );
Serial.println(packet.u8Lqi, DEC);
Serial.print("Supply Voltage: " );
Serial.print(packet.u16SupplyVoltage, DEC); Serial.println(" mV" );
Serial.print("Digital Input: " );
Serial.print(packet.bDiState[0 ] ? " DI1:Lo" : " DI1:Hi" );
Serial.print(packet.bDiState[1 ] ? " DI2:Lo" : " DI2:Hi" );
Serial.print(packet.bDiState[2 ] ? " DI3:Lo" : " DI3:Hi" );
Serial.println(packet.bDiState[3 ] ? " DI4:Lo" : " DI4:Hi" );
Serial.print("Analog Input: " );
Serial.print(" AI1:" ); Serial.print(packet.u16AiVoltage[0 ]); Serial.print(" mV" );
Serial.print(" AI2:" ); Serial.print(packet.u16AiVoltage[1 ]); Serial.print(" mV" );
Serial.print(" AI3:" ); Serial.print(packet.u16AiVoltage[2 ]); Serial.print(" mV" );
Serial.print(" AI4:" ); Serial.print(packet.u16AiVoltage[3 ]); Serial.println(" mV" );
});
上記のイベントは、超簡単!標準アプリからのパケットを受信したときにだけ呼び出されます。
受信したパケットの内容は ParsedAppTwelitePacket
型の引数 packet
に格納されています。
メッセージの内容 メッセージ 内容 Packet Timestamp
パケットのタイムスタンプ Source Logical ID
送信元 TWELITE の論理デバイスID LQI
無線通信品質(0~255) Supply Voltage
電源電圧 (mV) Digital Input
デジタル入力の状態 Analog Input
アナログ入力の状態
TWELITE のデータの更新 52行目では、Twelite.update()
を呼び出しています。
相手先の出力ポートの操作 超簡単!標準アプリの入力ポートの状態を取得するだけでなく、超簡単!標準アプリの出力ポートを操作してみましょう。
ここでは、TWELITE SPOT が受信した際の LQI(無線通信品質)に基づき、相手端末が TWELITE SPOT に近づいた際に、相手端末のデジタル出力ポートを点灯させてみます。
スケッチの改変 改変内容 はじめに、13行目へ下記のコードを追加します。
AppTweliteCommand command;
上記のコードでは、送信するコマンドの内容を格納する AppTweliteCommand
を作成しています。
次に、49-51行目へ下記のコードを追加します。
command.u8DestinationLogicalId = packet.u8SourceLogicalId; // LID
command.bDiState[0 ] = (packet.u8Lqi >= 100 ) ? true : false; // DI1
Twelite.send(command);
上記のコードでは、AppTweliteCommand
を操作し、Twelite.send()
でコマンドを送信しています。
これでスケッチの改変は終了です。改変後のコードを示します。
// Monitor example for TWELITE SPOT: Receive data from and send data to App_Twelite
#include <Arduino.h>
#include "MWings.h"
const int RST_PIN = 5 ;
const int PRG_PIN = 4 ;
const int LED_PIN = 18 ;
const uint8_t TWE_CHANNEL = 18 ;
const uint32_t TWE_APP_ID = 0x67720102 ;
AppTweliteCommand command;
void setup ()
{
// Initialize serial ports
Serial.begin(115200 );
Serial.println("Monitor example for TWELITE SPOT: App_Twelite" );
Serial2.begin(115200 , SERIAL_8N1);
// Initialize TWELITE
Twelite.begin(Serial2,
LED_PIN, RST_PIN, PRG_PIN,
TWE_CHANNEL, TWE_APP_ID);
// Attach an event handler to process packets from App_Twelite
Twelite.on([](const ParsedAppTwelitePacket& packet) {
Serial.println("" );
Serial.print("Packet Timestamp: " );
Serial.print(packet.u16SequenceNumber / 64.0f , 1 ); Serial.println(" sec" );
Serial.print("Source Logical ID: 0x" );
Serial.println(packet.u8SourceLogicalId, HEX);
Serial.print("LQI: " );
Serial.println(packet.u8Lqi, DEC);
Serial.print("Supply Voltage: " );
Serial.print(packet.u16SupplyVoltage, DEC); Serial.println(" mV" );
Serial.print("Digital Input: " );
Serial.print(packet.bDiState[0 ] ? " DI1:Lo" : " DI1:Hi" );
Serial.print(packet.bDiState[1 ] ? " DI2:Lo" : " DI2:Hi" );
Serial.print(packet.bDiState[2 ] ? " DI3:Lo" : " DI3:Hi" );
Serial.println(packet.bDiState[3 ] ? " DI4:Lo" : " DI4:Hi" );
Serial.print("Analog Input: " );
Serial.print(" AI1:" ); Serial.print(packet.u16AiVoltage[0 ]); Serial.print(" mV" );
Serial.print(" AI2:" ); Serial.print(packet.u16AiVoltage[1 ]); Serial.print(" mV" );
Serial.print(" AI3:" ); Serial.print(packet.u16AiVoltage[2 ]); Serial.print(" mV" );
Serial.print(" AI4:" ); Serial.print(packet.u16AiVoltage[3 ]); Serial.println(" mV" );
command.u8DestinationLogicalId = packet.u8SourceLogicalId; // LID
command.bDiState[0 ] = (packet.u8Lqi >= 100 ) ? true : false; // DI1
Twelite.send(command);
});
}
void loop ()
{
// Update TWELITE
Twelite.update();
}
動作確認 子機の TWELITE DIP の DO1 ピンと VCC ピンの間に LED と電流制限抵抗を接続してください。
改変したスケッチを書き込むと、TWELITE DIP が TWELITE SPOT に近づいた際(=通信品質がよいとき)に LED が点灯します。
TWELITE SPOT から子機を操作することができました!
2.5.1.1.3 - 超簡単!標準アプリのデータを取得・操作 v1.3.1
超簡単!標準アプリ (App_Twelite) のデータを取得・表示するサンプルスケッチ
monitor_spot_app_twelite
の解説です。最後に、相手先の出力ポートを操作する改変を行います。
サンプルスケッチの保存場所 MWings ライブラリを導入 していれば、Arduino IDE の ファイル -> スケッチ例 -> MWings -> TWELITE SPOT -> Receive -> monitor_spot_app_twelite からスケッチを開くことができます。
保存場所の表示例
スケッチ 以下はソースコード本体です。
// Monitor example for TWELITE SPOT: Receive data from App_Twelite
#include <Arduino.h>
#include "MWings.h"
const int RST_PIN = 5 ;
const int PRG_PIN = 4 ;
const int LED_PIN = 18 ;
const uint8_t TWE_CHANNEL = 18 ;
const uint32_t TWE_APP_ID = 0x67720102 ;
void setup ()
{
// Initialize serial ports
Serial.begin(115200 );
Serial.println("Monitor example for TWELITE SPOT: App_Twelite" );
Serial2.begin(115200 , SERIAL_8N1);
// Initialize TWELITE
Twelite.begin(Serial2,
LED_PIN, RST_PIN, PRG_PIN,
TWE_CHANNEL, TWE_APP_ID);
// Attach an event handler to process packets from App_Twelite
Twelite.on([](const ParsedAppTwelitePacket& packet) {
Serial.println("" );
Serial.print("Packet Timestamp: " );
Serial.print(packet.u16SequenceNumber / 64.0f , 1 ); Serial.println(" sec" );
Serial.print("Source Logical ID: 0x" );
Serial.println(packet.u8SourceLogicalId, HEX);
Serial.print("LQI: " );
Serial.println(packet.u8Lqi, DEC);
Serial.print("Supply Voltage: " );
Serial.print(packet.u16SupplyVoltage, DEC); Serial.println(" mV" );
Serial.print("Digital Input: " );
Serial.print(packet.bDiState[0 ] ? " DI1:Lo" : " DI1:Hi" );
Serial.print(packet.bDiState[1 ] ? " DI2:Lo" : " DI2:Hi" );
Serial.print(packet.bDiState[2 ] ? " DI3:Lo" : " DI3:Hi" );
Serial.println(packet.bDiState[3 ] ? " DI4:Lo" : " DI4:Hi" );
Serial.print("Analog Input: " );
Serial.print(" AI1:" ); Serial.print(packet.u16AiVoltage[0 ]); Serial.print(" mV" );
Serial.print(" AI2:" ); Serial.print(packet.u16AiVoltage[1 ]); Serial.print(" mV" );
Serial.print(" AI3:" ); Serial.print(packet.u16AiVoltage[2 ]); Serial.print(" mV" );
Serial.print(" AI4:" ); Serial.print(packet.u16AiVoltage[3 ]); Serial.println(" mV" );
});
}
void loop ()
{
// Update TWELITE
Twelite.update();
}
ライブラリのインクルード 4行目では、MWings ライブラリ をインクルードしています。
ピン番号の定義 6-8行目では、ピン番号を定義しています。
const int RST_PIN = 5 ;
const int PRG_PIN = 4 ;
const int LED_PIN = 18 ;
名称 内容 RST_PIN
TWELITE の RST ピンが接続されているピンの番号 PRG_PIN
TWELITE の PRG ピンが接続されているピンの番号 LED_PIN
基板上の ESP32 用 LED が接続されているピンの番号
TWELITE 設定の定義 10-11行目では、TWELITE SPOT に搭載された TWELITE 親機に適用する設定を定義しています。
const uint8_t TWE_CHANNEL = 18 ;
const uint32_t TWE_APP_ID = 0x67720102 ;
名称 内容 TWE_CHANNEL
TWELITE の 周波数チャネル TWE_APP_ID
TWELITE の アプリケーション ID
スケッチ中の値は、超簡単!標準アプリの初期値です。
シリアルポートの設定 16-18行目では、使用するシリアルポートを初期化するとともに、シリアルモニタへ起動メッセージを出力しています。
Serial.begin(115200 );
Serial.println("Monitor example for TWELITE SPOT: App_Twelite" );
Serial2.begin(115200 , SERIAL_8N1);
Serial
は、Arduino IDE の シリアルモニタとの通信に使います。シリアルモニタの設定に合わせて、ボーレートを 115200
bps としています。
一方、Serial2
は、TWELITE SPOT に搭載された TWELITE 親機との通信に使います。こちらも TWELITE 親機の初期設定に合わせて、ボーレートを 115200
bps としています。
TWELITE の設定 21-23行目では、Twelite.begin()
を呼び出し、TWELITE SPOT に搭載された TWELITE 親機の設定と起動を行っています。
Twelite.begin(Serial2,
LED_PIN, RST_PIN, PRG_PIN,
TWE_CHANNEL, TWE_APP_ID);
パケット受信時のイベントの登録 26-46行目では、Twelite.on()
を呼び出し、送られたデータに対して行う処理を登録しています。
ここでは、受信したパケットの内容をシリアルモニタに出力しています。
Twelite.on([](const ParsedAppTwelitePacket& packet) {
Serial.println("" );
Serial.print("Packet Timestamp: " );
Serial.print(packet.u16SequenceNumber / 64.0f , 1 ); Serial.println(" sec" );
Serial.print("Source Logical ID: 0x" );
Serial.println(packet.u8SourceLogicalId, HEX);
Serial.print("LQI: " );
Serial.println(packet.u8Lqi, DEC);
Serial.print("Supply Voltage: " );
Serial.print(packet.u16SupplyVoltage, DEC); Serial.println(" mV" );
Serial.print("Digital Input: " );
Serial.print(packet.bDiState[0 ] ? " DI1:Lo" : " DI1:Hi" );
Serial.print(packet.bDiState[1 ] ? " DI2:Lo" : " DI2:Hi" );
Serial.print(packet.bDiState[2 ] ? " DI3:Lo" : " DI3:Hi" );
Serial.println(packet.bDiState[3 ] ? " DI4:Lo" : " DI4:Hi" );
Serial.print("Analog Input: " );
Serial.print(" AI1:" ); Serial.print(packet.u16AiVoltage[0 ]); Serial.print(" mV" );
Serial.print(" AI2:" ); Serial.print(packet.u16AiVoltage[1 ]); Serial.print(" mV" );
Serial.print(" AI3:" ); Serial.print(packet.u16AiVoltage[2 ]); Serial.print(" mV" );
Serial.print(" AI4:" ); Serial.print(packet.u16AiVoltage[3 ]); Serial.println(" mV" );
});
上記のイベントは、超簡単!標準アプリからのパケットを受信したときにだけ呼び出されます。
受信したパケットの内容は ParsedAppTwelitePacket
型の引数 packet
に格納されています。
メッセージの内容 メッセージ 内容 Packet Timestamp
パケットのタイムスタンプ Source Logical ID
送信元 TWELITE の論理デバイスID LQI
無線通信品質(0~255) Supply Voltage
電源電圧 (mV) Digital Input
デジタル入力の状態 Analog Input
アナログ入力の状態
TWELITE のデータの更新 52行目では、Twelite.update()
を呼び出しています。
相手先の出力ポートの操作 超簡単!標準アプリの入力ポートの状態を取得するだけでなく、超簡単!標準アプリの出力ポートを操作してみましょう。
ここでは、TWELITE SPOT が受信した際の LQI(無線通信品質)に基づき、相手端末が TWELITE SPOT に近づいた際に、相手端末のデジタル出力ポートを点灯させてみます。
スケッチの改変 改変内容 はじめに、13行目へ下記のコードを追加します。
AppTweliteCommand command;
上記のコードでは、送信するコマンドの内容を格納する AppTweliteCommand
を作成しています。
次に、49-51行目へ下記のコードを追加します。
command.u8DestinationLogicalId = packet.u8SourceLogicalId; // LID
command.bDiState[0 ] = (packet.u8Lqi >= 100 ) ? true : false; // DI1
Twelite.send(command);
上記のコードでは、AppTweliteCommand
を操作し、Twelite.send()
でコマンドを送信しています。
これでスケッチの改変は終了です。改変後のコードを示します。
// Monitor example for TWELITE SPOT: Receive data from and send data to App_Twelite
#include <Arduino.h>
#include "MWings.h"
const int RST_PIN = 5 ;
const int PRG_PIN = 4 ;
const int LED_PIN = 18 ;
const uint8_t TWE_CHANNEL = 18 ;
const uint32_t TWE_APP_ID = 0x67720102 ;
AppTweliteCommand command;
void setup ()
{
// Initialize serial ports
Serial.begin(115200 );
Serial.println("Monitor example for TWELITE SPOT: App_Twelite" );
Serial2.begin(115200 , SERIAL_8N1);
// Initialize TWELITE
Twelite.begin(Serial2,
LED_PIN, RST_PIN, PRG_PIN,
TWE_CHANNEL, TWE_APP_ID);
// Attach an event handler to process packets from App_Twelite
Twelite.on([](const ParsedAppTwelitePacket& packet) {
Serial.println("" );
Serial.print("Packet Timestamp: " );
Serial.print(packet.u16SequenceNumber / 64.0f , 1 ); Serial.println(" sec" );
Serial.print("Source Logical ID: 0x" );
Serial.println(packet.u8SourceLogicalId, HEX);
Serial.print("LQI: " );
Serial.println(packet.u8Lqi, DEC);
Serial.print("Supply Voltage: " );
Serial.print(packet.u16SupplyVoltage, DEC); Serial.println(" mV" );
Serial.print("Digital Input: " );
Serial.print(packet.bDiState[0 ] ? " DI1:Lo" : " DI1:Hi" );
Serial.print(packet.bDiState[1 ] ? " DI2:Lo" : " DI2:Hi" );
Serial.print(packet.bDiState[2 ] ? " DI3:Lo" : " DI3:Hi" );
Serial.println(packet.bDiState[3 ] ? " DI4:Lo" : " DI4:Hi" );
Serial.print("Analog Input: " );
Serial.print(" AI1:" ); Serial.print(packet.u16AiVoltage[0 ]); Serial.print(" mV" );
Serial.print(" AI2:" ); Serial.print(packet.u16AiVoltage[1 ]); Serial.print(" mV" );
Serial.print(" AI3:" ); Serial.print(packet.u16AiVoltage[2 ]); Serial.print(" mV" );
Serial.print(" AI4:" ); Serial.print(packet.u16AiVoltage[3 ]); Serial.println(" mV" );
command.u8DestinationLogicalId = packet.u8SourceLogicalId; // LID
command.bDiState[0 ] = (packet.u8Lqi >= 100 ) ? true : false; // DI1
Twelite.send(command);
});
}
void loop ()
{
// Update TWELITE
Twelite.update();
}
動作確認 子機の TWELITE DIP の DO1 ピンと VCC ピンの間に LED と電流制限抵抗を接続してください。
改変したスケッチを書き込むと、TWELITE DIP が TWELITE SPOT に近づいた際(=通信品質がよいとき)に LED が点灯します。
TWELITE SPOT から子機を操作することができました!
2.5.1.2 - キューアプリのデータを取得 キューアプリのデータを取得・表示するサンプルスケッチ monitor_spot_app_cue
の解説
キューアプリ (App_CUE) のデータを取得・表示するサンプルスケッチ
monitor_spot_app_cue
の解説です。
2.5.1.2.1 - キューアプリのデータを取得 最新版
キューアプリ (App_CUE) のデータを取得・表示するサンプルスケッチ
monitor_spot_app_cue
の解説です。
サンプルスケッチの保存場所 MWings ライブラリを導入 していれば、Arduino IDE の ファイル -> スケッチ例 -> MWings -> TWELITE SPOT -> Receive -> monitor_spot_app_cue からスケッチを開くことができます。
保存場所の表示例
スケッチ 以下はソースコード本体です。
// Monitor example for TWELITE SPOT: Receive data from App_CUE (CUE Mode)
#include <Arduino.h>
#include "MWings.h"
const int RST_PIN = 5 ;
const int PRG_PIN = 4 ;
const int LED_PIN = 18 ;
const int8_t RX1_PIN = 16 ;
const int8_t TX1_PIN = 17 ;
const uint8_t TWE_CHANNEL = 18 ;
const uint32_t TWE_APP_ID = 0x67720102 ;
void printAccelEvent (const uint8_t event);
void printMagnetState (const uint8_t state, const bool changed);
void setup ()
{
// Initialize serial ports
Serial.begin(115200 );
Serial.println("Monitor example for TWELITE SPOT: App_CUE (CUE Mode)" );
Serial2.begin(115200 , SERIAL_8N1, RX1_PIN, TX1_PIN);
// Initialize TWELITE
Twelite.begin(Serial2,
LED_PIN, RST_PIN, PRG_PIN,
TWE_CHANNEL, TWE_APP_ID);
// Attach an event handler to process packets from App_CUE
Twelite.on([](const ParsedAppCuePacket& packet) {
Serial.println("" );
Serial.print("Packet Number: #" );
Serial.println(packet.u16SequenceNumber, DEC);
Serial.print("Source Logical ID: 0x" );
Serial.println(packet.u8SourceLogicalId, HEX);
Serial.print("LQI: " );
Serial.println(packet.u8Lqi, DEC);
Serial.print("Supply Voltage: " );
Serial.print(packet.u16SupplyVoltage, DEC); Serial.println(" mV" );
Serial.print("Accel Event: " );
printAccelEvent(packet.u8AccelEvent);
Serial.print("Accel X Axis [0]: " );
Serial.print(packet.i16SamplesX[0 ], DEC); Serial.println(" mG" );
Serial.print("Accel Y Axis [0]: " );
Serial.print(packet.i16SamplesY[0 ], DEC); Serial.println(" mG" );
Serial.print("Accel Z Axis [0]: " );
Serial.print(packet.i16SamplesZ[0 ], DEC); Serial.println(" mG" );
Serial.print("Magnet State: " );
printMagnetState(packet.u8MagnetState, packet.bMagnetStateChanged);
});
}
void loop ()
{
// Update TWELITE
Twelite.update();
}
void printAccelEvent (const uint8_t event)
{
switch (event) {
case 0x01 : { Serial.print("Dice (1)" ); break ; }
case 0x02 : { Serial.print("Dice (2)" ); break ; }
case 0x03 : { Serial.print("Dice (3)" ); break ; }
case 0x04 : { Serial.print("Dice (4)" ); break ; }
case 0x05 : { Serial.print("Dice (5)" ); break ; }
case 0x06 : { Serial.print("Dice (6)" ); break ; }
case 0x08 : { Serial.print("Shake" ); break ; }
case 0x10 : { Serial.print("Move" ); break ; }
default : break ;
}
Serial.println("" );
}
void printMagnetState (const uint8_t state, const bool changed)
{
if (changed) {
switch (state) {
case 0x0 : { Serial.print("Leaving or Not found" ); break ; }
case 0x1 : { Serial.print("N-pole is getting closer" ); break ; }
case 0x2 : { Serial.print("S-pole is getting closer" ); break ; }
default : break ;
}
} else {
switch (state) {
case 0x0 : { Serial.print("Not found" ); break ; }
case 0x1 : { Serial.print("N-pole is close" ); break ; }
case 0x2 : { Serial.print("S-pole is close" ); break ; }
default : break ;
}
Serial.print(" (Periodic packet)" );
}
Serial.println("" );
}
ライブラリのインクルード 4行目では、MWings ライブラリ をインクルードしています。
ピン番号の定義 6-11行目では、ピン番号を定義しています。
const int RST_PIN = 5 ;
const int PRG_PIN = 4 ;
const int LED_PIN = 18 ;
const int8_t RX1_PIN = 16 ;
const int8_t TX1_PIN = 17 ;
名称 内容 RST_PIN
TWELITE の RST ピンが接続されているピンの番号 PRG_PIN
TWELITE の PRG ピンが接続されているピンの番号 LED_PIN
基板上の ESP32 用 LED が接続されているピンの番号 RX1_PIN
TWELITE の RX1 ピンが接続されているピンの番号 TX1_PIN
TWELITE の TX1 ピンが接続されているピンの番号
TWELITE 設定の定義 13-14行目では、TWELITE SPOT に搭載された TWELITE 親機に適用する設定を定義しています。
const uint8_t TWE_CHANNEL = 18 ;
const uint32_t TWE_APP_ID = 0x67720102 ;
名称 内容 TWE_CHANNEL
TWELITE の 周波数チャネル TWE_APP_ID
TWELITE の アプリケーション ID
シリアルポートの設定 22-24行目では、使用するシリアルポートを初期化するとともに、シリアルモニタへ起動メッセージを出力しています。
Serial.begin(115200 );
Serial.println("Monitor example for TWELITE SPOT: App_CUE (CUE Mode)" );
Serial2.begin(115200 );
Serial
は、Arduino IDE の シリアルモニタとの通信に使います。シリアルモニタの設定に合わせて、ボーレートを 115200
bps としています。
一方、Serial2
は、TWELITE SPOT に搭載された TWELITE 親機との通信に使います。こちらも TWELITE 親機の初期設定に合わせて、ボーレートを 115200
bps としています。
TWELITE の設定 27-29行目では、Twelite.begin()
を呼び出し、TWELITE SPOT に搭載された TWELITE 親機の設定と起動を行っています。
Twelite.begin(Serial2,
LED_PIN, RST_PIN, PRG_PIN,
TWE_CHANNEL, TWE_APP_ID);
パケット受信時のイベントの登録 32-52行目では、Twelite.on()
を呼び出し、送られたデータに対して行う処理を登録しています。
ここでは、受信したパケットの内容をシリアルモニタに出力しています。
Twelite.on([](const ParsedAppCuePacket& packet) {
Serial.println("" );
Serial.print("Packet Number: #" );
Serial.println(packet.u16SequenceNumber, DEC);
Serial.print("Source Logical ID: 0x" );
Serial.println(packet.u8SourceLogicalId, HEX);
Serial.print("LQI: " );
Serial.println(packet.u8Lqi, DEC);
Serial.print("Supply Voltage: " );
Serial.print(packet.u16SupplyVoltage, DEC); Serial.println(" mV" );
Serial.print("Accel Event: " );
printAccelEvent(packet.u8AccelEvent);
Serial.print("Accel X Axis [0]: " );
Serial.print(packet.i16SamplesX[0 ], DEC); Serial.println(" mG" );
Serial.print("Accel Y Axis [0]: " );
Serial.print(packet.i16SamplesY[0 ], DEC); Serial.println(" mG" );
Serial.print("Accel Z Axis [0]: " );
Serial.print(packet.i16SamplesZ[0 ], DEC); Serial.println(" mG" );
Serial.print("Magnet State: " );
printMagnetState(packet.u8MagnetState, packet.bMagnetStateChanged);
});
上記のイベントは、キューアプリ(TWELITE CUE モード)からのパケットを受信したときにだけ呼び出されます。
受信したパケットの内容は ParsedAppCuePacket
型の引数 packet
に格納されています。
メッセージの内容 メッセージ 内容 Packet Number
パケットの続き番号 Source Logical ID
送信元 TWELITE の論理デバイスID LQI
無線通信品質(0~255) Supply Voltage
電源電圧 (mV) Accel Event
加速度センサーの状態 Accel X Axis
X 軸加速度(1サンプル目) Accel Y Axis
Y 軸加速度(1サンプル目) Accel Z Axis
Z 軸加速度(1サンプル目) Magnet State
磁気センサーの状態
加速度センサーの状態 出力される加速度センサーの状態は以下の通りです。
Dice (1)
- Dice (6)
サイコロの目(姿勢)を検知した。Shake
揺さぶるような動きを検知した。Move
ゆっくりとした動きを検知した。磁気センサーの状態 出力される磁気センサーの状態は以下の通りです。
S-pole is getting closer
新たに磁石のS極を検知した。N-pole is getting closer
新たに磁石のN極を検知した。Leaving or Not found
磁石が検知できなかった。S-pole is close (Periodic packet)
磁石のS極を検知している。N-pole is close (Periodic packet)
磁石のN極を検知している。Not found (Periodic packet)
磁石を連続で検知できていない(定期送信パケット)。TWELITE のデータの更新 58行目では、Twelite.update()
を呼び出しています。
2.5.1.2.2 - キューアプリのデータを取得 v1.0.1
キューアプリ (App_CUE) のデータを取得・表示するサンプルスケッチ
monitor_spot_app_cue
の解説です。
サンプルスケッチの保存場所 MWings ライブラリを導入 していれば、Arduino IDE の ファイル -> スケッチ例 -> MWings -> monitor_spot_app_cue からスケッチを開くことができます。
保存場所
スケッチ 以下はソースコード本体です。
// Monitor example for TWELITE SPOT: Receive data from App_CUE (CUE Mode)
#include <Arduino.h>
#include "MWings.h"
const int RST_PIN = 5 ;
const int PRG_PIN = 4 ;
const int LED_PIN = 18 ;
const uint8_t TWE_CHANNEL = 18 ;
const uint32_t TWE_APP_ID = 0x67720102 ;
void printAccelEvent (const uint8_t event);
void printMagnetState (const uint8_t state, const bool changed);
void setup ()
{
// Initialize serial ports
Serial.begin(115200 );
Serial.println("Monitor example for TWELITE SPOT: App_CUE (CUE Mode)" );
Serial2.begin(115200 );
// Initialize TWELITE
Twelite.begin(Serial2,
LED_PIN, RST_PIN, PRG_PIN,
TWE_CHANNEL, TWE_APP_ID);
// Attach an event handler to process packets from App_CUE
Twelite.on([](const ParsedAppCuePacket& packet) {
Serial.println("" );
Serial.print("Packet Number: #" );
Serial.println(packet.u16SequenceNumber, DEC);
Serial.print("Source Logical ID: 0x" );
Serial.println(packet.u8SourceLogicalId, HEX);
Serial.print("LQI: " );
Serial.println(packet.u8Lqi, DEC);
Serial.print("Supply Voltage: " );
Serial.print(packet.u16SupplyVoltage, DEC); Serial.println(" mV" );
Serial.print("Accel Event: " );
printAccelEvent(packet.u8AccelEvent);
Serial.print("Accel X Axis [0]: " );
Serial.print(packet.i16SamplesX[0 ], DEC); Serial.println(" mG" );
Serial.print("Accel Y Axis [0]: " );
Serial.print(packet.i16SamplesY[0 ], DEC); Serial.println(" mG" );
Serial.print("Accel Z Axis [0]: " );
Serial.print(packet.i16SamplesZ[0 ], DEC); Serial.println(" mG" );
Serial.print("Magnet State: " );
printMagnetState(packet.u8MagnetState, packet.bMagnetStateChanged);
});
}
void loop ()
{
// Update TWELITE
Twelite.update();
}
void printAccelEvent (const uint8_t event)
{
switch (event) {
case 0x01 : { Serial.print("Dice (1)" ); break ; }
case 0x02 : { Serial.print("Dice (2)" ); break ; }
case 0x03 : { Serial.print("Dice (3)" ); break ; }
case 0x04 : { Serial.print("Dice (4)" ); break ; }
case 0x05 : { Serial.print("Dice (5)" ); break ; }
case 0x06 : { Serial.print("Dice (6)" ); break ; }
case 0x08 : { Serial.print("Shake" ); break ; }
case 0x10 : { Serial.print("Move" ); break ; }
default : break ;
}
Serial.println("" );
}
void printMagnetState (const uint8_t state, const bool changed)
{
if (changed) {
switch (state) {
case 0x0 : { Serial.print("Leaving or Not found" ); break ; }
case 0x1 : { Serial.print("N-pole is getting closer" ); break ; }
case 0x2 : { Serial.print("S-pole is getting closer" ); break ; }
default : break ;
}
} else {
switch (state) {
case 0x0 : { Serial.print("Not found" ); break ; }
case 0x1 : { Serial.print("N-pole is close" ); break ; }
case 0x2 : { Serial.print("S-pole is close" ); break ; }
default : break ;
}
Serial.print(" (Periodic packet)" );
}
Serial.println("" );
}
ライブラリのインクルード 4行目では、MWings ライブラリ をインクルードしています。
ピン番号の定義 6-8行目では、ピン番号を定義しています。
const int RST_PIN = 5 ;
const int PRG_PIN = 4 ;
const int LED_PIN = 18 ;
名称 内容 RST_PIN
TWELITE の RST ピンが接続されているピンの番号 PRG_PIN
TWELITE の PRG ピンが接続されているピンの番号 LED_PIN
基板上の ESP32 用 LED が接続されているピンの番号
TWELITE 設定の定義 10-11行目では、TWELITE SPOT に搭載された TWELITE 親機に適用する設定を定義しています。
const uint8_t TWE_CHANNEL = 18 ;
const uint32_t TWE_APP_ID = 0x67720102 ;
名称 内容 TWE_CHANNEL
TWELITE の 周波数チャネル TWE_APP_ID
TWELITE の アプリケーション ID
シリアルポートの設定 19-21行目では、使用するシリアルポートを初期化するとともに、シリアルモニタへ起動メッセージを出力しています。
Serial.begin(115200 );
Serial.println("Monitor example for TWELITE SPOT: App_CUE (CUE Mode)" );
Serial2.begin(115200 );
Serial
は、Arduino IDE の シリアルモニタとの通信に使います。シリアルモニタの設定に合わせて、ボーレートを 115200
bps としています。
一方、Serial2
は、TWELITE SPOT に搭載された TWELITE 親機との通信に使います。こちらも TWELITE 親機の初期設定に合わせて、ボーレートを 115200
bps としています。
TWELITE の設定 24-26行目では、Twelite.begin()
を呼び出し、TWELITE SPOT に搭載された TWELITE 親機の設定と起動を行っています。
Twelite.begin(Serial2,
LED_PIN, RST_PIN, PRG_PIN,
TWE_CHANNEL, TWE_APP_ID);
パケット受信時のイベントの登録 29-49行目では、Twelite.on()
を呼び出し、送られたデータに対して行う処理を登録しています。
ここでは、受信したパケットの内容をシリアルモニタに出力しています。
Twelite.on([](const ParsedAppCuePacket& packet) {
Serial.println("" );
Serial.print("Packet Number: #" );
Serial.println(packet.u16SequenceNumber, DEC);
Serial.print("Source Logical ID: 0x" );
Serial.println(packet.u8SourceLogicalId, HEX);
Serial.print("LQI: " );
Serial.println(packet.u8Lqi, DEC);
Serial.print("Supply Voltage: " );
Serial.print(packet.u16SupplyVoltage, DEC); Serial.println(" mV" );
Serial.print("Accel Event: " );
printAccelEvent(packet.u8AccelEvent);
Serial.print("Accel X Axis [0]: " );
Serial.print(packet.i16SamplesX[0 ], DEC); Serial.println(" mG" );
Serial.print("Accel Y Axis [0]: " );
Serial.print(packet.i16SamplesY[0 ], DEC); Serial.println(" mG" );
Serial.print("Accel Z Axis [0]: " );
Serial.print(packet.i16SamplesZ[0 ], DEC); Serial.println(" mG" );
Serial.print("Magnet State: " );
printMagnetState(packet.u8MagnetState, packet.bMagnetStateChanged);
});
上記のイベントは、キューアプリ(TWELITE CUE モード)からのパケットを受信したときにだけ呼び出されます。
受信したパケットの内容は ParsedAppCuePacket
型の引数 packet
に格納されています。
メッセージの内容 メッセージ 内容 Packet Number
パケットの続き番号 Source Logical ID
送信元 TWELITE の論理デバイスID LQI
無線通信品質(0~255) Supply Voltage
電源電圧 (mV) Accel Event
加速度センサーの状態 Accel X Axis
X 軸加速度(1サンプル目) Accel Y Axis
Y 軸加速度(1サンプル目) Accel Z Axis
Z 軸加速度(1サンプル目) Magnet State
磁気センサーの状態
加速度センサーの状態 出力される加速度センサーの状態は以下の通りです。
Dice (1)
- Dice (6)
サイコロの目(姿勢)を検知した。Shake
揺さぶるような動きを検知した。Move
ゆっくりとした動きを検知した。磁気センサーの状態 出力される磁気センサーの状態は以下の通りです。
S-pole is getting closer
新たに磁石のS極を検知した。N-pole is getting closer
新たに磁石のN極を検知した。Leaving or Not found
磁石が検知できなかった。S-pole is close (Periodic packet)
磁石のS極を検知している。N-pole is close (Periodic packet)
磁石のN極を検知している。Not found (Periodic packet)
磁石を連続で検知できていない(定期送信パケット)。TWELITE のデータの更新 55行目では、Twelite.update()
を呼び出しています。
2.5.1.2.3 - キューアプリのデータを取得 v1.1.3
キューアプリ (App_CUE) のデータを取得・表示するサンプルスケッチ
monitor_spot_app_cue
の解説です。
サンプルスケッチの保存場所 MWings ライブラリを導入 していれば、Arduino IDE の ファイル -> スケッチ例 -> MWings -> TWELITE SPOT -> Receive -> monitor_spot_app_cue からスケッチを開くことができます。
保存場所の表示例
スケッチ 以下はソースコード本体です。
// Monitor example for TWELITE SPOT: Receive data from App_CUE (CUE Mode)
#include <Arduino.h>
#include "MWings.h"
const int RST_PIN = 5 ;
const int PRG_PIN = 4 ;
const int LED_PIN = 18 ;
const uint8_t TWE_CHANNEL = 18 ;
const uint32_t TWE_APP_ID = 0x67720102 ;
void printAccelEvent (const uint8_t event);
void printMagnetState (const uint8_t state, const bool changed);
void setup ()
{
// Initialize serial ports
Serial.begin(115200 );
Serial.println("Monitor example for TWELITE SPOT: App_CUE (CUE Mode)" );
Serial2.begin(115200 );
// Initialize TWELITE
Twelite.begin(Serial2,
LED_PIN, RST_PIN, PRG_PIN,
TWE_CHANNEL, TWE_APP_ID);
// Attach an event handler to process packets from App_CUE
Twelite.on([](const ParsedAppCuePacket& packet) {
Serial.println("" );
Serial.print("Packet Number: #" );
Serial.println(packet.u16SequenceNumber, DEC);
Serial.print("Source Logical ID: 0x" );
Serial.println(packet.u8SourceLogicalId, HEX);
Serial.print("LQI: " );
Serial.println(packet.u8Lqi, DEC);
Serial.print("Supply Voltage: " );
Serial.print(packet.u16SupplyVoltage, DEC); Serial.println(" mV" );
Serial.print("Accel Event: " );
printAccelEvent(packet.u8AccelEvent);
Serial.print("Accel X Axis [0]: " );
Serial.print(packet.i16SamplesX[0 ], DEC); Serial.println(" mG" );
Serial.print("Accel Y Axis [0]: " );
Serial.print(packet.i16SamplesY[0 ], DEC); Serial.println(" mG" );
Serial.print("Accel Z Axis [0]: " );
Serial.print(packet.i16SamplesZ[0 ], DEC); Serial.println(" mG" );
Serial.print("Magnet State: " );
printMagnetState(packet.u8MagnetState, packet.bMagnetStateChanged);
});
}
void loop ()
{
// Update TWELITE
Twelite.update();
}
void printAccelEvent (const uint8_t event)
{
switch (event) {
case 0x01 : { Serial.print("Dice (1)" ); break ; }
case 0x02 : { Serial.print("Dice (2)" ); break ; }
case 0x03 : { Serial.print("Dice (3)" ); break ; }
case 0x04 : { Serial.print("Dice (4)" ); break ; }
case 0x05 : { Serial.print("Dice (5)" ); break ; }
case 0x06 : { Serial.print("Dice (6)" ); break ; }
case 0x08 : { Serial.print("Shake" ); break ; }
case 0x10 : { Serial.print("Move" ); break ; }
default : break ;
}
Serial.println("" );
}
void printMagnetState (const uint8_t state, const bool changed)
{
if (changed) {
switch (state) {
case 0x0 : { Serial.print("Leaving or Not found" ); break ; }
case 0x1 : { Serial.print("N-pole is getting closer" ); break ; }
case 0x2 : { Serial.print("S-pole is getting closer" ); break ; }
default : break ;
}
} else {
switch (state) {
case 0x0 : { Serial.print("Not found" ); break ; }
case 0x1 : { Serial.print("N-pole is close" ); break ; }
case 0x2 : { Serial.print("S-pole is close" ); break ; }
default : break ;
}
Serial.print(" (Periodic packet)" );
}
Serial.println("" );
}
ライブラリのインクルード 4行目では、MWings ライブラリ をインクルードしています。
ピン番号の定義 6-8行目では、ピン番号を定義しています。
const int RST_PIN = 5 ;
const int PRG_PIN = 4 ;
const int LED_PIN = 18 ;
名称 内容 RST_PIN
TWELITE の RST ピンが接続されているピンの番号 PRG_PIN
TWELITE の PRG ピンが接続されているピンの番号 LED_PIN
基板上の ESP32 用 LED が接続されているピンの番号
TWELITE 設定の定義 10-11行目では、TWELITE SPOT に搭載された TWELITE 親機に適用する設定を定義しています。
const uint8_t TWE_CHANNEL = 18 ;
const uint32_t TWE_APP_ID = 0x67720102 ;
名称 内容 TWE_CHANNEL
TWELITE の 周波数チャネル TWE_APP_ID
TWELITE の アプリケーション ID
シリアルポートの設定 19-21行目では、使用するシリアルポートを初期化するとともに、シリアルモニタへ起動メッセージを出力しています。
Serial.begin(115200 );
Serial.println("Monitor example for TWELITE SPOT: App_CUE (CUE Mode)" );
Serial2.begin(115200 );
Serial
は、Arduino IDE の シリアルモニタとの通信に使います。シリアルモニタの設定に合わせて、ボーレートを 115200
bps としています。
一方、Serial2
は、TWELITE SPOT に搭載された TWELITE 親機との通信に使います。こちらも TWELITE 親機の初期設定に合わせて、ボーレートを 115200
bps としています。
TWELITE の設定 24-26行目では、Twelite.begin()
を呼び出し、TWELITE SPOT に搭載された TWELITE 親機の設定と起動を行っています。
Twelite.begin(Serial2,
LED_PIN, RST_PIN, PRG_PIN,
TWE_CHANNEL, TWE_APP_ID);
パケット受信時のイベントの登録 29-49行目では、Twelite.on()
を呼び出し、送られたデータに対して行う処理を登録しています。
ここでは、受信したパケットの内容をシリアルモニタに出力しています。
Twelite.on([](const ParsedAppCuePacket& packet) {
Serial.println("" );
Serial.print("Packet Number: #" );
Serial.println(packet.u16SequenceNumber, DEC);
Serial.print("Source Logical ID: 0x" );
Serial.println(packet.u8SourceLogicalId, HEX);
Serial.print("LQI: " );
Serial.println(packet.u8Lqi, DEC);
Serial.print("Supply Voltage: " );
Serial.print(packet.u16SupplyVoltage, DEC); Serial.println(" mV" );
Serial.print("Accel Event: " );
printAccelEvent(packet.u8AccelEvent);
Serial.print("Accel X Axis [0]: " );
Serial.print(packet.i16SamplesX[0 ], DEC); Serial.println(" mG" );
Serial.print("Accel Y Axis [0]: " );
Serial.print(packet.i16SamplesY[0 ], DEC); Serial.println(" mG" );
Serial.print("Accel Z Axis [0]: " );
Serial.print(packet.i16SamplesZ[0 ], DEC); Serial.println(" mG" );
Serial.print("Magnet State: " );
printMagnetState(packet.u8MagnetState, packet.bMagnetStateChanged);
});
上記のイベントは、キューアプリ(TWELITE CUE モード)からのパケットを受信したときにだけ呼び出されます。
受信したパケットの内容は ParsedAppCuePacket
型の引数 packet
に格納されています。
メッセージの内容 メッセージ 内容 Packet Number
パケットの続き番号 Source Logical ID
送信元 TWELITE の論理デバイスID LQI
無線通信品質(0~255) Supply Voltage
電源電圧 (mV) Accel Event
加速度センサーの状態 Accel X Axis
X 軸加速度(1サンプル目) Accel Y Axis
Y 軸加速度(1サンプル目) Accel Z Axis
Z 軸加速度(1サンプル目) Magnet State
磁気センサーの状態
加速度センサーの状態 出力される加速度センサーの状態は以下の通りです。
Dice (1)
- Dice (6)
サイコロの目(姿勢)を検知した。Shake
揺さぶるような動きを検知した。Move
ゆっくりとした動きを検知した。磁気センサーの状態 出力される磁気センサーの状態は以下の通りです。
S-pole is getting closer
新たに磁石のS極を検知した。N-pole is getting closer
新たに磁石のN極を検知した。Leaving or Not found
磁石が検知できなかった。S-pole is close (Periodic packet)
磁石のS極を検知している。N-pole is close (Periodic packet)
磁石のN極を検知している。Not found (Periodic packet)
磁石を連続で検知できていない(定期送信パケット)。TWELITE のデータの更新 55行目では、Twelite.update()
を呼び出しています。
2.5.1.3 - アリアアプリのデータを取得 アリアアプリのデータを取得・表示するサンプルスケッチ monitor_spot_app_aria
の解説
アリアアプリ (App_ARIA) のデータを取得・表示するサンプルスケッチ
monitor_spot_app_aria
の解説です。
2.5.1.3.1 - アリアアプリのデータを取得 最新版
アリアアプリ (App_ARIA) のデータを取得・表示するサンプルスケッチ
monitor_spot_app_aria
の解説です。
サンプルスケッチの保存場所 MWings ライブラリを導入 していれば、Arduino IDE の ファイル -> スケッチ例 -> MWings -> TWELITE SPOT -> Receive -> monitor_spot_app_aria からスケッチを開くことができます。
保存場所の表示例
スケッチ 以下はソースコード本体です。
// Monitor example for TWELITE SPOT: Receive data from App_ARIA (ARIA Mode)
#include <Arduino.h>
#include "MWings.h"
const int RST_PIN = 5 ;
const int PRG_PIN = 4 ;
const int LED_PIN = 18 ;
const int8_t RX1_PIN = 16 ;
const int8_t TX1_PIN = 17 ;
const uint8_t TWE_CHANNEL = 18 ;
const uint32_t TWE_APP_ID = 0x67720102 ;
void printMagnetState (const uint8_t state, const bool changed);
void setup ()
{
// Initialize serial ports
Serial.begin(115200 );
Serial.println("Monitor example for TWELITE SPOT: App_ARIA (ARIA Mode)" );
Serial2.begin(115200 , SERIAL_8N1, RX1_PIN, TX1_PIN);
// Initialize TWELITE
Twelite.begin(Serial2,
LED_PIN, RST_PIN, PRG_PIN,
TWE_CHANNEL, TWE_APP_ID);
// Attach an event handler to process packets from App_ARIA
Twelite.on([](const ParsedAppAriaPacket& packet) {
Serial.println("" );
Serial.print("Packet Number: #" );
Serial.println(packet.u16SequenceNumber, DEC);
Serial.print("Source Logical ID: 0x" );
Serial.println(packet.u8SourceLogicalId, HEX);
Serial.print("LQI: " );
Serial.println(packet.u8Lqi, DEC);
Serial.print("Supply Voltage: " );
Serial.print(packet.u16SupplyVoltage, DEC); Serial.println(" mV" );
Serial.print("Air Temperature: " );
Serial.print(packet.i16Temp100x / 100.0f , 2 ); Serial.println(" C" );
Serial.print("Relative Humidity: " );
Serial.print(packet.u16Humid100x / 100.0f , 2 ); Serial.println(" %" );
Serial.print("Magnet State: " );
printMagnetState(packet.u8MagnetState, packet.bMagnetStateChanged);
});
}
void loop ()
{
// Update TWELITE
Twelite.update();
}
void printMagnetState (const uint8_t state, const bool changed)
{
if (changed) {
switch (state) {
case 0x0 : { Serial.print("Leaving or not found" ); break ; }
case 0x1 : { Serial.print("N-pole is getting closer" ); break ; }
case 0x2 : { Serial.print("S-pole is getting closer" ); break ; }
default : break ;
}
} else {
switch (state) {
case 0x0 : { Serial.print("Not found" ); break ; }
case 0x1 : { Serial.print("N-pole is close" ); break ; }
case 0x2 : { Serial.print("S-pole is close" ); break ; }
default : break ;
}
Serial.print(" (Periodic packet)" );
}
Serial.println("" );
}
ライブラリのインクルード 4行目では、MWings ライブラリ をインクルードしています。
ピン番号の定義 6-11行目では、ピン番号を定義しています。
const int RST_PIN = 5 ;
const int PRG_PIN = 4 ;
const int LED_PIN = 18 ;
const int8_t RX1_PIN = 16 ;
const int8_t TX1_PIN = 17 ;
名称 内容 RST_PIN
TWELITE の RST ピンが接続されているピンの番号 PRG_PIN
TWELITE の PRG ピンが接続されているピンの番号 LED_PIN
基板上の ESP32 用 LED が接続されているピンの番号 RX1_PIN
TWELITE の RX1 ピンが接続されているピンの番号 TX1_PIN
TWELITE の TX1 ピンが接続されているピンの番号
TWELITE 設定の定義 13-14行目では、TWELITE SPOT に搭載された TWELITE 親機に適用する設定を定義しています。
const uint8_t TWE_CHANNEL = 18 ;
const uint32_t TWE_APP_ID = 0x67720102 ;
名称 内容 TWE_CHANNEL
TWELITE の 周波数チャネル TWE_APP_ID
TWELITE の アプリケーション ID
シリアルポートの設定 21-23行目では、使用するシリアルポートを初期化するとともに、シリアルモニタへ起動メッセージを出力しています。
Serial.begin(115200 );
Serial.println("Monitor example for TWELITE SPOT: App_ARIA (ARIA Mode)" );
Serial2.begin(115200 , SERIAL_8N1, RX1_PIN, TX1_PIN);
Serial
は、Arduino IDE の シリアルモニタとの通信に使います。シリアルモニタの設定に合わせて、ボーレートを 115200
bps としています。
一方、Serial2
は、TWELITE SPOT に搭載された TWELITE 親機との通信に使います。こちらも TWELITE 親機の初期設定に合わせて、ボーレートを 115200
bps としています。
TWELITE の設定 26-28行目では、Twelite.begin()
を呼び出し、TWELITE SPOT に搭載された TWELITE 親機の設定と起動を行っています。
Twelite.begin(Serial2,
LED_PIN, RST_PIN, PRG_PIN,
TWE_CHANNEL, TWE_APP_ID);
パケット受信時のイベントの登録 31-47行目では、Twelite.on()
を呼び出し、送られたデータに対して行う処理を登録しています。
ここでは、受信したパケットの内容をシリアルモニタに出力しています。
Twelite.on([](const ParsedAppAriaPacket& packet) {
Serial.println("" );
Serial.print("Packet Number: #" );
Serial.println(packet.u16SequenceNumber, DEC);
Serial.print("Source Logical ID: 0x" );
Serial.println(packet.u8SourceLogicalId, HEX);
Serial.print("LQI: " );
Serial.println(packet.u8Lqi, DEC);
Serial.print("Supply Voltage: " );
Serial.print(packet.u16SupplyVoltage, DEC); Serial.println(" mV" );
Serial.print("Air Temperature: " );
Serial.print(packet.i16Temp100x / 100.0f , 2 ); Serial.println(" C" );
Serial.print("Relative Humidity: " );
Serial.print(packet.u16Humid100x / 100.0f , 2 ); Serial.println(" %" );
Serial.print("Magnet State: " );
printMagnetState(packet.u8MagnetState, packet.bMagnetStateChanged);
});
上記のイベントは、アリアアプリ(TWELITE ARIA モード)からのパケットを受信したときにだけ呼び出されます。
受信したパケットの内容は ParsedAppAriaPacket
型の引数 packet
に格納されています。
メッセージの内容 メッセージ 内容 Packet Number
パケットの続き番号 Source Logical ID
送信元 TWELITE の論理デバイスID LQI
無線通信品質(0~255) Supply Voltage
電源電圧 (mV) Air Temperature
TWELITE ARIA が計測した気温 (°C) Relative Humidity
TWELITE ARIA が計測した相対湿度 (%) Magnet State
磁気センサーの状態
磁気センサーの状態 出力される磁気センサーの状態は以下の通りです。
S-pole is getting closer
新たに磁石のS極を検知した。N-pole is getting closer
新たに磁石のN極を検知した。Leaving or Not found
磁石が検知できなかった。S-pole is close (Periodic packet)
磁石のS極を検知している。N-pole is close (Periodic packet)
磁石のN極を検知している。Not found (Periodic packet)
磁石を連続で検知できていない(定期送信パケット)。TWELITE のデータの更新 53行目では、Twelite.update()
を呼び出しています。
2.5.1.3.2 - アリアアプリのデータを取得 v1.0.1
アリアアプリ (App_ARIA) のデータを取得・表示するサンプルスケッチ
monitor_spot_app_aria
の解説です。
サンプルスケッチの保存場所 MWings ライブラリを導入 していれば、Arduino IDE の ファイル -> スケッチ例 -> MWings -> monitor_spot_app_aria からスケッチを開くことができます。
保存場所
スケッチ 以下はソースコード本体です。
// Monitor example for TWELITE SPOT: Receive data from App_ARIA (ARIA Mode)
#include <Arduino.h>
#include "MWings.h"
const int RST_PIN = 5 ;
const int PRG_PIN = 4 ;
const int LED_PIN = 18 ;
const uint8_t TWE_CHANNEL = 18 ;
const uint32_t TWE_APP_ID = 0x67720102 ;
void printMagnetState (const uint8_t state, const bool changed);
void setup ()
{
// Initialize serial ports
Serial.begin(115200 );
Serial.println("Monitor example for TWELITE SPOT: App_ARIA (ARIA Mode)" );
Serial2.begin(115200 , SERIAL_8N1);
// Initialize TWELITE
Twelite.begin(Serial2,
LED_PIN, RST_PIN, PRG_PIN,
TWE_CHANNEL, TWE_APP_ID);
// Attach an event handler to process packets from App_ARIA
Twelite.on([](const ParsedAppAriaPacket& packet) {
Serial.println("" );
Serial.print("Packet Number: #" );
Serial.println(packet.u16SequenceNumber, DEC);
Serial.print("Source Logical ID: 0x" );
Serial.println(packet.u8SourceLogicalId, HEX);
Serial.print("LQI: " );
Serial.println(packet.u8Lqi, DEC);
Serial.print("Supply Voltage: " );
Serial.print(packet.u16SupplyVoltage, DEC); Serial.println(" mV" );
Serial.print("Air Temperature: " );
Serial.print(packet.i16Temp100x / 100.0f , 2 ); Serial.println(" C" );
Serial.print("Relative Humidity: " );
Serial.print(packet.u16Humid100x / 100.0f , 2 ); Serial.println(" %" );
Serial.print("Magnet State: " );
printMagnetState(packet.u8MagnetState, packet.bMagnetStateChanged);
});
}
void loop ()
{
// Update TWELITE
Twelite.update();
}
void printMagnetState (const uint8_t state, const bool changed)
{
if (changed) {
switch (state) {
case 0x0 : { Serial.print("Leaving or not found" ); break ; }
case 0x1 : { Serial.print("N-pole is getting closer" ); break ; }
case 0x2 : { Serial.print("S-pole is getting closer" ); break ; }
default : break ;
}
} else {
switch (state) {
case 0x0 : { Serial.print("Not found" ); break ; }
case 0x1 : { Serial.print("N-pole is close" ); break ; }
case 0x2 : { Serial.print("S-pole is close" ); break ; }
default : break ;
}
Serial.print(" (Periodic packet)" );
}
Serial.println("" );
}
ライブラリのインクルード 4行目では、MWings ライブラリ をインクルードしています。
ピン番号の定義 6-8行目では、ピン番号を定義しています。
const int RST_PIN = 5 ;
const int PRG_PIN = 4 ;
const int LED_PIN = 18 ;
名称 内容 RST_PIN
TWELITE の RST ピンが接続されているピンの番号 PRG_PIN
TWELITE の PRG ピンが接続されているピンの番号 LED_PIN
基板上の ESP32 用 LED が接続されているピンの番号
TWELITE 設定の定義 10-11行目では、TWELITE SPOT に搭載された TWELITE 親機に適用する設定を定義しています。
const uint8_t TWE_CHANNEL = 18 ;
const uint32_t TWE_APP_ID = 0x67720102 ;
名称 内容 TWE_CHANNEL
TWELITE の 周波数チャネル TWE_APP_ID
TWELITE の アプリケーション ID
シリアルポートの設定 18-20行目では、使用するシリアルポートを初期化するとともに、シリアルモニタへ起動メッセージを出力しています。
Serial.begin(115200 );
Serial.println("Monitor example for TWELITE SPOT: App_ARIA (ARIA Mode)" );
Serial2.begin(115200 , SERIAL_8N1);
Serial
は、Arduino IDE の シリアルモニタとの通信に使います。シリアルモニタの設定に合わせて、ボーレートを 115200
bps としています。
一方、Serial2
は、TWELITE SPOT に搭載された TWELITE 親機との通信に使います。こちらも TWELITE 親機の初期設定に合わせて、ボーレートを 115200
bps としています。
TWELITE の設定 23-25行目では、Twelite.begin()
を呼び出し、TWELITE SPOT に搭載された TWELITE 親機の設定と起動を行っています。
Twelite.begin(Serial2,
LED_PIN, RST_PIN, PRG_PIN,
TWE_CHANNEL, TWE_APP_ID);
パケット受信時のイベントの登録 28-44行目では、Twelite.on()
を呼び出し、送られたデータに対して行う処理を登録しています。
ここでは、受信したパケットの内容をシリアルモニタに出力しています。
Twelite.on([](const ParsedAppAriaPacket& packet) {
Serial.println("" );
Serial.print("Packet Number: #" );
Serial.println(packet.u16SequenceNumber, DEC);
Serial.print("Source Logical ID: 0x" );
Serial.println(packet.u8SourceLogicalId, HEX);
Serial.print("LQI: " );
Serial.println(packet.u8Lqi, DEC);
Serial.print("Supply Voltage: " );
Serial.print(packet.u16SupplyVoltage, DEC); Serial.println(" mV" );
Serial.print("Air Temperature: " );
Serial.print(packet.i16Temp100x / 100.0f , 2 ); Serial.println(" C" );
Serial.print("Relative Humidity: " );
Serial.print(packet.u16Humid100x / 100.0f , 2 ); Serial.println(" %" );
Serial.print("Magnet State: " );
printMagnetState(packet.u8MagnetState, packet.bMagnetStateChanged);
});
上記のイベントは、アリアアプリ(TWELITE ARIA モード)からのパケットを受信したときにだけ呼び出されます。
受信したパケットの内容は ParsedAppAriaPacket
型の引数 packet
に格納されています。
メッセージの内容 メッセージ 内容 Packet Number
パケットの続き番号 Source Logical ID
送信元 TWELITE の論理デバイスID LQI
無線通信品質(0~255) Supply Voltage
電源電圧 (mV) Air Temperature
TWELITE ARIA が計測した気温 (°C) Relative Humidity
TWELITE ARIA が計測した相対湿度 (%) Magnet State
磁気センサーの状態
磁気センサーの状態 出力される磁気センサーの状態は以下の通りです。
S-pole is getting closer
新たに磁石のS極を検知した。N-pole is getting closer
新たに磁石のN極を検知した。Leaving or Not found
磁石が検知できなかった。S-pole is close (Periodic packet)
磁石のS極を検知している。N-pole is close (Periodic packet)
磁石のN極を検知している。Not found (Periodic packet)
磁石を連続で検知できていない(定期送信パケット)。TWELITE のデータの更新 50行目では、Twelite.update()
を呼び出しています。
2.5.1.3.3 - アリアアプリのデータを取得 v1.1.3
アリアアプリ (App_ARIA) のデータを取得・表示するサンプルスケッチ
monitor_spot_app_aria
の解説です。
サンプルスケッチの保存場所 MWings ライブラリを導入 していれば、Arduino IDE の ファイル -> スケッチ例 -> MWings -> TWELITE SPOT -> Receive -> monitor_spot_app_aria からスケッチを開くことができます。
保存場所の表示例
スケッチ 以下はソースコード本体です。
// Monitor example for TWELITE SPOT: Receive data from App_ARIA (ARIA Mode)
#include <Arduino.h>
#include "MWings.h"
const int RST_PIN = 5 ;
const int PRG_PIN = 4 ;
const int LED_PIN = 18 ;
const uint8_t TWE_CHANNEL = 18 ;
const uint32_t TWE_APP_ID = 0x67720102 ;
void printMagnetState (const uint8_t state, const bool changed);
void setup ()
{
// Initialize serial ports
Serial.begin(115200 );
Serial.println("Monitor example for TWELITE SPOT: App_ARIA (ARIA Mode)" );
Serial2.begin(115200 , SERIAL_8N1);
// Initialize TWELITE
Twelite.begin(Serial2,
LED_PIN, RST_PIN, PRG_PIN,
TWE_CHANNEL, TWE_APP_ID);
// Attach an event handler to process packets from App_ARIA
Twelite.on([](const ParsedAppAriaPacket& packet) {
Serial.println("" );
Serial.print("Packet Number: #" );
Serial.println(packet.u16SequenceNumber, DEC);
Serial.print("Source Logical ID: 0x" );
Serial.println(packet.u8SourceLogicalId, HEX);
Serial.print("LQI: " );
Serial.println(packet.u8Lqi, DEC);
Serial.print("Supply Voltage: " );
Serial.print(packet.u16SupplyVoltage, DEC); Serial.println(" mV" );
Serial.print("Air Temperature: " );
Serial.print(packet.i16Temp100x / 100.0f , 2 ); Serial.println(" C" );
Serial.print("Relative Humidity: " );
Serial.print(packet.u16Humid100x / 100.0f , 2 ); Serial.println(" %" );
Serial.print("Magnet State: " );
printMagnetState(packet.u8MagnetState, packet.bMagnetStateChanged);
});
}
void loop ()
{
// Update TWELITE
Twelite.update();
}
void printMagnetState (const uint8_t state, const bool changed)
{
if (changed) {
switch (state) {
case 0x0 : { Serial.print("Leaving or not found" ); break ; }
case 0x1 : { Serial.print("N-pole is getting closer" ); break ; }
case 0x2 : { Serial.print("S-pole is getting closer" ); break ; }
default : break ;
}
} else {
switch (state) {
case 0x0 : { Serial.print("Not found" ); break ; }
case 0x1 : { Serial.print("N-pole is close" ); break ; }
case 0x2 : { Serial.print("S-pole is close" ); break ; }
default : break ;
}
Serial.print(" (Periodic packet)" );
}
Serial.println("" );
}
ライブラリのインクルード 4行目では、MWings ライブラリ をインクルードしています。
ピン番号の定義 6-8行目では、ピン番号を定義しています。
const int RST_PIN = 5 ;
const int PRG_PIN = 4 ;
const int LED_PIN = 18 ;
名称 内容 RST_PIN
TWELITE の RST ピンが接続されているピンの番号 PRG_PIN
TWELITE の PRG ピンが接続されているピンの番号 LED_PIN
基板上の ESP32 用 LED が接続されているピンの番号
TWELITE 設定の定義 10-11行目では、TWELITE SPOT に搭載された TWELITE 親機に適用する設定を定義しています。
const uint8_t TWE_CHANNEL = 18 ;
const uint32_t TWE_APP_ID = 0x67720102 ;
名称 内容 TWE_CHANNEL
TWELITE の 周波数チャネル TWE_APP_ID
TWELITE の アプリケーション ID
シリアルポートの設定 18-20行目では、使用するシリアルポートを初期化するとともに、シリアルモニタへ起動メッセージを出力しています。
Serial.begin(115200 );
Serial.println("Monitor example for TWELITE SPOT: App_ARIA (ARIA Mode)" );
Serial2.begin(115200 , SERIAL_8N1);
Serial
は、Arduino IDE の シリアルモニタとの通信に使います。シリアルモニタの設定に合わせて、ボーレートを 115200
bps としています。
一方、Serial2
は、TWELITE SPOT に搭載された TWELITE 親機との通信に使います。こちらも TWELITE 親機の初期設定に合わせて、ボーレートを 115200
bps としています。
TWELITE の設定 23-25行目では、Twelite.begin()
を呼び出し、TWELITE SPOT に搭載された TWELITE 親機の設定と起動を行っています。
Twelite.begin(Serial2,
LED_PIN, RST_PIN, PRG_PIN,
TWE_CHANNEL, TWE_APP_ID);
パケット受信時のイベントの登録 28-44行目では、Twelite.on()
を呼び出し、送られたデータに対して行う処理を登録しています。
ここでは、受信したパケットの内容をシリアルモニタに出力しています。
Twelite.on([](const ParsedAppAriaPacket& packet) {
Serial.println("" );
Serial.print("Packet Number: #" );
Serial.println(packet.u16SequenceNumber, DEC);
Serial.print("Source Logical ID: 0x" );
Serial.println(packet.u8SourceLogicalId, HEX);
Serial.print("LQI: " );
Serial.println(packet.u8Lqi, DEC);
Serial.print("Supply Voltage: " );
Serial.print(packet.u16SupplyVoltage, DEC); Serial.println(" mV" );
Serial.print("Air Temperature: " );
Serial.print(packet.i16Temp100x / 100.0f , 2 ); Serial.println(" C" );
Serial.print("Relative Humidity: " );
Serial.print(packet.u16Humid100x / 100.0f , 2 ); Serial.println(" %" );
Serial.print("Magnet State: " );
printMagnetState(packet.u8MagnetState, packet.bMagnetStateChanged);
});
上記のイベントは、アリアアプリ(TWELITE ARIA モード)からのパケットを受信したときにだけ呼び出されます。
受信したパケットの内容は ParsedAppAriaPacket
型の引数 packet
に格納されています。
メッセージの内容 メッセージ 内容 Packet Number
パケットの続き番号 Source Logical ID
送信元 TWELITE の論理デバイスID LQI
無線通信品質(0~255) Supply Voltage
電源電圧 (mV) Air Temperature
TWELITE ARIA が計測した気温 (°C) Relative Humidity
TWELITE ARIA が計測した相対湿度 (%) Magnet State
磁気センサーの状態
磁気センサーの状態 出力される磁気センサーの状態は以下の通りです。
S-pole is getting closer
新たに磁石のS極を検知した。N-pole is getting closer
新たに磁石のN極を検知した。Leaving or Not found
磁石が検知できなかった。S-pole is close (Periodic packet)
磁石のS極を検知している。N-pole is close (Periodic packet)
磁石のN極を検知している。Not found (Periodic packet)
磁石を連続で検知できていない(定期送信パケット)。TWELITE のデータの更新 50行目では、Twelite.update()
を呼び出しています。
2.5.2 - TWELITE に加えて無線 LAN を活用するスケッチの解説 TWELITE SPOT の応用的なサンプルスケッチの解説
TWELITE NET に加えて無線 LAN を活用した高度なサンプルスケッチを解説します。
2.5.2.1 - プリインストール済みスケッチ 子機からのデータを Web ページに表示するローカルサーバのサンプルスケッチ spot-server の解説
spot-server は、工場出荷時の TWELITE SPOT にプリインストールされています。
無線 LAN アクセスポイントとして振る舞い、Web ページ上に子機からのデータを表示するサンプルスケッチ
spot-server
の解説です。
2.5.2.1.1 - プリインストール済みスケッチ 最新(ESP32 Arduino Core v3.x.x)版
無線 LAN アクセスポイントとして振る舞い、Web ページ上に子機からのデータを表示するサンプルスケッチ
spot-server
の解説です。
spot-server は工場出荷時の TWELITE SPOT にプリインストールされています。
本稿では、サードパーティのオープンソースソフトウェアを使用します。
サードパーティのソフトウェアについて、その詳しい使用方法を弊社からご案内することはいたしかねます。また、サードパーティのソフトウェアを使用されたことによるいかなる損害についても、弊社は一切の責任を負いません。
ソースコードの入手 GitHub (monowireless/spot-server ) から入手できます。
システムの概要 spot-server は、TWELITE からのデータ受信と転送を行う Arduino スケッチ (.ino
) と、スマホに配信する Web ページ (.html
/ .css
/ .js
) で構成しています。
イメージ図
TWELITE 子機が送信したデータは Arduino スケッチで受信され、Arduino スケッチは公開中の Web ページに対してイベントを発火します。公開された Web ページでは、発火されたイベントに応じて HTML の内容を動的に書き換えています。
Web ページの開発には、HTML、CSS、ECMAScript (JavaScript) といった Web 技術に関する知識が必要です。
開発に必要なもの 環境整備 IDE とツールチェインの導入 Arduino IDE 1.x による開発環境の構築方法 をご覧ください。
ライブラリの導入 はじめに、Arduino のスケッチブックの保存場所(Arduino IDE 環境設定に記載。例:C:\Users\foo\Documents\Arduino
) に libraries
フォルダがない場合は、これを作成します。
非同期 TCP 通信ライブラリ GitHub (me-no-dev/AsyncTCP) から Zip ファイルをダウンロードしますZip ファイルを展開し、フォルダ名を AsyncTCP-master
から AsyncTCP
に変更します libraries
フォルダに AsyncTCP
フォルダを配置します非同期 Web サーバライブラリ GitHub (me-no-dev/ESPAsyncWebServer) から Zip ファイルをダウンロードしますZip ファイルを展開し、フォルダ名を AsyncWebServer-master
から AsyncWebServer
に変更します libraries
フォルダに AsyncWebServer
フォルダを配置しますOLED ディスプレイライブラリ GitHub (Seeed-Studio/OLED_Display_96X96) から Zip ファイルをダウンロードしますZip ファイルを展開し、フォルダ名を OLED_Display_96X96-master
から OLED_Display_96X96
に変更します libraries
フォルダに OLED_Display_96X96
フォルダを配置しますJSON ライブラリ ライブラリマネージャを開き、Arduino_JSON
をインストールします。
ここでは、サードパーティの ArduinoJson
ではなく、公式の Arduino_JSON
を使用します。
プラグインの導入 ファイルシステム書き込みプラグイン HTML などのファイルを ESP32 のフラッシュ領域に書き込むには、Arduino プラグインが必要です。
ここでは、lorol/arduino-esp32fs-plugin: Arduino plugin for uploading files to ESP32 file system を利用します(LittleFSに対応したプラグイン)。
インストール方法は TWELITE SPOT マニュアル ESP32 へのファイルの書き込み方法 をご覧ください。
プロジェクトファイルの入手 GitHub (monowireless/spot-server) から Zip ファイルをダウンロードしますZip ファイルを展開し、フォルダ名を spot-server-main
から spot-server
に変更します Arduino のスケッチブックの保存場所(Arduino IDE 環境設定に記載。例:C:\Users\foo\Documents\Arduino
)に spot-server
フォルダを配置します プロジェクトファイルの書き込み方法 スケッチ ESP32 へのスケッチの書き込み方法 をご覧ください。
Web ページ ESP32 へのファイルの書き込み方法 をご覧ください。
スケッチ Arduino スケッチ spot-server.ino の解説です。
ライブラリのインクルード Arduino および ESP32 公式ライブラリ 4-9行目では、Arduino および ESP32 の公式ライブラリをインクルードしています。
#include <Arduino.h>
#include <Arduino_JSON.h>
#include <ESPmDNS.h>
#include <LittleFS.h>
#include <WiFi.h>
#include "esp_wifi.h"
#include <Wire.h>
ヘッダファイル 内容 備考 Arduino.h
Arduino の基本ライブラリ 省略できる場合もあるが念のため記載 Arduino_JSON.h
JSON 文字列を扱う ArduinoJson
とは異なるESPmDNS.h
mDNS を使う ホスト名を使うために必要 LittleFS.h
LittleFS ファイルシステムを扱う ページ公開に必要 WiFi.h
ESP32 の WiFi を使う esp_wifi.h
WiFiの高度な設定を行う ロケール設定に必要 Wire.h
I2C を使う OLED ディスプレイ用
サードパーティのライブラリ 13-15行目では、サードパーティのライブラリをインクルードしています。
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <SeeedGrayOLED.h>
ヘッダファイル 内容 備考 AsyncTCP.h
非同期 TCP 通信を行う ESPAsyncWebServer.h
非同期 Web サーバを立てる AsyncTCP
に依存SeeedGrayOLED.h
OLED ディスプレイを使う
MWings ライブラリ 18行目では、MWings ライブラリをインクルードしています。
ピン番号の定義 21-25行目では、ピン番号を定義しています。
const uint8_t TWE_RST = 5 ;
const uint8_t TWE_PRG = 4 ;
const uint8_t LED = 18 ;
const uint8_t ESP_RXD1 = 16 ;
const uint8_t ESP_TXD1 = 17 ;
他の簡単なサンプルとは異なり、このスケッチでは、厳格に ESP32 の UART ピンを指定した例を示します。
名称 内容 TWE_RST
TWELITE の RST ピンが接続されているピンの番号 TWE_PRG
TWELITE の PRG ピンが接続されているピンの番号 LED
基板上の ESP32 用 LED が接続されているピンの番号 ESP_RXD1
TWELITE の TX ピンが接続されているピンの番号 ESP_TXD1
TWELITE の RX ピンが接続されているピンの番号
TWELITE 設定の定義 28-31行目では、TWELITE SPOT に搭載された TWELITE 親機に適用する設定を定義しています。
const uint8_t TWE_CH = 18 ;
const uint32_t TWE_APPID = 0x67720102 ;
const uint8_t TWE_RETRY = 2 ;
const uint8_t TWE_POWER = 3 ;
名称 内容 TWE_CH
TWELITE の 周波数チャネル TWE_APPID
TWELITE の アプリケーション ID TWE_RETRY
TWELITE の 再送回数(送信時) TWE_POWER
TWELITE の 送信出力
このサンプルでは、TWELITE 親機からのコマンド送信を行わないため、29-30行目の内容は関係ありません。
無線 LAN 設定の定義 34-46行目では、TWELITE SPOT に搭載された ESP32 に適用する無線 LAN 設定を定義しています。
wifi_country_t WIFI_COUNTRY_JP = {
cc: "JP" , // Contry code
schan: 1 , // Starting channel
nchan: 14 , // Number of channels
max_tx_power: 20 , // Maximum power in dBm
policy: WIFI_COUNTRY_POLICY_MANUAL
};
const char * WIFI_SSID_BASE = "TWELITE SPOT" ;
const char * WIFI_PASSWORD = "twelitespot" ;
const uint8_t WIFI_CH = 13 ;
const IPAddress WIFI_IP = IPAddress(192 , 168 , 1 , 1 );
const IPAddress WIFI_MASK = IPAddress(255 , 255 , 255 , 0 );
const char * HOSTNAME = "spot" ; // spot.local
名称 内容 WIFI_COUNTRY_JP
ロケール設定(日本) WIFI_SSID_BASE
SSID の共通部分の文字列 WIFI_PASSWORD
パスワード WIFI_CH
ESP32 の周波数チャネル WIFI_IP
IP アドレス WIFI_MASK
サブネットマスク HOSTNAME
ホスト名
グローバルオブジェクトの宣言 49-50行目では、グローバルオブジェクトを宣言しています。
AsyncWebServer server (80 );
AsyncEventSource events ("/events" );
名称 内容 server
80番ポートで開く非同期 Web サーバのインタフェース events
/events
で開くサーバー送信イベント ? のインタフェース
関数プロトタイプの宣言 53-57行目では、関数プロトタイプを宣言しています。
uint16_t createUidFromMac ();
String createJsonFrom (const ParsedAppTwelitePacket& packet);
String createJsonFrom (const ParsedAppAriaPacket& packet);
String createJsonFrom (const ParsedAppCuePacket& packet);
String createJsonFrom (const BarePacket& packet);
名称 内容 createUidFromMac()
MAC アドレスから SSID に使う識別子を作ります createJsonFrom()
<ParsedAppTwelitePacket&>
App_Twelite のパケットデータから JSON 文字列を作ります createJsonFrom()
<ParsedAppAriaPacket&>
App_ARIA のパケットデータから JSON 文字列を作ります createJsonFrom()
<ParsedAppCuePacket&>
App_CUE のパケットデータから JSON 文字列を作ります createJsonFrom()
<BarePacket&>
すべてのパケットデータから JSON 文字列を作ります
TWELITE の設定 66-71行目では、Twelite.begin()
を呼び出し、TWELITE SPOT に搭載された TWELITE 親機の設定と起動を行っています。
Serial2.begin(115200 , SERIAL_8N1, ESP_RXD1, ESP_TXD1);
if (Twelite.begin(Serial2,
LED, TWE_RST, TWE_PRG,
TWE_CH, TWE_APPID, TWE_RETRY, TWE_POWER)) {
Serial.println("Started TWELITE." );
}
引数 型 内容 Serial2
HardwareSerial&
TWELITE との通信に使うシリアルポート LED
int
ステータス LED を接続したピンの番号 TWE_RST
int
TWELITE の RST ピンを接続したピンの番号 TWE_PRG
int
TWELITE の PRG ピンを接続したピンの番号 TWE_CHANNEL
uint8_t
TWELITE の 周波数チャネル TWE_APP_ID
uint32_t
TWELITE の アプリケーション ID TWE_RETRY
uint8_t
TWELITE の 再送回数(送信時) TWE_POWER
uint8_t
TWELITE の 送信出力
App_Twelite:イベントハンドラの登録 73-80行目では、Twelite.on() <ParsedAppTwelitePacket>
を呼び出し、超簡単!標準アプリの子機からのパケットを受信した際に行う処理を登録しています。
Twelite.on([](const ParsedAppTwelitePacket& packet) {
Serial.println("Received a packet from App_Twelite" );
String jsonStr = createJsonFrom(packet);
if (not(jsonStr.length() <= 0 )) {
events.send(jsonStr.c_str(), "data_app_twelite" , millis());
}
events.send("parsed_app_twelite" , "data_parsing_result" , millis());
});
JSON 文字列の作成 75行目では、受信したデータからJSON 文字列を生成しています。
String jsonStr = createJsonFrom(packet);
受信したデータをWeb ページに表示するにはクライアント側の JavaScript にデータを送る必要がありますが、このとき文字列データのほうが扱いやすいため、JSON 文字列としています。
Web ページへのイベント送信 76-78行目では、生成した JSON 文字列を “Signal Viewer” ページへ送信しています。
if (not(jsonStr.length() <= 0 )) {
events.send(jsonStr.c_str(), "data_app_twelite" , millis());
}
イベント名は data_app_twelite
です。
各イベントに割り当てる ID には、millis()
で取得した現在時刻を使用しています。
79行目では、App_Twelite からのパケットを受信したことを “Serial Viewer” ページへ送信しています。
events.send("parsed_app_twelite" , "data_parsing_result" , millis());
App_ARIA:イベントハンドラの登録 82-92行目では、Twelite.on() <ParsedAppAriaPacket>
を呼び出し、アリアアプリ(TWELITE ARIA モード)の子機からのパケットを受信した際に行う処理を登録しています。
Twelite.on([](const ParsedAppAriaPacket& packet) {
Serial.println("Received a packet from App_ARIA" );
static uint32_t firstSourceSerialId = packet.u32SourceSerialId;
if (packet.u32SourceSerialId == firstSourceSerialId) {
String jsonStr = createJsonFrom(packet);
if (not(jsonStr.length() <= 0 )) {
events.send(jsonStr.c_str(), "data_app_aria_twelite_aria_mode" , millis());
}
}
events.send("parsed_app_aria_twelite_aria_mode" , "data_parsing_result" , millis());
});
対象の絞り込み 84-85行目では、処理の対象を 最初に受信した子機 に限定しています。
static uint32_t firstSourceSerialId = packet.u32SourceSerialId;
if (packet.u32SourceSerialId == firstSourceSerialId) {
こうしておかないと、複数の子機があった際にグラフの一貫性が失われてしまうからです。
JSON 文字列の作成 86行目では、受信したデータからJSON 文字列を生成しています。
String jsonStr = createJsonFrom(packet);
Web ページへのイベント送信 87-89行目では、生成した JSON 文字列を “ARIA Viewer” ページへ送信しています。
if (not(jsonStr.length() <= 0 )) {
events.send(jsonStr.c_str(), "data_app_aria_twelite_aria_mode" , millis());
}
イベント名は data_app_aria_twelite_aria_mode
です。
91行目では、App_Twelite からのパケットを受信したことを “Serial Viewer” ページへ送信しています。
events.send("parsed_app_aria_twelite_aria_mode" , "data_parsing_result" , millis());
App_CUE:イベントハンドラの登録 94-104行目では、Twelite.on() <ParsedAppCuePacket>
を呼び出し、キューアプリ(TWELITE CUE モード)の子機からのパケットを受信した際に行う処理を登録しています。
Twelite.on([](const ParsedAppCuePacket& packet) {
Serial.println("Received a packet from App_CUE" );
static uint32_t firstSourceSerialId = packet.u32SourceSerialId;
if (packet.u32SourceSerialId == firstSourceSerialId) {
String jsonStr = createJsonFrom(packet);
if (not(jsonStr.length() <= 0 )) {
events.send(jsonStr.c_str(), "data_app_cue_twelite_cue_mode" , millis());
}
}
events.send("parsed_app_cue_twelite_cue_mode" , "data_parsing_result" , millis());
});
その他:イベントハンドラの登録 106-134行目では、その他のアプリの子機からのパケットを受信した際に行う処理を登録しています。
アリアアプリ等と同様に “Serial Viewer” へイベントを送信しています。
すべて:イベントハンドラの登録 136-142行目では、すべてのアプリの子機からのパケットを受信した際に行う処理を登録しています。
Twelite.on([](const BarePacket& packet) {
String jsonStr = createJsonFrom(packet);
if (not(jsonStr.length() <= 0 )) {
events.send(jsonStr.c_str(), "data_bare_packet" , millis());
}
events.send("unparsed_bare_packet" , "data_parsing_result" , millis());
});
ここでも、“Serial Viewer” に対するパケットデータ文字列の送信を行っています。
OLED ディスプレイの設定 145-150行目では、OLED ディスプレイの設定を行っています。
Wire.begin();
SeeedGrayOled.init(SSD1327);
SeeedGrayOled.setNormalDisplay();
SeeedGrayOled.setVerticalMode();
SeeedGrayOled.setGrayLevel(0x0F );
SeeedGrayOled.clearDisplay();
OLED を接続していない場合は何も起こりません。
無線 LAN の設定 154-165行目では、無線 LAN の設定を行っています。
WiFi.mode(WIFI_AP);
esp_wifi_set_country(& WIFI_COUNTRY_JP);
char uidCString[8 ];
sprintf(uidCString, " (%02X)" , createUidFromMac());
char ssidCString[20 ];
sprintf(ssidCString, "%s%s" , WIFI_SSID_BASE, uidCString);
if (not WiFi.softAP(ssidCString, WIFI_PASSWORD, WIFI_CH, false, 10 )) {
Serial.println("Failed to start AP" );
}
delay(100 ); // IMPORTANT: Waiting for SYSTEM_EVENT_AP_START
WiFi.softAPConfig(WIFI_IP, WIFI_IP, WIFI_MASK);
MDNS.begin(HOSTNAME);
delay(100)
を省略すると初期化に失敗することがあります。
ファイルシステムの設定 198行目では、LittleFS ファイルシステムを設定しています。
if (LittleFS.begin()) { Serial.println("Mounted file system." ); }
フラッシュ領域内に書き込んだ HTML などのファイルをページとして取得することができるようになります。
Web サーバの設定 201-228行目では、Web サーバの設定を行っています。
GET リクエストのハンドリング 例えば、206-210行目 では /signal-viewer
への GET リクエストに対して、LittleFS ファイルシステム上の /signal-viewer.html
を返しています。
server.on("/signal-viewer" , HTTP_GET,
[](AsyncWebServerRequest* request) {
Serial.println("HTTP_GET: signal-viewer.html" );
request-> send(LittleFS, "/signal-viewer.html" , "text/html" );
});
サーバの初期化 226-228行目では、ファイルシステム上のルートをサーバのルートとして設定したあと、イベントソースを登録してサーバを立ち上げています。
server.serveStatic("/" , LittleFS, "/" );
server.addHandler(& events);
server.begin();
TWELITE のデータの更新 234行目では、Twelite.update()
を呼び出しています。
Twelite.update()
は、TWELITE 親機から送信されるパケットデータ(ModBus ASCII 形式)を順次1バイトずつ読み出す関数です。
loop()
内で繰り返し
Twelite.update()
を呼ぶことで、TWELITE 親機から送信されるパケットデータの解釈が進みます。パケットデータの解釈を終えた際に
上記 のようなイベントが呼ばれる仕組みです。
delay()
などの処理でこの関数の呼び出しをブロックすると、パケットデータ文字列の読み出しが間に合わないことがあります。時間のかかる処理は必ず非同期の実装として、
loop()
関数をできるだけ高速回転させるようにしてください。
Web ページ Web ページに関しては、詳しい解説を行いません。重要なポイントに絞って解説します。
HTML:グリッドシステム このサンプルの HTML では、Flexbox Grid を使っています(ソースファイルは data/css/flexboxgrid.min.css)。
下記のようにして Bootstrap に似た 12 分割のグリッドシステムを使用しています。
<div class = "col-xs-6 col-sm-6 col-md-5 col-lg-4" >
<div class = "neumorphic inset dense row center-xs middle-xs" >
<div class = "col-xs-12 col-sm-12 col-md-12 col-lg-12 npr npl" >
<img src = "./images/logo-lands.svg" class = "logo" />
</div >
</div >
</div >
<div class = "col-xs-6 col-sm-6 col-md-7 col-lg-8" >
<div class = "neumorphic inset dense row center-xs middle-xs" >
<div class = "col-xs-12 col-sm-12 col-md-12 col-lg-12 nwp npr npl" >
<span class = "medium bold" >TWELITE SPOT</span >
</div >
<div class = "col-xs-12 col-sm-12 col-md-12 col-lg-12 nwp npr npl" >
<span class = "small bold" >CUE Viewer</span >
</div >
</div >
</div >
ここでは、ロゴを中心とした要素の幅を 6/12 、文字列を中心とした要素の幅を 6/12 、すなわち両者を等しい幅で一列に配置しています。また、文字列 TWELITE SPOT
を中心とした要素と CUE Viewer
を中心とした要素の幅はどちらも 12/12 、すなわち1行ずつ2行に分けて配置しています。
xs-
や sm-
などは画面の幅を指定します。レスポンシブデザインに活用できます。
HTML:データ表示部 TWELITE 子機から受信したデータを表示する要素には、一意の ID を付与しています。
以下は TWELITE CUE から受信した X 軸加速度を表示する部分の抜粋です。
<div class = "col-xs-4 nwp npr npl" >
<code class = "medium"
id = "latest-accel-x" >±--.--</code >
<code class = "small" >G</code >
</div >
ここでは、ID として latest-accel-x
を付与しています。この ID を使って、スクリプトから値を書き換えます。
JS:グローバル変数 4-8行目では、最新の加速度値を保存するためのグローバル変数を宣言しています。
let latest_accel = {
x : 0.0 ,
y : 0.0 ,
z : 0.0
};
この値はグラフからも利用するため、実装を簡素にするためにグローバル変数を使用しています。
JS:グラフ設定 11-133行目では、グラフ描画ライブラリ Chart.js | Chart.js およびそのプラグイン chartjs-plugin-streaming の設定を行っています。
JS:ページ内容の更新 136-235行目の関数 processDataAppCueTweliteCueMode()
は、スケッチから data_app_cue_twelite_cue_mode
イベントを受信した際にページ内容を更新する関数です。
例えば、184-208行目では、TWELITE CUE の電源電圧に応じて電圧値と絵文字を更新しています。
if (data .vcc >= 3000 ) {
document.getElementById ("latest-vcc-icon" ).innerHTML = "🔋" ;
document.getElementById ("latest-vcc-data" ).innerHTML = ` ${ (data .vcc / 1000.0 ).toFixed (2 ).toString ().padStart (4 )} ` ;
document.getElementById ("latest-vcc-data" ).classList .remove ("red" );
document.getElementById ("latest-vcc-data" ).classList .remove ("yellow" );
document.getElementById ("latest-vcc-data" ).classList .add ("green" );
} else if (data .vcc >= 2700 ) {
document.getElementById ("latest-vcc-icon" ).innerHTML = "🔋" ;
document.getElementById ("latest-vcc-data" ).innerHTML = ` ${ (data .vcc / 1000.0 ).toFixed (2 ).toString ().padStart (4 )} ` ;
document.getElementById ("latest-vcc-data" ).classList .remove ("red" );
document.getElementById ("latest-vcc-data" ).classList .remove ("yellow" );
document.getElementById ("latest-vcc-data" ).classList .remove ("green" );
} else if (data .vcc >= 2400 ) {
document.getElementById ("latest-vcc-icon" ).innerHTML = "🪫" ;
document.getElementById ("latest-vcc-data" ).innerHTML = ` ${ (data .vcc / 1000.0 ).toFixed (2 ).toString ().padStart (4 )} ` ;
document.getElementById ("latest-vcc-data" ).classList .remove ("red" );
document.getElementById ("latest-vcc-data" ).classList .add ("yellow" );
document.getElementById ("latest-vcc-data" ).classList .remove ("green" );
} else {
document.getElementById ("latest-vcc-icon" ).innerHTML = "🪫" ;
document.getElementById ("latest-vcc-data" ).innerHTML = ` ${ (data .vcc / 1000.0 ).toFixed (2 ).toString ().padStart (4 )} ` ;
document.getElementById ("latest-vcc-data" ).classList .add ("red" );
document.getElementById ("latest-vcc-data" ).classList .remove ("yellow" );
document.getElementById ("latest-vcc-data" ).classList .remove ("green" );
}
ここでは、電源電圧が 2700mV 未満に降下した際に絵文字を 🔋 から 🪫 に変えているほか、3000mV → 2700mV → 2400mV と電圧降下に従って電圧値の文字色を適用する CSS クラスを入れ替えています。
イベントリスナーの登録 254-257行目では、スケッチからのイベントを受信した際の処理を登録しています。
source .addEventListener ("data_app_cue_twelite_cue_mode" , (e ) => {
console .log ("data_app_cue_twelite_cue_mode" , e .data );
processDataAppCueTweliteCueMode (JSON .parse (e .data ));
}, false );
ここでは、スケッチより 受信したイベントメッセージから JSON 文字列を取り出し、パースしたデータを先ほどの関数 processDataAppCueTweliteCueMode()
へ渡しています。
関連情報 Arduino ESP32 コミュニティ ライブラリ プラグイン Web関連 ECMAScript (JavaScript) コミュニティ 2.5.2.1.2 - プリインストール済みスケッチ ESP32 Arduino Core v2.x.x 版
無線 LAN アクセスポイントとして振る舞い、Web ページ上に子機からのデータを表示するサンプルスケッチ
spot-server
の解説です。
spot-server は工場出荷時の TWELITE SPOT にプリインストールされています。
本稿では、サードパーティのオープンソースソフトウェアを使用します。
サードパーティのソフトウェアについて、その詳しい使用方法を弊社からご案内することはいたしかねます。また、サードパーティのソフトウェアを使用されたことによるいかなる損害についても、弊社は一切の責任を負いません。
ソースコードの入手 GitHub (monowireless/spot-server ) から入手できます。
システムの概要 spot-server は、TWELITE からのデータ受信と転送を行う Arduino スケッチ (.ino
) と、スマホに配信する Web ページ (.html
/ .css
/ .js
) で構成しています。
イメージ図
TWELITE 子機が送信したデータは Arduino スケッチで受信され、Arduino スケッチは公開中の Web ページに対してイベントを発火します。公開された Web ページでは、発火されたイベントに応じて HTML の内容を動的に書き換えています。
Web ページの開発には、HTML、CSS、ECMAScript (JavaScript) といった Web 技術に関する知識が必要です。
開発に必要なもの 環境整備 IDE とツールチェインの導入 Arduino IDE 1.x による開発環境の構築方法 をご覧ください。
ライブラリの導入 はじめに、Arduino のスケッチブックの保存場所(Arduino IDE 環境設定に記載。例:C:\Users\foo\Documents\Arduino
) に libraries
フォルダがない場合は、これを作成します。
非同期 TCP 通信ライブラリ GitHub (me-no-dev/AsyncTCP) から Zip ファイルをダウンロードしますZip ファイルを展開し、フォルダ名を AsyncTCP-master
から AsyncTCP
に変更します libraries
フォルダに AsyncTCP
フォルダを配置します非同期 Web サーバライブラリ GitHub (me-no-dev/ESPAsyncWebServer) から Zip ファイルをダウンロードしますZip ファイルを展開し、フォルダ名を AsyncWebServer-master
から AsyncWebServer
に変更します libraries
フォルダに AsyncWebServer
フォルダを配置しますOLED ディスプレイライブラリ GitHub (Seeed-Studio/OLED_Display_96X96) から Zip ファイルをダウンロードしますZip ファイルを展開し、フォルダ名を OLED_Display_96X96-master
から OLED_Display_96X96
に変更します libraries
フォルダに OLED_Display_96X96
フォルダを配置しますJSON ライブラリ ライブラリマネージャを開き、Arduino_JSON
をインストールします。
サードパーティの ArduinoJson
ではなく、公式の Arduino_JSON
を使用します。
プラグインの導入 ファイルシステム書き込みプラグイン HTML などのファイルを ESP32 のフラッシュ領域に書き込むには、Arduino プラグインが必要です。
ここでは、lorol/arduino-esp32fs-plugin: Arduino plugin for uploading files to ESP32 file system を利用します。
インストール方法は TWELITE SPOT マニュアル ESP32 へのファイルの書き込み方法 をご覧ください。
プロジェクトファイルの入手 GitHub (monowireless/spot-server) から Zip ファイルをダウンロードしますZip ファイルを展開し、フォルダ名を spot-server-main
から spot-server
に変更します Arduino のスケッチブックの保存場所(Arduino IDE 環境設定に記載。例:C:\Users\foo\Documents\Arduino
)に spot-server
フォルダを配置します プロジェクトファイルの書き込み方法 スケッチ ESP32 へのスケッチの書き込み方法 をご覧ください。
Web ページ ESP32 へのファイルの書き込み方法 をご覧ください。
スケッチ Arduino スケッチ spot-server.ino の解説です。
ライブラリのインクルード Arduino および ESP32 公式ライブラリ 4-9行目では、Arduino および ESP32 の公式ライブラリをインクルードしています。
#include <Arduino.h>
#include <Arduino_JSON.h>
#include <ESPmDNS.h>
#include <LittleFS.h>
#include <WiFi.h>
#include <Wire.h>
ヘッダファイル 内容 備考 Arduino.h
Arduino の基本ライブラリ 省略できる場合もあるが念のため記載 Arduino_JSON.h
JSON 文字列を扱う ArduinoJson
とは異なるESPmDNS.h
mDNS を使う ホスト名を使うために必要 LittleFS.h
LittleFS ファイルシステムを扱う ページ公開に必要 WiFi.h
ESP32 の WiFi を使う Wire.h
I2C を使う OLED ディスプレイ用
サードパーティのライブラリ 12-14行目では、サードパーティのライブラリをインクルードしています。
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <SeeedGrayOLED.h>
ヘッダファイル 内容 備考 AsyncTCP.h
非同期 TCP 通信を行う ESPAsyncWebServer.h
非同期 Web サーバを立てる AsyncTCP
に依存SeeedGrayOLED.h
OLED ディスプレイを使う
MWings ライブラリ 17行目では、MWings ライブラリをインクルードしています。
ピン番号の定義 20-24行目では、ピン番号を定義しています。
const uint8_t TWE_RST = 5 ;
const uint8_t TWE_PRG = 4 ;
const uint8_t LED = 18 ;
const uint8_t ESP_RXD1 = 16 ;
const uint8_t ESP_TXD1 = 17 ;
他の簡単なサンプルとは異なり、このスケッチでは、厳格に ESP32 の UART ピンを指定した例を示します。
名称 内容 TWE_RST
TWELITE の RST ピンが接続されているピンの番号 TWE_PRG
TWELITE の PRG ピンが接続されているピンの番号 LED
基板上の ESP32 用 LED が接続されているピンの番号 ESP_RXD1
TWELITE の TX ピンが接続されているピンの番号 ESP_TXD1
TWELITE の RX ピンが接続されているピンの番号
TWELITE 設定の定義 27-30行目では、TWELITE SPOT に搭載された TWELITE 親機に適用する設定を定義しています。
const uint8_t TWE_CH = 18 ;
const uint32_t TWE_APPID = 0x67720102 ;
const uint8_t TWE_RETRY = 2 ;
const uint8_t TWE_POWER = 3 ;
名称 内容 TWE_CH
TWELITE の 周波数チャネル TWE_APPID
TWELITE の アプリケーション ID TWE_RETRY
TWELITE の 再送回数(送信時) TWE_POWER
TWELITE の 送信出力
このサンプルでは、TWELITE 親機からのコマンド送信を行わないため、29-30行目の内容は関係ありません。
無線 LAN 設定の定義 33-38行目では、TWELITE SPOT に搭載された ESP32 に適用する無線 LAN 設定を定義しています。
const char * WIFI_SSID_BASE = "TWELITE SPOT" ;
const char * WIFI_PASSWORD = "twelitespot" ;
const uint8_t WIFI_CH = 13 ;
const IPAddress WIFI_IP = IPAddress(192 , 168 , 1 , 1 );
const IPAddress WIFI_MASK = IPAddress(255 , 255 , 255 , 0 );
const char * HOSTNAME = "spot" ; // spot.local
名称 内容 WIFI_SSID_BASE
SSID の共通部分の文字列 WIFI_PASSWORD
パスワード WIFI_CH
ESP32 の周波数チャネル WIFI_IP
IP アドレス WIFI_MASK
サブネットマスク HOSTNAME
ホスト名
グローバルオブジェクトの宣言 41-42行目では、グローバルオブジェクトを宣言しています。
AsyncWebServer server (80 );
AsyncEventSource events ("/events" );
名称 内容 server
80番ポートで開く非同期 Web サーバのインタフェース events
/events
で開くサーバー送信イベント ? のインタフェース
関数プロトタイプの宣言 45-49行目では、関数プロトタイプを宣言しています。
uint16_t createUidFromMac ();
String createJsonFrom (const ParsedAppTwelitePacket& packet);
String createJsonFrom (const ParsedAppAriaPacket& packet);
String createJsonFrom (const ParsedAppCuePacket& packet);
String createJsonFrom (const BarePacket& packet);
名称 内容 createUidFromMac()
MAC アドレスから SSID に使う識別子を作ります createJsonFrom()
<ParsedAppTwelitePacket&>
App_Twelite のパケットデータから JSON 文字列を作ります createJsonFrom()
<ParsedAppAriaPacket&>
App_ARIA のパケットデータから JSON 文字列を作ります createJsonFrom()
<ParsedAppCuePacket&>
App_CUE のパケットデータから JSON 文字列を作ります createJsonFrom()
<BarePacket&>
すべてのパケットデータから JSON 文字列を作ります
TWELITE の設定 58-63行目では、Twelite.begin()
を呼び出し、TWELITE SPOT に搭載された TWELITE 親機の設定と起動を行っています。
Serial2.begin(115200 , SERIAL_8N1, ESP_RXD1, ESP_TXD1);
if (Twelite.begin(Serial2,
LED, TWE_RST, TWE_PRG,
TWE_CH, TWE_APPID, TWE_RETRY, TWE_POWER)) {
Serial.println("Started TWELITE." );
}
引数 型 内容 Serial2
HardwareSerial&
TWELITE との通信に使うシリアルポート LED
int
ステータス LED を接続したピンの番号 TWE_RST
int
TWELITE の RST ピンを接続したピンの番号 TWE_PRG
int
TWELITE の PRG ピンを接続したピンの番号 TWE_CHANNEL
uint8_t
TWELITE の 周波数チャネル TWE_APP_ID
uint32_t
TWELITE の アプリケーション ID TWE_RETRY
uint8_t
TWELITE の 再送回数(送信時) TWE_POWER
uint8_t
TWELITE の 送信出力
App_Twelite:イベントハンドラの登録 65-72行目では、Twelite.on() <ParsedAppTwelitePacket>
を呼び出し、超簡単!標準アプリの子機からのパケットを受信した際に行う処理を登録しています。
Twelite.on([](const ParsedAppTwelitePacket& packet) {
Serial.println("Received a packet from App_Twelite" );
String jsonStr = createJsonFrom(packet);
if (not(jsonStr.length() <= 0 )) {
events.send(jsonStr.c_str(), "data_app_twelite" , millis());
}
events.send("parsed_app_twelite" , "data_parsing_result" , millis());
});
JSON 文字列の作成 67行目では、受信したデータからJSON 文字列を生成しています。
String jsonStr = createJsonFrom(packet);
受信したデータをWeb ページに表示するにはクライアント側の JavaScript にデータを送る必要がありますが、このとき文字列データのほうが扱いやすいため、JSON 文字列としています。
Web ページへのイベント送信 68-70行目では、生成した JSON 文字列を “Signal Viewer” ページへ送信しています。
if (not(jsonStr.length() <= 0 )) {
events.send(jsonStr.c_str(), "data_app_twelite" , millis());
}
イベント名は data_app_twelite
です。
各イベントに割り当てる ID には、millis()
で取得した現在時刻を使用しています。
71行目では、App_Twelite からのパケットを受信したことを “Serial Viewer” ページへ送信しています。
events.send("parsed_app_twelite" , "data_parsing_result" , millis());
App_ARIA:イベントハンドラの登録 74-84行目では、Twelite.on() <ParsedAppAriaPacket>
を呼び出し、アリアアプリ(TWELITE ARIA モード)の子機からのパケットを受信した際に行う処理を登録しています。
Twelite.on([](const ParsedAppAriaPacket& packet) {
Serial.println("Received a packet from App_ARIA" );
static uint32_t firstSourceSerialId = packet.u32SourceSerialId;
if (packet.u32SourceSerialId == firstSourceSerialId) {
String jsonStr = createJsonFrom(packet);
if (not(jsonStr.length() <= 0 )) {
events.send(jsonStr.c_str(), "data_app_aria_twelite_aria_mode" , millis());
}
}
events.send("parsed_app_aria_twelite_aria_mode" , "data_parsing_result" , millis());
});
対象の絞り込み 76-77行目では、処理の対象を 最初に受信した子機 に限定しています。
static uint32_t firstSourceSerialId = packet.u32SourceSerialId;
if (packet.u32SourceSerialId == firstSourceSerialId) {
こうしておかないと、複数の子機があった際にグラフの一貫性が失われてしまうからです。
JSON 文字列の作成 78行目では、受信したデータからJSON 文字列を生成しています。
String jsonStr = createJsonFrom(packet);
Web ページへのイベント送信 79-81行目では、生成した JSON 文字列を “ARIA Viewer” ページへ送信しています。
if (not(jsonStr.length() <= 0 )) {
events.send(jsonStr.c_str(), "data_app_aria_twelite_aria_mode" , millis());
}
イベント名は data_app_aria_twelite_aria_mode
です。
83行目では、App_Twelite からのパケットを受信したことを “Serial Viewer” ページへ送信しています。
events.send("parsed_app_aria_twelite_aria_mode" , "data_parsing_result" , millis());
App_CUE:イベントハンドラの登録 86-96行目では、Twelite.on() <ParsedAppCuePacket>
を呼び出し、キューアプリ(TWELITE CUE モード)の子機からのパケットを受信した際に行う処理を登録しています。
Twelite.on([](const ParsedAppCuePacket& packet) {
Serial.println("Received a packet from App_CUE" );
static uint32_t firstSourceSerialId = packet.u32SourceSerialId;
if (packet.u32SourceSerialId == firstSourceSerialId) {
String jsonStr = createJsonFrom(packet);
if (not(jsonStr.length() <= 0 )) {
events.send(jsonStr.c_str(), "data_app_cue_twelite_cue_mode" , millis());
}
}
events.send("parsed_app_cue_twelite_cue_mode" , "data_parsing_result" , millis());
});
その他:イベントハンドラの登録 98-126行目では、その他のアプリの子機からのパケットを受信した際に行う処理を登録しています。
アリアアプリ等と同様に “Serial Viewer” へイベントを送信しています。
すべて:イベントハンドラの登録 128-134行目では、すべてのアプリの子機からのパケットを受信した際に行う処理を登録しています。
Twelite.on([](const BarePacket& packet) {
String jsonStr = createJsonFrom(packet);
if (not(jsonStr.length() <= 0 )) {
events.send(jsonStr.c_str(), "data_bare_packet" , millis());
}
events.send("unparsed_bare_packet" , "data_parsing_result" , millis());
});
ここでも、“Serial Viewer” に対するパケットデータ文字列の送信を行っています。
OLED ディスプレイの設定 137-142行目では、OLED ディスプレイの設定を行っています。
Wire.begin();
SeeedGrayOled.init(SSD1327);
SeeedGrayOled.setNormalDisplay();
SeeedGrayOled.setVerticalMode();
SeeedGrayOled.setGrayLevel(0x0F );
SeeedGrayOled.clearDisplay();
OLED を接続していない場合は何も起こりません。
無線 LAN の設定 146-154行目では、無線 LAN の設定を行っています。
WiFi.mode(WIFI_AP);
char uidCString[8 ];
sprintf(uidCString, " (%02X)" , createUidFromMac());
char ssidCString[20 ];
sprintf(ssidCString, "%s%s" , WIFI_SSID_BASE, uidCString);
WiFi.softAP(ssidCString, WIFI_PASSWORD, WIFI_CH, false, 8 );
delay(100 ); // IMPORTANT: Waiting for SYSTEM_EVENT_AP_START
WiFi.softAPConfig(WIFI_IP, WIFI_IP, WIFI_MASK);
MDNS.begin(HOSTNAME);
delay(100)
を省略すると初期化に失敗することがあります。
ファイルシステムの設定 187行目では、LittleFS ファイルシステムを設定しています。
if (LittleFS.begin()) { Serial.println("Mounted file system." ); }
フラッシュ領域内に書き込んだ HTML などのファイルをページとして取得することができるようになります。
Web サーバの設定 190-217行目では、Web サーバの設定を行っています。
GET リクエストのハンドリング 例えば、195-199行目 では /signal-viewer
への GET リクエストに対して、LittleFS ファイルシステム上の /signal-viewer.html
を返しています。
server.on("/signal-viewer" , HTTP_GET,
[](AsyncWebServerRequest* request) {
Serial.println("HTTP_GET: signal-viewer.html" );
request-> send(LittleFS, "/signal-viewer.html" , "text/html" );
});
サーバの初期化 215-217行目では、ファイルシステム上のルートをサーバのルートとして設定したあと、イベントソースを登録してサーバを立ち上げています。
server.serveStatic("/" , LittleFS, "/" );
server.addHandler(& events);
server.begin();
TWELITE のデータの更新 223行目では、Twelite.update()
を呼び出しています。
Twelite.update()
は、TWELITE 親機から送信されるパケットデータ(ModBus ASCII 形式)を順次1バイトずつ読み出す関数です。
loop()
内で繰り返し
Twelite.update()
を呼ぶことで、TWELITE 親機から送信されるパケットデータの解釈が進みます。パケットデータの解釈を終えた際に
上記 のようなイベントが呼ばれる仕組みです。
delay()
などの処理でこの関数の呼び出しをブロックすると、パケットデータ文字列の読み出しが間に合わないことがあります。時間のかかる処理は必ず非同期の実装として、
loop()
関数をできるだけ高速回転させるようにしてください。
Web ページ Web ページに関しては、詳しい解説を行いません。重要なポイントに絞って解説します。
HTML:グリッドシステム このサンプルの HTML では、Flexbox Grid を使っています(ソースファイルは data/css/flexboxgrid.min.css)。
下記のようにして Bootstrap に似た 12 分割のグリッドシステムを使用しています。
<div class = "col-xs-6 col-sm-6 col-md-5 col-lg-4" >
<div class = "neumorphic inset dense row center-xs middle-xs" >
<div class = "col-xs-12 col-sm-12 col-md-12 col-lg-12 npr npl" >
<img src = "./images/logo-lands.svg" class = "logo" />
</div >
</div >
</div >
<div class = "col-xs-6 col-sm-6 col-md-7 col-lg-8" >
<div class = "neumorphic inset dense row center-xs middle-xs" >
<div class = "col-xs-12 col-sm-12 col-md-12 col-lg-12 nwp npr npl" >
<span class = "medium bold" >TWELITE SPOT</span >
</div >
<div class = "col-xs-12 col-sm-12 col-md-12 col-lg-12 nwp npr npl" >
<span class = "small bold" >CUE Viewer</span >
</div >
</div >
</div >
ここでは、ロゴを中心とした要素の幅を 6/12 、文字列を中心とした要素の幅を 6/12 、すなわち両者を等しい幅で一列に配置しています。また、文字列 TWELITE SPOT
を中心とした要素と CUE Viewer
を中心とした要素の幅はどちらも 12/12 、すなわち1行ずつ2行に分けて配置しています。
xs-
や sm-
などは画面の幅を指定します。レスポンシブデザインに活用できます。
HTML:データ表示部 TWELITE 子機から受信したデータを表示する要素には、一意の ID を付与しています。
以下は TWELITE CUE から受信した X 軸加速度を表示する部分の抜粋です。
<div class = "col-xs-4 nwp npr npl" >
<code class = "medium"
id = "latest-accel-x" >±--.--</code >
<code class = "small" >G</code >
</div >
ここでは、ID として latest-accel-x
を付与しています。この ID を使って、スクリプトから値を書き換えます。
JS:グローバル変数 4-8行目では、最新の加速度値を保存するためのグローバル変数を宣言しています。
let latest_accel = {
x : 0.0 ,
y : 0.0 ,
z : 0.0
};
この値はグラフからも利用するため、実装を簡素にするためにグローバル変数を使用しています。
JS:グラフ設定 11-133行目では、グラフ描画ライブラリ Chart.js | Chart.js およびそのプラグイン chartjs-plugin-streaming の設定を行っています。
JS:ページ内容の更新 136-235行目の関数 processDataAppCueTweliteCueMode()
は、スケッチから data_app_cue_twelite_cue_mode
イベントを受信した際にページ内容を更新する関数です。
例えば、184-208行目では、TWELITE CUE の電源電圧に応じて電圧値と絵文字を更新しています。
if (data .vcc >= 3000 ) {
document.getElementById ("latest-vcc-icon" ).innerHTML = "🔋" ;
document.getElementById ("latest-vcc-data" ).innerHTML = ` ${ (data .vcc / 1000.0 ).toFixed (2 ).toString ().padStart (4 )} ` ;
document.getElementById ("latest-vcc-data" ).classList .remove ("red" );
document.getElementById ("latest-vcc-data" ).classList .remove ("yellow" );
document.getElementById ("latest-vcc-data" ).classList .add ("green" );
} else if (data .vcc >= 2700 ) {
document.getElementById ("latest-vcc-icon" ).innerHTML = "🔋" ;
document.getElementById ("latest-vcc-data" ).innerHTML = ` ${ (data .vcc / 1000.0 ).toFixed (2 ).toString ().padStart (4 )} ` ;
document.getElementById ("latest-vcc-data" ).classList .remove ("red" );
document.getElementById ("latest-vcc-data" ).classList .remove ("yellow" );
document.getElementById ("latest-vcc-data" ).classList .remove ("green" );
} else if (data .vcc >= 2400 ) {
document.getElementById ("latest-vcc-icon" ).innerHTML = "🪫" ;
document.getElementById ("latest-vcc-data" ).innerHTML = ` ${ (data .vcc / 1000.0 ).toFixed (2 ).toString ().padStart (4 )} ` ;
document.getElementById ("latest-vcc-data" ).classList .remove ("red" );
document.getElementById ("latest-vcc-data" ).classList .add ("yellow" );
document.getElementById ("latest-vcc-data" ).classList .remove ("green" );
} else {
document.getElementById ("latest-vcc-icon" ).innerHTML = "🪫" ;
document.getElementById ("latest-vcc-data" ).innerHTML = ` ${ (data .vcc / 1000.0 ).toFixed (2 ).toString ().padStart (4 )} ` ;
document.getElementById ("latest-vcc-data" ).classList .add ("red" );
document.getElementById ("latest-vcc-data" ).classList .remove ("yellow" );
document.getElementById ("latest-vcc-data" ).classList .remove ("green" );
}
ここでは、電源電圧が 2700mV 未満に降下した際に絵文字を 🔋 から 🪫 に変えているほか、3000mV → 2700mV → 2400mV と電圧降下に従って電圧値の文字色を適用する CSS クラスを入れ替えています。
イベントリスナーの登録 254-257行目では、スケッチからのイベントを受信した際の処理を登録しています。
source .addEventListener ("data_app_cue_twelite_cue_mode" , (e ) => {
console .log ("data_app_cue_twelite_cue_mode" , e .data );
processDataAppCueTweliteCueMode (JSON .parse (e .data ));
}, false );
ここでは、スケッチより 受信したイベントメッセージから JSON 文字列を取り出し、パースしたデータを先ほどの関数 processDataAppCueTweliteCueMode()
へ渡しています。
関連情報 Arduino ESP32 コミュニティ ライブラリ プラグイン Web関連 ECMAScript (JavaScript) コミュニティ 2.5.2.2 - WebSocketによる中継 子機からのデータを WebSocket サーバに中継するサンプルスケッチ spot-router の解説
無線 LAN 子機として振る舞い、LAN 上の WebSocket サーバに受信したパケットデータ文字列を中継するサンプルスケッチ
spot-router
の解説です。
2.5.2.2.1 - WebSocketによる中継 最新版
無線 LAN 子機として振る舞い、LAN 上の WebSocket サーバに受信したパケットデータ文字列を中継するサンプルスケッチ
spot-router
の解説です。
本稿では、サードパーティのオープンソースソフトウェアを使用します。
サードパーティのソフトウェアについて、その詳しい使用方法を弊社からご案内することはいたしかねます。また、サードパーティのソフトウェアを使用されたことによるいかなる損害についても、弊社は一切の責任を負いません。
ソースコードの入手 GitHub (monowireless/spot-router ) から入手できます。
システムの概要 spot-router は、TWELITE 親機が受信したデータに基づき出力した文字列(App_Wings の ModBus ASCII 形式)を WebSocket サーバへ転送します。
spot-server が中継したデータを受け取るには、WebSocket サーバを立てる必要があります。
開発に必要なもの 環境整備 IDE とツールチェインの導入 Arduino IDE 1.x による開発環境の構築方法 をご覧ください。
ライブラリの導入 はじめに、Arduino のスケッチブックの保存場所(Arduino IDE 環境設定に記載。例:C:\Users\foo\Documents\Arduino
) に libraries
フォルダがない場合は、これを作成します。
WebSocket ライブラリ GitHub (Links2004/arduinoWebSockets) から Zip ファイルをダウンロードしますZip ファイルを展開し、libraries
フォルダに arduinoWebSockets-<バージョン>
フォルダを配置します プロジェクトファイルの入手 GitHub (monowireless/spot-router) から Zip ファイルをダウンロードしますZip ファイルを展開し、フォルダ名を spot-router-main
から spot-router
に変更します Arduino のスケッチブックの保存場所(Arduino IDE 環境設定に記載。例:C:\Users\foo\Documents\Arduino
)に spot-router
フォルダを配置します ユーザ設定の変更 Arduino IDE 上部のタブから config.h
を開き、無線 LAN や WebSocket サーバに関する設定( 詳細 )を変更してください。
プロジェクトファイルの書き込み方法 ESP32 へのスケッチの書き込み方法 をご覧ください。
スケッチ Arduino スケッチ spot-router.ino の解説です。
ライブラリのインクルード Arduino および ESP32 公式ライブラリ 4-5行目では、Arduino および ESP32 の公式ライブラリをインクルードしています。
#include <Arduino.h>
#include <WiFi.h>
ヘッダファイル 内容 備考 Arduino.h
Arduino の基本ライブラリ 省略できる場合もあるが念のため記載 WiFi.h
ESP32 の WiFi を使う
サードパーティのライブラリ 8行目では、サードパーティのライブラリをインクルードしています。
#include <WebSocketsClient.h>
ヘッダファイル 内容 備考 WebSocketsClient.h
WebSocket クライアントになる
MWings ライブラリ 11行目では、MWings ライブラリをインクルードしています。
ユーザ設定の定義 14行目では、config.h
をインクルードしています。
config.h
では、ユーザ設定を定義しています。実行時には、この設定を書き換えてください。
無線 LAN 設定の定義 config.h
の4-5行目では、TWELITE SPOT に搭載された ESP32 に適用する無線 LAN 設定を定義しています。
const char * WIFI_SSID = "YOUR SSID" ; // Modify it
const char * WIFI_PASSWORD = "YOUR PASSWORD" ; // Modify it
名称 内容 WIFI_SSID
接続するネットワークの SSID WIFI_PASSWORD
接続するネットワークの パスワード
WebSocket 設定の定義 config.h
の8-10行目では、WebSocket クライアントの設定を定義しています。
const char * WS_SERVER_IP = "YOUR ADDRESS" ; // Modify it
const int WS_SERVER_PORT = 8080 ;
const char * WS_SERVER_PATH = "/" ;
名称 内容 WS_SERVER_IP
送信するサーバの IP アドレス WS_SERVER_PORT
送信するサーバのポート番号 WS_SERVER_PATH
送信するサーバの WebSocket サーバのパス
ピン番号の定義 17-21行目では、ピン番号を定義しています。
const uint8_t TWE_RST = 5 ;
const uint8_t TWE_PRG = 4 ;
const uint8_t LED = 18 ;
const uint8_t ESP_RXD1 = 16 ;
const uint8_t ESP_TXD1 = 17 ;
名称 内容 TWE_RST
TWELITE の RST ピンが接続されているピンの番号 TWE_PRG
TWELITE の PRG ピンが接続されているピンの番号 LED
基板上の ESP32 用 LED が接続されているピンの番号 ESP_RXD1
TWELITE の TX ピンが接続されているピンの番号 ESP_TXD1
TWELITE の RX ピンが接続されているピンの番号
TWELITE 設定の定義 24-27行目では、TWELITE SPOT に搭載された TWELITE 親機に適用する設定を定義しています。
const uint8_t TWE_CH = 18 ;
const uint32_t TWE_APPID = 0x67720102 ;
const uint8_t TWE_RETRY = 2 ;
const uint8_t TWE_POWER = 3 ;
名称 内容 TWE_CH
TWELITE の 周波数チャネル TWE_APPID
TWELITE の アプリケーション ID TWE_RETRY
TWELITE の 再送回数(送信時) TWE_POWER
TWELITE の 送信出力
このサンプルでは、TWELITE 親機からのコマンド送信を行わないため、29-30行目の内容は関係ありません。
グローバルオブジェクトの宣言 30行目では、グローバルオブジェクトを宣言しています。
WebSocketsClient webSocket;
名称 内容 webSocket
WebSocket クライアントのインタフェース
関数プロトタイプの宣言 33行目では、関数プロトタイプを宣言しています。
String createPacketStringFrom (const BarePacket& packet);
名称 内容 createPacketStringFrom()
受信したパケットデータから書式文字列を再構築します
TWELITE の設定 42-47行目では、Twelite.begin()
を呼び出し、TWELITE SPOT に搭載された TWELITE 親機の設定と起動を行っています。
Serial2.begin(115200 , SERIAL_8N1, ESP_RXD1, ESP_TXD1);
if (Twelite.begin(Serial2,
LED, TWE_RST, TWE_PRG,
TWE_CH, TWE_APPID, TWE_RETRY, TWE_POWER)) {
Serial.println("Started TWELITE." );
}
引数 型 内容 Serial2
HardwareSerial&
TWELITE との通信に使うシリアルポート LED
int
ステータス LED を接続したピンの番号 TWE_RST
int
TWELITE の RST ピンを接続したピンの番号 TWE_PRG
int
TWELITE の PRG ピンを接続したピンの番号 TWE_CHANNEL
uint8_t
TWELITE の 周波数チャネル TWE_APP_ID
uint32_t
TWELITE の アプリケーション ID TWE_RETRY
uint8_t
TWELITE の 再送回数(送信時) TWE_POWER
uint8_t
TWELITE の 送信出力
イベントハンドラの登録 49-54行目では、すべてのアプリの子機からのパケットを受信した際に行う処理を登録しています。
Twelite.on([](const BarePacket& packet) {
String packetStr = createPacketStringFrom(packet);
if (not(packetStr.length() <= 0 )) {
webSocket.sendTXT(packetStr.c_str());
}
});
ここでは、パケットデータから書式文字列(ModBus ASCII 形式)を再構成し、WebSocket サーバへ送信しています。
無線 LAN の設定 57-71行目では、無線 LAN の設定を行っています。
WiFi.mode(WIFI_STA);
WiFi.setAutoReconnect(true);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Serial.print("Connecting to WiFi .." );
while (WiFi.status() != WL_CONNECTED) {
static int count = 0 ;
Serial.print('.' );
delay(500 );
// Retry every 5 seconds
if (count++ % 10 == 0 ) {
WiFi.disconnect();
WiFi.reconnect();
Serial.print('!' );
}
}
ここでは、無線 LAN 子機として設定したうえで、指定のネットワークへ接続しています。
ネットワークに接続できるまで、while
文を出ません。
WebSocket の設定 76-77行目では、WebSocket を設定しています。
webSocket.begin(WS_SERVER_IP, WS_SERVER_PORT, WS_SERVER_PATH);
webSocket.setReconnectInterval(5000 );
ここでは、WebSocket サーバと再接続間隔を指定しています。
また、78-97行目では、サーバとの接続が切断されたとき、サーバと接続したとき、そしてメッセージを受信したときのイベントを登録しています。
webSocket.onEvent([](WStype_t type, uint8_t * payload, size_t length) {
switch (type) {
case WStype_DISCONNECTED: {
Serial.println("Disconnected!" );
break ;
}
case WStype_CONNECTED: {
Serial.print("Connected to url: " );
Serial.println(reinterpret_cast < char *> (payload));
webSocket.sendTXT("This is TWELITE SPOT to ground control" );
break ;
}
case WStype_TEXT: {
Serial.print("Got text: " );
Serial.println(reinterpret_cast < char *> (payload));
break ;
}
default : break ;
}
});
なかでも、サーバと接続したときには、サーバへメッセージを送るようにしています。
webSocket.sendTXT("This is TWELITE SPOT to ground control" );
TWELITE のデータの更新 102行目では、Twelite.update()
を呼び出しています。
Twelite.update()
は、TWELITE 親機から送信されるパケットデータ(ModBus ASCII 形式)を順次1バイトずつ読み出す関数です。
loop()
内で繰り返し
Twelite.update()
を呼ぶことで、TWELITE 親機から送信されるパケットデータの解釈が進みます。パケットデータの解釈を終えた際に
上記 のようなイベントが呼ばれる仕組みです。
delay()
などの処理でこの関数の呼び出しをブロックすると、パケットデータ文字列の読み出しが間に合わないことがあります。時間のかかる処理は必ず非同期の実装として、
loop()
関数をできるだけ高速回転させるようにしてください。
WebSocket のデータの更新 103行目では、WebSocket のデータを更新する処理を呼び出しています。
Twelite.update()
と同様に、
delay()
などの処理でこの関数の呼び出しをブロックすると、データ更新が間に合わないことがあります。時間のかかる処理は必ず非同期の実装として、
loop()
関数をできるだけ高速回転させるようにしてください。
<付録> WebSocket サーバによる動作確認 extra/python-websocket-server/server.py
は、Python スクリプトによって WebSocket サーバを立て、ESP32 からのパケットデータ文字列を表示するサンプルスクリプトです。このスクリプトを使うことで、スケッチの動作を確認できます。
# -*- coding: utf-8-unix -*-
# Python 3.11
import logging
from websocket_server import WebsocketServer
def new_client (client, server):
server. send_message_to_all("This is ground control to TWELITE SPOT" )
def new_message (client, server, message):
print("Received an message:" )
print(message)
server = WebsocketServer(host= "YOUR IP ADDRESS" , port= 8080 , loglevel= logging. INFO)
server. set_fn_new_client(new_client)
server. set_fn_message_received(new_message)
server. run_forever()
coding
変数を指定しているのは、筆者の環境が Emacs だからです。おまじないではありません。
動作確認の手順 スクリプトの実行 依存モジュール をインストールしてから実行します。
pip3 install websocket-server
python3 server.py
実行すると、下記のようなメッセージが表示されます。
INFO:websocket_server.websocket_server:Listening on port 8080 for clients..
INFO:websocket_server.websocket_server:Starting WebsocketServer on main thread.
クライアントの接続を確認 ESP32 が 無線 LAN への接続に成功すると、WebSocket サーバへの接続を試みます。
接続に成功すると、クライアント側のシリアルコンソールには下記のように出力されます。
Started TWELITE.
Connecting to WiFi .....
Connected. IP: xxx.xxx.xxx.xxx
Connected to url: /
Got text: This is ground control to TWELITE SPOT
一方で、サーバ側のターミナルには下記のように出力されます。
Received an message:
This is TWELITE SPOT to ground control
以降、TWELITE SPOT が子機からのパケットを受信すると、下記のようにサーバ側のターミナルへパケットデータ文字列が出力されます。
Received an message:
:80000000DE10098201BC8201800607003400038135001205350401000000113008020A8C1130010203AF0000000180050100020AC60102000211D7AF30
Received an message:
:80000000E4100A8201BC8201800607003400038135001205350401000000113008020A8C1130010203AC0000000180050100020AC40102000211DB0DCC
関連情報 TWELITE Arduino ESP32 コミュニティ ライブラリ プラグイン ネットワーク関連 WebSocket コミュニティ 2.5.2.3 - REST API の使用 子機からのデータを HTTP GET リクエストに利用するサンプルスケッチ spot-httpbin の解説
無線 LAN 子機として振る舞い、Web 上のモックサーバ httpbin.org へ受信したパケットのデータを送信するサンプルスケッチ
spot-httpbin
の解説です。
2.5.2.3.1 - REST API の使用 最新版
無線 LAN 子機として振る舞い、Web 上のモックサーバ
httpbin.org へ受信したパケットのデータを送信するサンプルスケッチ
spot-httpbin
の解説です。
本稿では、サードパーティのオープンソースソフトウェアを使用します。
サードパーティのソフトウェアについて、その詳しい使用方法を弊社からご案内することはいたしかねます。また、サードパーティのソフトウェアを使用されたことによるいかなる損害についても、弊社は一切の責任を負いません。
ソースコードの入手 GitHub リポジトリ monowireless/spot-httpbin から入手できます。
システムの概要 spot-httpbin は、TWELITE 親機が受信したデータの一部と NTP による現在時刻を HTTP GET リクエストとしてモックサーバへ送信し、そのレスポンスをシリアルモニタへ表示します。
このサンプルでは例として子機に TWELITE ARIA を使用しますが、HTTP リクエストの使用方法には関係ありません。
開発に必要なもの 環境整備 IDE とツールチェインの導入 Arduino IDE 1.x による開発環境の構築方法 をご覧ください。
ライブラリの導入 このサンプルでは、依存するライブラリをはじめから同梱しています。
スケッチと同じ階層の src
フォルダの内容は IDE に表示されませんが、再帰的にビルドされます。
プロジェクトファイルの入手 GitHub (monowireless/spot-httpbin) から Zip ファイルをダウンロードしますZip ファイルを展開し、フォルダ名を spot-httpbin-main
から spot-httpbin
に変更します Arduino のスケッチブックの保存場所(Arduino IDE 環境設定に記載。例:C:\Users\foo\Documents\Arduino
)に spot-httpbin
フォルダを配置します ユーザ設定の変更 Arduino IDE 上部のタブから config.h
を開き、Wi-Fi の SSID と パスワードを設定してください。WPA2-PSK ネットワークを想定しています。また、ルート証明書も登録してください。ルート証明書は、Chrome などのウェブブラウザの各ページに対するセキュリティ画面から入手できます。
ルート証明書(拡張子.cer
)は、下記のような形式のテキストファイルです。
-----BEGIN CERTIFICATE-----
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-----END CERTIFICATE-----
プロジェクトファイルの書き込み方法 ESP32 へのスケッチの書き込み方法 をご覧ください。
スケッチ Arduino スケッチ spot-httpbin.ino
および config.h
の解説です。
ライブラリのインクルード Arduino および ESP32 公式ライブラリ 4-6行目では、Arduino および ESP32 の公式ライブラリをインクルードしています。
#include <Arduino.h>
#include <WiFiClientSecure.h>
#include <WiFiUdp.h>
ヘッダファイル 内容 備考 Arduino.h
Arduino の基本ライブラリ 省略できる場合もあるが念のため記載 WiFiClientSecure.h
ESP32 で SSL通信を行う WiFiUdp.h
UDP 通信を行う NTP に必要
サードパーティのライブラリ 9-10行目では、同梱されたサードパーティのライブラリをインクルードしています。
#include "src/NTPClient/NTPClient.h"
#include "src/Time/TimeLib.h"
ヘッダファイル 内容 備考 NTPClient.h
NTP サーバへアクセスする TimeLib.h
エポック時間を変換する
MWings ライブラリ 13行目では、MWings ライブラリをインクルードしています。
ユーザ設定の定義 16行目では、config.h
をインクルードしています。
config.h
では、ユーザ設定を定義しています。実行時には、この設定を書き換えてください。
データ型の定義 19-26行目では、子機から受信したデータを保管しておく構造体の型を定義しています。
struct DataFromAria {
uint32_t serialId;
uint8_t logicalId;
uint16_t supplyVoltage;
uint8_t linkQuality;
int16_t temp100x;
uint16_t humid100x;
};
名称 内容 serialId
シリアルID logicalId
論理デバイスID supplyVoltage
電源電圧 linkQuality
LQI temp100x
100倍された温度 humid100x
100倍された湿度
ここでは、TWELITE ARIA を使用します。
config.h
再起動間隔の定義 config.h
の4行目では、ESP32 の再起動間隔を指定しています。
const uint32_t REBOOT_INTERVAL = 21600 ; // seconds
ここでは、21600秒=6時間としています。
長期間の運用では、メモリリークが累積して不具合を起こしてしまう場合があります。
そこで Wi-Fi ルータのように定期的な再起動を行うようにしています。
TWELITE 設定の定義 config.h
の7-8行目では、TWELITE SPOT に搭載された TWELITE 親機に適用する設定を定義しています。
const uint8_t TWE_CH = 18 ;
const uint32_t TWE_APPID = 0x67720102 ;
名称 内容 TWE_CH
TWELITE の 周波数チャネル TWE_APPID
TWELITE の アプリケーション ID
Wi-Fi 設定の定義 config.h
の11-12行目では、TWELITE SPOT に搭載された ESP32 に適用するWi-Fi 設定を定義しています。
const char * WIFI_SSID = "YOUR SSID" ;
const char * WIFI_PASSWORD = "YOUR PASSWORD" ;
名称 内容 WIFI_SSID
接続するネットワークの SSID WIFI_PASSWORD
接続するネットワークの パスワード
ルート証明書 config.h
の14-16行目では、ルート証明書の内容を記述するためのテンプレートを用意しています。
const char * CA_CERT =
"-----BEGIN CERTIFICATE----- \n "
"-----END CERTIFICATE----- \n " ;
ルート証明書は、Chrome などのウェブブラウザの各ページに対するセキュリティ画面から入手してください。
すべての行をダブルクォートで囲い、末尾のダブルクォートの前には改行文字 \n
を追加する必要があります。
ホストの設定 config.h
の18-19行目では、ホストの設定を定義しています。
const char * SERVER_HOST = "www.httpbin.org" ;
const uint16_t SERVER_PORT = 443 ;
名称 内容 SERVER_HOST
サーバのホスト名 SERVER_PORT
サーバのポート番号
各種定数の定義 config.h
の21行目からは、各種定数を定義しています。
const uint32_t NTP_UPDATE_INTERVAL = 10000 ; // ms
const int QUERIES_MAX_LENGTH = 128 ; // bytes (without \0)
const int32_t CONNECT_TIMEOUT = 10 ; // seconds
const uint32_t RECONNECT_MIN_INTERVAL = 5 ; // seconds
// SEND_MIN_INTERVAL must be longer than NTP_UPDATE_INTERVAL
const uint32_t SEND_MIN_INTERVAL = 10 ; // seconds
const uint32_t REQUEST_TIMEOUT = 10 ; // seconds
名称 内容 NTP_UPDATE_INTERVAL
NTP時刻の取得間隔 QUERIES_MAX_LENGTH
クエリ文字列の最大長(ヌル文字含まず) CONNECT_TIMEOUT
サーバへの接続時のタイムアウト RECONNECT_MIN_INTERVAL
Wi-Fiアクセスポイントへ再接続する際の最短間隔 SEND_MIN_INTERVAL
リクエスト間隔の最短間隔 REQUEST_TIMEOUT
リクエストからレスポンスまでのタイムアウト
SEND_MIN_INTERVAL
は、NTP_UPDATE_INTERVAL
以上に設定しています。
リクエスト間隔が短いと、リクエスト間でタイムスタンプが重複してしまう可能性があるからです。
SEND_MIN_INTERVAL
を短くすると、連続してパケットを受信した場合にサーバへ負担をかけてしまいます。
必ず適度な間隔を空けてください。
ピン番号の定義 29-34行目では、ピン番号を定義しています。
static const int RST_PIN = 5 ;
static const int PRG_PIN = 4 ;
static const int LED_PIN = 18 ;
static const int8_t RX1_PIN = 16 ;
static const int8_t TX1_PIN = 17 ;
名称 内容 RST_PIN
TWELITE の RST ピンが接続されているピンの番号 PRG_PIN
TWELITE の PRG ピンが接続されているピンの番号 LED_PIN
基板上の ESP32 用 LED が接続されているピンの番号 RX1_PIN
TWELITE の RX1 ピンが接続されているピンの番号 TX1_PIN
TWELITE の TX1 ピンが接続されているピンの番号
グローバルオブジェクトの宣言 37-40行目では、グローバルオブジェクトを宣言しています。
static WiFiClientSecure client;
static WiFiUDP ntpUDP;
static NTPClient timeClient (ntpUDP, "ntp.nict.jp" ,
32400 , NTP_UPDATE_INTERVAL); // JST(UTC+9)
名称 内容 client
HTTPS通信のインタフェース ntpUDP
NTP用のUDP通信のインタフェース timeClient
NTPのインタフェース
グローバル変数の宣言 43-44行目では、グローバル変数を宣言しています。
static DataFromAria LatestDataFromAria;
static bool IsThereNewDataFromAria;
名称 内容 LatestDataFromAria
TWELITE ARIA から受信した最新のデータ IsThereNewDataFromAria
TWELITE ARIA から新たなデータを受信したことを示すフラグ
関数プロトタイプの宣言 47-59行目では、関数プロトタイプを宣言しています。
void anotherLoopForTWELITE ();
void anotherLoopForNTP ();
名称 内容 anotherLoopForTWELITE
TWELITEのデータを処理するためのループ関数 anotherLoopForNTP
NTPで時刻を取得するためのループ関数
void initTWELITE ();
void initWiFi ();
void initNTP ();
名称 内容 initTWELITE
TWELITEの初期化関数 initWiFi
Wi-Fiの初期化関数 initNTP
NTPの初期化関数
void onAppAriaPacket (const ParsedAppAriaPacket& packet);
名称 内容 onAppAriaPacket
TWELITE ARIA からデータを受信した際のコールバック関数
void sendAriaData(const DataFromAria& data)
名称 内容 sendAriaData
TWELITE ARIAのデータを HTTP GET リクエストにのせて送る関数
setup()
62-90行目では、全体の初期化を行います。
void setup () {
Serial.begin(115200 );
initTWELITE();
initWiFi();
initNTP();
// Attach another loop function for TWELITE
// Note: Core 0 is also used for the WiFi task, which priority is 19 (ESP_TASKD_EVENT_PRIO - 1)
xTaskCreatePinnedToCore(
[](void * params) {
while (true) {
anotherLoopForTWELITE();
vTaskDelay(1 ); // IMPORTANT for Watchdog
}
},
"Task for anotherLoopForTWELITE()" , 8192 , nullptr , 18 , nullptr ,
0 ); // Priority is 18 (lower than WiFi)
// Attach another loop function for NTP
xTaskCreatePinnedToCore(
[](void * params) {
while (true) {
anotherLoopForNTP();
vTaskDelay(1 ); // IMPORTANT for Watchdog
}
},
"Task for anotherLoopForNTP()" , 8192 , nullptr , 17 , nullptr ,
0 ); // Priority is 17 (lower than WiFi and TWELITE)
}
xTaskCreatePinnedToCore()
により、loop()
とは別のタスクを登録しています。
下記の部分はキャプチャのない無名関数です。不要なグローバル空間の汚染を避けることができます。
[](void * params) {
while (true) {
anotherLoopForTWELITE();
vTaskDelay(1 ); // IMPORTANT for Watchdog
}
},
ウォッチドッグタイマへ介入する余地を設けるために、vTaskDelay()
を挿入しています。
loop()
93-114行目は、主となるループ処理です。
HTTP リクエストの処理、Wi-Fi 切断時の再接続処理、定期リセットの処理を行います。
void loop () {
static uint32_t lastTimeReconnected = 0 ;
if (WiFi.status() == WL_CONNECTED) {
// Regular operations
// Check for new data
if (IsThereNewDataFromAria) {
IsThereNewDataFromAria = false; // Clear first; data is updated on another thread
DataFromAria data = LatestDataFromAria; // Now, the buffer is open for incoming data
sendAriaData(data);
}
} else if (millis() - lastTimeReconnected > RECONNECT_MIN_INTERVAL * 1000 ) {
// Lost connection, reconnect periodically
Serial.println("Disconnected. Reconnecting to WiFi..." );
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
lastTimeReconnected = millis();
}
// Reboot every x interval
if (millis() > REBOOT_INTERVAL * 1000 ) {
Serial.println("Rebooting..." );
ESP.restart();
}
}
anotherLoopForTWELITE()
117-119行目は、TWELITE のためのループ処理です。
データの受信と解釈を逐次行うため、ブロッキング処理を含む loop()
とは別のタスクとしています。
void anotherLoopForTWELITE () {
Twelite.update();
}
anotherLoopForNTP()
120-123行目は、NTP のためのループ処理です。
こちらについても UDP の通信を行うため、ブロッキング処理を含む loop()
とは別のタスクとしています。
void anotherLoopForNTP () {
timeClient.update();
setTime(timeClient.getEpochTime());
}
initTWELITE()
126-133行目は、TWELITE の初期化処理です。
TWELITE SPOT に搭載された TWELITE を指定された設定で起動し、パケット受信時のコールバック関数を登録しています。
void initTWELITE () {
Serial2.begin(115200 );
if (Twelite.begin(Serial2, LED_PIN, RST_PIN, PRG_PIN, TWE_CHANNEL, TWE_APP_ID)) {
Serial.println("Started TWELITE." );
}
// Attach event handlers to process packets
Twelite.on(onAppAriaPacket);
}
initWiFi()
136-160行目は、Wi-Fi の初期化処理です。
接続されない場合は、5秒置きに再接続を試みます。
void initWiFi () {
Serial.print(" \n Connecting to the WiFi network " );
Serial.print(WIFI_SSID);
Serial.println("..." );
// Begin
WiFi.mode(WIFI_STA);
WiFi.setAutoReconnect(true);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
// Wait for connection
Serial.print("Connecting." );
while (WiFi.status() != WL_CONNECTED) x
static int count = 0 ;
Serial.print('.' );
delay(500 );
// Retry every 5 seconds
if (count++ % 10 == 0 ) {
WiFi.disconnect();
WiFi.reconnect();
Serial.print('!' );
}
}
Serial.println(" \n Connected!" );
// Set Root CA certificate
client.setCACert(CA_CERT);
}
initNTP()
163-167行目は、NTP の初期化処理です。
void initNTP () {
timeClient.begin();
timeClient.update();
setTime(timeClient.getEpochTime());
}
onAppAriaPacket()
170-180行目には、TWELITE ARIA からデータを受信した際の処理を記述しています。
ここでは HTTP の送信処理を行わず、グローバル変数へセットしています。
グローバル変数へセットしたデータは、別のタスクで sendAriaData()
によって処理します。
void onAppAriaPacket (const ParsedAppAriaPacket& packet)
{
// Store data
LatestDataFromAria.serialId = packet.u32SourceSerialId;
LatestDataFromAria.logicalId = packet.u8SourceLogicalId;
LatestDataFromAria.supplyVoltage = packet.u16SupplyVoltage;
LatestDataFromAria.linkQuality = packet.u8Lqi;
LatestDataFromAria.temp100x = packet.i16Temp100x;
LatestDataFromAria.humid100x = packet.u16Humid100x;
IsThereNewDataFromAria = true;
}
sendAriaData()
183-240行目は、TWELITE ARIA のデータを HTTP GET リクエストのクエリ文字列にセットして送信する関数です。
コードを簡潔とするために、HTTP GET を使用しています。
HTTP POST を使用される場合は、リクエストボディを追加してください。
サーバへの過度な負荷を防ぐため、高頻度でパケットが到着した際には送信をスキップしています。
void sendAriaData (const DataFromAria& data)
{
static uint32_t lastTimeRequested = 0 ;
if (millis() - lastTimeRequested > SEND_MIN_INTERVAL * 1000 or lastTimeRequested == 0 ) {
Serial.println("Connecting to the server..." );
if (not client.connect(SERVER_HOST, SERVER_PORT, CONNECT_TIMEOUT * 1000 )) {
Serial.println("Connection failed!" );
} else {
Serial.println("Connected to the server!" );
// Make a query string
char queries[QUERIES_MAX_LENGTH+ 1 ];
snprintf(queries, sizeof (queries),
"datetime=%04d%02d%02d%02d%02d%02d&sid=%X&lid=%d&temp=%d&humid=%d&bat=%d&lqi=%d" ,
// Note that NTP_UPDATE_INTERVAL is set for 10000ms by default; second() delays up to 10s.
// To prevent duplication of datetime, SEND_MIN_INTERVAL is set for 10s.
year(), month(), day(), hour(), minute(), second(),
data.serialId,
data.logicalId,
data.temp100x,
data.humid100x,
data.supplyVoltage,
data.linkQuality);
// Send a request
client.println(String("GET https://" ) +
SERVER_HOST +
String("/get?" ) +
queries +
String(" HTTP/1.1" ));
client.println("Accept: */*" );
client.println(String("Host: " ) + SERVER_HOST);
client.println("Connection: close" );
client.println();
uint32_t timeSentRequest = millis();
// Handle a response
while (client.connected()) {
String line = client.readStringUntil('\n' );
if (line == " \r " ) {
Serial.println("Headers received" );
break ;
}
if (millis() - timeSentRequest > REQUEST_TIMEOUT * 1000 ) {
Serial.println("Request was timed out" );
break ;
}
}
while (client.available()) {
char c = client.read();
Serial.write(c);
}
client.stop();
}
lastTimeRequested = millis();
} else {
Serial.println("Requests are too frequently; skip." );
}
}
2.5.2.3.2 - REST API の使用 mwings-v1.1.3
無線 LAN 子機として振る舞い、Web 上のモックサーバ
httpbin.org へ受信したパケットのデータを送信するサンプルスケッチ
spot-httpbin
の解説です。
本稿では、サードパーティのオープンソースソフトウェアを使用します。
サードパーティのソフトウェアについて、その詳しい使用方法を弊社からご案内することはいたしかねます。また、サードパーティのソフトウェアを使用されたことによるいかなる損害についても、弊社は一切の責任を負いません。
ソースコードの入手 GitHub リポジトリ monowireless/spot-httpbin から入手できます。
システムの概要 spot-httpbin は、TWELITE 親機が受信したデータの一部と NTP による現在時刻を HTTP GET リクエストとしてモックサーバへ送信し、そのレスポンスをシリアルモニタへ表示します。
このサンプルでは例として子機に TWELITE ARIA を使用しますが、HTTP リクエストの使用方法には関係ありません。
開発に必要なもの 環境整備 IDE とツールチェインの導入 Arduino IDE 1.x による開発環境の構築方法 をご覧ください。
ライブラリの導入 このサンプルでは、依存するライブラリをはじめから同梱しています。
スケッチと同じ階層の src
フォルダの内容は IDE に表示されませんが、再帰的にビルドされます。
プロジェクトファイルの入手 GitHub (monowireless/spot-httpbin) から Zip ファイルをダウンロードしますZip ファイルを展開し、フォルダ名を spot-httpbin-main
から spot-httpbin
に変更します Arduino のスケッチブックの保存場所(Arduino IDE 環境設定に記載。例:C:\Users\foo\Documents\Arduino
)に spot-httpbin
フォルダを配置します ユーザ設定の変更 Arduino IDE 上部のタブから config.h
を開き、Wi-Fi の SSID と パスワードを設定してください。WPA2-PSK ネットワークを想定しています。また、ルート証明書も登録してください。ルート証明書は、Chrome などのウェブブラウザの各ページに対するセキュリティ画面から入手できます。
ルート証明書(拡張子.cer
)は、下記のような形式のテキストファイルです。
-----BEGIN CERTIFICATE-----
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-----END CERTIFICATE-----
プロジェクトファイルの書き込み方法 ESP32 へのスケッチの書き込み方法 をご覧ください。
スケッチ Arduino スケッチ spot-httpbin.ino
および config.h
の解説です。
ライブラリのインクルード Arduino および ESP32 公式ライブラリ 4-6行目では、Arduino および ESP32 の公式ライブラリをインクルードしています。
#include <Arduino.h>
#include <WiFiClientSecure.h>
#include <WiFiUdp.h>
ヘッダファイル 内容 備考 Arduino.h
Arduino の基本ライブラリ 省略できる場合もあるが念のため記載 WiFiClientSecure.h
ESP32 で SSL通信を行う WiFiUdp.h
UDP 通信を行う NTP に必要
サードパーティのライブラリ 9-10行目では、同梱されたサードパーティのライブラリをインクルードしています。
#include "src/NTPClient/NTPClient.h"
#include "src/Time/TimeLib.h"
ヘッダファイル 内容 備考 NTPClient.h
NTP サーバへアクセスする TimeLib.h
エポック時間を変換する
MWings ライブラリ 13行目では、MWings ライブラリをインクルードしています。
ユーザ設定の定義 16行目では、config.h
をインクルードしています。
config.h
では、ユーザ設定を定義しています。実行時には、この設定を書き換えてください。
データ型の定義 19-26行目では、子機から受信したデータを保管しておく構造体の型を定義しています。
struct DataFromAria {
uint32_t serialId;
uint8_t logicalId;
uint16_t supplyVoltage;
uint8_t linkQuality;
int16_t temp100x;
uint16_t humid100x;
};
名称 内容 serialId
シリアルID logicalId
論理デバイスID supplyVoltage
電源電圧 linkQuality
LQI temp100x
100倍された温度 humid100x
100倍された湿度
ここでは、TWELITE ARIA を使用します。
config.h
再起動間隔の定義 config.h
の4行目では、ESP32 の再起動間隔を指定しています。
const uint32_t REBOOT_INTERVAL = 21600 ; // seconds
ここでは、21600秒=6時間としています。
長期間の運用では、メモリリークが累積して不具合を起こしてしまう場合があります。
そこで Wi-Fi ルータのように定期的な再起動を行うようにしています。
TWELITE 設定の定義 config.h
の7-8行目では、TWELITE SPOT に搭載された TWELITE 親機に適用する設定を定義しています。
const uint8_t TWE_CH = 18 ;
const uint32_t TWE_APPID = 0x67720102 ;
名称 内容 TWE_CH
TWELITE の 周波数チャネル TWE_APPID
TWELITE の アプリケーション ID
Wi-Fi 設定の定義 config.h
の11-12行目では、TWELITE SPOT に搭載された ESP32 に適用するWi-Fi 設定を定義しています。
const char * WIFI_SSID = "YOUR SSID" ;
const char * WIFI_PASSWORD = "YOUR PASSWORD" ;
名称 内容 WIFI_SSID
接続するネットワークの SSID WIFI_PASSWORD
接続するネットワークの パスワード
ルート証明書 config.h
の14-16行目では、ルート証明書の内容を記述するためのテンプレートを用意しています。
const char * CA_CERT =
"-----BEGIN CERTIFICATE----- \n "
"-----END CERTIFICATE----- \n " ;
ルート証明書は、Chrome などのウェブブラウザの各ページに対するセキュリティ画面から入手してください。
すべての行をダブルクォートで囲い、末尾のダブルクォートの前には改行文字 \n
を追加する必要があります。
ホストの設定 config.h
の18-19行目では、ホストの設定を定義しています。
const char * SERVER_HOST = "www.httpbin.org" ;
const uint16_t SERVER_PORT = 443 ;
名称 内容 SERVER_HOST
サーバのホスト名 SERVER_PORT
サーバのポート番号
各種定数の定義 config.h
の21行目からは、各種定数を定義しています。
const uint32_t NTP_UPDATE_INTERVAL = 10000 ; // ms
const int QUERIES_MAX_LENGTH = 128 ; // bytes (without \0)
const int32_t CONNECT_TIMEOUT = 10 ; // seconds
const uint32_t RECONNECT_MIN_INTERVAL = 5 ; // seconds
// SEND_MIN_INTERVAL must be longer than NTP_UPDATE_INTERVAL
const uint32_t SEND_MIN_INTERVAL = 10 ; // seconds
const uint32_t REQUEST_TIMEOUT = 10 ; // seconds
名称 内容 NTP_UPDATE_INTERVAL
NTP時刻の取得間隔 QUERIES_MAX_LENGTH
クエリ文字列の最大長(ヌル文字含まず) CONNECT_TIMEOUT
サーバへの接続時のタイムアウト RECONNECT_MIN_INTERVAL
Wi-Fiアクセスポイントへ再接続する際の最短間隔 SEND_MIN_INTERVAL
リクエスト間隔の最短間隔 REQUEST_TIMEOUT
リクエストからレスポンスまでのタイムアウト
SEND_MIN_INTERVAL
は、NTP_UPDATE_INTERVAL
以上に設定しています。
リクエスト間隔が短いと、リクエスト間でタイムスタンプが重複してしまう可能性があるからです。
SEND_MIN_INTERVAL
を短くすると、連続してパケットを受信した場合にサーバへ負担をかけてしまいます。
必ず適度な間隔を空けてください。
ピン番号の定義 29-31行目では、ピン番号を定義しています。
static const int RST_PIN = 5 ;
static const int PRG_PIN = 4 ;
static const int LED_PIN = 18 ;
名称 内容 RST_PIN
TWELITE の RST ピンが接続されているピンの番号 PRG_PIN
TWELITE の PRG ピンが接続されているピンの番号 LED_PIN
基板上の ESP32 用 LED が接続されているピンの番号
グローバルオブジェクトの宣言 34-37行目では、グローバルオブジェクトを宣言しています。
static WiFiClientSecure client;
static WiFiUDP ntpUDP;
static NTPClient timeClient (ntpUDP, "ntp.nict.jp" ,
32400 , NTP_UPDATE_INTERVAL); // JST(UTC+9)
名称 内容 client
HTTPS通信のインタフェース ntpUDP
NTP用のUDP通信のインタフェース timeClient
NTPのインタフェース
グローバル変数の宣言 40-41行目では、グローバル変数を宣言しています。
static DataFromAria LatestDataFromAria;
static bool IsThereNewDataFromAria;
名称 内容 LatestDataFromAria
TWELITE ARIA から受信した最新のデータ IsThereNewDataFromAria
TWELITE ARIA から新たなデータを受信したことを示すフラグ
関数プロトタイプの宣言 44-56行目では、関数プロトタイプを宣言しています。
void anotherLoopForTWELITE ();
void anotherLoopForNTP ();
名称 内容 anotherLoopForTWELITE
TWELITEのデータを処理するためのループ関数 anotherLoopForNTP
NTPで時刻を取得するためのループ関数
void initTWELITE ();
void initWiFi ();
void initNTP ();
名称 内容 initTWELITE
TWELITEの初期化関数 initWiFi
Wi-Fiの初期化関数 initNTP
NTPの初期化関数
void onAppAriaPacket (const ParsedAppAriaPacket& packet);
名称 内容 onAppAriaPacket
TWELITE ARIA からデータを受信した際のコールバック関数
void sendAriaData(const DataFromAria& data)
名称 内容 sendAriaData
TWELITE ARIAのデータを HTTP GET リクエストにのせて送る関数
setup()
59-87行目では、全体の初期化を行います。
void setup () {
Serial.begin(115200 );
initTWELITE();
initWiFi();
initNTP();
// Attach another loop function for TWELITE
// Note: Core 0 is also used for the WiFi task, which priority is 19 (ESP_TASKD_EVENT_PRIO - 1)
xTaskCreatePinnedToCore(
[](void * params) {
while (true) {
anotherLoopForTWELITE();
vTaskDelay(1 ); // IMPORTANT for Watchdog
}
},
"Task for anotherLoopForTWELITE()" , 8192 , nullptr , 18 , nullptr ,
0 ); // Priority is 18 (lower than WiFi)
// Attach another loop function for NTP
xTaskCreatePinnedToCore(
[](void * params) {
while (true) {
anotherLoopForNTP();
vTaskDelay(1 ); // IMPORTANT for Watchdog
}
},
"Task for anotherLoopForNTP()" , 8192 , nullptr , 17 , nullptr ,
0 ); // Priority is 17 (lower than WiFi and TWELITE)
}
xTaskCreatePinnedToCore()
により、loop()
とは別のタスクを登録しています。
下記の部分はキャプチャのない無名関数です。不要なグローバル空間の汚染を避けることができます。
[](void * params) {
while (true) {
anotherLoopForTWELITE();
vTaskDelay(1 ); // IMPORTANT for Watchdog
}
},
ウォッチドッグタイマへ介入する余地を設けるために、vTaskDelay()
を挿入しています。
loop()
90-111行目は、主となるループ処理です。
HTTP リクエストの処理、Wi-Fi 切断時の再接続処理、定期リセットの処理を行います。
void loop () {
static uint32_t lastTimeReconnected = 0 ;
if (WiFi.status() == WL_CONNECTED) {
// Regular operations
// Check for new data
if (IsThereNewDataFromAria) {
IsThereNewDataFromAria = false; // Clear first; data is updated on another thread
DataFromAria data = LatestDataFromAria; // Now, the buffer is open for incoming data
sendAriaData(data);
}
} else if (millis() - lastTimeReconnected > RECONNECT_MIN_INTERVAL * 1000 ) {
// Lost connection, reconnect periodically
Serial.println("Disconnected. Reconnecting to WiFi..." );
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
lastTimeReconnected = millis();
}
// Reboot every x interval
if (millis() > REBOOT_INTERVAL * 1000 ) {
Serial.println("Rebooting..." );
ESP.restart();
}
}
anotherLoopForTWELITE()
114-116行目は、TWELITE のためのループ処理です。
データの受信と解釈を逐次行うため、ブロッキング処理を含む loop()
とは別のタスクとしています。
void anotherLoopForTWELITE () {
Twelite.update();
}
anotherLoopForNTP()
117-120行目は、NTP のためのループ処理です。
こちらについても UDP の通信を行うため、ブロッキング処理を含む loop()
とは別のタスクとしています。
void anotherLoopForNTP () {
timeClient.update();
setTime(timeClient.getEpochTime());
}
initTWELITE()
123-130行目は、TWELITE の初期化処理です。
TWELITE SPOT に搭載された TWELITE を指定された設定で起動し、パケット受信時のコールバック関数を登録しています。
void initTWELITE () {
Serial2.begin(115200 );
if (Twelite.begin(Serial2, LED_PIN, RST_PIN, PRG_PIN, TWE_CHANNEL, TWE_APP_ID)) {
Serial.println("Started TWELITE." );
}
// Attach event handlers to process packets
Twelite.on(onAppAriaPacket);
}
initWiFi()
133-157行目は、Wi-Fi の初期化処理です。
接続されない場合は、5秒置きに再接続を試みます。
void initWiFi () {
Serial.print(" \n Connecting to the WiFi network " );
Serial.print(WIFI_SSID);
Serial.println("..." );
// Begin
WiFi.mode(WIFI_STA);
WiFi.setAutoReconnect(true);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
// Wait for connection
Serial.print("Connecting." );
while (WiFi.status() != WL_CONNECTED) x
static int count = 0 ;
Serial.print('.' );
delay(500 );
// Retry every 5 seconds
if (count++ % 10 == 0 ) {
WiFi.disconnect();
WiFi.reconnect();
Serial.print('!' );
}
}
Serial.println(" \n Connected!" );
// Set Root CA certificate
client.setCACert(CA_CERT);
}
initNTP()
160-164行目は、NTP の初期化処理です。
void initNTP () {
timeClient.begin();
timeClient.update();
setTime(timeClient.getEpochTime());
}
onAppAriaPacket()
167-177行目には、TWELITE ARIA からデータを受信した際の処理を記述しています。
ここでは HTTP の送信処理を行わず、グローバル変数へセットしています。
グローバル変数へセットしたデータは、別のタスクで sendAriaData()
によって処理します。
void onAppAriaPacket (const ParsedAppAriaPacket& packet)
{
// Store data
LatestDataFromAria.serialId = packet.u32SourceSerialId;
LatestDataFromAria.logicalId = packet.u8SourceLogicalId;
LatestDataFromAria.supplyVoltage = packet.u16SupplyVoltage;
LatestDataFromAria.linkQuality = packet.u8Lqi;
LatestDataFromAria.temp100x = packet.i16Temp100x;
LatestDataFromAria.humid100x = packet.u16Humid100x;
IsThereNewDataFromAria = true;
}
sendAriaData()
180-237行目は、TWELITE ARIA のデータを HTTP GET リクエストのクエリ文字列にセットして送信する関数です。
コードを簡潔とするために、HTTP GET を使用しています。
HTTP POST を使用される場合は、リクエストボディを追加してください。
サーバへの過度な負荷を防ぐため、高頻度でパケットが到着した際には送信をスキップしています。
void sendAriaData (const DataFromAria& data)
{
static uint32_t lastTimeRequested = 0 ;
if (millis() - lastTimeRequested > SEND_MIN_INTERVAL * 1000 or lastTimeRequested == 0 ) {
Serial.println("Connecting to the server..." );
if (not client.connect(SERVER_HOST, SERVER_PORT, CONNECT_TIMEOUT * 1000 )) {
Serial.println("Connection failed!" );
} else {
Serial.println("Connected to the server!" );
// Make a query string
char queries[QUERIES_MAX_LENGTH+ 1 ];
snprintf(queries, sizeof (queries),
"datetime=%04d%02d%02d%02d%02d%02d&sid=%X&lid=%d&temp=%d&humid=%d&bat=%d&lqi=%d" ,
// Note that NTP_UPDATE_INTERVAL is set for 10000ms by default; second() delays up to 10s.
// To prevent duplication of datetime, SEND_MIN_INTERVAL is set for 10s.
year(), month(), day(), hour(), minute(), second(),
data.serialId,
data.logicalId,
data.temp100x,
data.humid100x,
data.supplyVoltage,
data.linkQuality);
// Send a request
client.println(String("GET https://" ) +
SERVER_HOST +
String("/get?" ) +
queries +
String(" HTTP/1.1" ));
client.println("Accept: */*" );
client.println(String("Host: " ) + SERVER_HOST);
client.println("Connection: close" );
client.println();
uint32_t timeSentRequest = millis();
// Handle a response
while (client.connected()) {
String line = client.readStringUntil('\n' );
if (line == " \r " ) {
Serial.println("Headers received" );
break ;
}
if (millis() - timeSentRequest > REQUEST_TIMEOUT * 1000 ) {
Serial.println("Request was timed out" );
break ;
}
}
while (client.available()) {
char c = client.read();
Serial.write(c);
}
client.stop();
}
lastTimeRequested = millis();
} else {
Serial.println("Requests are too frequently; skip." );
}
}
2.5.2.4 - Google スプレッドシートの利用 TWELITE ARIA からのデータを Google スプレッドシートへアップロードするサンプルスケッチ spot-google-sheets の解説
無線 LAN 子機として振る舞い、クラウド上の Google スプレッドシートに TWELITE ARIA から受信したデータをアップロードするサンプルスケッチ
spot-google-sheets
の解説です。
2.5.2.4.1 - Google スプレッドシートの利用 TWELITE ARIA からのデータを Google スプレッドシートへアップロードするサンプルスケッチ spot-google-sheets の解説
無線 LAN 子機として振る舞い、クラウド上の Google スプレッドシートに TWELITE ARIA から受信したデータをアップロードするサンプルスケッチ
spot-google-sheets
の解説です。なお、このスケッチでは ESP32 の Arduino 環境から FreeRTOS の機能を利用しています。
本稿では、サードパーティのオープンソースソフトウェアを使用します。
サードパーティのソフトウェアについて、その詳しい使用方法を弊社からご案内することはいたしかねます。また、サードパーティのソフトウェアを使用されたことによるいかなる損害についても、弊社は一切の責任を負いません。
ソースコードの入手 GitHub (monowireless/spot-google-sheets ) から入手できます。
システムの概要 TWELITE SPOT は、事前に作成したサービスアカウントを使って自動的にスプレッドシートを作成し、指定したユーザアカウントへ、そのファイルを共有します。
ユーザアカウントへログインすると、Google ドライブの「共有アイテム」ページから、TWELITE SPOT によって作成されたスプレッドシートを閲覧・編集できます。
作成されるスプレッドシートのイメージ
TWELITE SPOT は、作成したスプレッドシートへデータ行を次々と追加していきます。
2023年5月現在、Google Sheets / Drive API の利用に追加料金はかかりません。
ただし、クエリの数などを定めた使用量上限(Sheets API / Drive API )があります。
例えば Google Sheets API では、リクエストを毎分60回以内に押さえなくてはなりません。超過したリクエストはエラーとなります。
サービスアカウントは、アプリケーションが使用するための Google アカウントです。
詳しくは Google による解説 をご覧ください。
開発に必要なもの
本稿では TWELITE ARIA を使用しますが、ソースコードを改変することで TWELITE CUE などの子機にも対応できます。
ただし、シートへ書き込むデータが増える場合は、API の 使用量上限 に気を配る必要があります。
環境整備 IDE とツールチェインの導入 Arduino IDE 1.x による開発環境の構築方法 をご覧ください。
ライブラリの導入 ESP-Google-Sheet-Client ライブラリ ライブラリマネージャを開き、検索ボックスに esp-google-sheet
と入力してインストールします。
なお、GitHub (mobizt/ESP-Google-Sheet-Client) からも入手できます。
公式 NTP ライブラリ ライブラリマネージャを開き、検索ボックスに ntpclient
と入力してインストールします。
TimeLib ライブラリ ライブラリマネージャを開き、検索ボックスに timelib
と入力してインストールします。
事前準備:API のセットアップ 事前に、API を使用できるように準備する必要があります。Google アカウントを使います。
ここでは、下記の作業を行います。
Google Cloud プロジェクトの作成 Google Sheets API の有効化 Google Drive API の有効化 サービスアカウントの作成と設定 サービスアカウントの認証情報の取得 プロジェクトの作成 API を使用するにあたって、まずは Google Cloud プロジェクトを作成します。
Google Cloud プロジェクトは、システム全体を束ねるような存在です。構築するシステムの名称をプロジェクト名にするとよいでしょう。ここでは、仮に SPOT-DEV
とします。
下記のリンクにアクセスし、プロジェクトを作成してください。
https://console.cloud.google.com/projectcreate
プロジェクト作成画面の例(個人)
組織に所属するアカウントでは、組織を選択する項目が並びます。
Sheets API の有効化 TWELITE SPOT からスプレッドシートを操作するために、Sheets API を有効化します。
下記のリンクにアクセスし、API を有効化してください。
https://console.cloud.google.com/apis/library/sheets.googleapis.com
Sheets APIの有効化を行う画面の例
Drive API の有効化 TWELITE SPOT からスプレッドシートを共有するために、Drive API を有効化します。
下記のリンクにアクセスし、API を有効化してください。
https://console.cloud.google.com/apis/library/drive.googleapis.com
Drive APIの有効化を行う画面の例
サービスアカウントの作成と設定 TWELITE SPOT からスプレッドシートを作成するために、サービスアカウントを作成します。
下記のリンクにアクセスし、プロジェクト名(ここでは SPOT-DEV
)を選択してサービスアカウント一覧画面を表示したのち、ページ上部のボタンからサービスアカウントの作成を開始します。
https://console.cloud.google.com/iam-admin/serviceaccounts
サービスアカウント一覧の表示画面の例
「① サービスアカウントの詳細」では、サービスアカウントの名称を入力します。
下記の例では、spot-dev-sa
としています。
サービスアカウント名の入力画面の例
入力したら、「作成して続行」ボタンを押して次へ進みます。
「② このサービスアカウントにプロジェクトへのアクセスを許可する(省略可)」では、サービスアカウントの権限を設定します。
ここでは、下記の例のようにして「オーナー」を選択してください。
サービスアカウント権限の入力画面の例
選択したら、「続行」ボタンを押して次へ進みます。
「③ ユーザーにこのサービスアカウントへのアクセスを許可(省略可)」では、何も行わずに「完了」を押してスキップします。
スキップする画面の例
サービスアカウントの作成が完了すると、サービスアカウントの一覧画面へ戻ります。作成したサービスアカウントが表示されていることを確認してください。
サービスアカウントの認証情報の取得 作成したサービスアカウントを確認したら、「メール」列のリンクをクリックし、サービスアカウントの詳細画面へ移ります。
サービスアカウントアカウント作成後の一覧画面の例
上部の「キー」タブを選択して、サービスアカウントの認証に必要な秘密鍵を管理する画面へ移ります。
サービスアカウントの詳細画面の例
「鍵を追加」ボタンから「新しい鍵を作成」を選択し、秘密鍵の作成を開始します。
鍵の作成ボタンの表示例
次の画面では、「JSON」を選択した状態のまま「作成」ボタンを押します。
タイプ選択画面の例
「作成」ボタンを押すと、秘密鍵ファイル(.json
)が自動的にダウンロードされます。
秘密鍵ファイルの取り扱いには十分注意してください。
秘密鍵ファイルをテキストエディタで開くと、下記のような構成になっているはずです。
{
"type" : "service_account" ,
"project_id" : "???" ,
"private_key_id" : "???" ,
"private_key" : "-----BEGIN PRIVATE KEY-----\n???\n-----END PRIVATE KEY-----\n" ,
"client_email" : "???@???.iam.gserviceaccount.com" ,
"client_id" : "???" ,
"auth_uri" : "https://accounts.google.com/o/oauth2/auth" ,
"token_uri" : "https://oauth2.googleapis.com/token" ,
"auth_provider_x509_cert_url" : "https://www.googleapis.com/oauth2/v1/certs" ,
"client_x509_cert_url" : "???" ,
"universe_domain" : "googleapis.com"
}
上記のうち、project_id
/ private_key
/ client_email
の内容を動作確認で使用します。
動作確認 まずは動作確認を行ってみましょう。
プロジェクトファイルを入手 GitHub (monowireless/spot-google-sheets) から Zip ファイルをダウンロードしますZip ファイルを展開し、フォルダ名を spot-google-sheets-main
から spot-google-sheets
に変更します Arduino のスケッチブックの保存場所(Arduino IDE 環境設定に記載。例:C:\Users\foo\Documents\Arduino
)に spot-google-sheets
フォルダを配置します スケッチの設定ファイルを修正 Arduino スケッチ spot-google-sheets.ino を開き、画面上部の config.h
タブを選択して、4-11行目の値を修正してください。
4-5行目は、無線 LAN 関連の設定です。
const char * WIFI_SSID = "YOUR SSID" ; // Modify it
const char * WIFI_PASSWORD = "YOUR PASSWORD" ; // Modify it
SSID と パスワードを設定しています。
一方、8-11行目はスプレッドシート関連の設定です。
const char * PROJECT_ID = "YOUR-PROJECT-ID" ; // Modify it
const char * SERVICE_ACCOUNT_EMAIL = "YOUR-SERVICE-ACCOUNT@YOUR-PROJECT-ID.iam.gserviceaccount.com" ; // Modify it
const char PRIVATE_KEY[] PROGMEM = "-----BEGIN PRIVATE KEY----- \n YOUR-PRIVATE-KEY \n -----END PRIVATE KEY----- \n " ; // Modify it
const char * USER_ACCOUNT_EMAIL = "YOUR-ACCOUNT@EMAIL" ; // Modify it
最初の3項目には .json
ファイルの内容をコピーして、最後の USER_ACCOUNT_EMAIL
にはあなたがログインしている Google アカウントのメールアドレスを入力してください。
スケッチを書き込み ESP32 へのスケッチの書き込み方法 を参考に、スケッチを書き込んでください。
ツール -> Flash Size の設定が 16MB
でないと正常に動きません。
パーティションテーブルには paritions.csv
を使用しますが、全体のサイズが小さいと正しく書き込めないからです。
親機と子機を起動 TWELITE SPOT のリセットボタン(ESP32 側)を押してください。
Arduino のシリアルコンソールに以下のような表示がされたら、起動に成功しています。
Initializing queue...
Completed.
Started TWELITE.
Connecting to WiFi ...!...
Connected. IP: xxx.xxx.xxx.xxx
Initializing NTP...Completed. UNIX time: xxxxxxxxxx
Initializing sheets...
Creating sheets...
OAuth2.0 access token on initializing
OAuth2.0 access token on signing
OAuth2.0 access token on exchange request
OAuth2.0 access token ready
Requesting to create...
Succeeded.
Adding headers for ARIA...
Requesting to add header...
Succeeded.
Formatting the sheet for ARIA...
Requesting to format...
Succeeded.
Extending the sheet for ARIA...
Requesting to extend...
Succeeded.
Completed.
TWELITE ARIA(初期設定)にもコイン電池を挿入し、電源を投入します。
コイン電池の挿入
TWELITE SPOT が TWELITE ARIA からのパケットを正常に受信し、データ列の追加に成功すると、下記のような表示がなされます。
Got a new packet from ARIA.
Got a new packet from ARIA.
Requesting to add data...
Got a new packet from ARIA.
Succeeded.
ちなみに、上記の例ではリクエスト中にパケットを受信しています。後述 のマルチタスクに成功している証です!
Google へアクセス Google ドライブの 共有アイテム へアクセスし、SPOT Sheet (xxx)
という名前のスプレッドシートを開きます。
以下のような画面が表示されます。
スプレッドシート画面のイメージ
スクロールしていくと、TWELITE ARIA からのデータを確認できるはずです。
最新の行へ移動するには、値の入った任意のセルをクリックしてから、Ctrl (⌘) + ↓
を押します。
TWELITE 子機のデータを Google スプレッドシートにアップロードできました!
スケッチ解説 Arduino スケッチ spot-google-sheets.ino の解説です。
ライブラリのインクルード Arduino および ESP32 公式ライブラリ 4-7行目では、Arduino および ESP32 の公式ライブラリをインクルードしています。
#include <Arduino.h>
#include <NTPClient.h>
#include <WiFi.h>
#include <WiFiUdp.h>
ヘッダファイル 内容 備考 Arduino.h
Arduino の基本ライブラリ NTPClient.h
NTP を使う ファイル名と受信時刻に使用 WiFi.h
ESP32 の WiFi を使う WiFiUdp.h
UDP を使う NTPClient に必要
サードパーティのライブラリ 10-11行目では、サードパーティのライブラリをインクルードしています。
#include <ESP_Google_Sheet_Client.h>
#include <TimeLib.h>
ヘッダファイル 内容 備考 ESP_Google_Sheet_Client.h
Google へアクセスする TimeLib.h
UNIX 時間をフォーマットする
MWings ライブラリ 14行目では、MWings ライブラリをインクルードしています。
ユーザ設定の定義 17行目では、config.h
をインクルードしています。
config.h
では、ユーザ設定を定義しています。実行時には、この設定を書き換えてください。
無線 LAN 設定の定義 config.h
の4-5行目では、TWELITE SPOT に搭載された ESP32 に適用する無線 LAN 設定を定義します。
const char * WIFI_SSID = "YOUR SSID" ; // Modify it
const char * WIFI_PASSWORD = "YOUR PASSWORD" ; // Modify it
名称 内容 WIFI_SSID
接続するネットワークの SSID WIFI_PASSWORD
接続するネットワークの パスワード
API 設定の定義 config.h
の8-11行目では、API の設定を定義しています。
const char * PROJECT_ID = "YOUR-PROJECT-ID" ; // Modify it
const char * SERVICE_ACCOUNT_EMAIL = "YOUR-SERVICE-ACCOUNT@YOUR-PROJECT-ID.iam.gserviceaccount.com" ; // Modify it
const char PRIVATE_KEY[] PROGMEM = "-----BEGIN PRIVATE KEY----- \n YOUR-PRIVATE-KEY \n -----END PRIVATE KEY----- \n " ; // Modify it
const char * USER_ACCOUNT_EMAIL = "YOUR-ACCOUNT@EMAIL" ; // Modify it
名称 内容 PROJECT_ID
プロジェクト ID SERVICE_ACCOUNT_EMAIL
サービスアカウントのメールアドレス PRIVATE_KEY
秘密鍵の本体 USER_ACCOUNT_EMAIL
スプレッドシートを共有するユーザアカウントのメールアドレス
ピン番号の定義 20-24行目では、ピン番号を定義しています。
const uint8_t TWE_RST = 5 ;
const uint8_t TWE_PRG = 4 ;
const uint8_t LED = 18 ;
const uint8_t ESP_RXD1 = 16 ;
const uint8_t ESP_TXD1 = 17 ;
名称 内容 TWE_RST
TWELITE の RST ピンが接続されているピンの番号 TWE_PRG
TWELITE の PRG ピンが接続されているピンの番号 LED
基板上の ESP32 用 LED が接続されているピンの番号 ESP_RXD1
TWELITE の TX ピンが接続されているピンの番号 ESP_TXD1
TWELITE の RX ピンが接続されているピンの番号
TWELITE 設定の定義 27-30行目では、TWELITE SPOT に搭載された TWELITE 親機に適用する設定を定義しています。
const uint8_t TWE_CH = 18 ;
const uint32_t TWE_APPID = 0x67720102 ;
const uint8_t TWE_RETRY = 2 ;
const uint8_t TWE_POWER = 3 ;
名称 内容 TWE_CH
TWELITE の 周波数チャネル TWE_APPID
TWELITE の アプリケーション ID TWE_RETRY
TWELITE の 再送回数(送信時) TWE_POWER
TWELITE の 送信出力
このサンプルでは、TWELITE 親機からのコマンド送信を行わないため、29-30行目の内容は関係ありません。
シート関連の定義 32-43行目では、シートに関連した情報を定義しています。
const char * SPREADSHEET_TITLE_PREFIX = "SPOT Sheet" ;
const char * SPREADSHEET_LOCALE = "ja_JP" ;
const char * SPREADSHEET_TIME_ZONE = "Asia/Tokyo" ;
const int MIN_REQUEST_INTERVAL = 1000 ; // 60 requests per minute
const int SHEETS_DEFAULT_ROWS = 1000 ; // Default length is 1000 rows
const int SHEETS_ROWS = 100000 ; // Max 1,000,000 rows at 10 columns
const int ARIA_SHEET_ID = 1 ;
const char * ARIA_SHEET_TITLE = "ARIA" ;
constexpr int ARIA_BUFFER_PACKETS = 32 ; // Max number of rows per addition request
名称 内容 SPREADSHEET_TITLE_PREFIX
スプレッドシートのファイル名の固定部分 SPREADSHEET_LOCALE
スプレッドシートのロケール SPREADSHEET_TIME_ZONE
スプレッドシートのタイムゾーン MIN_REQUEST_INTERVAL
リクエスト送信の最小間隔 SHEETS_DEFAULT_ROWS
各シートのデフォルトの行数 SHEETS_ROWS
各シートの行数 ARIA_SHEET_ID
ARIA 用シートの ID ARIA_SHEET_TITLE
ARIA 用シートの名称 ARIA_BUFFER_PACKETS
ARIA からのパケットを格納するキューの長さ
TWELITE ARIA 以外の子機に対応するときには、同一のスプレッドシート(ワークブック)に別のシートを作成することを推奨します。
したがって、ID、タイトル、キューの長さの3点を付け加える必要があります。
型の宣言 46-50行目では、型を宣言しています。
struct ParsedAppAriaPacketWithTime {
ParsedAppAriaPacket packet;
uint32_t elapsedMillis;
uint32_t unixTime;
};
名称 内容 ParsedAppAriaPacketWithTime
受信したパケットデータを受信時刻と合わせてキューへ格納するための型
elapsedMillis
:パケット受信時の起動からの経過時間(ミリ秒)unixTime
:パケット受信時の UNIX 時間(秒)です。
TWELITE ARIA 以外の子機に対応するときには、新たにキューを作成する必要があります。
したがって、ParsedAppAriaPacketWithTime
のようなキュー格納用の型についても付け加える必要があります。
グローバルオブジェクトの宣言 53-61行目では、グローバルオブジェクトを宣言しています。
WiFiUDP ntpUDP;
NTPClient timeClient (ntpUDP, "ntp.nict.jp" , 32400 );
String spreadsheetIdString; // Identifier of newly created file
bool readyForNewRequests = false;
uint32_t lastTimeRequestWasSent = UINT32_MAX;
QueueHandle_t ariaPacketQueue; // Store received data from ARIA
uint32_t rowToAddNewAriaData = 2 ; // Starting with the Row 2
名称 内容 ntpUDP
NTP のための UDP インタフェース timeClient
NTP のインタフェース spreadsheetIdString
作成したスプレッドシートのID readyForNewRequests
新たなリクエストを送信できる状態になったら true
lastTimeRequestWasSent
最後にリクエストを送信した時間 ariaPacketQueue
ARIA から受信したパケットと受信時刻を格納するキュー rowToAddNewAriaData
次に ARIA から受信したデータを追加する行
ariaPacketQueue
は、Arduino core for the ESP32 のベースになっている FreeRTOS の Queue 機能を使います。
TWELITE ARIA 以外の子機に対応するときには、受信データを格納するキューと書き込み先の行番号を格納する変数を付け加えます。
関数プロトタイプの宣言 64-71行目では、関数プロトタイプを宣言しています。
void anotherLoop ();
void waitUntilNewRequestsReady ();
String createSpreadsheet ();
bool formatSheet (const String spreadsheetId, const int sheetId);
bool extendSheet (const String spreadsheetId, const int sheetId, const int rows);
bool addSheetAriaHeaderRow (const String spreadsheetId, const char * const sheetTitle);
bool addSheetsDataRow (const String spreadsheetId);
名称 内容 anotherLoop()
非同期で TWELITE の処理を行う、もうひとつの loop()
waitUntilNewRequestsReady()
次のリクエストを送信可能になるまで待機する createSpreadsheet()
スプレッドシートを新規作成する formatSheet()
指定したシートの書式を設定する extendSheet()
指定したシートの行を増やし、書式を設定する addSheetAriaHeaderRow()
指定したシートへ ARIA 向けのヘッダー行を追加する addSheetsDataRow()
シートへデータ行を追加する
API のリクエストからレスポンスを待つ間にも TWELITE の受信処理を止めないために、FreeRTOS のマルチタスク機能を使って anotherLoop()
を作成し、そのなかで Twelite.update()
を実行しています。
TWELITE ARIA 以外の子機に対応するときには、例えば、下記のような方針でリクエストの内容を追加します。
createSpreadsheet()
:スプレッドシートを増やすように改変するformatSheet()
:新たなシートもフォーマットするように改変するextendSheet()
:内容はそのまま、新たなシートに対しても呼び出すaddSheet**HeaderRow()
:関数ごと付け加えるaddSheetsDataRow()
:新たなシートへデータを追加する処理を追加するキューの設定 82-83行目では、受信したパケットデータを受信時刻と合わせて格納するためのキューを初期化しています。
ariaPacketQueue = xQueueCreate(ARIA_BUFFER_PACKETS, sizeof (ParsedAppAriaPacketWithTime));
if (ariaPacketQueue == 0 ) { Serial.println("Failed to init a queue." ); }
xQueueCreate()
は、ESP32 の内部で動作する FreeRTOS の機能です。マルチタスクに対応したキューを簡単に作成することができます。
TWELITE ARIA 以外の子機に対応するときには、新たなキューについても初期化します。
TWELITE の設定 88-92行目では、Twelite.begin()
を呼び出し、TWELITE SPOT に搭載された TWELITE 親機の設定と起動を行っています。
Serial2.begin(115200 , SERIAL_8N1, ESP_RXD1, ESP_TXD1);
if (Twelite.begin(Serial2,
LED, TWE_RST, TWE_PRG,
TWE_CH, TWE_APPID, TWE_RETRY, TWE_POWER)) {
Serial.println("Started TWELITE." );
}
引数 型 内容 Serial2
HardwareSerial&
TWELITE との通信に使うシリアルポート LED
int
ステータス LED を接続したピンの番号 TWE_RST
int
TWELITE の RST ピンを接続したピンの番号 TWE_PRG
int
TWELITE の PRG ピンを接続したピンの番号 TWE_CHANNEL
uint8_t
TWELITE の 周波数チャネル TWE_APP_ID
uint32_t
TWELITE の アプリケーション ID TWE_RETRY
uint8_t
TWELITE の 再送回数(送信時) TWE_POWER
uint8_t
TWELITE の 送信出力
イベントハンドラの登録 94-103行目では、TWELITE ARIA からのパケットを受信した際に行う処理を登録しています。
Twelite.on([](const ParsedAppAriaPacket& packet) {
Serial.println("Got a new packet from ARIA." );
ParsedAppAriaPacketWithTime packetWithTime;
packetWithTime.elapsedMillis = millis();
packetWithTime.unixTime = timeClient.getEpochTime();
packetWithTime.packet = packet;
if (not(xQueueSend(ariaPacketQueue, & packetWithTime, 0 ) == pdPASS)) {
Serial.println("Failed to add packet data to the queue." );
}
});
TWELITE CUE など他の子機を使用する場合は、新たなイベントハンドラを追加します。
ここでは、xQueueSend()
により、受信したパケットデータを受信時刻と合わせてキューの末尾へ格納しています。
無線 LAN の設定 106-120行目では、無線 LAN の設定を行っています。
WiFi.mode(WIFI_STA);
WiFi.setAutoReconnect(true);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Serial.print("Connecting to WiFi .." );
while (WiFi.status() != WL_CONNECTED) {
static int count = 0 ;
Serial.print('.' );
delay(500 );
// Retry every 5 seconds
if (count++ % 10 == 0 ) {
WiFi.disconnect();
WiFi.reconnect();
Serial.print('!' );
}
}
ここでは、無線 LAN 子機として設定したうえで、指定のネットワークへ接続しています。
ネットワークに接続できるまで、while
文を出ません。
上記の実装では、5秒に一度、再接続を試みています。
NTP の設定 126-127行目では、NTP の設定をしています。
timeClient.begin();
timeClient.update();
Google スプレッドシートの設定 132-145行目では、Google スプレッドシートを設定しています。
GSheet.setTokenCallback([](TokenInfo info) {
// Print token initialization states
if (info.status == esp_signer_token_status_error) {
Serial.print("Token error " );
Serial.println(GSheet.getTokenError(info));
}
Serial.print(GSheet.getTokenType(info));
Serial.print(" " );
Serial.println(GSheet.getTokenStatus(info));
});
GSheet.setPrerefreshSeconds(60 ); // Set refresh rate for auth token
Serial.println("Initializing sheets..." );
GSheet.begin(SERVICE_ACCOUNT_EMAIL, PROJECT_ID, PRIVATE_KEY);
132-141行目でサービスアカウントのトークンを取得する際の状態表示の処理を登録したあと、142行目でトークンの再取得間隔を設定、145行目でサービスアカウントの初期化をしています。
また、147-173行目では、スプレッドシートの作成、ARIA 向けヘッダー行の追加、セルの書式設定、そして行の拡張を行っています。
Serial.println("Creating sheets..." );
waitUntilNewRequestsReady(); // Wait for token
spreadsheetIdString = createSpreadsheet();
if (not(spreadsheetIdString.length() > 0 )) {
Serial.println("Failed to create sheets." );
}
Serial.println("Adding headers for ARIA..." );
delay(MIN_REQUEST_INTERVAL);
waitUntilNewRequestsReady();
if (not addSheetAriaHeaderRow(spreadsheetIdString, ARIA_SHEET_TITLE)) {
Serial.println("Failed to add headers." );
}
Serial.println("Formatting the sheet for ARIA..." );
delay(MIN_REQUEST_INTERVAL);
waitUntilNewRequestsReady();
if (not formatSheet(spreadsheetIdString, ARIA_SHEET_ID)) {
Serial.println("Failed to format." );
}
Serial.println("Extending the sheet for ARIA..." );
delay(MIN_REQUEST_INTERVAL);
waitUntilNewRequestsReady();
if (not extendSheet(spreadsheetIdString, ARIA_SHEET_ID, SHEETS_ROWS - SHEETS_DEFAULT_ROWS)) {
Serial.println("Failed to extend." );
}
デフォルトでは、A-Z 列のセルが 1,000 行続きます。ここでは列を A-J の 10 列に絞り、行数を 100倍の 100,000 行に増やしています。
それでも足りない場合には、さらに行を増やす必要があります。ただし、セルの上限は 10,000,000 個のため、 A-J の10 列の場合、最大 1,000,000 行に制限されます。それ以上はセルを増やせないため、新たなスプレッドシート(ワークブック)を作成する必要があります。
TWELITE ARIA 以外の子機に対応するときには、新たに付け加えたヘッダ行作成関数などの呼び出しを付け加えます。
タスクの登録 179-186行目では、TWELITE のデータを非同期で更新するためのタスクを登録しています。
xTaskCreatePinnedToCore(
[](void * params) {
while (true) {
anotherLoop();
vTaskDelay(1 );
}
},
"Task for anotherLoop()" , 8192 , nullptr , 18 , nullptr , 0 );
xTaskCreatePinnedToCore()
は、FreeRTOS のマルチタスク機能に含まれる関数です。
ここでは、180-185行目のラムダ式を渡し、anotherLoop()
を無限に呼ぶタスクを登録しています。
[](void * params) {
while (true) {
anotherLoop();
vTaskDelay(1 ); // IMPORTANT for Watchdog
}
},
無限ループを含むタスクでは、必ず vTaskDelay(1);
などを挿入し、ウォッチドッグタイマの入る隙を与えてください。
タスクの名称は Task for anotherLoop()
で、スタックサイズは 8192
、タスクへのパラメータはなく、優先度は 18
(大きいほど高く、無線 LAN 関連の処理は1個上の 19
)、タスクを操作するインタフェースもなく、実行する CPU コアは無線 LAN などの RF 処理と同じ Core 0
です( loop()
等は Core 1
)。
"Task for anotherLoop()" , 8192 , nullptr , 18 , nullptr , 0 ); // Priority is 18 (lower than WiFi)
TWELITE のデータの更新 203行目では、anotherLoop()
内にて Twelite.update()
を呼び出しています。
Twelite.update()
は、TWELITE 親機から送信されるパケットデータ(ModBus ASCII 形式)を順次1バイトずつ読み出す関数です。
loop()
内で繰り返し
Twelite.update()
を呼ぶことで、TWELITE 親機から送信されるパケットデータの解釈が進みます。パケットデータの解釈を終えた際に
上記 のようなイベントが呼ばれる仕組みです。
通常、
delay()
などの処理でこの関数の呼び出しをブロックすると、パケットデータ文字列の読み出しが間に合わないことがあります。しかし、このスケッチでは FreeRTOS の機能によって
anotherLoop()
を切り離しているため、たとえ
loop()
内で同期処理があっても問題ありません。
スプレッドシートの更新 192-195行目では、スプレッドシートの更新処理を呼び出しています。
if (millis() - lastTimeRequestWasSent > MIN_REQUEST_INTERVAL) {
// Add available data
addSheetsDataRow(spreadsheetIdString);
}
192行目の if 文では、60リクエスト毎分の API 制限を守るために、前回のリクエスト送信から必ず 1 秒以上空けるようにしています(JavaScript の Throttle / Debounce における Throttle に相当します)。
194行目では、必要に応じてスプレッドシートへデータ行を追加します。
addSheetsDataRow(spreadsheetIdString);
API ライブラリの更新 196行目では、Google API 用ライブラリの更新を行い、リクエストの送信可否の状態を取得しています。
readyForNewRequests = GSheet.ready();
NTP ライブラリの更新 197行目では、NTP ライブラリの更新を行っています。
スプレッドシートの操作 217行目以降では、Sheets API によるスプレッドシートの操作を行っています。
詳しくは ライブラリの API リファレンス や Sheets API の REST リソース をご覧ください。
関連情報 Google Arduino ESP32 コミュニティ ライブラリ プラグイン 3 - TWELITE WINGS API / MWings TWELITE の親機を接続した端末で利用するライブラリ
MWings は、親機・中継機アプリ(App_Wings)を書き込んだ TWELITE を接続した端末で利用するライブラリです。App_Wings が出力する書式文字列を解釈し、親機が受信したデータを端末へ提供します。また、App_Wings へのコマンドを構成し、子機を操作します。
3.1 - TWELITE Wings API / MWings for Python Python のための TWELITE Wings API / MWings
3.1.1 - TWELITE Wings API / MWings for Python 最新版
TWELITE Wings API (MWings) を使うことで、PC 上の Python スクリプトから TWELITE を扱うことができるようになります。
Python に関する知識と経験のある読者を想定しています。
ライブラリの概要 TWELITE Wings API (以降 MWings) は、Python スクリプトから TWELITE を扱うためのライブラリです。
機能 ホストへ接続された TWELITE の親機を通じて、TWELITE の子機と通信できます。
受信データを解釈して、辞書や JSON のほか pandas データフレームへ変換※ 辞書から生成したコマンドを親機へ送信 ※ Lite版は pandas に非対応
Raspberry Pi には、通常版ではなくLite版を推奨します
モジュール名はmwings
ではなく、mwingslite
です pandas や numpy, pyarrow 等への依存関係がありませんRaspberry Pi では、これらをPyPIから導入できないことがあります なお pandas がないとき、データフレームを出力する関数 to_df()
は例外を発します 通常版と同じく、辞書やJSON文字列の出力には対応しています 要求する Python のバージョンを 3.11 以降へ落としています(通常版は 3.12 以降) 用途例 例えば、次のようなシステムを実現できます。
MONOSTICK で受信した温湿度データを JSON としてクラウドサーバへ送信 MONOSTICK で受信した加速度データを CSV または Excel ファイルへ記録※ PC から MONOSTICK を通じて TWELITE DIP へ接続された LED を制御 ※ Lite版は、直接 CSV や Excel ファイルを出力できません
特徴 モダン Python の モダン Python による モダン Python のためのモジュールです。
※ 例外あり。詳細は後述
インストール PyPI から入手できます。
pip の場合
poetry の場合
最も簡単なサンプルスクリプト わずか6行で超簡単!標準アプリ(App_Twelite)の受信データを JSON 形式で出力できます。
import mwings as mw
twelite = mw. Twelite(mw. utils. ask_user_for_port())
@twelite.on (mw. common. PacketType. APP_TWELITE)
def on_app_twelite (packet):
print(packet. to_json())
twelite. start()
Lite版の場合 import mwings as mw
をimport mwingslite as mw
とします。
環境整備と動作確認
MWings ライブラリは pip を使うだけで導入できますが、ここでは処理系やモジュールの依存関係の管理に対応した開発環境の構築方法を紹介します。また、TWELITE DIP の入力状態をJSON形式で表示するサンプルスクリプトを作成し、ライブラリの動作確認を行います。
用意するもの PC MONOSTICK (親機・中継機アプリ/デフォルト設定)TWELITE DIP (超簡単!標準アプリ/デフォルト設定)スイッチなどのペリフェラルを接続しておく(例:DI1 ポートと GND 間にタクトスイッチを接続) 環境整備
以下は一例です。Python 3.12 以降(Lite版は3.11以降)が使える環境であれば問題ありません。
好みの環境があれば、読み飛ばして ください。
外部ツールの使用において、当社は一切の責任を負いません。
また、外部ツールに関する質問はご遠慮ください。
pyenv の導入 処理系のバージョンを管理するために、pyenv を導入します。
Linux
curl https://pyenv.run | bash
事前に開発ツールを導入しておかなくてはならない場合があります Debian系
sudo apt update; sudo apt install build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev curl git libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev
Fedora系
yum install gcc make patch zlib-devel bzip2 bzip2-devel readline-devel sqlite sqlite-devel openssl-devel tk-devel libffi-devel xz-devel
参考:Home · pyenv/pyenv Wiki
macOS
brew update
brew install pyenv
必要に応じて Homebrew を導入してください
/bin/bash -c " $( curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh) "
事前に開発ツールを導入しておかなくてはならない場合があります Debian系
brew install openssl readline sqlite3 xz zlib tcl-tk
参考:Home · pyenv/pyenv Wiki
Windows Windows 向けの pyenv はありません。代わりに pyenv-win を使用します。
Invoke-WebRequest -UseBasicParsing -Uri "https://raw.githubusercontent.com/pyenv-win/pyenv-win/master/pyenv-win/install-pyenv-win.ps1" -OutFile "./install-pyenv-win.ps1" ; &"./install-pyenv-win.ps1"
pyenv / pyenv-win による Python の導入 MWings が対応する Python 3.12 以降(Lite版は3.11以降)の処理系を導入します。
導入できるバージョンの一覧を取得するには、下記を実行します。
ここでは例として、Python 3.12.4 を導入し、システム全体へ適用します。
pyenv install 3.12.4
pyenv global 3.12.4
導入済みバージョンの一覧を取得するには、下記を実行してください。
pipx の導入 poetry のようなコマンドラインツールを隔離された環境で管理するために、pipx を導入します。
Linux Debian系
sudo apt update
sudo apt install pipx
pipx ensurepath
pipから(Raspberry Piはこちらを推奨)
python3 -m pip install --user pipx
python3 -m pipx ensurepath
Fedora系
sudo dnf install pipx
pipx ensurepath
参考:Installation - pipx
macOS
brew install pipx
pipx ensurepath
Windows
scoop install pipx
pipx ensurepath
必要に応じて Scoop を導入してください
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Invoke-RestMethod -Uri https: //get.scoop.sh | Invoke-Expression
poetry の導入 プロジェクトに対する処理系のバージョンやモジュールの依存関係を Node.js のような形で管理するために、poetry を導入します。
エラーを吐く場合 TypeError: __init__() got an unexpected keyword argument 'encoding'
といったエラーを吐く場合は、pipxをパッケージマネージャではなくpipから導入してみてください。
python3 -m pip install --user pipx
python3 -m pipx ensurepath
プロジェクトの作成 ここでは、プロジェクト名を mwtest
とします。
プロジェクトを作成するディレクトリへ移動し、下記を実行してください。
mwtest
ディレクトリを生成します。
プロジェクトの設定 プロジェクトへ移動し、先ほど pyenv で導入した 処理系のバージョンを紐付けます。
MWings を導入します。
Linuxにて応答しない場合 次の環境変数の設定をお試しください。
export PYTHON_KEYRING_BACKEND= keyring.backends.null.Keyring
最も簡単なサンプルスクリプトの作成 まずは、先ほど紹介したスクリプト を動かしてみましょう。
import mwings as mw
twelite = mw. Twelite(mw. utils. ask_user_for_port())
@twelite.on (mw. common. PacketType. APP_TWELITE)
def on_app_twelite (packet):
print(packet. to_json())
twelite. start()
Lite版の場合 Raspberry Pi のserial0
を使う例を次に示します。
import mwingslite as mw
twelite = mw. Twelite("/dev/ttyS0" )
@twelite.on (mw. common. PacketType. APP_TWELITE)
def on_app_twelite (packet):
print(packet. to_json())
twelite. start()
なお pyserial の制約により、mw.utils.ask_user_for_port()
は/dev/ttyS0
を検知できません。
上記の内容で poetry が生成した __init__.py
と同じ階層に simple.py
を作成します。
📁 mwtest
└ 📁 mwtest
├ 📄 __init__.py
└ 📄 simple.py
最も簡単なサンプルスクリプトの実行 MONOSTICK を接続し、実行します。
poetry run python simple.py
複数のシリアルポートが存在する場合は、シリアルポートを選択してください。
JSON 文字列の出力を得ることができたら成功です。実際の出力例を下記に示します。
{
"time_parsed" : "2024-02-20T03:16:50.150386+00:00" ,
"packet_type" : "APP_TWELITE" ,
"sequence_number" : 13699 ,
"source_serial_id" : "810E0E23" ,
"source_logical_id" : 120 ,
"lqi" : 84 ,
"supply_voltage" : 3249 ,
"destination_logical_id" : 0 ,
"relay_count" : 0 ,
"periodic" : true ,
"di_changed" : [
true ,
true ,
false ,
false
],
"di_state" : [
false ,
false ,
false ,
false
],
"ai_voltage" : [
8 ,
272 ,
1032 ,
112
],
"mwings_implementation" : "python" ,
"mwings_version" : "1.0.0" ,
"hostname" : "silverstone.local" ,
"system_type" : "Darwin"
}
JSON 文字列の内容 mwings.parsers.app_twelite.ParsedPacket
キー 値 time_parsed
受信時刻(デフォルトはUTC, ISO8601形式) packet_type
パケット種別 sequence_number
シーケンス番号(App_Tweliteの場合は時間) source_serial_id
送信元シリアルID source_logical_id
送信元論理デバイスID lqi
電波通信品質(8bit) supply_voltage
電源電圧(mV) destination_logical_id
送信先論理デバイスID relay_count
中継回数 periodic
定期送信パケットか否か di_changed
各デジタルインタフェースの入力変化の有無 di_state
各デジタルインタフェースの入力状態 ai_voltage
各アナログインタフェースの入力電圧 mwings_implementation
MWings の実装(将来のための情報) mwings_version
MWings のバージョン hostname
受信したホストの名称 system_type
受信したホストのシステムの種別
実用的なスクリプトの作成 simple.py
はあくまでも説明用のサンプルです。実用的なスクリプトではありません。
なぜなら、twelite.start()
がデータを受信するためのスレッドを作成するものの、これを終了する手段を用意していないからです。非常に読みづらいスクリプトでもあります。
次はより実用的なスクリプトを作成しましょう。それを実行したのち、内容を解説します。
今回は、下記の3点を条件とします。
Ctrl+C
により、スレッドを正常終了できるようにすることPEP8 へ準拠すること(一部例外あり、詳細は後述 )型ヒント を導入することこれらを適用した例を下記に示します。
# -*- coding:utf-8 -*-
# Written for Python 3.12
# Formatted with Black
# MWings example: Receive data, print JSON, typed
from zoneinfo import ZoneInfo
import mwings as mw
# Main function
def main () -> None :
# Create a twelite object
twelite = mw. Twelite(mw. utils. ask_user_for_port())
# Use JST for received data
twelite. set_timezone(ZoneInfo("Asia/Tokyo" ))
# Register an event handler
@twelite.on (mw. common. PacketType. APP_TWELITE)
def on_app_twelite (packet: mw. parsers. app_twelite. ParsedPacket) -> None :
print(packet. to_json(verbose= True , spread= False ))
# Start receiving
try :
# Set as daemon thread
twelite. daemon = True
# Start the thread, Join to the main thread
twelite. start()
print("Started receiving" )
while True :
twelite. join(0.5 )
except KeyboardInterrupt :
# Stop the thread
print("Flushing..." )
twelite. stop()
print("Completed" )
if __name__ == "__main__" :
# Call the main function
main()
Lite版の場合 冒頭の import mwings as mw
をimport mwingslite as mw
としてください。
上記を practical.py
として保存してください。
📁 mwtest
└ 📁 mwtest
├ 📄 __init__.py
├ 📄 simple.py
└ 📄 practical.py
実用的なスクリプトの実行 下記のコマンドを実行すると、simple.py
と同じようにして JSON 形式の出力を得ることができます。
poetry run python practical.py
ただし、今回はエラーを発生させずに Ctrl+C
で終了できるほか、time_parsed
は日本標準時になっているものと思います。
実用的なスクリプトの解説 コードの解説 practical.py
を解説します。
import
文practical.py
では、2つのモジュールを import
しています。
from zoneinfo import ZoneInfo
import mwings as mw
zoneinfo.ZoneInfo
受信時刻のタイムゾーンを指定するために使用します。mwings
MWings ライブラリです。mw
に短縮して呼び出せるようにしています。Lite版の場合は mwingslite
です。オブジェクトの作成 mw.Twelite
オブジェクトは、ホストへ接続された TWELITE の親機へアクセスするためのインタフェースとなります。
# Create a twelite object
twelite = mw. Twelite(mw. utils. ask_user_for_port())
mw.utils.ask_user_for_port()
関数は、ホストで利用できるシリアルポートの一覧を取得し、ユーザが選択したポートのファイルディスクリプタのパスや COM ポート名を返します。
明示的にシリアルポートを指定する方法 mw.Twelite
のコンストラクタ へ、直接ファイルディスクリプタのパスや COM ポート名を指定します。
# Linux
twelite = mw. Twelite("/dev/ttyUSBx" )
# macOS
twelite = mw. Twelite("/dev/cu.usbserial-MWxxxxxx" )
# Windows
twelite = mw. Twelite("COMx" )
シリアルポートを使用しない場合 ログファイルを解釈するような用途では、None
を指定します。
twelite = mw. Twelite(port= None )
タイムゾーンの設定 デフォルトでは、データの受信時刻を UTC として扱います。
practical.py
では、これを JST としています。
# Use JST for received data
twelite. set_timezone(ZoneInfo("Asia/Tokyo" ))
ZoneInfo
には IANA のタイムゾーン識別子を渡してください。
受信ハンドラの登録 TWELITE の子機から送られるデータを処理するには、受信ハンドラを登録します。ここでは、超簡単!標準アプリ向けの受信ハンドラ内で受信したデータを JSON 形式に変換し、それを出力しています。
# Register an event handler
@twelite.on (mw. common. PacketType. APP_TWELITE)
def on_app_twelite (packet: mw. parsers. app_twelite. ParsedPacket) -> None :
print(packet. to_json(verbose= True , spread= False ))
受信ハンドラは、任意の関数へ twelite.on()
デコレータ ? を適用することで登録できます。
受信ハンドラは、
mw.Twelite
オブジェクトの初期化後に同一のスコープへ定義する必要があります(
practical.py
では
main()
関数内)。受信ハンドラの定義箇所に制約を設けることで、グローバル空間の不要な汚染を避けるように誘導しています。
受信ハンドラにおけるパケット種別の指定 受信ハンドラが受け取るデータの内容は、パケットの種別に応じて定義されたデータクラスに基づきます。
超簡単!標準アプリ
@twelite.on (mw. common. PacketType. APP_TWELITE)
def foobar (packet: mw. parsers. app_twelite. ParsedPacket):
# handle packets
リモコンアプリ
@twelite.on (mw. common. PacketType. APP_IO)
def foobar (packet: mw. parsers. app_io. ParsedPacket):
# handle packets
アリア(通常)
@twelite.on (mw. common. PacketType. APP_ARIA)
def foobar (packet: mw. parsers. app_aria. ParsedPacket):
# handle packets
キュー(通常)
@twelite.on (mw. common. PacketType. APP_CUE)
def foobar (packet: mw. parsers. app_cue. ParsedPacket):
# handle packets
キュー(動作パル・ムーブ/ダイス)
@twelite.on (mw. common. PacketType. APP_CUE_PAL_EVENT)
def foobar (packet: mw. parsers. app_cue_pal_event. ParsedPacket):
# handle packets
動作パル/キュー(動作パル・連続)
@twelite.on (mw. common. PacketType. APP_PAL_MOT)
def foobar (packet: mw. parsers. app_pal_mot. ParsedPacket):
# handle packets
環境パル
@twelite.on (mw. common. PacketType. APP_PAL_AMB)
def foobar (packet: mw. parsers. app_pal_amb. ParsedPacket):
# handle packets
開閉パル/アリア・キュー(開閉パル)
@twelite.on (mw. common. PacketType. APP_PAL_OPENCLOSE)
def foobar (packet: mw. parsers. app_pal_openclose. ParsedPacket):
# handle packets
シリアル通信(書式A、簡易)
@twelite.on (mw. common. PacketType. APP_UART_ASCII)
def foobar (packet: mw. parsers. app_uart_ascii. ParsedPacket):
# handle packets
シリアル通信(書式A、拡張)
@twelite.on (mw. common. PacketType. APP_UART_ASCII_EXTENDED)
def foobar (packet: mw. parsers. app_uart_ascii_extended. ParsedPacket):
# handle packets
アクト
@twelite.on (mw. common. PacketType. ACT)
def foobar (packet: mw. parsers. act. ParsedPacket):
# handle packets
受信ハンドラが受け取るデータクラス ParsedPacket
は、JSON 形式の文字列へ変換する to_json()
、辞書へ変換する to_dict()
、pandas データフレームへ変換する to_df()
といったメソッドを備えています。
ここでは、to_json()
メソッドを使って JSON 形式の文字列へと変換しています。
print(packet. to_json(verbose= True , spread= False ))
オプション引数について verbose
オプションを False
とした場合は system_type
などのシステム情報を出力しません。また、spread
オプションを True
とした場合は di_state
などの List-like な要素(mw.common.CrossSectional[T]
型)を個別に展開して出力します。ただし、加速度サンプルといった時系列データ(mw.common.TimeSeries[T]
型)は展開しません。
なお to_df()
に spread
オプションはありません。時系列でない List-like なデータは強制的に個別の列へ展開されるほか、時系列データは個別の行へ展開されます。
受信の開始と終了 mw.Twelite
は、threading.Thread
を継承しています
。practical.py
では、twelite.start()
が別のスレッドで受信処理を開始し、twelite.stop()
がそれを停止しています。
# Start receiving
try :
# Set as daemon thread
twelite. daemon = True
# Start the thread, Join to the main thread
twelite. start()
print("Started receiving" )
while True :
twelite. join(0.5 )
except KeyboardInterrupt :
# Stop the thread
print("Flushing..." )
twelite. stop()
print("Completed" )
twelite.daemon
を True
へ設定すると、受信処理を担うサブスレッドは デーモン化 されます。デーモンでない生存中のスレッドがすべて終了すると、 Python プログラム全体も終了します。ここではメインスレッド内で twelite.join()
を繰り返し呼ぶことで、メインスレッドを待機させています。
メインスレッドは Ctrl+C
の入力を検知すると except
節で twelite.stop()
を呼び出し、受信処理を停止させます。twelite.stop()
はサブスレッドが受信ハンドラの呼び出しを終えるまで待機します。
join()
に関する注意次のように while
ループを使用しない場合、Windows において Ctrl+C
を受け付けないことがあります。
try :
...
twelite. join()
except KeyboardInterrupt :
...
補足説明 PEP8 への対応 practical.py
や MWings のソースコードは、PEP8 に対応したコードフォーマッタ Black を使ってフォーマットされています。
正確には、完全に PEP8 へ準拠しているわけではありません Black は一行の最大長を除き、いかなる設定も受け付けない頑固なフォーマッタですが、コーディング規約を策定・共有する手間を省くことができます。コーディングルールはしばしば物議を醸す議題ですが、そうした取るに足らない作業へ費やすリソースを有益な作業へ割り当てることこそが Python らしさの本質でしょう。
プロジェクトへ Black を追加するには、下記を実行します。
poetry add --group dev black
dev
グループを指定することで、開発時の依存関係であることを示しています。Node.js の devDependencies
と似ています。
対象のファイルやディレクトリを指定して実行できます。
フォーマットせずに確認だけ行うこともできます。
poetry run black --check mwtest
型ヒントへの対応 practical.py
や MWings のソースコードは、型ヒント へ対応しています。
型ヒントとは 型ヒントは Python 3.5 で実装された機能です。動的型付けの Python における型アノテーションは実行時に意味を成しませんが、静的型チェッカによる検査はコードの品質と信頼性の向上に寄与します。
型ヒントに対応していないライブラリは、静的型チェッカのエラーを引き起こします。従来の パルスクリプト は未対応でした。
MWings ライブラリは、Python 公式の静的型チェッカである mypy を使用しています。
プロジェクトへ mypy を追加するには、下記を実行します。
poetry add --group dev mypy
こちらも Black と同様に、対象のファイルやディレクトリを指定して実行できます。
関連情報 実用的なスクリプトの応用 practical.py
をさらに発展させたスクリプトを公開しています。
mwings_python/examples at main
親機の出力を保存したテキストファイルを読み込み、解釈した結果を pandas データフレームへ保存し、最終的に CSV または Excel ファイルを出力します。Lite版は非対応。
コマンドラインツールとして利用できます
poetry run python log_export.py -h
usage: log_export.py [ -h] [ -x] [ -v] [ -s] INPUT_FILE
Parse a log file for App_Wings
positional arguments:
INPUT_FILE text file contains logs from App_Wings
options:
-h, --help show this help message and exit
-x, --excel export an Excel file instead of CSV
-v, --verbose include system information
-s, --sort sort columns in the output
接続された親機の出力を受け取り、解釈した結果を pandas データフレームへ保存し、最終的に CSV または Excel ファイルを出力します。Lite版は非対応。
CSV ファイルを選択した場合、すべての結果を一つのファイルへ保存します。 代わりに Excel ファイルを選択した場合、パケットの種別ごとに別のシートへ保存します。
コマンドラインツールとして利用できます
poetry run python rx_export.py -h
usage: rx_export.py [ -h] [ -x] [ -v] [ -s]
Log packets from App_Wings to csv or excel
options:
-h, --help show this help message and exit
-x, --excel export an Excel file instead of CSV
-v, --verbose include system information
-s, --sort sort columns in the output
rx_export.py
は受信したデータのすべてを一旦 pandas データフレームへ保存するため、長期間に渡る記録には適していません。しかし、Excel ファイルの出力に対応しています。
接続された親機の出力を受け取り、解釈した結果を送信元のシリアルIDごとに CSV ファイルへ追記していきます。Lite版は非対応。
コマンドラインツールとして利用できます
poetry run python rx_export_csv_durable.py -h
usage: rx_export_csv_durable.py [ -h] [ -v] [ -s]
Log packets from App_Wings to csv, line by line
options:
-h, --help show this help message and exit
-v, --verbose include system information
-s, --sort sort columns in the output
rx_export_csv_durable.py
はデータを受信するたびに CSV ファイルを開き、データを追記 します。rx_export.py
と異なり Excel ファイルの出力を行えませんが、長期間に及ぶ記録に適しています。
接続された親機の出力を受け取り、単に解釈した結果を pandas データフレームへ変換し、文字列として出力します。Lite版は非対応。
接続された親機の出力を受け取り、単に解釈した結果を辞書へ変換して出力します。Lite版も対応。
接続された親機の出力を受け取り、単に解釈した結果を JSON 文字列へ変換して出力します。Lite版も対応。
接続されたシリアル通信アプリの親機を介して、TWELITE UART へバイナリデータ [0xBE, 0xEF]
を送ります。Lite版も対応。
接続された親機・中継機アプリの親機を介して、TWELITE DIP の DO1 ポートに接続された LED を点滅させます。Lite版も対応。
接続された親機・中継機アプリの親機を介して、通知パルの LED を各色で点灯させます。Lite版も対応。
8秒ごとに3秒間点滅させるコマンドを送信します。通知パルの問い合わせ間隔(送信間隔)を2秒など短めに設定してください。デフォルトでは60秒に一度更新されます。
API リファレンス 3.2 - TWELITE Wings API / MWings for 32-bit Arduinos 32ビット Arduino ボードのための TWELITE Wings API / MWings
3.2.1 - TWELITE Wings API / MWings for 32-bit Arduinos 最新版
3.2.1.1 - TWELITE SPOT に使用する TWELITE SPOT に搭載された ESP32 に使用する方法
TWELITE SPOT スタートガイド:
TWELITE 子機からのデータ受信 をご覧ください。
3.2.1.2 - Arduino UNO R4 に使用する Arduino UNO R4 シリーズに使用する方法
Arduino UNO R4 シリーズ へ TWELITE UART や TWELITE DIP などの TWELITE 親機を接続し、MWings ライブラリを使って子機との通信を行う方法を案内します。
ハードウェアの準備 TWELITE の準備 TWELITE UART や TWELITE DIP といった製品へ親機・中継機アプリ(App_Wings)を書き込みます。
書き込みには TWELITE STAGE APP を使用 します。
2023年12月現在、シリアル通信によるアプリケーションID等の設定に対応した最新版の App_Wings(v1.3.0+)は TWELITE STAGE SDK に同梱しておりません(次期リリースに追加収録の予定です)。
下記をダウンロードしてから、書き込んで ください。
シリアル通信によるアプリケーションID等の設定を行わない場合は、従来の親機・中継機アプリを使用できます。
Arduino UNO R4 との接続 TWELITE のピンのうち、下記を使用します。
VCC(3.3V へ接続) GND(GND へ接続) TXD(D0/RX へ接続) RXD(D1/TX へ接続) RST(D11 など任意のポートへ接続) PRG(D12 など任意のポートへ接続)
Arduino UNO R4 の I/O ポートは 5V レベルですが、TWELITE は 3.3V レベルのため、レベル変換を必要とします。
RST および PRG ピンは、Arduino の起動時に TWELITE をリセットするために接続することを推奨します。
ライブラリ付属のサンプルスケッチに準じた接続例を以下に示します。
Arduino との接続例
Arduino Ethernet Shield 2 など、SPI 接続のシールドが D10-13 を使用するときは、別のピンを割り当ててください。
ソフトウェアの準備 ライブラリの導入 Arduino ライブラリマネージャからインストールできます。
TWELITE SPOT マニュアル:MWings ライブラリの導入 を参照してください。
サンプルスケッチの動作確認 ライブラリには、各 TWELITE と通信を行うための簡単なサンプルスケッチを同梱しています。
例えば、超簡単!標準アプリ(App_Twelite)のデータを受信する場合は、メニューバーから以下のサンプルスケッチを開きます。
ファイル > スケッチ例 > MWings > Arduino UNO R4 > Receive > monitor_uno_r4_app_twelite
表示例
monitor_uno_r4_app_twelite.ino
// Monitor example for TWELITE with Arduino UNO R4: Receive data from App_Twelite
#include <Arduino.h>
#include "MWings.h"
const int RST_PIN = D11;
const int PRG_PIN = D12;
const int LED_PIN = D13; // Use on-board LED as indicator
const uint8_t TWE_CHANNEL = 18 ;
const uint32_t TWE_APP_ID = 0x67720102 ;
void setup ()
{
// Initialize serial ports
while (! Serial && millis() < 5000 ); // Wait for internal USB-UART
Serial.begin(115200 );
Serial.println("Monitor example for TWELITE with Arduino UNO R4: App_Twelite" );
Serial1.begin(115200 );
// Initialize TWELITE
if (Twelite.begin(Serial1,
LED_PIN, RST_PIN, PRG_PIN,
TWE_CHANNEL, TWE_APP_ID)) {
Serial.println("Successfully initialized TWELITE" );
} else {
Serial.println("Failed to initialize TWELITE" );
}
// Attach an event handler to process packets from App_Twelite
Twelite.on([](const ParsedAppTwelitePacket& packet) {
Serial.println("" );
Serial.print("Packet Timestamp: " );
Serial.print(packet.u16SequenceNumber / 64.0f , 1 ); Serial.println(" sec" );
Serial.print("Source Logical ID: 0x" );
Serial.println(packet.u8SourceLogicalId, HEX);
Serial.print("LQI: " );
Serial.println(packet.u8Lqi, DEC);
Serial.print("Supply Voltage: " );
Serial.print(packet.u16SupplyVoltage, DEC); Serial.println(" mV" );
Serial.print("Digital Input: " );
Serial.print(packet.bDiState[0 ] ? " DI1:Lo" : " DI1:Hi" );
Serial.print(packet.bDiState[1 ] ? " DI2:Lo" : " DI2:Hi" );
Serial.print(packet.bDiState[2 ] ? " DI3:Lo" : " DI3:Hi" );
Serial.println(packet.bDiState[3 ] ? " DI4:Lo" : " DI4:Hi" );
Serial.print("Analog Input: " );
Serial.print(" AI1:" ); Serial.print(packet.u16AiVoltage[0 ]); Serial.print(" mV" );
Serial.print(" AI2:" ); Serial.print(packet.u16AiVoltage[1 ]); Serial.print(" mV" );
Serial.print(" AI3:" ); Serial.print(packet.u16AiVoltage[2 ]); Serial.print(" mV" );
Serial.print(" AI4:" ); Serial.print(packet.u16AiVoltage[3 ]); Serial.println(" mV" );
});
}
void loop ()
{
// Update TWELITE
Twelite.update();
}
/*
* Copyright (C) 2023 Mono Wireless Inc. All Rights Reserved.
* Released under MW-OSSLA-1J,1E (MONO WIRELESS OPEN SOURCE SOFTWARE LICENSE AGREEMENT).
*/
スケッチの詳細については、TWELITE SPOT 向けのスケッチ解説をご覧ください。大半の内容は共通しています。
以下は Arduino UNO R4 に固有の部分です。
ポート設定 6-8行目では、UART 関連を除く Arduino のポートを設定しています。
const int RST_PIN = D11;
const int PRG_PIN = D12;
const int LED_PIN = D13; // Use on-board LED as indicator
ポート 役割 備考 D11 TWELITEのRST制御 上記 の接続例参照D12 TWELITEのPRG制御 上記 の接続例参照D13 通信インジケータLED制御 内蔵LEDを使用
USBシリアルポートの初期化待ち 16行目では、USB シリアルポート(Serial
)の初期化を待っています。
while (! Serial && millis() < 5000 ); // Wait for internal USB-UART
Arduino UNO R4 は、UNO R3 のように USB シリアル変換 IC を搭載しておらず、本体の ARM CPU が USB シリアル変換機能を担っています。
そのため、シリアルポートの初期化が終了する前は通信を行えません。
関連情報 MWings ライブラリ API リファレンス TWELITE SPOT スタートガイドのスケッチ解説(スケッチ内容の大半は共通しています) TWELITE SPOT マニュアルの一部のスケッチ解説(スケッチ内容の大半は共通しています) 3.2.1.3 - パケットパーサの拡張 パケットパーサを追加する方法
MWings ライブラリでは、パケットパーサを簡単に追加できます。
ここでは、例として無線タグアプリ(App_Tag)のアナログセンサ用パーサの追加作業を取り上げます。
概要 パーサを追加するためには、次の4点のファイルを編集する必要があります。
(新規)パーサのヘッダファイル parser/FooBarPacketParser.h
解釈するパケットの中身と、正規パケットの判定条件を書く (新規)パーサのソースファイル parser/FooBarPacketParser.cpp
(追記)本体のヘッダファイル MWings.h
(追記)本体のソースファイル MWings.cpp
ソースファイルは GitHub から入手してください。
通常、Arduino のホームディレクトリ内にある libraries/
へ配置します。
パーサのヘッダファイル parser/
以下にある既存のファイルを複製したうえで名称変更してください。
ここでは、parser/AppTagAdcPacketParser.h
を作成します。
#ifndef APPTAGADCPACKETPARSER_H
#define APPTAGADCPACKETPARSER_H
#include "MWings_Common.h"
/**
* @struct ParsedAppTagAdcPacket
* @brief Packet content for App_Tag (ADC)
*/
struct ParsedAppTagAdcPacket final : public mwings:: ParsedPacketBase {
uint32_t u32RouterSerialId;
uint8_t u8SensorType;
uint16_t u16AiVoltage[2 ];
};
/**
* @class apptagadc::PacketParser
* @brief Packet parser for App_Tag (ADC)
*/
namespace apptagadc {
class PacketParser final : public mwings:: PacketParserBase {
public :
// Check if the packet is from App_Tag (ADC)
inline bool isValid(const BarePacket& barePacket) const override {
if ((barePacket.u8At(12 ) == 0x10 )
and (barePacket.u32At(18 ) == 0 )
and (barePacket.u16PayloadSize == 22 )) {
return true;
}
return false;
}
// Parse from bare packet
bool parse (const BarePacket& barePacket, mwings:: ParsedPacketBase* const parsedPacket) const override ;
};
}
extern apptagadc:: PacketParser AppTagAdcPacketParser;
#endif // APPTAGADCPACKETPARSER_H
解釈するパケットの中身の記述 はじめに、App_Tag(アナログセンサ)の出力書式 を確認してください。
出力データの例
:80000000B700628201015A0010DF08FD09A300000000E9
# データ 内容 値 :
char
ヘッダ :
80000000
0 uint32
中継機のシリアルID 中継なし B7
4 uint8
LQI 183/255
0062
5 uint16
続き番号 98
8201015A
7 uint32
送信元のシリアルID 0x201015A
00
11 uint8
送信元の論理デバイスID 0x00
10
12 uint8
センサー種別 アナログセンサー DF
13 uint8
電源電圧(mV) 3330
mV08FD
14 uint16
ADC1の電圧 2301
mV09A3
16 uint16
ADC2の電圧 2467
mV00000000
18 uint32
未使用 E9
22 uint8
チェックサム 0xE9
char
フッタ \r
char
フッタ \n
インクルードガードやnamespace
、コメント文を置換したら、mwings::ParsedPacketBase
を継承し、パケットの中身を記述します。
ここでは、対象の子機に固有のデータを記述します。宛先の論理デバイスIDといった一般的なデータは、既にmwings::ParsedPacketBase
へ登録されているからです。
mwings::ParsedPacketBase
にある項目型 名称 内容 uint32_t
u32SourceSerialId
送信元のシリアルID uint8_t
u8SourceLogicalId
送信元の論理デバイスID uint16_t
u16SequenceNumber
シーケンス番号 uint8_t
u8Lqi
LQI uint16_t
u16SupplyVoltage
電源電圧 (mV)
電源電圧など、空き項目があっても構いません。
以下の部分において、App_Tag(アナログセンサ)に固有のデータを宣言しています。
struct ParsedAppTagAdcPacket final : public mwings:: ParsedPacketBase {
uint32_t u32RouterSerialId;
uint8_t u8SensorType;
uint16_t u16AiVoltage[2 ];
};
正規パケットの判定条件の記述 mwings::PacketParserBase
を継承したapptagadc::PacketParser
を作成し、純粋仮想関数isValid()
をオーバーライドすることで正規パケットの判定条件を記述してください。
この条件に沿ったパケットを受信したとき、解釈を行います。
以下の部分では、センサ種別が0x12
(アナログセンサ)であること、未使用領域が0
であること、ペイロードの長さが22バイトであることを確認しています。
inline bool isValid (const BarePacket& barePacket) const override {
if ((barePacket.u8At(12 ) == 0x10 )
and (barePacket.u32At(18 ) == 0 )
and (barePacket.u16PayloadSize == 22 )) {
return true;
}
return false;
}
パーサのソースファイル parser/
以下にある既存のファイルを複製したうえで名称変更してください。
ここでは、parser/AppTagAdcPacketParser.cpp
を作成します。
#include "AppTagAdcPacketParser.h"
apptagadc:: PacketParser AppTagAdcPacketParser;
bool apptagadc:: PacketParser:: parse(const BarePacket& barePacket, mwings:: ParsedPacketBase* const parsedPacket) const
{
// WARNING: Note that there is NO RTTI
ParsedAppTagAdcPacket* const parsedAppTagAdcPacket = static_cast < ParsedAppTagAdcPacket*> (parsedPacket);
parsedAppTagAdcPacket-> u32SourceSerialId = barePacket.u32At(7 );
parsedAppTagAdcPacket-> u8SourceLogicalId = barePacket.u8At(11 );
parsedAppTagAdcPacket-> u16SequenceNumber = barePacket.u16At(5 );
parsedAppTagAdcPacket-> u8Lqi = barePacket.u8At(4 );
const uint16_t ecc = barePacket.u8At(13 );
if (ecc <= 170 ) {
parsedAppTagAdcPacket-> u16SupplyVoltage = 5 * ecc + 1950 ;
} else {
parsedAppTagAdcPacket-> u16SupplyVoltage = 10 * (ecc - 170 ) + 2800 ;
}
parsedAppTagAdcPacket-> u32RouterSerialId = barePacket.u32At(0 );
parsedAppTagAdcPacket-> u8SensorType = barePacket.u8At(12 );
for (int i = 0 ; i < 2 ; i++ ) {
parsedAppTagAdcPacket-> u16AiVoltage[i] = barePacket.u16At(2 * i+ 14 );
}
return true;
}
解釈する部分の記述 ヘッダファイル名やnamespace
を置換したら、parse()
の中身を記述します。
以下の部分では、データ書式に従ってパケットの中身を格納しています。
無線タグアプリ(アナログセンサ)の出力書式
# データ 内容 備考 char
ヘッダ :
のみ0 uint32
中継機のシリアルID 中継なしは80000000
4 uint8
LQI 0
-255
5 uint16
続き番号 7 uint32
送信元のシリアルID 11 uint8
送信元の論理デバイスID 12 uint8
センサー種別 13 uint8
電源電圧(mV) 電源電圧の計算 を参照14 uint16
ADC1の電圧 16 uint16
ADC2の電圧 18 uint32
未使用 22 uint8
チェックサム
BarePacket.u8At()
など のメソッドを使って、素のペイロードからデータを取り出します。
// WARNING: Note that there is NO RTTI
ParsedAppTagAdcPacket* const parsedAppTagAdcPacket = static_cast < ParsedAppTagAdcPacket*> (parsedPacket);
parsedAppTagAdcPacket-> u32SourceSerialId = barePacket.u32At(7 );
parsedAppTagAdcPacket-> u8SourceLogicalId = barePacket.u8At(11 );
parsedAppTagAdcPacket-> u16SequenceNumber = barePacket.u16At(5 );
parsedAppTagAdcPacket-> u8Lqi = barePacket.u8At(4 );
const uint16_t ecc = barePacket.u8At(13 );
if (ecc <= 170 ) {
parsedAppTagAdcPacket-> u16SupplyVoltage = 5 * ecc + 1950 ;
} else {
parsedAppTagAdcPacket-> u16SupplyVoltage = 10 * (ecc - 170 ) + 2800 ;
}
parsedAppTagAdcPacket-> u32RouterSerialId = barePacket.u32At(0 );
parsedAppTagAdcPacket-> u8SensorType = barePacket.u8At(12 );
for (int i = 0 ; i < 2 ; i++ ) {
parsedAppTagAdcPacket-> u16AiVoltage[i] = barePacket.u16At(2 * i+ 14 );
}
static_cast
についてここでは、mwings::ParsedPacketBase*
からapptagadc::ParsedPacket
へのダウンキャストをdynamic_cast
ではなくstatic_cast
によって行っています。これは、ハードウェアの制約により実行時型情報が使えないことに起因しています。
本体のヘッダファイル 既存のパーサに加えて、新たなパーサを追加します。
インクルード文の追加 パケットパーサのヘッダファイルをインクルードします。
//// AppTagAdcPacketParser for App_Tag (ADC)
#include "parser/AppTagAdcPacketParser.h"
初期化子リストの拡張 イベントハンドラをnullptr
で初期化します。
//// AppTagAdcPacketParser for App_Tag (ADC)
_onAppTagAdcPacket(nullptr ),
終了処理の追加 イベントハンドラをnullptr
に戻します。
//// AppTagAdcPacketParser for App_Tag (ADC)
_onAppTagAdcPacket = nullptr ;
イベントハンドラの登録メソッドの追加 イベントハンドラを登録するon()
メソッドを追加します。
//// AppTagAdcPacketParser for App_Tag (ADC)
inline void on (void (* callback)(const ParsedAppTagAdcPacket& packet)) { _onAppTagAdcPacket = callback; }
イベントハンドラの追加 イベントハンドラを格納するポインタを追加します。
//// AppTagAdcPacketParser for App_Tag (ADC)
void (* _onAppTagAdcPacket)(const ParsedAppTagAdcPacket& packet);
本体のソースファイルの編集 既存のパース処理に加えて、新たなパース処理を追加します。
イベントハンドラの初期化 begin()
の呼びだし時にもイベントハンドラが初期化されるようにします。
//// AppTagAdcPacketParser for App_Tag (ADC)
_onAppTagAdcPacket = nullptr ;
パース処理の追加 対象のパケットを受信したときに解釈を行うようにします。
//// Start: AppTagAdcPacketParser for App_Tag (ADC)
if (AppTagAdcPacketParser.isValid(barePacket) and _onAppTagAdcPacket) {
ParsedAppTagAdcPacket parsedAppTagAdcPacket;
if (AppTagAdcPacketParser.parse(barePacket, & parsedAppTagAdcPacket)) {
_onAppTagAdcPacket(parsedAppTagAdcPacket);
}
}
//// End: AppTagAdcPacketParser for App_Tag (ADC)
変更の適用 スケッチをビルドしたときに、ライブラリも再ビルドされます。
4 - Miscellaneous その他
その他の製品やサービスのマニュアル
4.1 - TWELITE PAL/CUE/ARIA Script TWELITE SENSE PALなどからのデータを処理するPythonスクリプト
新しいライブラリ MWings for Python をご検討ください。
パルシリーズ以外の TWELITE へ対応したほか、JSON や pandas データフレーム等を出力できます。
TWELITE PAL Script は、TWELITE SENSE PAL (センサーパル), TWELITE CUE (加速度センサー・磁気センサー), TWELITE ARIA (温湿度センサー・磁気センサー) からのデータの解釈、ログ記録するためのサンプルスクリプトです。
資料の取り扱いについて をご参照ください。 お気付きの点がありましたら、当サポート窓口にご連絡いただければ幸いです。
本アプリケーションは参考として提供されています。
本アプリケーションならびに本ドキュメントは無保証です。 予告無く仕様が変更されます。 モノワイヤレス ソフトウェア使用許諾 (MW-SLA-1J/E) に基づきます。 4.1.1 - 使用方法 TWELITE PAL Scriptの使用方法
TWELITE PALとMONOSTICKを使う場合の使用方法をご案内いたします。
PCの準備 ダウンロードしたアーカイブをわかりやすいフォルダ(例えばC:) に解凍する。
下記WebページよりPCの環境にあったAnacondaをダウンロードし、インストールする。https://www.anaconda.com/download/ Anacondaをインストールしたくない場合は”Anacondaをインストールしない場合”を参照
Anaconda Promptを立ち上げ、下記コマンドを実行しpyserialをインストールする。 (Windowsの場合、Anaconda Promptは スタートメニュー → Anaconda3 内にあるのでそちらから立ち上げること。)
Anacondaをインストールしない場合 下記のインストール手順はOSがWindowsの場合の一例です。 各種ライブラリのドキュメントをご覧の上、必要なソフトウェアおよびライブラリをインストールしてください。
下記ページよりPythonの最新版をダウンロードしインストールする。https://www.python.org/downloads/ その時、下図の枠で囲まれている部分にチェックを入れること もしくはPythonのインストール先にPathを通すこと。
コマンドプロンプトを立ち上げ、下記コマンドを入力しpyserialをインストールする。
TWELITE PAL の準備 BLUE PAL/RED PALにSENSE PALを接続する。 BLUE PAL/RED PALの電池ホルダーにコイン型電池(CR2032)を挿入する。 MONOSTICK の準備 MONOSTICKのアプリ(App_PAL-Parent-xxx-MONOSTICK.bin)を書き換える。 MONOSTICKをリセットもしくはUSBポートに差しなおす。 スクリプトの実行方法 MONOSTICKのCOMポートがCOM6の場合、Anaconda Promptで下記コマンドを実行すると下記のようなデータが出力されます。(Teratermが接続された状態では起動できません。)
cd C:\P AL_Script
python PAL_Script.py -t COM6
*** MONOWIRELESS App_PAL_Viewer 1.1.0 ***
*** Open COM6 ***
ArriveTime : 2021/03/05 09:43:28.880
LogicalID : 1
EndDeviceSID : 10B6465
RouterSID : No Relay
LQI : 180 ( -35.50 [ dBm])
…
スクリプトを終了させるにはAnaconda PromptでCtrl+C
を入力してください。
スクリプトの引数 スクリプト実行時に以下の引数を使用できます。
引数:-h 機能:コマンドライン引数の一覧を表示 使用例:python PAL_Script.py -h
引数:-t 機能:MONOSTICKが使用するポート名を指定 設定項目:MONOSTICKのポート名 初期値:Windowsの場合:COM3、Linuxなどの場合:/dev/ttyUSB0 使用例:python PAL_Script.py -t COM6
引数:-b 機能:MONOSTICKが使用するポートのボーレートを指定 設定項目:MONOSTICKのボーレート 初期値:115200 使用例:python PAL_Script.py -t COM6 -b 115200
引数:-l 機能:CSV形式のログを出力 使用例:python PAL_Script.py -t COM6 -l 備考:同一ディレクトリ内にCSVファイルが生成される。 ファイル名はAppPAL_シリアル番号_PAL_YYYYMMDD.csv
CSVファイルの読み方は下記表の通りです。
見出し 値の説明 単位 LogicalID 子機の論理デバイスID - EndDeviceSID 子機のシリアルナンバー - LQI LQI - Power 電源電圧 mV ADC* 電圧 mV HALLIC マグネットセンサーの状態 - Temperature 温度 ℃ Humidity 湿度 % Illuminance 照度 Lux AccelerationX AccelerationY AccelerationZ
加速度 g
4.1.2 - ソースファイル TWELITE PAL Scriptのソースファイル
動作環境 以下の環境で動作確認を行いました。
4.1.2.1 - PAL_Script.py TWELITE PAL Scriptの実行用スクリプト
本スクリプトを起動するためのコードで、MONOSTICKからのデータを読み込み、解釈されたデータの標準出力を行います。
読み出し方法 以下のコード例では、都度 MONOSTICK からデータを受信したかどうかを確認し、受信していればMain()に渡す処理を行っています。
from apppal import AppPAL
...
def mainloop (PAL):
global end_flag
try :
from Main_user import Main
except :
mainflag = False
else :
mainflag = True
if PAL. ReadSensorData():
if mainflag:
Main(PAL)
else :
PAL. ShowSensorData()
...
if __name__ == '__main__' :
...
try :
PAL = AppPAL(port= options. target, baud= options. baud, tout= 0.05 , sformat= options. format, autolog= bEnableLog, err= bEnableErrMsg, stdinput= options. stdinp, Logfilename= options. file)
except :
print("Cannot open \" AppPAL \" class..." )
exit(1 )
while True :
try :
mainloop(PAL)
except KeyboardInterrupt :
break
del PAL
まず、AppPALオブジェクトを生成します。オブジェクト生成時にシリアルポートの設定も行うため、シリアルポートの設定パラメータを引数として渡します。
PPAL = AppPAL(port= options. target, baud= options. baud, tout= 0.05 , sformat= options. format, autolog= bEnableLog, err= bEnableErrMsg, stdinput= options. stdinp, Logfilename= options. file)
次にmainloop()でシリアルデータが来ているかどうかを判断するために ReadSensorData() を呼びます。返り値が True だったら、解釈したをMain()に渡します。
def mainloop (PAL):
# ユーザが処理を記述するMain関数がインポートできるか確認する。
try :
from Main_user import Main
except :
mainflag = False
else :
mainflag = True
# データがあるかどうかの確認
if PAL. ReadSensorData():
if mainflag:
# Main関数が読めたらPALオブジェクトをMain()に渡す
Main(PAL)
else :
# Main関数が読めなかったらコンソールにデータを表示する。
PAL. ShowSensorData()
受け取る辞書に関してはこちら を参照してください。
4.1.2.2 - Main_user.py TWELITE PAL Scriptのうち、データを読み込んだ後に行う処理を記述するコード
本コードにはデータを読み込んだ後のメインの処理を記述します。
ここでは、データを受け取った際に解釈したデータをコンソールに出力するコードを記述しています。
# この関数に処理したい内容を書く
def Main (PAL= None ):
# 渡された変数がAppPALクラスか確認する。
if isinstance(PAL, AppPAL):
sns_data = PAL. GetDataDict()
# 受信時間
print('Receive Time: ' , end= '' )
if isinstance(sns_data['ArriveTime' ], datetime. datetime):
print(sns_data['ArriveTime' ]. strftime('%Y/%m/ %d %H:%M:%S' ) + '. %03d ' % (sns_data['ArriveTime' ]. microsecond/ 1000 ))
else :
print(sns_data['ArriveTime' ])
# 論理デバイスID
print('Logical ID: 0x %02X ' % sns_data['LogicalID' ])
# シリアル番号
print('Serial ID: 0x' + sns_data['EndDeviceSID' ])
# 電源電圧
print('Power: %d mV' % sns_data['Power' ])
# センサーの名前を調べる
sname = PAL. GetSensorName()
# センサー名がPALだったらPAL/ARIA/CUE、モデル名を出力する。
if sname == 'PAL' :
pid = PAL. GetPALName()
print('Sensor: ' + pid )
else :
print('Sensor: ' + sname )
# アナログセンサーモード(App_Tag)
if sname == 'Analog' :
print('ADC1: %d mV' % sns_data['ADC1' ])
print('ADC2: %d mV' % sns_data['ADC2' ])
else :
# ホールIC
if 'HALLIC' in sns_data. keys():
print('HALLIC: %d ' % sns_data['HALLIC' ])
# 温度
if 'Temperature' in sns_data. keys():
print('Temperature: %.02f degC' % sns_data['Temperature' ])
# 湿度
if 'Humidity' in sns_data. keys():
print('Humidity: %.02f %% ' % sns_data['Humidity' ])
# 照度
if 'Illuminance' in sns_data. keys():
print('Illuminance: %f lux' % sns_data['Illuminance' ])
# 気圧
if 'Pressure' in sns_data. keys():
print('Pressure: %f hPa' % sns_data['Pressure' ])
# 加速度
if 'AccelerationX' in sns_data. keys():
print('X: ' , end= '' )
print(sns_data['AccelerationX' ])
print('Y: ' , end= '' )
print(sns_data['AccelerationY' ])
print('Z: ' , end= '' )
print(sns_data['AccelerationZ' ])
# ジャイロ
if 'Roll' in sns_data. keys():
print('Roll: ' , end= '' )
print(sns_data['Roll' ])
print('Pitch: ' , end= '' )
print(sns_data['Pitch' ])
print('Yaw: ' , end= '' )
print(sns_data['Yaw' ])
# カラーセンサー
if 'Red' in sns_data. keys():
print('Red: ' , end= '' )
print(sns_data['Red' ])
print('Green: ' , end= '' )
print(sns_data['Green' ])
print('Blue: ' , end= '' )
print(sns_data['Blue' ])
print('IR: ' , end= '' )
print(sns_data['IR' ])
print()
4.1.2.3 - MNLib TWELITE PAL Scriptのうち、シリアルデータの読み込みやそれを解釈するコード
TWELITE PAL Scriptのうち、シリアルデータの読み込みやそれを解釈するコードが入ったフォルダです。
4.1.2.3.1 - apppal.py 読み込んだバイト列を解釈して辞書オブジェクトに登録するクラス
Class AppPAL
AppBaseを継承し、得られたペイロードを解釈して、使いやすいデータに変換して、辞書オブジェクトに登録するクラスです。
定義するときのパラメータ 初期値が設定されているものは指定不要。
変数名 型 初期値 内容 port string None 開くシリアルポート名
例:COM3、/dev/ttyUSB0 など
baud int 115200 ボーレート tout float 0.1 シリアル通信するときのタイムアウト時間(秒) sformat string Ascii 本設定値はAsciiで固定 autolog boolean False ペイロードが解釈出来たときに自動でCSVファイルにログを出力する場合はTrue err boolean False エラーメッセージを出力する場合はTrue
ReadSensorData()
本メソッドでペイロードを読み込んだら、 TWELITE PAL 親機の書式フォーマット に従ってそのペイロードの解釈を行います。
パラメータ なし
戻り値 データが読み込めた場合:True
読み込めなかった場合:False
辞書オブジェクトに格納されたデータのキーは下記の通りです。
EventIDなどのデータの意味に関しては、
こちら もご確認ください。
キー 型 内容 ArriveTime datetime ペイロードを得たときの時間 LogicalID int 子機の論理デバイスID EndDeviceSID int 子機のシリアル番号 RouterSID int 最初に受信した中継機のシリアル番号
(親機が直接子機のパケットを受信した場合は0x80000000)
LQI int 受信電波品質 SequenceNumber int パケットが送信されるごとにインクリメントされる続き番号
1からスタート、65535の次に0に戻る
Sensor int センサー種別(0x80で固定) PALID int PAL基板ID PALVersion int PAL基板バージョン HALLIC int ホールICの状態 Temperature float 温度(degC) Humidity float 湿度(%) Illuminance int 照度(lux) AccelerationX list,float X軸の加速度(g) AccelerationY list,float Y軸の加速度(g) AccelerationZ list,float Z軸の加速度(g) SamplingFrequency int 加速度のサンプリング周波数 EventID list,int イベントの要因とイベントID WakeupFactor list,int 起床した要因等のデータ
OutputCSV()
辞書オブジェクトをCSVファイルに出力します。
パラメータ なし
戻り値 なし
4.1.2.3.2 - appbase.py シリアルデータ解釈のための基底クラス
class AppBase
本コードでは、すべてのTWELITE APPS 共通で必要な機能が実装されており、シリアルデータの読み込みに必要なシリアルポートの開閉処理やシリアルデータの読み込み、ログファイルの出力などの処理が記述された基底クラスです。 これを継承した apppal.py が得られたバイト列を解釈し、辞書オブジェクトにデータを入れてメイン関数に返します。
GetDataDict()
ペイロードの解釈し、データを格納した辞書オブジェクトを返します。
パラメータ なし
戻り値 型 内容 Dict ペイロードを解釈したデータを格納した辞書オブジェクト
4.1.2.3.3 - mwSerial.py シリアルポートの管理を行うクラス
Class MWSerial
本クラスはシリアルの読み書きなど、シリアルポートの管理を行うクラスです。
定義するときのパラメータ 初期値が設定されているものは指定不要。
変数名 型 初期値 内容 port string None 開くシリアルポート名
例:COM3、/dev/ttyUSB0 など
baud int 115200 ボーレート timeout float 0.1 シリアル通信するときのタイムアウト時間(秒) parity int serial.PARITY_NONE パリティを指定する stop int 1 ストップビット byte int 8 データビット長 rtscts int 0 RTSとCTSを有効にする場合は1 dsrdtr int 0 DSRとDTRを有効にする場合は1 mode string Ascii 本設定値はAsciiで固定
SerialSelect
PCに接続されたシリアルポートを検索し、使用するシリアルポートをユーザー選択します。
シリアルポートが1ポートしかない場合は自動的にそのポート名を使用します。 シリアルポートがない場合はNoneを指定します。 シリアルポート名を引数に指定した場合はそのシリアルポートを使用します。
パラメータ 変数名 型 初期値 内容 portname string None 開くシリアルポート名 (例:COM3、/dev/ttyUSB0 など)
自動選択する場合は、指定しないこと。
戻り値 なし
4.1.2.3.4 - parseFmt.py parseFmt_*.py TWELITE シリアル書式パーサ
class FmtBase
書式パーサーの基底クラスで共通手続きを定義する。これを継承した FmtAscii (アスキー形式 ASCII形式), FmtBinary (バイナリ形式 Binary形式) を利用する。
書式パーサーは、シリアル入力を想定し、アスキー形式の場合は1行単位でバイナリ形式の場合は1バイト単位で入力系列を解釈し、その系列が書式で定義されるヘッダ、フッタ、チェックサムを満足した時、解釈の完了とし、ヘッダ、フッタを除いた内容(ペイロード)を格納する。
process(c)
入力文字列の解釈を行う。解釈後は is_complete()
が true
を返した場合、解釈が成功し get_payload()
によりペイロードを得ることができる。ペイロードは続く process()
処理などを実行すると内容を保証しないため、解釈終了後に速やかに利用します。
続けて別の系列を解釈したい場合は、そのまま process()
を実行する。
パラメータ パラメータ 内容 c
解釈したい入力系列。1バイト単位の解釈と系列単位の解釈の2種類に対応する。1バイト単位の入力では、int型のアスキーコード、str型、bytes型、list型の長さ1の系列。系列単位の入力では list 型、str型、bytes型の1系列を処理する。データに複数系列ある場合や途中で切れている場合は処理できない。
戻り値 なし
is_comp()
process()
処理後に呼び出し、書式解釈の完了状況を知らせる。true を得た場合は get_peyload()
または get_payload_in_str()
メソッドにより、ペイロードを取得する。
続く process()
などの処理により、内部格納されるペイロードは初期化や破壊されるため、速やかにデータをコピーします。
パラメータ なし
戻り値 値 内容 true
解釈に成功した。ペイロードが利用できる。 false
解釈に失敗した、または、書式の途中である。
get_payload()
ペイロードを返す。
パラメータ なし
戻り値 ヘッダやフッタが含まれないペイロード部を list型 バイト列として返します。
reinit()
明示的に内部を初期状態にします。
パラメータ なし
戻り値 なし
その他メソッド 内部で利用する目的でいくつかのメソッドが定義されています。詳細はソースコードを参照してください。
コード例 系列単位の解釈 str
型の系列 a
を解釈し、pay
にペイロード情報保存します。pay
には [ 0x78, 0x80, 0x01, ... , 0x00 ]
が格納されます。
import parseFmt_Ascii
fmta= parseFmt_Ascii. FmtAscii()
a = ':7880010F0F0380030002800200DF'
pay = []
fmta. process(a)
if fmta. is_comp():
pay = fmta. get_payload()
1バイト単位の解釈
バイナリの系列 b
について、1バイトごと process()
メソッドにより系列の解釈を進めます。終端の 0x04
を投入した時点で、解釈が完了しペイロードが pay
に保管されます。
import parseFmt_Binary
fmtb= parseFmt_Binary. FmtBinary()
b = [0xA5 , 0x5A , 0x80 , 0x05 , 0x78 , 0x00 , 0x11 , 0x22 , 0x33 , 0x78 , 0x04 ]
pay = []
for x in b:
fmtb. process(x)
if fmtb. is_comp():
pay = fmtb. get_payload()
break