An HSMS Reply's Session ID Is Not Always the One You Sent
Select.rsp and Linktest.rsp carry the Session ID the tool chose, not the one you sent. Data replies echo it. Three real HSMS captures.
Write your own host stack and you will write this code once: take the Session ID out of the Select.rsp, keep it, and put it in every data message you send after that. The equipment told you the value, so it must be right. Now suppose the equipment puts 00 0C in that reply and your configuration said 00 0B. Below is a capture of that, taken against a simulator listener. Not one error was raised. Byte 3 of the Select.rsp was 00 — accepted — and the System Bytes came back exactly as sent. The host goes SELECTED, and every data message after it carries a Session ID the equipment disowns. The equipment copies that value straight back into its reply. Nothing catches it.
Three captures
I attached to the simulator's EQ1 passive listener (127.0.0.1:5501) from outside, over a Python socket. Every hex line below is bytes that actually crossed the socket, and only frames the equipment side logged as RX are quoted. Captured 2026-09-30. I opened three separate TCP connections and call them A, B and C. The fault wrongSessionId was on for C only, and I confirmed it was back to {} afterwards. The raw export is in content/demos/hsms-reply-session-id-mismatch.json.
E37 counts the 10 header bytes after the 4-byte length prefix from zero. Bytes 0–1 are the Session ID, and that field is where E5's Device ID lives. This equipment is configured with Session ID 11 (00 0B) and Device ID 1.
A first — the run where nothing is wrong.
00:03:00.763 TX Select.req 00 00 00 0A 00 0B 00 00 00 01 00 00 03 01
RX Select.rsp 00 00 00 0A 00 0B 00 00 00 02 00 00 03 01 4.0 ms
00:03:00.768 TX S1F13 W=1 00 00 00 1A 00 0B 81 0D 00 00 00 00 03 02 01 02 41 07 48 4F 53 54 2D 30 31 41 03 31 2E 30
RX S1F14 00 00 00 37 00 0B 01 0E 00 00 00 00 03 02 01 02 21 01 00 ... 4.7 ms
Two control messages with SType 01/02, then a data message with SType 00. Session ID is 00 0B throughout. Nothing to look at. The 21 01 00 at the head of the S1F14 body is COMMACK 0, so the link is COMMUNICATING.
A control-message reply is not an echo
In B I deliberately filled the Session ID of control messages with FF FF.
00:03:00.784 TX Select.req 00 00 00 0A FF FF 00 00 00 01 00 00 03 11
RX Select.rsp 00 00 00 0A 00 0B 00 00 00 02 00 00 03 11 4.7 ms
00:03:00.786 TX Linktest.req 00 00 00 0A FF FF 00 00 00 05 00 00 03 12
RX Linktest.rsp 00 00 00 0A 00 0B 00 00 00 06 00 00 03 12 2.3 ms
Both replies came back 00 0B, not the FF FF I sent. The Select was not refused either — byte 3 is 00, accepted (how to read a Select.rsp). System Bytes 00 00 03 11 came back unchanged.
That is half of this article. The Session ID in a control-message reply is the tool's own value, and what the request carried does not come into it. Compare-sent-against-received on a control message and correct behaviour shows up as a mismatch.
I have not verified against the text of E37 what value its control-message tables say to put in the Session ID. Implementations differ — some put the Device ID there, some FF FF — and this listener uses its own. Whether another tool would echo the request value is not something this capture can tell you. Which collapses the rule to one line: expect nothing from the Session ID of a control reply.
The reply with right System Bytes and a wrong Session ID
For C I turned on wrongSessionId and sent the same Select.req as in A.
00:03:00.804 TX Select.req 00 00 00 0A 00 0B 00 00 00 01 00 00 03 21
RX Select.rsp 00 00 00 0A 00 0C 00 00 00 02 00 00 03 21 4.0 ms
00 0C. Twelve, not eleven. Everything else is in order: SType 02, byte 3 00 for accepted, System Bytes 00 00 03 21 exactly as sent. A host that pairs transactions on System Bytes alone — which is most of them — has a perfectly good reply here (when the System Bytes do not match). The session goes SELECTED.
Keep going on the same connection and it gets worse.
00:03:00.806 TX Linktest.req 00 00 00 0A 00 0B 00 00 00 05 00 00 03 22
RX Linktest.rsp 00 00 00 0A 00 0B 00 00 00 06 00 00 03 22 1.9 ms
00:03:00.807 TX S1F13 W=1 00 00 00 1A 00 0B 81 0D 00 00 00 00 03 23 01 02 41 07 48 4F 53 54 2D 30 31 41 03 31 2E 30
RX S1F14 00 00 00 37 00 0B 01 0E 00 00 00 00 03 23 ... 0.2 ms
Linktest.rsp is 00 0B and so is the S1F14. The only frame carrying the wrong value was the Select.rsp, and the next reply on the same connection is correct again. So this fault does not show up in a log skim. You catch it by looking at that one frame.
And the code from the opening picks a value up right here. A host that learns its Session ID from the Select.rsp is now carrying twelve.
A data message gets its own value back
Back in A, on one connection, I sent S1F1 three times and changed only the Session ID.
00:03:00.772 TX S1F1 W=1 00 00 00 0A 00 0B 81 01 00 00 00 00 03 03
RX S1F2 00 00 00 32 00 0B 01 02 00 00 00 00 03 03 01 02 41 15 ... 3.5 ms
00:03:00.775 TX S1F1 W=1 00 00 00 0A FF FF 81 01 00 00 00 00 03 04
RX S1F2 00 00 00 32 FF FF 01 02 00 00 00 00 03 04 01 02 41 15 ... 3.0 ms
00:03:00.777 TX S1F1 W=1 00 00 00 0A 00 63 81 01 00 00 00 00 03 05
RX S1F2 00 00 00 32 00 63 01 02 00 00 00 00 03 05 01 02 41 15 ... 2.2 ms
00 63 is 99. It does not belong to this tool. Neither does FF FF. All three drew the same S1F2, with the same body — MDLN "VX-9000 Plasma Etcher", SOFTREV "SECSGEM-1.4.1". The equipment copied the received Session ID straight into its reply header.
E5 has a message for this situation: an unknown Device ID is S9F1. It did not arrive. This listener does not check the Session ID. Whether another tool sends S9F1 varies by tool and is not something this capture established (why you cannot count on stream 9).
So the host that learned twelve in C sends data messages as twelve, the equipment returns twelve, and the replies keep coming. The wiring is wrong and the link is green. Where it finally bites is not at the SECS layer. It bites at the gateway or in MES, wherever a tool is identified by its Device ID, or in a multi-device setup that carries several Device IDs on one socket.
Where to look in host code
- The Session ID you send comes from your configuration file. Not from the Select.rsp. It is not a value the equipment tells you and not a value you negotiate.
- Do not compare the Session ID of a control-message reply. As B shows, it is not an echo.
- Do compare it on a data-message reply. That one is an echo, so a difference is genuinely strange — though on a tool that echoes blindly it will never fire.
- Do not throw the Select.rsp's Session ID away: log it. One warning line if it differs from what you configured. Do not raise — against a tool like B that warning fires on every connect. Let a person judge it.
- Add a line to the commissioning checklist. Send one data message with a deliberately wrong Session ID. If a normal reply comes back, that tool does not inspect the field, which means it is not the thing that will catch a typo in your own configuration.
The captures above were made against the passive listener in the SECS/GEM simulator. Turn on the wrongSessionId fault, send a single Select.req, and 00 0C comes straight back.