通信プロトコルModbus TCP(スレーブエミュレーター)

テンプレート説明

TC-3000がModbus TCPスレーブとしてLANに接続し、デバイスモデル(レジスタ/コイルマップ)に基づいてマスター機器からの要求に応答します。自ユニットID宛かつMBAP妥当な要求のみ処理し、未対応ファンクションコードや範囲外アドレスには例外応答を返します。

なお、Modbus TCPでは、応答するスレーブが接続を待ち受ける側(TCPサーバー)、要求するマスターが接続を開始する側(TCPクライアント)に対応します。本書では原則として「マスター/スレーブ」で表記します。

 

  • 1 マスター接続待ち・要求受信
    マスター機器からの接続を待ち受けます。接続確立後、MBAPヘッダ+要求PDUを受信し、プロトコルID・長さの妥当性を確認します。
  • 2 デバイスモデル参照・応答
    自ユニットID宛の要求をデバイスモデルで処理し、応答PDUを組み立ててMBAP付きで返送します。マップに存在しないアドレスや未対応FCには例外応答を返します。他ユニットID宛の要求は無視します。
  • 3 テスト停止まで継続
    上記①②をテスト停止まで繰り返します。接続が切断された場合は再接続を待ちます。応答方針は build_response() を編集することで、読取専用レジスタや意図的な異常応答などDUT固有の挙動を自由に再現できます。
初期ユニット配置
 ・スロット1:LANユニット(TC-IFLAN) ※1
  ETH1(TCPサーバー)/待受ポート 502(Modbus TCP標準)
接続設定(ユニット設定)

 ・接続モード:TCPサーバー(マスター機器からの接続を待ち受けます)。※2

 ・ETH1 IPアドレス/サブネットマスク:TC-3000側のアドレス。

 ・待受ポート番号:Modbus TCP標準は502。

※1 ユニットを別スロットへ変更する場合、ユニット設定のスロット割り付け変更を行うことで、設定値などを引き継ぎ可能です。
※2 スロットにユニットを取り付け・配線し、スクリプトの SLOTCH 設定を変更してください。IPアドレス・待受ポート等はユニット設定と、接続するマスター機器に合わせてください。

接続図

TC-3000(LANユニット)のETH1ポートと、マスター機器をEthernet(LAN)で接続します。TC-3000はスレーブ(TCPサーバー)として接続を待ち受け、デバイスモデルを参照して要求に応答します。

 

マスター機器 Modbus TCP クライアント 要求 → 応答受信 ETH(RJ45) 同一ネットワーク Ethernet(LAN) TCP/IP ・ Port 502 ①要求フレーム送信 ④応答フレーム受信 TC-3000(Modbus TCP スレーブ) LANユニット(TC-IFLAN) Modbus TCP スレーブ 自ユニットID = 1 ETH1(RJ45) 待受ポート 502 ②解析 ③応答 Luaスクリプト(device) device model 参照・応答生成 マップ / アドレス holding [0x0000] 0x0012 holding [0x0001] 0x0034 input [0x0000] 0x00FF coils [0x0000] 1 coils [0x0001] 0 discrete [0x0000] 1 未定義アドレス 例外0x02 未対応FC 例外0x01

※ TC-3000と対象機器を同一ネットワークに接続し、IPアドレス・サブネットマスクを整合させてください。ハブ/スイッチを経由する接続にも対応します。
※ マスター機器の接続先ポートを、ユニット設定の待受ポート(Modbus TCP標準は502)に合わせてください。

設定変数

全設定変数を記載しています。実機の仕様に合わせて変更してください。

変数名

内容

初期値

SLOT

使用するLANユニットのスロット番号。使用するユニットに応じて変更。

LAN1

CH

LANユニットのポート番号(ETH1=LanPort1/ETH2=LanPort2)

ETH1

OWN_UNIT_ID

自ユニットID(MBAPヘッダのUnit Identifier)。この宛先の要求のみ応答する。他ユニットID宛は無視。

1

CONNECT_TIMEOUT

マスター機器の接続(accept)の待機タイムアウト (ms)。この時間内に接続が無ければ再度待機に入る。

5000

RECEIVE_TIMEOUT

要求受信タイムアウト (ms)。この時間受信が無ければ再度受信待機に入る。

5000

device

スレーブが保持するデバイスモデル(メモリマップ)。マスターからのアクセスはこのマップを参照して処理します。各マップに存在しないアドレスへのアクセスには例外応答(0x02)を返します。

マップ 用途
holding_registers 保持レジスタ [アドレス]=16bit値。FC 0x03読出/0x06・0x10書込
input_registers 入力レジスタ(読取専用) [アドレス]=16bit値。FC 0x04読出
coils コイル [アドレス]=0/1。FC 0x01読出/0x05・0x0F書込
discrete_inputs 離散入力(読取専用) [アドレス]=0/1。FC 0x02読出

サンプル有
使用例は接続図参照

※ IPアドレス・サブネットマスク・待受ポートは、ユニット設定で設定します。接続するマスター機器と整合させてください。
※ 応答方針は build_response() を編集することで自由に変更できます。読取専用レジスタへの書込み拒否、特定アドレスへの意図的な異常応答など、DUT固有の挙動をここに実装できます。

グローバル変数の設定

以下の変数はグローバル変数に定義され、全テストスクリプトから共通で参照されます。

変数名

内容

初期値

MODBUS_TIMEOUT_MS

受信・応答関数でタイムアウト引数を省略した場合に使用する既定のタイムアウト (ms)。本テンプレートでは要求受信で RECEIVE_TIMEOUT を明示指定するため、通常この値は使用されません。

1000

MODBUS_TCP_NEXT_TID

Modbus TCPのMBAPヘッダに付与するトランザクションID(TID)の次回値。スレーブは受信した要求のTIDをそのまま応答へエコーするため、通常ユーザーが変更する必要はありません(初期値 0 のままで動作します)。

0

対応ファンクションコード

初期の build_response() が処理するファンクションコード(FC)です。未対応FCには例外応答(0x01 ILLEGAL FUNCTION)、範囲外アドレスには例外応答(0x02 ILLEGAL DATA ADDRESS)を返します。

FC

内容

対象マップ

0x01

コイル読出し

coils

0x02

離散入力(入力ステータス)読出し

discrete_inputs

0x03

保持レジスタ読出し

holding_registers

0x04

入力レジスタ読出し

input_registers

0x05

コイル1点書込み(0xFF00=ON/0x0000=OFF)

coils

0x06

保持レジスタ1点書込み

holding_registers

0x0F

コイル複数書込み

coils

0x10

保持レジスタ複数書込み

holding_registers

※ 本テンプレートはテスト実行ボタンで開始し、テスト停止ボタンで終了します。
※ 要求受信・解析・応答PDU組立・MBAP・送信の共通処理はグローバル関数(スクリプト)に定義されています。「どう応答するか」の方針のみ本スクリプトの build_response() で実装します。
※ マスター機器が接続を切断した場合、テンプレートは自動的に再接続を待ち受けます(切断時の内部エラーは pcall で捕捉し、テストを継続します)。

他のプロジェクトでModbusを扱う方法

本テンプレートは、Modbusプロトコルの処理をグローバル関数に実装しています。

・要求フレームの受信・解析、応答PDUの組立、MBAPヘッダの生成・検証、応答送信など、Modbusプロトコルの実装はすべてグローバル関数(スクリプト)に含まれます
・別のプロジェクトでModbusプロトコルを扱いたい場合は、このテンプレートのグローバル関数(スクリプト)の内容を、対象のプロジェクトのグローバル関数(スクリプト)にコピーすることで、同じModbus関数群(ModbusTcp*ModbusRtu* など)をそのまま利用できます。
・Modbus関数は MODBUS_TIMEOUT_MSMODBUS_TCP_NEXT_TID などのグローバル変数を参照します。あわせて、これらのグローバル変数も対象プロジェクトのグローバル変数に設定してください(「グローバル変数の設定」の項を参照)。
・同ライブラリはModbus TCP(LAN)とModbus RTU(RS-485/RS-422)の両方に対応しています。