Files
secs-gem/docs/17_e116_e120_e39_objects.md
T
raphael 0355c73211
tests / build-and-test (push) Successful in 2m9s
tests / thread-sanitizer (push) Successful in 2m35s
tests / tshark-dissector (push) Successful in 2m17s
tests / secs4j-interop (push) Successful in 1m6s
tests / libfuzzer (push) Successful in 3m7s
docs: refresh stale file paths after store/ reorg + gen_messages rename
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>
2026-06-09 23:23:42 +02:00

7.2 KiB
Raw Blame History

17 — E116 + E120 + E39: Performance, CEM, objects

16 E90 + E157 — Substrate and module tracking | Back to index | Next: 18 E84 — Parallel I/O handoff

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

// 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:

enum class EptEvent {
  Begin_NonScheduledTime,
  Begin_UnscheduledDowntime,
  Begin_ScheduledDowntime,
  Begin_Engineering,
  Begin_Standby,
  Begin_Productive,
};

What the FSM records

EptStateMachine 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:

class EptStore {
  // For each EptState, accumulated wall-clock duration.
  std::array<std::chrono::seconds, 6> bucket_;

  // 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 (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 §5 shows one concrete wiring; chapter 41 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

// 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. Tests: 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 and the generated message catalog.

Tests are bundled into tests/test_cem_objects.cpp and 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