#pragma once #include #include #include #include #include #include #include #include "secsgem/gem/e90_constants.hpp" #include "secsgem/gem/store/event_reports.hpp" #include "secsgem/gem/store/host_commands.hpp" // CommandParameter #include "secsgem/gem/store/spool.hpp" // SpoolRequestCode #include "secsgem/gem/substrate_state.hpp" // SubstrateState, SubstrateProcessingState #include "secsgem/hsms/connection.hpp" #include "secsgem/secs2/item.hpp" #include "secsgem/secs2/message.hpp" // GEM host-side message handler. Wraps an HSMS Connection (Active mode) // and provides: // // - Inbound dispatch with sensible automatic acks for the messages a // host is expected to accept passively (S5F1 alarms, S6F11 event // reports, S9F* errors, S10F1 terminal text). Each gets a // user-settable observer callback. // // - High-level workflow shortcuts: establish_communication() (S1F13) // and go_remote() (S1F17) are the standard GEM host startup pair. // // - Convenience senders for the GEM/E40/E94 message surface // (see host_handler_senders.hpp for the full menu in B2/B3). // // Mirrors secsgem-py's `GemHostHandler` in `gem/hosthandler.py`. Equipment- // side behaviour lives in the existing server app; pulling it into a // matching `EquipmentHandler` class is a separate refactor. namespace secsgem::gem { class HostHandler : public std::enable_shared_from_this { public: using ReplyHandler = std::function; using EventHandler = std::function& reports)>; using AlarmHandler = std::function; using TerminalHandler = std::function; using S9Handler = std::function& mhead)>; using LogHandler = std::function; // E90 substrate event observer. Triggered when an inbound S6F11 // carries a CEID in the e90:: kCeid* range; the handler receives a // best-effort decode (NoState for axes the CEID doesn't update). using SubstrateEventHandler = std::function; explicit HostHandler(std::shared_ptr conn); // Inbound observers. Each is optional; if unset, the message is acked // (where required) and otherwise ignored. void set_event_handler(EventHandler h) { on_event_ = std::move(h); } void set_alarm_handler(AlarmHandler h) { on_alarm_ = std::move(h); } void set_terminal_handler(TerminalHandler h) { on_terminal_ = std::move(h); } void set_s9_handler(S9Handler h) { on_s9_ = std::move(h); } void set_log_handler(LogHandler h) { on_log_ = std::move(h); } void set_substrate_event_handler(SubstrateEventHandler h) { on_substrate_ = std::move(h); } // Wire the inbound message handler into the underlying Connection. // Call once before Connection::start() so the dispatch table is live // when the first inbound primary arrives. void install(); // ---- Workflow shortcuts ------------------------------------------------ // S1F13/F14 Establish Communication. Resolves `cb` with the equipment's // S1F14 reply (or a timeout / error). void establish_communication(ReplyHandler cb); // S1F17/F18 Request Online. Equipment may reply Accepted / NotAllowed / // AlreadyOnline; the raw S1F18 message is forwarded to `cb`. void go_remote(ReplyHandler cb); // S1F15/F16 Request Offline. Counterpart to go_remote(). void go_offline(ReplyHandler cb); // ---- Status + subscription senders (B2) ------------------------------- // S1F3/F4 Selected Status Data: empty `svids` requests every SVID. void send_selected_status(const std::vector& svids, ReplyHandler cb); // S1F11/F12 Status Variable Namelist: empty `svids` requests every name. void send_status_namelist(const std::vector& svids, ReplyHandler cb); // S2F33/F34 Define Report. `reports[i] = {rptid, [vids]}`; an empty // rptid list per request resets that report (per E30 §6.11). void send_define_reports( uint32_t dataid, const std::vector>>& reports, ReplyHandler cb); // S2F35/F36 Link Event Reports. `links[i] = {ceid, [rptids]}`. void send_link_event_reports( uint32_t dataid, const std::vector>>& links, ReplyHandler cb); // S2F37/F38 Enable/Disable Events. Empty `ceids` = all. void send_enable_events(bool enable, const std::vector& ceids, ReplyHandler cb); // ---- Remote command senders (B3) -------------------------------------- // S2F41/F42 Host Command. `params` reuses CommandParameter from // host_commands.hpp so host- and equipment-side code share the type. void send_remote_command(const std::string& rcmd, const std::vector& params, ReplyHandler cb); // S2F49/F50 Enhanced Host Command (OBJSPEC-scoped + per-CP CPACK/CEPACK). void send_enhanced_remote_command(uint32_t dataid, const std::string& objspec, const std::string& rcmd, const std::vector& params, ReplyHandler cb); // S2F21/F22 legacy Remote Command (no parameter list, single ack byte). void send_legacy_remote_command(const std::string& rcmd, ReplyHandler cb); // ---- Host-initiated event/report queries (B3) ------------------------- // S6F15/F16: pull the current event-report payload for a given CEID. void send_event_report_request(uint32_t ceid, ReplyHandler cb); // S6F19/F20: pull a single RPTID's current values (no annotation). void send_individual_report_request(uint32_t rptid, ReplyHandler cb); // S6F21/F22: pull a single RPTID's values with (VID, V) annotation. void send_annotated_report_request(uint32_t rptid, ReplyHandler cb); // ---- Alarm management (B3) -------------------------------------------- // S5F3/F4 Enable/Disable Alarm. Spec uses ALED bit-7 to encode enable. void send_enable_alarm(uint32_t alid, bool enable, ReplyHandler cb); void send_list_alarms(const std::vector& alids, ReplyHandler cb); // S5F5/F6 void send_list_enabled_alarms(ReplyHandler cb); // S5F7/F8 // S5F13/F14 Exception Recover Request. Asks the equipment to perform // the named recovery action against the previously-posted EXID. void send_exception_recover(uint32_t exid, const std::string& exrecvra, ReplyHandler cb); void send_exception_recover_abort(uint32_t exid, ReplyHandler cb); // S5F17/F18 // ---- Process program transfer (B3) ------------------------------------ void send_request_eppd(ReplyHandler cb); // S7F19/F20 void send_pp_data(const std::string& ppid, const std::string& body, ReplyHandler cb); // S7F3/F4 void send_request_pp(const std::string& ppid, ReplyHandler cb); // S7F5/F6 // S7F1/F2 Process Program Load Inquire: announce a forthcoming S7F3 // of `length` bytes; equipment grants or denies. void send_pp_load_inquire(const std::string& ppid, uint32_t length, ReplyHandler cb); // S7F17/F18 Delete Process Program: empty list = delete all. void send_delete_pp(const std::vector& ppids, ReplyHandler cb); // ---- Spool (B3) ------------------------------------------------------- void send_request_spool(SpoolRequestCode code, ReplyHandler cb); // S6F23/F24 // ---- Terminal (B3) ---------------------------------------------------- void send_terminal_display(uint32_t tid, const std::string& text, ReplyHandler cb); // S10F1/F2 void send_terminal_display_multi(uint32_t tid, const std::vector& lines, ReplyHandler cb); // S10F5/F6 // ---- E40 Process Jobs (B3) -------------------------------------------- void send_create_process_job(const std::string& prjobid, const std::string& ppid, const std::vector& mtrloutspec, ReplyHandler cb); // S16F11/F12 void send_pr_job_command(const std::string& prjobid, const std::string& prcmd, ReplyHandler cb); // S16F5/F6 void send_pr_job_dequeue(const std::string& prjobid, ReplyHandler cb); // S16F13/F14 // ---- E94 Control Jobs (B3) -------------------------------------------- void send_create_control_job(const std::string& ctljobid, const std::vector& prjobids, ReplyHandler cb); // S14F9/F10 void send_delete_control_job(const std::string& ctljobid, ReplyHandler cb); // S14F11/F12 void send_cj_command(const std::string& ctljobid, const std::string& ctljobcmd, ReplyHandler cb); // S16F27/F28 // ---- Low-level: forward a primary verbatim ---------------------------- void send_request(secs2::Message msg, ReplyHandler cb); // Access to the underlying connection (sample apps and tests need it). hsms::Connection& connection() { return *conn_; } protected: // Single inbound dispatch entry point — installed on Connection. std::optional handle_inbound(const secs2::Message& msg); void log(const std::string& msg); std::shared_ptr conn_; EventHandler on_event_; AlarmHandler on_alarm_; TerminalHandler on_terminal_; S9Handler on_s9_; LogHandler on_log_; SubstrateEventHandler on_substrate_; }; } // namespace secsgem::gem