#pragma once #include #include #include #include #include #include #include namespace secsgem::gem { struct Alarm { uint32_t id; std::string text; // Lower 7 bits of ALCD: severity category (1=personal safety, // 2=equipment safety, 4=parameter control error, ...). Bit 7 marks // set vs cleared and is applied at emit time. uint8_t severity_category; }; enum class AlarmAck : uint8_t { Accept = 0, Error = 1, }; class AlarmRegistry { public: void add(Alarm a) { by_id_.insert_or_assign(a.id, std::move(a)); } std::optional get(uint32_t id) const { auto it = by_id_.find(id); if (it == by_id_.end()) return std::nullopt; return it->second; } std::vector all() const { std::vector out; out.reserve(by_id_.size()); for (const auto& [_, a] : by_id_) out.push_back(a); return out; } bool has(uint32_t id) const { return by_id_.count(id) > 0; } // S5F3 enable / disable. AlarmAck set_enabled(uint32_t id, bool enable) { if (!by_id_.count(id)) return AlarmAck::Error; if (enable) enabled_.insert(id); else enabled_.erase(id); return AlarmAck::Accept; } bool enabled(uint32_t id) const { return enabled_.count(id) > 0; } // Trigger set / clear; returns the ALCD byte to put on the wire (bit 7 // is the set flag, lower 7 carry the category). std::nullopt on unknown. std::optional set_active(uint32_t id) { auto it = by_id_.find(id); if (it == by_id_.end()) return std::nullopt; active_.insert(id); return static_cast((it->second.severity_category & 0x7F) | 0x80); } std::optional clear_active(uint32_t id) { auto it = by_id_.find(id); if (it == by_id_.end()) return std::nullopt; active_.erase(id); return static_cast(it->second.severity_category & 0x7F); } bool active(uint32_t id) const { return active_.count(id) > 0; } private: std::map by_id_; std::set enabled_; std::set active_; }; } // namespace secsgem::gem