docs: chapters 02 + 03 of the guided tour (Part 1 complete)
02 — The cast of characters: equipment, EAP, MES, fab planner, AMHS, operator. Who initiates which conversation, why the equipment is the passive side of HSMS by convention, how the AMHS handshake is out-of-band relative to SECS. Cross-references the relevant namespace and test files for each actor. 03 — Vocabulary + a wafer's journey: follows one 300 mm wafer end-to-end through a fab and labels every SECS message and acronym that fires. Introduces SVID / DVID / ECID / CEID / RPTID / ALID / PPID / MDLN / SOFTREV / HCACK / ALCD / OFLACK / CAACK / SMACK / etc. in context rather than as a list. Includes one-screen reference tables for the remaining acknowledge codes, T-timers in all four contexts (HSMS / SECS-I / E84 / E30 communication state), and a stream-by-stream summary. Part 1 (Foundations) of the guided tour is now complete — a reader who reads chapters 01–03 can describe the protocol stack, identify the actors, and recognise every acronym they'll meet in Part 2. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,417 @@
|
||||
# 02 — The cast of characters
|
||||
|
||||
← [01 What is SECS/GEM?](01_what_is_secs_gem.md) | [Back to index](00_index.md) | Next: [03 Vocabulary + a wafer's journey](03_vocabulary_and_a_wafers_journey.md) →
|
||||
|
||||
Chapter [01](01_what_is_secs_gem.md) explained that SECS/GEM is the
|
||||
protocol a fab uses to make ~100 tools talk to a central MES. That
|
||||
description hid a lot of structure. In reality, there are at least
|
||||
**six distinct actors** in a typical fab automation stack — six
|
||||
roles, each implemented by different software (often by different
|
||||
vendors), each with its own concerns.
|
||||
|
||||
This chapter introduces them all, draws who-talks-to-whom, and
|
||||
locates each one in this codebase. After this you'll be able to read
|
||||
any SECS conversation and know which actor is initiating, which is
|
||||
responding, and why.
|
||||
|
||||
---
|
||||
|
||||
## The six actors
|
||||
|
||||
```
|
||||
┌──────────────────┐
|
||||
│ Fab planner │ "make 100 wafers
|
||||
│ (MES upper) │ of recipe R by
|
||||
└────────┬─────────┘ Friday"
|
||||
│
|
||||
recipes, lot │ yields, KPIs,
|
||||
assignments, │ alarms, status
|
||||
process programs │
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ MES (the host) │ per-step orchestration
|
||||
└────────┬─────────┘
|
||||
│
|
||||
SECS/GEM │ SECS/GEM
|
||||
S2F41 RCMD, │ S6F11 events,
|
||||
S7F3 PP send, │ S5F1 alarms,
|
||||
S2F33 reports, │ S1F4 status
|
||||
… │ …
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ EAP / equipment automation program │
|
||||
│ (vendor application layer) │
|
||||
├──────────────────────────────────────────┤
|
||||
│ THIS CODEBASE — the SECS/GEM runtime │
|
||||
│ secsgem::gem / secsgem::hsms / … │
|
||||
└────────┬─────────────────────────────────┘
|
||||
│
|
||||
PLC / sensor / recipe-engine APIs (tool-specific)
|
||||
│
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ Equipment │ the physical tool:
|
||||
│ (the tool) │ chambers, robots,
|
||||
└────────┬─────────┘ sensors, recipes
|
||||
│
|
||||
E84 8-line │ (carrier moves, no SECS bytes)
|
||||
parallel I/O │
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ AMHS │ robot rails / OHT
|
||||
│ (the carriers) │ that move FOUPs
|
||||
└──────────────────┘
|
||||
|
||||
←───── Operator ──────→ panel buttons,
|
||||
recipe overrides,
|
||||
Online/Offline/Local/Remote
|
||||
```
|
||||
|
||||
Read the diagram top-down: a fab planner schedules work, the MES
|
||||
dispatches it tool by tool, each tool's EAP receives commands over
|
||||
SECS/GEM, the EAP drives the actual hardware, the AMHS robots feed
|
||||
carriers in and out. An operator can intervene at any layer.
|
||||
|
||||
Each actor has a section below.
|
||||
|
||||
---
|
||||
|
||||
## 1. Equipment — the tool itself
|
||||
|
||||
**What it is.** A physical processing tool — a chemical-vapor
|
||||
deposition (CVD) chamber, a plasma etcher, a wafer prober, a
|
||||
photolithography stepper, an ion implanter, an inspection
|
||||
microscope. Anywhere from one chamber the size of a microwave to a
|
||||
full lithography cluster the size of a small bus.
|
||||
|
||||
**What it does in SECS/GEM terms.**
|
||||
|
||||
- **Reports state** — its current control state (Equipment Offline,
|
||||
Online Remote, …), its processing state (IDLE, EXECUTING, …), its
|
||||
carrier slots, its current recipe.
|
||||
- **Emits events** — when something happens worth recording
|
||||
(processing started, wafer processed, alarm raised, recipe
|
||||
completed), it fires an `S6F11` to the host.
|
||||
- **Accepts commands** — START, STOP, ABORT, PAUSE, CHANGE-RECIPE,
|
||||
CARRIER-PROCEED, etc., delivered as `S2F41` Host Commands.
|
||||
- **Stores its data dictionary** — every Status Variable (SVID),
|
||||
Equipment Constant (ECID), Data Variable (DVID), Collection Event
|
||||
(CEID), Alarm (ALID), and Process Program (PPID) it supports.
|
||||
- **Manages its own physical safety** — it can refuse a host command
|
||||
if the requested action would damage hardware, and it can raise
|
||||
alarms autonomously.
|
||||
|
||||
**In SECS/GEM, the equipment is almost always the "passive" side of
|
||||
the connection** — it binds a TCP port and waits for the host to
|
||||
connect, rather than the other way around. This codebase reflects
|
||||
that: `apps/secs_server.cpp` is the equipment, and it listens.
|
||||
|
||||
**Where it lives in this codebase.**
|
||||
|
||||
- The equipment role's main binary: [`apps/secs_server.cpp`](../apps/secs_server.cpp).
|
||||
- The data dictionary: [`include/secsgem/gem/data_model.hpp`](../include/secsgem/gem/data_model.hpp)
|
||||
defines `EquipmentDataModel`, which composes every per-domain
|
||||
store (SVIDs, ECIDs, CEIDs, alarms, carriers, substrates, recipes,
|
||||
spool, …).
|
||||
- A worked example with sensor simulation, recipe runner, and alarm
|
||||
monitoring: [`examples/pvd_tool/main.cpp`](../examples/pvd_tool/main.cpp).
|
||||
- Tests covering equipment behaviour: [`tests/test_data_model.cpp`](../tests/test_data_model.cpp),
|
||||
[`tests/test_control_state.cpp`](../tests/test_control_state.cpp),
|
||||
[`tests/test_host_handler.cpp`](../tests/test_host_handler.cpp).
|
||||
|
||||
---
|
||||
|
||||
## 2. EAP — the equipment automation program
|
||||
|
||||
**What it is.** The vendor-written software layer that sits on top
|
||||
of the SECS/GEM runtime and *makes the tool actually do things*.
|
||||
The EAP is the glue between:
|
||||
|
||||
- The SECS/GEM library (this codebase),
|
||||
- The tool's PLCs / sensors / recipe engine / robot controllers,
|
||||
- The tool vendor's domain logic.
|
||||
|
||||
Every tool vendor ships their own EAP. Two CVD tools from different
|
||||
vendors both speak GEM, but their EAPs are entirely different
|
||||
codebases doing entirely different things internally.
|
||||
|
||||
**Why it's a separate role.** The SECS/GEM standards spell out
|
||||
*what* messages mean — "S2F41 with RCMD=START must initiate
|
||||
processing on the currently loaded recipe." They don't spell out
|
||||
*how* a specific CVD tool initiates processing on its specific
|
||||
hardware. The EAP is the layer that resolves that.
|
||||
|
||||
In particular:
|
||||
|
||||
- When `S2F41 RCMD=START` arrives, the EAP decides whether the tool
|
||||
is in a state to start (chamber pressure low enough? robot at
|
||||
home position? recipe loaded?), and if so, calls the tool's
|
||||
proprietary recipe engine to begin the cycle.
|
||||
- When a sensor reads a temperature change, the EAP decides whether
|
||||
to update an SVID, fire a CEID, or raise an alarm — and the
|
||||
per-tool rules for that aren't in any SEMI standard.
|
||||
- When a `S7F3` arrives with a new recipe payload, the EAP decides
|
||||
how to validate the recipe against the tool's actual hardware
|
||||
capabilities.
|
||||
|
||||
**Where it lives in this codebase.**
|
||||
|
||||
This codebase provides the SECS/GEM runtime; the EAP is what a
|
||||
customer writes on top of it. We ship two reference EAPs:
|
||||
|
||||
- [`apps/secs_server.cpp`](../apps/secs_server.cpp) — the demo
|
||||
server. Wires every Router handler the demo flow needs; uses
|
||||
static YAML data and doesn't simulate any sensors. Useful as a
|
||||
starting fork.
|
||||
- [`examples/pvd_tool/main.cpp`](../examples/pvd_tool/main.cpp) — a
|
||||
fictional PVD tool that adds a sensor simulator, a recipe runner,
|
||||
an alarm threshold monitor, EPT state cycling, and Prometheus
|
||||
metrics. This is the closest thing to "what a real EAP looks
|
||||
like" that we ship. See [`examples/pvd_tool/README.md`](../examples/pvd_tool/README.md)
|
||||
for the section-by-section walk.
|
||||
|
||||
The integration tutorial — how to *write* an EAP for a real tool —
|
||||
is [`INTEGRATION.md`](INTEGRATION.md). Chapter
|
||||
[41](41_integration_hardware_mes_production.md) in this series covers
|
||||
the same material with cross-references back to the standards.
|
||||
|
||||
---
|
||||
|
||||
## 3. MES — the host
|
||||
|
||||
**What it is.** The **Manufacturing Execution System**. A
|
||||
fab-wide server (or cluster) that orchestrates production across
|
||||
every tool, manages lots and recipes, collects yield and statistical
|
||||
process control (SPC) data, and provides the operator UI for the
|
||||
production floor.
|
||||
|
||||
Commercial MES vendors you'll meet: Applied Materials **E3**, Camstar
|
||||
**InSite**, Wonderware **MES**, Aegis **FactoryWorks**, Inficon
|
||||
**FabGuard**, Critical Manufacturing **MES**, and many in-house
|
||||
custom builds especially at the largest fabs.
|
||||
|
||||
**What it does in SECS/GEM terms.**
|
||||
|
||||
- **Connects** to each tool's equipment process. In SECS/GEM
|
||||
language, the MES is the **active** side of the HSMS connection
|
||||
(it initiates the TCP connect and sends `Select.req`).
|
||||
- **Establishes communications** — sends `S1F13` to which the
|
||||
equipment replies `S1F14(COMMACK=Accept)`.
|
||||
- **Identifies the tool** — sends `S1F1` (Are You There), reads
|
||||
back the `MDLN` (model name) and `SOFTREV` (software revision)
|
||||
in `S1F2`.
|
||||
- **Reads the data dictionary** — `S1F11` for the SVID namelist,
|
||||
`S2F29` for the ECID namelist, `S1F23` for the CEID namelist,
|
||||
`S5F5` for the alarm directory, `S7F19` for the recipe list.
|
||||
- **Configures event reports** — `S2F33` defines a report,
|
||||
`S2F35` links it to a Collection Event, `S2F37` enables it. This
|
||||
is how the MES tells the tool "when CEID 300 fires, send me the
|
||||
values of SVIDs 1 and 2 along with it."
|
||||
- **Issues remote commands** — `S2F41 RCMD=START`, `S2F41
|
||||
RCMD=PAUSE`, `S2F41 RCMD=ABORT`, etc.
|
||||
- **Manages recipes** — `S7F3` to send a recipe, `S7F19` to list,
|
||||
`S7F17` to delete, `S7F5` to read one back.
|
||||
- **Orchestrates process and control jobs** — `S16F11` to create
|
||||
a Process Job, `S14F9` to wrap it in a Control Job, `S16F27`
|
||||
CJSTART to begin execution.
|
||||
- **Receives alarms and events** — `S5F1` for alarm set/clear,
|
||||
`S6F11` for collection events. Acknowledges with `S5F2` and
|
||||
`S6F12` respectively.
|
||||
- **Sets and reads the equipment's clock** — `S2F17`/`S2F18` to
|
||||
read, `S2F31`/`S2F32` to set.
|
||||
|
||||
**Where it lives in this codebase.**
|
||||
|
||||
We don't *implement* an MES — that's a separate, much larger product
|
||||
category. We implement the host *side* of SECS/GEM so the codebase
|
||||
can drive equipment too, mainly for testing.
|
||||
|
||||
- [`apps/secs_client.cpp`](../apps/secs_client.cpp) — the active
|
||||
host that drives the demo server through ~24 transactions.
|
||||
- [`apps/secs_conformance.cpp`](../apps/secs_conformance.cpp) — the
|
||||
host-driven conformance harness that runs the 47 wire-level checks.
|
||||
- [`include/secsgem/gem/host_handler.hpp`](../include/secsgem/gem/host_handler.hpp)
|
||||
+ [`src/gem/host_handler.cpp`](../src/gem/host_handler.cpp) —
|
||||
symmetric handler module so the host side can decode equipment
|
||||
replies and act on equipment-initiated S5F1 / S6F11.
|
||||
- [`interop/host_vs_cpp_server.py`](../interop/host_vs_cpp_server.py)
|
||||
— the secsgem-py active host driving our C++ passive server.
|
||||
|
||||
For integrating against a **commercial** MES,
|
||||
[`MES_INTEROP.md`](MES_INTEROP.md) is the day-1 punch list.
|
||||
|
||||
---
|
||||
|
||||
## 4. Fab planner / MES upper layer
|
||||
|
||||
**What it is.** The layer *above* the MES. Goes by many names:
|
||||
**Advanced Planning and Scheduling (APS)**, **Fab scheduler**,
|
||||
**Dispatcher**, **MES upper**. Big fabs separate this from the
|
||||
operational MES; smaller ones bundle it in.
|
||||
|
||||
**What it does.** Decides which lot runs on which tool, in what
|
||||
order, against what recipe, by what deadline. This is fab-wide
|
||||
optimisation across hundreds of in-flight lots and dozens of routes.
|
||||
|
||||
**SECS/GEM contact:** none directly. The planner talks to the MES
|
||||
via REST / SQL / a message queue / a proprietary API. The MES
|
||||
translates planner decisions into SECS commands.
|
||||
|
||||
**Where it lives in this codebase.** Not implemented; out of scope.
|
||||
Mentioned here so the reader knows where the recipes and lot
|
||||
assignments ultimately come from, but no codebase artifact
|
||||
corresponds to this layer.
|
||||
|
||||
---
|
||||
|
||||
## 5. AMHS — Automated Material Handling System
|
||||
|
||||
**What it is.** The robot-rail network and overhead hoist transport
|
||||
(**OHT**) system that physically moves carriers (FOUPs holding ~25
|
||||
wafers each) between tools. In a modern 300 mm fab the AMHS is
|
||||
*always* moving carriers between tools 24/7; humans never touch a
|
||||
substrate.
|
||||
|
||||
**What it does in SECS/GEM terms.**
|
||||
|
||||
- The AMHS itself **doesn't speak SECS/GEM** — it has its own
|
||||
control plane talking to a Material Control System (MCS) which is
|
||||
conceptually peer to the MES.
|
||||
- But every time a carrier *arrives at* or *departs from* an
|
||||
equipment's load port, the AMHS-side robot and the equipment-side
|
||||
load port **handshake over 8 parallel I/O lines** defined by
|
||||
**E84**. This is a physical-layer handshake (CMOS-level voltages
|
||||
on real wires) with strict timing — TA1, TA2, TA3 timers — to
|
||||
make sure a $20 000 FOUP doesn't get dropped because both sides
|
||||
thought the other one was holding it.
|
||||
- Once the carrier is physically docked, the equipment fires a
|
||||
`S6F11(CarrierArrived)` event to the MES and the MES sends back a
|
||||
`S3F17(CarrierAction=ProceedWithCarrier)` to authorise processing.
|
||||
|
||||
**Where it lives in this codebase.**
|
||||
|
||||
- The E84 handshake state machine: [`include/secsgem/gem/e84.hpp`](../include/secsgem/gem/e84.hpp)
|
||||
+ [`src/gem/e84.cpp`](../src/gem/e84.cpp).
|
||||
- The TA1/TA2/TA3 timer wiring: [`include/secsgem/gem/e84_timers.hpp`](../include/secsgem/gem/e84_timers.hpp),
|
||||
[`include/secsgem/gem/e84_asio_timers.hpp`](../include/secsgem/gem/e84_asio_timers.hpp).
|
||||
- The per-port store: `e84_ports.hpp` (see [`include/secsgem/gem/e84_ports.hpp`](../include/secsgem/gem/e84_ports.hpp)).
|
||||
- Tests covering the timing rules: [`tests/test_e84.cpp`](../tests/test_e84.cpp),
|
||||
[`tests/test_e84_timers.cpp`](../tests/test_e84_timers.cpp),
|
||||
[`tests/test_e84_asio_timers.cpp`](../tests/test_e84_asio_timers.cpp),
|
||||
[`tests/test_e84_ports.cpp`](../tests/test_e84_ports.cpp).
|
||||
|
||||
Chapter [18](18_e84_parallel_io.md) covers E84 in full.
|
||||
|
||||
---
|
||||
|
||||
## 6. Operator — the human
|
||||
|
||||
**What it is.** The fab technician at the tool's local panel. Their
|
||||
job is to handle anything the automation can't: load a non-AMHS
|
||||
carrier, clear a jammed wafer, run a maintenance recipe, respond to
|
||||
an alarm the MES can't auto-clear.
|
||||
|
||||
**What they do in SECS/GEM terms.**
|
||||
|
||||
- **Mode switch.** The operator can push the equipment between
|
||||
control states: `EquipmentOffline`, `OnlineLocal` (commands
|
||||
accepted only from the local panel), `OnlineRemote` (commands
|
||||
accepted from the MES). This is E30 §6.2.
|
||||
- **Override.** An operator can override an MES command (refuse to
|
||||
start, force-clear an alarm, manually unload a carrier). In
|
||||
SECS/GEM terms this is reflected by control-state transitions:
|
||||
`OnlineRemote` → `OnlineLocal` means "operator has taken control."
|
||||
- **Local alarm acknowledgement.** Some alarms can be cleared at
|
||||
the panel without the MES being involved; the equipment then
|
||||
emits an `S5F1` with the cleared bit so the MES catches up.
|
||||
|
||||
**Where it lives in this codebase.**
|
||||
|
||||
- The control state machine: [`include/secsgem/gem/control_state.hpp`](../include/secsgem/gem/control_state.hpp)
|
||||
+ [`src/gem/control_state.cpp`](../src/gem/control_state.cpp).
|
||||
- The transition table loaded from YAML: [`data/control_state.yaml`](../data/control_state.yaml).
|
||||
- The operator-initiated transition handlers:
|
||||
`ControlStateMachine::operator_online`, `::operator_offline`,
|
||||
`::operator_local`, `::operator_remote` in the same header.
|
||||
- Tests: [`tests/test_control_state.cpp`](../tests/test_control_state.cpp).
|
||||
|
||||
Chapter [13](13_e30_gem.md) walks through control state in detail.
|
||||
|
||||
---
|
||||
|
||||
## Who talks to whom
|
||||
|
||||
A short reference table. "Init." marks who initiates the
|
||||
conversation; "Channel" marks the protocol layer.
|
||||
|
||||
| Pair | Init. | Channel | Examples |
|
||||
|----------------------------|------------|---------------------------------------------|-----------------------------------------------------------|
|
||||
| Planner ↔ MES | Planner | REST / SQL / queue (out of scope) | "run lot L on tool T with recipe R" |
|
||||
| MES ↔ EAP | MES | HSMS-SS (one TCP socket, equipment passive) | `S1F1`, `S2F41`, `S6F11`, `S5F1`, … |
|
||||
| MES ↔ EAP (multi-MES) | MES | HSMS-GS (one TCP socket, multiple sessions) | Same messages, demuxed by session_id |
|
||||
| EAP ↔ Equipment | Either | PLC / sensor APIs / recipe engine (tool-specific) | Out of scope of SECS/GEM |
|
||||
| AMHS ↔ Load port | AMHS | E84 8-line parallel I/O | VALID/CS_0/CS_1/TR_REQ/READY/BUSY/COMPT/CONT/L_REQ/U_REQ/ES |
|
||||
| MES ↔ EAP (carrier flow) | Equipment | HSMS | `S6F11(CarrierArrived)`, `S3F17(ProceedWithCarrier)` |
|
||||
| Operator ↔ Equipment | Operator | Local panel | Online/Offline buttons, alarm acks |
|
||||
|
||||
The four interesting things in this table:
|
||||
|
||||
1. **The MES is the active side, the equipment is the passive side.**
|
||||
Always. Equipment binds the port; MES connects to it. Some MES
|
||||
want this reversed and will negotiate, but the GEM default is
|
||||
equipment-passive.
|
||||
2. **One TCP socket per (MES, equipment) pair.** HSMS-SS doesn't
|
||||
multiplex; one connection serves one conversation. HSMS-GS adds
|
||||
session multiplexing on top.
|
||||
3. **Equipment-initiated traffic exists.** `S6F11` events and
|
||||
`S5F1` alarms fire from equipment to MES *autonomously*, not
|
||||
in reply to a host command. An EAP that never emits unsolicited
|
||||
traffic is broken.
|
||||
4. **The AMHS handshake is out-of-band relative to SECS/GEM.**
|
||||
E84's 8 parallel I/O lines are real wires with real voltages;
|
||||
the SECS messages that follow (`S6F11`, `S3F17`) are just the
|
||||
*bookkeeping* around a handoff that already happened in
|
||||
hardware.
|
||||
|
||||
---
|
||||
|
||||
## A small mental check
|
||||
|
||||
If you've internalised the chapter, you should be able to answer:
|
||||
|
||||
1. When the MES sends `S1F13`, who initiates the TCP connection?
|
||||
2. When a chamber pressure sensor reads out of range, who decides
|
||||
whether to fire `S5F1`?
|
||||
3. What language does the AMHS speak to the equipment to coordinate
|
||||
a FOUP handoff?
|
||||
4. Is the operator at the local panel a SECS/GEM actor?
|
||||
5. Is the fab planner a SECS/GEM actor?
|
||||
|
||||
Answers, in order:
|
||||
|
||||
1. The MES. The equipment is passive; it binds and waits. TCP
|
||||
connect is the MES's first move.
|
||||
2. The EAP (the vendor's application code on top of this library).
|
||||
The SECS/GEM library doesn't know what's a "normal" pressure;
|
||||
the EAP does. Once the EAP decides "this is alarm-worthy," it
|
||||
calls into the alarm store and the library emits `S5F1`.
|
||||
3. E84 8-line parallel I/O — physical wires, not SECS. After the
|
||||
handoff, the *bookkeeping* SECS messages (`S6F11`, `S3F17`) flow
|
||||
between equipment and MES.
|
||||
4. Yes — through E30 §6.2 control-state transitions. Not a SECS
|
||||
message *sender*, but a state-transition source the equipment
|
||||
has to report on.
|
||||
5. No. The planner talks to the MES; the MES talks to the EAP.
|
||||
The planner is invisible from the SECS wire.
|
||||
|
||||
---
|
||||
|
||||
## What's next
|
||||
|
||||
You now know who's in the room and who's talking to whom. The next
|
||||
chapter introduces the **vocabulary** — every SEMI acronym you'll
|
||||
read in a debug log (SVID, CEID, ALID, PPID, ALCD, HCACK, T-timers,
|
||||
…) — by tracing **one wafer's journey** end-to-end through a fab and
|
||||
labelling every SECS message that fires along the way.
|
||||
|
||||
Next: [→ 03 Vocabulary + a wafer's journey](03_vocabulary_and_a_wafers_journey.md)
|
||||
@@ -0,0 +1,592 @@
|
||||
# 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.hpp`](../include/secsgem/gem/e84.hpp)
|
||||
defines the FSM; [`include/secsgem/gem/e84_timers.hpp`](../include/secsgem/gem/e84_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/carrier_store.hpp`](../include/secsgem/gem/carrier_store.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/process_jobs.hpp`](../include/secsgem/gem/process_jobs.hpp),
|
||||
[`include/secsgem/gem/control_jobs.hpp`](../include/secsgem/gem/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/report_store.hpp`](../include/secsgem/gem/report_store.hpp),
|
||||
[`include/secsgem/gem/event_store.hpp`](../include/secsgem/gem/event_store.hpp).
|
||||
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/host_command_registry.hpp`](../include/secsgem/gem/host_command_registry.hpp)
|
||||
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/alarm_store.hpp`](../include/secsgem/gem/alarm_store.hpp);
|
||||
the dispatcher gates emission on the enable list in
|
||||
[`include/secsgem/gem/alarm_dispatcher.hpp`](../include/secsgem/gem/alarm_dispatcher.hpp).
|
||||
|
||||
---
|
||||
|
||||
## 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/generate_messages.py`](../tools/generate_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)
|
||||
Reference in New Issue
Block a user