0355c73211
generate_messages.py → gen_messages.py and several gem/ headers moved under gem/store/ (carrier_store.hpp → store/carriers.hpp, etc.); e84.hpp split into e84_state.hpp. The guided-tour chapters still pointed at the old paths — relink them so the deep-link footnotes resolve. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
593 lines
28 KiB
Markdown
593 lines
28 KiB
Markdown
# 03 — Vocabulary + a wafer's journey
|
|
|
|
← [02 The cast of characters](02_the_cast.md) | [Back to index](00_index.md) | Next: [10 E5 — SECS-II data items](10_e5_secs_ii_data_items.md) →
|
|
|
|
The SEMI standards bury everything in acronyms. Three-letter, four-
|
|
letter, sometimes the same letter pattern (`ACKC5`, `ACKC6`, `ACKC7`,
|
|
`ACKC10`) but with completely different semantics depending on which
|
|
stream you're in. Most readers learn them by absorbing them over
|
|
years of integration work.
|
|
|
|
This chapter accelerates that. We follow **one 300 mm wafer** from
|
|
the moment it enters the fab to the moment it leaves as a finished
|
|
die, and at every step we name every acronym that fires, what it
|
|
means, and where it lives in this codebase. By the end you'll have
|
|
seen `SVID`, `CEID`, `ALID`, `PPID`, `HCACK`, `ALCD`, `RPTID`,
|
|
`OFLACK`, `MDLN`, `SOFTREV`, `CAACK`, `SMACK`, and the rest in
|
|
*context* — not as a vocabulary list.
|
|
|
|
If you're confident with the vocabulary already, skip to Part 2,
|
|
Chapter [10](10_e5_secs_ii_data_items.md) (SECS-II encoding).
|
|
|
|
---
|
|
|
|
## The setup
|
|
|
|
- **The wafer**: an unpatterned 300 mm silicon disc, 775 µm thick,
|
|
with a serial number `W-2026-06-09-A47` etched on the bevel.
|
|
- **The carrier**: a Front-Opening Universal Pod (**FOUP**) that
|
|
holds 25 wafers in vertical slots. Our wafer is in slot 14. The
|
|
FOUP's bar code reads `C-31415`.
|
|
- **The tools**:
|
|
- **PVD-1** (physical vapour deposition — deposits a metal layer)
|
|
- **LITHO-3** (photolithography — patterns the metal layer)
|
|
- **ETCH-7** (plasma etch — removes uncovered metal)
|
|
- **The host**: a fab-wide MES called `meta-fab.example`.
|
|
- **The recipe**: `RECIPE-Cu-A` for PVD-1, `RECIPE-193nm-X` for
|
|
LITHO-3, `RECIPE-CL2-B` for ETCH-7.
|
|
|
|
For brevity we'll only show the wafer's first pass through PVD-1.
|
|
The same pattern repeats for LITHO-3 and ETCH-7.
|
|
|
|
---
|
|
|
|
## Stage 1 — Establishing communications (already done)
|
|
|
|
Before any wafer arrives, **PVD-1 and meta-fab.example have already
|
|
HSMS-SELECTed each other**. That's the once-per-power-on dance:
|
|
|
|
```
|
|
host (active) equipment (passive)
|
|
───────────── ───────────────────
|
|
TCP SYN ─────────────────────────► (bind on :5000)
|
|
◄──── TCP SYN-ACK
|
|
HSMS Select.req (sessionID=0) ───►
|
|
◄──── HSMS Select.rsp (SELECT_STATUS=0=accept)
|
|
[transport state: SELECTED]
|
|
S1F13 Establish Communications ──►
|
|
◄──── S1F14 (COMMACK=0=accepted, [MDLN, SOFTREV])
|
|
[GEM communication state: COMMUNICATING]
|
|
```
|
|
|
|
This introduces three acronyms:
|
|
|
|
- **`MDLN`** — Model Name. An ASCII string up to 20 chars
|
|
identifying the equipment model. PVD-1 returns `"ACME-PVD-3000"`.
|
|
- **`SOFTREV`** — Software Revision. ASCII string up to 20 chars
|
|
identifying the firmware / EAP version. PVD-1 returns `"1.4.2"`.
|
|
- **`COMMACK`** — Communication Acknowledge. One byte; 0 = accepted,
|
|
1 = denied. Defined in E30 §6.5.
|
|
|
|
**Where:** see `equipment.yaml` device block; emission flows through
|
|
[`gem::Router`](../include/secsgem/gem/router.hpp) →
|
|
[`secsgem::secs2::Message`](../include/secsgem/secs2/message.hpp).
|
|
|
|
---
|
|
|
|
## Stage 2 — The carrier arrives at PVD-1's load port
|
|
|
|
The AMHS overhead hoist swings FOUP `C-31415` onto load port 1.
|
|
*Before* anything SECS happens, the **E84 handshake** runs on the
|
|
physical I/O lines:
|
|
|
|
```
|
|
AMHS robot load port 1
|
|
────────── ───────────
|
|
CS_0 asserted ───────────────────► (carrier select bit 0)
|
|
CS_1 asserted ───────────────────► (carrier select bit 1)
|
|
VALID asserted ──────────────────► (lines above are stable)
|
|
◄──── L_REQ asserted (LOAD allowed)
|
|
TR_REQ asserted ─────────────────► (transfer requested)
|
|
◄──── READY asserted (kinematic interlocks ok)
|
|
BUSY asserted ───────────────────► (placement in progress)
|
|
… mechanical placement happens (~5 seconds) …
|
|
BUSY de-asserted ────────────────► (placement done)
|
|
◄──── COMPT asserted (complete)
|
|
CONT asserted ───────────────────► (carrier connected to load port)
|
|
```
|
|
|
|
This introduces the E84 line-name acronyms (`VALID`, `CS_0`, `CS_1`,
|
|
`TR_REQ`, `READY`, `BUSY`, `COMPT`, `CONT`, `L_REQ`, `U_REQ`, `ES`)
|
|
and three timer names:
|
|
|
|
- **`TA1`** — armed when `VALID` asserts; the load port must respond
|
|
with `L_REQ` within `TA1`. Default ~2 seconds.
|
|
- **`TA2`** — armed when `L_REQ` asserts; `TR_REQ` must follow
|
|
within `TA2`. Default ~2 seconds.
|
|
- **`TA3`** — armed when `BUSY` asserts (transfer in progress); the
|
|
whole transfer must finish within `TA3`. Default ~60 seconds.
|
|
|
|
Any of these timing out → both sides go to `HandoffFault` and the
|
|
operator gets paged. No FOUP gets dropped because the protocol
|
|
guarantees both sides agreed on every step.
|
|
|
|
**Where:** [`include/secsgem/gem/e84_state.hpp`](../include/secsgem/gem/e84_state.hpp)
|
|
defines the FSM; [`include/secsgem/gem/e84_asio_timers.hpp`](../include/secsgem/gem/e84_asio_timers.hpp)
|
|
defines the timer enforcement; chapter [18](18_e84_parallel_io.md)
|
|
walks the whole handshake.
|
|
|
|
---
|
|
|
|
## Stage 3 — The carrier is on the load port; PVD-1 tells the MES
|
|
|
|
The E84 handshake gave PVD-1 a docked carrier. Now SECS messages
|
|
flow:
|
|
|
|
```
|
|
PVD-1 (equipment) meta-fab (host)
|
|
───────────────── ───────────────
|
|
S6F11 CarrierArrived ────────────►
|
|
CEID = 10001
|
|
DATAID = 1
|
|
[ {RPTID=100, V=[CarrierID="C-31415", PortID=1]} ]
|
|
◄──── S6F12 (ACKC6=0=accepted)
|
|
|
|
S3F19 Slot Map Verify ───────────►
|
|
CARRIERID = "C-31415"
|
|
[ slot_state[1..25] ]
|
|
◄──── S3F20 (SMACK=0=match)
|
|
```
|
|
|
|
New acronyms in this stage:
|
|
|
|
- **`CEID`** — Collection Event ID. An identifier (any unsigned
|
|
width; we'll use `U4`) for a noteworthy thing that happened. CEIDs
|
|
are *defined in the equipment's YAML* and the MES learns them via
|
|
`S1F23/F24`. CEID 10001 = `CarrierArrived` per E87.
|
|
- **`RPTID`** — Report ID. A bundle of variables. When CEID 10001
|
|
fires, the MES gets back the values of every variable linked to
|
|
every report linked to CEID 10001. Reports are *defined by the
|
|
host* via `S2F33` and linked to CEIDs via `S2F35`.
|
|
- **`DATAID`** — Data ID, a per-host transaction counter. Lets the
|
|
host correlate report data to a specific request.
|
|
- **`ACKC6`** — Acknowledge Code 6. S6F12 reply byte. 0 =
|
|
accepted, anything else = MES couldn't process the event.
|
|
- **`CARRIERID`** — Carrier ID, an ASCII string. Matches what the
|
|
AMHS told us via E84.
|
|
- **`SMACK`** — Slot Map Acknowledge. S3F20 reply byte. 0 =
|
|
matches what the MES expected, 1 = mismatch. Defined in E87.
|
|
- **`CAACK`** — Carrier Action Acknowledge (we'll see this one
|
|
shortly). S3F18 reply byte for carrier-action commands.
|
|
|
|
Note the pattern: every primary message ends in an odd function
|
|
(F11, F19), every reply ends in the next even function (F12, F20).
|
|
This is invariant across SECS-II. See chapter [10](10_e5_secs_ii_data_items.md)
|
|
for the encoding details.
|
|
|
|
**Where:** `gem::CarrierStore` in [`include/secsgem/gem/store/carriers.hpp`](../include/secsgem/gem/store/carriers.hpp);
|
|
the E87 wire tests in [`tests/test_e87_wire_scenarios.cpp`](../tests/test_e87_wire_scenarios.cpp).
|
|
|
|
---
|
|
|
|
## Stage 4 — The host authorises processing
|
|
|
|
```
|
|
meta-fab (host) PVD-1 (equipment)
|
|
─────────────── ─────────────────
|
|
S3F17 CarrierAction ─────────────►
|
|
CARRIERACTION = "ProceedWithCarrier"
|
|
CARRIERID = "C-31415"
|
|
◄──── S3F18 (CAACK=0=accepted)
|
|
```
|
|
|
|
- **`CARRIERACTION`** — an ASCII string from a fixed E87 set:
|
|
`ProceedWithCarrier`, `CancelCarrier`, `CarrierOut`, …
|
|
- **`CAACK`** — Carrier Action Acknowledge. S3F18 reply byte. 0 =
|
|
accepted, 1 = unknown carrier, 2 = invalid action, 3 = invalid
|
|
state, 4 = mismatch, 5 = unknown.
|
|
|
|
The host could have sent `CancelCarrier` here instead and PVD-1
|
|
would have rejected the FOUP without processing. That decision
|
|
lives entirely on the host side.
|
|
|
|
---
|
|
|
|
## Stage 5 — The host queues a process job
|
|
|
|
```
|
|
meta-fab (host) PVD-1 (equipment)
|
|
─────────────── ─────────────────
|
|
S16F11 PRJobCreate ──────────────►
|
|
PRJobID = "PJ-2026-06-09-001"
|
|
MF = "Substrate"
|
|
PRMtlOutSpec = []
|
|
PRRecipeMethod = "RecipeOnly"
|
|
RCPSpec = "RECIPE-Cu-A"
|
|
PRProcessStart = false (we'll start it explicitly later)
|
|
PRMtlnameList = ["W-2026-06-09-A47"]
|
|
◄──── S16F12 (PRJobAck=0)
|
|
|
|
S14F9 CreateControlJob ─────────►
|
|
CJobID = "CJ-2026-06-09-001"
|
|
PRJobIDList = ["PJ-2026-06-09-001"]
|
|
◄──── S14F10 (OBJACK=0)
|
|
```
|
|
|
|
New acronyms:
|
|
|
|
- **`PRJobID`** — Process Job ID, an ASCII string the host invents
|
|
for tracking. Sometimes called `PJID`.
|
|
- **`MF`** — Material Format. ASCII; `Substrate`, `Carrier`,
|
|
`SubstrateLocation`. Tells the equipment what scale the job is
|
|
about.
|
|
- **`RCPSpec`** — Recipe specification. References a recipe by ID
|
|
(`PPID`, below).
|
|
- **`PPID`** — Process Program ID. The recipe's identifier. In our
|
|
case `"RECIPE-Cu-A"`.
|
|
- **`PRJobAck`** — S16F12 reply byte. 0 = accepted, non-zero
|
|
values for each failure mode.
|
|
- **`CJobID`** — Control Job ID. A control job wraps one or more
|
|
process jobs and adds scheduling semantics (start order, abort
|
|
policy, dependency on other CJs).
|
|
- **`OBJACK`** — Object Acknowledge. S14F10 reply byte. Generic
|
|
E39 object-services ack: 0 = accepted, 1 = error.
|
|
|
|
E40 governs process jobs; E94 governs control jobs above them.
|
|
|
|
**Where:** [`include/secsgem/gem/store/process_jobs.hpp`](../include/secsgem/gem/store/process_jobs.hpp),
|
|
[`include/secsgem/gem/store/control_jobs.hpp`](../include/secsgem/gem/store/control_jobs.hpp).
|
|
The state machines are loaded from
|
|
[`data/process_job_state.yaml`](../data/process_job_state.yaml) and
|
|
[`data/control_job_state.yaml`](../data/control_job_state.yaml).
|
|
See chapter [14](14_e40_e94_jobs.md) for the lifecycle in full.
|
|
|
|
---
|
|
|
|
## Stage 6 — The host configures event reports
|
|
|
|
Before processing starts, the MES wants to subscribe to specific
|
|
events. This is a three-message dance:
|
|
|
|
```
|
|
meta-fab (host) PVD-1 (equipment)
|
|
─────────────── ─────────────────
|
|
S2F33 DefineReport ──────────────►
|
|
DATAID = 2
|
|
[ { RPTID=200, VID=[1, 2, 5] } ] (link RPTID 200 to SVIDs 1,2,5)
|
|
◄──── S2F34 (DRACK=0=accepted)
|
|
|
|
S2F35 LinkEvent ─────────────────►
|
|
DATAID = 3
|
|
[ { CEID=300, RPTID=[200] } ] (when CEID 300 fires, send RPTID 200)
|
|
◄──── S2F36 (LRACK=0=accepted)
|
|
|
|
S2F37 EnableEvent ───────────────►
|
|
CEED = true
|
|
CEID = [300] (enable CEID 300)
|
|
◄──── S2F38 (ERACK=0=accepted)
|
|
```
|
|
|
|
New acronyms:
|
|
|
|
- **`SVID`** — Status Variable ID. An identifier (`U4` typical) for
|
|
a *long-lived* value the host can read at any time — current
|
|
control state, chamber pressure, wafer counter, recipe in progress,
|
|
clock. Roughly: instance variables that survive across events.
|
|
- **`DVID`** — Data Variable ID. Same shape, but only meaningful
|
|
*at the moment an event fires*. E.g. the temperature at the time
|
|
the `ProcessStarted` event was emitted. Not readable independently
|
|
via `S1F3`; only delivered as part of a report.
|
|
- **`ECID`** — Equipment Constant ID. Same shape, but the host can
|
|
*set* it (within declared `min`/`max` bounds) via `S2F15`.
|
|
Settings that survive power-cycle: nominal chamber pressure, T3
|
|
timeout, T7 timeout, etc.
|
|
- **`VID`** — Variable ID. A generic SVID-or-DVID, used in report
|
|
definitions.
|
|
- **`CEED`** — Collection Event Enable Disable. Boolean. `true` =
|
|
enable the listed CEIDs, `false` = disable them.
|
|
- **`DRACK`** — Define Report Acknowledge. S2F34 reply.
|
|
- **`LRACK`** — Link Report Acknowledge. S2F36 reply.
|
|
- **`ERACK`** — Enable Report Acknowledge. S2F38 reply.
|
|
|
|
Acknowledge bytes are *distinct enums per stream/function*. `DRACK
|
|
= 0` = accepted; `LRACK = 0` = accepted; `ERACK = 0` = accepted —
|
|
same value, but each one has its own enumeration of failure codes
|
|
(`3 = at least one CEID does not exist`, etc.). Don't reuse one
|
|
stream's enum for another's.
|
|
|
|
**Where:** [`include/secsgem/gem/store/event_reports.hpp`](../include/secsgem/gem/store/event_reports.hpp)
|
|
(reports + collection events live together — the same store backs S2F33/F35/F37).
|
|
The configuration flow is the heart of E30 §6.6 Dynamic Event Report
|
|
Configuration; see chapter [13](13_e30_gem.md).
|
|
|
|
---
|
|
|
|
## Stage 7 — Processing begins
|
|
|
|
```
|
|
meta-fab (host) PVD-1 (equipment)
|
|
─────────────── ─────────────────
|
|
S2F41 RemoteCommand ─────────────►
|
|
RCMD = "START"
|
|
CPNAME[] / CPVAL[] = []
|
|
◄──── S2F42 (HCACK=0=accepted)
|
|
|
|
S6F11 ProcessStarted ──────────►
|
|
CEID = 300
|
|
DATAID = 4
|
|
[ {RPTID=200,
|
|
V=[ControlState="OnlineRemote",
|
|
Clock="20260609173000",
|
|
WaferCount=147]} ]
|
|
◄──── S6F12 (ACKC6=0)
|
|
```
|
|
|
|
New acronyms:
|
|
|
|
- **`RCMD`** — Remote Command name. ASCII. `"START"`, `"STOP"`,
|
|
`"PAUSE"`, `"ABORT"`, `"VENT"`, etc. Equipment-vendor-defined.
|
|
- **`CPNAME` / `CPVAL`** — Command Parameter name / value pairs.
|
|
Empty list here; some commands take parameters (e.g.
|
|
`RCMD="CHANGE-RECIPE", CPNAME="PPID", CPVAL="RECIPE-Cu-B"`).
|
|
- **`HCACK`** — Host Command Acknowledge. S2F42 reply. 0 =
|
|
accepted, 1 = invalid command, 2 = cannot perform now, 3 = at
|
|
least one parameter is invalid, 4 = accepted-and-will-finish-later,
|
|
5 = rejected, 6 = invalid object.
|
|
|
|
The `S6F11(CEID=300)` that fires next is the event report
|
|
**defined three messages earlier**. The MES correlated this by:
|
|
|
|
1. Earlier sent `S2F33` → equipment now knows that "RPTID 200 =
|
|
[SVID 1, SVID 2, SVID 5]."
|
|
2. Earlier sent `S2F35` → equipment now knows that "when CEID 300
|
|
fires, the report payload should include RPTID 200."
|
|
3. Earlier sent `S2F37` → CEID 300 is enabled, so when the
|
|
processing logic fires it, an `S6F11` actually leaves the wire.
|
|
(If CEID 300 had been left *disabled*, the processing logic
|
|
would still fire it but the wire would stay quiet.)
|
|
|
|
**Where:** [`include/secsgem/gem/store/host_commands.hpp`](../include/secsgem/gem/store/host_commands.hpp)
|
|
(`HostCommandRegistry`) maps `RCMD` strings to handlers; the report-emission machinery lives
|
|
in `EquipmentDataModel` ([`include/secsgem/gem/data_model.hpp`](../include/secsgem/gem/data_model.hpp))
|
|
via `compose_reports_for(ceid)`. Wire-level tests:
|
|
[`tests/test_wire_ceid_emission.cpp`](../tests/test_wire_ceid_emission.cpp).
|
|
|
|
---
|
|
|
|
## Stage 8 — An alarm fires
|
|
|
|
Mid-processing, the chamber pressure sensor reads above its
|
|
configured `ECID="ChamberPressureMax"` threshold. The EAP's alarm
|
|
monitor decides this is alarm-worthy and calls
|
|
`alarms.set(ALID=42)`:
|
|
|
|
```
|
|
PVD-1 (equipment) meta-fab (host)
|
|
───────────────── ───────────────
|
|
S5F1 AlarmReport ────────────────►
|
|
ALCD = 0x84 (bit 7 set + category 4 = process)
|
|
ALID = 42
|
|
ALTX = "Chamber pressure above max threshold"
|
|
◄──── S5F2 (ACKC5=0)
|
|
```
|
|
|
|
- **`ALID`** — Alarm ID. An identifier (`U4` typical) for one
|
|
named alarm in the equipment's alarm directory.
|
|
- **`ALCD`** — Alarm Code. One byte. Bit 7 = "set" (1) or "clear"
|
|
(0). Lower 7 bits = category (1 = personal safety, 2 = equipment
|
|
safety, 3 = parameter control warning, 4 = parameter control
|
|
error, 5 = irrecoverable error, 6 = equipment status warning, 7 =
|
|
attention flag, 8 = data integrity, others reserved). E5 §13.
|
|
- **`ALTX`** — Alarm Text. ASCII description, up to 120 chars per
|
|
E5 §13.
|
|
- **`ACKC5`** — Acknowledge Code 5. S5F2 reply. 0 = accepted.
|
|
|
|
If the host had previously *disabled* ALID 42 (via `S5F3
|
|
ALED=0x00`), this `S5F1` wouldn't have left the wire — the equipment
|
|
would still note the alarm internally (so `S5F5` would list it), but
|
|
the host wouldn't get pinged.
|
|
|
|
When the pressure returns to range, a second `S5F1` fires with
|
|
`ALCD=0x04` (bit 7 cleared) and the same ALID, signalling "alarm
|
|
cleared."
|
|
|
|
**Where:** [`include/secsgem/gem/store/alarms.hpp`](../include/secsgem/gem/store/alarms.hpp)
|
|
defines `AlarmRegistry`, which both stores the definitions and gates
|
|
S5F1 emission on the enable list.
|
|
|
|
---
|
|
|
|
## Stage 9 — Processing completes
|
|
|
|
```
|
|
PVD-1 (equipment) meta-fab (host)
|
|
───────────────── ───────────────
|
|
S6F11 ProcessCompleted ──────────►
|
|
CEID = 301
|
|
DATAID = 5
|
|
[ {RPTID=200, V=[…]} ]
|
|
◄──── S6F12 (ACKC6=0)
|
|
```
|
|
|
|
Same pattern as `ProcessStarted` — just a different CEID for a
|
|
different lifecycle moment.
|
|
|
|
The MES sees `CEID=301` and updates its tracking: process job
|
|
`PJ-2026-06-09-001` is now `ProcessComplete` per E40. It clears its
|
|
"in progress" counter and updates wafer `W-2026-06-09-A47`'s
|
|
location in E90 substrate tracking.
|
|
|
|
---
|
|
|
|
## Stage 10 — Carrier transfers out
|
|
|
|
```
|
|
meta-fab (host) PVD-1 (equipment)
|
|
─────────────── ─────────────────
|
|
S3F25 CarrierTransfer ───────────►
|
|
CARRIERID = "C-31415"
|
|
PortID = 2 (transfer from LP1 to LP2 = outbound)
|
|
◄──── S3F26 (CAACK=0)
|
|
|
|
PVD-1 (equipment) meta-fab (host)
|
|
───────────────── ───────────────
|
|
S6F11 CarrierTransfered ─────────►
|
|
CEID = 10002
|
|
[ … ]
|
|
◄──── S6F12 (ACKC6=0)
|
|
```
|
|
|
|
Then E84 runs in reverse: the AMHS robot couples to the load port,
|
|
the parallel I/O lines hand control back, the OHT hoist lifts the
|
|
FOUP, and `C-31415` heads to LITHO-3 for the next process step.
|
|
|
|
---
|
|
|
|
## Wait, what other acronyms exist?
|
|
|
|
The journey above covered the most common acronyms but skipped a
|
|
handful that show up in other contexts. A reference list for the
|
|
rest:
|
|
|
|
### Acknowledge codes you haven't met yet
|
|
|
|
| Code | Stream | Where | 0 = accepted, then… |
|
|
|----------|--------|--------------------------------|----------------------------------------------|
|
|
| `OFLACK` | 1 | S1F16 reply to "Request Offline" | 0=accept, 1=already offline |
|
|
| `ONLACK` | 1 | S1F18 reply to "Request Online" | 0=accept, 1=not allowed, 2=already online |
|
|
| `ACKC7` | 7 | S7F4 / S7F18 (recipe send/delete) | 0=accept, 1=permission denied, 2=length err,3=matrix err,4=PPID not found,5=mode unsupported,6=other |
|
|
| `ACKC10` | 10 | S10F2 / F4 / F6 (terminal services)| 0=accept, 1=not displayed, 2=no terminal |
|
|
| `CMDA` | 2 | S2F22 reply to legacy `S2F21` | 0=ok, 1=invalid command, 2=cannot do now,3=invalid arg |
|
|
| `TIACK` | 2 | S2F32 reply to "Set Clock" | 0=accept, 1=err not done |
|
|
| `EAC` | 2 | S2F16 reply to "Set EC values" | 0=accept, 1=≥1 constant out of range, 2=busy, 3=≥1 constant unknown |
|
|
| `RSPACK` | 2 | S2F44 reply to "Set Spool Streams" | 0=accept, 1=spool not supported, 2=≥1 stream unknown |
|
|
| `RSDA` | 6 | S6F24 reply to "Spool Data Send" | 0=ok, 1=denied |
|
|
| `PPGNT` | 7 | S7F2 reply to "PP Load Inquire"| 0=permit, 1=already have, 2=no room, 3=invalid PPID, 4=mode unsupported, 5=PP non-existent, 6=other |
|
|
|
|
### Control codes you haven't met
|
|
|
|
| Code | Stream | Where | What it means |
|
|
|----------|--------|-----------------------------|----------------------------------------------------------------|
|
|
| `RSDC` | 6 | S6F23 host command to spool | 0=transmit spooled, 1=purge spool |
|
|
| `ALED` | 5 | S5F3 host enable/disable alarm | bit 7 set = enable, bit 7 cleared = disable |
|
|
| `TID` | 10 | S10F1/F3/F5 terminal display | Which terminal screen to address (0 = main) |
|
|
| `TEXT` | 10 | S10F1/F3/F5 terminal display | The ASCII text payload |
|
|
|
|
### Object-services codes (E39)
|
|
|
|
| Code | Stream | Where | What it means |
|
|
|-----------|--------|-----------------------------|--------------------------------------------------------------|
|
|
| `OBJSPEC` | various | S2F49, S14F1 | An "object specifier" — a typed path identifying a target object |
|
|
| `OBJACK` | 14 | S14F2 / F10 / F12 reply | 0=ok, 1=command failed |
|
|
| `CPACK` | 2 | S2F42 reply (modern) | Per-parameter ack for each `CPNAME/CPVAL` in the command |
|
|
| `CEPACK` | 2 | S2F50 reply (enhanced) | Per-parameter ack for enhanced remote commands |
|
|
|
|
---
|
|
|
|
## All the T-timers in one place
|
|
|
|
You'll meet timer acronyms in three different contexts. They use
|
|
the same letters with different meanings — pin them down:
|
|
|
|
### HSMS T-timers (E37 §10)
|
|
|
|
These bound the *network* behaviour. Only fire when something is
|
|
slow or stuck.
|
|
|
|
| Name | Default | What it bounds |
|
|
|------|-------------|------------------------------------------------------|
|
|
| `T3` | 45 s | Reply timeout for a W=1 primary message |
|
|
| `T5` | 10 s | How long active side waits between connect attempts |
|
|
| `T6` | 5 s | Control-transaction (Select / Linktest) reply timeout |
|
|
| `T7` | 10 s | Passive side: max time without Select.req after TCP |
|
|
| `T8` | 5 s | Max time between bytes of a single frame |
|
|
|
|
Chapter [11](11_e37_hsms.md) covers each one in detail.
|
|
|
|
### SECS-I T-timers (E4 §10)
|
|
|
|
These bound the *serial-block* behaviour. Distinct from HSMS
|
|
T-timers despite the name overlap.
|
|
|
|
| Name | Default | What it bounds |
|
|
|------|-------------|------------------------------------------------------|
|
|
| `T1` | 500 ms | Inter-character timeout within one block |
|
|
| `T2` | 10 s | Protocol timer (handshake state) |
|
|
| `T3` | 45 s | Reply timeout for a W=1 primary message |
|
|
| `T4` | 45 s | Inter-block timeout in a multi-block message |
|
|
|
|
`T3` exists in both HSMS and SECS-I with the same semantics — it's
|
|
load-bearing in both transports.
|
|
|
|
### E84 timers (E84 §6)
|
|
|
|
These bound the *physical handoff* timing. Distinct again.
|
|
|
|
| Name | Default | What it bounds |
|
|
|-------|---------|-------------------------------------------------|
|
|
| `TA1` | ~2 s | `VALID` → `L_REQ` |
|
|
| `TA2` | ~2 s | `L_REQ` → `TR_REQ` |
|
|
| `TA3` | ~60 s | `BUSY` → transfer complete |
|
|
|
|
### E30 communication-state timers (E30 §6.5)
|
|
|
|
These bound the *application-level* establish-communications loop:
|
|
|
|
| Name | Default | What it bounds |
|
|
|-----------|---------|-----------------------------------------------------------------|
|
|
| `T_CRA` | 45 s | Wait for `S1F14` (Comm Request Acknowledge) reply after `S1F13` |
|
|
| `T_DELAY` | 10 s | Retry interval after a failed `S1F13` round-trip |
|
|
|
|
Defined in [`include/secsgem/gem/communication_state.hpp`](../include/secsgem/gem/communication_state.hpp);
|
|
tested in [`tests/test_communication_state.cpp`](../tests/test_communication_state.cpp).
|
|
|
|
---
|
|
|
|
## Stream-by-stream summary
|
|
|
|
The streams you'll meet most often, with one sentence each:
|
|
|
|
| Stream | What it's for | Most-used messages |
|
|
|--------|----------------------------------------------------------|---------------------------------------------------|
|
|
| S1 | Identification, status, control | `S1F1/F2`, `S1F3/F4`, `S1F11/F12`, `S1F13/F14`, `S1F15-F18`, `S1F19/F20`, `S1F21-F24` |
|
|
| S2 | Equipment constants, clock, events, commands | `S2F13-F18`, `S2F29-F38`, `S2F41/F42`, `S2F43-F50` |
|
|
| S3 | Carrier management (E87) | `S3F17/F18`, `S3F19/F20`, `S3F25-F28` |
|
|
| S5 | Alarms, exception recovery | `S5F1-F8`, `S5F9-F18` |
|
|
| S6 | Data collection, event reports, spool | `S6F11/F12`, `S6F15/F16`, `S6F19-F22`, `S6F23-F26` |
|
|
| S7 | Recipe / process program management | `S7F1-F6`, `S7F17-F20`, `S7F23-F26` |
|
|
| S9 | Protocol-error reports (auto-emitted by equipment) | `S9F1`, `S9F3`, `S9F5`, `S9F7`, `S9F9`, `S9F11`, `S9F13` |
|
|
| S10 | Terminal services | `S10F1-F6` |
|
|
| S12 | Wafer maps | (per-stream — chapter [10](10_e5_secs_ii_data_items.md) §6) |
|
|
| S14 | Generic object services (E39), control jobs (E94) | `S14F1/F2`, `S14F9-F12` |
|
|
| S16 | Process jobs (E40) | `S16F5-F8`, `S16F9`, `S16F11-F14`, `S16F27/F28` |
|
|
|
|
Where every named message lives in code: [`build/generated/secsgem/gem/messages.hpp`](../build/generated/secsgem/gem/messages.hpp)
|
|
(after a build) — generated from
|
|
[`data/messages.yaml`](../data/messages.yaml) by
|
|
[`tools/gen_messages.py`](../tools/gen_messages.py).
|
|
Chapter [31](31_spec_as_data_and_codegen.md) walks the codegen.
|
|
|
|
---
|
|
|
|
## You've made it through Part 1
|
|
|
|
You can now:
|
|
|
|
- Explain why SECS/GEM exists, and what each of "SECS", "HSMS", and
|
|
"GEM" actually refers to.
|
|
- Name every actor in the fab automation stack and describe who
|
|
talks to whom.
|
|
- Recognise every common acronym (SVID, ECID, DVID, CEID, RPTID,
|
|
ALID, PPID, MDLN, SOFTREV, HCACK, ALCD, OFLACK, …) and the
|
|
acknowledge bytes that go with each stream.
|
|
- List the T-timers in four different contexts (HSMS, SECS-I, E84,
|
|
E30 communication state) and not confuse them.
|
|
|
|
Part 2 of this guide takes one standard at a time, from the
|
|
ground up: byte-level encoding, wire diagrams, every message, every
|
|
ack value, the FSMs, and the code that implements each. We start
|
|
with the foundation everything else stands on — **E5 SECS-II**, the
|
|
data-item encoding.
|
|
|
|
Next: [→ 10 E5 — SECS-II data items](10_e5_secs_ii_data_items.md)
|