Your HSMS Session Is SELECTED and S1F3 Still Comes Back as S1F0
SELECTED is E37, COMMUNICATING is E30. Real bytes showing an S1F3 sent before S1F13/S1F14 aborted as S1F0, and the same S1F3 answered after.
The HSMS session is SELECTED. Linktest goes back and forth fine. Then the first S1F3 the host sends comes back not as an S1F4 but as an S1F0 — ten header bytes, no body. With no equipment to test against, that costs half a day.
Nothing is broken on the equipment. Two states one layer apart got read as one. SELECTED is the HSMS connection state SEMI E37 defines; COMMUNICATING is the GEM communication state defined by SEMI E30's communication state model. Finishing E37 does not open E30. Until S1F13/S1F14 completes with COMMACK 0 the equipment is NOT COMMUNICATING, and in that window every primary message except S1F13 is refused.
Every frame below went over a socket to the SECS/GEM simulator's passive listener (127.0.0.1:5501, SessionID 11), driven by a plain TCP client.
Select finishes E37, and that is all it finishes
Bring the session up first.
TX Select.req 00 00 00 0A 00 0B 00 00 00 01 00 00 20 01
RX Select.rsp 00 00 00 0A 00 0B 00 00 00 02 00 00 20 01
SessionID 00 0B is 11. Byte 5 is the SType: 01 in the request (Select.req), 02 in the reply (Select.rsp). Header byte 3, which would carry a Function on a data message, carries the Select Status on a Select.rsp — 00 here, a Select Status 0, so the select was accepted (SEMI E37). The HSMS state is now SELECTED.
That is everything E37 asks for. A host driver that logs "connected" at this point and moves on to its normal-operation code is where this bug starts.
A primary sent before S1F13 comes back as S1F0
The moment SELECTED lands, send S1F3, Selected Equipment Status Request, carrying one SVID as L[1]{U4 101}.
TX S1F3 W 00 00 00 12 00 0B 81 03 00 00 00 00 20 02 01 01 B1 04 00 00 00 65
| Bytes | Field | Value |
|---|---|---|
00 00 00 12 | Length | 18 — a 10-byte header plus an 8-byte body |
00 0B | SessionID | 11 |
81 | Header byte 2 | W-bit set, Stream 1 |
03 | Header byte 3 | Function 3 |
00 00 | PType, SType | 0, 0 — a data message |
00 00 20 02 | SystemBytes | 0x00002002 |
01 01 B1 04 00 00 00 65 | Body | L[1]{U4 101} |
What came back:
RX S1F0 00 00 00 0A 00 0B 01 00 00 00 00 00 20 02
The length is 00 00 00 0A, 10 — header only, no body. Byte 2 is 01: the W-bit is clear and the stream is still 1. Byte 3 is 00, Function 0. The SystemBytes 00 00 20 02 are the request's own.
In SEMI E5, SxF0 is abort transaction: the reply carries the request's stream with function 0 and an empty body. So this is an abort, not an error report. There is no S9 message and no ERRCODE — nothing inside the message tells you what was wrong. What SxF0 means next to a real stream 9 message is why you should not write a host that expects S9.
An aborted request changes no state on the equipment. The abort reply carries the request's own stream, so on a tool that answers this way an S2F41 sent before S1F13 would come back as an S2F0 rather than an HCACK. That is inference from E5's rule, not capture — the only primary sent before S1F13 here was the S1F3.
S1F13, S1F14 and COMMACK 0
Now open the gate with an Establish Communications Request.
TX S1F13 W 00 00 00 17 00 0B 81 0D 00 00 00 00 20 03
01 02 41 04 48 4F 53 54 41 03 31 2E 30
The body is L[2]{A "HOST", A "1.0"}. 41 04 is a 4-byte ASCII item and 48 4F 53 54 is HOST. 41 03 31 2E 30 is 1.0. Those are the host's own MDLN and SOFTREV slots. Most equipment does not care what the host calls itself, but leaving them empty trips the stricter parsers.
RX S1F14 00 00 00 37 00 0B 01 0E 00 00 00 00 20 03
01 02
21 01 00
01 02 41 15 56 58 2D 39 30 30 30 20 50 6C 61 73 6D 61 20 45 74 63 68 65 72
41 0D 53 45 43 53 47 45 4D 2D 31 2E 34 2E 31
The body is L[2]{B 0, L[2]{MDLN, SOFTREV}}. 21 01 00 is a one-byte Binary item with value 0 — COMMACK 0, accepted. The L[2] after it is the equipment's MDLN, VX-9000 Plasma Etcher, and SOFTREV, SECSGEM-1.4.1. At this point the E30 state moves to COMMUNICATING.
A COMMACK that is not 0 does not open the gate, and the host's next move there is a retry, not the next message. The whole ordered startup is in proving the E30 startup handshake in one command.
S1F13 can also come from the equipment. E30 lets either side send it, so the host must be able to answer an incoming S1F13 with an S1F14 of its own. That direction is not in this capture, so that is as far as I will take it.
Same bytes, different answer
Send the S1F3 that was refused in step 2 again, changing only the SystemBytes.
TX S1F3 W 00 00 00 12 00 0B 81 03 00 00 00 00 20 04 01 01 B1 04 00 00 00 65
RX S1F4 00 00 00 31 00 0B 01 04 00 00 00 00 20 04
01 04
41 04 49 64 6C 65
81 08 40 38 3A E1 47 AE 14 7B
81 08 3F F1 F7 CE D9 16 87 2B
41 09 45 54 43 48 5F 42 41 53 45
The request is byte for byte the step 2 request apart from 20 02 becoming 20 04. Same socket, same SessionID, the same bytes. This time the reply is an S1F4 rather than an S1F0. The only thing that changed is the E30 state.
What that proves is one fact: the primary is answered instead of aborted. The body says nothing beyond that. This simulator returns all four of the variables it holds regardless of which SVID was requested, and it keys its variables by name, so the U4 101 in the request was never resolved. The shape E5 specifies for S1F4 — one value per requested SVID, in the requested order — was not verified against this tool. Do not read L[4]{A "Idle", F8 24.23, F8 1.123, A "ETCH_BASE"} as an SVID mapping.
Then close the session.
TX Separate.req 00 00 00 0A 00 0B 00 00 00 09 00 00 20 05
SType 09, and no reply by design.
What goes into the host driver
- Sequence S1F13 ahead of every other primary. Do not release the send queue on Select.rsp; release it on COMMACK 0.
- Treat both symptoms as one cause. (a) An SxF0 abort straight back, (b) silence until T3 expires. Both mean communication is not established yet, and the retry path for both is S1F13.
- Do not log the abort as a protocol error. SxF0 carries no diagnostics. Unless you record the SystemBytes and the E30 state at that moment alongside it, you cannot tell the causes apart later.
Symptom (a) needs a qualifier. Answering with SxF0 is what this equipment does. SEMI E30 does not mandate an abort reply while NOT COMMUNICATING, and real equipment commonly just stays silent, which leaves the host eating a T3 timeout. Code that branches on one symptom breaks again on the other kind of tool. The silent case is SELECTED does not mean communicating, and the stage before it, where Linktest is alive but Select never lands, is Linktest alive but not SELECTED.
Every frame above really went over a socket. The raw export sits in content/demos/e30-communication-gate-s1f0-before-s1f13.json, and this run is SystemBytes 0x2001–0x2005 (the file also holds an earlier run). To push the same bytes yourself, point a socket at the SECS/GEM simulator.