QP/C++  7.3.3
Real-Time Embedded Framework
Loading...
Searching...
No Matches
qf_time.cpp
Go to the documentation of this file.
1//$file${src::qf::qf_time.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2//
3// Model: qpcpp.qm
4// File: ${src::qf::qf_time.cpp}
5//
6// This code has been generated by QM 6.1.1 <www.state-machine.com/qm>.
7// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
8//
9// This code is covered by the following QP license:
10// License # : LicenseRef-QL-dual
11// Issued to : Any user of the QP/C++ real-time embedded framework
12// Framework(s) : qpcpp
13// Support ends : 2024-12-31
14// License scope:
15//
16// Copyright (C) 2005 Quantum Leaps, LLC <state-machine.com>.
17//
18// Q u a n t u m L e a P s
19// ------------------------
20// Modern Embedded Software
21//
22// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
23//
24// This software is dual-licensed under the terms of the open source GNU
25// General Public License version 3 (or any later version), or alternatively,
26// under the terms of one of the closed source Quantum Leaps commercial
27// licenses.
28//
29// The terms of the open source GNU General Public License version 3
30// can be found at: <www.gnu.org/licenses/gpl-3.0>
31//
32// The terms of the closed source Quantum Leaps commercial licenses
33// can be found at: <www.state-machine.com/licensing>
34//
35// Redistributions in source code must retain this top-level comment block.
36// Plagiarizing this software to sidestep the license obligations is illegal.
37//
38// Contact information:
39// <www.state-machine.com/licensing>
40// <info@state-machine.com>
41//
42//$endhead${src::qf::qf_time.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
43#define QP_IMPL // this is QP implementation
44#include "qp_port.hpp" // QP port
45#include "qp_pkg.hpp" // QP package-scope interface
46#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
47#ifdef Q_SPY // QS software tracing enabled?
48 #include "qs_port.hpp" // QS port
49 #include "qs_pkg.hpp" // QS facilities for pre-defined trace records
50#else
51 #include "qs_dummy.hpp" // disable the QS software tracing
52#endif // Q_SPY
53
54// unnamed namespace for local definitions with internal linkage
55namespace {
56Q_DEFINE_THIS_MODULE("qf_time")
57} // unnamed namespace
58
59//$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
60// Check for the minimum required QP version
61#if (QP_VERSION < 730U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U))
62#error qpcpp version 7.3.0 or higher required
63#endif
64//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
65
66//$define${QF::QTimeEvt} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
67namespace QP {
68
69//${QF::QTimeEvt} ............................................................
71
72//${QF::QTimeEvt::QTimeEvt} ..................................................
74 QActive * const act,
75 QSignal const sig,
76 std::uint_fast8_t const tickRate) noexcept
77 :
78 QEvt(sig),
79 m_next(nullptr),
80 m_act(act),
81 m_ctr(0U),
82 m_interval(0U)
83{
86 Q_REQUIRE_INCRIT(300, (sig != 0U)
87 && (tickRate < QF_MAX_TICK_RATE));
89
90 // The refCtr_ attribute is not used in time events, so it is
91 // reused to hold the tickRate as well as other information
92 refCtr_ = static_cast<std::uint8_t>(tickRate);
93}
94
95//${QF::QTimeEvt::armX} ......................................................
97 QTimeEvtCtr const nTicks,
98 QTimeEvtCtr const interval) noexcept
99{
100 std::uint8_t const tickRate = refCtr_ & TE_TICK_RATE;
101 QTimeEvtCtr const ctr = m_ctr;
102 #ifdef Q_SPY
103 std::uint_fast8_t const qsId =
104 static_cast<QActive const *>(m_act)->m_prio;
105 #endif
106
109 QF_MEM_SYS();
110
111 Q_REQUIRE_INCRIT(400, (m_act != nullptr)
112 && (ctr == 0U)
113 && (nTicks != 0U)
114 && (tickRate < static_cast<std::uint8_t>(QF_MAX_TICK_RATE))
115 && (sig >= static_cast<QSignal>(Q_USER_SIG)));
116 #ifdef Q_UNSAFE
117 Q_UNUSED_PAR(ctr);
118 #endif
119
120 m_ctr = nTicks;
121 m_interval = interval;
122
123 // is the time event unlinked?
124 // NOTE: For the duration of a single clock tick of the specified tick
125 // rate a time event can be disarmed and yet still linked into the list
126 // because un-linking is performed exclusively in the QF_tickX() function.
127 if (static_cast<std::uint_fast8_t>(
128 static_cast<std::uint_fast8_t>(refCtr_) & TE_IS_LINKED) == 0U)
129 {
130 // mark as linked
131 refCtr_ = static_cast<std::uint8_t>(refCtr_ | TE_IS_LINKED);
132
133 // The time event is initially inserted into the separate
134 // "freshly armed" list based on timeEvtHead_[tickRate].act.
135 // Only later, inside QTimeEvt::tick(), the "freshly armed"
136 // list is appended to the main list of armed time events based on
137 // timeEvtHead_[tickRate].next. Again, this is to keep any
138 // changes to the main list exclusively inside QTimeEvt::tick().
139 m_next = timeEvtHead_[tickRate].toTimeEvt();
140 timeEvtHead_[tickRate].m_act = this;
141 }
142
143 QS_BEGIN_PRE_(QS_QF_TIMEEVT_ARM, qsId)
144 QS_TIME_PRE_(); // timestamp
145 QS_OBJ_PRE_(this); // this time event object
146 QS_OBJ_PRE_(m_act); // the active object
147 QS_TEC_PRE_(nTicks); // the # ticks
148 QS_TEC_PRE_(interval); // the interval
149 QS_U8_PRE_(tickRate); // tick rate
150 QS_END_PRE_()
151
152 QF_MEM_APP();
153 QF_CRIT_EXIT();
154}
155
156//${QF::QTimeEvt::disarm} ....................................................
157bool QTimeEvt::disarm() noexcept {
158 #ifdef Q_SPY
159 std::uint_fast8_t const qsId = static_cast<QActive *>(m_act)->m_prio;
160 #endif
161
164 QF_MEM_SYS();
165
166 // is the time event actually armed?
167 bool wasArmed;
168 if (m_ctr != 0U) {
169 wasArmed = true;
170 refCtr_ = static_cast<std::uint8_t>(refCtr_ | TE_WAS_DISARMED);
171
172 QS_BEGIN_PRE_(QS_QF_TIMEEVT_DISARM, qsId)
173 QS_TIME_PRE_(); // timestamp
174 QS_OBJ_PRE_(this); // this time event object
175 QS_OBJ_PRE_(m_act); // the target AO
176 QS_TEC_PRE_(m_ctr); // the # ticks
177 QS_TEC_PRE_(m_interval); // the interval
178 QS_U8_PRE_(refCtr_& TE_TICK_RATE); // tick rate
179 QS_END_PRE_()
180
181 m_ctr = 0U; // schedule removal from the list
182 }
183 else { // the time event was already disarmed automatically
184 wasArmed = false;
185 refCtr_ = static_cast<std::uint8_t>(refCtr_
186 & static_cast<std::uint8_t>(~TE_WAS_DISARMED));
187
188 QS_BEGIN_PRE_(QS_QF_TIMEEVT_DISARM_ATTEMPT, qsId)
189 QS_TIME_PRE_(); // timestamp
190 QS_OBJ_PRE_(this); // this time event object
191 QS_OBJ_PRE_(m_act); // the target AO
192 QS_U8_PRE_(refCtr_& TE_TICK_RATE); // tick rate
193 QS_END_PRE_()
194 }
195
196 QF_MEM_APP();
197 QF_CRIT_EXIT();
198
199 return wasArmed;
200}
201
202//${QF::QTimeEvt::rearm} .....................................................
203bool QTimeEvt::rearm(QTimeEvtCtr const nTicks) noexcept {
204 std::uint8_t const tickRate = refCtr_ & TE_TICK_RATE;
205
206 #ifdef Q_SPY
207 std::uint_fast8_t const qsId = static_cast<QActive *>(m_act)->m_prio;
208 #endif
209
212 QF_MEM_SYS();
213
214 Q_REQUIRE_INCRIT(600, (m_act != nullptr)
215 && (tickRate < static_cast<std::uint8_t>(QF_MAX_TICK_RATE))
216 && (nTicks != 0U)
217 && (sig >= static_cast<QSignal>(Q_USER_SIG)));
218
219 // is the time evt not running?
220 bool wasArmed;
221 if (m_ctr == 0U) {
222 wasArmed = false;
223
224 // NOTE: For a duration of a single clock tick of the specified
225 // tick rate a time event can be disarmed and yet still linked into
226 // the list, because unlinking is performed exclusively in the
227 // QTimeEvt::tickX() function.
228
229 // is the time event unlinked?
230 if (static_cast<std::uint8_t>(refCtr_ & TE_IS_LINKED) == 0U) {
231 // mark as linked
232 refCtr_ = static_cast<std::uint8_t>(refCtr_ | TE_IS_LINKED);
233
234 // The time event is initially inserted into the separate
235 // "freshly armed" list based on timeEvtHead_[tickRate].act.
236 // Only later, inside QTimeEvt::tick(), the "freshly armed"
237 // list is appended to the main list of armed time events based on
238 // timeEvtHead_[tickRate].next. Again, this is to keep any
239 // changes to the main list exclusively inside QTimeEvt::tick().
240 m_next = timeEvtHead_[tickRate].toTimeEvt();
241 timeEvtHead_[tickRate].m_act = this;
242 }
243 }
244 else { // the time event was armed
245 wasArmed = true;
246 }
247 m_ctr = nTicks; // re-load the tick counter (shift the phasing)
248
249 QS_BEGIN_PRE_(QS_QF_TIMEEVT_REARM, qsId)
250 QS_TIME_PRE_(); // timestamp
251 QS_OBJ_PRE_(this); // this time event object
252 QS_OBJ_PRE_(m_act); // the target AO
253 QS_TEC_PRE_(m_ctr); // the # ticks
254 QS_TEC_PRE_(m_interval); // the interval
255 QS_2U8_PRE_(tickRate, (wasArmed ? 1U : 0U));
256 QS_END_PRE_()
257
258 QF_MEM_APP();
259 QF_CRIT_EXIT();
260
261 return wasArmed;
262}
263
264//${QF::QTimeEvt::wasDisarmed} ...............................................
265bool QTimeEvt::wasDisarmed() noexcept {
268 QF_MEM_SYS();
269
270 std::uint8_t const isDisarmed = refCtr_ & TE_WAS_DISARMED;
271 refCtr_ = static_cast<std::uint8_t>(refCtr_ | TE_WAS_DISARMED);
272
273 QF_MEM_APP();
274 QF_CRIT_EXIT();
275
276 return isDisarmed != 0U;
277}
278
279//${QF::QTimeEvt::tick} ......................................................
281 std::uint_fast8_t const tickRate,
282 void const * const sender) noexcept
283{
284 #ifndef Q_SPY
285 Q_UNUSED_PAR(sender);
286 #endif
287
290 QF_MEM_SYS();
291
292 Q_REQUIRE_INCRIT(100, tickRate < Q_DIM(timeEvtHead_));
293
294 QTimeEvt *prev = &timeEvtHead_[tickRate];
295
296 QS_BEGIN_PRE_(QS_QF_TICK, 0U)
297 prev->m_ctr = (prev->m_ctr + 1U);
298 QS_TEC_PRE_(prev->m_ctr); // tick ctr
299 QS_U8_PRE_(tickRate); // tick rate
300 QS_END_PRE_()
301
302 // scan the linked-list of time events at this rate...
303 std::uint_fast8_t limit = 2U*QF_MAX_ACTIVE; // loop hard limit
304 for (; limit > 0U; --limit) {
305 QTimeEvt *e = prev->m_next; // advance down the time evt. list
306
307 if (e == nullptr) { // end of the list?
308
309 // any new time events armed since the last run of tick()?
310 if (timeEvtHead_[tickRate].m_act != nullptr) {
311
312 // sanity check
313 Q_ASSERT_INCRIT(110, prev != nullptr);
314 prev->m_next = timeEvtHead_[tickRate].toTimeEvt();
315 timeEvtHead_[tickRate].m_act = nullptr;
316 e = prev->m_next; // switch to the new list
317 }
318 else { // all currently armed time events are processed
319 break; // terminate the for-loop
320 }
321 }
322
323 // the time event 'e' must be valid
325
326 if (e->m_ctr == 0U) { // time event scheduled for removal?
327 prev->m_next = e->m_next;
328 // mark time event 'e' as NOT linked
329 e->refCtr_ = static_cast<std::uint8_t>(e->refCtr_
330 & static_cast<std::uint8_t>(~TE_IS_LINKED));
331 // do NOT advance the prev pointer
332 QF_MEM_APP();
333 QF_CRIT_EXIT(); // exit crit. section to reduce latency
334
335 // NOTE: prevent merging critical sections
336 // In some QF ports the critical section exit takes effect only
337 // on the next machine instruction. If the next instruction is
338 // another entry to a critical section, the critical section
339 // might not be really exited, but rather the two adjacent
340 // critical sections would be MERGED. The QF_CRIT_EXIT_NOP()
341 // macro contains minimal code required to prevent such merging
342 // of critical sections in QF ports, in which it can occur.
344 }
345 else {
346 e->m_ctr = (e->m_ctr - 1U);
347
348 if (e->m_ctr == 0U) { // is time evt about to expire?
349 QActive * const act = e->toActive();
350
351 if (e->m_interval != 0U) { // periodic time evt?
352 e->m_ctr = e->m_interval; // rearm the time event
353 prev = e; // advance to this time event
354 }
355 else { // one-shot time event: automatically disarm
356 prev->m_next = e->m_next;
357
358 // mark time event 'e' as NOT linked
359 e->refCtr_ = static_cast<std::uint8_t>(e->refCtr_
360 & static_cast<std::uint8_t>(~TE_IS_LINKED));
361 // do NOT advance the prev pointer
362
363 QS_BEGIN_PRE_(QS_QF_TIMEEVT_AUTO_DISARM, act->m_prio)
364 QS_OBJ_PRE_(e); // this time event object
365 QS_OBJ_PRE_(act); // the target AO
366 QS_U8_PRE_(tickRate); // tick rate
367 QS_END_PRE_()
368 }
369
370 QS_BEGIN_PRE_(QS_QF_TIMEEVT_POST, act->m_prio)
371 QS_TIME_PRE_(); // timestamp
372 QS_OBJ_PRE_(e); // the time event object
373 QS_SIG_PRE_(e->sig); // signal of this time event
374 QS_OBJ_PRE_(act); // the target AO
375 QS_U8_PRE_(tickRate); // tick rate
376 QS_END_PRE_()
377
378 #ifdef QXK_HPP_
379 if (e->sig < Q_USER_SIG) {
381 QF_MEM_APP();
382 QF_CRIT_EXIT();
383 }
384 else {
385 QF_MEM_APP();
386 QF_CRIT_EXIT(); // exit crit. section before posting
387
388 // act->POST() asserts if the queue overflows
389 act->POST(e, sender);
390 }
391 #else
392 QF_MEM_APP();
393 QF_CRIT_EXIT(); // exit crit. section before posting
394
395 // act->POST() asserts if the queue overflows
396 act->POST(e, sender);
397 #endif
398 }
399 else {
400 prev = e; // advance to this time event
401
402 QF_MEM_APP();
403 QF_CRIT_EXIT(); // exit crit. section to reduce latency
404
405 // prevent merging critical sections, see NOTE above
407 }
408 }
409 QF_CRIT_ENTRY(); // re-enter crit. section to continue the loop
410 QF_MEM_SYS();
411 }
412
413 Q_ENSURE_INCRIT(190, limit > 0U);
414 QF_MEM_APP();
415 QF_CRIT_EXIT();
416}
417
418//${QF::QTimeEvt::noActive} ..................................................
419bool QTimeEvt::noActive(std::uint_fast8_t const tickRate) noexcept {
422 Q_REQUIRE_INCRIT(800, tickRate < QF_MAX_TICK_RATE);
423 QF_CRIT_EXIT();
424
425 bool inactive;
426 if (timeEvtHead_[tickRate].m_next != nullptr) {
427 inactive = false;
428 }
429 else if (timeEvtHead_[tickRate].m_act != nullptr) {
430 inactive = false;
431 }
432 else {
433 inactive = true;
434 }
435 return inactive;
436}
437
438//${QF::QTimeEvt::QTimeEvt} ..................................................
440 :
441 QEvt(0U),
442 m_next(nullptr),
443 m_act(nullptr),
444 m_ctr(0U),
445 m_interval(0U)
446{
447 // The refCtr_ attribute is not used in time events, so it is
448 // reused to hold the tickRate as well as other information
449 refCtr_ = 0U; // default rate 0
450}
451
452} // namespace QP
453//$enddef${QF::QTimeEvt} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Active object class (based on the QHsm implementation strategy)
Definition qp.hpp:724
std::uint8_t m_prio
Definition qp.hpp:726
Event class.
Definition qp.hpp:139
std::uint8_t volatile refCtr_
Definition qp.hpp:142
static bool verify_(QEvt const *const e) noexcept
Definition qp.hpp:163
QSignal sig
Definition qp.hpp:141
Time Event class.
Definition qp.hpp:955
static QTimeEvt timeEvtHead_[QF_MAX_TICK_RATE]
Definition qp.hpp:963
static bool noActive(std::uint_fast8_t const tickRate) noexcept
Definition qf_time.cpp:419
QTimeEvt * toTimeEvt() noexcept
Definition qp.hpp:1012
QTimeEvtCtr m_interval
Definition qp.hpp:960
QTimeEvt *volatile m_next
Definition qp.hpp:957
QTimeEvt() noexcept
Definition qf_time.cpp:439
static void tick(std::uint_fast8_t const tickRate, void const *const sender) noexcept
Definition qf_time.cpp:280
QTimeEvtCtr volatile m_ctr
Definition qp.hpp:959
void * m_act
Definition qp.hpp:958
bool wasDisarmed() noexcept
Definition qf_time.cpp:265
bool disarm() noexcept
Definition qf_time.cpp:157
QActive * toActive() noexcept
Definition qp.hpp:1009
bool rearm(QTimeEvtCtr const nTicks) noexcept
Definition qf_time.cpp:203
void armX(QTimeEvtCtr const nTicks, QTimeEvtCtr const interval=0U) noexcept
Definition qf_time.cpp:96
static void timeout_(QActive *const act)
Definition qxk_xthr.cpp:300
QP/C++ framework.
Definition qequeue.hpp:50
constexpr enum_t Q_USER_SIG
Definition qp.hpp:217
std::uint16_t QSignal
Definition qp.hpp:130
constexpr std::uint8_t TE_IS_LINKED
Definition qp_pkg.hpp:88
constexpr std::uint8_t TE_WAS_DISARMED
Definition qp_pkg.hpp:89
std::uint32_t QTimeEvtCtr
Definition qp.hpp:588
constexpr std::uint8_t TE_TICK_RATE
Definition qp_pkg.hpp:90
@ QS_QF_TICK
QTimeEvt tick was called.
Definition qs.hpp:114
@ QS_QF_TIMEEVT_ARM
a time event was armed
Definition qs.hpp:117
@ QS_QF_TIMEEVT_POST
a time event posted itself directly to an AO
Definition qs.hpp:122
@ QS_QF_TIMEEVT_AUTO_DISARM
a time event expired and was disarmed
Definition qs.hpp:118
@ QS_QF_TIMEEVT_REARM
rearming of a time event
Definition qs.hpp:121
@ QS_QF_TIMEEVT_DISARM
true disarming of an armed time event
Definition qs.hpp:120
@ QS_QF_TIMEEVT_DISARM_ATTEMPT
attempt to disarm a disarmed QTimeEvt
Definition qs.hpp:119
#define QF_MEM_APP()
Definition qp.hpp:1276
#define Q_UNUSED_PAR(par_)
Definition qp.hpp:541
#define QF_MEM_SYS()
Definition qp.hpp:1271
#define Q_DIM(array_)
Definition qp.hpp:544
#define QF_CRIT_EXIT_NOP()
Definition qp.hpp:1266
#define QF_MAX_TICK_RATE
#define QF_MAX_ACTIVE
Internal (package scope) QP/C++ interface.
Sample QP/C++ port.
#define QS_TIME_PRE_()
Definition qs.hpp:473
QS/C++ package-scope interface.
QS/C++ port to a 32-bit CPU, generic C++ compiler.
QP Functional Safety (FuSa) Subsystem.
#define QF_CRIT_ENTRY()
Definition qsafe.h:58
#define Q_ASSERT_INCRIT(id_, expr_)
Definition qsafe.h:72
#define Q_ENSURE_INCRIT(id_, expr_)
Definition qsafe.h:145
#define QF_CRIT_EXIT()
Definition qsafe.h:62
#define Q_REQUIRE_INCRIT(id_, expr_)
Definition qsafe.h:136
#define QF_CRIT_STAT
Definition qsafe.h:54