Files
secs-gem/docs/19_e42_e148_s9_misc.md
T
raphael 40df3067a4 docs: chapters 14–19 — GEM 300 standards (Part 2 complete)
Six more chapters finishing Part 2.  Together with chapters 10–13
they document every SEMI standard this codebase implements.

14 — E40 + E94: process jobs (8-state lifecycle, S16F11/F5/F7/F9
on the wire) and control jobs (CJ wraps PJs with batch policy,
S14F9/S16F27 messages).  Worked cascade showing how CJSTART
propagates through the PJ FSM and triggers S6F11 CEIDs at each
transition.

15 — E87 carriers: three orthogonal sub-machines (CarrierID,
SlotMap, CarrierAccess) per carrier and three more (Transfer,
Reservation, Association) per load port.  S3F17 CarrierAction
strings + CAACK codes, S3F19 SlotMap verify, the 5-state slot
encoding, multi-port concurrency.

16 — E90 + E157: substrate tracking via three orthogonal axes
(STS / SPS / SubstrateIDStatus) and module process tracking
(NotExecuting / GeneralExecuting / StepExecuting / StepCompleted).
End-to-end PVD example showing E40 + E157 + E90 transitions
cascading into CEIDs.

17 — E116 + E120 + E39: equipment performance time-buckets across
six states, common equipment model object hierarchy, S14F1/F3
GetAttr/SetAttr as the uniform wire access for any object type
across multiple standards.

18 — E84 parallel I/O: ten signal lines, the 9-state handshake
FSM, the three TA1/TA2/TA3 timing-critical timers, why a physical
handshake gets modeled in software (testability, timer enforcement,
CEID emission, multi-port concurrency), the pure-FSM + asio-adapter
split.

19 — E42 + E148 + S5F9–F18: formatted recipes (S7F23/F25 typed
PPBODY), time synchronization with 16-char + 14-char accepted on
set, exception recovery as a persistent multi-step host-supervised
FSM (Posted → Recovering → Cleared with abort/retry).  Revisits
the auto-S9 family and contrasts S9 (transport) vs S5F9
(application).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-09 20:14:42 +02:00

10 KiB
Raw Blame History

19 — E42 + E148 + S9 + exception recovery

18 E84 — Parallel I/O handoff | Back to index | Next: 30 Repository tour

Three remaining standards-shaped concerns to round out Part 2:

  • E42 — Formatted (enhanced) Process Programs.
  • E148 — Time synchronization.
  • S5F9S5F18 — Exception recovery (E5 §13 + GEM Additional).

Each is narrow enough that a half-chapter would do. Together they round out the GEM 300 picture.


E42 — Formatted Process Programs

What it is

E30's Process Program Management (chapter 13) covers unformatted recipes: the PPBODY is opaque bytes that only the equipment knows how to parse. E42 adds formatted PPs — the recipe has a typed SECS-II structure the host can introspect.

In practice, formatted recipes are a fab-internal standard rather than a SEMI-defined schema. E42 just gives the wire shape; the fab agrees what the structure means.

The messages

S/F Direction Purpose
S7F23 H → E Formatted PP Send. Body: PPID + typed SECS-II body.
S7F24 E → H ACKC7 reply.
S7F25 H → E Formatted PP Request. Body: PPID.
S7F26 E → H Formatted PP Send (back). Body: PPID + typed body.

Compare to unformatted S7F3 / S7F5: same direction pattern, just a typed body instead of opaque bytes.

Implementation

RecipeStore carries both views per recipe: an unformatted PPBODY (opaque bytes) and an optional formatted body (a secs2::Item tree). S7F3 sends the unformatted; S7F23 sends the formatted; both are stored side by side and the host can request either via S7F5 (unformatted) or S7F25 (formatted).

Tests: tests/test_e42_formatted_pp.cpp (6 cases — send formatted, request back, round-trip integrity, ACKC7 error paths).

Why both?

Some MES — and some equipment — only speak unformatted PPs. Coexistence lets a vendor ship one EAP that handles both. COMPLIANCE §4j has the audit detail.


E148 — Time synchronization

What it does

In a multi-tool fab, the host and the equipment need a common notion of time for timestamp correlation. If tool A logs an alarm at 14:32:01 and tool B logs a related alarm at 14:31:58, did B precede A or did the clocks drift?

E148 defines the wire mechanism for keeping equipment clocks in sync with a host-authoritative time source — typically NTP behind the scenes — and lets equipment report clock quality so the host knows how much to trust the timestamps coming off the tool.

The messages

E148 doesn't add new streams; it specialises the existing E30 clock messages:

S/F Direction Purpose
S2F17 H → E Read clock.
S2F18 E → H Reply with current time string.
S2F31 H → E Set clock to specified time string.
S2F32 E → H TIACK reply.

The time string is 16 ASCII chars YYYYMMDDhhmmsscc (E148 extended form, including hundredths). 14-char YYYYMMDDhhmmss (without hundredths) is the older E30 form; the codebase accepts both on set but emits 16 chars on read by default. See docs/COMPLIANCE.md §4g.

Clock store

include/secsgem/gem/store/clock.hpp holds the wall-clock plus a drift / quality indicator:

  • Drift_ms: cumulative drift since last set.
  • Quality: enum from {Authoritative, GoodNTP, FreeRunning, Unreliable}.

A host can read both via E120/E39 attribute access (chapter 17) or via DVID exposures (the EAP wires them).

Why this matters

Without clock sync, alarm root-cause analysis is impossible. SPC charts get the X-axis wrong. Yield correlations across tools fall apart. Most modern fabs run NTP on every tool's control-plane host; E148 is the mechanism for reporting clock state, not for synchronising it (that's NTP's job).


Exception recovery — S5F9S5F18

What it adds beyond base alarms

E5 §13 + E30 Alarm Management (covered in chapter 13) handles alarms as set/clear events: an alarm goes active, the equipment fires S5F1; later it clears, equipment fires another S5F1. Simple.

But some alarms aren't simple to clear. A vacuum leak that required a chamber vent + manual seal replacement can't just "go away" — the equipment has to run a recovery procedure with the host's involvement. S5F9S5F18 is the exception recovery family that handles that.

The exception lifecycle

Defined in include/secsgem/gem/exception_state.hpp:

enum class ExceptionState : uint8_t {
  Posted        = 0,  // S5F9 sent; awaiting host action
  Recovering    = 1,  // S5F13 accepted; recovery in progress
  RecoverFailed = 2,  // S5F15 reported failure; retry possible
  Cleared       = 3,  // resolved; terminal
};

Events: Created (NoState → Posted), Recover (host's S5F13), RecoveryComplete, RecoveryFailed, RecoveryAbort (host's S5F17), Clear.

The messages

S/F Direction Purpose
S5F9 E → H Exception Post. Equipment-initiated. Body: EXID + EXTYPE + EXMESSAGE + recovery-method list.
S5F10 H → E Ack.
S5F11 E → H Exception Clear. Equipment-initiated when condition resolves.
S5F12 H → E Ack.
S5F13 H → E Exception Recover. Body: EXID + which recovery method to attempt.
S5F14 E → H Recovery progress.
S5F15 E → H Recovery Complete (or Failed).
S5F16 H → E Ack.
S5F17 H → E Exception Recover Abort. Cancel an in-progress recovery.
S5F18 E → H Recovery Aborted reply.

The flow:

1. Vacuum leak detected.  EAP calls exceptions.post(EXID=42, recovery=["vent","seal","pump-down"]).
   → ExceptionState: NoState → Posted.
   → S5F9 fires.
2. Host sees S5F9 → operator decides to attempt recovery → host sends S5F13(EXID=42, method="vent").
   → ExceptionState: Posted → Recovering.
3. Recovery in progress.  EAP fires S5F14 periodically with progress.
4. EAP completes the venting step.  Fires recover_complete event.
   → ExceptionState: Recovering → Cleared.
   → S5F15 fires.
5. Host acknowledges (S5F16).  EAP fires S5F11 to confirm the
   underlying condition is gone.

Or, the abort path:

3'. Operator decides recovery isn't working → host sends S5F17.
4'. ExceptionState: Recovering → Posted.
5'. EAP can be re-instructed via another S5F13 with a different
    method, or the condition can clear autonomously (Clear event
    → Cleared state).

Code

State machine: include/secsgem/gem/exception_state.hpp. Store: include/secsgem/gem/store/exceptions.hpp — persistent, so an exception in flight survives a power cycle. Tests: tests/test_exceptions.cpp (11 cases) + persistence in tests/test_exception_persistence.cpp (5 cases).

Why this is its own family

Two reasons:

  1. State persistence. Alarms come and go in seconds; exception recovery can span hours and a few power cycles. The store journal lets the equipment remember "we were halfway through recovery method 2 of EXID=42" across restarts.
  2. Multi-step coordination. Each step (S5F13S5F14S5F15) is a host-supervised transaction. Base alarms can't express "host, here are three recovery options, pick one."

Exception recovery is an Additional GEM capability — not every MES asks for it — but the codebase implements it because it's upstream-absent in secsgem-py (see docs/COMPLIANCE.md §4k) and because the persistent state machine is a nice example of the spec-as-data pattern applied to a less-trivial FSM.


The auto-S9 family (revisited)

We covered the S9 wire-error replies in chapter 11. Worth re-listing here because S9 is part of the error/exception layer even though it's transport-level rather than application-level:

Function Trigger
S9F1 Unrecognized Device ID
S9F3 Unrecognized Stream
S9F5 Unrecognized Function
S9F7 Illegal Data (body failed to decode)
S9F9 Transaction Timer Timeout (T3 expired)
S9F11 Data Too Long (body exceeded configured cap)
S9F13 Conversation Timer Timeout (equipment-internal)

Implementation: hsms::Connection::emit_s9 called from the connection's framing and routing paths. Tested across tests/test_hsms_s9.cpp and tests/test_s9_fallback.cpp.

Difference from S5F9: S9 is transport-level (the bytes themselves were wrong); S5F9 is application-level (the equipment can't continue normal operation).


End of Part 2

You now know every SECS/GEM and GEM 300 standard that this codebase implements. Twelve standards across nine chapters, each one mapped to its state machine, its messages, its store, and the tests that hold it down.

Part 3 starts. We turn from "what the spec says" to "how this codebase implements it" — repository tour, codegen, the data model structure, transport internals, state-machine composition, persistence mechanics.

Next: → 30 Repository tour