RTOS Wrapper
API reference
Loading...
Searching...
No Matches
FlagsSaver.h
Go to the documentation of this file.
1
30#ifndef HF_UTILS_RTOS_WRAP_FLAGSSAVER_H_
31#define HF_UTILS_RTOS_WRAP_FLAGSSAVER_H_
32
33#include <atomic>
34#include <climits>
35#include <cstddef>
36#include <cstdint>
37
38#include "OsAbstraction.h"
39#include "OsUtility.h"
40
41namespace hf {
42
49template <std::size_t kWordCount>
51 uint64_t bits[kWordCount > 0 ? kWordCount : 1]{};
52 uint32_t seq{0};
53 uint32_t last_change_ms{0};
54};
55
59template <typename FlagId, std::size_t kCount>
61public:
62 static constexpr std::size_t kWordCount =
63 (kCount + 63U) / 64U > 0U ? (kCount + 63U) / 64U : 1U;
65
66 virtual ~FlagsReader() noexcept = default;
67
69 [[nodiscard]] virtual bool IsSet(FlagId id) const noexcept = 0;
70
72 virtual void Snapshot_(Snapshot& out) const noexcept = 0;
73
76 [[nodiscard]] virtual uint32_t Seq() const noexcept = 0;
77
79 [[nodiscard]] virtual uint32_t LastChangeMs() const noexcept = 0;
80
86 virtual bool WaitForChange(uint32_t timeout_ms) noexcept = 0;
87
89 virtual bool ClearWaitEvent() noexcept = 0;
90};
91
95template <typename FlagId, std::size_t kCount>
97public:
98 virtual ~FlagsWriter() noexcept = default;
99
106 virtual bool Set(FlagId id, uint32_t now_ms = 0) noexcept = 0;
107
112 virtual bool Clear(FlagId id, uint32_t now_ms = 0) noexcept = 0;
113
115 virtual bool ClearAll(uint32_t now_ms = 0) noexcept = 0;
116};
117
125template <typename FlagId, std::size_t kCount>
126class FlagsSaver final
127 : public FlagsReader<FlagId, kCount>
128 , public FlagsWriter<FlagId, kCount>
129{
130public:
132 using Snapshot = typename Base::Snapshot;
133 static constexpr std::size_t kWordCount = Base::kWordCount;
134
135 FlagsSaver() noexcept = default;
136
137 ~FlagsSaver() override
138 {
139 if (event_group_created_) {
140 (void)os_event_group_delete(&event_group_);
141 event_group_created_ = false;
142 }
143 }
144
145 FlagsSaver(const FlagsSaver&) = delete;
146 FlagsSaver& operator=(const FlagsSaver&) = delete;
147
148 /* ── Writer surface ──────────────────────────────────────────── */
149
150 bool Set(FlagId id, uint32_t now_ms = 0) noexcept override
151 {
152 return WriteSlot_(id, true, now_ms);
153 }
154
155 bool Clear(FlagId id, uint32_t now_ms = 0) noexcept override
156 {
157 return WriteSlot_(id, false, now_ms);
158 }
159
160 bool ClearAll(uint32_t now_ms = 0) noexcept override
161 {
162 bool changed = false;
163 for (auto& w : words_) {
164 const uint64_t prev = w.exchange(0, std::memory_order_acq_rel);
165 if (prev != 0U) changed = true;
166 }
167 if (!changed) return false;
168 if (now_ms != 0U) last_change_ms_.store(now_ms, std::memory_order_release);
169 SignalChange_();
170 return true;
171 }
172
173 /* ── Reader surface ──────────────────────────────────────────── */
174
175 [[nodiscard]] bool IsSet(FlagId id) const noexcept override
176 {
177 const std::size_t idx = static_cast<std::size_t>(id);
178 if (idx >= kCount) return false;
179 const std::size_t word = idx / 64U;
180 const std::size_t bit = idx % 64U;
181 return (words_[word].load(std::memory_order_acquire)
182 & (uint64_t{1} << bit)) != 0U;
183 }
184
185 void Snapshot_(Snapshot& out) const noexcept override
186 {
187 for (std::size_t i = 0; i < kWordCount; ++i) {
188 out.bits[i] = words_[i].load(std::memory_order_acquire);
189 }
190 out.seq = seq_.load(std::memory_order_acquire);
191 out.last_change_ms = last_change_ms_.load(std::memory_order_acquire);
192 }
193
194 [[nodiscard]] uint32_t Seq() const noexcept override
195 {
196 return seq_.load(std::memory_order_acquire);
197 }
198
199 [[nodiscard]] uint32_t LastChangeMs() const noexcept override
200 {
201 return last_change_ms_.load(std::memory_order_acquire);
202 }
203
204 bool WaitForChange(uint32_t timeout_ms) noexcept override
205 {
206 if (!EnsureEventGroup_()) return false;
207 OS_Ulong actual = 0;
208 const OS_Ulong wait = (timeout_ms == UINT32_MAX)
209 ? static_cast<OS_Ulong>(OS_WAIT_FOREVER)
210 : static_cast<OS_Ulong>(os_convert_msec_to_delay_ticks(timeout_ms));
211 // Consume the signal: the next WaitForChange() waits for a new change.
212 const OS_Uint rc = os_event_group_get(&event_group_, kEventBit_,
213 static_cast<OS_Uint>(OS_OR) |
214 static_cast<OS_Uint>(OS_EVENT_CLEAR),
215 &actual, wait);
216 return (rc == OS_SUCCESS) && ((actual & kEventBit_) != 0U);
217 }
218
219 bool ClearWaitEvent() noexcept override
220 {
221 if (!EnsureEventGroup_()) return false;
222 return os_event_group_clear(&event_group_, kEventBit_) == OS_SUCCESS;
223 }
224
225private:
226 bool WriteSlot_(FlagId id, bool set, uint32_t now_ms) noexcept
227 {
228 const std::size_t idx = static_cast<std::size_t>(id);
229 if (idx >= kCount) return false;
230
231 const std::size_t word = idx / 64U;
232 const uint64_t mask = uint64_t{1} << (idx % 64U);
233 auto& w = words_[word];
234
235 const uint64_t prev = set
236 ? w.fetch_or(mask, std::memory_order_acq_rel)
237 : w.fetch_and(~mask, std::memory_order_acq_rel);
238
239 const bool was_set = (prev & mask) != 0U;
240 if (was_set == set) return false; // no transition
241
242 if (now_ms != 0U) last_change_ms_.store(now_ms, std::memory_order_release);
243 SignalChange_();
244 return true;
245 }
246
247 void SignalChange_() noexcept
248 {
249 seq_.fetch_add(1, std::memory_order_acq_rel);
250 if (EnsureEventGroup_()) {
251 (void)os_event_group_set(&event_group_, kEventBit_);
252 }
253 }
254
255 bool EnsureEventGroup_() noexcept
256 {
257 if (event_group_created_) return true;
258 if (os_event_group_create(&event_group_, "FlagsSaver") == OS_SUCCESS) {
259 event_group_created_ = true;
260 }
261 return event_group_created_;
262 }
263
264 static constexpr OS_Ulong kEventBit_ = 0x1U;
265
266 std::atomic<uint64_t> words_[kWordCount]{};
267 std::atomic<uint32_t> seq_{0};
268 std::atomic<uint32_t> last_change_ms_{0};
269 OS_EventGroup event_group_{};
270 bool event_group_created_{false};
271};
272
273} // namespace hf
274
275#endif /* HF_UTILS_RTOS_WRAP_FLAGSSAVER_H_ */
Generic RTOS abstraction — public header.
C-facing helper functions for delays, cycle counters, and creation of RTOS handles (queues,...
constexpr uint32_t os_convert_msec_to_delay_ticks(uint32_t milliseconds)
Converts milliseconds to delay ticks, rounding down but never to zero.
Definition OsUtility.h:74
Read-side ABC for FlagsSaver.
Definition FlagsSaver.h:60
virtual uint32_t LastChangeMs() const noexcept=0
Most recent now_ms value passed to Set / Clear (0 if never).
virtual void Snapshot_(Snapshot &out) const noexcept=0
Copy current bit state + sequence + last-change timestamp into out.
virtual bool IsSet(FlagId id) const noexcept=0
True if id is currently set.
virtual bool ClearWaitEvent() noexcept=0
Discard any pending change-signal without waiting.
virtual bool WaitForChange(uint32_t timeout_ms) noexcept=0
Block up to timeout_ms waiting for any change since the last call to WaitForChange or ClearWaitEvent.
static constexpr std::size_t kWordCount
Definition FlagsSaver.h:62
virtual uint32_t Seq() const noexcept=0
virtual ~FlagsReader() noexcept=default
Concrete two-state flag bitset.
Definition FlagsSaver.h:129
FlagsSaver() noexcept=default
uint32_t Seq() const noexcept override
Definition FlagsSaver.h:194
void SignalChange_() noexcept
Definition FlagsSaver.h:247
typename Base::Snapshot Snapshot
Definition FlagsSaver.h:132
FlagsSaver & operator=(const FlagsSaver &)=delete
uint32_t LastChangeMs() const noexcept override
Most recent now_ms value passed to Set / Clear (0 if never).
Definition FlagsSaver.h:199
bool WriteSlot_(FlagId id, bool set, uint32_t now_ms) noexcept
Definition FlagsSaver.h:226
bool ClearAll(uint32_t now_ms=0) noexcept override
Reset every slot to Cleared and signal a change.
Definition FlagsSaver.h:160
bool ClearWaitEvent() noexcept override
Discard any pending change-signal without waiting.
Definition FlagsSaver.h:219
bool EnsureEventGroup_() noexcept
Definition FlagsSaver.h:255
FlagsSaver(const FlagsSaver &)=delete
bool Clear(FlagId id, uint32_t now_ms=0) noexcept override
Mark id cleared. Idempotent: returns false if state was already Cleared (no event signalled).
Definition FlagsSaver.h:155
void Snapshot_(Snapshot &out) const noexcept override
Copy current bit state + sequence + last-change timestamp into out.
Definition FlagsSaver.h:185
bool WaitForChange(uint32_t timeout_ms) noexcept override
Block up to timeout_ms waiting for any change since the last call to WaitForChange or ClearWaitEvent.
Definition FlagsSaver.h:204
bool Set(FlagId id, uint32_t now_ms=0) noexcept override
Mark id set. Idempotent: returns false if state was already Set (no event signalled).
Definition FlagsSaver.h:150
bool IsSet(FlagId id) const noexcept override
True if id is currently set.
Definition FlagsSaver.h:175
Write-side ABC for FlagsSaver.
Definition FlagsSaver.h:96
virtual ~FlagsWriter() noexcept=default
Definition ErrorHistory.h:34
@ OS_SUCCESS
Definition os_cmsis.h:50
@ OS_EVENT_CLEAR
Definition os_cmsis.h:53
@ OS_OR
Definition os_cmsis.h:52
@ OS_WAIT_FOREVER
Definition os_cmsis.h:48
static OS_Uint os_event_group_set(OS_EventGroup *g, OS_Ulong flags)
Definition os_cmsis.h:320
static OS_Uint os_event_group_get(OS_EventGroup *g, OS_Ulong flags, OS_Uint option, OS_Ulong *actual, OS_Ulong wait)
Definition os_cmsis.h:330
static OS_Uint os_event_group_delete(OS_EventGroup *g)
Definition os_cmsis.h:316
static OS_Uint os_event_group_clear(OS_EventGroup *g, OS_Ulong flags)
Definition os_cmsis.h:325
osEventFlagsId_t OS_EventGroup
Definition os_cmsis.h:31
unsigned int OS_Uint
Definition os_cmsis.h:36
unsigned long OS_Ulong
Definition os_cmsis.h:35
static OS_Uint os_event_group_create(OS_EventGroup *g, const char *name)
Definition os_cmsis.h:309
Snapshot of a FlagsSaver at a point in time.
Definition FlagsSaver.h:50
uint32_t last_change_ms
Definition FlagsSaver.h:53
uint32_t seq
Definition FlagsSaver.h:52
uint64_t bits[kWordCount > 0 ? kWordCount :1]
Definition FlagsSaver.h:51