Skip to content
Start free evaluation

SECS/GEM troubleshooting

Use this page when the PDComm SECS/GEM SDK or simulator doesn’t do what you expect. It helps you find the stage that fails and points you to the details. For the meaning of each code, see Status codes and errors. For connection and timer problems, see Connections and timeouts.

A SECS/GEM session moves through these stages in order. Each stage must finish before the next one starts.

Program start ─> TCP connection ─> HSMS Select ─> GEM communication ─> Requests and replies
(library load) tcp=1,2,5 tcp=3 → 4 gem=1 → 3 RESULT ...

In the tutorial peers (pdcomm-tutorial and PDComm.Tutorial), type state to see the current stage:

STATE tcp=4 gem=1
  • tcp is the HSMS connection state: 0 Stopped, 1 Connecting, 2 Listening, 3 NotSelected, 4 Selected, 5 RetryWait.
  • gem is the GEM communication state: 0 Disconnected, 1 NotCommunicating, 2 WaitingAck, 3 Communicating.

The C# peer prints the names instead, for example STATE tcp=Selected gem=NotCommunicating. In the simulator GUI, the TCP TRANSPORT, HSMS SELECTION, and GEM COMMUNICATION cards on the Overview workspace show the same information.

When you need a record of what happened, turn on the diagnostics log. Diagnose failures and send feedback shows how.

Symptom Check first Check next
The program can’t load the library at startup. Make sure the operating system and CPU architecture match the SDK bundle, and that the loader can find the native library: PATH on Windows, LD_LIBRARY_PATH on Linux, or an rpath to sdk/lib that you add with -Wl,-rpath when you build on macOS. Windows C++ programs also need the x64 Visual C++ runtime. On macOS, dyld: Library not loaded: @rpath/libpdcomm_ffi.dylib means the rpath is missing.
A C# program fails in PdcommRuntime.Initialize. Pass the absolute path of the native library. A wrong path raises System.DllNotFoundException. NotSupportedException means that PDComm.dll and the native library have incompatible ABI versions. Use both files from the same SDK bundle.
The simulator can’t find the Qt platform plugin. Copy the whole simulator folder, including its plugins and notice files. Clear QT_PLUGIN_PATH or QTDIR if they point to another Qt installation. On a Linux server without a display, use the headless simulator.
The passive side stays at tcp=2 (Listening). Check that the active program runs and uses the same IP address and port. Check that both sides aren’t passive and that no firewall blocks the port.
The active side keeps returning to tcp=5 (RetryWait). Check that something listens on that port. If nothing does, the connection is refused. See Connection refused.
TCP connects, but the state stays at tcp=3 (NotSelected). Check the log for a T6 timeout: the peer didn’t answer Select.req. Check whether another host already uses the equipment. See TCP connects but never becomes Selected.
The state is tcp=4 (Selected) but gem=1 (NotCommunicating). Make sure the host requested S1F13: establish in the tutorial, Establish communication in the GUI. If S1F13 fails after T3, check that both sides use the same session ID. PDComm doesn’t resend S1F13 by itself.
values returns nothing or unexpected values. Make sure the IDs exist on the peer. The simulator’s built-in equipment has SVIDs 1001 and 1002; the tutorial equipment has SVIDs 1 and 2. An unknown ID comes back as a zero-length item. For example, the reply to values 9 is SECS-II 01 01 01 00.
You see COMMAND ERROR ... InvalidState. The request isn’t allowed in the current state, for example values before communication is established, or a second establish. Check the role, and check that you don’t call a setup function that’s only allowed before start.
You see COMMAND ERROR ... Backpressure. The endpoint already waits for replies to 32 requests, or an event queue is full. Keep draining events, and send again after the replies or failures arrive. Don’t retry in a tight loop.
You see StaleToken. You used a token or event from a generation before a reconnect. After a reconnect, start the flow again with new requests.
A request ends with RESULT kind=3 (Failed). Find out whether T3 expired, the peer aborted the transaction with F0, or the connection dropped. See GEM results and T3 reply timeout.
One request always fails after T3, and later every request fails. Check whether the peer application leaves W1 messages it doesn’t handle without a reply. Every W1 message needs a reply, at least an F0 abort. See Unhandled messages and S9.
Every call returns Poisoned. The endpoint caught an unexpected internal failure and can’t be used anymore. Destroy the endpoint and create a new one. Send the reproduction steps and the log to support.
A SECS-I endpoint reports a Fault event. Make sure the read and write callbacks return immediately and never report more bytes than the buffer holds. Don’t call endpoint functions from inside a callback, and use the endpoint only on the thread that created it. See SECS-I virtual pair.
The log shows that a request was accepted but nothing after that. Acceptance only means the request was queued. Look for a reply (RESULT kind=2) or a failure (kind=3). Confirm that the equipment actually finished the work through its own events or values. ACK 0 means the request was accepted, not that the work is done.

When a GUI button is disabled, read its tooltip and the feedback text at the bottom of the workspace first. If you repeat an action before the state is right, you can end up with several queued requests.

Change one thing at a time:

  1. Use the examples and simulator from the same SDK bundle. Don’t mix PDComm.dll or native libraries from different bundles.
  2. Close every earlier session and process, and start on a new port.
  3. With the default settings (Transport fault set to Normal), run only communication setup, identity, and values.
  4. If that works, add the one feature you want to check. Write down the first failing input, the time, and the state.
  5. Run the same area again with a headless simulator scenario or an example program. Keep the record of the first failure even if another setup succeeds.
  6. Clean up with quit, Stop, or DisposeAsync, and check each process’s exit code.

Steps 3–5 are easier to explain with the diagnostics log turned on. See Diagnose failures and send feedback.

Collect the following:

  • The console output, error messages, and exit codes of the programs you ran.
  • The trace JSON file you exported from the GUI or the MCP server.
  • The diagnostics log (JSONL) and its written, dropped, and write_errors counters.
  • The SHA-256 hash of the native library you used.

Get the hash and the environment details with these commands:

터미널 창
# Linux
sha256sum "$PDCOMM_SDK/lib/libpdcomm_ffi.so"
# macOS
shasum -a 256 "$PDCOMM_SDK/lib/libpdcomm_ffi.dylib"
dotnet --info
uname -a
터미널 창
Get-FileHash "$Sdk\lib\pdcomm_ffi.dll" -Algorithm SHA256
dotnet --info

Logs and traces never contain message bodies. If they still show private details such as equipment names, lot IDs, or recipe names, mask them before you send the files, and say what you masked. Keep the originals.

Copy this form and fill it in:

SDK bundle version and native library SHA-256:
Operating system and CPU architecture:
Language and compiler or dotnet version:
Page and step you followed:
Your program's role and mode / the peer's role and mode:
Address (IP:port) and HSMS session ID:
MCP session_id, generation, and revision (if you used MCP):
State, catalog, or profile before you started:
Commands, buttons, or minimal code:
Expected reply or value:
Actual reply, error message, and exit code:
How often it happens and when it first happened:
Log and trace file names and their SHA-256:
Results from another path (headless scenario, example program):
What you need: