QP/C++  7.4.0-rc.1
Real-Time Embedded Framework
Loading...
Searching...
No Matches
qf_actq.cpp
Go to the documentation of this file.
1//$file${src::qf::qf_actq.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2//
3// Model: qpcpp.qm
4// File: ${src::qf::qf_actq.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_actq.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//============================================================================
55// unnamed namespace for local definitions with internal linkage
56namespace {
57Q_DEFINE_THIS_MODULE("qf_actq")
58} // unnamed namespace
59
60//$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
61// Check for the minimum required QP version
62#if (QP_VERSION < 730U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U))
63#error qpcpp version 7.3.0 or higher required
64#endif
65//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
67//$define${QF::QActive::post_} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
68namespace QP {
69
70//${QF::QActive::post_} ......................................................
72 QEvt const * const e,
73 std::uint_fast16_t const margin,
74 void const * const sender) noexcept
75{
76 #ifndef Q_SPY
77 Q_UNUSED_PAR(sender);
78 #endif
79
80 #ifdef Q_UTEST // test?
81 #if Q_UTEST != 0 // testing QP-stub?
82 if (m_temp.fun == Q_STATE_CAST(0)) { // QActiveDummy?
83 return static_cast<QActiveDummy *>(this)->fakePost(e, margin, sender);
84 }
85 #endif
86 #endif
87
90 QF_MEM_SYS();
91
92 #ifndef Q_UNSAFE
94
95 std::uint8_t const pcopy = static_cast<std::uint8_t>(~m_prio_dis);
96 Q_INVARIANT_INCRIT(102, m_prio == pcopy);
97 #endif
98
99 QEQueueCtr nFree = m_eQueue.m_nFree; // get volatile into temporary
100
101 // test-probe#1 for faking queue overflow
104 nFree = 0U;
105 )
106
107 bool status;
108 if (margin == QF::NO_MARGIN) {
109 if (nFree > 0U) {
110 status = true; // can post
111 }
112 else {
113 status = false; // cannot post
114 Q_ERROR_INCRIT(190); // must be able to post the event
115 }
116 }
117 else if (nFree > static_cast<QEQueueCtr>(margin)) {
118 status = true; // can post
119 }
120 else {
121 status = false; // cannot post, but don't assert
122 }
123
124 // is it a mutable event?
125 if (e->getPoolNum_() != 0U) {
126 QEvt_refCtr_inc_(e); // increment the reference counter
127 }
128
129 if (status) { // can post the event?
130
131 --nFree; // one free entry just used up
132 m_eQueue.m_nFree = nFree; // update the original
133 if (m_eQueue.m_nMin > nFree) {
134 m_eQueue.m_nMin = nFree; // update minimum so far
135 }
136
137 QS_BEGIN_PRE_(QS_QF_ACTIVE_POST, m_prio)
138 QS_TIME_PRE_(); // timestamp
139 QS_OBJ_PRE_(sender); // the sender object
140 QS_SIG_PRE_(e->sig); // the signal of the event
141 QS_OBJ_PRE_(this); // this active object
142 QS_2U8_PRE_(e->getPoolNum_(), e->refCtr_); // poolNum & refCtr
143 QS_EQC_PRE_(nFree); // # free entries
144 QS_EQC_PRE_(m_eQueue.m_nMin); // min # free entries
145 QS_END_PRE_()
146
147 #ifdef Q_UTEST
148 // callback to examine the posted event under the same conditions
149 // as producing the #QS_QF_ACTIVE_POST trace record, which are:
150 // the local filter for this AO ('m_prio') is set
151 if (QS_LOC_CHECK_(m_prio)) {
152 QF_MEM_APP();
153 QF_CRIT_EXIT();
154
155 QS::onTestPost(sender, this, e, status);
156
158 QF_MEM_SYS();
159 }
160 #endif
161
162 if (m_eQueue.m_frontEvt == nullptr) { // empty queue?
163 m_eQueue.m_frontEvt = e; // deliver event directly
164 #ifdef QXK_HPP_
165 if (m_state.act == Q_ACTION_CAST(0)) { // eXtended thread?
166 QXTHREAD_EQUEUE_SIGNAL_(this); // signal the event queue
167 }
168 else {
169 QACTIVE_EQUEUE_SIGNAL_(this); // signal the event queue
170 }
171 #else
172 QACTIVE_EQUEUE_SIGNAL_(this); // signal the event queue
173 #endif
174 }
175 // queue is not empty, insert event into the ring-buffer
176 else {
177 // insert event into the ring buffer (FIFO)
178 m_eQueue.m_ring[m_eQueue.m_head] = e;
179
180 if (m_eQueue.m_head == 0U) { // need to wrap head?
181 m_eQueue.m_head = m_eQueue.m_end; // wrap around
182 }
183 // advance the head (counter clockwise)
184 m_eQueue.m_head = (m_eQueue.m_head - 1U);
185 }
186
187 QF_MEM_APP();
188 QF_CRIT_EXIT();
189 }
190 else { // cannot post the event
191
192 QS_BEGIN_PRE_(QS_QF_ACTIVE_POST_ATTEMPT, m_prio)
193 QS_TIME_PRE_(); // timestamp
194 QS_OBJ_PRE_(sender); // the sender object
195 QS_SIG_PRE_(e->sig); // the signal of the event
196 QS_OBJ_PRE_(this); // this active object
197 QS_2U8_PRE_(e->getPoolNum_(), e->refCtr_); // poolNum & refCtr
198 QS_EQC_PRE_(nFree); // # free entries
199 QS_EQC_PRE_(margin); // margin requested
200 QS_END_PRE_()
201
202 #ifdef Q_UTEST
203 // callback to examine the posted event under the same conditions
204 // as producing the #QS_QF_ACTIVE_POST trace record, which are:
205 // the local filter for this AO ('m_prio') is set
206 if (QS_LOC_CHECK_(m_prio)) {
207 QF_MEM_APP();
208 QF_CRIT_EXIT();
209
210 QS::onTestPost(sender, this, e, status);
211
213 QF_MEM_SYS();
214 }
215 #endif
216
217 QF_MEM_APP();
218 QF_CRIT_EXIT();
219
220 #if (QF_MAX_EPOOL > 0U)
221 QF::gc(e); // recycle the event to avoid a leak
222 #endif
223 }
224
225 return status;
226}
227
228} // namespace QP
229//$enddef${QF::QActive::post_} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
230
231//$define${QF::QActive::postLIFO} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
232namespace QP {
233
234//${QF::QActive::postLIFO} ...................................................
235void QActive::postLIFO(QEvt const * const e) noexcept {
236 #ifdef Q_UTEST // test?
237 #if Q_UTEST != 0 // testing QP-stub?
238 if (m_temp.fun == Q_STATE_CAST(0)) { // QActiveDummy?
239 static_cast<QActiveDummy *>(this)->QActiveDummy::fakePostLIFO(e);
240 return;
241 }
242 #endif
243 #endif
244
247 QF_MEM_SYS();
248
249 #ifndef Q_UNSAFE
251
252 std::uint8_t const pcopy = static_cast<std::uint8_t>(~m_prio_dis);
253 Q_INVARIANT_INCRIT(202, m_prio == pcopy);
254 #endif
255
256 #ifdef QXK_HPP_
257 Q_REQUIRE_INCRIT(200, m_state.act != Q_ACTION_CAST(0));
258 #endif
259
260 QEQueueCtr nFree = m_eQueue.m_nFree; // get volatile into temporary
261
262 // test-probe#1 for faking queue overflow
265 nFree = 0U;
266 )
267
268 Q_REQUIRE_INCRIT(201, nFree != 0U);
269
270 if (e->getPoolNum_() != 0U) { // is it a mutable event?
271 QEvt_refCtr_inc_(e); // increment the reference counter
272 }
273
274 --nFree; // one free entry just used up
275 m_eQueue.m_nFree = nFree; // update the original
276 if (m_eQueue.m_nMin > nFree) {
277 m_eQueue.m_nMin = nFree; // update minimum so far
278 }
279
280 QS_BEGIN_PRE_(QS_QF_ACTIVE_POST_LIFO, m_prio)
281 QS_TIME_PRE_(); // timestamp
282 QS_SIG_PRE_(e->sig); // the signal of this event
283 QS_OBJ_PRE_(this); // this active object
284 QS_2U8_PRE_(e->getPoolNum_(), e->refCtr_); // poolNum & refCtr
285 QS_EQC_PRE_(nFree); // # free entries
286 QS_EQC_PRE_(m_eQueue.m_nMin); // min # free entries
287 QS_END_PRE_()
288
289 #ifdef Q_UTEST
290 // callback to examine the posted event under the same conditions
291 // as producing the #QS_QF_ACTIVE_POST trace record, which are:
292 // the local filter for this AO ('m_prio') is set
293 if (QS_LOC_CHECK_(m_prio)) {
294 QF_MEM_APP();
295 QF_CRIT_EXIT();
296
297 QS::onTestPost(nullptr, this, e, true);
298
300 QF_MEM_SYS();
301 }
302 #endif
303
304 QEvt const * const frontEvt = m_eQueue.m_frontEvt;
305 m_eQueue.m_frontEvt = e; // deliver the event directly to the front
306
307 if (frontEvt == nullptr) { // was the queue empty?
308 QACTIVE_EQUEUE_SIGNAL_(this); // signal the event queue
309 }
310 else { // queue was not empty, leave the event in the ring-buffer
311 m_eQueue.m_tail = (m_eQueue.m_tail + 1U);
312 if (m_eQueue.m_tail == m_eQueue.m_end) { // need to wrap the tail?
313 m_eQueue.m_tail = 0U; // wrap around
314 }
315
316 m_eQueue.m_ring[m_eQueue.m_tail] = frontEvt;
317 }
318
319 QF_MEM_APP();
320 QF_CRIT_EXIT();
321}
322
323} // namespace QP
324//$enddef${QF::QActive::postLIFO} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
325
326//$define${QF::QActive::get_} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
327namespace QP {
328
329//${QF::QActive::get_} .......................................................
330QEvt const * QActive::get_() noexcept {
333 QF_MEM_SYS();
334
335 QACTIVE_EQUEUE_WAIT_(this); // wait for event to arrive directly
336
337 // always remove evt from the front
338 QEvt const * const e = m_eQueue.m_frontEvt;
340
341 QEQueueCtr const nFree = m_eQueue.m_nFree + 1U; // get volatile into tmp
342 m_eQueue.m_nFree = nFree; // update the # free
343
344 if (nFree <= m_eQueue.m_end) { // any events in the ring buffer?
345 // remove event from the tail
346 m_eQueue.m_frontEvt = m_eQueue.m_ring[m_eQueue.m_tail];
347 if (m_eQueue.m_tail == 0U) { // need to wrap the tail?
348 m_eQueue.m_tail = m_eQueue.m_end; // wrap around
349 }
350 m_eQueue.m_tail = (m_eQueue.m_tail - 1U);
351
352 QS_BEGIN_PRE_(QS_QF_ACTIVE_GET, m_prio)
353 QS_TIME_PRE_(); // timestamp
354 QS_SIG_PRE_(e->sig); // the signal of this event
355 QS_OBJ_PRE_(this); // this active object
356 QS_2U8_PRE_(e->getPoolNum_(), e->refCtr_); // poolNum & refCtr
357 QS_EQC_PRE_(nFree); // # free entries
358 QS_END_PRE_()
359 }
360 else {
361 m_eQueue.m_frontEvt = nullptr; // the queue becomes empty
362
363 // all entries in the queue must be free (+1 for fronEvt)
364 Q_ASSERT_INCRIT(310, nFree == (m_eQueue.m_end + 1U));
365
366 QS_BEGIN_PRE_(QS_QF_ACTIVE_GET_LAST, m_prio)
367 QS_TIME_PRE_(); // timestamp
368 QS_SIG_PRE_(e->sig); // the signal of this event
369 QS_OBJ_PRE_(this); // this active object
370 QS_2U8_PRE_(e->getPoolNum_(), e->refCtr_); // poolNum & refCtr
371 QS_END_PRE_()
372 }
373
374 QF_MEM_APP();
375 QF_CRIT_EXIT();
376
377 return e;
378}
379
380} // namespace QP
381//$enddef${QF::QActive::get_} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
382
383//$define${QF::QTicker} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
384namespace QP {
385
386//${QF::QTicker} .............................................................
387
388//${QF::QTicker::QTicker} ....................................................
389QTicker::QTicker(std::uint_fast8_t const tickRate) noexcept
390: QActive(nullptr)
391{
392 // reuse m_head for tick-rate
393 m_eQueue.m_head = static_cast<QEQueueCtr>(tickRate);
394}
395
396//${QF::QTicker::init} .......................................................
398 void const * const e,
399 std::uint_fast8_t const qsId)
400{
401 Q_UNUSED_PAR(e);
402 Q_UNUSED_PAR(qsId);
403
406 QF_MEM_SYS();
407
408 m_eQueue.m_tail = 0U;
409
410 QF_MEM_APP();
411 QF_CRIT_EXIT();
412}
413
414//${QF::QTicker::dispatch} ...................................................
416 QEvt const * const e,
417 std::uint_fast8_t const qsId)
418{
419 Q_UNUSED_PAR(e);
420 Q_UNUSED_PAR(qsId);
421
424 QF_MEM_SYS();
425
426 QEQueueCtr nTicks = m_eQueue.m_tail; // save # of ticks
427 m_eQueue.m_tail = 0U; // clear the # ticks
428
429 QF_MEM_APP();
430 QF_CRIT_EXIT();
431
432 for (; nTicks > 0U; --nTicks) {
433 QTimeEvt::tick(static_cast<std::uint_fast8_t>(m_eQueue.m_head),
434 this);
435 }
436}
437
438//${QF::QTicker::trig_} ......................................................
439void QTicker::trig_(void const * const sender) noexcept {
440 #ifndef Q_SPY
441 Q_UNUSED_PAR(sender);
442 #endif
443
446 QF_MEM_SYS();
447
448 if (m_eQueue.m_frontEvt == nullptr) {
449
450 static QEvt const tickEvt(0U); // immutable event
451
452 m_eQueue.m_frontEvt = &tickEvt; // deliver event directly
453 m_eQueue.m_nFree = (m_eQueue.m_nFree - 1U); // one less free event
454
455 QACTIVE_EQUEUE_SIGNAL_(this); // signal the event queue
456 }
457
458 // account for one more tick event
459 m_eQueue.m_tail = (m_eQueue.m_tail + 1U);
460
461 QS_BEGIN_PRE_(QS_QF_ACTIVE_POST, m_prio)
462 QS_TIME_PRE_(); // timestamp
463 QS_OBJ_PRE_(sender); // the sender object
464 QS_SIG_PRE_(0U); // the signal of the event
465 QS_OBJ_PRE_(this); // this active object
466 QS_2U8_PRE_(0U, 0U); // poolNum & refCtr
467 QS_EQC_PRE_(0U); // # free entries
468 QS_EQC_PRE_(0U); // min # free entries
469 QS_END_PRE_()
470
471 QF_MEM_APP();
472 QF_CRIT_EXIT();
473}
474
475} // namespace QP
476//$enddef${QF::QTicker} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Dummy Active Object for testing.
Definition qs.hpp:844
void fakePostLIFO(QEvt const *const e) noexcept
Definition qutest.cpp:544
Active object class (based on the QHsm implementation strategy)
Definition qp.hpp:722
friend class QTicker
Definition qp.hpp:754
bool post_(QEvt const *const e, std::uint_fast16_t const margin, void const *const sender) noexcept
Definition qf_actq.cpp:71
QACTIVE_EQUEUE_TYPE m_eQueue
Definition qp.hpp:736
QEvt const * get_() noexcept
Definition qf_actq.cpp:330
void postLIFO(QEvt const *const e) noexcept
Definition qf_actq.cpp:235
std::uint8_t m_prio
Definition qp.hpp:724
Event class.
Definition qp.hpp:137
QSignal sig
Definition qp.hpp:139
std::uint8_t volatile refCtr_
Definition qp.hpp:140
std::uint_fast8_t getPoolNum_() const noexcept
Definition qp.hpp:165
static bool verify_(QEvt const *const e) noexcept
Definition qp.hpp:161
void trig_(void const *const sender) noexcept
Definition qf_actq.cpp:439
void dispatch(QEvt const *const e, std::uint_fast8_t const qsId) override
Definition qf_actq.cpp:415
void init(void const *const e, std::uint_fast8_t const qsId) override
Definition qf_actq.cpp:397
static void tick(std::uint_fast8_t const tickRate, void const *const sender) noexcept
Definition qf_time.cpp:280
void gc(QEvt const *const e) noexcept
Definition qf_dyn.cpp:222
constexpr std::uint_fast16_t NO_MARGIN
Definition qp.hpp:1095
void onTestPost(void const *sender, QActive *recipient, QEvt const *e, bool status)
QP/C++ framework.
Definition qequeue.hpp:50
void QEvt_refCtr_inc_(QEvt const *const e) noexcept
Definition qp_pkg.hpp:92
std::uint16_t QEQueueCtr
Definition qequeue.hpp:55
@ QS_QF_ACTIVE_GET_LAST
AO got an event and its queue is empty.
Definition qs.hpp:92
@ QS_QF_ACTIVE_POST_ATTEMPT
attempt to post an evt to AO failed
Definition qs.hpp:134
@ QS_QF_ACTIVE_POST_LIFO
an event was posted (LIFO) directly to AO
Definition qs.hpp:90
@ QS_QF_ACTIVE_GET
AO got an event and its queue is not empty.
Definition qs.hpp:91
@ QS_QF_ACTIVE_POST
an event was posted (FIFO) directly to AO
Definition qs.hpp:89
#define QACTIVE_EQUEUE_SIGNAL_(me_)
Definition qk.hpp:148
#define QACTIVE_EQUEUE_WAIT_(me_)
Definition qk.hpp:143
#define QF_MEM_APP()
Definition qp.hpp:1331
#define Q_UNUSED_PAR(par_)
Definition qp.hpp:539
#define Q_STATE_CAST(handler_)
Definition qp.hpp:491
#define QF_MEM_SYS()
Definition qp.hpp:1326
Internal (package scope) QP/C++ interface.
#define Q_ACTION_CAST(act_)
Definition qp_pkg.hpp:82
Sample QP/C++ port.
#define QS_TIME_PRE_()
Definition qs.hpp:473
#define QS_TEST_PROBE_DEF(fun_)
Definition qs.hpp:870
#define QS_TEST_PROBE_ID(id_, code_)
Definition qs.hpp:877
#define QS_LOC_CHECK_(qsId_)
Definition qs.hpp:384
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_INVARIANT_INCRIT(id_, expr_)
Definition qsafe.h:154
#define QF_CRIT_EXIT()
Definition qsafe.h:62
#define Q_REQUIRE_INCRIT(id_, expr_)
Definition qsafe.h:136
#define Q_ERROR_INCRIT(id_)
Definition qsafe.h:76
#define QF_CRIT_STAT
Definition qsafe.h:54
#define QXTHREAD_EQUEUE_SIGNAL_(me_)
Definition qxk.hpp:277