はじめに
普通にやってたらコンテナからUSB接続のシリアル通信デバイスにアクセスできないので調べた。
開発環境を共有したいので、なんとかコンテナでやる方法ないか調べてみた。
Dockerコンテナで、シリアル通信のための/dev/tty
を使えるようにしたい。
Docker run
docker run
するときに渡せる。
docker run --device=/dev/ttyUSB0:/dev/ttyUSB0 --rm -it debian
ここ参照。
DockerコンテナからUSBデバイスへのアクセス | Armadillo
Docker compose
docker-compose.ymlだと、こんな感じでUSBシリアルの接続情報を渡せる。
devices:
- "/dev/ttyUSB0:/dev/ttyUSB0"
ここ参照。
Compose file version 3 reference | Docker Documentation
名前がわからないときは、/dev
をわたしちゃうこともできるらしい。
ただ、Version 3は対応してないらしい・・・
docker-compose device wildcard - Stack Overflow
そもそも
Macには対応してないらしい・・・
Exposing a tty serial device requires privileged and doesn't work · Issue #900 · docker/for-mac
シリアル通信をエミュレートすることにした。
mockをどこで作るかみたいな話になるかなと思うけども、エミュレートする方法があったので、試してみた。
socat
なにか送ったら、なにか返してくれるやつが欲しかったので、こんな感じで試してみたらいい感じやった。
socat PTY,link=./virtual-tty,raw,echo=0 EXEC:cat
- linkで普段
/dev/tty*
とかのポート名を指定できる - EXECでコマンド渡せる
- 2つ設定を並べたらインプットとアウトプットにしてくれる
ここらを参考にした。
socatで仮想シリアルポートを作る - Qiita
Virtual Serial Port for Linux - Stack Overflow
c++ - Emulate serial port - Stack Overflow
Emulate serial port - DebugCN
go
こんなコード使って動作確認してみた。
package main
import (
"log"
"github.com/tarm/serial"
)
func main() {
c := &serial.Config{Name: "./virtual-tty", Baud: 9600}
s, err := serial.OpenPort(c)
if err != nil {
log.Fatal(err)
}
sendMessage := "hoge1"
log.Println(sendMessage)
_, err = s.Write([]byte(sendMessage))
if err != nil {
log.Fatal(err)
}
buf := make([]byte, 128)
n1, err := s.Read(buf)
if err != nil {
log.Fatal(err)
}
log.Printf("%q", buf[:n1])
}
$ go run main.go
2021/03/26 08:30:46 hoge1
2021/03/26 08:30:46 "hoge1"
おわりに
謎技術だったコンテナと少し仲良くなれてよかった。
ペリフェラルっぽいところ関係する開発やとコンテナめんどそうやなと思ってたけど、そこそこどうにかなりそうなので、敷居がさがった。良い感じ。