Files
secs-gem/apps/secs_gemd.cpp
T
raphael cb85199f49 feat(daemon): FireEvent + event name resolution + in-process gRPC tests
- 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>
2026-06-10 18:07:12 +02:00

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;
}