#pragma once #include #include #include #include #include // E87 §6 Carrier Management — three independent state models that // every carrier carries simultaneously: // // CIDS CarrierIDStatus id-verification lifecycle // CSMS CarrierSlotMapStatus slot-map verification lifecycle // CAS CarrierAccessingStatus is access in progress? // // Each FSM is per-carrier (keyed by CARRIERID inside CarrierStore) and // shares the table-driven pattern used by ProcessJobStateMachine / // ExceptionStateMachine. The wire-byte values match the on-the-wire // enums (E87-0716 §10.3). namespace secsgem::gem { // CIDS — CARRIER ID Status (E87-0716 §10.3.2). enum class CarrierIDStatus : uint8_t { NotConfirmed = 0, // initial; carrier has arrived, ID not yet verified Confirmed = 1, // host accepted the ID Mismatched = 2, // host rejected the ID Unknown = 3, // carrier ID could not be read NoState = 255, }; const char* carrier_id_status_name(CarrierIDStatus s); std::optional parse_carrier_id_status(const std::string& s); enum class CarrierIDEvent { Read, // equipment internal: an ID was read ProceedWithCarrier, // host: accept the ID (NotConfirmed -> Confirmed) CancelCarrier, // host: reject (any -> NotConfirmed) IDFailed, // equipment internal: read attempt failed Bind, // host explicit bind: any -> Confirmed (E87 §10.2.5) }; const char* carrier_id_event_name(CarrierIDEvent e); // CSMS — CARRIER Slot Map Status (E87-0716 §10.3.3). enum class SlotMapStatus : uint8_t { NotRead = 0, Read = 1, Mismatched = 2, NoState = 255, }; const char* slot_map_status_name(SlotMapStatus s); enum class SlotMapEvent { Read, // equipment internal: slot map was scanned Confirm, // host: matches what was expected Mismatch, // host: did not match expected Reset, // any -> NotRead (e.g. carrier removed) }; const char* slot_map_event_name(SlotMapEvent e); // CAS — CARRIER Accessing Status (E87-0716 §10.3.4). enum class CarrierAccessStatus : uint8_t { NotAccessed = 0, InAccess = 1, Complete = 2, // (CarrierCompleted in some texts) NoState = 255, }; const char* carrier_access_status_name(CarrierAccessStatus s); enum class CarrierAccessEvent { BeginAccess, // equipment internal: first substrate-move at carrier EndAccess, // equipment internal: last substrate processed Cancel, // any -> Complete (cancelled before access began) }; const char* carrier_access_event_name(CarrierAccessEvent e); // One row of each transition table; same shape as the PJ/CJ FSM rows // elsewhere in the project. template struct CarrierTransition { State from; Event on; std::optional to; std::optional ack_code; }; using CarrierIDTransition = CarrierTransition; using SlotMapTransition = CarrierTransition; using CarrierAccessTransition = CarrierTransition; template class CarrierTransitionTable { public: using Row = CarrierTransition; void add(Row r) { rows_.push_back(r); } const Row* find(State from, Event on) const { for (const auto& r : rows_) if (r.from == from && r.on == on) return &r; return nullptr; } std::size_t size() const { return rows_.size(); } const std::vector& rows() const { return rows_; } private: std::vector rows_; }; using CarrierIDTable = CarrierTransitionTable; using SlotMapTable = CarrierTransitionTable; using CarrierAccessTable = CarrierTransitionTable; CarrierIDTable default_carrier_id_table(); SlotMapTable default_slot_map_table(); CarrierAccessTable default_carrier_access_table(); // Per-carrier triple-FSM. All three substates are independent — a // carrier in CAS::InAccess may still be CIDS::NotConfirmed if the host // hasn't acknowledged the ID yet; the application is responsible for // any cross-FSM constraints it cares about. class CarrierStateMachine { public: using IDChangeHandler = std::function; using SlotMapChangeHandler = std::function; using AccessChangeHandler = std::function; CarrierStateMachine(); CarrierIDStatus id_status() const { return id_state_; } SlotMapStatus slot_map_status() const { return sm_state_; } CarrierAccessStatus access_status() const { return acc_state_; } void set_id_handler(IDChangeHandler h) { on_id_change_ = std::move(h); } void set_slot_map_handler(SlotMapChangeHandler h) { on_sm_change_ = std::move(h); } void set_access_handler(AccessChangeHandler h) { on_acc_change_ = std::move(h); } bool on_id_event(CarrierIDEvent e); bool on_slot_map_event(SlotMapEvent e); bool on_access_event(CarrierAccessEvent e); private: CarrierIDTable id_table_; SlotMapTable sm_table_; CarrierAccessTable acc_table_; CarrierIDStatus id_state_ = CarrierIDStatus::NotConfirmed; SlotMapStatus sm_state_ = SlotMapStatus::NotRead; CarrierAccessStatus acc_state_ = CarrierAccessStatus::NotAccessed; IDChangeHandler on_id_change_; SlotMapChangeHandler on_sm_change_; AccessChangeHandler on_acc_change_; }; } // namespace secsgem::gem