224130d99f
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>
65 lines
1.7 KiB
C++
65 lines
1.7 KiB
C++
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <map>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "secsgem/secs2/item.hpp"
|
|
|
|
// E30 §6.21 Limits Monitoring.
|
|
//
|
|
// A limit definition attaches an upper/lower deadband pair to a VID under
|
|
// some limit id. Multiple definitions per VID are allowed (different
|
|
// LIMITIDs can monitor different ranges). Store is pure data; the actual
|
|
// "value crossed limit" detection and CEID emission is the application's
|
|
// job (typically wired into the SVID/DVID set_value path).
|
|
|
|
namespace secsgem::gem {
|
|
|
|
namespace s2 = secsgem::secs2;
|
|
|
|
// Defined here (not in the generated messages.hpp) so the data model can
|
|
// own the type and the codegen can reference it as external_struct.
|
|
struct LimitDefinition {
|
|
uint8_t limitid;
|
|
s2::Item upper;
|
|
s2::Item lower;
|
|
};
|
|
|
|
enum class LimitMonitorAck : uint8_t { // S2F46 VLAACK
|
|
Accept = 0,
|
|
LimitsNotEqualToExisting = 1,
|
|
CannotChangeAttributes = 2,
|
|
LimitValueError = 3,
|
|
VidNotExist = 4,
|
|
VidNoLimitSupport = 5,
|
|
};
|
|
|
|
class LimitMonitorStore {
|
|
public:
|
|
void set_for_vid(uint32_t vid, std::vector<LimitDefinition> defs) {
|
|
by_vid_.insert_or_assign(vid, std::move(defs));
|
|
}
|
|
void clear() { by_vid_.clear(); }
|
|
|
|
std::vector<LimitDefinition> get_for_vid(uint32_t vid) const {
|
|
auto it = by_vid_.find(vid);
|
|
if (it == by_vid_.end()) return {};
|
|
return it->second;
|
|
}
|
|
std::vector<uint32_t> all_vids() const {
|
|
std::vector<uint32_t> out;
|
|
out.reserve(by_vid_.size());
|
|
for (const auto& [vid, _] : by_vid_) out.push_back(vid);
|
|
return out;
|
|
}
|
|
bool has(uint32_t vid) const { return by_vid_.count(vid) > 0; }
|
|
std::size_t size() const { return by_vid_.size(); }
|
|
|
|
private:
|
|
std::map<uint32_t, std::vector<LimitDefinition>> by_vid_;
|
|
};
|
|
|
|
} // namespace secsgem::gem
|