#pragma once #include #include #include #include #include #include #include "secsgem/gem/e84_state.hpp" namespace secsgem::gem { // E84 (Parallel I/O) is per-load-port: each port has its own ten-wire // handshake with the AMHS. Earlier revisions of this codebase modeled // E84 as a single equipment-wide FSM; multi-LP tools need one FSM per // port. E84PortStore keys per-port FSMs by port_id (1-based, matching // LoadPortStore). class E84PortStore { public: using StateChangeHandler = std::function; E84PortStore() = default; E84PortStore(const E84PortStore&) = delete; E84PortStore& operator=(const E84PortStore&) = delete; E84PortStore(E84PortStore&&) = delete; E84PortStore& operator=(E84PortStore&&) = delete; void set_state_change_handler(StateChangeHandler h) { on_change_ = std::move(h); } bool create(uint8_t port_id) { if (ports_.count(port_id)) return false; auto fsm = std::make_unique(); const uint8_t pid = port_id; fsm->set_state_change_handler( [this, pid](E84State f, E84State t, E84Signal sig) { if (on_change_) on_change_(pid, f, t, sig); }); ports_.emplace(port_id, std::move(fsm)); return true; } bool has(uint8_t port_id) const { return ports_.count(port_id) > 0; } E84StateMachine* get(uint8_t port_id) { auto it = ports_.find(port_id); return it == ports_.end() ? nullptr : it->second.get(); } const E84StateMachine* get(uint8_t port_id) const { auto it = ports_.find(port_id); return it == ports_.end() ? nullptr : it->second.get(); } // Convenience pass-throughs that auto-create the port on first use. // Real applications should call create() explicitly with their // expected port set, but the implicit create keeps quick demos // ergonomic. bool on_signal_change(uint8_t port_id, E84Signal s, bool value) { if (!ports_.count(port_id)) create(port_id); auto* fsm = get(port_id); if (!fsm) return false; fsm->on_signal_change(s, value); return true; } bool reset(uint8_t port_id) { auto* fsm = get(port_id); if (!fsm) return false; fsm->reset(); return true; } std::size_t size() const { return ports_.size(); } std::vector ids() const { std::vector out; out.reserve(ports_.size()); for (const auto& kv : ports_) out.push_back(kv.first); return out; } private: std::map> ports_; StateChangeHandler on_change_; }; } // namespace secsgem::gem