全てのページ
GitBook提供
1 / 14

クラス

MWX_APIRET

32bit型をラップしたAPI戻り値クラス。MSB(bit31)は失敗、成功のフラグ。bit0..30は戻り値を格納するために使用します。

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の値部を取得する。

alloc

コンテナクラス(smplbuf, smplque)のテンプレート引数として指定し、内部で利用するメモリの確保または領域指定します。

このクラスはユーザコードから直接呼び出すものではありませんが、内部的にコンテナの宣言に用いられています。

内容

alloc_attach<T>

すでにあるバッファを指定する

alloc_local<T, int N>

Nバイトのバッファを内部に静的確保する

alloc_heap<T>

指定したサイズをヒープに確保する

alloc_attachやalloc_heapではメモリ確保クラスに応じた初期化メソッド (begin())を実行する必要があります。

初期化

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のように、コンパイルエラーを発生させるためのメソッドです。

axis_xyzt

3軸の加速度センサーの値を格納するための構造体ですが、コンテナクラスに格納したときの利便性を上げるための手続きを追加しています。

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;
}

packet_rx

このクラスはTWENETのtsRxDataApp構造体のラッパークラスです。

このクラスオブジェクトは、ビヘイビアのコールバック関数またはthe_twelite.receiver.read()により取得できます。

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)が指定されています。

packet_tx

このクラスはTWENET CライブラリのtsTxDataApp構造体のラッパクラスで、このクラスをベースとした派生クラスのオブジェクトをネットワークビヘイビアより取得して利用します。

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を指定します。宛先アドレスの値については、ネットワークビヘイビアの仕様を参照してください。

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>では、同じ内容のパケットを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の規格の性質上、例外的な使用方法とお考え下さい。

この指定は有効です。

最初の送信から1秒を超えて再送され到達した同一パケットについては、新たなパケットが到達したとして重複除外が為されません。再送間隔を長く設定したり、中継でのパケット到達遅延により1秒を超えて同じパケットを受信する場合があります。

重複パケットの処理の設定は<NWK_SIMPLE>ビヘイビアの初期化で設定できます。

tx_process_immediate

tx_process_immediate()

パケット送信を「できるだけ速やかに」実行するように要求する設定です。TWENETでのパケット送信処理は、1msごとに動作するTickTimer起点で行われています。この設定をすることで、要求後速やかにパケット送信要求が処理されます。もちろん、tx_packet_delay(0,0,0)以外の設定では意味がない指定になります。

他のパケット送信処理が行われている場合は、通常の処理になります。

この指定は有効です。

tx_ack_required

tx_ack_required()

無線パケット通信では、送信完了後、送信相手先からACK(アック)という短い無線電文を得て、送信成功とする送信方法があります。このオプションを設定することで、ACK付き送信を行います。

<NWK_SIMPLE>では、この指定は無効です。コンパイルエラーになります。

<NWK_SIMPLE>は、シンプルに動作する中継ネットワークの実装を目的としており、ACK付きの通信は行いません。

tx_addr_broadcast

tx_addr_broadcast()

ブロードキャストの指定を行います。

<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>ではタイプIDを内部的に使用しています。ユーザは使用できません。

serparser

シリアル書式入出力 (mwx::serial_parser)

シリアル書式の入出力のために用います。内部に解釈済みのバイナリ系列を保持するバッファを持ち、入力時は1バイトずつ系列を読み出し書式に従い内部バッファに格納し、系列の解釈が完了した時点で完了状態になるものです。反対に出力時は内部バッファから所定の出力書式に従いバッファを出力します。

メモリバッファ取り扱い方法(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] 

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;
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); 

上記の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>>

通常の配列のように[]演算子などを用いて要素にアクセスできますし、イテレータを用いたアクセスも可能です。

smplbuf_u8<32> b1;
b1.reserve(5);

b1[0] = 1;
b1[1] = 4;
b1[2] = 9;
b1[3] = 16;
b1[4] = 25;

for(uint8_t x : b1) {
  Serial << int(x) << ",";
}

smplbufはストリーム(stream)インタフェースも有しているため、いくつかのストリーム用のメソッドを使用することができます。

smplbuf_u8<32> b1;
b1 << uint8_t(0x01)
   << uint32_t(0x1234abd);

push_back()メソッドを定義しています。末尾にデータを追記するタイプのアルゴリズムが使用可能になります。

宣言・初期化

smplbuf_local<T,N>
smplbuf_local<T,N>::init_local()

smplbuf_attach<T>
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_attachでは、使用するバッファの先頭ポインタT* bufと配列の初期サイズsizeと最大サイズNを指定します。

smplbuf_localのみ、ローカルオブジェクトとして宣言する場合は、初期化メソッド.init_local()を省略できます。

alloc_localでグローバルオブジェクトを生成する場合は、smplbufコンテナの使用前に.init_local()メソッドを呼び出します。

初期化子リスト

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)

末尾にメンバー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_hear(), 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は末尾から一つ手前となります。

to_stream()

inline std::pair<T*, T*> to_stream()

//例
smplbuf_local<uint8_t, 10> b1;
b1.init_local();
b1 = { 0x30, 0x31, 0x32, 0x33 };

Serial << b1.to_stream();
// Output->0123

ストリームへの出力目的で利用します。

ストリーム (stream)

inline size_t write(int n)
inline static void vOutput(char out, void* vp)
inline void flush(void)

上記の実装を行っています。

  • << 演算子を用いて配列にデータを書き込む

  • printfのアルゴリズムを用いた関数を持ちて配列にデータを書き込む

  • flush()によりバッファの末尾にヌル文字を書きこむ(配列のサイズは変更しません)

smplque

FIFOキューを構造のコンテナクラスです。

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です。必要に応じてサイズを拡張しながら使用します。

// 内部に固定配列
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);

FIFOキューですのでpush(),pop(),front()といったメソッドを用いて操作します。

smplque_local<int, 32> q1;
q1.init_local();

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,

イテレータによるアクセスも可能です。

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) << ',';
}

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のみ、ローカルオブジェクトとして宣言する場合は、初期化メソッド.init_local()を省略できます。

smplque_localのグローバルオブジェクトを生成する場合は、smplbufコンテナの使用前に.init_local()メソッドを呼び出します。

メソッド

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構造体の特定のメンバーに注目したイテレータによるアクセスがあります。

mwx::stream

入出力ストリーム

入出力ストリームを処理する上位クラスです。

  • CRTP (Curiously Recurring Template Pattern) 手法を用いたポリモーフィズムにより、いくつかのクラス(Serial, Wire, SPI, smplbuf) にインタフェースを提供します。

    • CRTP では下位クラスは template class Derived : public stream<Derived>;のように定義し、上位クラスからも下位クラスのメソッドを参照します。

  • 本クラスでは 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バイト出力する(ビッグエンディアン順)

format()

printf 形式での出力

mwx::crlf

改行 CRLF の出力

mwx::flush

出力のフラッシュ

bigendian()

数値型をビッグエンディアン順で出力する。(右辺値)

std::pair<T*, T*>

バイト型の begin(), end() ポインタを格納したペア。make_pair により生成できる。Tは uint8_t 型を想定する。(右辺値)

bytelist()

std::initializer_list を用いるバイト列の出力

smplbuf<T>::to_stream()

smplbuf<T> のデータを出力する Tは uint8_t 型を想定する

バイト列として出力する際は、uint8_t, uint16_t, uint32_t 型にキャストします。また文字列として数値出力する場合は明示的にint形にキャストするようにしてください。

operator >>

// examples
Serial << "this value is" // const char*
       << int(123)
       << '.';
       << mwx::crlf;
// result -> this value is 123.

// example: SPI transmission
uint8_t val;
if (auto&& x = SPI.get_rwer()) {
  (x << (0x61)) >> null_stream(1); // discard read byte
  (x << (0x00)) >> val; // read a byte to val
}

入力処理を行います。

setup() 内では実行できません。

引数型

解説

uint8_t

1バイト入力

uint16_t

2バイト入力(ビッグエンディアン順)

uint32_t

4バイト入力(ビッグエンディアン順)

null_stream(int n)

nバイト読み捨てる

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); // set timeout as 1000ms.
uint32_t u32val;
Serial >> u32val;

入力タイムアウトとエラーを管理します。set_timeout() によりタイムアウト時間を指定し、>>演算子により入力処理を行います。所定時間内までに入力が得られない場合は get_error_status() によりエラー値を読み出せます。clear_error_status()によりエラー状況をクリアします。

引数型

解説

centisec

1/100秒単位でタイムアウト時間を設定します

エラー値

値

意味

0

エラーなし

1

エラー状況

format (mwx::mwx_format)

mwx::stream に printf の書式を入力

mwx::stream の << 演算子に対してフォーマット書式を書き出すヘルパークラスです。ライブラリ内では Using format=mwx::mwx_format; として別名定義しています。

Serial << format("formatted print: %.2f", (double)3123 / 100.) << mwx::crlf;

// formatted print: 31.23[改行]

可変数引数リストに登録できる引数は最大4つ。

  • コンストラクタで受け取った引数リストを、パラメータパックの展開機能を用いてクラス内部変数に格納する

  • operator << が呼び出された時点で、fctprintf() を呼び出し、ストリームにデータを書き出す

コンストラクタ

format(const char *fmt, ...)

コンストラクタでは、書式のポインタとパラメータを保存します。続く <<演算子による呼び出しでフォーマットを解釈して出力処理を行います。

パラメータ

解説

fmt

フォーマット書式。

TWESDK/TWENET/current/src/printf/README.md 参照

...

フォーマット書式に応じたパラメータ。 ※ 最大数は4で、5つ以上のパラメータではコンパイルエラーとなる。

※ 書式との整合性はチェックしないため、不整合な入力に対しては安全ではない。

fmtは本オブジェクトが破棄されるまで、アクセス可能であることが必要です。

mwx::bigendian

twe::stream にビッグエンディアン順で数値型のデータを出力する

mwx::stream の << 演算子に対して数値型をビッグエンディアンのバイト列で出力するヘルパークラスです。

Serial << mwx::bigendian(0x1234abcdUL);

// output binary -> 0x12 0x34 0xab 0xcd

コンストラクタ

template <typename T>
bigendian::bigendian(T v)

パラメータ

解説

v

uint16_t または uint32_t の型の値

mwx::crlf

twe::stream に改行コードを出力する

mwx::stream の << 演算子に対して改行コード (CR LF) を出力するためのヘルパークラスのインスタンスです。

Serial << "hello world!" << mwx::crlf;

mwx::flush

twe::stream へのバッファ出力をフラッシュする。

mwx::stream の出力バッファをフラッシュする。flush() メソッドを呼び出すヘルパークラスへのインスタンス。

for (int i = 0; i < 127; ++i) {
    Serial << "hello world! (" << i << ")" << twe::endl << twe::flush;
}
  • シリアルポートの場合は出力完了までポーリング待ちを行う

  • mwx::simpbuf バッファの場合は 0x00 を末尾に出力する(サイズは変更しない)