#pragma once #include #include #include #include #include #include #include #include "secsgem/gem/carrier_state.hpp" // shared CarrierTransition template // E116 §6 Equipment Performance Tracking — top-level equipment state // model that classifies operating time into productive / non-productive // categories. Each transition is timestamped so the application can // compute MTBF / availability / utilization from the same source. // // The states correspond directly to the SEMI-defined buckets in E116- // 0712 §6.2; the wire byte values match the order the spec presents. namespace secsgem::gem { enum class EptState : uint8_t { NonScheduledTime = 0, // equipment not scheduled to operate ScheduledDowntime = 1, // scheduled maintenance UnscheduledDowntime = 2, // unscheduled downtime (faults) Engineering = 3, // engineering / qualification time Standby = 4, // idle, available but not producing Productive = 5, // actively producing NoState = 255, }; const char* ept_state_name(EptState s); std::optional parse_ept_state(const std::string& s); // Events correspond to transitions the equipment can declare; events // are intentionally state-neutral (any -> X) since EPT is a "what kind // of time is this" classifier rather than a strict lifecycle. enum class EptEvent { EnterNonScheduled, EnterScheduledDown, EnterUnscheduledDown, EnterEngineering, EnterStandby, EnterProductive, }; const char* ept_event_name(EptEvent e); using EptTable = CarrierTransitionTable; EptTable default_ept_table(); class EptStateMachine { public: using StateChangeHandler = std::function; EptStateMachine(); EptState state() const { return state_; } void set_state_change_handler(StateChangeHandler h) { on_change_ = std::move(h); } // Fire a transition. Returns true if a row matched. The dwell time // (how long we sat in the previous state) is computed off the // monotonic clock and surfaced to the handler so accounting code // doesn't need a parallel timestamp tracker. bool on_event(EptEvent e); // --- E116 time-bucket accounting -------------------------------------- // Total accumulated time spent in `s` since the FSM was constructed // or since reset_history() was last called. Time spent in the // *current* state up to now is included. std::chrono::milliseconds accumulated(EptState s) const; // Total time across all states (= time since reset_history()). Useful // as the denominator for utilization / availability ratios. std::chrono::milliseconds total_elapsed() const; // S2F43-style history clear. Sets every bucket to zero and re-anchors // the current-state timer at "now". void reset_history(); private: EptTable table_; EptState state_ = EptState::NonScheduledTime; std::chrono::steady_clock::time_point entered_; std::chrono::steady_clock::time_point reset_anchor_; std::array buckets_{}; // indexed by EptState 0..5 StateChangeHandler on_change_; }; } // namespace secsgem::gem