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 sits in NOT COMMUNICATING in SEMI E30's communication state model. The only SECS-II messages that pass in that window are S1F13 and S1F14. What shape a tool sends the other primaries back in is not something E30 fixes, and the equipment below sends them back as SxF0.
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
TX and RX are from the host's side. The committed export is the equipment's own log, so the same frames appear flipped in it. Each line is a 4-byte length followed by the 10-byte E37 header, and header bytes are numbered from 0 the way E37 numbers them.
SessionID 00 0B is 11. Header 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.
Nor is this a stream 1 story. On a fresh socket, S2F41 (Host Command Send) went out before any S1F13.
TX S2F41 W 00 00 00 15 00 0B 82 29 00 00 00 00 31 02 01 02 41 05 53 54 41 52 54 01 00
RX S2F0 00 00 00 0A 00 0B 02 00 00 00 00 00 31 02
Header byte 2 is 82 — W-bit set, Stream 2. Byte 3, 29, is Function 41. The body L[2]{A "START", L[0]} is the RCMD START with an empty parameter list. Back came a length of 10, header byte 2 02 (Stream 2, W-bit clear), byte 3 00 — an S2F0, SystemBytes 31 02 unchanged. That is E5's rule for an abort: the request's own stream, function 0.
Push S1F13 through on the same socket and send the identical bytes again, and the answer changes.
TX S2F41 W 00 00 00 15 00 0B 82 29 00 00 00 00 31 04 01 02 41 05 53 54 41 52 54 01 00
RX S2F42 00 00 00 11 00 0B 02 2A 00 00 00 00 31 04 01 02 21 01 02 01 00
Byte 3 is now 2A, Function 42. The body L[2]{B 2, L[0]} is HCACK 2, E5's "cannot perform now". This tool refused because its control state is OFF-LINE. Both are refusals and they are different shapes. S2F0 means communication is not open yet; S2F42 with HCACK 2 means communication is open and the control state is wrong. A host log that files both under "S2F41 failed" cannot tell them apart later.
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. E30 draws that interval as substates inside NOT COMMUNICATING — WAIT CRA while the S1F13 is out and the CRA has not arrived, WAIT DELAY where the host sits after a failure before sending again. How long that delay runs is equipment configuration, so no number for it here. 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 article's runs are SystemBytes 0x2001–0x2005 and 0x3101–0x3105 (the file holds other runs too). To push the same bytes yourself, point a socket at the SECS/GEM simulator.