ヘルパークラス版はより抽象度の高い実装です。読み書きを行うオブジェクト
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
で指定したデータバイト分だけ読み飛ばします。