#pragma once #include #include #include #include // E84 §6 Parallel I/O — the digital handshake between AMHS (Automated // Material Handling System) and equipment for carrier load/unload. // // E84 is signal-level, not SECS: ten parallel boolean wires between the // AMHS robot and the equipment, sequenced in a strict handshake. This // FSM models the signal bitmap and the handshake state, accepting // signal-change events as input and exposing state transitions for // observation. Real wiring uses opto-isolated 24V lines; we abstract // it as bool getters/setters so the same FSM drives both real hardware // and back-to-back testing. namespace secsgem::gem { enum class E84Signal : uint8_t { CS_0 = 0, // AMHS -> equip: carrier stage select 0 CS_1 = 1, // AMHS -> equip: carrier stage select 1 VALID = 2, // AMHS -> equip: handshake start TR_REQ = 3, // AMHS -> equip: transfer request BUSY = 4, // AMHS -> equip: transfer in progress COMPT = 5, // AMHS -> equip: transfer complete L_REQ = 6, // equip -> AMHS: load request (port ready to receive) U_REQ = 7, // equip -> AMHS: unload request (port ready to release) READY = 8, // equip -> AMHS: ready ES = 9, // either direction: emergency stop }; const char* e84_signal_name(E84Signal s); // 10-bit signal bitmap with bool get/set. class E84SignalSet { public: bool get(E84Signal s) const { return (bits_ & (uint16_t{1} << static_cast(s))) != 0; } void set(E84Signal s, bool v) { const uint16_t mask = uint16_t{1} << static_cast(s); if (v) bits_ |= mask; else bits_ &= static_cast(~mask); } uint16_t raw() const { return bits_; } void clear() { bits_ = 0; } private: uint16_t bits_ = 0; }; // E84 handoff handshake state (E84 §6.3). Names are short for log // readability; semantics in comments. enum class E84State : uint8_t { Idle = 0, // no signals asserted (or carrier absent) CarrierPresent = 1, // CS_0 or CS_1 asserted; no VALID yet ValidAsserted = 2, // CS && VALID; equipment hasn't acknowledged LoadReady = 3, // VALID && L_REQ; ready to receive carrier UnloadReady = 4, // VALID && U_REQ; ready to release carrier Transferring = 5, // BUSY asserted; transfer in progress Complete = 6, // COMPT asserted; AMHS reports done EmergencyStop = 7, // ES asserted NoState = 255, }; const char* e84_state_name(E84State s); class E84StateMachine { public: using StateChangeHandler = std::function; E84State state() const { return state_; } const E84SignalSet& signals() const { return signals_; } bool signal(E84Signal s) const { return signals_.get(s); } void set_state_change_handler(StateChangeHandler h) { on_change_ = std::move(h); } // Apply a single signal change. Re-evaluates the handshake state // and fires the change handler on transition. Order of signal // changes matters for the AMHS-equipment handshake; the FSM accepts // any order and just reports the resulting state. void on_signal_change(E84Signal s, bool value); // Convenience: clear all signals; resets state to Idle. void reset(); private: void reevaluate(E84Signal trigger); E84SignalSet signals_; E84State state_ = E84State::Idle; StateChangeHandler on_change_; }; } // namespace secsgem::gem