100%/C: Limits Monitoring (S2F45–F48, E30 §6.21)
tests / build-and-test (push) Failing after 35s

New LimitMonitorStore keyed by VID; each entry is a vector of
LimitDefinition (LIMITID + upper/lower deadband as arbitrary Items).
S2F45/F46 set, S2F47/F48 read.  VLAACK validates each VID exists.

Four new SxFy in the catalog; codegen handles the nested
list-of-(VID, list-of-LimitDefinition) shape.  LimitDefinition is
defined in store/limits.hpp and referenced as external_struct so the
data model and the message codecs share one type.

The actual "value crossed limit" detection + CEID emission is left to
the application's set_value path (E30 §6.21 leaves *how* the equipment
detects crossings up to the implementer).

COMPLIANCE.md: Limits Monitoring Additional capability flips .
Tests: 80 cases / 465 assertions.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-07 02:08:19 +02:00
parent 65db38d9f2
commit 224130d99f
6 changed files with 202 additions and 2 deletions
+30
View File
@@ -112,6 +112,36 @@ TEST_CASE("S10F3 terminal display round-trip") {
CHECK(parsed->text == "ALARM: chiller temperature high");
}
// ---- Limits Monitoring (S2F45-F48) -------------------------------------
TEST_CASE("S2F45 round-trips define-limits request") {
std::vector<VidLimitsEntry> entries = {
{100, {{0, s2::Item::u4(uint32_t{1000}), s2::Item::u4(uint32_t{0})}}},
{101, {{0, s2::Item::f4(2.0f), s2::Item::f4(0.5f)},
{1, s2::Item::f4(3.0f), s2::Item::f4(0.1f)}}},
};
auto m = s2f45_define_variable_limits(7, entries);
auto parsed = parse_s2f45(m);
REQUIRE(parsed.has_value());
CHECK(parsed->dataid == 7);
REQUIRE(parsed->entries.size() == 2);
CHECK(parsed->entries[0].vid == 100);
REQUIRE(parsed->entries[0].limits.size() == 1);
CHECK(parsed->entries[0].limits[0].upper == s2::Item::u4(uint32_t{1000}));
CHECK(parsed->entries[1].vid == 101);
REQUIRE(parsed->entries[1].limits.size() == 2);
}
TEST_CASE("S2F46 / S2F48 round-trips") {
CHECK(*ack_byte(s2f46_define_variable_limits_ack(LimitMonitorAck::VidNotExist)) == 4);
std::vector<VidLimitsEntry> rows = {
{100, {{0, s2::Item::u4(uint32_t{1000}), s2::Item::u4(uint32_t{0})}}}};
auto m = s2f48_variable_limit_attribute_data(rows);
REQUIRE(m.body.has_value());
REQUIRE(m.body->is_list());
}
// ---- S9 error-stream round-trips ----------------------------------------
TEST_CASE("S9 MHEAD-carrying messages round-trip") {