#pragma once #include #include #include #include #include #include "secsgem/gem/store/host_commands.hpp" // HostCmdAck namespace secsgem::gem { // E94 §6 Control Job state model. // // E94 governs the *batch* of work — a CJ owns an ordered list of PRJOBIDs // (process jobs) and a processing policy. States below match E94-0705 §6 // (the values are this project's own opaque encoding — E94 does not pin a // PRJOBSTATE-style wire enum for CJ; we surface state via S6F11 CEIDs in // the demo). enum class ControlJobState : uint8_t { Queued = 0, Selected = 1, WaitingForStart = 2, Executing = 3, Paused = 4, Completed = 5, // terminal: all PJs done, awaiting deletion Stopping = 6, Aborting = 7, NoState = 255, }; const char* control_job_state_name(ControlJobState s); std::optional parse_control_job_state(const std::string& s); enum class ControlJobEvent { Created, // -> Queued Select, // Queued -> Selected SetupComplete, // Selected -> WaitingForStart Start, // host: CJSTART -> Executing Pause, // host: CJPAUSE -> Paused Resume, // host: CJRESUME -> Executing Stop, // host: CJSTOP -> Stopping Abort, // host: CJABORT -> Aborting AllJobsComplete, // internal: Executing/Stopping -> Completed AbortComplete, // internal: Aborting -> Completed }; const char* control_job_event_name(ControlJobEvent e); std::optional parse_control_job_event(const std::string& s); // Wire-name -> event mapping for the CTLJOBCMD string on S16F27. std::optional ctl_cmd_to_event(const std::string& cmd); struct ControlJobTransition { ControlJobState from; ControlJobEvent on; std::optional to; std::optional ack_code; // HostCmdAck when applicable }; class ControlJobTransitionTable { public: void add(ControlJobTransition row); const ControlJobTransition* find(ControlJobState from, ControlJobEvent on) const; std::size_t size() const { return rows_.size(); } const std::vector& rows() const { return rows_; } static ControlJobTransitionTable default_table(); private: std::vector rows_; }; class ControlJobStateMachine { public: using StateChangeHandler = std::function; ControlJobStateMachine(); explicit ControlJobStateMachine(ControlJobTransitionTable table, ControlJobState initial = ControlJobState::Queued); ControlJobState state() const { return state_; } void set_state_change_handler(StateChangeHandler h) { on_change_ = std::move(h); } HostCmdAck on_host_command(ControlJobEvent event); bool on_internal(ControlJobEvent event); private: const ControlJobTransition* fire(ControlJobEvent on); void transition(ControlJobState next, ControlJobEvent trigger); ControlJobTransitionTable table_; ControlJobState state_; StateChangeHandler on_change_; }; // S14F10 / F12 OBJACK — generic ObjectService ack. Used by the // CreateControlJob / DeleteControlJob handlers. enum class ObjectAck : uint8_t { Success = 0, Error = 1, Denied_UnknownObject = 2, Denied_AlreadyExists = 3, Denied_InvalidAttribute = 4, Denied_BadState = 5, }; } // namespace secsgem::gem