#pragma once #include #include #include #include #include #include #include #include "secsgem/gem/store/event_reports.hpp" #include "secsgem/hsms/connection.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; 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); } // 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); // ---- 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_; }; } // namespace secsgem::gem