# Modbus サーバー

> ステーション自身の Modbus TCP サーバー：「通信」欄にあるその行、オンとオフの切り替え、ポートと接続中のクライアント、タグ、Logic の変数、警報の状態を提供するレジスターマップ、クライアントが読み書きするもの、通しの例、そしてこのサーバーがしないこと。

**Modbus サーバー**を使うと、Modbus TCP しか話さない PLC、HMI、ビル管理システムが、ステーションのタグ、Logic の変数、警報の状態を読み、許可したタグと変数に書き込めます。データがステーションから出ていく 2 つ目の道で、[内蔵の OPC UA サーバー](connector-opcua-server)と並びます。ドライバーではありません。ドライバーは機器を読みますが、Modbus サーバーは機器から読まれる側で、PLC が接続してくるのを待ち、自分からはどこにも接続しません。パネルはタイトルの下でそう言っています：「Modbus TCP で読み書きする PLC、HMI、ビル管理システムに応答します。接続を受けるだけで、自分からは接続しません。」

Modbus にはユーザー名もパスワードもありません。ポートに届いた者は、マップが提供するすべてのレジスターを読めます。そのためサーバーはオフで始まり、マップのどの行も読み取り専用で始まり、書き込みは誰かがそう選んだ行ごとに許可されます。Connector の表示 でこのページを読め、Connector の構成 で変更できます。

## 欄の中の行 {#the-row-in-the-column}

**Modbus サーバー**の行は、「通信」欄のツリーのサーバーのフォルダーの中、OPC UA サーバーの行の下にあり、ドライバーがプラグを示すところにサーバーのアイコンを示します。この行はいつもあります。ステーションにちょうど 1 つあり、作ることも削除することもありません。検索ボックスは名前でこの行を見つけ、状態チップは状態でこの行を分けます。オフのあいだは**オフ**、ポートが使われているか待ち受けられなかったときは**問題あり**、それ以外は**正常**です。名前の横にサーバーがいま何をしているかを書き、ドットがそれをまとめます：

| 行の表示 | ドット | いつ |
| --- | --- | --- |
| 「オフ」 | 灰色 | サーバーはオフです。どのステーションもこの状態で始まります。 |
| 「ポート 502 で待ち受け中」、続いて接続中のクライアントの数：「接続中のクライアントはありません」「1 台のクライアントが接続中」「3 台のクライアントが接続中」 | 緑 | サーバーはオンで、ランタイムが動いています。ポートは開いています。 |
| 「ポート 502 は使用中です」 | 赤 | サーバーはオンですが、別のプログラムがポートを押さえています。 |
| 「ポート 502 で待ち受けできませんでした」 | 赤 | サーバーはオンですが、Windows が別の理由でポートを開くのを拒みました。 |
| 「ランタイム停止中」 | 灰色 | サーバーはオンで、ランタイムは止まっています。ランタイムがまた動くまでポートは閉じたままです。 |

このドットはサーバーだけのものです。ドライバーのフォルダーのまとめにもステータスバーにも入りません。そちらはステーションが読む機器についてのものだからです。行を選ぶとサーバーのパネルが開き、その見出しは同じドットの横に状態を繰り返します。コマンドはコマンドバーにあり、行そのものにメニューはありません。

## オンとオフ {#turning-it-on-and-off}

| コマンド | 何をするか | 灰色になるとき（状況） | 描かれないとき（ロール） |
| --- | --- | --- | --- |
| **有効化** | ツールチップのとおりサーバーをオンにします：「サーバーをオンにします。ランタイムの動作中はポート 502 で待ち受けます。」ランタイムが動いていればポートはすぐに開き、操作ログ帯に「Modbus サーバーをオンにしました。」と出ます。 | サーバーがすでにオン（「サーバーはすでにオンです。」）、実行記録がステーションを押さえている、またはランタイムが止まっているとき。ツールチップに理由が出ます。 | Connector の構成 がないとき。 |
| **無効化** | サーバーをオフにします：「サーバーをオフにします。ポートを閉じ、すべてのクライアントを切断します。」操作ログ帯に「Modbus サーバーをオフにしました。」と出ます。 | サーバーがすでにオフ（「サーバーはすでにオフです。」）、実行記録がステーションを押さえている、またはランタイムが止まっているとき。 | Connector の構成 がないとき。 |

オンかオフかはステーションが覚えている設定で、待ち受けはランタイムに従います：

| 場面 | サーバーがすること |
| --- | --- |
| ステーションが起動する | オンのまま残されたサーバーは、ランタイムが立ち上がり、再開する実行記録が戻ってからポートを開きます。オフのまま残されたサーバーはオフのままです。 |
| ポートを開けない | 行に「ポート 502 は使用中です」または「ポート 502 で待ち受けできませんでした」と出て、「ポートとクライアント」カードがポートの欄の下に「ポート 502 はこのコンピューターで使用中です。使っているものを閉じるか、別のポートを選んでください。」と出すか、同じ失敗に Windows が示した理由を添えて出します。ステーションはサーバーなしで動き続けます。サーバーは自分ではやり直しません。ポートが空いたら、オフにしてからまたオンにするか、別のポートに移してください。 |
| ランタイムが止められる | ポートが閉じ、すべてのクライアントが切断されます。まだ応答を待っていた書き込みは待つのをやめます。行には「ランタイム停止中」と出て、ランタイムを再起動するとポートがまた開きます。 |
| アプリケーションを閉じる | ほかのすべてと一緒にポートが閉じます。 |

## 「ポートとクライアント」カード {#the-port-and-clients-card}

パネルの最初のカードは**ポートとクライアント**です。

| 項目 | 何をするか | 値と既定 |
| --- | --- | --- |
| **TCP ポート** | サーバーが待ち受けるポートで、このコンピューターのすべてのアドレス、IPv4 と IPv6 で待ち受けます。待ち受け中に変えると古いポートを閉じて新しいポートを開くので、すべてのクライアントが切断されます。操作ログ帯に「Modbus サーバーをポート 5020 に移しました。」と出ます。 | 1 から 65535。既定は Modbus の標準の 502。 |
| **接続中のクライアント** | いま接続しているクライアントの数：「接続中のクライアントはありません」「1 台のクライアントが接続中」「3 台のクライアントが接続中」。誰かが接続している間は、表が 1 台ずつ**クライアントのアドレス**（その IP アドレスとポート、たとえば `192.168.0.20:51234`）と**接続時刻**（ステーションの書式での日付と時刻）を並べます。 | 読み取りのみ。 |

サーバーが移れないポートは、何かを保存する前に拒否されます。理由は欄の下に出て、欄は使用中のポートに戻り、サーバーは元の場所に残ります。拒否される入力は 6 つです：範囲外の数（「ポートは 1 から 65535 の間にしてください。」）、[リモートアクセス](remote-access)で設定した Web サーバーのポート（「ポート N はすでに Web サーバーが使っています。別のポートを選ぶか、先に Web サーバーを移してください。」）、[エージェント](agent)のページでエージェントアクセスに設定したポート、エージェントアクセスがオンでもオフでも（「ポート N はすでにエージェントアクセスが使っています。別のポートを選ぶか、先にエージェントアクセスを移してください。」）、[構成](connector-opcua-configuration)にある OPC UA サーバーのポート、動いていても止まっていても（「ポート N はすでに OPC UA サーバーが使っています。別のポートを選ぶか、先にサーバーを移してください。」）、Connector のページにある [MQTT ブローカー](connector-mqtt-broker) のポート、ブローカーがオンでもオフでも（「ポート N はすでに MQTT ブローカーが使っています。別のポートを選ぶか、先に MQTT ブローカーを移してください。」）、そしてこのコンピューターでいまほかの何かが押さえているポート（「ポート N はこのコンピューターで使用中です。使っているものを閉じるか、別のポートを選んでください。」）。ほかの 4 つのポートの欄も、今度はこのサーバーのポートを拒否します。理由は、欄が次に受け入れるポートまで、または行がもう一度選ばれるまで欄の下に残ります。

カードの下には注記があります：「どのユニット ID にも応答します。ほかのコンピューターがこのサーバーに届くのは、Windows ファイアウォールが TCP ポート 502 の受信を許可している場合だけです。許可するかどうかは利用者が決めることで、このステーションが自分で許可することはありません。」

サーバーが同時に受け入れるクライアントは最大 16 台です。17 台目の接続は開いたとたんに閉じられ、診断ログにそう記録されます。接続を閉じずに消えたクライアント（電源の切れた PLC、抜けたケーブル）は TCP のキープアライブで見つかり、その枠はおよそ 1 分半で空きます。

### Windows ファイアウォール {#windows-firewall}

注記の下で、点と 1 つの文が、ステーション自身の受信の規則がこのポートを通しているかどうかを述べます。[クライアントアクセス](connector-opcua-client-access#windows-firewall)のカードが OPC UA のポートについて述べるのと同じで、通していないときは 1 つの操作を差し出します。

| 状態 | 文 |
| --- | --- |
| 許可（緑） | 「プライベートネットワークとドメインネットワークで、ポート N への Modbus の受信接続を許可しています。」 |
| 未設定（琥珀） | 「ポート N を許可するこのアプリの規則がないため、ネットワーク上のクライアントが遮断される可能性があります。」**ローカルネットワークを許可** のボタンが描かれます。 |
| 対応していない（灰色） | 「この起動方法では Windows ファイアウォールを操作できません。必要であれば、オペレーティングシステム側で受信を設定してください。」開発版、持ち運びの実行、デモの起動、あるいはインストールされたアプリケーション以外の実行です。 |
| 不明（灰色） | 「Windows ファイアウォールの状態を確認できませんでした。」 |

| コマンド | 何をするか | 灰色になるとき（状況） | 描かれないとき（ロール） |
| --- | --- | --- | --- |
| **ローカルネットワークを許可** | アプリ自身の補助を昇格して起こすので、Windows が管理者の承認を求め、このポートの規則を、プライベートとドメインのプロファイル、ローカルのサブネット、そしてこのプログラムに絞って足します。その間は「適用しています…」と読め、操作ログ帯に「Modbus のポート N 向けに、Windows ファイアウォールの許可を要求しています…」、そのあと「Windows ファイアウォールは、ポート N での Modbus 接続を許可しました。」または状態の文がエラーとして出ます。承認の問いを取り消すと、状態は未設定のままです。 | 別の端末のブラウザーから（「ファイアウォールの規則は、ステーションのデスクトップアプリからのみ適用できます。」）、実行記録がステーションを押さえている、またはランタイムが止まっているとき、そして規則を当てている間（「ファイアウォールの規則を適用しています。」）。 | Connector の構成 がないとき。 |

この状態は、カードが開いたときと、ポートが変わったときに読み直されます。ですから新しいポートは、許可するまで未設定と出ます。ステーションが自分から規則を足すことはありません。

## レジスターマップ {#the-register-map}

2 つ目のカード、**レジスターマップ**がサーバーの提供するものです。各行は 1 つのタグ、1 つの Logic 変数、または 1 つの警報の状態を、クライアントが指定するレジスターやコイルに置きます。どの行も覆っていないレジスターは、クライアントにとって存在しません。カードにはこうあります：「各行は 1 つのタグ、Logic 変数、または警報の状態を 1 つのレジスターで提供します。書き込みを許可するまで行は読み取り専用で、警報を提供する行は常に読み取り専用です。許可すると、クライアントの書き込みはほかの書き込みと同じ経路を通り、クライアントのアドレスとともに診断ログに記録されます。」

### 表 {#the-table}

| 列 | 表示するもの |
| --- | --- |
| **レジスターの種類** | 保持レジスター（4xxxx）、入力レジスター（3xxxx）、コイル（0xxxx）、ディスクリート入力（1xxxx）。どれもマニュアルのアドレスがその種類に付ける先頭の数字を添えています。 |
| **レジスター** | 行が始まるレジスター（0 から数えます）と、その行が使う最後のレジスター。レジスター 1 つの行なら `0`、Float なら `0-1`。 |
| **マニュアル上** | 同じ位置を、クライアントのマニュアルや PLC のツールが書く表記で示したもの。種類の先頭の数字に、1 から数えたレジスターを続けます。保持レジスター 0 なら `40001`、そこにある Float なら `40001 から 40002 まで`、9999 を超えると 6 桁です（保持レジスター 9999 なら `410000`）。 |
| **データ型** | Boolean、Int16、UInt16、Int32、Float、String。 |
| **アクセス** | 読み取りのみ、または読み書き。 |
| **信号源** | 選択欄が付ける名前での信号源。 |
| **現在の値** | クライアントがいまそこで読む値。その行を読むクライアントが例外 04 を受け取るときはダッシュです。 |

行は種類順（保持レジスター、入力レジスター、コイル、ディスクリート入力）、次にレジスター順に並びます。行がないときは「まだ提供しているレジスターはありません。新しい行で追加してください。」と出ます。行をクリックするとその行が選ばれ、表の下にその項目が開きます。どの行が選ばれているかは、使っているウィンドウごとに別です。

表を増やすものと行を終わらせるものは、カードのタイトルの右にあります：

| コマンド | 何をするか | 灰色になるとき（状況） | 描かれないとき（ロール） |
| --- | --- | --- | --- |
| **新しい行** | どの行も使っていない最初の保持レジスターに行を追加します。Float、2 つの順序のチェックはオン、読み取り専用、信号源はまだありません。その行が選ばれ、操作ログ帯に「保持レジスター（4xxxx） 40001 から 40002 まで に行を追加しました。」と出ます。保持レジスターが残っていないときは「新しい行に使える保持レジスターが残っていません。」と出ます。 | 実行記録がステーションを押さえている、またはランタイムが止まっているとき。 | Connector の構成 がないとき。 |
| **行を削除**（危険の色） | 表で選ばれている行を、確認なしにすぐ削除します。ツールチップがその行を名指しし（「保持レジスター（4xxxx） 40001 から 40002 まで の行を削除」）、操作ログ帯に「保持レジスター（4xxxx） 40001 から 40002 まで の行を削除しました。」と出ます。その行が提供していたタグや変数には手を付けません。以後、それらのレジスターを読むクライアントは例外 02 を受け取ります。 | 行が選ばれていない（「削除する行をレジスターマップで選んでください。」）、実行記録がステーションを押さえている、またはランタイムが止まっているとき。 | Connector の構成 がないとき。 |

### 行の項目 {#a-rows-fields}

行が持つ項目と規則は、[Modbus のタグ](driver-modbus-tcp#tag-addressing)とまったく同じです。線の一方の端で受け入れられたポイントは、もう一方の端でも受け入れられます。各項目は変わった瞬間に保存され（数値は欄を離れるか Enter を押したとき、選択は選んだとき、チェックはオンにしたとき）、クライアントは切断されることなく、次の要求から新しい行で応答を受けます。

| 項目 | 何をするか | 値と既定 |
| --- | --- | --- |
| **レジスターの種類** | 行が Modbus のどの表で応答するか。コイルかディスクリート入力を選ぶと型は Boolean になり、入力レジスターかディスクリート入力を選ぶと行は読み取り専用になります。 | 保持レジスター（4xxxx）、入力レジスター（3xxxx）、コイル（0xxxx）、ディスクリート入力（1xxxx）。新しい行では保持レジスター。 |
| **レジスター番号（0 から数えます）** | 行が始まる位置で、要求の中を流れるとおりの番号です。保持レジスター 0 は、古典的な表記で 40001 と呼ぶものです。隣の**マニュアル上のアドレス**が、「マニュアル上」の列と同じく、行をその表記で示します。 | 0 から 65535。新しい行では最初の空いている保持レジスター。 |
| **データ型** | 値の並べ方で、Modbus のタグと同じ並べ方です（[値の型と個数](driver-modbus-tcp#value-types-and-quantities)）。Boolean は 1 つのレジスター（1 か 0）または 1 ビット、Int16 と UInt16 は 1 つのレジスター、Int32 と Float は 2 つ、String は UTF-8 でレジスター 1 つに 2 バイトです。コイルとディスクリート入力が持てるのは Boolean だけです。レジスターの行で Boolean を選ぶとディスクリート入力（読み取り専用）かコイル（読み書き）に移り、コイルやディスクリート入力で数値を選ぶと入力レジスターか保持レジスターに移ります。Modbus のタグのパネルと同じ動きです。 | Boolean、Int16、UInt16、Int32、Float、String。新しい行では Float。 |
| **長さ（レジスター数）** | String のときだけ描かれます。テキストが使うレジスターの数です。 | 空なら 4。1 から 65535。 |
| **上位バイトを先に（MSB first、ビッグエンディアン）** | 各レジスターのどちらのバイトを先に送るか。括弧の中はマニュアルがこの設定に使う言葉です。String では描かれず、コイルやディスクリート入力でも描かれません。 | オン。 |
| **上位ワードを先に（high word first）** | 2 つのレジスターのどちらが上位の半分を持つか。Int32 と Float のときだけ描かれます。2 つのチェックがオンなら、Float は仕様の順序どおり `AB CD` で送られます（[バイト順とワード順](driver-modbus-tcp#byte-and-word-order)）。チェックの下の**値のバイト順**が、2 つが作る並び（ABCD、CDAB、BADC、DCBA）を示します。 | オン。 |
| **アクセス** | クライアントがその行に書き込めるかどうか。入力レジスターやディスクリート入力では、**読み書き**は一覧に残ったまま灰色になり、ツールチップに「書き込みを受けるのは保持レジスターとコイルだけです。」と出ます。警報を提供する行でも灰色になり、「警報を提供する行は読み取り専用です。」と出ます。 | **読み取りのみ**または**読み書き**。新しい行では読み取りのみ。 |
| **信号源** | 行が提供するもの。一覧は「（なし）」で始まり、次に有効な機器の有効なタグがすべて、ドライバー、機器、タグ自身の名前で（「タグ · Simulated · Oven · Temperature」）、次に値を持つ Logic の変数（ブール、整数、小数、文字列、日時）がすべて、その名前で（「変数 · Setpoint」。フォルダーに入っている変数は、そのフォルダーと名前で「変数 · Oven / Setpoint」となり、同じ名前の変数も見分けられます）並びます。続いて、すべての警報が同じように名前で並びます（「警報 · Oven / High temperature」）。警報を提供する行は常に読み取り専用で、**提供する警報の状態**が示す状態を提供します。行は信号源を識別子で持つので、タグや変数の名前を変えても、機器をフォルダーに入れても、行は同じポイントのままです。一覧に出なくなった信号源は選ばれたまま残り、名前で示されます。無効なタグは「タグ · Simulated · Oven · Temperature（無効）」、無効な機器のタグは「タグ · Simulated · Oven · Temperature（機器が無効）」となり、見つからないタグまたは見つからない変数という名前に識別子が添えられるのは、もう存在しない信号源だけです。タグの[「使っている場所」](connector-tags#the-used-by-card)のカードはそのタグを提供している行を一覧にし、すべて差し替えはそれらの行を選んだタグへ動かします。 | 新しい行では「（なし）」。 |
| **提供する警報の状態** | 警報を提供する行に出ます。クライアントが警報のどの状態を読むかを選びます。**発生中（Boolean）** は条件が成り立つ間 1、**確認済み（Boolean）** は確認待ちがない間 1、**状態（数値）** は状態を数値にしたものです。 | 新しい警報の行では 発生中（Boolean）。 |

項目の下には、行を読み返す 3 つの行が出ます。位置（「レジスター 0 を使います。」または「レジスター 0 から 1 を使います。」）、クライアントにできること（「クライアントはこの行を読めますが、書き込めません。」または「クライアントはこの行を読み書きできます。書き込みはそのアドレスとともに診断ログに記録されます。」、警報を提供する行では「クライアントはこの警報の状態を読むだけで、書き込むことはありません。数値では 0 が正常、1 が発生中・未確認、2 が発生中・確認済み、3 が復帰・未確認です。」）、そしてクライアントがいまそこで読む値（「現在の値: 21.5」）です。その行を読むクライアントが値を受け取れないときは、理由が続きます：

| パネルの表示 | いつ |
| --- | --- |
| 「この行はまだ何も提供していません。信号源を選んでください。」 | 信号源が選ばれていません。 |
| 「この行の信号源はもうありません。この行を読むクライアントには例外 04 を返します。」 | タグや変数が削除されました。 |
| 「信号源にはいま有効な値がありません。有効な値が戻るまで、この行を読むクライアントには例外 04 を返します。」 | タグに有効な値がない（機器が応答せず、タグが代替値を示さない、タグかその機器が無効、限界の異常で品質が不良になった）、または変数が欠測です。 |
| 「信号源の値はこの行の型に収まりません。この行を読むクライアントには例外 04 を返します。」 | この型の行には持てない値です。整数の行の NaN や、行のレジスターより長いテキストなどです。 |

### 行が拒否するもの {#what-a-row-refuses}

サーバーの規則が拒否した変更は保存されません。理由が行の項目の上に赤で出て、直せるように変更は画面に残り、変更が受け入れられるまで行はそれまでのものを提供し続けます。ほかの行には影響しません。

| パネルの表示 | いつ |
| --- | --- |
| 「レジスター番号は 0 から 65535 の間にしてください。」 | プロトコルの範囲外のレジスター。 |
| 「Modbus のポイントが持てる型は Boolean, Int16, UInt16, Int32, Float, String です。」 | この 6 つ以外の型。エージェントだけが求められます。 |
| 「コイルとディスクリート入力が持てるのは Boolean だけです。」 | コイルやディスクリート入力の数値。エージェントだけが求められます。 |
| 「テキストが使うレジスター数は 1 から 65535 です。」 | 範囲外の String の長さ。 |
| 「レジスター 65535 から 65536 はレジスター 65535 を超えます。」 | 最後のレジスターより後で終わる行。ここでは 65535 の Float です。 |
| 「レジスター 40001 から 40002 は 保持レジスター（4xxxx） 40002 の行と重なります。」 | 同じ種類の 2 つの行が 1 つのレジスターを共有しています。 |
| 「入力レジスターとディスクリート入力はクライアントからは読み取り専用です。書き込みを受けるのは保持レジスターとコイルだけです。」 | 入力の種類で書き込みを許可したもの。エージェントだけが求められます。 |
| 「書き込みを受ける行には、書き込み先のタグまたは変数が必要です。」 | 信号源より先に読み書きを選んだ、または書き込みを許可した行で信号源を「（なし）」に戻した。先に信号源を選んでください。 |
| 「この信号源には書き込めません。書き込みアクセスのあるタグか内部値の変数を選ぶか、行を読み取り専用のままにしてください。」 | 信号源が読み取り専用のタグ、書き込まないドライバーのタグ、式の変数、またはもうない信号源である行で、書き込みを許可したもの。 |
| 「信号源はテキストか日時を持っています。それを持てるのは String の行だけです。」 | テキストや日時のタグ、または文字列か日時の変数を、ほかの型の行に置いたもの。 |
| 「警報を提供する行は読み取り専用です。クライアントは警報の状態を読むだけで、書き込むことはありません。」 | 警報を提供する行に読み書きを求めた場合。これを求められるのはエージェントだけです。 |
| 「レジスターマップのこの行はもうありません。読み込み直してからやり直してください。」 | 編集している間に、ほかのウィンドウやエージェントがその行を削除しました。 |

実行記録がステーションを押さえている間やランタイムが止まっている間は、ページのほかの変更と同じく変更が拒否され、理由が操作ログ帯に出て（「ユニットが実行中の間は構成がロックされます。」「ランタイム停止中」）、何も保存されません。

## クライアントが読み書きするもの {#what-a-client-reads-and-writes}

サーバーはどのユニット ID にも応答し、問われたユニット ID のまま応答します。TCP ではステーションを IP アドレスで指定するからです。レジスター番号は 0 から数えたまま流れます。1 から数える PLC のツールや古典的な表記を書くツールは、ずれを自分で足します：

| レジスターの種類 | 読むときの機能 | 書くときの機能 | 古典的な表記でのレジスター 0 |
| --- | --- | --- | --- |
| 保持レジスター（4xxxx） | 3 | 6（1 レジスター）または 16（複数） | 40001 |
| 入力レジスター（3xxxx） | 4 | なし：読み取り専用 | 30001 |
| コイル（0xxxx） | 1 | 5（1 コイル）または 15（複数） | 00001 |
| ディスクリート入力（1xxxx） | 2 | なし：読み取り専用 | 10001 |

ほかの機能コードには例外 01 を返します。1 つの要求で読めるのは最大 125 レジスターか 2000 のコイルまたは入力、書けるのは最大 123 レジスターか 1968 コイルです。

読み取りには、全部を返すか何も返さないかのどちらかです。各値はステーションの現在の状態から読まれ、クライアントのために評価されることはありません。タグは工業値、つまり[値の変換経路](connector-value-pipeline)を通ったあとにステーションが示す値を返し、変数はその値を返し、警報は行が指定する状態を返します。値はステーション共通の 1 つの変換で行の型に変えられます。整数の行では実数をいちばん近い整数に丸め（半分はゼロから遠い側へ）、型の限界で止めるので、Int16 の行は 40000 に対して 32767 を返します。読み取りは 2 レジスターの行の一部だけを求めてもかまいません。求めたレジスターを、符号化した値が持つとおりに受け取ります。信号源に有効な値がない行に、サーバーが取っておいた最後の値が返されることはありません。レジスターは品質を持たないので、古い数を読んだ PLC は、ステーションがもう現在の値ではないと知っている値で動いてしまうからです。クライアントには代わりに例外 04 が返り、どうするかはその PLC 自身の通信異常の処理が決めます。その代わり、値のない行が 1 つあると、それをまたぐブロック読み取りが失敗します。どの行かはマップの「現在の値」列が示します。自分で代替値を示すタグ（[無効な読み取り](connector-value-pipeline)の段で設定した、保持した最後の有効な値や宣言した数）は有効な値を持ち続け、その代替値はほかの値と同じように返されます。

クライアントの書き込みは、ほかのすべての書き込みと同じ 1 つの書き込みの入口を通ります（[Logic](logic#writing-values) を参照）。タグはその機器の配送キューを通り、工業値はタグの変換を逆にたどります。内部値の変数は Logic のキューを通ります。信号源のロックが効くので、実行中の Process のレシピやインターロックが押さえている信号源は拒否されます。入口は各値を旧値から新値として `Modbus client 192.168.0.20:51234` という出どころで診断ログに記録し、応答は各値の受領を待ちます。タグの場合、受領とは機器自身の応答です。

- 書き込みは行の全体を覆います。Float の行のレジスターを 1 つだけ書くと拒否されるので、Float は機能 16、個数 2 で書きます。
- 書き込みが届くすべての行は、値を 1 つでも送る前にマップと照合されます。どの行にもないレジスターや読み取り専用の行があれば、要求全体が拒否され、何も書かれません。
- そのあと値はレジスター順にそれぞれの信号源へ送られます。入口がそのうちの 1 つに出した拒否がクライアントへの応答になりますが、同じ要求のほかの行もすでに渡されています。

| 例外 | いつ |
| --- | --- |
| 01（不正な機能） | 1、2、3、4、5、6、15、16 以外の機能コード。 |
| 02（不正なデータアドレス） | どの行にもないレジスター、読み取り専用の行や行の一部への書き込み、65535 を超える範囲、書き込みの入口が書けないと言う信号源。 |
| 03（不正なデータ値） | 範囲外の個数や形の崩れた要求、オンかオフ以外で書かれたコイル、信号源が受け取れない値。 |
| 04（サーバー機器の障害） | 有効な値のない信号源、もうない信号源、行が持てない値。機器が拒否したか応答しなかった書き込み、または接続していない機器。 |
| 06（サーバー機器が使用中） | 実行中の Process が押さえている信号源、または止まりつつあるランタイム。 |

## 通しの例 {#a-worked-example}

PLC がステーションから炉の温度と扉のスイッチを読み、炉の設定値、つまり内部値の変数 `Variables.Oven.Setpoint` に書き込みます。パネルでは：

1. **Modbus サーバー**の行を選び、**新しい行**を押します。**レジスターの種類**を入力レジスター（3xxxx）に（レジスターは 0 のまま）、**信号源**を「タグ · Simulated · Oven · Temperature」にします。行には「レジスター 0 から 1 を使います。」と出て、**マニュアル上のアドレス**は 30001 から 30002 までになり、「現在の値」列に温度が出ます。
2. もう一度**新しい行**を押し、**レジスターの種類**をディスクリート入力（1xxxx）にし（型は Boolean になり、レジスターは 0 のまま）、扉のスイッチ「タグ · Simulated · Oven · DoorOpen」を選びます。
3. 3 回目の**新しい行**を押します。行は保持レジスター 0 に Float で置かれます。先に「変数 · Oven / Setpoint」を選び、それから**アクセス**を**読み書き**にします。行には「クライアントはこの行を読み書きできます。書き込みはそのアドレスとともに診断ログに記録されます。」と出ます。
4. コマンドバーの**有効化**を押します。行には「ポート 502 で待ち受け中」と出ます。ほかのコンピューターの PLC のために、それから「ポートとクライアント」カードの **ローカルネットワークを許可** を押します。

2 つの順序のチェックがオンのとき（Float はビッグエンディアン、上位ワードが先、`ABCD`）に PLC が求めるもの：

| 値 | 機能 | アドレス | 個数 | 古典的な表記 |
| --- | --- | --- | --- | --- |
| 温度（読み取り） | 4 | 0 | 2 | 30001-30002 |
| 扉のスイッチ（読み取り） | 2 | 0 | 1 | 10001 |
| 設定値（書き込み） | 16 | 0 | 2 | 40001-40002 |
| 設定値（読み返し） | 3 | 0 | 2 | 40001-40002 |

同じことをエージェントで、Connector の範囲の 4 つのツールを使って行うと：

```text
modbus_map_upsert(source: "Connector.Simulated.Oven.Temperature", registerClass: "InputRegister", register: 0, type: "Float")
modbus_map_upsert(source: "Connector.Simulated.Oven.DoorOpen", registerClass: "DiscreteInput", register: 0)
modbus_map_upsert(source: "Variables.Oven.Setpoint", registerClass: "HoldingRegister", register: 0, type: "Float", access: "ReadAndWrite")
modbus_server_configure(enabled: true)
```

エージェントが作った行は、`access` がほかを指定しない限り読み取り専用で、型を指定しないコイルやディスクリート入力は Boolean になります。`modbus_server_status` はサーバー全体を読み返します。状態、クライアント、そして各行とクライアントがいまそこで読む値です。ツールは[ツールを範囲ごとに](agent-tools#connector--configure)で説明しています。

## 権限とロック {#permissions-and-locks}

| 権限 | ここで開くもの |
| --- | --- |
| Connector の表示 | 行、パネル、レジスターマップを読み取りのみで。カードは「Connector を変更するには「Connector の構成」の権限が必要です。」という注記の下で操作できなくなり、動詞は 1 つも描かれません。有効化、無効化、新しい行、行を削除のどれも出ません。 |
| Connector の構成 | ページのすべて。サーバーのオンとオフ、ポート、マップの各行。 |

実行記録がステーションを押さえている間やランタイムが止まっている間は、[Connector](connector#engineering-boundaries) のページのどこでもそうであるように、動詞は描かれたまま理由付きで灰色になり、すべての変更が拒否されます。パネルを読むことと、クライアントがサーバーを読むことは続きます。エージェントがサーバーを変えられるのは[エージェントアクセス](agent-areas)の Connector の構成の範囲を通してだけで、エージェントのした変更はすべてエージェントのものとして記録されます。

## 診断ログ {#the-journal}

サーバーはイベントの[コンソール](events-console)に、Server の範囲、コンポーネント Modbus server として書きます。待ち受けを始めたときと止めたとき、開けなかったポート、すでに 16 台に応答していたので閉じた接続、そして拒否したすべての要求とその例外コードです。マップにないレジスターを毎周期問い合わせる PLC のように繰り返す拒否は、最初の 1 回を書き、続く間は数分ごとにまとめ、クライアントにまた応答できたときに 1 行で締めくくります。接続と切断は細部なので、[詳細記録](events-console#detailed-capture)のために取っておかれます。サーバーの設定やマップの変更も、ページからでもエージェントからでも記録されます。クライアントの書き込みが何をしたかは、書き込みの入口自身の行で、出どころは `Modbus client <address>:<port>` です。

## サーバーがしないこと {#what-the-server-does-not-do}

- 提供するのは MBAP ヘッダー付きの Modbus TCP だけです。シリアル回線上の Modbus RTU や ASCII のサーバーはなく、TCP 上の RTU フレームもありません。
- Windows ファイアウォールを自分から開けることはなく（開けるのは、押したときの **ローカルネットワークを許可** だけです）、1 枚のネットワークカードだけで待ち受けることもできません。コンピューターのすべてのアドレスで、1 つのポートで待ち受けます。
- どのユニット ID にも同じ 1 つのマップで応答します。マップの違う複数のユニットを持つことはできません。
- Modbus にないので、ユーザーもパスワードも暗号化もありません。ポートに届いた者はすべての行を読み、書き込みを許可したすべての行に書けます。クライアントが書く必要のない行は読み取り専用のままにし、関係のないネットワークにはポートを閉じておいてください。
- 自分からはどこにも接続しません。Modbus の機器を読むには、[Modbus TCP](driver-modbus-tcp) か [Modbus RTU](driver-modbus-rtu) のドライバーの下に追加してください。
- 自分のレジスターは持ちません。どの行も覆っていないレジスターは存在せず、クライアントが書いたものはすべてタグか変数に入ります。
- 欠けた値の代わりに返すための自分の値を取っておくことはなく、ほかの機能コード（Read/Write Multiple Registers、Mask Write Register、機器の識別）も実行しません。それらには例外 01 を返します。
- マップに独自のインポートやエクスポートはありません。ステーションの構成とともに[バックアップ](settings-backups)に入って運ばれます。
