# mwx::stream

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

* CRTP (Curiously Recurring Template Pattern) 手法を用いたポリモーフィズムにより、いくつかのクラス(`Serial, Wire, SPI, smplbuf`) にインタフェースを提供します。
  * CRTP では下位クラスは `template class Derived : public stream<Derived>;`のように定義し、上位クラスからも下位クラスのメソッドを参照します。
* 本クラスでは `print` メソッド、`<<` 演算子などの共通処理の定義を行い、下位クラスで実装した `write()` メソッドなどを呼び出すことで、仮想関数を用いるのと近い実装を行っています。

## インタフェース（下位クラスで実装）

下位クラスでは、以下に列挙する関数を実装します。

### available()

```cpp
int available()

// example
while(Serial.available()) {
  int c = Serial.read();
  // ... any
}
```

入力が存在する場合は 1、存在しない場合は 0 を返します。

| パラメータ     | 解説               |
| --------- | ---------------- |
| 戻り値 `int` | 0: データなし 1:データあり |

{% hint style="warning" %}
本実装の戻り値はバッファ長ではありません。
{% endhint %}

###

### flush()

```cpp
void flush()

// example
Serial.println("long long word .... ");
Serial.flush();
```

出力をフラッシュ（出力完了まで待つ）します。

### read()

```cpp
int read()

// example
int c;
while (-1 != (c = read())) {
    // any
}
```

ストリームより１バイトデータを入力します。データが存在しない場合は `-1` を戻します。

### write()

```cpp
size_t write(int c)

// example
Serial.write(0x30);
```

ストリームに１バイト出力します。

| パラメータ        | 解説                  |
| ------------ | ------------------- |
| `n`          | 出力したい文字。            |
| 戻り値 `size_t` | 出力が成功すれば 1、失敗すれば 0。 |

### vOutput()

```cpp
static void vOutput(char out, void* vp)
```

１バイト出力を行うスタティック関数です。クラスメソッドではないため、メンバー変数等の情報は利用できません。替わりにパラメータとして渡される vp にクラスインスタンスへのポインタを渡します。

このスタティック関数は内部的に利用され`fctprintf()`の１バイト出力関数として関数ポインタが渡ります。これを用いて`print`メソッドなどを実装しています。

| パラメータ | 解説                                                           |
| ----- | ------------------------------------------------------------ |
| `out` | 出力したい文字                                                      |
| `vp`  | <p>クラスインスタンスへのポインタ<br>通常は、元のクラスにキャストして write() メソッドを呼び出す</p> |

## インタフェース

### putchar()

```cpp
void mwx::stream::putchar(char c)

// example
Serial.putchar('A');
// result -> A
```

１バイト出力します。

### print(), println()

```cpp
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`       | <p>出力形式</p><p>BIN 二進数 / OCT ８進数 / DEC 10進数 / HEX 16進数</p> |
| `place`      | 小数点以下の桁数                                                  |
|              |                                                           |
| 戻り値 `size_t` | 書き出したバイト数                                                 |

### printfmt

```cpp
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 <<

```cpp
// 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`                    | １バイト出力 （数値としてフォーマットはしない）                                                                  |
| `int`                     | 整数出力 (printf の "%d")                                                                      |
| `double`                  | 数値出力 (printf の "%.2f")                                                                    |
| `uint8_t`                 | １バイト出力する(char型と同様)                                                                        |
| `uint16_t`                | ２バイト出力する(ビッグエンディアン順)                                                                      |
| `uint32_t`                | ４バイト出力する(ビッグエンディアン順)                                                                      |
| `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()` | <p><code>smplbuf\<T></code> のデータを出力する<br><code>T</code>は <code>uint8\_t</code> 型を想定する</p> |

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

### operator >>

```cpp
// 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
}
```

入力処理を行います。

{% hint style="danger" %}
`setup()` 内では実行できません。
{% endhint %}

| 引数型                  | 解説                 |
| -------------------- | ------------------ |
| `uint8_t`            | １バイト入力             |
| `uint16_t`           | ２バイト入力（ビッグエンディアン順） |
| `uint32_t`           | ４バイト入力（ビッグエンディアン順） |
| `null_stream(int n)` | nバイト読み捨てる          |

### set\_timeout(), get\_error\_status(),  clear\_error\_status()

```cpp
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 | エラー状況 |
