QP/C  7.4.0-rc.3
Real-Time Embedded Framework
Loading...
Searching...
No Matches
qf_time.c
Go to the documentation of this file.
1//$file${src::qf::qf_time.c} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2//
3// Model: qpc.qm
4// File: ${src::qf::qf_time.c}
5//
6// This code has been generated by QM 6.2.0 <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) : qpc
13// Support ends : 2025-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.c} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
43#define QP_IMPL // this is QP implementation
44#include "qp_port.h" // QP port
45#include "qp_pkg.h" // 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.h" // QS port
49 #include "qs_pkg.h" // QS facilities for pre-defined trace records
50#else
51 #include "qs_dummy.h" // disable the QS software tracing
52#endif // Q_SPY
53
54Q_DEFINE_THIS_MODULE("qf_time")
55
56//$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
57// Check for the minimum required QP version
58#if (QP_VERSION < 730U) || (QP_VERSION != ((QP_RELEASE^4294967295U)%0x2710U))
59#error qpc version 7.3.0 or higher required
60#endif
61//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
62//$define${QF::QTimeEvt} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
63
64//${QF::QTimeEvt} ............................................................
65QTimeEvt QTimeEvt_timeEvtHead_[QF_MAX_TICK_RATE];
66
67//${QF::QTimeEvt::ctorX} .....................................................
68//! @public @memberof QTimeEvt
69void QTimeEvt_ctorX(QTimeEvt * const me,
70 QActive * const act,
71 enum_t const sig,
72 uint_fast8_t const tickRate)
73{
76 Q_REQUIRE_INCRIT(300, (sig != 0)
77 && (tickRate < QF_MAX_TICK_RATE));
79
80 // Initialize the QEvt superclass:
81 // NOTE: The refCtr_ attribute is not used in time events,
82 // so it is reused to hold the tickRate as well as other
83 // information about the status of the time event.
84 me->super.sig = (QSignal)sig;
85 me->super.refCtr_ = (uint8_t)tickRate;
87
88 me->next = (QTimeEvt *)0;
89 me->act = act;
90 me->ctr = 0U;
91 me->interval = 0U;
92}
93
94//${QF::QTimeEvt::armX} ......................................................
95//! @public @memberof QTimeEvt
96void QTimeEvt_armX(QTimeEvt * const me,
97 QTimeEvtCtr const nTicks,
98 QTimeEvtCtr const interval)
99{
100 uint_fast8_t const tickRate
101 = ((uint_fast8_t)me->super.refCtr_ & QTE_TICK_RATE);
102 QTimeEvtCtr const ctr = me->ctr;
103 #ifdef Q_SPY
104 uint_fast8_t const qsId = ((QActive *)(me->act))->prio;
105 #endif
106
109 QF_MEM_SYS();
110
111 Q_REQUIRE_INCRIT(400, (me->act != (void *)0)
112 && (ctr == 0U)
113 && (nTicks != 0U)
114 && (tickRate < (uint_fast8_t)QF_MAX_TICK_RATE)
115 && (me->super.sig >= (QSignal)Q_USER_SIG));
116 #ifdef Q_UNSAFE
117 Q_UNUSED_PAR(ctr);
118 #endif
119
120 me->ctr = nTicks;
121 me->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 QTimeEvt_tick_().
127 if ((me->super.refCtr_ & QTE_IS_LINKED) == 0U) {
128 // mark as linked
130
131 // The time event is initially inserted into the separate
132 // "freshly armed" link list based on QTimeEvt_timeEvtHead_[tickRate].act.
133 // Only later, inside the QTimeEvt_tick_() function, the "freshly armed"
134 // list is appended to the main list of armed time events based on
135 // QTimeEvt_timeEvtHead_[tickRate].next. Again, this is to keep any
136 // changes to the main list exclusively inside the QTimeEvt_tick_().
137 me->next = (QTimeEvt *)QTimeEvt_timeEvtHead_[tickRate].act;
138 QTimeEvt_timeEvtHead_[tickRate].act = me;
139 }
140
141 QS_BEGIN_PRE_(QS_QF_TIMEEVT_ARM, qsId)
142 QS_TIME_PRE_(); // timestamp
143 QS_OBJ_PRE_(me); // this time event object
144 QS_OBJ_PRE_(me->act); // the active object
145 QS_TEC_PRE_(nTicks); // the # ticks
146 QS_TEC_PRE_(interval); // the interval
147 QS_U8_PRE_(tickRate); // tick rate
148 QS_END_PRE_()
149
150 QF_MEM_APP();
151 QF_CRIT_EXIT();
152}
153
154//${QF::QTimeEvt::disarm} ....................................................
155//! @public @memberof QTimeEvt
156bool QTimeEvt_disarm(QTimeEvt * const me) {
157 #ifdef Q_SPY
158 uint_fast8_t const qsId = QACTIVE_CAST_(me->act)->prio;
159 #endif
160
163 QF_MEM_SYS();
164
165 // is the time event actually armed?
166 bool wasArmed;
167 if (me->ctr != 0U) {
168 wasArmed = true;
170
171 QS_BEGIN_PRE_(QS_QF_TIMEEVT_DISARM, qsId)
172 QS_TIME_PRE_(); // timestamp
173 QS_OBJ_PRE_(me); // this time event object
174 QS_OBJ_PRE_(me->act); // the target AO
175 QS_TEC_PRE_(me->ctr); // the # ticks
176 QS_TEC_PRE_(me->interval); // the interval
177 QS_U8_PRE_(me->super.refCtr_ & QTE_TICK_RATE); // tick rate
178 QS_END_PRE_()
179
180 me->ctr = 0U; // schedule removal from the list
181 }
182 else { // the time event was already disarmed automatically
183 wasArmed = false;
184 me->super.refCtr_ &= (uint8_t)(~QTE_WAS_DISARMED & 0xFFU);
185
186 QS_BEGIN_PRE_(QS_QF_TIMEEVT_DISARM_ATTEMPT, qsId)
187 QS_TIME_PRE_(); // timestamp
188 QS_OBJ_PRE_(me); // this time event object
189 QS_OBJ_PRE_(me->act); // the target AO
190 QS_U8_PRE_(me->super.refCtr_ & QTE_TICK_RATE); // tick rate
191 QS_END_PRE_()
192 }
193
194 QF_MEM_APP();
195 QF_CRIT_EXIT();
196
197 return wasArmed;
198}
199
200//${QF::QTimeEvt::rearm} .....................................................
201//! @public @memberof QTimeEvt
202bool QTimeEvt_rearm(QTimeEvt * const me,
203 QTimeEvtCtr const nTicks)
204{
205 uint_fast8_t const tickRate
206 = (uint_fast8_t)me->super.refCtr_ & QTE_TICK_RATE;
207 #ifdef Q_SPY
208 uint_fast8_t const qsId = ((QActive *)(me->act))->prio;
209 #endif
210
213 QF_MEM_SYS();
214
215 Q_REQUIRE_INCRIT(600, (me->act != (void *)0)
216 && (tickRate < QF_MAX_TICK_RATE)
217 && (nTicks != 0U)
218 && (me->super.sig >= (QSignal)Q_USER_SIG));
219
220 // is the time evt not running?
221 bool wasArmed;
222 if (me->ctr == 0U) {
223 wasArmed = false;
224
225 // NOTE: For the duration of a single clock tick of the specified
226 // tick rate a time event can be disarmed and yet still linked into
227 // the list, because unlinking is performed exclusively in the
228 // QTimeEvt_tick_() function.
229
230 // is the time event unlinked?
231 if ((me->super.refCtr_ & QTE_IS_LINKED) == 0U) {
232 // mark as linked
234
235 // The time event is initially inserted into the separate
236 // "freshly armed" list based on QTimeEvt_timeEvtHead_[tickRate].act.
237 // Only later, inside the QTimeEvt_tick_() function, the "freshly
238 // armed" list is appended to the main list of armed time events
239 // based on QTimeEvt_timeEvtHead_[tickRate].next. Again, this is
240 // to keep any changes to the main list exclusively inside the
241 // QTimeEvt_tick_().
242 me->next = (QTimeEvt *)QTimeEvt_timeEvtHead_[tickRate].act;
243 QTimeEvt_timeEvtHead_[tickRate].act = me;
244 }
245 }
246 else { // the time event was armed
247 wasArmed = true;
248 }
249 me->ctr = nTicks; // re-load the tick counter (shift the phasing)
250
251 QS_BEGIN_PRE_(QS_QF_TIMEEVT_REARM, qsId)
252 QS_TIME_PRE_(); // timestamp
253 QS_OBJ_PRE_(me); // this time event object
254 QS_OBJ_PRE_(me->act); // the target AO
255 QS_TEC_PRE_(me->ctr); // the # ticks
256 QS_TEC_PRE_(me->interval); // the interval
257 QS_2U8_PRE_(tickRate, (wasArmed ? 1U : 0U));
258 QS_END_PRE_()
259
260 QF_MEM_APP();
261 QF_CRIT_EXIT();
262
263 return wasArmed;
264}
265
266//${QF::QTimeEvt::wasDisarmed} ...............................................
267//! @public @memberof QTimeEvt
268bool QTimeEvt_wasDisarmed(QTimeEvt * const me) {
271 QF_MEM_SYS();
272
273 uint8_t const wasDisarmed = (me->super.refCtr_ & QTE_WAS_DISARMED);
274 me->super.refCtr_ |= QTE_WAS_DISARMED; // mark as disarmed
275
276 QF_MEM_APP();
277 QF_CRIT_EXIT();
278
279 return wasDisarmed != 0U;
280}
281
282//${QF::QTimeEvt::currCtr} ...................................................
283//! @public @memberof QTimeEvt
284QTimeEvtCtr QTimeEvt_currCtr(QTimeEvt const * const me) {
287 QTimeEvtCtr const ctr = me->ctr;
288 QF_CRIT_EXIT();
289
290 return ctr;
291}
292
293//${QF::QTimeEvt::tick_} .....................................................
294//! @static @private @memberof QTimeEvt
295void QTimeEvt_tick_(
296 uint_fast8_t const tickRate,
297 void const * const sender)
298{
299 #ifndef Q_SPY
300 Q_UNUSED_PAR(sender);
301 #endif
302
305 QF_MEM_SYS();
306
307 Q_REQUIRE_INCRIT(100, tickRate < Q_DIM(QTimeEvt_timeEvtHead_));
308
309 QTimeEvt *prev = &QTimeEvt_timeEvtHead_[tickRate];
310
311 QS_BEGIN_PRE_(QS_QF_TICK, 0U)
312 ++prev->ctr;
313 QS_TEC_PRE_(prev->ctr); // tick ctr
314 QS_U8_PRE_(tickRate); // tick rate
315 QS_END_PRE_()
316
317 // scan the linked-list of time events at this rate...
318 uint_fast8_t lbound = 2U*QF_MAX_ACTIVE; // fixed upper loop bound
319 for (; lbound > 0U; --lbound) {
320 QTimeEvt *e = prev->next; // advance down the time evt. list
321
322 if (e == (QTimeEvt *)0) { // end of the list?
323
324 // any new time events armed since the last QTimeEvt_tick_()?
325 if (QTimeEvt_timeEvtHead_[tickRate].act != (void *)0) {
326
327 // sanity check
328 Q_ASSERT_INCRIT(110, prev != (QTimeEvt *)0);
329 prev->next = (QTimeEvt *)QTimeEvt_timeEvtHead_[tickRate].act;
330 QTimeEvt_timeEvtHead_[tickRate].act = (void *)0;
331 e = prev->next; // switch to the new list
332 }
333 else { // all currently armed time events are processed
334 break; // terminate the for-loop
335 }
336 }
337
338 // the time event 'e' must be valid
339 Q_INVARIANT_INCRIT(112, QEvt_verify_(Q_EVT_CAST(QEvt)));
340
341 if (e->ctr == 0U) { // time event scheduled for removal?
342 prev->next = e->next;
343 // mark time event 'e' as NOT linked
344 e->super.refCtr_ &= (uint8_t)(~QTE_IS_LINKED & 0xFFU);
345 // do NOT advance the prev pointer
346 QF_MEM_APP();
347 QF_CRIT_EXIT(); // exit crit. section to reduce latency
348
349 // NOTE: prevent merging critical sections
350 // In some QF ports the critical section exit takes effect only
351 // on the next machine instruction. If the next instruction is
352 // another entry to a critical section, the critical section
353 // might not be really exited, but rather the two adjacent
354 // critical sections would be MERGED. The QF_CRIT_EXIT_NOP()
355 // macro contains minimal code required to prevent such merging
356 // of critical sections in QF ports, in which it can occur.
358 }
359 else {
360 --e->ctr;
361
362 if (e->ctr == 0U) { // is time event about to expire?
363 QActive * const act = (QActive *)e->act;
364
365 if (e->interval != 0U) { // periodic time evt?
366 e->ctr = e->interval; // rearm the time event
367 prev = e; // advance to this time event
368 }
369 else { // one-shot time event: automatically disarm
370 prev->next = e->next;
371
372 // mark time event 'e' as NOT linked
373 e->super.refCtr_ &= (uint8_t)(~QTE_IS_LINKED & 0xFFU);
374 // do NOT advance the prev pointer
375
376 QS_BEGIN_PRE_(QS_QF_TIMEEVT_AUTO_DISARM, act->prio)
377 QS_OBJ_PRE_(e); // this time event object
378 QS_OBJ_PRE_(act); // the target AO
379 QS_U8_PRE_(tickRate); // tick rate
380 QS_END_PRE_()
381 }
382
383 QS_BEGIN_PRE_(QS_QF_TIMEEVT_POST, act->prio)
384 QS_TIME_PRE_(); // timestamp
385 QS_OBJ_PRE_(e); // the time event object
386 QS_SIG_PRE_(e->super.sig); // signal of this time event
387 QS_OBJ_PRE_(act); // the target AO
388 QS_U8_PRE_(tickRate); // tick rate
389 QS_END_PRE_()
390
391 #ifdef QXK_H_
392 if (e->super.sig < Q_USER_SIG) {
393 QXThread_timeout_(act);
394 QF_MEM_APP();
395 QF_CRIT_EXIT();
396 }
397 else {
398 QF_MEM_APP();
399 QF_CRIT_EXIT(); // exit crit. section before posting
400
401 // QACTIVE_POST() asserts if the queue overflows
402 QACTIVE_POST(act, &e->super, sender);
403 }
404 #else
405 QF_MEM_APP();
406 QF_CRIT_EXIT(); // exit crit. section before posting
407
408 // QACTIVE_POST() asserts if the queue overflows
409 QACTIVE_POST(act, &e->super, sender);
410 #endif
411 }
412 else {
413 prev = e; // advance to this time event
414
415 QF_MEM_APP();
416 QF_CRIT_EXIT(); // exit crit. section to reduce latency
417
418 // prevent merging critical sections, see NOTE above
420 }
421 }
422 QF_CRIT_ENTRY(); // re-enter crit. section to continue the loop
423 QF_MEM_SYS();
424 }
425
426 Q_ENSURE_INCRIT(190, lbound > 0U);
427 QF_MEM_APP();
428 QF_CRIT_EXIT();
429}
430
431//${QF::QTimeEvt::noActive} ..................................................
432//! @static @public @memberof QTimeEvt
433bool QTimeEvt_noActive(uint_fast8_t const tickRate) {
436 Q_REQUIRE_INCRIT(800, tickRate < QF_MAX_TICK_RATE);
437 QF_CRIT_EXIT();
438
439 bool inactive;
440 if (QTimeEvt_timeEvtHead_[tickRate].next != (QTimeEvt *)0) {
441 inactive = false;
442 }
443 else if ((QTimeEvt_timeEvtHead_[tickRate].act != (void *)0)) {
444 inactive = false;
445 }
446 else {
447 inactive = true;
448 }
449 return inactive;
450}
451//$enddef${QF::QTimeEvt} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#define QF_MEM_APP()
Definition qp.h:1288
#define Q_UNUSED_PAR(par_)
Helper macro to clearly mark unused parameters of functions.
Definition qp.h:536
#define QEVT_MARKER
QEvt memory marker (for internal integrity checks)
Definition qp.h:138
uint32_t QTimeEvtCtr
Data type to store the block-size defined based on the macro QF_TIMEEVT_CTR_SIZE.
Definition qp.h:637
#define Q_EVT_CAST(class_)
Perform downcast of an event onto a subclass of QEvt class_
Definition qp.h:527
@ Q_USER_SIG
offset for the user signals (QP Application)
Definition qp.h:263
#define QF_MEM_SYS()
Definition qp.h:1283
#define QACTIVE_POST(me_, e_, sender_)
Invoke the direct event posting facility QActive_post_().
Definition qp.h:1207
int enum_t
Definition qp.h:107
#define Q_DIM(array_)
Definition qp.h:539
#define QF_CRIT_EXIT_NOP()
No-operation for exiting a critical section.
Definition qp.h:1269
uint16_t QSignal
The signal of event QEvt.
Definition qp.h:129
#define QF_MAX_TICK_RATE
Maximum # clock tick rates in the system (0..15)
Definition qp_config.h:138
#define QF_MAX_ACTIVE
Maximum # Active Objects in the system (1..64)
Definition qp_config.h:118
Internal (package scope) QP/C interface.
#define QACTIVE_CAST_(ptr_)
Definition qp_pkg.h:96
#define QTE_WAS_DISARMED
Definition qp_pkg.h:83
#define QTE_IS_LINKED
Definition qp_pkg.h:82
#define QTE_TICK_RATE
Definition qp_pkg.h:84
Sample QP/C port.
@ QS_QF_TIMEEVT_AUTO_DISARM
a time event expired and was disarmed
Definition qs.h:126
@ QS_QF_TIMEEVT_DISARM
true disarming of an armed time event
Definition qs.h:128
@ QS_QF_TIMEEVT_REARM
rearming of a time event
Definition qs.h:129
#define QS_TIME_PRE_()
Definition qs.h:450
@ QS_QF_TIMEEVT_POST
a time event posted itself directly to an AO
Definition qs.h:130
@ QS_QF_TIMEEVT_DISARM_ATTEMPT
attempt to disarm a disarmed QTimeEvt
Definition qs.h:127
@ QS_QF_TICK
QTimeEvt tick was called.
Definition qs.h:122
@ QS_QF_TIMEEVT_ARM
a time event was armed
Definition qs.h:125
QS/C package-scope interface.
Sample QS/C port.
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_INVARIANT_INCRIT(id_, expr_)
Definition qsafe.h:154
#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
Active object class (based on the QHsm implementation strategy)
Definition qp.h:804
uint8_t prio
QF-priority [1..QF_MAX_ACTIVE] of this AO.
Definition qp.h:809
Event class.
Definition qp.h:145
QSignal sig
Signal of the event (see Event Signal)
Definition qp.h:149
uint8_t evtTag_
Event "tag" containing pool-ID (indicating which event pool it came from) plus event marker.
Definition qp.h:157
uint8_t volatile refCtr_
Reference counter (for mutable events and 0 for immutable (static) events)
Definition qp.h:154
Time Event class.
Definition qp.h:973
struct QTimeEvt *volatile next
Link to the next time event in the list.
Definition qp.h:980
void *volatile act
Active object that receives the time events.
Definition qp.h:983
QTimeEvtCtr volatile ctr
Down-counter of the time event.
Definition qp.h:986
QTimeEvtCtr interval
Interval for periodic time event (zero for one-shot time event)
Definition qp.h:989
QEvt super
Definition qp.h:975