QP/C  7.3.4
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.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) : qpc
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.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) % 0x3E8U))
59#error qpc version 7.3.0 or higher required
60#endif
61//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
62
63//$define${QF::QTimeEvt} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
64
65//${QF::QTimeEvt} ............................................................
66QTimeEvt QTimeEvt_timeEvtHead_[QF_MAX_TICK_RATE];
67
68//${QF::QTimeEvt::ctorX} .....................................................
69//! @public @memberof QTimeEvt
70void QTimeEvt_ctorX(QTimeEvt * const me,
71 QActive * const act,
72 enum_t const sig,
73 uint_fast8_t const tickRate)
74{
77 Q_REQUIRE_INCRIT(300, (sig != 0)
78 && (tickRate < QF_MAX_TICK_RATE));
80
81 // Initialize the QEvt superclass:
82 // NOTE: The refCtr_ attribute is not used in time events,
83 // so it is reused to hold the tickRate as well as other
84 // information about the status of the time event.
85 me->super.sig = (QSignal)sig;
86 me->super.refCtr_ = (uint8_t)tickRate;
88
89 me->next = (QTimeEvt *)0;
90 me->act = act;
91 me->ctr = 0U;
92 me->interval = 0U;
93}
94
95//${QF::QTimeEvt::armX} ......................................................
96//! @public @memberof QTimeEvt
97void QTimeEvt_armX(QTimeEvt * const me,
98 QTimeEvtCtr const nTicks,
99 QTimeEvtCtr const interval)
100{
101 uint_fast8_t const tickRate
102 = ((uint_fast8_t)me->super.refCtr_ & QTE_TICK_RATE);
103 QTimeEvtCtr const ctr = me->ctr;
104 #ifdef Q_SPY
105 uint_fast8_t const qsId = ((QActive *)(me->act))->prio;
106 #endif
107
110 QF_MEM_SYS();
111
112 Q_REQUIRE_INCRIT(400, (me->act != (void *)0)
113 && (ctr == 0U)
114 && (nTicks != 0U)
115 && (tickRate < (uint_fast8_t)QF_MAX_TICK_RATE)
116 && (me->super.sig >= (QSignal)Q_USER_SIG));
117 #ifdef Q_UNSAFE
118 Q_UNUSED_PAR(ctr);
119 #endif
120
121 me->ctr = nTicks;
122 me->interval = interval;
123
124 // is the time event unlinked?
125 // NOTE: For the duration of a single clock tick of the specified tick
126 // rate a time event can be disarmed and yet still linked into the list
127 // because un-linking is performed exclusively in QTimeEvt_tick_().
128 if ((me->super.refCtr_ & QTE_IS_LINKED) == 0U) {
129 // mark as linked
131
132 // The time event is initially inserted into the separate
133 // "freshly armed" link list based on QTimeEvt_timeEvtHead_[tickRate].act.
134 // Only later, inside the QTimeEvt_tick_() function, the "freshly armed"
135 // list is appended to the main list of armed time events based on
136 // QTimeEvt_timeEvtHead_[tickRate].next. Again, this is to keep any
137 // changes to the main list exclusively inside the QTimeEvt_tick_().
138 me->next = (QTimeEvt *)QTimeEvt_timeEvtHead_[tickRate].act;
139 QTimeEvt_timeEvtHead_[tickRate].act = me;
140 }
141
142 QS_BEGIN_PRE_(QS_QF_TIMEEVT_ARM, qsId)
143 QS_TIME_PRE_(); // timestamp
144 QS_OBJ_PRE_(me); // this time event object
145 QS_OBJ_PRE_(me->act); // the active object
146 QS_TEC_PRE_(nTicks); // the # ticks
147 QS_TEC_PRE_(interval); // the interval
148 QS_U8_PRE_(tickRate); // tick rate
149 QS_END_PRE_()
150
151 QF_MEM_APP();
152 QF_CRIT_EXIT();
153}
154
155//${QF::QTimeEvt::disarm} ....................................................
156//! @public @memberof QTimeEvt
157bool QTimeEvt_disarm(QTimeEvt * const me) {
158 #ifdef Q_SPY
159 uint_fast8_t const qsId = QACTIVE_CAST_(me->act)->prio;
160 #endif
161
164 QF_MEM_SYS();
165
166 // is the time event actually armed?
167 bool wasArmed;
168 if (me->ctr != 0U) {
169 wasArmed = true;
171
172 QS_BEGIN_PRE_(QS_QF_TIMEEVT_DISARM, qsId)
173 QS_TIME_PRE_(); // timestamp
174 QS_OBJ_PRE_(me); // this time event object
175 QS_OBJ_PRE_(me->act); // the target AO
176 QS_TEC_PRE_(me->ctr); // the # ticks
177 QS_TEC_PRE_(me->interval); // the interval
178 QS_U8_PRE_(me->super.refCtr_ & QTE_TICK_RATE); // tick rate
179 QS_END_PRE_()
180
181 me->ctr = 0U; // schedule removal from the list
182 }
183 else { // the time event was already disarmed automatically
184 wasArmed = false;
185 me->super.refCtr_ &= (uint8_t)(~QTE_WAS_DISARMED & 0xFFU);
186
187 QS_BEGIN_PRE_(QS_QF_TIMEEVT_DISARM_ATTEMPT, qsId)
188 QS_TIME_PRE_(); // timestamp
189 QS_OBJ_PRE_(me); // this time event object
190 QS_OBJ_PRE_(me->act); // the target AO
191 QS_U8_PRE_(me->super.refCtr_ & QTE_TICK_RATE); // tick rate
192 QS_END_PRE_()
193 }
194
195 QF_MEM_APP();
196 QF_CRIT_EXIT();
197
198 return wasArmed;
199}
200
201//${QF::QTimeEvt::rearm} .....................................................
202//! @public @memberof QTimeEvt
203bool QTimeEvt_rearm(QTimeEvt * const me,
204 QTimeEvtCtr const nTicks)
205{
206 uint_fast8_t const tickRate
207 = (uint_fast8_t)me->super.refCtr_ & QTE_TICK_RATE;
208 #ifdef Q_SPY
209 uint_fast8_t const qsId = ((QActive *)(me->act))->prio;
210 #endif
211
214 QF_MEM_SYS();
215
216 Q_REQUIRE_INCRIT(600, (me->act != (void *)0)
217 && (tickRate < QF_MAX_TICK_RATE)
218 && (nTicks != 0U)
219 && (me->super.sig >= (QSignal)Q_USER_SIG));
220
221 // is the time evt not running?
222 bool wasArmed;
223 if (me->ctr == 0U) {
224 wasArmed = false;
225
226 // NOTE: For the duration of a single clock tick of the specified
227 // tick rate a time event can be disarmed and yet still linked into
228 // the list, because unlinking is performed exclusively in the
229 // QTimeEvt_tick_() function.
230
231 // is the time event unlinked?
232 if ((me->super.refCtr_ & QTE_IS_LINKED) == 0U) {
233 // mark as linked
235
236 // The time event is initially inserted into the separate
237 // "freshly armed" list based on QTimeEvt_timeEvtHead_[tickRate].act.
238 // Only later, inside the QTimeEvt_tick_() function, the "freshly
239 // armed" list is appended to the main list of armed time events
240 // based on QTimeEvt_timeEvtHead_[tickRate].next. Again, this is
241 // to keep any changes to the main list exclusively inside the
242 // QTimeEvt_tick_().
243 me->next = (QTimeEvt *)QTimeEvt_timeEvtHead_[tickRate].act;
244 QTimeEvt_timeEvtHead_[tickRate].act = me;
245 }
246 }
247 else { // the time event was armed
248 wasArmed = true;
249 }
250 me->ctr = nTicks; // re-load the tick counter (shift the phasing)
251
252 QS_BEGIN_PRE_(QS_QF_TIMEEVT_REARM, qsId)
253 QS_TIME_PRE_(); // timestamp
254 QS_OBJ_PRE_(me); // this time event object
255 QS_OBJ_PRE_(me->act); // the target AO
256 QS_TEC_PRE_(me->ctr); // the # ticks
257 QS_TEC_PRE_(me->interval); // the interval
258 QS_2U8_PRE_(tickRate, (wasArmed ? 1U : 0U));
259 QS_END_PRE_()
260
261 QF_MEM_APP();
262 QF_CRIT_EXIT();
263
264 return wasArmed;
265}
266
267//${QF::QTimeEvt::wasDisarmed} ...............................................
268//! @public @memberof QTimeEvt
269bool QTimeEvt_wasDisarmed(QTimeEvt * const me) {
272 QF_MEM_SYS();
273
274 uint8_t const wasDisarmed = (me->super.refCtr_ & QTE_WAS_DISARMED);
275 me->super.refCtr_ |= QTE_WAS_DISARMED; // mark as disarmed
276
277 QF_MEM_APP();
278 QF_CRIT_EXIT();
279
280 return wasDisarmed != 0U;
281}
282
283//${QF::QTimeEvt::currCtr} ...................................................
284//! @public @memberof QTimeEvt
285QTimeEvtCtr QTimeEvt_currCtr(QTimeEvt const * const me) {
288 QTimeEvtCtr const ctr = me->ctr;
289 QF_CRIT_EXIT();
290
291 return ctr;
292}
293
294//${QF::QTimeEvt::tick_} .....................................................
295//! @static @private @memberof QTimeEvt
296void QTimeEvt_tick_(
297 uint_fast8_t const tickRate,
298 void const * const sender)
299{
300 #ifndef Q_SPY
301 Q_UNUSED_PAR(sender);
302 #endif
303
306 QF_MEM_SYS();
307
308 Q_REQUIRE_INCRIT(100, tickRate < Q_DIM(QTimeEvt_timeEvtHead_));
309
310 QTimeEvt *prev = &QTimeEvt_timeEvtHead_[tickRate];
311
312 QS_BEGIN_PRE_(QS_QF_TICK, 0U)
313 ++prev->ctr;
314 QS_TEC_PRE_(prev->ctr); // tick ctr
315 QS_U8_PRE_(tickRate); // tick rate
316 QS_END_PRE_()
317
318 // scan the linked-list of time events at this rate...
319 uint_fast8_t limit = 2U*QF_MAX_ACTIVE; // loop hard limit
320 for (; limit > 0U; --limit) {
321 QTimeEvt *e = prev->next; // advance down the time evt. list
322
323 if (e == (QTimeEvt *)0) { // end of the list?
324
325 // any new time events armed since the last QTimeEvt_tick_()?
326 if (QTimeEvt_timeEvtHead_[tickRate].act != (void *)0) {
327
328 // sanity check
329 Q_ASSERT_INCRIT(110, prev != (QTimeEvt *)0);
330 prev->next = (QTimeEvt *)QTimeEvt_timeEvtHead_[tickRate].act;
331 QTimeEvt_timeEvtHead_[tickRate].act = (void *)0;
332 e = prev->next; // switch to the new list
333 }
334 else { // all currently armed time events are processed
335 break; // terminate the for-loop
336 }
337 }
338
339 // the time event 'e' must be valid
340 Q_ASSERT_INCRIT(112, QEvt_verify_(Q_EVT_CAST(QEvt)));
341
342 if (e->ctr == 0U) { // time event scheduled for removal?
343 prev->next = e->next;
344 // mark time event 'e' as NOT linked
345 e->super.refCtr_ &= (uint8_t)(~QTE_IS_LINKED & 0xFFU);
346 // do NOT advance the prev pointer
347 QF_MEM_APP();
348 QF_CRIT_EXIT(); // exit crit. section to reduce latency
349
350 // NOTE: prevent merging critical sections
351 // In some QF ports the critical section exit takes effect only
352 // on the next machine instruction. If the next instruction is
353 // another entry to a critical section, the critical section
354 // might not be really exited, but rather the two adjacent
355 // critical sections would be MERGED. The QF_CRIT_EXIT_NOP()
356 // macro contains minimal code required to prevent such merging
357 // of critical sections in QF ports, in which it can occur.
359 }
360 else {
361 --e->ctr;
362
363 if (e->ctr == 0U) { // is time event about to expire?
364 QActive * const act = (QActive *)e->act;
365
366 if (e->interval != 0U) { // periodic time evt?
367 e->ctr = e->interval; // rearm the time event
368 prev = e; // advance to this time event
369 }
370 else { // one-shot time event: automatically disarm
371 prev->next = e->next;
372
373 // mark time event 'e' as NOT linked
374 e->super.refCtr_ &= (uint8_t)(~QTE_IS_LINKED & 0xFFU);
375 // do NOT advance the prev pointer
376
377 QS_BEGIN_PRE_(QS_QF_TIMEEVT_AUTO_DISARM, act->prio)
378 QS_OBJ_PRE_(e); // this time event object
379 QS_OBJ_PRE_(act); // the target AO
380 QS_U8_PRE_(tickRate); // tick rate
381 QS_END_PRE_()
382 }
383
384 QS_BEGIN_PRE_(QS_QF_TIMEEVT_POST, act->prio)
385 QS_TIME_PRE_(); // timestamp
386 QS_OBJ_PRE_(e); // the time event object
387 QS_SIG_PRE_(e->super.sig); // signal of this time event
388 QS_OBJ_PRE_(act); // the target AO
389 QS_U8_PRE_(tickRate); // tick rate
390 QS_END_PRE_()
391
392 #ifdef QXK_H_
393 if (e->super.sig < Q_USER_SIG) {
394 QXThread_timeout_(act);
395 QF_MEM_APP();
396 QF_CRIT_EXIT();
397 }
398 else {
399 QF_MEM_APP();
400 QF_CRIT_EXIT(); // exit crit. section before posting
401
402 // QACTIVE_POST() asserts if the queue overflows
403 QACTIVE_POST(act, &e->super, sender);
404 }
405 #else
406 QF_MEM_APP();
407 QF_CRIT_EXIT(); // exit crit. section before posting
408
409 // QACTIVE_POST() asserts if the queue overflows
410 QACTIVE_POST(act, &e->super, sender);
411 #endif
412 }
413 else {
414 prev = e; // advance to this time event
415
416 QF_MEM_APP();
417 QF_CRIT_EXIT(); // exit crit. section to reduce latency
418
419 // prevent merging critical sections, see NOTE above
421 }
422 }
423 QF_CRIT_ENTRY(); // re-enter crit. section to continue the loop
424 QF_MEM_SYS();
425 }
426
427 Q_ENSURE_INCRIT(190, limit > 0U);
428 QF_MEM_APP();
429 QF_CRIT_EXIT();
430}
431
432//${QF::QTimeEvt::noActive} ..................................................
433//! @static @public @memberof QTimeEvt
434bool QTimeEvt_noActive(uint_fast8_t const tickRate) {
437 Q_REQUIRE_INCRIT(800, tickRate < QF_MAX_TICK_RATE);
438 QF_CRIT_EXIT();
439
440 bool inactive;
441 if (QTimeEvt_timeEvtHead_[tickRate].next != (QTimeEvt *)0) {
442 inactive = false;
443 }
444 else if ((QTimeEvt_timeEvtHead_[tickRate].act != (void *)0)) {
445 inactive = false;
446 }
447 else {
448 inactive = true;
449 }
450 return inactive;
451}
452//$enddef${QF::QTimeEvt} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#define QF_MEM_APP()
Definition qp.h:1284
uint16_t QSignal
Definition qp.h:131
#define Q_UNUSED_PAR(par_)
Definition qp.h:532
#define QEVT_MARKER
Definition qp.h:140
uint32_t QTimeEvtCtr
Definition qp.h:633
#define Q_EVT_CAST(class_)
Definition qp.h:523
@ Q_USER_SIG
offset for the user signals (QP Application)
Definition qp.h:260
#define QF_MEM_SYS()
Definition qp.h:1279
#define QACTIVE_POST(me_, e_, sender_)
Definition qp.h:1203
int enum_t
Definition qp.h:109
#define Q_DIM(array_)
Definition qp.h:535
#define QF_CRIT_EXIT_NOP()
Definition qp.h:1265
#define QF_MAX_TICK_RATE
Definition qp_config.h:130
#define QF_MAX_ACTIVE
Definition qp_config.h:112
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_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:800
uint8_t prio
Definition qp.h:805
Event class.
Definition qp.h:147
uint8_t evtTag_
Definition qp.h:159
uint8_t volatile refCtr_
Definition qp.h:156
QSignal sig
Definition qp.h:151
Time Event class.
Definition qp.h:969
struct QTimeEvt *volatile next
Definition qp.h:976
void *volatile act
Definition qp.h:979
QEvt super
Definition qp.h:971
QTimeEvtCtr interval
Definition qp.h:985
QTimeEvtCtr volatile ctr
Definition qp.h:982