Loading...
Loading...
Loading...
サンプルコード
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
標準アプリケーション
TWELITE DIPに工場出荷時に書き込まれている標準アプリ(App_Twelite)のシリアルメッセージを解釈してLCD画面上に表示します。
M5stickに接続する前に書き込んだTWELITE DIPが無線パケットを受信してデータを出力するかPCで確認しておいてください。
M5Stack側のTWELITE DIPは、以下のような接続をしておきます。以下の配線はTWELITE DIPを親機設定(M1=GND)とした配線をしています。AI1-4はアナログポートがオープンになり不定な入力を防ぐためです(App_TweliteではVCCレベルを入力した場合、そのポートを未使用とする意味を持たせています)
シリアルポートの初期化を行っています。
LCDスクリーンの初期化を行います。処理の内容はscreen.cにあり、ターミナル画面の初期設定を行います。
シリアルポートの入力チェックを行います。入力したデータを the_input_uart
キューにいったん投入します。
シリアルポートから入力データを処理します。ここではパーサーに文字列を投入します。パーサーによりシリアル電文が解釈できた場合は、update_screen()
を呼び出しターミナル画面に文字を更新します。
LCD画面上のターミナル画面領域を書き換えます。処理の内容はscreen.cにあります。
受信したパケットデータを読み取り、画面表示を更新します。
この関数内ではエスケープシーケンスを用いて画面の表示位置などを制御しています。
パケットデータはspLastPacket
に格納されています。これの内容を紐解くにはretTwePacketTwelite()
を呼び出します。xの値を読み出して、これに対応して画面を更新します。
MWM5ライブラリには、シリアル入出力、画面出力など多岐にわたるコードが含まれます。ここでは、コマンドライン(コンソール)画面上で動作標準入出力のみを用いる単純なサンプルについて解説します。
サンプルはexamples_con/
以下に格納します。
glancer_con : App_Wings(または各アプリのUART出力)を解釈して、各パケットメッセージの概要を表示します。
ハードウェア接続
MONOSTICK または TWELITE-R と TWELITE モジュールを接続し、必要に応じて各OS向けのデバイスドライバの設定を行います。
TWELITE DIPとの接続例です。シリアルポート(UART)のTX,RXのみのシンプルな接続です。この接続では TWELITE 上のファームウェアの書き込みなどが行えません。
以下の配線をすることで PGM/RESET/SET ピンが接続されます。TWELITE STAGEアプリケーションを利用する場合は、下記の配線を行ってください。
ハードウェアの接続構成によっては、結線してはいけない場合もあります。ハードウェアの接続については M5Stack の資料も参考の上、十分注意して行ってください。
例: M5Stack faces の GPIO05 ピンは、キーパッドの割り込みピン(出力)が接続されているため、M5Stack側で出力制御を行うことはできません(故障の原因になりえます)。TWELITE STAGEアプリケーションでは、キーパッドに対応するI2Cデバイスを検出した場合は、出力制御しないようにしています。
Raspberry Pi では /dev/srial0
(TWELITE STAGEのマニュアル参照) を選択した場合(raspi-config などの設定等により異なる場合があります)、以下の配線にてシリアルポートの経由でTWELITE無線マイコンとのUART接続を行います。
TWELITE, RaspberryPi ともに製造元のマニュアルを参照ください。
DIP# は TWELITE DIP のピン番号です。
上記配線は TWELITE 無線マイコンモジュールが安定稼働することを保証するものではありません。
ライブラリの使用
ソースコード上でライブラリを使用するには #include <mwm5.h>
をソースコード上に記述します。
Arduino.h, M5Stack.h は mwm5.hより後でインクルードしてください。
mwm5.hにはusing namespace
を用いて、ライブラリ中の名前空間を可視にし省略できる宣言が含まれています。これら名前空間を明示的に記述したい場合は替わりに#include <twelite.hpp>
を記述してください。
ここでは、以下の解説が含まれます。
ビルド(コンパイル)について
開発環境は以下のリンクを参照ください。
M5Stack Library - https://github.com/m5stack/M5Stack
最初に上記ライブラリに含まれるサンプルスケッチをビルド、書き込みを行ってください。
MWM5ライブラリは https://github.com/monowireless/mwm5 で配布しています。ソースファイル一式をダウンロードしてください。本ドキュメント記載時点に一致するバージョンは変更履歴に記載があります。
変更履歴にある zip ファイルをダウンロードして、開発環境の指定するlibraryディレクトリに展開するか、開発環境の「zip形式のライブラリのインストール」を行ってください。アンインストールはライブラリディレクトリを削除します。
PS2Keyboard - http://www.pjrc.com/teensy/td_libs_PS2Keyboard.html esp32/PS2Keyboard.7z をライブラリディレクトリに展開してください。ビルド時に必要になります。 PS2Keyboard プロジェクトの成果物に対して 1) 日本語レイアウトのキーボード対応 2) カーソルキー等の取り扱いの微調整を実施しています。修正内容はソースコードを参照ください。
Windows10ではVisual Studio 2019でビルドを行っています。また MingW32 用のビルド定義も含めています。
以下が必要になります。
make
gcc9 (gcc-9, g++-9)
以下が必要になります。
make XCodeに付随します。OS バージョンにもよりますが、ターミナルで make と入力すればインストーラーが起動します。
gcc9 (gcc-9, g++-9) homebrew のパッケージをダウンロードして利用します。
macOS 10.15 (Catalina) では、clangを用いることも可能です。オプションOSX_COMPILERTYPE=clang
を追加してmakeしてください。
※ C++17 の filesystem ライブラリがバージョン依存になります。10.15以前ではビルドできず、またビルドしたバイナリを10.14以前で動作させることもできません。
以下が必要になります。
gcc9 (gcc-9, g++-9)
SDL2 開発者向けライブラリ (libsdl2-dev
)
SDL2 のライブラリやヘッダファイルは、ソースパッケージに添付していますが、依存ライブラリのリンクに必要です。
以下を参考にしてください
M5Stack Library - https://github.com/m5stack/M5Stack
TWELITE_Stage アプリは examples/TWELITE_Stage にあります。M5Stackライブラリ導入後、このフォルダに対してビルドしてください。
プロジェクト MWM5.sln を開きます。
Sketch>TWELITE_Stage をスタートアッププロジェクトにします。 必須ではありませんが、デバッガを起動する際などにこのプロジェクトが選択されます。
Debug/Release のいずれかを選択します。
32bit/64bit のいずれかを選択します。
Sketch>TWELITE_Stage を右クリックしてビルドを選択します。
実行形式は msc\Release msc\Debug などのディレクトリに格納されます。
コマンドプロンプト、シェルを開きます。
make, gcc-9, g++-9 が動作することを確認します。
{ソースコードを展開したディレクトリ}/examples/
{ビルドしたいプロジェクト:例 TWELITE_Stage}/build
に移動します。
make を実行します。
make のルール本体は {ソースコードを展開したディレクトリ}/mkfiles
以下に格納しています。
VSCode用のTWELITE STAGE 用のデバッガ起動定義(.vscode/launch.json
)を含めています。環境に合わせて利用ください。
stopAtEntry
は、main()
の先頭で停止する設定で false でも構わない。
externalConsole
は、false
でないと起動しない。
cwd
は、TWELITE STAGEの場合 MWSDKディレクトリを指定する。
App_Wings(または各アプリのUART出力)を解釈して、各パケットメッセージの概要を表示します。
glancerは「glance(一目する)人」の意味の英単語です。
プロジェクトフォルダのソースコードはglancer.cpp
のみです。残りの必要なコードはsrc/..
を参照します。
MWM5ライブラリ全てのファイルは必要ありません。以下に必要なファイルを列挙します。
上記で必要なファイル等は本ドキュメントと相違ある場合もあります。問題があればビルド時にエラーが表示されますので、エラーファイルに記述される"~not found"といったメッセージを頼りに足りないファイルをコピーしてください。
examples/glancer_con というプロジェクト定義がありますので、こちらをビルドしてください。
make (GNU) と g++ (gcc より) が必要です。事前にインストールを済ませてください。
Makefile
を確認してください。以下の定義は必要に応じて書き換えます。
makeコマンドを実行します。
標準入力(通常の1バイト入力を用いているため改行が入力されるまでは入力文字列は評価されません)にアスキー形式のUARTメッセージを入力します。出力はPKT...
となります。
先頭の項目について解説します。
解説 Parser についても参照ください。
必要な標準ライブラリヘッダとMWM5ライブラリヘッダを読み込みます。
MWM5ライブラリでは細かく名前空間が使用されていますが、利用時には煩雑ですのですべてusing namespace
により省略可能とします。
AsciiParser
のクラスインスタンスを生成しておきます。
このサンプルでは標準入力から1バイトずつ入力(std::cin::get()
)して、これをASCIIパーサーに投入します。
標準入力ではシステムによって改行コードが異なりますが、ここでは'r'
または'\n'
のいずれが来ても'\r'
を投入するようにしています。本パーサーは末尾の'\r'
のみを評価するためです。
投入後書式が完了した場合はparse_ascii
はtrue
を戻します。ここでデータを解釈します。
ASCIIパーサーにより得られたバイト列は.get_payload()
メソッドにより配列SmplBuf_Byte
型として取り出すことが出来ます。
このサンプルでは得られたバイト列を解釈して、どの種別のUARTメッセージなのか、何が格納されているのかを取り出せるようにします。
バイト列を解釈する手続きはnewTwePacket()
にバイト列payl
を与えます。戻り値としてクラスオブジェクトpkt
を生成します。このオブジェクトはspTwePacket
型の(メモリ管理を行う)スマートオブジェクトで、TwePacket
型のオブジェクトを格納します。
実際にはpkt
は種別に応じたTwePacket
型の派生クラスのインスタンスが格納されています。この派生クラスの種別を確認するのがidentify_pkt_type()
で、パケット種別としてE_PKT
型の値を返します。
パケット種別が得られたら、パケット種別ごとの表示関数print_???(spTwePacket)
を呼び出しています。
ここから先はパケット種別ごとに手続きが違います。以下にApp_Tweliteの解釈例、App_PALの解釈例を示します。
App_Twelite の UARTメッセージの解釈を行います。まずspTwePacket
型のままでは、App_Twelite特有のデータにアクセスできません。
まずrefTwePacketTwelite()
を呼びます。戻り値はTwePacketTwelite
の参照型です。App_TweliteのUARTメッセージを解釈した特有のデータが含まれます。例えば.DI1
はDI1のHigh/Low状態を示します。
TWELITE PALのUARTメッセージを解釈します。TWELITE PALは接続される基板によって異なるUARTメッセージが出力されます。このためデータ取得も一旦PALとして解釈してから、さらに個別のPAL基板のデータを取り出します。
最初にPAL共通データをrefTwePacketPal()
により取り出します。
最初にパケットにイベントが含まれるかどうかの判定を行います。イベントパケットは例えば通知(NOTICE)PALの加速度センサーが静止状態から加速度を検出した(タップ)といった現象をイベント番号として伝えるものです。イベントパケットにも様々なデータが付加されますが、通常はイベント番号を参照します。
パケットの種別を.get_PalDataType()
により判定します。
PAL基板の種別がわかったら、PAL基板の種別に応じた手続き(.get_PalMag()
など)により、PAL基板特有のデータが含まれるクラスオブジェクトを得ます。
上記の例では開閉センサーPALの磁気センサーの状態を得ています。
TWELITE PAL
TWELITE PAL のパケットデータの表示を行います。
TWELITE PALの親機用ファームウェア(App_PAL-Parent-BLUE.binまたはApp_PAL-Parent-RED.bin)をTWELITE DIPにあらかじめ書き込んでおきます。
M5Stackに接続する前に書き込んだTWELITE DIPが無線パケットを受信してデータを出力するかPCで確認しておいてください。
M5Stack側のTWELITE DIPは、以下のような接続をしておきます。
シリアルポートの初期化を行っています。
LCDスクリーンの初期化を行います。処理の内容はscreen.cにあり、ターミナル画面の初期設定を行います。
パケットデータの管理クラスの初期化を行います。
シリアルポートの入力チェックを行います。入力したデータを the_input_uart
キューにいったん投入します。
シリアルポートから入力データを処理します。ここではパーサーに文字列を投入します。パーサーによりシリアル電文が解釈できた場合は、update_screen()
を呼び出しターミナル画面に文字を更新します。
LCD画面上のターミナル画面領域を書き換えます。処理の内容はscreen.cにあります。
入力データの管理と表示を行う関数です。
このクラスでは、パケットデータに含まれる送信元論理IDごとのspTwePacket
データを保存しています。新しいデータを受信したら都度更新します。
画面表示は論理ID1から順に、最後のデータまで1行ずつ表示します。1画面に収まらない場合は、次のページに表示します。
init_screen()
は初回の初期化を行います。fmt_status
は上部タイトルエリアへの出力文字を指定します。
フォント変更などで画面サイズに変化があった場合はreinit_screen()
を呼び出します。
受信パケットデータを登録します。内部的にはIDに対応したspTwePacket
の配列に値を入れます。
ページ設定を行います。画面の更新をするため、直後にupdate_term()
を呼び出します。
set_page()
はentry
に対応する論理IDが含まれるページに移動します。
上部タイトルエリアの文字列を再設定します。
ターミナル画面の表示文字列の更新を行います。
パラメータなしで呼び出すか、update_all=trueで呼び出すと、ターミナル全体の再描画を行います。
pal_upd
を指定しupdate_all=false
の場合は、pal_upd
の表示行のみを更新します。
環境
以下の環境で開発しています。
動作等の不都合がある場合は、下記の環境を参考にしてください。
ターミナル(コンソール)クラスの利用例
M5stackの320x200ドット液晶に固定幅ターミナルウインドウを表示します。
以下は画面出力の例です。
まずターミナルオブジェクトを生成します。ここでは最大64カラム、最大20行、左上から (0,16)の位置に(320,192)サイズの領域とします。
次に「東雲フォント16ドット」をフォントID=10で生成しています。フォントを管理するオブジェクトはライブラリ内部で生成・管理されます。
ターミナルにフォントなどを基本的な設定を行います。フォントを先ほどのフォントID=10として指定し、フォントの文字色と背景色を指定します。カーソルを2(ブリンク表示)とします。最後にforece_refresh()
にて初期描画を行います。
setup()
が終了したらloop()
での周期実行中に、一定時間ごとに画面の描画を行います。ここでは32ms以上経過したら再描画するようにしています。
以下の例ではボ タン Aでは"hello world!" + 改行の出力、ボタンBでは画面のクリア、ボタンCも同様に画面のクリア(エスケープシーケンスによる)を行います。
シリアル電文パーサーの利用例
TWELITE 無線マイコンから UART (シリアルポート)経由での電文書式を解釈します。電文書式は、可読性・エラー検出などを目的として、伝送したいデータ列に対して所定の変換を行います。
ここではアスキー形式の解釈を行うAsciiParser
について解説します。
アスキー形式は、バイナリで構成されたデータ列を文字列で表現する方法です。TWELITE無線マイコンでは最も良く用いられる形式です。
例えばバイト列で 00A01301FF123456
をアスキー形式で表現すると、以下のようになります。先頭は :
で B1
がチェックサム、終端は [CR:0x0d][LF:0x0a]
となります。
:00A01301FF123456B1[CR][LF]
終端のチェックサムを省略できます。チェックサムからCRLFの系列をX
に置き換えます。文字化けによる誤ったデータ系列には弱くなりますが、実験などでデータを送付したいときに便利です。
:00A01301FF123456X
上記の例では parser_ascii
というオブジェクトを内部バッファ256バイトで生成しています。このバッファサイズは、書式の解釈後に必要なバイト数です。
ASCII形式では実際のバイト数の約2倍の書式になります。例えば書式が200バイトの系列の場合は、実データは約100バイトになります。
無線パケットの最大格納バイト数が100バイト強であるため、この例では余裕をもって256バイトのバッファとしています。
このAsciiParserは1バイトずつの処理を行います。シリアルポートからは1バイトずつデータが到着するためです。
上記例では、シリアルポートから1バイト読み出してはparse_acsii
に1バイトずつ<<演算子を用いて読み込ませています。
直後のif(pars_ascii)
での判定は、アスキー形式の系列が正しく解釈できたかどうかを判定しています。
以下のように配列にアクセスできます。
Parser
オブジェクトにデータ列が格納されている場合、>>
演算子を用いることで書式をシリアルポート(Serial
)やターミナル(ITerm
)などに出力することが出来ます。
通常は、解釈用のParser
オブジェクトと出力用のParser
オブジェクトは別々に用意します。
解釈用のオブジェクトはシリアル入力など都度処理が行われます。このオブジェクトを一時的なデータ出力の目的で使用すると、解釈中の内部データが破壊されます。
newTwePacket()
は入力されたデータ系列を解釈して、spTwePacket
型のオブジェクトを生成します。このオブジェクトはTwePacket
型のデータを格納するスマートポインタstd::shared_ptr
で、メモリ管理を簡素化することができます。
パケット種別はE_PKT
列挙体で定義されています。ここではTWELITE PALの出力形式PKT_PAL
の解釈を行います。
std::shared_ptr
の利用は、パケット情報を他にコピーして利用する場合を想定しています。例えば履歴配列に保存して、過去の情報を参照するような場合です。
オブジェクトは参照カウンタにより管理されていて、所有者が0になれば破棄されます。
解釈されたパケットの種別はidentify_packet_type()
により判別します。パケット種別はE_PKT
列挙体で定義されています。
解釈したパケットがE_PKT::PKT_PAL
と判定された場合は、refTwePacketPal()
によりTwePacketPal
型として参照できます。上記コード例ではユニバーサル参照auto&&
を用いて型名を推測させています。
PALのパケット書式は様々な派生があります。
解釈済みの系列はget_payload()
メソッドにて取得できます。get_payload()
はの参照型を戻します。
解釈時にまずイベントデータがあるかどうか取り出します。イベントが含まれるパケットはにより判定できます。イベントのみ受信できれば良い場合はで得られたイベントデータを参照して終了です。
イベント以外の情報が欲しい場合は、一旦を用いてパケットのデータ構造を特定します。特定したデータ構造に応じたデータ取得を行います。
上記の例では、MAG(OPEN-CLOSE SENSE PAL)のオブジェクトを生成しています。ここではオープンクローズに応じた分岐にを読み出しています。
オプション
内容
DEBUG_BUILD=1
デバッグビルドを行います。デバッガを使用する場合に使います。
OSX_COMPILERTYPE=clang
clang でビルドします (OS X のみ)
ファイル名
内容
mwm5.mk
コンパイルするファイルなどの定義
rules.mk
コンパイルのルール
arch.mk
実行OSの判定
arch_linux.mk
Linux用の諸定義
arch_mac.mk
macOS用の諸定義
arch_win.mk
MingW64用の諸定義
環境
内容
OS
Windows10 バージョン1903
M5Stack ハードウェア
M5stack BASIC
M5Stackライブラリ
0.2.9
定義
内容
TWE_STDINOUT_ONLY
必須。標準入出力のみでビルドしたい場合に必要な定義です。
TWE_HAS_MILLIS
システム時間[ms]を得るmillis()
を実装した場合は定義します。定義するとパケット情報にタイムスタンプ[ms]情報が含まれます。
※ millis()
の実装には、システム時間を取得するためのOS依存のシステムコールが必要です。
定義名
CXX
g++-9 など実行名が違う場合に書き換えます。
※ Makefile 中で動作環境を判定している部分があり、この部分に定義が含まれます。
DEFINES
必要に応じて。 -D???
の定義をコンパイラに与えます。
CFLAGS
必要に応じて。コンパイルオプションをコンパイラに与えます。
項目
内容
Typ=
パケットの種別です。
Lq=
LQI値が格納されます。
Ad=
32bitの送信元アドレスと8bitの送信元論理アドレスが格納されます。
Vmv=
電源電圧です。
※ メッセージにデータがない場合は 0000 となります。
Tms=
メッセージを受信したシステム時間が格納されます。
※ millis()
を実装しておく必要があります。
====== | 元データのバイト数 | バイト数 | 解説 |
ヘッダ | 1 |
|
データ部 | N | 2N | 元データの各バイトをアスキー文字列2文字(A-F は大文字)で表現します。
例えば 0x1F は |
チェックサム | 2 | データ部の各バイトの和を8ビット幅で計算し2の補数をとります。つまりデータ部の各バイトの総和+チェックサムバイトを8ビット幅で計算すると0になります。
チェックサムバイトをアスキー文字列2文字で表現します。
例えば |
フッタ | 2 | [CR] (0x0D) [LF] (0x0A) を指定する。 |