cb85199f49
- name_index: add resolve_event(name) -> CEID (unit-tested). - equipment_service.hpp: extract the gRPC service + value/state conversion into a shared header; add FireEvent (optional per-fire variable values, then trigger the collection event by name). secs_gemd slims to main(). - test_daemon_service: real in-process gRPC integration test (client stub -> service -> EquipmentRuntime) proving SetVariables lands in the model, GetControlState reports the state, FireEvent and unknown-name paths behave. Separate secs_gemd_tests target (links grpc++/proto), gated on the daemon. Core suite 459/459 (2799 assertions); daemon gRPC tests 15/15. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
70 lines
2.5 KiB
C++
70 lines
2.5 KiB
C++
// secs_gemd — the SECS/GEM daemon.
|
|
//
|
|
// Runs the GEM engine (EquipmentRuntime + the default handlers) on a background
|
|
// thread, owning the HSMS link to the host, and exposes a small name-based gRPC
|
|
// API (proto/secsgem/v1/equipment.proto) so a tool's software — in any language
|
|
// — can drive the equipment without linking C++ or knowing SEMI.
|
|
//
|
|
// Increment 1: the universal "report state to the host" RPCs (SetVariables,
|
|
// FireEvent) plus control-state visibility. Alarms, GetVariables, and the
|
|
// host->tool Subscribe command stream follow (see docs/DAEMON_ROADMAP.md).
|
|
|
|
#include <grpcpp/grpcpp.h>
|
|
|
|
#include <cstdint>
|
|
#include <iostream>
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
#include "equipment_service.hpp"
|
|
#include "secsgem/gem/default_handlers.hpp"
|
|
#include "secsgem/gem/runtime.hpp"
|
|
|
|
namespace gem = secsgem::gem;
|
|
|
|
namespace {
|
|
std::string arg(int argc, char** argv, const std::string& key, const std::string& def) {
|
|
for (int i = 1; i + 1 < argc; ++i)
|
|
if (key == argv[i]) return argv[i + 1];
|
|
return def;
|
|
}
|
|
} // namespace
|
|
|
|
int main(int argc, char** argv) {
|
|
const std::string hsms_port = arg(argc, argv, "--port", "5000");
|
|
const std::string grpc_addr = arg(argc, argv, "--grpc", "0.0.0.0:50051");
|
|
const std::string cfgdir = arg(argc, argv, "--config-dir", "data");
|
|
|
|
gem::EquipmentRuntime::Config cfg;
|
|
cfg.equipment_yaml = cfgdir + "/equipment.yaml";
|
|
cfg.control_state_yaml = cfgdir + "/control_state.yaml";
|
|
cfg.process_job_yaml = cfgdir + "/process_job_state.yaml";
|
|
cfg.control_job_yaml = cfgdir + "/control_job_state.yaml";
|
|
cfg.port = static_cast<uint16_t>(std::stoi(hsms_port));
|
|
cfg.log = [](const std::string& m) { std::cout << "[gemd] " << m << std::endl; };
|
|
|
|
std::unique_ptr<gem::EquipmentRuntime> rt;
|
|
try {
|
|
rt = std::make_unique<gem::EquipmentRuntime>(cfg);
|
|
} catch (const std::exception& e) {
|
|
std::cerr << "[gemd] config error: " << e.what() << std::endl;
|
|
return 1;
|
|
}
|
|
gem::register_default_handlers(*rt);
|
|
rt->run_async(); // engine + HSMS link on a background thread
|
|
|
|
secsgem::daemon::EquipmentService service(*rt);
|
|
grpc::ServerBuilder builder;
|
|
builder.AddListeningPort(grpc_addr, grpc::InsecureServerCredentials());
|
|
builder.RegisterService(&service);
|
|
std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
|
|
if (!server) {
|
|
std::cerr << "[gemd] failed to start gRPC server on " << grpc_addr << std::endl;
|
|
return 1;
|
|
}
|
|
std::cout << "[gemd] gRPC on " << grpc_addr
|
|
<< "; HSMS equipment on :" << hsms_port << std::endl;
|
|
server->Wait();
|
|
return 0;
|
|
}
|