TOPPERS BASE PLATFORMを改造してESP32をATコマンドで使ってみる

# Wi-Fi接続に対応したい

Azure IoTに接続するアプリを作ったのですが、有線LANで接続するものしかなかったのでWi-Fiでも接続したいと思い、手元にあったESP32を使用することにしました。
ESP32自体でもArduino IDEやIDFを使って単体でソフトを作ることができますが、TOPPERSのRTOSはESP32のCPU（Xtensa）には移植されていませんので、直接ESP32でTOPPERSを動作させることは現状出来ません。
そこで、ESP32のファームウェアとして提供されているATコマンドファームウェアを使い、外部CPUからのWi-Fi接続を実現することにしました。

# TOPPERS BASE PLATFORM

TOPPERSプロジェクトでは、組込み技術者養成用の教育コンテンツを提供していて、そのコンテンツで使用するソフトウェアプラットフォームとして、TOPPERS BASE PLATFORMというのを提供しています。
そのTOPPERS BASE PLATFORMに含まれるサンプルアプリにEPSのATコマンドをシリアルコンソールを通して、手打ちで確認できるサンプルアプリがあります。
これを改造し簡単なATコマンドパーサーを追加し、Wi-Fi接続とTCPの接続が関数呼び出しで実現できるようにしました。

TOPPERS BASE PLATFORMは下記からダウンロードできます。
https://www.toppers.jp/edu-baseplatform.html

# ESP-WROOM-02シールド向けサンプルアプリ

ESPのATコマンド手打ちアプリのパスは、上記のサイトからダウンロードした```asp_baseplatformv1.4.1_051120.tar.gz```では、NOCLEO-F401RE向けのサンプルアプリで、下記のフォルダにあります。
```asp\OBJ\STM32F401NUCLEO_GCC\espshield```
このフォルダにある```esptest.c```のヘッダーコメントに書いてありますが、[ESP-WROOM-02シールド](https://www.switch-science.com/catalog/2619/)向けのコードになっているようです。
シリアルを接続するピンなどは、このシールドに合わせてあるようです。
余談ですが、TOPPERS BASE PLATFORMのリリースでは文字コードに「EUC-JP」が使われているので、「UTF-8」変換して使っています。

# シリアルコンソール

TOPPERS BASE PLATFORMではシリアルコンソール（モニター）が実装されていて、このサンプルアプリでATコマンドを入力すると、ESP32へコマンドが転送され、応答が表示されます。
ESP32のATコマンドは[ここ](https://docs.espressif.com/projects/esp-at/en/latest/AT_Command_Set/index.html)にあるように、```AT+GMR```のように入力し、改行コードも```CRLF```を使用しますが、シリアルコンソール経由では、下記のように入力し、形式が違っているので注意が必要です。改行コードも```LF```のままです。

```bash
mon> AT GMR
AT+GMR
ver ...
```

初めの```AT```＋スペースまでが、シリアルコンソールのコマンドで、引数として```GMR```を渡しています。ESP32には```AT+GMR```が渡されるようになっています。
ESP32のATコマンドを試してみるには便利ですが、通信ソフトを組み込みたいときには機能が足りません。

# ATコマンドパーサーの追加

TOPPERS BASE PLATFORMのサンプルアプリでは、ATコマンドの仲介をするだけのコードしかないので、ATコマンドの応答を読み取り、Wi-Fiの接続状態やTCPの接続状態を遷移させるような処理を実装を追加しました。
ESP32と接続したシリアルからの入力を処理するメインタスクと、入力コマンドを処理するモニタタスクの２つがあり、リングバッファを介して繋がっています。
この改造では、ESP32からのシリアル入力をユーザーへの表示ではなくATコマンドの解析処理をするコマンドパーサーに渡して、応答を処理します。
一方ユーザーからのコマンド入力で、Wi-Fi接続やTCP接続を行うので、ATコマンドを発行する側はモニタタスクになります。
ATコマンド発行を含むコマンドは、以下のようなコマンドがあります。

```bash
mon> device wifi ssid password
mon> device csgen mqtt scopeid deviceid key
mon> device setcs connection_string
mon> device iot
```

２つのタスク間のデータのやり取りにはタスク間通信が必要で、データはリングバッファで、通知はデータキューを使っています。

改造部分を含むソースコードは下記のサイトにあります。
https://dev.toppers.jp/trac_user/contrib/wiki/azure_iot_hub_riscv

# ATコマンドパーサーとAzure IoT SDK for Cを繋ぐ

ATコマンドを使ったTCP接続を行うアプリとして、Azure IoT接続サンプルアプリを使います。
ATコマンドパーサーは自前で作ったものなので、Azure IoT SDK for C には繋がるコードはありません。
GR-LYCHEEというmbed対応基板のもESP32が付いていて、それを使った経験から、mbed向けのコードから改造することにしました。
TCP接続の実装部分のファイル```socketio_mbed_os5.c```を元に、```socketio_esp_at.c```を作って、関数名のプリフィックス```tcpsocketconnection```を```esp_at_socket```にリネーム、このファイルから呼ばれる下記の関数をATコマンドパーサーのファイル```esp_at_socket.c```に実装しました。

|関数名|実装内容|
|:-:|:-:|
|```esp_at_socket_create```|TCP接続用の領域確保|
|```esp_at_socket_destroy```|TCP接続用の領域解放|
|```esp_at_socket_connect```|```AT+CIPSTART```コマンド発行し、応答があるまで待機|
|```esp_at_socket_close```|```AT+CIPCLOSE```コマンド発行、応答があるまで待機|
|```esp_at_socket_set_blocking```|設定を保存|
|```esp_at_socket_receive```|バッファにデータがある場合は読み込む、バッファにはESPからのシリアル受信時にデータが入る|
|```esp_at_socket_send```|```AT+CIPSEND```コマンド発行、応答があるまで待機|

詳しくはAzure IoT SDK for Cのポーティングガイドを見てください。
https://github.com/Azure/azure-c-shared-utility/blob/master/devdoc/porting_guide.md

# SSL/TLS

クラウドサービスにはSSL/TLSも必要です。ESP32のATコマンドでもSSL/TLS接続ができますが、ESP32と本体側CPUとはシリアルで通信しているので、簡単に読み取られてしまいます。
セキュリティを考えて本体側CPUにSSL/TLS通信部分をを実装し、それにwolfSSLを使っています。Azure IoT SDK for Cにも対応するコードが入っているのですぐに使えます。また、セキュリティ意識の高いAzure Sphereでも使われているので、安心かと思います。クローズドソースの商用向けには有償なようですが、GPLを組み込んでもいい公開用のサンプルアプリなら問題ないです。

# 動作確認したデバイス

実際にESP32とシリアル接続したデバイスは、STマイクロの「NUCLEO F401RE」と「NUCLEO F767ZI」、Sipeed社のRISC-Vボード「Maix Bit」です。

## ESP32のピン

![ESP32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242320/90d0d7a3-d382-2e62-bc84-e13655ec5750.png)

## NUCLEO F401RE

![NUCLEO_F401RE.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242320/56f98a53-a988-de87-b172-e977a7742d1b.jpeg)

- GND ⇔ GND
- D8 ⇔ U2 RXD
- D2 ⇔ U2 TXD

## NUCLEO F767ZI
![NUCLEO_F767ZI.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242320/dd786f28-84a2-7520-f8ff-d6162f1e1517.jpeg)

- GND ⇔ GND
- TX D1 ⇔ U2 RXD
- RX D0 ⇔ U2 TXD

## Maix Bit
![MAIX_BIT.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242320/62426a7f-c0f2-7cb0-d751-4625f03c444b.jpeg)

- GND ⇔ GND
- 6 ⇔ U2 RXD
- 7 ⇔ U2 TXD

# その他

また、Azure IoT Centralに接続するまでの動画もありますので、参考になればうれしいです。
https://www.youtube.com/watch?v=EAdgV0TPsZY