セクションの複数ページをまとめています。 印刷またはPDF形式で保存...
API リファレンス
- 1: MWX ライブラリ
- 1.1: MWX ライブラリ
- 1.1.1: 全般
- 1.1.2: 定義
- 1.1.3: クラスオブジェクト
- 1.1.3.1: the_twelite
- 1.1.3.2: Analogue
- 1.1.3.3: Buttons
- 1.1.3.4: EEPROM
- 1.1.3.5: PulseCounter
- 1.1.3.6: Serial
- 1.1.3.7: SerialParser
- 1.1.3.8: SPI
- 1.1.3.8.1: SPI (メンバ関数版)
- 1.1.3.8.2: SPI (ヘルパークラス版)
- 1.1.3.9: TickTimer
- 1.1.3.10: Timer0 .. 4
- 1.1.3.11: Wire
- 1.1.3.11.1: Wire (メンバ関数版)
- 1.1.3.11.2: Wire (ヘルパークラス版)
- 1.1.4: クラス
- 1.1.4.1: MWX_APIRET
- 1.1.4.2: alloc
- 1.1.4.3: axis_xyzt
- 1.1.4.4: packet_rx
- 1.1.4.5: packet_tx
- 1.1.4.6: serparser
- 1.1.4.7: pktparser
- 1.1.4.7.1: E_PKT
- 1.1.4.7.2: identify_packet_type()
- 1.1.4.7.3: TwePacket
- 1.1.4.7.3.1: TwePacketTwelite
- 1.1.4.7.3.2: TwePacketIO
- 1.1.4.7.3.3: TwePacketUART
- 1.1.4.7.3.4: TwePacketPAL
- 1.1.4.8: smplbuf
- 1.1.4.8.1: get_stream_helper()
- 1.1.4.8.2: smplbuf_strm_u8
- 1.1.4.9: smplque
- 1.1.4.10: 入出力ストリーム
- 1.1.4.10.1: mwx::mwx_format
- 1.1.4.10.2: mwx::bigendian
- 1.1.4.10.3: mwx::crlf
- 1.1.4.10.4: mwx::flush
- 1.1.4.10.5: stream_helper
- 1.1.4.11: SM_SIMPLE ステートマシン
- 1.1.5: コールバック関数
- 1.1.5.1: setup()
- 1.1.5.2: begin()
- 1.1.5.3: loop()
- 1.1.5.4: wakeup()
- 1.1.5.5: init_coldboot()
- 1.1.5.6: init_warmboot()
- 1.1.5.7: on_rx_packet()
- 1.1.5.8: on_tx_comp()
- 1.1.6: ビヘイビア
- 1.1.6.1: PAL_AMB-behavior
- 1.1.7: 関数
- 1.1.7.1: システム関数
- 1.1.7.1.1: millis()
- 1.1.7.1.2: delay()
- 1.1.7.1.3: delayMicroseconds()
- 1.1.7.1.4: random()
- 1.1.7.2: 汎用デジタルIO
- 1.1.7.2.1: pinMode()
- 1.1.7.2.2: digitalWrite()
- 1.1.7.2.3: digitalRead()
- 1.1.7.2.4: attachIntDio()
- 1.1.7.2.5: detachIntDio()
- 1.1.7.2.6: digitalReadBitmap()
- 1.1.7.3: ユーティリティ関数
- 1.1.7.3.1: printfの実装
- 1.1.7.3.2: pack_bits()
- 1.1.7.3.3: collect_bits()
- 1.1.7.3.4: Byte array utils
- 1.1.7.3.5: pack_bytes()
- 1.1.7.3.6: expand-bytes()
- 1.1.7.3.7: CRC8, XOR, LRC
- 1.1.7.3.8: div10(), div100(), div1000()
- 1.1.7.3.9: Scale utils
- 1.1.7.3.10: pnew()
- 1.1.8: 外部ライブラリ
- 1.1.8.1: EASTL
- 1.1.9: ボードビヘイビア (BRD)
- 1.1.9.1: <BRD_APPTWELITE>
- 1.1.9.2: <MONOSTICK>
- 1.1.9.3: PAL 共通定義
- 1.1.9.3.1: <PAL_AMB>
- 1.1.9.3.2: <PAL_MAG>
- 1.1.9.3.3: <PAL_MOT>
- 1.1.9.3.4: <PAL_NOTICE>
- 1.1.9.4: <CUE>
- 1.1.9.5: <ARIA>
- 1.1.10: センサーデバイス (SNS)
- 1.1.10.1: SHTC3
- 1.1.10.2: SHT3x
- 1.1.10.3: LTR-308ALS
- 1.1.10.4: MC3630
- 1.1.10.5: BMx280
- 1.1.10.6: PCA9632
- 1.1.10.7: SHT4x
- 1.1.11: ネットワークビヘイビア (NWK)
- 1.1.11.1: シンプル中継ネット <NWK_SIMPLE>
- 1.1.11.2: <NWK_LAYERED>
- 1.1.12: 設定ビヘイビアによる設定インタフェース
- 1.1.12.1: <STG_STD>
- 1.1.13: MWXライブラリ改版履歴
- 2: TWELITE SDK / MWSDK (Legacy)
- 3: TWELITE Wings API / MWings
- 3.1: TWELITE Wings API / MWings for 32-bit Arduinos
- 3.1.1: TWELITE Wings API / MWings for 32-bit Arduinos
- 3.1.1.1: データ型と手続きの一覧
- 3.1.1.2: クラスの一覧
- 3.1.1.2.1: mwings::MWings クラス
- 3.2: TWELITE Wings API / MWings for Python
- 3.2.1: TWELITE Wings API / MWings for Python
- 3.2.1.1: mwings モジュール
- 3.2.1.1.1: mwings.common モジュール
- 3.2.1.1.2: mwings.parsers モジュール
- 3.2.1.1.2.1: mwings.parsers.app_twelite モジュール
- 3.2.1.1.2.2: mwings.parsers.app_io モジュール
- 3.2.1.1.2.3: mwings.parsers.app_aria モジュール
- 3.2.1.1.2.4: mwings.parsers.app_cue モジュール
- 3.2.1.1.2.5: mwings.parsers.app_cue_pal_event モジュール
- 3.2.1.1.2.6: mwings.parsers.app_pal_openclose モジュール
- 3.2.1.1.2.7: mwings.parsers.app_pal_amb モジュール
- 3.2.1.1.2.8: mwings.parsers.app_pal_mot モジュール
- 3.2.1.1.2.9: mwings.parsers.app_uart_ascii モジュール
- 3.2.1.1.2.10: mwings.parsers.app_uart_ascii_extended モジュール
- 3.2.1.1.2.11: mwings.parsers.act モジュール
- 3.2.1.1.3: mwings.serializers モジュール
- 3.2.1.1.3.1: mwings.serializers.app_twelite モジュール
- 3.2.1.1.3.2: mwings.serializers.app_io モジュール
- 3.2.1.1.3.3: mwings.serializers.app_pal_notice モジュール
- 3.2.1.1.3.4: mwings.serializers.app_pal_notice_detailed モジュール
- 3.2.1.1.3.5: mwings.serializers.app_pal_notice_event モジュール
- 3.2.1.1.3.6: mwings.serializers.app_uart_ascii モジュール
- 3.2.1.1.4: mwings.utils モジュール
- 4: TWENET リファレンス
- 4.1: TWENETmcu - マイコンライブラリ
- 4.1.1: マイコンについて
- 4.1.2: 始動関数 main(), WarmMain()
- 4.1.3: RAMの割当
- 4.1.4: printf について (デバッグ, シリアル出力)
- 4.2: TWENETmwf - ペリフェラルC++ライブラリ
- 4.2.1: mwf_common
- 4.2.2: mwf_periph_common - ペリフェラル共通
- 4.2.3: mwf_periph_adc - ADC
- 4.2.4: mwf_periph_gint - GINT(GPIO)
- 4.2.5: mwf_periph_i2c - I2C
- 4.2.6: mwf_periph_ntag - NTAG
- 4.2.7: mwf_periph_pwm - PWM, Timer
- 4.2.8: mwf_periph_rng - TRNG
- 4.2.9: mwf_periph_spi - SPI
- 4.2.10: mwf_periph_wtimer - WTIMER, FRWT
- 4.2.11: mwf_periph_wwdt - WWDT
- 4.2.12: class tick_counter - Stop Watch
- 4.2.13: mwf-utils - utils
- 4.3: TWENETutils - TWENET ユーティリティ
- 4.3.1: utils.h
- 4.3.2: Timerライブラリ
- 4.3.3: fprintf ライブラリ
- 4.4: TWENETcmpt - AHI互換レイヤー
- 4.4.1: AHI互換関数
- 4.4.2: ADC関連のAHI関数と解説
- 4.4.3: DIO (GPIO)関連のAHI関数と解説
- 4.4.4: Timer (PWM)関連のAHI関数と解説
- 4.4.5: SMBUS(I2C)関連の手続きを定義したSMBus.c,hの解説
- 4.4.6: SPI関連のAHI関数と解説
- 4.4.7: Random(乱数)関連のAHI関数と解説
- 4.4.8: UART関連のAHI関数と解説
- 4.4.9: WatchDog(WDT)関連のAHI関数と解説
- 4.4.10: WakeTimer(ウェイクタイマー)関連のAHI関数と解説
- 4.4.11: Onchip temp sensor (温度センサー)関連のAHI関数と解説
- 4.5: TWENETeastl - EASTLライブラリ
- 4.6: TWENETstgs - twesettingsライブラリ
- 4.6.1: printfライブラリ
- 4.6.2: TWESTG_CMD_u32CmdOp() コマンド解説
1 - MWX ライブラリ
1.1 - MWX ライブラリ
資料に関する注意事項をご参照ください。
お気付きの点がありましたら、サポート窓口へご連絡ください。
1.1.1 - 全般
+-----------------------+
| act (USER APPs)... |
+-----------------------+
| MWX C++ LIB |
+---------------+ |
| TWENET C LIB | |
+------------+----------+
| MAC LAYER | AHI APIs |
+-----------------------+
| TWELITE HARDWARE |
+-----------------------+
MWX ライブラリの名称は Mono Wireless C++ Library for TWELITE です。MW は MonoWireless から、また C++ -> CXX -> double X -> WX。この MW と WX を重ねて MWX になりました。 このライブラリを用いて記述したコードを「アクト(act)」と呼びます。
表記等について
本解説での表記について記載します。
auto&&
ユニバーサル参照と呼ばれ、標準ライブラリなどで良く用いられます。当ライブラリでもほとんどの場合auto&&
と記載します。
auto
はC言語ではローカル変数(自動変数)を宣言する際のキーワードとなっていますが、ここでは型推論により宣言を行う意味です。C++のテンプレート構文では非常に煩雑な型名になることが多く、同時に型名を明示的に記述しなくても実装できる場面で便利な記法です。
下記の例では、v
の型に対する最大値最小値を発見する標準ライブラリのアルゴリズム std::minmax_element
を用いた例で、結果の戻り値を auto
により宣言しています。この場合、auto
で推論された型はstd::pair<int, int>
になります。
#include <algorithm>
int v[] = { 1, 3, -1, 5, 10 };
auto&& result = std::minmax_element(std::begin(v), std::end(v));
Serial << "min=" << int(result.first)
<< ",max=" << int(result.second);
auto &&
の&&
の厳格な意味合いについては専門書籍などを紐解いていただく必要がありますが、ここでは「戻りが参照型(C言語でいうポインタ渡しに近い)であっても値であっても、気にせず宣言できる」とお考え下さい。
名前空間について
namespace
, inline namespace
, using
を用いて、名前の再定義などを行っています。解説中でも一部省略して記載しています。
制限事項 (TWENET)
MWXライブラリは、下層に位置する各ライブラリ・機能(TWNET Cライブラリでの機能、また半導体ベンダが提供するマイコン・ペリフェラル機能、IEEE802.15.4の機能)について、その全てに対応する目的では開発しておりません。
制限事項 (C++の利用)
MWXライブラリはC++言語で記述されておりアクトの記述においても C++ での記述を行うことになります。しかしながらC++言語であってもすべての機能が使えるわけではありません。特に以下の点に注意してください。
new
,new[]
演算子でのメモリ確保は行えますが、確保したメモリを破棄することはできません。C++ライブラリで動的メモリ確保をするものは殆どが事実上利用不可能です。- グローバルオブジェクトのコンストラクタが呼び出されません。
- 参考:必要な場合は、初期化関数(
setup()
) でnew ((void*)&obj_global) class_foo();
のように初期化することでコンストラクタの呼び出しを含めた初期化を行えます。 - 例外
exception
が使用できません。 - 仮想関数
virtual
が使用できません。 - 上記の制約があるためSTLなどC++標準ライブラリの一部のみの利用となります。
※ 当社で把握しているものについての記載です。
ライブラリのソースコードについて
ソースコードは以下から参照できます。
{MWSDKインストールフォルダ}/TWENET/current/src/mwx
- https://github.com/monowireless/mwx
1.1.1.1 - ライセンス
保証・ライセンス
本パッケージ内で、ライセンス上特別な記述のないものは、モノワイヤレスソフトウェア使用許諾契約書(MW-SLA)またはモノワイヤレスオープンソースソフトウェア使用許諾契約書(MW-OSSLA)を適用します。
本ドキュメントについても、本ライブラリパッケージ部の一部としてMW-SLA下の取り扱いとします。
本ソフトウェアについては、モノワイヤレス株式会社が正式にサポートを行うものではありません。お問い合わせにはご回答できない場合もございます。予めご了承ください。
不具合などのご報告に対してモノワイヤレス株式会社は、修正や改善をお約束するものではありません。
また導入パッケージなどお客様の環境に依存して動作しない場合もございます。
1.1.1.2 - 用語
一般的な用語
SDK (TWELITE SDK, MWSDK)
ソフトウェア開発環境
IEEE802.15.4
TWELITE無線モジュールが利用する無線規格です。MWXライブラリを使用する限り、無線規格の詳細を意識する必要はありません。
パケット
無線通信における最小の通信単位です。
最大量は通信方式や通信時の設定によって変わりますが、MWXライブラリ標準の通信<NWK_SIMPLE>では、ユーザが1パケットで送信できるデータ量は90バイトです。
ペイロード
「貨物」といった意味合いですが、無線パケットに含まれるデータ本体のことをいいます。
ノード
「点・節」といった意味合いですが、無線ネットワーク内の無線局のことを言います。
MWXライブラリ特有の用語
アクト/act
本ライブラリを用いて作成したプログラム。そのソースコードまたは動作するプログラムのことを言います。
ビヘイビア
アクトの中でも特にイベント形式のプログラム。そのソースコードまたは動作するプログラムのことを言います。
ビヘイビアは1つのクラス定義による記述で、TWENETからのコールバック関数やイベントや割り込み処理を記述しひとまとめにしています。MWXライブラリでは以下の3種類のビヘイビアがあります。
- アプリケーションビヘイビア:イベントドリブンでのアプリケーション記述を行い、ユーザが定義するクラス。
- ボードビヘイビア:TWELITE無線モジュールを実装するボードの機能利用を簡素化するためのクラス。
- ネットワークビヘイビア:無線ネットワークの手続きを簡素化するためのクラス。
ビヘイビア名は < >
で括って表記します。例えばシンプル中継ネットワークのビヘイビア名は <NWK_SIMPLE>
です。
クラスオブジェクト
本ライブラリの解説では、ライブラリで最初からグローバル宣言されたオブジェクトをクラスオブジェクトと呼称します。Serial
, Wire
などです。これらクラスオブジェクトは手続きなしまたは開始手続きを行うことで利用できます。
メモリを比較的多く消費するクラスオブジェクトは、初期化手続きの際(.setup()
または.begin()
メソッド)に初期化パラメータに沿ったメモリを確保します。
C++に関する用語
C++
C++言語のこと。
C++11
C++規格のバージョンの一つ。2011年式のC++といった意味合いで、2011年にISOで規格化されています。直前のC++03から大きく機能拡張されています。C++14, C++17といったより新しいバージョンがあります。
クラス
あるデータに注目して、その手続きをひとまとめにしたもの。構造体に、その構造体を取り扱うための手続きが含まれています。実際にはもっと深い話題に発展しますが、専門書を参考にしてください。
C++においては、キーワードの struct
と class
は本質的には同じもので、いずれのキーワードで宣言してもクラスとなります。
struct myhello {
int _i;
void say_hello() { printf("hello %d\n", _i); }
};
上記のクラス定義をC言語でも行った場合、例えば以下のようになります。
typedef struct _c_myhello {
int _i;
void (*pf_say_hello)(struct _c_myhello *);
} c_myhello;
void say_hello(c_myhello*p) { p->pf_say_hello(); }
void init_c_my_hello(c_myhello*p) {
p->pf_say_hello = say_hello;
}
ラッパークラス
既存のC言語のライブラリやその内部の構造体などをクラスに包含し、C++特有の機能性を追加するなどして、利用の便を図ったものです。解説中でも「~構造体をラップした」といった記述をする場合があります。
メソッド/メンバ関数
クラスに定義される関数で、クラスに紐付いています。
struct myhello {
int _i;
void say_hello() { printf("hello %d\n", _i); } //メソッド
};
オブジェクト/インスタンス
クラスを実体化(メモリ確保)したもの。
void func() {
myhello obj_hello; // obj_helloがmyhelloクラスのオブジェクト
obj_hello._i = 10;
obj_hello.say_hello();
}
本解説ではオブジェクトとインスタンスは同じ意味合いとして取り扱っています。
コンストラクタ
オブジェクト生成時の初期化手続き。
struct myhello {
int _i;
void say_hello() { printf("hello %d\n", _i); }
myhello(int i = 0) : _i(i) {} // コンストラクタ
};
void my_main() {
myhello helo(10); // ここでコンストラクタが呼び出され_i=10にセットされる
}
デストラクタ
コンストラクタと対になってオブジェクトが破棄されるときの手続きです。
struct myhello {
int _i;
void say_hello() { printf("hello! %d\n", _i); }
myhello(int i = 0) : _i(i) {} // コンストラクタ
~myhello() {
printf("good bye! %d\n", _i);
} //デストラクタ
};
抽象クラス
C++では仮想クラスによりポリモーフィズム(多態性)を実現します。具体的にはvirtualキーワードで指定た純粋仮想関数を定義したクラスです。
struct Base {
virtual void say_hello() = 0;
};
struct DeriveEng : public Base {
void say_hello() { printf("Hello!"); }
};
struct DeriveJpn : public Base {
void say_hello() { printf("Kontiwa!"); }
};
スコープ
C/C++言語では { }
で括った範囲と考えてください。この中で生成したオブジェクトは、スコープから出るときに破棄されます。この時デストラクタが呼び出されます。
以下は、明示的にスコープを設定したものです。helo2
は8行目まで実行された時点で破棄され、デストラクタが呼び出されます。
void my_main() {
myhello helo1(1);
helo1.say_hello();
{
myhello helo2(2);
helo2.say_hello();
}
}
// hello! 1
// hello! 2
// good bye! 2
// good bye! 1
MWXライブラリでは以下のような記法を用いています。ここではif文の条件判定式内で宣言(C89といった旧いC言語ではこういった場所での宣言はできません)されたオブジェクトの有効期間は、if文の{}
内になります。
struct myhello {
int _i;
void say_hello() { printf("hello! %d\n", _i); }
operator bool() { return true; } // if()での判定用の演算子
myhello(int i = 0) : _i(i) {} // コンストラクタ
~myhello() { printf("good bye! %d\n", _i); } // コンストラクタ
};
// myhello オブジェクトを生成する関数 (ジェネレータ)
myhello gen_greeting() { return my_hello(); }
void my_main() {
if (myhello x = gen_greeting()) {
// myhelloのオブジェクト x は if文中有効
x.say_hello();
}
// if 分を抜けるときにオブジェクトxは破棄される
}
例えば二線シリアルバスなど、開始と終了の手続きがあって、その間だけオブジェクトによってバスを操作するような手続きです。オブジェクトの生成後、バスの接続が適切であればif文のtrue節が実行され、生成したオブジェクトによってバスの書き込みまたは読み出しを行います。バスの読み書き操作が終了したらif文を脱出し、この時デストラクタが呼び出され、バスの利用終了手続きが行われます。
const uint8_t DEV_ADDR = 0x70;
if (auto&& wrt = Wire.get_writer(DEV_ADDR)) { //バスの初期化、接続判定
wrt(SHTC3_TRIG_H); // 書き出し
wrt(SHTC3_TRIG_L);
} // バスの利用終了手続き
名前空間 (namespace)
定義名の重複を避けるためC++では名前空間が積極的に用いられます。名前空間にある定義にアクセスするには::
を用います。
namespace MY_NAME { // 名前空間の宣言
const uint8_t MYVAL1 = 0x00;
}
...
void my_main() {
uint8_t i = MY_NAME::MYVAL1; // MY_NAME の参照
}
テンプレート (template)
テンプレートはC言語のマクロを拡張したものと考えてください。
template <typename T, int N>
class myary {
T _buf[N];
public:
myary() : _buf{} {}
T operator [] (int i) { return _buf[i % N]; }
};
myary<int, 10> a1; // int 型で要素数10の配列
myary<char, 128> a2; // char 型の要素数128の配列
この例では、簡単な配列を定義しています。T
とN
はテンプレートのパラメータで、T
は型名をN
は数値を指定し、T
型で要素数N
の配列クラスを定義しています。
nullptr
C++11ではNULLポインタをnullptr
と記述するようになりました。なお NULL
は 0
を表すマクロですが、nullptr
は多くの場合 0
とは異なる実体を持ちます。
参照型
C++では、参照型を利用できます。これはポインタによるアクセスに似ていますが、必ずオブジェクトを参照しなければならないという制約があります。
以下のような参照渡しのパラメータを持つ関数ではi
の値をincr()
内で書き換えることが出来ます。
void incr(int& lhs, int rhs) { lhs += rhs; }
void my_main() {
int i = 10; j = 20;
incr(i, j);
}
テンプレートの解説例ですがoperator[]
の戻り型をT&
に変更しています。こうすることでa[0]=1
のように配列内部のデータに対して直接代入操作ができるようになります。
template <typename T, int N>
class myary {
T _buf[N];
public:
myary() : _buf{} {}
T& operator [] (int i) { return _buf[i % N]; }
};
myary<int, 10> a1;
void my_main() {
a1[0] = 1;
a1[1] = 2;
}
型推論
C++11 では型推論のauto
キーワードが導入されています。これはコンパイラが初期化の記述からそのオブジェクトの型を推論するため、具体的な型名の記述を省略できます。これはtemplate
を用いたクラス名が非常に長くなるような場合に効果的です。
解説中では多くの場合ユニバーサル参照と呼ばれるauto&&を用いています。ユニバーサル参照については、ここでは参照渡しの場合も意識せずに記述できるものと考えてください。
auto&& p = std::make_pair("HELLO", 5);
// const char* と int のペア std::pair
コンテナ
配列など特定のデータ型のオブジェクトを複数個格納するためのクラスをコンテナと呼びます。テンプレートの例で挙げたmyary
のような配列クラスもコンテナと呼んでいます。
smplbuf
とFIFOキュークラスsmplque
を用意しています。イテレータ, .begin()
, .end()
C言語で言うところのポインタ(もちろんC++でも同じようにポインタは使えます)を拡張した概念です。C言語のポインタは、メモリが連続した要素を先頭から末尾まで連続的にアクセスする手段と考えることが出来ます。FIFOキューを考えてみます。もっとも単純なキューの実装はリングバッファによるものですが、メモリーの連続性はありません。こういったデータ構造であっても、イテレータを用いるとポインタと同じように記述できます。
イテレータを取得するため.begin()
,.end()
のメソッドが用いられます。コンテナの先頭を指すイテレータを.begin()
で取得します。末尾の次を指すイテレータを.end()
で取得します。末尾ではなく、末尾の次である理由にはfor
やwhile
文のループ記述の明快さ、コンテナに格納される要素数が0の場合の取り扱いが挙げられます。
my_queue que; // my_queue はキューのクラス
auto&& p = que.begin();
auto&& e = que.end();
while(p != e) {
some_process(*p);
++p;
}
上記では、que
の各要素について、イテレータp
を用いて各要素にsome_process()
を適用しています。p
は++
演算子によって次の要素を指すイテレータとしてインクリメントしています。本来ポインタでは記述できないデータ構造を持つコンテナであっても、このようにポインタを用いた処理と同じような処理が出来ます。
.end()
が末尾の次を示すため、while
文の終了判定は(p != e)
のように簡潔です。キューに要素がない場合は.begin()
は.end()
と同じイテレータを返します。(何も格納されていない要素のイテレータの次ですから、最初に格納すべき領域を示すイテレータと考えればよいでしょう)
メモリ上で連続したコンテナの場合、通常、そのイテレータは通常のポインタとなります。その操作時に大きなオーバーヘッドにはならないことが期待できます。
C++標準ライブラリ
C++の標準ライブラリにはSTL(Standard Template Library)が含まれます。MWXライブラリでの一部を利用しています。
アルゴリズム
例えば最大や最小値を求めるといった処理をC言語では型に応じて別々に記述していました。こういったコードは型の部分だけ違って他は同じといったものも少なくありません。C++ではtemplate
やイテレータなどを用いて、こういった処理を型に依存せず記述することができます。これをアルゴリズムと呼んでいます。
// 任意のイテレータをパラメータとし最大値を持つイテレータを戻す
template <class Iter>
Iter find_max(Iter b, Iter e) {
Iter m = b; ++b;
while(b != e) {
if (*b > *m) { m = b; }
++b;
}
return m;
}
例えば上記のように最大値を求めるアルゴリズムです。このアルゴリズムは型に依存しません。(ジェネリックプログラミングと呼ばれます)
#include <algorithm>
auto&& minmax = std::minmax_element( // 最大最小を得るアルゴリズム
que.begin(), que.end());
auto&& min_val = *minmax.first;
auto&& max_val = *minmax.second;
ここではque
のイテレータを指定し、その最大と最小を得るアルゴリズムstd::minmax_elenet
を適用しています。std::minmax_elemet
はC++標準ライブラリ内に定義されています。その戻り値は任意の2つの値を組み合わせるstd::pair
です。このアルゴリズムは、イテレータの示す要素同士で<
,>
,==
といった演算子での比較が出来れば最大と最小を計算してくれます。戻り型もイテレータの型から導かれます。
1.1.1.3 - 設計情報
設計方針について
- アプリケーションのループ記述では、一般によく用いられる API 体系に近い記述を出来ることを目的とするが、TWELITEの特性に合わせた実装とする。
- TWENET はイベントドリブンによるコード記述であり、これを扱えるようにクラス化を行う。上記クラス化によりアプリケーションのふるまいをカプセル化できるようにする。
- イベントドリブンとループの記述は共存できる形とする。
- 代表的なペリフェラルはクラス化して手続きを簡素化する。可能な限りループ記述でアクセスできるようにする。
- 当社で販売する MONOSTICK/PAL といったボードを利用する手続きをクラス化し手続きを簡素化する。(例えば外部のウォッチドッグタイマーの利用を自動化する)
- アプリケーションクラスやボードクラスは、ポリモーフィズムの考え方を導入し、統一した手続きによって利用できるようにする。(例えば、いくつかの振る舞いをするアプリケーションクラスを始動時にロードするような場合、また TWENET C ライブラリの接続部のコードを都度定義しなくてよいようにするため)。
- C++の機能については、特に制限を設けず利用する。例えば、無線パケットを取り扱うにあたり煩雑なパケット構築、分解といった代表的な手続きを簡略化する手段を提供する。
- 演算子 -> を極力使用しないようにし、原則として参照型による API とする。
C++ コンパイラについて
バージョン
gcc version 4.7.4
C++言語規格
C++11 (コンパイラ対応状況は一般の情報を参考にしてください)
C++ の制限事項
※ 当社で把握しているものについての記載です。
new
,new[]
演算子でのメモリ確保は行えますが、確保したメモリを破棄することはできません。C++ライブラリで動的メモリ確保をするものは殆どが事実上利用不可能です。一度だけ生成してそれ以降破棄しないオブジェクトに使用しています。- グローバルオブジェクトのコンストラクタが呼び出されません。
- 参考:必要な場合は、初期化関数(
setup()
) でnew ((void*)&obj_global) class_foo();
のように初期化することでコンストラクタの呼び出しを含めた初期化を行えます。 - 例外
exception
が使用できません。 - 仮想関数
virtual
が使用できません。
設計メモ
本節ではMWXライブラリのコードを参照する際に理解の助けとなる情報を記載します。
現状の実装
限られた時間で実装を進めているため、詳細部分の整備が十分でない場合があります。例えば const
に対する考慮は多くのクラスで十分なされていません。
名前空間
名前空間について、以下の方針としています。
- 定義は原則として共通の名前空間
mwx
に配置する。 - 名前空間の識別子なしで利用できるようにしたいが、一部の定義は識別子を必須としたい。
- クラス名については比較的長い命名とし、ユーザが利用するものは別名定義とする。
クラス・関数・定数は一部の例外を除きmwx
名(正確にはinline namespace L1
で囲んだmwx::L1
)の名前空間内に定義しています。inline namespace
を指定しているのは、mwx::
の指定を必須とする定義と、必須としない定義を共存させるためです。
殆どの定義はusing namespace
により名前空間名を指定しなくても良いようになっています。これらの指定はライブラリ内のusing_mwx_def.hpp
で行っています。
// at some header file.
namespace mwx {
inline namespace L1 {
class foobar {
// class definition...
};
}
}
// at using_mwx_def.hpp
using namespace mwx::L1; // mwx::L1 内の定義は mwx:: なしでアクセスできる
// しかし mwx::L2 は mwx:: が必要。
例外的に比較的短い名前についてはmwx::crlf
, mwx::flush
のように指定します。これらはinline namespace
のmwx::L2
の名前空間に配置されています。using namespace mwx::L2;
を指定することで名前空間名の指定なしで利用できるようになります。
また、いくつかのクラス名はusing
指定をしています。
MWXライブラリ内で利用するstd::make_pair
をusing
指定しています。
CRTP(奇妙に再帰したテンプレートパターン)
仮想関数 (virtual
), 実行時型情報(RTTI) が利用できない、かつ利用できるようにしたとしても、パフォーマンス面で難があるため、これに代わる設計手法として CRTP(Curiously recurring template pattern : 奇妙に再帰したテンプレートパターン)を用いています。CRTPは、継承元の親クラスから子クラスのメソッドを呼び出すためのテンプレートパターンです。
以下の例では Base
を継承した Derived
クラスに interface()
というインタフェースを実装する例です。Base
からはDerived::print()
メソッドを呼び出しています。
template <class T>
class Base {
public:
void intrface() {
T* derived = static_cast<T*>(this);
derived->prt();
}
};
class Derived : public class Base<Derived> {
void prt() {
// print message here!
my_print("foo");
}
}
MWXライブラリで利用されている主要クラスは以下です。
- イベント処理の基本部分
mwx::appdefs_crtp
- ステートマシン
public mwx::processev_crtp
- ストリーム
mwx::stream
CRTP での仮想化
CRTPクラスは、継承元のクラスはインスタンスごとに違います。このため、親クラスにキャストして、同じ仲間として取り扱うといったこともできませんし、仮想関数(virtual
)やRTTI(実行時型情報)を用いたような高度なポリモーフィズムも使うことが出来ません。
以下は上述のCRTPの例を、仮想関数で実装した例です。CRTPではBase* b[2]
のように同じ配列にインスタンスをまとめて管理することは、そのままではできません。
class Base {
virtual void prt() = 0;
public:
void intrface() { prt(); }
};
class Derived1 : public Base {
void prt() { my_print("foo"); }
};
class Derived2 : public Base {
void prt() { my_print("bar"); }
};
Derived1 d1;
Derived2 d2;
Base* b[2] = { &d1, &d2 };
void tst() {
for (auto&& x : b) { x->intrface(); }
}
MWXライブラリでは、CRTP のクラスインスタンスを格納するための専用クラスを定義し、このクラスに同様のインタフェースを定義することで解決しています。以下にコード例を挙げます。
class VBase {
public:
void* p_inst;
void (*pf_intrface)(void* p);
public:
void intrface() {
if (p_inst != nullptr) {
pf_intrface(p_inst);
}
}
};
template <class T>
class Base {
friend class VBase;
static void s_intrface(void* p) {
T* derived = static_cast<T*>(p);
derived->intrface();
}
public:
void intrface() {
T* derived = static_cast<T*>(this);
derived->prt();
}
};
class Derived1 : public Base<Derived1> {
friend class Base<Derived1>;
void prt() { my_print("foo"); }
};
class Derived2 : public Base<Derived2> {
friend class Base<Derived2>;
void prt() { my_print("bar"); }
};
Derived1 d1;
Derived2 d2;
VBase b[2];
void tst() {
b[0] = d1;
b[1] = d2;
for (auto&& x : b) {
x.intrface();
}
}
VBase
クラスのメンバ変数 p_inst
は、Base <T>
型のオブジェクトへのポインタを格納し、pf_intrface
は Base<T>::s_intrface
へのメンバ関数ポインタです。 Base<T>::s_intrface
は、自身のオブジェクトインスタンスを引数として渡され、T
型にstatic_cast
することでT::intrface
メソッドを呼び出します。
VBase
への格納は、ここでは =
演算子のオーバーロードによって実装しています(ソース例は後述)。
上記の例ではb[0].intrface()
の呼び出しを行う際には、VBase::pf_intrface
関数ポインタを参照しBase<Derived1>::s_intrface()
が呼び出されることになります。さらにDerived1::intrface()
の呼び出しを行うことになります。この部分はコンパイラによるinline展開が期待できます。
VBase
型から元のDerived1
やDerived2
への変換を行うことも、強制的なキャストにより可能ですが、void*
で格納されたポインタの型を直接知る方法はありません。完全に安全な方法はないものの、以下のようにクラスごとに一意のID(TYPE_ID
)を設けて、キャスト実行時(get()
メソッド)にIDのチェックを行うようにしています。違う型を指定して get()
メソッドを呼び出したときは、エラーメッセージを表示するといった対処になります。
Base<T>
型としてのポインタが格納されるとT
型に正しく変換できない可能性(T
が多重継承している場合など)あるため、<type_trails>
のis_base_of
によりBase<T>
型の派生であることをコンパイル時に static_assert
によって判定しています。
#include <type_trails>
class Derived1 : public Base<Derived1> {
public:
static const uint8_t TYPE_ID = 1;
}
class Derived1 : public Base<Derived1> {
public:
static const uint8_t TYPE_ID = 2;
}
class VBase {
uint8_t type_id;
public:
template <class T>
void operator = (T& t) {
static_assert(std::is_base_of<Base<T>, T>::value == true,
"is not base of Base<T>.");
type_id = T::TYPE_ID;
p_inst = &t;
pf_intrface = T::s_intrface;
}
template <class T>
T& get() {
static_assert(std::is_base_of<Base<T>, T>::value == true,
"is not base of Base<T>.");
if(T::TYPE_ID == type_id) {
return *reinterpret_cast<T*>(p_inst);
} else {
// panic code here!
}
}
}
Derived1 d1;
Derived2 d2;
VBase b[2];
void tst() {
b[0] = d1;
b[1] = d2;
Derived1 e1 = b[0].get<Derived1>(); // OK
Derived2 e2 = b[1].get<Derived2>(); // OK
Derived2 e3 = b[1].get<Derived1>(); // PANIC!
}
new, new[] 演算子
TWELITEモジュールのマイコンには十分なメモリもなければ、高度なメモリ管理もありません。しかしマイコンのメモリマップの末尾からスタックエリアまでの領域はヒープ領域として、必要に応じて確保できる領域があります。以下にメモリマップの概要を図示します。APPがアプリケーションコードで確保されたRAM領域、HEAPはヒープ領域、STACKはスタック領域です。
|====APP====:==HEAP==.. :==STACK==|
0 32KB
たとえdelete
できなくてもnew
演算子が有用である場面も想定されます。そのため、以下のようにnew
, new[]
演算子を定義しています。pvHear_Alloc()
は半導体ライブラリで提供されているメモリ確保の関数で、u32HeapStart
, u32HeapEnd
も同様です。0xdeadbeef
はダミーアドレスです。
beef
がdead
なのは変だとかいう指摘はしないでください。
void* operator new(size_t size) noexcept {
if (u32HeapStart + size > u32HeapEnd) {
return (void*)0xdeadbeef;
} else {
void *blk = pvHeap_Alloc(NULL, size, 0);
return blk;
}
}
void* operator new[](size_t size) noexcept {
return operator new(size); }
void operator delete(void* ptr) noexcept {}
void operator delete[](void* ptr) noexcept {}
例外も使えないため失敗したときの対処はありません。また、メモリ容量を意識せず確保を続けた場合、スタック領域と干渉する可能性もあります。
コンテナクラス
MWXライブラリでは、マイコンのリソースが小さい点、メモリーの動的確保ができない点を考慮し標準ライブラリで提供されるコンテナクラスの利用はせず、シンプルなコンテナクラスを2種類定義しています。コンテナクラスにはイテレータやbegin()
, end()
メソッドを定義しているため、範囲for
文やSTLのアルゴリズムの一部を利用できます。
smplbuf<int16_t, alloc_local<int16_t, 16>> buf;
buf.push_back(-1); // push_back() は末尾に追加
buf.push_back(2);
...
buf.push_back(10);
//範囲for文
for(auto&& x : buf) { Serial << int(x) << ',' }
//アルゴリズム std::minmax
auto&& minmax = std::minmax_element(buf.begin(), buf.end());
Serial << "Min=" << int(*minmax.first)
<< ",Max=" << int(*minmax.second);
クラス名 | 概要 |
---|---|
smplbuf | 配列クラスで、最大領域 (capacity) と最大領域範囲内で都度サイズを指定できる利用領域(size)を管理します。また本クラスは stream インタフェースを実装しているため、<< 演算子を用いてデータを書き込むことができます。 |
smplque | FIFOキューを実装しています。キューのサイズはテンプレートのパラメータで決定します。割り込み禁止を用いキューを操作するためのテンプレート引数もあります。 |
コンテナクラスのメモリについて
コンテナクラスではメモリの確保方法をtemplate
引数のパラメータとして指定します。
クラス名 | 概要 |
---|---|
alloc_attach | すでに確保済みのバッファメモリを指定する。Cライブラリ向けに確保したメモリ領域を管理したいとき、同じバッファ領域の分断領域として処理したい時などに使用します。 |
alloc_static | クラス内に静的配列として確保する。事前にサイズが決まっていたり、一時利用の領域として使用します。 |
alloc_heap | ヒープ領域に確保する。システムのヒープに確保後は破棄できませんが、初期化時にアプリケーションの設定などに従い領域を確保するといった使い方に向いています。 |
可変数引数
MWXライブラリでは、バイト列やビット列の操作、printf
相当の処理を行う処理に可変数引数を用いています。下記の例は指定のビット位置に1をセットする処理です。
// packing bits with given arguments, which specifies bit position.
// pack_bits(5, 0, 1) -> (b100011) bit0,1,5 are set.
// 再帰取り出しの一番最初の関数
template <typename Head>
constexpr uint32_t pack_bits(Head head) { return 1UL << head; }
// head を取り出し、残りのパラメータを再帰呼び出しにて pack_bits に転送
template <typename Head, typename... Tail>
constexpr uint32_t pack_bits(Head head, Tail&&... tail) {
return (1UL << head) | pack_bits(std::forward<Tail>(tail)...);
}
// コンパイル後、以下の2つは同じ結果になります。
constexpr uint32_t b1 = pack_bits(1, 4, 0, 8);
// b1 and b2 are the same!
const uint32_t b2 = (1UL << 1)|(1UL << 4)|(1UL << 0)|(1UL << 8);
この処理では template
のパラメータパック (typename...
の部分) で、再帰的な処理を行い引数の展開を行っています。上記の例ではconstexpr
の指定があるため、コンパイル時に計算が行われマクロ定義やb2
のようなconst
値の指定と同等の結果になります。また変数を引数として動的に計算する関数としても振る舞うこともできます。
以下の例では、expand_bytes
関数により、受信パケットのデータ列からローカル変数に値を格納しています。パラメータパックを用いた場合各引数の型を把握できるため、下記のように、受信パケットのバイト列から、サイズや異なる型にあった値を格納することができます。
auto&& rx = the_twelite.receiver.read(); // 受信パケット
// 展開後のパケットの内容を格納する変数
// パケットのペイロードはバイト列で以下のように並んでいる。
// [B0][B1][B2][B3][B4][B5][B6][B7][B8][B9][Ba][Bb]
// <message ><adc* ><vcc* ><timestamp* >
// * 数値型はビッグエンディアン並び
uint8_t msg[MSG_LEN];
uint16_t adcval, volt;
uint32_t timestamp;
// expand packet payload
expand_bytes(rx.get_payload().begin(), rx.get_payload().end()
, msg // 4bytes of msg
, adcval // 2bytes, A1 value [0..1023]
, volt // 2bytes, Module VCC[mV]
, timestamp // 4bytes of timestamp
);
イテレータ
イテレータはポインタの抽象化で、例えばメモリの連続性のないようなデータ構造においても、あたかもポインタを使ったようにデータ構造にアクセスできる効果があります。
C++のSTLでは、begin()
メソッドで得られるコンテナの先頭を示すイテレータと、end()
メソッドで得られるコンテナの末尾の「次」を示すイテレータの組み合わせが良く用いられます。
smplque<uint8_t, alloc_local<uint8_t, 5> > que;
que.push('a'); que.push('b'); que.pop(); que.push('c'); ...
auto&& p = que.begin();
auto&& e = que.end();
while(p != e) { // pがeまで進んだ=全要素処理した
Serial << *p;
++p; // イテレータのインクリメントは前置演算子を使います。
// この場合、p++ と記述すると、コンパイラによる最適化が行われる可能性は
// 高いものの、コード上はイテレータのコピーが発生します。
}
イテレータを標準ライブラリの仕様に適合させることで、範囲for
文が利用できたり、標準ライブラリのアルゴリズムを利用できるようになります。
#include <algorithm>
#include <cctype>
// ラムダ式による文字変換
std::for_each(que.begin(), que.end(),
[](uint8_t& x) { x = std::toupper(x); });
// 範囲for文
for (uint8_t x : que) {
Serial << x;
}
(MWXライブラリではC++標準ライブラリに対する適合度や互換性についての検証は行っていません。動作確認の上利用ください)
以下の例では、通常のポインタでは連続的なアクセスができないFIFOキューのイテレータ、さらに、FIFOキューの構造体の特定メンバー(例ではX軸)のみを抽出するイテレータを利用する例です。
// XYZTの4軸構造体を要素とする要素数5のキュー
smplque<axis_xyzt, alloc_local<axis_xyzt, 5> > que;
// テスト用にデータを投入
que.push(axis_xyzt(1, 2, 3, 4));
que.push(axis_xyzt(5, 2, 3, 4));
...
// 構造体としてのイテレータを用いたアクセス
for (auto&& e : v) { Serial << int(e.x) << ','; }
// キューの中の X 軸を取り出す
auto&& vx = get_axis_x(que);
// X軸のイテレータを用いたアクセス
for (auto&& e : vx) { Serial << int(e) << ','; }
// int16_t要素のイテレータなので、STLのアルゴリズム(最大最小)が使える
auto&& minmax = std::minmax_element(vx.begin(), vx.end());
以下は smplque
クラスのイテレータの実装の抜粋です。このイテレータでは、キューオブジェクトの実体と、インデックスにより管理しています。キューのメモリが不連続になる(末尾の次は先頭を指す必要があるリングバッファ構造)部分はsmplque::operator []
で解決しています。オブジェクトのアドレスが一致することとインデックスが一致すればイテレータは同じものを指していることになります。
この実装部分には <iterator>
が要求する typedef
なども含まれ、より多くのSTLのアルゴリズムが適用できるようになります。
class iter_smplque {
typedef smplque<T, alloc, INTCTL> BODY;
private:
uint16_t _pos; // index
BODY* _body; // point to original object
public: // for <iterator>
typedef iter_smplque self_type;
typedef T value_type;
typedef T& reference;
typedef T* pointer;
typedef std::forward_iterator_tag iterator_category;
typedef int difference_type;
public: // pick some methods
inline reference operator *() {
return (*_body)[_pos];
}
inline self_type& operator ++() {
_pos++;
return *this;
}
};
構造体を格納したコンテナ中の、特定構造体メンバーだけアクセスするイテレータは少々煩雑です。構造体のメンバーにアクセスするメンバー関数を予め定義しておきます。このメンバー関数をパラメータ(R& (T::*get)()
)としたテンプレートを定義します。Iter
はコンテナクラスのイテレータ型です。
struct axis_xyzt {
int16_t x, y, z;
uint16_t t;
int16_t& get_x() { return x; }
int16_t& get_y() { return y; }
int16_t& get_z() { return z; }
};
template <class Iter, typename T, typename R, R& (T::*get)()>
class _iter_axis_xyzt {
Iter _p;
public:
inline self_type& operator ++() {
_p++;
return *this; }
inline reference operator *() {
return (*_p.*get)(); }
};
template <class Ixyz, class Cnt>
class _axis_xyzt_iter_gen {
Cnt& _c;
public:
_axis_xyzt_iter_gen(Cnt& c) : _c(c) {}
Ixyz begin() { return Ixyz(_c.begin()); }
Ixyz end() { return Ixyz(_c.end()); }
};
// 長いので using で短縮
template <typename T, int16_t& (axis_xyzt::*get)()>
using _axis_xyzt_axis_ret = _axis_xyzt_iter_gen<
_iter_axis_xyzt<typename T::iterator, axis_xyzt, int16_t, get>, T>;
// X 軸を取り出すジェネレータ
template <typename T>
_axis_xyzt_axis_ret<T, &axis_xyzt::get_x>
get_axis_x(T& c) {
return _axis_xyzt_axis_ret<T, &axis_xyzt::get_x>(c);
}
値にアクセスするoperator *
この上述のメンバー関数を呼び出しています。(*_p
はaxis_xyzt
構造体で、(*_p.*get)()
は、T::*get
に&axis_xyzt::get_x
を指定した場合_p->get_x()
を呼び出します)
_axis_xyzt_iter_gen
クラスはbegin()
, end()
のみを実装し、上記のイテレータを生成します。これで範囲for
文やアルゴリズムが利用できるようになります。
このクラス名は非常に長くなりソースコード中に記述するのは困難です。このクラスを生成するためのジェネレータ関数を用意します。下記の例では末尾の行の get_axis_x()
です。このジェネレータ関数を用いることで冒頭のようなauto&& vx = get_axis_x(que);
といった簡潔な記述になります。
また、この軸だけを抽出するイテレータは、配列型のsmplbuf
クラスでも同様に利用できます。
割り込み・イベント・状態ハンドラの実装
ユーザ定義クラスによりアプリケーション動作を記述するため、代表的なハンドラは必須メソッドとして定義が必要ですが、それ以外に多数ある割り込みハンドラ、イベントハンドラ、ステートマシンの状態ハンドラをすべて定義するのは煩雑です。ユーザが定義したものだけ定義され、それのみのコードが実行されるのが理想です。
class my_app_def {
public: // 必須メソッドの定義
void network_event(twe::packet_ev_nwk& pEvNwk) {}
void receive(twe::packet_rx& rx) {}
void transmit_complete(twe::packet_ev_tx& pEvTx) {}
void loop() {}
void on_sleep(uint32_t& val) {}
void warmboot(uint32_t& val) {}
void wakeup(uint32_t& val) {}
public: // これらを必須記述とするのは煩雑
// DIO割り込みハンドラ 20種類ある
// DIOイベントハンドラ 20種類ある
// タイマー割り込みハンドラ 5種類ある
// タイマーイベントハンドラ 5種類ある
// ...
}
MWXライブラリでは、数の多い DIO割り込みハンドラ(TWELITEハード上は単一の割り込みですが、利用しやすさのためDIO一つずつにハンドラを割り当てることにしました)などを、テンプレートによる空のハンドラーとして定義した上、ユーザ定義のメンバー関数をそのテンプレートの特殊化することにより定義する手法を採用しました。
// hpp file
class my_app_def : class app_defs<my_app_def>, ... {
// 空のハンドラ
template<int N> void int_dio_handler(uint32_t arg, uint8_t& handled) { ; }
...
// 12番だけ実装する
public:
// TWENET から呼び出されるコールバック関数
uint8 cbTweNet_u8HwInt(uint32 u32DeviceId, uint32 u32ItemBitmap);
};
// cpp file
template <>
void my_app_def::int_dio_handler<12>(uint32_t arg, uint8_t& handled) {
digitalWrite(5, LOW);
handled = true;
return;
}
void cbTweNet_u8HwInt(uint32 u32DeviceId, uint32 u32ItemBitmap) {
uint8_t b_handled = FALSE;
switch(u32DeviceId) {
case E_AHI_DEVICE_SYSCTRL:
if (u32ItemBitmap & (1UL << 0)){int_dio_handler<0>(0, b_handled);}
if (u32ItemBitmap & (1UL << 1)){int_dio_handler<1>(1, b_handled);}
...
if (u32ItemBitmap & (1UL << 12)){int_dio_handler<12>(12, b_handled);}
...
if (u32ItemBitmap & (1UL << 19)){int_dio_handler<19>(19, b_handled);}
break;
}
}
実際のユーザ記述コードは、マクロ化やヘッダファイルのインクルードを行うことで、簡素化されていますが、上記は解説のために必要なコードを含めています。
TWENETからの割り込みハンドラからmy_app_def::cbTweNet_u8HwInt()
が呼び出されます。cpp
ファイル中では、int_dio_handler<12>
のみが特殊化されて記載された内容でインスタンス化されます。12番以外はhpp
ファイル中のテンプレートからインスタンス化されます。結局以下のように展開されることになります。
case E_AHI_DEVICE_SYSCTRL:
if (u32ItemBitmap & (1UL << 0)){;}
if (u32ItemBitmap & (1UL << 1)){;}
...
if (u32ItemBitmap & (1UL << 12)){
int_dio_handler<12>(12, b_handled);}
...
if (u32ItemBitmap & (1UL << 19)){;}
break;
// ↓ ↓ ↓
// 結局、このように最適化されることが期待できる。
case E_AHI_DEVICE_SYSCTRL:
if (u32ItemBitmap & (1UL << 12)){
// int_dio_handler<12> もinline展開
digitalWrite(5, LOW);
handled = true;
}
break;
最終的に、コンパイラの最適化により12番以外のコードは無意味と判断されコード中から消えてしまうことが期待できます(ただし、上記のように最適化されることを保証するものではありません)。
つまりユーザコード上では12番の割り込み時の振る舞いを定義したいときはint_dio_handler<12>
を記述するだけで良い、ということになります(注:DIO割り込みを有効にするには attachInterrupt()
を呼び出す必要があります)。登録しないハンドラはコンパイル時の最適化により低コストな呼び出しで済むことが期待できます。
ユーザが関数を定義したときにこれを有効にし、定義しない場合は別の関数を呼び出す手法として、リンク時の解決方法があります。下記のように__attribute__((weak))
を指定します。ユーザコードで wakeup()
関数が定義された場合は、ユーザーコードを関数をリンクし、未定義の場合は中身が空の関数をリンクします。
// mwx_appcore.cpp
void wakeup() __attribute__((weak));
void wakeup() { }
上記ハンドラの実装においてはweak指定したメンバー変数を明示的に生成する必要があり、またinline化による最適化が行いにくいため使用しませんが、wakeup()
といったいくつかのTWENETからのコールバック関数の受け皿としてweak指定の関数を定義しています。
Streamクラス
ストリームクラスは、主にUART(シリアルポート)の入出力に用います。MWXライブラリでは、出力用の手続きを主に定義しています。一部入力用の定義もあります。
ここでは派生クラスが必要とする実装について解説します。
template <class D>
class stream {
protected:
void* pvOutputContext; // TWE_tsFILE*
public:
inline D* get_Derived() { return static_cast<D*>(this); }
inline D& operator << (char c) {
get_Derived()->write(c);
return *get_Derived();
}
};
class serial_jen : public mwx::stream<serial_jen> {
public:
inline size_t write(int n) {
return (int)SERIAL_bTxChar(_serdef._u8Port, n);
}
};
上記は1文字書き出すwrite()
メソッドの実装です。親クラスのstream<serial_jen>
からはキャストを実行するget_Drived()
メソッドを用いて、serial_jen::write()
メソッドにアクセスしています。
必要に応じて write()
, read()
, flush()
, available()
といったメソッドを定義します。
書式出力にはMarco Paland氏によるprintfライブラリを利用しています。MWXライブラリから利用するための実装が必要になります。下記の例で派生クラスのserial_jen
で必要なことは1バイト出力のための vOutput()
メソッドを定義することと、vOutput()
がstatic
メソッドであるため出力のための補助情報を親クラスのpvOutputContext
に保存することです。
template <class D>
class stream {
protected:
void* pvOutputContext; // TWE_tsFILE*
public:
inline tfcOutput get_pfcOutout() { return get_Derived()->vOutput; }
inline D& operator << (int i) {
(size_t)fctprintf(get_pfcOutout(), pvOutputContext, "%d", i);
return *get_Derived();
}
};
class serial_jen : public mwx::stream<serial_jen> {
using SUPER = mwx::stream<serial_jen>;
TWE_tsFILE* _psSer; // シリアル出力のためのローレベル構造体
public:
void begin() {
SUPER::pvOutputContext = (void*)_psSer;
}
static void vOutput(char out, void* vp) {
TWE_tsFILE* fp = (TWE_tsFILE*)vp;
fp->fp_putc(out, fp);
}
};
get_pfcOutput()
により、派生クラスで定義したvOutput()
関数を指定し、そのパラメータとしてpvOutputContext
が渡されます。上記の例では<<
演算子がint
型で呼び出されたときserial_jen::vOutput()
とUART用に設定済みのTWE_tsFILE*
をfctprintf()
関数に渡しています。
Wire, SPIのワーカーオブジェクト
Wire
クラスでは、2線デバイスとの送信・受信時に、通信開始から終了までを管理する必要があります。ワーカーオブジェクトを利用する記述について内容を記述します。
if (auto&& wrt = Wire.get_writer(SHTC3_ADDRESS)) {
Serial << "{I2C SHTC3 connected.";
wrt << SHTC3_TRIG_H;
wrt << SHTC3_TRIG_L;
Serial << " end}";
}
periph_twowire::writer
クラスの抜粋です。streamインタフェースを実装するために mwx::stream<writer>
を継承しています。steamインタフェースを利用するために write()
と vOutput()
メソッドの実装を行っています。
コンストラクタでは2線シリアルの通信開始を、デストラクタで通信終了のメソッドを呼び出しています。また、operator bool()
演算子では、2線シリアルのデバイスの通信開始に成功した場合 true
を返すようになっています。
class periph_twowire {
public:
class writer : public mwx::stream<writer> {
friend class mwx::stream<writer>;
periph_twowire& _wire;
public:
writer(periph_twowire& ref, uint8_t devid) : _wire(ref) {
_wire.beginTransmission(devid); // コンストラクタで通信開始
}
~writer() {
_wire.endTransmission(); // デストラクタで通信終了
}
operator bool() {
return (_wire._mode == periph_twowire::MODE_TX);
}
private: // stream interface
inline size_t write(int n) {
return _wire.write(val);
}
// for upper class use
static void vOutput(char out, void* vp) {
periph_twowire* p_wire = (periph_twowire*)vp;
if (p_wire != nullptr) {
p_wire->write(uint8_t(out));
}
}
};
public:
writer get_writer(uint8_t address) {
return writer(*this, address);
}
};
class periphe_twowire Wire; // global instance
// ユーザコード
if (auto&& wrt = Wire.get_writer(SHTC3_ADDRESS)) {
Serial << "{I2C SHTC3 connected.";
wrt << SHTC3_TRIG_H;
wrt << SHTC3_TRIG_L;
Serial << " end}";
}
get_writer()
メソッドによりオブジェクトwrt
を生成します。この時にオブジェクトのコピーは通常発生しません。C++コンパイラのRVO(Return Value Optimization)という最適化により、writer
はwrt
に直接生成されるためコピーは発生せず、コンストラクタで実行されているバスの初期化を多重に行ったりすることはありません。ただしRVOはC++の仕様では保証されておらず、念のためMWXライブラリ中ではコピー、代入演算子の削除、moveコンストラクタを定義しています(moveコンストラクタが評価される可能性はないと考えられますが)。
if
節の中の wrt
は、まずコンストラクタにより初期化され同時に通信開始します。通信開始でエラーがなければ、条件判定時のbool演算子がtrue
を返し、if
節スコープ内の処理が行われます。スコープを脱出するとデストラクタにより、2線シリアルバスの利用終了処理を行います。通信の相手先がない場合は false
が戻り、wrt
オブジェクトは破棄されます。
Wire
, SPI
特有の定義としてoperator << (int)
の定義をオーバーライドしています。ストリームのデフォルトの振る舞いは、数値を文字列に変換して出力するのですが、Wire
やSPI
で数値文字列をバスに書き込むことは稀で、反対に設定値など数値型のリテラルをそのまま入力したいことが多いのですが、数値型リテラルは多くの場合int
型として評価されるため、この振る舞いを変更します。
writer& operator << (int v) {
_wire.write(uint8_t(v & 0xFF));
return *this;
}
ここではint
型の値については8bitに切り詰めて、その値を出力しています。
1.1.2 - 定義
ライブラリ中で共通的に読み込まれる定義について、定義内容を引用します。
mwx_common.h
##include <cstdint> // for type name
typedef char char_t;
typedef uint8_t byte;
typedef uint8_t boolean;
##ifndef NULL
##define NULL nullptr
##endif
1.1.3 - クラスオブジェクト
クラスオブジェクトは、MWXライブラリであらかじめ定義されたオブジェクトで、TWENETを取り扱うthe_twelite
、ペリフェラルの利用のためのオブジェクトが定義されています。
各オブジェクトは.setup()
, .begin()
メソッドの呼び出しを行って初期化する必要があります。
(UART0
を利用するSerial
オブジェクトのみ初期化は必要ありません)
1.1.3.1 - the_twelite
the_twelite
オブジェクトは、TWENETの利用手続きをまとめたもので、無線の基本設定やスリープ等の手続きなど無線マイコンを操作するための手続きが含まれます。概要
the_twelite
はsetup()
関数内で設定と開始the_twelite.begin()
を行います。setup()
以外では設定は行えません。
void setup() {
...
the_twelite
<< TWENET::appid(APP_ID)
<< TWENET::channel(CHANNEL)
<< TWENET::rx_when_idle();
...
the_twelite.begin();
}
上記の例では、アプリケーションIDの設定、通信チャネルの設定、受信回路の設定を行っています。
様々な手続きが含まれます。
// シリアル番号を得る
uint32_t u32hwser = the_twelite.get_hw_serial();
// チャネルを 11 に設定する
the_twelite.change_channel(11);
// 1秒のスリープを行う
the_twelite.sleep(1000);
// リセットを行う
the_twelite.reset_system();
また無線ネットワークを取り扱うクラスやボード対応をまとめたクラス、ユーザ記述のイベントドリブン処理を行うクラスを登録できるようになっています。このクラスを登録することにより、専用化した機能を手軽に利用できるようになります。これらのクラスを本解説中では「ビヘイビア」と呼称します。
void setup() {
/*** SETUP section */
// use PAL_AMB board support.
auto&& brd = the_twelite.board.use<PAL_AMB>();
...
// Register Network
auto&& nwk = the_twelite.network.use<NWK_SIMPLE>();
nwk << NWK_SIMPLE::logical_id(u8ID);
上記の例では環境センサーパル<PAL_AMB>
と、シンプル中継ネットワーク<NWK_SIMPLE>
の2種類を登録しています。これらを登録することにより環境センサーパル上のセンサーなどハードウェアを簡易に取り扱うことが出来ます。また煩雑な無線パケットの取り扱いについて中継の処理や重複で届いたパケットの自動破棄などの機能を暗黙に持たせることが出来ます。
メソッド
MWXライブラリには、ここで紹介したメソッド以外にも定義されています。
アクト記述には直接関係ないもの、設定しても有効に機能しないもの、内部的に使用されているものが含まれます。
<<
演算子 (設定)
オブジェクトthe_twelite
の初期設定を行うために<<
演算子を用います。
以下に挙げる設定用のクラスオブジェクトを入力とし、設定をしなければデフォルト値が適用されます。
TWENET::appid(uint32_t id)
パラメータid
に指定したアプリケーションIDを設定します。これは必須指定です。
設定の読み出しは uint32_t the_twelite.get_appid()
で行います。
TWENET::channel(uint8_t ch)
パラメータch
に指定したチャネル番号(11
..26
)を設定します。
設定の読み出しはuint8_t the_twelite.get_channel()
で行います。
TWENET::tx_power(uint8_t pw)
パラメータpw
に指定した出力設定を(0
..3
)を設定します。デフォルトは(3:出力減衰無し)です。
設定値の読み出しはuint8_t the_twelite.get_tx_power()
で行います。
TWENET::rx_when_idle(uint8_t bEnable)
パラメータbEnable
が1
であれば常に受信回路を動作させ、他からの無線パケットを受信できるようになります。デフォルトは0
で、もっぱら送信専用となります。
設定値の読み出しはuint8_t the_twelite.get_rx_when_idle()
で行います。
TWENET::chmgr(uint8_t ch1 = 18, uint8_t ch2 = 0, uint8_t ch3 = 0)
チャネルマネージャを有効にします。チャネルを複数指定すると複数チャネルでの送受信を行います。ch2
,ch3
に0を指定すると、その指定は無効になります。
STG_STD
インタラクティブモードの設定値を反映します。
auto&& set = the_twelite.settings.use<STG_STD>();
...
set.reload(); // 設定値をロード
the_twelite << set; // インタラクティブモードの設定値を反映
反映される項目は以下です。
app_id
channel
tx_power
- MAC ack 使用時の再送回数
begin()
void begin()
事前に設定(<<
演算子参照)や、ビヘイビアの登録を済ませた後に実行します。通常はsetup()
関数内の一番最後に記述します。
the_twelite
設定完了- ビヘイビアの初期化
setup()
関数が終了した後にも実行されます。多くの処理はsetup()
が終了した後に実行するようになっているため、ここでは初期化以外の処理を行わないようにしてください。例
void setup() {
// use PAL_AMB board support.
auto&& brd = the_twelite.board.use<PAL_AMB>();
// settings
the_twelite
<< TWENET::appid(APP_ID)
<< TWENET::channel(CHANNEL)
<< TWENET::rx_when_idle();
// Register Network
auto&& nwk = the_twelite.network.use<NWK_SIMPLE>();
nwk << NWK_SIMPLE::logical_id(u8ID);
// somo others
// begin the TWENET!
the_twelite.begin();
}
change_channel()
inline bool change_channel(uint8_t u8Channel)
チャネル設定を変更します。失敗時にはチャネルは変更されずfalse
を戻します。
get_channel_phys()
uint8_t get_channel_phys()
現在設定中のチャネル番号(11..26)を取得する。MAC層のAPIより取得します。
get_hw_serial()
inline uint32_t get_hw_serial()
モジュールのシリアル番号を取得します。
sleep()
inline void sleep(
uint32_t u32Periodms,
bool_t bPeriodic = true,
bool_t bRamOff = false,
uint8_t u8Device = TWENET::SLEEP_WAKETIMER_PRIMARY)
モジュールをスリープさせる。
パラメータ | 解説 |
---|---|
u32Periodms | スリープ時間[ms] |
bPeriodic | 前回の起床時間をもとに次の起床時間を再計算する。 ※次の起床タイミングが迫っているなどの理由で、現在のタイミングからになる場合もあります。 |
bRamoff | true に設定すると、RAMを保持しないスリープになる(起床後はwakeup() ではなくsetup() から再初期化する必要がある) |
u8Device | スリープに用いるウェイクアップタイマーの指定。TWENET::SLEEP_WAKETIMER_PRIMARY または TWENET::SLEEP_WAKETIMER_SECONDARY を指定する。 |
on_sleep()
メソッドが呼び出され、スリープ前の手続きを行います。スリープ復帰後は反対に on_wakeup()
メソッドにより復帰処理が行われます。is_wokeup_by_dio()
bool is_wokeup_by_dio(uint8_t port)
スリープからの復帰要因が指定したディジタルピンである場合にtrue
を返します。
is_wokeup_by_wktimer()
bool is_wokeup_by_wktimer()
スリープからの復帰要因がウェイクアップタイマーである場合にtrue
を返します。
reset_system()
inline void reset_system()
システムをリセットします。リセット後はsetup()
からの処理となります。
stop_watchdog()
inline void stop_watchdog()
ウォッチドッグタイマーを停止します。長時間のポーリング待ちを行うような場合はタイマーを停止します。
restart_watchdog()
inline void restart_watchdog()
ウォッチドッグタイマーを再開します。
ビヘイビア
twe_twelite
には3つのビヘイビアを登録でき、これらを格納する以下のクラスオブジェクトを定義されています。
network
: ネットワークを実装するビヘイビアです。通常は<NWK_SIMPLE>
を登録します。network2
: ネットワークを実装するビヘイビアです。最初にnetwork
でペイロードのデータ構造などの判定により受理しなかったパケットを、別のネットワーク ビヘイビアで処理させたい場合に使用します。(参考: NWK_LAYERED と NWK_SIMPLEの併用)board
: ボード対応のビヘイビアです。ボード上の各デバイス利用手続きが付加されます。app
: ユーザアプリケーションを記述したビヘイビアです。割り込みやイベント記述、ステートマシンによる状態遷移によるふるまいの記述が可能です。また複数のアプリケーション記述を定義しておいて、起動時に全く振る舞いの違うアプリケーションを選択する記述が容易に行えます。settings
: 設定(インタラクティブモード)を実行するためのビヘイビアです。<SET_STD>
を登録します。
use<B>()
// 例
auto&& brd = the_twelite.board.use<PAL_AMB>();
ビヘイビア<B>
を登録します。登録はsetup()
内で行います。戻り値は登録したビヘイビアに対応するオブジェクトの参照です。
登録後は登録時と同じ書式でオブジェクトの取得を行います。
グローバル変数としてビヘイビアのオブジェクトを宣言することを想定していません。利用都度use<B>()
を用いてください。
void loop() {
auto&& nwk = the_twelite.network.use<NWK_SIMPLE>();
}
ただし、グローバル変数にオブジェクトのポインタを定義して以下のように記述することは可能です。(MWXライブラリでは原則としてポインタ型の利用を最小限にとどめ参照型を利用する方針ですので、下記のような記述は推奨しません)
NWK_SIMPLE *pNwk = nullptr;
setup() {
auto&& nwk = the_twelite.network.use<NWK_SIMPLE>();
pNwk = &nwk;
}
void transmit() {
if (auto&& pkt = pNwk->prepare_tx_packet()) {
...
}
}
クラスオブジェクト
the_twelite
には上述のboard
, network
, app
の3つのクラスオブジェクトが定義されていますが他に以下が定義されています。
tx_status
送信完了状態を通知する。
transmit_complete()
コールバックで管理します。is_complete()
bool is_complete(uint8_t cbid)
指定したIDのパケットが送信完了したときにtrue
を返す。
is_success()
bool is_success(uint8_t cbid)
指定したIDのパケットが送信完了し、かつ送信成功したときにtrue
を返す。
receiver
受信パケットを取得する。
the_twelite.receiver
は推奨されません。
従来loop()
内での記述を意図して the_twelite.receiver
による処理を行っていましたが、キューによる遅延処理である点で原理的に取りこぼしが発生し、また記述も煩雑になりがちである点から on_rx_packet()
を追加しました。
- イベントドリブンのビヘイビアの記述では
receive()
コールバックで取得します。
read()
メソッドで得られる受信パケットデータは、続くパケットが受信処理時に上書きされる設計となっています。available
直後に読み出してなにか短い処理をする場合は問題になることはありませんが、原則として読み出し→アプリケーションが使うため必要なデータのコピー→loop()
の終了を速やかに行います。例えばloop()
中で長いdelay()
を行うと受信パケットの取りこぼしなどが発生します。available()
bool available()
まだ読み出していない受信パケットが存在する場合にtrue
を返す。
read()
packet_rx& read()
パケットを読み出します。
1.1.3.2 - Analogue
定数
ピンの定義
定数 | 種別 | 標準アプリでのピン名 |
---|---|---|
uint8_t PIN_ANALOGUE::A1 = 0 | ADC1ピン | AI1 |
uint8_t PIN_ANALOGUE::A2 = 1 | ADC2ピン | AI3 |
uint8_t PIN_ANALOGUE::A3 = 2``uint8_t PIN_ANALOGUE::D0 = 2 | ADC3ピン (DIO0) *1 | AI2 |
uint8_t PIN_ANALOGUE::A4 = 3``uint8_t PIN_ANALOGUE::D1 = 3 | ADC4ピン (DIO1) *1 | AI4 |
uint8_t PIN_ANALOGUE::VCC = 4 | Vcc 電源電圧 |
*1 ディジタル、アナログ共用のADC2/ADC3ピンは利用手続きと利用制限があります。
ADC開始前に利用するピンをプルアップ無しとします。これを実行しないと常にプルアップ電圧をADCで観察することになります。
pinMode(PIN_DIGITAL::DIO0, PIN_MODE::INPUT);
pinMode(PIN_DIGITAL::DIO1, PIN_MODE::INPUT);
通常の回路構成では、スリープ時には電流リークが発生します。 ソフトウェアの記述のみで回避することは出来ません。
スリープ時の電流リーク回避には、アナログ回路部分のGNDをFETスイッチなどで切り離し、スリープ中はフローティング状態にします。またスリープ前には入力かつプルアップ状態にピンを設定します。
メソッド
setup()
void setup(
bool bWaitInit = false,
uint8_t kick_ev = E_AHI_DEVICE_TICK_TIMER,
void (*fp_on_finish)() = nullptr)
ADCの初期化を行います。setup()では、半導体内部のレギュレータの始動、周期実行するためのタイマーデバイスの指定、指定チャネルすべてのADCが終了したときに呼び出されるコールバック関数の指定します。
パラメータ | 解説 |
---|---|
bWaitInit | true を指定すると、半導体内部のレギュレータの初期化を待つ。 |
kick_ev | 周期実行に指定するタイマーデバイスを指定する。指定可能なデバイスは、以下の5種類で、初回以外は割り込みハンドラ内でADが開始される。E_AHI_DEVICE_TICK_TIMER (TickTimer)``E_AHI_DEVICE_TIMER0 .. 4 (Timer0 .. 4) |
fp_on_finish | 指定されたポートすべてのADCが終了後に、割り込みハンドラ内から呼び出されるコールバック関数。ADC計測値をFIFOキューなどに別途格納したい場合に利用する。 |
begin()
void begin(uint8_t bmPorts, uint8_t capt_tick = 1)
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ごとの処理になります。
void begin()
デフォルトのADCピン(PIN_ANALOGUE::A1
,PIN_ANALOGUE::A2
)を指定してADC処理を開始します。end()
では中断したADC処理を再開します。
end()
void end()
ADC処理を終了し、半導体内部のレギュレータを停止します。
available()
inline bool available()
ADCの値が取得後にtrue
になります。本関数により確認した後は次のADC完了まではfalse
です。
read()
, read_raw()
inline int16_t read(uint8_t s)
inline int16_t read_raw(uint8_t s)
ADC値を読み出します。パラメータには読み出したいADCピンを指定します。read()
はmVに変換した読み値、read_raw()
はADCの値(0..1023)を戻します。
read()
で読み出すことを推奨します。read_raw()
の値からmVに変換するには、特別な変換式を適用する必要があるためです。loop()
の処理中であっても値が更新されるためです。ADC割り込みハンドラ
ADCの割り込みハンドラはsetup()
の呼び出し時にperiph_analogue::ADC_handler()
に設定されます。
半導体のペリフェラルライブラリで別途ハンドラを指定すると正常に動作しなくなります。
スリープ時の振る舞い
ADCがbegin()
により周期実行状態であれば、スリープ復帰後もADC処理を再開します。
スリープからの復帰時は setup(true)
を自動的に呼び出すため、E_AHI_DEVICE_TICK_TIMER
以外のタイマを使用する際などには wakeup()
内で明示的に再初期化してください。
例えば、次のコードを挿入すると、復帰時にE_AHI_DEVICE_TIMER0
を指定して再初期化します。
void wakeup()
{
Analogue.setup(true, E_AHI_DEVICE_TIMER0, adc_handler);
Analogue.begin(pack_bits(PIN_ANALOGUE::A1), 1);
}
1.1.3.3 - Buttons
メソッド
setup()
void setup(uint8_t max_history);
パラメータのmax_history
は、begin()
で設定可能な参照回数の最大値です。ここではメモリーの確保と初期化を行います。
begin()
void begin(uint32_t bmPortMask,
uint8_t u8HistoryCount,
uint16_t tick_delta);
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
のイベントハンドラで行っています。割り込みハンドラではないので、処理等の遅延の影響を受けますが、メカ式ボタン等のチャタリング抑制には十分です。
end()
void end()
Buttons
の動作を終了します。
available()
inline bool available()
変化が検出されたときにtrue
を返します。read()
を実行するとクリアされます。
read()
bool read(uint32_t& u32port, uint32_t& u32changed)
availableになったとき呼び出します。u32port
は現在の入力DIOのビットマップ、u32changed
は変化が検出されたDIOのビットマップです。
Buttonsが動作していない場合はfalse
を返します。
動作について
初回の値確定
Buttonsが動作を開始した時点では、DIOの入力状態は未確定です。値が確定した時点でavailableになります。このときread()
で読み出すビットマップのMSB(bit31)が1にセットされます。
動作確定を要するため、入力値が定常的に変化するポートを監視する目的では利用できません。
スリープ
スリープ前にButtonsが稼働状態であれば、復帰後に再開します。再開後、初回確定を行います。
1.1.3.4 - EEPROM
TWELITE 無線マイコンの内蔵EEPROMに対して読み書きを実行します。
内蔵EEPROMはアドレス0x000~0xEFFまでの3480バイトが利用可能です。
先頭部分は設定(インタラクティブモード)に利用されるため、併用する場合は後半のアドレスの利用を推奨します。設定(インタラクティブモード)でどの程度の領域を消費するかは、その実装に依存します。最小限度の設定であっても先頭から256バイトまでは利用されるため、それ以降の利用を推奨します。
メソッド
read()
uint8_t read(uint16_t address)
EEPROMからaddress
に対応するデータを読み出します。
write()
void write(uint16_t address, uint8_t value)
EEPROMからaddress
に対してvalue
を書き込みます。
update()
void update(uint16_t address, uint8_t value)
write()
と同じく書き込みを行いますが、先にaddress
にあるデータを読み出してvalue
と違う場合のみ、書き込みを行います。EEPROMの書き換え寿命を考慮し、書換回数を減らしたいときに用います。
get_stream_helper()
auto&& get_stream_helper()
// 戻り値型は長くなるためauto&&と省略しています。
後述のmwx::stream
を用いた読み書きを行うために、ヘルパーオブジェクトを取得します。
mwx::stream
インタフェースを用いた入出力
stream_helper
ヘルパーオブジェクトを経由して、mwx::stream
による演算子やメソッドを用います。mwx::stream
を用いるとuint16_t
やuint32_t
型といった整数型の読み書き、uint8_t
の固定長配列型の読み書き、format()
オブジェクトによる書式整形などが可能になります。
auto&& strm = EEPROM.get_stream_helper();
// ヘルパーオブジェクトの型名は長くなるためauto&&により解決しています。
このオブジェクトに対して<<
演算子などmwx::stream
で定義されたインタフェースを利用できます。
strm.seek(1024); // 1024バイト目に移動
strm << format("%08x", 12345678); // 12345678を16進数の8文字で記録
strm << uint32_t(0x12ab34cd); // 0x12ab34cd の4バイトを記録
uint8_t msg_hello[16] = "HELLO WORLD!";
strm << msg_hello; // バイト列 "HELLO WORLD!" を記録(終端なし)
// 結果
// 0400: 30 30 62 63 36 31 34 65 12 ab 34 cd 48 45 4c 4c
// 0 0 b c 6 1 4 e 0x12ab34cd H E L L
// 0410: 4f 20 57 4f 52 4c 44 21 00 00 00 00 ff ff ff ff
// O SP W O R L D !
.seek()
を用いてEEPROMのアドレスを1024に移動しています。
上記では8バイト文字列(00bc614e
)、4バイト整数(0x12ab34cd
)、16バイトバイト列(HELLO WORLD!...
)、1バイト終端文字を書き込んでいます。
strm.seek(1024);
uint8_t msg1[8];
strm >> msg1;
Serial << crlf << "MSG1=" << msg1;
// MSG1=00bc614e
uint32_t var1;
strm >> var1;
Serial << crlf << "VAR1=" << format("%08x", var1);
// VAR1=12ab34cd
uint8_t msg2[16]; // "HELLO WORLD!"の文字数
strm >> msg2;
Serial << crlf << "MSG2=" << msg2;
// MSG2=HELLO WORLD!
.seek()
を用いてEEPROMのアドレスを1024に移動しています。
先ほど書き出したデータ列を読み出します。順番に8バイト文字、4バイト整数、16バイト文字列を>>
演算子を用いて読み出します。
1.1.3.5 - PulseCounter
パルスカウンターは2系統あります。PC0はPulseCounter0
, PC1はPulseCounter1
に割り当てられます。また**PulseCounter
はPulseCounter1
**の別名です。
メソッド
begin()
void begin(uint16_t refct = 0,
E_PIN_INT_MODE edge = PIN_INT_MODE::FALLING,
uint8_t debounce = 0)
オブジェクトを初期化し、計数を開始します。1番目のパラメータrefct
は割り込みやavailable判定の基準となるカウント数です。この数を超えたときにアプリケーションに報告されます。またrefct
には0を指定することもできます。この場合は、スリープ起床要因にはなりません。
2番目のパラメータedge
は割り込みが立ち会がり(PIN_INT_MODE::RISING
)か立下り(PIN_INT_MODE::FALLING
)を指定します。
3番目のdebounce
は、0,1,2,3の値をとります。1,2,3の設定はノイズの影響を小さくするため値の変化の検出に連続した同じ値を要する設定です。
設定 | 連続サンプル数 | 最大検出周波数 |
---|---|---|
0 | - | 100Khz |
1 | 2 | 3.7Khz |
2 | 4 | 2.2Khz |
3 | 8 | 1.2Khz |
end()
void end()
検出を中止します。
available()
inline bool available()
指定カウント数(begin()
のrefct
)が0の場合は、カウントが1以上でtrue
を返します。
指定カウント数(begin()
のrefct
)が1以上の場合は、検出回数が指定カウント数を超えた場合にtrue
となります。
read()
uint16_t read()
カウント値を読み出します。読み出し後にカウント値を0にリセットします。
1.1.3.6 - Serial
mwx::stream
を実装し TWELITE の UART0 で入出力します。Serial
オブジェクトはシステム起動時に UART0, 115200 bps で初期化され、ライブラリ内で初期化処理が行われます。ユーザコード上は、setup()
から利用できます。Serial1
オブジェクトは、ライブラリ内で用意されていますが、初期化処理は行っていません。UART1を有効化するためには、必要な初期化手続きSerial1.setup(), Serial1.begin()
を行ってください。
setup(), wakeup()
やスリープ直前の flush
処理で、出力が不安定になる場合があります。setup()
void setup(uint16_t buf_tx, uint16_t buf_rx)
オブジェクトの初期化を行う。
- TX/RX用のFIFOバッファのメモリ確保
- TWE_tsFILE 構造体のメモリ確保
Serial
(UART0) は ライブラリ内で setup()
の呼び出しが自動で行われます。ユーザによる呼び出しを行う必要はありません。
また、Serial
(UART0) のバッファサイズは、コンパイル時に決定されます。マクロ MWX_SER_TX_BUFF
(未指定時は 768), MWX_SER_RX_BUFF
(未指定時 256) により変更できます。
パラメータ | 解説 |
---|---|
buf_tx | TX用のFIFOバッファサイズ |
buf_rx | RX用のFIFOバッファサイズ |
begin()
void begin(unsigned long speed = 115200, uint8_t config = 0x06)
ハードウェアの初期化を行う。
Serial
(UART0) は ライブラリ内で begin()
の呼び出しが自動で行われます。ユーザによる呼び出しを行う必要はありません。パラメータ | 解説 |
---|---|
speed | UART のボーレートを指定する。 |
config | serial_jen::E_CONF::PORT_ALT ビットを指定したときは、UART1を |
指定したボーレートの下2桁の数値は0に丸めて処理します。またハードウェアの制限により指定したボーレートより誤差が生じます。
ボーレートの計算には除算が発生し計算時間がかかる場合があります。9600,38400,115200を指定する場合は、除算をせずに計算を行います。処理の詳細は、constexpr uint16_t _serial_get_hect_baud(uint32_t baud)
を参照してください。
end()
(未実装)ハードウェアの使用を停止する。
get_tsFile()
TWE_tsFILE* get_tsFile();
Cライブラリで利用する TWE_tsFILE*
形式での構造体を得る。
_sSerial
構造体が定義されています。1.1.3.7 - SerialParser
初期化時(begin()
)にヒープから内部で使用するバッファ領域を確保するmwx::serial_parser<mwx::alloc_heap<uint8_t>>
型として定義されています。
詳細はクラス serparser
を参照してください。
1.1.3.8 - SPI
注意事項
定数
定数 | 意味 |
---|---|
const uint8_t SPI_CONF::MSBFIRST | MSB を先頭ビットにする |
const uint8_t SPI_CONF::LSBFIRST | LSB を先頭ビットにする |
const uint8_t SPI_CONF::SPI_MODE0 | SPI MODE 0 に設定する |
const uint8_t SPI_CONF::SPI_MODE1 | SPI MODE 1 に設定する |
const uint8_t SPI_CONF::SPI_MODE2 | SPI MODE 2 に設定する |
const uint8_t SPI_CONF::SPI_MODE3 | SPI MODE 3 に設定する |
初期化と終了
SPIバスの利用手続きはbegin()
メソッドによります。
begin()
void begin(uint8_t slave_select, SPISettings settings)
SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
ハードウェアの初期化を行います。
パラメータ | 解説 |
---|---|
slave_select | 対象のペリフェラルのセレクトピンを指定する。0 : DIO19``1 : DIO0 (DIO 19 は予約されます)``2 : DIO1 (DIO 0,19 は予約されます) |
settings | SPIのバス設定を指定します。clock [hz]でSPIバスの周波数を指定します。指定した周波数に近いディバイザが選択されます。16Mhzまたは16Mhzを偶数で割った値になります。bitOrder はSPI_CONF::MSBFIRST かSPI_CONF::LSBFIRST を指定します。dataMode はSPI_CONF::SPIMODE0..3 を指定します。 |
例
void setup() {
...
SPI.begin(0, SPISettings(2000000, SPI_CONF::MSBFIRST, SPI_CONF::SPI_MODE3));
...
}
void wakeip() {
...
SPI.begin(0, SPISettings(2000000, SPI_CONF::MSBFIRST, SPI_CONF::SPI_MODE3));
...
}
end()
void end()
SPIのハードウェアの利用を終了します。
読み書き
読み書きの手続きは、以下の2種類あります。いずれかを選択して利用します。
- メンバ関数版 (以下のメンバ関数を用いた入出力)
beginTransaction(), endTransaction(), transfer(), transfer16(), transfer32()
- ヘルパークラス版(stream機能が使用可能)
transceiver
使用例
次のサンプルコードは、Analog Devices の温度センサ ADT7310 から1秒おきに温度を取得し、シリアルポートへ出力します。
#include <TWELITE>
#include <SM_SIMPLE>
enum class STATE : uint8_t {
INTERACTIVE = 255,
INIT = 0,
INIT_WAIT,
SENSOR,
LOOP_WAIT
};
SM_SIMPLE<STATE> step;
struct SensorData {
uint8_t highByte;
uint8_t lowByte;
uint16_t rawValue;
int32_t tempValue16th;
div_result_i32 temperature;
} sensorData;
void setup() {
step.setup(); // 状態マシンの初期化
}
void loop() {
do {
switch (step.state()) {
case STATE::INIT: // 初期状態
SPI.begin(0 /* DIO19をチップセレクトとして使用 */
, { 400000UL /* クロック周波数 */
, SPI_CONF::MSBFIRST
, SPI_CONF::SPI_MODE3
}
);
// ソフトウェアリセット
SPI.beginTransaction();
for (int i = 0; i < 4; i++) {
SPI.transfer(0xFF);
}
SPI.endTransaction();
// Continuous Readモード開始
SPI.beginTransaction();
SPI.transfer(0x54);
SPI.endTransaction();
step.set_timeout(300); // 待機時間の設定
step.next(STATE::INIT_WAIT);
break;
case STATE::INIT_WAIT: // 待機
if (step.is_timeout()) {
step.next(STATE::SENSOR);
}
break;
case STATE::SENSOR: // センサーデータの読み取り
SPI.beginTransaction();
sensorData.highByte = SPI.transfer(0x00); // ダミーデータを送信してクロック信号を生成
sensorData.lowByte = SPI.transfer(0x00); // ダミーデータを送信してクロック信号を生成
SPI.endTransaction();
sensorData.rawValue = (((uint16_t)sensorData.highByte << 8) | sensorData.lowByte) >> 3;
if (sensorData.rawValue & 0x1000) {
sensorData.tempValue16th = int32_t(sensorData.rawValue) - 0x2000;
} else {
sensorData.tempValue16th = sensorData.rawValue;
}
// div100()を使用して温度計算
sensorData.temperature = div100((sensorData.tempValue16th * 100) / 16);
// 結果をシリアル出力
Serial << crlf << sensorData.temperature.format() << "°C";
step.set_timeout(1000); // 次のキャプチャまで待機
step.next(STATE::LOOP_WAIT);
break;
case STATE::LOOP_WAIT: // 待機
if (step.is_timeout()) {
step.next(STATE::SENSOR);
}
break;
default:
break;
}
} while (step.b_more_loop());
}
ここでは、メンバ関数版のインタフェースを利用しています。
1.1.3.8.1 - SPI (メンバ関数版)
begin()
メソッドによりハードウェアの初期化を行った後、beginTransaction()
によりバスの読み書きができるようになります。beginTransaction()
を実行するとSPIのセレクトピンが選択されます。読み書きはtransfer()
関数を用います。SPIは読み出しと書き込みを同時に実行します。beginTransaction()
void beginTransaction()
void beginTransaction(SPISettings settings)
バスの利用開始を行います。SPIのセレクトピンをセットします。
settings
パラメータを与えて呼び出した場合は、バスの設定を行います。
endTransaction()
void endTransaction()
バスの利用を終了します。SPIのセレクトピンを解除します。
transfer()
, transfer16()
, transfer32()
inline uint8_t transfer(uint8_t data)
inline uint16_t transfer16(uint16_t data)
inline uint32_t transfer32(uint32_t data)
バスの読み書きを行います。trasnfer()
は8bit、transfer16()
は16bit、transfer32()
は32bitの転送を行います。
1.1.3.8.2 - SPI (ヘルパークラス版)
transceiver
を生成することでバスの利用を開始し、オブジェクトを破棄することでバスの利用を終了します。if文の判定式内でオブジェクトの生成を行うことで、オブジェクトの有効期間はif節内のスコープに限定され、if節を抜けた時点でオブジェクトは破棄され、その時点でバスの利用終了の手続きを行います。
uint8_t c;
if (auto&& trs = SPI.get_rwer()) { // オブジェクトの生成とデバイスの通信判定
// このスコープ(波かっこ)内が trs の有効期間。
trs << 0x00; // 0x00 を mwx::stream インタフェースで書き出し
trs >> c; // 読み出したデータをcに格納。
}
// if 節を抜けるところで wrt は破棄され、バスの利用終了
また、読み書きオブジェクトは、mwx::stream
インタフェースを実装しているため<<
演算子などを利用できます。
- バスの利用開始と終了をオブジェクトの有効期間と一致させることで、ソースコードの見通しを良くし、また終了手続きの記述漏れなどを防ぎます
mwx::stream
インタフェースによる読み書き手続きを統一します
読み書き
読み込み処理とその終了手続きをスコープ内 if() { ... }
で行うためのヘルパークラスを用いた読み込み方法。
inline uint8_t _spi_single_op(uint8_t cmd, uint8_t arg) {
uint8_t d0, d1;
if (auto&& x = SPI.get_rwer()) {
d0 = x.transfer(cmd); (void)d0;
d1 = x.transfer(arg);
// (x << (cmd)) >> d0;
// (x << (arg)) >> d1;
}
return d1;
}
上記では get_rwer()
メソッドにより生成された x
オブジェクトを用いて1バイトずつ読み書きを行っています。
if(...)
内でx
オブジェクトを生成します。同時にSPIバスのセレクトピンをセットします。(型は、型推論によるユニバーサル参照auto&&
で解決しています。)- 生成した
x
オブジェクトにはoperator bool ()
が定義されており、判定式の評価として利用される。SPIバスの場合は常にtrue
となる。 x
オブジェクトにはuint8_t transfer(uint8_t)
メソッドが定義されていて、これを呼び出すことでSPIに対して8bitの読み書き転送を行。if() { ... }
スコープの末尾でx
のデストラクタが呼び出され、SPIバスのセレクトピンを解除します。
get_rwer()
periph_spi::transceiver get_rwer()
SPIバスの読み書きに用いるワーカーオブジェクトを取得します。
ワーカーオブジェクト
transfer()
, transfer16()
, transfer32()
uint8_t transfer(uint8_t val)
uint16_t transfer16(uint16_t val)
uint32_t transfer32(uint32_t val)
それぞれ8bit,16bit,32bitの転送を行い、読み取り結果を書き込んだデータ幅と同じデータ幅で返す。
<<
演算子
operator << (int c)
operator << (uint8_t c)
operator << (uint16_t c)
operator << (uint32_t c)
int
型,uint8_t
型は8bitの転送を行います。
uint16_t
型、uint32_t
型は、それぞれ16bitの転送、32bitの転送を行います。
転送結果は最大16バイトの内部FIFOキューに格納され >>
演算子により読み出します。バッファが大きくないので、転送都度読み出すことを想定します。
>>
演算子
operator >> (uint8_t& c)
operator >> (uint16_t& c)
operator >> (uint32_t& c)
null_stream(size_t i = 1)
operator >> (null_stream&& p)
直前の転送と同じデータ幅の変数を指定します。
読み出した結果が不要の場合はnull_stream()
オブジェクトを使用します。i
で指定したデータバイト分だけ読み飛ばします。
1.1.3.9 - TickTimer
TickTimer
はTWENETの内部制御用に利用され、暗黙に実行されています。タイマーの周期は1msです。loop()
中でTickTimerイベントにより1msごとの処理を記述する目的でavailable()
メソッドのみを定義しています。必ず1ms刻みでavailableになる訳ではない点に注意してください。
ユーザプログラムの記述内容や、システム内部の割り込み処理などが要因で、大きな遅延が発生することもあり、イベントが飛ばされるような場合もあります。
void loop() {
if (TickTimer.available()) {
if ((millis() & 0x3FF) == 0) { // これは処理されない場合がある
Serial << '*';
}
}
}
メソッド
available()
inline bool available()
TickTimer
割り込み発生後にセットされ、その直後のloop()
でtrue
になります。loop()
終了後にクリアされます。
1.1.3.10 - Timer0 .. 4
組み込みオブジェクト名は Timer0..4
ですが、このページでは TimerX
と記載します。
メソッド
setup()
void setup()
タイマーを初期化します。この呼び出しにより必要なメモリ領域の確保を行います。
begin()
void begin(uint16_t u16Hz, bool b_sw_int = true, bool b_pwm_out = false)
タイマーを開始します。1番目のパラメータは、タイマーの周期でHzで指定します。2番目のパラメータをtrue
にするとソフトウェア割り込みが有効になります。3番目のパラメータをtrue
にするとPWM出力を有効にします。
change_hz()
で周波数を変更することが出来ます。change_hz()
ではbegin()
の指定より細かい指定が可能です。
change_duty()
でPWM出力のデューティー比を変更できます。
割り込みハンドラの処理を記述するには、アプリケーションビヘイビアの定義が必要です。
end()
void end()
タイマーの動作を停止します。
available()
inline bool available()
タイマー割り込みが発生した直後のloop()
でtrue
になり、loop()
が終了すればfalse
になります。
change_duty()
void change_duty(uint16_t duty, uint16_t duty_max = 1024)
デューティー比の設定です。1番目のパラメータにデューティ比を指定します(小さい値を指定すると波形の平均はGNDレベルに近づき、大きい値を指定するとVccレベルに近づく)。2番目のパラメータはデューティ比の最大値を指定します。
duty_max
は1024,4096,16384
のいずれかの指定を推奨します。
内部でのカウント値の計算に除算が発生しますが、これら3つに限りビットシフトによる演算を行っていますが、これ以外の値では計算量の大きい除算処理が実行されます。
change_hz()
void change_hz(uint16_t hz, uint16_t mil = 0)
タイマーの周波数を設定します。2番目のパラメータは周波数の小数点3桁分の値を整数で指定します。例えば 10.4 Hz としたい場合は hz=10, mil=400
と指定します。
1.1.3.11 - Wire
定義
別名定義
using TwoWire = mwx::periph_twowire<MWX_TWOWIRE_RCVBUFF>;
mwx::periph_wire<MWX_TWOWIRE_RCVBUFF>
はTwoWire
として参照可能です。
型定義
以下の定義型で引数や戻り値の型を記載します。
typedef uint8_t size_type;
typedef uint8_t value_type;
注意事項
write(), writer::operator() ()
には、本解説以外にもいくつか引数が定義されてます。
- 固定配列型
uint8_t cmds[]={11,12};
...
Wire.write(cmds);
initializer_list<>
型Wire.write({11,12})
初期化と終了
Wire
インスタンスの生成
ライブラリ内でインスタンスの生成と必要な初期化は行われます。ユーザコードでは Wire.begin()
を呼び出すことで利用可能となります。
requestFrom()
メソッドを用いる場合、データを一時保管するための FIFO キューのサイズを指定できます。コンパイル時にマクロMWX_TWOWIRE_BUFF
に必要なバイト数を指定してコンパイルする。デフォルトは 32 バイトです。
例:
-DMWX_TWOWIRE_BUFF=16
begin()
void begin(
const size_type u8mode = WIRE_100KHZ,
bool b_portalt = false)
ハードウェアの初期化を行います。
パラメータ | 解説 |
---|---|
u8mode | バス周波数を指定する。デフォルトは100Khz(WIRE_CONF::WIRE_100KHZ )周波数は WIRE_CONF::WIRE_??KHZ で指定し?? には50 ,66 ,80 ,100 ,133 ,160 ,200 ,266 ,320 ,400 を指定できる。 |
b_portalt | ハードウェアのピン割り当てを変更する。 |
例
void setup() {
...
Wire.begin();
...
}
void wakeup() {
...
Wire.begin();
...
}
読み書き
読み書きの手続きは、以下の2種類あります。いずれかを選択して利用します。
requestFrom(), beginTransmission(), endTransmission(), write()
reader, writer
その他
プローブ(デバイスの存在判定)
bool probe(uint8_t address)
address
で指定したデバイスが応答するかを確認します。デバイスが存在する場合は true
が戻ります。
setClock()
void setClock(uint32_t speed)
本来はバス周波数を変更するための手続きですが、何も処理をしません。
1.1.3.11.1 - Wire (メンバ関数版)
メンバ関数を利用した方法は、抽象度が比較的低く、C言語ライブラリで提供されるような一般的なAPI体系に倣っています。二線シリアルバスの操作手続きがより直感的です。
ただしバスの利用の開始と終了を明示的に意識して記述する必要があります。
読み込み
requestFrom()
size_type requestFrom(
uint8_t u8address,
size_type length,
bool b_send_stop = true)
指定バイト数分を一括で読み出します。読みだした結果はキューに保存されるため、直後にキューが空になるまで .read()
メソッドを呼び出すようにしてください。
パラメータ | 解説 |
---|---|
u8address | 読み出し対象のI2Cアドレス |
length | 読み出しバイト数 |
b_send_stop=true | true の時、読み込み終了時にSTOP ビットを設定する。 |
戻り値型 size_type | 読み出したバイト数。 0 は読み出しの失敗。 |
コード例
int len = Wire.requestFrom(0x70, 6);
for (int i = 0; i < 6; i++) {
if (Wire.available()) {
au8data[i] = Wire.read();
Serial.print(buff[i], HEX);
}
}
// skip the rest (just in case)
// while (Wire.available()) Wire.read(); // normally, not necessary.
書き出し
書き出し処理は、beginTransmission()
を実行後、write()
メソッドにより行います。一連の書き出しが終了したら endTranmission()
を呼びます。
#define DEV_ADDR (0x70)
const uint8_t msg[2] =
{SHTC3_SOFT_RST_H, SHTC3_SOFT_RST_L};
Wire.beginTransmission(DEV_ADDR);
Wire.write(msg, sizeof(msg));
Wire.endTransmission();
beginTransmission()
void beginTransmission(uint8_t address)
書き出しの転送を初期化する。書き出し処理終了後、速やかに endTransmission()
を呼び出す。
パラメータ | 解説 |
---|---|
u8address | 書き出し対象のI2Cアドレス |
write(value)
size_type write(const value_type value)
1バイトの書き出しを行う。
パラメータ | 解説 |
---|---|
value | 書き込むバイト |
戻り値 size_type | 書き込んだバイト数。0 はエラー。 |
write(*value, quantity)
size_type write(
const value_type* value,
size_type quantity)
バイト列の書き出しを行います。
パラメータ | 解説 |
---|---|
*value | 書き込むバイト列 |
size_type | バイト数 |
戻り値 size_type | 書き込んだバイト数。0はエラー。 |
endTransmission()
uint8_t endTransmission(bool sendStop = true)
書き出しの終了処理を行います。
パラメータ | 解説 |
---|---|
sendStop = true | STOPビットを発行します。 |
戻り値 uint8_t | 0: 成功 4: 失敗 |
1.1.3.11.2 - Wire (ヘルパークラス版)
reader, writer
を生成することがバスの利用開始となり、オブジェクトを破棄するとバス利用の終了手続きを行います。if文の判定式内でオブジェクトの生成を行うことで、オブジェクトの有効期間はif節内のスコープに限定され、if節を抜けた時点でオブジェクトは破棄され、その時点でバスの利用終了の手続きを行います。
if (auto&& wrt = Wire.get_writer(...)) { // オブジェクトの生成とデバイスの通信判定
// このスコープ(波かっこ)内が wrt の有効期間。
wrt << 0x00; // 0x00 を mwx::stream インタフェースで書き出し
}
// if 節を抜けるところで wrt は破棄され、バスの利用終了
また読み書きオブジェクトはmwx::stream
インタフェースを実装しているため<<
演算子などを利用することができます。
- バスの利用開始と終了をオブジェクトの有効期間と一致させることで、ソースコードの見通しを良くし、また終了手続きの記述漏れなどを防ぐ
mwx::stream
インタフェースによる読み書き手続きの統一
読み込み
読み込み処理とその終了手続きをスコープ内 if() { ... }
で行うためのヘルパークラスを用いた読み込み方法です。
const uint8_t DEV_ADDR = 0x70;
uint8_t au8data[6];
if (auto&& rdr = Wire.get_reader(DEV_ADDR, 6)) {
for (auto&& c: au8data) {
c = rdr();
}
}
// same above
uint16_t u16temp, u16humd;
uint8_t u8temp_csum, u8humd_csum;
if (auto&& rdr = Wire.get_reader(SHTC3_ADDRESS, 6)) {
rdr >> u16temp;
rdr >> u8temp_csum;
rdr >> u16humd;
rdr >> u8humd_csum;
}
上記では get_readr()
メソッドにより生成された rdr
オブジェクトを用いて1バイトずつ読み出しします。 メソッドのパラメータには読み込みたい二線シリアル ID を指定します。
if(...)
内でrdr
オブジェクトを生成。(型は、型推論によるユニバーサル参照auto&&
で解決しています。)- 生成した
rdr
オブジェクトにはoperator bool ()
が定義されており、判定式の評価として利用される。指定された ID により通信が可能であればtrue
となる。 rdr
オブジェクトにはint operator () (void)
演算子が定義されていて、これを呼び出すことで2線シリアルバスから1バイトのデータを読み出す。読み込みに失敗したときは-1
が戻り、成功した場合は読み込んだバイト値が戻る。if() { ... }
スコープの末尾でrdr
のデストラクタが呼び出され、二線シリアルバスのSTOP
を行う。
get_reader(addr, read_count=0)
periphe_wire::reader
get_reader(uint8_t addr, uint8_t read_count = 0)
I2C 読み出しに用いるワーカーオブジェクトを取得します。
パラメータ | 解説 |
---|---|
addr | 読み込み用のI2Cアドレス |
read_count | 読み出しバイト数(この値を指定すると最後の転送で STOP ビットを発行する)。0を指定した場合は STOP ビットなしとなる(デバイスによっては動作するものもあります) |
書き出し (writer
)
書き出し処理とその終了手続きをスコープ内 if() { ... }
で行うためのヘルパークラスを用いた読み込み方法です。
const uint8_t DEV_ADDR = 0x70;
if (auto&& wrt = Wire.get_writer(DEV_ADDR)) {
wrt(SHTC3_TRIG_H);
wrt(SHTC3_TRIG_L);
}
// same above
if (auto&& wrt = Wire.get_writer(DEV_ADDR)) {
wrt << SHTC3_TRIG_H; // int type is handled as uint8_t
wrt << SHTC3_TRIG_L;
}
上記では get_writer()
メソッドにより生成された wrt
オブジェクトを用いて1バイトずつ書き出す。 メソッドのパラメータには読み出したい二線シリアル ID を指定します。
if(...)
内でwrt
オブジェクトを生成する。(型名は長くなるため auto で解決)- 生成した
wrt
オブジェクトにはoperator bool ()
が定義されており、判定式の評価として利用される。指定された ID により通信が可能であればtrue
となる。 wrt
オブジェクトにはint operator () (void)
演算子が定義されていて、これを呼び出すことで2線シリアルバスに1バイトのデータを書き出しす。失敗したときは-1
が戻り、成功した場合は書き込んだバイト値が戻る。if() { ... }
スコープの末尾でwrt
のデストラクタが呼び出され、二線シリアルバスのSTOP
を行う。
get_writer()
periph_wire::writer
get_writer(uint8_t addr)
I2C書き出しに用いるワーカーオブジェクトを取得します。
パラメータ | 解説 |
---|---|
addr | 書き出し用のI2Cアドレス |
ワーカーオブジェクト (writer)
<<
演算子
operator << (int c)
operator << (uint8_t c)
operator << (uint16_t c)
operator << (uint32_t c)
int
型,uint8_t
型は8bitの転送を行います。データ並び順はビッグエンディアン形式(上位バイトが先に転送される)です。
()
演算子
operator() (uint8_t val)
operator() (int val)
1バイト書き出す。
ワーカーオブジェクト (reader)
>>
演算子
operator >> (uint8_t& c)
operator >> (uint16_t& c)
operator >> (uint32_t& c)
operator >> (uint8_t(&c)[N]) // Nバイトの固定配列
それぞれのデータ型のサイズ分だけ読み出します。データ並び順はビッグエンディアン形式(先に転送されたほうが上位バイトに格納される)です。
()
演算子
int operator() (bool b_stop = false)
//例
uint8_t dat[6];
if (auto&& rdr = Wire.get_reader(0x70)) {
for(uint8_t& x : dat) {
x = rdr();
}
}
1バイト読み出します。エラーがある場合は-1を戻し、正常時は読み出したバイト値を戻します。
b_stop
をtrue
にすると、その読み出しにおいてSTOPビットを発行します。
例
以下の例は、環境センサーパルの温湿度センサーSHTC3の計測例です。
Wire.begin();
// reset (may not necessary...)
if (auto&& wrt = Wire.get_writer(0x70)) {
wrt << 0x80; // SHTC3_SOFT_RST_H
wrt << 0x05; // SHTC3_SOFT_RST_L
}
delay(5); // wait some
// start read
if (auto&& wrt = Wire.get_writer(0x70)) {
wrt << 0x60; // SHTC3_TRIG_H
wrt << 0x9C; // SHTC3_TRIG_L
}
delay(10); // wait some
// read result
uint16_t u16temp, u16humd;
uint8_t u8temp_csum, u8humd_csum;
if (auto&& rdr = Wire.get_reader(0x70, 6)) {
rdr >> u16temp;
rdr >> u8temp_csum;
rdr >> u16humd;
rdr >> u8humd_csum;
}
// checksum 0x31, init=0xFF
if (CRC8_u8CalcU16(u16temp, 0xff) != u8temp_csum) {
Serial << format("{SHTC3 T CKSUM %x}", u8temp_csum); }
if (CRC8_u8CalcU16(u16humd, 0xff) != u8humd_csum) {
Serial << format("{SHTC3 H CKSUM %x}", u8humd_csum); }
// calc temp/humid (degC x 100, % x 100)
int16_t i16Temp = (int16_t)(-4500 + ((17500 * int32_t(u16temp)) >> 16));
int16_t i16Humd = (int16_t)((int32_t(u16humd) * 10000) >> 16);
Serial << "temp=" << int(i16Temp)
<< ",humid=" << int(i16Humd) << mwx::crlf;
1.1.4 - クラス
1.1.4.1 - MWX_APIRET
class MWX_APIRET {
uint32_t _code;
public:
MWX_APIRET() : _code(0) {}
MWX_APIRET(bool b) {
_code = b ? 0x80000000 : 0;
}
MWX_APIRET(bool b, uint32_t val) {
_code = (b ? 0x80000000 : 0) + (val & 0x7fffffff);
}
inline bool is_success() const { return ((_code & 0x80000000) != 0); }
inline bool is_fail() const { return ((_code & 0x80000000) == 0); }
inline uint32_t get_value() const { return _code & 0x7fffffff; }
inline operator uint32_t() const { return get_value(); }
inline operator bool() const { return is_success(); }
};
コンストラクタ
MWX_APIRET()
MWX_APIRET(bool b)
MWX_APIRET(bool b, uint32_t val)
デフォルトコンストラクタはfalse
,0
の組み合わせで構築します。
またbool
型とuint32_t
型をパラメータとする明示的な構築も可能です。
bool
型のコンストラクタを実装しているため、以下のようにtrue
/false
を用いることができます。
MWX_APIRET myfunc() {
if (...) return true;
else false;
}
メソッド
is_success()
, operator bool()
inline bool is_success()
inline operator bool()
MSBに1
がセットされていればtrue
を返す。
inline bool is_fail()
MSBが0
の場合にtrue
を返す。
inline uint32_t get_value()
inline operator uint32_t()
bit0..30の値部を取得する。
1.1.4.2 - alloc
smplbuf
, smplque
)のテンプレート引数として指定し、内部で利用するメモリの確保または領域指定します。クラス名 | 内容 |
---|---|
alloc_attach<T> | すでにあるバッファを指定する |
alloc_local<T, int N> | Nバイトのバッファを内部に静的確保する |
alloc_heap<T> | 指定したサイズをヒープに確保する |
alloc_attach
やalloc_heap
ではメモリ確保クラスに応じた初期化メソッド (init_???()
)を実行する必要があります。
初期化
void attach(T* p, int n) // alloc_attach
void init_local() // alloc_local
void init_heap(int n) // alloc_heap
バッファーp
・サイズn
で初期化します。
メソッド
alloc_size()
uint16_t alloc_size()
バッファのサイズを返す。
_is_attach()
, _is_local()
, _is_heap()
想定したallocクラスと異なるメソッド呼び出し記述に対して、static_assert
のように、コンパイルエラーを発生させるためのメソッドです。
1.1.4.3 - axis_xyzt
struct axis_xyzt {
int16_t x;
int16_t y;
int16_t z;
uint16_t t;
};
get_axis_{x,y,z}_iter()
/*戻り型は長いテンプレート型名なのでauto&&と記載します*/
auto&& get_axis_x_iter(Iter p)
auto&& get_axis_y_iter(Iter p)
auto&& get_axis_z_iter(Iter p)
axis_xyzt
を格納したコンテナクラスのイテレータをパラメータとして、X, Y, Z 軸のいずれかの要素にアクセスするイテレータを生成します。
以下の例では、buf.begin()
, buf.end()
をX軸用のイテレータとしてアルゴリズムstd::minmax_element
に用いています。
##include <algorithm>
void myfunc() {
// コンテナクラス
smplbuf_local<axis_xyzt, 10> buf;
// テスト用にデータを投入
buf[0] = { 1, 2, 3, 4 };
buf[1] = { 2, 3, 4, 5 };
...
// 最大、最小値を得るアルゴリズム
auto&& minmax = std::minmax_element(
get_axis_x_iter(buf.begin()),
get_axis_x_iter(buf.end()));
Serial << "min=" << int(*minmax.first)
<< ",max=" << int(*minmax.second) << mwx::crlf;
}
get_axis_{x,y,z}()
/*戻り型は長いテンプレート型名なのでauto&&と記載します*/
auto&& get_axis_x(T& c)
auto&& get_axis_y(T& c)
auto&& get_axis_z(T& c)
axis_xyzt
を格納したコンテナクラスのXYZ軸のいずれかの軸を取り出した仮想的なコンテナクラスを生成する関数です。この生成したクラスにはbegin()
とend()
メソッドのみ実装されています。このbegin()
とend()
メソッドで取得できるイテレータは前節get_axis_{x,y,z}_iter()
のイテレータと同じものになります。
##include <algorithm>
void myfunc() {
// コンテナクラス
smplbuf_local<axis_xyzt, 10> buf;
// テスト用にデータを投入
buf[0] = { 1, 2, 3, 4 };
buf[1] = { 2, 3, 4, 5 };
...
// キューの中の X 軸を取り出す
auto&& vx = get_axis_x(que);
// 範囲for文の利用
for (auto&& e : vx) { Serial << int(e) << ','; }
// 最大、最小値を得るアルゴリズム
auto&& minmax = std::minmax_element(
vx.begin(), vx.end());
Serial << "min=" << int(*minmax.first)
<< ",max=" << int(*minmax.second) << mwx::crlf;
}
1.1.4.4 - packet_rx
tsRxDataApp
構造体のラッパークラスです。このクラスオブジェクトは、ビヘイビアのコールバック関数またはon_rx_packets()
により取得できます。
packet_rx
では、特にパケットのデータペイロードをsmplbuf
コンテナで取り扱えるようにし、expand_bytes()
などのユーティリティ関数によりペイロードの解釈記述を簡素化しています。
<NWK_SIMPLE>
で必要とされるものを中心にメソッド等のインタフェースを実装しています。メソッド
get_payload()
smplbuf_u8_attach& get_payload()
パケットのデータペイロードを取得する。
<NWK_SIMPLE>
を用いた場合は、先頭に<NWK_SIMPLE>
用のヘッダデータがあります。戻りとして参照されるコンテナは、このヘッダ部分を除いた部分配列になります。ヘッダ部分まで参照したいときはget_psRxDataApp()
によりtsRxDataApp
構造体を参照してください。get_psRxDataApp()
const tsRxDataApp* get_psRxDataApp()
TWENET Cライブラリの受信構造体を得る。
get_length()
uint8_t get_length()
ペイロードのデータ長を返す。.get_payload().size()
と同じ値になる。
get_lqi()
uint8_t get_lqi()
LQI値 (Link Quality Indicator)を得る。
LQIとは電波通信品質を示す値です。0から255までの数値で表されます。
ちなみに、いくつかの段階で評価する場合は、50未満(悪い -80dbm 未満)、50~100(やや悪い)、100~150(良好)、150以上(アンテナの近傍)といった区分けも可能です。これらは目安である点にご留意ください。
get_addr_src_long()
, get_addr_src_lid()
uint32_t get_addr_src_long()
uint8_t get_addr_src_lid()
送信元のアドレスを得る。
get_addr_src_long()
は送信元のシリアル番号で、MSB(bit31)が必ず1になります。
get_addr_src_lid()
は送信元の論理IDで0x00
-0xFE
までの値をとります(<NWK_SIMPLE>
で指定する論理IDです)。
get_addr_dst()
uint32_t get_addr_dst()
宛先アドレスを得ます。
宛先アドレスは、送信元で指定され、宛先の種別によって値の範囲が変わります。
値 | 解説 |
---|---|
MSB(bit31)がセットされている | 宛先としてシリアル番号を指定しています。 |
0x00 -0xFF | 宛先として論理ID(8bit)が指定されています。 |
is_secure_pkt()
bool is_secure_pkt()
暗号化パケットの場合は true
を返し、平文の時はfalse
を返します。
get_network_type()
uint8_t get_network_type()
ネットワークビヘイビアで識別されるパケットのネットワークタイプを返す。
値 | 解説 |
---|---|
mwx::NETWORK::LAYERED | <NWK_LAYERED> からのパケット |
mwx::NETWORK::SIMPLE | <NWK_SIMPLE> からのパケット |
mwx::NETWORK::NONE | ネットワークを介さないパケット (App_Tweliteなど) |
その他 | エラーまたは識別できないパケット |
1.1.4.5 - packet_tx
tsTxDataApp
構造体のラッパクラスで、このクラスをベースとした派生クラスのオブジェクトをネットワークビヘイビアまたはon_tx_comp()
により取得します。
if (auto&& pkt = the_twelite.network.use<NWK_SIMPLE>().prepare_tx_packet()) {
pkt << tx_addr(0x00)
<< tx_retry(0x1)
<< tx_packet_delay(0,50,10);
pack_bytes(pkt.get_payload()
, make_pair("APP1", 4)
, uint8_t(u8DI_BM)
);
pkt.transmit();
}
オブジェクトの生成
ネットワークビヘイビアの .prepare_tx_packet()
によって行います。
if (auto&& pkt = the_twelite.network.use<NWK_SIMPLE>().prepare_tx_packet()) {
...
}
上記の例ではthe_twelite.network.use<NWK_SIMPLE>()
によってネットワークビヘイビアのオブジェクトを取り出します。このオブジェクトの.prepare_tx_packet()
によってオブジェクトpkt
が生成されます。型名はauto&&で推論されていますがpacket_tx
の派生クラスになります。
このpkt
オブジェクトは、まず、()
内の条件判定にてtrue
かfalse
を返します。false
が返ってくるのは、送信用のキューが一杯でこれ以上要求が追加できない時です。
送信設定
無線パケットには宛先情報など相手に届けるための様々な設定を行います。設定には設定内容を含むオブジェクトを«演算子の右辺値に与えます。
pkt << tx_addr(0x00)
<< tx_retry(0x1)
<< tx_packet_delay(0,50,10);
以下に設定に用いるオブジェクトについて記載します。
tx_addr
tx_addr(uint32_t addr)
宛先アドレスaddr
を指定します。宛先アドレスの値については、ネットワークビヘイビアの仕様を参照してください。
<NWK_SIMPLE>
MSB(bit31=0x80000000
)がセットされるアドレスは、無線モジュールのシリアル番号宛という意味になります。0x00
..0xEF
は、8bitの論理IDを意味します。0xFEは子機宛(0x01
..0xEF
)の同報通信(ブロードキャスト)、0xFF
は親機子機関係なく同報通信(ブロードキャスト)します。
tx_retry
tx_retry(uint8_t u8count, bool force_retry = false)
再送回数の指定を行います。再送回数はu8countで指定します。force_retry
は、送信が成功しようがしまいが、指定回数の再送を行う設定です。
<NWK_SIMPLE>
ネットワークビヘイビア<NWK_SIMPLE>
では、同じ内容のパケットをu8count+1
回送信します。force_retry
の設定は無視されます。
tx_packet_delay
tx_packet_delay(uint16_t u16DelayMin,
uint16_t u16DelayMax,
uint16_t u16RetryDur)
パケットを送信するまでの遅延と再送間隔を設定します。u16DelayMin
とu16DelayMax
の2つの値をミリ秒[ms]で指定します。送信要求をしてからこの間のどこかのタイミングで送信を開始します。再送間隔をu16RetryDur
の値[ms]で指定します。再送間隔は一定です。
内部処理の都合で指定通りのタイミングで送信処理が始まらない場合もあります。また、IEEE802.15.4の処理でもパケット創出までの時間ブレが発生します。これらのタイミングのブレは、多くのシステムではパケットの衝突回避を行う上で有効な手立てとなります。
厳格なタイミングでのパケット送信は、IEEE802.15.4の規格の性質上、例外的な使用方法とお考え下さい。
<NWK_SIMPLE>
この指定は有効です。 最初の送信から1秒を超えて再送され到達した同一パケットについては、新たなパケットが到達したとして重複除外が為されません。再送間隔を長く設定したり、中継でのパケット到達遅延により1秒を超えて同じパケットを受信する場合があります。 重複パケットの処理の設定は<NWK_SIMPLE>
ビヘイビアの初期化で設定できます。
tx_process_immediate
tx_process_immediate()
パケット送信を「できるだけ速やかに」実行するように要求する設定です。TWENETでのパケット送信処理は、1msごとに動作するTickTimer起点で行われています。この設定をすることで、要求後速やかにパケット送信要求が処理されます。もちろん、tx_packet_delay(0,0,0)
以外の設定では意味がない指定になります。
他のパケット送信処理が行われている場合は、通常の処理になります。
<NWK_SIMPLE>
この指定は有効です。
tx_ack_required
tx_ack_required()
無線パケット通信では、送信完了後、送信相手先からACK(アック)という短い無線電文を得て、送信成功とする送信方法があります。このオプションを設定することで、ACK付き送信を行います。
<NWK_SIMPLE>
<NWK_SIMPLE>
では、この指定は無効です。コンパイルエラーになります。<NWK_SIMPLE>
は、シンプルに動作する中継ネットワークの実装を目的としており、ACK付きの通信は行いません。
tx_addr_broadcast
tx_addr_broadcast()
ブロードキャストの指定を行います。
<NWK_SIMPLE>
<NWK_SIMPLE>
では、この指定は無効です。コンパイルエラーになります。 替わりに宛先アドレスtx_addr(0xFF)
(ブロードキャスト)またはtx_addr(0xFE)
(子機宛のブロードキャスト)を指定します。
tx_packet_type_id
tx_packet_type_id(uint8_t)
0..7の指定ができるTWENET無線パケットのタイプIDを指定します。
<NWK_SIMPLE>
<NWK_SIMPLE>
では、この指定は無効です。コンパイルエラーになります。<NWK_SIMPLE>
ではタイプIDを内部的に使用しています。ユーザは使用できません。
1.1.4.6 - serparser
メモリバッファ取り扱い方法(alloc
)に応じて3種類のクラス名が定義されています。
// serparser_attach : 既存のバッファを用いる
serparser_attach
// serparser : Nバイトのバッファを内部に確保する
serparser_local<N>
// serparser_heap : ヒープ領域にバッファを確保する
serparser_heap
定数(書式種別)
begin()
の初期化のパラメータで渡す書式の種別です。ここではアスキー形式とバイナリー形式の2種類があります。
定数 | 種別 |
---|---|
uint8_t PARSER::ASCII = 1 | アスキー形式 |
uint8_t PARSER::BINARY = 2 | バイナリー形式 |
形式について
アスキー形式
アスキー形式は、バイナリで構成されたデータ列を文字列で表現する方法です。
例えばバイト列で 00A01301FF123456
をアスキー形式で表現すると、以下のようになります。先頭は :
で B1
がチェックサム、終端は [CR:0x0d][LF:0x0a]
となります。
:00A01301FF123456B1[CR][LF]
終端のチェックサムを省略できます。チェックサムからCRLFの系列をX
に置き換えます。文字化けによる誤ったデータ系列には弱くなりますが、実験などでデータを送付したいときに便利です。
:00A01301FF123456X
定義
====== | 元データのバイト数 | バイト数 | 解説 |
---|---|---|---|
ヘッダ | 1 | : (0x3A) コロンを指定します。 | |
データ部 | N | 2N | 元データの各バイトをアスキー文字列2文字(A-F は大文字)で表現します。 例えば 0x1F は 1 (0x31) F (0x46) と表現します。 |
チェックサム | 2 | データ部の各バイトの和を8ビット幅で計算し2の補数をとります。つまりデータ部の各バイトの総和+チェックサムバイトを8ビット幅で計算すると0になります。 チェックサムバイトをアスキー文字列2文字で表現します。 例えば 00A01301FF123456 では 0x00 + 0xA0 + … + 0x56 = 0x4F となり、この二の補数は0xB1 です。(つまり 0x4F + 0xB1 = 0x00) | |
フッタ | 2 | [CR] (0x0D) [LF] (0x0A) を指定する。 |
バイナリ形式
通常はアスキー形式を利用してください。
マイコン間通信での実装を考えるとバイナリ形式のほうが効率的ですが、実験などでの送受信の確認にはバイナリ通信に対応した特別なターミナルなどを準備する必要があり、チェックサムの計算も必須です。アスキー形式より利用の難易度は高くなります。
バイナリ形式は、バイナリで構成されたデータ列にヘッダとチェックサムを付加して送付する方法です。
例えば 00A01301FF123456
をバイナリ形式で表現すると、以下のようになります。
0xA5 0x5A 0x80 0x08 0x00 0xA0 0x13 0x01 0xFF 0x12 0x34 0x56 0x3D
定義
====== | 元データのバイト数 | 形式におけるバイト数 | 解説 |
---|---|---|---|
ヘッダ | 2 | 0xA5 0x5A を指定します。 | |
データ長 | 2 | データ長はビッグエンディアン形式の2バイトで、MSB (0x8000) を設定した上、データ部の長さを指定します。 例えばデータ部の長さが 8 バイトなら 0x80 0x08 を指定します。 | |
データ部 | N | N | 元データを指定します。 |
チェックサム | 1 | データ部の各バイトの XOR を計算します。 例えばデータ部が 00A01301FF123456 なら 0x00 xor 0xA0 xor … 0x56 = 0x3D となります。 | |
フッタ | (1) | チェックサムが事実上の終端です。無線モジュールからの出力では 0x04 (EOT) が付加されます。 |
メソッド
宣言, begin()
// serparser_attach : 既存のバッファを用いる
serparser_attach p1;
uint8_t buff[128];
p1.begin(ARSER::ASCII, buff, 0, 128);
// serparser : Nバイトのバッファを内部に確保する
serparser p2<128>;
p2.begin(PARSER::ASCII);
// serparser_heap : ヒープ領域にバッファを確保する
serparser_heap p3;
p3.begin(PARSER::ASCII, 128);
宣言にはメモリの確保クラスを指定します。この指定は煩雑であるため、上述のように別名定義を行っています。
クラス名(別名定義) メモリ確保 | 内容 |
---|---|
serparser_attach | すでにあるバッファをbegin() にて指定する |
serparser_local<N> | Nバイトのバッファを内部に確保する |
serparser_heap | begin() メソッドのパラメータで指定したサイズをヒープに確保する |
メモリ確保クラスに応じたbegin()
メソッドを呼び出します。
serparser_attach
void begin(uint8_t ty, uint8_t *p, uint16_t siz, uint16_t max_siz)
ty
で指定する形式で、p
で指定したバッファを用います。バッファの最大長はmax_siz
で、バッファの有効データ長をsiz
で指定します。
この定義は、特に、データ列を書式出力したい場合に用います(>>
演算子参照)
serparser_local<N>
- 内部にバッファを確保する
void begin(uint8_t ty)
ty
で指定する形式で初期化を行います。
serparser_heap
- ヒープに確保
void begin(uint8_t ty, uint16_t siz)
ty
で指定する形式で、siz
で指定したサイズをヒープに確保して初期化します。
get_buf()
BUFTYPE& get_buf()
内部バッファを返す。バッファは smplbuf<uint8_t, alloc>
型となります。
parse()
inline bool parse(uint8_t b)
入力文字を処理する。書式入力の入力文字列を1バイト受け取り書式に従い解釈します。例えばASCII書式では:00112233X
のような系列を入力として受け取りますが : 0 0 ... X
の順で1バイトずつ入力し、最後の X
を入力した時点で書式の解釈を完了し、完了済みと報告します。
parse()
のパラメータは入力バイト、戻り値は解釈完了であればtrue
を戻します。
parse()
で読み出し完了になったとき、次のparse()
を実行すると読み出し中のステータスに戻ります。例
while (Serial.available()) {
int c = Serial.read();
if (SerialParser.parse(c)) {
// 書式解釈完了、b に得られたデータ列(smplbuf<uint8_t>)
auto&& b = SerialParser.get_buf();
// 以下は得られたデータ列に対する処理を行う
if (b[0] == 0xcc) {
// ...
}
}
}
operator bool()
operator bool()
true
ならparse()
により読み出しが完了した状態で、false
なら解釈中となります。
例 (parse()
の例は以下のように書き換えられる)
while (Serial.available()) {
int c = Serial.read();
SerialParser.parse(c);
if(SerialParser) {
// 書式解釈完了、b に得られたデータ列(smplbuf<uint8_t>)
auto&& b = SerialParser.get_buf();
// ...
}
}
<<
演算子
内部バッファを書式形式でストリーム(Serial)に対して出力します。
例
uint8_t u8buf[] = { 0x11, 0x22, 0x33, 0xaa, 0xbb, 0xcc };
ser_parser pout;
pout.begin(ARSER::ASCII, u8buf, 6, 6); // u8bufの6バイトを指定
Serial << pout;// Serialに書式出力 -> :112233AABBCC??[CR][LF]
1.1.4.7 - pktparser
serparser_heap parser_ser;
void setup() {
// init ser parser (heap alloc)
parser_ser.begin(PARSER::ASCII, 256);
}
void loop() {
int c;
while ((c = Serial.read()) >= 0) {
parser_ser.parse(c);
if (parser_ser.available()) {
// get buffer object
auto&& payl = parser_ser.get_buf();
// identify packet type
auto&& typ = identify_packet_type(payl.begin(), payl.end());
// if packet type is TWELITE standard 0x81 message
if (typ == E_PKT::PKT_TWELITE) {
pktparser pkt; // packet parser object
// analyze packet data
typ = pkt.parse<TwePacketTwelite>(payl.begin(), payl.end());
if (typ != E_PKT::PKT_ERROR) { // success!
// get data object
auto&& atw = pkt.use<TwePacketTwelite>();
// display packet inforamtion
Serial << crlf << format("TWELITE: SRC=%08X LQI=%03d "
, app.u32addr_src, app.u8lqi);
Serial << " DI1..4="
<< atw.DI1 ? 'L' : 'H' << atw.DI2 ? 'L' : 'H'
<< atw.DI3 ? 'L' : 'H' << atw.DI4 ? 'L' : 'H';
}
}
}
}
}
上記の例は、標準アプリケーションの0x81メッセージの解釈を行っています。parser_serオブジェクトによりSerialより入力された電文をバイト列に変換します。このバイト列をまずidentify_packet_type()
により電文の種別E_PKT
を特定します。電文の種別が判定できたら次に.parse<TwePacketTwelite>()
により電文を解析します。解析結果はTwePacketTwelite
型になりますが、このオブジェクトを取り出す手続きが.use<TwePacketTwelite>()
です。TwePacketTwelite
型はクラスですが構造体として直接メンバー変数を参照します。
parse<T>
template <class T>
E_PKT parse(const uint8_t* p, const uint8_t* e)
バイト列を解析します。
T
には解析対象のパケット型を指定します。例えば標準アプリケーションの0x81メッセージならTwePacketTwelite
を指定します。
p
とe
はバイト列の先頭と終端の次を指定します。
戻り値はE_PKT
型です。エラーの場合はE_PKT::PKT_ERROR
が戻ります。
user<T>
template
T& use()
解釈したバイト列に対応するパケット型に対応するオブジェクトの参照を返します。事前にparse<T>を実行しエラーがなかった場合に呼び出すせます。
T
はparse<T>
で実行した型と同じもの、または基本的な情報のみ取得できるTwePacket
を指定します。
1.1.4.7.1 - E_PKT
以下のパケットに対応します。
名前 | 解説 |
---|---|
PKT_ERROR | パケット解釈前やパケット種別が特定できないなど、TwePacketには意味のあるデータが格納されていない |
PKT_TWELITE | 標準アプリ App_Twelite の 0x81 コマンドを解釈したもの |
PKT_PAL | TWELITE PALのシリアル形式を解釈したもの |
PKT_APPIO | リモコンアプリ App_IO のUARTメッセージを解釈したもの |
PKT_APPUART | シリアル通信アプリ App_UART の拡張書式を解釈したもの。 |
PKT_APPTAG | 無線タグアプリApp_TagのUARTメッセージを解釈したもの。センサ固有部分は解釈されずpayloadとしてバイト列を報告します。 |
PKT_ACT_STD | アクト(Act)のサンプルなどで使用される出力書式。 |
1.1.4.7.2 - identify_packet_type()
idenify_packet_type()
パケットデータのバイト列を入力として、パケットの種別を判定します。戻り値はE_PKT
です。
E_PKT identify_packet_type(uint8_t* p, uint8_t u8len)
特定のパケットであると解釈できなかった場合はE_PKT::PKT_ERROR
が戻ります。
1.1.4.7.3 - TwePacket
common
にはアドレス情報など共通情報が含まれます。
class TwePacket {
public:
static const E_PKT _pkt_id = E_PKT::PKT_ERROR;
struct {
uint32_t tick; // 解釈実行時のシステム時刻[ms]
uint32_t src_addr; // 送信元アドレス(シリアル番号)
uint8_t src_lid; // 送信元アドレス(論理アドレス)
uint8_t lqi; // LQI
uint16_t volt; // 電圧[mV]
} common;
};
pktparser
型として配列等に格納するような場合に、アドレス情報などを最小限の情報を取得したい場合に使用します。1.1.4.7.3.1 - TwePacketTwelite
TwePacketTwelite
クラスは、標準アプリApp_Tweliteの0x81コマンドを解釈したものです。
class TwePacketTwelite : public TwePacket, public DataTwelite { ... };
パケットデータ内の諸情報はparse<TwePacketTwelite>()
実行後にパケット情報がDataTwelite
に格納されます。
DataTwelite
構造体
struct DataTwelite {
//送信元のシリアル#
uint32_t u32addr_src;
// 送信元の論理ID
uint8_t u8addr_src;
// 宛先の論理ID
uint8_t u8addr_dst;
// 送信時のタイムスタンプ
uint16_t u16timestamp;
// 低レイテンシ送信時のフラグ
bool b_lowlatency_tx;
// リピート中継回数
uint16_t u8rpt_cnt;
// LQI値
uint16_t u8lqi;
// DIの状態 (true がアクティブ Lo,GND)
bool DI1, DI2, DI3, DI4;
// DIの状態ビットマップ (LSBから順にDI1,2,3,4)
uint8_t DI_mask;
// DIアクティブならtrue (過去にアクティブになったことがある)
bool DI1_active, DI2_active, DI3_active, DI4_active;
// DIのアクティブビットマップ(LSBから順にDI1,2,3,4)
uint8_t DI_active_mask;
// モジュールの電源電圧[mV]
uint16_t u16Volt;
// AD値 [mV]
uint16_t u16Adc1, u16Adc2, u16Adc3, u16Adc4;
// ADがアクティブ(有効)なら 1 になるビットマップ (LSBから順にAD1,2,3,4)
uint8_t Adc_active_mask;
};
1.1.4.7.3.2 - TwePacketIO
TwePacketAppIO
クラスは、標準アプリApp_IOのシリアルメッセージ(0x81)を解釈したものです。
class TwePacketAppIO : public TwePacket, public DataAppIO { ... };
パケットデータ内の諸情報はparse<TwePacketIO>()
実行後にDataTwelite
に格納されます。
DataAppIO
構造体
struct DataAppIO {
//送信元のシリアル#
uint32_t u32addr_src;
// 送信元の論理ID
uint8_t u8addr_src;
// 宛先の論理ID
uint8_t u8addr_dst;
// 送信時のタイムスタンプ
uint16_t u16timestamp;
// 低レイテンシ送信時のフラグ
bool b_lowlatency_tx;
// リピート中継回数
uint16_t u8rpt_cnt;
// LQI値
uint16_t u8lqi;
// DIの状態ビットマップ (LSBから順にDI1,2,3,4,...)
uint8_t DI_mask;
// DIのアクティブ(使用なら1)ビットマップ(LSBから順にDI1,2,3,4,...)
uint8_t DI_active_mask;
// DIが割り込み由来かどうかのビットマップ(LSBから順にDI1,2,3,4,...)
uint16_t DI_int_mask;
};
1.1.4.7.3.3 - TwePacketUART
TwePacketAppUart
クラスは、App_UARTの拡張書式を親機・中継機アプリApp_Wingsで受信したときの形式です。
class TwePacketAppUART : public TwePacket, public DataAppUART
パケットデータ内の諸情報はparse<TwePacketUART>()
実行後にDataAppUART
に格納されます。
parse<TwePacketUART>()
ではE_PKT::PKT_ERROR
を戻します。内容を確認するには元のバイト列を直接参照してください。DataAppUART
構造体
struct DataAppUART {
/**
* source address (Serial ID)
*/
uint32_t u32addr_src;
/**
* source address (Serial ID)
*/
uint32_t u32addr_dst;
/**
* source address (logical ID)
*/
uint8_t u8addr_src;
/**
* destination address (logical ID)
*/
uint8_t u8addr_dst;
/**
* LQI value
*/
uint8_t u8lqi;
/**
* Response ID
*/
uint8_t u8response_id;
/**
* Payload length
*/
uint16_t u16paylen;
/**
* payload
*/
##if MWX_PARSER_PKT_APPUART_FIXED_BUF == 0
mwx::smplbuf_u8_attach payload;
##else
mwx::smplbuf_u8<MWX_PARSER_PKT_APPUART_FIXED_BUF> payload;
##endif
};
payload
はデータ部分ですが、マクロ定義によってデータ格納の方法が変わります。
MWX_PARSER_PKT_APPUART_FIXED_BUF
の値が0
としてコンパイルした場合は、payload
はパケット解析を行うバイト列を直接参照します。元のバイト列の値が変更されるとpayload
中のデータは破壊されます。
MWX_PARSER_PKT_APPUART_FIXED_BUF
の値を0
より大きい値として定義した場合は、payload
にはその値(バイト数)のバッファが確保されます。ただしシリアル電文のデータがバッファサイズを超えた場合はparse<TwePacketAppUART>()
は失敗しE_PKT::PKT_ERROR
を戻します。
1.1.4.7.3.4 - TwePacketPAL
TwePacketPal
クラスは、TWELITE PALのパケットデータを解釈したものです。このクラスはTWELITE PAL(センサーデータなど上り方向)共通に取り扱います。
class TwePacketPal : public TwePacket, public DataPal { ... };
PAL共通データはDataPal
に定義されています。
PALの各センサー基板特有のデータを取り出すためのジェネレータ関数を用意しています。
DataPal
構造体
PALは接続されるセンサーなどによってパケットデータ構造が異なりますが、DataPal
では共通部のデータ構造を保持します。
struct DataPal {
uint8_t u8lqi; // LQI値
uint32_t u32addr_rpt; // 中継器のアドレス
uint32_t u32addr_src; // 送信元のアドレス
uint8_t u8addr_src; // 送信元の論理アドレス
uint16_t u16seq; // シーケンス番号
E_PAL_PCB u8palpcb; // PAL基板の種別
uint8_t u8palpcb_rev; // PAL基板のレビジョン
uint8_t u8sensors; // データに含まれるセンサーデータの数 (MSB=1はエラー)
uint8_t u8snsdatalen; // センサーデータ長(バイト数)
union {
const uint8_t *au8snsdata; // センサーデータ部への参照
uint8_t _pobj[MWX_PARSER_PKT_APPPAL_FIXED_BUF]; // 各センサーオブジェクト
};
};
PALのパケットデータ構造は大まかに2つのブロックからなり、全てのPAL共通部と個別のデータ部になります。個別のデータ部は、パケットの解釈を行わずそのまま格納しています。取り扱いを単純化するため32バイトを超えるデータは動的に確保するuptr_snsdata
に格納します。
個別のデータ部は、PalBase
をベースクラスに持つ構造体に格納されます。この構造体は、TwePacketPal
に定義されるジェネレータ関数により生成されます。
parse<TwePacketPAL>()
実行時にMWX_PARSER_PKT_APPPAL_FIXED_BUF
に収まるサイズであれば、センサー個別のオブジェクトを生成します。
収まらない場合はau8snsdata
に解析時のバイト列の参照が保存されます。この場合、解析に用いたバイト列のデータが書き換えられた場合は、センサー個別のオブジェクトは生成できなくなります。
PalBase
PALの各センサーのデータ構造体はすべてPalBase
を継承します。センサーデータの格納状況u32StoredMask
が含まれます。
struct PalBase {
uint32_t u32StoredMask; // 内部的に利用されるデータ取得フラグ
};
PalEvent
PALイベントは、センサーなどの情報を直接送るのではなく、センサー情報を加工し一定の条件が成立したときに送信される情報です。例えば加速度センサーの静止状態から一定以上の加速度が検出された場合などです。
struct PalEvent {
uint8_t b_stored; // 格納されていたら true
uint8_t u8event_source; // 予備
uint8_t u8event_id; // イベントID
uint32_t u32event_param;// イベントパラメータ
};
イベントデータが存在する場合はTwePacketPal
の.is_PalEvent()
がtrue
になることで判定でき、.get_PalEvent()
によりPalEvent
データ構造を得られます。
ジェネレータ関数
センサーPALの各種データを取り出すためのジェネレータ関数です。
void print_pal(pktparser& pkt) {
auto&& pal = pkt.use<TwePacketPal>();
if (pal.is_PalEvent()) {
PalEvent obj = pal.get_PalEvent();
} else
switch(pal.u8palpcb) {
case E_PAL_PCB::MAG:
{
// generate pal board specific data structure.
PalMag obj = pal.get_PalMag();
} break;
case E_PAL_PCB::AMB:
{
// generate pal board specific data structure.
PalAmb obj = pal.get_PalAmb();
} break;
...
default: ;
}
}
ジェネレータ関数を利用するには、まずpkt
がイベントかどうか判定(.is_PalEvent()
)します。イベントの場合はget_PalEvent()
を持ちます。それ以外はu8palpcb
に応じてオブジェクトを生成します。
get_PalMag()
PalMag get_PalMag()
// MAG
struct PalMag : public PalBase {
uint16_t u16Volt; // モジュール電圧[mV]
uint8_t u8MagStat; // 磁気スイッチの状態 [0:磁石なし,1,2]
uint8_t bRegularTransmit; // MSB flag of u8MagStat
};
.u8palpcb==E_PAL_PCB::MAG
の場合、開閉センサーパルのデータPalMag
を取り出します。
get_PalAmb()
PalAmb get_PalAmb()
// AMB
struct PalAmb : public PalBase {
uint16_t u16Volt; // モジュール電圧[mV]
int16_t i16Temp; // 温度(100倍値)
uint16_t u16Humd; // 湿度(100倍値)
uint32_t u32Lumi; // 照度(Lux相当)
};
.u8palpcb==E_PAL_PCB::AMB
の場合、環境センサーパルのデータPalAmb
を取り出します。
get_PalMot()
PalMot get_PalMot()
// MOT
struct PalMot : public PalBase {
uint16_t u16Volt; // モジュール電圧[mV]
uint8_t u8samples; // サンプル数
uint8_t u8sample_rate_code; // サンプルレート (0: 25Hz, 4:100Hz)
int16_t i16X[16]; // X 軸
int16_t i16Y[16]; // Y 軸
int16_t i16Z[16]; // Z 軸
};
.u8palpcb==E_PAL_PCB::MOT
の場合、動作センサーパルのデータPalMot
を取り出します。
get_PalEvent()
PalEvent get_PalEvent()
// PAL event
struct PalEvent {
uint8_t b_stored; // trueならイベント情報あり
uint8_t u8event_source; // イベント源
uint8_t u8event_id; // イベントID
uint32_t u32event_param; // 24bit、イベントパラメータ
};
.is_PalEvent()
がtrue
の場合PalEvent
(PALイベント)を取り出します。
1.1.4.8 - smplbuf
template <typename T, int N> smplbuf_local
template <typename T> smplbuf_attach
template <typename T> smplbuf_heap
smplbuf
は要素の型T
とメモリの確保方法alloc
で指定したメモリ領域に対して配列の操作を提供するコンテナクラスです。alloc
の指定は煩雑であるためusing
を用いた別名定義が行っています。
オブジェクトの宣言例です。宣言の直後に初期化用のメソッド呼び出しを行います。いずれも初期化直後の最大サイズは128バイトで、サイズは0です。必要に応じてサイズを拡張しながら使用します。
// 配列領域は、クラスメンバー変数の固定配列
smplbuf_local<uint8_t, 128> b1;
// 配列領域は、すでにある領域を参照
uint8_t buf[128];
smplbuf_attach<uint8_t> b2(;
// 配列領域は、ヒープに確保
smplbuf_heap<uint8_t> b3;
// 初期化(グローバル定義の場合はsetup()で行う)
void setup() {
b1.init_local();
b2.attach(buf, 0, 128);
b3.init_heap(128);
}
// 処理関数内
void some_func() {
smplbuf_local<uint8_t, 128> bl;
// bl.init_local(); // smplbuf_localがローカル定義の場合は省略可能
bl.push_back('a');
}
上記のuint8_t
型に限り別名定義があります。
template <int N>
smplbuf_u8
// smplbuf<uint8_t, alloc_local<uint8_t, N>>
smplbuf_u8_attach
// smplbuf<uint8_t, alloc_attach<uint8_t>>
smplbuf_u8_heap
// smplbuf<uint8_t, alloc_heap<uint8_t>>
通常の配列のように[]演算子などを用いて要素にアクセスできますし、イテレータを用いたアクセスも可能です。
void begin() { // begin()は起動時1回だけ動作する
smplbuf_u8<32> b1;
b1.reserve(5); // 5バイト分利用領域に初期化(b1[0..5]にアクセスできる)
b1[0] = 1;
b1[1] = 4;
b1[2] = 9;
b1[3] = 16;
b1[4] = 25;
for(uint8_t x : b1) { // 暗黙に .begin() .end() を用いたループ
Serial << int(x) << ",";
}
}
push_back()
メソッドを定義しています。末尾にデータを追記するタイプのアルゴリズムが使用可能になります。
宣言・初期化
smplbuf_local<T,N>()
smplbuf_local<T,N>::init_local()
smplbuf_attach<T>(T* buf, uint16_t size, uint16_t N)
smplbuf_attach<T>::attach(T* buf, uint16_t size, uint16_t N)
smplbuf_heap<T>()
smplbuf_heap<T>::init_heap(uint16_t N)
// 例
// 内部に固定配列
smplbuf_local<uint8_t, 128> b1;
b1.init_local();
// すでにある配列を利用する
uint8_t buf[128];
smplbuf_attach<uint8_t> b2;
b2.attach(buf, 0, 128);
// ヒープに確保する
smplbuf_heap<uint8_t> b3;
b3.init_heap(128);
型T
でサイズN
のコンテナを宣言します。宣言後に初期化のメソッドを呼び出します。
smplbuf_local
は、内部に固定配列により領域を確保します。コンストラクタによる初期化も可能です。
smplbuf_attach
では、使用するバッファの先頭ポインタT* buf
と配列の初期サイズsize
と最大サイズN
を指定します。コンストラクタによる初期化も可能です。
smplbuf_heap
は、HEAP領域(解放は不可能だが随時確保可能なメモリ領域)にメモリを確保します。一度確保したら開放できない領域ですので通常はグローバル領域に定義します。領域確保はinit_heap()
で行います。コンストラクタによるメモリ確保はできません。必ずinit_heap()
を呼び出して利用してください。
setup()
を推奨)に初期化関数init_local()
,attach()
,init_heap()
を呼び出すようにしてください。初期化子リスト
void in_some_func() {
smplbuf_local<uint8_t, 5> b1;
b1.init_local();
b1 = { 0, 1, 2, 3, 4 };
smplbuf_local<uint8_t, 5> b2{0, 1, 2, 3, 4};
}
初期化子リスト(イニシャライザリスト){ ... }
によるメンバーの初期化をできます。smplbuf_local
のローカル宣言でのコンストラクタでの利用を除き、初期化のメソッドを呼び出した後に有効です。
- 代入演算子の右辺値 (
smplbuf_local
,smplbuf_attach
,smplbuf_heap
) - コンストラクタ(
smplbuf_local
のローカル宣言、グローバル宣言は不可)
メソッド
append()
, push_back()
, pop_back()
inline bool append(T&& c)
inline bool append(const T& c)
inline void push_back(T&& c)
inline void push_back(const T& c)
inline void pop_back()
末尾にメンバーc
を追加します。append()
の戻り値はbool
で、バッファが一杯で追加できないときにfalse
が返ります。
pop_back()
は末尾のエントリを抹消します。ただしエントリのクリアはしません。
empty()
, size()
, capacity()
inline bool empty()
inline bool is_end()
inline uint16_t size()
inline uint16_t capacity()
empty()
は配列に要素が格納されていない場合にtrue
を戻します。is_end()
は反対に配列サイズ一杯まで要素が格納されているときにtrue
を戻します。
size()
は配列の要素数を返します。
capacity()
は配列の最大格納数を返します。
reserve()
, reserve_head()
, redim()
inline bool reserve(uint16_t len)
inline void reserve_head(uint16_t len)
inline void redim(uint16_t len)
reserve()
は配列のサイズを拡張します。配列が格納されていない領域はデフォルトで初期化されます。
reserve_hear()
は配列の先頭部に指定したサイズの領域を確保します。コンテナオブジェクトからは参照できない領域となります。例えばパケットペイロードのヘッダ部分を読み飛ばした部分配列にアクセスするようなコンテナとして利用できるようにします。確保した領域を戻しすべてアクセスできるようにコンテナを戻すには確保時と同じ負の値を与えます。
redim()
は利用領域のサイズを変更します。reserve()
と違い、未使用領域の初期化を行いません。
operator []
inline T& operator [] (int i)
inline T operator [] (int i) const
要素にアクセスします。
i
に負の値を与えるとバッファー末尾からの要素となります。-1
の場合は末尾の要素、-2
は末尾から一つ手前となります。
mwx::stream
への出力
uint8_t
型の配列オブジェクト(smplbuf<uint8_t, *>
)は、mwx::stream
の派生オブジェクトに対して、そのまま出力できます。
<<
演算子
template <class L_STRM, class AL>
mwx::stream<L_STRM>& operator << (
mwx::stream<L_STRM>& lhs, mwx::_smplbuf<uint8_t, AL>& rhs)
//例
smplbuf_u8<128> buf;
buf.push_back('a');
buf.push_back('b');
buf.push_back('c');
Serial << buf;
// 出力: abc
Serial
などmwx::stream
の派生オブジェクトに対して、バイト列を出力します。
to_stream()
inline std::pair<T*, T*> to_stream()
//例
smplbuf_u8<128> buf;
buf.push_back('a');
buf.push_back('b');
buf.push_back('c');
Serial << buf.to_stream();
// 出力:0123
ストリームへの出力目的で利用します。«演算子の実装に用いられています。
mwx::stream
でデータ生成
mwx::stream
では<<
演算子やprintfmt()
メソッドと行ったストリームに対してバイト列を出力するための関数・演算子が定義されています。uint8_t
型のsmplbufの配列を出力先と見立ててストリーム出力手続きを行えます。
方法は2種類あります。
get_stream_helper()
により生成されるヘルパーオブジェクトを利用する。mwx::stream
を継承したsmplbufクラスを利用する。
1.1.4.8.1 - get_stream_helper()
smplbuf_u8<32> b;
auto&& bs = b.get_stream_helper(); // ヘルパーオブジェクト
// データ列の生成
uint8_t FOURCHARS[]={'A', 'B', 'C', 'D'};
bs << FOURCHARS;
bs << ';';
bs << uint32_t(0x30313233); // "0123"
bs << format(";%d", 99);
Serial << b << crlf; // Serialへの出力は smplbuf_u8<32> クラス経由で
//結果: ABCD;0123;99
ヘルパーオブジェクトの型名は長くなるためauto&&
により解決しています。このオブジェクトに対して<<
演算子などmwx::stream
で定義されたインタフェースを利用できます。
生成されたヘルパーオブジェクトbs
は生成時に大本の配列b
の先頭位置から読み書きを始めます。配列の末尾の場合はappend()
によりデータを追加します。読み書きを行うたびに位置は次に移動していきます
ヘルパー関数では読み出し用の>>
演算子が利用できます。
//..上例の続き
// ABCD;0123;99 <- bに格納されている
//読み出しデータ格納変数
uint8_t FOURCHARS_READ[4];
uint32_t u32val_read;
uint8_t c_read[2];
// >>演算子で読み出す
bs.rewind(); //ポジションを先頭に巻き戻す
bs >> FOURCHARS_READ; //4文字
bs >> mwx::null_stream(1); //1文字スキップ
bs >> u32val_read; //32bitデータ
bs >> mwx::null_stream(1); //1文字スキップ
bs >> c_read; //2文字
// 結果表示
Serial << crlf << "4chars=" << FOURCHARS_READ;
Serial << crlf << format("32bit val=0x%08x", u32val_read);
Serial << crlf << "2chars=" << c_read;
// 4chars=ABCD
// 32bit val=0x30313233
// 2chars=99
1.1.4.8.2 - smplbuf_strm_u8
// smplbuf_strm_u8<N> : ローカル確保
template <int N> using smplbuf_strm_u8
= _smplbuf_stream<uint8_t, mwx::alloc_local<uint8_t, N>>;
// smplbuf_strm_u8_attach : 既存バッファへのアタッチ版
using smplbuf_strm_u8_attach
= mwx::_smplbuf_stream<uint8_t, mwx::alloc_attach<uint8_t>>;
// smplbuf_strm_u8_heap : HEAP確保
using smplbuf_strm_u8_heap
= mwx::_smplbuf_stream<uint8_t, mwx::alloc_heap<uint8_t>>;
// << 演算子の定義
template <class L_STRM, class ALOC>
mwx::stream<L_STRM>& operator << (
mwx::stream<L_STRM>& lhs,
mwx::_smplbuf_stream<uint8_t, ALOC>& rhs)
{
lhs << rhs.to_stream();
return lhs;
}
例
smplbuf_strm_u8<128> sb1;
sb1 << "hello";
sb1 << uint32_t(0x30313233);
sb1 << format("world%d",99);
sb1.printfmt("Z!");
Serial << sb1;
// hello0123world99Z!
1.1.4.9 - smplque
template <typename T, int N, class Intr> smplbuf_local
template <typename T, class Intr> smplbuf_attach
template <typename T, class Intr> smplbuf_heap
smplque
は要素の型T
とメモリの確保方法alloc
で指定したメモリ領域に対してFIFOキューの操作を提供するコンテナクラスです。alloc
の指定は煩雑であるためusing
を用いた別名定義が行っています。
宣言時に割り込み禁止設定を行うクラスIntr
を登録することが出来ます。このクラスは指定しない場合は、割り込み禁止制御を行わない通常の動作となります。
オブジェクトの宣言例です。宣言の直後に初期化用のメソッド呼び出しを行います。いずれも初期化直後の最大サイズは128バイトで、初期サイズは0で何も格納されていません。最大サイズは変更できません。
void some_func() {
// 内部に固定配列
smplque_local<uint8_t, 128> q1;
// すでにある配列を利用する
uint8_t buf[128];
smplque_attach<uint8_t> q2;
// ヒープに確保する
smplque_heap<uint8_t> q3;
}
void setup() {
// グローバル定義のオブジェクトは setup() で初期化
q1.init_local();
q2.attach(buf, 128);
q3.init_heap(128);
}
void some_func() {
// ローカル定義の smplque_local は init_local() は省略できる
smplque_local<uint8_t, 128> q_local;
..
}
FIFOキューですのでpush()
,pop()
,front()
といったメソッドを用いて操作します。
void begin() { // begin() は起動時1回のみ動作する
smplque_local<int, 32> q1;
q1.push(1);
q1.push(4);
q1.push(9);
q1.push(16);
q1.push(25);
while(!q1.empty()) {
Serial << int(q1.front()) << ',';
q1.pop();
}
// output -> 1,4,9,16,25,
}
イテレータによるアクセスも可能です。
void begin() { // begin() は起動時1回のみ動作する
smplque_local<int, 32> q1;
q1.init_local();
q1.push(1);
q1.push(4);
q1.push(9);
q1.push(16);
q1.push(25);
// イテレータを利用
for(int x : q1) {
Serial << int(x) << ',';
}
// STLアルゴリズムの適用
auto&& minmax = std::minmax_element(q1.begin(), q1.end());
Serial << "min=" << int(*minmax.first)
<< ",max=" << int(*minmax.second);
// output -> 1,4,9,16,25,min=1,max=25[]
}
宣言・初期化
smplbuf_local<T,N>
smplbuf_local<T,N>::init_local()
smplbuf_attach<T>
smplbuf_attach<T>::attach(T* buf, uint16_t N)
smplbuf_heap<T>
smplbuf_heap<T>::init_heap(uint16_t N);
//例
// 内部に固定配列
smplque_local<uint8_t, 128> q1;
q1.init_local();
// すでにある配列を利用する
uint8_t buf[128];
smplque_attach<uint8_t> q2;
q2.attach(buf, 128);
// ヒープに確保する
smplque_heap<uint8_t> q3;
q3.init_heap(128);
型T
でサイズN
のコンテナを宣言します。宣言後に初期化のメソッドを呼び出します。
smplque_local
は、内部に固定配列により領域を確保します。コンストラクタによる初期化も可能です。
smplque_attach
では、使用するバッファの先頭ポインタT* buf
と配列の初期サイズsize
と最大サイズN
を指定します。コンストラクタによる初期化も可能です。
smplque_heap
は、HEAP領域(解放は不可能だが随時確保可能なメモリ領域)にメモリを確保します。一度確保したら開放できない領域ですので通常はグローバル領域に定義します。領域確保はinit_heap()
で行います。コンストラクタによるメモリ確保はできません。必ずinit_heap()
を呼び出して利用してください。
setup()
を推奨)に初期化関数init_local()
,attach()
,init_heap()
を呼び出すようにしてください。メソッド
push()
, pop()
, front()
, back()
inline void push(T&& c)
inline void push(T& c)
inline void pop()
inline T& front()
inline T& back()
inline T& pop_front()
push()
はエントリをキューに追加します。
pop()
はエントリをキューから抹消します。
front()
は先頭のエントリ(一番最初に追加されたもの)を参照します。
back()
は末尾のエントリ(一番最後に追加されたもの)を参照します。
pop_front()
は先頭のエントリを戻り値として参照し、同時にそのエントリをキューから抹消します。
empty()
, size()
, is_full()
inline bool empty()
inline bool is_full()
inline uint16_t size()
inline uint16_t capacity()
empty()
は配列に要素が格納されていない場合にtrue
を戻します。is_full()
は反対に配列サイズ一杯まで要素が格納されているときにtrue
を戻します。
size()
はキューに格納されている要素数を返します。
capacity()
はキューの最大格納数を返します。
clear()
inline void clear()
キューのすべての要素を抹消します。
operator []
inline T& operator[] (int i)
要素にアクセスします。0
が最初に追加した要素です。
イテレータ
inline smplque::iterator begin()
inline smplque::iterator end()
begin()
とend()
によるイテレータを取得できます。イテレータの先頭はキューの最初に登録した要素です。イテレータを用いることで範囲for文やアルゴリズムが利用できます。
応用としてaxis_xyzt
構造体の特定のメンバーに注目したイテレータによるアクセスがあります。
1.1.4.10 - 入出力ストリーム
- CRTP (Curiously Recurring Template Pattern) 手法を用いたポリモーフィズムにより、いくつかのクラス(
Serial, Wire, SPI, smplbuf
) にインタフェースを提供します。- CRTP では下位クラスは
template class Derived : public stream<Derived>;
のように定義し、上位クラスからも下位クラスのメソッドを参照します。
- CRTP では下位クラスは
- 本クラスでは
print
メソッド、<<
演算子などの共通処理の定義を行い、下位クラスで実装したwrite()
メソッドなどを呼び出すことで、仮想関数を用いるのと近い実装を行っています。
インタフェース(下位クラスで実装)
下位クラスでは、以下に列挙する関数を実装します。
available()
int available()
// example
while(Serial.available()) {
int c = Serial.read();
// ... any
}
入力が存在する場合は 1、存在しない場合は 0 を返します。
パラメータ | 解説 |
---|---|
戻り値 int | 0: データなし 1:データあり |
flush()
void flush()
// example
Serial.println("long long word .... ");
Serial.flush();
出力をフラッシュ(出力完了まで待つ)します。
read()
int read()
// example
int c;
while (-1 != (c = read())) {
// any
}
ストリームより1バイトデータを入力します。データが存在しない場合は -1
を戻します。
write()
size_t write(int c)
// example
Serial.write(0x30);
ストリームに1バイト出力します。
パラメータ | 解説 |
---|---|
n | 出力したい文字。 |
戻り値 size_t | 出力が成功すれば 1、失敗すれば 0。 |
vOutput()
static void vOutput(char out, void* vp)
1バイト出力を行うスタティック関数です。クラスメソッドではないため、メンバー変数等の情報は利用できません。替わりにパラメータとして渡される vp にクラスインスタンスへのポインタを渡します。
このスタティック関数は内部的に利用されfctprintf()
の1バイト出力関数として関数ポインタが渡ります。これを用いてprint
メソッドなどを実装しています。
パラメータ | 解説 |
---|---|
out | 出力したい文字 |
vp | クラスインスタンスへのポインタ 通常は、元のクラスにキャストして write() メソッドを呼び出す |
インタフェース
putchar()
void mwx::stream::putchar(char c)
// example
Serial.putchar('A');
// result -> A
1バイト出力します。
print()
, println()
size_t print(T val, int base = DEC) // T: 整数型
size_t print(double val, int place = 2)
size_t print(const char*str)
size_t print(std::initializer_list<int>)
// example
Serial.print("the value is ");
Serial.print(123, DEC);
Serial.println(".");
// result -> the value is 123.
Serial.print(123.456, 1);
// result -> 123.5
Serial.print({ 0x12, 0x34, 0xab, 0xcd });
// will output 4byte of 0x12 0x34 0xab 0xcd in binary.
各種整形出力を行います。
パラメータ | 解説 |
---|---|
val | 整形出力したい数値型 |
base | 出力形式BIN 二進数 / OCT 8進数 / DEC 10進数 / HEX 16進数 |
place | 小数点以下の桁数 |
戻り値 size_t | 書き出したバイト数 |
printfmt()
size_t printfmt(const char* format, ...);
// example
Serial.printfmt("the value is %d.", 123);
// result -> the value is 123.
printf 形式での出力を行います。
TWESDK/TWENET/current/src/printf/README.md 参照
operator <<
// examples
Serial << "this value is" // const char*
<< int(123)
<< '.';
<< mwx::crlf;
// result -> this value is 123.
Serial << fromat("this value is %d.", 123) << twe::crlf;
// result -> this value is 123.
Serial << mwx::flush; // flush here
Serial << bigendian(0x1234abcd);
// will output 4byte of 0x12 0x34 0xab 0xcd in binary.
Serial << int(0x30) // output 0x30=48, "48"
<< '/'
<< uint8_t(0x31); // output '1', not "48"
// result -> 48/1
smplbuf<char,16> buf = { 0x12, 0x34, 0xab, 0xcd };
Serail << but.to_stream();
// will output 4byte of 0x12 0x34 0xab 0xcd in binary.
Seiral << make_pair(buf.begin(), buf.end());
// will output 4byte of 0x12 0x34 0xab 0xcd in binary.
Serial << bytelist({ 0x12, 0x34, 0xab, 0xcd });
// will output 4byte of 0x12 0x34 0xab 0xcd in binary.
引数型 | 解説 |
---|---|
char | 1バイト出力 (数値としてフォーマットはしない) |
int | 整数出力 (printf の “%d”) |
double | 数値出力 (printf の “%.2f”) |
uint8_t | 1バイト出力する(char型と同様) |
uint16_t | 2バイト出力する(ビッグエンディアン順) |
uint32_t | 4バイト出力する(ビッグエンディアン順) |
const char*``uint8_t*``const char[S] | 終端文字までを出力します。出力には終端文字は含まれません。(S は固定配列のサイズ指定) |
uint8_t[S] | 配列サイズS バイト分をそのまま出力します。(S は固定配列のサイズ指定) |
format() | printf 形式での出力 |
mwx::crlf | 改行 CRLF の出力 |
mwx::flush | 出力のフラッシュ |
bigendian() | 数値型をビッグエンディアン順で出力する。(右辺値) |
std::pair<T*, T*> | バイト型の begin(), end() ポインタを格納したペア。make_pair により生成できる。T は uint8_t 型を想定する。(右辺値) |
bytelist() | std::initializer_list を用いるバイト列の出力 |
smplbuf<uint8_t,AL>& | uint8_t 型の配列クラスの内容を出力する。ALC はメモリ確保手段。 |
smplbuf<uint8_t, AL>::to_stream() | smplbuf<T> のデータを出力するT は uint8_t 型、AL はメモリ確保手段。 |
uint8_t, uint16_t, uint32_t
型にキャストします。また文字列として数値出力する場合は明示的にint
形にキャストするようにしてください。uint8_t[S]
型を用いるようにしてください。set_timeout()
, get_error_status()
, clear_error_status()
uint8_t get_error_status()
void clear_error_status()
void set_timeout(uint8_t centisec)
// example
Serial.set_timeout(100); // 1000msのタイムアウトを設定
uint8_t c;
Serial >> c;
>>
演算子を用いた入力タイムアウトとエラーを管理します。
set_timeout()
によりタイムアウト時間を指定し、>>
演算子により入力処理を行います。所定時間内までに入力が得られない場合は get_error_status()
によりエラー値を読み出せます。clear_error_status()
によりエラー状況をクリアします。
引数型 | 解説 |
---|---|
centisec | 1/10秒単位でタイムアウト時間を設定します。0xff を指定した場合は、タイムアウトを無効とします。 |
エラー値
値 | 意味 |
---|---|
0 | エラーなし |
1 | エラー状況 |
operator >>
inline D& operator >> (uint8_t& v)
inline D& operator >> (char_t& v)
template <int S> inline D& operator >> (uint8_t(&v)[S])
inline D& operator >> (uint16_t& v)
inline D& operator >> (uint32_t& v)
inline D& operator >> (mwx::null_stream&& p)
//// 例
uint8_t c;
the_twelite.stop_watchdog(); // ウォッチドッグの停止
Serial.set_timeout(0xFF); // タイムアウト無し
// 1バイト読み出す
Serial >> c;
Serial << crlf << "char #1: [" << c << ']';
// 読み捨てる
Serial >> null_stream(3); // 3バイト分読み捨てる
Serial << crlf << "char #2-4: skipped";
// 4バイト分読み出す (uint8_t 型固定長配列限定)
uint8_t buff[4];
Serial >> buff;
Serial << crlf << "char #5-8: [" << buff << "]";
入力処理を行います。
setup()
内では実行できません。- ポーリング待ちを行うため、タイムアウトの時間設定(タイムアウト無しなど)によっては、ウォッチドッグタイマーが発動してリセットする場合があります。
通常はloop()
中で以下のような読み出しを行います。
void loop() {
uint8_t c;
while(Serial.available()) {
Serial >> c;
// または c = Serial.read();
switch(c) { ... } // cの値によって処理を分岐する
}
}
以下に読み出し格納できる型を列挙します。
引数型 | 解説 |
---|---|
uint8_t, char_t | 1バイト入力 |
uint16_t | 2バイト入力(ビッグエンディアン順) |
uint32_t | 4バイト入力(ビッグエンディアン順) |
uint8_t[S] | S バイト分入力(S は固定配列のサイズ指定) |
null_stream(int n) | n バイト読み捨てる |
1.1.4.10.1 - mwx::mwx_format
mwx::stream
の « 演算子に対してフォーマット書式を書き出すヘルパークラスです。ライブラリ内では Using format=mwx::mwx_format;
として別名定義しています。
Serial << format("formatted print: %.2f", (double)3123 / 100.) << mwx::crlf;
// formatted print: 31.23[改行]
- コンストラクタで受け取った引数リストを、パラメータパックの展開機能を用いてクラス内部変数に格納する
operator <<
が呼び出された時点で、fctprintf()
を呼び出し、ストリームにデータを書き出す
コンストラクタ
format(const char *fmt, ...)
コンストラクタでは、書式のポインタとパラメータを保存します。続く <<
演算子による呼び出しでフォーマットを解釈して出力処理を行います。
パラメータ | 解説 |
---|---|
fmt | フォーマット書式。TWESDK/TWENET/current/src/printf/README.md 参照 |
... | フォーマット書式に応じたパラメータ。 ※ 最大数は4で、5つ以上のパラメータではコンパイルエラーとなる。※ 書式との整合性はチェックしないため、不整合な入力に対しては安全ではない。 |
fmt
は本オブジェクトが破棄されるまで、アクセス可能であることが必要です。1.1.4.10.2 - mwx::bigendian
mwx::stream
の <<
演算子に対して数値型をビッグエンディアンのバイト列で出力するヘルパークラスです。
Serial << mwx::bigendian(0x1234abcdUL);
// output binary -> 0x12 0x34 0xab 0xcd
コンストラクタ
template <typename T>
bigendian::bigendian(T v)
パラメータ | 解説 |
---|---|
v | uint16_t または uint32_t の型の値 |
1.1.4.10.3 - mwx::crlf
mwx::stream
の <<
演算子に対して改行コード (CR LF) を出力するためのヘルパークラスのインスタンスです。
Serial << "hello world!" << mwx::crlf;
1.1.4.10.4 - mwx::flush
mwx::stream
の出力バッファをフラッシュします。flush()
メソッドを呼び出すヘルパークラスへのインスタンスです。
for (int i = 0; i < 127; ++i) {
Serial << "hello world! (" << i << ")" << twe::endl << twe::flush;
}
- シリアルポートの場合は出力完了までポーリング待ちを行う
mwx::simpbuf
バッファの場合は0x00
を末尾に出力する(サイズは変更しない)
1.1.4.10.5 - stream_helper
stream_helper
は、mwx::stream
インタフェースを付与するヘルパーオブジェクトです。データクラスを参照するヘルパーオブジェクトを生成し、ヘルパーオブジェクト経由でデータの入出力を行います。以下にはsmplbufの配列b
からヘルパーオブジェクトbs
を生成しmwx::stream::operator <<()
演算子によるデータ入力を行っています。
smplbuf_u8<32> b;
auto&& bs = b.get_stream_helper(); // ヘルパーオブジェクト
// データ列の生成
uint8_t FOURCHARS[]={'A', 'B', 'C', 'D'};
bs << FOURCHARS;
bs << ';';
bs << uint32_t(0x30313233); // "0123"
bs << format(";%d", 99);
Serial << b << crlf; // Serialへの出力は smplbuf_u8<32> クラス経由で
//結果: ABCD;0123;99
概要
stream_helper
はデータ配列をストリームに見立てて振舞います。
内部にはデータ配列中の読み書き位置を保持しています。次のようにふるまいます。
- 読み出しまたは書き込みをすると次の読み書き位置に移動します。
- 最期のデータを読み出した後、またはデータを末尾に追記した後には、読み書き位置は終端となります。
- 読み書き位置が終端の場合、
available()
がfalse
になります。- 読み出しは出来ません。
- 書き込みは書き込み可能範囲であれば追記します。
stream_helper
の生成
stream_helper
は、データクラス (smplbuf, EEPROM) のメンバー関数より生成します。
auto&& obj_helper = obj.get_stream_helper()
// obj はデータクラスのオブジェクト、obj_helperの型は長くなるのでauto&&で受けています。
メソッド
rewind()
void rewind()
読み書き位置を先頭に移動します。
seek()
int seek(int offset, int whence = MWX_SEEK_SET)
読み書き位置を設定します。
whence | 設定位置 |
---|---|
MWX_SEEK_SET | 先頭位置から設定します。offset に0 を指定するとrewind() と同じ意味になります。 |
MWX_SEEK_CUR | 現在位置を基準にoffset 分移動しまします。 |
MWX_SEEK_END | 終端位置にします。offset は0 にすると終端に設定します。-1 を設定すると最後の文字に移動します。 |
tell()
int tell()
読み書き位置を返します。終端位置の場合は-1
を返します。
available()
int available()
読み書き位置が終端であれば0
を返します。終端でなければそれ以外の値を返します。
1.1.4.11 - SM_SIMPLE ステートマシン
SM_SIMPLE
は、サンプルコード中の状態遷移、タイムアウト待ち、送信完了などの処理待ちを行うために用意しています。SM_SIMPLE
の基本的なコードを示します。
##include <SM_SIMPLE>
enum class STATE : uint8_t {
INIT = 0,
SENSOR,
TX,
TX_WAIT_COMP,
GO_SLEEP
};
SM_SIMPLE<STATE> step;
begin() {
...
step.init(); //初期化
}
loop() {
do {
switch(step.state()) {
case STATE::INIT:
...
step.next(STATE::SENSOR);
break;
case STATE::SENSOR:
...
step.next(STATE::TX);
break;
case STATE::TX:
if (/*送信要求成功*/) {
step.set_timeout(100); // タイムアウトの設定
step.clear_flag(); //処理待ち
step.next(STATE::TX_WAIT_COMP);
}
break;
case STATE::TX_WAIT_COMP:
if (step.is_timeout()) the_twelite.reset_system(); // タイムアウト
if (step.is_flag_ready()) sleepNow(); // flagがセットされた
break;
...
}
} while(step.b_more_loop());
}
void on_tx_comp(mwx::packet_ev_tx& ev, bool_t &b_handled) {
step.set_flag(ev.bStatus);
}
void sleepNow() {
step.on_sleep(false); // reset state machine.
the_twelite.sleep(10000); // 10sec
}
解説
SM_SIMPLE
を利用するには状態一覧としてのenum class
定義が必要です。上記ではSTATE
として定義しています。このステージをパラメータとしてSM_SIMPLE<STATE> step;
のようにクラスオブエクトを生成します。生成したクラスオブジェクトは.setup()
により初期化しておきます。
enum class STATE : uint8_t {
INIT = 0,
SENSOR,
TX,
TX_WAIT_COMP,
GO_SLEEP
};
SM_SIMPLE<STATE> step;
void setup() {
step.init();
}
SM_SIMPLE
の初期状態は値が0で、上記の例ではSTATE::INIT
が対応します。現在の状態を取得するには.state()
を用、上記例のように_do while_文中の_switch_節の判定式に用います。
loop() {
do {
switch(step.state()) {
case STATE::INIT: // 値0の状態
...
状態の遷移には.next()
を呼び出します。状態が変更された場合、b_more_loop()
がtrue
になり_do while_節のループがもう一度実行されます。例ではSTATE::SENSOR
状態から.next(STATE::TX)
を呼び出すことで、ループがもう一度実行されcase STATE::TX:
節も実行されることになります。状態を変更しない場合は_do while_ループを脱出しloop()
を一旦終了します。次のloop()
の呼び出しまで一旦待ちます。
do {
switch(step.state()) {
...
case STATE::SENSOR:
...
step.next(STATE::TX); // (1)状態遷移
break;
case STATE::TX: // (3) 2回めのループで呼び出される
if (/*送信要求成功*/) {
...
}
} while (b_more_loop()); // (2) ループ継続判定 true
送信完了などの処理待ちをしたい場合は.clear_flag()
を呼び出し、別のコールバック関数などで.set_flag(uint32_t)
により処理完了を知らせます。ここで指定したuint32_t
型のパラメータをは.get_flag_value()
から読み出せます。
またタイムアウトの処理を行いたい場合は.set_timeout(uint32_t)
を呼び出した時刻を記録し、.is_timeout()
によりタイムアウト時間が経過したかを調べることができます。
case STATE::TX:
if (/*送信要求成功*/) {
step.set_timeout(100); // タイムアウトの設定
step.clear_flag(); //処理待ち
step.next(STATE::TX_WAIT_COMP);
}
break;
case STATE::TX_WAIT_COMP:
if (step.is_timeout()) ...; // タイムアウト
if (step.is_flag_ready()) ...; // flagがセットされた
break;
...
// 送信完了イベント
void on_tx_comp(mwx::packet_ev_tx& ev, bool_t &b_handled) {
step.set_flag(ev.bStatus); // flag を設定する
}
スリープからの復帰で再びSM_SIMPLE
を利用することになりますが、スリープ前に必ず.on_sleep(bool)
を呼び出すようにします。パラメータにfalse
を入れると復帰後に0
状態から開始し、true
を入れるとスリープ直前の状態から再開します。
void sleepNow() {
step.on_sleep(false); // reset state machine.
the_twelite.sleep(10000); // 10sec
}
ソースコード
以下にSM_SIMPLE
のソースコードを示します。
// very simple class to control state used in loop().
template <typename STATE>
class SM_SIMPLE {
uint32_t _u32_flag_value; // optional data when flag is set.
uint32_t _ms_start; // system time when start waiting.
uint32_t _ms_timeout; // timeout duration
STATE _step; // current state
STATE _step_prev; // previous state
bool_t _b_flag; // flag control.
public:
// init
void setup() { memset(this, 0, sizeof(SM_SIMPLE)); }
// call befoer sleeping (save state machine status)
void on_sleep(bool b_save_state = false) {
STATE save = _step;
setup();
if(b_save_state) _step = _step_prev = save;
}
// state control
void next(STATE next) { _step = next; } // set next state
STATE state() { return _step; } // state number
bool b_more_loop() { // if state is changed during the loop, set true
if (_step != _step_prev) { _step_prev = _step; return true; }
else return false;
}
// timeout control
void set_timeout(uint32_t timeout) {
_ms_start = millis();
_ms_timeout = timeout;
}
bool is_timeout() { return (millis() - _ms_start) >= _ms_timeout; }
// flag control
void clear_flag() { _b_flag = false; _u32_flag_value = 0; }
void set_flag(uint32_t u32_flag_value = 0) {
_b_flag = true;
_u32_flag_value = u32_flag_value; }
uint32_t get_flag_value() { return _u32_flag_value; }
bool is_flag_ready() { return _b_flag; }
};
- バージョンによって内容が変化する場合があり。
- 本体は MWX ライブラリソースフォルダの
SM_SIMPLE.hpp
に格納されます。
1.1.5 - コールバック関数
以下のコールバック関数は必須定義です。
setup()
loop()
それ以外の関数は定義しない場合は、何も実行しない空の関数が替わりにリンクされます。
通常のコールバック呼び出し順序
init_coldboot()
↓ (TWENET内部処理:初期化1)
setup()
↓(TWENET内部処理:初期化2)
begin() --- 初回のみ
↓
loop() <--+
↓ |イベント処理、ビヘイビア処理
CPU DOZE -+
mwx_appcore.cpp
を参照してください。スリープ復帰時のコールバック呼び出し順序
the_twelite.sleep()
↓ sleeping...
init_warmboot()
↓ (TWENET内部処理:初期化3)
wakeup()
↓(TWENET内部処理:初期化4)
loop() <--+
↓ |イベント処理、ビヘイビア処理
CPU DOZE -+
mwx_appcore.cpp
を参照してください。1.1.5.1 - setup()
TWENETの初期化は setup()
関数が終了した後にも実行されます。多くの処理はTWENETが終了した後に実行するようになっているため、ここでは初期化以外の処理を行わないようにしてください。
注意すべき事項を以下に列挙します。
- スリープ
the_twenet.sleep()
の実行はできません。初期化後速やかにスリープしたいときはbegin()
関数内に最初のスリープ処理を記述してください。 delay()
関数は後述の処理に置き換えられます。この場合、パラメータのms
はミリ秒を指定するものではありません。
static inline void delay(uint32_t ms) {
volatile uint32_t ct = ms * 4096;
while (ct > 0) {
--ct;
}
}
1.1.5.2 - begin()
loop()
関数の初回コールの手前で一度だけ呼び出されます。TWENET の初期化は終了しているのでsetup()
のような制約を考慮する必要はありません。主に下記のような場面で使用します。
- 始動メッセージの表示
- テスト用のコードを記述
- 始動直後のスリープ遷移
setup()
で不都合がある処理(無線パケット処理・タイマー動作など)
1.1.5.3 - loop()
アクトでは、ほとんどの処理がこのループ内に記述されます。
1.1.5.4 - wakeup()
loop()
に移行する前に呼ばれ、スリープ復帰後の初期化処理や復帰状態によって処理を分岐するための手続きを含めます。loop()
での処理がないときは、この関数内で再びスリープを実行できます。1.1.5.5 - init_coldboot()
1.1.5.6 - init_warmboot()
1.1.5.7 - on_rx_packet()
void on_rx_packet(mwx::packet_rx& pkt, bool_t &b_handled)
無線パケットを受信したときにpacket_rx
として pkt
にデータが格納された状態で、本関数が MWX ライブラリ内から呼び出されます。アプリケーション中で本関数が定義されない場合は何もしない weak 関数がリンクされます。
本関数中で b_handled
に true をセットすると、MWX ライブラリに受信パケットがアプリケーション内で処理されたことを伝達します。処理済みとした場合、不要な処理を抑制します。(the_twelite.receiver
の処理を行わない)
the_twelite.receiver
は推奨されません。
従来loop()
内での記述を意図して the_twelite.receiver
による処理を行っていましたが、キューによる遅延処理である点で原理的に取りこぼしが発生し、また記述も煩雑になりがちである点から on_rx_packet()
を追加しました。
1.1.5.8 - on_tx_comp()
void on_tx_comp(mwx::packet_ev_tx& ev, bool_t &b_handled)
無線パケットの送信が終了したときにpacket_ev_tx
として ev
にデータが格納された状態で、本関数が MWX ライブラリ内から呼び出されます。アプリケーション中で本関数が定義されない場合は何もしない weak 関数がリンクされます。
ev.u8CbId
は送信時のID、ev.bStatus
は送信の成功(1)または失敗(0)を示すフラグです。
本関数中で b_handled
に true をセットすると、MWX ライブラリに受信パケットがアプリケーション内で処理されたことを伝達します。処理済みとした場合、不要な処理を抑制します。(the_twelite.app
, .board
, .settings
に対してはイベントコールバック関数を呼び出さない)
1.1.6 - ビヘイビア
the_twelite
クラスオブジェクトに登録できるようになります。登録したビヘイビアはTWENETに組み込まれて動作し、ユーザコードではアプリケーションの振る舞いを記述できます。ループでの記述とは異なり、TWENETからの割り込みハンドラやイベントのコールバック関数を定義できます。記述量が多くなりますが、より複雑なアプリケーションの構築に適しています。クラス定義 (.hpp
)
ビヘイビアの定義には下記に示すようなクラス定義が必要です。
class MY_APP_CLASS: MWX_APPDEFS_CRTP(MY_APP_CLASS)
{
public:
static const uint8_t TYPE_ID = 0x01;
// load common definition for handlers
#define __MWX_APP_CLASS_NAME MY_APP_CLASS
#include "_mwx_cbs_hpphead.hpp"
#undef __MWX_APP_CLASS_NAME
public:
// constructor
MY_APP_CLASS() {}
void _setup() {}
void _begin() {}
public:
// TWENET callback handler (mandate)
void loop() {}
void on_sleep(uint32_t & val) {}
void warmboot(uint32_t & val) {}
void wakeup(uint32_t & val) {}
void on_create(uint32_t& val) { _setup(); }
void on_begin(uint32_t& val) { _begin(); }
void on_message(uint32_t& val) { }
public:
void network_event(mwx::packet_ev_nwk& pEvNwk) {}
void receive(mwx::packet_rx& rx) {}
void transmit_complete(mwx::packet_ev_tx& evTx) {}
};
上記の例ではMY_APP_CLASSという名前でビヘイビアクラスを定義しています。いくつかの箇所にMY_APP_CLASSの記述が必要です。
class MY_APP_CLASS: MWX_APPDEFS_CRTP(MY_APP_CLASS)
クラス名の定義と、ベース(親)クラスの定義をします。MWX_APPDEFS_CRTP()
はマクロです。
#define __MWX_APP_CLASS_NAME MY_APP_CLASS
#include "_mwx_cbs_hpphead.hpp"
#undef __MWX_APP_CLASS_NAME
ここでは必要な定義を #include
により取り込んでいます。
MY_APP_CLASS() {}
コンストラクタの定義です。
メソッド
loop()
メインループで、グローバル定義のloop()
と同じ役割の関数です。
on_create()
on_create()
はオブジェクト生成時(use<>()
メソッド)に呼び出されます。val
は将来の拡張のためのパラメータです。
on_begin()
on_begin()
はsetup()
終了後に呼び出されます。val
は将来の拡張のためのパラメータです。
on_sleep()
スリープ前に呼び出されます。val
は将来の拡張のためのパラメータです。
warmboot()
スリープ復帰時の初期段階で呼び出されます。val
は将来の拡張のためのパラメータです。
この時点でまだペリフェラルが初期化されていません。スリープ起床要因の確認ができます。
wakeup()
スリープ復帰時に呼び出されます。val
は将来の拡張のためのパラメータです。
receive()
void receive(mwx::packet_rx& rx)
パケットが受信されたとき、受信したパケット情報をrx
として呼び出されます。
transmit_complete()
void transmit_complete(mwx::packet_ev_tx& evTx)
パケット送信完了時に送信情報をevTx
として呼び出されます。evTx.u8CbId
が送信時のIDでevTx.bStatus
が送信の成功(1
)失敗(0
)を示すフラグです。
ハンドラの定義 (.cpp
)
ビヘイビアのハンドラ(割り込み、イベント、状態定義)はcppファイルに定義します。ファイルは分割できず、全てのハンドラ定義を一つのファイル中に記述します。
cppファイルの冒頭と末尾にはMWXライブラリの必要な定義(#include "_mwx_cbs_cpphead.hpp"
)をインクルードする必要があります。
##include <TWELITE>
##include "myAppClass.hpp" // ビヘイビア定義ファイル
/*****************************************************************/
// MUST DEFINE CLASS NAME HERE
##define __MWX_APP_CLASS_NAME MY_APP_CLASS
##include "_mwx_cbs_cpphead.hpp" // 冒頭の定義
/*****************************************************************/
ファイルの冒頭には、上記のようにビヘイビア定義の.hppファイルをインクルードします。__MWX_APP_CLASS_NAME
にはビヘイビアのクラス名を指定します。上記ではMY_APP_CLASS
です。
/*****************************************************************/
// common procedure (DO NOT REMOVE)
##include "_mwx_cbs_cpptail.cpp"
// MUST UNDEF CLASS NAME HERE
##undef __MWX_APP_CLASS_NAME
/*****************************************************************/
ファイルの末尾では必要な定義(#include "_mwx_cbs_cpptail.cpp"
)をインクルードします。
ハンドラ定義は以下の例のように記述します。定義の種別については後述します。定義用のマクロを用いて利用したいハンドラの定義を記述します。利用しないハンドラは記述しないようにしてください。
MWX_???_INT()
は割り込みハンドラの定義、MWX_???_EVENT()
はイベントハンドラの定義、MWX_STATE()
はステートマシンの状態定義です。
// TickTimer割り込み
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);
}
// PAL_AMB::PIN_BIN(12)のイベント
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;
}
// 状態 STATE_0 の動作定義
MWX_STATE(E_MWX::STATE_0, uint32_t ev, uint32_t evarg) {
if (ev == E_EVENT_START_UP) {
Serial << "[STATE_0:START_UP]" << mwx::crlf;
} else
if (ev == E_ORDER_KICK) {
PEV_SetState(E_MWX::STATE_1);
}
}
// 状態 STATE_1 の動作定義
MWX_STATE(E_MWX::STATE_1, uint32_t ev, uint32_t evarg) {
if (ev == E_EVENT_NEW_STATE) {
Serial << "[STATE_1]" << mwx::crlf;
} else
if (ev == E_ORDER_KICK) {
PEV_SetState(E_MWX::STATE_2);
} else
if (ev == E_EVENT_TICK_SECOND) {
Serial << "<1>";
}
}
割り込み・イベントハンドラ
割り込みハンドラは、マイコンの割り込みが発生したときに現在実行中のコードを中断して実行されます。このため、可能な限り短い処理を記述することが望ましく、また、変数等の操作に対しても細心の注意が必要です。
割り込みハンドラのパラメータにはuint8_t& handled
があり、この値をtrue
にセットすることで、続くイベント呼び出しを行いません。
handled
がfalse
のまま割り込みハンドラを終了した場合、アプリケーションループ(通常コード)の中でイベントハンドラが呼び出されます。イベントハンドラにはhandled
のパラメータはありません。イベントハンドラは通常コードですので、比較的大きな処理を行うことが出来ます。イベントハンドラのオーバーヘッドも発生するため、頻繁な割り込み都度呼び出されるような処理の場合、処理しきれなくなる可能性があります。また、イベントの発生はシステム内部のFIFOキューにより処理されるため、一定時間内に処理できない場合はイベントが消失する場合もあります。
以下にハンドラ関数定義用のマクロの解説を行います。
DIO
MWX_DIO_INT(N, uint32_t arg, uint8_t& handled)
MWX_DIO_EVENT(N, arg)
DIO(ディジタルIO)割り込み・イベントです。N
は対象DIOの番号を指定します。arg
は将来の拡張のための定義です。
割り込みを発生させるためにはpinMode()
による適切な入力設定, attachDioInt()
による割り込み開始の設定が必要です。
TICKTIMER
MWX_TICKTIMER_INT(uint32_t arg, uint8_t& handled)
MWX_TICKTIMER_EVENT(uint32_t arg)
TickTimer割り込み・イベントです。arg
は将来の拡張のための定義です。
handled
フラグをtrue
にセットしてはいけません。TWENETが動作しなくなります。TIMER
MWX_TIMER_INT(N, uint32_t arg, uint8_t& handled)
MWX_TIMER_EVENT(N, uint32_t arg)
タイマー割り込み・イベントです。N
は対象タイマーの番号を指定します。arg
は将来の拡張のための定義です。
割り込みを発生させるためには、Timerオブジェクトをソフトウェア割り込みを有効にして開始します。
その他
その他の割り込み・イベントは以下のハンドラ関数で受けることが出来ます。これらは将来的に専用のハンドラが定義された場合、利用できなくなります。
MWX_MISC_INT(uint32_t arg, uint32_t arg2, handled)
MWX_MISC_EVENT(auint32_t rg, uint32_t arg2)
ペリフェラル (AHI) の割り込みハンドラのu32DeviceId
がarg
、u32ItemBitmap
がarg2
に対応します。
状態マシン
状態マシン(ステートマシン)は、メッセージを受け取り、そのメッセージに応じて状態を遷移させながら動作させるアプリケーションの記述方法です。
PAL_AMB-behaviorサンプルでは、センサーの動作開始からセンサーの値取得、無線パケット送信から送信完了まで、スリープ遷移といったアプリケーションの動作の流れを記述しています。実例として参考にしてください。
受け取るイベントは以下となります。
イベント名 | 内容 |
---|---|
E_EVENT_START_UP | システム始動時に呼び出される。電源投入直後はパラメータが0 で呼び出されます。実行初期であるため、通常処理を行う状態に遷移する場合は一旦begin()メソッドからPEV_Process() を呼び出し動作を開始させます。スリープ復帰後も呼び出されるがパラメータは 0 以外です。この状態からは通常処理を行えます。 |
E_EVENT_NEW_STATE | 状態遷移直後に新しい状態で呼び出されます。ある状態に遷移したときに最初に実行される処理を記述します。 |
E_EVENT_TICK_TIMER | 1msごとのTickTimerで呼び出されます。 |
E_EVENT_TICK_SECOND | 1秒毎に呼び出されます。 |
PEV_SetState()
void PEV_SetState(uint32_t s)
状態をs
に設定します。
状態ハンドラを抜けると次の状態に遷移し、続けてE_EVENTS_NEW_STATE
イベントで状態ハンドラが呼び出されます。
PEV_u32Elaspsed_ms()
uint32_t PEV_u32Elaspsed_ms()
状態遷移してからの経過時間[ms]を返します。タイムアウトを管理するような目的で使用します。
MWX_STATE(MY_APP_CHILD::STATE_TX, uint32_t ev, uint32_t evarg) {
...
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();
}
}
上記の例では100ms経過した時点でシステムリセットを行います。
PEV_Process()
void PEV_Process(uint32_t ev, uint32_t u32evarg) {
状態ハンドラ外から呼び出します。状態ハンドラをイベントev
パラメータu32evarg
で実行します。
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_EVENT_NEW_STATE
が実行されないなどの問題が発生します。PEV_KeepStateOnWakeup()
void PEV_KeepStateOnWakeup()
スリープ直前に設定します。スリープ復帰後に、直前の状態を維持します。つまり、スリープを開始した状態でE_EVENT_START_UP
で状態ハンドラが呼び出されます。
PEV_is_coldboot()
bool PEV_is_coldboot(uint32_t ev, uint32_t u32evarg)
イベントが起床時のE_EVENT_START_UP
かどうか判定します。
PEV_is_warmboot()
bool PEV_is_warmboot(uint32_t ev, uint32_t u32evarg)
イベントがスリープ復帰時のE_EVENT_START_UP
かどうか判定します。
1.1.6.1 - PAL_AMB-behavior
環境センサーパル AMBIENT SENSE PAL を用い、センサー値の取得を行います。
アクトの機能
- 環境センサーパル AMBIENT SENSE PAL を用い、センサー値の取得を行います。
- コイン電池で動作させるための、スリープ機能を利用します。
アクトの使い方
TWELITEの準備
役割 | 例 |
---|---|
親機 | MONOSTICK BLUEまたはRED |
子機 | BLUE PAL または RED PAL +環境センサーパル AMBIENT SENSE PAL |
ファイル構成
- 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>
を登録します。
親機のビヘイビア
親機はスリープをしない受信機としてふるまい、子機からのパケットを受信したときにシリアルポートにパケットの情報を出力します。
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.1.7 - 関数
1.1.7.1 - システム関数
1.1.7.1.1 - millis()
uint32_t millis()
システム時刻はTickTimerの割り込みで更新されます。
1.1.7.1.2 - delay()
void delay(uint32_t ms)
ms
にて与えられた期間待ち処理を行います。
時間の計測はTickTimerのカウントによって行っています。また長い時間待ちを行う場合はCPUのクロックを低下してポーリング処理を行います。
delay()
を呼び出してから約5ms経過するごとにTWELITEマイコン内部のウォッチドッグ処理を行います。
※例えばwhile(1) delay(1);
を実行した場合は、delay()
内部で5ms経過しないためウォッチドッグ処理が行われず、一定時間後リセットが実行されます。
setup(), wakeup()
関数内では、TickTimerがまだ動作していないため、whileループによる時間待ち処理になります。この場合、指定値との誤差は大きくなります。このループカウンタは32Mhzに合わせて調整しています。これら関数内でCPUクロックを変化させた場合は、そのクロックに比例した誤差が発生します。
パラメータに1,2といった短い時間を指定した場合は、誤差が大きくなる場合があります。
1.1.7.1.3 - delayMicroseconds()
void delayMicroseconds(uint32_t microsec)
microsec
にて与えられた期間待ち処理を行います。
時間の計測はTickTimerのカウントによって行っています。また長い時間待ちを行う場合はCPUのクロックを低下してポーリング処理を行います。
setup(), wakeup()
関数内では、TickTimerがまだ動作していないため、whileループによる時間待ち処理になります。この場合、指定値との誤差は大きくなります。このループカウンタは32Mhzに合わせて調整しています。これら関数内でCPUクロックを変化させた場合は、そのクロックに比例した誤差が発生します。
パラメータに10以下といった短い時間を指定した場合は、誤差が大きくなる場合があります。
1.1.7.1.4 - random()
uint32_t random(uint32_t maxval)
uint32_t random(uint32_t minval, uint32_t maxval)
1行目は0..(maxval-1)
の値を戻します。maxvalの値が最大値ではないことに注意してください。
2行目はminval..maxval-1
の値を戻します。
1.1.7.2 - 汎用デジタルIO
汎用デジタルIO(DIO)の操作には以下の関数を利用します。
pinMode()
digitalWrite()
digitalRead()
attachIntDio()
detachIntDio()
定数
ピン名と番号
定義 | 名称 |
---|---|
const uint8_t PIN_DIGITAL::DIO0 .. 19 | DIOピン0~19 |
const uint8_t PIN_DIGITAL::DO0 .. 1 | DOピン0,1 |
ピンのモード(DIO0..19)
以下の列挙値は型名 E_PIN_MODE
で取り扱われます。
定義 | プルアップ | 名称 |
---|---|---|
PIN_MODE::INPUT | 無 | 入力 |
PIN_MODE::OUTPUT | 無 | 出力 |
PIN_MODE::INPUT_PULLUP | 有 | 入力 |
PIN_MODE::OUTPUT_INIT_HIGH | 無 | 出力(初期状態HIGH) |
PIN_MODE::OUTPUT_INIT_LOW | 無 | 出力(初期状態LOW) |
PIN_MODE::WAKE_FALLING | 無 | 入力、起床ピン、立下り |
PIN_MODE::WAKE_RISING | 無 | 入力、起床ピン、立上り |
PIN_MODE::WAKE_FALLING_PULLUP | 有 | 入力、起床ピン、立下り |
PIN_MODE::WAKE_RISING_PULLUP | 有 | 入力、起床ピン、立上り |
PIN_MODE::DISABLE_OUTPUT | 有 | 入力状態に戻す |
ピンのモード(DO0,1)
以下の列挙値は型名 E_PIN_MODE
で取り扱われます。
定義 | 名称 |
---|---|
PIN_MODE::OUTPUT | 出力 |
PIN_MODE::OUTPUT_INIT_HIGH | 出力(初期状態HIGH) |
PIN_MODE::OUTPUT_INIT_LOW | 出力(初期状態LOW) |
PIN_MODE::DISABLE_OUTPUT | 出力設定をやめる |
ピンの状態
以下の列挙値は型名 E_PIN_STATE
で取り扱われます。
定義 | 値 | 名称 |
---|---|---|
PIN_STATE::HIGH | 1 | HIGHレベル(=Vccレベル) |
PIN_STATE::LOW | 0 | LOWレベル(=GNDレベル) |
ピンの立ち上がり、立ち下がり
以下の列挙値は型名 E_PIN_INT_MODE
で取り扱われます。
定義 | 名称 |
---|---|
PIN_INT_MODE::FALLING | 立ち下り |
PIN_INT_MODE::RISING | 立ち上がり |
1.1.7.2.1 - pinMode()
void pinMode(uint8_t u8pin, E_PIN_MODE mode)
この関数では DIO0..19 と、DO0,1のピンの状態を変更できます。設定内容は E_PIN_MODE
の列挙値のDIOの解説とDOの解説を参照してください。
DO0,1は特殊なピンで、原則として他の目的で利用されるものですが、出力としても設定可能です。ただしハード的な制約があるピンですので、利用には注意が必要です。
両方のピンは、電源投入時にHIGHレベルが担保される必要があります。不安定な電圧をとったりするような回路構成の場合、モジュールが起動しないなどの問題が出ます。
1.1.7.2.2 - digitalWrite()
static inline void digitalWrite(uint8_t u8pin, E_PIN_STATE ulVal)
事前にpinMode()
にて設定対象のピンを出力用に設定しておきます。1番目のパラメータは、設定対象のピン番号を指定します。2番目のパラメータはHIGH
かLOW
のいずれかを指定します。
E_PIN_STATE
型となっています。E_PIN_STATE
からint
型への変換演算子は定義していませんので、数値による直接の入力はできないようになっています。1.1.7.2.3 - digitalRead()
static inline E_PIN_STATE digitalRead(uint8_t u8pin)
事前に入力に設定したピンの入力値をLOW
またはHIGH
で得ることができます。
E_PIN_STATE
型からint
型への変換演算子は定義していないため、数値型への直接的な代入はできません。1.1.7.2.4 - attachIntDio()
void attachIntDio(uint8_t u8pin, E_PIN_INT_MODE mode)
事前に入力設定したピンに対して、1番目のパラメータは割り込みを有効にしたいピン番号で、2番目は割り込み方向(立ち上がり、立ち下がり)を指定します。
例
DIO5のピンがHIGHからLOWに変化したときに割り込みが発生する設定を行います。
void setup() {
the_twelite.app.use<myAppClass>();
pinMode(PIN_DIGITAL::DIO5, PIN_MODE::INPUT_PULLUP);
attachIntDio(PIN_DIGITAL::DIO5, PIN_INT_MODE::FALLING);
}
void loop() {
;
}
myAppClass.hpp
class myAppClass: public mwx::BrdPal, MWX_APPDEFS_CRTP(myAppClasslMot)
{
};
ビヘイビアmyAppClass
の基本定義。詳細は省略しています。
myAppClass.cpp
/*****************************************************************/
// MUST DEFINE CLASS NAME HERE
##define __MWX_APP_CLASS_NAME myAppClass
##include "_mwx_cbs_cpphead.hpp"
/*****************************************************************/
MWX_DIO_INT(PIN_DIGITAL::DIO5, uint32_t arg, uint8_t& handled) {
static uint8_t ct;
digitalWrite(PIN_DIGITAL::DIO12, (++ct & 1) ? HIGH : LOW);
handled = false; // if true, no further event.
}
MWX_DIO_EVENT(PIN_DIGITAL::DIO5, uint32_t arg) {
Serial << '*';
}
/*****************************************************************/
// common procedure (DO NOT REMOVE)
##include "_mwx_cbs_cpptail.cpp"
// MUST UNDEF CLASS NAME HERE
##undef __MWX_APP_CLASS_NAME
} // mwx
/*****************************************************************/
ビヘイビアmyAppClass
の割り込みハンドラの記述。DIO5の割り込み発生時にDIO12の出力設定を反転させ、割り込みハンドラが終了してから発生するイベントではシリアルポートSerial
に*
を表示します。
1.1.7.2.5 - detachIntDio()
void detachIntDio(uint8_t u8pin)
1.1.7.2.6 - digitalReadBitmap()
uint32_t digitalReadBitmap()
LSB側から順にDIO0 … DIO19 の順に値が格納されます。
HIGH
側のピンには 1 が、LOW
側のピンには 0 が設定されます。
1.1.7.3 - ユーティリティ関数
1.1.7.3.1 - printfの実装
printf()
に近い実装を用意しています。
int mwx_printf(const char* format, ...)
int mwx_snprintf(char* buffer, size_t count, const char* format, ...)
mwx_printf()
はSerial
オブジェクトに対してprintf
出力を行います。Serial.printfmt()
と同じ処理になります。
mwx_snprintf()
はバッファに対してsnprintf
を行います。
mwx::stream
でデータ生成を参照してください。1.1.7.3.2 - pack_bits()
constexpr uint32_t pack_bits(...)
パラメータは可変数引数で指定でき、各パラメータはビット位置を指定する0..31の整数を指定する。例えばpack_bits(1,3,6)
と指定すると((1UL<<1)|(1UL<<3)|(1UL<<6))
を返します。
constexpr
は定数による計算が可能な場合はコンパイル時に定数展開します。背景
IOポート(DI,DO)の状態など各種ビットマップに値を参照・設定する場面があり、その記述を簡素化するため。
1.1.7.3.3 - collect_bits()
constexpr uint32_t collect_bits(uint32_t bm, ...)
パラメータbmに指定する値から、その後の可変数パラメータで指定する0..31のビット位置に対応する値を取り出します。取り出した値はパラメータ順に並べビットマップとして戻り値になります。
ビットマップの並び順は、最初のパラメータを上位ビットとし末尾のパラメータがbit0になります。
uint32_t b1 = 0x12; // (b00010010)
uint32_t b2 = collect_bits(b1, 4, 2, 1, 0);
// bit4->1, bit2->0, bit1->1, bit0->0
// b2=0x10 (b1010)
例ではb1のビット4,2,1,0を取り出すと (1,0,1,0) になります。これをb1010として0x10のように計算されます。
背景
IOポート(DI,DO)の状態など各種ビットマップに値を参照・設定する場面があり、その記述を簡素化するため。
1.1.7.3.4 - Byte array utils
読み出し
バイト配列から、uint8_t
ビッグエンディアン並びとして、uint16_t
, uint32_t
の値を取得する。
inline uint8_t G_BYTE(const uint8_t*& p) {
return *(p)++;
}
inline uint16_t G_WORD(const uint8_t*& p) {
uint32_t r = *p++;
r = (r << 8) + *p++;
return r;
}
inline uint32_t G_DWORD(const uint8_t*& p) {
uint32_t r = *p++;
r = (r << 8) + *p++;
r = (r << 8) + *p++;
r = (r << 8) + *p++;
return r;
}
p
は読み出したバイト数分だけインクリメントされる。
書き込み
ポインタq
で指定するバイト配列にuint8_t
,ビッグエンディアンでuint16_t
,uint32_t
の値を書き込む。
inline uint8_t& S_OCTET(uint8_t*& q, uint8_t c) {
*q++ = c;
return *q;
}
inline uint8_t& S_WORD(uint8_t*& q, uint16_t c) {
*(q) = ((c) >> 8) & 0xff; (q)++;
*(q) = ((c) & 0xff); (q)++;
return *q;
}
inline uint8_t& S_DWORD(uint8_t*& q, uint32_t c) {
*(q) = ((c) >> 24) & 0xff; (q)++;
*(q) = ((c) >> 16) & 0xff; (q)++;
*(q) = ((c) >> 8) & 0xff; (q)++;
*(q) = ((c) & 0xff); (q)++;
return *q;
}
q
は書き込んだバイト数分だけインクリメントされる。
背景
無線パケットのデータペイロードの生成・分解時の操作を簡略化するため。
より簡略化したpack_bytes()
, expand_bytes()
も利用できます。
1.1.7.3.5 - pack_bytes()
uint8_t* pack_bytes(uint8_t* b, uint8_t* e, ...)
pack_bytes
はコンテナクラスのbegin()
,end()
イテレータをパラメータとし、続くパラメータで指定されるデータをバイト列としてコンテナに書き込みます。
可変引数パラメータに与えるデータは以下に示すとおりです。
データ型 | バイト数 | 解説 |
---|---|---|
uint8_t | 1 | |
uint16_t | 2 | ビッグエンディアン並びで格納される |
uint32_t | 4 | ビッグエンディアン並びで格納される |
uint8_t[N] | N | uint8_t 型の固定長配列 |
std::pair<char*,N> | N | char* ,uint8_t* 型の配列と配列長のペア。make_pair() で生成できる。 |
smplbuf_u8& pack_bytes(smplbuf_u8& c, ...)
pack_bytes
はコンテナオブジェクトをパラメータとし、続くパラメータで指定されるデータをバイト列としてコンテナに書き込みます。コンテナの.push_back()
メソッドで末尾に追加します。
可変引数パラメータに与えるデータは以下に示すとおりです。
データ型 | バイト数 | 解説 |
---|---|---|
uint8_t | 1 | |
uint16_t | 2 | ビッグエンディアン並びで格納される |
uint32_t | 4 | ビッグエンディアン並びで格納される |
uint8_t[N] | N | uint8_t 型の固定長配列 |
std::pair<char*,N> | N | char* ,uint8_t* 型の配列と配列長のペア。make_pair() で生成できる。 |
smplbuf_u8? | .size() | uint8_t 型のsmplbuf<> コンテナ。コンテナ長(.size() )のデータを格納する。 |
例
auto&& rx = the_twelite.receiver.read();
smplbuf<uint8_t, 128> buf;
mwx::pack_bytes(buf
, uint8_t(rx.get_addr_src_lid()) // src addr (LID)
, uint8_t(0xCC) // cmd id (0xCC, fixed)
, uint8_t(rx.get_psRxDataApp()->u8Seq) // seqence number
, uint32_t(rx.get_addr_src_long()) // src addr (long)
, uint32_t(rx.get_addr_dst()) // dst addr
, uint8_t(rx.get_lqi()) // LQI
, uint16_t(rx.get_length()) // payload length
, rx.get_payload() // payload
);
この例では受信パケットの各属性やペイロードを別のバッファbuf
に再格納しています。
背景
無全パケットのデータペイロードの生成やデータの取り出しで用いられるuint8_t
型のバイト配列の記述を簡素化するため。
auto&& rx = the_twelite.receiver.read();
uint8_t data[128];
data[0] = rx.get_addr_src_lid();
data[1] = 0xCC;
data[2] = rx.get_psRxDataApp()->u8Seq;
data[4] = rx.get_addr_src_long() & 0x000000FF;
data[5] = (rx.get_addr_src_long() & 0x0000FF00) >> 8;
data[6] = (rx.get_addr_src_long() & 0x00FF0000) >> 16;
data[7] = (rx.get_addr_src_long() & 0xFF000000) >> 24;
...
上記はもっとも単純な記述だが、以下のようにByte array utilsを用いてバイト配列を生成できる。
auto&& rx = the_twelite.receiver.read();
uint8_t data[128], *q = data;
S_OCTET(q, rx.get_addr_src_lid());
S_OCTET(q, 0xCC);
S_OCTET(q, rx.get_psRxDataApp()->u8Seq);
S_DWORD(q, rx.get_addr_src_long());
S_DWORD(q, rx.get_addr_dst());
S_OCTET(q, rx.get_lqi());
S_WORD(q, rx.get_length());
for (auto x : rx.get_payload()) {
S_OCTET(q, x);
}
1.1.7.3.6 - expand-bytes()
const uint8_t* expand_bytes(
const uint8_t* b, const uint8_t* e, ...)
expand_bytes()
は、パラメータにuint8_t*
型のイテレータの組み合わせを指定します。これは解析対象の先頭と末尾の次のイテレータの指定となります。e
の位置まで解析が進んだ場合はエラーとなりnullptr
を返します。
展開にエラーがない場合は、次の読み出しを行うイテレータを戻します。
可変数パラメータには以下を指定します。
バイト数 | データ長 | 解説 |
---|---|---|
uint8_t | 1 | |
uint16_t | 2 | ビッグエンディアン並びとして展開する |
uint32_t | 4 | ビッグエンディアン並びとして展開する |
uint8_t[N] | N | uint8_t 型の固定長配列 |
std::pair<char*,N> | N | char* ,uint8_t* 型の配列と配列長Nのペアmake_pair() で生成できる |
例
auto&& rx = the_twelite.receiver.read();
char fourchars[5]{};
auto&& np =
expand_bytes(rx.get_payload().begin(), rx.get_payload().end()
, make_pair((uint8_t*)fourchars, 4)
);
// 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]
);
この例では、まず4バイトの文字列を読み出しています。ここではmake_pair()
を用いて明示的に4バイト分のデータを読み出します。
戻されたイテレータnp
をもとに、次のデータを読み出します。次のデータはuint8_t
型、あとはuint16_t
型が5つ続いています。
背景
無全パケットのデータペイロードの生成やデータの取り出しで用いられるuint8_t
型のバイト配列の記述を簡素化するため。
auto&& rx = the_twelite.receiver.read();
char fourchars[5]{};
uint8_t u8DI_BM_remote = 0xff;
uint16_t au16AI_remote[5];
uint8_t *p = rx.get_payload().begin();
fourchars[0] = p[0];
fourchars[1] = p[1];
fourchars[2] = p[2];
fourchars[3] = p[3];
fourchars[4] = 0;
p += 4;
u8DI_BM_remote = (p[0] << 8) + p[1]; p+=2;
au16AI_remote[0] = (p[0] << 8) + p[1]; p+=2;
...
上記はもっとも単純な記述だが、以下のようにByte array utilsを用いてバイト配列から読み出せる。
auto&& rx = the_twelite.receiver.read();
char fourchars[5]{};
uint8_t u8DI_BM_remote = 0xff;
uint16_t au16AI_remote[5];
uint8_t *p = rx.get_payload().begin();
fourchars[0] = G_BYTE(p);
fourchars[1] = G_BYTE(p);
fourchars[2] = G_BYTE(p);
fourchars[3] = G_BYTE(p);
fourchars[4] = 0;
u8DI_BM_remote = G_WORD(p);
au16AI_remote[0] = G_WORD(p);
...
1.1.7.3.7 - CRC8, XOR, LRC
uint8_t CRC8_u8Calc(uint8_t *pu8Data, uint8_t size, uint8_t init=0)
uint8_t CRC8_u8CalcU32(uint32_t u32c, uint8_t init=0)
uint8_t CRC8_u8CalcU16(uint16_t u16c, uint8_t init=0)
uint8_t XOR_u8Calc(uint8_t *pu8Data, uint8_t size)
uint8_t LRC_u8Calc(uint8_t* pu8Data, uint8_t size)
CRC8, XOR, LRC(アスキー形式で使用)の計算を行います。
CRC8_u8CalcU16(), CRC8_u8CalcU32()
はu16c, u32c
をビッグエンディアン並びとして、CRC8を計算します。
X^8+X^5+X^4+1
(Polynomial Valueを0x31)をとしたものを使用しています。これはCRC8-CCITT や CRC8-Maximと呼ばれることがあります。背景
無線パケットのデータ列、アスキー形式のチェックサム(LRC)、各種センサーのデータチェック用に利用されるため、ライブラリ手続きとして追加した。
1.1.7.3.8 - div10(), div100(), div1000()
struct div_result_i32 {
int32_t quo; // quotient
int16_t rem; // remainder
uint8_t b_neg; // true if negative
uint8_t digits_rem; // digits of remainder
};
div_result_i32 div10(int32_t val);
div_result_i32 div100(int32_t val);
div_result_i32 div1000(int32_t val);
センサー値などで100倍した値をuint16_t
型にして受け渡しする場合がありますが、除算回路がないマイコンでの計算処理には相応の時間がかかるため、加算・減算・乗算とビットシフトを用いた近似計算と補正により計算を行います。
val
に計算したい値、rem
は余りの格納変数、neg
は符号を格納する変数を渡します。
戻り値は商の値(常に正)、rem
には余りの値(常に正)、neg
は負ならtrue
が格納されます。
計算アルゴリズムの制約(桁あふれ)からdiv100()
とdiv1000()
での計算可能な値域が決まっています。div100()
は-99999~99999までの値に対応し、div1000()
は-999999~999999までの値に対応します。
商を得る近似計算式
div100()
int dv = val * 1311 >> 17;
div1000()
int dv = val * 131 >> 17;
使用例
auto d1 = div100(sns_val.u16temp_object);
auto d2 = div100(sns_val.u16temp_object);
Serial
<< crlf << format("..Object = %c%2d.%02d"
, d1.b_neg ? '-' : '+', d1.quo, d1.rem)
<< format(" Ambient = %c%2d.%02d"
, d2.b_neg ? '-' : '+', d2.quo, d2.rem);
計算速度
10分の1程度になります。
結果の出力
// 変換オプション
struct DIVFMT {
static const int STD = 0; // displays with minimul digits (no padding, no positive sign)
static const int PAD_ZERO = 1; // set padding character as '0' instead of ' '.
static const int SIGN_PLUS = 2; // put '+' sign if value is positive or 0.
static const int PAD_ZERO_SIGN_PLUS = 3; // PAD_ZERO & SIGN_PLUS
static const int SIGN_SPACE = 4; // put ' ' sign if value is positive or 0.
static const int PAD_ZERO_SIGN_SPACE = 5; // PAD_ZERO & SIGN_SPACE
};
// 文字列変換結果を格納するためのクラス
class _div_chars {
...
const char* begin() const {...}
const char* end() const {...}
const char* c_str() const { return begin(); }
operator const char*() const { return begin(); }
};
// format()メソッド
_div_chars div_result_i32::format(
int dig_quo = 0, uint32_t opt = DIVFMT::STD) const;
// Serialへのインタフェースの実装
template <class D> class stream {
...
inline D& operator << (const mwx::_div_chars&& divc);
inline D& operator << (const mwx::div_result_i32&&);
inline D& operator << (const mwx::div_result_i32&);
};
割り算の結果を格納するdiv_result_i32
クラスにはformat()
メソッドを用い_div_chars
クラスオブジェクトを得ることが出来る。_div_chars()
クラスオブジェクトは文字列バッファを内包していてconst char*
型として文字列バッファにアクセスするメソッドが用意されている。また、Serial
オブジェクトに対する<<
演算子も実装している。
format()
メソッドのパラメータの1番目dig_quo
は出力桁数(符号部を含まず)を指定します。出力桁数に足りない場合(以下、不足桁)は空白または0
で埋めます。2番目のパラメータopt
は書式を指定します。
optパラメータ | 内容 |
---|---|
DIVFMT::STD | 標準的な出力で、不足桁は空白で埋め、負の値に限り- を付加します。 |
DIVFMT::PAD_ZERO | 不足桁は0 で埋めます。 |
DIVFMT::SIGN_PLUS | 正の値にも+ 符号を付加します。 |
DIVFMT::PAD_ZERO_SIGN_PLUS | 不足桁は0 で埋め、正の値にも+ 符号を付加します。 |
DIVFMT::SIGN_SPACE | 正の値の場合は+ 符号の替わりに空白を付加します。 |
DIVFMT::PAD_ZERO_SIGN_SPACE | 不足桁は0 で埋め、正の値の場合は+ 符号の替わりに空白を付加します。 |
例
//// div_result_i32オブジェクトから直接出力
Serial << div100(-1234) << crlf;
// 結果: -12.34
//// 3桁で出力します
Serial << div100(3456).format(3, DIVFMT::PAD_ZERO_SIGN_PLUE) << crlf;
// 結果: +034.56
//// c_str()を使ってconst char*を得る
char str1[128];
auto x = div100(-5678);
mwx_snprintf(str1, 16, "VAL=%s", x.format.c_str()); // const char*
Serial << str1;
// 結果: VAL=-56.78
背景
TWELITE BLUE/RED では除算はコストが高い演算であるため、目的を限定した除算アルゴリズムを追加した。
ライブラリ内では温度・湿度といった一部のセンサー値、100倍の値(25.12℃なら2512)を用いて表現しているため、100で割った商と余りを得るための簡素な手続きを定義した。
dev_result_i32::format()
については、書式出力を行う際の煩雑さを避けるためである。
1.1.7.3.9 - Scale utils
x*1000/255
)の替わりに乗算とビットシフトによって近似計算します。
static inline uint8_t scale_1000_to_127u8(uint16_t x)
static inline uint16_t scale_127u8_to_1000(uint8_t x)
static inline uint8_t scale_1000_to_255u8(uint16_t x)
static inline uint16_t scale_255u8_to_1000(uint8_t x)
static inline uint8_t scale_1000_to_256u8(uint16_t x)
static inline uint16_t scale_256u16_to_1000(uint16_t x)
scale_1000_to_127u8()
0..1000 を 0..127 にスケールします。(16646*x+65000)>>17
を用いて近似計算します。
scale_127u8_to_1000()
0..127 を 0..1000 にスケールします。(2064000UL*x+131072)>>18
を用いて近似計算します。
scale_1000_to_255u8()
0..1000 を 0..255 にスケールします。(33423*x+65000)>>17
を用いて近似計算します。
scale_255u8_to_1000()
0..255 を 0..1000 にスケールします。(1028000UL*uint32_t(x)+131072)>>18
を用いて近似計算します。
scale_1000_to_256u8()
0..1000 を 0..256 にスケールします。(33554*x+66000) >> 17
を用いて近似計算します。
注: x=999,1000は計算値が256になりますがuint8_t
の範囲として255を返します。
scale_256u16_to_1000()
0..256 を 0..1000 にスケールします。(1028000UL*uint32_t(x)+131072)>>18
を用いて近似計算します。
背景
ハードウェアに設定すべき値は0..255といった2進数が前提になることが多く、ユーザアプリケーションで取り扱う数は0..1000といった10進数基準のほうが扱いやすい。これらのスケール変換に除算を行わない式を定義した。
1.1.7.3.10 - pnew()
template <class T, class... Args>
T* pnew(T& obj, Args&&... args) {
return (T*)new ((void*)&obj) T(std::forward<Args&&>(args)...);
}
例えば以下のように利用します。コンストラクタ引数を与えることもできます。
class my_class {
int _a;
public:
my_class(int a = -1) : _a(a) {}
};
my_class obj_1; // このコンストラクタは呼ばれない!
my_class obj_2; // このコンストラクタは呼ばれない!
void setup() {
mwx::pnew(obj_1); // my_class obj_1; に相当
mwx::pnew(obj_2, 2); // my_class obj_2(2); に相当
...
}
背景
コンパイラの制約のためグローバルオブジェクトのコンストラクタが呼び出されないため、これを初期化する方法は配置newを使用する方法が挙げられます。しかしながら、配置new(placement new)の構文は煩雑に見えるため。
他にstd::unique_ptr
(または eastl::unique_ptr
)を用いる方法もある。
std::unique_ptr<my_class> obj_3;
void setup() {
obj_3.reset(new my_class(3));
// TWELITE マイコンでは new は1回だけ確保し delete はできないため、
// 事実上グローバルオブジェクトと同等です。
}
1.1.8 - 外部ライブラリ
- EASTL - EASTL は Electronic Arts 社による C++ 標準ライブラリで、固定長メモリで動作するコンテナが用意されており、組み込みマイコンで利用しやすい特徴があります。TWELITE STAGE SDK では特別な設定なしでビルド可能できます。
1.1.8.1 - EASTL
本ライブラリは EASTL を TWENET 内で利用できるようにしています。
以下はバッファ最大長が固定の配列とソートアルゴリズムの適用です。
以下にEASTLの特徴を記載します。
- メモリ固定確保のコンテナ (
fixed_
) : 動的確保を行わず、固定長の要素数を持つコンテナの宣言が可能です。グローバル宣言すれば、コンパイル時に固定的にメモリ領域が確保され、ローカル宣言すればスタックエリアに確保されそのスコープ内で利用できます。 - Intrusive コンテナ:通常のコンテナは任意のデータ構造を格納できますが、Intrusiveコンテナはデータ構造に対して専用の基底クラスを継承することで、コンテナ内のリンク構造などを維持するためのリンク情報などを保持します。コンテナ内の各要素はそのコンテナ専用になりますが、リストやマップ構造では非常にメモリ利用効率の良くなります。(参考: Intrusive and non-intrusive containers)
2007年の記事EASTL (open-std.org)に開発動機などが記されています。(関連記事:EASTL から垣間見るゲームソフトウェア開発現場の現状 その 1, その 2)
TWENETでの利用
以下に留意してください。
当社ではライブラリの動作については包括的な検証は行っておりません。お客様での動作検証をお願いいたします。また EASTL の利用方法についてのお問い合わせについても当社では対応できません。配布元の開設資料・ライブラリソースコードなどの情報を参照してください。
- EASTL3.07 (2018/1/31) のバージョンを利用します。(C++11でコンパイルできる一番最後のバージョン)
- 以下のライブラリは組み込んでいません。
test/packages/EAAssert
,source/assert.cpp
test/packages/EATest
test/packages/EAThread
,source/thread_support.cpp
- テストコード
test/source
の動作移植はしていません。 - _sprintf_関連では
EA::StdC::Vsnprintf(char8_t*, ...)
のみを printf.h ライブラリ中のvsnprintf_()
を呼び出すことで解決しています。
組み込み・コンパイル方法
EASTL はアクト Act の記述の際に利用できます。
TWELITE 向けの開発環境で必要なインクルードパスの追加、ライブラリの追加は行います。作成するコード中でライブラリヘッダのインクルードを行ってください。
#include <TWELITE>
#include <EASTL/fixed_string.h>
using namespace eastl;
using tstr128 = fixed_string<char, 127 + 1, false>;
void setup() {
tstr128 s1;
s1 = "Hello World";
Serial << s1.c_str();
}
void loop() {
;
}
組み込み方法(詳細)
ライブラリのコンパイルやインクルードパスの設定は、MWSDK/TWENET 以下のディレクトリで実施済みですが、内部的な設定を以下に記載します。
- EASTL/source 内のコードをコンパイルして、ライブラリアーカイブとしておく (
libEASTL.a
)。リンク時にはこのライブラリの参照が必須です。 - コンパイル時に以下のインクルードパスを追加しておく。
$(PATH_EASTL)
を EASTL ディレクトリとした場合、インクルードパスは以下となります。
-I$(PATH_EASTL)/include
-I$(PATH_EASTL)/test/packages/EAAssert/include
-I$(PATH_EASTL)/test/packages/EABase/include/Common
-I$(PATH_EASTL)/test/packages/EAMain/include
-I$(PATH_EASTL)/test/packages/EAStdC/include
-I$(PATH_EASTL)/test/packages/EATest/include
-I$(PATH_EASTL)/test/packages/EAThread/include
コーディングについて
std::
と eastl::
について
MWXライブ内部でも std::
名前空間の標準ライブラリを利用しています。
標準ライブラリ (std::
) と EASTL(eastl::
)では同じ名前で同じ機能を持つものが定義されています。これらは混在できる場合もありますが、使用するとエラーになる場合もあります。つまりEASTLで使用するものは、通常はEASTL内の定義を用います(例:std::unique_ptr
に eastl::fixed_string
を格納しようとするとコンパイラエラーになります)。
またusing namespace std;
といったような記述を行う場合は、名前の衝突に注意してください。
グローバルオブジェクトの初期化1 (配置new)
TWENET の開発では、コンパイラの制約により、グローバル宣言のオブジェクトのコンストラクタが実行されません。グローバル宣言宣言したオブジェクトのメモリ領域がゼロクリアされるだけです。そのまま、コードを実行すると大抵の場合 null pointer access によりハングアップします。
このオブジェクトを初期化するためには*placement new (配置new)*を用います。
#include <TWELITE>
#include <EASTL/fixed_string.h>
using namespace eastl;
using tstr128 = fixed_string<char, 127 + 1, false>;
tstr128 g_str1; // constructor is NOT called! needs to be initialized before use.
void setup() {
(void) new ((void*)&g_str1) tstr128("Hello World");
Serial << g_str1.c_str();
}
placement new のコードは少し乱雑に見えるため、補助関数mwx::pnew()
を用意しています。先ほどの例を以下のように書き換えることができます。
(void) new ((void*)&g_str1) tstr128("Hello World");
// ↓
mwx::pnew(g_str1, "Hello World");
※ 2番目の引数以降は可変数で、コンストラクタにそのまま渡されます。
グローバルオブジェクトの初期化2 (unique_ptr
)
グローバルオブジェクトの初期化方法として unique_ptr
(std::unique_ptrの解説)を用いる方法もあります。unique_ptr
は std::
にも eastl::
にもありますが、EASTLのクラスではeastl::
のものを使用します。
以下のように初期化のタイミングで .reset()
を呼び出します。
#include <TWELITE>
#include <EASTL/unique_ptr.h>
#include <EASTL/fixed_string.h>
using namespace eastl;
using tstr128 = fixed_string<char, 127 + 1, false>;
eastl::unique_ptr<tstr128> uq_str1;
void setup() {
uq_str1.reset(new tstr128("Hello World"));
if (uq_str1) { // true: object is stored.
Serial << uq_str1->c_str();
}
}
intrusive
コンテナについて
以下の例は intrusive_list
の要素定義例です。メンバーは int mX
のみです。
struct IntNode : public eastl::intrusive_list_node {
int mX;
IntNode(int x = 0) : mX(x) { }
// no need to call super class's constructor eastl::intrusive_list_node()
};
inline bool operator<(const IntNode& a, const IntNode& b) { return a.mX < b.mX; }
inline bool operator>(const IntNode& a, const IntNode& b) { return a.mX > b.mX; }
intrusive_list
の要素は、必ず intrusive_list_node
を基底クラスに持っている必要があります。基底クラス内にはリストを維持するためのリンクポインタが含まれます。ここではさらに sort
などで使用する比較演算子の定義も行います。
using tiList = intrusive_list<IntNode>;
void setup() {
IntNode nodeA(5);
IntNode nodeB(1);
IntNode nodeC(9);
IntNode nodeD(2);
IntNode nodeE(4);
tiList l; // intrusive_list body
l.push_front(nodeA); // forming list strucure
// by updating link info in intrusive_list_node.
l.push_front(nodeB);
l.push_front(nodeC);
l.push_front(nodeD);
l.push_front(nodeE);
l.sort(); // sort, using < operator
l.sort(eastl::greater<tilist::value_type>()); // sort, using > operator
}
参考資料
- EA Standard Template Library ーTWENET に収録されているライブラリは EASTL 3.07 用で、それ以降に実装・変更された要素が含む点に注意してください)
- cpprefjp - C++日本語リファレンス ーC++ リファレンスですが STL の解説が参考になります。
本サンプルについて
EASTLのライセンス記述は以下です。
Modified BSD License (3-Clause BSD license) see the file LICENSE in the project root.
/*
Copyright (C) 2015 Electronic Arts Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of
its contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
サンプルコードは MWSLA-1J/E を適用します。
コード例
fixed_vector
最大長が固定された(つまり拡張しない)配列。 (※ mwx::smplbuf
も同様に最大長固定の配列ですが、MWXライブラリの内部処理に一部特化しています)
#include <TWELITE>
#include <EASTL/fixed_vector.h>
#include <EASTL/sort.h>
using tvct = eastl::fixed_vector<uint16_t, 64, false>;
tvct v;
void setup() {
mwx::pnew(v); // initialize
v = { 3, 1, 2 ,4 }; // set initial list.
// push and pop
v.pop_back(); // 3, 1, 2
v.push_back(5); // 3, 1, 2, 5
// sort
eastl::sort(v.begin(), v.end(), eastl::less<tvct::value_type>());
// 1, 2, 3, 5
// disp all
for (auto x : v) { Serial << format(" %d", x); }
Serial << crlf;
// using [] operator
for (int i = 0; i < v.size(); i++) { Serial << format(" %d", v[i]); }
}
fixed_vector
のテンプレート引数は3つあり、1番目が型、2番目が最大数、3番目は_false_にします。 配列の操作については、一般の std::vector
と類似した .puch_back()
や .pop_back()
、[]演算子
などが利用できます。
また、ソートアルゴリズムなどの適用も可能です。上記の例では eastl::sort
を昇順 eastl::less
にて行っています。
fixed_list
最大エレメント数が固定されたリスト構造(intrusive_list
についても要参照)。
#include <TWELITE>
#include <EASTL/fixed_list.h>
#include <EASTL/sort.h>
using tdata = eastl::pair<uint8_t, void (*)(uint8_t)>; // element data type
using tlst = eastl::fixed_list<tdata, 3, false>; // fixed_list with 3 elements.
tlst l; // list object
void setup() {
mwx::pnew(l); // initialize (call constructor)
// add
if (!l.full()) l.insert(l.begin(), eastl::make_pair('A', [](uint8_t v){ Serial << format("(1:%c)", v); } ));
if (!l.full()) l.insert(l.begin(), eastl::make_pair('B', [](uint8_t v){ Serial << format("(2:%c)", v); } ));
if (!l.full()) l.insert(l.begin(), eastl::make_pair('C', [](uint8_t v){ Serial << format("(3:%c)", v); } ));
if (!l.full()) l.insert(l.begin(), eastl::make_pair('D', [](uint8_t v){ Serial << format("(4:%c)", v); } )); // fails
Serial << crlf << "init: "; for(auto &x: l) x.second(x.first);
// find & erase
auto p = eastl::find_if(l.begin(), l.end(), [](tdata& x) { return (x.first == 'B'); } );
if (p != l.end()) l.erase(p);
Serial << crlf << "find&erase: "; for(auto &x: l) x.second(x.first);
// append
if (!l.full()) l.insert(l.end(), eastl::make_pair('D', [](uint8_t v){ Serial << format("(4:%c)", v); } ));
Serial << crlf << "append: "; for(auto &x: l) x.second(x.first);
// sort
eastl::sort(l.begin(), l.end(), eastl::less<tlst::value_type>());
Serial << crlf << "sort:"; for(auto &x: l) x.second(x.first);
// sort reverse
eastl::sort(l.begin(), l.end(), eastl::greater<tlst::value_type>());
Serial << crlf << "sort(rev):"; for(auto &x: l) x.second(x.first);
}
fixed_list
のテンプレート引数は3つあり、1番目が型、2番目が最大数、3番目は_false_にします。リストの操作については、一般の std::list
に類似した .insert()
, .erase()
などが利用できます。
上記のコードでは、リストにはペア eastl::pair
の要素を格納し、ペアの first を uint8_t
型の整数、second を void (*)(uint8_t)
の関数ポインタとしています。コード中はラムダ式を直接記述しています。コード中の x.second(x.first);
は second から得られる関数に対して first の値を与えるという意味合いになります。
このリストに対して eastl::find_if
による要素の検索を行ったり、bubble_sort
によるソートが可能です。
intrusive_list
通常のリストは任意のデータ構造を要素とできますが、intrusive_list
は要素に特定のデータを付与し、そのデータを用いることでデータ構造を構築します。
以下の例では、intruslve_list データ構造の要素となるには eastl::intrusive_list_node
を継承したデータ要素型であることを要件とします。eastl::intrusive_list_node
には前後の要素に対するポインタを格納できるような拡張です。
#include <TWELITE>
#include <EASTL/fixed_vector.h>
#include <EASTL/intrusive_list.h>
#include <EASTL/unique_ptr.h>
// list element of intrusive_list.
struct IntNode : public eastl::intrusive_list_node {
int mX;
IntNode(int x = 0) : mX(x) { }
};
inline bool operator>(const IntNode& a, const IntNode& b) { return a.mX > b.mX; } // for sort
using tpool = eastl::fixed_vector<IntNode, 16, false>;
using tlst = eastl::intrusive_list<IntNode>;
tpool pool; // instance pool.
tlst l; // list object
void setup() {
mwx::pnew(pool); // prepare isntances
mwx::pnew(l); // initialize (call constructor)
pool.resize(5); // create 4 instances into pool
// insert an IntNode element into List.
int i = 0;
pool[i].mX = 5; l.push_front(pool[i]); i++;
pool[i].mX = 1; l.push_front(pool[i]); i++;
pool[i].mX = 2; l.push_front(pool[i]); i++;
pool[i].mX = 4; l.push_front(pool[i]); i++;
pool[i].mX = 3; l.push_front(pool[i]); i++;
Serial << crlf << "init: ";
for(auto& x : l) { Serial << format(" %d", x.mX); }
l.remove(pool[2]);
Serial << crlf << "remove: ";
for(auto& x : l) { Serial << format(" %d", x.mX); }
l.sort(eastl::greater<tlst::value_type>());
Serial << crlf << "sort: ";
for(auto& x : l) { Serial << format(" %d", x.mX); }
}
この例で eastl::fixed_vector<>
が使用されているのは、IntNode
の要素を必要数確保する目的で、fixed_vector
が必要だったわけではありません。5つの要素にテストの値を格納して intrusive_list
を構築します。例では l.push_pront()
を呼び出し要素をひとつずつリストに格納しています。実際は格納するのではなく、各要素 IntNode
が持つポインタの繋ぎ変えです。
ソートの記述は l.sort()
のようにメンバ関数の呼び出しで行います。
ring_buffer
リングバッファ ring_buffer
は、他のコンテナ(例では fixed_vector
) との組み合わせで構築されます。
#include <TWELITE>
#include <EASTL/fixed_vector.h>
#include <EASTL/bonus/ring_buffer.h>
const size_t N_RING_ELE = 4; // element max for RING BUFFER.
using tvec = eastl::fixed_vector<uint8_t, N_RING_ELE + 1, false>; // One extra element is required.
using tring = eastl::ring_buffer<uint8_t, tvec>;
tring rb;
void setup() {
mwx::pnew(rb, N_RING_ELE);
rb.push_front(5);
rb.push_front(1);
rb.push_front(4);
rb.push_front(2);
Serial << crlf; for (auto x : rb) Serial << format(" %d", x);
rb.push_front(3);
Serial << crlf; for (auto x : rb) Serial << format(" %d", x);
rb.push_front(8);
Serial << crlf; for (auto x : rb) Serial << format(" %d", x);
rb.push_front(9);
Serial << crlf; for (auto x : rb) Serial << format(" %d", x);
Serial << crlf << format("back=%d", rb.back()) << crlf;
rb.pop_back();
for (auto x : rb) Serial << format(" %d", x);
}
ring_buffer
の定義は、要素型とそのコンテナ型の組み合わせです。要素型は余分に一つ要素を持たせておきます。
上記の例では .push_front()
で先頭に要素を挿入します。オーバーフローすると末尾は消えてしまいます。 .back()
により一番古い要素を取り出します。pop_back()
で一番古い要素を削除します。
intrusive_hash_map
マップ構造は、キーと値をもつデータ構造で、キー値により効率よく要素を抽出できるように設計されたデータ構造です。 intrusive_hash_map
は intrusive 構造とハッシュ値を用いて実装しています。いくばくか定義は煩雑ですが、メモリ消費量は抑制できます。
intrusive_list
と同様独自の要素型 IntNode
を eastl::intrusive_hash_node_key<要素型>
を継承した形で定義する必要があります。またハッシュを用いるためハッシュ最大値 (N_BUCKET_CT
) を定めておく必要があります。この値は、想定される格納要素数に応じて適切に素数の値を設定します。
#include <TWELITE>
#include <EASTL/internal/intrusive_hashtable.h>
#include <EASTL/intrusive_hash_map.h>
static const unsigned N_BUCKET_CT = 7;
// intrusive element type
struct IntNode : public eastl::intrusive_hash_node_key<uint8_t> {
using SUP = intrusive_hash_node_key;
void (*m_func)(); // member variable is func pointer.
IntNode(uint8_t key = 0) { SUP::mKey = key; } // key will be passed by the constructor.
};
// intrusive map type
using tmap = eastl::intrusive_hash_map<uint8_t, IntNode, N_BUCKET_CT>;
tmap mp;
IntNode nd_a, nd_b, nd_c, nd_d;
void setup() {
mwx::pnew(mp); // initialize (call constructor)
mwx::pnew(nd_a, 'A')->m_func = []() { Serial << "FuncA"; };
mwx::pnew(nd_b, 'B')->m_func = []() { Serial << "FuncB"; };
mwx::pnew(nd_c, 'C')->m_func = []() { Serial << "FuncC"; };
mwx::pnew(nd_d, 'D')->m_func = []() { Serial << "FuncD"; };
mp.insert(nd_a);
mp.insert(nd_b);
mp.insert(nd_c);
mp.insert(nd_d);
}
void loop() {
int c = Serial.read();
if(c != -1) {
Serial << crlf << '[' << uint8_t(c) << ']';
auto&& it = mp.find(uint8_t(c));
if (it != mp.end()) it->m_func();
}
}
上記の例は、マップのキーを uint8_t
型の1文字とし、マップの値部分を関数ポインタとします。loop()
ではキーの入力に応じた関数を実行するといった処理を行います。
最初に、グローバルオブジェクトとしてテーブルと要素を定義したため、setup()
中で mwx::pnew()
を呼び出すことでデータ要素(nd_a, nd_b, nd_c, nd_d
)の初期化、ハッシュマップの初期化 (mp
) を行っておきます。mwx::pnew()
の戻り値は、構築したオブジェクトへのポインタですので、初期化後直接メンバ変数に値(ラムダ式)を書き込んでいます。
要素(nd_a, nd_b, nd_c, nd_d
)の初期と値の設定が終わったら mp.insert(nd_a)
のようにマップに要素を挿入していきます。
loop()
ではシリアルから文字を入力するたびに、ハッシュマップの検索を行います。検索は mp.find()
メソッドを呼び出し、戻り値はイテレータで、検索失敗時は mp.end()
が戻ります。検索が成功したら (*it)
により検索出来た要素を参照できます。
intrusive_hash_multimap
は値の重複を許容するマルチマップです。利用方法はハッシュマップとほぼ同じですが、検索時に .equal_range()
用い、イテレータのペアとして取り扱う点が違います。
using tmap = eastl::intrusive_hash_multimap<uint8_t, IntNode, N_BUCKET_CT>;
...
// find emelents by key `c'
auto ip = mp.equal_range(uint8_t(c));
for(auto&& it = ip.first; it != ip.second; it++) {
it->m_func();
}
1.1.9 - ボードビヘイビア (BRD)
- 定数の定義(ピン番号など)
- ハードウェアの初期化
- センサー等の取り扱い
1.1.9.1 - <BRD_APPTWELITE>
定数
以下の定数を定義しています。
static const uint8_t PIN_DI1 = mwx::PIN_DIGITAL::DIO12;
static const uint8_t PIN_DI2 = mwx::PIN_DIGITAL::DIO13;
static const uint8_t PIN_DI3 = mwx::PIN_DIGITAL::DIO11;
static const uint8_t PIN_DI4 = mwx::PIN_DIGITAL::DIO16;
static const uint8_t PIN_DO1 = mwx::PIN_DIGITAL::DIO18;
static const uint8_t PIN_DO2 = mwx::PIN_DIGITAL::DIO19;
static const uint8_t PIN_DO3 = mwx::PIN_DIGITAL::DIO4;
static const uint8_t PIN_DO4 = mwx::PIN_DIGITAL::DIO9;
static const uint8_t PIN_M1 = mwx::PIN_DIGITAL::DIO10;
static const uint8_t PIN_M2 = mwx::PIN_DIGITAL::DIO2;
static const uint8_t PIN_M3 = mwx::PIN_DIGITAL::DIO3;
static const uint8_t PIN_BPS = mwx::PIN_DIGITAL::DIO17;
static const uint8_t PIN_AI1 = mwx::PIN_ANALOGUE::A1;
static const uint8_t PIN_AI2 = mwx::PIN_ANALOGUE::A3;
static const uint8_t PIN_AI3 = mwx::PIN_ANALOGUE::A2;
static const uint8_t PIN_AI4 = mwx::PIN_ANALOGUE::A4;
BRD_APPTWELITE::PIN_DI1
のようにアクセスできます。
メソッド
DIP SW (M1 M2 M3 BPS) ピンの値を取得するためのメソッドが用意されています。
inline uint8_t get_M1()
inline uint8_t get_M2()
inline uint8_t get_M3()
inline uint8_t get_BPS()
inline uint8_t get_DIPSW_BM()
戻り値はHIGH, LOWではなく、0
がセットされていない(HIGH側)、1
がスイッチがセットされる(LOW側)という意味です。
get_DIPSW_BM()
は、bit0から順にM1,M2,M3,BPSピンの値を返します。
1.1.9.2 - <MONOSTICK>
定数
以下の定数を定義しています。
const uint8_t PIN_LED = mwx::PIN_DIGITAL::DIO16; // LED
const uint8_t PIN_WDT = mwx::PIN_DIGITAL::DIO9; // WDT (shall tick < 1sec)
const uint8_t PIN_WDT_EN = mwx::PIN_DIGITAL::DIO11; // WDT (LO as WDT enabled)
const uint8_t PIN_LED_YELLOW = mwx::PIN_DIGITAL::DO1; // YELLOW LED
MONOSTICK::PIN_LED
のようにアクセスできます。
ハードの初期化
pinMode(PIN_LED, OUTPUT_INIT_HIGH);
pinMode(PIN_WDT, OUTPUT_INIT_LOW);
pinMode(PIN_WDT_EN, OUTPUT_INIT_LOW);
pinMode(PIN_LED_YELLOW, OUTPUT);
上記のコードのように各ピンが初期化されます。
ウォッチドッグタイマー
起動時、スリープ起床時、起動後一定時間経過後に外部のウォッチドッグタイマーを再セットします。
ウォッチドッグタイマーのタイムアウトは1秒です。
MONOSTICKでは通常スリープするアプリケーションを実行しませんが、その場合はMONOSTICK::PIN_WDT_EN
をHIGHにしてからスリープします。
メソッド
set_led()
void set_led_red(uint8_t mode, uint16_t tick)
void set_led_yellow(uint8_t mode, uint16_t tick)
LED(赤、黄)の制御を行います。
黄色のLED(MONOSTICK::PIN_LED_YELLOW
)はSPIMISOピン(半導体のピン名DO1)です。本ボードビヘイビアではPWM制御による点灯用のメソッドや手続きは含まれません。必要に応じて以下の記述を行います。
set_led_yellow()
は呼び出さないようにして下さい。- 始動後にPWM出力の初期化を別途行います。SPIMISOピンはApp_Twelite標準アプリケーションではPWM3に対応し、Timer3クラスオブジェクトにより制御できます。
- スリープ復帰後にPWM出力の初期化を別途行います。その際、DO1の出力設定を解除します。
- PWM設定前にDO1の出力設定を解除してください。
pinMode(PIN_LED_YELLOW, DISABLE_OUTPUT);
MONOSTICK::PIN_LED_YELLOW
)は、スリープ中に点灯させることはできません。mode
は以下のパラメータを取ります。tick
は点灯時間[ms]を指定しますが、詳細はmode
の解説を参照してください。
指定 | 意味 |
---|---|
LED_TIMER::BLINK | LEDを点滅させます。tick に与える時間[ms]ごとにON/OFFが切り替わります。スリープ復帰後はカウントをリセットし点灯状態から始まります。 |
LED_TIMER::ON_RX | パケットの受信時にtick に与える時間[ms]だけ点灯します。 |
LED_TIMER::ON_TX_COMP | 送信完了時にtick に与える時間[ms]だけ点灯します。 |
1.1.9.3 - PAL 共通定義
定数
以下の定数を定義しています。
static const uint8_t PIN_BTN = 12; // button (as SET)
static const uint8_t PIN_LED = 5; // LED
static const uint8_t PIN_WDT = 13; // WDT (shall tick every 60sec)
static const uint8_t PIN_D1 = 1; // DIP SW1
static const uint8_t PIN_D2 = 2; // DIP SW2
static const uint8_t PIN_D3 = 3; // DIP SW3
static const uint8_t PIN_D4 = 4; // DIP SW4
static const uint8_t PIN_SNS_EN = 16;
static const uint8_t PIN_SNS_INT = 17;
PAL_AMB::PIN_BTN
のようにアクセスできます。
ハードの初期化
pinMode(PIN_BTN, INPUT_PULLUP);
pinMode(PIN_LED, OUTPUT_INIT_HIGH);
pinMode(PIN_WDT, OUTPUT_INIT_HIGH);
pinMode(PIN_D1, INPUT_PULLUP);
pinMode(PIN_D2, INPUT_PULLUP);
pinMode(PIN_D3, INPUT_PULLUP);
pinMode(PIN_D4, INPUT_PULLUP);
上記のコードのように各ピンが初期化されます。
ウォッチドッグタイマー
起動時、スリープ起床時、起動後一定時間経過後に外部のウォッチドッグタイマーを再セットします。
メソッド
set_led()
void set_led(uint8_t mode, uint16_t tick)
LED(D1)の制御を行います。
mode
は以下のパラメータを取ります。tick
は点灯時間[ms]を指定しますが、詳細はmode
の解説を参照してください。
指定 | 意味 |
---|---|
LED_TIMER::BLINK | LEDを点滅させます。tick に与える時間[ms]ごとにON/OFFが切り替わります。スリープ復帰後はカウントをリセットし点灯状態から始まります。 |
LED_TIMER::ON_RX | パケットの受信時にtick に与える時間[ms]だけ点灯します。 |
LED_TIMER::ON_TX_COMP | 送信完了時にtick に与える時間[ms]だけ点灯します。 |
led_one_shot()
void led_one_shot(uint16_t tick)
指定期間だけLEDを点灯します。set_led()
の機能と同時には使えません。
get_D1() .. D4(), get_DIPSW_BM()
inline uint8_t get_D1()
inline uint8_t get_D2()
inline uint8_t get_D3()
inline uint8_t get_D4()
inline uint8_t get_DIPSW_BM()
get_D1() .. get_D4()
はDIP SWがHIGH(スイッチが上)の時0
、LOW(スイッチが下)のとき1
を返します。
get_DIPSW_BM()
はDIP SWの設定値を0..15
で返します。SW1==LOW
を1
, SW2 == LOW
を2
, SW3 == LOW
を4
, SW4 == LOW
を8
とした和を返します。
D1..D4のHIGH(1),LOW(0)
の値とは反対になります。
DIP SWのLOW(0)
側がセットされた、つまり、1
の値を持つと意味付けしているためです。
1.1.9.3.1 - <PAL_AMB>
共通定義に加えボード上のセンサーを取り扱えるようになっています。
- 温湿度センサー SHTC3
- 照度センサー LTR308ALS
void setup() {
auto&& brd = the_twelite.board.use<PAL_AMB>();
}
メンバーオブジェクト
sns_SHTC3
SHTC3センサーのオブジェクトです。
sns_LTR308ALS
LTR-308ALSセンサーのオブジェクトです。
1.1.9.3.2 - <PAL_MAG>
void setup() {
auto&& brd = the_twelite.board.use<PAL_MAG>();
}
開閉センサーパルのセンサーは磁気センサーで、2本の信号線の割り込みの入力のみです。
const uint8_t PAL_MAG::PIN_SNS_NORTH = 16;
const uint8_t PAL_MAG::PIN_SNS_OUT1 = 16;
const uint8_t PAL_MAG::PIN_SNS_SOUTH = 17;
const uint8_t PAL_MAG::PIN_SNS_OUT2 = 17;
PAL_MAG::PIN_SNS_NORTHはセンサーがN極を検出したとき、PAL_MAG::PIN_SNS_SOUTHはセンサーがN極を検出したときに割り込みが入ります。
スリープ前に以下の設定をしておきます。
pinMode(PAL_MAG::PIN_SNS_OUT1, PIN_MODE::WAKE_FALLING);
pinMode(PAL_MAG::PIN_SNS_OUT2, PIN_MODE::WAKE_FALLING);
起床時に起床要因のIOを確認します。
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);
1.1.9.3.3 - <PAL_MOT>
共通定義に加えボード上のセンサーを取り扱えるようになっています。
- 加速度センサー MC3630
void setup() {
auto&& brd = the_twelite.board.use<PAL_MOT>();
}
メンバーオブジェクト
sns_MC3630
MC3630センサーのオブジェクトです。
1.1.9.3.4 - <PAL_NOTICE>
共通定義に加えボード上のセンサーを取り扱えるようになっています。
- LEDドライバ PCA9632
- 加速度センサー MC3630
void setup() {
auto&& brd = the_twelite.board.use<PAL_NOTICE>();
}
メンバーオブジェクト
sns_PCA9632
PCA9632デバイスのオブジェクトです。ボード定義ではWireの初期化、デバイスの初期化を実施します。原則として後述のPCA9632操作メソッドを用いて制御します。
コイン電池を利用する場合、周期的に一瞬光るといった動作を行えば大きな電流による影響を緩和できます。
例えば1秒おきに20ms程度光るような設定を行えば、視覚的に十分な明るさを維持でき、上記影響を緩和できるだけでなく、電池の消耗も小さくできます(連続で5mA程度流す照度設定を、1秒に20ms点灯する場合はLED消費の平均電流は0.1mA)。
sns_MC3630
MC3630センサーのオブジェクトです。ボード定義ではSPIの初期化、MC3630デバイスの初期化、MC3630の割り込み処理などを行っています。諸処理はsns_MC3630
定義の手続きを用います。
PCA9632 定義
static const uint8_t LED_OFF = SnsPCA9632::LED_OFF;
static const uint8_t LED_ON = SnsPCA9632::LED_PWM;
static const uint8_t LED_BLINK = SnsPCA9632::LED_BLINK;
static const uint8_t LED_NOP = SnsPCA9632::LED_NOP;
static const uint8_t LED_R = SnsPCA9632::LED1;
static const uint8_t LED_G = SnsPCA9632::LED2;
static const uint8_t LED_B = SnsPCA9632::LED3;
static const uint8_t LED_W = SnsPCA9632::LED4;
static const uint8_t LED_REG_MAX_PWM = 127;
static const uint8_t LED_REG_BOOST_PWM = 255;
点灯状態
定義 | 意味 |
---|---|
PAL_NOTICE::LED_OFF | 消灯 |
PAL_NOTICE::LED_ON | 点灯(PWM照度制御) |
PAL_NOTICE::LED_BLINK | 点滅 |
PAL_NOTICE::LED_NOP | 変更しない |
LED識別子
定義 | 意味 |
---|---|
PAL_NOTICE::LED_R | LED赤 |
PAL_NOTICE::LED_G | LED緑 |
PAL_NOTICE::LED_B | LED青 |
PAL_NOTICE::LED_W | LED白 |
レジスタ設定定義
定義 | 意味 |
---|---|
PAL_NOTICE::LED_REG_MAX_PWM | 標準照度のPMWレジスタ設定値(全灯の1/2を標準とする) |
PAL_NOTICE::LED_REG_BOOST_PWM | ブースト時のPWMレジスタ設定値 |
PCA9632 操作メソッド
マスタースイッチ
void set_led_master_sw_on() { digitalWrite(PIN_SNS_EN, LOW); }
void set_led_master_sw_off() { digitalWrite(PIN_SNS_EN, HIGH); }
NOTICE PAL では、PCA9632の出力後段にFETスイッチを設けています。このスイッチをONにしない限りLEDは点灯しません。
点灯状態変更
void set_led_r_blink()
void set_led_r_on()
void set_led_r_off()
void set_led_g_on()
void set_led_g_blink()
void set_led_g_off()
void set_led_b_on()
void set_led_b_blink()
void set_led_b_off()
void set_led_w_on()
void set_led_w_blink()
void set_led_w_off()
個別のLEDを消灯、点灯、点滅に設定します。
void set_leds(uint8_t r, uint8_t g, uint8_t b, uint8_t w)
void set_leds_off()
set_leds()は全てのLEDの点灯状態を変更します。パラメータは点灯状態PAL_NOTICE::LED_OFF
PAL_NOTICE::LED_ON
PAL_NOTICE::LED_BLINK
PAL_NOTICE::LED_NOP
のいずれかを指定します。
点灯照度制御
void set_led_brightness_r_reg(uint8_t duty)
void set_led_brightness_g_reg(uint8_t duty)
void set_led_brightness_b_reg(uint8_t duty)
void set_led_brightness_w_reg(uint8_t duty)
void set_leds_brightness_reg(uint8_t r, uint8_t g, uint8_t b, uint8_t w)
void set_led_brightness_r1000(uint16_t duty, bool boost = false)
void set_led_brightness_g1000(uint16_t duty, bool boost = false)
void set_led_brightness_b1000(uint16_t duty, bool boost = false)
void set_led_brightness_w1000(uint16_t duty, bool boost = false)
void set_leds_brightness1000(
uint16_t r, uint16_t g, uint16_t b, uint16_t w, bool boost = false)
PWMのデューティ比(LEDの点灯明るさ)を指定します。
set_led_brightness_?_reg()
とset_leds_brightness_reg()
はレジスタ値を直接指定します。0..255を指定し点灯は比duty/256
となります。
set_led_brightness_?1000()
とset_leds_brightness1000()
は、デューティ比を0..1000で指定します。0は消灯相当で値が大きくなるほど明るく(点灯区間が長くなる)なります。boost
をfalse
にすると1000を指定したときのレジスタ値が127となります。true
では255となります。
点滅制御
void set_blink_cycle_ms(uint16_t x)
void set_blink_duty1000(uint16_t x)
PAL_NOTICE::LED_BLINK
を指定したLEDは、指定した周期・点灯期間比で点滅します。
- 個別に点滅パターンを指定することは出来ません。
- 上記の点灯照度設定で指定したPWMデューティ比で点灯するため、明るさの制御も可能です。
set_blink_cycle_ms()
はx
で指定した期間[ms]を周期として点滅します。
set_blink_duty1000()
はx
を0..1000で指定し周期*x/1000
を点灯期間として点滅します。
テスト点灯
void test_led()
ごく短い間4つのLEDを点灯します。点灯後はマスタースイッチがON(set_led_master_sw_on()
)になります。
1.1.9.4 - <CUE>
ボード上の加速度センサー、磁気センサー、LEDを取り扱えるようになっています。
- 加速度センサー
- 磁気センサー
- LED
void setup() {
auto&& brd = the_twelite.board.use<CUE>();
}
加速度センサー
MC3630センサーのメンバーオブジェクト (sns_MC3630
) が定義されています。
磁気センサー
開閉センサーパルのセンサーは磁気センサーで、2本の信号線の割り込みの入力のみです。
const uint8_t CUE::PIN_SNS_NORTH = 16;
const uint8_t CUE::PIN_SNS_OUT1 = 16;
const uint8_t CUE::PIN_SNS_SOUTH = 8;
const uint8_t CUE::PIN_SNS_OUT2 = 8;
CUE::PIN_SNS_NORTH
はセンサーがN極を検出したとき、CUE::PIN_SNS_SOUTH
はセンサーがN極を検出したときに割り込みが入ります。
スリープ前に以下の設定をしておきます。
pinMode(CUE::PIN_SNS_OUT1, PIN_MODE::WAKE_FALLING);
pinMode(CUE::PIN_SNS_OUT2, PIN_MODE::WAKE_FALLING);
起床時に起床要因のIOを確認します。
uint8_t b_north =
the_twelite.is_wokeup_by_dio(CUE::PIN_SNS_NORTH);
uint8_t b_south =
the_twelite.is_wokeup_by_dio(CUE::PIN_SNS_SOUTH);
LED
set_led()
void set_led(uint8_t mode, uint16_t tick)
LED(D1)の制御を行います。
mode
は以下のパラメータを取ります。tick
は点灯時間[ms]を指定しますが、詳細はmode
の解説を参照してください。
指定 | 意味 |
---|---|
LED_TIMER::BLINK | LEDを点滅させます。tick に与える時間[ms]ごとにON/OFFが切り替わります。スリープ復帰後はカウントをリセットし点灯状態から始まります。 |
LED_TIMER::ON_RX | パケットの受信時にtick に与える時間[ms]だけ点灯します。 |
LED_TIMER::ON_TX_COMP | 送信完了時にtick に与える時間[ms]だけ点灯します。 |
led_one_shot()
void led_one_shot(uint16_t tick)
指定期間だけLEDを点灯します。set_led()
の機能と同時には使えません。
ウォッチドッグタイマー
起動時、スリープ起床時、起動後一定時間経過後に外部のウォッチドッグタイマーを再セットします。
1.1.9.5 - <ARIA>
ボード上の加速度センサー、磁気センサー、LEDを取り扱えるようになっています。
- 温湿度センサー
- 磁気センサー
- LED
void setup() {
auto&& brd = the_twelite.board.use<ARIA>();
}
温湿度センサー
SHT4xセンサーのメンバーオブジェクト (sns_SHT4x
) が定義されています。
磁気センサー
開閉センサーパルのセンサーは磁気センサーで、2本の信号線の割り込みの入力のみです。
const uint8_t CUE::PIN_SNS_NORTH = 16;
const uint8_t CUE::PIN_SNS_OUT1 = 16;
const uint8_t CUE::PIN_SNS_SOUTH = 8;
const uint8_t CUE::PIN_SNS_OUT2 = 8;
ARIA::PIN_SNS_NORTH
はセンサーがN極を検出したとき、ARIA::PIN_SNS_SOUTH
はセンサーがN極を検出したときに割り込みが入ります。
スリープ前に以下の設定をしておきます。
pinMode(CUE::PIN_SNS_OUT1, PIN_MODE::WAKE_FALLING);
pinMode(CUE::PIN_SNS_OUT2, PIN_MODE::WAKE_FALLING);
起床時に起床要因のIOを確認します。
uint8_t b_north =
the_twelite.is_wokeup_by_dio(CUE::PIN_SNS_NORTH);
uint8_t b_south =
the_twelite.is_wokeup_by_dio(CUE::PIN_SNS_SOUTH);
LED
set_led()
void set_led(uint8_t mode, uint16_t tick)
LED(D1)の制御を行います。
mode
は以下のパラメータを取ります。tick
は点灯時間[ms]を指定しますが、詳細はmode
の解説を参照してください。
指定 | 意味 |
---|---|
LED_TIMER::BLINK | LEDを点滅させます。tick に与える時間[ms]ごとにON/OFFが切り替わります。スリープ復帰後はカウントをリセットし点灯状態から始まります。 |
LED_TIMER::ON_RX | パケットの受信時にtick に与える時間[ms]だけ点灯します。 |
LED_TIMER::ON_TX_COMP | 送信完了時にtick に与える時間[ms]だけ点灯します。 |
led_one_shot()
void led_one_shot(uint16_t tick)
指定期間だけLEDを点灯します。set_led()
の機能と同時には使えません。
ウォッチドッグタイマー
起動時、スリープ起床時、起動後一定時間経過後に外部のウォッチドッグタイマーを再セットします。
1.1.10 - センサーデバイス (SNS)
センサー取り扱いのための手続き
温度センサーなど、センサー稼働開始→待ち時間→センサー値の読み出しといった手続きが共通のものもあります。
I2Cセンサーの取り扱い前にWire.begin()
を実施しておいてください。スリープ復帰後は、Wireの再初期化は自動で行われるため特別な記述は必要ありません(注:ユーザコード上から明示的に Wire.end()
を呼び出した場合は、再初期化を wakeup()
に記述します)
void setup() {
auto&& brd = the_twelite.board.use<PAL_AMB>();
..
Wire.begin();
brd.sns_SHTC3.begin();
brd.sns_LTR308ALS.begin();
}
読み出し開始後の手続きはセンサーの種類ごとに違いますが例えば<PAL_AMB>
のセンサーは2つとも時間経過を管理します。時間経過をセンサーオブジェクトに伝えるには process_ev()
メソッドを用います。
void loop() {
auto&& brd = the_twelite.board.use<PAL_AMB>();
// mostly process every ms.
if (TickTimer.available()) {
// wait until sensor capture finish
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);
}
..
上記の例では1msおきのTickTimerを起点にして時間経過を伝えています。E_EVENT_TICK_TIMER
はセンサーオブジェクトに1msの経過を伝えるものです。
スリープ復帰などで十分な時間が経過したときは替わりにE_EVENT_START_UP
を渡します。センサーオブジェクトは速やかに読み出し可能として処理されます。
センサー共通メソッド
setup()
void setup(uint32_t arg1 = 0, uint32_t arg2 = 0)
センサーの初期化を行います。
begin()
, end()
void begin(uint32_t arg1 = 0, uint32_t arg2 = 0)
void end()
センサーの取得を開始, 終了する。
process_ev()
void process_ev(uint32_t arg1, uint32_t arg2 = 0)
待ち時間処理のセンサーの場合はarg1
にE_EVENT_TICK_TIMER
またはE_EVENT_START_UP
を与え時間の経過を知らせます。このメソッド呼出し後に、必要な時間が経過していればavailableになり、センサー値の読み出しが可能になります。
available()
bool available()
センサーが読み出し条件を満足したときにtrue
を返します。
probe()
bool probe()
(対応しているセンサーのみ)センサーが接続されているときにtrue
を返します。
probe()
直後の初回の通信が失敗することがある。1.1.10.1 - SHTC3
<PAL_AMB>
を読み込んだ時のみ使用可能です。begin()
以外の共通メソッドの手続きはボードビヘイビア中で実行されています。処理の流れ
Wire.begin()
: バスの初期化.begin()
: センサーの動作開始- 時間待ち数ms
.available()
がtrue
になる.get_temp(), .get_humid()
: 値の読み出し
動作に必要な手続き
Wireバス
begin()
メソッド呼び出し前にWire.begin()
によりWireが動作状態にしておきます。
スリープ復帰時の手続き
スリープ直前もWireバスが動作状態にしておきます(スリープ復帰後自動でWireを回復します)。
メソッド
get_temp()
, get_temp_cent()
double get_temp()
int16_t get_temp_cent()
温度を読み出す。get_temp()
は℃で、get_temp_cent()
は℃の100倍の値を整数値で返します。
エラー時は-32760
から-32768
の値が返ります。
get_humid()
, get_humid_per_dmil()
double get_humid()
int16_t get_humid_per_dmil()
湿度を読み出す。get_humid()
は%で、get_humid_per_dmil()
は%の100倍の値を整数値で返します。
エラー時は-32760
から-32768
の値が返ります。
共通メソッド
setup()
void setup()
センサー用のメモリ領域の確保や初期化を行います。
begin()
, end()
void begin()
void end()
センサーの取得を開始します。センサーの値を読み出すまで約5ms待ち時間が必要です。
end()
には対応しません。
process_ev()
void process_ev(uint32_t arg1, uint32_t arg2 = 0)
待ち時間処理のセンサーの場合はarg1
にE_EVENT_TICK_TIMER
またはE_EVENT_START_UP
を与え時間の経過を知らせます。このメソッド呼出し後に、必要な時間が経過していればavailableになり、センサー値の読み出しが可能になります。
available()
bool available()
センサーが読み出し条件を満足したときにtrue
を返します。
probe()
bool probe()
センサーが接続されているときにtrue
を返します。
1.1.10.2 - SHT3x
本センサーはTWELITE PALシリーズでは使用されていません。利用例は以下を参照ください。
処理の流れ
Wire.begin()
: バスの初期化.setup()
: センサーの初期化.begin()
: センサーの動作開始- 時間待ち数ms
.available()
がtrue
になる.get_temp(), .get_humid()
: 値の読み出し
動作に必要な手続き
Wireバス
setup()
メソッド呼び出し前にWire.begin()
によりWireが動作状態にしておきます。
スリープ復帰時の手続き
スリープ直前もWireバスが動作状態にしておきます(スリープ復帰後自動でWireを回復します)。
コード例
##include <TWELITE>
##include <SNS_SHT3X>
SNS_SHT3X sns_sht3x; // オブジェクトの宣言
#include <SNS_SHT3X>
とSNS_SHT3X
クラスオブジェクトの宣言が必要です。
初期化
void setup() {
Wire.begin();
sns_sht3x.setup();
}
センサー値の取得開始
void loop() {
if(eState == E_STATE::INIT) {
sns_sht3x.begin();
eState = E_STATE::CAPTURE;
}
}
センサー値の取得開始には.begin()
を呼び出します。完了まで数msかかります。
※ 上記 loop()
内は状態変数eStateにより処理が分岐する設計とします。(参考)
センサー値の取得待ち
void loop() {
if(eState == E_STATE::CAPTURE) {
if (sns_sht3x.available()) {
// センサー値読み出し可能
}
}
}
センサー値が準備できたかどうかは.available()
により判定できます。
センサー値の読み出し
void loop() {
if(eState == E_STATE::CAPTURE) {
if (sns_sht3x.available()) {
Serial << crlf << "SHT3X:"
<< " T=" << sns_sht3x.get_temp() << 'C'
<< " H=" << sns_sht3x.get_humid() << '%';
}
}
}
センサー値が準備出来次第、値を読み出すことが出来ます。
.get_temp(), get_humid()
は浮動小数点演算が含まれます。100倍整数値を取得することもできます。
auto temp = div100(sns_sht3x.get_temp_cent());
auto humd = div100(sns_sht3x.get_humid_per_dmil);
Serial << crlf << "SHT3X:"
<< format(" T=%c%d.%02d", temp.neg ? '-' : ' ', temp.quo, temp.rem)
<< format(" T=%c%d.%02d", humd.neg ? '-' : ' ', humd.quo, humd.rem);
ここではdiv100()
を用いて100倍値を整数部と小数部に分解しています。
メソッド
get_temp()
, get_temp_cent()
double get_temp()
int16_t get_temp_cent()
温度を読み出す。get_temp()
は℃で、get_temp_cent()
は℃の100倍の値を整数値で返します。
エラー時は-32760~-32768の値が返ります。
get_humid()
, get_humid_per_dmil()
double get_humid()
int16_t get_humid_per_dmil()
湿度を読み出す。get_humid()
は%で、get_humid_per_dmil()
は%の100倍の値を整数値で返します。
エラー時は-32760
~-32768
の値が返ります。
共通メソッド
setup()
void setup(uint32_t arg1 = 0UL)
センサー用のメモリ領域の確保や初期化を行います。
arg1
のLSBから8bitには、I2Cアドレスを格納することが出来ます。指定しない場合は0としておきます。
##include <SNS_SHT3X>
SNS_SHT3X sns_sht3x;
bool b_found_sht3x = false;
void setup() {
sns_sht3x.setup();
if (!sns_sht3x.probe()) {
delayMicroseconds(100); // just in case, wait for devices to listen furthre I2C comm.
sns_sht3x.setup(0x45); // alternative ID
if (sns_sht3x.probe()) b_found_sht3x = true;
} else {
b_found_sht3x = true;
}
}
上記の例では、まずデフォルトのI2C IDで初期化を試み、応答が無ければ0x45
のアドレスでの初期化を試みています。
begin()
, end()
void begin()
void end()
センサーの取得を開始します。センサーの値を読み出すまで数ms必要でavailable()
がtrue
になるまで待つ必要があります。
end()
には対応しません。
process_ev()
void process_ev(uint32_t arg1, uint32_t arg2 = 0)
待ち時間処理のセンサーの場合はarg1
にE_EVENT_TICK_TIMER
またはE_EVENT_START_UP
を与え時間の経過を知らせます。このメソッド呼出し後に、必要な時間が経過していればavailable()
がtrue
になり、センサー値の読み出しが可能になります。
available()
bool available()
センサーが読み出し条件を満足したときにtrue
を返します。
probe()
bool probe()
センサーが接続されているときにtrue
を返します。
sns_stat()
uint32_t sns_stat()
センサーデバイスの諸情報が格納されます。
- 本デバイスでは格納値は未定義です。
sns_opt()
uint32_t& sns_opt()
setup(uint32_t arg1)
で渡した値が格納されています。
- 下位8bitには指定したI2Cデバイスのアドレスが格納されます。
1.1.10.3 - LTR-308ALS
<PAL_AMB>
を読み込んだ時のみ使用可能です。begin()
以外の共通メソッドの手続きはボードビヘイビア中で実行されています。処理の流れ
Wire.begin()
: バスの初期化.begin()
: センサーの動作開始- 時間待ち50ms
.available()
がtrue
になる.get_luminance()
: 値の読み出し
動作に必要な手続き
Wireバス
.begin()
メソッド呼び出し前にWire.begin()
によりWireが動作状態にしておきます。
スリープ復帰時の手続き
スリープ直前もWireバスが動作状態にしておきます(スリープ復帰後自動でWireを回復します)。
メソッド
get_luminance()
uint32_t get_luminance()
照度[lx]を整数値で返します。
エラーの時は-1
が返ります。
共通メソッド
setup()
void setup()
センサー用のメモリ領域の確保や初期化を行います。
begin()
, end()
void begin()
void end()
センサーの取得を開始します。センサーの値を読み出すまで約50ms待ち時間が必要です。
end()
には対応しません。
process_ev()
void process_ev(uint32_t arg1, uint32_t arg2 = 0)
待ち時間処理のセンサーの場合はarg1
にE_EVENT_TICK_TIMER
またはE_EVENT_START_UP
を与え時間の経過を知らせます。このメソッド呼出し後に、必要な時間が経過していればavailableになり、センサー値の読み出しが可能になります。
available()
bool available()
センサーが読み出し条件を満足したときにtrue
を返します。
probe()
bool probe()
センサーが接続されているときにtrue
を返します。
1.1.10.4 - MC3630
<PAL_MOT>
<PAL_NOTICE> <CUE>
を読み込んだ時のみ使用可能です。begin(), available()
以外の共通メソッドの手続きはボードビヘイビア中で実行されています。動作の流れ
.begin()
: センサーの動作開始PIN_SNS_INT
割り込み またはavailable()
: FIFOキューが規定数に達する.get_que()
: FIFOキューからのデータを取得する
動作に必要な手続き
SPI バス
特にありません。
スリープ手続き
PIN_SNS_INT
割り込みによる起床を行うため、スリープ前に以下の設定行います。
pinMode(PAL_MOT::PIN_SNS_INT, WAKE_FALLING);
スリープ復帰時の手続き
.wakeup()
メソッドの呼び出しが必要です。この処理は<PAL_MOT>
ボードビヘイビア中で実行されています。
データ構造
各サンプルはaxis_xyzt
構造体を要素とするキューsmplque
に格納されます。メンバーx
, y
, z
はそれぞれ X, Y, Z 軸に対応します。
struct axis_xyzt {
int16_t x;
int16_t y;
int16_t z;
uint16_t t;
};
各軸の値は1Gを1000とした値として格納されます。t
はサンプルの番号で0
から順番にサンプルごとに割り振られます。
メソッド
read()
uint8_t read()
半導体のFIFOキューからデータを読み出します。読みだしたバイト数が戻りますが.get_que()
で参照するキューのサイズに格納されるデータ数を読み出すようにしてください。
<PAL_MOT>
ではread()
が行われます。get_que()
smplque<axis_xyzt>& get_que()
加速度のサンプルを取得します。キューはaxis_xyzt
を要素としたsmplque
です。availableになってから速やかにキューを空にする必要があります。
共通メソッド
setup()
void setup()
このセンサーではsetup()
を使用しません。
begin()
, end()
void begin(uint32_t conf)
void end()
conf
で指定した設定で初期化します。
conf[0:15]
(bit0-15) : サンプリングモード、conf[16:23]
(bit16-23): 加速度のレンジ、conf[24:31]
(bit24-31) : 割り込み発生までのサンプル数を設定します。
conf[0:15] サンプルモード | 内容 |
---|---|
MODE_LP_1HZ_UNOFFICIAL | 1Hz Low Power (非公式設定) |
MODE_LP_2HZ_UNOFFICIAL | 2Hz Low Power (非公式設定) |
MODE_LP_7HZ_UNOFFICIAL | 7Hz Low Power (非公式設定) |
MODE_LP_14HZ | 14Hz Low Power (デフォルト) |
MODE_LP_28HZ | 28Hz Low Power |
MODE_LP_54HZ | 54Hz Low Power |
MODE_LP_105HZ | 105Hz Low Power |
MODE_LP_210HZ | 210Hz Low Power |
MODE_LP_400HZ | 400Hz Low Power |
MODE_ULP_25HZ | 25Hz Ultra Low Power |
MODE_ULP_50HZ | 50Hz Ultra Low Power |
MODE_ULP_100HZ | 100Hz Ultra Low Power |
MODE_ULP_190HZ | 190Hz Ultra Low Power |
MODE_ULP_380HZ | 380Hz Ultra Low Power |
conf[16:23] 加速度レンジ | 内容 |
---|---|
RANGE_PLUS_MINUS_8G | ±8G (デフォルト) |
RANGE_PLUS_MINUS_4G | ±4G |
RANGE_PLUS_MINUS_2G | ±2G |
RANGE_PLUS_MINUS_1G | ±1G |
process_ev()
void process_ev(uint32_t arg1, uint32_t arg2 = 0)
このセンサーではprocess_ev()
を使用しません。
available()
bool available()
センサーにデータが読み出され内部のキューにデータが保存されているとtrue
を戻します。
probe()
bool probe()
このセンサーではprobe()
は使用できません。
wakeup()
void wakeup()
スリープ復帰後のSPIバスの再初期化を行い、加速度データを読み出します。
1.1.10.5 - BMx280
本センサーはTWELITE PALシリーズでは使用されていません。利用例は以下を参照ください。
処理の流れ
Wire.begin()
: バスの初期化.setup()
: センサーの初期化.begin()
: センサーの動作開始- 時間待ち数ms
.available()
がtrue
になる.get_press(), .get_temp(), .get_humid()
: 値の読み出し
動作に必要な手続き
Wireバス
setup()
メソッド呼び出し前にWire.begin()
によりWireが動作状態にしておきます。
スリープ復帰時の手続き
スリープ直前もWireバスが動作状態にしておきます(スリープ復帰後自動でWireを回復します)。
コード例
##include <TWELITE>
##include <SNS_BME280>
SNS_BME280 sns_bme280; // オブジェクトの宣言
#include <SNS_SHT3X>
とSNS_SHT3X
クラスオブジェクトの宣言が必要です。
初期化
void setup() {
Wire.begin();
sns_bme280.setup();
}
センサー値の取得開始
void loop() {
if(eState == E_STATE::INIT) {
sns_bme280.begin();
eState = E_STATE::CAPTURE;
}
}
センサー値の取得開始には.begin()
を呼び出します。完了まで数msかかります。
※ 上記 loop()
内は状態変数eStateにより処理が分岐する設計とします。(参考)
センサー値の取得待ち
void loop() {
if(eState == E_STATE::CAPTURE) {
if (sns_bme280.available()) {
// センサー値読み出し可能
}
}
}
センサー値が準備できたかどうかは.available()
により判定できます。
センサー値の読み出し
void loop() {
if(eState == E_STATE::CAPTURE) {
if (sns_bme280.available()) {
Serial << crlf << "BMx280:"
<< " P=" << int(sns_bme280.get_press()) << "hP";
<< " T=" << sns_bme280.get_temp() << 'C'
<< " H=" << sns_bme280.get_humid() << '%';
}
}
}
センサー値が準備出来次第、値を読み出すことが出来ます。
.get_temp(), get_humid()
は浮動小数点演算が含まれます。100倍整数値を取得することもできます。
auto temp = div100(sns_bme280.get_temp_cent());
auto humd = div100(sns_bme280.get_humid_per_dmil);
Serial << crlf << "BMx280:"
<< " P=" << int(sns_bme280.get_press()) << "hP";
<< format(" T=%c%d.%02d", temp.neg ? '-' : ' ', temp.quo, temp.rem)
<< format(" T=%c%d.%02d", humd.neg ? '-' : ' ', humd.quo, humd.rem);
ここではdiv100()
を用いて100倍値を整数部と小数部に分解しています。
メソッド
get_press()
int16_t get_press()
気圧を読み出します。単位はヘクトパスカル(hectopascal)で、通常は1000前後の値を示します。
get_temp()
, get_temp_cent()
double get_temp()
int16_t get_temp_cent()
温度を読み出す。get_temp()
は℃で、get_temp_cent()
は℃の100倍の値を整数値で返します。
エラー時は-32760
から-32768
の値が返ります。
get_humid()
, get_humid_per_dmil()
double get_humid()
int16_t get_humid_per_dmil()
湿度を読み出す。get_humid()
は%で、get_humid_per_dmil()
は%の100倍の値を整数値で返します。
エラー時は-32760
から-32768
の値が返ります。
共通メソッド
setup()
void setup(uint32_t arg1 = 0UL)
センサー用のメモリ領域の確保や初期化を行います。
arg1
のLSBから8bitには、I2Cアドレスを格納することが出来ます。指定しない場合は0としておきます。
##include <SNS_BME280>
SNS_BME280 sns_bme280;
bool b_found_bme280 = false;
void setup() {
...
sns_bme280.setup();
if (!sns_bme280.probe()) {
delayMicroseconds(100); // device needs small time for further I2C comm.
sns_bme280.setup(0x77); // alternative ID
if (sns_bme280.probe()) b_found_bme280 = true;
} else {
b_found_bme280 = true;
}
...
上記のコードではまずデフォルトのI2C IDでデバイスが応答するかを試し、応答が無ければ 0x77
で試みます。
begin()
, end()
void begin()
void end()
センサーの取得を開始します。センサーの値を読み出すまで数ms必要でavailable()
がtrue
になるまで待つ必要があります。
end()
には対応しません。
process_ev()
void process_ev(uint32_t arg1, uint32_t arg2 = 0)
待ち時間処理のセンサーの場合はarg1
にE_EVENT_TICK_TIMER
またはE_EVENT_START_UP
を与え時間の経過を知らせます。このメソッド呼出し後に、必要な時間が経過していればavailable()
がtrue
になり、センサー値の読み出しが可能になります。
available()
bool available()
センサーが読み出し条件を満足したときにtrue
を返します。
probe()
bool probe()
センサーが接続されているときにtrue
を返します。
sns_stat()
uint32_t sns_stat()
センサーデバイスの諸情報が格納されます。
- 下位8bitにはBME280/BMP280のチップモデルが格納されます。
0x60
ならBME280,0x58
ならBMP280となります。
sns_opt()
uint32_t& sns_opt()
setup(uint32_t arg1)
で渡した値が格納されています。
- 下位8bitには指定したI2Cデバイスのアドレスが格納されます。
1.1.10.6 - PCA9632
処理の流れ
Wire.begin()
: バスの初期化.setup()
: クラスオブジェクトの初期化.reset()
: ドライバの初期化- 各種手続き
PCA9632について
4chのLEDドライバです。
- 各chは消灯・全点灯・PWM点灯・点滅の4つの状態を指定できる
- 各chで独立して照度制御(PWM)できる
- 点滅指定したchはすべて同じ点滅パターンとなる
- 点滅時はPWMによる各ch個別の照度制御ができる
動作に必要な手続き
Wireバス
setup()
メソッド呼び出し前にWire.begin()
によりWireが動作状態にしておきます。
スリープ復帰時の手続き
スリープ直前もWireバスが動作状態にしておきます(スリープ復帰後自動でWireを回復します)。
コード例
##include <TWELITE>
##include <SNS_PCA9632>
SNS_PCA9632 pca;
#include <SNS_PCA9632>
とSNS_PCA9632
クラスオブジェクトの宣言が必要です。
初期化&リセット
void setup() {
Wire.begin();
pca.setup();
pca.reset();
}
点灯
...
pca.set_led_duty_all(
127,
127,
127,
127
);
pca.set_led_status(
SNS_PCA9632::LED_PWM,
SNS_PCA9632::LED_NOP,
SNS_PCA9632::LED_PWM,
SNS_PCA9632::LED_NOP);
上記の例ではLED1,3をPWM制御により点灯します。
メソッド
コンストラクタ, setup()
SnsPCA9632(uint8_t i2c_addr = DEFAULT_I2C_ADDRESS)
void setup(uint8_t i2c_addr = DEFAULT_I2C_ADDRESS)
コンストラクタではi2c_addr
を指定します。
グローバル宣言でクラスオブジェクトを定義した場合、コンストラクタが呼びだされませんので、setup()
を呼び出すようにしてください。
reset()
bool reset()
デバイスを初期化します。
レジスタアドレス 0x0 から順に {0x81, 0x35, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x0B, 0x00}
を書き込みます。
set_mode2()
bool set_mode2(uint8_t u8var = 0x35)
MODE2レジスタに値を書き込みます。
set_power_mode()
bool set_power_mode(bool b_pow_on)
b_pow_on
をtrue
にすると通常運用、false
にするとスリープします。
set_blink_cycle()
, set_blink_cycle_ms()
bool set_blink_cycle(uint8_t u8var)
bool set_blink_cycle_ms(uint16_t u16ms)
点滅(グループPWM)周期を決めます。
u8var
を指定すると周期は(u8var+1)/24
[秒]となります。
u16ms
は周期を[ms]で指定します。
set_blink_duty()
bool set_blink_duty(uint8_t u8duty);
点滅(グループPWM)のデューティ比を決めます。点灯期間はu8duty/256
となり、0は消灯相当、255は全灯相当になります。
set_led_duty()
bool set_led_duty(uint8_t port, uint8_t duty)
明るさ(PMW制御のデューティ比)を指定します。
port
は対象のLED(SNS_PCA9632::LED1..4
)を指定します。
duty
は0..255を指定し、比率duty/256
で点灯します。
set_led_duty_all()
bool set_led_duty_all(uint8_t p1, uint8_t p2, uint8_t p3, uint8_t p4)
全てのLEDに対して明るさ(PMW制御のデューティ比)を指定します。
p1,p2,p3,p4
はLED1..4のデューティで0..255を指定します。比率duty/256
で点灯します。
set_led_status()
bool set_led_status(uint8_t u8led1, uint8_t u8led2, uint8_t u8led3, uint8_t u8led4)
全てのLEDの点灯状態を変更します。
u8led1..4
は順にLED1..4の状態を指定します。
指定できる状態は、以下の通りです。
内容 | |
---|---|
SNS_PCA9632::LED_OFF | 消灯 |
SNS_PCA9632::LED_ON | 全灯 |
SNS_PCA9632::LED_PWM | 照度制御(PWM) |
SNS_PCA9632::LED_BLINK | 点滅制御(グループPWM) |
SNS_PCA9632::LED_NOP | 状態を変更しない |
probe()
bool probe()
I2Cバス上にデバイスが存在すればtrue
を返します。
show_registers()
void show_registers()
レジスタ(0x0-0x8)の値を表示します。
1.1.10.7 - SHT4x
<ARIA>
を読み込んだ時のみ使用可能です。begin()
以外の共通メソッドの手続きはボードビヘイビア中で実行されています。処理の流れ
Wire.begin()
: バスの初期化.begin()
: センサーの動作開始- 時間待ち数ms
.available()
がtrue
になる.get_temp(), .get_humid()
: 値の読み出し
動作に必要な手続き
Wireバス
begin()
メソッド呼び出し前にWire.begin()
によりWireが動作状態にしておきます。
スリープ復帰時の手続き
スリープ直前もWireバスが動作状態にしておきます(スリープ復帰後自動でWireを回復します)。
メソッド
get_temp()
, get_temp_cent()
double get_temp()
int16_t get_temp_cent()
温度を読み出す。get_temp()
は℃で、get_temp_cent()
は℃の100倍の値を整数値で返します。
エラー時は-32760~-32768の値が返ります。
get_humid()
, get_humid_per_dmil()
double get_humid()
int16_t get_humid_per_dmil()
湿度を読み出す。get_humid()
は%で、get_humid_per_dmil()
は%の100倍の値を整数値で返します。
エラー時は-32760~-32768の値が返ります。
共通メソッド
setup()
void setup()
センサー用のメモリ領域の確保や初期化を行います。
begin()
, end()
void begin()
void end()
センサーの取得を開始します。センサーの値を読み出すまで約5ms待ち時間が必要です。
end()
には対応しません。
process_ev()
void process_ev(uint32_t arg1, uint32_t arg2 = 0)
待ち時間処理のセンサーの場合はarg1
にE_EVENT_TICK_TIMER
またはE_EVENT_START_UP
を与え時間の経過を知らせます。このメソッド呼出し後に、必要な時間が経過していればavailableになり、センサー値の読み出しが可能になります。
available()
bool available()
センサーが読み出し条件を満足したときにtrue
を返します。
probe()
bool probe()
センサーが接続されているときにtrue
を返します。
1.1.11 - ネットワークビヘイビア (NWK)
<NWK_SIMPLE>
- 非常にシンプルな簡易中継ネットワークです。<NWK_LAYERED>
- レイヤーを用いた簡略化された木構造ネットワーク。(注:MWXは受信のみのパラントノードしかサポートしていません。)
1.1.11.1 - シンプル中継ネット <NWK_SIMPLE>
auto&& nwksmpl = the_twelite.network.use<NWK_SIMPLE>();
nwksmpl << NWK_SIMPLE::logical_id(0xFE)
<< NWK_SIMPLE::repeat_max(3);
上記はネットワークの利用宣言と設定例です。詳細は後述しますが、ネットワークのアドレスについての考え方など基本的な内容をまず解説します。
このネットワークでの各無線局は8bitの論理IDで識別されます。この値は起動時に各無線局が独自に設定します。論理IDは重複しても構いませんが、重複したことを前提とした通信を行う必要があります。
各無線局のIDを設定します。通常はネットワークには親機の役割の無線局と子機の役割の無線局を配置します。子機のみのネットワークも運用できます。
また子機は中継機の役割にもなります。
無線局の識別ID | 役割 |
---|---|
0x00 | 親局 |
0x01 ..0xEF | 子局 |
0xFE | IDを割り振らない子局 |
論理IDを宛先として指定できますが、0xFE
,0xFF
は特別な意味を持ちます。下表に宛先指定についてまとめます。
宛先ID | 意味 |
---|---|
0x00 | 子局から親局を指定する。親局からの指定は無効。 |
0x01 ..0xEF | 特定の子局を指定する。 |
0xFE | すべての子局を指定する同報通信(ブロードキャスト)。 |
0xFF | すべての無線局を指定する同報通信(ブロードキャスト)。 |
また、無線局を特定するのに32bitで指定するシリアル番号も利用できます。
パケットの配送は、IEEE802.15.4のブロードキャストを用います。ACKを用いないため、配送の成功が送信元では判別できませんが、替わりに要求に合った成功率が得られる適当な再送回数を設定したうえ、到達確認が必要な場合は通常パケットの通信を用います。
大規模で頻繁な通信を行う場合は非効率に見えるかもしれませんが、もっぱらデータ収集のみを行い、比較的中継段数が少ないネットワークの場合などより効率的になる場合もあります。
またネットワークを構築するための通信を必要としないため、障害等例外的な状況においても全く通信が止まってしまうといったことが原理的に少なくなります。親機が受信状態かつ子機からの無線到達範囲にあって、子機がパケットを送信しさえすれば、多くの場合親機は受信できます。ネットワークの構築のために通信が必要なネットワークでは、一旦、設定情報などが失われた後は、再度親機と子機間の通信確立のための通信が完了しなければデータが送れません。ネットワークビヘイビア<NWK_SIMPLE>
がその命名にシンプルとしているのは、こういった理由があります。
このシンプルネットワークを動作させるためには、多くの場合複数回届く再送パケット(同一パケット)を無視する必要があります。<NWK_SIMPLE>
での同一パケットの識別は送信元のシリアル番号と送信時のパケットの続き番号によって行います(重複チェッカと呼びます)。続き番号は0..63として、順番に割り当てられ、近い時間に届くパケットの続き番号は近い番号であるという仮定を置いています。一定時間以上経過した番号的に遠い(今10番を受信したとしたら40番台のパケットはしばらく前に送信されたと考えられる)続き番号はタイムアウトとして重複対象から除外します。
重複チェッカでの考慮すべきことは以下になります。
- チェック可能な要素数(数を増やせばメモリ消費とチェックのための処理時間が増える)
- タイムアウト時間の設定
デフォルトではタイムアウトは1秒で、チェックする無線局の数は16です。つまり中継パケットがまわりまわって1秒以上経過した場合、重複パケットとみなされななくなります。また短期的に16を超える無線局からのパケットが到達した場合、超過した無線局については重複チェックが出来なくなります。
中継段数や段数が少なくとも中継局の数が多い場合、再送を非常に長い間隔で行う場合は、設定を考慮すべき場合もあります。
宣言・登録
ネットワークビヘイビア<NWK_SIMPLE>
を利用例を挙げます。
##include <TWELITE>
##include <NWK_SIMPLE>
void setup() {
...
auto&& nwk = the_twelite.network.use<NWK_SIMPLE>();
}
2行目で<NWK_SIMPLE>
の定義情報をインクルードします。7行目でthe_twelite
に<NWK_SIMPLE>
を登録します。
設定
<NWK_SIMPLE>
登録後に設定を行います。
void setup() {
auto&& nwksmpl = the_twelite.network.use<NWK_SIMPLE>();
nwksmpl << NWK_SIMPLE::logical_id(0xFE);
}
設定は<<
演算子で行います。
<<
演算子 (設定)
オブジェクトthe_twelite
の初期設定を行うために<<
演算子を用います。
以下に挙げる設定用のクラスオブジェクトを入力とし、設定をしなければデフォルト値が適用されます。
NWK_SIMPLE::logical_id(uint8_t id)
パラメータid
に指定した論理デバイスIDを設定します。デフォルトは0xFE
(ID未設定子機)です。
NWK_SIMPLE::retry_default(uint8_t val)
パラメータval
に指定した回数を送信時の再送回数のデフォルト値とします。
NWK_SIMPLE::repeat_max(uint8_t val)
パラメータval
に指定した回数を最大中継回数とします。デフォルトは2
です。
中継をさせたくない場合は0
を指定します。
NWK_SIMPLE::dup_check(uint8_t maxnodes, uint16_t timeout_ms, uint8_t tickscale)
重複パケットの検出アルゴリズムのパラメータです。
maxnodes
は履歴を保持するため無線局(ノード)の数です。ノード数を少なく設定した場合、短期間に設定以上のノードからのパケットが来た場合、重複除外できないノードが出てきます。重複除外できない場合、受信時に複数回データが表示される、必要以上に再中継してしまうといった問題が出ます。デフォルトは16
です。1ノード当たり21バイトメモリを消費します。timeout_ms
は履歴を抹消するまでのタイムアウト時間[ms]です。タイムアウトは続き番号のブロック単位で管理されていて、ブロック単位でタイムアウト処理が行われます。デフォルトは1000
[ms]です。tickscale
はタイムアウトを管理するための時間単位で2^tickscale
[ms]となります。時間は7bitで管理されるため、127*(2^tickscale) > timeout_ms
になるように設定します。デフォルトは5
(32ms)です。
NWK_SIMPLE::secure_pkt(const uint8_t *pukey, bool b_recv_plain_pkt = false)
暗号化パケットの有効化します。
pukey
は暗号化の鍵を 16バイト (128bit) で指定します。b_recv_plain_pkt
はtrue
を指定すると、同じアプリケーションID、チャネルの平文パケットを受信します。
packet_rx::is_secure_pkt()
が true
(暗号化) か false
(平文) で判定できます。STG_STD
インタラクティブモードの設定値を反映します。以下の値を反映します。
auto&& set = the_twelite.settings.use<STG_STD>();
auto&& nwk = the_twelite.network.use<NWK_SIMPLE>();
...
set.reload(); // 設定値をロード
nwk << set; // インタラクティブモードの設定値を反映
- logical_id
- retry_default
メソッド
prepare_tx_packet()
// 型名はpacket_tx_nwk_simple<NWK_SIMPLE>ですがauto&&と記載します。
auto&& preare_tx_packet()
//例
if (auto&& pkt =
the_twelite.network.use<NWK_SIMPLE>().prepare_tx_packet()) {
...
pkt.transmit();
}
送信オブジェクトを取得します。オブジェクトはpacket_tx
の派生クラスになります。このオブジェクトに送信アドレスやペイロードを格納し.transmit()
メソッドで送信を行います。
このオブジェクトにはbool
演算子が定義されています。オブジェクト生成時にTWENETが送信要求を受け付けられない場合はfalse
を返します。
送信オブジェクト
.prepare_tx_packet()
メソッドにて取得した送信オブジェクトのメソッドです。
bool
演算子
operator bool()
// 例
if (auto&& pkt =
the_twelite.network.use<NWK_SIMPLE>().prepare_tx_packet()) {
オブジェクト生成時にTWENETが送信要求を受け付けられない場合はfalse
を返します。
transmit()
MWX_APIRET transmit()
// 例
uint8_t txid;
if (auto&& pkt =
the_twelite.network.use<NWK_SIMPLE>().prepare_tx_packet()) {
...
MWX_APIRET ret = pkt.transmit();
if (ret) {
txid = pkt.get_value();
}
}
パケットの送信処理を行います。MWX_APIRET
がtrue
の場合に送信要求が成功ですが、この要求時点では送信処理が始まりません。
パケットの送信IDはMWX_APIRET
の.get_value()
で得られる値部に格納されます。the_twelite.tx_status.is_complete()
またはtransmit_complete()
より送信完了を確認できます。
パケット最大長と構造
パケットの最大長を以下に示します。宛先をLID(論理デバイスID)とした場合は、暗号化無しで91バイトまで含めることが可能です。
ネットワーク層 | 暗号化 | ペイロードの最大 |
---|---|---|
<NWK_SIMPLE> | なし | 91 |
<NWK_SIMPLE> | あり | 89 |
※ 将来のための予備として2バイト分は予備としています。ユーザの判断でこの予備バイトを利用することも可能です。
パケットの構造は以下のようになっています。
|MacH:XX[........................................]MacF:2|
TWENET:3[.....................]TwenetF:1
NWK_SIMPLE:11|PAYLOAD
(:nはバイト数)
1: MacH は IEEE802.15.4 MAC のヘッダ情報
2: TwenetH は TWENET 識別のための情報
3: NWK_SIMPLE は NWK_SIMPLEネットワークの制御情報
|Type:1|Src LID:1|Src Addr:4|Dest LID:1|Dst Addr:4|Repeat:1|
4: PAYLOAD はペイドード
5: TwenetF は CRC8 のチェックサム(TWENETパケットの弁別を目的とする)
6: MacF は CRC16 のMAC 層のチェックサム
1.1.11.2 - <NWK_LAYERED>
以下のように setup()
中で初期化します。NWK_LAYERED::ROLE_PARENT
として親機としてのロールを割り当てます。
##include <NWK_LAYERED>
void setup() {
...
auto&& nwk_ly = the_twelite.network.use<NWK_LAYERED>();
nwk_ly << NWK_LAYERED::network_role(NWK_LAYERED::ROLE_PARENT);
// set a role as parent.
}
パケットの受信が行われたときは、NWK_SIMPLE
と同様に on_rx_packet()
が呼び出されます。
void on_rx_packet(packet_rx& rx, bool_t &handled) {
auto type = rx.get_network_type();
if (type == mwx::NETWORK::LAYERED) {
; // レイヤーツリーネットのパケット
handled = true; // 処理済みにする
}
}
rx
はパケット情報をラップしたクラスです。内部的には _get_network_type()
の処理用の内部フラグを設定する以外はパケット情報等の加工は行っていません。
つまりtsRxDataApp*
を返すrx.get_psRxDataApp()
を参照すれば、TWENET C ライブラリと同様のパケット情報が得られます。packet_rx
はこの情報にアクセスするためのいくつかの手続きが定義されていますが、得られる情報に変わりはありません。
NWK_SIMPLE
との併用
NWK_SIMPLE
と併用する場合は、the_twelite.network
にNWK_LAYERED
を、the_twelite.newwork2
にNWK_SIMPLE
を割り当てます。
##include <NWK_LAYERED>
##include <NWK_SIMPLE>
void setup() {
...
auto&& nwk_ly = the_twelite.network.use<NWK_LAYERED>();
auto&& nwk_sm = the_twelite.network2.use<NWK_SIMPLE>();
}
void on_rx_packet(packet_rx& rx, bool_t &handled) {
auto type = rx.get_network_type();
if (type == mwx::NETWORK::LAYERED) {
; // レイヤーツリーネットのパケット
}
else if (type == mwx::NETWORK::SIMPLE) {
; // NWK_SIMPLE のパケット
}
else if (type == mwx::NETWORK::NONE) {
; // 通常のアプリ (App_Twelite など)
}
else {
; // 解釈できなかったもの
}
// パケットを処理済みにし、これ以上 MWX ライブラリの介入はしない。
handled = true;
}
各パケット種別は上記のように .get_network_type()
により判別します。
mwx::NETWORK::LAYERED
: そのままパケット情報を参照します。mwx::NETWORK::SIMPLE
:NWK_SIMPLE
の処理に倣います。mwx::NETWORK::NONE
: ネットワーク処理や重複パケットの処理など一切が行われません。例えば App_Twelite 標準アプリケーションの場合、例えば1送信ごとに再送を含め3パケットずつ送出されます。この際、すべてのパケットの受信が成功した場合on_rx_packt()
が3回呼び出されることになります。通常は、3回受信できたからと言って2回目、3回目のデータは必要ありません。こういった重複パケットの処理を追加する必要があります。
実例はAct_SamplesのRcv_Univsl
を参照してください。TWELITE PAL, Act_samples, App_Twelite といった無線チャネルとアプリケーションIDが同一だが、種別の違うパケットの受信処理しています。さらに App_Twelite のために重複チェッカーの処理も用意しています。
1.1.12 - 設定ビヘイビアによる設定インタフェース
UART0
(Serial
)を利用します。設定ビヘイビアで利用しなかった入力文字列は、設定ビヘイビア内に確保されたFIFOキューに投入され、Serial
はこのキューを参照するようにふるまいます。設定ビヘイビアを登録しない場合と内部的なふるまいが違う点に留意ください。1.1.12.1 - <STG_STD>
<STG_STD>
は、最小限の設定項目を有した設定ビヘイビアです。
設定画面例
[CONFIG/MY_APP:0/SID=8102ECE3]
a: (0x1234ABCD) Application ID [HEX:32bit]
i: ( 1) Device ID [1-100,etc]
c: ( 13) Channel [11-26]
o: (0x00000000) Option Bits [HEX:32bit]
[ESC]:Back [!]:Reset System [M]:Extr Menu
Serial
オブジェクトの入出力をフックし、インタラクティブモードでの画面入出力を行います。アプリケーション中で入力処理を明示的に記述する必要はありません。インタラクティブモード画面中のアプリケーションからの画面出力は抑制されます。使用法
登録
// use twelite mwx c++ template library
##include <TWELITE>
##include <NWK_SIMPLE>
##include <STG_STD> // interactive mode
上記のように #include <STG_STD>
を追加します。
setup()
による読み出し
uint32_t APP_ID;
uint8_t CHANNEL;
uint8_t LID;
void setup() {
...
auto&& set = the_twelite.settings.use<STG_STD>();
// call reload() before reading values.
set.reload();
// read value
APP_ID = set.u32appid();
CHANNEL = set.u8ch();
LID = set.u8devid();
// apply them
the_twelite
<< TWENET::appid(APP_ID)
<< TWENET::channel(CHANNEL);
auto&& nwk = the_twelite.network.use<NWK_SIMPLE>();
nwk << NWK_SIMPLE::logical_id(LID);
}
多くの場合、設定の読み出しはsetup()
中の早い段階で行います。
上記の例はでは、まずthe_twelite.settings.use<STG_STD>()
により設定ビヘイビアを登録します。
つぎにset.reload()
を呼び出し、実際にEEPROMからデータを読み出し、これを解釈します。自動で読み出さないことに注意してください。
set.u32appid()
, set.u8ch()
, set.u8devid()
は各々アプリケーションIDの設定値、チャネルの設定値、論理デバイスIDの設定値を取得しています。ここでは変数に各設定値を格納しています。
あとは、設定値を利用してアプリケーションIDやチャネルなどの値を反映します。
設定一覧
以下が設定IDの一覧(enum class E_STGSTD_SETID
)定義です。
設定ID | 内容 |
---|---|
APPID | アプリケーションID |
LOGICALID | 論理デバイスID (8bit) |
CHANNEL | チャネル |
CHANNELS_3 | チャネル(3chまで) |
POWER_N_RETRY | 出力とリトライ回数 |
OPTBITS | Option 1 |
OPT_DWORD2 | Option 2 |
OPT_DWORD3 | Option 3 |
OPT_DWORD4 | Option 4 |
ENC_MODE | 暗号化モード |
ENC_KEY_STRING | 暗号化キー(文字列入力) |
<STG_STD>
では、代表的な設定と自由に使える32bit値を4つ定義されています。これらは、ユーザが自由に利用できます。
<STG_STD>
から読み出すだけでは設定は反映されません。- 不要な項目を非表示にできます。
- 項目名や項目詳細を変更できます。
設定ビヘイビアのカスタマイズ
設定ビヘイビアのカスタマイズは.reload()
を行う前に全項目を行っておきます。
アプリケーション名
auto&& set = the_twelite.settings.use<STG_STD>();
set << SETTINGS::appname("MY_APP");
...
set.reload();
アプリケーション名はインタラクティブモードの先頭行に表示されます。
[CONFIG/MY_APP:0/SID=8102ECE3]
文字列ポインタを指定してください。内部でコピーを作らないようにしているため、ローカル変数を指定できません。
デフォルト値
auto&& set = the_twelite.settings.use<STG_STD>();
set << SETTINGS::appid_default(0x13579be);
set << SETTINGS::ch_default(18);
set << SETTINGS::lid_default(7);
...
set.reload();
アプリケーションID、周波数チャネル、論理デバイスID(LID)については、デフォルト値を変更できます。
複数チャネル設定メニュー
auto&& set = the_twelite.settings.use<STG_STD>();
set << SETTINGS::ch_multi();
...
set.reload();
SETTINGS::ch_multi()
を指定すると、チャネル設定が複数指定になります。複数設定を行う場合、設定値の読み出しは.u32chmask()
を用います。
すぐに設定画面を表示する
auto&& set = the_twelite.settings.use<STG_STD>();
set << SETTINGS::open_at_start();
...
set.reload();
アプリケーションID、チャネル、論理IDについては、デフォルト値を変更できます。
項目名、詳細の記述内容の変更
const TWESTG_tsMsgReplace SET_MSGS[] = {
{ int(E_STGSTD_SETID::OPTBITS), "オプション1",
"オプション1を設定してください" },
{ int(E_STGSTD_SETID::OPT_DWORD2), "オプション2",
"オプション2を設定してください\r\nオプション2は云々" },
{ 0xFF } // terminator
};
setup() {
auto&& set = the_twelite.settings.use<STG_STD>();
set.replace_item_name_desc(SET_MSGS);
...
項目名を別のモノに変更することが出来ます。上記の例ではUTF-8による日本語にしていますが、ターミナルの表示など条件がそろわないと適切には表示されません。
この配列は最後に { 0xFF }
で終端します。
1番目のエントリは設定ID、2番目が項目名、3番目が設定入力時に表示される解説になります。\r
により改行できます。
現在設定画面かどうか判定
auto&& set = the_twelite.settings.use<STG_STD>();
if (!set.is_screen_opened()) {
// 設定画面が出ていないときの処理
}
設定画面出力中にシリアルへの出力を行うと画面が崩れたりする原因になります。設定画面でないことを確認するには.is_screen_opened()
で確認します。
項目の削除
auto&& set = the_twelite.settings.use<STG_STD>();
set.hide_items(E_STGSTD_SETID::OPT_DWORD3, E_STGSTD_SETID::OPT_DWORD4);
...
if(set.is_hidden(E_STGSTD_SETID::OPT_DWORD3) {
; // OPT_DWORD3は非表示
}
不要な項目の削除を行います。.hide_items
は項目IDをパラメータとして(可変引数で複数指定可能)不要な項目を非表示にします。非表示項目かどうかは.is_hidden()
により確認できます。
-DSIZE_SETSTD_CUST_COMMON=48
のように指定できます。メソッド
reload()
auto&& set = the_twelite.settings.use<STG_STD>();
set << SETTINGS::appname(APP_NAME)
<< SETTINGS::appid_default(DEF_APP_ID)
<< SETTINGS::open_at_start();
set.reload();
設定を読み込みます。すべてのカスタマイズが終わってから実行します。
メソッド (データ読み出し)
データの読み出しは以下のメソッドを呼び出します。
.reload()
を呼び出してください。メソッド | 内容 |
---|---|
uint32_t u32appid() | アプリケーションID |
uint8_t u8devid() | 論理デバイスID |
uint8_t u8ch() | 設定チャネル (11..26) |
uint32_t u32chmask() | チャネル設定マスク (ビットマスクで指定、13 なら 1UL « 13 にビットを設定する) |
uint8_t u8power() | 出力設定 (0..3) |
uint8_t u8retry() | リトライ数 |
uint32_t u32opt1() | オプション1 |
uint32_t u32opt2() | オプション2 |
uint32_t u32opt3() | オプション3 |
uint32_t u32opt4() | オプション4 |
uint8_t u8encmode() | 暗号化モード (0: なし 1: 有効 2: 有効、平文パケットも表示する) |
const uint8_t * u8enckeystr() | 暗号化キーの取得 |
設定の反映
the_twelite
や<NWK_SIMPLE>
オブジェクトに対して、本オブジェクトを用いて直接設定を反映できます。
auto&& set = the_twelite.settings.use<STG_STD>();
...
set.reload(); //ここで実際に設定がEEPROMより読み出される
the_twelite << set; // 設定値の反映 (APPIDなど)
auto&& nwk = the_twelite.network.use<NWK_SIMPLE>();
nwk << set; // 設定値の反映 (LIDなど)
反映される設定値は以下となります。.hide_items()
により非表示になっている項目は反映しません。
対象 | 項目ID | 内容 |
---|---|---|
the_twelite | APPID | TWENET::appid(値) に反映されます。 |
CHANNEL | TWENET::channel(値) に反映されます。※ SETTINGS::ch_multi() を指定したときは反映されません | |
CHANNELS_3 | TWENET::chmask(値) による設定を行います。※ SETTINGS::ch_multi() を指定したときのみ、チャネルマスクとして反映されます。 | |
POWER_N_RETRY | TWENET::tx_power(値) とTWENET::mac_retry_count(値) による設定を行います。注: <NWK_SIMPLE> での再送設定も同じ値を参照します。 | |
<NWK_SIMPLE> | LOGICALID | NWK_SIMPLE::logical_id(LID) による設定を行います。 |
POWER_N_RETRY | NWK_SIMPLE::repeat_max(LID) による設定を行います。 |
項目ID
.hide_items()
などで項目IDを指定する場合があります。この項目IDはenum class E_STGSTD_SETID
で定義されてます。
E_STGSTD_SETID:: | 内容 |
---|---|
APPID | アプリケーションID |
LOGICALID | 論理ID(0..100) |
CHANNEL | チャネル |
CHANNELS_3 | チャネル(複数指定) |
POWER_N_RETRY | 出力とリトライ設定 |
OPTBITS | オプションビット |
UARTBAUD | UARTのボーレート設定 |
OPT_DWORD2 | オプションビット2 |
OPT_DWORD3 | オプションビット3 |
OPT_DWORD4 | オプションビット4 |
ENC_MODE | 暗号化モード |
ENC_KEY_STRING | 暗号化キー |
Extra Menu
[ROOT MENU/BAT1/SID=810B645E]
0: CONFIG
1: EEPROM UTIL
2: H/W UTIL
[ESC]:Back [!]:Reset System
Mキーを入力すると追加メニューにアクセスできます。
- CONFIG : 設定画面に戻ります
- EEPROM UTIL : EEPROMのメンテナンスを行うためのメニューです
- H/W UTIL : ハードウェアの状態を調べるためのメニューです
EEPROM UTIL
[EEPROM UTIL/BAT1/SID=810B645E]
r: Read sector.
R: Read ALL sectors.
e: Erase sector.
E: Erase ALL sectors.
[ESC]:Back [!]:Reset System [M]:Extr Menu
セクターの読み出し、削除を行います。全読み出し、全消去を行うときは大文字で “YES” の3文字を入力します。
H/W UTIL
[H/W UTIL/BAT1/SID=810B645E]
現バージョンでは機能は提供されません。
1.1.13 - MWXライブラリ改版履歴
更新方法
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.2 (MWSDK2025_08版)
- マルチアプリ対応(MULTINONE, 複数アプリコードを1本のバイナリにまとめ、起動時に選択する)を行った。
cbToCoNet_???
関数にMWX_
プレフィックスを追加。mwx_appcore.c
にてMWX_USE_ALIAS
マクロと追加した。定義されている場合、MWX_cbToCoNet???()
コールバック関数を直接cbToCoNet???()
にエリアスし、冗長な関数呼び出しを抑制する。
- modified packect queue size to
ToCoNet_USE_MOD_TXRXQUEUE_MULTINONE
. - インタラクティブモード用のアプリケーション定義コールバック関数の関数ポインタ化を行った (
MWX_TWEINTRCT_***
, etc.) - MWX ライブラリで用いられるコールバック関数群を関数ポインタにより呼び出すように変更した
mwx_pf_init_coldboot
,mwx_pf_setup
,mwx_pf_begin
,mwx_pf_loop
,mwx_pf_init_warmboot
,mwx_pf_wakeup
,mwx_pf_on_rx_packet
,mwx_pf_on_tx_comp
,mwx_pf_on_nwk_event
setup()
前後の処理に一貫性が無かったため、以下のように修正した。- introduced
on_setup()
method which is called just after::setup()
procedure. - changed
on_begin()
which is always called just before::begin()
procedure. The on_begin() used for board behavior was called the_twelite.begin() procedure in ::setup().
- introduced
mwx::G_BYTE()
,mwx::G_WORD()
,mwx::G_DWORD()
の定義を改善し、右辺値でも利用できるようにした。Serial::println(T, fmt)
のfmt
がDEC
,OCT
指定時に正しく出力されない問題を修正したWire
オブジェクトでNAK
が正しく送付されていなかったserioal_parser
で 以下のように右辺値であってもSerial <<
で出力できるようにしたSerial << serparser_attach(PARSER::ASCII, buf.begin(), buf.size())
operator bool()
メソッドにexplicit
を追加したmwx::S_OCTET()
をmwx::S_BYTE()
にリネームした- intorduced predefined MACRO
MWX_PF_CALLBACKS_PRESENT
to check if(*mwx_pf_setup)()
,(*mwx_pf_loop)()
, … are supported, which should be used to ask library to use user defined funtion instead ofsetup()
,loop()
, … mwx::stream::vprintfmt()
を追加し、va_list
パラメータに対応した。- 外部メモリ(FIFO用)を指定したシリアルポート初期化手続きを追加した
mwx::serial_jen::setup(uint16_t siz_buf_tx, uint8_t *pu8_buf_tx, uint16_t siz_buf_rx, uint8_t *pu8_buf_rx)
mwx_debug.h
にUSE_IN_TWENET_C
マクロを追加した。(mwx ライブラリをリンクせずにNWK_SIMPLE
クラスを利用しようとした実験的な試み)
0.2.1 (MWSDK2024_07G版)
- Call
on_rx_packet()
for packets without network information (NWK_SIMPLE or others, but just a plain packet). - added energy sacn feature on MWX.
- added
on_nwk_event()
call back on MWX (pass the completion event of Enery Scan).
- added
- I2C デバイスの使用終了の手続き
vSMBusDeInit()
を追加した。 - [GOLD] BANK7メモリ領域の設定保存マクロ定義に対応した。
G_TWENET_FREE_RUNNING_WTIMER_ENABLED()
G_TWENET_CHIPSENSOR_ADC_TIMES_SCALER()
G_TWENET_CHIPSENSOR_AUTO_ON_BOOT()
0.2.1 2023-06-29
app_core.c
でのイベント処理の不具合対応と動作の統一化(以下0.2.2の修正も含めて記述)cbToCoNet_vRxEvent()
でネットワークビヘイビアでイベントを処理された場合はthe_vapp.cbToCoNet_vRxEvent()
を呼び出し、そうでない場合はon_rx_packet()
を呼び出す。cbToCoNet_vTxEvent()
でネットワークビヘイビアでイベントを処理された場合はthe_vapp.cbToCoNet_vTxEvent()
を呼び出し、そうでない場合はon_tx_comp()
を呼び出す。cbToCoNet_vNwkEvent()
でネットワークビヘイビアでイベントを処理された場合は.cbToCoNet_vNwkEvent()
を呼び出し、そうでない場合はon_nwk_event()
を呼び出す。
- TWELITE RED 用で ADC5,6 を利用できるようにした。
- TWELITE RED の ADC の電源電圧の mV 演算が間違えていたのを修正した。
settings::do_command()
を追加した。MWX_STGS_STD_DEF_APPID
マクロを追加、インタラクティブモードsettings
のデフォルトAPP_ID
を明示的に設定する。- [GOLD] MC3630 センサードライバの TWELITE GOLD 対応を行った。
- added
div100_128th()
to convert 128th value intodiv100()
style object. - [GOLD] modified
CPUCLK_XXX
defines to fit TWELITE GOLD. - [GOLD] added
mac_temp_update()
to temperature recal of MAC/RADIO when bigger change is seen. - [GOLD] added
get_on_boot_temperature()
andget_on_boot_voltage()
indiv_result_i32
object. - [GOLD] I2C関連のライブラリコード
SMBus.[ch]
を TWENETcmpt ライブラリに組み込んだ。 - [GOLD] MWX では
g_twenet_chipsensor_auto_on_boot = 1;
を設定し、チップ温度センサー取得を自動的に行う。このセンサーはRF部分の初期化パラメータに使用される。 - fixed that
vAHI_DioWakeEdge()
is not called properly whenpinMode()
is called for two or more ports. (storing bitmap state internally in mwx codes) - fixed
attachIntDio()
detachIntDio()
to consider behavior ofvAHIDioInterruptEdge()
. - fixed that repeat count of
<NWK_SIMPLE>
is not incremented when it’s repeating.
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のサポート追加
- EASTL用のnew[]演算子の追加
- 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 |
主な改定内容
- 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の整備。- EEPROMクラスオブジェクトを追加 (https://mwx.twelite.info/v/v0.1.7/api-reference/predefined_objs/eeprom)
- サンプル (https://github.com/monowireless/Act_samples/tree/master/Unit_EEPROM)
smplbuf::get_stream_helper()
の不具合修正pktparser
クラスを追加しました (https://mwx.twelite.info/v/v0.1.7/api-reference/classes/pktparser)- サンプル (https://github.com/monowireless/Act_samples/tree/master/Unit_PktParser)
serparser/pktparser
を他のプラットフォームでビルドできるようサンプルを用意しました (https://github.com/monowireless/mwx/tree/master/stdio)
0.1.6 - 2020-10-09
ライブラリ名 | 依存バージョン |
---|---|
mwx | 0.1.6 |
twesettings | 0.2.5 |
TWENET C | 1.3.4 |
主な改定内容
- 商・余を計算する
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
にすると、平文のパケットも受信する。
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) << NWK_SIMPLE::secure_pkt((const uint8_t*)"0123456789ABCDEF"); ;
- 暗号化を有効にするには
- 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
を追加。バスクロックの主要な設定値を追加した。
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引数が含まれる場合は引数の数は制限される。
0.1.2 - 2020-04-24
MWSDK2020_04 に対応
主な改定内容
Timer0..4
の初期化の問題を修正mwx::format()
の内部処理を変更- インタラクティブモード対応のための実験的なコードの追加
0.1.1 - 2020-02-28
主な改定内容
- パケット内の中継フラグの扱いについての問題を修正
0.1.0 - 2019-12-23
初版リリース (SDL 2019/12月号収録)
2 - TWELITE SDK / MWSDK (Legacy)
TWELITE SDK は、TWELITE を扱うための低水準なツールチェーンです。
C言語で書かれたレガシーな TWELITE 向けファームウェアをメンテナンスする際や、TWELITE NET の仕組みを調べるとき、また高度に最適化されたファームウェアを構築する場合に参照してください。
3 - TWELITE Wings API / MWings
3.1 - TWELITE Wings API / MWings for 32-bit Arduinos
3.1.1 - TWELITE Wings API / MWings for 32-bit Arduinos
3.1.1.1 - データ型と手続きの一覧
構造体
BarePacket
親機が子機から受信したパケットの電文情報から得た素のデータを格納します。
データ
型 | 名称 | 内容 |
---|---|---|
uint8_t* | u8Payload | バイナリ変換したペイロードデータ(: とチェックサム、CRLF を除く) |
uint16_t | u16PayloadSize | 上記データのバイト数 |
uint8_t | u8Checksum | 上記データのチェックサム |
手続き
型と名称 | 内容 |
---|---|
uint8_t* u8From(int) | 指定位置以降のペイロードデータを取得する |
uint8_t u8At(int) | 指定位置のペイロードデータを8ビット非不整数として取得する |
int8_t i8At(int) | 指定位置のペイロードデータを8ビット整数として取得する |
uint16_t u16At(int) | 指定位置のペイロードデータを16ビット非不整数として取得する |
int16_t i16At(int) | 指定位置のペイロードデータを16ビット整数として取得する |
uint32_t u32At(int) | 指定位置のペイロードデータを32ビット非不整数として取得する |
int32_t i32At(int) | 指定位置のペイロードデータを32ビット整数として取得する |
mwings::ParsedPacketBase
親機が子機から受信したパース済みデータを格納する構造体の抽象型です。
データ
型 | 名称 | 内容 |
---|---|---|
uint32_t | u32SourceSerialId | 送信元のシリアルID |
uint8_t | u8SourceLogicalId | 送信元の論理デバイスID |
uint16_t | u16SequenceNumber | シーケンス番号 |
uint8_t | u8Lqi | LQI |
uint16_t | u16SupplyVoltage | 電源電圧 (mV) |
この抽象型には、共通して利用されるデータを記述しています。
この抽象型から派生した構造体(例:ParsedAppTwelitePacket
)では、この抽象型のデータを併せて利用できます。
ParsedAppTwelitePacket
親機が超簡単!標準アプリの子機から受信したデータを格納する構造体です。
データ
型 | 名称 | 内容 |
---|---|---|
uint8_t | u8DestinationLogicalId | 送信先の論理デバイスID |
uint8_t | u8RelayCount | 中継回数 |
bool | bPeriodic | 定期送信パケットならtrue |
bool[4] | bDiChanged | 各 DI1-4 が変化したならtrue |
bool[4] | bDiState | 各 DI1-4 が Low 状態ならtrue |
uint16_t[4] | u16AiVoltage | 各 AI1-4 の入力電圧 (mV) |
ParsedAppIoPacket
親機がリモコンアプリの子機から受信したデータを格納する構造体です。
データ
型 | 名称 | 内容 |
---|---|---|
uint8_t | u8RelayCount | 中継回数 |
bool[12] | bDiState | 各 DI が Low 状態ならtrue |
bool[12] | bDiValid | 各 DI が有効ならtrue |
bool[12] | bDiInterrupt | 各 DI が割り込みにより変化したならtrue |
ParsedAppAriaPacket
親機がアリアアプリの子機(TWELITE ARIA モード)から受信したデータを格納する構造体です。
データ
型 | 名称 | 内容 |
---|---|---|
uint32_t | u32RouterSerialId | 最初の中継機のシリアルID 未中継なら 0x80000000 (v1.2.2+) |
int16_t | i16Temp100x | 100倍された温度(摂氏) |
uint16_t | u16Humid100x | 100倍された相対湿度 (%) |
uint8_t | u8MagnetState | 磁気イベントID |
bool | bMagnetStateChanged | 磁気センサの状態が変化したならtrue |
磁気イベントID
ID | 内容 |
---|---|
0x00 | 近くに磁石がない |
0x01 | N極が近くにある |
0x02 | S極が近くにある |
ParsedAppCuePacket
親機がキューアプリの子機(TWELITE CUE モード)から受信したデータを格納する構造体です。
データ
型 | 名称 | 内容 |
---|---|---|
uint32_t | u32RouterSerialId | 最初の中継機のシリアルID 未中継なら 0x80000000 (v1.2.2+) |
int16_t[10] | i16SamplesX | 各サンプルの X 軸加速度 (mG) |
int16_t[10] | i16SamplesY | 各サンプルの Y 軸加速度 (mG) |
int16_t[10] | i16SamplesZ | 各サンプルの Z 軸加速度 (mG) |
uint8_t | u8SampleCount | サンプル数 |
bool | bHasAccelEvent | 加速度イベントがあるならtrue |
uint8_t | u8AccelEvent | 加速度イベントID |
uint8_t | u8MagnetState | 磁気イベントID |
bool | bMagnetStateChanged | 磁気センサの状態が変化したならtrue |
加速度イベントID
ID | 内容 |
---|---|
0x01 ~0x06 | サイコロ |
0x08 | シェイク |
0x10 | ムーブ |
磁気イベントID
ID | 内容 |
---|---|
0x00 | 近くに磁石がない |
0x01 | N極が近くにある |
0x02 | S極が近くにある |
ParsedAppPalAmbPacket
親機がパルアプリの子機(環境センサーパル)から受信したデータを格納する構造体です。
データ
型 | 名称 | 内容 |
---|---|---|
uint32_t | u32RouterSerialId | 最初の中継機のシリアルID 未中継なら 0x80000000 (v1.2.2+) |
uint16_t | u16Ai1Voltage | AI1 の入力電圧 (mV) |
int16_t | i16Temp100x | 100倍された温度(摂氏) |
uint16_t | u16Humid100x | 100倍された相対湿度 (%) |
uint32_t | u32Illuminance | 照度(ルクス) |
ParsedAppPalMotPacket
親機がパルアプリの子機(動作センサーパル)から受信したデータを格納する構造体です。
データ
型 | 名称 | 内容 |
---|---|---|
uint32_t | u32RouterSerialId | 最初の中継機のシリアルID 未中継なら 0x80000000 (v1.2.2+) |
uint16_t | u16Ai1Voltage | AI1 の入力電圧 (mV) |
int16_t[16] | i16SamplesX | 各サンプルの X 軸加速度 (mG) |
int16_t[16] | i16SamplesY | 各サンプルの Y 軸加速度 (mG) |
int16_t[16] | i16SamplesZ | 各サンプルの Z 軸加速度 (mG) |
uint8_t | u8SampleCount | サンプル数 |
uint16_t | u16SamplingFrequency | サンプリング周波数 (Hz) |
ParsedAppPalOpenClosePacket
親機がパルアプリの子機(開閉センサーパル)から受信したデータを格納する構造体です。
データ
型 | 名称 | 内容 |
---|---|---|
uint32_t | u32RouterSerialId | 最初の中継機のシリアルID 未中継なら 0x80000000 (v1.2.2+) |
uint16_t | u16Ai1Voltage | AI1 の入力電圧 (mV) |
uint8_t | u8MagnetState | 磁気イベントID |
bool | bMagnetStateChanged | 磁気センサの状態が変化したならtrue |
磁気イベントID
ID | 内容 |
---|---|
0x00 | 近くに磁石がない |
0x01 | N極が近くにある |
0x02 | S極が近くにある |
ParsedAppUartAsciiPacket
親機がシリアル通信アプリの子機(Aモード)から受信したデータ(簡易形式)を格納する構造体です。
データ
型 | 名称 | 内容 |
---|---|---|
uint8_t | u8CommandId | コマンド種別(応答ID) |
uint8_t* | u8Data | データ |
uint16_t | u16DataSize | データ長 |
ParsedAppUartAsciiExtendedPacket
親機がシリアル通信アプリの子機(Aモード)から受信したデータ(拡張形式)を格納する構造体です。
AppUartAsciiExtendedPacketParser.h
データ
型 | 名称 | 内容 |
---|---|---|
uint32_t | u32DestinationSerialId | 送信先のシリアルID |
uint8_t | u8CommandId | コマンド種別(応答ID) |
uint8_t* | u8Data | データ |
uint16_t | u16DataSize | データ長 |
ParsedActPacket
親機がactの子機から受信したデータを格納する構造体です。
データ
型 | 名称 | 内容 |
---|---|---|
uint8_t | u8CommandId | コマンド種別(応答ID) |
uint8_t* | u8Data | データ |
uint16_t | u16DataSize | データ長 |
mwings::CommandBase
親機から子機に送信するコマンドデータを格納する構造体の抽象型です。
データ
型 | 名称 | 内容 |
---|---|---|
uint8_t | u8DestinationLogicalId | 送信先の論理デバイスID |
手続き
型と名称 | 内容 |
---|---|
bool isValid() | データが正常ならtrue を返す(純粋仮想関数) |
この抽象型には、共通して利用されるデータや手続きを記述しています。
この抽象型から派生した構造体(例:AppTweliteCommand
)では、この抽象型のデータや手続きを併せて利用できます。
AppTweliteCommand
mwings::CommandBase
から派生
親機から超簡単!標準アプリの子機へ送信するコマンドデータを格納する構造体です。
データ
型 | 名称 | 内容 |
---|---|---|
bool[4] | bDiToChange | 各 DO1-4 の状態を変更する場合はtrue |
bool[4] | bDiState | 各 DO1-4 を Low 状態にする場合はtrue |
bool[4] | bPwmToChange | 各 PWM1-4 の状態を変更する場合はtrue |
uint16_t[4] | u16PwmDuty | 各 PWM1-4 のデューティ比 (0-1024) |
AppIoCommand
mwings::CommandBase
から派生
親機から超簡単!標準アプリの子機へ送信するコマンドデータを格納する構造体です。
データ
型 | 名称 | 内容 |
---|---|---|
bool[12] | bDiToChange | 各 O1-12 の状態を変更する場合はtrue |
bool[12] | bDiState | 各 O1-12 を Low 状態にする場合はtrue |
AppPalNoticeCommand
mwings::CommandBase
から派生
親機からパルアプリ(通知パル)の子機へ送信するコマンドデータを格納する構造体です。
AppPalNoticeCommandSerializer.h
データ
型 | 名称 | 内容 |
---|---|---|
AppPalNoticeColor | eColor | 点灯色 |
AppPalNoticeBlinkSpeed | eBlinkSpeed | 点滅速度 |
uint8_t | u8Brightness | 明るさ (0-15) |
uint16_t | u16DurationInSec | 点灯時間(秒) |
AppPalNoticeDetailedCommand
mwings::CommandBase
から派生
親機からパルアプリ(通知パル)の子機へ送信するコマンドデータを格納する構造体です(詳細形式)。
AppPalNoticeDetailedCommandSerializer.h
データ
型 | 名称 | 内容 |
---|---|---|
AppPalNoticeRGBWColor | sRGBWColor | 点灯色 (RGBW) |
uint8_t | u8BlinkDutyPercentage | 点灯時間の割合 (%) |
float | fBlinkPeriodInSec | 点滅周期(秒) |
uint16_t | u16DurationInSec | 点灯時間(秒) |
AppPalNoticeEventCommand
mwings::CommandBase
から派生
親機からパルアプリ(通知パル)の子機へ送信するコマンドデータ(詳細形式)を格納する構造体です。
AppPalNoticeEventCommandSerializer.h
データ
型 | 名称 | 内容 |
---|---|---|
uint8_t | u8EventId | イベントID (0x00-0x10) |
AppUartAsciiCommand
mwings::CommandBase
から派生
親機からシリアル通信アプリ(Aモード)の子機へ送信するコマンドデータ(簡易形式)を格納する構造体です。
データ
型 | 名称 | 内容 |
---|---|---|
uint8_t | u8CommandId | コマンド種別(応答ID) |
uint8_t* | u8Data | データ |
uint16_t | u16DataSize | データ長 |
AppUartAsciiCommand
で表される簡易形式のコマンドデータは、シリアライズする必要がありません。
下記のようにして、Twelite.send()
を直接呼び出してください。
Twelite.send(command.u8DestinationLogicalId, command.u8CommandId,
command.u8Data, command.u16DataSize);
AppPalNoticeRGBWColor
AppPalNoticeDetailedCommand
で使用する点灯色(RGBW)を定義した構造体です。
AppPalNoticeDetailedCommandSerializer.h
データ
型 | 名称 | 内容 |
---|---|---|
uint8_t | red | R (0-15) |
uint8_t | green | G (0-15) |
uint8_t | blue | B (0-15) |
uint8_t | white | W (0-15) |
手続き
型と名称 | 内容 |
---|---|
bool isValid() | データが正常ならtrue を返す |
uint16_t u16() | LSB から RGBW の順に4ビットずつ並べた16ビット非不整数を返す |
列挙型
AppPalNoticeColor
uint8_t
ベースの enum class
?
AppPalNoticeCommand
で使用する点灯色を定義した列挙型です。
AppPalNoticeCommandSerializer.h
識別子 | 値 | 内容 |
---|---|---|
AppPalNoticeColor::RED | 0 | 赤 |
AppPalNoticeColor::GREEN | 1 | 緑 |
AppPalNoticeColor::BLUE | 2 | 青 |
AppPalNoticeColor::YELLOW | 3 | 黄色 |
AppPalNoticeColor::PURPLE | 4 | 紫 |
AppPalNoticeColor::LIGHT_BLUE | 5 | 水色 |
AppPalNoticeColor::WHITE | 6 | 白 |
AppPalNoticeColor::WARM_WHITE | 7 | 暖かい白 |
AppPalNoticeBlinkSpeed
uint8_t
ベースの enum class
AppPalNoticeCommand
で使用する点滅速度を定義した列挙型です。
AppPalNoticeCommandSerializer.h
識別子 | 値 | 内容 |
---|---|---|
AppPalNoticeBlinkSpeed::ALWAYS_ON | 0 | 常時点灯 |
AppPalNoticeBlinkSpeed::SLOW | 1 | おちついた点滅 |
AppPalNoticeBlinkSpeed::MEDIUM | 2 | ほどほどの点滅 |
AppPalNoticeBlinkSpeed::FAST | 3 | せわしない点滅 |
その他のデータ型
手続き
GetAppTweliteSerializedCommandPayloadSize()
constexpr
関数 ?
AppTweliteCommand
をシリアライズしたあとの固定長データのペイロードサイズを返す関数です。
型と名称 | 内容 |
---|---|
int GetAppTweliteSerializedCommandPayloadSize() | バイト数を返します |
GetAppAppPalNoticeSerializedCommandPayloadSize()
constexpr
関数
AppPalNoticeCommand
をシリアライズしたあとの固定長データのペイロードサイズを返す関数です。
AppPalNoticeCommandSerializer.h
型と名称 | 内容 |
---|---|
int GetAppPalNoticeSerializedCommandPayloadSize() | バイト数を返します |
GetAppAppPalNoticeDetailedSerializedCommandPayloadSize()
constexpr
関数
AppPalNoticeDetailedCommand
をシリアライズしたあとの固定長データのペイロードサイズを返す関数です。
AppPalNoticeDetailedCommandSerializer.h
型と名称 | 内容 |
---|---|
int GetAppPalNoticeDetailedSerializedCommandPayloadSize() | バイト数を返します |
GetAppAppPalNoticeEventSerializedCommandPayloadSize()
constexpr
関数
AppPalNoticeEventCommand
をシリアライズしたあとの固定長データのペイロードサイズを返す関数です。
AppPalNoticeEventCommandSerializer.h
型と名称 | 内容 |
---|---|
int GetAppPalNoticeEventSerializedCommandPayloadSize() | バイト数を返します |
3.1.1.2 - クラスの一覧
3.1.1.2.1 - mwings::MWings クラス
mwings::MWings
クラスの解説です。Twelite
オブジェクトは、mwings::MWings
クラスのインスタンスです。mwings::MWings
クラスをスケッチ内でインスタンス化する必要はありません。自動的に初期化される Twelite
オブジェクトを使用してください。コンストラクタ
MWings()
コンストラクタです。内部変数を初期化します。
MWings()
引数
なし
デストラクタ
~MWings()
デストラクタです。確保したバッファを開放します。
~MWings()
公開メンバ関数
begin()
TWELITE を初期化し、指定した設定で起動します。
bool begin(HardwareSerial& serial,
const int indicatorPin = -1,
const int resetPin = -1,
const int programPin = -1,
const uint8_t channel = 18,
const uint32_t appId = 0x67720102,
const uint8_t retryCount = 2,
const uint8_t txPower = 3,
const int rxBufferSize = 1024,
const int timeout = 100,
const uint32_t encryptKey = 0,
HardwareSerial* debugSerial = nullptr);
引数
型 | 名称 | 内容 | 省略 | 備考 |
---|---|---|---|---|
HardwareSerial& | serial | TWELITE と通信するポート | ||
int | indicatorPin | ステータスLEDを接続したピン | 🆗 | -1 で省略可 |
int | resetPin | TWELITE の RST ピン | 🆗 | -1 で省略可 |
int | programPin | TWELITE の PRGピン | 🆗 | -1 で省略可 |
uint8_t | channel | 周波数チャネル | 🆗 | 省略時は0x67720102 |
uint32_t | appId | アプリケーション ID | 🆗 | 省略時は18 |
uint8_t | retryCount | 再送回数 | 🆗 | 0-9 |
uint8_t | txPower | 送信出力 | 🆗 | 0-3 |
int | rxBufferSize | パケット受信バッファのサイズ | 🆗 | バイナリベース |
int | timeout | 各パケットのタイムアウト時間 | 🆗 | 受信完了まで |
uint32_t | encryptKey | 暗号化鍵 | 🆗 | 0 で無効,v1.2.3+ |
HardwareSerial* | debugSerial | デバッグ出力ポート | 🆗 |
戻り値
型 | 値 | 内容 | 備考 |
---|---|---|---|
bool | true | 成功 | |
false | エラー |
end()
すべての内部変数を初期化します。
inline void end()
引数
なし
戻り値
なし
update()
シリアル受信バッファを読み出し、親機から送られた ModBus ASCII 形式のデータをパースします。
void update();
引数
なし
戻り値
なし
on()
<BarePacket
>
すべての子機から送られたデータに対して行う処理を登録します。
inline void on(void (*callback)(const BarePacket& packet))
引数
型 | 名称 | 内容 | 省略 | 備考 |
---|---|---|---|---|
void (*)(BarePacket&) | callback | イベントハンドラ |
BarePacket
の詳細は データと手続き をご覧ください。戻り値
なし
on()
<ParsedAppTwelitePacket
>
超簡単!標準アプリの子機から送られたデータに対して行う処理を登録します。
inline void on(void (*callback)(const ParsedAppTwelitePacket& packet))
引数
型 | 名称 | 内容 | 省略 | 備考 |
---|---|---|---|---|
void (*)(ParsedAppTwelitePacket&) | callback | イベントハンドラ |
ParsedAppTwelitePacket
の詳細は データと手続き をご覧ください。戻り値
なし
on()
<ParsedAppIoPacket
>
リモコンアプリの子機から送られたデータに対して行う処理を登録します。
inline void on(void (*callback)(const ParsedAppIoPacket& packet))
引数
型 | 名称 | 内容 | 省略 | 備考 |
---|---|---|---|---|
void (*)(ParsedAppIoPacket&) | callback | イベントハンドラ |
ParsedAppIoPacket
の詳細は データと手続き をご覧ください。戻り値
なし
on()
<ParsedAppAriaPacket
>
アリアアプリ(TWELITE ARIA モード)の子機から送られたデータに対して行う処理を登録します。
inline void on(void (*callback)(const ParsedAppAriaPacket& packet))
引数
型 | 名称 | 内容 | 省略 | 備考 |
---|---|---|---|---|
void (*)(ParsedAppAriaPacket&) | callback | イベントハンドラ |
ParsedAppAriaPacket
の詳細は データと手続き をご覧ください。戻り値
なし
on()
<ParsedAppCuePacket
>
キューアプリ(TWELITE CUE モード)の子機から送られたデータに対して行う処理を登録します。
inline void on(void (*callback)(const ParsedAppCuePacket& packet))
引数
型 | 名称 | 内容 | 省略 | 備考 |
---|---|---|---|---|
void (*)(ParsedAppCuePacket&) | callback | イベントハンドラ |
ParsedAppCuePacket
の詳細は データと手続き をご覧ください。戻り値
なし
on()
<ParsedAppPalOpenClosePacket
>
パルアプリ(開閉センサーパル)の子機から送られたデータに対して行う処理を登録します。
inline void on(void (*callback)(const ParsedAppPalOpenClosePacket& packet))
引数
型 | 名称 | 内容 | 省略 | 備考 |
---|---|---|---|---|
void (*)(ParsedAppPalOpenClosePacket&) | callback | イベントハンドラ |
ParsedAppPalOpenClosePacket
の詳細は データと手続き をご覧ください。戻り値
なし
on()
<ParsedAppPalAmbPacket
>
パルアプリ(環境センサーパル)の子機から送られたデータに対して行う処理を登録します。
inline void on(void (*callback)(const ParsedAppPalAmbPacket& packet))
引数
型 | 名称 | 内容 | 省略 | 備考 |
---|---|---|---|---|
void (*)(ParsedAppPalAmbPacket&) | callback | イベントハンドラ |
ParsedAppPalAmbPacket
の詳細は データと手続き をご覧ください。戻り値
なし
on()
<ParsedAppPalMotPacket
>
パルアプリ(動作センサーパル)の子機から送られたデータに対して行う処理を登録します。
inline void on(void (*callback)(const ParsedAppPalMotPacket& packet))
引数
型 | 名称 | 内容 | 省略 | 備考 |
---|---|---|---|---|
void (*)(ParsedAppPalMotPacket&) | callback | イベントハンドラ |
ParsedAppPalMotPacket
の詳細は データと手続き をご覧ください。戻り値
なし
on()
<ParsedAppUartAsciiPacket
>
シリアル通信アプリ(Aモード)の子機から送られたデータ(簡易形式)に対して行う処理を登録します。
inline void on(void (*callback)(const ParsedAppUartAsciiPacket& packet))
引数
型 | 名称 | 内容 | 省略 | 備考 |
---|---|---|---|---|
void (*)(ParsedAppUartAsciiPacket&) | callback | イベントハンドラ |
ParsedAppUartAsciiPacket
の詳細は データと手続き をご覧ください。戻り値
なし
on()
<ParsedAppUartAsciiExtendedPacket
>
シリアル通信アプリ(Aモード)の子機から送られたデータ(拡張形式)に対して行う処理を登録します。
inline void on(void (*callback)(const ParsedAppUartAsciiExtendedPacket& packet))
引数
型 | 名称 | 内容 | 省略 | 備考 |
---|---|---|---|---|
void (*)(ParsedAppUartAsciiExtendedPacket&) | callback | イベントハンドラ |
ParsedAppUartAsciiExtendedPacket
の詳細は データと手続き をご覧ください。戻り値
なし
on()
<ParsedActPacket
>
act の子機から送られたデータに対して行う処理を登録します。
inline void on(void (*callback)(const ParsedActPacket& packet))
引数
型 | 名称 | 内容 | 省略 | 備考 |
---|---|---|---|---|
void (*)(ParsedActPacket&) | callback | イベントハンドラ |
ParsedActPacket
の詳細は データと手続き をご覧ください。戻り値
なし
send()
<uint8_t*, int, uint8_t
>
任意のコマンド(ModBus ASCII 形式)を親機に送信します。
inline bool send(const uint8_t* const payload,
const int payloadSize,
const uint8_t checksum)
引数
型 | 名称 | 内容 | 省略 | 備考 |
---|---|---|---|---|
uint8_t* | payload | ペイロード | : と LRC の間 | |
int | payloadSize | ペイロードのサイズ | ||
uint8_t | checksum | チェックサム | ペイロードの LRC |
戻り値
型 | 値 | 内容 | 備考 |
---|---|---|---|
bool | true | 成功 | |
false | エラー |
send()
<uint8_t*, int
>
任意のコマンド(ModBus ASCII 形式)を親機に送信します(チェックサム自動付与)。
inline bool send(const uint8_t* const payload,
const int payloadSize)
引数
型 | 名称 | 内容 | 省略 | 備考 |
---|---|---|---|---|
uint8_t* | payload | ペイロード | : と LRC の間 | |
int | payloadSize | ペイロードのサイズ |
戻り値
型 | 値 | 内容 | 備考 |
---|---|---|---|
bool | true | 成功 | |
false | エラー |
send()
<uint8_t, uint8_t, uint8_t* int, uint8_t
>
任意のコマンド(ModBus ASCII 形式)を親機に送信します。
inline bool send(const uint8_t logicalId,
const uint8_t commandId,
const uint8_t* const payload,
const int payloadSize,
const uint8_t checksum)
引数
型 | 名称 | 内容 | 省略 | 備考 |
---|---|---|---|---|
uint8_t | logicalId | 宛先の論理デバイス ID | ||
uint8_t | commandId | コマンド種別 | ||
uint8_t* | payload | ペイロード | : と LRC の間 | |
int | payloadSize | ペイロードのサイズ | ||
uint8_t | checksum | チェックサム | ペイロードの LRC |
戻り値
型 | 値 | 内容 | 備考 |
---|---|---|---|
bool | true | 成功 | |
false | エラー |
send()
<uint8_t, uint8_t, uint8_t* int
>
任意のコマンド(ModBus ASCII 形式)を親機に送信します(チェックサム自動付与)。
inline bool send(const uint8_t logicalId,
const uint8_t commandId,
const uint8_t* const payload,
const int payloadSize)
引数
型 | 名称 | 内容 | 省略 | 備考 |
---|---|---|---|---|
uint8_t | logicalId | 宛先の論理デバイス ID | ||
uint8_t | commandId | コマンド種別 | ||
uint8_t* | payload | ペイロード | : と LRC の間 | |
int | payloadSize | ペイロードのサイズ |
戻り値
型 | 値 | 内容 | 備考 |
---|---|---|---|
bool | true | 成功 | |
false | エラー |
send()
<AppTweliteCommand
>
超簡単!標準アプリの端末を操作するためのコマンドを親機に送信します。
inline bool send(AppTweliteCommand& command)
引数
型 | 名称 | 内容 | 省略 | 備考 |
---|---|---|---|---|
AppTweliteCommand | command | コマンドデータ |
AppTweliteCommand
の詳細は データと手続き をご覧ください。戻り値
型 | 値 | 内容 | 備考 |
---|---|---|---|
bool | true | 成功 | |
false | エラー |
send()
<AppIoCommand
>
リモコンアプリの端末を操作するためのコマンドを親機に送信します。
inline bool send(AppIoCommand& command)
引数
型 | 名称 | 内容 | 省略 | 備考 |
---|---|---|---|---|
AppIoCommand | command | コマンドデータ |
AppIoCommand
の詳細は データと手続き をご覧ください。戻り値
型 | 値 | 内容 | 備考 |
---|---|---|---|
bool | true | 成功 | |
false | エラー |
send()
<AppPalNoticeCommand
>
パルアプリ(通知パル)の端末を操作するためのコマンドを親機に送信します。
inline bool send(AppPalNoticeCommand& command)
引数
型 | 名称 | 内容 | 省略 | 備考 |
---|---|---|---|---|
AppPalNoticeCommand | command | コマンドデータ |
AppPalNoticeCommand
の詳細は データと手続き をご覧ください。戻り値
型 | 値 | 内容 | 備考 |
---|---|---|---|
bool | true | 成功 | |
false | エラー |
send()
<AppPalNoticeDetailedCommand
>
パルアプリ(通知パル)の端末を操作するためのコマンド(詳細形式)を親機に送信します。
inline bool send(AppPalNoticeDetailedCommand& command)
引数
型 | 名称 | 内容 | 省略 | 備考 |
---|---|---|---|---|
AppPalNoticeDetailedCommand | command | コマンドデータ |
AppPalNoticeDetailedCommand
の詳細は データと手続き をご覧ください。戻り値
型 | 値 | 内容 | 備考 |
---|---|---|---|
bool | true | 成功 | |
false | エラー |
send()
<AppPalNoticeEventCommand
>
パルアプリ(通知パル)の端末を操作するためのコマンド(イベント)を親機に送信します。
inline bool send(AppPalNoticeEventCommand& command)
引数
型 | 名称 | 内容 | 省略 | 備考 |
---|---|---|---|---|
AppPalNoticeEventCommand | command | コマンドデータ |
AppPalNoticeEventCommand
の詳細は データと手続き をご覧ください。戻り値
型 | 値 | 内容 | 備考 |
---|---|---|---|
bool | true | 成功 | |
false | エラー |
send()
<AppPalUartAsciiCommand
>
シリアル通信アプリ(Aモード)の端末を操作するためのコマンド(簡易形式)を親機に送信します。
inline bool send(AppPalUartAsciiCommand& command)
引数
型 | 名称 | 内容 | 省略 | 備考 |
---|---|---|---|---|
AppPalUartAsciiCommand | command | コマンドデータ |
AppPalUartAsciiCommand
の詳細は データと手続き をご覧ください。戻り値
型 | 値 | 内容 | 備考 |
---|---|---|---|
bool | true | 成功 | |
false | エラー |
3.2 - TWELITE Wings API / MWings for Python
3.2.1 - TWELITE Wings API / MWings for Python
3.2.1.1 - mwings モジュール
mwings
直接利用することの多い、トップレベルのモジュールです。
Twelite
TWELITE のインタフェース
Twelite()
Twelite(port=None, rx_buffer_size=1024, timeout=100, tz=None, debugging=False)
コンストラクタです。シリアルポートを指定している場合は、これを開きます。
引数
名称 | 型 | 内容 |
---|---|---|
port | optional str | シリアルポート名:None で無効 |
rx_buffer_size | int | 受信バッファのサイズ:バイト数 |
timeout | int | 受信パケット間のタイムアウト(ms) |
tz | optional tzinfo | 受信データへ適用するイムゾーン:None でUTC |
debugging | bool | デバッグ出力:True で有効 |
例外
IOError
シリアルポートが存在しないかビジー状態
close()
v1.0.10+
close()
シリアルポートを開いている場合、これを閉じます。
通常、開いたシリアルポートはclose()
を呼ばずとも自動的に閉じられます。
明示的に閉じたい場合には、この関数またはwith
文を使用してください。
引数
なし
戻り値
なし
add_listener()
@overload
add_listener(event, handler)
add_listener(event, handler)
受信ハンドラを登録します。
引数
名称 | 型 | 内容 |
---|---|---|
event | common.PacketType | 受信イベントの識別子 |
handler | Callable[[common.BarePacket], None] | 受信イベントのハンドラ(素のデータ) |
Callable[[common.SomeCallable], None] | 受信イベントのハンドラ(パースしたデータ) |
戻り値
なし
on()
on(event)
受信ハンドラを登録します(デコレータ版)。
引数
名称 | 型 | 内容 |
---|---|---|
event | common.PacketType | 受信イベント識別子 |
戻り値
型 | 値 | 内容 |
---|---|---|
Callable[[common.SomeCallable], common.SomeCallable] | - | デコレートされた関数 |
remove_all_listeners()
v1.0.9+
remove_all_listeners()
登録した受信ハンドラをすべて削除します。
引数
なし
戻り値
なし
parse()
@overload
parse(character, use_lf=False)
parse(character, use_lf=False)
parse(character, use_lf=False)
与えられた受信データを解釈します。
引数
名称 | 型 | 内容 |
---|---|---|
character | str | 受信データの文字:長さ1の文字列 |
bytes | 受信データの文字:長さ1のバイト列 | |
int | 受信データの文字:ASCIIコード | |
use_lf | bool | 改行文字の種別:True のとき LF |
戻り値
型 | 値 | 内容 |
---|---|---|
optional common.PacketType | common.PacketType | 解釈したパケットの種別 |
None | 解釈したパケットなし |
例外
RuntimeError
シリアルポートを指定してしまっているValueError
不正な文字データを検出
parse_line()
parse_line(line, use_lf=True)
一行の文字列として表現された受信データを解釈します。
引数
名称 | 型 | 内容 |
---|---|---|
line | str | 受信データの文字列:一行の文字列 |
use_lf | bool | 改行文字の種別:True のとき LF |
戻り値
型 | 値 | 内容 |
---|---|---|
optional common.PacketType | common.PacketType | 解釈したパケットの種別 |
None | 解釈したパケットなし |
例外
RuntimeError
シリアルポートを指定してしまっている
receive()
receive()
シリアルポートに届いたデータを解釈します。一つのパケットの解釈が終わるまで待機します。
引数
なし
戻り値
型 | 値 | 内容 |
---|---|---|
common.PacketType | - | 解釈したパケットの種別 |
例外
RuntimeError
シリアルポートを指定していない
run()
run()
受信を行うサブスレッドを走らせます。threading.Thread.run()
をオーバーライドしています。
start()
を使用すると自動的に呼び出されます。引数
なし
戻り値
なし
send()
@overload
send(data)
send(data)
シリアルポートからコマンドを送信します。
引数
名称 | 型 | 内容 |
---|---|---|
data | common.SomeCommand | 各種コマンドデータ |
common.BarePacket | 素のコマンドデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
bool | True | 成功 |
False | 失敗 |
例外
RuntimeError
シリアルポートを指定していない
set_timezone()
set_timezone(tz)
受信データへ適用するタイムゾーンを設定します。
引数
名称 | 型 | 内容 |
---|---|---|
tz | tzinfo | 任意のタイムゾーン:ZoneInfo |
None | UTC |
戻り値
なし
start()
start()
受信を行うサブスレッドを開始します。threading.Thread.start()
をオーバーライドしています。
引数
なし
戻り値
なし
例外
RuntimeError
シリアルポートを指定していない
stop()
stop()
受信を行うサブスレッドを終了します。残りの受信データに対するハンドラの呼び出しを終えるまで待機します。これには数秒かかる場合があります。
引数
なし
戻り値
なし
例外
RuntimeError
シリアルポートを指定していない
update()
update()
シリアルポートへ届いたデータを解釈します。受信バッファのすべてのデータを処理したら、すぐに処理を抜けます。
引数
なし
戻り値
型 | 値 | 内容 |
---|---|---|
optional common.PacketType | common.PacketType | 解釈したパケットの種別 |
None | 解釈したパケットなし |
例外
RuntimeError
シリアルポートを指定していない
timezone
@property
update()
戻り値
型 | 値 | 内容 |
---|---|---|
tzinfo | - | 受信データへ適用するタイムゾーン |
3.2.1.1.1 - mwings.common モジュール
mwings.common
ライブラリ全体で使用するデータや手続きを格納しています。
AccelEvent
加速度イベントの識別子
継承:
enum.IntEnum
DICE_1
サイコロ:1DICE_2
サイコロ:2DICE_3
サイコロ:3DICE_4
サイコロ:4DICE_5
サイコロ:5DICE_6
サイコロ:6SHAKE
シェイクMOVE
ムーブNONE
イベントなし
AppPalNoticeBlinkSpeed
通知パル/点滅速度の識別子
継承:
enum.IntEnum
ALWAYS_ON
常時点灯SLOW
おちついた点滅MEDIUM
ほどほどの点滅FAST
せわしない点滅
AppPalNoticeColor
通知パル/点灯色の識別子
継承:
enum.IntEnum
RED
赤GREEN
緑BLUE
青YELLOW
黄PURPLE
紫LIGHT_BLUE
水色WHITE
白WARM_WHITE
暖かな白
AppPalNoticeRGBWColor
通知パル/RGBWによる点灯色のデータ
AppPalNoticeRGBWColor()
AppPalNoticeRGBWColor(*, red=0, green=0, blue=0, white=15)
引数
名称 | 型 | 内容 |
---|---|---|
red | common.UInt8 | 赤:0 -0xF |
green | common.UInt8 | 緑:0 -0xF |
blue | common.UInt8 | 青:0 -0xF |
white | common.UInt8 | 白:0 -0xF |
**
で unpack した辞書を渡すことができます。
u16()
u16()
RGBWの16ビット表現を取得します。
引数
なし
戻り値
型 | 値 | 内容 |
---|---|---|
common.UInt16 | - | RGBWの16ビット表現 |
BarePacket
素のパケットデータ
BarePacket()
BarePacket(payload, checksum=None, logical_and_command_id=None)
引数
名称 | 型 | 内容 |
---|---|---|
payload | bytes | ペイロードのバイナリデータ |
checksum | optional common.UInt8 | LRC8:None で自動計算 |
logical_and_command_id | optional tuple(common.UInt8, common.UInt8) | 論理デバイスIDとコマンドID |
第3引数を指定する場合は、ペイロードの冒頭を省略します。
i16_at()
i16_at(index)
指定した位置の符号あり16ビット整数を取得します。
引数
名称 | 型 | 内容 |
---|---|---|
index | int | ペイロードにおける位置 |
戻り値
型 | 値 | 内容 |
---|---|---|
common.Int16 | - | 数値データ |
i32_at()
i32_at(index)
指定した位置の符号あり32ビット整数を取得します。
引数
名称 | 型 | 内容 |
---|---|---|
index | int | ペイロードにおける位置 |
戻り値
型 | 値 | 内容 |
---|---|---|
common.Int32 | - | 数値データ |
i8_at()
i8_at(index)
指定した位置の符号あり8ビット整数を取得します。
引数
名称 | 型 | 内容 |
---|---|---|
index | int | ペイロードにおける位置 |
戻り値
型 | 値 | 内容 |
---|---|---|
common.Int8 | - | 数値データ |
u16_at()
u16_at(index)
指定した位置の符号なし16ビット整数を取得します。
引数
名称 | 型 | 内容 |
---|---|---|
index | int | ペイロードにおける位置 |
戻り値
型 | 値 | 内容 |
---|---|---|
common.UInt16 | - | 数値データ |
u32_at()
u32_at(index)
指定した位置の符号なし32ビット整数を取得します。
引数
名称 | 型 | 内容 |
---|---|---|
index | int | ペイロードにおける位置 |
戻り値
型 | 値 | 内容 |
---|---|---|
common.UInt32 | - | 数値データ |
u8_at()
u8_at(index)
指定した位置の符号なし8ビット整数を取得します。
引数
名称 | 型 | 内容 |
---|---|---|
index | int | ペイロードにおける位置 |
戻り値
型 | 値 | 内容 |
---|---|---|
common.UInt8 | - | 数値データ |
u8_from()
u8_from(index)
指定した位置に続くバイト列を取得します。
引数
名称 | 型 | 内容 |
---|---|---|
index | int | ペイロードにおける先頭の位置 |
戻り値
型 | 値 | 内容 |
---|---|---|
optional bytes | bytes | 部分的なバイト列 |
None | 指定位置が無効 |
CommandBase
コマンドの抽象基底クラス
CommandBase()
CommandBase(*, destination_logical_id=120)
引数
名称 | 型 | 内容 |
---|---|---|
destination_logical_id | common.UInt8 | 送信先の論理デバイスID |
**
で unpack した辞書を渡すことができます。
is_valid()
is_valid()
コマンドデータが有効であるか否かを確認します。
引数
なし
戻り値
型 | 値 | 内容 |
---|---|---|
bool | True | 有効 |
False | 無効 |
CommandSerializerBase
コマンドシリアライザの静的抽象基底クラス
継承:
ABC
serialize()
serialize(command)
与えられたコマンドを素のパケットのバイト列へ展開します。
引数
名称 | 型 | 内容 |
---|---|---|
command | common.SomeCommand | 何らかのコマンドデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
optional common.BarePacket | common.BarePacket | 展開したデータ |
None | 無効なコマンドデータである |
CrossSectional[T]
特定の時刻における横断的なデータ列を格納するためのタプルに相当するクラス
CrossSectional[T]()
CrossSectional[T](length, elements)
引数
名称 | 型 | 内容 |
---|---|---|
T | common.T | 要素の型 |
length | int | 要素の数 |
elements | Iterable[T] | 要素 |
例外
ValueError
要素の数が不正
DtypedDecimal
pandas の dtype
属性を保持する数値型のための抽象基底クラス
get_dtype()
get_dtype()
pandas の dtype
識別子を取得します。
引数
なし
戻り値
型 | 値 | 内容 |
---|---|---|
str | - | dtype 識別子 |
FixedList[T]
固定長リストに相当するクラス
FixedList[T]()
FixedList[T](length, initial_elements)
引数
名称 | 型 | 内容 |
---|---|---|
T | common.T | 要素の型 |
length | int | 要素の数 |
initial_elements | Iterable[T] | 初期の要素 |
例外
ValueError
要素の数が不正
insert()
insert(index, value)
指定した位置へ要素を配置します。
引数
名称 | 型 | 内容 |
---|---|---|
index | int | 配置する位置 |
value | common.T | 配置する要素 |
戻り値
なし
例外
IndexError
位置が不正
FixedTuple[T]
固定長タプルに相当するクラス
継承:
Sequence[T]
FixedTuple[T]()
FixedTuple[T](length, elements)
引数
名称 | 型 | 内容 |
---|---|---|
T | common.T | 要素の型 |
length | int | 要素の数 |
elements | Iterable[T] | 要素 |
例外
ValueError
要素の数が不正
Float32
32ビット浮動小数点数を格納するクラス
継承:
float
,common.DtypedDecimal
Float32()
Float32(value=None)
引数
名称 | 型 | 内容 |
---|---|---|
value | optional float | 初期の値 |
例外
ValueError
範囲外の値
Float64
64ビット浮動小数点数を格納するクラス
継承:
float
,common.DtypedDecimal
Float64()
Float64(value=None)
引数
名称 | 型 | 内容 |
---|---|---|
value | optional float | 初期の値 |
例外
ValueError
範囲外の値
Int16
16ビット整数を格納するクラス
継承:
int
,common.DtypedDecimal
Int16()
Int16(value=None)
引数
名称 | 型 | 内容 |
---|---|---|
value | optional int | 初期の値 |
例外
ValueError
範囲外の値
hex()
hex()
16進数表記の文字列を取得します。
Python 組み込み関数の hex()
は int
のサブクラスを受け付けません。float
に対する組み込みメソッド hex()
と同じように扱えるようにしています。
引数
なし
戻り値
型 | 値 | 内容 |
---|---|---|
str | - | 16進数表記の文字列(小文字) |
Int32
32ビット整数を格納するクラス
継承:
int
,common.DtypedDecimal
Int32()
Int32(value=None)
引数
名称 | 型 | 内容 |
---|---|---|
value | optional int | 初期の値 |
例外
ValueError
範囲外の値
hex()
hex()
16進数表記の文字列を取得します。
Python 組み込み関数の hex()
は int
のサブクラスを受け付けません。float
に対する組み込みメソッド hex()
と同じように扱えるようにしています。
引数
なし
戻り値
型 | 値 | 内容 |
---|---|---|
str | - | 16進数表記の文字列(小文字) |
Int8
8ビット整数を格納するクラス
継承:
int
,common.DtypedDecimal
Int8()
Int8(value=None)
引数
名称 | 型 | 内容 |
---|---|---|
value | optional int | 初期の値 |
例外
ValueError
範囲外の値
hex()
hex()
16進数表記の文字列を取得します。
Python 組み込み関数の hex()
は int
のサブクラスを受け付けません。float
に対する組み込みメソッド hex()
と同じように扱えるようにしています。
引数
なし
戻り値
型 | 値 | 内容 |
---|---|---|
str | - | 16進数表記の文字列(小文字) |
MagnetState
磁石イベントの識別子
継承:
enum.IntEnum
NOT_DETECTED
磁石なしN_POLE_IS_CLOSE
N極が近くにあるS_POLE_IS_CLOSE
S極が近くにある
PacketParserBase
パケットパーサの静的抽象基底クラス
継承:
ABC
is_valid()
is_valid(bare_packet)
与えられた素のパケットが有効であるか否かを確認します。
引数
名称 | 型 | 内容 |
---|---|---|
bare_packet | common.BarePacket | 素のパケットデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
bool | True | 有効、パース可 |
False | 無効、パース不可 |
parse()
parse(bare_packet)
与えられた素のパケットをパースします。
引数
名称 | 型 | 内容 |
---|---|---|
bare_packet | common.BarePacket | 素のパケットデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
optional common.ParsedPacketBase | common.ParsedPacketBase を基底クラスにもつデータ | パースしたデータ |
None | パース不可 |
PacketType
パケット種別の識別子
継承:
enum.StrEnum
BARE
素のパケット(未パース)ACT
actAPP_TWELITE
超簡単!標準アプリAPP_IO
リモコンアプリAPP_ARIA
アリアアプリAPP_CUE
キューアプリ(TWELITE CUE モード)APP_CUE_PAL_EVENT
キューアプリ(動作パルモード:ダイス/ムーブモード)APP_PAL_OPENCLOSE
パルアプリ(開閉パル)APP_PAL_AMB
パルアプリ(環境パル)APP_PAL_MOT
パルアプリ(動作パル)/キューアプリ(動作パルモード:加速度計測)APP_UART_ASCII
シリアル通信アプリ(書式モード:簡易形式)/超簡単!標準アプリ/リモコンアプリAPP_UART_ASCII_EXTENDED
シリアル通信アプリ(書式モード:拡張形式)
ParsedPacketBase
パース済みパケットの抽象基底クラス
ParsedPacketBase()
ParsedPacketBase(*, time_parsed=None, packet_type=PacketType.BARE, sequence_number=None, source_serial_id=0, source_logical_id=0, lqi=None, supply_voltage=None)
引数
名称 | 型 | 内容 |
---|---|---|
time_parsed | optional AwareDatetime | パース時刻 |
packet_type | common.PacketType | パケット種別 |
sequence_number | optional common.UInt16 | シーケンス番号 |
source_serial_id | common.UInt32 | 送信元のシリアルID |
source_logical_id | common.UInt8 | 送信元の論理デバイスID |
lqi | common.UInt8 | 電波通信品質 |
supply_voltage | optional common.UInt16 | 電源電圧(mV) |
**
で unpack した辞書を渡すことができます。
コンストラクタの引数へ指定する変数に加えて、次の @computed_field
を持ちます。
名称 | 型 | 内容 |
---|---|---|
mwings_implementation | str | MWings の実装("python" のみ) |
mwings_version | str | MWings のバージョン(PEP440形式) |
hostname | str | ホストマシン名 |
system_type | str | システム種別("Linux" など) |
適用される field_validator
source_logical_id
:値の範囲を自動的に検証しますcheck_source_logical_id(lid)
time_parsed
:タイムゾーンが付与されているかを自動的に検証しますdatetime_must_be_clear(dt)
適用される field_serializer
packet_type
:列挙子の名前をそのままJSON等に適用しますserialize_packet_type(packet_type)
source_serial_id
:16進表記の文字列をJSON等に適用しますserialize_source_serial_id(source_serial_id)
time_parsed
:ISO 8601形式の文字列をJSON等に適用しますserialize_time_parsed(dt)
to_df()
to_df(include=None, exclude=None, verbose=True)
パースしたデータを pandas のデータフレーム形式へ変換します。
mwingslite
の場合、pandas
が導入されていない場合はEnvironmentError
を発します。引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | データフレームへ含めるカラム(メンバ)の集合 |
exclude | optional set[str] | データフレームへ含めないカラム(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
戻り値
型 | 値 | 内容 |
---|---|---|
pd.DataFrame | - | 変換したデータフレーム |
例外
EnvironmentError
pandas のない場合
to_dict()
to_dict(include=None, exclude=None, verbose=True, spread=False, sort_keys=False)
パースしたデータを辞書形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | 辞書へ含めるキー(メンバ)の集合 |
exclude | optional set[str] | 辞書へ含めないキー(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
spread | bool | 時系列でないlist-likeデータの分割の有無 |
sort_keys | bool | キーによるソートの有無 |
spread
を設定すると、common.CrossSectional[T]
型のデータを分割します。例えば、超簡単!標準アプリのdi_state[4]
をdi_state_1
/di_state_2
/di_state_3
/di_state_4
へ分割します。common.TimeSeries[T]
型の時系列データは分割しません。戻り値
型 | 値 | 内容 |
---|---|---|
dict[str, Any] | - | 変換した辞書 |
to_json()
to_json(include=None, exclude=None, verbose=True, spread=False, indent=2, sort_keys=False)
パースしたデータをJSON形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | JSONへ含めるキー(メンバ)の集合 |
exclude | optional set[str] | JSONへ含めないキー(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
spread | bool | 時系列でないlist-likeデータの分割の有無 |
indent | optional int | インデントの数(None で改行なし) |
sort_keys | bool | キーによるソートの有無 |
spread
を設定すると、common.CrossSectional[T]
型のデータを分割します。例えば、超簡単!標準アプリのdi_state[4]
をdi_state_1
/di_state_2
/di_state_3
/di_state_4
へ分割します。common.TimeSeries[T]
型の時系列データは分割しません。戻り値
型 | 値 | 内容 |
---|---|---|
str | - | 変換したJSON文字列 |
SomeCallable
TypeVar("SomeCallable", bound=Callable[..., Any])
各種ハンドラを表す型
SomeCommand
TypeVar(‘SomeCommand’, bound=CommandBase)
各種コマンドデータを表す型
SomeParsedPacket
TypeVar(‘SomeParsedPacket’, bound=ParsedPacketBase)
各種パケットデータを表す型
T
TypeVar("T")
ジェネリクスで利用する型
TimeSeries[T]
時系列データを格納するためのタプルに相当するクラス
TimeSeries[T]()
TimeSeries[T](length, elements)
引数
名称 | 型 | 内容 |
---|---|---|
T | common.T | 要素の型 |
length | int | 要素の数 |
elements | Iterable[T] | 要素 |
例外
ValueError
要素の数が不正
Timezone
全体へ適用するtzinfo
UInt16
16ビット非不整数を格納するクラス
継承:
int
,common.DtypedDecimal
UInt16()
UInt16(value=None)
引数
名称 | 型 | 内容 |
---|---|---|
value | optional int | 初期の値 |
例外
ValueError
範囲外の値
hex()
hex()
16進数表記の文字列を取得します。
Python 組み込み関数の hex()
は int
のサブクラスを受け付けません。float
に対する組み込みメソッド hex()
と同じように扱えるようにしています。
引数
なし
戻り値
型 | 値 | 内容 |
---|---|---|
str | - | 16進数表記の文字列(小文字) |
UInt32
32ビット非不整数を格納するクラス
継承:
int
,common.DtypedDecimal
UInt32()
UInt32(value=None)
引数
名称 | 型 | 内容 |
---|---|---|
value | optional int | 初期の値 |
例外
ValueError
範囲外の値
hex()
hex()
16進数表記の文字列を取得します。
Python 組み込み関数の hex()
は int
のサブクラスを受け付けません。float
に対する組み込みメソッド hex()
と同じように扱えるようにしています。
引数
なし
戻り値
型 | 値 | 内容 |
---|---|---|
str | - | 16進数表記の文字列(小文字) |
UInt8
8ビット非不整数を格納するクラス
継承:
int
,common.DtypedDecimal
UInt8()
UInt8(value=None)
引数
名称 | 型 | 内容 |
---|---|---|
value | optional int | 初期の値 |
例外
ValueError
範囲外の値
hex()
hex()
16進数表記の文字列を取得します。
Python 組み込み関数の hex()
は int
のサブクラスを受け付けません。float
に対する組み込みメソッド hex()
と同じように扱えるようにしています。
引数
なし
戻り値
型 | 値 | 内容 |
---|---|---|
str | - | 16進数表記の文字列(小文字) |
3.2.1.1.2 - mwings.parsers モジュール
mwings.parsers
3.2.1.1.2.1 - mwings.parsers.app_twelite モジュール
mwings.parsers.app_twelite
超簡単!標準アプリから送信されたデータを表すパケットを解釈するパーサと、そのデータを扱います。
PacketParser
超簡単!標準アプリから送信されたデータを表すパケットを解釈するパーサの静的クラス
is_valid()
is_valid(bare_packet)
与えられた素のパケットが有効であるか否かを確認します。
引数
名称 | 型 | 内容 |
---|---|---|
bare_packet | common.BarePacket | 素のパケットデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
bool | True | 有効、パース可 |
False | 無効、パース不可 |
parse()
parse(bare_packet)
与えられた素のパケットをパースします。
引数
名称 | 型 | 内容 |
---|---|---|
bare_packet | common.BarePacket | 素のパケットデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
optional ParsedPacket | ParsedPacket の型をもつデータ | パースしたデータ |
None | パース不可 |
ParsedPacket
超簡単!標準アプリから送信されたデータを表すパケットを解釈した結果を格納するための構造体
ParsedPacket()
ParsedPacket(*, time_parsed=None, packet_type=PacketType.BARE, sequence_number=None, source_serial_id=0, source_logical_id=0, lqi=None, supply_voltage=None, destination_logical_id=120, relay_count=0, periodic=False, di_changed=<mwings.common.CrossSectional object>, di_state=<mwings.common.CrossSectional object>, ai_voltage=<mwings.common.CrossSectional object>)
引数
名称 | 型 | 内容 |
---|---|---|
time_parsed | optional AwareDatetime | パース時刻 |
packet_type | common.PacketType | パケット種別 |
sequence_number | optional common.UInt16 | シーケンス番号 |
source_serial_id | common.UInt32 | 送信元のシリアルID |
source_logical_id | common.UInt8 | 送信元の論理デバイスID |
lqi | optional common.UInt8 | 電波通信品質 |
supply_voltage | optional common.UInt16 | 電源電圧(mV) |
destination_logical_id | common.UInt8 | 送信先の論理デバイスID |
relay_count | common.UInt8 | 中継回数 |
periodic | bool | 定期送信か否か |
di_changed | common.CrossSectional[bool](4) | デジタルインタフェースの変化の有無 |
di_state | common.CrossSectional[bool](4) | デジタルインタフェースの状態 |
ai_voltage | common.CrossSectional[common.UInt16](4) | アナログインタフェースの電圧 |
**
で unpack した辞書を渡すことができます。
コンストラクタの引数へ指定する変数に加えて、次の @computed_field
を持ちます。
名称 | 型 | 内容 |
---|---|---|
mwings_implementation | str | MWings の実装("python" のみ) |
mwings_version | str | MWings のバージョン(PEP440形式) |
hostname | str | ホストマシン名 |
system_type | str | システム種別("Linux" など) |
適用される field_validator
source_logical_id
:値の範囲を自動的に検証しますcheck_source_logical_id(lid)
time_parsed
:タイムゾーンが付与されているかを自動的に検証しますdatetime_must_be_clear(dt)
ai_voltage
:値の範囲を自動的に検証しますcheck_ai_voltage(aiv)
destination_logical_id
:値の範囲を自動的に検証しますcheck_destination_logical_id(lid)
適用される field_serializer
packet_type
:列挙子の名前をそのままJSON等に適用しますserialize_packet_type(packet_type)
source_serial_id
:16進表記の文字列をJSON等に適用しますserialize_source_serial_id(source_serial_id)
time_parsed
:ISO 8601形式の文字列をJSON等に適用しますserialize_time_parsed(dt)
to_df()
to_df(include=None, exclude=None, verbose=True)
パースしたデータを pandas のデータフレーム形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | データフレームへ含めるカラム(メンバ)の集合 |
exclude | optional set[str] | データフレームへ含めないカラム(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
戻り値
型 | 値 | 内容 |
---|---|---|
pd.DataFrame | - | 変換したデータフレーム |
例外
EnvironmentError
pandas のない場合
to_dict()
to_dict(include=None, exclude=None, verbose=True, spread=False, sort_keys=False)
パースしたデータを辞書形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | 辞書へ含めるキー(メンバ)の集合 |
exclude | optional set[str] | 辞書へ含めないキー(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
spread | bool | 時系列でないlist-likeデータの分割の有無 |
sort_keys | bool | キーによるソートの有無 |
spread
を設定すると、common.CrossSectional[T]
型のデータを分割します。戻り値
型 | 値 | 内容 |
---|---|---|
dict[str, Any] | - | 変換した辞書 |
to_json()
to_json(include=None, exclude=None, verbose=True, spread=False, indent=2, sort_keys=False)
パースしたデータをJSON形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | JSONへ含めるキー(メンバ)の集合 |
exclude | optional set[str] | JSONへ含めないキー(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
spread | bool | 時系列でないlist-likeデータの分割の有無 |
indent | optional int | インデントの数(None で改行なし) |
sort_keys | bool | キーによるソートの有無 |
spread
を設定すると、common.CrossSectional[T]
型のデータを分割します。戻り値
型 | 値 | 内容 |
---|---|---|
str | - | 変換したJSON文字列 |
model_*()
pydantic.BaseModel
の各メソッドを利用できます。3.2.1.1.2.2 - mwings.parsers.app_io モジュール
mwings.parsers.app_io
リモコンアプリから送信されたデータを表すパケットを解釈するパーサと、そのデータを扱います。
PacketParser
リモコンアプリから送信されたデータを表すパケットを解釈するパーサの静的クラス
is_valid()
is_valid(bare_packet)
与えられた素のパケットが有効であるか否かを確認します。
引数
名称 | 型 | 内容 |
---|---|---|
bare_packet | common.BarePacket | 素のパケットデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
bool | True | 有効、パース可 |
False | 無効、パース不可 |
parse()
parse(bare_packet)
与えられた素のパケットをパースします。
引数
名称 | 型 | 内容 |
---|---|---|
bare_packet | common.BarePacket | 素のパケットデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
optional ParsedPacket | ParsedPacket の型をもつデータ | パースしたデータ |
None | パース不可 |
ParsedPacket
リモコンアプリから送信されたデータを表すパケットを解釈した結果を格納するための構造体
ParsedPacket()
ParsedPacket(*, time_parsed=None, packet_type=PacketType.BARE, sequence_number=None, source_serial_id=0, source_logical_id=0, lqi=None, supply_voltage=None, relay_count=0, di_state=<mwings.common.CrossSectional object>, di_valid=<mwings.common.CrossSectional object>, di_interrupt=<mwings.common.CrossSectional object>)
引数
継承元のプロパティも合わせて表記します。
名称 | 型 | 内容 |
---|---|---|
time_parsed | optional AwareDatetime | パース時刻 |
packet_type | common.PacketType | パケット種別 |
sequence_number | optional common.UInt16 | シーケンス番号 |
source_serial_id | common.UInt32 | 送信元のシリアルID |
source_logical_id | common.UInt8 | 送信元の論理デバイスID |
lqi | optional common.UInt8 | 電波通信品質 |
supply_voltage | optional common.UInt16 | ADCを使わないため常にNone |
relay_count | common.UInt8 | 中継回数 |
di_changed | common.CrossSectional[bool](12) | デジタルインタフェースの変化の有無 |
di_state | common.CrossSectional[bool](12) | デジタルインタフェースの状態 |
di_interrupt | common.CrossSectional[bool](12) | デジタルインタフェースの割り込みの有無 |
**
で unpack した辞書を渡すことができます。
コンストラクタの引数へ指定する変数に加えて、次の @computed_field
を持ちます。
名称 | 型 | 内容 |
---|---|---|
mwings_implementation | str | MWings の実装("python" のみ) |
mwings_version | str | MWings のバージョン(PEP440形式) |
hostname | str | ホストマシン名 |
system_type | str | システム種別("Linux" など) |
適用される field_validator
source_logical_id
:値の範囲を自動的に検証しますcheck_source_logical_id(lid)
time_parsed
:タイムゾーンが付与されているかを自動的に検証しますdatetime_must_be_clear(dt)
適用される field_serializer
packet_type
:列挙子の名前をそのままJSON等に適用しますserialize_packet_type(packet_type)
source_serial_id
:16進表記の文字列をJSON等に適用しますserialize_source_serial_id(source_serial_id)
time_parsed
:ISO 8601形式の文字列をJSON等に適用しますserialize_time_parsed(dt)
to_df()
to_df(include=None, exclude=None, verbose=True)
パースしたデータを pandas のデータフレーム形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | データフレームへ含めるカラム(メンバ)の集合 |
exclude | optional set[str] | データフレームへ含めないカラム(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
戻り値
型 | 値 | 内容 |
---|---|---|
pd.DataFrame | - | 変換したデータフレーム |
例外
EnvironmentError
pandas のない場合
to_dict()
to_dict(include=None, exclude=None, verbose=True, spread=False, sort_keys=False)
パースしたデータを辞書形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | 辞書へ含めるキー(メンバ)の集合 |
exclude | optional set[str] | 辞書へ含めないキー(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
spread | bool | 時系列でないlist-likeデータの分割の有無 |
sort_keys | bool | キーによるソートの有無 |
spread
を設定すると、common.CrossSectional[T]
型のデータを分割します。戻り値
型 | 値 | 内容 |
---|---|---|
dict[str, Any] | - | 変換した辞書 |
to_json()
to_json(include=None, exclude=None, verbose=True, spread=False, indent=2, sort_keys=False)
パースしたデータをJSON形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | JSONへ含めるキー(メンバ)の集合 |
exclude | optional set[str] | JSONへ含めないキー(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
spread | bool | 時系列でないlist-likeデータの分割の有無 |
indent | optional int | インデントの数(None で改行なし) |
sort_keys | bool | キーによるソートの有無 |
spread
を設定すると、common.CrossSectional[T]
型のデータを分割します。戻り値
型 | 値 | 内容 |
---|---|---|
str | - | 変換したJSON文字列 |
model_*()
pydantic.BaseModel
の各メソッドを利用できます。3.2.1.1.2.3 - mwings.parsers.app_aria モジュール
mwings.parsers.app_aria
アリアアプリから送信されたデータを表すパケットを解釈するパーサと、そのデータを扱います。
PacketParser
アリアアプリから送信されたデータを表すパケットを解釈するパーサの静的クラス
is_valid()
is_valid(bare_packet)
与えられた素のパケットが有効であるか否かを確認します。
引数
名称 | 型 | 内容 |
---|---|---|
bare_packet | common.BarePacket | 素のパケットデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
bool | True | 有効、パース可 |
False | 無効、パース不可 |
parse()
parse(bare_packet)
与えられた素のパケットをパースします。
引数
名称 | 型 | 内容 |
---|---|---|
bare_packet | common.BarePacket | 素のパケットデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
optional ParsedPacket | ParsedPacket の型をもつデータ | パースしたデータ |
None | パース不可 |
ParsedPacket
アリアアプリから送信されたデータを表すパケットを解釈した結果を格納するための構造体
ParsedPacket()
ParsedPacket(*, time_parsed=None, packet_type=PacketType.BARE, sequence_number=None, source_serial_id=0, source_logical_id=0, lqi=None, supply_voltage=None, temp_100x=0, humid_100x=0, magnet_state=MagnetState.NOT_DETECTED, magnet_state_changed=False)
引数
継承元のプロパティも合わせて表記します。
名称 | 型 | 内容 |
---|---|---|
time_parsed | optional AwareDatetime | パース時刻 |
packet_type | common.PacketType | パケット種別 |
sequence_number | optional common.UInt16 | シーケンス番号 |
source_serial_id | common.UInt32 | 送信元のシリアルID |
source_logical_id | common.UInt8 | 送信元の論理デバイスID |
lqi | optional common.UInt8 | 電波通信品質 |
supply_voltage | optional common.UInt16 | 電源電圧(mV) |
router_serial_id | common.UInt32 | 最初の中継機のシリアルID(中継なしは0x80000000 )v1.0.13+ |
temp_100x | common.Int16 | 100倍された温度(セ氏) |
humid_100x | common.UInt16 | 100倍された相対湿度 |
magnet_state | common.MagnetState | 磁石の状態 |
magnet_state_changed | bool | 磁石の状態の変化の有無 |
**
で unpack した辞書を渡すことができます。
コンストラクタの引数へ指定する変数に加えて、次の @computed_field
を持ちます。
名称 | 型 | 内容 |
---|---|---|
mwings_implementation | str | MWings の実装("python" のみ) |
mwings_version | str | MWings のバージョン(PEP440形式) |
hostname | str | ホストマシン名 |
system_type | str | システム種別("Linux" など) |
適用される field_validator
source_logical_id
:値の範囲を自動的に検証しますcheck_source_logical_id(lid)
time_parsed
:タイムゾーンが付与されているかを自動的に検証しますdatetime_must_be_clear(dt)
適用される field_serializer
packet_type
:列挙子の名前をそのままJSON等に適用しますserialize_packet_type(packet_type)
source_serial_id
:16進表記の文字列をJSON等に適用しますserialize_source_serial_id(source_serial_id)
time_parsed
:ISO 8601形式の文字列をJSON等に適用しますserialize_time_parsed(dt)
magnet_state
:列挙子の名前をそのままJSON等に適用しますserialize_magnet_state(magnet_state)
to_df()
to_df(include=None, exclude=None, verbose=True)
パースしたデータを pandas のデータフレーム形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | データフレームへ含めるカラム(メンバ)の集合 |
exclude | optional set[str] | データフレームへ含めないカラム(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
戻り値
型 | 値 | 内容 |
---|---|---|
pd.DataFrame | - | 変換したデータフレーム |
例外
EnvironmentError
pandas のない場合
to_dict()
to_dict(include=None, exclude=None, verbose=True, spread=False, sort_keys=False)
パースしたデータを辞書形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | 辞書へ含めるキー(メンバ)の集合 |
exclude | optional set[str] | 辞書へ含めないキー(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
spread | bool | 時系列でないlist-likeデータの分割の有無 |
sort_keys | bool | キーによるソートの有無 |
戻り値
型 | 値 | 内容 |
---|---|---|
dict[str, Any] | - | 変換した辞書 |
to_json()
to_json(include=None, exclude=None, verbose=True, spread=False, indent=2, sort_keys=False)
パースしたデータをJSON形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | JSONへ含めるキー(メンバ)の集合 |
exclude | optional set[str] | JSONへ含めないキー(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
spread | bool | 時系列でないlist-likeデータの分割の有無 |
indent | optional int | インデントの数(None で改行なし) |
sort_keys | bool | キーによるソートの有無 |
戻り値
型 | 値 | 内容 |
---|---|---|
str | - | 変換したJSON文字列 |
model_*()
pydantic.BaseModel
の各メソッドを利用できます。3.2.1.1.2.4 - mwings.parsers.app_cue モジュール
mwings.parsers.app_cue
キューアプリ(TWELITE CUEモード)から送信されたデータを表すパケットを解釈するパーサと、そのデータを扱います。
PacketParser
キューアプリ(TWELITE CUEモード)から送信されたデータを表すパケットを解釈するパーサの静的クラス
is_valid()
is_valid(bare_packet)
与えられた素のパケットが有効であるか否かを確認します。
引数
名称 | 型 | 内容 |
---|---|---|
bare_packet | common.BarePacket | 素のパケットデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
bool | True | 有効、パース可 |
False | 無効、パース不可 |
parse()
parse(bare_packet)
与えられた素のパケットをパースします。
引数
名称 | 型 | 内容 |
---|---|---|
bare_packet | common.BarePacket | 素のパケットデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
optional ParsedPacket | ParsedPacket の型をもつデータ | パースしたデータ |
None | パース不可 |
ParsedPacket
キューアプリ(TWELITE CUEモード)から送信されたデータを表すパケットを解釈した結果を格納するための構造体
ParsedPacket()
ParsedPacket(*, time_parsed=None, packet_type=PacketType.BARE, sequence_number=None, source_serial_id=0, source_logical_id=0, lqi=None, supply_voltage=None, sample_count=10, samples_x=<mwings.common.TimeSeries object>, samples_y=<mwings.common.TimeSeries object>, samples_z=<mwings.common.TimeSeries object>, has_accel_event=False, accel_event=AccelEvent.NONE, magnet_state=MagnetState.NOT_DETECTED, magnet_state_changed=False)
引数
継承元のプロパティも合わせて表記します。
名称 | 型 | 内容 |
---|---|---|
time_parsed | optional AwareDatetime | パース時刻 |
packet_type | common.PacketType | パケット種別 |
sequence_number | optional common.UInt16 | シーケンス番号 |
source_serial_id | common.UInt32 | 送信元のシリアルID |
source_logical_id | common.UInt8 | 送信元の論理デバイスID |
lqi | optional common.UInt8 | 電波通信品質 |
supply_voltage | optional common.UInt16 | 電源電圧(mV) |
router_serial_id | common.UInt32 | 最初の中継機のシリアルID(中継なしは0x80000000 )v1.0.13+ |
sample_count | common.UInt8 | 各軸の加速度サンプルの数 |
samples_x | common.TimeSeries[common.Int16] | X軸の加速度サンプル |
samples_y | common.TimeSeries[common.Int16] | Y軸の加速度サンプル |
samples_z | common.TimeSeries[common.Int16] | Z軸の加速度サンプル |
has_accel_event | bool | 加速度イベントの有無 |
accel_event | common.AccelEvent | 加速度イベント |
magnet_state | common.MagnetState | 磁石の状態 |
magnet_state_changed | bool | 磁石の状態の変化の有無 |
**
で unpack した辞書を渡すことができます。
コンストラクタの引数へ指定する変数に加えて、次の @computed_field
を持ちます。
名称 | 型 | 内容 |
---|---|---|
mwings_implementation | str | MWings の実装("python" のみ) |
mwings_version | str | MWings のバージョン(PEP440形式) |
hostname | str | ホストマシン名 |
system_type | str | システム種別("Linux" など) |
適用される field_validator
source_logical_id
:値の範囲を自動的に検証しますcheck_source_logical_id(lid)
time_parsed
:タイムゾーンが付与されているかを自動的に検証しますdatetime_must_be_clear(dt)
適用される field_serializer
packet_type
:列挙子の名前をそのままJSON等に適用しますserialize_packet_type(packet_type)
source_serial_id
:16進表記の文字列をJSON等に適用しますserialize_source_serial_id(source_serial_id)
time_parsed
:ISO 8601形式の文字列をJSON等に適用しますserialize_time_parsed(dt)
accel_event
:列挙子の名前をそのままJSON等に適用しますserialize_accel_event(accel_event)
magnet_state
:列挙子の名前をそのままJSON等に適用しますserialize_magnet_state(magnet_state)
to_df()
to_df(include=None, exclude=None, verbose=True)
パースしたデータを pandas のデータフレーム形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | データフレームへ含めるカラム(メンバ)の集合 |
exclude | optional set[str] | データフレームへ含めないカラム(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
戻り値
型 | 値 | 内容 |
---|---|---|
pd.DataFrame | - | 変換したデータフレーム |
例外
EnvironmentError
pandas のない場合
to_dict()
to_dict(include=None, exclude=None, verbose=True, spread=False, sort_keys=False)
パースしたデータを辞書形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | 辞書へ含めるキー(メンバ)の集合 |
exclude | optional set[str] | 辞書へ含めないキー(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
spread | bool | 時系列でないlist-likeデータの分割の有無 |
sort_keys | bool | キーによるソートの有無 |
spread
を設定しても、common.TimeSeries[T]
型の時系列データは分割しません。戻り値
型 | 値 | 内容 |
---|---|---|
dict[str, Any] | - | 変換した辞書 |
to_json()
to_json(include=None, exclude=None, verbose=True, spread=False, indent=2, sort_keys=False)
パースしたデータをJSON形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | JSONへ含めるキー(メンバ)の集合 |
exclude | optional set[str] | JSONへ含めないキー(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
spread | bool | 時系列でないlist-likeデータの分割の有無 |
indent | optional int | インデントの数(None で改行なし) |
sort_keys | bool | キーによるソートの有無 |
spread
を設定しても、common.TimeSeries[T]
型の時系列データは分割しません。戻り値
型 | 値 | 内容 |
---|---|---|
str | - | 変換したJSON文字列 |
model_*()
pydantic.BaseModel
の各メソッドを利用できます。3.2.1.1.2.5 - mwings.parsers.app_cue_pal_event モジュール
mwings.parsers.app_cue_pal_event
キューアプリ(動作パルモード:ダイス/ムーブモード)から送信されたデータを表すパケットを解釈するパーサと、そのデータを扱います。
PacketParser
キューアプリ(動作パルモード:ダイス/ムーブモード)から送信されたデータを表すパケットを解釈するパーサの静的クラス
is_valid()
is_valid(bare_packet)
与えられた素のパケットが有効であるか否かを確認します。
引数
名称 | 型 | 内容 |
---|---|---|
bare_packet | common.BarePacket | 素のパケットデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
bool | True | 有効、パース可 |
False | 無効、パース不可 |
parse()
parse(bare_packet)
与えられた素のパケットをパースします。
引数
名称 | 型 | 内容 |
---|---|---|
bare_packet | common.BarePacket | 素のパケットデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
optional ParsedPacket | ParsedPacket の型をもつデータ | パースしたデータ |
None | パース不可 |
ParsedPacket
キューアプリ(動作パルモード:ダイス/ムーブモード)から送信されたデータを表すパケットを解釈した結果を格納するための構造体
ParsedPacket()
ParsedPacket(*, time_parsed=None, packet_type=PacketType.BARE, sequence_number=None, source_serial_id=0, source_logical_id=0, lqi=None, supply_voltage=None, ai1_voltage=0, accel_event=AccelEvent.NONE)
引数
継承元のプロパティも合わせて表記します。
名称 | 型 | 内容 |
---|---|---|
time_parsed | optional AwareDatetime | パース時刻 |
packet_type | common.PacketType | パケット種別 |
sequence_number | optional common.UInt16 | シーケンス番号 |
source_serial_id | common.UInt32 | 送信元のシリアルID |
source_logical_id | common.UInt8 | 送信元の論理デバイスID |
lqi | optional common.UInt8 | 電波通信品質 |
supply_voltage | optional common.UInt16 | 電源電圧(mV) |
router_serial_id | common.UInt32 | 最初の中継機のシリアルID(中継なしは0x80000000 )v1.0.13+ |
ai1_voltage | common.UInt16 | AI1 の電圧(mV) |
accel_event | common.AccelEvent | 加速度イベント |
**
で unpack した辞書を渡すことができます。
コンストラクタの引数へ指定する変数に加えて、次の @computed_field
を持ちます。
名称 | 型 | 内容 |
---|---|---|
mwings_implementation | str | MWings の実装("python" のみ) |
mwings_version | str | MWings のバージョン(PEP440形式) |
hostname | str | ホストマシン名 |
system_type | str | システム種別("Linux" など) |
適用される field_validator
source_logical_id
:値の範囲を自動的に検証しますcheck_source_logical_id(lid)
time_parsed
:タイムゾーンが付与されているかを自動的に検証しますdatetime_must_be_clear(dt)
適用される field_serializer
packet_type
:列挙子の名前をそのままJSON等に適用しますserialize_packet_type(packet_type)
source_serial_id
:16進表記の文字列をJSON等に適用しますserialize_source_serial_id(source_serial_id)
time_parsed
:ISO 8601形式の文字列をJSON等に適用しますserialize_time_parsed(dt)
accel_event
:列挙子の名前をそのままJSON等に適用しますserialize_accel_event(accel_event)
to_df()
to_df(include=None, exclude=None, verbose=True)
パースしたデータを pandas のデータフレーム形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | データフレームへ含めるカラム(メンバ)の集合 |
exclude | optional set[str] | データフレームへ含めないカラム(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
戻り値
型 | 値 | 内容 |
---|---|---|
pd.DataFrame | - | 変換したデータフレーム |
例外
EnvironmentError
pandas のない場合
to_dict()
to_dict(include=None, exclude=None, verbose=True, spread=False, sort_keys=False)
パースしたデータを辞書形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | 辞書へ含めるキー(メンバ)の集合 |
exclude | optional set[str] | 辞書へ含めないキー(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
spread | bool | 時系列でないlist-likeデータの分割の有無 |
sort_keys | bool | キーによるソートの有無 |
戻り値
型 | 値 | 内容 |
---|---|---|
dict[str, Any] | - | 変換した辞書 |
to_json()
to_json(include=None, exclude=None, verbose=True, spread=False, indent=2, sort_keys=False)
パースしたデータをJSON形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | JSONへ含めるキー(メンバ)の集合 |
exclude | optional set[str] | JSONへ含めないキー(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
spread | bool | 時系列でないlist-likeデータの分割の有無 |
indent | optional int | インデントの数(None で改行なし) |
sort_keys | bool | キーによるソートの有無 |
戻り値
型 | 値 | 内容 |
---|---|---|
str | - | 変換したJSON文字列 |
model_*()
pydantic.BaseModel
の各メソッドを利用できます。3.2.1.1.2.6 - mwings.parsers.app_pal_openclose モジュール
mwings.parsers.app_pal_openclose
パルアプリ(開閉パル)から送信されたデータを表すパケットを解釈するパーサと、そのデータを扱います。
PacketParser
パルアプリ(開閉パル)から送信されたデータを表すパケットを解釈するパーサの静的クラス
is_valid()
is_valid(bare_packet)
与えられた素のパケットが有効であるか否かを確認します。
引数
名称 | 型 | 内容 |
---|---|---|
bare_packet | common.BarePacket | 素のパケットデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
bool | True | 有効、パース可 |
False | 無効、パース不可 |
parse()
parse(bare_packet)
与えられた素のパケットをパースします。
引数
名称 | 型 | 内容 |
---|---|---|
bare_packet | common.BarePacket | 素のパケットデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
optional ParsedPacket | ParsedPacket の型をもつデータ | パースしたデータ |
None | パース不可 |
ParsedPacket
パルアプリ(開閉パル)から送信されたデータを表すパケットを解釈した結果を格納するための構造体
ParsedPacket()
ParsedPacket(*, time_parsed=None, packet_type=PacketType.BARE, sequence_number=None, source_serial_id=0, source_logical_id=0, lqi=None, supply_voltage=None, ai1_voltage=0, magnet_state=MagnetState.NOT_DETECTED, magnet_state_changed=False)
引数
継承元のプロパティも合わせて表記します。
名称 | 型 | 内容 |
---|---|---|
time_parsed | optional AwareDatetime | パース時刻 |
packet_type | common.PacketType | パケット種別 |
sequence_number | optional common.UInt16 | シーケンス番号 |
source_serial_id | common.UInt32 | 送信元のシリアルID |
source_logical_id | common.UInt8 | 送信元の論理デバイスID |
lqi | optional common.UInt8 | 電波通信品質 |
supply_voltage | optional common.UInt16 | 電源電圧(mV) |
router_serial_id | common.UInt32 | 最初の中継機のシリアルID(中継なしは0x80000000 )v1.0.13+ |
ai1_voltage | common.UInt16 | AI1 の電圧(mV) |
magnet_state | common.MagnetState | 磁石の状態 |
magnet_state_changed | bool | 磁石の状態の変化の有無 |
**
で unpack した辞書を渡すことができます。
コンストラクタの引数へ指定する変数に加えて、次の @computed_field
を持ちます。
名称 | 型 | 内容 |
---|---|---|
mwings_implementation | str | MWings の実装("python" のみ) |
mwings_version | str | MWings のバージョン(PEP440形式) |
hostname | str | ホストマシン名 |
system_type | str | システム種別("Linux" など) |
適用される field_validator
source_logical_id
:値の範囲を自動的に検証しますcheck_source_logical_id(lid)
time_parsed
:タイムゾーンが付与されているかを自動的に検証しますdatetime_must_be_clear(dt)
適用される field_serializer
packet_type
:列挙子の名前をそのままJSON等に適用しますserialize_packet_type(packet_type)
source_serial_id
:16進表記の文字列をJSON等に適用しますserialize_source_serial_id(source_serial_id)
time_parsed
:ISO 8601形式の文字列をJSON等に適用しますserialize_time_parsed(dt)
magnet_state
:列挙子の名前をそのままJSON等に適用しますserialize_magnet_state(magnet_state)
to_df()
to_df(include=None, exclude=None, verbose=True)
パースしたデータを pandas のデータフレーム形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | データフレームへ含めるカラム(メンバ)の集合 |
exclude | optional set[str] | データフレームへ含めないカラム(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
戻り値
型 | 値 | 内容 |
---|---|---|
pd.DataFrame | - | 変換したデータフレーム |
例外
EnvironmentError
pandas のない場合
to_dict()
to_dict(include=None, exclude=None, verbose=True, spread=False, sort_keys=False)
パースしたデータを辞書形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | 辞書へ含めるキー(メンバ)の集合 |
exclude | optional set[str] | 辞書へ含めないキー(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
spread | bool | 時系列でないlist-likeデータの分割の有無 |
sort_keys | bool | キーによるソートの有無 |
戻り値
型 | 値 | 内容 |
---|---|---|
dict[str, Any] | - | 変換した辞書 |
to_json()
to_json(include=None, exclude=None, verbose=True, spread=False, indent=2, sort_keys=False)
パースしたデータをJSON形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | JSONへ含めるキー(メンバ)の集合 |
exclude | optional set[str] | JSONへ含めないキー(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
spread | bool | 時系列でないlist-likeデータの分割の有無 |
indent | optional int | インデントの数(None で改行なし) |
sort_keys | bool | キーによるソートの有無 |
戻り値
型 | 値 | 内容 |
---|---|---|
str | - | 変換したJSON文字列 |
model_*()
pydantic.BaseModel
の各メソッドを利用できます。3.2.1.1.2.7 - mwings.parsers.app_pal_amb モジュール
mwings.parsers.app_pal_amb
パルアプリ(環境パル)から送信されたデータを表すパケットを解釈するパーサと、そのデータを扱います。
PacketParser
パルアプリ(環境パル)から送信されたデータを表すパケットを解釈するパーサの静的クラス
is_valid()
is_valid(bare_packet)
与えられた素のパケットが有効であるか否かを確認します。
引数
名称 | 型 | 内容 |
---|---|---|
bare_packet | common.BarePacket | 素のパケットデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
bool | True | 有効、パース可 |
False | 無効、パース不可 |
parse()
parse(bare_packet)
与えられた素のパケットをパースします。
引数
名称 | 型 | 内容 |
---|---|---|
bare_packet | common.BarePacket | 素のパケットデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
optional ParsedPacket | ParsedPacket の型をもつデータ | パースしたデータ |
None | パース不可 |
ParsedPacket
パルアプリ(環境パル)から送信されたデータを表すパケットを解釈した結果を格納するための構造体
ParsedPacket()
ParsedPacket(*, time_parsed=None, packet_type=PacketType.BARE, sequence_number=None, source_serial_id=0, source_logical_id=0, lqi=None, supply_voltage=None, ai1_voltage=0, temp_100x=0, humid_100x=0, illuminance=0)
引数
継承元のプロパティも合わせて表記します。
名称 | 型 | 内容 |
---|---|---|
time_parsed | optional AwareDatetime | パース時刻 |
packet_type | common.PacketType | パケット種別 |
sequence_number | optional common.UInt16 | シーケンス番号 |
source_serial_id | common.UInt32 | 送信元のシリアルID |
source_logical_id | common.UInt8 | 送信元の論理デバイスID |
lqi | optional common.UInt8 | 電波通信品質 |
supply_voltage | optional common.UInt16 | 電源電圧(mV) |
router_serial_id | common.UInt32 | 最初の中継機のシリアルID(中継なしは0x80000000 )v1.0.13+ |
ai1_voltage | common.UInt16 | AI1 の電圧(mV) |
temp_100x | common.Int16 | 100倍された温度(セ氏) |
humid_100x | common.UInt16 | 100倍された相対湿度 |
illuminance | common.UInt32 | 照度(lx) |
**
で unpack した辞書を渡すことができます。
コンストラクタの引数へ指定する変数に加えて、次の @computed_field
を持ちます。
名称 | 型 | 内容 |
---|---|---|
mwings_implementation | str | MWings の実装("python" のみ) |
mwings_version | str | MWings のバージョン(PEP440形式) |
hostname | str | ホストマシン名 |
system_type | str | システム種別("Linux" など) |
適用される field_validator
source_logical_id
:値の範囲を自動的に検証しますcheck_source_logical_id(lid)
time_parsed
:タイムゾーンが付与されているかを自動的に検証しますdatetime_must_be_clear(dt)
適用される field_serializer
packet_type
:列挙子の名前をそのままJSON等に適用しますserialize_packet_type(packet_type)
source_serial_id
:16進表記の文字列をJSON等に適用しますserialize_source_serial_id(source_serial_id)
time_parsed
:ISO 8601形式の文字列をJSON等に適用しますserialize_time_parsed(dt)
to_df()
to_df(include=None, exclude=None, verbose=True)
パースしたデータを pandas のデータフレーム形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | データフレームへ含めるカラム(メンバ)の集合 |
exclude | optional set[str] | データフレームへ含めないカラム(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
戻り値
型 | 値 | 内容 |
---|---|---|
pd.DataFrame | - | 変換したデータフレーム |
例外
EnvironmentError
pandas のない場合
to_dict()
to_dict(include=None, exclude=None, verbose=True, spread=False, sort_keys=False)
パースしたデータを辞書形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | 辞書へ含めるキー(メンバ)の集合 |
exclude | optional set[str] | 辞書へ含めないキー(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
spread | bool | 時系列でないlist-likeデータの分割の有無 |
sort_keys | bool | キーによるソートの有無 |
戻り値
型 | 値 | 内容 |
---|---|---|
dict[str, Any] | - | 変換した辞書 |
to_json()
to_json(include=None, exclude=None, verbose=True, spread=False, indent=2, sort_keys=False)
パースしたデータをJSON形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | JSONへ含めるキー(メンバ)の集合 |
exclude | optional set[str] | JSONへ含めないキー(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
spread | bool | 時系列でないlist-likeデータの分割の有無 |
indent | optional int | インデントの数(None で改行なし) |
sort_keys | bool | キーによるソートの有無 |
戻り値
型 | 値 | 内容 |
---|---|---|
str | - | 変換したJSON文字列 |
model_*()
pydantic.BaseModel
の各メソッドを利用できます。3.2.1.1.2.8 - mwings.parsers.app_pal_mot モジュール
mwings.parsers.app_pal_mot
パルアプリ(動作パル)やキューアプリ(動作パルモード:加速度計測)から送信されたデータを表すパケットを解釈するパーサと、そのデータを扱います。
PacketParser
パルアプリ(動作パル)やキューアプリ(動作パルモード:加速度計測)から送信されたデータを表すパケットを解釈するパーサの静的クラス
is_valid()
is_valid(bare_packet)
与えられた素のパケットが有効であるか否かを確認します。
引数
名称 | 型 | 内容 |
---|---|---|
bare_packet | common.BarePacket | 素のパケットデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
bool | True | 有効、パース可 |
False | 無効、パース不可 |
parse()
parse(bare_packet)
与えられた素のパケットをパースします。
引数
名称 | 型 | 内容 |
---|---|---|
bare_packet | common.BarePacket | 素のパケットデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
optional ParsedPacket | ParsedPacket の型をもつデータ | パースしたデータ |
None | パース不可 |
ParsedPacket
パルアプリ(動作パル)やキューアプリ(動作パルモード:加速度計測)から送信されたデータを表すパケットを解釈した結果を格納するための構造体
ParsedPacket()
ParsedPacket(*, time_parsed=None, packet_type=PacketType.BARE, sequence_number=None, source_serial_id=0, source_logical_id=0, lqi=None, supply_voltage=None, ai1_voltage=0, sample_count=16, samples_x=<mwings.common.TimeSeries object>, samples_y=<mwings.common.TimeSeries object>, samples_z=<mwings.common.TimeSeries object>, sampling_frequency=25)
引数
継承元のプロパティも合わせて表記します。
名称 | 型 | 内容 |
---|---|---|
time_parsed | optional AwareDatetime | パース時刻 |
packet_type | common.PacketType | パケット種別 |
sequence_number | optional common.UInt16 | シーケンス番号 |
source_serial_id | common.UInt32 | 送信元のシリアルID |
source_logical_id | common.UInt8 | 送信元の論理デバイスID |
lqi | optional common.UInt8 | 電波通信品質 |
supply_voltage | optional common.UInt16 | 電源電圧(mV) |
router_serial_id | common.UInt32 | 最初の中継機のシリアルID(中継なしは0x80000000 )v1.0.13+ |
ai1_voltage | common.UInt16 | AI1 の電圧(mV) |
sample_count | common.UInt8 | 各軸の加速度サンプルの数 |
samples_x | common.TimeSeries[common.Int16] | X軸の加速度サンプル |
samples_y | common.TimeSeries[common.Int16] | Y軸の加速度サンプル |
samples_z | common.TimeSeries[common.Int16] | Z軸の加速度サンプル |
sampling_frequency | common.UInt16 | 加速度サンプリング周波数 |
**
で unpack した辞書を渡すことができます。
コンストラクタの引数へ指定する変数に加えて、次の @computed_field
を持ちます。
名称 | 型 | 内容 |
---|---|---|
mwings_implementation | str | MWings の実装("python" のみ) |
mwings_version | str | MWings のバージョン(PEP440形式) |
hostname | str | ホストマシン名 |
system_type | str | システム種別("Linux" など) |
適用される field_validator
source_logical_id
:値の範囲を自動的に検証しますcheck_source_logical_id(lid)
time_parsed
:タイムゾーンが付与されているかを自動的に検証しますdatetime_must_be_clear(dt)
sampling_frequency
:値を検証しますcheck_sampling_frequency(freq)
適用される field_serializer
packet_type
:列挙子の名前をそのままJSON等に適用しますserialize_packet_type(packet_type)
source_serial_id
:16進表記の文字列をJSON等に適用しますserialize_source_serial_id(source_serial_id)
time_parsed
:ISO 8601形式の文字列をJSON等に適用しますserialize_time_parsed(dt)
to_df()
to_df(include=None, exclude=None, verbose=True)
パースしたデータを pandas のデータフレーム形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | データフレームへ含めるカラム(メンバ)の集合 |
exclude | optional set[str] | データフレームへ含めないカラム(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
戻り値
型 | 値 | 内容 |
---|---|---|
pd.DataFrame | - | 変換したデータフレーム |
例外
EnvironmentError
pandas のない場合
to_dict()
to_dict(include=None, exclude=None, verbose=True, spread=False, sort_keys=False)
パースしたデータを辞書形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | 辞書へ含めるキー(メンバ)の集合 |
exclude | optional set[str] | 辞書へ含めないキー(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
spread | bool | 時系列でないlist-likeデータの分割の有無 |
sort_keys | bool | キーによるソートの有無 |
spread
を設定しても、common.TimeSeries[T]
型の時系列データは分割しません。戻り値
型 | 値 | 内容 |
---|---|---|
dict[str, Any] | - | 変換した辞書 |
to_json()
to_json(include=None, exclude=None, verbose=True, spread=False, indent=2, sort_keys=False)
パースしたデータをJSON形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | JSONへ含めるキー(メンバ)の集合 |
exclude | optional set[str] | JSONへ含めないキー(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
spread | bool | 時系列でないlist-likeデータの分割の有無 |
indent | optional int | インデントの数(None で改行なし) |
sort_keys | bool | キーによるソートの有無 |
spread
を設定しても、common.TimeSeries[T]
型の時系列データは分割しません。戻り値
型 | 値 | 内容 |
---|---|---|
str | - | 変換したJSON文字列 |
model_*()
pydantic.BaseModel
の各メソッドを利用できます。3.2.1.1.2.9 - mwings.parsers.app_uart_ascii モジュール
mwings.parsers.app_uart_ascii
シリアル通信アプリ(書式モード:簡易形式)から送信されたデータを表すパケットを解釈するパーサと、そのデータを扱います。
PacketParser
シリアル通信アプリ(書式モード:簡易形式)から送信されたデータを表すパケットを解釈するパーサの静的クラス
is_valid()
is_valid(bare_packet)
与えられた素のパケットが有効であるか否かを確認します。
引数
名称 | 型 | 内容 |
---|---|---|
bare_packet | common.BarePacket | 素のパケットデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
bool | True | 有効、パース可 |
False | 無効、パース不可 |
parse()
parse(bare_packet)
与えられた素のパケットをパースします。
引数
名称 | 型 | 内容 |
---|---|---|
bare_packet | common.BarePacket | 素のパケットデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
optional ParsedPacket | ParsedPacket の型をもつデータ | パースしたデータ |
None | パース不可 |
ParsedPacket
シリアル通信アプリ(書式モード:簡易形式)から送信されたデータを表すパケットを解釈した結果を格納するための構造体
ParsedPacket()
ParsedPacket(*, time_parsed=None, packet_type=PacketType.BARE, sequence_number=None, source_serial_id=0, source_logical_id=0, lqi=None, supply_voltage=None, command_id=0, data=b'')
引数
継承元のプロパティも合わせて表記します。
名称 | 型 | 内容 |
---|---|---|
time_parsed | optional AwareDatetime | パース時刻 |
packet_type | common.PacketType | パケット種別 |
sequence_number | optional common.UInt16 | 取得不可、常にNone |
source_serial_id | common.UInt32 | 送信元のシリアルID |
source_logical_id | common.UInt8 | 送信元の論理デバイスID |
lqi | optional common.UInt8 | 取得不可、常にNone |
supply_voltage | optional common.UInt16 | 取得不可、常にNone |
commnad_id | common.UInt8 | コマンドID |
data | bytes | データ |
**
で unpack した辞書を渡すことができます。
コンストラクタの引数へ指定する変数に加えて、次の @computed_field
を持ちます。
名称 | 型 | 内容 |
---|---|---|
mwings_implementation | str | MWings の実装("python" のみ) |
mwings_version | str | MWings のバージョン(PEP440形式) |
hostname | str | ホストマシン名 |
system_type | str | システム種別("Linux" など) |
data_base64 | str | データのBase64表記 |
data_hexstr | str | データの16進数表記 |
data
はJSON等に含まれません。data_base64
やdata_hexstr
を利用してください。適用される field_validator
source_logical_id
:値の範囲を自動的に検証しますcheck_source_logical_id(lid)
time_parsed
:タイムゾーンが付与されているかを自動的に検証しますdatetime_must_be_clear(dt)
sampling_frequency
:値を検証しますcheck_sampling_frequency(freq)
data
:長さを自動的に検証しますcheck_data(data)
適用される field_serializer
packet_type
:列挙子の名前をそのままJSON等に適用しますserialize_packet_type(packet_type)
source_serial_id
:16進表記の文字列をJSON等に適用しますserialize_source_serial_id(source_serial_id)
time_parsed
:ISO 8601形式の文字列をJSON等に適用しますserialize_time_parsed(dt)
- ``
to_df()
to_df(include=None, exclude=None, verbose=True)
パースしたデータを pandas のデータフレーム形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | データフレームへ含めるカラム(メンバ)の集合 |
exclude | optional set[str] | データフレームへ含めないカラム(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
戻り値
型 | 値 | 内容 |
---|---|---|
pd.DataFrame | - | 変換したデータフレーム |
例外
EnvironmentError
pandas のない場合
to_dict()
to_dict(include=None, exclude=None, verbose=True, spread=False, sort_keys=False)
パースしたデータを辞書形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | 辞書へ含めるキー(メンバ)の集合 |
exclude | optional set[str] | 辞書へ含めないキー(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
spread | bool | 時系列でないlist-likeデータの分割の有無 |
sort_keys | bool | キーによるソートの有無 |
戻り値
型 | 値 | 内容 |
---|---|---|
dict[str, Any] | - | 変換した辞書 |
to_json()
to_json(include=None, exclude=None, verbose=True, spread=False, indent=2, sort_keys=False)
パースしたデータをJSON形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | JSONへ含めるキー(メンバ)の集合 |
exclude | optional set[str] | JSONへ含めないキー(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
spread | bool | 時系列でないlist-likeデータの分割の有無 |
indent | optional int | インデントの数(None で改行なし) |
sort_keys | bool | キーによるソートの有無 |
戻り値
型 | 値 | 内容 |
---|---|---|
str | - | 変換したJSON文字列 |
model_*()
pydantic.BaseModel
の各メソッドを利用できます。3.2.1.1.2.10 - mwings.parsers.app_uart_ascii_extended モジュール
mwings.parsers.app_uart_ascii_extended
シリアル通信アプリ(書式モード:拡張形式)から送信されたデータを表すパケットを解釈するパーサと、そのデータを扱います。
PacketParser
シリアル通信アプリ(書式モード:拡張形式)から送信されたデータを表すパケットを解釈するパーサの静的クラス
is_valid()
is_valid(bare_packet)
与えられた素のパケットが有効であるか否かを確認します。
引数
名称 | 型 | 内容 |
---|---|---|
bare_packet | common.BarePacket | 素のパケットデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
bool | True | 有効、パース可 |
False | 無効、パース不可 |
parse()
parse(bare_packet)
与えられた素のパケットをパースします。
引数
名称 | 型 | 内容 |
---|---|---|
bare_packet | common.BarePacket | 素のパケットデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
optional ParsedPacket | ParsedPacket の型をもつデータ | パースしたデータ |
None | パース不可 |
ParsedPacket
シリアル通信アプリ(書式モード:拡張形式)から送信されたデータを表すパケットを解釈した結果を格納するための構造体
ParsedPacket()
ParsedPacket(*, time_parsed=None, packet_type=PacketType.BARE, sequence_number=None, source_serial_id=0, source_logical_id=0, lqi=None, supply_voltage=None, destination_serial_id=120, command_id=0, data=b'')
引数
継承元のプロパティも合わせて表記します。
名称 | 型 | 内容 |
---|---|---|
time_parsed | optional AwareDatetime | パース時刻 |
packet_type | common.PacketType | パケット種別 |
sequence_number | optional common.UInt16 | 取得不可、常にNone |
source_serial_id | common.UInt32 | 送信元のシリアルID |
source_logical_id | common.UInt8 | 送信元の論理デバイスID |
lqi | common.UInt8 | 電波通信品質 |
supply_voltage | optional common.UInt16 | 取得不可、常にNone |
destination_serial_id | common.UInt32 | 送信先のシリアルID |
commnad_id | common.UInt8 | コマンドID |
data | bytes | データ |
**
で unpack した辞書を渡すことができます。
コンストラクタの引数へ指定する変数に加えて、次の @computed_field
を持ちます。
名称 | 型 | 内容 |
---|---|---|
mwings_implementation | str | MWings の実装("python" のみ) |
mwings_version | str | MWings のバージョン(PEP440形式) |
hostname | str | ホストマシン名 |
system_type | str | システム種別("Linux" など) |
data_base64 | str | データのBase64表記 |
data_hexstr | str | データの16進数表記 |
data
はJSON等に含まれません。data_base64
やdata_hexstr
を利用してください。適用される field_validator
source_logical_id
:値の範囲を自動的に検証しますcheck_source_logical_id(lid)
time_parsed
:タイムゾーンが付与されているかを自動的に検証しますdatetime_must_be_clear(dt)
sampling_frequency
:値を検証しますcheck_sampling_frequency(freq)
data
:長さを自動的に検証しますcheck_data(data)
適用される field_serializer
packet_type
:列挙子の名前をそのままJSON等に適用しますserialize_packet_type(packet_type)
source_serial_id
:16進表記の文字列をJSON等に適用しますserialize_source_serial_id(source_serial_id)
time_parsed
:ISO 8601形式の文字列をJSON等に適用しますserialize_time_parsed(dt)
- ``
to_df()
to_df(include=None, exclude=None, verbose=True)
パースしたデータを pandas のデータフレーム形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | データフレームへ含めるカラム(メンバ)の集合 |
exclude | optional set[str] | データフレームへ含めないカラム(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
戻り値
型 | 値 | 内容 |
---|---|---|
pd.DataFrame | - | 変換したデータフレーム |
例外
EnvironmentError
pandas のない場合
to_dict()
to_dict(include=None, exclude=None, verbose=True, spread=False, sort_keys=False)
パースしたデータを辞書形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | 辞書へ含めるキー(メンバ)の集合 |
exclude | optional set[str] | 辞書へ含めないキー(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
spread | bool | 時系列でないlist-likeデータの分割の有無 |
sort_keys | bool | キーによるソートの有無 |
戻り値
型 | 値 | 内容 |
---|---|---|
dict[str, Any] | - | 変換した辞書 |
to_json()
to_json(include=None, exclude=None, verbose=True, spread=False, indent=2, sort_keys=False)
パースしたデータをJSON形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | JSONへ含めるキー(メンバ)の集合 |
exclude | optional set[str] | JSONへ含めないキー(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
spread | bool | 時系列でないlist-likeデータの分割の有無 |
indent | optional int | インデントの数(None で改行なし) |
sort_keys | bool | キーによるソートの有無 |
戻り値
型 | 値 | 内容 |
---|---|---|
str | - | 変換したJSON文字列 |
model_*()
pydantic.BaseModel
の各メソッドを利用できます。3.2.1.1.2.11 - mwings.parsers.act モジュール
mwings.parsers.act
act から送信されたデータを表すパケットを解釈するパーサと、そのデータを扱います。
PacketParser
act から送信されたデータを表すパケットを解釈するパーサの静的クラス
is_valid()
is_valid(bare_packet)
与えられた素のパケットが有効であるか否かを確認します。
引数
名称 | 型 | 内容 |
---|---|---|
bare_packet | common.BarePacket | 素のパケットデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
bool | True | 有効、パース可 |
False | 無効、パース不可 |
parse()
parse(bare_packet)
与えられた素のパケットをパースします。
引数
名称 | 型 | 内容 |
---|---|---|
bare_packet | common.BarePacket | 素のパケットデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
optional ParsedPacket | ParsedPacket の型をもつデータ | パースしたデータ |
None | パース不可 |
ParsedPacket
act から送信されたデータを表すパケットを解釈した結果を格納するための構造体
ParsedPacket()
ParsedPacket(*, time_parsed=None, packet_type=PacketType.BARE, sequence_number=None, source_serial_id=0, source_logical_id=0, lqi=None, supply_voltage=None, command_id=0, data=b'')
引数
継承元のプロパティも合わせて表記します。
名称 | 型 | 内容 |
---|---|---|
time_parsed | optional AwareDatetime | パース時刻 |
packet_type | common.PacketType | パケット種別 |
sequence_number | optional common.UInt16 | 取得不可、常にNone |
source_serial_id | common.UInt32 | 送信元のシリアルID |
source_logical_id | common.UInt8 | 送信元の論理デバイスID |
lqi | optional common.UInt8 | 電波通信品質 |
supply_voltage | optional common.UInt16 | 取得不可、常にNone |
commnad_id | common.UInt8 | コマンドID |
data | bytes | データ |
**
で unpack した辞書を渡すことができます。
コンストラクタの引数へ指定する変数に加えて、次の @computed_field
を持ちます。
名称 | 型 | 内容 |
---|---|---|
mwings_implementation | str | MWings の実装("python" のみ) |
mwings_version | str | MWings のバージョン(PEP440形式) |
hostname | str | ホストマシン名 |
system_type | str | システム種別("Linux" など) |
data_base64 | str | データのBase64表記 |
data_hexstr | str | データの16進数表記 |
data
はJSON等に含まれません。data_base64
やdata_hexstr
を利用してください。適用される field_validator
source_logical_id
:値の範囲を自動的に検証しますcheck_source_logical_id(lid)
time_parsed
:タイムゾーンが付与されているかを自動的に検証しますdatetime_must_be_clear(dt)
sampling_frequency
:値を検証しますcheck_sampling_frequency(freq)
適用される field_serializer
packet_type
:列挙子の名前をそのままJSON等に適用しますserialize_packet_type(packet_type)
source_serial_id
:16進表記の文字列をJSON等に適用しますserialize_source_serial_id(source_serial_id)
time_parsed
:ISO 8601形式の文字列をJSON等に適用しますserialize_time_parsed(dt)
to_df()
to_df(include=None, exclude=None, verbose=True)
パースしたデータを pandas のデータフレーム形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | データフレームへ含めるカラム(メンバ)の集合 |
exclude | optional set[str] | データフレームへ含めないカラム(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
戻り値
型 | 値 | 内容 |
---|---|---|
pd.DataFrame | - | 変換したデータフレーム |
例外
EnvironmentError
pandas のない場合
to_dict()
to_dict(include=None, exclude=None, verbose=True, spread=False, sort_keys=False)
パースしたデータを辞書形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | 辞書へ含めるキー(メンバ)の集合 |
exclude | optional set[str] | 辞書へ含めないキー(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
spread | bool | 時系列でないlist-likeデータの分割の有無 |
sort_keys | bool | キーによるソートの有無 |
戻り値
型 | 値 | 内容 |
---|---|---|
dict[str, Any] | - | 変換した辞書 |
to_json()
to_json(include=None, exclude=None, verbose=True, spread=False, indent=2, sort_keys=False)
パースしたデータをJSON形式へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
include | optional set[str] | JSONへ含めるキー(メンバ)の集合 |
exclude | optional set[str] | JSONへ含めないキー(メンバ)の集合 |
verbose | bool | システム情報の有無(他の引数がNone の場合のみ) |
spread | bool | 時系列でないlist-likeデータの分割の有無 |
indent | optional int | インデントの数(None で改行なし) |
sort_keys | bool | キーによるソートの有無 |
戻り値
型 | 値 | 内容 |
---|---|---|
str | - | 変換したJSON文字列 |
model_*()
pydantic.BaseModel
の各メソッドを利用できます。3.2.1.1.3 - mwings.serializers モジュール
mwings.serializers
3.2.1.1.3.1 - mwings.serializers.app_twelite モジュール
mwings.serializers.app_twelite
超簡単!標準アプリへ送信するパケットを表すコマンドを生成するシリアライザと、そのデータを扱います。
CommandSerializer
超簡単!標準アプリへ送信するパケットを表すコマンドを生成するシリアライザの静的クラス
serialize()
serialize(command)
与えられたコマンドを素のパケットのバイト列へ展開します。
引数
名称 | 型 | 内容 |
---|---|---|
command | Command | コマンドデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
optional common.BarePacket | common.BarePacket | 展開したデータ |
None | 無効なコマンドデータである |
Command
超簡単!標準アプリへ送信するパケットを表すコマンドを生成する際に用意するデータを格納するための構造体
Command()
Command(*, destination_logical_id=120, di_to_change=<mwings.common.FixedList object>, di_state=<mwings.common.FixedList object>, pwm_to_change=<mwings.common.FixedList object>, pwm_duty=<mwings.common.FixedList object>)
引数
名称 | 型 | 内容 |
---|---|---|
destination_logical_id | common.UInt8 | 送信先の論理デバイスID |
di_to_change | common.FixedList[bool](4) | 変更するデジタルインタフェース |
di_state | common.FixedList[bool](4) | 変更後のデジタルインタフェースの状態 |
pwm_to_change | common.FixedList[bool](4) | 変更する PWM インタフェース |
pwm_duty | common.FixedList[int](4) | 変更後の PWM インタフェースのデューティ |
**
で unpack した辞書を渡すことができます。
pwm_to_change
の値は、0
-1024
の範囲を指定します。0xFFFF
指定時は無効となります。is_valid()
is_valid()
コマンドデータが有効であるか否かを確認します。
引数
なし
戻り値
型 | 値 | 内容 |
---|---|---|
bool | True | 有効 |
False | 無効 |
model_*()
pydantic.BaseModel
の各メソッドを利用できます。3.2.1.1.3.2 - mwings.serializers.app_io モジュール
mwings.serializers.app_io
リモコンアプリへ送信するパケットを表すコマンドを生成するシリアライザと、そのデータを扱います。
CommandSerializer
リモコンアプリへ送信するパケットを表すコマンドを生成するシリアライザの静的クラス
serialize()
serialize(command)
与えられたコマンドを素のパケットのバイト列へ展開します。
引数
名称 | 型 | 内容 |
---|---|---|
command | Command | コマンドデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
optional common.BarePacket | common.BarePacket | 展開したデータ |
None | 無効なコマンドデータである |
Command
リモコンアプリへ送信するパケットを表すコマンドを生成する際に用意するデータを格納するための構造体
Command()
Command(*, destination_logical_id=120, di_to_change=<mwings.common.FixedList object>, di_state=<mwings.common.FixedList object>)
引数
名称 | 型 | 内容 |
---|---|---|
destination_logical_id | common.UInt8 | 送信先の論理デバイスID |
di_to_change | common.FixedList[bool](12) | 変更するデジタルインタフェース |
di_state | common.FixedList[bool](12) | 変更後のデジタルインタフェースの状態 |
**
で unpack した辞書を渡すことができます。
is_valid()
is_valid()
コマンドデータが有効であるか否かを確認します。
引数
なし
戻り値
型 | 値 | 内容 |
---|---|---|
bool | True | 有効 |
False | 無効 |
model_*()
pydantic.BaseModel
の各メソッドを利用できます。3.2.1.1.3.3 - mwings.serializers.app_pal_notice モジュール
mwings.serializers.app_pal_notice
パルアプリ(通知パル)へ送信するパケットを表すコマンドを生成するシリアライザと、そのデータを扱います。
CommandSerializer
パルアプリ(通知パル)へ送信するパケットを表すコマンドを生成するシリアライザの静的クラス
serialize()
serialize(command)
与えられたコマンドを素のパケットのバイト列へ展開します。
引数
名称 | 型 | 内容 |
---|---|---|
command | Command | コマンドデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
optional common.BarePacket | common.BarePacket | 展開したデータ |
None | 無効なコマンドデータである |
Command
パルアプリ(通知パル)へ送信するパケットを表すコマンドを生成する際に用意するデータを格納するための構造体
Command()
Command(*, destination_logical_id=120, color=AppPalNoticeColor.WHITE, blink_speed=AppPalNoticeBlinkSpeed.ALWAYS_ON, brightness=8, duration_in_sec=5)
引数
名称 | 型 | 内容 |
---|---|---|
destination_logical_id | common.UInt8 | 送信先の論理デバイスID |
color | common.AppPalNoticeColor | 点灯色の名称 |
blink_speed | common.AppPalNoticeBlinkSpeed | 点滅の速度 |
brightness | common.UInt8 | 明るさ |
duration_in_sec | common.UInt8 | 点灯(点滅)の合計時間(秒) |
**
で unpack した辞書を渡すことができます。
is_valid()
is_valid()
コマンドデータが有効であるか否かを確認します。
引数
なし
戻り値
型 | 値 | 内容 |
---|---|---|
bool | True | 有効 |
False | 無効 |
model_*()
pydantic.BaseModel
の各メソッドを利用できます。3.2.1.1.3.4 - mwings.serializers.app_pal_notice_detailed モジュール
mwings.serializers.app_pal_notice_detailed
パルアプリ(通知パル)へ送信する詳細なパケットを表すコマンドを生成するシリアライザと、そのデータを扱います。
CommandSerializer
パルアプリ(通知パル)へ送信する詳細なパケットを表すコマンドを生成するシリアライザの静的クラス
serialize()
serialize(command)
与えられたコマンドを素のパケットのバイト列へ展開します。
引数
名称 | 型 | 内容 |
---|---|---|
command | Command | コマンドデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
optional common.BarePacket | common.BarePacket | 展開したデータ |
None | 無効なコマンドデータである |
Command
パルアプリ(通知パル)へ送信する詳細なパケットを表すコマンドを生成する際に用意するデータを格納するための構造体
Command()
Command(*, destination_logical_id=120, color=AppPalNoticeRGBWColor(red=0, green=0, blue=0, white=15), blink_duty_percentage=100, blink_period_in_sec=1.0, duration_in_sec=1)
引数
名称 | 型 | 内容 |
---|---|---|
destination_logical_id | common.UInt8 | 送信先の論理デバイスID |
color | common.AppPalNoticeRGBWColor | 点灯色のRGBW値 |
blink_duty_percentage | common.UInt8 | 点灯時間の割合(%) |
blink_period_in_sec | common.Float64 | 点滅の周期(秒) |
duration_in_sec | common.UInt8 | 点灯(点滅)の合計時間 |
**
で unpack した辞書を渡すことができます。
is_valid()
is_valid()
コマンドデータが有効であるか否かを確認します。
引数
なし
戻り値
型 | 値 | 内容 |
---|---|---|
bool | True | 有効 |
False | 無効 |
model_*()
pydantic.BaseModel
の各メソッドを利用できます。3.2.1.1.3.5 - mwings.serializers.app_pal_notice_event モジュール
mwings.serializers.app_pal_notice_event
パルアプリ(通知パル)へ送信するイベントデータのパケットを表すコマンドを生成するシリアライザと、そのデータを扱います。
CommandSerializer
パルアプリ(通知パル)へ送信するイベントデータのパケットを表すコマンドを生成するシリアライザの静的クラス
serialize()
serialize(command)
与えられたコマンドを素のパケットのバイト列へ展開します。
引数
名称 | 型 | 内容 |
---|---|---|
command | Command | コマンドデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
optional common.BarePacket | common.BarePacket | 展開したデータ |
None | 無効なコマンドデータである |
Command
パルアプリ(通知パル)へ送信するイベントデータのパケットを表すコマンドを生成する際に用意するデータを格納するための構造体
Command()
Command(*, destination_logical_id=120, event_id=0)
引数
名称 | 型 | 内容 |
---|---|---|
destination_logical_id | common.UInt8 | 送信先の論理デバイスID |
event_id | common.UInt8 | イベントID |
**
で unpack した辞書を渡すことができます。
is_valid()
is_valid()
コマンドデータが有効であるか否かを確認します。
引数
なし
戻り値
型 | 値 | 内容 |
---|---|---|
bool | True | 有効 |
False | 無効 |
model_*()
pydantic.BaseModel
の各メソッドを利用できます。3.2.1.1.3.6 - mwings.serializers.app_uart_ascii モジュール
mwings.serializers.app_uart_ascii
シリアル通信アプリへ送信するデータ(書式モード:簡易形式)のパケットを表すコマンドを生成するシリアライザと、そのデータを扱います。
CommandSerializer
シリアル通信アプリへ送信するデータ(書式モード:簡易形式)のパケットを表すコマンドを生成するシリアライザの静的クラス
serialize()
serialize(command)
与えられたコマンドを素のパケットのバイト列へ展開します。
引数
名称 | 型 | 内容 |
---|---|---|
command | Command | コマンドデータ |
戻り値
型 | 値 | 内容 |
---|---|---|
optional common.BarePacket | common.BarePacket | 展開したデータ |
None | 無効なコマンドデータである |
Command
シリアル通信アプリへ送信するデータ(書式モード:簡易形式)のパケットを表すコマンドを生成する際に用意するデータを格納するための構造体
Command()
Command(*, destination_logical_id=120, command_id=0, data)
引数
名称 | 型 | 内容 |
---|---|---|
destination_logical_id | common.UInt8 | 送信先の論理デバイスID |
command_id | common.UInt8 | コマンドID |
data | bytes | データ |
**
で unpack した辞書を渡すことができます。
is_valid()
is_valid()
コマンドデータが有効であるか否かを確認します。
引数
なし
戻り値
型 | 値 | 内容 |
---|---|---|
bool | True | 有効 |
False | 無効 |
model_*()
pydantic.BaseModel
の各メソッドを利用できます。3.2.1.1.4 - mwings.utils モジュール
mwings.utils
汎用的なユーティリティ関数を格納しています。
ask_user()
ask_user(prompt, regex, on_error, ex_verifier=None, max_attempts=None)
コンソールでユーザからの入力を得ます。
引数
名称 | 型 | 内容 |
---|---|---|
prompt | str | プロンプトへ表示するメッセージ |
regex | str | ユーザの入力を検証する正規表現 |
on_error | str | ユーザの入力が不正であった場合のメッセージ |
ex_verifier | optional Callable[[str], bool] | 正規表現に加えて入力文字列を検証する関数 |
max_attempts | optional int | リトライ回数。None なら無限 |
戻り値
型 | 値 | 内容 |
---|---|---|
str | - | 検証済みのユーザによる入力文字列 |
ask_user_for_port()
ask_user_for_port()
ユーザへ使用するポートを選択させます。
引数
なし
戻り値
型 | 値 | 内容 |
---|---|---|
str | - | 指定されたポート名 |
byte_count_from()
byte_count_from(character_count)
アスキー文字列で表現されたバイト列の長さをバイナリ表現の長さへ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
character_count | int | アスキー表現のバイト列の長さ |
戻り値
型 | 値 | 内容 |
---|---|---|
int | - | バイナリ表現のバイト列の長さ |
character_from()
character_from(hexvalue)
0x0
-0xF
の数値を16進数表記の文字へ変換します。
引数
名称 | 型 | 内容 |
---|---|---|
hexvalue | int | 数値 |
戻り値
型 | 値 | 内容 |
---|---|---|
int | - | 文字のアスキーコード |
find_ascii()
find_ascii(port, data, timeout, debugging=False)
指定されたアスキー文字列の受信を待機します。
引数
名称 | 型 | 内容 |
---|---|---|
port | serial.Serial | シリアルポート |
data | str | アスキー文字列 |
timeout | int | タイムアウト(秒) |
debuggign | bool | デバッグ出力 |
戻り値
型 | 値 | 内容 |
---|---|---|
bool | True | 受信を確認 |
bool | False | 受信を確認できず |
find_binary()
find_binary(port, data, timeout, debugging=False)
指定されたバイト列の受信を待機します。
引数
名称 | 型 | 内容 |
---|---|---|
port | serial.Serial | シリアルポート |
data | str | バイト列 |
with_terminal | bool | 終端データ使用の有無 |
terminal | int | 終端として扱うデータ |
timeout | int | タイムアウト(秒) |
debuggign | bool | デバッグ出力 |
戻り値
型 | 値 | 内容 |
---|---|---|
bool | True | 受信を確認 |
bool | False | 受信を確認できず |
flush_rx_buffer()
flush_rx_buffer(port)
受信バッファをクリアします。
引数
名称 | 型 | 内容 |
---|---|---|
port | serial.Serial | シリアルポート |
戻り値
なし
flush_tx_buffer()
flush_tx_buffer(port)
送信バッファをクリアします。
引数
名称 | 型 | 内容 |
---|---|---|
port | serial.Serial | シリアルポート |
戻り値
なし
get_ports()
get_ports()
使用できるシリアルポートの一覧を取得します。
引数
なし
戻り値
型 | 値 | 内容 |
---|---|---|
list[str] | - | ポート名のリスト |
hex_from()
hex_from(character)
16進数を表すアスキー文字を数値へ変換します。0
-9
,A
-F
以外の数値を入力した場合の値は不定です。
引数
名称 | 型 | 内容 |
---|---|---|
character | int | 文字のアスキーコード |
戻り値
型 | 値 | 内容 |
---|---|---|
int | - | 数値 |
is_initialized()
is_initialized(port)
シリアルポートが初期化されているかどうかを確認します。
引数
名称 | 型 | 内容 |
---|---|---|
port | serial.Serial | シリアルポート |
戻り値
型 | 値 | 内容 |
---|---|---|
bool | True | 初期化済み |
False | 未初期化 |
is_readable()
is_readable(port)
シリアルポートからデータを取得できるかどうかを確認します。
引数
名称 | 型 | 内容 |
---|---|---|
port | serial.Serial | シリアルポート |
戻り値
型 | 値 | 内容 |
---|---|---|
bool | True | 受信バッファにデータあり |
False | 受信不可 |
is_there_some_ports()
is_there_some_ports()
使用できるシリアルポートが存在するかどうかを確認します。
引数
なし
戻り値
型 | 値 | 内容 |
---|---|---|
bool | True | シリアルポートあり |
False | なし |
is_writable()
is_writable(port)
シリアルポートへデータを送信できるかどうかを確認します。
引数
名称 | 型 | 内容 |
---|---|---|
port | serial.Serial | シリアルポート |
戻り値
型 | 値 | 内容 |
---|---|---|
bool | True | 送信可 |
False | 送信不可 |
lrc8()
lrc8(data)
8ビットのLRCを計算します。
引数
名称 | 型 | 内容 |
---|---|---|
data | bytes | 計算対象のバイト列 |
戻り値
型 | 値 | 内容 |
---|---|---|
int | - | LRC8 |
millis()
millis()
現在のシステム時間をミリ秒単位で取得します。
引数
なし
戻り値
型 | 値 | 内容 |
---|---|---|
int | - | システム時間 |
open_on_system()
open_on_system(path)
指定されたパスのファイルをシステムの既定のアプリケーションで開きます。
引数
名称 | 型 | 内容 |
---|---|---|
path | Path | ファイルパス |
戻り値
なし
write_binary()
write_binary(port, data)
バイト列をシリアルポートへ送信します。
引数
名称 | 型 | 内容 |
---|---|---|
port | serial.Serial | シリアルポート |
data | int | 送信するデータ |
bytes | 送信するデータ列 |
戻り値
なし
write_in_ascii()
write_in_ascii(port, data)
アスキー表現のバイト列をシリアルポートへ送信します。
引数
名称 | 型 | 内容 |
---|---|---|
port | serial.Serial | シリアルポート |
data | int | 送信する文字 |
bytes | 送信する文字列 |
戻り値
なし
4 - TWENET リファレンス
通常のAct開発においては、多くの場合、参照する必要はございません。
- 内部開発向けの情報が含まれており、通常の開発の利用には推奨しない場合があります。
- 一部開発中の情報も含まれます。
一般開発向けで参照すべき情報一覧
一般開発向けで参照する可能性のある資料を列挙します。
Act (MWX C++ ライブラリ) による開発
Act (MWXライブラリ)の開発では以下を参照してください。
TWENET C (C言語) による開発
TWENET C (C言語) による、半導体メーカ提供の API および TWENET ライブラリを用いた開発です。多くも TWELITE Apps は、TWENET C で記述されています。
TWENTEcmptライブラリ — TWELITE GOLD 向けに実装した AHI 関数(BLUE/RED向け半導体メーカ提供API) 向けの互換ライブラリ
TWENETutilsライブラリ — 主に TWENET C で用いるマクロやライブラリ関数について
その他ライブラリについて
TWENETeastlライブラリ — Act向けの EASTL テンプレートライブラリ
TWENETstgs/printf — Act の実装でも用いられる printf ライブラリについて
4.1 - TWENETmcu - マイコンライブラリ
TWENETmcu - マイコンライブラリ
マイコンの基本的な動作のためのソースコードが含まれます。多くのコードは JN5189 向け SDK からコピーされたもので、これを TWENET 向けに一部調整しています。また、始動時の関数 main()
, WarmMain()
が含まれ、この中で TWENET を動作させています。
- board - ハードウェアの初期化 (クロック・GPIO ピンなど初期化手続き)
- component - 比較的上位機能を提供する諸ライブラリ群 (SDK_X.Y.Z/components, middleware などから)
- framework - 比較的上位機能を提供する諸ライブラリ群 (SDK_X.Y.Z/middleware/wireless/framework から)
- device, startup - JN5189 向けHAL層
- drivers - ペリフェラル手続きのための FSL ライブラリ他
- libs - ライブラリファイル(libXXX.a)
- main - main() や デバッグ向けの出力処理を行う _putchar() など
- printf - printf() ライブラリ (NewLibのものは使わない)
- uMac - MMAC.h を格納
- utilities - assert() やデバッグ PRINTF() など
技術資料
TWENETの実装に関する事項や、アプリケーションプログラム作成上留意すべき事項を記載します。
4.1.1 - マイコンについて
マイコンについて
TWELITE GOLDで使用されるマイコンはARM CortexM4コアでIEEE802.15.4を備えています。TWELITE BLUE/REDではOpenRISCコアを用いており全く違うマイコンで、いくつか留意する必要があります。
※ 特に仕様面で注意を払う内容を記載していますが、お客様が作成するシステムやハードウェア要件によっては、さらに深い情報が必要になる場合があります。詳しくはNXP JN5189データシートを参照してください。
本書の記述について
- 本書は TWELITE BLUE/RED での利用との相違点を主に記述していますが、JN5189 データシートを一次資料として参照ください。
- ピン番号を表現する場合 PIO と表記する場合はマイコン本来での番号、DIO/DOと表記する場合は TWELITE BLUE/RED で使用されるピン名を表現します。文脈によりADC1,ADC2も同様です。
- アプリケーションの移植を円滑にするため「AHIサブセット」ライブラリを提供します。このライブラリは、当社が実装する一部のアプリケーションの移植を目的としています。そのため TWELITE BLUE/RED 上の API との振る舞いは、異なる場合があります。
マイコンの相違点
- TWELITE BLUE/RED はビッグエンディアンですが TWELITE GOLD はリトルエンディアンです。
- ARM CortexM4はクロックは柔軟に構成できるアーキテクチャですが、原則としてマイコンの動作クロックは12MHz/32MHz/48Mhzで、IO(PWMなど)は32Mhzで動作します。TWELITE BLUE/REDは、マイコンの主要クロックは16Mhz/32MhzでIOは16Mhzです。
- ピンごとのGPIO割り込みの利用には制限があります。GINT(グループ割り込み)を用い、各ピンが変化したときに割り込みが発生させることができます。
- AHIサブセットで実装しています。当社製アプリコードの移植を目的としているため、網羅的な実装は行わず、また、一部仕様や振る舞いが異なる場合があります。
- GINTでの実装では、割り込みの発生は常に両エッジです。
- 例えば、立ち下がりエッジに設定したいピンがあって初期状態がLOとします。ピンの状態がLO->HI->LOと遷移した場合、LO->HIGH, HIGH->LO両方について割り込みが発生します。
- マイコン稼働中はAHIサブセットにより前者は抑制しますが、スリープ起床に用いる場合はソフトウェアによる抑制は行えず、LO->HIGHの遷移が起きたタイミングで起床します。
- 反対にTWELITE BLUE/REDでは出来なかった両エッジの検出が可能で、AHIサブセットにも反映しています(
vAHI_DioInterruptEdge()
,vAHI_DioWakeEdge()
)。
- ピンごとの割り込み機能として PINT 機能があります。PINT で使用できるピンの上限数が決まっています。
- AHIサブセットでは未使用の機能で併用にあたっての特別な手続きはありません。
マイコンの機能
- RTCを内蔵しています。TWELITE BLUE/REDは外部オシレータなどを接続しタイマーを高精度化できましたが、TWELITE GOLDでは32Khzオシレータを内蔵しRTC機能を有しています。
- 浮動小数点演算のための回路は含まれません。従前どおりソフトウェアライブラリによる計算です。ただし、Cortex-M4には固定小数点演算を用いるDSP機能がありますので、こちらを利用することも選択肢です。
モジュールの相違点
- TWELITE RED/BLUEではDIO20ピンに加えSPI専用2ピン・アナログ専用2ピンの合計24ピンありましたが、TWELITE GOLDではディジタル専用ピン16ピン、ディジタルアナログ共用ピン6ピンの22ピンです。このため、TWELITE GOLDでは2ピンが共用となっています。
- PIO0はDO0(SPICLK)とDIO11と共用です。
- PIO14はADC2(Vref)とDIO8は共用です。
- AHIサブセットでは、DIO8を利用する前にディジタルポートに設定する必要があります。
- TWELITE BLUE/REDのDIOピンはリセット時にハイインピーダンス・プルアップとなっていましたが、TWELITE GOLDではピンごとに状態が違います。AHIサブセットでは初期化時に DIO0..19 DO0,1 は入力、プルアップに、ADC1,2 はアナログ入力としています。
取り扱いに注意を要するピン
詳細は JN518x データシートを参照してください。
- PIO=5 (ISP_ENTRY) : TWELITE BLUE/RED同様、リセット時にLOW状態になるとファームウェア書き込みなどを行うモードになります。
- PIO=4 (ISE_SEL) : ISP_ENTRY 有効時に、その後の振る舞いが変更されます。ファームウェア書き込み時にはHIGHレベルにしないとファームウェア書き込みが実施できません。
- PIO=10,11: 主にI2Cの利用を想定しているため、他でGPIOで利用できるピンと異なります。具体的にはプルアップ・ダウンの設定がないなどです。
ペリフェラルについて
TWENETmwf(ペリフェラルて手続きで主要機能を整理), TWENETcmpt ライブラリ(AHIを用いたコードの移植を目的)の資料を参照ください。
4.1.2 - 始動関数 main(), WarmMain()
始動関数 main(), WarmMain()
本ドキュメントではTWELITE GOLDでのファームウェアの始動関数およびコールバック関数について記述しています。
main(), WarmMain()
TWELITE GOLDではファームウェアはmain()
関数から開始します。また、スリープの復帰はWarmMain()
から行われます。これら関数はweak
指定されているためユーザーが独自に定義することも可能です。
__attribute__((weak)) int main(void);
__attribute((weak)) void WarmMain(void);
int main(void) {
ToCoNet_vInit_Cold_Pre();
ToCoNet_vBoard_Init(FALSE);
ToCoNet_vInit_Cold(0, 0);
ToCoNet_vMain(NULL);
}
void WarmMain(void)
{
vAHI_OnWakeup_MW(FALSE);
ToCoNet_vInit_Warm_Pre();
ToCoNet_vBoard_Init(TRUE);
ToCoNet_vInit_Warm(0);
ToCoNet_vMain(NULL);
}
// source/twenet_main.c
コールドブート(電源投入・リセット)時の呼び出しフロー
main()
ToCoNet_vInit_Cold_Pre() <= メモリ初期化
TWENET C:cbAppColdStart(FALSE), MWX:init_cold()の呼び出し
ToCoNet_vBoard_Init(FALSE)
vAHI_RegEvMgr_MW() <= mwfライブラリの初期化
BOARD_InitBootPins()
BOARD_InitPins() <= この関数で各ピンの初期化
BOARD_BootClockRUN() <= クロックの初期化
vAHI_FRWTStart_MW() <= FRWT(WTIMER)の開始
G_TWENET_CHIPSENSOR_AUTO_ON_BOOT()
<= オンチップの温度センサーの取得準備
GPIO_PortInit() <= GPIO の初期化
checkIrqPending() <= 割り込み状態のクリア
AES_Init() <= AES 暗号化の初期化
__enable_irq() <= 割り込み開始
ToCoNet_vInit_Cold() <= TWENET の初期化
TWENET C:cbAppColdStart(TRUE), MWX:setup()の呼び出し
ToCoNet_vMain() <= TWENET メインループ
ウォームブート(RAM保持スリープ復帰)時の呼び出しフロー
WarmMain()
vAHI_OnWakeup_MW(FALSE) <= 復帰直後のペリフェラル処理
ToCoNet_vInit_Warm_Pre() <= TWENET C:cbAppWarmStart(FALSE), MWX:init_warm() の呼び出し
ToCoNet_vBoard_Init(TRUE)
BOARD_BootClockRUN() <= クロックの初期化
vAHI_FRWTSetBootCount_MW() <= FRWT(WTIMER)の起床時カウント保存
G_TWENET_CHIPSENSOR_AUTO_ON_BOOT()
<= オンチップの温度センサーの取得準備
GPIO_PortInit() <= GPIO の初期化
vAHI_OnWakeup_MW() <= 起床時の処理
checkIrqPending() <= 割り込み状態のクリア
AES_Init() <= AES 暗号化の初期化
__enable_irq(); <= 割り込み開始
ToCoNet_vInit_Warm() <= TWENET の初期化
TWENET C:cbAppWarmStart(TRUE), MWX:wakeup()の呼び出し
ToCoNet_vMain() <= TWENET メインループ
RAM OFF スリープ起床時の呼び出しフロー
main()
vAHI_OnWakeupRamOff_MW(FALSE) <= ペリフェラル処理(DIO状態の確認)
ToCoNet_vInit_Cold_Pre() <= メモリ初期化
TWENET C:cbAppColdStart(FALSE), MWX:init_cold()の呼び出し
ToCoNet_vBoard_Init(FALSE)
vAHI_RegEvMgr_MW() <= mwfライブラリの初期化
BOARD_BootClockRUN() <= クロックの初期化
vAHI_FRWTStart_MW() <= FRWT(WTIMER)の開始
G_TWENET_CHIPSENSOR_AUTO_ON_BOOT()
<= オンチップの温度センサーの取得準備
GPIO_PortInit() <= GPIO の初期化
vAHI_OnWakeupRamOff_MW(TRUE) <= ペリフェラル処理 (GPIO RETENTIONのリリース)
checkIrqPending() <= 割り込み状態のクリア
AES_Init() <= AES 暗号化の初期化
__enable_irq() <= 割り込み開始
ToCoNet_vInit_Cold() <= TWENET の初期化
TWENET C:cbAppColdStart(TRUE), MWX:setup()の呼び出し
ToCoNet_vMain() <= TWENET メインループ
ToCoNet_vBoard_Init(bool_t)
__attribute__((weak)) void ToCoNet_vBoard_Init(bool_t bWarm);
// source/twenet_main.c
この関数では、始動時のハードウェアの初期化を行います。weak指定されているためユーザ独自の初期化手続きを記述できます。詳細はソースコードtwenet_main.c
を参照してください。
これら一連の初期化については MCUXpresso でのプロジェクトウィザードが出力するプロジェクトに対して必要な修正を行っています。関数の構造などについては SDK 資料などを参考にコードを読み下して下さい。
独自のハードウェア初期化を行う場合もこの部分を書き換えることになりますが、動作に対してセンシティブな部分ですので、慎重な修正と十分な検証が求められます。
ToCoNet_vInitCold(uint32)
void ToCoNet_vInit_Cold(uint32 flag, uint32 u32SysHz)
TWENETの初期化手続きを行います。
パラメータ | 内容 |
---|---|
flag | 起動時指定です。通常は0 を指定してください。 |
u32SysHz | SysTickタイマーの周波数を指定します。通常は0 を指定します。必要に応じて1000の倍数で指定します。 |
ToCoNet_vInit_Warm()
void ToCoNet_vInit_Warm(uint32 flag)
スリープ復帰時のTWENET初期化手続きを行います。
パラメータ | 内容 |
---|---|
flag | 起動時指定です。通常は0 を指定してください。 |
ToCoNet_vMain()
void ToCoNet_vMain(PR_TOCONET_MAIN_HOOK fp_hook)
TWENETのメインループです。
checkIrqPending()
static bool_t checkIrqPending();
uint64_t g_twenet_irq_bm_on_boot;
WEAK bool_t __twenet_irq_handler_pending_on_boot(int32_t);
スリープ中または起床後本関数が呼び出されるまでに発生した割り込み情報を保存及びクリアする関数です。
g_twenet_irq_bm_on_boot
の各ビットは、割り込み源 (IRQ_Type
) に対応します(1uul << IRQ_Type)
。- 割り込みの種別は
JN5189.h
に定義されるtypedef enum IRQn
を参照します。 - 割り込みのクリアは、
NVIC_ClearPendingIRQ()
を呼び出します。 __twenet_irq_handler_pending_on_boot(int32_t IRQ_Type)
関数をユーザが定義した場合、IRQ_Type
の割り込みが有効な場合、本関数が呼び出されます。本関数の戻り値をFALSE
とした場合、NVIC_ClearPendingIRQ(IRQ_Type)
を実行します。TRUE
の場合は何もしません。
システムのタイマー周期について
SysTickタイマー周期は以下の方法で設定できます。
ToCoNet_vInitCold()
関数で設定する。この設定が優先される。G_TWENET_SYSTICK_HZ()
をcbAppColdStart(FALSE)
中で設定する。上記2方法の設定を行わない場合は
sToCoNet_AppContext.u16TickHz
の値が採用される。
以下に留意してください。
- TWENETの処理周期(
sToCoNet_AppContext.u16TickHz
)は最大1000Hz。- SysTickの周期は
sToCoNet_AppContext.u16TickHz
の整数倍。
- SysTickの周期は
- 標準的な設定はSysTick=1000Hz,
sToCoNet_AppContext.u16TickHz
=1000Hz。- 準標準として SysTick=2000Hz または 4000Hz、
sToCoNet_AppContext.u16TickHz
=1000Hz。一部(UART)のバックグラウンド処理をTWENETの周期外で実施し、負荷の分散を図ります。またより速いSysTickタイマー割り込みを用いた処理を行う (参照AppQAPI_SysTick_Hnd_Reg()
)。 - 準標準として SysTick=250hz、
sToCoNet_AppContext.u16TickHz
=250Hz。無線パケットの1パケットあたりの時間が2-5ms程度(変調したときの伝送時間やパケット間の隙間時間)であるため。省電力やタイマーごとの処理が重い場合の設定です。 - 準標準での各APIや当社製アプリケーションの動作確認は実施しません。必要な場合は十分な検証を行ってください。
- 準標準として SysTick=2000Hz または 4000Hz、
初期化
G_TWENET_B_MAC_ALWAYS_RESET_ON_WAKE()
bool_t G_TWENET_B_MAC_ALWAYS_RESET_ON_WAKE()
// マクロ定義
本変数を 1
に設定することでスリープ起床時に MAC 層を再初期化します。再初期化には余分に処理時間がかかります(約400usec@32MHz)。
- 本オプションを設定しても、スリープ前の処理(MAC層の状態保存、約100usec@32MHz)はオプション非設定時と同様に実行されます。
4.1.3 - RAMの割当
TWENETmcs/linker/linkscripts
以下のリンカスクリプトを変更します。RAMの割当
TWWLIET GOLD の SRAM 領域は以下のようになっています。
BASE | TOP(末尾+1) | SIZE | |
---|---|---|---|
SRAM11 | 0x0402_C000 | 0x0403_0000 | 16KB |
SRAM10 | 0x0402_8000 | 0x0402_C000 | 16KB |
SRAM9 | 0x0402_4000 | 0x0402_8000 | 16KB |
SRAM8 | 0x0402_0000 | 0x0402_4000 | 16KB |
SRAM7 | 0x0401_5000 | 0x0401_6000 | 4KB |
SRAM6 | 0x0401_4000 | 0x0401_5000 | 4KB |
SRAM5 | 0x0401_2000 | 0x0401_4000 | 8KB |
SRAM4 | 0x0401_0000 | 0x0401_2000 | 8KB |
SRAM3 | 0x0400_C000 | 0x0401_0000 | 16KB |
SRAM2 | 0x0400_8000 | 0x0400_C000 | 16KB |
SRAM1 | 0x0400_4000 | 0x0400_8000 | 16KB |
SRAM0 | 0x0400_0000 | 0x0400_4000 | 16KB |
TWENET ではメモリマップを以下のように定義しています。
BASE | TOP | サイズ | 用途 | RET | バンク名 | |
---|---|---|---|---|---|---|
アプリケーション利用 | 0x0400_0000 | コンパイル時に決定 | ~64KB | MMACのリンク時に必要 | 〇 | SRAM0..3 |
ヒープ | 0x0401_5000 (変更可) | 0x0401_5C00 | 3KB | ヒープ領域 (malloc, new) | 〇 | SRAM7 |
未使用 | 0x0402_0000 | 0x0402_C000 | 48KB | 未使用領域 | SRAM8,9,10 SRAM11 | |
未使用 | 0x0402_C000 | 0x0402_F000 | 12KB | 未使用領域 | SRAM11 | |
スタック | 0x0402_F000 | 0x0403_0000 | 4KB | スタック領域 | SRAM11 | |
(BASE: 開始アドレス, TOP: 終了アドレス+1, RET: スリープ時のRAM保持)
- アプリケーション利用領域は、コンパイル時に決まる静的なメモリ範囲です。末尾アドレスは
(uint32)&_end_fw_retention
にて参照できます。スリープ時には末尾アドレスをもとに不要なバンクを保持しないように設定してます。 - ヒープ領域は、
malloc()
やnew
演算子で確保される領域です。一般論として領域補確保・解放を繰り返すと断片化が問題になり、これを意識してアプリケーションの実装を行います。規定ではメモリの割り当てをSRAMのバンク7としています。ただし、バンク7の末尾512バイトはマイコン半導体の仕様で、続く512バイトはTWENETにて予約しています。- この領域は
App_User_Defs.ld
(build ディレクトリ直下に配置する) にHEAP_START=0x04014000;
HEAP_SIZE = 8192 - BANK7_RESERVE;
のように記述することで調整できます。HEAP_START
はヒープの開始アドレス、HEAP_SIZE
は確保サイズです。代表的な組み合わせを挙げます。- 0x04014000, 8192-BANK7_RESERVE(7KB, BANK6-7)
- 0x04012000,16384-BANK7_RESERVE(15KB, BANK5-7)
- 0x04010000,24576-BANK7_RESERVE(23KB, BANK4-7)
- 0x0,0 (最大限、つまり
_end_fw_rentention
から 0x04016000-BANK7_RESERVE までの領域をHEAPに設定する)
- この領域は
- 未使用領域は、SRAM8,9,10 の各16KBです。
- スタック領域は、SRAM11 の一番最後 (
0x0403_0000
)から 4096 バイトを規定として確保しています。- この領域は
App_User_Defs.ld
(build ディレクトリ直下に配置する) にSTACK_SIZE = 8192;
のように記述すると、サイズを変更することができます。またSTACK_TOP = 0x04024000;
のように、末尾アドレスを指定できます。 - build ディレクトリに作成される mapファイルの
_vStackTop
__StackLimit
を確認してください。 - この領域はスリープ時に保持されません。
- この領域は
スリープ時の保持領域の設定
アプリケーション利用領域やヒープ領域は、TWENETライブラリ内でスリープ時に保持すべきSRAMバンクを適切に設定しています。アプリケーションの設計や実装によっては、保持されないバンクを保持状態にしたい場合もあります。TWENETcmptライブラリ中に定義されるグローバル変数 G_TWENET_POWER_DOWN_RETENTION_CONFIG_ADD()
に、追加的に必要なバンクに対応するビットをセットしておきます。
例えばバンク8,9の32KBを保持したい場合は、TWENET CライブラリのToCoNet_vSleep()
や mwx ライブラリのthe_twelite.sleep()
呼び出し前に以下を指定します。
G_TWENET_POWER_DOWN_RETENTION_CONFIG_ADD() = PM_CFG_SRAM_BANK8_RET | PM_CFG_SRAM_BANK9_RET;
※ 保持するSRAM領域が増えると、その分スリープ電流が増加します。
App_User_Defs.ld 設定例
未指定時は HEAP は 0x0401_5000
から0x0401_5FE0
、STACKは 0x0402_F000
から0x0403_0000
となります。以下に .../build/App_User_Defs.ld
の設定例を記載します。
- HEAPを
_end_fw_retention
から0x0401_5FE0
まで最大限確保する。
HEAP_START = 0;
HEAP_SIZE = 0;
- RAM6,7にHEAPを確保する (約8KB)。
HEAP_START = 0x04014000;
HEAP_SIZE = 8192 - BANK7_RESERVE;
- HEAPを
_end_fw_retention
から0x0401_5000
まで、STACKを0x0401_5000
から0x0401_5FE0
とする。(0x0402_0000
から0x0403_0000
のBANK8..11を未使用領域にする)
HEAP_TOP = 0x04015000;
HEAP_START = 0;
HEAP_SIZE = 0;
STACK_TOP = 0x04015fe0;
STACK_SIZE = 4096-BANK7_RESERVE;
注:HEAP_START
とHEAP_SIZE
がともに0の場合 HEAP_TOP
を設定できます。この場合 HEAP_TOP
は0x0402_0000
以上の領域には設定できません。
- HEAP領域に
0x0402_0000
から64KB確保しSTACK領域は0x04015fe0
以下の領域に移動する。
HEAP_START = 0x04020000;
HEAP_SIZE = 0x10000;
STACK_TOP = 0x04015fe0;
STACK_SIZE = 4096-BANK7_RESERVE;
OneTime_Heap.c,h
TWENETutils には、メモリ破棄を行わず順番にメモリを確保するための One Time Heap を用意しています。未使用領域の利用を容易にするものです。
#include <OneTimeHeap.h>
OTHEAP_tsContext scOTHeap;
void setup() {
uint32 u32bytes;
void *p;
// 0x0402_0000 から 0x0402_4000 の 16KB 領域を利用する。
OTHEAP_Init(&scOTHeap, 0x04020000, 0x04024000, NULL);
Serial << crlf << "--- One Time HEAP ---";
Serial << crlf << format("start %08x", (uint32)OTHEAP_pvGetRegionStart(&scOTHeap));
Serial << crlf << format("top %08x", (uint32)OTHEAP_pvGetRegionTop(&scOTHeap));
// 100バイト確保する
u32bytes = 100;
Serial << crlf;
Serial << crlf << format("head %08x", (uint32)OTHEAP_pvGetHead(&scOTHeap));
p = OTHEAP_pvAlloc(&scOTHeap, u32bytes, TRUE);
// p=0x0402_0004 (4バイトのヘッダの後が利用可能)
Serial << crlf << format("alloc %dbytes [%08x->%08x)", u32bytes, (uint32)p, (uint32)p+u32bytes);
if(p) Serial << crlf << format("next %08x", *(uint32*)((uint32)p - 4));
// ヘッダは次のブロックのアドレス (0x0402_0068)
// 10バイト確保する (4バイト境界に配置されるため実際は12バイト)
u32bytes = 10;
Serial << crlf;
Serial << crlf << format("head %08x", (uint32)OTHEAP_pvGetHead(&scOTHeap));
p = OTHEAP_pvAlloc(&scOTHeap, u32bytes, TRUE);
// p=0x0402_006c
Serial << crlf << format("alloc %dbytes [%08x->%08x)", u32bytes, (uint32)p, (uint32)p+u32bytes);
if(p) Serial << crlf << format("next %08x", *(uint32*)((uint32)p - 4));
// ヘッダは次のブロックのアドレス (0x0402_0078)
// 最後に確保されたブロックを開放する。解放されたブロックのアドレス(p=0x0402_006c)
p = OTHEAP_pvFreeLastBlock(&scOTHeap);
}
4.1.4 - printf について (デバッグ, シリアル出力)
printf について (デバッグ, シリアル出力)
printfライブラリ
TWENETライブラリ内で使用する printf()
処理です。詳細は TWENETmuc/printf を御覧ください。
デバッグ用の PRINTF
NXP提供のfslライブラリではPRINTF()
マクロを用いてデバッグ出力を行い、リリース時はコンパイル対象から外すようになっています。TWENETライブラリでも、PRINTF()
を利用できるようにコードを調整していますが、fslライブラリの機能そのままではありません。
PRINTF()
マクロの呼び出し先は上述のprintf_()
です。GETCHAR()
マクロなど入力には非対応です。
JN518x SDK2.6.3,2.6.4 での NewLib, NewLibNano ではデータ出力の化けや抜けなどが見られ、適切な振る舞いをしません(バッファリングに関する問題と考えられる。RedLib では当該現象がみられないが C/C++ 混在プロジェクトでは使用できない)。このため PRINTF()
マクロを libTWENETmcu/printf 内の printf_()
関数を用いるように変更しています。
SDK_DEBUGCONSOLE 定義
SDK_DEBUGCONSOLE
の値によって振る舞いが変わります。ビルド対象のアプリケーション内の PRINTF()
の振る舞いが変更されます。
値 | 内容 |
---|---|
0 | デバッグコンソール(Semihost)へ出力されます(この手続は非常に低速です)。 ※ この出力を有効にするためには libTWENETmcu(Debugビルド)の SDK_DEBUGCONSOLE=0 設定を行いライブラリの再ビルドを行い、アプリケーションコード中で_putchar(-1) を周期的(16ms程度)に呼び出す必要があります。(サンプル Samp_bare_MMAC 中に定義された SysTick_Handler() 参照) |
1 | Debug ビルド時の設定です。PRINTF はprintf_ 関数(libTWENETmcu)を用います。_putchar() の再定義を行わない場合SERIAL_bTxChar(0, c); が呼び出されます。TWENETxxxライブラリの Debug 設定もこの値です。 |
2 | Release ビルド時の設定です。PRINTF はコンパイル対象から外され、またprintf_() は何も出力しません。printf_() を用いる場合は_putchar(int) を再定義してください。TWENETxxxライブラリの Release 設定もこの値です。 |
- libTWENETmcuライブラリ中の
_putchar()
は weak リンク指定です。アプリケーションコード中に定義した_putchar()
が優先されます。 - TWENETxxx ライブラリ中の
PRINTF()
を有効にする場合は、アプリケーション内のSDK_DEBUGCOSOLE
と同じ定義を行い、ライブラリの再ビルドが必要です。
SWO について
TWENETmcu/source には SWO 向けの出力コードが含まれます。この機能については正式サポートは行いませんが、コード内の記述等を以下に解説します。
- ソース中は
-DDEBUG
-DSERIAL_PORT_TYPE=1
の定義を行った部分が SWO 関連処理としている。この定義を行うとPRINTF()
の出力はSWOのITMに出力されるようにコード調整している (main/retarget_itm.c
,main/retarget_putchar.c
)。 - SWOのポートは PIO14 としている。
- SWOを有効にしてデバッグが開始しないことが多い。ISPピン(PIO5)=LO操作をデバッガ起動直前まで維持すると動作する場合がある。
4.2 - TWENETmwf - ペリフェラルC++ライブラリ
TWENETmwf - ペリフェラルC++ライブラリ
マイコンのペリフェラルを扱う手続きを C++ クラスとして、簡素化したものです。
定義済みオブジェクトが用意されており(例mwf::the_i2c0
はI2C0)、このオブジェクト経由で機能にアクセスします。定義済みオブジェクトはstd::unique_ptr<>
によるスマートポインタで、初回の初期化により実体を構築します。
このライブラリでは定義済みオブジェクトは、スリープ前、スリープ復帰時の手続きが含まれ、一括してスリープ前処理、復帰処理を行うことが出来ます。
ペリフェラルオブジェクトについて
ペリフェラルの多くは、初期化などの手続きが一体になっています。そのため、クラスオブジェクトとして、その生成から破棄までを管理します。
クラスオブジェクトは、全て std::unique_ptr<>
によるスマートポインタになっています。オブジェクトの生成前は nullptr
になっているため、いかなるアクセスも行えません(おそらくヌルポインタアクセスによりハングアップします)。利用時には nullptr
のチェックを挟むようにしてください。
if (the_adc) { // nullptr チェックをしてから
the_adc->enable((1UL << 0) | (1UL << 1));
the_adc->start();
}
定義済みのペリフェラルクラスオブジェクト
オブジェクト名 | 説明 |
---|---|
the_adc | アナログディジタル変換(ADC)を利用する |
the_gpio | 汎用IO(GPIO)割り込みを利用する。(割り込みを利用しない場合はクラスオブジェクトは利用しません) |
the_i2c0 | I2Cバスを利用する。(I2C0のみ) |
the_ntag | NTAG用のEEPROMを利用する |
the_pwm[0..9] | PWM0..9を利用する |
the_rng | 乱数生成ライブラリ |
the_spi1 | SPIバスを利用する (SPI1のみ) |
the_wtimer | ウェイクアップタイマーを利用する |
the_wwdt | ウォッチドッグタイマーを利用する |
ライブラリについて
オブジェクト名 | 説明 |
---|---|
mwf_common | 共通定義、ペリフェラルオブジェクトの基底クラスの定義 |
mwf_periph_common | 共通定義、ピン操作のための手続き |
mwf_periph_adc | ADC利用のための手続き |
mwf_periph_gint | 汎用IO(GPIO)割り込み |
mwf_periph_i2c | I2Cバスを利用する。(I2C0のみ) |
mwf_periph_ntag | NTAG用のEEPROMを利用する |
mwf_periph_pwm | PWM0..9を利用する |
mwf_periph_rng | 乱数生成ライブラリ |
mwf_periph_spi | SPIバスを利用する (SPI1のみ) |
mwf_periph_wtimer | ウェイクアップタイマーを利用する |
mwf_periph_wwdt | ウォッチドッグタイマーを利用する |
名前空間について
原則として、以下の名前空間にクラスや関数を定義しています。
mwf::
mwf::periph::
4.2.1 - mwf_common
mwf_common
共通定義やペリフェラル用のクラスのための基底クラスを定義する。
マクロ
BEGIN_CRITICAL, END_CRITICAL (割込み禁止)
#define BEGIN_CRITICAL { uint32_t __TWENET_regPrimask = DisableGlobalIRQ();
#define END_CRITICAL() EnableGlobalIRQ(__TWENET_regPrimask); }
// 例
extern volatile int critical_value;
void some_func() {
...
// 以下はクリティカルセクション
BEGIN_CRITICAL
{
critical_value++;
}
END_CRITICAL();
}
割込み禁止区間を設定するためのマクロです。DisableGlobalIRQ()
, EnableGlobalIRQ()
を呼び出すだけのマクロですが、ローカル変数を定義する必要があるなど、記述が煩雑に見えるため do {…} while() 構文に似せたマクロを定義しています。
上記例では、割り込みハンドラなどで変更しうる値 critical_value
がある場合に、アプリケーション処理内でその値を安全に更新するための手続きです。
※ このマクロは C++ コードのみで使用できます。
定数・列挙体など
enum class ID_SYSHAND
ペリフェラルクラスオブジェクトを識別するための ID を定義しています。
class sys_ev_handler
スリープとスリープ復帰時の手続きを共通化するためのインタフェース定義を行う上位(抽象)クラス。
on_sleep()
ペリフェラルのスリープ前の手続きを記述する。
on_wakeup(bool init_2nd)
スリープ復帰時に、スリープ前の状態に復帰するためのペリフェラルの手続きを記述する。この関数は2回呼び出されることを想定しています。
init_end
がfalseの場合は、起床後ごく初期の段階で呼び出されます。主に変数の初期化などを行いますが、デバイスなどの再初期化などはここでは行いません。trueで呼び出された2回目で。デバイスの再初期化などを行い、スリープ前の状態に復元します。TWENETでは
vAHI_OnWakeup_MW()
の呼び出し中に処理されます。以下のような呼び出し順になります。詳細は TWENETmcu のtwenet_main.c
を参照してください。WarmMain()
関数の呼び出し (スリープ復帰時に最初に呼び出される関数)vAHI_OnWakeup_MW(FALSE)
- ここで mwf ライブラリオブジェクトの
on_wakeup(false)
が呼び出される
- ここで mwf ライブラリオブジェクトの
ToCoNet_vInit_Warm_Pre()
cbAppWarmStart(FALSE)
(mwxではinit_warm()
)
ToCoNet_vBoard_Init()
- 無線マイコンのハードウェアの初期化(クロックなど)
vAHI_OnWakeup_MW(TRUE)
- ここで mwf ライブラリオブジェクトの
on_wakeup(true)
が呼び出される
- ここで mwf ライブラリオブジェクトの
ToCoNet_vInit_Warm()
cbAppWarmStart(TRUE)
(mwx ではsetup()
)
- TWENET初期化
- TWENETアプリケーションループ
class sys_global_resource_handler
I2C, PWMなど同一機能が複数単位定義される場合に、初期化と破棄の手続きを管理する上位クラス。
これら複数利用可能なペリフェラルでは一度だけ初期化の際に行う手続きと、全て利用終了してから破棄する手続きが存在する場合に利用する。(左記のペリフェラルであっても、実装状況に応じて本クラスを利用したりしない場合がある)
初期化と破棄の手続きは、オブジェクトが生成・破棄されるたびに更新される参照カウンタ(コンストラクタより渡す)により行う。
※ sys_ev_handler は抽象クラスだが、本クラスは CRTP を用いている。
init()
参照カウンタが1
になったとき(=初期化が必要な場合)に T::global_init()
を呼び出す。
※ このメンバ関数はペリフェラルクラスのコンストラクタから明示的に呼び出すこと。
deinit()
参照カウンタが0
になったとき T::global_deinit()
を呼び出す。
※ このメンバ関数はペリフェラルクラスのデストラクタから明示的に呼び出すこと。
class sys_ev_manager
ペリフェラルクラスオブジェクトを一括管理するためのコレクションクラス。ただし、オブジェクトの所有はせず、sys_ev_handler
クラスポインタを格納する固定配列にID_SYSHAND
列挙体が示すIDをインデックスとして格納する。
主目的はon_sleep()
, on_wake()
の手続きを一括で行うためである。
どのペリフェラルクラスオブジェクトが生成されるかはユーザプログラム次第であるため、すべてのクラスオブジェクトに対して if(the_pwm1) the_pwm1->on_sleep();
といった呼び出しは余分なコードをリンクすることにもなり非効率である。sys_ev_handler
型の抽象オブジェクトとして格納し、virtual
メソッドを呼び出している。
global_init_sysevmgr()
the_sys_ev_manager
インスタンスを生成する。
global_deinit_sysevmgr()
the_sys_ev_manager
インスタンスを破棄する。
reg_obj()
ペリフェラルクラスオブジェクトを登録する。
unreg_obj()
ペリフェラルクラスオブジェクトを登録から除外する。
on_wakeup(bool init_2nd)
登録オブジェクトに全てに対し、on_wake()
を実行する。
void on_sleep()
登録オブジェクトに全てに対し、on_sleep()
を実行する。
ペリフェラルクラスの定義例
class timer_n_pwm :
public mwf::sys_ev_handler // 基底クラス
, public mwf::sys_global_resource_handler<timer_n_pwm> // 基底クラス(必要な場合のみ)
{
using global_hdr = mwf::sys_global_resource_handler<timer_n_pwm>;
// 長いので省略形を定義しておく
static uint32_t _global_init_ct;
// sys_global_resource_handlerの参照カウンタ
public:
static void global_init_pwm(uint8_t u8_pwm_id, ...) { ... }
static void global_deinit_pwm_manager(uint8_t u8_pwm_id) { ... }
// the_pwm? の実体を生成・破棄するための手続き。
public:
// コンストラクタ
timer_n_pwm(/* コンストラクタ引数 */)
: mwf::sys_ev_handler(/*ID*/ ,static_cast<sys_ev_handler*>(this))
, mwf::sys_global_resource_handler<timer_n_pwm>(_global_init_ct)
{
global_hdr::init(); // sys_global_resource_handler<>の生成手続き
}
// デストラクタ (抽象クラスを継承しているため virtual 定義する)
virtual ~timer_n_pwm()
{
global_hdr::deinit(); // sys_global_resource_handler<>の破棄手続き
}
// sys_ev_handlerクラスの実装
virtual void on_sleep() { ... } // スリープ前に呼び出す
virtual void on_wakeup() { ... } // スリープ復帰後に呼び出す
// sys_global_resource_handler<>の実装。staticメンバ関数。
static void global_init(); // 一番最初の初期化手続き
static void global_deinit(); // 一番最後の破棄手続き
};
...
uint32_t mwf::periph::timer_n_pwm::_global_init_ct; // 参照カウンタの実体
上記は PWM (mwf_periph_pwm.hpp
) ペリフェラルクラスの定義抜粋です。他の殆どのクラスではsys_global_resource_handler<>
を利用していません。
4.2.2 - mwf_periph_common - ペリフェラル共通
mwf_periph_common - ペリフェラル共通
include
#include "mwf_periph_common.hpp"
GPIO操作関数
struct pin 内に定義する static 関数(インライン関数)を呼び出します。
set_pin_as_input()
static void set_pin_as_input(uint8_t pin, uint32_t param = 0)
pin
を入力状態に設定します。
param
は未使用です。
set_pin_as_output()
static void set_pin_as_output(uint8_t pin, uint32_t param = PORTOUT_INITSTATE_HIGH)
pin
を出力状態に設定します。
param
はPORTOUT_INITSTATE_HIGH
を指定すると、本関数の呼び出し時にHIGH側に設定されます。
set_output()
void set_output(uint8_t pin, uint8_t value)
pin
の出力状態を変更します。value
をPORT_HIGH
(1)にするとHIGH、PORT_LOW
(0)にするとLOWにします。
get_input()
static uint8_t get_input(uint8_t pin)
入力状態にあるpin
の状態を読み出します。戻り値はHIGHの場合はPORT_HIGH
(1)、LOWの場合はPORT_LOW
(0)です。
get_input_bm()
static uint32_t get_input_bm(uint32_t u32mask = 0x3FFFFF)
// 例
uint32_t bm = get_input_bm((1ul << 0) | (1ul << 3));
if (bm & (1ul << 3)) { ... } // PIO3 が HIGH の場合
else { ... } // PIO3 が LOW の場合
全ピンの入力状態をビットマップで読み出します。
- PIOnの値は (1UL « n) のビットに対応します。
- 入力状態にないピンの値は未定義です。
例ではピンのビットマップ(u32mask
)を指定し、入力ピンの状態をまとめて取得します。ビットマップは、例えば PIO0 と PIO3 の値が必要な場合は (1ul << 0) | (1ul << 3)
と指定します。
戻り値も同様に入力状態のビットマップです。HIGHレベルが1
、LOWレベルが0
で表現します。例えば PIO3 が HIGH の場合は LSB から数えて4番目のビットが 1 になります。
set_output_bm()
static void set_output_bm(uint32_t u32mask, uint8_t value)
// 例
set_output_bm((1ul << 0) | (1ul << 3), 0); // PIO0, 3 を LOW レベルに設定する
u32mask
で指定したビットマップに対応するピンについて出力状態を変更する。
- PIOnの値は (1UL « n) のビットに対応します。
value
をPORT_HIGH
(1)にするとHIGH、PORT_LOW
(0)にするとLOWにします。
例ではピンのビットマップ(u32mask
)を指定し、出力の状態をまとめて設定します。ビットマップは、例えば PIO0 と PIO3 を設定する場合は (1ul << 0) | (1ul << 3)
と指定します。また出力状態value
は1
がHIGHレベル、0
がLOWレベルです。
PIN操作関数
struct pin 内に定義する static 関数(インライン関数)を呼び出します。
static void __conf_digital()
static void __conf_digital(uint8_t pin, uint8_t func)
指定したピンpin
のPIOレジスタに対してIOCON_PIO_FUNC(func)
を設定します。
IOCON->PIO[0][pin] =
( 0
| IOCON_PIO_FUNC(func) // SETFUNC (e.g. PWM is 0x04)
| IOCON_PIO_MODE(0x00u) // 0x00:pullup
| IOCON_PIO_DIGIMODE(0x01u)
| IOCON_PIO_INPFILT_OFF
);
static void conf_default()
static void conf_default(uint8_t pin)
ピンをデフォルト定義に戻します。TWENETmcu ライブラリ中の board/pin_mux.c で設定した値にします。
static void __conf_gpio_input()
static void __conf_gpio_input(uint8_t pin)
内部的に使用します。ピンpin
を GPIO の入力とします。
※ ユーザプログラムでは set_pin_as_input()
を使用します。
static void __conf_gpio_output()
static void __conf_gpio_output(uint8_t pin, bool b_init_high = true)
内部的に使用します。ピンpin
をGPIOの出力とします。b_init_high
をtrueにすると規定出力がHIGH(Vcc)レベル、falseならLOW(GND)レベルです。
※ ユーザプログラムでは set_pin_as_output()
を使用します。
static void set_pullup()
static void set_pullup(uint8_t pin, uint8_t mode)
指定したピンpin
のPIOレジスタに対してIOCON_PIO_MODE(mode)
を設定します。プルアップの制御のビットです。
static void conf_pwmout()
static void conf_pwmout(uint8_t pin, bool b_enable)
__conf_digital()
を用い、指定したピンpin
のPIOレジスタに対してIOCON_PIO_FUNC(0x04)
を設定します。通常はPWM出力に設定されます。
static void conf_adc_input()
static void conf_adc_input(uint8_t pin)
PIO14..19に対してADCに設定するため以下の指定を行います。
IOCON->PIO[0][pin] =
( 0
| IOCON_PIO_FUNC(0x00u) // FUNC_ALT0
| IOCON_PIO_MODE(0x00u) // 0x00:pullup
| IOCON_PIO_DIGIMODE(0x00u) // ANALOGUE
| IOCON_PIO_INPFILT_OFF
);
static void conf_sclN_pioM()
static void conf_scl0_pio10() {
__conf_digital(10, 0x05);
}
static void conf_sda0_pio11() {
__conf_digital(11, 0x05);
}
static void conf_scl0_pio15() {
__conf_digital(15, 0x05);
}
static void conf_sda0_pio16() {
__conf_digital(11, 0x05);
}
static void conf_scl1_pio06() {
__conf_digital(06, 0x05);
}
static void conf_sda1_pio07() {
__conf_digital(07, 0x05);
}
static void conf_scl1_pio12() {
__conf_digital(12, 0x05);
}
static void conf_sda1_pio13() {
__conf_digital(13, 0x05);
}
ピンをI2Cで利用するための設定関数です。
static void conf_uart1(uint8_t tx, uint8_t rx)
static void conf_uart1(uint8_t tx, uint8_t rx)
UART1のTXDピンをtx
に、RXDピンをrx
に指定します。
- 本関数では、TXD または RDX の一方のみを設定することはできません。
その他
struct ts_retention_context
struct ts_retention_context {
uint32_t u32_bm_io;
uint32_t u32_bm_set;
void save();
void restore();
};
static ts_retention_context s_retention_context;
static void retention_on_sleep()
static void retention_on_wake()
内部的に利用します。GPIO出力状態のスリープ時の保持に関する処理と必要なデータを管理します。
static bool __b_check_swdbg_port(uint8_t pin)
static bool __b_check_swdbg_port(uint8_t pin)
内部的に利用します。pin
がデバッグ時に、デバッガで使用されるかどうかを判定します。
スリープ時のふるまい
- GPIO の出力状態を
set_pin_as_output()
による手続きを行ったピンについて、スリープ時にも出力状態が維持されます。ただしretention_on_sleep()
並びにretention_on_wake()
が適切に呼び出される必要があります。TWENETでは、TWENETmcu,TWENETcmptライブラリ内で処理されるスリープ前処理、スリープ復帰処理でこれらが呼び出されています。
4.2.3 - mwf_periph_adc - ADC
mwf_periph_adc - ADC
アナログディジタル変換(ADC)を利用するための手続きをまとめたペリフェラルオブジェクトです。
コード例
以下の例では mwf::
名前空間を明示的に指定しています。省略する場合は using namespape mwf;
を記述してください。
- include
#include "mwf_periph_adc.hpp"
- 初期化手続き
// the_adc クラスオブジェクトの生成
mwf::the_adc->global_init_adc_manager();
// ADCの入力ピンを指定
mwf::pin::conf_adc_input(14);
mwf::pin::conf_adc_input(15);
// 初期化
mwf::the_adc->init();
- ADCの開始(ワンショット)
// チャネルの指定
mwf::the_adc->enable(
(1ul << mwf::adc::CH_0)
| (1ul << mwf::adc::CH_1)
| (1ul << mwf::adc::CH_VCC));
// ADC 開始
mwf::the_adc->start(); // ワンショット
while(!mwf::the_adc->available()) {} // ポーリングで終了待ちを行う
// 値の取得
int16_t v_ch0 = mwf::the_adc->get_value_mv(mwf::adc::CH_0);
int16_t v_ch1 = mwf::the_adc->get_value_mv(mwf::adc::CH_1);
int16_t v_vcc = mwf::the_adc->get_value_mv(mwf::adc::CH_VCC);
- ADCの開始(連続)
// チャネルの指定
mwf::the_adc->enable(
(1ul << mwf::adc::CH_0)
| (1ul << mwf::adc::CH_1)
| (1ul << mwf::adc::CH_VCC));
// ADC 開始
mwf::the_adc->start(true); // 連続
// アプリケーションループ内で。
void loop() {
if (mwf::the_adc->available()) {
// 値の取得(周期的に実行する)
int16_t v_ch0 = mwf::the_adc->get_value_mv(mwf::adc::CH_0);
int16_t v_ch1 = mwf::the_adc->get_value_mv(mwf::adc::CH_1);
int16_t v_vcc = mwf::the_adc->get_value_mv(mwf::adc::CH_VCC);
...
}
}
- 温度の測定
int32_t i32temp;
int16_t i16volt;
// 内部センサーの電源ON、安定化待ち処理、ADCの計測処理 (1回のみ)までを実行。
mwf::the_adc->temp_capture(i32temp, i16volt, 0);
// i32temp は温度℃の128倍値。i16volt はミリボルト
Serial << format("%dC %dmV", i32temp >> 7, i16volt);
class mwf::periph::adc
the_adc クラスオブジェクトの主要定義を記載します。
定数定義
static const uint8_t CH_MAX = 7;
static const uint8_t CH_0 = 0; // ADC0
static const uint8_t CH_1 = 1; // ADC1
static const uint8_t CH_2 = 2; // ADC2
static const uint8_t CH_3 = 3; // ADC3
static const uint8_t CH_4 = 4; // ADC4
static const uint8_t CH_5 = 5; // ADC5
static const uint8_t CH_VCC = 6; // VCC
static const uint8_t CH_TEMP = 7; // 内部温度センサー (通常のADとは取得方法が違います)
ADCチャネルについての設定定義です。
struct config
struct config {
uint8_t prescale;
};
設定を行うための構造体。init()
のパラメータとして渡す。
prescale
: **《現バージョンではDEFAULT_PRESCALE=6
のみに対応》**ADCの変換時間を決めるためのプリスケール値。fslライブラリで定義されるadc_config_t::clockDividerNumber
に(1ul << .prescale)
を設定し::ADC_Init()
を呼び出します。
global_init_adc_manager() global_deinit_adc_manager()
static void global_init_adc_manager();
static void global_deinit_adc_manager();
クラスオブジェクトthe_adc
の生成と破棄を行う。
set_pin_as_adc()
static void set_pin_as_adc(uint8_t pin)
指定したピン番号pin
をADC入力にする。
init() deinit()
void init(bool b_wait_init = true);
void deinit();
ADCを初期化します。
b_wait_init
をFALSEに設定すると、ADCの安定化の待ち時間 (300ms) を省略します。待ち時間の扱いについてはis_periph_enabled()
を参照してください。
内部温度センサー取得用に ADC を初期化または再初期化するには init_for_temp_volt()
を呼び出します。すでに init()
により初期化済みの場合は temp_capture()
を
is_periph_enabled()
bool is_periph_enabled()
void force_periph_enabled()
uint32_t get_init_freerun_tick()
ADCが初期化され必要な待ち時間を経過すると true
を戻します。
the_wtimer
で提供するFRWT(Free Running Wake Timer)が動作している場合は、is_periph_enabled()
が適切な時期までfalse
を戻します。init()
が呼び出されたときのカウント値を得るにはget_init_freerun_tick()
を呼び出します。- FRWTが動作していない場合は初回の
is_periph_enabled()
の呼び出し時におよそ300usecの待ち時間が発生します。この待ち処理を行わないようにするためにはinit()
呼び出し直後にforce_periph_enabled()
を呼び出しておきます。この処理は内部状態を強制的に待ち時間が経過したものとして取り扱います。
enable()
void enable(uint32_t chmask);
ADCを動作可能な状態にします。chmask
は変換対象のチャネルのビットマスクで、ADC0 と ADC1 と VCC が対象の場合は (1ul << CH_0) | (1ul << CH_1) | (1ul << CH_VCC)
と指定します。
start() stop()
void start(bool b_cont = false);
void stop();
enable()
実行後に start()
を実行することで、ADCを開始します。b_cont == true
とした場合は、連続変換を行います。すでにstart()
が呼び出されADCが実行中のときには、呼び出してはいけません。
連続変換時に変換を停止するには stop()
を呼び出します。
変換が終了した時点で the_adc->available()
の読み出しが true になります。
available()
bool available();
変換終了後に true を戻します。trueを読み出した後は再びfalseを戻します。
is_started()
bool is_started();
start()
によりADCが実行中である場合trueを戻します。
get_value()
uint16_t get_value(uint8_t ch);
ch
で指定するチャネルのAD変換値(12bit)を取得する。AD変換終了後に呼び出す。
get_value_mv()
int16_t get_value_mv(uint8_t ch);
ch
で指定するチャネルのAD変換値をmvで取得する。AD変換終了後に呼び出す。
global_init_device() global_deinit_device()
static void global_init_device();
static void global_deinit_device();
ハードウェアの初期化と利用終了の手続きを行う。
※ コンストラクタ、デストラクタなどから内部的に呼び出され、ユーザアプリケーションから明示的に呼び出す必要はありません。
register_callback()
typedef void (*PFN_ADC_CALLBACK)(uint32_t, uint32_t);
void register_callback(PFN_ADC_CALLBACK pfn)
割り込みハンドラ内からのコールバック関数の指定。
コールバック関数の第一パラメータは kADC_ConvSeqAInterruptFlag
, 第二パラメータは変換が行われたチャネルのビットマスクが渡されます。
温度センサー
temp_capture()
bool temp_capture(
int32_t& temp128th,
int16_t& volt_mv,
uint8_t times_adc_scaler = 0,
bool b_power_on_temp_sensor = true)
オンチップ温度センサーの値を取得する。副次的に電源電圧も計測する。
temp128th
には、温度の計測結果を格納する変数を指定する。値は摂氏の128倍値になる。整数部はtemp128th >> 7
、小数点1桁部分は(10 * temp128th) >> 7
で計算できる。volt_mv
には、電圧の計測結果を格納する変数を指定する。値はミリボルト[mV]。times_adc_scaler
には、ADCの繰り返し回数に対応するスケーラ値を指定する。0..3まで指定でき、0の場合は1回、1は2回、2は4回、3は8回のAD変換を行ったのち、値を平均化処理する。- 戻り値は成功時にtrue,失敗時にfalseを戻す。
暗黙に以下の処理を行います。
- 温度センサーがONになっていない場合は、センサーをONに設定し必要な待ち処理を行います。(
temp_power_on()
参照) - 実行後は温度センサーをOFFにします。
- ADCの初期化(
init()
)が行われていない場合は失敗します。 - ADCの初期化後、デバイスが利用可能になっていない場合は、待ち処理を行います (
is_periph_enabled()
参照)。
temp_get_capt_tick()
uint32_t temp_get_capt_tick()
最後に温度を取得したときの FRWT のカウンタ値を返す。
temp_power_on(), temp_power_off()
void temp_power_on()
void temp_power_off()
明示的に温度センサーのON/OFFを行う。
FRWT が有効な場合に限り、カウント値をもとに待ち時間が完了しているかを判定するため、事前にON処理を行っておくことで待ち時間を短縮できる。
temp_computation()
int32_t temp_computation(
uint16_t adcout_vbat_lsb_sum8,
uint16_t tsens_adcout_T_sum8,
uint8_t nb_samples_actual = 1)
内部的に利用します。ADC計測値から温度を計算します。
get_ctrl0_adc_reg_context()
class ctrl0_adc_reg;
ctrl0_adc_reg get_ctrl0_adc_reg_context(uint8_t mode, uint8_t tsamp)
//例
if (auto rc = get_ctrl0_adc_reg_context(
0x0
, 0x14
)) {
; // このスコープ内は (0x0, 0x14) の設定が有効。スコープを出ると元の値に戻す。
}
内部的に利用します。一時的に ADCの設定パラメータを変更します。
class mwf::periph::adc (sys_ev_handler)
on_sleep()
ADCの停止処理を行います。
on_wakeup()
スリープ前に ADC が初期化されていた場合は、初期化手続き(init()
)を行います。enable()
, start()
は改めて実行する必要があります。
その他
連続モードでの動作について
変換周期はハードウェアによって決まっています。現バージョンではプリスケーラの値は固定です。
AHI, mwx での利用
AHI や mwx ライブラリの内部では mwf::the_adc
を利用していますので、直接 mwf::the_adc
を利用する場合は注意が必要です。
- AHIライブラリを利用しかつ
mwf::the_adc
を利用する場合は、ADCに関連する一切の手続きを呼び出さないようにしてください (vAHI_ApConfigure()
,vAHI_AdcEnable()
,vAHI_AdcStartSample()
など。App_Tweline 付属のadc.c
) - mwx ライブラリを利用しかつ
mwf::the_adc
を利用する場合は、Analogue
クラスオブジェクトに対して操作を行わないようにしてください(Analogue.setup()
など)。
4.2.4 - mwf_periph_gint - GINT(GPIO)
mwf_periph_gint - GINT(GPIO)
汎用IOの入出力の設定、また GINT を用いたIO割り込みを実装しています。
TWENETでは、初期化、割り込み処理はTWENETライブラリ(TWENETcmpt)内で処理されます。ユーザプログラム内で本関数を呼び出すことは通常ありません。
include
#include "mwf_periph_gint.hpp"
class mwf::periph::gint
the_gint
クラスオブジェクトの定義です。ピンを割り込み動作させる場合(スリープ割り込みも含む)、the_gint
クラスオブジェクトの生成が必要です。実装の詳細は後述の「GINTを用いたDIO割り込み実装」を参照してください。
global_init_gint_manager() global_deinit_gint_manager()
static void global_init_gint_manager();
static void global_deinit_gint_manager();
クラスオブジェクトthe_gint
の生成と破棄を行う。
init_int() deinit_int()
void init_int(tpf_gpio_int_handler pf_callback, void *p_data = nullptr);
void deinit_int();
GPIO 割り込みの初期化を行う。割り込みハンドラ(pf_callback
と割り込みハンドラに伝達されるパラメータ(p_data
)を指定します。
GPIO 割り込みを停止するには deinit_int()
を呼びます。
pf_callback
は、以下のように定義されます。
using tpf_gpio_int_handler = void(*)(uint32_t bm_now, uint32_t bm_changed, void *p_data);
bm_now
は、現時点でのピン状態に対応するビットマップ。bm_changed
は、変更のあったピンに対応するビットマップ。p_data
は、init_int()
で指定したp_data
です。
set_int_pins_bm()
void set_int_pins_bm(uint32_t u32mask_rising_edge, uint32_t u32mask_falling_edge);
割り込み対象のピンを指定します。
1番目のパラメータu32mask_rising_edge
は立ち上がりエッジの検出対象ピンのビットマップ、2番目のパラメータu32mask_falling_edge
は立ち下がりエッジの検出対象ピンのビットマップです。
立ち上がり、立ち下がり両方のエッジを設定することも可能です。
gint_poll()
void gint_poll();
割り込み時の処理と同じ処理を行う。
1msシステムタイマーなどから一定周期で呼び出すことで、後述の「GINTを用いたDIO割り込み実装」で解説する制限(割り込みハンドラ中で読み出した状態からポート状態が変化してそのままその変化が処理されない場合)を緩和できる場合があります。多くの場合はこの処理は必要ありません。
set|unset|get_opt_stop_int_when_changed()
void set_opt_stop_int_when_changed();
void unset_opt_stop_int_when_changed();
bool get_opt_stop_int_when_changed();
メカボタンのチャタリングなどの影響を緩和するために、状態変化検出後に当該ピンの割り込み動作を停止します。
具体的には、ピンの状態が変化し割り込みが発生し、かつ、その割り込みハンドラ中で変化があったと判定されたピン*について、割り込みピンから一時的に除外します。
*割り込み要因のピンはGINTの割り込み機構では知ることが出来ないため、割り込みハンドラが実行された直後にピンの状態を読み出し、直前の状態で比較することで変化を検出しています。
このオプションを設定した場合、ピンの変化が検出されたあとピンの状態の安定を待ってからreactivate_in_pins()
を呼び出します。
reavtivate_int_pins()
void reavtivate_int_pins();
割り込みを一時停止したピンの割り込みを再開する。set_opt_stop_int_when_changed()
のオプション設定参照。
get_gint_context()
gint_context& get_gint_context();
内部構造体にアクセスします。設定済みの立ち上がり立ち下がりピンのビットマップ(.bm_rise
.bm_fall
)や、スリープ起床時の起床要因のピン(.bm_wake
)を得るために使用します。
_gint_update()
std::tuple<uint32_t, uint32_t> _gint_update(
uint32_t u32mask_rising_edge = 0x80000000
, uint32_t u32mask_falling_edge = 0x80000000);
(内部的に呼び出される関数でユーザプログラムからは使用しません)
1.割り込みピンの設定を行う。
2.ピンの状態変化を判定、更新する(u32mask_rising_edge
, u32mask_falling_edge
が0x80000000
の場合)。状態変化があれば init_int()
で登録したコールバック関数を呼び出す。
gint_handler()
static void gint_handler();
(内部的に呼び出される関数でユーザプログラムからは使用しません)
GINTの割り込みハンドラ。
_gint_get_changed_by_specified_edge()
uint32_t _gint_get_changed_by_specified_edge(uint32_t bm_cur, uint32_t bm_changed)
(内部的に呼び出される関数でユーザプログラムからは使用しません)
変化したピンのから、立ち上がり・立ち下がりの指定条件に合致するピンを抽出します。計算には、現在のビットマップ状態(bu_cur
)と変化したピン(bm_changed
)を用います。
class mwf::periph::gpio (sys_ev_handler)
on_sleep()
GINTが稼働中なら割り込みの停止を行います。
TWENETでは vAHI_DioOnSleep_MW()
で、本ライブラリを経由(set_int_pins_bm()
)して設定した割り込み設定ピンをスリープ起床用として設定しています。なお、スリープ起床では立ち上がりまたは立下りのエッジの指定はできません。
on_wakeup()
GPIO割り込み起床した場合は、起床要因に対応するピン情報 (PMC->WAKEIOSOUCE
) を保存します。
また、スリープ前に割り込みピンの指定があった場合は、改めて GINT による割り込みが動作するように再初期化します。
GINTを用いたDIO割り込み実装
PINT機能は利用数が最大4ポートまでの制限があるため、GINT(Group INT)の機能を用い類似の機能を実装してます。PINTのように特定のピンに注目した割り込み検出機構ではないため制限事項が存在します。TWENET ライブラリ中では PINT を用いていませんので、GINTによる実装の制限に問題がある場合は、PINT による実装も検討してください。
制限事項
ノイズや短いパルスといった状態変化後に短時間で再び状態が変化する信号の場合、期待しないふるまいになる場合があります(取りこぼしなど)。
- 状態変化後、一定の間同じ状態が維持されることを想定します。
- GINTの制約上、ごく短いパルスの場合GINT割り込みは検出できますが、変化したピンを得ることは出来ません。詳細は後述の「実装」を御覧ください。
- 変化(エッジ)から約10usecの間状態が維持されれば、GINT のエッジ再設定が行えるため原理的には動作が期待できますが、安全を見て割り込みハンドラ1回の処理時間に相当する約30~50usecの間同じ状態が維持することを目安としてください。
- GND状態で立ち下がりエッジを検出する、またその反対に VCC 状態で立ち上がりエッジを検出する場合は、原理上、取りこぼしが発生しやすくなります。
- チャタリング・ノイズが含まれるものについては、初回割り込み発生時点で割り込み対象から外すオプション(
vAHI_DioInterruptDisablePinsIntWhenChanged_MW(TRUE);
またはmwf::the_gpio->set_opt_stop_int_when_changed();
)を利用し、割り込み発生時点から一定時間待ってから、vAHI_DioInterruptReavtivate_MW();
またはmwf::the_gpio->reavtivate_int_pins();
を呼び出してください。 - 多くの場合必要ありませんが
the_gpio->gint_poll()
を1ms単位のシステムティックなど一定周期で呼び出すことで、割り込みのオーバーヘッドが増えるものの、取りこぼしの影響を緩和できる場合があります。
※ 記載の数値は CPU が 32Mhz 動作した場合を前提としてます。
※ 半導体の機能をそのまま利用したい場合は、当ライブラリの初期化を行わず、GINT や PINT を直接利用してください。
- 状態変化後、一定の間同じ状態が維持されることを想定します。
実装
GINTは本来、複数のピンをグループとして扱い、全体として変化があった場合に割り込みを発生させるもので、個別のピンの状態を意識した機能ではありません。
以下のように実装しています。
- 現在のピンの状態を読み出し、Hなら立ち下がり、Lなら立ち上がりエッジとして、GINTでの検出エッジの設定して、割り込みを有効にする。
- GINT割り込み発生(いずれかのピンに変化し、割り込みハンドラが呼び出される)
- 各ピンの状態を読み出し、変化のあったピンを検出する
- GINTの検出エッジ設定を、読み出したピンの状態に合わせて再設定する
- 変化のあったピンに対してアプリケーションに通知(コールバック)する
※ 割り込みハンドラは、直後にもう一度呼び出されます。
動作例
※ 記載中の数値などは、開発中のライブラリコード、検出対象ピンは2つ、マイコンは CPUは32MHzで駆動した場合です。
同時に2つのピンが L レベルになった時
割り込み発生から 1.5usec で割り込みハンドラが呼び出されます。割り込みの前段階の処理(ピンの読み出しと検出エッジの再設定)は、6.6usec後までかかります。その後、アプリケーション通知(割り込み時のコールバック)を行います(割り込み発生から 22usecまで)。
さらにもう一度割り込みが発生します(GINTのハードウェアの振る舞いと考えられます)。2回目の割り込みでは、多くの場合状態の変化は検出されないため値の確認のみですが、例外的な取りこぼしを抑制する場合があります。

- 横軸 (10usec/DIV)
- ピンク:割り込みハンドラの先頭から、GINTの検出エッジ再設定まで (1V/div)
- シアン・イエロー:入力信号 (2V/div)
割り込みハンドラ中に他のピンが変化した場合1
この例では、割り込みハンドラの前半処理中に他のピン(シアン)が変化したため、最初のハンドラ中で矛盾なく処理できた例です。上述の同時変化と同じ振る舞いになります。最初の割り込みでイエローとシアン両方の変化がアプリケーションに伝達されます。

- 横軸 (10usec/DIV)
- ピンク:割り込みハンドラの先頭から、GINTの検出エッジ再設定まで (2V/div)
- ブルー:割り込みハンドラの開始から終了まで (2V/div)
- シアン・イエロー:入力信号 (5V/div)
割り込みハンドラ中に他のピンが変化した場合2
この例では、割り込みハンドラ中で他のピン(シアン)が変化していますが、検出エッジ再設定後の変化であるため、直後に割り込みが発生しています。2回目のハンドラ終了後に、更にもう一度ハンドラが実行されます。最初の割り込みでイエローの変化がアプリケーションに伝達され、2回目の割りr込みでシアンの変化が伝達されます。

- 横軸 (10usec/DIV)
- ピンク:割り込みハンドラの先頭から、GINTの検出エッジ再設定まで (2V/div)
- ブルー:割り込みハンドラの開始から終了まで (2V/div)
- シアン・イエロー:入力信号 (5V/div)
4.2.5 - mwf_periph_i2c - I2C
mwf_periph_i2c - I2C
I2Cバスを用いるための手続きをまとめたペリフェラルオブジェクトです。
コード例
以下の例では mwf::
名前空間を明示的に指定しています。省略する場合は using namespape mwf;
を記述してください。
- include
#include "mwf_periph_i2c.hpp"
- 初期化
// create instance of the_i2c0.
if (!mwf::the_i2c0) {
mwf::i2c::global_init_i2c0_manager();
}
// I2C device init
mwf::the_i2c0->init();
// write 2bytes (e.g. kick sensor capturing)
const uint8_t cmd1[] = { 0x60, 0x9C };
if (!mwf::the_i2c0->write_blocking(0x70, cmd1)) return false;
// wait (e.g. wait sensor data conversion.)
CLOCK_uDelay(1000*30); // wait some for sensor data conversion.
// read 6 bytes (e.g. read the sensor data.)
uint8_t data[6];
mwf::the_i2c0->read_blocking(0x70, data);
- 読み出し(ブロッキング API)
// write 2bytes (e.g. kick sensor capturing)
const uint8_t cmd1[] = { 0x60, 0x9C };
if (!mwf::the_i2c0->write_blocking(0x70, cmd1)) return false;
// wait (e.g. wait sensor data conversion.)
CLOCK_uDelay(1000*30); // wait some for sensor data conversion.
// read 6 bytes (e.g. read the sensor data.)
uint8_t data[6];
mwf::the_i2c0->read_blocking(0x70, data);
この例では、センサーの取得開始コマンドを送付し、センサー動作時間待ち(センサーが必要とする時間)を経てから、データ取得を行なっています。
- 読み出し(ノンブロッキング API)
// write 2bytes (e.g. kick sensor capturing)
const uint8_t cmd1[] = { 0x60, 0x9C };
if (!mwf::the_i2c0->write(0x70, cmd1)) return false;
while(!mwf::the_i2c0->available()); // waiting for completion of write operation.
// wait (e.g. wait sensor data conversion.)
CLOCK_uDelay(1000*30); // wait some for sensor data conversion.
// read 6 bytes (e.g. read the sensor data.)
uint8_t data[6];
mwf::the_i2c0->read(0x70, data);
while(!mwf::the_i2c0->available()); // waiting for completion of read operation.
ブロッキングAPIと同じwrite/readですが、ノンブロッキングAPIでは write()
/read()
関数はデータ送信完了を待たず速やかに終了します。十分な時間を待つか the_i2c0->available()
がtrueになるのを待ってから続く操作を行う必要があります(上記の例では、write/read直後にポーリング待ちを行っているので、ブロッキングAPIの利用と違いがありません)。
class mwf::periph::i2c
I2Cを利用するための手続きを記述しています。
※ 現状の実装では I2C0 を利用する the_i2c0
クラスオブジェクトのみが利用できます。
E_PIN_CONF
enum class E_PIN_CONF : uint8_t {
NODEF = 0, // 未指定
PRIMARY = 1, // 主割り当て (PIO10/11)
ALT = 2 // 副割り当て (PIO15/16)
};
// enum class と int 型の代入、比較等をするための型。
using wE_PIN_CONF = mwf::enum_wapper<E_PIN_CONF>;
ピン割り当てを指定するための列挙体。
global_init_i2c0_manager(), global_deinit_i2c0_manager()
static void global_init_i2c0_manager(wE_PIN_CONF pin_conf = E_PIN_CONF::PRIMARY);
static void global_deinit_i2c0_manager();
the_i2c0
クラスオブジェクトの生成と破棄を行います。
生成時にピン配置をpin_conf
にE_PIN_CONF::PRIMARY 値:0
(SCL=PIO10,SDA=PIO11)またはE_PIN_CONF::ALT 値:1
(SCL=PIO15,SDA=PIO16)を指定します。ピンの初期化は init()
呼出時に行われる。
(eE_PIN_CONF
はenum class E_PIN_CONF
のラッパクラスで、int
型との代入比較のための定義を設けています)
init(), deinit()
void init(uint32_t clock_freq = 0, wE_PIN_CONF pin_conf = E_PIN_CONF::NODEF);
void deinit();
I2Cバスの初期化と利用終了手続きを行う。初期化時にはclock_freq
をパラメータとして与え、0
の場合は規定クロック100kHzが選択され、それ以外はclock_freq
[Hz]を周波数として指定する。
pin_conf
を指定しない場合(E_PIN_CONF::NODEF 値:0
)は、global_init_i2c0_manager()
で指定したピンを用います。pin_conf
を指定した場合、そのピン設定を用いて初期化します。以降、本パラメータの省略時は最後に指定したピンを用います。
write_blocking(), write()
bool write_blocking(uint8_t addr, const uint8_t* buf, unsigned size);
template <unsigned N> bool write_blocking(uint8_t addr, const uint8_t (&buf)[N]);
bool write(uint8_t addr, const uint8_t* buf, unsigned size);
template <unsigned N> bool write(uint8_t addr, const uint8_t (&buf)[N]);
I2Cバスへデータを書き込む。
write_blocking()
は書き込み完了まで待ち処理を行うブロッキング処理、write()
は書き出し完了を待たずに関数を終了するノンブロッキング処理です。書き出しが完了すると .available()
が true になります。
addr
はI2Cバスのアドレス(7bit)、buf
は書き出すデータ、size
は書き出すデータバイト数を指定します。buf
がサイズN
の固定配列の場合はNバイト書き出します。
read_blocking(), read()
bool read_blocking(uint8_t addr, uint8_t* buf, unsigned size);
template <unsigned N> bool read_blocking(uint8_t addr, uint8_t(&buf)[N]);
bool read(uint8_t addr, uint8_t* buf, unsigned size);
template <unsigned N> bool read(uint8_t addr, uint8_t(&buf)[N]);
I2Cバスからデータを読み込む。
read_blocking()
は読み出し完了まで待ち処理を行うブロッキング処理、write()
は読み出し完了を待たずに関数を終了するノンブロッキング処理です。読み出しが完了すると .available()
が true になります。
addr
はI2Cバスのアドレス(7bit)、buf
はデータ格納バッファ、size
は読み出すデータバイト数を指定します。buf
がサイズN
の固定配列の場合はNバイト読み出します。
_transfer()
bool _transfer(OPT op, uint8_t addr, uint8_t* buf, unsigned size);
ノンブロッキング読み書きを行う処理関数。op
は読み出しか書込みの指定、addr
はI2Cバスのアドレス、buf
は読み書きのためのバッファ、size
は読み書きバイト数です。
_transfer_blocking(), _start_blockin(), _stop_blocking()
bool _transfer_blocking(OPT op, uint8_t* buf, unsigned size, bool sendStop = false)
bool _start_blocking(OPT op, uint8_t addr);
bool _stop_blocking();
mwxライブラリ向けに調整したブロッキング読み書きの手続き。_start_blocking()
、_transfer_blocking()を必要な回数、
_stop_blocking()の順で呼び出す。サイトの転送で
sendStop`をtrueに設定することで適切にSTOP信号を発光できる。
available()
bool available();
ノンブロッキングAPI利用時に、転送終了を判定する。転送終了するとtrueを戻す。
is_success()
bool is_success();
ノンブロッキングAPI利用時に、直前の転送が成功したかどうかを返す。trueなら転送が成功したことを示す。
class mwf::periph::i2c (sys_ev_handler)
on_sleep()
スリープ前の手続きとして I2C デバイスの利用終了手続きを行う。
on_wakeup()
スリープ時に初期化(init()
呼出)済みの場合は、再度 init()
の呼び出しを行い初期化する。
4.2.6 - mwf_periph_ntag - NTAG
このページでは、EEPROMの手続きのみ記述しています。
NTAG 通信の扱いについては、後日追記する予定です。
mwf_periph_ntag - NTAG
チップ内蔵の近距離無線通信(NTAG)コントローラ(NT3H2211)のEEPROMを読み書きするための手続きです。コントローラはI2C接続されていますがmwf::periph::i2c
は用いません。
本手続きにより読み書きできるのは 1KB の領域(NT3H2211 の I2C block address 64-127)です。
コード例
#include "mwf_periph_ntag.hpp"
void func() {
// create the_ntag class object.
if (!mwf::the_ntag) {
mwf::ntag::global_init_ntag_manager();
}
// initialize
mwf::the_ntag->init();
// write 128bytes
uint8_t xfer1[128];
for (unsigned i = 0; i < 128; i++) xfer1[i] = i;
mwf::the_ntag->write_user_area(0x00, xfer1);
// read 128bytes
uint8_t xfer2[128];
mwf::the_ntag->read_user_area(0x00, xfer2);
}
class mwf::periph::ntag
global_init_ntag_manager(), global_deinit_ntag_manager()
static void global_init_ntag_manager();
static void global_deinit_ntag_manager();
the_ntag
クラスオブジェクトの生成と破棄を行います。
init(), deinit()
void init();
void deinit();
デバイスアクセスのための初期化と利用終了手続きを行います。初期化init()
には300usecの待ち処理が含まれます。
write_user_area()
bool write_user_area(uint16_t addr, const uint8_t *p, uint16_t len);
template <unsigned N> bool write_user_area(uint8_t addr, const uint8_t (&buf)[N]);
EEPROMのユーザエリアにバイト列を書き込みます。
addr
は開始アドレスで0..1023を指定します。p
またはbuf
は書込みデータのバッファです。len
またはN
はデータバイト数です。
read_user_area()
bool read_user_area(uint16_t addr, uint8_t *p, uint16_t len);
template <unsigned N> bool read_user_area(uint8_t addr, const uint8_t (&buf)[N]);
EEPROMのユーザエリアからバイト列を読み出します。
addr
は開始アドレスで0..1023を指定します。p
またはbuf
は読み出し先のデータのバッファです。len
またはN
はデータバイト数です。
class mwf::periph::ntag (sys_ev_handler)
on_sleep()
スリープ前に利用終了の手続きを行います。
on_wakeup()
スリープ時に初期化済みの場合は、再度初期化します。再初期化が不要な場合は deinit()
してからスリープしてください。
4.2.7 - mwf_periph_pwm - PWM, Timer
mwf_periph_pwm - PWM, Timer
PWM,タイマーを用いるための手続きをまとめたペリフェラルオブジェクトです。
クラスオブジェクトthe_pwm[]
を用いて操作します。クラスオブジェクトは配列として定義されていますがPWM0(the_pwm[0]
)からPWM9(the_pwm[9]
)まで利用できます。
PWM10は本ライブラリでは対応しません。
コード例
以下の例では mwf::
名前空間を明示的に指定しています。省略する場合は using namespape mwf;
を記述してください。
TWENETcmpt (AHI 互換関数) を利用する場合は、
#include "mwf_periph_pwm.hpp"
// in some func.
void func() {
// create instance of PMW0.
if (!the_pwm[0]) { // The class object of PMW0 is the_pwm[0].
timer_n_pwm::global_init_pwm_manager(
0, // PWM0
timer_n_pwm::PIN::ALT,
// The timer_n_pwm::PIN::PRIMARY will assign smaller PIO number PIO0 from PWM0,
// or conversely, timer_n_pwm::PIN::::ALT assigns PIO12.
true // set true to enable PWM output.
);
}
// set `x' as an alias of the_pwm[0].
auto& x = the_pwm[0];
// Init the device
//x->init(); // not necessary, the constructor will call init() implicitly.
// if needs INT, set true. (default: false)
x->set_int_enabled(true);
// set prescale
x->set_prescale(6); // 0:32MHz 1:16Mhz 2:8Mhz ...
// set polarity: if false, set HIGH while active state. (default: false)
x->set_invert(false);
// set cycle
// note: 500Hz Duty 10% (Hi 0.2ms, Low 1.8ms)
x->set_cycle(
100 // conut for an active state (HIGH)
, 999 // count for a period (+1)
);
// start PWM out
x->restart();
}
// INT handler (call set_int_enabled() before restart())
// note: if TWENETcmpt library is not linked, the IRQ handlers for PWM1..9 shall be defined.
extern "C" void PWM0_IRQHandler(void) {
... // some procedures.
PWM_ClearStatusFlags(PWM, kPWM_Pwm0);
}
class mwf::periph::timer_n_pwm
global_init_pwm_manager()
static void global_init_pwm_manager(
uint8_t u8_pwm_id
, uint8_t u8_pin_number
, bool b_output_enabled = true
);
static void global_init_pwm_manager(
uint8_t u8_pwm_id
, PIN e_pin
, bool b_output_enabled = true
);
クラスオブジェクトthe_pwm[]
を構築します。構築時にPWM番号と対応するピンを指定します。
PWM番号は(u8_pwm_id
)として指定すします。各PWMは利用可能なピンが2ピンあり(PWM5はPIO16のみ)、本APIではu8_pin_number
として直接ピン番号を指定するか、指定可能なピンのうち若い番号(timer_n_pwm::PIN::PRIMARY
)または別のピン番号(timer_n_pwm::PIN::ALT
)を指定します。
矛盾する番号を指定した場合の動作は未定義です。
global_deinit_pwm_manager()
static void global_deinit_pwm_manager(uint8_t u8_pwm_id);
構築済みのthe_pwm[]
クラスオブジェクトを破棄します。
set_pwm_output()
void set_pwm_output(bool_t b_enable);
bool get_pwm_output();
ピンの出力状態を変更します。b_enable
がtrueの場合は出力を有効にする指定でハードウェアのピンも設定変更されます。falseの場合はデフォルトのピン(conf::pin::conf_defautl()
)に設定します。
- PWM出力中に呼び出すことが出来ます。
global_init_pwm_manager()
のパラメータで出力設定している場合、改めて呼ぶ必要はありません。
set_int_enabled()
void set_int_enabled(bool_t b_enable);
bool get_int_enabled();
割り込みの有効・無効を設定します。b_enable
がtrueの場合は割り込みが有効、falseの場合は無効になります。
- PWM出力中に呼び出すことが出来ます。
- 後述の「割り込みハンドラ」を参照してください。
set_prescale(), set_divisor()
void set_prescale(uint8_t u8_prescale);
void set_divisor(uint16_t u16_div);
PWM制御のプリスケールを設定します。これによりPWM制御周波数が決まります。
- PWM出力中に呼び出すことが出来ます。
set_prescale(u8_prescale)
を指定した場合、制御周波数は0
:32Mhz,1
:16Mhz,2
:8Mhz, …,9
: 62500Hz,10
: 31250Hz,11
以降は未定義(デバッグ時assert
)です。set_divisor(u16_div)
を指定した場合, 制御周波数は (32Mhz / u16_div) です。値域は 1..1024 の範囲で、それ以外の値を指定した場合の振る舞いは未定義です。- PWM周期とDUTY比は
set_cycle()
のパラメータで決まります。- 例えば
set_prescale(2)
と指定した場合は制御周波数は fb=8Mhz です。この設定でset_cycle(2, 10)
を指定すると PWM 周期は fbx10=800Khz で、パルス幅が 2x1/fb=1/8000000=250nsec になります。
- 例えば
set_cycle()
void set_cycle(uint16_t ct_comp, uint16_t ct_period);
uint16_t get_period_val(); // get total period count
uint16_t get_comp_val(); // get active region count
PWM1周期とその中でのアクティブ区間を決めるカウント値を指定します。アクティブ区間の間ピンの値が変化し、その終わりに割り込みが発生します。
ct_comp
までの値がアクティブ、ct_period
が1周期のカウント数です。例えばct_comp
を100
、ct_period
を1000
とした場合、PWM周期はPWM制御周波数で1000カウント分、set_invert(false)
の条件で100カウント分がHIGH、残りの900カウントがLOWになる振る舞いをします。
- PWM出力中に呼び出すことが出来ます。
ct_comp
は0
からct_period-1
までが有効です。アクティブが(ct_period-1/ct_period)
の比率までが上限で100%に設定することが出来ません。set_duty()
では100%の設定を考慮しています。- 1周期分のカウント値
ct_period
について、ハードウェアレジスタにはct_period - 1
として設定しています。本関数にはハードウェアレジスタ値を指定しないよう注意してください。
set_duty()
void set_duty(uint16_t u16duty, uint16_t u16duty_max = 1000);
PWMのDUTY比を設定します。
- 事前に
set_cycle()
を用いて、PWMの1周期のカウント数を指定しておきます。左記の手続きを省略した場合u16duty_max
がPWM周期のカウント数として設定されます。 - 1周期に対して
u16_duty/u16duty_max
の割合をアクティブ区間とします。例えばset_duty(100)
と指定した場合はアクティブ区間は1周期に対して10%です。 u16duty
にu16duty_max
と同じ値を指定した場合は、全区間がアクティブとなりデフォルトの反転しない波形出力set_invert(false)
の場合HIGHレベルに設定します(ハードウェアの制約からアクティブ区間を全区間に設定できないため、内部的には波形出力レジスタを反転して、アクティブ区間を0に設定しています)。- このため
set_duty()
で100%設定した後にset_cycle()
を呼び出すと波形が反転します。混用しないように注意してください。
- このため
set_invert()
void set_invert(bool_t b_invert);
bool get_invert();
出力波形を反転します。false(デフォルト)設定時はアクティブ区間がHIGHレベル、trueではLOWレベルです。
start(), stop()
void start();
void restart();
void stop();
PWM出力の開始、設定&開始(再開)、停止処理を行います。
- 停止処理
stop()
時のピンの状態は、set_invert(false)
(デフォルト)の場合 LOW レベル、set_invert(false)
の場合HIGHレベルです。
class mwf::periph::timer_n_pwm (sys_ev_handler)
sys_ev_handler
はスリープ前後の手続きです。
on_sleep()
PWMの実行状態を保存した上で、スリープ時のピン状態をデフォルト設定に戻す。
on_wakeup()
スリープ前の状態した状態を復元する。
class mwf::periph::timer_n_pwm (sys_global_resource_handler)
sys_global_resouce_handler<T>
(T
はtimer_n_pwm
クラス)は、複数のPWMクラスオブジェクトに対して、1度だけ必要な初期化処理、終了手続きを行うための手続きです。内部的に暗黙に利用されます。
- コンストラクタや
on_wakeup()
でsys_global_resource_handler<T>::init()
を呼び出します。- 最初に作成されたインスタンスの場合は
T::global_init()
を呼び出します。
- 最初に作成されたインスタンスの場合は
- デストラクタや
on_sleep()
でsys_global_resource_handler<T>::deinit()
を呼び出します。- 最後に破棄されるインスタンスの場合は
T::global_deinit()
を呼び出します。
- 最後に破棄されるインスタンスの場合は
T::global_init()
::PWM_Init()
を呼び出し、PWMを初期化します。
T::global_deinit()
::PWM_DeInit()
を呼び出し、PWMの利用終了手続きを行います。
割り込み
set_int_enabled(true)
を設定すると、アクティブ区間の終了で割り込みが発生します。割り込みハンドラはシステムで用意されたもので PWMn_IRWHandler()
(nはPWMチャネル)です。
割り込み発生 割り込み発生
V V
Vcc +----+ +----+
| | | | t
GND----+ +-------------+ +-------- ->
<----> アクティブ区間
<------------------> PWM 1周期
割り込みハンドラを明示的に定義します。TWENETcmpt ライブラリをリンクするかどうかで要定義のハンドラ関数が変わります。
- TWENETcmpt をリンク => 使用する PWM チャネルのみ定義する
- TWENETcmpt をリンクしない => PWM0 から PWM9 チャネルまでの割り込みハンドラを割り込みを使用していなくても明示的に定義する
割り込みハンドラ
TWENET を利用する場合は、割り込み関数(cbToCoNet_u8HwInt()
)、イベント(cbToCoNet_vHwEvent()
)に変換されます。
独自の割り込みハンドラを定義する場合は PWNn_IRQHandler()
を別途定義します。以下の例は PWM1 の定義例です。独自に定義する場合 TWENET の割り込み・イベントは発生しません。
// note: in c file, `extern "C"' should be remoded.
extern "C" void PWM1_IRQHandler(void) {
PWM_ClearStatusFlags(PWM, kPWM_Pwm1);
}
4.2.8 - mwf_periph_rng - TRNG
mwf_periph_rng - TRNG
チップ内蔵の乱数生成ハードウェアを利用するため手続きをまとめたペリフェラルオブジェクトthe_rng
を実装しています。
TWENET では、暗黙に利用しますので、ユーザプログラム上での初期化の手続きは不要です。
コード例
if (!mwf::the_rng) {
mwf::rng::global_init_rng_manager();
mwf::the_rng->init();
}
uint32_t val = mwf::the_rng->random();
class mwf::periph::rng
global_init_rng_manager(), global_deinit_rng_manager()
static void global_init_rng_manager();
static void global_deinit_rng_manager();
the_rng
クラスオブジェクトの生成と破棄を行います。クラスオブジェクト生成時に自動的に初期化され、ランダム値の取得が可能になります。
random()
uint32_t random()
乱数値を戻します。
class mwf::periph::rng (sys_ev_handler)
on_sleep()
TRNGの停止処理を行います。
on_wakeup()
TRNGの始動処理を行います。
4.2.9 - mwf_periph_spi - SPI
mwf_periph_spi - SPI
SPIバスを利用するためのクラスオブジェクトthe_spi1
を実装しています。
- SPI0 の対応コードは含まれません。
- 一部 non blocking (非ブロック) を想定した定義が含まれますが、現バージョンでは blocking (ブロック) の API のみ利用可能です。
コード例
#include "mwf_periph_spi.hpp"
void func_spi_init() {
if (!mwf::the_spi1) {
mwf::spi::global_init_spi1_manager();
Serial << crlf << "the_spi1 constructed.";
}
mwf::spi::config conf{};
conf.baud = 4000000UL; // 4MHz
conf.bits = 8; // 8bit
conf.dir = mwf::spi::E_SPI_DIR::MSB_FIRST;
conf.mode = mwf::spi::E_SPI_MODE::MODE_3_INV_RISE;
conf.pin_ssel[0] = mwf::spi::E_PIN_SSEL::SSEL0_PIO3;
conf.pin_ssel[1] = mwf::spi::E_PIN_SSEL::SSEL1_PIO16;
mwf::the_spi1->init(conf);
}
void func_spi_transfer() {
uint8_t tx[16] = { 0xa5, 0x5a, 0x11, 0x88 }; // data to transmit
uint8_t rx[16]; // receive buffer
mwf::the_spi1->ssel_select(0);
mwf::the_spi1->transfer_blocking(tx, rx, 4); // four bytes transfer
CLOCK_uDelay(5); // wait 5us
mwf::the_spi1->transfer_blocking(tx, rx, 4); // four bytes transfer
mwf::the_spi1->ssel_deselect();
}
class mwf::periph::spi
struct config
mwf::periph::spi::config
構造体は以下のように定義されています。
struct config {
// evaluated only in init()
E_PIN_MAIN pin_conf; // master pin configuration (so far not used)
E_PIN_SSEL pin_ssel[3]; // SSEL0..2 (assignment settings for slave select pins.
// At least pin_ssel[0] shall be configured.
// evaluated in conf(), reconf()
uint32_t baud; // SPI frequency (default 50Mhz)
E_SPI_DIR dir; // transfer LSB first
E_SPI_MODE mode; // SPI mode (clock polarity and detect edge)
uint8_t bits; // bit width (0:default=8, ...)
uint8_t ssel; // 0..3 or 0x80..0x80 (if MSB is set, assert/deassert SSEL automatically)
};
構造体に値を設定してinit()
を呼び出します。init()
中で構造体の設定値は内部的にコピーされますので、呼び出し後は構造体領域を破棄しても構いません。
構造体の各メンバーの解説です。
信号名 | 解説 |
---|---|
pin_conf | 使用するピン割り当て(主・副)の指定を行います。E_PIN_CONF::NODEF (=0)を選択した場合は global_init_spi1_manager() の指定を利用します。 |
pin_ssel[3] | SELECTピンを指定します。配列の0番目はSPI SELECTの0番目(SSEL0)のピン、1番目はSSEL1、2番目はSSEL2を指定します。SSEL0は必ず指定し SSEL1,2 は E_PIN_SSEL::SSEL_VOID=0 にしておきます。ピンを2種類利用する場合は SSEL0, SSEL1 を指定し、3種類の場合は全てに値を格納します。※ソフトウェア制御のピン( E_PIN_SSEL::SSEL0_PIO3 など )を指定した場合は、すべてのセレクトピンはソフトウェアによる制御を行います。ソフトウエア制御ではピンはHIGHレベルで常時出力設定となり、セレクト時に対象ピンが LOW レベルに変化します。なお、TWENETcmpt (AHIライブラリ互換) ではソフトウェア制御を用いています。※ハードウェア制御の場合 SELECT ピンの制御は fsl_spi.c の SPI_MasterTransferNonBlocking() の動作に倣います。 |
baud | SPIのクロック周波数を指定します。32Mhz まで設定可能ですがセンサーデバイスなどは 1Mhz 前後がよく使われます。 (動作は、fsl_spi.h の spi_master_config_t::bandRate_Bps , fsl_spi.c のSPI_MasterSetBaud() に倣います) |
mode | SPISELはinit() で指定します。 |
bits | 転送単位です。通常は8を指定します。1..16まで設定できます。9ビット以上の場合、データ転送時に指定するバイト配列は2バイト単位で読み出されるため、データ数の二倍必要で、1バイト目が LSB から 8ビット分2バイト目が 残りのビットを表現します。 (動作は、fsl_spi.hの SPI_MasterTransferBlocking() に倣います) |
ssel | SPIのSELECTです。0..2 を指定します。 |
enum class E_PIN_CONF
enum class E_PIN_CONF : uint8_t {
NODEF = 0, // 未指定
PRIMARY = 1, // 主割り当て (PIO10/11)
ALT = 2 // 副割り当て (PIO15/16)
};
// enum class と int 型の代入、比較等をするための型。
using wE_PIN_CONF = mwf::enum_wapper<E_PIN_CONF>;
ピン割り当てを指定するための列挙体です。
enum class E_PIN_SSEL
enum class E_PIN_SSEL : uint8_t {
SSEL_VOID = 0, // 未定義
SSEL_PRIMARY, // 主設定ピン
SSEL_ALT, // 副設定ピン
SSEL_SOFT = 0x10,
SSEL0_PIO3, // SSEL0 をソフトウェア制御し PIO3 を使用する
SSEL1_PIO16, // SSEL1 をソフトウェア制御し PIO16 を使用する
SSEL2_PIO17, // SSEL2 をソフトウェア制御し PIO17 を使用する
SSEL1_PIO4, // SSEL1 をソフトウェア制御し PIO4 を使用する
SSEL2_PIO13, // SSEL2 をソフトウェア制御し PIO13 を使用する
};
この列挙体はSPI SELECTピンの配置を決めます。spi::confg::pin_ssel[3]
に対応する値か保存されます。
利用デバイス数に応じて
pin_ssel[]
を設定します。- 1つの場合
pin_ssel[0]
を設定。pin_ssel[1]
,pin_ssel[2]
はSSEL_VOID
- 2つの場合
pin_ssel[0]
とpin_ssel[1]
を設定。pin_ssel[2]
はSSEL_VOID
。 - 3つの場合
pin_ssel[0]
,pin_ssel[1]
,pin_ssel[2]
を設定。
- 1つの場合
ハードウェア制御を指定する場合
SSEL_PRIMARY
またはSSEL_ALT
(およびSSEL_VOID
)を指定します。混在させた場合は、ソフトウェア制御となります。
enum class E_SPI_DIR
enum class E_SPI_DIR {
MSB_FIRST = 0,
LSB_FIRST
};
ビットの並び順を指定します。通常は MSB_FIRST
です。
enum class E_SPI_MODE
enum class E_SPI_MODE {
MODE_0_RISE = 0,
MODE_1_FALL = 1,
MODE_2_INV_FALL = 2,
MODE_3_INV_RISE = 3,
};
SPI転送モードの指定です。クロックの判定エッジと、その時の H/L の値を 0 とするか 1 とするかを決めます。接続デバイスのデータシートに従い設定します。
global_init_spi1_manager(), global_deinit_spi1_manager()
static void global_init_spi1_manager(E_PIN_MAIN pin_conf = E_PIN_MAIN::PRIMARY);
static void global_deinit_spi1_manager();
SPI1のバスを利用するためのクラスオブジェクトの生成と破棄を行います。クラスオブジェクト生成時にpin_conf
により利用するためのピンの組み合わせを選択します。ピン設定の指定は E_PIN_MAIN::PRIMARY 値:0
及びE_PIN_MAIN::ALT 値:1
を指定できます。
init()
void init();
void init(spi::config& cnf);
void init(spi::config&& cnf);
SPIバスを初期化します。パラメータcnf
を与えることでいくつかの設定を行います。パラメータを省略した場合は、以前の設定を用いて最初期化します。
- セレクトピンをユーザプログラムでソフトウェア制御する場合であっても、必ず1つは指定してください。指定されたピンはGPIOの出力として設定されます。
unset_ssel_auto()
を呼び出しておけば、当該ピンに対するライブラリによる制御は行われなくなります。
reconf()
void reconf();
ペリフェラルのパラメータを再反映します。内部設定にアクセスするには spi::config& get_conf()
を用います。この手続でピンの設定 (pin_ssel[]
)は反映されません。
set_data_width()
void set_data_width(uint8_t bits);
転送データ幅を変更します。reconf()
より軽い手続きです。
set|unset|get_ssel_auto()
void set_ssel_auto();
void unset_ssel_auto();
bool get_ssel_auto();
セレクトピンの自動制御フラグの設定、解除、取得。
- ソフトウェア制御を利用する場合のみ有効。
transfer_blocking()
呼び出し時に自動的にSELECTピンがLOWに制御され、終了時にSELECTピンがHIGHに設定される。
ssel_select()
void ssel_select(uint8_t select);
セレクトピンの指定を行います。select
は 0, 1, 2 の値をとり、各々 SSEL0..2 に対応します。
- ハードウェア制御、ソフトウェア制御で自動制御フラグ(
set_ssel_auto()
)設定時は、ピンの制御は転送API呼び出し時に行われる。 - ソフトウェア制御の場合は、自動制御フラグの有無に関係なく
ssel_select()
呼び出し直後に、SELECTピンがLOWに設定される。 - ハードウェア制御の場合は、
reconf()
を呼び出し再初期化します。この処理は処理時間のコストが大きいため、頻繁にデバイスを切り替えて転送を行う場合は、ソフトウエア制御を使用してください。
ssel_deselect()
void ssel_deselect();
セレクトピンの解除を行います。
- ソフトウェア制御の場合は、セレクトピンをすべて HIGH レベルに戻します。
- ハードウェア制御の場合は、なにもしません。
ssel_select()
でのピンの指定は変更しません。
その他
bool has_init(); // init() 実行済みであれば true を返す
spi::config& get_conf(); // 内部保存の設定情報にアクセスする
ピンの割り当て
E_PIN_CONF::PRIMARYの場合
信号名 | PIO番号 | 解説 |
---|---|---|
SCK | 0 | クロック信号 |
MOSI | 2 | SPIMOSIです。TWELITE 側が出力、外部SPIデバイス側が入力です。 |
MISO | 5 | SPIMISOです。TWELITE 側が入力、外部SPIデバイス側が出力です。 |
セレクトピン
pin_ssel | E_PIN_SSEL | PIO | 備考 |
---|---|---|---|
SSEL0 pin_ssel[0] | SSEL_PRIMARY | 3 | |
SSEL_ALT | 16 | ||
SSEL0_PIO3 | 3 | ソフトウェア制御 | |
SSEL0_PIO16 | 16 | ソフトウェア制御 | |
SSEL1 pin_ssel[1] | SSEL_PRIMARY | 4 | |
SSEL_ALT | 14 | ||
SSEL1_PIO4 | 4 | ソフトウェア制御 | |
SSEL1_PIO14 | 14 | ソフトウェア制御 | |
SSEL1_PIO16 | 16 | ソフトウェア制御(SSEL0_PIO16 の指定は不可) | |
SSEL_VOID | セレクトは SSEL0 のみとする | ||
SSEL2 pin_ssel[2] | SSEL_PRIMARY | 13 | |
SSEL2_PIO13 | 13 | ソフトウェア制御 | |
SSEL2_PIO17 | 17 | ソフトウェア制御 | |
SSEL_VOID | セレクトは SSEL0 SSEL1 の2つとする |
- セレクトは
SSEL0
から順にSSEL1
SSEL2
まで最大3種類設定できます。 pin_ssel[]
のいずれかの指定がソフトウェア制御の場合、セレクトピンは全てライブラリ中でソフトウェア制御を行います。
E_PIN_CONF::ALTの場合
信号名 | PIO番号 | 解説 |
---|---|---|
SCK | 15 | クロック信号 |
MOSI | 17 | SPIMOSIです。TWELITE 側が出力、外部SPIデバイス側が入力です。 |
MISO | 18 | SPIMISOです。TWELITE 側が入力、外部SPIデバイス側が出力です。 |
セレクトピン
pin_ssel | E_PIN_SSEL | PIO | 備考 |
---|---|---|---|
SSEL0 pin_ssel[0] | SSEL_PRIMARY | 16 | |
SSEL_ALT | 3 | ||
SSEL0_PIO3 | 3 | ソフトウェア制御 | |
SSEL0_PIO16 | 16 | ソフトウェア制御 | |
SSEL1 pin_ssel[1] | SSEL_PRIMARY | 14 | SSEL0の指定必須 |
SSEL_ALT | 4 | ||
SSEL1_PIO4 | 4 | ソフトウェア制御 | |
SSEL1_PIO14 | 14 | ソフトウェア制御 | |
SSEL_VOID | セレクトは SSEL0 のみとする | ||
SSEL2 pin_ssel[2] | SSEL_PRIMARY | 13 | |
SSEL_ALT | 5 | PRGピンでもあるので注意が必要。 | |
SSEL2_PIO5 | 5 | ソフトウェア制御。PRGピンでもあるので注意が必要。 | |
SSEL2_PIO13 | 13 | ソフトウェア制御 | |
SSEL_VOID | セレクトは SSEL0 SSEL1 の2つとする |
- セレクトは
SSEL0
から順にSSEL1
SSEL2
まで最大3種類設定できます。 pin_ssel[]
のいずれかの指定がソフトウェア制御の場合、セレクトピンは全てライブラリ中でソフトウェア制御を行います。
class mwf::periph::spi (sys_ev_handler)
on_sleep()
スリープ前の手続きとして、SPIを未使用状態に戻す。
init()
により初期化済みであればこれを保存しておく。
on_wakeup()
スリープ前に初期化状態であれば、SPI バスを利用できるように最初期化します。
4.2.10 - mwf_periph_wtimer - WTIMER, FRWT
mwf_periph_wtimer - WWDT, FRWT
ウェイクアップタイマーを利用するため手続きをまとめたペリフェラルオブジェクトthe_wtimer
を実装しています。
TWENETでは暗黙に使用されますので、ユーザプログラムでの初期化は不要です。
ウェイクアップタイマーはモジュール内に内蔵する 32768Hz の水晶振動子に基づき減算カウントします。例えば32768からタイマーを開始した場合、1秒後にカウンタは0にり割り込みが発生します。通常はスリープ起床に用います。起床後もカウンター値は減算を継続するため、起床後にカウント値を読み出すことで、起床後からの経過時間を計算できます。
ウェイクアップタイマーは、2系統あり系統0は40bit(当ライブラリでは32bitカウンタとして利用)、系統1は28bitのカウンタを用います。
またウェイクアップタイマーを利用した FTWT (Free Running Wake Timer) の手続きが含まれます。スリープ時も低消費電流で動作できる特徴をいかし、2系統あるウェイクアップタイマーのうちの一つを常に動作させることで、実時間に対応するカウンタとして利用します。TWENETでは、特定の設定を行うことでFRWTが機能し、FRWTが動作している場合は ADC の初期化待ちなどを効率的に行えます。
TWENETでは系統0をFRWTとして利用し、系統1を通常の起床用タイマーとして利用します。
コード例
- include
#include "mwf_periph_wtimer.hpp"
class mwf::periph::wtimer
global_init_wtimer_manager(), global_deinit_wtimer_manager()
static void global_init_wtimer_manager();
static void global_deinit_wtimer_manager();
the_wtimer
クラスオブジェクトの生成と破棄を行います。
init(), deinit()
void init();
void deinit();
ウェイクアップタイマーを初期化または終了します。
- 初期化時のパラメータ
u32ms
はタイムアウトをミリ秒(ms)で指定します。0
または省略したときは4000msとなります。
start(), stop()
void start(uint8_t dev, uint32_t u32ct)
void stop(uint8_t dev)
ウェイクアップタイマーを開始または停止します。
dev
には、使用するウェイクアップタイマーのデバイス番号(WTIMER0_DEVICE
またはWTIMER1_DEVICE
)を指定します。u32ct
には、開始時のカウント値を指定します。- FRWT が動作しているウェイクアップタイマーを指定した場合は、なにもしません。
read()
uint32_t read(uint8_t dev)
ウェイクアップタイマーのカウント値を読み出します。
dev
には、使用するウェイクアップタイマーのデバイス番号(WTIMER0_DEVICE
またはWTIMER1_DEVICE
)を指定します。- FRWT が動作しているウェイクアップタイマーの値は読み出せません。
is_running()
bool is_running(uint8_t dev)
ウェイクアップタイマーが動作中かを判定します。
dev
には、使用するウェイクアップタイマーのデバイス番号(WTIMER0_DEVICE
またはWTIMER1_DEVICE
)を指定します。- FRWT が動作しているウェイクアップタイマーを指定した場合は、falseを戻します。
set_interrupt()
void set_interrupt(uint8_t dev, bool b_enabled)
ウェイクアップタイマーが割り込みを発生させるかどうかを指定します。
dev
には、使用するウェイクアップタイマーのデバイス番号(WTIMER0_DEVICE
またはWTIMER1_DEVICE
)を指定します。b_enabled
をtrueに設定すると割り込みを発生させます。この指定がないと、スリープ起床時にも割り込みが発生しません。なお、いちどtrueを指定したウェイクアップタイマーに対してfalseを指定しても、割り込みを無効にすることはできません。- FRWT が動作しているウェイクアップタイマーを指定した場合は、なにもしません。
get_fired_status_on_wakeup()
uint8_t get_fired_status_on_wakeup()
スリープ起床後に呼び出し、その起床要因がウェイクアップタイマーであった場合は、デバイスに対応するビット (WTIMER0_DEVICE_MASK
またはWTIMER1_DEVICE_MASK
)が設定される。
class mwf::periph::wtimer (sys_ev_handler)
on_sleep()
特別な処理はありません。
on_wakeup()
起床要因を確認し内部に情報を保存し、割り込み状態をクリアします。また、タイマーは停止しません。
FRWT関連
freerun_start(), freerun_stop()
void freerun_start(uint8_t dev)
void freerun_stop()
FRWTの開始と終了を行います。カウント値は開始時を0として、32768Hzで加算される値です。
dev
には、ウェイクアップタイマーのデバイス番号(WTIMER0_DEVICE
またはWTIMER1_DEVICE
)を指定します。
freerun_is_running()
bool freerun_is_running()
FRWT が動作している場合に true を返す。
freerun_is_device()
bool freerun_is_device(uint8_t dev)
FRWT が動作しているデバイスなら true を返します。
dev
には、ウェイクアップタイマーのデバイス番号(WTIMER0_DEVICE
またはWTIMER1_DEVICE
)を指定します。
freerun_ct_get()
uint32_t freerun_ct_get()
FRWTのカウント値を返します。FRWTのカウント値は、ウェイクアップタイマーの値そのものではなく、0から加算される値に変換されます(大まかには正負反転した値)。
カウント値計算関数
FRWTカウント値をミリ秒に変換したり、2つのカウント値の差を計算する関数です。
freerun_ct_convert_msec()
uint32_t freerun_ct_convert_msec(uint32_t ct, uint32_t* dec_part = nullptr)
FRWTのカウント値ct
をミリ秒に変換します。dec_part
を指定した場合は、1/10 の桁の値を 0..9 で設定します。
freerun_ct_diff()
int32_t freerun_ct_diff(uint32_t val_past, uint32_t val_now)
カウント値同士を差を計算します。基本的にはval_now - val_past
の値ですが、カウンタが最大値から0に戻った場合を考慮して計算します。カウンタの最大値の半分までの時間差が計算可能で、val_past
の方が古い場合は、正の値を戻します。
freerun_ct_diff_msec()
int32_t freerun_ct_diff_msec(int32 vdiff)
freerun_ct_diff()
で得られるカウンタ差分vdiff
をミリ秒に変換します。
freerun_ct_diff_usec()
int32_t freerun_ct_diff_usec(int32 vdiff)
int32_t freerun_ct_diff_usec(uint32_t val_past, uint32_t val_now)
freerun_ct_diff()
で得られるカウンタ差分値vdiff
またはval_past
,val_now
により計算されるカウンタ差分をマイクロ秒に変換します。
- 計算上int32_t型の計算による桁溢れが発生します(およそ2000秒を超えるような場合)。
4.2.11 - mwf_periph_wwdt - WWDT
mwf_periph_wwdt - WWDT
ウォッチドッグタイマーを利用するため手続きをまとめたペリフェラルオブジェクトthe_wwdt
を実装しています。
TWENETでは暗黙に使用されますので、ユーザプログラムでの初期化は不要です。
コード例
void setup_func() {
mwf::gobal_init_wwdt_manager();
the_wwdt.init(); // timeout in 4000ms approx.
}
// in some function called periodically (e.g. invoked by SysTick Timer.)
void do_every_tick() {
the_wwdt.refresh();
}
class mwf::periph::wwdt
global_init_wwdt_manager(), global_deinit_wwdt_manager()
static void global_init_wwdt_manager();
static void global_deinit_wwdt_manager();
the_wwdt
クラスオブジェクトの生成と破棄を行います。
init(), deinit()
void init(uint32_t u32ms = 0);
void deinit();
ウォッチドッグタイマーを初期化・停止(※1)します。
- 初期化時のパラメータ
u32ms
はタイムアウトをミリ秒(ms)で指定します。0
または省略したときは4000msとなります。 - ※1 ハードウェアの制約上、一度実行したウォッチドッグタイマーは停止しません。
deinit()
はライブラリ手続きとして用意しています。(タイマーの再始動時などにdeinit()
を実行してからinit()
を再度呼び出す)
set_timeout()
void set_timeout(uint32_t u32ms);
ウォッチドッグタイマーのタイムアウトまでの時間を変更します。u32ms
にはタイムアウト時間をミリ秒(ms)で指定します。
u32ms
の妥当性の検証はしません。init()
では0
を規定値としていましたが、本関数で0
を与えた場合の振る舞いは未定です。
refresh()
void refresh();
ウォッチドッグタイマーのタイムアウトまでに必ず呼び出すリフレッシュ関数です。
class mwf::periph::wwdt (sys_ev_handler)
on_sleep()
WWDTの停止処理を行います。
on_wakeup()
WWDTの始動処理を行います。
- スリープ前に稼働状態の場合は、WWDTを再度稼働させます。
4.2.12 - class tick_counter - Stop Watch
class tick_counter - Stop Watch
msec, usec 領域のごく短い処理時間を計測するために用います。マイコンのハードウェアのカウント機能を用いています。
本ライブラリコードについては、十分な確認の上、実験的な利用にとどめておくことを推奨します。最小30usec程度の単位での計測でよい場合は、ウェイクアップタイマーのカウント値が簡便です。
CoreDebug->DEMCR
,DWT
レジスタを制御します。- これらレジスタは一般に広く利用することを目的に紹介されているものではないと考えられます。開発中の一時的な時間計測等の利用では大きな問題を経験しないと考えられますが、最終的な運用段階でのファームウェアでの利用については推奨しません。
同時に複数の
tick_counter
オブジェクトを構築することが可能です- 利用するカウント機能は一つで、オブジェクト間で機能を共有します。
- 最初のオブジェクト構築でカウント機能を動作させ、すべてのオブジェクト破棄時にカウント機能を停止させます。
例:
#include <mwf_stop_watch.hpp>
void some_func() {
...
// 計測開始1
mwf::periph::tick_counter sw;
sw.lap(); // 計測開始1(直前の sw 構築時にも lap() は呼ばれるが、より厳密に処理の直前に lap() を呼び出す
... // 計測したい処理
sw.lap(); // 計測終了1
// 値の表示(計測開始1~計測終了1)
PRINTF("%dusec", sw.get_us());
// 次の処理
sw.lap(); // 計測開始2
... // 計測したい処理
sw.lap(); // 計測終了2
// 値の表示(計測開始2~計測終了2)
PRINTF("%dusec", sw.get_us());
}
_start_counter(), _stop_counter()
static void _start_counter();
static void _stop_counter();
CoreDebug機能を用い、カウントタイマーの開始と停止を行います。
tick_counter()
コストラクタです。他に構築されたオブジェクトがなければカウンターを開始し、また、lap() を呼び出し計測を開始します。
~tick_couter()
デストラクタです。すべてのクラスオブジェクトが破棄された時点でカウンターを停止します。
lap()
直前のカウント値を退避し、呼び出された時点でのカウント値を保存します。
経過時間は get_us()
により得ます。
4.2.13 - mwf-utils - utils
mwf_utils
その他ユーティリティ。
prepare_object()
template <class T>
static inline std::unique_ptr<T>& prepare_object(std::unique_ptr<T>& spobj, bool b_construct_if_null = true) {
if (!spobj && b_construct_if_null) {
spobj.reset(new T());
}
return spobj;
}
スマートポインタstd::unique_ptr<>
のオブジェクトを参照します。オブジェクトが構築されていない場合は new T()
により構築します。
get_value_if()
// 関数などから値を得て、その値を用いて処理をすすめる場合
int v = some_func();
if (v != -1) {
// v の値を用いてなにか処理をする
printf("%d", v);
}
// 以下のように書き換える
if (auto x = get_value_if::ne(some_func(), -1)) {
printf("%d", x.value());
}
上記の例のように、関数の戻り値をある条件の場合に利用するときの記述を、if節中の変数宣言を用いて記述するためのユーティリティクラスです。
上記の例では get_value_if::ne()
を用い、1つ目のパラメータは戻り値をもった関数呼び出し、2つ目のパラメータは比較する値を指定します。この場合 some_func()
の戻り値が -1
でない場合に if 節の中が評価されます。1つ目のパラメータと2つ目のパラメータの型は同じでなければなりません。
判定式により eq
, ne
, lt
, le
, gt
, ge
が利用できます。
get_value_if::xx() (T は型) | 判定式 | |
---|---|---|
eq(T lhs, const T rhs) | (lhs == rhs) | 値が同じであれば true |
ne (T lhs, const T rhs) | (lhs != rhs) | 値が違っていれば true |
lt (T lhs, const T rhs) | (lhs < rhs) | 値の比較、より小さい値なら true |
le (T lhs, const T rhs) | (lhs <= rhs) | 値の比較、以下なら true |
gt (T lhs, const T rhs) | (lhs > rhs) | 値の比較、より大きい値なら true |
ge (T lhs, const T rhs) | (lhs >= rhs) | 値の比較、以上なら true |
※ T
は型を示します (template 構文の型パラメータ)
4.3 - TWENETutils - TWENET ユーティリティ
TWENETutils - TWENET ユーティリティ
このライブラリは一般的なアルゴリズムやペリフェラルの手続きなどが含まれます。libTWENETutils.a に相当します。
- TWELITE NET API リファレンス「Utils リファレンス、他」参照
4.3.1 - utils.h
utils.h
utils.h をインクルードすることで利用できるマクロ・関数を紹介します。
S_OCTET(x)
1バイトをメモリを書き込む。
uint8 *q = &sTx.au8Data[0];
S_OCTET(0x12);
S_BE_WORD(0x1234);
S_BE_DWORD(0x12345678);
uint8 *q
をローカル変数として宣言しておき、データを読み込みたい領域のポインタとしておく。代入演算子の評価後 q++ が実行される。
S_BE_WORD(x)
2バイトをメモリを書き込む。
uint8 *q = &sTx.au8Data[0];
S_OCTET(0x12);
S_BE_WORD(0x1234);
S_BE_DWORD(0x12345678);
uint8 *q をローカル変数として宣言しておき、データを読み込みたい領域のポインタとしておく。代入演算子の評価後 q+=2 が実行される。
BE はビッグエンディアン、LE はリトルエンディアン。
S_BE_DWORD(x)
4バイトをメモリを書き込む。
uint8 *q = &sTx.au8Data[0];
S_OCTET(0x12);
S_BE_WORD(0x1234);
S_BE_DWORD(0x12345678);
uint8 *q
をローカル変数として宣言しておき、データを読み込みたい領域のポインタとしておく。代入演算子の評価後 q+=4 が実行される。
BE はビッグエンディアン、LE はリトルエンディアン。
G_OCTET()
1バイトメモリを読み込み uint8 型の変数に値を格納する。
uint8 *p = &sRx.au8Data[0];
uint8 u8data1 = OCTET();
uint16 u16data2 = G_BE_WORD();
uint32 u32data3 = G_BE_DWORD();
uint8 *p
をローカル変数として宣言しておき、データを読み込みたい領域のポインタとしておく。=
演算子の評価後 p++
が実行される。
G_BE_WORD()
2バイトメモリを読み込み uint16 型の変数に値を格納する。
uint8 *p = &sRx.au8Data[0];
uint8 u8data1 = OCTET();
uint16 u16data2 = G_BE_WORD();
uint32 u32data3 = G_BE_DWORD();
uint8 *p
をローカル変数として宣言しておき、データを読み込みたい領域のポインタとしておく。=
演算子の評価後 p+=2
が実行される。
BE はビッグエンディアン、LE はリトルエンディアン。
G_BE_DWORD()
1バイトメモリを読み込み uint8 型の変数に値を格納する。
uint8 *p = &sRx.au8Data[0];
uint8 u8data1 = OCTET();
uint16 u16data2 = G_BE_WORD();
uint32 u32data3 = G_BE_DWORD();
uint8 *p
をローカル変数として宣言しておき、データを読み込みたい領域のポインタとしておく。=
演算子の評価後 p+=4
が実行される。
BE はビッグエンディアン、LE はリトルエンディアン。
ENCODE_VOLT(x)
2000~3600 の値を 8bit 値に変換します。
- 1.95~2.80V は 5mV 刻み
- 2.81~3.65V は 10mV 刻み
// utils.h の定義
#define ENCODE_VOLT(m) \
(m < 1950 ? 0 : \
(m > 3650 ? 255 : \
(m <= 2802 ? ((m-1950+2)/5) : ((m-2800-5)/10+171)) ))
...
uint16 u16Volt = 2860;
uint8 u8Volt_enc = ENCODE_VOLT(u16Volt);
uint16 u16Volt_dec = DECODE_VOLT(u8Volt_Enc);
2000~2800 の値は 5 刻み、2800~は10 刻みで 8bit 値に割り当てます。
DECODE_VOLT(x)
ENCODE_VOLT() により得られた8bit値を元の値に戻します。
- 1.95~2.80V は 5mV 刻み
- 2.81~3.65V は 10mV 刻み
// utils.h の定義
#define DECODE_VOLT(i) \
(i <= 170 ? (1950+i*5) : (2800+(i-170)*10) )
...
uint16 u16Volt = 2860;
uint8 u8Volt_enc = ENCODE_VOLT(u16Volt);
uint16 u16Volt_dec = DECODE_VOLT(u8Volt_Enc);
2000~2800 の値は 5 刻み、2800~は10 刻みで 8bit 値に割り当てます。
vPortAsInput(c)
ポートcを入力に設定する
#define vPortAsInput(c) vAHI_DioSetDirection(1UL << (c), 0)
vPortAsOutput(c)
ポートcを出力に設定する
#define vPortAsOutput(c) vAHI_DioSetDirection(0, 1UL << (c))
vPortSetHi(c)
ポートcをHi状態にする
#define vPortSetHi(c) vAHI_DioSetOutput(1UL << (c), 0)
vPortSetLo(c)
ポートcをLo状態にする
#define vPortSetLo(c) vAHI_DioSetOutput(0, 1UL << (c))
vPortSet_TrueAsLo(c, s)
ポート c を s が TRUE なら Lo, FALSE なら Hi に設定する
#define vPortSet_TrueAsLo(c, s) vAHI_DioSetOutput((s) ? \
0 : 1UL << (c), s ? 1UL << (c) : 0)
bPortRead(c)
ポート c を読み出す。Loレベルなら TRUE が返る
#define bPortRead(c) ((u32AHI_DioReadInput() & \
(1UL<<(c))) ? FALSE : TRUE)
u32PortReadBitmap()
ポート c を読み出す。Loレベルなら TRUE が返る。
#define u32PortReadBitmap() (u32AHI_DioReadInput())
ビットマップの1がHi,0がLoとなります。
bPortCheckBitmap(bitmap, c)
読みだしたビットマップのポート c に対応するビットがLoレベルならTRUEを返す。
#define bPortCheckBitmap(bitmap, c) \
(bitmap & (1UL<<(c))) ? FALSE : TRUE)
vPortDisablePullup(c)
ポート c のプルアップを停止する。
#define vPortDisablePullup(c) vAHI_DioSetPullup(0x0, 1UL << (c))
_C
switch でスコープを定義したい場合 _C { … } と記述している。
#define _C if(1)
// for example
switch(c) {
case 1:
_C {
uint8 u8work;
; // work
} break;
default:
}
LB
改行コード (CRLF) 文字列です。
2バイトの文字列リテラルですので、vPutChar() では利用できません。
#define LB "\r\n"
vWait()関数
ループによる時間待ちを行います。
void vWait(uint32 c) {
static volatile uint32 u32ct = 0;
while (c-- > 0)
u32ct++;
}
処理内容はソースコードの通りです。
vAnalogueConfig(), vAnalogueDisable()
ADC機能の初期化と停止を行う手続きをまとめています。既存コードの互換性を目的としています。
void vAnalogueConfig(void) {
#if defined(JN516x)
if (!bAHI_APRegulatorEnabled()) {
vAHI_ApConfigure(E_AHI_AP_REGULATOR_ENABLE,
E_AHI_AP_INT_DISABLE,
E_AHI_AP_SAMPLE_4,
E_AHI_AP_CLOCKDIV_1MHZ,
E_AHI_AP_INTREF);
while (!bAHI_APRegulatorEnabled())
;
}
#elif defined(CPU_JN518X)
#endif
void vAnalogueDisable(void) {
#if defined(JN516x)
vAHI_ApConfigure(E_AHI_AP_REGULATOR_DISABLE,
E_AHI_AP_INT_DISABLE,
E_AHI_AP_SAMPLE_4,
E_AHI_AP_CLOCKDIV_1MHZ,
E_AHI_AP_INTREF);
#elif defined(CPU_JN518X)
#endif
}
その他マクロ定義
// 64bit mac address
#define MAC_EXT_ADDR_TO_64BIT(ext) ((uint64)(ext.u32L) | (((uint64)(ext.u32H)) << 32))
// TIME COMPARE
#define u32TimeDiff(ref, now) (now - ref < 0x7FFFFFFF ? now - ref : )
// IO settings
#define vPortSetHi(c) vAHI_DioSetOutput(1UL << (c), 0)
#define vPortSetLo(c) vAHI_DioSetOutput(0, 1UL << (c))
#define vPortSet_TrueAsLo(c, s) vAHI_DioSetOutput((s) ? 0 : 1UL << (c), s ? 1UL << (c) : 0)
#define vPortAsInput(c) vAHI_DioSetDirection(1UL << (c), 0)
#define vPortAsOutput(c) vAHI_DioSetDirection(0, 1UL << (c))
#define bPortRead(c) ((u32AHI_DioReadInput() & (1UL<<(c))) ? FALSE : TRUE) // Lo as True
#define u32PortReadBitmap() (u32AHI_DioReadInput())
#define bPortCheckBitmap(bitmap, c) ((bitmap & (1UL<<(c))) ? FALSE : TRUE)
#define vPortDisablePullup(c) vAHI_DioSetPullup(0x0, 1UL << (c))
#if defined(JN516x) || defined(CPU_JN518X)
#define PORT_KIT_SW1 2
#define PORT_KIT_SW2 3
#define PORT_KIT_SW3 10
#define PORT_KIT_SW4 9
#define PORT_KIT_LED1 17
#define PORT_KIT_LED2 13
#define PORT_KIT_LED3 12
#define PORT_KIT_LED4 11
#endif
#define PORT_KIT_SW1_MASK (1UL << PORT_KIT_SW1)
#define PORT_KIT_SW2_MASK (1UL << PORT_KIT_SW2)
#define PORT_KIT_SW3_MASK (1UL << PORT_KIT_SW3)
#define PORT_KIT_SW4_MASK (1UL << PORT_KIT_SW4)
#define PORT_KIT_SW_ALL2_MASK (PORT_KIT_SW1_MASK | PORT_KIT_SW2_MASK)
#define PORT_KIT_SW_ALL4_MASK (PORT_KIT_SW1_MASK | PORT_KIT_SW2_MASK | PORT_KIT_SW3_MASK | PORT_KIT_SW4_MASK)
#define PORT_KIT_LED1_MASK (1UL << PORT_KIT_LED1)
#define PORT_KIT_LED2_MASK (1UL << PORT_KIT_LED2)
#define PORT_KIT_LED3_MASK (1UL << PORT_KIT_LED3)
#define PORT_KIT_LED4_MASK (1UL << PORT_KIT_LED4)
#define PORT_KIT_LED_ALL2_MASK (PORT_KIT_LED1_MASK | PORT_KIT_LED2_MASK)
#define PORT_KIT_LED_ALL4_MASK (PORT_KIT_LED1_MASK | PORT_KIT_LED2_MASK | PORT_KIT_LED3_MASK | PORT_KIT_LED4_MASK)
// UART related
#define WAIT_UART_OUTPUT(P) SERIAL_vFlush(P)
// IO clock (on JN514x, IO runs at 16Mhz regardless of CPU clock.
#if defined(JN516x)
#define u32IO_FREQ_HZ 16000000UL
#elif defined(CPU_JN518X)
//#define u32IO_FREQ_HZ 32000000UL
#define u32IO_FREQ_HZ 16000000UL
#endif
void vAnalogueConfig(void);
void vAnalogueDisable(void);
void vWait(uint32 c);
4.3.2 - Timerライブラリ
Timer
ライブラリを紹介します。Timerライブラリ
tsTimerContext
Timer
ライブラリで用いる設定用の構造体。
- 0クリアすること。
- 静的に確保すること。
型 | 名前 | 解説 |
---|---|---|
uint8 | u8Device | タイマーデバイスを指定する (E_AHI_DEVICE_TIMER0 .. 4)。 |
uint16 | u16Hz | タイマー周波数を Hz で指定する。 |
uint8 | u8PreScale | 16Mhz クロックに対するプリスケールを設定する。 |
bool_t | bPWMOut | TRUE なら PWM 出力を行う。 |
bool_t | bDisableInt | TRUE なら割り込みを禁止する。 |
vTimerConfig()
解説
Timer
の初期化を行う。
引数
型 | 名前 | 詳細 |
---|---|---|
tsTimerContext | psTC | タイマー設定の構造体。 |
戻り値
なし
サンプル
tsTimerContext sTimerApp; // global or static allocation
// set 64ticks/sec
memset(&sTimerApp, 0, sizeof(tsTimerContext));
sTimerApp.u8Device = E_AHI_DEVICE_TIMER0;
sTimerApp.u16Hz = 64;
sTimerApp.u8PreScale = 4; // 15625ct@2^4
vTimerStart()
解説
Timer
を開始する。
本関数は、既に開始済みのTimer
についても呼び出し可能です。Duty 比の変更を行う場合などに利用します。
引数
型 | 名前 | 詳細 |
---|---|---|
tsTimerContext | psTC | タイマー設定の構造体。 |
戻り値
なし
サンプル
// initialize and start
vTimerConfig(&sTimerApp); // initialize
vTimerStart(&sTimerApp); // start
// change duty
sTimerPWM.u16Duty = 256; // set new duty ratio
vTimerStart(&sTimerPWM); // just start again to change duty
vTimerStop()
解説
Timer
の動作を停止する。
引数
型 | 名前 | 詳細 |
---|---|---|
tsTimerContext | psTC | タイマー設定の構造体。 |
戻り値
なし。
サンプル
// just stop the timer
vTimerStop(&sTimerApp);
...
// restart
vTimerStart(&sTimerApp);
...
// now, disable timer completely
vTimerStop(&sTimerApp);
vTimerDisable(&sTimerApp);
vTimerDisable()
Timer
を破棄する。
引数
型 | 名前 | 詳細 |
---|---|---|
tsTimerContext | psTC | タイマー設定の構造体。 |
戻り値
なし
サンプル
// just stop the timer
vTimerStop(&sTimerApp);
...
// restart
vTimerStart(&sTimerApp);
...
// now, disable timer completely
vTimerStop(&sTimerApp);
vTimerDisable(&sTimerApp);
4.3.3 - fprintf ライブラリ
fprintf
の簡易的な実装です。fprintf ライブラリ
fprintf
の簡易的な実装です。
TWENETmcu/printf
の利用を推奨します参考
TWENETmcu/printf
-printf
ライブラリ(オープンソース)TWENETstgs
-TWE_fprintf()
など
tsFILE
vfPrintf()
vPutChar()
で指定する出力先を定義した構造体。
メンバー
型 | 名前 | 詳細 |
---|---|---|
uint8 | u8Device | シリアルポート (E_AHI_UART_0 または E_AHI_UART_1 を指定する) |
bool_t (*) (uint8 u8Device, uint8 u8Char) | bPutChar | 出力用の関数ポインタ。SERIAL ライブラリ用には SERIAL_bTxChar() が準備されているので、これを指定する。 |
{% hint style=“info” %}
SERIAL_bTxChar()
は、u8Char
として渡されたバイトを SERIAL
ライブラリ内の FIFO キューに投入します。
独自に出力関数を準備することで、UART 以外への文字列の出力にも利用できます。 {% endhint %}
サンプルコード
#include "serial.h"
#include "fprintf.h"
tsFILE sSerStream;
tsSerialPortSetup sSerPort;
void vSerialInit(uint32 u32Baud, tsUartOpt *pUartOpt) {
// initialize sSerPort
...
SERIAL_vInit(&sSerPort);
// for vfPrintf()
sSerStream.bPutChar = SERIAL_bTxChar;
sSerStream.u8Device = E_AHI_UART_0;
}
void vSerOut() {
vfPrintf(&sSerStream, "HELLO!");
}
以下は、キャラクタ LCD の出力コードとして利用した一例です。
#include "serial.h"
#include "fprintf.h"
tsFILE sLcdStream;
// handle LCD display
PUBLIC bool_t LCD_bTxChar(uint8 u8Device, uint8 u8Data) {
int i;
switch (u8Data) {
case '\n':
...
}
void vInitHardware() {
/* Initialise the LCD */
vLcdReset(3, 0);
/* register for vfPrintf() */
sLcdStream.bPutChar = LCD_bTxChar;
sLcdStream.u8Device = 0xFF;
}
void vSomeOutput() {
vfPrintf(&sLcdStream, "Hello World!\n");
}
vfPrintf()
解説
tsFILE
構造体の示す出力先(UART)に printf
書式にて出力する。
引数
型 | 名前 | 詳細 |
---|---|---|
tsFILE* | psStream | 出力先 |
const char * | pcFormat | 出力書式 |
… | 可変引数 |
対応する書式
s | 文字列 |
---|---|
d | 整数(32bitまで) |
u | 符号なし整数(32bitまで) |
x | 16進数。a-f は小文字。 |
X | 16進数。A-F は大文字。 |
b | bit列 |
戻り値
なし。
サンプル
void cbToCoNet_vMain(void) {
while (!SERIAL_bRxQueueEmpty(sSerPort.u8SerialPort)) {
int16 i16Char;
i16Char = SERIAL_i16RxChar(sSerPort.u8SerialPort);
vfPrintf(&sSerStream, "\n\r## [%c] --> ", i16Char);
SERIAL_vFlush(sSerStream.u8Device);
...
}
}
vPutChar()
解説
tsFILE
構造体の示す出力先(UART)に1バイト出力する。
引数
型 | 名前 | 詳細 |
---|---|---|
tsFILE* | psStream | 出力先 |
uint8 | u8Char | 出力バイト |
戻り値
なし
サンプル
#define IS_ASC(c) ((c) >= 0x20 && (c) <= 0x7e)
void cbToCoNet_vRxEvent(tsRxDataApp *pRx) {
uint8 u8i;
vfPrintf(&sSerStream, LB"RX(len=%d):[", pRx->u8Len);
for (i = 0; i < pRx->u8Len; i++) {
uint8 c = pRx->auData[i];
vPutChar(&sSerStream, IS_ASC(c) ? c : '.');
}
}
4.4 - TWENETcmpt - AHI互換レイヤー
TWENETcmpt - AHI互換レイヤー
AHIライブラリの互換性を目的としたライブラリです。
- TweApps のビルド、動作を目的としており包括的な互換性を達成することは目的としてません。
- 実装には TWENETmwfライブラリ(fslライブラリにより実装されたC++ライブラリ)を用いています。
以下には、互換レイヤーの諸定義について留意事項を記述しています。
リンク | 内容 |
---|---|
共通・その他 | 諸関数 |
ADC | ADC関連のAPI |
GPIO | GPIO関連のAPI |
PWM | PWM関連のAPI |
I2C (SMBus) | I2C関連のAPI |
SPI | SPIバス |
Random | 乱数生成 |
UART | UART関連のAPI |
WDT | ウォッチドッグタイマー |
WTIMER | ウェイクタイマー、FRWT |
OnChipTemp | チップ内温度センサー(ADC利用) |
4.4.1 - AHI互換関数
AHI互換関数
AHI 関数群の一部について、ソースコードの互換を目的として実装しています。
- 本ライブラリの実装は、 fsl ドライバの手続きをまとめた TWENETmwf ライブラリを用いて実装されています。
- この実装は完全な互換性を保つことを目的とはしていません。
- 独自拡張を行った関数は関数名に
_MW
を付記しています。 - 本書記述時点で判明している留意点などを記載します。
- 内部の実装は予告なく変更される場合があります。
- 解説中のパラメータについても、留意が必要な部分のみ記述しています。省略部分は、原典の AHI ライブラリマニュアルを参照ください。
- TWELITE GOLD 特有の話題や FSL ライブラリ、またマイコンコアなどの振る舞いについては、NXP社のJN5189半導体マニュアル及び TWENETmcu ライブラリの実装を参照してください。
以下には AHI 互換関数について記載しています。SPI, I2C などは別ファイルに記載しているものもあります。
一般関数
u32AHI_Init()
uint32 u32AHI_Init();
本来AHIライブラリの初期化を行いますが、本ライブラリでは一部の変数の初期化のみを実施します。
bAHI_SetClockRate(), u8AHI_GetSystemClkRate()
bool_t bAHI_SetClockRate(uint8 u8clk_code);
uint8 u8AHI_GetSystemClkRate();
CPUのクロック速度を設定または設定値の取得を行います。
設定されるクロックは以下のようになります。TWELITE BLUE/REDの設定とは大きく異なるため注意が必要です。
u8clk_code | TWELITE BLUE/RED | TWELITE GOLD |
---|---|---|
0 | 4Mhz | 12Mhz |
1 | 8Mhz | 12Mhz |
2 | 16Mhz | 32Mhz |
3 | 32Mhz | 48Mhz |
4.. | 設定有り | 無視される |
kFROM1M_to_MAIN_CLK
といったクロックも fsl ライブラリ内では設定可能ですが、動作に大きな難があるため設定できないようにしています。- デバッガを利用するような場合は、クロック変更に支障が出る場合があります。
- 規定値は 2、32Mhz (TWELITE GOLD) です。(参考:TWELITE BLUE/REDでは 16MHz)
bAHI_Set32KhzClockMode()
bool_t bAHI_Set32KhzClockMode(uint8 u8mode);
なにもしません。
vAHI_CpuDoze()
static inline void vAHI_CpuDoze() { __WFI(); }
割り込み待ち低電力待機 DOZE 状態に入ります。TWELITE-GOLD では WFI (割り込み待ち) を発効します。
vAHI_SwReset()
static inline void vAHI_SwReset() { NVIC_SystemReset(); }
リセットを行います。
電源関係
u16AHI_PowerStatus()
uint16 u16AHI_PowerStatus();
本関数では、以下のビットマップを報告します。
ビット | 解説 |
---|---|
bit0 | スリープからの復帰時に 1 |
bit1 | RAMが保持されていた場合に 1 |
POR 時は 0
、通常のRAM保持スリープからの復帰は 3
になります。
vAHI_BrownOutConfigure()
static inline void vAHI_BrownOutConfigure(
uint8 const u8VboSelect,
bool_t const bVboRstEn,
bool_t const bVboEn,
bool_t const bVboIntEnFalling,
bool_t const bVboIntEnRising) { ; } // DUMMY FUNC
コンパイルエラー回避のための定義です。この関数は何もしません。
スリープについて
void ToCoNet_vSleep(uint8 u8Device, uint32 u32Periodms, bool_t bPeriodic, bool_t bRamOff)
スリープは TWENET C ライブラリでは ToCoNet_vSleep()
関数を用います。
※ mwxライブラリでは the_twelite.sleep()
を用います。
bRamOff
はTRUEを指定した場合、全てのRAMセグメントを保持しない形でスリープを行います。なお、この場合もJN518x FSL ライブラリ定義のPM_POWER_DOWN
を用いPM_DEEP_DOWN
は使用しません。
スリープの失敗について(TWELITE GOLD)
TWELITE GOLD では、スリープ遷移の半導体ライブラリ中の手続き(POWER_EnterPowerMode()
)が稀に失敗し、スリープが行われません。そのため以下の対処を行っています。
- 半導体ライブラリの手続き失敗時は関数呼び出しからそのまま抜けてしまうが、100usec 相当(
DelayLoopN(100)
)のループ待ちを行った後、再度スリープの手続きを実行します。 - 上記を3回試行して失敗した場合は
ToCoNet_vSleep()
は無限ループを呼び出し、通常はウォッチドッグタイマーによるリセットが発生します。当社では、2回または3回の再試行は確認されていませんが、念のため3回までとしています。 - 上記スリープ手続きが行われた場合、スリープ復帰後
extern uint8 g_twenet_power_down_fails;
の値が0
以外であれば、上記の再試行が行われていたことを示します。但し、ウォッチドッグタイマーによるリセット時はこの変数は初期化されます。
内部処理用
u32AppApiInit()
uint32
u32AppApiInit(PR_GET_BUFFER prMlmeGetBuffer,
PR_POST_CALLBACK prMlmeCallback,
void *pvMlmeParam,
PR_GET_BUFFER prMcpsGetBuffer,
PR_POST_CALLBACK prMcpsCallback,
void *pvMcpsParam);
AppQAPIの初期化処理を行います。
vAHI_RegEvMgr_MW()
void vAHI_RegEvMgr_MW();
TWENETmwfライブラリでのクラスオブジェクトを管理するための管理オブジェクト(mwf::the_sys_ev_manager
)を構築します。
vAHI_OnWakeup_MW(), vAHI_OnWakeupRamOff_MW()
void vAHI_OnWakeup_MW(bool_t b_init_2nd);
void vAHI_OnWakeupRamOff_MW(bool_t b_init_2nd);
起床時に実施する手続きです。TWENETmcuのtwenet_main.cの処理を参照してください。
- TWENETmwf ライブラリ内のクラスオブジェクトの起床時処理
mwf::the_sys_ev_manager->on_wakeup()
を行います。 vAHI_DioOnWakeup_MW()
を呼び出します。起床要因のピンを保存します。b_init_2nd
がFALSEの場合は始動初期の段階の呼び出しで、TRUEの場合はある程度の初期化が終わった時点(cbAppWarmStart(TRUE)
呼び出し前)での呼び出しになります。
vAHI_OnWakeupRamOff_MW()
はRAM非保持スリープ復帰時に呼び出されます。
b_init_2nd
がFALSEの場合は始動初期の段階の呼び出しで、TRUEの場合はある程度の初期化が終わった時点(cbAppWarmStart(TRUE)
呼び出し後)での呼び出しになります。
vAHI_OnSleep_MW()
vAHI_OnSleep_MW();
スリープ前に実施する手続きです。
- TWENETmwf ライブラリ内のクラスオブジェクトのスリープ前処理
mwf::the_sys_ev_manager->on_sleep()
を行います。 vAHI_DioOnSleep_MW()
を呼び出します。DIO起床ピンの設定をします。
vAHI_DMAEnable_MW(), vAHI_DMADisable_MW()
void vAHI_DMAEnable_MW();
void vAHI_DMADisable_MW();
DMA機能の有効化と無効化を行います。
vAHI_DMADisable_MW()
は何も実行しません。
4.4.2 - ADC関連のAHI関数と解説
ADC
AHI の ADC(アナログディジタル変換) 関連の一部について、ソースコードの互換を目的として実装しています。
- この実装は完全な互換性を保つことを目的とはしていません。
- 本書記述時点で判明している留意点などを記載します。
- 内部の実装は予告なく変更される場合があります。
概要
ADCのハードウェア仕様はモデルによって違いがあります。
TWELITE BLUE | TWELITE RED | TWELITE GOLD | |
---|---|---|---|
ビット数 | 10bit | 10bit | 12bit |
フルスケール | 2470mV | 2470mV | 3600mV |
チャネル数 (API未サポート) | 4 | 4 (2) | 4 (2) |
本ライブラリでは ADC0..3 までの4チャネルと Vcc を利用するための処理を記述しています。ただし、変換時間や変換データの互換性まではライブラリでは実施せず、アプリケーションソースで調整する前提です。
なお6ピンまでの変換や、複数チャネルをまとめた ADC、AHIライブラリでは対応せずmwf::the_adc
を直接利用するようにしてください。
関連:オンチップ温度センサー
ピン
PIO | 備考 | |
---|---|---|
ADC0 | 15 | |
ADC1 | 14 | DIO8と共用 |
ADC2 | 16 | |
ADC3 | 17 |
AHIcmpt_ADC.cpp
本ライブラリ内では、TWELITE BLUE/RED の AHI ライブラリとの違いについて記述します。APIの仕様については、AHIライブラリマニュアルも参照ください。
vAHI_ApConfigure()
void vAHI_ApConfigure(
bool_t bAPRegulator,
bool_t bIntEnable,
uint8 u8SampleSelect,
uint8 u8ClockDivRatio,
bool_t bRefSelect);
ADCの初期化(mwf::the_adc
オブジェクトの構築と the_adc->init()
初期化)を行います。
bAPRegulator
をTRUEに指定するとADCを有効化します。FALSEにした場合はADCを無効化します。bIntEnable
をTRUEに指定するとADC割り込みが有効になります。u8SampleSelect
とbRefSelect
は無視されます。u8ClockDivRatio
も現時点では設定が反映されません。bAHI_APRegulatorEnabled()
を用いたアナログ回路の安定化待ち処理は必要です。
bAHI_APRegulatorEnabled()
bool_t bAHI_APRegulatorEnabled(void)
ウェイクタイマを用いたFRWTを動作していない場合は(Cライブラリでは標準)、固定時間の待ち処理を行います(300usec)。この場合vAHI_ApConfigure()
呼び出し直後に本関数を呼び出すことを推奨します。相応の時間経過後であっても固定時間の待ち処理を行います。
FRWTを有効化している場合は、タイマカウント値に基づき、必要な待ち処理を行います。相応の時間経過後は、本関数内の待ち処理は行いません。
vAHI_APRegisterCallback()
void vAHI_APRegisterCallback(PR_HWINT_APPCALLBACK prApCallback);
割り込みハンドラを登録します。ADC完了時に呼び出されます。
vAHI_AdcEnable()
void void vAHI_AdcEnable(
bool_t bContinuous,
bool_t bInputRange,
uint8 u8Source);
ADCの変換設定を行います。
bContinuous
を選択すると連続変換しますが、内部的な割り込みが変換都度発生するため、パフォーマンス面で注意が必要です。bInputRange
を指定しても、そういったハードウェア機能がないため反映されません。- この呼出時に
u8Source
に対応したピンがADC用として設定されます。 vAHI_ApConfigure()
実行後にbAHI_APRegulatorEnabled()
を未実行で待ち処理が実行されなかった場合は、本呼び出しにて待ち処理を行います。
vAHI_AdcDisable()
void vAHI_AdcDisable(void);
ADCを停止します。
vAHI_AdcStartSample()
void vAHI_AdcStartSample(void);
ADCの変換開始を行います。
- 原則として初期化時は入力状態ですが、厳密には TWENETmcu ライブラリの pinmux.c
BOARD_InitPins()
の初期化状態が規定値になります。
bAHI_AdcPoll()
bool_t bAHI_AdcPoll(void);
ADC完了待ちを行うポーリング待ち処理while(bAHI_AdcPoll());
に使用します。
- ADC完了の割り込み後、本呼び出しは1度だけ FALSE を返します。
u16AHI_AdcRead(), i16AHI_AdcRead_mv()
uint16 u16AHI_AdcRead(void);
int16 i16AHI_AdcRead_mv(void); // 非AHI独自関数
実行したADC値を読み出します。
u16AHI_AdcRead()
は ADC 値を 12bit (0..4095) で返します。エラー時は 0xffff
を戻します。i16AHI_AdcRead_mv()
は AHI ライブラリにはない独自関数で、ADC値を mV で返します。エラー時は-32768
を戻します。
s_adc_int_handler()
static void s_adc_int_handler(uint32_t a1, uint32_t a2);
AHIcmpt_ADC.cpp
で定義された静的関数で、ADC完了時に呼び出される割り込みハンドラとして、TWENETの AppQApi に割り込みを伝達します。
vAHI_APRegisterCallback()
にてコールバック関数が指定されいている場合は、呼び出されません。
実験的な実装
複数チャネル一括処理
// TWELITE GOLD 専用
// FSLドライバ機能を用いて複数チャネルのADC取得を一括で行う。
// ADC実行(パラメータはvAHI_AdcEnable()と同様)
void vAHI_AdcEnableSeq(
bool_t bContinuous,
bool_t bInputRange,
uint32 u32MaskSource);
// ADC値の読出し
uint16 u16AHI_AdcReadSeq(
uint8 u8Source
);
// ADC値の読出し (mV値にて)
int16 i16AHI_AdcReadSeq_mv(
uint8 u8Source
);
sensor_driver, adc.c, adc.h
sensor_driver
は既存のTWEAppsアプリケーションなどで利用される処理関数群で、センサー処理の抽象化するためのメカニズムを提供しています。adc.c
,.h
は、sensor_driver
でチップ内ADCを動作させるために、一連のコマンド発行、待ち、データ取得といった順序処理を記述したものです。なお TWENETmwx/sensors/legacy
以下には ADC 以外のいくつかのセンサー向けの実装が含まれます。
TWELITE BLUE/REDのプロジェクトをTWELITE GOLDに移行する場合は、App_Twelite/Common
に格納された調整済みのファイルを利用下さい。但し、プロジェクトごとに内容が違う場合があるため、修正等が必要になる場合があります。
ソース名 | 内容 |
---|---|
adc.c | adc処理部分 (ADC値の変換部分は TWELITE GOLD の値域に合わせている) |
adc.h | 定義部 |
sensor_driver.c | センサー処理抽象化部分 |
sensor_driver.h | 定義部 |
コード例
以下のコード中のコメントを参照してください。
#include "sensor_driver.h"
#include "adc.h"
tsObjData_ADC sObjADC; // ADC管理構造体(データ部)
tsSnsObj sADC; // ADC管理構造体(制御部)
int16 a1,a2,ab; // 結果格納用
...
// ADC 初期化
vSnsObj_Init(&sADC);
vADC_Init(&sObjADC, &sADC, TRUE);
vADC_WaitInit(); // ハード初期化待ちを行う
...
// ADC計測したいポートの指定(以下では電源電圧とADC1,2)
sObjADC.u8SourceMask = TEH_ADC_SRC_VOLT
| TEH_ADC_SRC_ADC_1 | TEH_ADC_SRC_ADC_2;
// ADC開始
vSnsObj_Process(&sADC, E_ORDER_KICK); // 開始の号令
// ADCの1チャネル処理が終わるのを待って(=E_AHI_DEVICE_ANALOGUE割り込み)
// vSnsObj_Process() を順次呼び出す。
void cbToCoNet_vHwEvent(uint32 u32DeviceId, uint32 u32ItemBitmap) {
switch (u32DeviceId) {
case E_AHI_DEVICE_ANALOGUE:
// ADC完了割り込み
vSnsObj_Process(&sADC, E_ORDER_KICK);
if (bSnsObj_isComplete(&sADC)) {
// 全チャネルの処理が終わった。
// 値は以下に格納される
a1=sObjADC.ai16Result[TEH_ADC_IDX_ADC_1]; // ADC1[mV]
a2=sObjADC.ai16Result[TEH_ADC_IDX_ADC_2]; // ADC2[mV]
ab=sObjADC.ai16Result[TEH_ADC_IDX_VOLT]; // 電源電圧[mV]
// ADC開始前の初期状態に戻す
vSnsObj_Process(&sADC, E_ORDER_KICK);
// 連続して実行する場合はもう一度E_ORDER_KICK
vSnsObj_Process(&sADC, E_ORDER_KICK);
}
break;
default:
break;
}
}
関数
vSnsObj_Init()
void vSnsObj_Init(tsSnsObj *pSnsObj)
センサー管理構造体を初期化します。vADC_Init()
の直前に呼び出します。
vADC_Init()
void vADC_Init(tsObjData_ADC *pData, tsSnsObj *pSnsObj, bool_t bInitAPR)
ADCの初期化を行います。tsObjData構造体(結果格納用)とtsSnsObj構造体(ADC管理)はあらかじめ用意しておきます。
- bInitAPRはTRUEの場合、ADCハードウェアの初期化を行います。ハードウェアの初期化には若干の時間が必要ですので、必ずvADC_WaitInit()を実行して初期化を待ちます。
vSnsObj_Process()
void vSnsObj_Process(tsSnsObj *pObj, teEvent eEv)
ADC処理の進捗させる。具体的には、ADCの1ポート分の変換完了するたびに本処理を呼び出す。
本処理中で、ADC値の取得と mV値への演算処理が行われ、tsSnsObj
構造体中に値が格納される。
本処理は、tsSnsObj
構造体で管理される状態遷移に対するイベント処理になる。本処理直後にbSnsObj_isComplete()
を呼び出し処理が完了したかを確認する。再び初期状態に戻すには、改めてE_ORDER_KICK
を引数として本処理を実行する(つまりADCを再度実行するには完了後にE_ORDER_KICK
を2回実行することになる)。
tsObjData_ADC
構造体
この構造体には、指定する ADC チャネル、結果として得られる電圧値が含まれます。
u8SourceMask
:ADC対象のポートを指定するビットマップ。指定したポートがADC対象となる。- TEH_ADC_SRC_VOLT : 電源電圧-TEH_ADC_SRC_ADC_1-4
: ADC1,2,3,4u8InputRangeMask
:ADC対象のポートのレンジ(0-Vrefまたは0-2Vref)を指定する。指定したポートは0-Vrefとなる。未指定の場合 0-2Vref となる。ai16Result[]
:ADC値を保存する構造体。結果はmV値として格納される。- TEH_ADC_IDX_VOLT : 電源電圧-TEH_ADC_IDX_ADC_1-4
: ADC1,2,3,4
4.4.3 - DIO (GPIO)関連のAHI関数と解説
DIO (GPIO)
AHI の DIO (GPIO) 関連の一部について、ソースコードの互換を目的として実装しています。
- この実装は完全な互換性を保つことを目的とはしていません。
- 本書記述時点で判明している留意点などを記載します。
- 内部の実装は予告なく変更される場合があります。
- 解説中のパラメータについても、留意が必要な部分のみ記述しています。省略部分は、原典の AHI ライブラリマニュアルを参照ください。
- 本解説で PIO と DIO という2つの用語が出てきます。
- PIO: TWELITE GOLD の使用半導体で定義されているピン番号で、FSLライブラリなどでは全てこのピン番号を用いる。
- DIO: TWELITE BLUE/RED での AHI API でも使用するピン番号です。当ライブラリでは TWELITE BLUE/RED のソースコードの互換性を保つために DIO から PIO の変換、またはその反対を行っています。
概要
ピンの割当については TWELITE BLUE/RED とは違うアーキテクチャになっています。ここでは TWELITE BLUE/RED で使用したピンを DIO0..19/DO0..1/ADC0…3、TWELITE GOLD の半導体でのピン名を PIO0..21 と記載します。ピンの詳細は、各モジュール利用の半導体データシートを参照ください。
- モジュール上のピンの対応が1:1にならない部分がある。
- PIO0 は DIO11 と DO0 で共用。
- PIO14 は DIO8 と ADC1 で共用。
- DIO割り込みについて、以下の相違点がある。
- DIO0..19まで独立した割り込みが可能であったが、そういった機能は存在しないため GINT (グループ割り込み) 機能を用いて、類似の動作を実現している。(他に独立した割り込みが可能な PINT という機能があるが4ポートまでの利用なので、本ライブラリでは使用していない)
- ハードウェアの割り込み検出は両エッジのみであるため、いずれかのエッジで内部割込みが発生する。
- 稼働中(スリープしていない)の場合は、割り込み発生後のピンの状態で AHI の割り込みハンドラを呼び出すか決めているため、両エッジであることは表面的に見えません。
- スリープ起床でのエッジは指定できません。
ピンの割当
DIO | DIO | PIO | 備考 |
---|---|---|---|
DIO0 | 0 | 16 | |
DIO1 | 1 | 17 | |
DIO2 | 2 | 18 | |
DIO3 | 3 | 19 | |
DIO4 | 4 | 7 | |
DIO5 | 5 | 6 | |
DIO6 | 6 | 8 | |
DIO7 | 7 | 9 | |
DIO8 | 8 | 14 | ADC1と共用 |
DIO9 | 9 | 12 | |
DIO10 | 10 | 4 | |
DIO11 | 11 | 0 | DO0と共用 |
DIO12 | 12 | 13 | |
DIO13 | 13 | 1 | |
DIO14 | 14 | 10 | |
DIO15 | 15 | 11 | |
DIO16 | 16 | 20 | |
DIO17 | 17 | 21 | |
DIO18 | 18 | 2 | |
DIO19 | 19 | 3 | |
DO0 (PROG) | 0 | DIO11と共用 | |
DO1 | 5 | ||
ADC2 | 14 | DIO8と共用 | |
ADC1 | 15 |
AHIcmpt_Dio.cpp - 定義・定数
定義
#define BOARD_GPIO_PORT_MAX_PIN_COUNT 22 // ピン数
#define BOARD_GPIO_PIN_TABLE_SIZE 24 // ピン数22を4の倍数で切り上げたもの
g_twenet_ioport_remap_by_PIOn[]
const uint8 g_twenet_ioport_remap_by_PIOn[BOARD_GPIO_PIN_TABLE_SIZE];
(ライブラリ内部使用)PIO番号をDIO番号に変換するテーブル。
- 0x80: SPIMISO ピン
- 0x90: ADC1ピン (アナログ専用)
- 0xFF: 未使用・未定義
g_twenet_ioport_remap_by_AHIn[]
const uint8 g_twenet_ioport_remap_by_AHIn[BOARD_GPIO_PIN_TABLE_SIZE];
(ライブラリ内部使用)AHI番号からPIO番号を参照するテーブル。
AHIcmpt_Dio.cpp - 定義
変数
uint32 G_TWENET_IOPORT_OUTPUT_BM() = 0; // 出力ポート一覧のDIOビットマップ
uint32 G_TWENET_IOPORT_INT_ENABLED_BM() = 0; // 割り込み有効ポート一覧のDIOビットマップ
uint32 G_TWENET_IOPORT_INT_RISING_BM() = 0; // 立ち上がり割り込み有効のDIOビットマップ
uint32 G_TWENET_IOPORT_INT_FALLING_BM() = 0; // 立ち下がり割り込み有効のDIOビットマップ
volatile uint32 G_TWENET_IOPORT_INT_STATUS() = 0; // DIO割り込み起床した場合の、起床ピンを記録したDIOビットマップ
uint32 G_TWENET_IOPORT_WAKE_STATUS() = 0; // 起床時のIO割り込み要因を保存したDIOビットマップ
- DIOビットマップはビットnがDIOnに対応します (例: DIO0, 3 なら
(1UL << 0) | (1UL << 3)
)
check_pio(), get_pio(), get_dio()
static inline bool check_pio(uint8 u8pio);
static inline uint8 get_pio(const uint8 u8dio);
static inline uint8 get_dio(const uint8 u8pio);
check_pio()
: 指定された PIO が有効な番号か、また、他のペリフェラルで使用済みかどうかを判定するインライン関数。get_pio()
: 指定された DIO 番号に対応する PIO 番号を返します。無効な割当である場合は0xff
を返します。get_dio()
: 指定された PIO 番号に対応する DIO 番号を返します。無効な割当である場合は0xff
を返します。
s_gpio_int_handler()
static void s_gpio_int_handler(uint32 bm_pio, uint32 bm_pio_changed, void* p_data);
DIO割り込み発生時に内部的に呼び出される割り込み処理関数。
- ピンの変化がある場合は
__twenet_vAppQApiPostHwIntT()
を用いて、AppQAPI 経由で割り込み情報を伝達します。
AHIcmpt_Dio.cpp - AHI関数定義
vAHI_DioSetDirection()
void vAHI_DioSetDirection(
uint32 u32Inputs,
uint32 u32Outputs);
ポートの入出力を設定します。
- 原則として初期化時は入力状態ですが、厳密には TWENETmcu ライブラリの pinmux.c
BOARD_InitPins()
の初期化状態が規定値になります。
vAHI_DioSetOutput()
void vAHI_DioSetOutput( // u32On:HIGH, u32Off::LOW
uint32 u32On,
uint32 u32Off);
ポートの出力状態を変更します。u32On
はHIGHレベルに変更するDIOビットマップ、u32off
はLOWレベルに変更するDIOビットマップです。
- 複数のピンを指定した場合はピンの変化は同時では有りません。
- 内部実装として、ループ内で1ピンずつ設定されるためです。
vAHI_DioSetPullup()
void vAHI_DioSetPullup(
uint32 u32On,
uint32 u32Off);
プルアップ状態を設定します。
- 原則としてプルアップ有りの設定ですが、厳密には TWENETmcu ライブラリの pinmux.c
BOARD_InitPins()
の初期化状態が規定値になります。
u32AHI_DioReadInput()
uint32 u32AHI_DioReadInput(void);
すべてのポートの状態を一度に取得します。
- 戻り値が全ポートの状態を示すビットマップで
1
になっているビットがHIGHレベル、0
がLOWレベルです。 - 存在しないDIO番号やペリフェラルなどで使用中のポートの値は未定義です。
vAHI_DioWakeEnable()
void vAHI_DioWakeEnable(
uint32 u32Enable,
uint32 u32Disable);
DIO割り込みを開始します。u32Enable
には割り込み処理を追加するDIOビットマップ、u32Disable
には割り込み処理を除外するDIOビットマップを指定します。加えて割り込みを有効にしたピンに対して vAHI_DioWakeEdge()
により割り込みエッジを指定する必要があります。
- 入力設定ピンでないピン(出力ピンや他のペリフェラル機能が割り当てられているピン)を指定した時の振る舞いは未定です。
vAHI_DioWakeEdge()
void vAHI_DioWakeEdge(
uint32 u32Rising,
uint32 u32Falling);
割り込みピンの設定を行います。この呼び出しでは、指定したピンに対して立ち上がり立ち下がり設定を一度に行います。追加や削除は出来ないことに注意してください。
本関数名には Wake が含まれますが、稼働中の割り込みの処理と、スリープ復帰の処理の両方を設定します。
- 動作原理上
u32Rising
とu32Falling
に同一ピンを指定した場合は、双方のエッジで割り込みが発生します。(ただし、AHIでの有効な設定ではないため、動作検証外とします) - 割り込み動作中は
vAHI_DioWakeEnable()
が内部的に呼び出され再設定されます。 - 入力設定ピンでないピン(出力ピンや他のペリフェラル機能が割り当てられているピン)を指定した時の振る舞いは未定です。
- スリープ復帰時の割り込みエッジは、両エッジになります。
u32AHI_DioWakeStatus()
uint32 u32AHI_DioWakeStatus(void);
DIO割り込み起床時の起床要因となったピンのビットマップを返します。
- 内部的には、呼び出し時の
__twenet_ioport_int_status
の値を返します。呼び出し後は0
にセットされます。
bAHI_DoEnableOutputs()
static inline bool_t bAHI_DoEnableOutputs(bool_t bEnableDO) {
return bAHI_DoEnableOutputsEx_MW(bEnableDO, bEnableDO);
}
DO0,DO1ピンを出力設定にします。
- DO0/DO1 双方ともに出力設定にします。
- 片側だけを設定したい場合は
bAHI_DoEnableOutputsEx_MW()
を呼び出します。- DO1 (PIO5) は、始動時にプログラムモードへの遷移判定(ISP_ENT)をするピンに割り当てられているため、ハードウェア設計上留意が必要なピンです。特別な理由がなければ、別のピンを利用することを推奨します。
- DO0(PIO0) は DIO11 にも割り当てられているため、両方利用している場合はコードの調整(片側の制御を除外する)が必要です。
vAHI_DoSetDataOut()
void vAHI_DoSetDataOut(
uint8 u8On,
uint8 u8Off);
DO0(PIO0),DO1(PIO1)に対して出力設定を行います。
- DO0がbit0 (0x1)、DO1がbit1 (0x2) のビットマップで指定します。
u8On
にビットを設定すると HIGH レベル、u8off
に指定すると LOW レベルになります。
vAHI_DoSetPullup()
void vAHI_DoSetPullup(
uint8 u8On,
uint8 u8Off);
なにもしません。
AHIcmpt_Dio.cpp - AHI拡張API
末尾に _MW
がつく関数は、AHI ライブラリには存在しない独自拡張です。
bAHI_DoEnableOutputsEx_MW()
bool_t bAHI_DoEnableOutputsEx_MW(
bool_t bEnableDO0, bool_t bEnableDO1);
DO0, DO1 を出力用に設定する。bAHI_DoEnableOutputs()
が2ポート双方を設定するために追加した関数。
vAHI_DioInterruptDisablePinsIntWhenChanged_MW(), vAHI_DioInterruptReavtivate_MW()
void vAHI_DioInterruptDisablePinsIntWhenChanged_MW(bool_t bSet);
void vAHI_DioInterruptReavtivate_MW();
割り込み判定されたピンの割り込みを一時的に停止する。
bSet
をTRUEとして呼び出すと、DIO割り込みが発生した時点で、その割り込み対象ピンの割り込みは一時的に停止します。チャタリングが多いメカボタンなどの入力の場合この設定を有効にして、割り込み発生から一定時間経過後に vAHI_DioInterruptReavtivate_MW()
を呼び出し割り込みを再開します。
vAHI_DioOnSleep_MW()
void vAHI_DioOnSleep_MW();
内部的な処理関数でユーザは呼び出しを行いません。スリープ前の DIO 割り込み関係の処理を行います。具体的には DIO 起床ピンの設定を行います。
vAHI_DioOnWakeup_MW()
void vAHI_DioOnWakeup_MW(bool_t b_init_2nd);
内部的な処理関数でユーザは呼び出しを行いません。起床時の DIO 割り込み関係の処理を行います。起床要因となったピンを保存します。
b_init_2nd
がfalse
の呼び出しは、WarmMain()
処理のごく初期の段階で呼び出され、起床要因の特定などの処理が行われます。つづいてcbAppWarmStart(TRUE)
の呼び出しの直前にtrue
での呼び出しを行います。
vAHI_DioRetentionRelease_MW()
void vAHI_DioRetentionRelease_MW();
スリープ復帰後の DIO 出力状態保持を解除する。本関数は RAM OFF スリープ復帰時かつcbAppColdStart()
内で使用します。
JN518Xでは、DIO出力状態を保持するためのレジスタ設定 (SYSCON->RETENTIONCTRL
) を行ってからスリープします。出力設定を行ったDIOピンはレジスタ設定時の出力状態を維持し、スリープ復帰後もレジスタ設定を変更しない限り出力状態が保持されます。本関数を呼び出すことで出力保持が解除されます。
スリープ前の状態と同じ設定にするには本関数呼び出し前にvAHI_DioSetDirection()
やvAHI_DioSetOutput()
を行い、明示的に出力設定を行っておきます。DIOの内部レジスタはスリープ時にクリアされるためです。
cbAppColdStart()
呼び出し後は、TWENETmcuライブラリ内の処理として、本関数と同じ処理を実行します。不用意なポートのHI/LO遷移を避けたい場合は、cbAppColdStart()
内でポートの出力設定を行うようにしてください。
その他
本ライブラリを利用しない場合の留意事項
本ライブラリ中の関数は呼び出さないようにしてください。呼び出しを行わない場合であっても、本ライブラリは TWENETmcu, TWENETlib ライブラリと依存性があります。
依存関係を解消するためには以下を参考にしてください。
- スリープ手続きを行う際の割り込みピンに関する部分
vAHI_DioOnSleep_MW()
,vAHI_DioOnWakeup_MW()
を調整する必要があります。- この2つの関数は TWENETcmpt 内の
vAHI_OnSleep_MW()
,vAHI_OnWakeup_MW()
から呼び出されます。
- この2つの関数は TWENETcmpt 内の
vAHI_OnSleep_MW()
関数は、ソース非開示のTWENETlibライブラリに依存しています。vAHI_DioOnSleep_MW()
で__twenet_ioport_int_status
に割り込み起床判定を行う PIO ビットマップを指定します。ToCoNet_vSleep()
内で反映され、適切にスリープ実行されます。
vAHI_OnWakeup_MW()
,vAHI_DioOnWakeup_MW()
は、TWENETmcuライブラリソース中で呼び出されます。必要に応じて処理を変更してください。
4.4.4 - Timer (PWM)関連のAHI関数と解説
Timer (PWM)
AHI の Timer 関連の API の一部について、ソースコード互換を取る目的で実装しています。
- この実装は完全な互換性を保つことを目的とはしていません。
- 本書記述時点で判明している留意点などを記載します。
- 内部の実装は予告なく変更される場合があります。
- 解説中のパラメータについても、留意が必要な部分のみ記述しています。省略部分は、原典の AHI ライブラリマニュアルを参照ください。
AHI APIについて
vAHI_TimerFineGrainDIOControl()
void vAHI_TimerFineGrainDIOControl(uint8 u8BitMask)
出力ピンを無効化するビットマスクを指定します。TIMER_0 … TIMER_4 に対応するビットのみ有効です。
vAHI_TimerEnable()
実行前に本関数を呼び出します。vAHI_TimerEnable()
のパラメータで出力を有効化していても、ピンを無効化設定されている場合は、出力無効化として取り扱います。
vAHI_TimerAssignPIOPin_MW()
void vAHI_TimerAssignPIOPin_MW(
uint8 u8_timer_id,
uint8 u8_pin_id)
TWELITE GOLD専用です。
指定したタイマーデバイス(u8_timer_id
)で使用するピンをPIO番号で指定します。
PIO番号には特定のPWMチャネルが紐づいています。またPWMが使用できないPIO番号もあります。指定方法によっては、重複したPWMチャネルを利用するといった矛盾した設定になる場合があります。PIO番号とPWMチャネルの割り当てについては、ピン配置表などを参照してください。
u8_timer_id
は、対象のタイマーデバイス (E_AHI_DEVICE_TIMER0-4
)を指定します。vAHI_TimerFineGrainDIOControl()
の設定も有効ですが、出力の有無はvAHI_TImerEnable()
のbOutputEnable
で出力の制御を行います。- 出力を行わずタイマー割り込みのみを利用する場合でも、利用するPWMチャネルに対応したピン番号を指定します。
本ライブラリの独自関数です。
vAHI_TimerEnable()
void vAHI_TimerEnable(
uint8 u8_timer_id,
uint8 u8Prescale,
bool_t bIntRiseEnable,
bool_t bIntPeriodEnable,
bool_t bOutputEnable)
タイマーを有効化します。
bIntRiseEnable==TRUE
の場合はbIntPeriodEnable==TRUE
として取り扱います。bOutputEnable==TRUE
の設定が行われてもvAHI_TimerFineGrainDIOControl()
でピンが無効化されている場合はFALSE
として取り扱います。- すでに有効化したタイマーIDに対して、再度本関数を呼び出した場合の動作は不定です。
ハードウェア資源に矛盾がある場合
TWELITE BLUE/RED とのハードウェアの差異から、すべてのタイマーデバイスを同じように利用できるわけではありません。詳しくは後述のピン割当を参照してください。
- PWM出力が有効になっている場合は、ソフトウェアでのPWM出力エミュレーションを行います。
- PWM出力が無効になっている場合は、目的がタイマー割り込みと限定されるため、空いているPWM3またはPWM5をピン出力無しで利用します。
- 上記割当を行ったかどうかを調べるAPIや手続きは用意していません。
vAHI_TimerDisable()
void vAHI_TimerDisable(uint8 u8_timer_id)
タイマーを無効化します。
- 出力ポートは入力(プルアップは設定変更しない)に戻します。
vAHI_TimerConfigure()
void vAHI_TimerConfigure(
uint8 u8_timer_id,
bool_t bInvertPwmOutput,
bool_t bGateDisable)
タイマーの設定を変更します。
bInvertPwmOutput
の設定を行います。bGateDisable
は無視されます。
vAHI_TimerStartRepeat()
void vAHI_TimerStartRepeat(
uint8 u8_timer_id,
uint16 u16Hi,
uint16 u16Lo)
タイマーを開始します。
- この関数はタイマー動作中にも呼び出すことができ、PWMのDUTY設定を変更する目的で使用できます。
vAHI_TimerStop()
void vAHI_TimerStop(uint8 u8_timer_id)
タイマーを停止します。
vAHI_TimerSetLocation()
void vAHI_TimerSetLocation(
uint8 u8Timer,
bool_t bLocation,
bool_t bLocationOverridePWM3andPWM2)
ピンの割当変更を行います。
vAHI_TimerEnable()
実行前に本関数を呼び出します。
vAHI_TimerXRegisterCallback
PUBLIC void vAHI_Timer0RegisterCallback(
PR_HWINT_APPCALLBACK prTimer0Callback);
PUBLIC void vAHI_Timer1RegisterCallback(
PR_HWINT_APPCALLBACK prTimer1Callback);
PUBLIC void vAHI_Timer2RegisterCallback(
PR_HWINT_APPCALLBACK prTimer2Callback);
PUBLIC void vAHI_Timer3RegisterCallback(
PR_HWINT_APPCALLBACK prTimer3Callback);
PUBLIC void vAHI_Timer4RegisterCallback(
PR_HWINT_APPCALLBACK prTimer4Callback);
割り込みハンドラの登録関数は実装されていません。AppQAPIにより割り込みハンドラが呼び出されます。
独自に割り込みハンドラの定義を行う場合は、以下のWEAK
定義のハンドラ関数を実装します。実装についてはAHIcmpt_TImers.cpp
の実装を参考にしてください。少なくともPWM_ClearStatusFlags(PWM, kPWM_PwmX);
を呼び出しておく必要があります。
WEAK void PWM0_DriverIRQHandler(void); // MONO WIRELESS, DEFINED AS WEAK FUNCTION.
WEAK void PWM1_DriverIRQHandler(void);
WEAK void PWM2_DriverIRQHandler(void);
WEAK void PWM3_DriverIRQHandler(void);
WEAK void PWM4_DriverIRQHandler(void);
WEAK void PWM5_DriverIRQHandler(void);
WEAK void PWM6_DriverIRQHandler(void);
WEAK void PWM7_DriverIRQHandler(void);
WEAK void PWM8_DriverIRQHandler(void);
WEAK void PWM9_DriverIRQHandler(void);
上記以外の関数
void vAHI_TimerClockSelect(
uint8 u8Timer,
bool_t bExternalClock,
bool_t bInvertClock);
void vAHI_TimerStartSingleShot(
uint8 u8Timer,
uint16 u16Hi,
uint16 u16Lo);
関数定義なし、または、何もしないダミー関数です。
出力ピンについて
- 出力ピンは
vAHI_TimerEnabled()
呼び出し時に PWM 用途として初期化されます。 - 出力ピンは
vAHI_TimerDisable()
呼び出し時に、入力ポート (プルアップ設定は設定を変えない) として最初期化します。
割り込みについて
周期途中の出力変化点での割り込みには対応しません。周期ごとの割り込みのみに対応します。
割り込みハンドラ
割り込みハンドラは、TWENET 標準の cbToCoNet_u8HwInt()
, cbToCoNet_vHwEvent()
のみに対応します。別途ハンドラを登録することはできません。
個別のハンドラを定義したい場合はPWMx_IRQHandler()
関数を別途定義します。この場合、定義されたハンドラから TWENET へのイベント通知は行いません。
ピン割当
ピン割当は TIMER_ID 毎に個別に設定できますが、TWELITE BLACK ではハードウェアの違いから、割当が困難な場合があります。
標準
AHI TIMER ID | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
SMD PIN## | 12 | 16 | 13 | 15 | 19 |
AHI DIO## | 10 | 11 | 12 | 13 | 17 |
PIO## | 4 | 0 | 13 | 1 | 21 |
PWM channel | 4 | 0 | 2 | 1 | 9 |
標準で DO1,2 を利用した場合
AHI TIMER ID | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
SMD PIN## | 12 | 16 | 1 | 2 | 19 |
AHI DIO## | 10 | 11 | DO0 | DO1 | 17 |
PIO## | 4 | 0 | 0 | 5 | 21 |
PWM channel | 4 | 0 | 0 | N/A | 9 |
- TIMER_1, TIMER_2 の割当が衝突します。
- TIMER_3 の出力ピンにはハードウェアタイマーの機能がありません。
副割当
AHI TIMER ID | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
SMD PIN## | 6 | 7 | 8 | 9 | 10 |
AHI DIO## | 4 | 5 | 6 | 7 | 8 |
PIO## | 7 | 6 | 8 | 9 | 14 |
PWM channel | 7 | 6 | 8 | 9 | 1 |
副割当で DO1,2 を利用した場合
AHI TIMER ID | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
SMD PIN## | 6 | 7 | 1 | 9 | 10 |
AHI DIO## | 4 | 5 | DO0 | DO1 | 8 |
PIO## | 7 | 6 | 0 | 5 | 14 |
PWM channel | 7 | 6 | 0 | N/A | 1 |
- TIMER_3 の出力ピンにはハードウェアタイマーの機能がありません。
その他
ピン割り当てに矛盾が出たときの振る舞い
- PWM出力設定をしている場合で矛盾が出たピン(そもそもPWM機能がないものなど)は、ソフトウェアでのエミュレーションになります。
- ソフトウェアでのエミュレーションはシステムタイマー(SysTick)の割り込み処理下で16クロックを1周期として出力を制御します。1Khz で動作する場合は 1000/16 = 約62Hz の PWM 周期です。
- PWM出力設定をしない場合で矛盾が出たピン(PWM デバイス番号の衝突)は、空いている PWM3 または PWM5 を割り当てます。ピン出力なしの場合でもPWM割り込みは動作します。
本ライブラリのPWM機能を利用しない場合
- AHI のタイマー関連の API (
?AHI_Timer???
) を呼び出さないようにしてください。- 当該APIを呼び出すことで、AHI互換のための処理オブジェクトを生成します。この状態で
fsl_pwm.h
に定義されるAPIを呼び出した場合の振る舞いは未定義です。
- 当該APIを呼び出すことで、AHI互換のための処理オブジェクトを生成します。この状態で
PWM0_IRQHandler()
…PWM9_IRQHandler()
を別途定義してください。これらはweak
リンク指定されているので、アプリケーションで定義したweak
指定のないものが優先してリンクされます。
スリープ復帰時の振る舞い
- RAM保持スリープ時は、スリープ直前の PWM 出力状態の状態を復元します。RAM非保持の場合は、通常のDIO初期化を実施します。
関連AHI API
void vAHI_TimerFineGrainDIOControl(
uint8 u8BitMask);
PUBLIC void vAHI_TimerConfigure(
uint8 u8Timer,
bool_t bInvertPwmOutput,
bool_t bGateDisable);
PUBLIC void vAHI_TimerEnable(
uint8 u8Timer,
uint8 u8Prescale,
bool_t bIntRiseEnable,
bool_t bIntPeriodEnable,
bool_t bOutputEnable);
PUBLIC void vAHI_TimerDisable(
uint8 u8Timer);
PUBLIC void vAHI_TimerClockSelect(
uint8 u8Timer,
bool_t bExternalClock,
bool_t bInvertClock);
PUBLIC void vAHI_TimerStartRepeat(
uint8 u8Timer,
uint16 u16Hi,
uint16 u16Lo);
PUBLIC void vAHI_TimerStop(
uint8 u8_timer_id);
PUBLIC void vAHI_TimerSetLocation(
uint8 u8Timer,
bool_t bLocation,
bool_t bLocationOverridePWM3andPWM2);
※ マクロで関数名が再定義されているものもあります。
※ utils.h のタイマーライブラリも上記APIを利用します。
ハンドラー定義例
最小限の手続きを含めた定義です。
void PWM0_IRQHandler(void) { PWM_ClearStatusFlags(PWM, kPWM_Pwm0); }
void PWM1_IRQHandler(void) { PWM_ClearStatusFlags(PWM, kPWM_Pwm1); }
void PWM2_IRQHandler(void) { PWM_ClearStatusFlags(PWM, kPWM_Pwm2); }
void PWM3_IRQHandler(void) { PWM_ClearStatusFlags(PWM, kPWM_Pwm3); }
void PWM4_IRQHandler(void) { PWM_ClearStatusFlags(PWM, kPWM_Pwm4); }
void PWM5_IRQHandler(void) { PWM_ClearStatusFlags(PWM, kPWM_Pwm5); }
void PWM6_IRQHandler(void) { PWM_ClearStatusFlags(PWM, kPWM_Pwm6); }
void PWM7_IRQHandler(void) { PWM_ClearStatusFlags(PWM, kPWM_Pwm7); }
void PWM8_IRQHandler(void) { PWM_ClearStatusFlags(PWM, kPWM_Pwm8); }
void PWM9_IRQHandler(void) { PWM_ClearStatusFlags(PWM, kPWM_Pwm9); }
- この関数定義を行うとTWENETへの割り込み・イベント伝達は行われません。
本ライブラリの実装について
AHIcmpt_Timer.cpp
には主要な実装コードが含まれます。上記コードは
_periph_pwm.hpp
,_periph_pwm.cpp
を引用しています。これらはプラットフォームドライバ(driver/fs_???
)を用いた手続きをまとめたクラスライブラリです。
4.4.5 - SMBUS(I2C)関連の手続きを定義したSMBus.c,hの解説
SMBUS(I2C)
TWENETを用いたサンプルコードやアプリコードの多くは、I2Cバスの利用は、AHIライブラリ内の低レベル手続きは直接用いず、読み書き手続きを簡素化したSMBus.c
, .h
定義関数群を用いています。
以下に、利用する関数名を列挙します。
void vSMBusInit(void);
void vSMBusInit_setClk(uint32 u32Clk);
void vSMBusDeInit();
void vSMBusDeInit(void);
bool_t bSMBusWrite(uint8 u8Address, uint8 u8Command,
uint8 u8Length, uint8* pu8Data);
bool_t bSMBusSequentialRead(uint8 u8Address, uint8 u8Length,
uint8* pu8Data);
SMBus.c SMBus.h
I2C の代表的な手続きをまとめた関数群でTWENETmwx/source/sensors/legacy
にソースコードを格納しています。
※TWENETmwx ライブラリをリンクしない場合(Cプロジェクト)は、このソースコードをコピーして利用します。
vSMBusInit()
void vSMBusInit(void);
I2Cバスを初期化します。使用するピンはDIO14(CLK),15(DATA)で、クロック周波数は100Kbpsです。
vSMBusInit_setClk(uint32)
void vSMBusInit_setClk(uint32 u32Clk);
vSMBusInit()
の替わりに本関数を用いることで、u32clk
に対応するクロックにてI2Cバスを初期化します。
u32clk>=7
かつu32clk>=255
の場合⇒クロック周波数320000ul/(u32clk+1)
を指定して初期化します。例えば31
を指定すると、100KHz、7
を指定すると400kHzとなります。u32clk >= 12500
かつu32clk <= 400000
⇒u32clk
を指定して初期化します。- それ以外⇒未定義
※ 実際の周波数は、ハードウェアのクロックディバイザに対応し近傍の周波数が選択されます。具体的な計算方法についてはソースコードを参照 (TWELITE GOLDの場合は NXP の FSL ライブラリの仕様を参照ください。
// TWELITE GOLDの実装
PUBLIC void TWENET_smbus_vSMBusInit_setClk(uint32_t u32clk)
{
...
if (u32clk >= 7 && u32clk <= 255) { // given by divisor
u32clk = 3200000ul / (u32clk + 1);
}
if (u32clk < 12500ul || u32clk > 400000ul) {
u32clk = 100000ul;
}
// initialize the I2C
//...以下、呼び出し先関数の実装
_conf.baudRate_bps = u32clk;
I2C_MasterGetDefaultConfig(&_conf); // FSLライブラリ関数
}
// TWELITE BLUE/RED の実装
void vSMBusInit_setClk(uint32 u32Clk)
{
/* convert clock to clock devisor */
if (u32Clk > 255) {
u32Clk = (3200000UL / u32Clk) - 1;
}
if (u32Clk < 7 || u32Clk > 255) u32Clk = 31; // set 100kHz
/* run bus at specified value */
vAHI_SiMasterConfigure(TRUE, FALSE, u32Clk);
// 16/[(PreScaler + 1) x 5]MHz
// --> 31:100KHz, 7:400KHz, 47:66Khz
}
vSMBusDeInit()
void vSMBusDeInit();
I2Cバスの利用を停止します。
- TWELITE BLUE/RED は
vAHI_SiMasterDisable()
を呼び出します。 - TWELITE GOLDはI2Cバスの利用の停止と、DIO14,15ピンを TWENET ライブラリ初期化時の設定 (入力ポート、プルアップ) に戻します。
bSMBusWrite()
bool_t bSMBusWrite(
uint8 u8Address,
uint8 u8Command,
uint8 u8Length,
uint8* pu8Data)
I2Cバスへの書き込みを行います。
u8Address
⇒I2Cバスのデバイスアドレスを指定します。u8Command
⇒書き込み時のコマンド(最初の転送バイト)を指定します。u8Length
⇒続くバイト数。0
の場合はコマンドのみの転送です。1以上を指定した場合はpu8Data
の定義が必須です。pu8Data
⇒転送するバイト列を格納したメモリ領域へのポインタを指定します。
転送が成功した場合は TRUE
を戻し、失敗した場合は FALSE
を戻します。
bSMBusSequentialRead()
bool_t bSMBusSequentialRead(
uint8 u8Address,
uint8 u8Length,
uint8* pu8Data)
I2Cバスの読み込みを行います。
u8Address
⇒I2Cバスのデバイスアドレスを指定します。u8Length
⇒読み出すバイト数(1以上)を指定します。pu8Data
⇒読み出すバイト列を格納するメモリ領域へのポインタを指定します。
転送が成功した場合は TRUE
を戻し、失敗した場合は FALSE
を戻します。
その他
スリープ時の取り扱い
- TWELITE BLUE/REDは、スリープ復帰時にハードウェアの再初期化を行う必要があります。
vSMBusDeInit()
を呼び出さない場合のピンの状態は未定義(またはJN516x のペリフェラル仕様書に基づく)ですが、再度vSMBusInit()
vSMBusInit_setClk()
の呼び出しを行うことで初期化することができます。 - TWELITE GOLDは、以下の振る舞いをします。
- RAM ON(通常)スリープ時:スリープ手続きを行った時点で、I2Cバスが初期化されていた場合は、スリープ復帰時に再初期化を行います。I2Cバスが使用されていない場合は、通常の汎用IOのスリープ復帰時の手続きとなります。
- RAM OFF(ディープ)スリープ時:スリープ復帰時にTWENETによるピンの初期化(入力ピン、プルアップ)行います。
TWELITE GOLD の実装
AHIライブラリ互換関数は用意せず SMBus.c
,h
に対応する関数を実装しています。
// TWENETcmptライブラリ内での実装
PUBLIC void TWENET_smbus_vSMBusInit(void);
PUBLIC void TWENET_smbus_vSMBusDeInit(void);
PUBLIC void TWENET_smbus_vSMBusInit_setClk(uint32 u32clk);
PUBLIC bool_t TWENET_smbus_bSMBusWrite(uint8 u8Address,
uint8 u8Command, uint8 u8Length, uint8* pu8Data);
PUBLIC bool_t TWENET_smbus_bSMBusSequentialRead(uint8 u8Address,
uint8 u8Length, uint8* pu8Data);
// SMBus.hで inline 定義により上記関数群を呼び出す
static inline void vSMBusInit(void) {
TWENET_smbus_vSMBusInit();
}
static inline void vSMBusInit_setClk(uint32 u32Clk) {
TWENET_smbus_vSMBusInit_setClk(u32Clk);
}
static inline void vSMBusDeInit() {
TWENET_smbus_vSMBusDeInit();
}
static inline void vSMBusDeInit(void) {
TWENET_smbus_vSMBusInit();
}
static inline bool_t bSMBusWrite(uint8 u8Address, uint8 u8Command,
uint8 u8Length, uint8* pu8Data) {
return TWENET_smbus_bSMBusWrite(u8Address, u8Command, u8Length, pu8Data);
}
static inline bool_t bSMBusSequentialRead(uint8 u8Address, uint8 u8Length,
uint8* pu8Data) {
return TWENET_smbus_bSMBusSequentialRead(u8Address, u8Length, pu8Data);
}
4.4.6 - SPI関連のAHI関数と解説
SPI
SPI関連のAHI互換関数の実装です。
- この実装は完全な互換性を保つことを目的とはしていません。
- 本書記述時点で判明している留意点などを記載します。
- 内部の実装は予告なく変更される場合があります。
- 解説中のパラメータについても、留意が必要な部分のみ記述しています。省略部分は、原典の AHI ライブラリマニュアルを参照ください。
SPIの対応については、以下のピンを利用します。
信号名 | ピン名(PIO番号) | 解説 |
---|---|---|
SCK | SPLCLK=DIO11(PIO0) | クロック信号 このピンはSPICLK, DIO11共用になっています |
MOSI | DIO18(PIO2) | SPIMOSIです。TWELITE 側が出力、外部SPIデバイス側が入力です。 |
MISO | SPIMISO(PIO5) | SPIMISOです。TWELITE 側が入力、外部SPIデバイス側が出力です。 |
SEL0 | DIO19(PIO3) | |
SEL1 | DIO0(PIO16) | |
SEL2 | DIO1(PIO17) |
副割り当てのピン (vAHI_SpiSetLocation_MW(FALSE)
により設定)を用いた場合は、以下となります。
信号名 | ピン名(PIO番号) | 解説 |
---|---|---|
SCK | ADC1(PIO15) | クロック信号 |
MOSI | DIO1(PIO17) | SPIMOSIです。TWELITE 側が出力、外部SPIデバイス側が入力です。 |
MISO | DIO2(PIO18) | SPIMISOです。TWELITE 側が入力、外部SPIデバイス側が出力です。 |
SEL0 | DIO0(PIO16) | |
SEL1 | DIO8=ADC2(PIO14) | このピンはDIO8, ADC2共用になっています |
SEL2 | DIO12(PIO13) |
SPIはハードウェアの機能を用い動作するため、ピンの振る舞い(特に転送していないときの HIGH/LOW の状態など)には一部違いが出ます。
- 実装は、ブロッキング転送を用いています。コードの互換性を維持するため、転送APIの直後にポーリング待ちコードを含めるようにしてください(
bAHI_SpiPollBusy()
,vAHI_SpiWaitBusy()
)。
vAHI_SpiConfigure()
void vAHI_SpiConfigure(
uint8 u8SlaveEnable,
bool_t bLsbFirst,
bool_t bPolarity,
bool_t bPhase,
uint8 u8ClockDivider,
bool_t bInterruptEnable,
bool_t bAutoSlaveSelect);
SPIの初期化を行います。
bInterruptEnable
には対応してません。パラメータは無視されます。
vAHI_SpiDisable()
void vAHI_SpiDisable(void);
SPIの利用停止をします。
vAHI_SpiSelect()
void vAHI_SpiSelect(
uint8 u8SlaveMask)
SPIのSELECTピンを選択します。
vAHI_SpiConfigure()
のbAutoSlaveSelect
がTRUE設定の場合は、制御対象のピンを指定します。この呼出時点ではピンの制御は行いません。vAHI_SpiConfigure()
のbAutoSlaveSelect
がFALSE設定の場合は、SELECTピンの制御(対象品のみをLOW,それ以外はHIGH) します。
vAHI_SpiStop()
PUBLIC void vAHI_SpiStop(void);
SELECTピンを解除します。vAHI_SpiSelect(0)
と同じ処理です。
vAHI_SpiStartTransfer()
void vAHI_SpiStartTransfer(
uint8 u8CharLen,
uint32 u32Out);
void vAHI_SpiStartTransfer32(uint32 u32Out)
void vAHI_SpiStartTransfer16(uint16 u16Out)
void vAHI_SpiStartTransfer8(uint8 u8Out)
SPI転送を実行します。
- この処理はブロッキングで実行されます。
- 8の倍数ビット数でない場合は、転送が2~3回に分割されます。
- 32bit指定時は、エンディアンの違いによるメモリ上のバイト配置にかかわらず、数値の上位のバイトから下位のバイトの順に送信されます。結果として、BLUEとGOLDでは転送波形が同じになります。
AHI_SpiReadTransfer
static inline uint32 u32AHI_SpiReadTransfer32(void);
static inline uint16 u16AHI_SpiReadTransfer16(void);
static inline uint8 u8AHI_SpiReadTransfer8(void);
転送完了後に呼び出し、読み出した値を返す。
bAHI_SpiPollBusy()
bool_t bAHI_SpiPollBusy(void);
inline void vAHI_SpiWaitBusy(void) { while(bAHI_SpiPollBusy()); }
常に FALSE を返します。転送APIがブロッキング転送を行うためです。
bAHI_SpiTransferBlocking_MW()
bool_t bAHI_SpiTransferBlocking_MW(
uint8 *au8tx,
uint8 *au8rx,
uint8 u8len);
バイト単位の転送を行います。au8tx
が送信データの配列、au8rx
が受信データの配列、u8len
が転送バイト数です。
- 配列の先頭から順に転送されるため、LSBから順に転送する場合は、バイト順も LSB 側のバイトを先に格納しておく必要があります。受信データも同様です。
vAHI_SpiWaitBusy()
void vAHI_SpiWaitBusy(void);
速やかに return します。
vAHI_SpiSetLocation_MW()
void vAHI_SpiSetLocation_MW(bool_t bLocation);
使用するピンの組み合わせを変更します。既定のピンを用いる場合は本関数の呼び出しは不要ですが、副割り当てピンを用いる場合はvAHI_SpiConfigure()
関数呼び出し前に本関数を呼び出します。
bLocation == FALSE
(デフォルト)→既定のピン割り当てを用います。bLocation == TRUE
→副割り当てピンを用います。
その他
転送の分割
vAHI_SpiStartTransfer()
では8bitの整数倍(8,16,24,32bit)以外の転送を行う場合は、内部的に転送を2分割して行います。そのため、1回目と2回目の転送の間、波形は一定時間保持されることになります。
スリープ復帰時の振る舞い
RAM保持スリープ直前にSPIバスが初期化済みである場合は、復帰時に初期化状態を復元します。RAM非保持スリープの場合は、通常の始動時のDIO初期化が行われます。
BLUE/REDとのコード互換性を高めたい場合はスリープ前に vAHI_SpiDisable()
を明示的に呼び出すようにしてください。
4.4.7 - Random(乱数)関連のAHI関数と解説
Random(乱数)
乱数生成関連のAHI 互換関数の実装。
- この実装は完全な互換性を保つことを目的とはしていません。
- 本書記述時点で判明している留意点などを記載します。
- 内部の実装は予告なく変更される場合があります。
- 解説中のパラメータについても、留意が必要な部分のみ記述しています。省略部分は、原典の AHI ライブラリマニュアルを参照ください。
vAHI_Start|StopRandomNumberGenerator()
void vAHI_StartRandomNumberGenerator(bool_t const bMode, bool_t const bIntEn);
void vAHI_StopRandomNumberGenerator(void);
乱数生成を開始・停止します。
u16AHI_ReadRandomNumber()
uint16 u16AHI_ReadRandomNumber(void);
16bitの乱数値を読み出します。
- 乱数生成が開始されていない場合は
57005
を戻します。
u32AHI_ReadRandomNumber_MW()
uint32 u32AHI_ReadRandomNumber_MW(void);
(TWELITE GOLD 専用関数)32bitの乱数値を読み出します。
- 乱数生成が開始されていない場合は
3735928559
を返します。
vAHI_ReinitRandomNumberGenerator_MW()
void vAHI_ReinitRandomNumberGenerator_MW();
(TWELITE GOLD 専用関数)乱数生成デバイスの再初期化を行います。
4.4.8 - UART関連のAHI関数と解説
UART
UARTの利用は TWENETutils にある serial.c
,.h
および uart.c
,.h
を用います。ここでは、TWELITE GOLD で特有の振る舞いをするAHI互換関数について解説します。
- UART1を用いる場合は、
vAHI_UartSetLocation()
またはvAHI_UartSetLocationByPio_MW()
を呼び出し、事前に割り当てポートを指定する必要があります。 - UART0 は使用にあたりUART1のような特別な手続きは必要ありません。
vAHI_UartSetLocation()
void vAHI_UartSetLocation(uint8_t u8port, bool_t bSel);
UART のポート割り当てを指定します。
- UART0 の割り当てには影響しません。規定のポート(DIO6,7)から変更できません。
- UART1 の割り当ては以下の2種類が可能です。
- UART1を利用する場合は必ず本館数を呼び出す必要があります。
- UART1 の他の割り当てを行うには
vAHI_UartSetLocationEx_MW()
を用いてください。
bSel | TX | RX |
---|---|---|
FALSE | DIO14(PIO10) | DIO15(PIO11) |
TRUE | DIO11(PIO0)*1 | DIO13(PIO1) |
*1 規定のSPICLKピンと重複します。
vAHI_UartSetLocationByPio_MW()
void vAHI_UartSetLocationByPio_MW(uint8_t u8port, uint8 u8TxPort, uint8 u8RxPort)
UART のポート割り当てを行います。u8port
はE_AHI_UART_1
を指定します。TXポートとRXポートのPIO番号を、u8TxPort
とu8RxPort
で指定します。
設定可能なPIO番号(DIO番号)
- TX : 0(DO0,DIO11) 6(DIO5) 10(DIO14) 20(DIO16)
- RX : 7(DIO4) 1(DIO13) 11(DIO15) 19(DIO13)
vAHI_UartDisable()
void vAHI_UartDisable(uint8_t u8port)
u8port
で指定するUARTポートを利用停止します。ピンの状態は起動直後の初期化状態(TWENETmcu/board/pin_mux.c
での定義)に戻ります。
4.4.9 - WatchDog(WDT)関連のAHI関数と解説
WatchDog(WDT)
vAHI_WatchdogStart()
void vAHI_WatchdogStart(uint8 u8Prescale);
ウォッチドッグタイマーを利用開始します。
- タイムアウト時間はおおよその値を設定している。具体的にはタイムアウトは
u8Prescale == 0
の場合8
ms, それ以外は((1UL<<(u8Prescale-1)) + 1) * 8
msとしてthe_wwdt->init()
を呼び出している。 - 値域外の値
u8Presacale > 12
を指定した場合は、u8Prescale = 10
(約4秒) とする。 -DDEBUG
でコンパイルするデバッグ時はこの処理は実行されず、WDTは停止したままとします。
vAHI_WatchdogStop()
void vAHI_WatchdogStop();
TWELITE GOLD では、いったん稼働したウォッチドッグの停止を行うことが出来ません。本関数は、ウォッチドッグタイマーのタイムアウトを変更する際に以下のように呼び出します。
...
vAHI_WatchdogStop(); // 一旦停止API(実際は停止しない)を呼び出す
vAHI_WatchdogStart(12); // 約16秒に再設定する
vAHI_WatchdogRestart()
void vAHI_WatchdogRestart();
ウォッチドッグタイマーのタイムアウトまでに呼び出します。
-DDEBUG
でコンパイルするデバッグ時はこの処理は実行されません。
4.4.10 - WakeTimer(ウェイクタイマー)関連のAHI関数と解説
WakeTimer(ウェイクタイマー)
vAHI_WakeTimer
関連の互換関数の実装です。
- この実装は完全な互換性を保つことを目的とはしていません。
- 本書記述時点で判明している留意点などを記載します。
- 内部の実装は予告なく変更される場合があります。
- 解説中のパラメータについても、留意が必要な部分のみ記述しています。省略部分は、原典の AHI ライブラリマニュアルを参照ください。
ウェイクタイマーは2系統あり、スリープ中問わずカウンタが動作します。カウンタは減算式で値が0になったときに割り込みが発生します。またウェイクタイマーは、動作し続ける特性から起動時からの経過時間を計る時計として利用することもできます。時計として利用するための手続きをまとめた FRWT(FreeRunning WTimer)関数軍も用意しています。
- タイマーは
E_AHI_WAKE_TIMER_0
の場合41ビット、E_AHI_WAKE_TIMER_1
の場合28ビットです。後者は BLUE/RED(JN516x) と仕様が違いますので注意してください(カウンタ値として時間差分を計算する場合は、最大値が0x0FFFFFFF
である点に注意してください。例えばct1
からct2
の間の経過カウントを計算する場合は(((ct2 << 4) - (ct1 << 4)) >> 4)
のように計算します) - 本ライブラリでは 32ビットを超えるタイマー値を扱う関数は用意していません。
- mwxライブラリやいくつかのアプリケーションでは、タイマーの1系統(
E_AHI_WAKE_TIMER_0
を動作しつづけて時間計測をするための処理(Free Running WTimer:FRWT
API)を行います。
vAHI_WakeTimerEnable()
void vAHI_WakeTimerEnable(uint8 u8Timer,
bool_t bIntEnable)
タイマーを初期化する。
vAHI_WakeTimerStart()
void vAHI_WakeTimerStart(uint8 u8Timer, uint32 u32Count)
タイマーを開始する。u32count
はカウンター値を指定する。TWELITE GOLD の場合、1秒後に割り込みを発生させたい場合は 32768
(32KHz 水晶振動子の周波数) を指定する。
vAHI_WakeTimerStop()
void vAHI_WakeTimerStop(uint8 u8Timer)
タイマーを停止する。
u32AHI_WakeTimerCalibrate()
uint32 u32AHI_WakeTimerCalibrate(void);
ウェイクタイマーのキャリブレーション値 10000
を返します。
- 本来は精度の低いRCタイマーで 10000 に対して±30%程度の値になりますが、TWELITE GOLDでは32KHz水晶によるタイマー回路が含まれるため、この水準でのキャリブレーションは不要です。無条件で
10000
を返します。
u32AHI_WakeTimerRead()
uint32 u32AHI_WakeTimerRead(uint8 dev)
カウンタ値を返します。起床割り込みはカウンタが0になったときに発生します。その後もカウンタは減算を続けます(0の次はカウンタの最大値)。
u8AHI_WakeTimerStatus()
uint8 u8AHI_WakeTimerStatus(void)
タイマーの稼働状況のビットマップを返す。E_AHI_WAKE_TIMER_0
の場合 E_AHI_WAKE_TIMER_MASK_0
(1)
、E_AHI_WAKE_TIMER_1
の場合E_AHI_WAKE_TIMER_MASK_1
(2)
が設定されます。
u8AHI_WakeTimerFiredStatus()
uint8 u8AHI_WakeTimerFiredStatus()
起床直後に使用し、起床要因が WTIMER の場合、0 以外の値が戻ります。
E_AHI_WAKE_TIMER_0
の場合、E_AHI_WAKE_TIMER_MASK_0
(1)
が戻ります。E_AHI_WAKE_TIMER_1
の場合、E_AHI_WAKE_TIMER_MASK_1
(2)
が戻ります。
Free Running WTimer (FRWT)
WAKE TIMER を1系統(原則E_AHI_WAKE_TIMER_0
)用い、実行し続けることによりリアルタイムカウンタとして用います。スリープ状態を問わず時間を計測することができます。
グローバル変数
G_TWENET_FREE_RUNNING_WTIMER_ENABLED()
uint8_t G_TWENET_FREE_RUNNING_WTIMER_ENABLED() // MACRO
この辺数は cbAppColdStart(FALSE)
呼び出しで設定します。0x80
を指定することで E_AHI_WAKE_TIMER_0
をFRWTとして動作させます。WAKE TIMER のカウンタは時間の経過とともに減算されますが、FRWTは加算します。
- mwxライブラリでは、自動的に
E_AHI_WAKE_TIMER_0
によるFRWTが設定されます。
g_twenet_free_running_wtimer_boot_tick
uint32_t g_twenet_free_running_wtimer_boot_tick
スリープ復帰直後(RAM保持)のカウント値を保存します。TWENETライブラリ中からvAHI_FRWTSetBootCount_MW()
が呼び出されることにより設定されます。
vAHI_FRWTStart_MW()
void vAHI_FRWTStart_MW(uint8_t u8Timer)
本関数はTWENETライブラリ中で用いるため、原則としてユーザプログラムでは使用しません。グローバル変数G_TWENET_FREE_RUNNING_WTIMER_ENABLED()
の設定によりFRWTを起動させます。
u32AHI_FRWTGetCurrentCount_MW()
uint32 u32AHI_FRWTGetCurrentCount_MW()
FRWTのカウント値(32000カウント/秒) を返す。
u32AHI_FRWTGetCurrentCount_msec_MW()
uint32 u32AHI_FRWTGetCurrentCount_msec_MW(uint32* dec_part)
現在のFRWTをミリ秒で返す。
dec_part
はNULL
またはuint32
変数へのポインタを指定します。指定された場合は 1/10 ミリ秒の値 (0..9) を返します。
u32AHI_FRWTConvertCount_msec_MW()
static inline uint32 u32AHI_FRWTConvertCount_msec_MW(uint32 ct, uint32* dec_part) {
// note: see wtimer::freerun_ct_convert_msec()
uint64_t v = 1000ull * ct;
if(dec_part) *dec_part = (10*(v & 32767)) >> 15;
return (uint32)(v >> 15);
}
FRWTのカウント値をミリ秒に変換します。dec_part
は指定された場合は 1/10 ミリ秒の値(0..9)を返します。
i32AHI_FRWTCompareCount_MW()
int32 i32AHI_FRWTCompareCount_MW(uint32 val_past, uint32 val_now)
FRWTのカウント値の比較を行います。val_now
がより最近の値、val_past
がより過去の値を指定し、この場合は正の値のカウント値を戻します。
i32AHI_FRWTCompareCount_msec_MW()
int32 i32AHI_FRWTCompareCount_msec_MW(uint32 val_past, uint32 val_now)
FRWTのカウント値の比較を行います。val_now
がより最近の値、val_past
がより過去の値を指定し、この場合は正の値のミリ秒を戻します。
vAHI_FRWTSetBootCount_MW()
void vAHI_FRWTSetBootCount_MW()
本関数はTWENETライブラリ中で用いるため、原則としてユーザプログラムでは使用しません。
スリープ起床時(RAM保持、ウォームブート)に、FRWTカウント値を保存するために用います。
uint32 u32AHI_FRWTGetBootCount_MW()
uint32 u32AHI_FRWTGetBootCount_MW()
スリープ起床時(RAM保持、ウォームブート)に、FRWTカウント値を返します。
u32AHI_FRWTGetBootCount_msec_MW()
uint32 u32AHI_FRWTGetBootCount_msec_MW()
スリープ起床時(RAM保持、ウォームブート)に、FRWTカウント値をミリ秒に変換して返します。
4.4.11 - Onchip temp sensor (温度センサー)関連のAHI関数と解説
Onchip temp sensor (温度センサー)
TWELITE GOLDでは、内部チップ中に温度センサーが実装されています。このセンサー値は、無線MAC層の初期化のパラメータとして用いられます。
MAC層の初期化時の温度センサーの取り扱い
- 温度センサーの値が取得できない場合は20℃として初期化します。
- スリープ復帰時に
G_TWENET_CHIPSENSOR_ADC_INTERVAL_MS()
ミリ秒以上経過している場合は、スリープ起床時(RAM保持)に再度温度計測を行い、センサー値をもとにMACの再初期化を行う。
グローバル変数
uint8 G_TWENET_CHIPSENSOR_AUTO_ON_BOOT()
// 変数アクセス用のマクロ
温度センサーの取得を自動で行うための設定用変数。cbAppColdStart(FALSE)
中で設定する。
設定値 | 内容 | 備考 |
---|---|---|
0 | 温度センサーの取得を自動で行わない。 | MAC層の温度補正は固定値 (20℃で行う) |
1 | 温度センサーの取得を自動で行う。 |
uint8_t G_TWENET_CHIPSENSOR_ADC_TIMES_SCALER()
// 変数アクセス用のマクロ
温度センサーのADC回数に対応するスケーラー値を指定します。
設定値 | ADC回数 |
---|---|
0 | 1 |
1 | 2 |
2 | 4 |
3 | 8 |
int32 G_TWENET_CHIPSENSOR_TEMP128TH()
// 変数アクセス用のマクロ
TWENETライブラリ内で計測されたチップセンサーの温度(℃ の128倍値)が格納される。
int16 g_twenet_chipsensor_volt_on_boot;
TWENETライブラリ内で計測された電圧値[mV]。温度センサー計測時に同時に計測された値が格納される。
uint32 G_TWENET_CHIPSENSOR_ADC_INTERVAL_MS()
= (10*60*1000ul)
// 変数アクセス用のマクロ
この変数で指定された期間内は温度センサーの取得を省略する。cbAppColdStart(FALSE)
中で設定する。
uint8 g_twemet_chipsensor_capture_this_time;
ブート時に温度測定を行うか否かを判定した内部フラグ。
bAHI_AdcTemp_Measure_MW()
bool_t bAHI_AdcTemp_Measure_MW(
int32 *i32temp_128th,
int16 *i16volt_mv,
uint8 adc_times_scaler,
bool_t bTurnOnSensor)
温度センサーの計測を行います。
i32temp_128th
は温度計測結果を返すint32
がたの変数へのポインタ。i16volt_mv
は同時に計測される電源電圧[mV]値。adc_times_scaler
は温度センサーのADC回数に対応するスケーラー値を指定します。設定値はG_TWENET_CHIPSENSOR_ADC_TIMES_SCALER()
の解説を参照してください。bTurnOnSensor
はTRUE
を設定すると、関数呼び出し内で温度センサーの電源を投入し必要な待ち処理を行います。FALSE
を指定した場合は、事前にvAHI_AdcTemp_TurnOn_MW()
を行い必要な待ち時間を経過している必要があります。
vAHI_AdcTemp_TurnOn_MW()
void vAHI_AdcTemp_TurnOn_MW()
温度センサーの電源を投入する。この呼び出し後 100μ秒 の待ち時間が必要です。
uint32 u32AHI_AdcTemp_GetCaptTick_MW()
uint32 u32AHI_AdcTemp_GetCaptTick_MW()
最後に温度センサー値を取得した FRWT 時刻を32KHzカウント値で返す。
uint32 u32AHI_AdcTemp_GetCaptTick_msec_MW()
uint32 u32AHI_AdcTemp_GetCaptTick_msec_MW()
最後に温度センサー値を取得した FRWT 時刻をミリ秒で返す。
u32AHI_AdcTemp_ElapsedFromCapt_msec_MW(), u32AHI_AdcTemp_TickrefFromCapt_msec_MW()
uint32 u32AHI_AdcTemp_ElapsedFromCapt_msec_MW()
uint32 u32AHI_AdcTemp_TickrefFromCapt_msec_MW(uint32 tick_ref)
最後に温度計測してからの経過時間をミリ秒で返す。
4.5 - TWENETeastl - EASTLライブラリ
TWENETeastl - EASTLライブラリ
EASTL は Electronic Arts 社が整備した標準テンプレートライブラリ(コンテナ・アルゴリズム)で、C++ の STL (Standard Template Library) に倣い実装されていますが、制約の多いゲーム機の開発で整備されてきた経緯があり、メモリの取り扱いに制約が大きい環境を意識したコンテナやアルゴリズムが用意されています。
本ライブラリは EASTL を TWENET 内で利用できるようにしています。
以下に特徴的な要素を記載します。
- メモリ固定確保のコンテナ (
fixed_
) : 動的確保を行わず、固定長の要素数を持つコンテナの宣言が可能です。グローバル宣言すれば、コンパイル時に固定的にメモリ領域が確保され、ローカル宣言すればスタックエリアに確保されそのスコープ内で利用できます。 - Intrusive コンテナ:通常のコンテナは任意のデータ構造を格納できますが、Intrusiveコンテナはデータ構造に対して専用の基底クラスを継承することで、コンテナ内のリンク構造などを維持するためのリンク情報などを保持します。コンテナ内の各要素はそのコンテナ専用になりますが、リストやマップ構造では非常にメモリ利用効率の良くなります。(参考: Intrusive and non-intrusive containers)
2007年の記事EASTL (open-std.org)に開発動機などが記されています。(関連記事:EASTL から垣間見るゲームソフトウェア開発現場の現状 その 1, その 2)
EASTL ライブラリ添付資料
doc 以下の html ファイルを参照して下さい。
配布時に最上位ディレクトリに格納されている README.md, CONTRIBUTING.md は doc/ に移動しています。
TWENETでの利用
以下に留意してください。
当社ではライブラリの動作については包括的な検証は行っておりません。お客様での動作検証をお願いいたします。また EASTL の利用方法についてのお問い合わせについても当社では対応できません。配布元の開設資料・ライブラリソースコードなどの情報を参照してください。
- EASTL3.07 (2018/1/31) のバージョンを利用します。(C++11でコンパイルできる一番最後のバージョン)
- 以下のライブラリは組み込んでいません。
test/packages/EAAssert
,source/assert.cpp
test/packages/EATest
test/packages/EAThread
,source/thread_support.cpp
- テストコード
test/source
の動作移植はしていません。 - sprintf関連では
EA::StdC::Vsnprintf(char8_t*, ...)
のみを printf.h ライブラリ中のvsnprintf_()
を呼び出すことで解決しています。
組み込み・コンパイル方法
EASTL はアクト Act の記述の際に利用できます。
TWELITE 向けの開発環境で必要なインクルードパスの追加、ライブラリの追加は行います。作成するコード中でライブラリヘッダのインクルードを行ってください。
#include <TWELITE>
#include <EASTL/fixed_string.h>
using namespace eastl;
using tstr128 = fixed_string<char, 127 + 1, false>;
void setup() {
tstr128 s1;
s1 = "Hello World";
Serial << s1.c_str();
}
void loop() {
;
}
組み込み方法(詳細)
- EASTL/source 内のコードをコンパイルして、ライブラリアーカイブとしておく (
libEASTL.a
)。リンク時にはこのライブラリの参照が必須です。 - コンパイル時に以下のインクルードパスを追加しておく。
$(PATH_EASTL)
を EASTL ディレクトリとした場合、インクルードパスは以下となります。
-I$(PATH_EASTL)/include
-I$(PATH_EASTL)/test/packages/EAAssert/include
-I$(PATH_EASTL)/test/packages/EABase/include/Common
-I$(PATH_EASTL)/test/packages/EAMain/include
-I$(PATH_EASTL)/test/packages/EAStdC/include
-I$(PATH_EASTL)/test/packages/EATest/include
-I$(PATH_EASTL)/test/packages/EAThread/include
コーディングについて
std::
と eastl::
について
標準ライブラリ (std::
) と EASTL(eastl::
)では同じ名前で同じ機能を持つものが定義されています。これらは混在できる場合もありますが、使用するとエラーになる場合もあります。つまりEASTLで使用するものは、通常はEASTL内の定義を用います(例:std::unique_ptr
に eastl::fixed_string
を格納しようとするとコンパイラエラーになる)。
グローバルオブジェクトの初期化1 (配置new)
TWENET の開発では、コンパイラの制約により、グローバル宣言のオブジェクトのコンストラクタが実行されません。グローバル宣言宣言したオブジェクトのメモリ領域がゼロクリアされるだけです。そのまま、コードを実行すると大抵の場合 null pointer access によりハングアップします。
このオブジェクトを初期化するためには*placement new (配置new)*を用います。
#include <TWELITE>
#include <EASTL/fixed_string.h>
using namespace eastl;
using tstr128 = fixed_string<char, 127 + 1, false>;
tstr128 g_str1; // constructor is NOT called! needs to be initialized before use.
void setup() {
(void) new ((void*)&g_str1) tstr128("Hello World");
Serial << g_str1.c_str();
}
placement new のコードは少し乱雑に見えるため、補助関数mwx::pnew()
を用意しています。先ほどの例を以下のように書き換えることができます。
(void) new ((void*)&g_str1) tstr128("Hello World");
// ↓
mwx::pnew(g_str1, "Hello World");
※ 2番目の引数以降は可変数で、コンストラクタにそのまま渡されます。
グローバルオブジェクトの初期化2 (unique_ptr)
グローバルオブジェクトの初期化方法として unique_ptr
(std::unique_ptrの解説)を用いる方法もあります。unique_ptr
は std::
にも eastl::
にもありますが、EASTLのクラスではeastl::
のものを使用します。
以下のように初期化のタイミングで .reset()
を呼び出します。
#include <TWELITE>
#include <EASTL/unique_ptr.h>
#include <EASTL/fixed_string.h>
using namespace eastl;
using tstr128 = fixed_string<char, 127 + 1, false>;
eastl::unique_ptr<tstr128> uq_str1;
void setup() {
uq_str1.reset(new tstr128("Hello World"));
if (uq_str1) { // true: object is stored.
Serial << uq_str1->c_str();
}
}
intrusive コンテナについて
以下の例は intrusive_list
の要素定義例です。メンバーは int mX
のみです。
struct IntNode : public eastl::intrusive_list_node {
int mX;
IntNode(int x = 0) : mX(x) { }
// no need to call super class's constructor eastl::intrusive_list_node()
};
inline bool operator<(const IntNode& a, const IntNode& b) { return a.mX < b.mX; }
inline bool operator>(const IntNode& a, const IntNode& b) { return a.mX > b.mX; }
intrusive_list
の要素は、必ず intrusive_list_node
を基底クラスに持っている必要があります。基底クラス内にはリストを維持するためのリンクポインタが含まれます。ここではさらに sort
などで使用する比較演算子の定義も行います。
using tiList = intrusive_list<IntNode>;
void setup() {
IntNode nodeA(5);
IntNode nodeB(1);
IntNode nodeC(9);
IntNode nodeD(2);
IntNode nodeE(4);
tiList l; // intrusive_list body
l.push_front(nodeA); // forming list strucure
// by updating link info in intrusive_list_node.
l.push_front(nodeB);
l.push_front(nodeC);
l.push_front(nodeD);
l.push_front(nodeE);
l.sort(); // sort, using < operator
l.sort(eastl::greater<tilist::value_type>()); // sort, using > operator
}
参考資料
- EA Standard Template Library ーTWENET に収録されているライブラリは EASTL 3.07 用で、それ以降に実装・変更された要素が含む点に注意してください)
- cpprefjp - C++日本語リファレンス ーC++ リファレンスですが STL の解説が参考になります。
本サンプルについて
EASTLのライセンス記述は以下です。
Modified BSD License (3-Clause BSD license) see the file LICENSE in the project root.
/*
Copyright (C) 2015 Electronic Arts Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of
its contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
サンプルコードは MWSLA-1J/E を適用します。
4.6 - TWENETstgs - twesettingsライブラリ
TWENETstgs - twesettingsライブラリ
このライブラリは主にインタラクティブモードにより設定処理を行うための諸関数が含まれます。
※ これらの関数はエンドユーザ向けの API としては公開していません。
4.6.1 - printfライブラリ
printf 相当関数
本 TWENETstgs ではオープンソースによるprintfライブラリを利用した
fprintf
, vfprintf
, sprintf
相当関数を定義しています。
int TWE_fprintf(TWE_tsFILE *fp, const char *format, ...);
int TWE_vfprintf(TWE_tsFILE *fp, const char *format, va_list va);
#define TWE_snprintf(out,siz,fmt,...) snprintf_(out,siz,fmt,__VA_ARGS__)
参照するソースコードの記述
///////////////////////////////////////////////////////////////////////////////
// \author (c) Marco Paland (info@paland.com)
// 2014-2019, PALANDesign Hannover, Germany
//
// \license The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on
// embedded systems with a very limited resources.
// Use this instead of bloated standard/newlib printf.
// These routines are thread safe and reentrant.
//
///////////////////////////////////////////////////////////////////////////////
4.6.2 - TWESTG_CMD_u32CmdOp() コマンド解説
TWESTG_CMD_u32CmdOp() コマンド解説(内部開発者向け)
TWESTG_CMD_u32CmdOp()
関数によるコマンド実行は、TWENETstgs ライブラリを利用し実装されたアプリケーション(ファームウェア)との共通的な手続きを提供するものですが、この情報はライブラリ内部の実装に関するもので、通常のユーザが使用することは想定していません。概要
twesettings_cmd.[ch]
の TWESTG_CMD_u32CmdOp()
関数は、0xdb
コマンドの実行処理を行うことを想定している。この関数は、モジュールの諸情報の取得、設定情報の取得、設定情報の反映、リセットなどの処理が含まれる。多くの処理は設定関連の補助関数 TWEINTRCT_cbu32GenericHandler()
を呼び出すようになっている。
データ型
TWE_APIRET
は、0x80000000
のビットの有で成功、なしで失敗。残りの31ビットをパラメータとする。TWE_tsBuffer
はバッファへのポインタ、系列長、バッファ最大長を格納した構造体。TWESTG_tsFinal
は、設定関連の管理構造体。
TWESTG_CMD_u32CmdOp()
TWE_APIRET TWESTG_CMD_u32CmdOp(uint8 u8Op, TWE_tsBuffer *pBufIn, TWE_tsBuffer *pBufOut, TWESTG_tsFinal *psFinal)
処理内容u8Op
に対応した処理を行う。処理によって入力データpBufIn
、出力データpBufOut
を用いる。最後のパラメータは設定管理構造体は psFinal
を指定する。
パラメータ | 型 | 処理 |
---|---|---|
u8Op | uint8 | 処理内容を指定する。 |
pBufIn | TWE_tsBuffer * | 入力系列。 |
pBufOut | TWE_tsBuffer * | 出力データの格納領域を指定する。処理によっては NULL 指定でも構わない。処理の失敗時の状態は原則未定義である。 |
psFinal | TWESTG_tsFinal * | 設定情報管理構造体を指定する。 |
u8Opの概要は以下である。
E_TWESTG_CMD_OP_ACK = 0xF0 ACK処理
E_TWESTG_CMD_OP_QUERY_MODULE_INFO = 0xF1 SIDなどの取得
E_TWESTG_CMD_OP_APPLY_SETTINGS = 0xF2 設定の反映(セーブはしない)
E_TWESTG_CMD_OP_QUERY_SETTINGS = 0xF3 設定の読出
E_TWESTG_CMD_OP_MODULE_CONTROL = 0xF8 設定関連の諸処理
E_TWESTG_CMD_OP_REVERT = 0xFD 設定を元に戻す
E_TWESTG_CMD_OP_SAVE = 0xFE 設定の保存
E_TWESTG_CMD_OP_DO_MDDULE_RESET = 0xFF, モジュールリセット
戻り値は成功・失敗を戻す。処理によってはパラメータが設定されることがある。
戻り値 | VALUE | 状況 |
---|---|---|
TWE_APIRET_SUCCESS | b0..b7 → u8Op、他は処理次第 | 成功時 |
TWE_APIRET_FAIL | b0..b7 → u8Op、他は処理次第 | 失敗時 |
処理
E_TWESTG_CMD_OP_ACK (F0)
ACK応答を行う。入力した系列をそのまま出力する。
例
(なし) -> 01 : 入力なしの場合は 01 が戻る
112233 -> 112233 : 112233の場合は、出力にそのまま戻る。
E_TWESTG_CMD_OP_QUERY_MODULE_INFO (F1)
モジュールの諸情報を取得する。
入力列 | データ型 | 値 | 内容 |
---|---|---|---|
[0] | OCTET | 0x01 | モジュールのSIDを得る。 |
そのほか | 未定義 | ||
以降のデータは未定義 |
出力列 ([0] == 0x01) | データ型 | 値 | 内容 |
---|---|---|---|
[0..3] | BE_DWORD | モジュールのSID。 |
E_TWESTG_CMD_OP_APPLY_SETTINGS(F2)
設定情報を変更する。
- 設定情報はセーブ&リセットされるまでは反映されません。
- 未反映の状態でのアプリケーションのふるまいは未定義です。
- 未定義の状態でインタラクティブモードに遷移すると変更したデータは破棄されます。
- 設定済みのデータと同じ内容に変更しようとしたときも、この処理は成功として戻り値を返します。ただしセーブ(
E_TWESTG_CMD_OP_SAVE
)を実行しても、実際のセーブは行われません。 - この処理は出力 (
pBufOut
) には書き込みません。
入力列 | データ型 | 値 | 内容 |
---|---|---|---|
[0] | OCTET | 0x01 | IDに指定する設定を変更する。 |
[1] | OCTET | 0x00以外 | 設定ID |
[2..] | データ型依存 |
設定データ
設定ID | 内容 | 入力データ | 備考 |
---|---|---|---|
0x01 | アプリケーションID | BE_DWORD (uint32_t) | |
0x02 | 論理ID (8bit) | OCTET (uint8_t) | |
0x03 | チャネル | OCTET (uint8_t) | |
0x04 | チャネル(複数指定) | BE_WORD(uint16_t) | b0: ch11, b1: ch12, …, b15: ch16 |
BE_DWORD(uint32_t) | 1UL « ch のビット和 (11, 13なら 1UL « 11 | 1UL « 13) ※ STGSTD では無効化されている。 | ||
0x05 | 無線出力と再送 | OCTET (uint8_t) | 上位4ビットが再送回数、下位4ビットは出力設定 (0..3, 3が最高出力) |
0x06, 0x08, 0x09, 0x0A | オプション(32bit) | BE_DWORD (uint32_t) | |
0x07 | UART 設定 | BE_WORD (int16_t) | 内部形式の設定データをそのまま入力する。 |
BE_DWORD | ボーレートを指定する(9600 … 250000)。他の通信条件は 8N1 を指定する。 | ||
BE_DWORD OCTET OCTET OCTET | 全パラメータを指定する。 - ボーレート(DWORD) - ビット数 (7 or 8) - パリティ (‘N’ or ‘E’ or ‘O’) - ストップビット (1 or 2) |
例
01011234BEEF アプリケーションID(0x01)に0x1234BEEF を設定する。
010212 チャネル(0x02)に0x12(18)を設定する。
E_TWESTG_CMD_OP_QUERY_SETTINGS(F3)
設定情報を取得する。
入力列 | データ型 | 値 | 内容 |
---|---|---|---|
[0] | OCTET | 0x01 | (QTYP)IDに指定する設定を取得する。 |
[1] | OCTET | 0x00以外 | 設定ID |
QTYP==1 の出力
備考 | ||
---|---|---|
[0] | OCTET | データタイプ (uint8_t: 1, int8_t: 2, uint16_t: 3, int16_t: 4, uint32_t: 5, int32_t:6, uint8_t[]: 0x80 (下位5bitはデータ長) |
[...] | データタイプ依存 (整数型 WORD, DWORD は BigEndian並び) |
設定ID | 内容 | 入力データ | 備考 |
---|---|---|---|
0x01 | アプリケーションID | BE_DWORD (uint32_t) | |
0x02 | 論理ID (8bit) | OCTET (uint8_t) | |
0x03 | チャネル | OCTET (uint8_t) | |
0x04 | チャネル(複数指定) | BE_WORD(uint16_t) | b0: ch11, b1: ch12, …, b15: ch16 |
0x05 | 無線出力と再送 | OCTET (uint8_t) | 上位4ビットが再送回数、下位4ビットは出力設定 (0..3, 3が最高出力) |
0x06, 0x08, 0x09, 0x0A | オプション(32bit) | BE_DWORD (uint32_t) | |
0x07 | UART 設定 | BE_WORD (int16_t) | 内部形式の設定データ b15: 1 なら 7bit, 0 なら 8bit b14: 1 なら STOPBIT=2, 0 なら 1 b12,13: 0->NONE, 1->ODD, 2->EVEN b0..b11->ボーレートの1/100 |
例
0101 -> 051234BEEF -> アプリケーションID(uint32_t 0x1234beef)
0102 -> 010D -> チャネル(uint8_t 13)
E_TWESTG_CMD_OP_REVERT (0xFD)
このコマンドを実行直後に E_TWESTG_CMD_OP_SAVE
を発効することで、設定情報を初期値に戻す。
TWEINTRCT_cbu32GenericHandler(psIntr, E_TWEINRCT_OP_REVERT, TRUE, 0, NULL)
を呼び出す。第3引数のTRUE
指定により、セーブされた設定情報はロードしない。アプリケーションのTWEINTRCT_cbu32GenericHandler()
が正しく実装されていること。
入力データ、出力データは無し。
E_TWESTG_CMD_OP_SAVE (0xFE)
設定情報を変更した場合に、不揮発性メモリに保存する。
- 上書き、既に設定済みと同じ値に変更しようとした場合は、セーブは行わない。関数の戻り値として
TWE_APIRET_SUCCESS_W_VALUE(0x100 | E_TWESTG_CMD_OP_SAVE)
を返す。 - セーブを行った場合は、速やかにリセットを行う(設定変更したままの動作は未定義)。
入力データ、出力データは無し。
E_TWESTG_CMD_OP_DO_MDDULE_RESET (0xFF)
モジュールをリセットする。
入力データ、出力データは無し。