← Articles
SECS/GEM/6 min read/— views

A Zero in the S2F33 Report List Makes It a Delete-All, Not a Define

Real socket capture: an S2F33 define and an empty-list S2F33 get byte-identical DRACK 0 replies, and one list count byte separates them.

SECS/GEMMESSCADATroubleshootingChecklists

I wrote a host that re-defines its reports on every reconnect. Connect, send S1F13, walk the config table, send S2F33. Then one day the table was empty — a config file that didn't load, or a filter that matched nothing. The code did not stop. It sent S2F33 with an empty report list, the equipment answered DRACK 0, and the host log got one line reading "report definition complete". From that day on, not a single S6F11 arrived.

The 10 bytes of an S2F33 body: L,2 then a U4 DATAID, with the last two bytes holding the report list. A zero length byte makes it a delete-all request S2F33 body — 10 bytes L,2 DATAID report list 0102 B10400 000001 01 00 Llength list count byte

The two frames differ in one trailing byte

SEMI E5 gives S2F33 Define Report the body L,2 { DATAID, L,n { L,2 { RPTID, L,m { VID } } } }. The second element of the outer list is the report list, and n is its length.

E5 assigns that n = 0 case its own meaning. An empty report list is a request to delete every report defined on the equipment. By the same rule, a report entry whose VID list is empty deletes that one RPTID. Define, delete-one and delete-all all live inside the same S2F33, and the only thing that distinguishes them is a list count byte.

That byte is usually a variable in host code. len(reports), straight through. When the table is empty it is zero, and a zero there still produces a perfectly valid S2F33. Nothing is malformed — not the frame, not the count of length bytes in the item header. It becomes a well-formed different command, and no parser has a complaint.

The capture — one define, then a delete-all

These bytes come from a socket client against the EQ1 passive listener in the SECS/GEM simulator (127.0.0.1:5501, SessionID 11, no faults). Select and S1F13 took the session to COMMUNICATING first — SELECTED is not COMMUNICATING.

An ordinary define: RPTID 500 over VID 101 and 102.

TX S2F33 W   00 00 00 2A 00 0B 82 21 00 00 00 00 70 03
             01 02 B1 04 00 00 00 01
                   01 01 01 02 B1 04 00 00 01 F4 01 02 B1 04 00 00 00 65 B1 04 00 00 00 66
RX S2F34     00 00 00 0D 00 0B 02 22 00 00 00 00 70 03  21 01 00

The body is <L [2] <U4 1> <L [1] <L [2] <U4 500> <L [2] <U4 101> <U4 102>>>>>. The frame after the 4-byte length prefix is 0x2A = 42 bytes. 01 01 is the report list, length one.

Same host, same socket, and the only thing changed is the report list.

TX S2F33 W   00 00 00 14 00 0B 82 21 00 00 00 00 70 06
             01 02 B1 04 00 00 00 01
                   01 00
RX S2F34     00 00 00 0D 00 0B 02 22 00 00 00 00 70 06  21 01 00

01 00 — one list item, length zero. The frame shrank to 0x14 = 20 bytes. And the two S2F34 replies differ only in SystemBytes, 70 03 against 70 06; the other 13 bytes are identical. 21 01 00: a one-byte binary item, DRACK 0.

There is a conclusion to stop short of here. This listener does not process S2F33 structurally. It is the same permissive listener that answers 0 even when you link reports in the wrong order, and it exposes no report store. So I have not verified that a delete actually happened. What I verified in bytes is two things: the empty-list S2F33 is a valid frame on the wire, and this equipment's reply cannot tell a define from a delete-all. The delete semantics are E5's text, and on a real tool they need checking separately.

Where the host stops it

  • Check the length before you send. If the report list is empty, don't build the S2F33 at all. A delete-all should be something an operator presses deliberately, not a failure path in a config loader.
  • Don't read DRACK 0 as "my definition landed". Zero means the equipment accepted the request, and the request may have been a deletion. E5 defines rejection codes too, but this listener returns only 0, so I did not verify them here.
  • Confirm by reading back. Whether S2F35 links against the RPTID, and whether S6F11 actually arrives, is the only confirmation worth anything. An ack is not a confirmation.
  • The equipment's report definitions are not yours alone. A delete-all takes out reports another host or an engineer configured. That is what makes this one quiet: the data collection that breaks belongs to someone else.

Even if you never wrote code to delete a report definition, the path where len() returns zero already exists. Walking that path once is the whole point of this article. The bytes are reproducible against the simulator.