29f646c7ca
tests / build-and-test (push) Failing after 34s
A host couldn't drive the new messages through the HostHandler class — only the server side knew how to dispatch them. Adds six new senders plus a unit test that walks each through a real loopback connection: * send_legacy_remote_command -> S2F21 * send_event_report_request -> S6F15 * send_individual_report_request -> S6F19 * send_annotated_report_request -> S6F21 * send_pp_load_inquire -> S7F1 * send_delete_pp -> S7F17 Suite: 296 cases / 1571 assertions. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
221 lines
10 KiB
C++
221 lines
10 KiB
C++
#pragma once
|
|
|
|
#include <array>
|
|
#include <cstdint>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <system_error>
|
|
#include <vector>
|
|
|
|
#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<HostHandler> {
|
|
public:
|
|
using ReplyHandler = std::function<void(std::error_code, const secs2::Message&)>;
|
|
using EventHandler = std::function<void(uint32_t dataid, uint32_t ceid,
|
|
const std::vector<ReportData>& reports)>;
|
|
using AlarmHandler = std::function<void(uint32_t alid, uint8_t alcd,
|
|
const std::string& altx)>;
|
|
using TerminalHandler = std::function<void(uint32_t tid, const std::string& text)>;
|
|
using S9Handler = std::function<void(uint8_t function,
|
|
const std::array<uint8_t, 10>& mhead)>;
|
|
using LogHandler = std::function<void(const std::string&)>;
|
|
// 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<void(uint32_t ceid, SubstrateState location,
|
|
SubstrateProcessingState processing)>;
|
|
|
|
explicit HostHandler(std::shared_ptr<hsms::Connection> 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<uint32_t>& svids, ReplyHandler cb);
|
|
|
|
// S1F11/F12 Status Variable Namelist: empty `svids` requests every name.
|
|
void send_status_namelist(const std::vector<uint32_t>& 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<std::pair<uint32_t, std::vector<uint32_t>>>& reports,
|
|
ReplyHandler cb);
|
|
|
|
// S2F35/F36 Link Event Reports. `links[i] = {ceid, [rptids]}`.
|
|
void send_link_event_reports(
|
|
uint32_t dataid,
|
|
const std::vector<std::pair<uint32_t, std::vector<uint32_t>>>& links,
|
|
ReplyHandler cb);
|
|
|
|
// S2F37/F38 Enable/Disable Events. Empty `ceids` = all.
|
|
void send_enable_events(bool enable, const std::vector<uint32_t>& 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<CommandParameter>& 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<CommandParameter>& 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<uint32_t>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<secs2::Message> handle_inbound(const secs2::Message& msg);
|
|
|
|
void log(const std::string& msg);
|
|
|
|
std::shared_ptr<hsms::Connection> conn_;
|
|
EventHandler on_event_;
|
|
AlarmHandler on_alarm_;
|
|
TerminalHandler on_terminal_;
|
|
S9Handler on_s9_;
|
|
LogHandler on_log_;
|
|
SubstrateEventHandler on_substrate_;
|
|
};
|
|
|
|
} // namespace secsgem::gem
|