interop: secsgem-py cross-validation harness + lenient identifier parsing
Adds a Docker-based interop harness that drives the C++ server with
secsgem-py 0.3.0 as the active host and probes a secsgem-py-passive
equipment from a minimal C++ active client. Surfaces and fixes four
interoperability bugs uncovered by cross-testing:
* SEMI E5 identifier formatcodes are a U1|U2|U4|U8 wildcard;
secsgem-py picks the narrowest fitting width while our parsers
only accepted U4. `as_uN_scalar` / `as_iN_scalar` now accept
any unsigned/signed width and range-check the downcast.
* PPBODY (S7F3/F6) is "ASCII | Binary | List" per the spec;
secsgem-py defaults to ASCII. Added BINARY_OR_ASCII codegen
item type with `as_text_or_binary` accessor.
* S1F23/F24 Collection Event Namelist was unimplemented; added
schema + `vids_for(ceid)` accessor on EventReportSubscriptions
plus the dispatch handler.
* S10F1 was registered as a host->equipment handler, but per
SEMI E5 §12 S10F1 is equipment->host; S10F3 is the actual
host->equipment Terminal Display Single. Added an S10F3
handler alongside (we keep S10F1 too for backward compat).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -77,6 +77,11 @@ class EventReportSubscriptions {
|
||||
by_ceid_.insert_or_assign(ce.id, std::move(ce));
|
||||
}
|
||||
bool has_event(uint32_t ceid) const { return by_ceid_.count(ceid) > 0; }
|
||||
std::optional<CollectionEvent> event_info(uint32_t ceid) const {
|
||||
auto it = by_ceid_.find(ceid);
|
||||
if (it == by_ceid_.end()) return std::nullopt;
|
||||
return it->second;
|
||||
}
|
||||
std::vector<CollectionEvent> all_events() const {
|
||||
std::vector<CollectionEvent> out;
|
||||
out.reserve(by_ceid_.size());
|
||||
@@ -154,6 +159,28 @@ class EventReportSubscriptions {
|
||||
|
||||
bool is_enabled(uint32_t ceid) const { return enabled_.count(ceid) > 0; }
|
||||
|
||||
// --- S1F24 directory --------------------------------------------------
|
||||
// Return the deduplicated set of VIDs referenced by every report linked
|
||||
// to this CEID — i.e. the data the equipment would emit in S6F11 for
|
||||
// the CEID, projected onto its variable identifiers. Used to answer
|
||||
// S1F23 Collection-Event-Namelist-Request. Returns an empty list if
|
||||
// no reports are linked (the CEID is known but no host has configured
|
||||
// a report for it yet).
|
||||
std::vector<uint32_t> vids_for(uint32_t ceid) const {
|
||||
std::vector<uint32_t> out;
|
||||
auto it = links_.find(ceid);
|
||||
if (it == links_.end()) return out;
|
||||
std::set<uint32_t> seen;
|
||||
for (auto rptid : it->second) {
|
||||
auto rit = reports_.find(rptid);
|
||||
if (rit == reports_.end()) continue;
|
||||
for (auto v : rit->second.vids) {
|
||||
if (seen.insert(v).second) out.push_back(v);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// --- S6F11 emission --------------------------------------------------
|
||||
std::vector<ReportData> compose_for(uint32_t ceid, const VidLookup& lookup) const {
|
||||
std::vector<ReportData> out;
|
||||
|
||||
Reference in New Issue
Block a user