Skip to content
Start free evaluation

HSMS

HSMS (High-Speed SECS Message Services, SEMI E37) carries SECS-II messages over TCP/IP. It replaces the serial SECS-I transport, and nearly all new equipment uses it. SEMI E37.1 (HSMS-SS) narrows HSMS to a single session per connection. PDComm implements HSMS-SS.

HSMS sends messages back to back over the TCP byte stream. Each message is a 4-byte length, a 10-byte header and the body (SEMI E37, HSMS message format):

+--------------------+--------------------------------+------------------+
| message length | header (10 bytes) | body (SECS-II) |
| 4 bytes, big-endian| see below | optional |
+--------------------+--------------------------------+------------------+
header byte 0..1 2 3 4 5 6..9
session ID W-bit + stream function PType SType system bytes
  • The message length counts the header and the body, so a message without a body has length 10.
  • The session ID tells which equipment a data message belongs to. It plays the role of the SECS-II device ID.
  • In a data message, bytes 2 and 3 hold the W-bit, stream and function. In a control message, they hold a status code or a reject reason.
  • PType names the body’s presentation type; 0 means SECS-II. PDComm accepts PType 0 only.
  • SType names the message type.

The PDComm option max_frame_bytes counts the whole frame, including the length field and header (14 bytes). The C++ tutorial example, for instance, sets max_frame_bytes to 4110 for 4096-byte messages.

SType Message Purpose
0 Data message Carries a SECS-II message.
1, 2 Select.req, Select.rsp Make the connection ready for data messages.
3, 4 Deselect.req, Deselect.rsp End communication without closing the connection.
5, 6 Linktest.req, Linktest.rsp Check that the peer is still alive.
7 Reject.req Refuse a message that can’t be accepted.
9 Separate.req End communication without a reply and close the connection.

HSMS-SS control messages use session ID 0xFFFF. PDComm treats a control message other than Reject.req with any other session ID as a protocol error.

  • The passive side opens a TCP port and waits.
  • The active side opens the TCP connection to the passive side and then sends Select.req.

Which side is active doesn’t depend on whether it’s the host or the equipment. The background overview lists the combinations.

In PDComm, you choose the mode when you create the endpoint (PDCOMM_TCP_ACTIVE or PDCOMM_TCP_PASSIVE; HsmsMode in .NET):

  • Addresses are numeric IPv4 or IPv6 addresses with a port, such as 127.0.0.1:5000. PDComm doesn’t resolve DNS names.
  • A passive endpoint binds its port as soon as you create it. With port 0, the operating system picks a free port, and you read the actual port with the local address function.
  • An active endpoint sends Select.req automatically once the TCP connection is up.
  • A passive endpoint answers Select.req with status 0 (success), or with status 1 if it’s already selected.

The HSMS state machine in SEMI E37 has three states:

TCP connected
NOT CONNECTED ---------------------------> CONNECTED: NOT SELECTED
^ | ^
| Select | | Deselect
| TCP closed, Separate.req, v |
| T6 / T7 / T8 expired CONNECTED: SELECTED
+-----------------------------------------+

A TCP connection alone isn’t enough to send data messages. Only after the Select procedure puts the connection in the SELECTED state can SECS-II messages flow.

PDComm reports the state with these values (PDCOMM_TCP_* in C, HsmsConnectionState in .NET):

Value PDComm state .NET name E37 state
0 PDCOMM_TCP_STOPPED Stopped The endpoint is stopped.
1 PDCOMM_TCP_CONNECTING Connecting NOT CONNECTED; the active side is connecting.
2 PDCOMM_TCP_LISTENING Listening NOT CONNECTED; the passive side is waiting.
3 PDCOMM_TCP_NOT_SELECTED NotSelected CONNECTED: NOT SELECTED
4 PDCOMM_TCP_SELECTED Selected CONNECTED: SELECTED
5 PDCOMM_TCP_RETRY_WAIT RetryWait NOT CONNECTED; the active side waits T5 before reconnecting.

So when the tutorial’s state command prints STATE tcp=4, the connection is selected.

When a connection drops, an active endpoint waits in RETRY_WAIT for T5 and then reconnects. A passive endpoint goes back to LISTENING for the next connection. PDComm increments a generation number for every connection attempt; if you use a token from an earlier connection on a new one, the call fails with PDCOMM_STALE_TOKEN.

Active (host) Passive (equipment)
| ---------- TCP connect -------------------> |
| ---------- Select.req --------------------> |
| <--------- Select.rsp (status 0) ---------- | both SELECTED
| ---------- S1F13 W -----------------------> |
| <--------- S1F14 -------------------------- |
| ---------- Linktest.req ------------------> |
| <--------- Linktest.rsp ------------------- |
| ---------- Separate.req ------------------> | connection closes

In PDComm, the active endpoint sends Select for you. Either side can send a linktest with pdcomm_tcp_linktest, and the receiver answers automatically. When you stop a selected endpoint, PDComm sends Separate.req.

Select.rsp and Deselect.rsp carry a status code in header byte 3 (SEMI E37, control messages):

Message Code Meaning
Select.rsp 0 Communication established
Select.rsp 1 Communication already active
Select.rsp 2 Connection not ready
Select.rsp 3 Connect exhaust
Deselect.rsp 0 Communication ended
Deselect.rsp 1 Communication not established
Deselect.rsp 2 Communication busy

Reject.req carries a reason in byte 3: 1 for an unsupported SType, 2 for an unsupported PType, 3 for a transaction that isn’t open, and 4 when the entity isn’t selected. If the peer refuses a Select, the PDComm request ends with a failure event (PDCOMM_TCP_FAILED) that carries the status code.

HSMS detects an unresponsive peer with five timers (SEMI E37, HSMS timers). PDComm has no default values: you set every timer yourself, in milliseconds.

Timer Meaning C field / .NET property What PDComm does when it expires
T3 Reply timeout: how long a W-bit request waits for its reply. t3_ms / T3Milliseconds Fails that request only (PDCOMM_TCP_T3_TIMEOUT). The connection stays up.
T5 Connection separation timeout: how long the active side waits before reconnecting. t5_ms / T5Milliseconds Reconnects when RETRY_WAIT ends.
T6 Control transaction timeout: how long Select, Deselect or Linktest waits for a response. t6_ms / T6Milliseconds Fails the request (PDCOMM_TCP_T6_TIMEOUT) and drops the connection.
T7 Not-selected timeout: how long a new connection may stay unselected. t7_ms / T7Milliseconds Drops the connection.
T8 Network intercharacter timeout: the longest gap between bytes of one message. t8_ms / T8Milliseconds Drops the connection.

Equipment manuals often specify values such as T3 45 s, T5 10 s, T6 5 s, T7 10 s and T8 5 s. Agree on the real values with the equipment or host you connect to. The tutorial examples use short values so local tests finish quickly; don’t copy them to real equipment.

Timer C++ tutorial (tutorial_options.hpp) C# tutorial (TutorialOptions.cs)
T3 5000 2000
T5 1000 20
T6 2000 2000
T7 2000 5000
T8 1000 2000

The session ID occupies header bytes 0 and 1 of every data message. In PDComm you set it with session_id (SessionId in .NET), and both sides must use the same value. When a data message arrives with a different session ID, PDComm reports a protocol error (PDCOMM_TCP_WRONG_SESSION). The tutorial examples use session ID 7.

Besides the timers, PdcommTcpOptions (HsmsOptions in .NET) holds time and memory limits. PDComm lets your application size every queue and buffer, so memory use has a fixed upper bound.

C field .NET property Meaning
connect_timeout_ms ConnectTimeoutMilliseconds The longest time one active connection attempt can block poll.
shutdown_timeout_ms ShutdownTimeoutMilliseconds The longest time a stop spends closing the connection gracefully.
write_timeout_ms WriteTimeoutMilliseconds The longest time a frame write may stall before the connection counts as failed.
max_frame_bytes MaxFrameBytes The largest frame sent or accepted, including the 14 framing bytes.
max_events, max_queued_bytes MaxEvents, MaxQueuedBytes Count and byte limits of the internal event queue.
max_write_frames, max_write_bytes MaxWriteFrames, MaxWriteBytes Count and byte limits of frames waiting to be written.
max_io_chunk MaxIoChunk The most bytes one socket call reads or writes.
max_application_events, max_application_bytes MaxApplicationEvents, MaxApplicationBytes Count and byte limits of events waiting for your application.
poll_budget PollBudget The number of internal actions one poll performs.
item_limits ItemLimits Size limits for SECS-II bodies; see SECS-II messages.

You create the endpoint with pdcomm_tcp_create in C or TcpEndpoint in C++. Input that exceeds a limit is refused with PDCOMM_LIMIT_EXCEEDED or PDCOMM_BACKPRESSURE; it’s never silently dropped. Creating an endpoint, or starting a stopped one, needs a license for the secs-gem module; without one you get PDCOMM_LICENSE_REQUIRED. Endpoints that are already connected aren’t affected. See Install and check a license.