Files
secs-gem/docs/17_e116_e120_e39_objects.md
T
raphael 4b4b2ac690 docs: correct drifted and fabricated APIs in chapters 13/17/35/51
An audit of doc code blocks against the real headers found APIs that do
not exist in the codebase, presented as authoritative walkthroughs:

- ch35 (dispatch): an entirely fabricated callback architecture —
  HostCommandRegistry::set_emit_ceid_handler, CommandOutcome, emit_ceids.
  Rewritten to the real Spec/Result/dispatch + the new set_handler hook.
- ch13 (E30): wrong store names — EventStore/ReportStore -> EventReportSubscriptions,
  SvidStore -> StatusVariableStore, AlarmStore/AlarmDispatcher -> AlarmRegistry,
  ClockStore -> Clock, TerminalServiceStore -> (no store), in both the
  capability tables and the worked S2F33 example.
- ch17 (E116): EptStore/seconds/bucket_ -> EptStateMachine/milliseconds/buckets_.
- ch51 (extending): stale host-command handler -> the real set_handler signature.

Verified clean by grep: no fabricated symbols remain in docs/.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 18:00:58 +02:00

230 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 17 — E116 + E120 + E39: Performance, CEM, objects
← [16 E90 + E157 — Substrate and module tracking](16_e90_e157_substrates_modules.md) | [Back to index](00_index.md) | Next: [18 E84 — Parallel I/O handoff](18_e84_parallel_io.md) →
Three smaller GEM 300 standards in one chapter. Each is narrow in
scope but load-bearing for production fab operations.
- **E116** — Equipment Performance Tracking. Time-buckets per
equipment state for OEE / utilisation reporting.
- **E120** — Common Equipment Model. A generic typed object
hierarchy the host can query.
- **E39** — Object Services. CRUD-style messages (`S14F*`) that
operate over E120 (and other) object types.
---
## E116 — Equipment Performance Tracking
### What it does
In a fab, **equipment utilisation** is a primary KPI. Tools cost
$10100M; idle minutes are visible on quarterly P&L statements.
E116 standardises how equipment reports *how much time it spent
in each state* so MES dashboards can compute OEE (Overall Equipment
Effectiveness) without per-vendor logic.
### The states
```cpp
// include/secsgem/gem/ept_state.hpp:22
enum class EptState : uint8_t {
NonScheduledTime = 0, // not in the schedule (weekend, planned down)
UnscheduledDowntime = 1, // in schedule, but broken (alarm, fault)
ScheduledDowntime = 2, // in schedule, planned maintenance
Engineering = 3, // running engineering / qualification work
Standby = 4, // ready, awaiting material
Productive = 5, // actively processing
};
```
These are the SEMI E116 §6.2 standard states. Per-state events:
```cpp
enum class EptEvent {
Begin_NonScheduledTime,
Begin_UnscheduledDowntime,
Begin_ScheduledDowntime,
Begin_Engineering,
Begin_Standby,
Begin_Productive,
};
```
### What the FSM records
[`EptStateMachine`](../include/secsgem/gem/ept_state.hpp) is a
"what kind of time is this" classifier rather than a strict
lifecycle. Any state can transition to any other. What it
tracks: **how long was the equipment in each state**.
The store accumulates time-buckets:
```cpp
class EptStateMachine {
// For each EptState, accumulated wall-clock duration.
std::array<std::chrono::milliseconds, 6> buckets_{};
// Current state + when it was entered (so the dwell so far is
// counted as part of the current bucket on read).
};
```
A host querying "how much Productive time today?" gets the bucket
value for `Productive`, plus the dwell of the current state if
that state is Productive.
### Wire
E116 doesn't define its own S/F messages. Like E90, state changes
fire as **CEIDs** the host has subscribed to.
Tests:
[`tests/test_ept.cpp`](../tests/test_ept.cpp) (7 cases — initial
state, transitions, bucket accumulation including current dwell,
reset, same-state no-op).
### When EPT transitions happen
EPT classification is *application logic*. The library doesn't
decide that processing a PJ = Productive — the EAP does, by
explicitly calling `EptStateMachine::on_event(Begin_Productive)`
when a PJ starts. Typical wiring:
```
PJ Processing → EPT Productive
PJ Paused → EPT Standby (or Engineering, depending on cause)
Alarm category 2 (equipment safety) → EPT UnscheduledDowntime
Maintenance recipe running → EPT ScheduledDowntime
```
The [`examples/pvd_tool/main.cpp`](../examples/pvd_tool/main.cpp) §5
shows one concrete wiring; chapter
[41](41_integration_hardware_mes_production.md) discusses the
production patterns.
---
## E120 — Common Equipment Model
### What it does
E120 defines a **generic typed object hierarchy** the equipment can
expose to the host. The motivation: every E30/GEM 300 standard
defines its own object type (Carrier, Substrate, ProcessJob,
ControlJob, Alarm, …), each with its own attributes. E120 says
"all of these are *objects* with the same hierarchical structure;
let's standardise how the host queries them."
### The object types
```cpp
// include/secsgem/gem/store/cem_objects.hpp:27
enum class CemObjectType : uint8_t {
Equipment = 1,
IOProcessor = 2,
IODevice = 3,
SubsystemController = 4,
Subsystem = 5,
Module = 6,
// ... more
};
```
Each object has:
- A unique `OBJID` (ASCII string).
- A type from the enum above.
- A `parent_objid` (or empty for root — Equipment).
- A typed attribute bag.
That builds the hierarchy:
```
Equipment "PVD-1"
├── IOProcessor "IOP-1"
│ ├── IODevice "Sensor-Pressure-A"
│ └── IODevice "Sensor-Temp-A"
└── SubsystemController "SubC-1"
├── Subsystem "Vacuum"
│ └── Module "Pump-1"
└── Subsystem "Gas-Manifold"
```
The host can walk this tree, read attributes, and update its own
asset model.
### Code
Store:
[`include/secsgem/gem/store/cem_objects.hpp`](../include/secsgem/gem/store/cem_objects.hpp).
Tests:
[`tests/test_cem_objects.cpp`](../tests/test_cem_objects.cpp) (3
cases — create, lookup, child enumeration).
### Wire
E120 itself doesn't define messages — it defines the *data model*.
The wire access is **E39 Object Services**.
---
## E39 — Object Services
### What it does
E39 generalises "get attribute of an object" and "set attribute of
an object" into one message family — `S14F*` — that works across
**any object type** (E120 hierarchy, E40 process jobs, E94 control
jobs, E87 carriers, …).
### The messages
| S/F | Direction | Purpose |
|-------|-----------|----------------------------------------------------------|
| S14F1 | H → E | GetAttr. Body: object type + OBJID + attribute name list. |
| S14F2 | E → H | GetAttr reply. Body: attribute values + OBJACK byte. |
| S14F3 | H → E | SetAttr. Body: object type + OBJID + name/value pairs. |
| S14F4 | E → H | SetAttr reply. |
OBJACK = 0 means accepted; non-zero means error.
E39 is the **uniform API** for object introspection — same shape
of message whether the host is reading a Carrier attribute, an
Alarm attribute, or a Process Module attribute.
### Code
Handlers live in
[`include/secsgem/gem/store/host_commands.hpp`](../include/secsgem/gem/store/host_commands.hpp)
and the generated message catalog.
Tests are bundled into
[`tests/test_cem_objects.cpp`](../tests/test_cem_objects.cpp) and
[`tests/test_messages.cpp`](../tests/test_messages.cpp) — the
`S14F1`/`S14F2` round-trip is exercised against multiple object
types.
### Why E39 exists separately from E120
The split is the SEMI typical-shape: one standard defines the
*data model*, a separate standard defines the *wire access*. This
way E39 can extend to objects defined in other standards (E40 PJs,
E94 CJs, E87 carriers) without E120 having to know about them.
In code, each object store registers itself with a generic
attribute-resolver; `S14F1` handlers look up the right resolver by
object type.
---
## Where to go next
You now know how the equipment reports *time* (E116), *structure*
(E120), and *attribute access* (E39). The next chapter is the
last GEM 300 standard with its own state machine — the **parallel
I/O handshake** that physically hands carriers between robot and
load port.
Next: [→ 18 E84 — Parallel I/O handoff](18_e84_parallel_io.md)