# 13 — E30: GEM — the behavioural model ← [12 E4 — SECS-I](12_e4_secs_i.md) | [Back to index](00_index.md) | Next: [14 E40 + E94 — Process and control jobs](14_e40_e94_jobs.md) → E5 (chapter 10) is the data encoding. E37 / E4 (chapters 11–12) move the encoded bytes. This chapter is the first one where *behaviour* enters the picture. **SEMI E30 — Generic Equipment Model (GEM)**, published 1992, specifies what an equipment must *do* when its host sends specific messages. E5 says how to encode S1F13; E30 says what state must change when an S1F13 arrives, what reply must come back, and under what conditions either side may refuse. E30 has two top-level concepts: 1. **Two state machines** — communication state (above HSMS) and control state (governs who's allowed to issue commands). 2. **GEM Capabilities** — Fundamentals (mandatory) and Additionals (optional but de-facto required). Each capability defines its own scenarios + messages. By the end of this chapter you'll know both state machines, the 14 Fundamentals + Additionals, and where each one lives in code. --- ## The two GEM state machines GEM has **two** state machines that live on top of HSMS's transport state machine. Read carefully — beginners conflate these all the time: | State machine | Lives where | Concerns | |----------------------|---------------------------------------------------|-----------------------------------------------| | **HSMS transport** | `secsgem::hsms::Connection` | NOT-CONNECTED → NOT-SELECTED → SELECTED | | **GEM communication**| `secsgem::gem::CommunicationStateMachine` | DISABLED / WAIT-CRA / WAIT-DELAY / COMMUNICATING | | **GEM control** | `secsgem::gem::ControlStateMachine` | EquipmentOffline / OnlineLocal / OnlineRemote / … | All three can be in independent states. `SELECTED` (HSMS) doesn't imply `COMMUNICATING` (GEM-comm); `COMMUNICATING` doesn't imply `OnlineRemote` (control). ### Communication state (E30 §6.5) What it answers: **have host and equipment agreed they can talk to each other at the GEM level?** This is *above* HSMS — even after HSMS is SELECTED, GEM-comm starts at WAIT-CRA and only reaches COMMUNICATING after a successful `S1F13 / S1F14 (COMMACK=Accept)` exchange. ``` wire: S1F13 → DISABLED ─enable──► WAIT-CRA ─────────────► COMMUNICATING │ ◄─ S1F14(Accept) │ │ S1F14(Deny) or T_CRA expires ▼ WAIT-DELAY │ T_DELAY expires ▼ WAIT-CRA (retry) ``` Two timers, both in `gem::CommunicationStateMachine`: - **T_CRA** (default 45 s): how long to wait for the S1F14 reply after sending S1F13. - **T_DELAY** (default 10 s): how long to back off after a rejected S1F14 before retrying. Code: [`include/secsgem/gem/communication_state.hpp`](../include/secsgem/gem/communication_state.hpp); tests in [`tests/test_communication_state.cpp`](../tests/test_communication_state.cpp) (12 cases — every transition, every timer expiry). The state machine is **IO-free** — it raises actions (send S1F13, arm T_CRA, …) that the caller translates into asio work. This makes it unit-testable without spinning up a TCP socket. Same design pattern as `secsi::Protocol` from chapter 12. ### Control state (E30 §6.2) What it answers: **who's allowed to issue commands right now?** Five states: | State | Meaning | |------------------|------------------------------------------------------------| | `EquipmentOffline` | Off-network. Both panel and host commands disabled. | | `AttemptOnline` | Transient: equipment is dialing host. Rare. | | `HostOffline` | Host disconnected (or never connected). Operator can act, host cannot. | | `OnlineLocal` | Operator at the local panel has control. Host can read, not act. | | `OnlineRemote` | Host has full control. | Defined in [`include/secsgem/gem/control_state.hpp`](../include/secsgem/gem/control_state.hpp). Transitions are driven by **events** (operator pressed Online, host sent S1F17, AttemptOnline succeeded or failed, …) and encoded as a transition table loaded from [`data/control_state.yaml`](../data/control_state.yaml): ```yaml # data/control_state.yaml transitions: - {from: EquipmentOffline, on: operator_switch_online, to: AttemptOnline, then: OnlineRemote} - {from: OnlineRemote, on: host_request_offline, to: HostOffline, ack: Accept} - {from: OnlineLocal, on: host_request_remote, ack: NotAccept} ... ``` The table is **pure data**. `ControlTransitionTable` looks up rows; `ControlStateMachine` applies them. No `if/else` ladders embedded in C++. ```cpp // include/secsgem/gem/control_state.hpp:53 struct ControlTransition { ControlState from; ControlEvent on; std::optional to; std::optional then; // chain through AttemptOnline std::optional ack_code; }; ``` This is **spec-as-data** in its purest form: the SEMI standard section 6.2 is one YAML file. Add a state, add a transition, edit the YAML — no recompile, no C++ change. See chapter [31](31_spec_as_data_and_codegen.md) for the wider story. Tests: [`tests/test_control_state.cpp`](../tests/test_control_state.cpp) (15 cases — every YAML-defined transition, both ACK codes). --- ## GEM Fundamentals (E30 §5.2) The **mandatory** capabilities. An equipment that doesn't ship these isn't GEM-compliant, end of story. | Fundamental | Messages | Code | |---------------------------------------------|---------------------------------------------------------|---------------------------------------------------------------| | State models | — | `ControlStateMachine`, `CommunicationStateMachine` | | Equipment Processing States | — | `ControlTransitionTable` (vendor supplies concrete states) | | Host-Initiated S1F13/F14 | S1F13 / S1F14 | `gem::CommunicationStateMachine` | | Event Notification | S6F11 / S6F12 | `EventReportSubscriptions` + `EquipmentDataModel::compose_reports_for` | | On-Line Identification | S1F1 / S1F2 | Router handler in `apps/secs_server.cpp` | | Error Messages | S9F1/F3/F5/F7/F9/F11 | `Connection::emit_s9` + `Router::dispatch_with_s9` | | Documentation | S1F19/F20, S1F21/F22, S1F23/F24 | `gem::compliance` / namelist handlers | | Control (Operator-Initiated) | — | `ControlStateMachine::operator_online/offline/local/remote` | Full per-capability accounting with status + spec section + code ref: [docs/COMPLIANCE.md](COMPLIANCE.md) §3. --- ## GEM Additionals (E30 §5.3) The **optional** capabilities — but every commercial MES will require all of them. In practice "Additional" means "optional per the SEMI spec, but mandatory for procurement." | Additional | Messages | Code | |---------------------------------------|---------------------------------------------------------------------------|-----------------------------------------------| | Establish Communications | S1F13/F14 | `CommunicationStateMachine` (also in Fundamentals) | | Dynamic Event Report Configuration | S2F33/F34, S2F35/F36, S2F37/F38 | `EventReportSubscriptions` | | Variable Data Collection | S1F21/F22 + DVID values via `vid_value` | `DataVariableStore` | | Trace Data Collection | S2F23/F24, S6F1/F2 | `TraceStore` | | Status Data Collection | S1F3/F4, S1F11/F12 | `StatusVariableStore` | | Alarm Management | S5F1/F2, S5F3/F4, S5F5/F6, S5F7/F8 | `AlarmRegistry` | | Remote Control | S2F41/F42, S2F49/F50, S2F21/F22 | `HostCommandRegistry` | | Equipment Constants | S2F13/F14, S2F15/F16, S2F29/F30 | `EquipmentConstantStore` | | Process Program Management | S7F1–F6, S7F17–F20, S7F23–F26 | `RecipeStore` | | Material Movement | (handled by E40 + E94 + E87 + E90 + E157) | see chapters 14–16 | | Equipment Terminal Services | S10F1/F2, S10F3/F4, S10F5/F6 | S10F1–F6 Router handlers (no dedicated store) | | Clock | S2F17/F18, S2F31/F32 | `Clock` (+ E148 in chapter 19) | | Limits Monitoring | S2F45/F46, S2F47/F48 | `LimitMonitorStore` | | Spooling | S2F43/F44, S6F23/F24, S6F25/F26 | `SpoolStore` (persistent file-backed journal) | Every capability has its **own store** (a namespace bundle of state + behaviour) and its **own Router handlers** for the messages that drive it. Stores compose into `EquipmentDataModel`. Chapter [32](32_stores_and_the_data_model.md) is the deep dive. --- ## How a typical scenario lands in code Pick **Event Notification** — the canonical GEM scenario: ``` 1. Host sends S2F33 (DefineReport): "RPTID 100 = [SVID 1, SVID 5]" 2. Equipment stores the definition in EventReportSubscriptions; replies S2F34(DRACK=0). 3. Host sends S2F35 (LinkEvent): "CEID 300 → RPTID 100" 4. Equipment stores the link in EventReportSubscriptions; replies S2F36(LRACK=0). 5. Host sends S2F37 (EnableEvent CEED=true, CEID=[300]) 6. Equipment marks CEID 300 enabled in EventReportSubscriptions; replies S2F38(ERACK=0). 7. Later: some FSM transition decides to fire CEID 300. compose_reports_for(300) walks EventReportSubscriptions → StatusVariableStore and assembles {RPTID=100, V=[svid1_val, svid5_val]}. 8. Equipment emits S6F11 with the assembled body. 9. Host replies S6F12(ACKC6=0). ``` Steps 1, 3, 5 are inbound — `gem::Router` dispatches by `(stream, function)` to a registered handler. Steps 2, 4, 6, 8 are outbound — the handler or the FSM hands a built `secs2::Message` to the Connection. Step 7 is *internal* — the EquipmentDataModel walks its own stores; nothing on the wire happens until step 8. Router and dispatch is in chapter [35](35_state_machines_and_dispatch.md); store internals in chapter [32](32_stores_and_the_data_model.md). --- ## The host-side analogue Everything above describes the equipment side. The host side has its own E30 state — every Additional capability has a host-side view too (the host can disable an alarm, change a host command, etc.). This codebase implements the host-side as a thin module: ```cpp // include/secsgem/gem/host_handler.hpp class HostHandler { // Decode equipment-initiated S5F1 / S6F11 / S9Fx. // Maintain the host's view of CEID enables, alarm enables, … }; ``` `apps/secs_client.cpp` is the canonical host binary. In the two-container demo it walks ~24 transactions against `apps/secs_server.cpp` — the host side mostly *reads* what the equipment reports and acknowledges. Driving an MES is a much bigger story (see chapter [41](41_integration_hardware_mes_production.md)). --- ## Where to go next You now have: - E5 codec. - E37/E4 transport. - E30 state machines and capabilities. That's the complete **base GEM stack**. Modern fab automation needs more — process job lifecycles, carrier management, substrate tracking — and that's what **GEM 300** adds. The next six chapters tackle the GEM 300 standards one family at a time. Each one fits on top of E30 in the same way: a state machine + a store + Router handlers + per-CEID emissions. Next: [→ 14 E40 + E94 — Process and control jobs](14_e40_e94_jobs.md)