Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
汎用クラス・関数
基本クラス、関数
Loading...
Loading...
ユーティリティ関数
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
アスキー形式のパーサー
アスキー書式の解釈を行うパーサーですが、TWESYS::TimeOut
クラスをベースクラスに持つことで、タイムアウト処理を行っています。
パーサーオブジェクトを生成します。
生成時のパラメータにmaxbuffsiz
を与えると、maxbuffsiz
をバッファサイズとして動的にメモリ確保して、パーサーを初期化します。
あらかじめ生成されたSmplBuf_Byte
配列bobj
を参照して、パーサーを初期化することもできます。
アスキー書式の解釈アルゴリズムを実装します。バイトの入力のたびにタイムアウトのチェックを行います。
書式出力を行います。s_Output()
メソッドを呼び出します。
vPutByte()
は、ストリームに対して与えられたバイトu8byte
をアスキー2文字で出力します。例えば0x9Aであれば"9A"という2バイト文字になります。
s_vOutput()
は、ストリームに対して、与えられたバイト配列SmplBuf_Byte
のバイト列をアスキー形式で出力します。
書式パーサー
書式パーサーは、IParserを基底クラスとして、書式ごとに派生クラスを実装します。
パーサーは、シリアルポートのように1バイトずつ入力されるデバイスを想定し、1バイト単位での解釈を行い、都度状態を遷移する状態遷移マシンとして実装されます。
パケット定義
書式を解釈して得られたデータ列は、受信したパケット情報が含まれます。ここでは、このデータ列のことをパケットデータと呼びます。
パケットデータはTwePacket
クラスで表現されます。TwePacket
クラスのデータを解釈することで、その種別を判定し、各アプリケーションや接続ハードウェアに応じたデータ構造となります。TwePacket
クラスは基底クラスでさらにパケット種別ごとの派生クラスとなります。
このオブジェクトは無線パケットのデータ量に準じたメモリ領域を消費し、また、アプリケーションでは多数のパケットを保持することも考えられます。メモリ管理を簡略化するためTwePacket
をスマートポインタstd:shared_ptr<TwePacket>
にて管理します。このスマートポインタをspTwePacket
にtypedef
しています。
以下に、TWELITE PALのパケットデータの場合のクラス関係を示します。TwePacketPal
の基底クラスの一つDataPal
はTWELITE PAL特有のデータを格納しています。TWELITE PALには、さらに接続されるセンサーパルによって格納すべきデータが異なります。TwePacketPal
からさらにPalAmb
やPalMot
を生成します。例えばPalAmb
には温室センサーの値や照度センサーの値が格納されます。このTwePacketPal
をスマートポインタspTwePacket
という形に生成するのがnewTwePacket()
です。
spTwePacket
型はスマートポインタですので、オブジェクトのコピー渡しによる記述を行うことで、コピーのオーバーヘッドを最小にしつつ、メモリーの管理を自動化できます。以下の例はパケットの履歴を管理する単純なクラスです。
パケットオブジェクト
パケットデータは種別によってデータ構造が違いますが、様々な種類のパケットを一元管理するための基底クラスです。
spTwePacket
はメモリ管理のためのスマートポインタです。std::shared_ptr
を用いています。
TwePacketクラスは、パケットデータのパケット種別の管理を行います。また、パケットデータの解釈を行うための仮想関数parse()メソッドを定義しています。パケット特有のデータ構造に基づく解釈やデータの保存等の取り扱いは、派生クラスに実装します。
デフォルトでは、未解釈状態として E_PKT::PKT_ERROR
で初期化します。
パケットの種別をE_PKT
型で返します。
パケットデータのバイト列を与えて、パケットデータを解釈する。
派生クラスで、そのパケットに対応するデータ構造を解釈するための実装を行います。
戻り値は E_PKT
型 で、成功時は解釈されたパケット種別を、エラー時に E_PKT::PKT_ERROR
を返します。
パーサーの基底クラス
パーサーオブジェクトに1バイトずつ電文を投入することで、電文系列を解釈する状態遷移マシンです。
パーサーに1バイト入力します。入力のたびにパーサーの状態が変化し、パーサーの解釈が完了するとstate()
がE_TWESERCMD_COMPLETE
に変化し解釈完了状態となります。
パーサーの状態を取得します。
パーサーの状態がE_TWESERCMD_COMPLETE
の場合true
になります。
パーサーで解釈済みのバイト列のデータ長を返します。
パーサーの解釈済みのバイト列にアクセスします。
パーサーの解釈済みのバイト列を格納した配列クラスSmplBuf_Byte
を参照します。
パーサーの解釈途中の内容を破棄し、新たな解釈を始めます。
IStreamOutをベースクラスにもつストリームオブジェクトに、書式出力します。
1バイト入力して解釈を進める仮想関数です。派生クラスにより実装されます。
バイト配列bobj
に格納されるバイト列に対応する書式をストリームp
に出力する仮想関数です。派生クラスにより実装されます。
アプリ記述setup(),loop()の切り替え
アプリケーションはsetup()
,loop()
の2つの関数で記述されますが、例えば1画面ごとに大きく振る舞いが違うもの(ここではサブアプリと呼びます)を複数定義して、メニューで切り替えるといった動作を行う場合は、そのままsetup()
,loop()
内に記述しては煩雑になります。また変数についても管理する必要があります。
setup(), loop(), 関連する変数の切り替えを簡素化するためMWM5ライブラリでは以下の2つの仕組みを実装しています。
サブアプリ : setup()
, loop()
, 関連変数
をクラスとしてまとめ、切り替える
アプリハンドラ: サブアプリ内で setup()
, loop()
を切り替える
上記例は説明に必要な最小限のコードのみを記述します。APP_DEF
を継承したApp_Foo
,App_Bar
が、2種類のサブアプリの定義となり、各々がsetup()
,loop()
メンバー関数を定義しています。実際には振る舞いごとに必要なメンバー変数やその他メンバー関数が定義されます。サブアプリの登録や切り替えはライブラリ定義のクラスオブジェクトthe_app
に対して操作を行います。s_change_app()
関数はサブアプリを切り替える要求(サブアプリ終了時など)に対して、実際の切り替え部を実装していて、この関数をsetup()
中で呼び出すthe_app.setup()
のパラメータとして渡しておきます。loop()
中にはthe_app.loop()
を記述しておきます。
void setup()
とvoid loop()
を記述しておきます。setup()はサブアプリが初期化されるときに1度だけ呼び出されます。loop()
はthe_app.loop()
関数中で呼び出されます。
実行中のサブアプリが終了する場合に呼び出されます。サブアプリは1以上のIDにより種別を管理し、切り替えのために関数int (*)(THE_APP_MGR&, int, int, int)
を実装しておきます。
パラメータn_appsel
には、切り替えたいアプリケーションのIDが渡されます。パラメータはthe_app.exit()
で指定した値です。-1
が渡された場合は、デフォルトのサブアプリに切り替えるよう記述しておきます。
パラメータprev_app
には、直前のサブアプリIDです。直前が無ければ0となります。
パラメータexit_id
は、サブアプリがthe_app.exit()
で指定した値です。
n_appsel
で次に動作させるサブアプリを指定し、exit_id
はサブアプリに対するパラメータとして用います。
サブアプリ切り替え関数内部ではthe_app.new_app<T>()
(T
は次に生成するサブアプリのクラス)を呼び出しています。この呼び出しによりクラスT
のオブジェクトが生成され、同時にこれまで動作していたサブアプリのオブジェクトは破棄されます。
setup()
とサブアプリ切り替え関数内で呼び出し、サブアプリのオブジェクトを生成し、同時に現在のサブアプリを破棄します。
最初に動作させるサブアプリはsetup()
で生成します。
テンプレートパラメータT
はサブアプリ定義クラスでAPP_DEF
を継承している必要があります。
テンプレートパラメータargs
は、コンストラクタに渡されるパラメータです。オブジェクトはnew T(std::forward(args)...)
で生成されます。サブアプリがパラメータを指定しないデフォルトコンストラクタで構築される場合は何も指定しません。パラメータを指定する場合はサブアプリのコンストラクタの定義が必要です(例えばApp_Foo::App_Bar(int)
を定義しておいてthe_app.new_app<App_Bar>(exit_id)
)。
サブアプリのloop()
内で呼び出し、loop()
を抜けた直後にサブアプリを切り替えます。
上記の例のように大本のloop()
からはthe_app.loop()
が呼び出され、さらにサブアプリのloop()
が呼び出されます。サブアプリのloop()
中でthe_app.exit()
が呼び出されると、the_app.loop()
内でアプリケーションの切り替えが行われます。実際に切り替えているのはユーザが定義するサブアプリ切り替え関数です。
パラメータexit_code
は、サブアプリの終了コードを指定します。任意の数を指定できます。
パラメータnext_app
は、次のサブアプリを明示的に指定する意味合いの識別子です。-1
はデフォルトのサブアプリ、0
は切り替えを行わない、1
以上が次のサブアプリの識別子と意味付けをしています。
exit_code
とnext_app
は、そのままサブアプリ切り替え関数に渡されます。サブアプリ切り替え関数は、その2つのパラメータを参照して次のサブアプリを決定します。
大本のloop()
からthe_app
で生成したサブアプリのクラスオブジェクトを参照し、さらにサブアプリが指定したvoid*
型のポインタデータを取得します。
例えば、サブアプリ構築時に共通のクラスオブジェクトを持っていて(例えばメイン画面となるターミナル画面)、大本のloop()
から共通のオブジェクトにアクセスします(例えばメイン画面上の文字列を取得)。
アプリハンドラAPP_HNDLR
は、サブアプリ中での簡易的なsetup()
,loop()
処理の切り替えを行います。例えば、リスト一覧→リスト選択後、エラーといった複数の画面を切り替えるような動作です。
サブアプリの実装ではAPPDEF
を継承しましたが、さらにAPP_HNDLR<S>
(Sはサブアプリクラスを指定します)を継承します。サブアプリ中に処理関数(アプリハンドラ)を実装し、アプリハンドラを切り替えます。
上記がアプリハンドラを用いたときのソース構造の例です。
hndr_scr_def()
とhndr_scr_next()
がアプリハンドラ関数です。パラメータとしてev
とarg
が与えられ、ev
はEV_SETUP
,EV_LOOP
,EV_EXIT
のいずれかになり、setup()
,loop()
と終了処理に対応します。
アプリハンドラ関数はsetup()
,loop()
に相当する処理を行います。加えてハンドラが切り替えられる、つまり現在登録されているハンドラが終了するときの処理を記述できます。
パラメータev
に対応した処理を記述します。
パラメータarg
は、APP_HNDLR::new_hnbdlr()
やAPP_HNDLR::loop()
でパラメータが与えられたときに、値が格納されます。
アプリハンドラを初回生成する(サブアプリクラスのsetup()
)、またはアプリハンドラ内から次のアプリハンドラへ切り替えます。
パラメータhnd_next
はアプリハンドラ関数(メンバー関数のポインタ)を指定します。
パラメータarg
はアプリハンドラ関数のEV_SETUP
呼び出し時のパラメータを指定します。(EV_SETUP
による初期化時の処理を分岐したいときに利用します)
サブアプリのloop()
から毎回呼び出します。
パラメータarg
を指定するとアプリハンドラにその値が渡されます。
サブアプリのデストラクタから呼び出すようにしてください。
この記述を省略した場合、サブアプリのオブジェクトが破棄されるときに、アプリハンドラも破棄されますが EX_EXIT
メッセージが呼び出されません。
アプリハンドラは、サブアプリ内でsetup(),loop()コンテキスト切り替えの仕組みで、サブアプリ下でのメンバー関数の実行という携帯です。そのため、アクセスできるデータはサブアプリのメンバー変数となります。
ここでは、アプリハンドラ独自のデータを保持するクラスを追加します。
APPHNDLR_DCを継承したクラスを準備します。このクラスにはアプリハンドラ内で使用するデータやメンバー関数を定義します。以下の例ではDC_MyAppHndlr
というクラスを定義しています。
以下の定義を行う必要があります。
static const int CLS_ID
: データ格納クラス種別を識別するための個別のIDです。
int get_class_id()
: CLS_ID
を戻すメンバ関数です。
コンストラクタ : サブアプリクラスオブジェクトをパラメータとします。このオブジェクトは上記の例ではappに保存しDC_MyAppHndlr
からサブアプリにアクセスする目的で利用します。
継承したAPPHNDLR_DCをAPPHNDLR_DC(CLS_ID)
として初期化します。
DC_MyAppHndlr
はサブアプリのメンバー変数や関数にアクセスすることも多いためfriend
宣言しておきます。もちろん一般のクラス設計のようにpublicインタフェースを用意してカプセル化してもよいのですが、この場合、カプセル化の利点があまりなく記述が煩雑になるためです。
アプリハンドラではAPP_HNDLR::use<>()
を用いてデータオブジェクトを取得します。オブジェクトの生成・破棄は暗黙に行われます。別のアプリハンドラに切り替えられたときにデータオブジェクトが破棄されます。
上記の例では、アプリハンドラ関数の最初でdc
を取得しています。初回呼び出しにオブジェクトが生成され、それ以降は生成されたオブジェクトを参照します。
あとは生成されたdc
オブジェクトを操作します。
パケット種別ごとの定義
対応するパケット種別は定義を参照してください。
パケット種別判定
パケットデータのバイト列を入力として、パケットの種別を判定します。また既に生成済みのオブジェクトの種別を返します。戻り値はです。
spTwePacketオブジェクトの参照
本関数はオブジェクトをとして参照します。
この関数は、->
演算子や*
演算子を極力使用しない方針でライブラリを設定しているため、スマートポインタの参照を行うために用意しています。
上記の判定式を(pkt && pkt->get_type() == E_PKT::PKT_TWELITE)
と記述しても同じ判定が得られます。
パケット種別定義
以下のパケットに対応します。
App_Wings の親機で出力されるアスキー書式に対応します。
パケットデータの解釈とオブジェクト生成
パケットデータのバイト列を入力として、パケット種別の判定と、種別に応じたオブジェクトを生成します。
事前にを用いてパケットの種別が特定できている場合はeType
を与えます。
戻り値はです。
状態名
値
状態
E_TWESERCMD_EMPTY
0
解釈前で、まだ系列のヘッダも認識できていない
1..0x7F
解釈中
E_TWESERCMD_COMPLETE
0x80
系列が正しく解釈できた
E_TWESERCMD_ERROR
0x81
系列の解釈にエラーがあった
E_TWESERCMD_CHECKSUM_ERROR
0x82
系列は得られたがチェックサムエラーだった
EV_SETUP
setup()に相当し、アプリハンドラが登録・切替時に呼び出される。
EV_LOOP
loop()に相当し、都度呼び出される。
EV_EXIT
アプリハンドラの切り替えられ、現在のハンドラが終了する際に呼び出される。
PALセンサー共通データ
PALの各センサーのデータ構造体はすべてPalBase
を継承します。センサーデータの格納状況u32StoredMask
とモジュール電源電圧u16Volt
の情報が含まれます。
派生構造体に定義されるSTORE_COMP_MASK
とu32StoreMask
が一致すれば、全てのセンサーのデータが適切に解釈され、格納されていることになります。
TwePacketAppIO
のデータ部分。
PAL共通データ
PALは接続されるセンサーなどによってパケットデータ構造が異なりますが、DataPal
では共通部のデータ構造を保持します。
PALのパケットデータ構造は大まかに2つのブロックからなり、全てのPAL共通部と個別のデータ部になります。個別のデータ部は、パケットの解釈を行わずそのまま格納しています。取り扱いを単純化するため32バイトを超えるデータは動的に確保するuptr_snsdata
に格納します。
個別のデータ部は、PalBase
をベースクラスに持つ構造体に格納されます。この構造体は、TwePacketPal
に定義されるジェネレータ関数により生成されます。
PALイベントは、センサーなどの情報を直接送るのではなく、センサー情報を加工し一定の条件が成立したときに送信される情報です。例えば加速度センサーの静止状態から一定以上の加速度が検出された場合などです。
イベントデータが存在する場合はTwePacketPal
の.is_PalEvent()
がtrueになることで判定でき、.get_PalEvent()
によりPalEvent
データ構造を得られます。
TWELITE PALのパケット
TwePacketPal
クラスは、TWELITE PALのパケットデータを解釈したものです。このクラスはTWELITE PAL(センサーデータなど上り方向)共通に取り扱います。
PAL共通データはDataPal
に定義されています。
PALの各センサー基板特有のデータを取り出すためのジェネレータ関数を用意しています。
spTwePacket
オブジェクトからTwePacketPal
オブジェクトを参照します。spTwePacket
にTwePacketPal
以外が格納されている場合は、未解釈のオブジェクトを戻します。
センサーPALの各種データを取り出すためのジェネレータ関数です。
.u8palpcb==E_PAL_PCB::MAG
の場合、開閉センサーパルのデータPalMag
を取り出します。
.u8palpcb==E_PAL_PCB::AMB
の場合、環境センサーパルのデータPalAmb
を取り出します。
.u8palpcb==E_PAL_PCB::MOT
の場合、動作センサーパルのデータPalMot
を取り出します。
.is_PalEvent()
がtrue
の場合PalEvent
(PALイベント)を取り出します。
名前 | 解説 |
PKT_ERROR | パケット解釈前やパケット種別が特定できないなど、TwePacketには意味のあるデータが格納されていない |
PKT_TWELITE | 標準アプリ App_Twelite の を解釈したもの |
PKT_PAL | のシリアル形式を解釈したもの |
PKT_APPIO | リモコンアプリ のを解釈したもの |
PKT_APPUART | シリアル通信アプリ のを解釈したもの。 |
PKT_APPTAG | 無線タグアプリApp_TagのUARTメッセージを解釈したもの。センサ固有部分は解釈されずpayloadとしてバイト列を報告します。 |
PKT_ACT_STD | のサンプルなどで使用される出力書式。 |
PAL基板種別
下記のPAL基板に対応します。
開閉センサーパル(MAG)のセンサーデータ
動作センサーパル(MOT)のセンサーデータ
※ パケット間の各サンプルの連続性を確認するには、パケットのシーケンス番号の抜けが無いことを確認してください。
環境センサーパル(AMB)のセンサーデータ
TwePacketActStd
のデータ部。 (書式はApp_UARTと同一でDataAppUART
型を流用しています)
名前
解説
NOPCB
基板未接続、エラー
MAG
マグネットセンサー付きのMAG (開閉センサーパル)
AMB
温湿度センサー、照度センサー付きのAMB (環境センサーパル)
MOT
加速度センサー付きのMOT (動作センサーパル)
NOTICE
LED付きのMOT (通知パル)
TwePacketAppUart
のデータ部。
App_Twelite データ
TwePacketTwelite
のデータ部分。
ターミナル(コンソール)
namesace TWETERM
はターミナル(コンソール)画面を実装するためのクラスや関数などをまとめています。
基本的なクラス構造は以下のようになっています。クラスITerm
ではターミナルの文字列バッファとその処理、TWETerm_M5_Console
クラスはITermの文字列描画部分を実装したものです。IStreamOutはITerm派生クラスオブジェクトが文字列をターミナルに投入するための基本的な手続きを提供しています。
ターミナル(コンソール)
本ライブラリのターミナル(コンソール)は、文字列ベースの画面を構成することを目的としてます。
以下に設計時の考慮事項を記載します。
固定幅の画面構成を行うこと
日本語の表示が可能であること
ソースコード中に直接日本語文字列を含められるようにすること
UTF-8でソースコードを記述する前提とする
内部処理をUnicodeとすること
UTF-8デコードが出来るようにすること
旧来のキャラクター型のインタフェースを実装できるよう、いくつかのエスケープシーケンスを実装しておくこと
ただしANSIエスケープシーケンスの完全な互換性を目的とはしない
文字色、背景色、太字といった表示属性に対応すること
カーソルを表示・非表示にできること
画面の順方向のスクロールに対応すること
カラム数を超えて文字列を出力した場合は、折り返しを行えること
右端カラムへの文字出力を行った場合、その時点では折り返しを行わないようにすること
上記を実装は、折り返し処理の実装より優先すること
複数のターミナル表示を画面上に同時に表示できること
毎回全画面書き換えといったような描画パフォーマンスの悪い実装でないこと
変更がある行のみを書き換える行単位の描画を行うようにした
フォントを選択できること
配布可能なフォントをライブラリ内に同梱しておくこと
より大きな文字を表示するため、倍角表示に対応すること
本ライブラリのターミナルは、大まかに分けて2要素から構成されます。
エスケープシーケンス
エスケープシーケンスは ESC 文字 '\033' で始まり何文字かで完結する制御コードです。
本ライブラリが動作するプログラム上や、シリアルポートの先にあるマイコンから制御文字をターミナルに投入することで、様々な画面制御(画面のクリア、カーソルの移動、色などの表示属性の変更)を行うことが出来ます。
以下に対応するエスケープシーケンスを記述します。表中の ESC はエスケープ文字 '\033'、イタリックの n や m は数字の入力です。
ITerm
で対応するエスケープシーケンスは、ANSIターミナル互換を目的としたものではありません。解釈や仕様には違いがあります。
エスケープシーケンス
意味
ESC [ n A
カーソルをn行上に移動する。(n省略時は1行)
ESC [ n B
カーソルをn行下に移動する。(n省略時は1行)
ESC [ n C
カーソルをn列右に移動する。(n省略時は1列)
ESC [ n D
カーソルをn列左に移動する。(n省略時は1列)
ESC [ n G
カーソルのカラムnの位置に移動する (n省略時は1カラム目=行頭)
ESC [ n ; m H
カーソル位置を行n列mに移動する。先頭位置の場合は1を指定します。n;mを省略した場合は左上ホームポジションにカーソルを移動します。
ESC [ n ; m f
ESC [ n ; m Hに同じ。
ESC [ 2 J
画面をクリアしてカーソルをホームポジションに移動する。
ESC [ n K
n=0 または省略 カーソル行より後ろを削除する ※ 背景色を変更して呼び出すと行末まで指定した背景色でクリアします。
n=1 カーソル行より前を削除する
n=2 行全体を削除する
ESC [ n1 ; n2 ; ...; n4 m
描画属性の設定を行う。n1 .. n4 は任意数指定できる。
1 → 太字
7 → 反転
30 .. 37 → 文字色
40 .. 47 → 背景色
0 → 属性抹消
フォント定義クラス
フォント定義と関連する手続きをまとめたクラスです。
このクラスオブジェクトはフォントジェネレータcreateFont???()
によりライブラリ内部で生成・管理され、ユーザがコンストラクタを用いて直接オブジェクトを生成することはありません。
パラメータを省略した場合は、フォントのシングル幅文字の幅を返します。この値にはフォント生成時に指定した文字間スペースも含まれます。
wc
を指定した場合は、Unicode wc
に対応するフォントの幅を返します。日本語などダブル幅のフォントの場合は、シングル幅の2倍の値が戻ります。
フォントの高さを返します。この値にはフォント生成時に指定した行間スペースも含まれます。
デフォルトフォントのオブジェクトである場合 true
を返します。
デフォルトフォントのオブジェクトはcreateFont???()
やqueryFont()
のエラー時など例外時にも利用されます。
フォントIDを取得します。
Unicode c
に対応する、ダブル幅フォント定義配列インデックスを検索します。
戻り値は、字形データが存在する場合は、インデックス配列のインデックス(データ配列のインデックスが計算できる)、存在しない場合は-1
を返します。
フォント定義は、インデックス配列、データ配列の2つから構成されます。インデックス配列の各値は昇順に並んだ Unicode になっていて、データ配列のインデックスに対応しています。
以下の例ではインデックス配列の IDX=829 が U+5a2f で "娯" という文字です。データ配列の対応する番地を参照すれば、この字形データが格納されています。
インデックス配列内の値は昇順に並ぶよう構成した目的は、本関数で実装されている二分探索を利用するためです。
フォントジェネレータ関数
フォントジェネレータ関数は、収録フォントごとに定義されています。関数パラメータは共通で、以下のようになります。
上記は東雲フォント16ドット版(常用漢字収録)のジェネレータの例です。
id
は、ユーザが指定するフォントID。
line_space
はフォントの行間スペースをピクセル数で指定します。
char_space
は文字間スペースでピクセルで指定します。文字間スペースはシングル幅のフォントの指定です。ダブル幅のフォントの場合は倍になります。
u32Opt
は、フォントのオプションを指定します。オプションはU32_OPT_FONT_TATEBAI
とU32_OPT_FONT_YOKOBAI
があり、論理和で指定します。
フォントジェネレータの戻り値はFontDef&
になっています。この戻り値はライブラリ内部のフォント管理テーブルに生成されたオブジェクトへの参照です。既に登録済みのIDであるばあいは、そのIDに対して上書きを行います。登録できなかった場合は.is_default()
メソッドがtrue
になるデフォルトフォントが返されます。
M5Stack用のLcd描画ターミナル
M5Stack の 320x240 LCD 用のターミナルの実装です。ITerm
を実装しています。
本クラスはnamespace TWEARD
内に定義されます。
ITerm
のコンストラクタにdrawArea
と_M5
のパラメータが追加されています。
drawArea
は、LCD内のターミナル描画エリアを決めます。Rect
構造体で指定しx,y,w,hを指定します。(x,y)は領域の左上の座標、(w,h)は領域の幅と高さです。
_M5
は、M5Stackのグローバルインスタンス M5
を指定します。
カラム最大値を64、行数の最大値を20、左上座標を (0, 16)、領域サイズを (320, 192) として the_screen
オブジェクトを構築します。
ITerm::refresh()
の実装です。この関数により画面の描画を行います。loop()
関数内で定期的に呼び出します。
本実装では、パフォーマンスの向上のため、原則として描画変更の必要にある行のみを上書きします。画面全領域を再描画したい場合はforce_refresh()
メソッドを呼び出します。
以下の例では32msごとに描画を行います。
フォントを指定します。
u8id
はフォントIDを指定します。
u8col_request
は、設定したいカラム数を指定します。指定した数値が領域サイズに対して大きい場合は指定領域に入るように値が丸められます。0を指定した場合は、領域サイズから計算できる最大のカラム数に設定されます。
u8row_request
は、設定したい行数を指定します。指定した数値が領域サイズに対して大きい場合は指定領域に入るように値が丸められます。0を指定した場合は、領域サイズから計算できる最大の行数に設定されます。
font_id()
は、指定したフォントのIDを返します。
font_width()
は、指定したフォントの幅をピクセル数で返します。ダブル幅のピクセル数は、この値の2倍になります。
font_height()
は、指定したフォントの高さをピクセル数で返します。
ターミナルの文字色と背景色を指定します。
color
は文字色を指定します。
bgcolor
は背景色を指定します。
色は565形式の16bit値です。TWEARD::color565()
関数で計算します。
白色は ALMOST_WHITE
で指定します。color565(255,255,255) または WHITE を指定すると描画が崩れます。
ターミナルで使用できる8色のテーブルを指定します。ptbl
はuint16_t
型の配列で8つの要素が必要です。
上記の例では青とマゼンダの色調を変えたテーブルを指定し、ターミナルオブジェクト the_screen
に指定しています。
r, g, b
を指定して、565形式の色コードを生成します。
フォント定義や描画
namespace TWEFONT
には、フォントの定義やフォント描画のための手続きをまとめています。
このフォントライブラリは M5Stack 標準のライブラリのフォントには準じていないため M5Stackでのフォント描画APIなどで使用することが出来ません。
フォントはFontDef
クラスにより管理されます。フォントごとに用意されるFontDef
クラスオブジェクトのジェネレータ関数により生成され、ライブラリ内部で生成時に指定したフォントIDと紐づけて管理されます。フォントは最大7つまで定義できます。フォント作成時に字間・行間・倍角を指定することができます。同じフォントに対して複数のフォントIDの登録が可能です。
下記の例では、フォントID 10 に16ドットの東雲フォント(縦倍角・横倍角指定)を、フォントIDを11に同じフォントですが倍角指定なし、行間を1ピクセルとしたフォント定義を行います。
コンパイル時に、ジェネレータ関数createFont???()
を呼び出されたフォントのデータがリンクされます。
フォントの登録した種類だけROM容量が必要になります。最小限のフォントを選択するようにしてください。
本ライブラリには、作者が事実上パブリックドメイン(著作権等取扱はソースヘッダに含まれるクレジットを参照ください)を宣言しているフォントをいくつか含めています。
本ライブラリに含めるにあたって、以下の調整を行っています。
大本がBDF形式を変換し、描画ルーチンに適したデータ構造とした
これらフォントをUnicodeとして取り扱うための参照テーブルを用意した
latin1補助文字 U+00A0~u+00FFについて、フォント定義があるものについては収録した
JIS X201 半角カナ U+FF61~U+FF9F について、フォント定義があるものについては収録した
常用漢字(2645 文字)のフォントデータと、全収録(東雲フォントのみ、一部未収録字形があります)を用意した
ジェネレータ関数createFont???()には収録文字数に応じて3種類のジェネレータを用意しています。文字セットの生成は{MWM5ライブラリ}/fontsフォルダにあるスクリプトによって行います。
全収録版(_full
)は字形データが多いためより多くのROM容量が必要です。同じフォントサイズのデータで常用版と全収録版の両方を登録する意味はありません。常用漢字版の字形データは全収録版に包含されるためです。
12,14,16ドット版をライブラリに含めています。
常用漢字のみのジェネレータ (createFontShinonome12???()
, createFontShinonome14???()
, createFontShinonome16???()
)を呼び出します。
ジェネレータ createFontMP10???()
または createFontMP12???()
を呼び出します。
ジェネレータ createFontLcd8x6()
を呼び出します。
latin拡張文字や日本語フォントは含まれません。
このフォントはいずれかのジェネレータ関数createFont???()
が呼び出されたときに、デフォルトとしてフォントID=0に登録されます。
フォントIDは作成したフォントごとに割り当てられます。
IDは 0..32 の値を指定可能ですが、ユーザが登録できるのは 1..32 で最大7フォント登録できます。
ID=0 のフォントは 8x6 LCD フォントに割り当てられます。
フォント情報にアクセスするためには、queryFont()
によりFontDef
オブジェクトを取得し、諸情報を得ます。
ターミナルにフォントを指定するには、フォントの生成を行い、フォントIDをターミナルオブジェクトに指定します。フォント指定後はforce_refresh()
メソッドによる再描画を行います。
ターミナルのフォント変更は、set_font()
によりフォントを指定し、その後、clear_screen()
とforce_refresh()
を呼び出します。
drawChar()
関数を用いて描画することができます。
ターミナル用文字バッファ管理クラス
ターミナル(コンソール)の基底クラスで、画面上の文字列を管理する。このクラスは、実際の画面描画についての手続きは含まれず、このクラスを継承したサブクラスによって画面描画を実装します。
カラム数u8c
と行数u8l
を指定して、ターミナルを構築する。カラム数と行数はターミナルで管理できる最大の値を指定する。ターミナルのサイズ変更を行った場合でも各々の最大の値を超える変更は行われない。
pAryLines
とpBuff
を指定する場合は、ITerm内でのメモリ確保は行われず、外部で確保済みの配列を利用する。
動的にメモリを確保した場合は、そのメモリ領域を破棄します。
clear()
は画面バッファのクリア、home()
はカーソル位置をホームポジションに移動、clear_screen()
は両者を実行します。
サブクラスにより実装される画面更新描画のためのメソッドです。描画方法は2種類あり、メンバー変数u32Dirty
に定義されるビットマスクに対応した行のみを再描画するものと、force_refresh()
メソッドによる画面全体を再描画するものがあります。
画面全体の再描画では、いったん背景を背景色で塗りつぶしてから再描画します。初回の描画ではforce_refresh()
を行うようにしてください。
ターミナルに1文字書き出します。カーソル位置に文字を書き出します。16bit wchar_t
型のUnicodeを渡します。
char_t
(char) 型のパラメータを渡した場合は、入力をUTF-8として取り扱います。例えば0x7F までのASCII文字はそのままwrite(wchar_t)
が呼び出され、3バイトのUTF-8エンコードされた日本語文字は、連続して3バイトを投入した時点でwrite(wchar_t)
が呼び出されます。
日本語文字セットを表示するためのフォントの取り扱いについてはTWEFONT::FontDefを参照してください。
ターミナルの行数、カラム数を返す。
<<
演算子を用いてターミナルに文字列を書き出します。
フォントの描画
フォントをスクリーン上に描画します。
以下の例では、Bボタンを押すたびに、事前に生成したフォントID=10のフォントを用いて固定の文字列を描画します。
font
を用い、左上座標(x
,y
)に、文字色fg
、背景色bg
、オプションopt
で文字を描画します。
uint16_t c
をパラメターとして与えた場合は、Unicode c
に対応する文字を1文字描画します。
const char *s
をパラメータとして与えた場合は、s
をUTF-8としてデコードし、文字列として出力します。
const uint16_t* s
をパラメータとして与えた場合は、Unicode文字列として描画します。
opt
はオプションのビットマップです。以下の指定が可能です。
0x01
- 太字指定
0x02
- カーソルの描画
戻り値は、描画が行われればX(幅)方向に描画したピクセル数を返し、エラーなどが発生したときは0を返します。
実装時では以下のM5StackのAPIを利用しています。
M5.Lcd.startWrite()
M5.Lcd.setWindow()
M5.Lcd.endWrite()
tft_Write_16()
固定長キューFixedQueue
を利用し、入力キューとしていくつかのメソッドを追加しています。
キューが一杯になった後にpush()
で要素を追加した場合は、末尾の要素を抹消して追加します。
n
を最大値としてキューを初期化・生成します。
n
を最大値としてキューを初期化・生成します。
キューに要素を追加します。
キューが一杯になった後にpush()
で要素を追加した場合は、末尾の要素を抹消して追加します。
キューの先頭要素を戻り値し、またキューよりその要素を削除します。
キューが一杯になるとtrue
を返します。
キューに要素があればtrue(!=0)
、なければfalse(==0)
といった判定を目的とします。
printfmt, fPrintf(), snPrintf()
printf, sprintfに対応する処理を行います。
本ライブラリではMacro Poland氏のprintf,sprintfライブラリを利用しています。
ストリームオブジェクトに対して<<
演算子の右オペランドとして利用します。
printfmt
クラスのコストラクタのパラメータの1番目fmt
に書式を指定します。以降のパラメータはC++テンプレートのパラメータパックで実装されており可変数引数となっています。printfのように書式に対応した引数を指定します。printfと違い引数の数は最大4つに制限されます。
ストリームオブジェクトを出力先としてfprintfと同じ処理を行います。
1番目の引数がストリームオブジェクトとなる点を除きfprintfと同じ使い方です。
snprintfの処理を行います。
本クラスは namespace TWE
内に定義されています。
出力ストリームの基底クラスで、以下のメソッドが定義されており、1バイトの出力、改行文字など特殊クラスを受け付けるためのメソッドが定義されています。
operator ()
はchar_t
型の1文字を出力するための仮想関数です。write_w()
はwchar_t
型の出力に対応します。
ストリームへの出力は<<
演算子を用います。最終的には上記の出力用の関数が呼び出されます。
以下の例はITermクラスでの実装例です。
operator << の右オペランドとして以下の型に対応します。
曖昧性の解決のため、派生クラスで明示的なオーバーライドが必要になる場合があります。
特殊な文字列などを指定するためのオブジェクトを定義するための基底クラスです。
派生クラスとして CR LF (0x0d 0x0a) を出力する IStream_endl が定義されています。
オブジェクトcrlf
は以下のように使用します。
固定長キュー
固定長のキューを実装します。
n
を最大値としてキューを初期化・生成します。
n
を最大値としてキューを初期化・生成します。
キューに要素を追加します。
キューに要素を追加しますが、キュー内部にはデータコピーせず、替わりにキュー内部の要素へのポインタを返します。
キューから要素を削除します。
先頭要素にアクセスします。
末尾要素にアクセスします。
配列のようにインデックスを指定して、キューの要素にアクセスします。
キューの先頭要素を戻り値し、またキューよりその要素を削除します。(pop()
とfront()
の組み合わせです)
キューが空の場合true
を返します。
現在キューにあるアイテム個数を返します。
キューの最大長を返します。
設定
意味
TERM_ATTR_OFF = 0x0
すべての属性をクリアする
TERM_BOLD
文字を太字にする
TERM_REVERSE
背景色と文字色を反転表示する
設定
意味
TERM_COLOR_FG_BLACK
黒
TERM_COLOR_FG_RED
赤
TERM_COLOR_FG_GREEN
緑
TERM_COLOR_FG_YELLOW
黄
TERM_COLOR_FG_BLUE
青
TERM_COLOR_FG_MAGENTA
マゼンタ
TERM_COLOR_FG_CYAN
シアン
TERM_COLOR_FG_WHITE
白
設定
意味
TERM_COLOR_BG_BLACK
黒
TERM_COLOR_BG_RED
赤
TERM_COLOR_BG_GREEN
緑
TERM_COLOR_BG_YELLOW
黄
TERM_COLOR_BG_BLUE
青
TERM_COLOR_BG_MAGENTA
マゼンタ
TERM_COLOR_BG_CYAN
シアン
TERM_COLOR_BG_WHITE
白
ジェネレータ
ワイド幅 文字数
収録
createFont???_mini()
576
ASCII, latin1拡張, JIS-X201(半角カナ:0xA1-DF), かな,カナ,記号(選別), 漢字(選別:MWM5ソース中に出現する文字をスクリプトにより抽出・追加), スクリプト指定文字
createFont???_std()
createFont???()
2645
ASCII, latin1拡張, JIS-X201(半角カナ:0xA1-DF), かな,カナ,記号,常用漢字,スクリプト指定文字
createFont???_full()
6867
ASCII, latin1拡張, JIS-X201(半角カナ:0xA1-DF), かな,カナ,記号,漢字,スクリプト指定文字
パラメータ
意味
const char *s
文字列 s をターミナルに書き出す (UTF-8のデコードを行います)
IStreamSpecial& sc
crlf (改行)など特殊文字を出力する
char_t c
文字 c をターミナルに書き出す (UTF-8のでコードを行います)
wchar_t c
文字 c (Unicode)をターミナルに書き出す
int i
printf("%d", i) に該当する出力を行います
TermAttr a
文字属性を設定します
メソッド名
解説
post_refresh()
サブクラスでのrefresh()実装で、最後に呼び出す必要があります。必要な変数の初期化を行います。
resize_screen()
指定されたカラム数・行数に従い、バッファを再構成します。コンストラクタ指定の初期値を超えた指定はできません。
column_idx_to_vis()
uint16_t column_idx_to_vis(int16_t idx , int16_t lin)
Unicodeで管理されている画面バッファー上の行位置・カラム位置(ともに0が先頭位置)から、画面上のカラム位置を計算します。日本語文字のような2文字幅文字を2カラムとして計算します。 "abcあいう"という文字列が格納された行のカラム位置4は"い"の文字が格納されますが、本関数で画面上のカラム位置を計算すると5になります。
column_vis_to_idx()
column_vis_to_idx(int16_t c_vis, int16_t lin)
画面上の行位置、カラム位置(ともに0が先頭位置)から、画面バッファー上のカラム位置を計算します。日本語文字のような2文字幅文字を2カラムとして計算します。 "abcあいう"という文字列が格納された行の画面上のカラム位置5または6は"い"の文字が格納されますが、本関数で画面バッファー上のカラム位置を計算すると4になります。
右オペランドの型 | 解説 |
| 1バイト出力する |
| 文字列を出力する |
| ワイド文字を出力する(派生クラスで対応がある場合) |
| 特殊文字列を出力する |
| printf()に相当する出力を行う |
| printf("%d", n)に相当する出力を行う |
| printf("%.3%, n)に相当する出力を行う |
uint8_t
型のバイト配列ですが、メモリ確保をローカル変数とします。一時的なオブジェクトして利用することを想定しています。
uint8_t
型のバイト配列ですが、メモリ確保をローカル変数とします。一時的なオブジェクトして利用することを想定しています。
uint8_t
型のバイト配列ですが、メモリ確保をローカル変数とします。一時的なオブジェクトして利用することを想定しています。
またIStreamOut
を継承しているため<<
演算子などを利用したバッファへのデータ投入が可能です。wchar_t
型の文字列に対してはUTF-8への変換を行います。
固定バッファ長の配列クラス
可変長の配列ですが、最大長は固定の配列クラスです。
配列のメモリは、外部の固定バッファを参照する方法と、内部にコストラクタで確保する方法の2種類があります。
外部のバッファを参照する場合、参照先のメモリを安全に利用できるようユーザプログラムで管理しなければなりません。
いくつかの派生クラスを定義するためtemplateによる定義となっています。
パラメータなしのコンストラクタは、バッファ未登録として初期化します。バッファが未登録の場合はlength_max()
が0になります。このオブジェクトを配列として利用するにはattach()
メソッドにより改めてバッファを登録する必要があります。
外部のバッファを参照する場合は、バッファへのポインタp
、配列の初期長u16len
、配列の最大長u16maxlen
を指定します。
メモリを動的確保するにはu16maxlen
のみを指定するコンストラクタを呼び出します。
コピー元が、外部メモリ参照の場合は、コピー元の参照先をそのままコピーします。
コピー元が、内部にメモリ確保している場合は、コピー元のメモリ領域をそのまま利用します。新たにメモリのコピーを作成するわけではありません。本クラスでの内部確保したメモリは、スマートポインタshared_ptr
で管理されます。コピー先とコピー元すべてのオブジェクトが破棄された時点で、メモリ領域を破棄します。
配列の参照先を再設定します。
内部メモリ確保のオブジェクトの場合、内部メモリのスマートポインタを破棄しません。
一時的に部分配列として取り扱うといった使い方を想定します。以下の例では、128バイトの長さのbuf
を生成した後に、先頭17バイト目から末尾までの部分配列buf_sub
を生成しています。
配列の先頭ポインタ、末尾+1のアドレスのポインタを返します。STLのアルゴリズムや範囲for文などで利用されます。
配列バッファの先頭ポインタを得るときにbegin()
を用います。
⇒push_back()
配列の末尾に要素を追加します。要素が追加できないときはfalseが戻ります。
⇒size(), capacity()
size()
は配列の長さ、capacity()
は配列の最大長を返します。
⇒reserve()
配列の長さを変更します。現在の長さより大きくなる場合は要素型T
のデフォルトの初期化方法T{}
にて初期化されます。数値型なら0です。
配列へのアクセス手段を提供します。
インデックスi
は、負の値の場合は配列の末尾からのインデックスとなります。-1
が末尾になります。
引数
意味
T
データ型
SOUT
IStreamOut
派生クラスを継承することで<<
演算子などを用いたデータ追加を可能とします。
IStreamOut
クラスを継承するとメンバー変数が増えるため、デフォルトはダミーとなっています。
is_sting_type
1
を指定すると、文字列型 (uint8_t
やwchar_t
) の場合に、NUL終端を意識したコードを有効にします。
バッファを確保する際に終端文字分を余分に確保する
固定長配列によるコピーコンストラクトなどではNUL文字までをコピー対象とする