E1: SubstrateStateMachine + SubstrateStore (E90 §6)
Per-substrate dual FSM with two orthogonal axes:
Location (STS):
AtSource -> AtWork (Acquire) -> AtDestination (Release)
AtWork -> AtSource (Return; processing aborted before completion)
Processing:
NeedsProcessing -> InProcess (Start) -> Processed (End)
InProcess -> {Aborted, Stopped, Rejected, Lost} terminal
NeedsProcessing -> {Skipped, Lost} terminal
Wire-byte values pinned via static_assert to E90-0716 §10.3.
SubstrateStore mirrors the CarrierStore pattern: non-movable, per-row
SubstrateStateMachine heap-allocated with handlers dispatching through
the store's location/processing callbacks; fire_location_event accepts
an optional new_location string so the application can carry
equipment-specific module names alongside the FSM state.
Joins EquipmentDataModel alongside carriers / load_ports. 9 test
cases cover initial state, full location lifecycle, all five
processing exits, and store-level dual-axis observer firing.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "secsgem/gem/carrier_state.hpp" // shared CarrierTransition template
|
||||
|
||||
// E90 §6 Substrate Tracking — per-substrate state model.
|
||||
//
|
||||
// E90 actually defines several related state models per substrate:
|
||||
//
|
||||
// STS Substrate State the processing lifecycle
|
||||
// SLS Substrate Location where the wafer physically is
|
||||
// IDS Substrate ID Status has the ID been verified
|
||||
//
|
||||
// This first pass covers the most-used STS model (E90-0716 §10.3.1) at
|
||||
// full fidelity and exposes a Location string the application can
|
||||
// update as it sees substrate moves. IDS / cross-state guards mirror
|
||||
// the CIDS pattern from E87 and remain a follow-on.
|
||||
namespace secsgem::gem {
|
||||
|
||||
// Wire-byte values per E90-0716 §10.3.1 STS.
|
||||
enum class SubstrateState : uint8_t {
|
||||
AtSource = 0,
|
||||
AtWork = 1, // in-process at a module
|
||||
AtDestination = 2, // moved to final location
|
||||
NoState = 255,
|
||||
};
|
||||
|
||||
const char* substrate_state_name(SubstrateState s);
|
||||
std::optional<SubstrateState> parse_substrate_state(const std::string& s);
|
||||
|
||||
// "Processing" lifecycle (E90 §6.4.4); orthogonal to STS.
|
||||
enum class SubstrateProcessingState : uint8_t {
|
||||
NeedsProcessing = 0,
|
||||
InProcess = 1,
|
||||
Processed = 2,
|
||||
Aborted = 3,
|
||||
Stopped = 4,
|
||||
Rejected = 5,
|
||||
Lost = 6,
|
||||
Skipped = 7,
|
||||
NoState = 255,
|
||||
};
|
||||
|
||||
const char* substrate_processing_state_name(SubstrateProcessingState s);
|
||||
|
||||
enum class SubstrateEvent {
|
||||
Acquire, // AtSource -> AtWork (machine picked up the wafer)
|
||||
Release, // AtWork -> AtDestination (deposited)
|
||||
Return, // AtWork -> AtSource (returned without processing)
|
||||
};
|
||||
|
||||
const char* substrate_event_name(SubstrateEvent e);
|
||||
|
||||
enum class SubstrateProcessingEvent {
|
||||
StartProcessing, // NeedsProcessing -> InProcess
|
||||
EndProcessing, // InProcess -> Processed
|
||||
Abort, // any -> Aborted
|
||||
Stop, // any -> Stopped
|
||||
Reject, // any -> Rejected
|
||||
ReportLost, // any -> Lost
|
||||
Skip, // any -> Skipped
|
||||
};
|
||||
|
||||
const char* substrate_processing_event_name(SubstrateProcessingEvent e);
|
||||
|
||||
using SubstrateTable =
|
||||
CarrierTransitionTable<SubstrateState, SubstrateEvent>;
|
||||
using SubstrateProcessingTable =
|
||||
CarrierTransitionTable<SubstrateProcessingState, SubstrateProcessingEvent>;
|
||||
|
||||
SubstrateTable default_substrate_table();
|
||||
SubstrateProcessingTable default_substrate_processing_table();
|
||||
|
||||
class SubstrateStateMachine {
|
||||
public:
|
||||
using LocationChangeHandler =
|
||||
std::function<void(SubstrateState from, SubstrateState to, SubstrateEvent)>;
|
||||
using ProcessingChangeHandler =
|
||||
std::function<void(SubstrateProcessingState from,
|
||||
SubstrateProcessingState to,
|
||||
SubstrateProcessingEvent)>;
|
||||
|
||||
SubstrateStateMachine();
|
||||
|
||||
SubstrateState location_state() const { return loc_; }
|
||||
SubstrateProcessingState processing_state() const { return proc_; }
|
||||
|
||||
void set_location_handler(LocationChangeHandler h) { on_loc_ = std::move(h); }
|
||||
void set_processing_handler(ProcessingChangeHandler h) { on_proc_ = std::move(h); }
|
||||
|
||||
bool on_location_event(SubstrateEvent e);
|
||||
bool on_processing_event(SubstrateProcessingEvent e);
|
||||
|
||||
private:
|
||||
SubstrateTable loc_table_;
|
||||
SubstrateProcessingTable proc_table_;
|
||||
SubstrateState loc_ = SubstrateState::AtSource;
|
||||
SubstrateProcessingState proc_ = SubstrateProcessingState::NeedsProcessing;
|
||||
LocationChangeHandler on_loc_;
|
||||
ProcessingChangeHandler on_proc_;
|
||||
};
|
||||
|
||||
} // namespace secsgem::gem
|
||||
Reference in New Issue
Block a user