Skip to content
Start free evaluation

TCP-to-serial gateway

A gateway receives Modbus TCP requests, forwards them to devices on a serial bus and returns the responses. In this tutorial a PDComm headless simulator acts as the gateway, and an RTU server across a pair of virtual serial ports stands in for the serial device.

terminal B terminal G terminal V terminal A
TCP client ──TCP──> gateway 127.0.0.1:1504 ── modbus-b ══ pair ══ modbus-a ── RTU server (address 7)
unit 1 ─────────> routes {"1":7, "2":9}
  • Understand a configuration with role gateway and its routes table.
  • Use trace to see TCP unit identifiers turn into serial addresses.
  • Tell a missing route (exception 0A) from a silent serial device (exception 0B).
  • The prerequisites of RTU and ASCII communication: the SDK, the C++ console and pdcomm-vserial
  • Four terminals, all started in the same working folder

Run this in terminal V and keep it open:

터미널 창
pdcomm-vserial pair --link-a "$PWD/modbus-a" --link-b "$PWD/modbus-b"

2. Open an RTU server as the serial device

Section titled “2. Open an RTU server as the serial device”

In terminal A, open an RTU server with address 7 on modbus-a:

터미널 창
"$MODBUS_SDK/bin/pdcomm-modbus-headless"
{"action":"configure","config":{"transport":"rtu","role":"server","address":"127.0.0.1:0","port":"/absolute/path/modbus-a","unit":7,"baud":19200,"parity":"even","stop_bits":1,"timeout_ms":1000}}
{"action":"connect"}
{"action":"data_set","table":"holding_registers","address":0,"values":[1200,1185]}

In terminal G, configure a second headless simulator as the gateway:

터미널 창
"$MODBUS_SDK/bin/pdcomm-modbus-headless"
{"action":"configure","config":{"transport":"rtu","role":"gateway","address":"127.0.0.1:1504","port":"/absolute/path/modbus-b","unit":1,"baud":19200,"parity":"even","stop_bits":1,"timeout_ms":1000,"routes":{"1":7,"2":9}}}
{"action":"connect"}

In a gateway configuration:

Field Meaning
transport The serial bus side, rtu or ascii. The TCP side is always Modbus TCP; tcp fails with Gateway requires a serial bus transport.
address Where TCP clients connect
port, baud, parity, stop_bits The serial bus settings, matching the devices on the bus
routes TCP unit identifier → serial address. Here unit 1 goes to address 7 and unit 2 to address 9.
timeout_ms How long to wait for the serial device; afterwards the gateway returns exception 0B.

A gateway doesn’t use unit, but the format needs a value from 1 to 247. Route keys (TCP units) must be 1–255 and values (serial addresses) 1–247; 0 or out-of-range values fail with Invalid gateway route.

In terminal B, start the C++ console and connect to the gateway. Give the client a longer timeout_ms than the gateway’s serial wait, so you receive exception 0B instead of a timeout.

터미널 창
./build/modbus-tutorial/pdcomm-modbus-tutorial
{"action":"configure","config":{"transport":"tcp","role":"client","address":"127.0.0.1:1504","port":"","unit":1,"baud":19200,"parity":"even","stop_bits":1,"timeout_ms":3000}}
{"action":"connect"}
{"action":"request","pdu":"0300000002"}
{"action":"request","pdu":"0600010064"}
{"action":"request","unit":2,"pdu":"0300000001"}
{"action":"request","unit":3,"pdu":"0300000001"}
{"action":"request","pdu":"0300000002"}
{"ok":true,"result":{"response":[3,4,4,176,4,161],"source":"wire","status":"success"}}
{"ok":true,"result":{"response":[6,0,1,0,100],"source":"wire","status":"success"}}
{"ok":true,"result":{"response":[131,11],"source":"wire","status":"exception"}}
{"ok":true,"result":{"response":[131,10],"source":"wire","status":"exception"}}
{"ok":true,"result":{"response":[3,4,4,176,0,100],"source":"wire","status":"success"}}
Request Result Explanation
Unit 1 read and write Normal Route 1→7 forwarded them to the serial server.
Unit 2 Exception 0B ([131,11]) after about 1 s Route 2→9 exists, but no device with address 9 answered.
Unit 3 Exception 0A ([131,10]) at once The route table has no unit 3, so nothing goes on the serial bus.

In terminal G, read the gateway’s record:

{"action":"trace"}

The first byte of each tx entry is the serial address:

bytes Meaning
[7,3,0,0,0,2,196,109] Unit 1’s read went to address 7.
[7,3,4,4,176,4,161,95,156] (rx) Address 7’s response
[9,3,0,0,0,1,133,66] Unit 2’s read went to address 9, with no rx after it.

Unit 3’s request never reached the serial bus, so it has no entry.

  1. Terminal B: quit
  2. Terminals G and A: {"action":"shutdown"}
  3. Terminal V: {"command":"stop"}
  • The serial bus carries one transaction at a time. Requests from several TCP clients queue up to 64 deep; beyond that a client gets exception 06 (Server Device Busy).
  • Queued requests of a client whose TCP connection closed are dropped, and a late serial reply is never delivered as the reply to another request.
  • Serial-line-only functions (07, 08, 11, 12, 17) get exception 01.
  • Serial requests are never resent automatically; a failure returns exception 0B.
  • Up to 32 TCP clients can connect.
  • Like a server, a gateway works only while it’s polled. The headless simulator and the GUI poll for you.

To reach real RS-485 devices, set port to the name of a USB-RS485 adapter and match the bus settings. See Connect a real device for wiring and settings.