Armadilloフォーラム

dockerコンテナ内でmodbusの受信メッセージが表示されません

s.tanaka

2021年4月26日 13時08分

お世話になってります。

こちらで紹介されているプログラムを参考にWMB-DIO8R制御しているのですが
コンテナからデバイスに信号は送れるもののデバイスからのメッセージが表示されません。
https://armadillo.atmark-techno.com/howto/connect-armadillo-iot-g3l-wit…

なおコンテナではなくホストから直だとメッセージが表示されます。

docker run --detach --interactive --tty --restart=always --name [コンテナ名] --privileged --network host \
--mount type=bind,source=/dev,destination=/dev,bind-propagation=shared \
--mount type=bind,source=/var/run/docker.sock,destination=/var/run/docker.sock,readonly \
[イメージ名] /root/.nvm/versions/node/v14.2.0/bin/node /root/.nvm/versions/node/v14.2.0/bin/node-red

bind-propagationの設定変更を試したりしましたがエラーが出てうまくいっておりません。
docker: Error response from daemon: OCI runtime create failed: container_linux.go:370: starting container process caused: process_linux.go:459: container init caused: open /dev/console: input/output error: unknown.

何か解決法はありますでしょうか?

4.9.133-at16
アドオンモジュール RS02

コメント

古関です。

アクセス権の問題かもしれません。

dockerの起動時に、--deviceでシリアルポートのデバイスファイルに対する
アクセス許可を与えたらどうなるでしょうか?

docker run --device=/dev/ttymxc1:/dev/ttymxc1 --rm -it debian

※ ttyのデバイスファイル名は環境に合わせて変えてください。

https://docs.docker.com/engine/reference/commandline/run/
https://docs.docker.jp/engine/reference/commandline/run.html#device

https://docs.docker.com/compose/compose-file/compose-file-v3/#devices

古関様

回答いただきありがとうございます。
試したところ状況変わらずでした。

docker run --detach --interactive --tty --restart=always --name [コンテナ名] \
--privileged --network host \
--device=/dev/ttymxc0:/dev/ttymxc0 \
--device=/dev/ttymxc1:/dev/ttymxc1 \
--mount type=bind,source=/var/run/docker.sock,destination=/var/run/docker.sock,readonly \
[イメージ名] /root/.nvm/versions/node/v14.2.0/bin/node /root/.nvm/versions/node/v14.2.0/bin/node-red
--rmオプションは--restartと競合したので外しました。

RS00(RS232C)の方でも試してみましたが同じく、送信はできるが受信ができずといった状況です。

Docker version 19.03.15, build 99e3ed8919

よろしくお願いします。

古関様

お世話になっております。
こちらで色々確認していたところ、データを受信するとデバイス?プログラム?がスタックするするようです。
原因がどこにあるかは分かっていませんが情報共有します。
ホスト側のsyslogには何も出ていないようでした。

よろしくお願いします。

========================================
root@armadillo:/# jpnevulator --tty /dev/ttymxc1:38400 --read
08 52 08 EA^C
root@armadillo:/# jpnevulator --tty /dev/ttymxc1:38400 --read
0A F2 0A F9^C
root@armadillo:/#
========================================
root@armadillo:/# cu -s 38400 -l /dev/ttymxc1
Connected.
莨~.

Disconnected.
root@armadillo:/#
root@armadillo:/# cu -s 38400 -l /dev/ttymxc1
Connected.
譚>~.

Disconnected.
root@armadillo:/#
========================================
docker run --detach --interactive --tty --restart=always --name [コンテナ名] --hostname hostname \
--privileged --network host \
--device=/dev/ttymxc0:/dev/ttymxc0 --device=/dev/ttymxc1:/dev/ttymxc1 \
--mount type=bind,source=/var/run/docker.sock,destination=/var/run/docker.sock,readonly \
[イメージ名] /root/.nvm/versions/node/v14.2.0/bin/node /root/.nvm/versions/node/v14.2.0/bin/node-red

古関です。

こちらで試してみましたが、動作できました。

Node-REDでは試していませんが、
debianコンテナ上のアプリケーション(cuコマンド)から、
/dev/ttymxc0(アドオンインターフェース1に接続したRS232Cアドオンモジュール)
でデータ送受信が実行できています。

一か所だけ注意が必要で、コンテナ(debian)内のrootユーザーを
dialoutグループに入れないとttymxc0を触れませんでした。

以下、ログです。

以下を参考にインストール
https://docs.docker.com/install/linux/docker-ce/debian/
 
root@armadillo:~# docker -v
Docker version 19.03.15, build 99e3ed8919
 
root@armadillo:~# docker pull debian
root@armadillo:~# docker run --device=/dev/ttymxc4:/dev/ttymxc4 --device=/dev/ttymxc0:/dev/ttymxc0  --rm -it debian
 
root@f866a0f515ae:/# apt-get update
root@f866a0f515ae:/# apt-get install cu
root@f866a0f515ae:/# cu -l /dev/ttymxc0 -s 115200
cu: open (/dev/ttymxc0): Permission denied
cu: /dev/ttymxc0: Line in use
 
root@f866a0f515ae:/# ls -la /dev/ttymxc0
crw-rw---- 1 root dialout 207, 16 Apr 27 10:42 /dev/ttymxc0
 
root@f866a0f515ae:/# usermod -aG dialout root
root@f866a0f515ae:/# su -
root@f866a0f515ae:/# cu -l /dev/ttymxc0 -s 115200
※送受信確認

> こちらで色々確認していたところ、
> データを受信するとデバイス?プログラム?がスタックするようです。
状況があまり理解できていないのですが、
コンテナ上だとプログラムが2重に実行されるということでしょうか?

ありがとうございます。

cuやjpnevulatorでデータを継続受信できるようになりました。
modbusのメッセージを送信するプログラムはデバッグモードでは受信を確認できたものの
意図した出力が出来ていないので確認していきたいと思います。

よろしくお願いします。

古関です。

ご報告ありがとうございました。
ひとまず、通信確認できてよかったです。

> modbusのメッセージを送信するプログラムはデバッグモードでは受信を確認できたものの
> 意図した出力が出来ていないので確認していきたいと思います。

先月、Linux-Kernel側のRS485(シリアル)通信に関する不具合を修正しています。

https://armadillo.atmark-techno.com/news/20210325/software-update-aiotg…

もし、Linux カーネル (at19)よりも古いものをご利用の場合
この不具合に当たっている可能性があるため、
アップデートをしてから問題切り分けをした方がよさそうです。

以下のコマンドでバージョン確認ができます。

root@armadillo:~# uname -a
Linux armadillo 4.9.133-at19 #2 SMP PREEMPT Thu Mar 25 13:21:39 JST 2021 armv7l GNU/Linux

以下、LinuxカーネルイメージとDTBのアップデート方法です。
https://manual.atmark-techno.com/armadillo-iot-g3l/armadillo-iotg-g3l_p…

イメージは以下からダウンロードできます。
https://armadillo.atmark-techno.com/resources/software/armadillo-iot-g3…

よろしくお願いいたします。

古関さま
お世話になっております。

早速新しいカーネル試してみましたが結果は変わりませんでした。

ここまでの調査で分かったのはコンテナ上ではlibmodbusが正しく動いていないようです。
何らかの理由で受信したメッセージのslaveIDが正しくないと判断しメッセージ長を0で返しているようです。

ひとまず1バイトずつCRC-16/modbusを計算しメッセージ中のCRCと一致をみてメッセージの終わりとして運用しようと思います。

以上です。

古関です。

参考になるかわからないのですが、こちらでも確認した所、
以下の環境の場合、似たようなエラーが出ました。

エラー内容や対策です。

------------------------------------------------------
* ホスト側
debian stretch

* dockerコンテナ側
debian buster
libmodbus-devバージョン v3.1.4-2

* 確認用のアプリ
以下のhowtoのサンプルコードをコンテナ側でそのまま動作させた
https://armadillo.atmark-techno.com/howto/connect-armadillo-x1_armadill…

* エラー内容

root@9c5088e3a8ff:/# ./wmb-dio8r-ctrl /dev/ttymxc0 on
Opening /dev/ttymxc0 at 19200 bauds (N, 8, 1)
[01][05][00][03][FF][00][7C][3A]
Waiting for a confirmation...
<01><05><00><03><FF><00><7C><3A>
Request for slave 1 ignored (not -1)

------------------------------------------------------

howto記載のサンプルコードはdebian stretch環境では動作するのですが、
busterではlibmodbusのバージョン違いによりこのエラーが出るようです。

libmodbusの以下のコードパスに入っています。
https://github.com/stephane/libmodbus/blob/master/src/modbus-rtu.c#L368

こちらの環境では、サンプルコードを以下のように改造すると、エラーはでなくなりました。

diff --git a/wmb-dio8r-ctrl.c b/wmb-dio8r-ctrl.c
index ac44c85..2c00bbc 100644
--- a/wmb-dio8r-ctrl.c
+++ b/wmb-dio8r-ctrl.c
@@ -72,6 +72,13 @@ int main(int argc, char *argv[])
                return EXIT_FAILURE;
        }
 
+       if (modbus_set_slave(ctx, raw_req[0]) == -1) {
+               fprintf(stderr, "faild: %s\n"
+                       "modbus error\n",
+               modbus_strerror(errno));
+               ret = EXIT_FAILURE;
+       }
+
        req_length = modbus_send_raw_request(ctx, raw_req, raw_req_size);
        if (req_length < 0 ) { 
                fprintf(stderr, "faild: %s\n"

元のサンプルコードではModbus-RTUのRAWパケットを自前で生成し、
Slaveアドレスをパケット内に直接埋め込んでいるのですが、
新しいlibmodbusではmodbus_set_slave()で明示的に指定しないとこのエラーが出るようです。