gRPC 使って TOPPERS/箱庭 単体ロボットシミュレータにBluetooth デバイスを追加する(クライアント編)

# 概要
前回(2020/2/7)，以下の記事で，gRPC のサーバー側の説明をしました．

* [gRPC 使って TOPPERS/箱庭 単体ロボットシミュレータにBluetooth デバイスを追加する(サーバー編)](https://qiita.com/kanetugu2018/items/ca29ac2e964efde290b4)

今回は，クライアント側の説明です．

# サーバープログラムの実行
とはいえ，サーバー側のプログラムの実行方法説明してなかったので，ここでご説明します．

## サーバープログラムのダウンロード
まず，サーバープログラムを以下のコマンドでダウンロードしましょう．

```
git clone https://github.com/toppers/athrill-device.git
```

## サーバー側のプログラム(C#)開発環境のインストール

Visual Studio 2019をインストールしてください．
以下のサイトが参考になります．

https://qiita.com/elu_jaune/items/6a123bf73aa838c95511

## Visual Studio 2019 でサーバープロジェクトを起動

先ほどダウンロードしたサーバープログラムですが，実は Visual Studio のプロジェクトファイルが入っています．

以下のファイルを Visual Studio 2019 で起動しましょう．

```
athrill-device\device\ev3com\grpc\server\csharp\BtSerial.csproj
```
 
上記ファイルをマウスで右クリックして，「プログラムから開く」を選択し，「Micro Soft Visual Stuido 1029」を選択すると，以下のように起動されます．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244147/ceb508fc-adba-61cc-e669-e0aed2d2b00f.png)

## サーバープログラムの IP アドレス設定
起動した Visual Studio 2019 の「ソリューションエクスプローラ」内の「program.cs」をダブルクリックしましょう．

本プログラムの中で，Main関数のローカル変数 ipaddr に，適切なIPアドレスを設定してください．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244147/b89924c9-e498-c32b-1412-a08aab9b4682.png)

## サーバープログラムの起動
上記の編集が終わったら，「BtSerial」のボタンをクリックすると，以下のようにサーバープログラムが起動します．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244147/9053f0c4-ba8c-54bf-ed72-5d84c103652a.png)

サーバープログラムは，クライアントに対して，テストデータを送信し，受信待ちとなっています．

# クライアント側
ここからクライアント側の話です．
クライアント側のプログラムですが，今度はC++で実装します．
さらに，プログラムビルドは cmake でやります．

## RPC用のデータ定義
gRPC なので，まずはRPCで使うデータ定義からです．
こちらについては，すでにサーバ側で説明した通り，同じものを使用します．

https://github.com/toppers/athrill-device/blob/main/device/ev3com/grpc/proto/serial.proto

## クライアント側のプログラム

gRPC なので，当然，RPC部分は自動生成です．
コマンド実行して自動生成でもよいですが，[CMakeLists.txt](https://github.com/toppers/athrill-device/blob/main/device/ev3com/grpc/CMakeLists.txt)で以下のように自動生成することにしてます．

```cmake
get_filename_component(serial_proto "./proto/serial.proto" ABSOLUTE)
get_filename_component(serial_proto_path "${serial_proto}" PATH)
set(serial_proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/serial.pb.cc")
set(serial_proto_hdrs "${CMAKE_CURRENT_BINARY_DIR}/serial.pb.h")
set(serial_grpc_srcs "${CMAKE_CURRENT_BINARY_DIR}/serial.grpc.pb.cc")
set(serial_grpc_hdrs "${CMAKE_CURRENT_BINARY_DIR}/serial.grpc.pb.h")
add_custom_command(
      OUTPUT "${serial_proto_srcs}" "${serial_proto_hdrs}" "${serial_grpc_srcs}" "${serial_grpc_hdrs}"
      COMMAND ${_PROTOBUF_PROTOC}
      ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}"
        --cpp_out "${CMAKE_CURRENT_BINARY_DIR}"
        -I "${serial_proto_path}"
        --plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}"
        "${serial_proto}"
      DEPENDS "${serial_proto}")
```

## クライアント側の開発環境
おっと，忘れてました．
クライアント側の開発環境ですが，C++用に様々なツールのインストールが必要なので，docker で開発することにしてます．

以下のように開発環境を構築(docker イメージ作成)します．

```shell
$ cd <work_dir※作業フォルダを作ってください>
$ git clone https://github.com/toppers/athrill.git
$ git clone https://github.com/toppers/athrill-target-v850e2m.git
$ git clone https://github.com/toppers/athrill-device.git .
$ cd athrill-device/docker/v850/
$ bash create-image-athrill.bash 
```

イメージ作成成功すると，こうなります．

```
$ docker images
REPOSITORY                         TAG       IMAGE ID       CREATED        SIZE
kanetugu2015/athrill-device-v850   v1.0.0    eb2ad78d305f   7 days ago     1.31GB
```

# クライアント側のビルド方法
無事，イメージ作成でいたら，以下のコマンドでdocker コンテナ起動しましょう．

```
$ bash run-athrill.bash 
# cd athrill-device/device/ev3com/build/
# bash build.bash all
```

これでおしまいです．ビルド成功です．

## プログラムファイル構成
あ，忘れてました．クライアント側のプログラム構成ですが，以下の２ファイルです．

* [serial_client.cc](https://github.com/toppers/athrill-device/blob/main/device/ev3com/grpc/client/cpp/serial_client.cc)
  * gRPC で自動生成された RPC コードを呼び出すラッパープログラムです．
* [serial_client_main.cc](https://github.com/toppers/athrill-device/blob/main/device/ev3com/grpc/client/cpp/serial_client_main.cc)
  * 上記のラッパープログラムを呼び出すサンプルプログラムです．引数にサーバー側のIPアドレスとポート番号を取ります．

これで終わりです．チョー簡単！！

# デモの実行方法
あとは，デモです．

サーバー側はすでに起動していますから，クライアント側を以下のように実行してください．
クライアント側から，Hello World を10 回送信しています．
サーバ側は，クライアントからのデータ受信したエコーバックして，クライアント側はそのデータを表示して次のメッセージ送信を続けます．

```
root@xxx:~/workspace/athrill-device/device/ev3com/build# ./grpc/serial_client_main 172.25.0.1 50051
RECV DATA: Hello World[ 1 / 10 ]
SEND DATA: Hello World[ 1 / 10 ]
RECV DATA: Hello World[ 2 / 10 ]
SEND DATA: Hello World[ 2 / 10 ]
RECV DATA: Hello World[ 3 / 10 ]
SEND DATA: Hello World[ 3 / 10 ]
RECV DATA: Hello World[ 4 / 10 ]
SEND DATA: Hello World[ 4 / 10 ]
RECV DATA: Hello World[ 5 / 10 ]
SEND DATA: Hello World[ 5 / 10 ]
RECV DATA: Hello World[ 6 / 10 ]
SEND DATA: Hello World[ 6 / 10 ]
RECV DATA: Hello World[ 7 / 10 ]
SEND DATA: Hello World[ 7 / 10 ]
RECV DATA: Hello World[ 8 / 10 ]
SEND DATA: Hello World[ 8 / 10 ]
RECV DATA: Hello World[ 9 / 10 ]
SEND DATA: Hello World[ 9 / 10 ]
RECV DATA: Hello World[ 10 / 10 ]
SEND DATA: Hello World[ 10 / 10 ]
```

サーバー側のログはこんな感じ．

```
ipaddr=172.25.0.1 portno=50051
START BT TEST>>>>
SEND DATA:  Hello World[ 1 / 10 ]
RECV DATA:  Hello World[ 1 / 10 ]
TEST PASSED [ 1 ]
SEND DATA:  Hello World[ 2 / 10 ]
RECV DATA:  Hello World[ 2 / 10 ]
TEST PASSED [ 2 ]
SEND DATA:  Hello World[ 3 / 10 ]
RECV DATA:  Hello World[ 3 / 10 ]
TEST PASSED [ 3 ]
SEND DATA:  Hello World[ 4 / 10 ]
RECV DATA:  Hello World[ 4 / 10 ]
TEST PASSED [ 4 ]
SEND DATA:  Hello World[ 5 / 10 ]
RECV DATA:  Hello World[ 5 / 10 ]
TEST PASSED [ 5 ]
SEND DATA:  Hello World[ 6 / 10 ]
RECV DATA:  Hello World[ 6 / 10 ]
TEST PASSED [ 6 ]
SEND DATA:  Hello World[ 7 / 10 ]
RECV DATA:  Hello World[ 7 / 10 ]
TEST PASSED [ 7 ]
SEND DATA:  Hello World[ 8 / 10 ]
RECV DATA:  Hello World[ 8 / 10 ]
TEST PASSED [ 8 ]
SEND DATA:  Hello World[ 9 / 10 ]
RECV DATA:  Hello World[ 9 / 10 ]
TEST PASSED [ 9 ]
SEND DATA:  Hello World[ 10 / 10 ]
RECV DATA:  Hello World[ 10 / 10 ]
TEST PASSED [ 10 ]
<<<<END BT TEST
```