Skip to content
Start free evaluation

The simulator GUI

The PDComm Modbus Simulator is a Qt application for testing Modbus servers, clients and gateways on screen. It uses the same service commands as the SDK: each button sends one JSON command.

OS How to start
macOS Open PDComm Modbus Simulator.app at the top of the SDK, or run open "$MODBUS_SDK/PDComm Modbus Simulator.app" in a terminal.
Windows bin\pdcomm-modbus-simulator.exe in the SDK
Linux "$MODBUS_SDK/bin/pdcomm-modbus-simulator"; needs a desktop session.

Keep the SDK folder together: the GUI uses the libraries in the same SDK’s lib/.

The status line at the bottom of the window shows the result of the last command:

Status line Meaning
Completed: <command> The command succeeded, for example Completed: connect.
<command> failed: <message> The command failed. The message is the SDK’s error string, for example connect failed: Io(ConnectionRefused, ...).
Connecting... You clicked Connect and the result is pending.

The GUI sends poll from a worker thread every 5 ms, so servers and gateways keep answering while the window is open. Client requests also run on the worker thread, so the window never freezes.

Connection tab connected as a TCP server on 127.0.0.1:1502, showing the Disconnect buttonConnection tab connected as a TCP server on 127.0.0.1:1502, showing the Disconnect button
Field Configuration member Description
Transport transport TCP, RTU or ASCII. Only transports included in the SDK are listed.
Role role Server, Client or Gateway. Gateway appears only in builds with both TCP and a serial transport.
TCP address address IP:port: where a server listens, where a client connects, or a gateway’s TCP side.
Serial port port Serial device path (/dev/cu.usbserial-..., COM3)
Unit unit 1–247
Baud, Parity, Stop bits baud, parity, stop_bits Serial settings. With Parity none, Stop bits must be 2.
Request timeout (ms) timeout_ms Client requests and connects, and a gateway’s serial wait
ASCII character timeout (ms) ascii_timeout_ms Longest gap between ASCII characters
Broadcast turnaround (ms) turnaround_ms Wait after a broadcast
Gateway routes (TCP unit to serial unit JSON) routes Gateway route table, such as {"1":7,"2":9}
  • Connect sends configure with the current values, then connect. On success the button turns into Disconnect. A server opened on port 0 updates TCP address to the actual address.
  • Apply configuration sends configure only. Use it to try Execute locally on the Request tab with a configuration such as RTU, without connecting.
  • You can’t change the configuration while connected; click Disconnect first. Apply configuration while connected reports configure failed: Disconnect before changing configuration.

Connected as a client, the tab looks like this:

Connection tab with Role Client, connected to 127.0.0.1:1502Connection tab with Role Client, connected to 127.0.0.1:1502

When a connection fails, the status line tells you why. Here the client tried a port nobody listens on:

Connection tab with connect failed: Io(ConnectionRefused, Connection refused) in the status lineConnection tab with connect failed: Io(ConnectionRefused, Connection refused) in the status line
Request tab: FC 03 with PDU 030000000A executed locally, response shown in hexRequest tab: FC 03 with PDU 030000000A executed locally, response shown in hex
  • Pick FC 01 to FC 43 in the list to fill in an example PDU for that function, then edit the address and values.
  • Enter a complete request PDU in hex, starting with the function code. Leave out the unit address, the MBAP header and the CRC.
  • Execute locally sends execute: it runs against this window’s data model without any I/O, and source is local.
  • Send to peer sends request: a connected client sends it to the peer, and source is wire.
  • The unit is the Unit value of the Connection tab.
  • The response pane shows the result JSON, with PDUs as hex bytes (03 08 04 B0 ...) for readability.

A request sent from a client to a server:

Request tab: FC 03 sent with Send to peer, response with source wireRequest tab: FC 03 sent with Send to peer, response with source wire

An exception response has status exception. Here a read with quantity 0 returns exception 03:

Request tab: PDU 0300000000 executed, response 83 03 with status exceptionRequest tab: PDU 0300000000 executed, response 83 03 with status exception
Data tab: JSON editor showing coils, discrete inputs, registers, files, FIFOs and device identification objectsData tab: JSON editor showing coils, discrete inputs, registers, files, FIFOs and device identification objects
  • Read model sends data_get and shows the four tables, file records, FIFOs, device identification objects, server ID and exception status as JSON.
  • Edit the values and click Apply model to replace the whole model with model_set. Every member must be present.
  • If the JSON doesn’t parse, nothing is sent and the status line shows Invalid model JSON.
  • Well-formed JSON with invalid values (such as 2 in a bit table) fails with an error like model_set failed: Bit table values must be zero or one, and the model stays as it was.
  • While connected as a server, you read and change the live server model.

JSON command reference describes the model format.

Diagnostics tab showing counters, delimiter, event_log, listen_only and registerDiagnostics tab showing counters, delimiter, event_log, listen_only and register

Read diagnostics sends diagnostics. It shows a serial server’s counters (counters), the ASCII end character (delimiter, 10 is LF), the event log, listen-only mode (listen_only) and the diagnostic register (register). A TCP server still counts exceptions (exceptions). See Diagnostics sub-functions for what each counter means.

Trace / Fault tab listing wire entries with hex request and response, and the Decode raw fault buttonTrace / Fault tab listing wire entries with hex request and response, and the Decode raw fault button
  • Read trace sends trace and lists the last 1000 requests and responses plus raw serial bytes. source is local (Execute locally) or wire (real communication).
  • Decode raw fault sends fault. Just for this button, it treats the text in the Request tab’s PDU field as raw bytes and decodes them with the decoder of the Connection tab’s Transport. The result’s source is synthetic; nothing is injected into a real line.
  • Afterwards, put a normal PDU back into the Request tab’s field.

For example, with Transport RTU and 01030000000AC5CC in the field, Decode raw fault reports Checksum in errors. Observe addresses and frames has more examples.

Security tab with a Security JSON containing mode, chain, private_key, trust, roles and null_roleSecurity tab with a Security JSON containing mode, chain, private_key, trust, roles and null_role

The Security tab takes the configuration’s security object as JSON.

  • Leave it empty for plain Modbus TCP.
  • When it has content, Connect and Apply configuration send it as security. The format is in PDComm security configuration.
  • Invalid JSON fails with configure failed: invalid type: string "Invalid JSON", expected struct Security.
  • Servers use roles and null_role; clients use hostname.
  • Paths may be relative to the folder the GUI started in, but use absolute paths in projects you’ll open elsewhere.
  • In an SDK without Security, the editor is disabled and shows Security is excluded from this build.
Menu Command Description
Save… (Ctrl+S, Cmd+S on macOS) project_export Saves the configuration and the model as a *.modbus.json file. Fails with Cannot save project.
Open… (Ctrl+O, Cmd+O on macOS) project_import Loads a file and refreshes Connection, Security and Data.
  • You can open a project only while disconnected; otherwise you get project_import failed: Disconnect before loading a project.
  • A file larger than 16 MiB or one that can’t be read gives Cannot read project; a file that isn’t JSON gives Invalid project JSON.
  • A kind other than pdcomm.modbus.project or a version other than 1 gives Unsupported Modbus project kind or version, and the current state stays unchanged.
  • The headless simulator and the MCP server load the same files with project_import; see Project files.