912304966f
register_default_handlers was a relocated app main(): one 1086-line function, all-or-nothing. It is now 15 per-capability registration functions along the lines GEM itself defines (S1F19): identification, equipment constants, clock, event reports, remote commands, trace/limits, spooling, alarms, exceptions, material tracking (E90/E116/E157), carriers (E87), recipes, object services (E39), jobs (E40/E94), terminal services. A sensor-class tool registers three functions instead of carrying carrier/job handlers it doesn't have; register_default_handlers composes all 15. Each function derives exactly the runtime aliases its handlers use (generated programmatically from the moved bodies with boundary/substitution guards — zero hand-retyping). Magic constants are gone: the control-state/clock SVIDs (were hardcoded 1/2) and the CJ Executing/Completed CEIDs (were 400/401) now come from a "roles:" block in equipment.yaml via EquipmentDescriptor, with historical defaults when absent, loader parsing, and validation (CEID roles must name declared events). The coupling is now visible in ONE file instead of silently split between YAML and C++ — the exact drift class this repo's spec-as-data philosophy exists to kill. Tests: capability subsetting, role-driven SVID refresh via S1F3, roles loader (shipped/custom/absent). Battery: core 473/3087 incl. the 53-handler conformance sweep, daemon 125/125, live GEM300 demo (client exit 0), daemon interop 20/20 vs secsgem-py. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
73 lines
2.5 KiB
C++
73 lines
2.5 KiB
C++
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <optional>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "secsgem/gem/control_job_state.hpp"
|
|
#include "secsgem/gem/control_state.hpp"
|
|
#include "secsgem/gem/data_model.hpp"
|
|
#include "secsgem/gem/process_job_state.hpp"
|
|
|
|
// YAML-driven loaders for the E30 control-state transition table and the
|
|
// equipment data dictionary. Behaviour rules live in the YAML; this is the
|
|
// parser that wires them into the runtime structures.
|
|
namespace secsgem::config {
|
|
|
|
class ConfigError : public std::runtime_error {
|
|
public:
|
|
using std::runtime_error::runtime_error;
|
|
};
|
|
|
|
struct ControlStateConfig {
|
|
gem::ControlTransitionTable table;
|
|
gem::ControlState initial = gem::ControlState::HostOffline;
|
|
};
|
|
|
|
// Loads data/control_state.yaml.
|
|
ControlStateConfig load_control_state(const std::string& yaml_path);
|
|
|
|
struct EquipmentDescriptor {
|
|
uint16_t device_id = 0;
|
|
std::string model_name;
|
|
std::string software_rev;
|
|
std::string equipment_type; // S1F20 EQPTYP
|
|
std::vector<std::pair<uint8_t, std::string>> capabilities; // (CCODE, CDESC)
|
|
std::optional<uint32_t> emit_on_control_change;
|
|
|
|
// Role bindings (`roles:` in equipment.yaml): which configured ids the
|
|
// engine's built-in behaviours are wired to. Replaces magic constants that
|
|
// silently had to match the YAML. Defaults preserve the historical wiring
|
|
// for configs without a roles block.
|
|
uint32_t control_state_svid = 1; // SVID refreshed with the control state
|
|
uint32_t clock_svid = 2; // SVID refreshed with the clock string
|
|
uint32_t cj_executing_ceid = 400; // CEID fired when a CJ enters Executing
|
|
uint32_t cj_completed_ceid = 401; // CEID fired when a CJ enters Completed
|
|
};
|
|
|
|
// Loads data/equipment.yaml into the given data model and returns the
|
|
// equipment header (device id, MDLN, SOFTREV, optional auto-emit CEID).
|
|
EquipmentDescriptor load_equipment(const std::string& yaml_path,
|
|
gem::EquipmentDataModel& model);
|
|
|
|
struct ProcessJobStateConfig {
|
|
gem::ProcessJobTransitionTable table;
|
|
gem::ProcessJobState initial = gem::ProcessJobState::Queued;
|
|
};
|
|
|
|
// Loads data/process_job_state.yaml.
|
|
ProcessJobStateConfig load_process_job_state(const std::string& yaml_path);
|
|
|
|
struct ControlJobStateConfig {
|
|
gem::ControlJobTransitionTable table;
|
|
gem::ControlJobState initial = gem::ControlJobState::Queued;
|
|
};
|
|
|
|
// Loads data/control_job_state.yaml.
|
|
ControlJobStateConfig load_control_job_state(const std::string& yaml_path);
|
|
|
|
} // namespace secsgem::config
|