Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
本パッケージ内で、ライセンス上特別な記述のないものは、モノワイヤレスソフトウェア使用許諾契約書(MW-SLA)を適用します。
本ドキュメントについても、本ライブラリパッケージ部の一部としてMW-SLA下の取り扱いとします。
本ソフトウェアについては、モノワイヤレス株式会社が正式にサポートを行うものではありません。お問い合わせにはご回答できない場合もございます。予めご了承ください。
不具合などのご報告に対してモノワイヤレス株式会社は、修正や改善をお約束するものではありません。
また導入パッケージなどお客様の環境に依存して動作しない場合もございます。
開発環境を構築するためには、ソフトウェア群のインストール、またこれらの利用許諾に同意する必要があります。また、PC、ワークステーション上でセキュリティ設定等が必要になる場合があります。
配布時には十分注意しておりますが、ウィルスなどの確認はお客様のほうでも留意いただくようお願いいたします。
お客様のセキュリティの考え方や運用(例:外部アプリケーションのインストールの可否)については、お客様の環境の管理者にご確認ください。
また、開発環境をインストールまた動作するにあたり、OSが介在し設定等必要になる場合があります(例:開発元が不明なアプリケーションの実行。開発環境または紹介するツール群の多くは、アプリケーションは開発元を証明する仕組みが組み込まれせん)。設定方法については、一般の情報を参考いただくようお願いいたします。
MWXライブラリを用いてアプリケーションを記述するには以下が必要です。
MWSDK(ソフトウェア開発環境)
開発用エディタ(Microsoft社のVisualStudio Codeを紹介します)
コンパイラのツールチェインなどは比較的環境への依存度が低いため、多くの環境で動作することが期待できますが、サポート中のWindows10バージョンを推奨します。動作環境の差異により動作しないような場合は、当社で確認している環境を参考に別途環境を用意してください。
以下、開発で使用しているバージョンを挙げます。
Windows10 #1809, #1903
.NET CLR v4.0.30319
FTDI社のドライバが動作していること (MONOSTICK, TWELITE Rを動作させるため)
WSL (Windows Subsystem Linux) 環境下でもコンパイラを動作させることが出来ます。ただしコンパイルのみでファームウェアの書き換え等はWindows10上のユーティリティから実施してください。
WSL環境は必須ではありません。
コンパイラのツールチェインなどは比較的環境への依存度が低いため、多くの環境で動作することが期待できますが、現在サポート中のディストリビューションを推奨します。動作環境の差異により動作しないような場合は、当社で確認している環境を参考に別途環境を用意してください。
以下、開発で使用しているバージョンを挙げます。
Ubuntu 16.04 LTS 64bit
Ubuntu 18.04 LTS 64bit
*32bitのシステムはサポートしません。
コンパイラのツールチェインなどは比較的環境への依存度が低いため、多くの環境で動作することが期待できますが、現在サポート中のディストリビューションを推奨します。動作環境の差異により動作しないような場合は、当社で確認している環境を参考に別途環境を用意してください。
以下、開発で使用しているバージョンを挙げます。
macOS 14.06
開発環境を動作させるための環境や使用方法については、その開発元やコミュニティの情報を参照ください。
コード記述作業の効率面で Visual Studio Code (VSCode) の利用を推奨します。
MWXライブラリでは、C言語の開発に比べ、読み込むヘッダファイルが多くなるため、VSCode上でのコード解釈等にはより多くのPCのリソースを要求します。
Linux/WSL環境下/macOSのビルド結果はWindows10の結果と異なります。通常系の動作で差異が見られることは当社が把握する限りありませんが、特にgccのLTOを無効にしているためバイナリサイズが数%程度大きくなる傾向にあります。
動作等に疑問を感じた際は、必ず Windows10 上のビルドを実施し再現することを確認してから、お問い合わせください。
Install and Build
MWXライブラリを用いてアプリケーションを記述(本書ではアクトと呼びます)し、実行するために開発環境のセットアップが必要です。
下の記述は TWELITE STAGE SDK MWSDK2020_12 に対応します。
TWELITE STAGE SDK をダウンロードした場合は、配布zipアーカイブを、日本語や空白文字が含まれないディレクトリに展開します。
TWELITE STAGE については以下もご覧ください。
TWELITE STAGE アプリを用いる場合は、環境変数の設定は不要です。コマンドラインでビルドを行う場合は設定してください。
MWSDK_ROOT
, MWSDK_ROOT_WINNAME
(Windows10のみ) の設定が必要です。
ここでは展開後のディレクトリ名を C:\MWSTAGE
とします。別のディレクトリにインストールした場合は、読み替えてください。
C:\MWSTAGE\Tools\SET_ENV.CMD
を実行してください。以下の環境変数を設定します。
MWSDK_ROOT
MWSDK_ROOT_WINNAME
例えば以下のような設定になります。
インストールしたPC上からTWELITE STAGE SDKをアンインストールするには以下を行ってください。
UNSET_ENV.cmd
を実行してください。環境変数の設定を解除します。
MWSTAGEディレクトリを削除してください。
開発環境やシェルに MWX_ROOT
環境変数を反映されるように設定してください。
方法はいくつかありますが、ホームディレクトリの.profile
(ファイルがなければ新しく作成してください)に以下の設定を追加します。この設定でVSCodeのビルドまで可能です。
MWSDK_ROOT=/foo/bar/MWSTAGE/MWSDK/
export MWSDK_ROOT
エディタを使用せずに追加するには以下のようにコマンド入力します。$
はプロンプトで環境によって表示が違います。/foo/bar/MSWSDK
の部分はインストールしたディレクトリに応じて書き換えてください。
開発環境やシェルに MWX_ROOT
環境変数を反映されるように設定してください。
方法はいくつかありますが、ホームディレクトリの.profile
(ファイルがなければ新しく作成してください)に以下の設定を追加します。この設定でVSCodeのビルドまで可能です。
MWSDK_ROOT=/foo/bar/MWSTAGE/MWSDK/
export MWSDK_ROOT
エディタを使用せずに追加するには以下のようにコマンド入力します。$
はプロンプトで環境によって表示が違います。/foo/bar/MSWSDK
の部分はインストールしたディレクトリに応じて書き換えてください。
環境全体にMWSDK_ROOT
を適用にするにはLaunchDを用います。
VS Codeの一部の設定で環境変数を参照していますが、ビルドには必須ではありません。
SDKに収録された時点から、ライブラリソースコードに修正がある場合があります。改版履歴を参照の上、必要に応じでライブラリソースコードを差し替えてください。
軽微な修正にあたるものは、本改版履歴には記載を行わずGitHub上の改版のみとなります。必要に応じて修正を引用ください。
TWELITE STAGE の配布パッケージリリース後の修正・追加分などはGitHubレポジトリに格納しております。必要に応じて配布パッケージの位置を差し替えて利用いただくようお願いいたします。
MWSDKの他の更新が必要になる場合があります。更新時のリリース記述を参照してください。MWSDKの更新についてはこちらを参照ください。
ライブラリのソースコードは GitHub (https://github.com/monowireless/mwx)にて公開しています。ライブラリのソースコードの差し替えは、以下の手順で行ってください。
各リリースのリンクよりGitのクローンを行うか zip 形式でソースコードをダウンロードします。
以下のディレクトリの内容を差し替えます。
リリース前の更新については上記に掲載する場合があります。
インタラクティブモード中で Serialクラスオブジェクトを用いた出力を可能とする内部手続きを追加 (Serial._force_Serial_out_during_intaractive_mode()
)
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
を用いスリープを行うと、復帰時にピンが正しく初期化されなかった
TWELITE CUE のボードビヘイビア(https://mwx.twelite.info/v/v0.1.7/boards/cue)を追加。
NWK_SIMPLE 利用時に NWK_SIMPLE 形式でない他のパケット(ネットワーク利用無し)を受信する方法を追加。NWK_SIMPLE::receive_nwkless_pkt()
を追加してNWK_SIMPLEを初期化する。 このパケット情報を用いる場合は .get_psRxDataApp()
による TWENET C ライブラリ層の構造体、および .get_payload()
により得られるデータ配列のみを利用してください。受信パケット(auto&& rx = the_twelite.receiver.read()
)の他のメソッドから得られる情報は不定です。
get_stream_helper()
コードのリファインと読み書き位置のAPIの整備。
smplbuf::get_stream_helper()
の不具合修正
serparser/pktparser
を他のプラットフォームでビルドできるようサンプルを用意しました (https://github.com/monowireless/mwx/tree/master/stdio)
商・余を計算する div100()
をSerial等へ出力できるようにした
smplbuf<>
配列クラスの実装変更。消費メモリの削減などを目的としてmwx::stream
の継承をやめ、別途継承クラスとヘルパークラス定義した
mwx_printf()
mwx_snprintf()
の関数を追加した
the_twelite.stop_watchdog()
, the_twelite.restart_watchdog()
を追加した
mwx::stream
のメンテナンス: operator bool()
の廃止。読み出しタイムアウトの設定で 0xff を指定した場合(.set_timeout(0xff)
)タイムアウトを無効に。その他 <<
演算子の定義を追加。
NOTICE PAL / PCA9632 のサポートを追加 (解説 https://mwx.twelite.info/v/latest/boards/pal/pal_notice, サンプル https://github.com/monowireless/Act_samples/tree/master/Unit_using_PAL_NOTICE)
除算を行わない 8bit と 0..1000 間のスケール関数を追加。
10,100,1000による除算(商と余を同時に計算) div10()
, div100()
, div1000()
を追加。値域を制限し乗算とビットシフトを中心に構成。
暗号化パケットの対応メソッドを追加
packet_rx::is_secure_pkt()
: 受信パケットが暗号化されているかどうかの判定
STG_STD::u8encmode()
: インタラクティブモードでの暗号化設定を取得
STG_STD::pu8enckeystr()
: インタラクティブモードでの暗号化鍵バイト列の取得
Serial1: デフォルトのポートは半導体の仕様では I2C と重複する DIO14,15 だが、通常 I2C に割り当てられるため DIO11(TxD), DIO9(RxD) とした。
Serial: ボーレートの指定で /100 が発生するが、主要なボーレートについてこの計算を省略するようにした。
Serial: available()
, read()
を外部で実施するための代理関数の保持を void*
のみとし、仕様メモリを 8bytes 削減。
typedef boolean
の追加
ネットワーク: 暗号化の対応を追加。
暗号化を有効にするには NWK_SIMPLE::secure_pkt(const uint8_t*, bool = false)
を設定追加する。1番目のパラメータは暗号キー、2番目を true
にすると、平文のパケットも受信する。
SHT3xとBME280のセンサーサポート追加
センサー: レガシーコード(Cライブラリのラッパクラス)で、設定パラメータや状態をやり取りするための仕掛けを追加した。
センサー: SHT3x, BME280では I2C アドレスを指定可能とした。
設定: hide_items()
を追加。不要な設定項目を削除可能。
設定: H/W UTIL メニューを追加。DIの状態表示、I2Cのプローブ、PAL EEPROM内容の表示。
設定: 暗号化関連のメニューの追加
I2C関連の修正(TwoWireクラスを用いて実装されたコードとの親和性を向上するための修正)
requestFrom(false)
の処理時に NO_STOP メッセージの送信コードが無かったため処理が正常に行われなかった。
TwoWire
のクラス名エリアスを追加した。
begin()
処理で、多重初期化しないようにした。
setClock()
メソッドを追加(ただしダミー関数で何もしない)
WIRE_CONF::WIRE_???KHZ
を追加。バスクロックの主要な設定値を追加した。
チャネルマネージャ chmgr
の実装
delayMilliseconds()
の追加
digitalReadBitmap()
の追加
delay()
の精度向上
Serial1
インスタンスが定義されていない問題を修正
Analogue
の割り込みハンドラが呼び出されない問題を修正
MWSDK2020_05 に対応
重複チェッカ duplicate_checker の初期化等に不備があり期待通りの除去を行っていなかった
format() の実装を機種依存の少ないものとした。また、引数を最大8までとした。64bit引数が含まれる場合は引数の数は制限される。
修正は MWSDK2020_05 を前提としています。
本修正については、更新を推奨します。
MWSDK2020_04 に対応
Timer0..4の初期化の問題を修正
mwx::format() の内部処理を変更
インタラクティブモード対応のための実験的なコードの追加
本修正は MWSDK2020_04 を前提としています。
本修正については、更新を推奨します。
パケット内の中継フラグの扱いについての問題を修正
本修正については、更新を推奨します。
初版リリース (SDL 2019/12月号収録)
新しいプロジェクトの作成は、すでにあるサンプルアクトのディレクトリを別の名前でコピーし、ファイル名の編集を行います。
コピー先のディレクトリは MWSDK 配下のディレクトリでなくても構いません。ただし、ディレクトリ名に空白文字や日本語名が含まれてはいけません。
MWSDK以外のディレクトリにコピーした場合 VS Code のワークスペース定義の一部が機能しなくなります。ワークスペースにmwxライブラリのソースコードディレクトリが追加されている場合は、新たに設定してください。
ライブラリソース設定をしなくてもビルドには影響はありません。より深いコード解釈をVSCode上で行い、編集効率を上げるための設定です。
プロジェクトのファイル構造は以下のようになっています(ここでは PingPong
を例に挙げます)。
この PingPong
ディレクトリを別の場所(ただしディレクトリ名に日本語や空白が含まない)にコピーします。
編集の必要があるのは、PingPong.cpp
のファイル名です。これをディレクトリ名と同じAlphaBravo.cpp
に変更します。
build\build-BLUE.cmd
を実行してBINファイルが生成されれば完了です(Windows10)。
Linux/WSL/macOS ではmake TWELITE=BLUE
を実行して、ビルドが成功するか確認します。
プロジェクトのディレクトリ名と同じ名前の .cpp ファイルは必須です。 (MWSDK 2020-04 では、任意のファイル名でOKになりました)
ビルド対象のファイルを追加する場合は build/Makefile を編集します。編集方法は をご覧ください。
ライブラリ名
依存バージョン
mwx
twesettings
TWENET C
1.3.5
ライブラリ名
依存バージョン
mwx
twesettings
TWENET C
1.3.5
ライブラリ名
依存バージョン
mwx
twesettings
TWENET C
1.3.4
ライブラリ名
依存バージョン
mwx
twesettings
TWENET C
1.3.4
ライブラリ名
依存バージョン
mwx
twesettings
TWENET C
1.3.4
ライブラリ名
依存バージョン
mwx
twesettings
TWENET C
1.3.3
他のプラットフォームでも一部の機能(serparser, pktparser, コンソール用Serialオブジェクト)をビルドできるように、ビルド定義を用意しています。必要なファイルのみを切り出しています。
ビルド定義は{mwxライブラリ格納}/stdio
フォルダに格納しています。ビルド方法はREADME.md(リンクはGitHub上)を参照してください。
C++11でのコンパイルが出来ること。
C++11の標準ライブラリヘッダが利用できること (utility, algorithm, functional, iteratorなど)
new/delete/virtualは使用しません。
newによるメモリ確保は例外的に使用する場合があります。
serparser/pktparserでnew演算子を利用するalloc_heap
ではdelete
による処理を行っています。
(参考) ただしmwxライブラリとしてはdelete
については考慮しない前提で設計されている部分もあります。
テンプレートコードです。
the_twelite
を設定してアプリケーションID APP_ID
, 無線チャネルCHANNEL
、受信有を設定します。
またnwk
を生成し、子機アドレス0xFE
を指定しています。このアドレスは子機でアドレスを指定していない名無しの子機という意味です。
設定できるアドレスは0x00: 親機,0x01~0xEF: 子機, 0xFE:子機アドレス未指定の範囲です。
送信先として指定するアドレスは0x00は親機宛、0x01~0xEFは指定の親機アドレス、0xFEは任意の子機アドレス、0xFFは親機を含む任意のアドレスです。
またButtons
オブジェクトを初期化します。連続参照によるチャタリング抑制アルゴリズムです。10msごとに5回連続同じ値になれば対象のポート(PIN_BTN
のみ)のHI
またはLOW
を確定します。pack_bits(N1, N2, ..)
は1UL<<N1 | 1UL << N2 | ...
を行いビットマップを生成します。
the_twelite
を開始するための手続きです。act0..4では出てきませんでしたがthe_twelite
の設定や各種ビヘイビアの登録を行った場合は、必ず呼び出すようにしてください。
始動時setup()
の後に1回だけ呼び出されます。メッセージの表示のみ。
Buttonsによる連続参照により状態を確定します。ボタン状態が変化したらシリアルに出力します。
Serial.available()
がtrue
の場合は、シリアルポートからの入力が保存されています。シリアルから1文字読み込んで、入力文字に応じた処理をします。
t
を入力して無線送信't
'を入力したときは送信を行います。このサンプルではtx_busy
フラグを用い連続的に入力は行わないようにしています。
送信要求は一定数までキューに保存されるため、キューの範囲(3パケット)で要求を積むことは可能です。
以下はif(!tx_busy)
の判定をしないようにして 'tttt
'と連続的に入力した場合の処理例です。4つ目の要求でキューが一杯になって要求は失敗しています。Transmit()
の.prepare_tx_packet()
で得られたpkt
オブジェクトがfalse
になります。
送信タイミングはランダム化されるため、送信完了は送信要求順にはなりません。
s
を入力してスリープ5000ms=5秒のスリープを実施します。復帰後はwakeup()
が実行されます。
スリープ起床時に最初に呼び出されます。メッセージの表示のみ。
送信要求を行う最小限の手続きです。
この関数を抜けた時点では、まだ要求は実行されていません。しばらく待つ必要があります。この例では100-200msの送信開始の遅延を設定しているため、送信が開始されるのは早くて100ms後です。
送信完了時に呼び出されます。evには送信IDと完了ステータスが含まれます。
パケットを受信したら、送信元のアドレス情報を表示します。
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
エラーが発生した場合は、モジュールリセットする
パケット送信を行うため <NWK_SIMPLE>
をインクルードしています。また、アプリケーションIDなど基本的な定義は "Common.h"
に記述しています。
loop()
内の順次処理を記述うするため、このサンプルではステートマシン(状態遷移)の考え方を用います。ごく単純な状態遷移の処理をまとめた<SM_SIMPLE>
を用います。
Common.h
に以下の状態に対応する列挙体 STATE
が定義されています。
状態を示す列挙体STATE
を用いてSM_SIMPLE
ステートマシン(状態遷移)を宣言します。
ここで宣言されたstep
は、状態の管理、タイムアウト、処理待ちを行うための機能が含まれています。
このサンプルではセンサーデーターの処理は行いませんが、ダミーデータを用意しておきます。
変数やクラスオブジェクトの初期化を行います。
step
ステートマシンの初期化
the_twelite
クラスオブジェクトの初期化
ネットワーク <NWK_SIMPLE>
の登録と初期化(DEVICE_ID
の登録)を行います。
つづいてクラスオブジェクトやハードウェアなどの開始処理を行います。
the_twelite
を開始するための手続きです。act0..4では出てきませんでしたがthe_twelite
の設定や各種ビヘイビアの登録を行った場合は、必ず呼び出すようにしてください。
setup()
の直後に一度だけ呼び出されます。SleepNow()
関数夜を呼び出して初回のスリープ手続きを行います。
起床直後に呼び出されます。ここではセンサーデータ領域の初期化と、起床時のメッセージを出力しています。
上記のコードは、実際のコードを簡略化したものです。
この制御構造はSM_SIMPLEステートマシンを利用しています。do..while() 構文のループになっています。ループの中はswitch case節となっていて、.state()
で得られた状態により処理を分岐しています。状態の遷移は.next()
を呼び出しステートマシン内の内部変数を新しい状態値に書き換えます。
step.b_more_loop()
は、.next()
により状態遷移があった場合trueに設定されます。これは状態遷移が発生したときloop()
を脱出せずに次の状態のコード(case節)を実行する目的です。
以下に各状態の解説を行います。
ダミーーのセンサー値を初期化します。一つは加算カウンタ、一つはカウンター停止値でランダムに決定しています。
WORK_JOB状態では1msごとのタイマー単位で処理します。TickタイマーごとにTickTimer.available()
になります。Tickタイマーごとにカウンタを加算しdummy_work_ct_max
になったら、次の状態STATE::TX
に遷移します。
Transmit()
関数を呼び出しパケット送信要求を行います。送信要求が成功した場合はSTATE::WAIT_TXEVENT
に遷移して送信完了を待つことになります。ここでは完了待ちとしてSM_SIMPLEステートマシンのタイムアウトとフラッグ機能を用います(待ちループ中での変数値の変化により判定する単純なものです)。
単一の送信要求が失敗することは通常想定しませんが、失敗時はSTATE::EXIT_FATAL
として例外処理する状態に遷移します。
この時点ではまだパケットが送信されていないため、この時点でスリープをしてはいけません。多くの場合、送信完了を待ってから、続く処理を行います。
Transmit()
関数はMWX_APIRET
オブジェクトを返しますが、このオブジェクトはbool型の成功の可否と、最大31ビットの値を保持しています。bool型として評価できますから、if文の判定は送信要求が成功したらtrue、失敗したらfalseを返します。
送信完了待ちは後述のon_tx_comp()
によりステートマシン機能のフラッグをセットすることで判定しています。タイムアウトは.is_timeout()
を呼び出すことで.set_timeout()
を行ったときからの経過時間により判定します。
送信が成功しても失敗しても通常は完了通知がありますが、タイムアウトを設け例外処理のための状態STATE::EXIT_FATAL
に遷移します。
SleepNow()
を呼び出して、スリープ処理に入ります。
重大なエラーとして、システムリセットを行います。
周期スリープを行います。スリープ時間はrandom()
関数を用いて、一定の時間ブレを作っています。これは複数のデバイスの送信周期が同期した場合、著しく失敗率が上がる場合があるためです。
スリープ前にはSM_SIMPLEステートマシンの状態を.on_sleep()
を呼び出してセットしておきます。
ID=0x00
の親機宛に無線パケットの送信要求を行います。格納されるデータはActサンプルで共通に使われている4文字識別子(FOURCC
)に加え、システム時間[ms]とダミーセンサー値(sensor.dummy_work_ct_now
)を格納します。
まず最初に送信パケットを格納するオブジェクトを取得します。このオブジェクトを操作し、送信データや条件を設定します。
mwx ライブラリでは、if文中でオブジェクトを取得し、そのオブジェクトのbool判定でtrueの場合に処理を行う記述を採用しています。ここではthe_twelite.network.use<NWK_SIMPLE>()
によりボードオブジェクトを取得し、ボードオブジェクトの.prepare_tx_packet()
によりパケットオブジェクトを取得しています。パケットオブジェクトの取得失敗は通常想定しませんが、失敗時は送信キューが一杯で送信要求が受け付けられない場合です。このサンプルは単一の送信のみですから、エラーは想定外の重大な問題に限られます。
得られたpkt
オブジェクトに対して、送信条件(宛先や再送など)を<<演算子を用いて設定します。tx_addr
はパケットの宛先を指定します。tx_retry
は再送回数、tx_packet_delay
は送信遅延の指定です。
パケットのペイロード(データ部分)は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 型のポインタを用いてデータの書き込みを行うことも出来ます。
.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()
)に格納しています。
送信完了時に呼び出されるシステムイベントです。ここでは.set_flag()
により完了としています。
2台のシリアル接続しているTWELITEの片方からPING(ピン)の無線パケットを送信すると、他方からPONG(ポン)の無線パケットが返ってきます。
いずれかを2台。
TWELITE R でUART接続されているTWELITE DIPなど
全てのアクトで<TWELITE>
をインクルードします。ここでは、シンプルネットワーク <NWK_SIMPLE>
をインクルードしておきます。
サンプルアクト共通宣言
長めの処理を関数化しているため、そのプロトタイプ宣言(送信と受信)
アプリケーション中のデータ保持するための変数
大まかな流れは、各部の初期設定、各部の開始となっています。
このオブジェクトはTWENETを操作するための中核クラスオブジェクトです。
the_twelite
に設定を反映するには <<
を用います。
TWENET::appid(APP_ID)
アプリケーションIDの指定
TWENET::channel(CHANNEL)
チャネルの指定
TWENET::rx_when_idle()
受信回路をオープンにする指定
<<, >>
演算子は本来ビットシフト演算子ですが、その意味合いと違った利用とはなります。MWXライブラリ内では、C++標準ライブラリでの入出力利用に倣ってライブラリ中では上記のような設定やシリアルポートの入出力で利用しています。
次にネットワークを登録します。
1行目は、ボードの登録と同じ書き方で <>
には <NWK_SIMPLE>
を指定します。
2行目は、<NWK_SIMPLE>
の設定で、0xFE
(ID未設定の子機)という指定を行います。
3行目は、中継回数の最大値を指定しています。この解説では中継には触れませんが、複数台で動作させたときにパケットの中継が行われます。
setup()
関数の末尾で the_twelite.begin()
を実行しています。
ADC(アナログディジタルコンバータ)を取り扱うクラスオブジェクトです。
初期化Analogue.setup()
で行います。パラメータのtrue
はADC回路の安定までその場で待つ指定です。
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()
で行います。1番目のパラメータは検出対象のDIOです。BRD_APPTWELITE::
に定義されるPIN_BTN
(12) を指定しています。2番めのパラメータは状態を確定するのに必要な検出回数です。3番めのパラメータは検出間隔です。10
を指定しているので10msごとに5回連続で同じ値が検出できた時点で、HIGH, LOWの状態が確定します。
ButtonsでのDIO状態の検出はイベントハンドラで行います。イベントハンドラは、割り込み発生後にアプリケーションループで呼ばれるため割り込みハンドラに比べ遅延が発生します。
Serial オブジェクトは、初期化や開始手続きなく利用できます。
シリアルポートへの文字列出力を行います。mwx::crlf
は改行文字です。
ループ関数は TWENET ライブラリのメインループからコールバック関数として呼び出されます。ここでは、利用するオブジェクトが available になるのを待って、その処理を行うのが基本的な記述です。ここではアクトで使用されているいくつかのオブジェクトの利用について解説します。
TWENET ライブラリのメインループは、事前にFIFOキューに格納された受信パケットや割り込み情報などをイベントとして処理し、そののちloop()
が呼び出されます。loop()
を抜けた後は CPU が DOZE モードに入り、低消費電流で新たな割り込みが発生するまでは待機します。
したがってCPUが常に稼働していることを前提としたコードはうまく動作しません。
Serial.available()
がtrue
の間はシリアルポートからの入力があります。内部のFIFOキューに格納されるためある程度の余裕はありますが、速やかに読み出すようにします。データの読み出しはSerial.read()
を呼びます。
ここでは't'
キーの入力に対応してvTransmit()
関数を呼び出しPINGパケットを送信します。
DIO(ディジタルIO)の入力変化を検出したタイミングで available になり、Buttons.read()
により読み出します。
1番目のパラメータは、現在のDIOのHIGH/LOWのビットマップで、bit0から順番にDIO0,1,2,.. と並びます。例えば DIO12 であれば btn_state & (1UL << 12)
を評価すれば HIGH / LOW が判定できます。ビットが1になっているものがHIGHになります。
初回のIO状態確定時は MSB (bit31) に1がセットされます。スリープ復帰時も初回の確定処理を行います。
初回確定以外の場合かつPIN_BTNのボタンが離されたタイミングでvTransmit()
を呼び出しています。押したタイミングにするには(!(btn_state && (1UL << PIN_BTN)))
のように条件を論理反転します。
無線パケットの送信要求をTWENETに行う関数です。本関数が終了した時点では、まだ無線パケットの処理は行われません。実際に送信が完了するのは、送信パラメータ次第ですが、数ms後以降になります。ここでは代表的な送信要求方法について解説します。
ネットワークオブジェクトをthe_twelite.network.use<NWK_SIMPLE>()
で取得します。そのオブジェクトを用いて.prepare_tx_packet()
によりpkt
オブジェクトを取得します。
ここではif文の条件判定式の中で宣言しています。宣言したpkt
オブジェクトはif節の終わりまで有効です。pktオブジェクトはbool型の応答をし、ここではTWENETの送信要求キューに空きがあって送信要求を受け付ける場合にtrue
、空きがない場合にfalse
となります。
パケットの設定はthe_twelite
の初期化設定のように<<
演算子を用いて行います。
tx_addr()
パラメータに送信先アドレスを指定します。0x00
なら自分が子機で親機宛に、0xFE
なら自分が親機で任意の子機宛のブロードキャストという意味です。
tx_retry()
パラメータに再送回数を指定します。例の3
は再送回数が3回、つまり合計4回パケットを送ります。無線パケット1回のみの送信では条件が良くても数%程度の失敗はあります。
tx_packet_delay()
送信遅延を設定します。一つ目のパラメータは、送信開始までの最低待ち時間、2番目が最長の待ち時間です。この場合は送信要求を発行後におよそ100msから200msの間で送信を開始します。3番目が再送間隔です。最初のパケットが送信されてから20ms置きに再送を行うという意味です。
ペイロードは積載物という意味ですが、無線パケットでは「送りたいデータ本体」という意味でよく使われます。無線パケットのデータにはデータ本体以外にもアドレス情報などいくつかの補助情報が含まれます。
送受信を正しく行うために、データペイロードのデータ並び順を意識するようにしてください。ここでは以下のようなデータ順とします。このデータ順に合わせてデータペイロードを構築します。
データペイロードには90バイト格納できます(実際にはあと数バイト格納できます)。
IEEE802.15.4の無線パケットの1バイトは貴重です。できるだけ節約して使用することを推奨します。1パケットで送信できるデータ量に限りがあります。パケットを分割する場合は分割パケットの送信失敗などを考慮する必要がありコストは大きくつきます。また1バイト余分に送信するのに、およそ16μ秒×送信時の電流に相当するエネルギーが消費され、特に電池駆動のアプリケーションには大きく影響します。
上記のデータペイロードのデータ構造を実際に構築してみます。データペイロードは pkt.get_payload()
により simplbuf<uint8_t>
型のコンテナとして参照できます。このコンテナに上記の仕様に基づいてデータを構築します。
上記のように記述できますがMWXライブラリでは、データペイロード構築のための補助関数pack_bytes()
を用意しています。
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()
メソッドを用います。
このアクトでは使用しませんが、戻り値には、要求の成功失敗の情報と要求に対応する番号が格納されています。送信完了まで待つ処理を行う場合は、この戻り値の値を利用します。
受信パケットがある場合の処理です。
まず受信パケットのデータはパラメータrx
として渡されます。rx
から無線パケットのアドレス情報やデータペイロードにアクセスします。
次の行では、受信パケットデータには、送信元のアドレス(32bitのロングアドレスと8bitの論理アドレス)などの情報を参照しています。
<NWK_SIMPLE>
では、8bitの論理IDと32bitのロングアドレスの2種類が常にやり取りされます。送り先を指定する場合はロングアドレスか論理アドレスのいずれかを指定します。受信時には両方のアドレスが含まれます。
MWXライブラリにはtransmit()
の時に使ったpack_bytes()
の対になる関数expand_bytes()
が用意されています。
1行目から3行目までは、データを格納する変数を指定しています。
6行目でexpand_bytes()
によりパケットのペイロードのデータを変数に格納します。1番目のパラメータでコンテナの先頭イテレータ(uint8_t*
ポインタ)を指定します。.begin()
メソッドにより取得できます。2番目のパラメータはコンテナの末尾の次を指すイテレータで.end()
メソッドで取得できます。2番目はコンテナの末尾を超えた読み出しを行わないようにするためです。
3番目以降のパラメータに変数を列挙します。列挙した順番にペイロードの読み出しとデータ格納が行われます。
このアクトでは、パケット長が間違っていた場合などのエラーチェックを省いています。チェックを厳格にしたい場合は、expand_bytes()
の戻り値により判定してください。
expand_bytes()
の戻り値は uint8_t*
ですが、末尾を超えたアクセスの場合はnullptr(ヌルポインタ)
を戻します。
msg
に読み出した4バイト文字列の識別子が"PING"
の場合はPONGメッセージを送信する処理です。
続いて到着したパケット情報を表示します。
数値のフォーマット出力が必要になるのでformat()
を用いています。>>
演算子向けにprintf()と同じ構文を利用できるようにしたヘルパークラスですが、引数の数は最大8つまで(32bitパラメータの場合)に制限されています。(制限を超えるとコンパイルエラーが出ます。なおSerial.printfmt()
には引数の数の制限がありません。)
mwx::crlf
は改行文字(CR LF)を、mwx::flush
は出力完了待ちを指定します。(mxw::flush
はSerial.flush()
と記述しても構いません)
act0 から始まるアクト(Act)は、actを始める - Opening actで紹介されたものを収録しています。LEDやボタンの動作のみの単純なものですが、最初にお試しいただくことをお勧めします。
環境センサーパル AMBIENT SENSE PAL を用い、センサー値の取得を行います。
このアクトには以下が含まれます。
無線パケットの送受信
インタラクティブモードによる設定 - <STG_STD>
ステートマシンによる状態遷移制御 - <SM_SIMPLE>
<PAL_AMB>ボードビヘイビアによるボード操作
環境センサーパル AMPIENT SENSE PAL を用い、センサー値の取得を行います。
コイン電池で動作させるための、スリープ機能を利用します。
環境センサーパル <PAL_AMB>
のボードビヘイビアをインクルードします。
最初に変数などの初期化を行います。ここではステートマシンstepの初期化を行っています。
最初にボードサポート <PAL_AMB>
を登録します。ボードサポートの初期化時にセンサーやDIOの初期化が行われます。最初に行うのは、ボードのDIP SWなどの状態を確認してから、ネットワークの設定などを行うといった処理が一般的だからです。
つづいて、インタラクティブモード関連の初期化と読出しを行います。
ここではsetオブジェクトの取得、アプリ名の反映、デフォルトのアプリケーションIDの反映、設定メニューで不要項目の削除を行います。
次にSETピンの状態を読み出します。このサンプルはスリープによる間欠動作を行うため、+++入力によるインタラクティブモード遷移は出来ません。替わりに起動時のSETピン=LO状態でインタラクティブモードに遷移します。このときSETTINGS::open_at_start()
を指定していますが、これはsetup()
を終了後速やかにインタラクティブモード画面に遷移する指定です。
最後に.reload()
を実行して設定値をEEPROMから読み出します。設定値を各変数にコピーしています。
続いてLEDの設定を行います。ここでは 10ms おきに ON/OFF の点滅の設定をします(スリープを行い起床時間が短いアプリケーションでは、起床中は点灯するという設定とほぼ同じ意味合いになります)。
このアクトではもっぱら無線パケットを送信しますので、TWENET の設定では動作中に受信回路をオープンにする指定(TWENET::rx_when_idle()
)は含めません。
ボード上のセンサーはI2Cバスを用いますので、バスを利用開始しておきます。
ボード上のセンサーの取得を開始します。startSensorCapture()
の解説を参照ください。
loop()
は、SM_SIMPLEステートマシンstep
を用いた制御を行っています。スリープ復帰からセンサー値取得、無線パケット送信、送信完了待ち、スリープといった一連の流れを簡潔に表現するためです。ループの戦闘ではbrd
オブジェクトを取得しています。
インタラクティブモード中にメインループが動作するのは都合が悪いため、この状態に固定します。
センサーのデータ取得を開始します。
ボード上のセンサーは .sns_LTR308ALS
または .sns_SHTC3
という名前でアクセスでき、このオブジェクトに操作を行います。センサーの完了待ちを行います。まだセンサーの取得が終わっていない場合(.available()
がfalse
)はセンサーに対して時間経過のイベント(.process_ev(E_EVENT_TICK_TIMER)
)を送付します。
上記2つのセンサーがavailableになった時点で、センサー値を取得し、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)
送信手続きについては他のアクトのサンプルと同様です。ここでは、再送1回、再送遅延を最小にする設定になっています。
パケットのペイロード部に識別子のFOURCHARS
とセンサーデータを格納します。得られた値のうち温度値は int16_t
ですが、送信パケットのデータ構造は符号なしで格納するため、uint16_t
にキャストしています。
送信要求を行います。送信要求が成功したら送信完了街の準備を行います。完了イベントを待つために.clear_flag()
、万が一のときのタイムアウトをset_timeout(100)
を指定します。パラメータの100の単位はミリ秒[ms]です。
ここではタイムアウトの判定、送信完了イベントの判定を行います。
sleepNow()
の処理を行います。
送信完了時に呼び出されるシステムイベントです。ここでは.set_flag()
により完了としています。
スリープに入る手続きをまとめています。
スリープ前に.on_sleep(false)
によりステートマシンの状態を初期化します。パラメータのfalseはスリープ復帰後STATE::INIT(=0)
から始めます。
ここでは、起床までの時間を乱数により 1750ms から 2250ms の間に設定しています。これにより他の同じような周期で送信するデバイスのパケットとの連続的な衝突を避けます。
周期が完全に一致すると、互いのパケットで衝突が起き通信が困難になります。通常は時間の経過とともにタイマー周期が互いにずれるため、しばらくすると通信が回復し、また時間がたつと衝突が起きるという繰り返しになります。
8,9行目、この例ではシリアルポートからの出力を待ってスリープに入ります。通常は消費エネルギーを最小化したいため、スリープ前のシリアルポートの出力は最小限(または無し)にします。
12行目、スリープに入るには the_twelite.sleep()
を呼びます。この呼び出しの中で、ボード上のハードウェアのスリープ前の手続きなどが行われます。たとえばLEDは消灯します。
パラメータとしてスリープ時間をmsで指定しています。
TWELITE PAL では、必ず60秒以内に一度起床し、ウォッチドッグタイマーをリセットしなければなりません。スリープ時間は60000
を超えないように指定してください。
スリープから復帰し起床すると wakeup()
が呼び出されます。そのあとloop()
が都度呼び出されます。wakeup()
の前に、UARTなどの各ペリフェラルやボード上のデバイスのウェイクアップ処理が行われます。例えばLEDの点灯制御を再始動します。
アクト PAL_AMB-UseNap は、センサーのデータ取得待ちをスリープで行い、より低消費エネルギーで動作できます。
begin()
関数はsetup()
関数を終了し(そのあとTWENETの初期化が行われる)一番最初のloop()
の直前で呼ばれます。
setup()
終了後に初回スリープを実行します。setup()
中にセンサーデータ取得を開始していますが、この結果は評価せず、センサーを事前に一度は動かしておくという意味あいで、必ずしも必要な手続きではありません。
起床後の手続きです。以下の処理を行います。
まだセンサーデータの取得開始をしていない場合、センサーデータ取得を行い、短いスリープに入る。
直前にセンサーデータ取得開始を行ったので、データを確認して無線送信する。
上記の分岐をグローバル変数の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()
で正しい時間を設定したかどうかで決まります。短い時間で起床した場合は、必要とされる時間経過に足りないため、続く処理でセンサーデータが得られないなどのエラーが出ることが想定されます。
ごく短いスリープを実行する。
sleepのパラメータの2番目をtrueにすると前回のスリープ復帰時刻をもとに次の復帰時間を調整します。常に5秒おきに起床したいような場合設定します。
3番目をtrueにするとメモリーを保持しないスリープになります。復帰後はwakup()は呼び出されじ、電源再投入と同じ処理になります。
4番目はウェイクアップタイマーの2番目を使う指定です。ここでは1番目は通常のスリープに使用して、2番目を短いスリープに用いています。このアクトでは2番目を使う強い理由はありませんが、例えば上述の5秒おきに起床したいような場合、短いスリープに1番目のタイマーを用いてしまうとカウンター値がリセットされてしまい、経過時間の補正計算が煩雑になるため2番目のタイマーを使用します。
あまり短いスリープ時間を設定してもスリープ復帰後のシステムの再初期化などのエネルギーコストと釣り合いません。目安として最小時間を30-50ms程度とお考え下さい。
このアクトには以下が含まれます。
無線パケットの送受信
開閉センサーパル OPEN-CLOSE SENSE PAL を用い、磁気センサーの検出時に割り込み起床し、無線送信します。
コイン電池で動作させるための、スリープ機能を利用します。
最初にボードビヘイビア<PAL_MAG>
を登録します。ボードビヘイビアの初期化時にセンサーやDIOの初期化が行われます。最初に行うのは、ボードのDIP SWなどの状態を確認してから、ネットワークの設定などを行うといった処理が一般的だからです。
ここでは、ボード上の4ビットDIP SWのうち3ビットを読み出して子機のIDとして設定しています。0の場合は、ID無しの子機(0xFE
)とします。
LEDの設定を行います。ここでは 10ms おきに ON/OFF の点滅の設定をします(スリープを行い起床時間が短いアプリケーションでは、起床中は点灯するという設定とほぼ同じ意味合いになります)。
begin()
関数はsetup()
関数を終了し(そのあとTWENETの初期化が行われる)一番最初のloop()
の直前で呼ばれます。
setup()
終了後にsleepNow()
を呼び出し初回スリープを実行します。
スリープに入るまえに磁気センサーのDIOピンの割り込み設定をします。pinMode()
を用います。2番めのパラメータはPIN_MODE::WAKE_FALLING
を指定しています。これはHIGHからLOWへピンの状態が変化したときに起床する設定です。
7行目でthe_twelite.sleep()
でスリープを実行します。パラメータの60000は、TWELITE PAL ボードのウォッチドッグをリセットするために必要な起床設定です。リセットしないと60秒経過後にハードリセットがかかります。
スリープから復帰し起床すると wakeup()
が呼び出されます。そのあとloop()
が都度呼び出されます。wakeup()
の前に、UARTなどの各ペリフェラルやボード上のデバイスのウェイクアップ処理(ウォッチドッグタイマーのリセットなど)が行われます。例えばLEDの点灯制御を再始動します。
ここではウェイクアップタイマーからの起床の場合(the_twelite.is_wokeup_by_wktimer()
)は再びスリープを実行します。これは上述のウォッチドッグタイマーのリセットを行う目的のみの起床です。
磁気センサーの検出時の起床の場合は、このままloop()処理に移行します。
ここでは、検出された磁気センサーのDIOの確認を行い、パケットの送信を行い、パケット送信完了後に再びスリープを実行します。
b_transmit
変数によってloop()
内の振る舞いを制御しています。送信要求が成功した後、この値を1にセットしパケット送信完了待ちを行います。
磁気センサーの検出DIOピンの確認を行います。検出ピンは二種類あります。N極検知とS極検知です。単に磁石が近づいたことだけを知りたいならいずれかのピンの検出されたことが条件となります。
起床要因のピンを確認するにはthe_twelite.is_wokeup_by_dio()
を用います。パラメータはピン番号です。戻り値をuint8_tに格納しているのはパケットのペイロードに格納するためです。
通信条件の設定やペイロードにデータを格納後、送信を行います。
その後、loop()
中 b_transmit
が true
になっている場合は、完了チェックを行い、完了すれば sleepNow()
によりスリープします。
送信完了に確認は the_twelite.tx_status.is_complete(u8txid)
で行っています。u8txid
は送信時に戻り値として戻されたID値です。
の記述サンプルです。詳細はを参照ください。
のサンプルを少し改良して、センサーデータ取得中の待ち時間(約50ms)を、スリープで待つようにします。
このアクトの解説の前にのアクトの解説をご覧ください。
を用い、センサー値の取得を行います。
インタラクティブモードによる設定 -
ステートマシンによる状態遷移制御 -
またはボードビヘイビアによるボード操作
開閉センサーパルのボード ビヘイビアをインクルードします。
名前
内容
act0
処理の記述がないテンプレート
act1
Lチカ(LEDの点滅)
act2
タイマーを用いたLチカ
act3
2つのタイマーを用いたLチカ
act4
ボタン(スイッチ)を用いたLED点灯
役割
例
親機
アクトParent_MONOSTICKを動作させる。
子機
このアクトではスリープ復帰後に数サンプル加速度データを取得しそのデータを送ります。
のアクトには以下が含まれます。
無線パケットの送受信
インタラクティブモードによる設定 - <STG_STD>
ステートマシンによる状態遷移制御 - <SM_SIMPLE>
起床→加速度センサーの取得開始→加速度センサーのFIFO割り込み待ち→加速度センサーのデータの取り出し→無線送信→スリープという流れになります。
加速度センサーは、FIFOキューが一杯になるとFIFOキューへのデータ追加を停止します。
MOT PALまたはTWELITE CUEに対応するため、インクルード部分はマクロになっています。USE_PAL_MOT
または、USE_CUE
のいずれかを定義します。
USE_PAL_MOT
が定義されている場合は動作センサーパルのボードビヘイビア<PAL_MOT>
をインクルードしています。
loop()
中の順次処理を行うために状態を定義し、またステートマシンstep
を宣言します。
センサーデータを格納するためのデータ構造です。
ボード、設定、ネットワークの各ビヘイビアオブジェクトの登録を行います。
インタラクティブモードの初期化を行います。
まず、設定項目の調整を行います。ここでは、メニュー項目で表示されるタイトル名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
は、システムの基本的な振る舞いを管理するクラスオブジェクトです。このオブジェクトは、setup()
内でアプリケーションIDやチャネルなど様々な初期化を行います。
ここではインタラクティブモードの設定値の一部を反映しています。
インタラクティブモード設定で反映した項目を別の設定に変更したい場合は、続いて上書きしたい設定を行います。
ネットワークビヘイビアオブジェクトに対しても設定を行います。インタラクティブモードの論理デバイスID(LID)と再送設定が反映されます。
LEDのブリンク設定などを行います。
setup()
を終了した後に呼ばれます。ここでは初回スリープを実行しています。ただしインタラクティブモードの画面が表示される場合はスリープしません。
起床後は状態変数eState
を初期状態INITにセットしています。この後loop()
が実行されます。
loop()
の基本構造は<SM_STATE>
ステートマシンstate
を用いswitch ... case節での制御です。初期状態はSTATE::INIT
またはSTATE::INTERACTIVE
です。
インタラクティブモード画面が表示されているときの状態です。何もしません。この画面ではSerialの入出力はインタラクティブモードが利用します。
初期状態のINITです。
状態INITでは、初期化(結果格納用のキューのクリア)や結果格納用のデータ構造の初期化を行います。STATE::START_CAPTUREに遷移します。この遷移設定後、もう一度whileループが実行されます。
状態START_CAPTUREでは、MC3630センサーのFIFO取得を開始します。ここでは400Hzで4サンプル取得できた時点でFIFO割り込みが発生する設定にしています。
例外処理のためのタイムアウトの設定と、次の状態STATE::WAIT_CAPTURE
に遷移します。
状態WAIT_CAPTUREでは、FIFO割り込みを待ちます。割り込みが発生し結果格納用のキューにデータが格納されるとsns_MC3630.available()
がtrue
になります。sns_MC3630.end()
を呼び出し処理を終了します。
サンプル数とサンプルのシーケンス番号を取得します。
すべてのサンプルデータに対して読み出し、平均値をとる処理をします。
ここでは取得されたサンプルに対して、各軸に対応するイテレータを用い最大・最小を得ています。
C++ Standard Template Library のアルゴリズムを使用する例としてstd::mimmax_element
紹介していますが、コメント内のようにforループ内で最大、最小を求めても構いません。
.sns_MC3630.get_que().clear()
を呼び出し、キューにあるデータをクリアします。これを呼び出さないと続くサンプル取得ができません。その後STATE::REQUEST_TX
状態に遷移します。
.is_timeout()
はタイムアウトをチェックします。タイムアウト時は異常としてSTATE::EXIT_FATAL
に遷移します。
状態REQUEST_TX
ではローカル定義関数TxReq()
を呼び出し、得られたセンサーデータの処理と送信パケットの生成・送信を行います。送信要求は送信キューの状態などで失敗することがあります。送信要求が成功した場合、TxReq()はtrueとして戻りますが、まだ送信は行われません。送信完了はon_tx_comp()
コールバックが呼び出されます。
また.clear_flag()
により送信完了を知らせるためのフラグをクリアしておきます。同時にタイムアウトも設定します。
状態STATE::WAIT_TX
では、無線パケットの送信完了を待ちます。フラグはon_tx_comp()
コールバック関数でセットされ、セット後に.is_flag_ready()
がtrueになります。
一連の動作が完了したときは状態STATE::EXIT_NORMAL
に遷移しローカル定義の関数sleepNow()
を呼び出しスリープを実行します。またエラーを検出した場合は状態STATE::EXIT_FATAL
に遷移し、システムリセットを行います。
最期にパケットの生成と送信を要求を行います。パケットには続き番号、サンプル数、XYZの平均値、XYZの最小サンプル値、XYZの最大サンプル値を含めます。
スリープの手続きです。
シリアルポートはスリープ前にSerial.flush()
を呼び出してすべて出力しておきます。
<SM_SIMPLE>
ステートマシンはon_sleep()
を行う必要があります。
クラスオブジェクトは、MWXライブラリであらかじめ定義されたオブジェクトで、TWENETを取り扱うthe_twelite
、ペリフェラルの利用のためのオブジェクトが定義されています。
各オブジェクトは.setup()
, .begin()
メソッドの呼び出しを行って初期化する必要があります。(UART0を利用するSerial
オブジェクトのみ初期化は必要ありません)
役割 | 例 |
親機 |
子機 |
動作センサーパル MOTION SENSE PAL を用い、センサー値の取得を行います。
のアクトには以下が含まれます。
無線パケットの送受信
インタラクティブモードによる設定 - <STG_STD>
ステートマシンによる状態遷移制御 - <SM_SIMPLE>
動作センサーパル MOTION SENSE PAL を用い、加速度センサーの加速度を連続的に計測し、無線送信します。
コイン電池で動作させるための、スリープ機能を利用します。
動作センサーパルのボードビヘイビア<PAL_MOT>
をインクルードします。
最初にボードビヘイビア<PAL_MOT>
を登録します。ボードビヘイビアの初期化時にセンサーやDIOの初期化が行われます。最初に行うのは、ボードのDIP SWなどの状態を確認してから、ネットワークの設定などを行うといった処理が一般的だからです。
ここでは、ボード上の4ビットDIP SWのうち3ビットを読み出して子機のIDとして設定しています。0の場合は、ID無しの子機(0xFE
)とします。
LEDの設定を行います。ここでは 10ms おきに ON/OFF の点滅の設定をします(スリープを行い起床時間が短いアプリケーションでは、起床中は点灯するという設定とほぼ同じ意味合いになります)。
加速度センサーの計測を開始します。加速度センサーの設定(SnsMC3630::Settings
)には計測周波数と測定レンジを指定します。ここでは14HZの計測(SnsMC3630::MODE_LP_14HZ
)で、±4Gのレンジ(SnsMC3630::RANGE_PLUS_MINUS_4G
)で計測します。
開始後は加速度センサーの計測が秒14回行われ、その値はセンサー内部のFIFOキューに保存されます。センサーに28回分の計測が終わった時点で通知されます。
begin()
関数はsetup()
関数を終了し(そのあとTWENETの初期化が行われる)一番最初のloop()
の直前で呼ばれます。
setup()
終了後にsleepNow()
を呼び出し初回スリープを実行します。
スリープに入るまえに加速度センサーのDIOピンの割り込み設定をします。FIFOキューが一定数まで到達したときに発生する割り込みです。pinMode()
を用います。2番めのパラメータはPIN_MODE::WAKE_FALLING
を指定しています。これはHIGHからLOWへピンの状態が変化したときに起床する設定です。
3行目でthe_twelite.sleep()
でスリープを実行します。パラメータの60000は、TWELITE PAL ボードのウォッチドッグをリセットするために必要な起床設定です。リセットしないと60秒経過後にハードリセットがかかります。
加速度センサーのFIFO割り込みにより、スリープから復帰し起床すると wakeup()
が呼び出されます。そのあとloop()
が都度呼び出されます。wakeup()
の前に、UARTなどの各ペリフェラルやボード上のデバイスのウェイクアップ処理(ウォッチドッグタイマーのリセットなど)が行われます。例えばLEDの点灯制御を再始動します。
ここではloop()
で使用する変数の初期化を行っています。
ここでは、加速度センサー内のFIFOキューに格納された加速度情報を取り出し、これをもとにパケット送信を行います。パケット送信完了後に再びスリープを実行します。
b_transmit
変数によってloop()
内の振る舞いを制御しています。送信要求が成功した後、この値を1にセットしパケット送信完了待ちを行います。
最初にセンサーがavailableかどうかを確認します。割り込み起床後であるため、availableでないのは通常ではなく、そのままスリープします。
無線送信パケットでは使用しないのですが、取り出した加速度の情報を確認してみます。
加速度センサーの計測結果は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回行われます。
送信するパケットに含めるサンプル数とサンプル最初の続き番号をパケットのペイロードの先頭部分に格納します。
最後に加速度データを格納します。先程は平均値の計算のためにキューの各要素を参照のみしましたが、ここではキューから1サンプルずつ読み出してパケットのペイロードに格納します。
加速度センサーからのデータキューの先頭を読み出すのは.front()
を用います。読みだした後.pop()
を用いて先頭キューを開放します。
加速度センサーから取得されるデータは1Gを1000としたミリGの単位です。レンジを±4Gとしているため、12bitの範囲に入るように2で割って格納します。データ数を節約するため最初の4バイトにX,Y軸とZ軸の上位8bitを格納し、次の1バイトにZ軸の下位4bitの合計5バイトを生成します。
2回分の送信待ちを行うため送信IDはtxid[]
配列に格納します。
その後、loop()
中 b_transmit
が true
になっている場合は、完了チェックを行い、完了すれば sleepNow()
によりスリープします。
送信完了に確認は the_twelite.tx_status.is_complete()
で行っています。txid[]
は送信時に戻り値として戻されたID値です。
TWELITE 無線マイコンの内蔵EEPROMに対して読み書きを実行します。
内蔵EEPROMはアドレス0x000~0xEFFまでの3480バイトが利用可能です。
EEPROMからaddress
に対応するデータを読み出します。
エラーの検出は行いません。
EEPROMからaddress
に対してvalue
を書き込みます。
エラーの検出は行いません。
write()
と同じく書き込みを行いますが、先にaddress
にあるデータを読み出してvalue
と違う場合のみ、書き込みを行います。EEPROMの書き換え寿命を考慮し、書換回数を減らしたいときに用います。
後述のmwx::stream
を用いた読み書きを行うために、ヘルパーオブジェクトを取得します。
このオブジェクトに対して<<
演算子などmwx::stream
で定義されたインタフェースを利用できます。
.seek()
を用いてEEPROMのアドレスを1024に移動しています。
上記では8バイト文字列(00bc614e
)、4バイト整数(0x12ab34cd
)、16バイトバイト列(HELLO WORLD!...
)、1バイト終端文字を書き込んでいます。
.seek()
を用いてEEPROMのアドレスを1024に移動しています。
先ほど書き出したデータ列を読み出します。順番に8バイト文字、4バイト整数、16バイト文字列を>>
演算子を用いて読み出します。
アクトを動作させる。
+
先頭部分はに利用されるため、併用する場合は後半のアドレスの利用を推奨します。設定(インタラクティブモード)でどの程度の領域を消費するかは、その実装に依存します。最小限度の設定であっても先頭から256バイトまでは利用されるため、それ以降の利用を推奨します。
を経由して、による演算子やメソッドを用います。mwx::stream
を用いるとuint16_t
やuint32_t
型といった整数型の読み書き、uint8_t
の固定長配列型の読み書き、format()
オブジェクトによる書式整形などが可能になります。
役割
例
親機
アクトParent_MONOSTICKを動作させる。
子機
ディジタル入力管理クラス (mwx::periph_buttons)
ディジタル入力の変化を検出します。このクラスは、同じ検出値が複数回得られたときに変化を検出します。メカ式のボタンのチャタリングの影響を小さくするのに有効です。
パラメータのmax_history
は、begin()
で設定可能な参照回数の最大値です。ここではメモリーの確保と初期化を行います。
Buttons
の動作を開始します。1番目のパラメータbmPortMask
は監視対象のディジタル入力のビットマップを指定します。bit 0がDIO 0, ... , bit N がDIO Nに対応します。複数指定することができます。2番目のu8HistoryCount
は値の確定をするのに必要な回数です。3番目のtick_delta
は値の確認を行う間隔をmsで指定します。
値の確定にはu8HistoryCount*tick_delta
[ms]かかることになります。例えばu8HistoryCount
=5, tick_delta
=4の場合は、状態の確定に最低約20msかかります。
確認はTickTimer
のイベントハンドラで行っています。割り込みハンドラではないので、処理等の遅延の影響を受けますが、メカ式ボタン等のチャタリング抑制には十分です。
Buttons
の動作を終了します。
変化が検出されたときにtrue
を返します。read()
を実行するとクリアされます。
availableになったとき呼び出します。u32port
は現在の入力DIOのビットマップ、u32changed
は変化が検出されたDIOのビットマップです。
Buttonsが動作していない場合はfalse
を返します。
Buttonsが動作を開始した時点では、DIOの入力状態は未確定です。値が確定した時点でavailableになります。このときread()
で読み出すビットマップのMSB(bit31)が1にセットされます。
動作確定を要するため、入力値が定常的に変化するポートを監視する目的では利用できません。
スリープ前にButtonsが稼働状態であれば、復帰後に再開します。再開後、初回確定を行います。
ADC (mwx::periph_analogue.hpp)
Analogueは、ADCの実行と値の取得を行います。一度に複数のチャネルを連続取得でき、またこれをタイマーなどの周期に合わせて逐次実行可能です。
標準アプリ(App_Twelite)では、半導体データシート中のピン名ADC2/ADC3が、TWELITE DIPの並びにあわせてAI3/AI2 となっています。ご注意ください。
*1 ディジタル、アナログ共用のADC2/ADC3ピンは利用手続きと利用制限があります。
ADC開始前に利用するピンをプルアップ無しとします。これを実行しないと常にプルアップ電圧をADCで観察することになります。
通常の回路構成では、スリープ時には電流リークが発生します。 ソフトウェアの記述のみで回避することは出来ません。
スリープ時の電流リーク回避には、アナログ回路部分のGNDをFETスイッチなどで切り離し、スリープ中はフローティング状態にします。またスリープ前には入力かつプルアップ状態にピンを設定します。
ADCの初期化を行います。setup()では、半導体内部のレギュレータの始動、周期実行するためのタイマーデバイスの指定、指定チャネルすべてのADCが終了したときに呼び出されるコールバック関数の指定します。
1番目のパラメータにはADCを行いたいポートを指定します。ポートの指定はピンの定義で述べたポート番号に対応するビットをセットしたビットマップになります。例えば PIN_ANALOGUE::A2
とPIN_ANALOGUE::VCC
の2つのピンの値を得たい場合は (1 <<PIN_ANALOGUE::A1 | 1<<PIN_ANALOGUE::VCC )
を指定します。pack_bits
を用いpack_bits(PIN_ANALOGUE::A1,PIN_ANALOGUE::VCC)
のように記述することもできます。
begin()
の呼び出し後、速やかに最初のADC処理が開始され、その終了割り込から次のピンの処理を開始します。すべての処理が終われば(指定されている場合)コールバック関数が呼び出されます。次のタイマー割り込みが発生まで待ってから新たなADC処理を開始します。
2番目のパラメータは、ACを開始するまでのタイマー割り込みの回数を指定します。例えばTickTimer
は1msごとに呼び出されますが、パラメータに16
を指定すれば 16msごとの処理になります。
デフォルトのADCピン(PIN_ANALOGUE::A1
,PIN_ANALOGUE::A2
)を指定してADC処理を開始します。end()
では中断したADC処理を再開します。
ADC処理を終了し、半導体内部のレギュレータを停止します。
ADCの値が取得後にtrue
になります。本関数により確認した後は次のADC完了まではfalse
です。
ADC値を読み出します。パラメータには読み出したいADCピンを指定します。read()
はmVに変換した読み値、read_raw()
はADCの値(0..1023)を戻します。
Vccはread()
で読み出すことを推奨します。read_raw()
の値からmVに変換するには、特別な変換式を適用する必要があるためです。
ADC完了(available)後、次のADC処理が実行するタイミング付近まで遅れて値を読み出すと、次のADC値が戻される場合があります。ADCの処理は割り込みハンドラで実施されているためloop()
の処理中であっても値が更新されるためです。
ADCの割り込みハンドラはsetup()
の呼び出し時にperiph_analogue::ADC_handler()
に設定されます。
半導体のペリフェラルライブラリで別途ハンドラを指定すると正常に動作しなくなります。
ADCがbegin()
により周期実行状態であれば、スリープ復帰後もADC処理を再開します。
パルスカウンタ (mwx::periph_pulse_counter)
パルスカウンタは、マイコンのCPUが稼働していない時もパルスを読み取り計数する回路です。パルスカウンターは2系統あります。PC0はPulseCounter0
, PC1はPulseCounter1
に割り当てられます。
またPulseCounter
はPulseCounter1
の別名です。
オブジェクトを初期化し、計数を開始します。1番目のパラメータrefct
は割り込みやavailable判定の基準となるカウント数です。この数を超えたときにアプリケーションに報告されます。またrefct
には0を指定することもできます。この場合は、スリープ起床要因にはなりません。
2番目のパラメータedge
は割り込みが立ち会がり(PIN_INT_MODE::RISING
)か立下り(PIN_INT_MODE::FALLING
)を指定します。
3番目のdebounce
は、0,1,2,3の値をとります。1,2,3の設定はノイズの影響を小さくするため値の変化の検出に連続した同じ値を要する設定です。
検出を中止します。
指定カウント数(begin()
のrefct
)が0の場合は、カウントが1以上でtrue
を返します。
指定カウント数(begin()
のrefct
)が1以上の場合は、検出回数が指定カウント数を超えた場合にtrue
となります。
カウント値を読み出します。読み出し後にカウント値を0にリセットします。
TWELITE の UART0 ポート (mwx::serial_jen)
Serial
オブジェクトはシステム起動時に UART0, 115200 bps で初期化され、ライブラリ内で初期化処理が行われます。ユーザコード上は、setup()
から利用できます。
Serial1
オブジェクトは、ライブラリ内で用意されていますが、初期化処理は行っていません。UART1を有効化するためには、必要な初期化手続き Serial1.setup(), Serial1.begin()
を行ってください。
起動直後の setup(), wakeup()
やスリープ直前の flush
処理で、出力が不安定になる場合があります。
オブジェクトの初期化を行う。
TX/RX用のFIFOバッファのメモリ確保
TWE_tsFILE 構造体のメモリ確保
Serial
(UART0) は ライブラリ内で setup()
の呼び出しが自動で行われます。ユーザによる呼び出しを行う必要はありません。
また、Serial
(UART0) のバッファサイズは、コンパイル時に決定されます。マクロ MWX_SER_TX_BUFF
(未指定時は 768), MWX_SER_RX_BUFF
(未指定時 256) により変更できます。
ハードウェアの初期化を行う。
Serial
(UART0) は ライブラリ内で begin()
の呼び出しが自動で行われます。ユーザによる呼び出しを行う必要はありません。
指定したボーレートの下2桁の数値は0に丸めて処理します。またハードウェアの制限により指定したボーレートより誤差が生じます。
ボーレートの計算には除算が発生し計算時間がかかる場合があります。9600,38400,115200を指定する場合は、除算をせずに計算を行います。処理の詳細は、constexpr uint16_t _serial_get_hect_baud(uint32_t baud)
を参照してください。
(未実装)ハードウェアの使用を停止する。
Cライブラリで利用する TWE_tsFILE*
形式での構造体を得る。
Serial (UART) では、_sSerial
構造体が定義されています。
TWENET 利用の中核クラス (mwx::twenet)
the_twelite
オブジェクトは、TWENETの利用手続きをまとめたもので、無線の基本設定やスリープ等の手続きなど無線マイコンを操作するための手続きが含まれます。
the_twelite
はsetup()
関数内で設定と開始the_twelite.begin()
を行います。setup()
以外では設定は行えません。
上記の例では、アプリケーションIDの設定、通信チャネルの設定、受信回路の設定を行っています。
様々な手続きが含まれます。
上記の例では環境センサーパル<PAL_AMB>
と、シンプル中継ネットワーク<NWK_SIMPLE>
の2種類を登録しています。これらを登録することにより環境センサーパル上のセンサーなどハードウェアを簡易に取り扱うことが出来ます。また煩雑な無線パケットの取り扱いについて中継の処理や重複で届いたパケットの自動破棄などの機能を暗黙に持たせることが出来ます。
MWXライブラリには、ここで紹介したメソッド以外にも定義されています。
アクト記述には直接関係ないもの、設定しても有効に機能しないもの、内部的に使用されているものが含まれます。
<<
演算子 (設定)オブジェクトthe_twelite
の初期設定を行うために<<
演算子を用います。
以下に挙げる設定用のクラスオブジェクトを入力とし、設定をしなければデフォルト値が適用されます。
パラメータid
に指定したアプリケーションIDを設定します。これは必須指定です。
設定の読み出しは uint32_t the_twelite.get_appid()
で行います。
パラメータch
に指定したチャネル番号(11
..26
)を設定します。
設定の読み出しはuint8_t the_twelite.get_channel()
で行います。
パラメータpw
に指定した出力設定を(0
..3
)を設定します。デフォルトは(3:出力減衰無し)です。
設定値の読み出しはuint8_t the_twelite.get_tx_power()
で行います。
パラメータbEnable
が1
であれば常に受信回路を動作させ、他からの無線パケットを受信できるようになります。デフォルトは0
で、もっぱら送信専用となります。
設定値の読み出しはuint8_t the_twelite.get_rx_when_idle()
で行います。
チャネルマネージャを有効にします。チャネルを複数指定すると複数チャネルでの送受信を行います。ch2
,ch3
に0を指定すると、その指定は無効になります。
反映される項目は以下です。
app_id
channel
tx_power
MAC ack 使用時の再送回数
MWXライブラリコード中には他にも設定項目がありますが、現時点ではライブラリの機能に無関係な設定であったり、設定を行うと矛盾を起こす可能性があるものです。
事前に設定(<<
演算子参照)や、ビヘイビアの登録を済ませた後に実行します。通常はsetup()
関数内の一番最後に記述します。
the_twelite
設定完了
ビヘイビアの初期化
TWENETの初期化は setup()
関数が終了した後にも実行されます。多くの処理はTWENETが終了した後に実行するようになっているため、ここでは初期化以外の処理を行わないようにしてください。
チャネル設定を変更します。失敗時にはチャネルは変更されずfalse
を戻します。
現在設定中のチャネル番号(11..26)を取得する。MAC層のAPIより取得します。
モジュールのシリアル番号を取得します。
モジュールをスリープさせる。
スリープ前に組み込みオブジェクトやビヘイビアの on_sleep()
メソッドが呼び出され、スリープ前の手続きを行います。スリープ復帰後は反対に on_wakeup()
メソッドにより復帰処理が行われます。
スリープからの復帰要因が指定したディジタルピンである場合にtrue
を返します。
スリープからの復帰要因がウェイクアップタイマーである場合にtrue
を返します。
システムをリセットします。リセット後はsetup()
からの処理となります。
ウォッチドッグタイマーを停止します。長時間のポーリング待ちを行うような場合はタイマーを停止します。
ウォッチドッグタイマーはライブラリ内部のメインループで都度再開(restart)しています。タイマーが切れリセットがかかるまで約4秒です。
ウォッチドッグタイマーを再開します。
twe_twelite
には3つのビヘイビアを登録でき、これらを格納する以下のクラスオブジェクトを定義されています。
board
: ボード対応のビヘイビアです。ボード上の各デバイス利用手続きが付加されます。
app
: ユーザアプリケーションを記述したビヘイビアです。割り込みやイベント記述、ステートマシンによる状態遷移によるふるまいの記述が可能です。また複数のアプリケーション記述を定義しておいて、起動時に全く振る舞いの違うアプリケーションを選択する記述が容易に行えます。
settings
: 設定(インタラクティブモード)を実行するためのビヘイビアです。<SET_STD>
を登録します。
登録後は登録時と同じ書式でオブジェクトの取得を行います。
誤ったビヘイビアを指定した場合は、パニック動作(無限ループ)となりプログラムの動作が停止します。
グローバル変数としてビヘイビアのオブジェクトを宣言することを想定していません。利用都度use<B>()
を用いてください。
ただし、グローバル変数にオブジェクトのポインタを定義して以下のように記述することは可能です。(MWXライブラリでは原則としてポインタ型の利用を最小限にとどめ参照型を利用する方針ですので、下記のような記述は推奨しません)
the_twelite
には上述のboard
, network
, app
の3つのクラスオブジェクトが定義されていますが他に以下が定義されています。
送信完了状態を通知する。
指定したIDのパケットが送信完了したときにtrue
を返す。
指定したIDのパケットが送信完了し、かつ送信成功したときにtrue
を返す。
受信パケットを取得する。
read()
メソッドで得られる受信パケットデータは、続くパケットが受信処理時に上書きされる設計となっています。available
直後に読み出してなにか短い処理をする場合は問題になることはありませんが、原則として読み出し→アプリケーションが使うため必要なデータのコピー→loop()
の終了を速やかに行います。例えばloop()
中で長いdelay()
を行うと受信パケットの取りこぼしなどが発生します。
まだ読み出していない受信パケットが存在する場合にtrue
を返す。
パケットを読み出します。
を実装し TWELITE の UART0 で入出力する。
また無線ネットワークを取り扱うクラスやボード対応をまとめたクラス、ユーザ記述のイベントドリブン処理を行うクラスを登録できるようになっています。このクラスを登録することにより、専用化した機能を手軽に利用できるようになります。これらのクラスを本解説中では「」と呼称します。
を反映します。
network
: ネットワークを実装するビヘイビアです。通常はを登録します。
ビヘイビア<B>を登録します。登録は内で行います。戻り値は登録したビヘイビアに対応するオブジェクトの参照です。
イベントドリブンのビヘイビアの記述ではで管理します。
イベントドリブンのビヘイビアの記述ではで取得します。