QP/C  7.4.0-rc.3
Real-Time Embedded Framework
Loading...
Searching...
No Matches
qep_hsm.c
Go to the documentation of this file.
1//$file${src::qf::qep_hsm.c} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2//
3// Model: qpc.qm
4// File: ${src::qf::qep_hsm.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::qep_hsm.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("qep_hsm")
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${QEP::QP_versionStr[16]} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
63
64//${QEP::QP_versionStr[16]} ..................................................
65char const QP_versionStr[16] = QP_VERSION_STR;
66//$enddef${QEP::QP_versionStr[16]} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
67
68//============================================================================
69//! @cond INTERNAL
70
71//$define${QEP::QEvt::reserved_[4]} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
72QEvt const QEvt_reserved_[4] = {
77};
78
79//$enddef${QEP::QEvt::reserved_[4]} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
80
81// helper macro to handle reserved event in an QHsm
82#define QHSM_RESERVED_EVT_(state_, sig_) \
83 ((*(state_))(me, &QEvt_reserved_[(sig_)]))
84
85// helper macro to trace state entry
86#define QS_STATE_ENTRY_(state_, qsId_) \
87 QS_CRIT_ENTRY(); \
88 QS_MEM_SYS(); \
89 QS_BEGIN_PRE_(QS_QEP_STATE_ENTRY, (qsId_)) \
90 QS_OBJ_PRE_(me); \
91 QS_FUN_PRE_(state_); \
92 QS_END_PRE_() \
93 QS_MEM_APP(); \
94 QS_CRIT_EXIT()
95
96// helper macro to trace state exit
97#define QS_STATE_EXIT_(state_, qsId_) \
98 QS_CRIT_ENTRY(); \
99 QS_MEM_SYS(); \
100 QS_BEGIN_PRE_(QS_QEP_STATE_EXIT, (qsId_)) \
101 QS_OBJ_PRE_(me); \
102 QS_FUN_PRE_(state_); \
103 QS_END_PRE_() \
104 QS_MEM_APP(); \
105 QS_CRIT_EXIT()
106
107//! @endcond
108
109enum {
110 // maximum depth of state nesting in a QHsm (including the top level),
111 // must be >= 3
112 QHSM_MAX_NEST_DEPTH_ = 6
113};
114
115//$define${QEP::QHsm} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
116
117//${QEP::QHsm} ...............................................................
118
119//${QEP::QHsm::ctor} .........................................................
120//! @protected @memberof QHsm
121void QHsm_ctor(QHsm * const me,
122 QStateHandler const initial)
123{
124 static struct QAsmVtable const vtable = { // QAsm virtual table
125 &QHsm_init_,
126 &QHsm_dispatch_,
127 &QHsm_isIn_
128 #ifdef Q_SPY
129 ,&QHsm_getStateHandler_
130 #endif
131 };
132 // do not call the QAsm_ctor() here
133 me->super.vptr = &vtable;
134 me->super.state.fun = Q_STATE_CAST(&QHsm_top);
135 me->super.temp.fun = initial;
136}
137
138//${QEP::QHsm::init_} ........................................................
139//! @private @memberof QHsm
140void QHsm_init_(
141 QAsm * const me,
142 void const * const e,
143 uint_fast8_t const qsId)
144{
146
147 #ifdef Q_SPY
149 QS_MEM_SYS();
150 if ((QS_priv_.flags & 0x01U) == 0U) {
151 QS_priv_.flags |= 0x01U;
152 QS_MEM_APP();
153 QS_CRIT_EXIT();
154 QS_FUN_DICTIONARY(&QHsm_top);
155 }
156 else {
157 QS_MEM_APP();
158 QS_CRIT_EXIT();
159 }
160 #else
161 Q_UNUSED_PAR(qsId);
162 #endif
163
164 QStateHandler t = me->state.fun;
165
167 Q_REQUIRE_INCRIT(200, (me->vptr != (struct QAsmVtable *)0)
168 && (me->temp.fun != Q_STATE_CAST(0))
169 && (t == Q_STATE_CAST(&QHsm_top)));
170 QF_CRIT_EXIT();
171
172 // execute the top-most initial tran.
173 QState r = (*me->temp.fun)(me, Q_EVT_CAST(QEvt));
174
176 // the top-most initial tran. must be taken
177 Q_ASSERT_INCRIT(210, r == Q_RET_TRAN);
178
179 QS_MEM_SYS();
180 QS_BEGIN_PRE_(QS_QEP_STATE_INIT, qsId)
181 QS_OBJ_PRE_(me); // this state machine object
182 QS_FUN_PRE_(t); // the source state
183 QS_FUN_PRE_(me->temp.fun); // the target of the initial tran.
184 QS_END_PRE_()
185 QS_MEM_APP();
186
187 QF_CRIT_EXIT();
188
189 // drill down into the state hierarchy with initial transitions...
190 do {
191 QStateHandler path[QHSM_MAX_NEST_DEPTH_]; // tran. entry path array
192 int_fast8_t ip = 0; // tran. entry path index
193
194 path[0] = me->temp.fun;
195 (void)QHSM_RESERVED_EVT_(me->temp.fun, Q_EMPTY_SIG);
196 // note: ip is the fixed upper loop bound
197 while ((me->temp.fun != t) && (ip < (QHSM_MAX_NEST_DEPTH_ - 1))) {
198 ++ip;
199 path[ip] = me->temp.fun;
200 (void)QHSM_RESERVED_EVT_(me->temp.fun, Q_EMPTY_SIG);
201 }
203 // too many state nesting levels or "malformed" HSM
204 Q_ENSURE_INCRIT(220, ip < QHSM_MAX_NEST_DEPTH_);
205 QF_CRIT_EXIT();
206
207 me->temp.fun = path[0];
208
209 // retrace the entry path in reverse (desired) order...
210 // note: ip is the fixed upper loop bound
211 do {
212 // enter path[ip]
213 if (QHSM_RESERVED_EVT_(path[ip], Q_ENTRY_SIG)
214 == Q_RET_HANDLED)
215 {
216 QS_STATE_ENTRY_(path[ip], qsId);
217 }
218 --ip;
219 } while (ip >= 0);
220
221 t = path[0]; // current state becomes the new source
222
223 r = QHSM_RESERVED_EVT_(t, Q_INIT_SIG); // execute initial tran.
224
225 #ifdef Q_SPY
226 if (r == Q_RET_TRAN) {
228 QS_MEM_SYS();
229 QS_BEGIN_PRE_(QS_QEP_STATE_INIT, qsId)
230 QS_OBJ_PRE_(me); // this state machine object
231 QS_FUN_PRE_(t); // the source state
232 QS_FUN_PRE_(me->temp.fun); // the target of the initial tran.
233 QS_END_PRE_()
234 QS_MEM_APP();
235 QS_CRIT_EXIT();
236 }
237 #endif // Q_SPY
238 } while (r == Q_RET_TRAN);
239
241
242 QS_MEM_SYS();
243 QS_BEGIN_PRE_(QS_QEP_INIT_TRAN, qsId)
244 QS_TIME_PRE_(); // time stamp
245 QS_OBJ_PRE_(me); // this state machine object
246 QS_FUN_PRE_(t); // the new active state
247 QS_END_PRE_()
248 QS_MEM_APP();
249
250 QF_CRIT_EXIT();
251
252 me->state.fun = t; // change the current active state
253 #ifndef Q_UNSAFE
254 me->temp.uint = ~me->state.uint;
255 #endif
256}
257
258//${QEP::QHsm::dispatch_} ....................................................
259//! @private @memberof QHsm
260void QHsm_dispatch_(
261 QAsm * const me,
262 QEvt const * const e,
263 uint_fast8_t const qsId)
264{
265 #ifndef Q_SPY
266 Q_UNUSED_PAR(qsId);
267 #endif
268
269 QStateHandler s = me->state.fun;
270 QStateHandler t = s;
272
274 Q_REQUIRE_INCRIT(300, QEvt_verify_(e));
275 Q_INVARIANT_INCRIT(302, (s != Q_STATE_CAST(0))
276 && (me->state.uint == (uintptr_t)(~me->temp.uint)));
277
278 QS_MEM_SYS();
279 QS_BEGIN_PRE_(QS_QEP_DISPATCH, qsId)
280 QS_TIME_PRE_(); // time stamp
281 QS_SIG_PRE_(e->sig); // the signal of the event
282 QS_OBJ_PRE_(me); // this state machine object
283 QS_FUN_PRE_(s); // the current state
284 QS_END_PRE_()
285 QS_MEM_APP();
286
287 QF_CRIT_EXIT();
288
289 // process the event hierarchically...
290 QState r;
291 me->temp.fun = s;
292 int_fast8_t ip = QHSM_MAX_NEST_DEPTH_; // fixed upper loop bound
293 do {
294 s = me->temp.fun;
295 r = (*s)(me, e); // invoke state handler s
296
297 if (r == Q_RET_UNHANDLED) { // unhandled due to a guard?
298
300 QS_MEM_SYS();
301 QS_BEGIN_PRE_(QS_QEP_UNHANDLED, qsId)
302 QS_SIG_PRE_(e->sig); // the signal of the event
303 QS_OBJ_PRE_(me); // this state machine object
304 QS_FUN_PRE_(s); // the current state
305 QS_END_PRE_()
306 QS_MEM_APP();
307 QS_CRIT_EXIT();
308
309 r = QHSM_RESERVED_EVT_(s, Q_EMPTY_SIG); // superstate of s
310 }
311
312 --ip;
313 } while ((r == Q_RET_SUPER) && (ip > 0));
314
316 Q_ENSURE_INCRIT(310, ip > 0);
317 QF_CRIT_EXIT();
318
319 if (r >= Q_RET_TRAN) { // regular tran. taken?
320 QStateHandler path[QHSM_MAX_NEST_DEPTH_];
321
322 path[0] = me->temp.fun; // tran. target
323 path[1] = t; // current state
324 path[2] = s; // tran. source
325
326 // exit current state to tran. source s...
327 ip = QHSM_MAX_NEST_DEPTH_; // fixed upper loop bound
328 for (; (t != s) && (ip > 0); t = me->temp.fun) {
329 // exit from t
330 if (QHSM_RESERVED_EVT_(t, Q_EXIT_SIG) == Q_RET_HANDLED) {
331 QS_STATE_EXIT_(t, qsId);
332 // find superstate of t
333 (void)QHSM_RESERVED_EVT_(t, Q_EMPTY_SIG);
334 }
335 --ip;
336 }
338 Q_ENSURE_INCRIT(320, ip > 0);
339 QF_CRIT_EXIT();
340
341 ip = QHsm_tran_(me, path, qsId); // take the tran.
342
343 #ifdef Q_SPY
344 if (r == Q_RET_TRAN_HIST) {
346 QS_MEM_SYS();
347 QS_BEGIN_PRE_(QS_QEP_TRAN_HIST, qsId)
348 QS_OBJ_PRE_(me); // this state machine object
349 QS_FUN_PRE_(t); // the source of the tran.
350 QS_FUN_PRE_(path[0]); // the target of the tran. to history
351 QS_END_PRE_()
352 QS_MEM_APP();
353 QS_CRIT_EXIT();
354 }
355 #endif // Q_SPY
356
357 // execute state entry actions in the desired order...
358 // note: ip is the fixed upper loop bound
359 for (; ip >= 0; --ip) {
360 // enter path[ip]
361 if (QHSM_RESERVED_EVT_(path[ip], Q_ENTRY_SIG)
362 == Q_RET_HANDLED)
363 {
364 QS_STATE_ENTRY_(path[ip], qsId);
365 }
366 }
367 t = path[0]; // stick the target into register
368 me->temp.fun = t; // update the next state
369
370 // drill into the target hierarchy...
371 while (QHSM_RESERVED_EVT_(t, Q_INIT_SIG) == Q_RET_TRAN) {
372
374 QS_MEM_SYS();
375 QS_BEGIN_PRE_(QS_QEP_STATE_INIT, qsId)
376 QS_OBJ_PRE_(me); // this state machine object
377 QS_FUN_PRE_(t); // the source (pseudo)state
378 QS_FUN_PRE_(me->temp.fun); // the target of the tran.
379 QS_END_PRE_()
380 QS_MEM_APP();
381 QS_CRIT_EXIT();
382
383 ip = 0;
384 path[0] = me->temp.fun;
385
386 // find superstate
387 (void)QHSM_RESERVED_EVT_(me->temp.fun, Q_EMPTY_SIG);
388
389 // note: ip is the fixed upper loop bound
390 while ((me->temp.fun != t) && (ip < (QHSM_MAX_NEST_DEPTH_ - 1))) {
391 ++ip;
392 path[ip] = me->temp.fun;
393 // find superstate
394 (void)QHSM_RESERVED_EVT_(me->temp.fun, Q_EMPTY_SIG);
395 }
397 // too many state nesting levels or "malformed" HSM
398 Q_ENSURE_INCRIT(330, ip < QHSM_MAX_NEST_DEPTH_);
399 QF_CRIT_EXIT();
400
401 me->temp.fun = path[0];
402
403 // retrace the entry path in reverse (correct) order...
404 // note: ip is the fixed upper loop bound
405 do {
406 // enter path[ip]
407 if (QHSM_RESERVED_EVT_(path[ip], Q_ENTRY_SIG)
408 == Q_RET_HANDLED)
409 {
410 QS_STATE_ENTRY_(path[ip], qsId);
411 }
412 --ip;
413 } while (ip >= 0);
414
415 t = path[0]; // current state becomes the new source
416 }
417
419 QS_MEM_SYS();
420 QS_BEGIN_PRE_(QS_QEP_TRAN, qsId)
421 QS_TIME_PRE_(); // time stamp
422 QS_SIG_PRE_(e->sig); // the signal of the event
423 QS_OBJ_PRE_(me); // this state machine object
424 QS_FUN_PRE_(s); // the source of the tran.
425 QS_FUN_PRE_(t); // the new active state
426 QS_END_PRE_()
427 QS_MEM_APP();
428 QS_CRIT_EXIT();
429 }
430
431 #ifdef Q_SPY
432 else if (r == Q_RET_HANDLED) {
434 QS_MEM_SYS();
435 QS_BEGIN_PRE_(QS_QEP_INTERN_TRAN, qsId)
436 QS_TIME_PRE_(); // time stamp
437 QS_SIG_PRE_(e->sig); // the signal of the event
438 QS_OBJ_PRE_(me); // this state machine object
439 QS_FUN_PRE_(s); // the source state
440 QS_END_PRE_()
441 QS_MEM_APP();
442 QS_CRIT_EXIT();
443 }
444 else {
446 QS_MEM_SYS();
447 QS_BEGIN_PRE_(QS_QEP_IGNORED, qsId)
448 QS_TIME_PRE_(); // time stamp
449 QS_SIG_PRE_(e->sig); // the signal of the event
450 QS_OBJ_PRE_(me); // this state machine object
451 QS_FUN_PRE_(me->state.fun); // the current state
452 QS_END_PRE_()
453 QS_MEM_APP();
454 QS_CRIT_EXIT();
455 }
456 #endif // Q_SPY
457
458 me->state.fun = t; // change the current active state
459 #ifndef Q_UNSAFE
460 me->temp.uint = ~me->state.uint;
461 #endif
462}
463
464//${QEP::QHsm::getStateHandler_} .............................................
465#ifdef Q_SPY
466//! @private @memberof QHsm
467QStateHandler QHsm_getStateHandler_(QAsm * const me) {
468 return me->state.fun;
469}
470#endif // def Q_SPY
471
472//${QEP::QHsm::isIn_} ........................................................
473//! @private @memberof QHsm
474bool QHsm_isIn_(
475 QAsm * const me,
476 QStateHandler const state)
477{
481 == (uintptr_t)(~me->temp.uint));
482 QF_CRIT_EXIT();
483
484 bool inState = false; // assume that this HSM is not in 'state'
485
486 // scan the state hierarchy bottom-up
487 QStateHandler s = me->state.fun;
488 int_fast8_t lbound = QHSM_MAX_NEST_DEPTH_ + 1; // fixed upper loop bound
490 for (; (r != Q_RET_IGNORED) && (lbound > 0); --lbound) {
491 if (s == state) { // do the states match?
492 inState = true; // 'true' means that match found
493 break; // break out of the for-loop
494 }
495 else {
496 r = QHSM_RESERVED_EVT_(s, Q_EMPTY_SIG);
497 s = me->temp.fun;
498 }
499 }
500
502 Q_ENSURE_INCRIT(690, lbound > 0);
503 QF_CRIT_EXIT();
504
505 #ifndef Q_UNSAFE
506 me->temp.uint = ~me->state.uint;
507 #endif
508
509 return inState; // return the status
510}
511
512//${QEP::QHsm::childState} ...................................................
513//! @public @memberof QHsm
514QStateHandler QHsm_childState(QHsm * const me,
515 QStateHandler const parent)
516{
517 QStateHandler child = me->super.state.fun; // start with current state
518 bool isFound = false; // start with the child not found
519
520 // establish stable state configuration
521 me->super.temp.fun = child;
522 QState r;
523 int_fast8_t lbound = QHSM_MAX_NEST_DEPTH_; // fixed upper loop bound
524 do {
525 // is this the parent of the current child?
526 if (me->super.temp.fun == parent) {
527 isFound = true; // child is found
528 r = Q_RET_IGNORED; // break out of the loop
529 }
530 else {
531 child = me->super.temp.fun;
532 r = QHSM_RESERVED_EVT_(me->super.temp.fun, Q_EMPTY_SIG);
533 }
534 --lbound;
535 } while ((r != Q_RET_IGNORED) // the top state not reached
536 && (lbound > 0));
537
538 #ifndef Q_UNSAFE
539 me->super.temp.uint = ~me->super.state.uint;
540 #else
541 Q_UNUSED_PAR(isFound);
542 #endif
543
546 // NOTE: the following postcondition can only succeed when
547 // (lbound > 0), so no extra check is necessary.
548 Q_ENSURE_INCRIT(890, isFound);
549 QF_CRIT_EXIT();
550
551 return child;
552}
553
554//${QEP::QHsm::tran_} ........................................................
555//! @private @memberof QHsm
556int_fast8_t QHsm_tran_(
557 QAsm * const me,
558 QStateHandler * const path,
559 uint_fast8_t const qsId)
560{
561 #ifndef Q_SPY
562 Q_UNUSED_PAR(qsId);
563 #endif
564
565 int_fast8_t ip = -1; // tran. entry path index
566 QStateHandler t = path[0];
567 QStateHandler const s = path[2];
569
570 // (a) check source==target (tran. to self)...
571 if (s == t) {
572 // exit source s
573 if (QHSM_RESERVED_EVT_(s, Q_EXIT_SIG) == Q_RET_HANDLED) {
574 QS_STATE_EXIT_(s, qsId);
575 }
576 ip = 0; // enter the target
577 }
578 else {
579 // find superstate of target
580 (void)QHSM_RESERVED_EVT_(t, Q_EMPTY_SIG);
581
582 t = me->temp.fun;
583
584 // (b) check source==target->super...
585 if (s == t) {
586 ip = 0; // enter the target
587 }
588 else {
589 // find superstate of src
590 (void)QHSM_RESERVED_EVT_(s, Q_EMPTY_SIG);
591
592 // (c) check source->super==target->super...
593 if (me->temp.fun == t) {
594 // exit source s
595 if (QHSM_RESERVED_EVT_(s, Q_EXIT_SIG) == Q_RET_HANDLED) {
596 QS_STATE_EXIT_(s, qsId);
597 }
598 ip = 0; // enter the target
599 }
600 else {
601 // (d) check source->super==target...
602 if (me->temp.fun == path[0]) {
603 // exit source s
604 if (QHSM_RESERVED_EVT_(s, Q_EXIT_SIG) == Q_RET_HANDLED) {
605 QS_STATE_EXIT_(s, qsId);
606 }
607 }
608 else {
609 // (e) check rest of source==target->super->super..
610 // and store the entry path along the way
611 int_fast8_t iq = 0; // indicate that LCA was found
612 ip = 1; // enter target and its superstate
613 path[1] = t; // save the superstate of target
614 t = me->temp.fun; // save source->super
615
616 // find target->super->super...
617 // note: ip is the fixed upper loop bound
618 QState r = QHSM_RESERVED_EVT_(path[1], Q_EMPTY_SIG);
619 while ((r == Q_RET_SUPER)
620 && (ip < (QHSM_MAX_NEST_DEPTH_ - 1)))
621 {
622 ++ip;
623 path[ip] = me->temp.fun; // store the entry path
624 if (me->temp.fun == s) { // is it the source?
625 iq = 1; // indicate that the LCA found
626 --ip; // do not enter the source
627 r = Q_RET_HANDLED; // terminate the loop
628 }
629 else { // it is not the source, keep going up
630 r = QHSM_RESERVED_EVT_(me->temp.fun, Q_EMPTY_SIG);
631 }
632 }
634 // NOTE: The following postcondition succeeds only when
635 // ip < QHSM_MAX_NEST_DEPTH, so no additional check is necessary
636 // too many state nesting levels or "malformed" HSM.
637 Q_ENSURE_INCRIT(510, r != Q_RET_SUPER);
638 QF_CRIT_EXIT();
639
640 // the LCA not found yet?
641 if (iq == 0) {
642 // exit source s
643 if (QHSM_RESERVED_EVT_(s, Q_EXIT_SIG)
644 == Q_RET_HANDLED)
645 {
646 QS_STATE_EXIT_(s, qsId);
647 }
648
649 // (f) check the rest of source->super
650 // == target->super->super...
651 iq = ip;
652 r = Q_RET_IGNORED; // indicate that the LCA NOT found
653 // note: iq is the fixed upper loop bound
654 do {
655 if (t == path[iq]) { // is this the LCA?
656 r = Q_RET_HANDLED; // indicate the LCA found
657 ip = iq - 1; // do not enter the LCA
658 iq = -1; // cause termination of the loop
659 }
660 else {
661 --iq; // try lower superstate of target
662 }
663 } while (iq >= 0);
664
665 // the LCA not found yet?
666 if (r != Q_RET_HANDLED) {
667 // (g) check each source->super->...
668 // for each target->super...
669 r = Q_RET_IGNORED; // keep looping
670 int_fast8_t lbound = QHSM_MAX_NEST_DEPTH_;
671 do {
672 // exit from t
673 if (QHSM_RESERVED_EVT_(t, Q_EXIT_SIG)
674 == Q_RET_HANDLED)
675 {
676 QS_STATE_EXIT_(t, qsId);
677 // find superstate of t
678 (void)QHSM_RESERVED_EVT_(t, Q_EMPTY_SIG);
679 }
680 t = me->temp.fun; // set to super of t
681 iq = ip;
682 do {
683 // is this the LCA?
684 if (t == path[iq]) {
685 ip = iq - 1; // do not enter the LCA
686 iq = -1; // break out of inner loop
687 r = Q_RET_HANDLED; // break outer loop
688 }
689 else {
690 --iq;
691 }
692 } while (iq >= 0);
693
694 --lbound;
695 } while ((r != Q_RET_HANDLED) && (lbound > 0));
697 Q_ENSURE_INCRIT(530, lbound > 0);
698 QF_CRIT_EXIT();
699 }
700 }
701 }
702 }
703 }
704 }
706 Q_ENSURE_INCRIT(590, ip < QHSM_MAX_NEST_DEPTH_);
707 QF_CRIT_EXIT();
708 return ip;
709}
710
711//${QEP::QHsm::top} ..........................................................
712//! @protected @memberof QAsm
713QState QHsm_top(QHsm const * const me,
714 QEvt const * const e)
715{
716 Q_UNUSED_PAR(me);
717 Q_UNUSED_PAR(e);
718 return Q_RET_IGNORED; // the top state ignores all events
719}
720//$enddef${QEP::QHsm} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ Q_RET_HANDLED
event handled (internal transition)
Definition qp.h:205
@ Q_RET_IGNORED
event silently ignored (bubbled up to top)
Definition qp.h:206
@ Q_RET_TRAN
regular transition
Definition qp.h:216
@ Q_RET_UNHANDLED
event unhandled due to a guard
Definition qp.h:202
@ Q_RET_SUPER
event passed to superstate to handle
Definition qp.h:200
@ Q_RET_TRAN_HIST
transition to history of a given state
Definition qp.h:221
QEvt const QEvt_reserved_[4]
char const QP_versionStr[16]
the current QP version number string in ROM, based on QP_VERSION_STR
#define Q_UNUSED_PAR(par_)
Helper macro to clearly mark unused parameters of functions.
Definition qp.h:536
#define QP_VERSION_STR
Version string complying with Semantic Versioning
Definition qp.h:47
#define Q_STATE_CAST(handler_)
Perform cast to QStateHandler.
Definition qp.h:530
QState(* QStateHandler)(void *const me, QEvt const *const e)
Pointer to a state-handler function.
Definition qp.h:229
enum QStateRet QState
Type returned from state-handler functions.
Definition qp.h:226
#define Q_EVT_CAST(class_)
Perform downcast of an event onto a subclass of QEvt class_
Definition qp.h:527
@ Q_INIT_SIG
signal for coding initial transitions
Definition qp.h:262
@ Q_EMPTY_SIG
signal to execute the default case
Definition qp.h:259
@ Q_EXIT_SIG
signal for coding exit actions
Definition qp.h:261
@ Q_ENTRY_SIG
signal for coding entry actions
Definition qp.h:260
#define QEVT_INITIALIZER(sig_)
Initializer for immutable (constant) QEvt instances.
Definition qp.h:459
Internal (package scope) QP/C interface.
Sample QP/C port.
@ QS_QEP_STATE_INIT
an initial transition was taken in a state
Definition qs.h:84
@ QS_QEP_TRAN_HIST
a tran. to history was taken
Definition qs.h:162
#define QS_TIME_PRE_()
Definition qs.h:450
#define QS_FUN_DICTIONARY(fun_)
Definition qs.h:517
@ QS_QEP_INIT_TRAN
the top-most initial transition was taken
Definition qs.h:85
#define QS_MEM_APP()
Definition qs.h:588
@ QS_QEP_INTERN_TRAN
an internal transition was taken
Definition qs.h:86
@ QS_QEP_UNHANDLED
an event was un-handled due to a guard
Definition qs.h:90
@ QS_QEP_TRAN
a regular transition was taken
Definition qs.h:87
@ QS_QEP_DISPATCH
an event was dispatched (begin of RTC step)
Definition qs.h:89
@ QS_QEP_IGNORED
an event was ignored (silently discarded)
Definition qs.h:88
#define QS_CRIT_EXIT()
Definition qs.h:578
#define QS_MEM_SYS()
Definition qs.h:583
#define QS_CRIT_ENTRY()
Definition qs.h:573
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
Abstract State Machine class (state machine interface)
Definition qp.h:280
struct QAsmVtable const * vptr
Virtual pointer inherited by all QAsm subclasses (see also Object Orientation)
Definition qp.h:284
union QAsmAttr state
Current state (pointer to the current state-handler function)
Definition qp.h:289
union QAsmAttr temp
Temporary storage for target/act-table etc.
Definition qp.h:292
Virtual table for the QAsm class.
Definition qp.h:301
Event class.
Definition qp.h:145
QSignal sig
Signal of the event (see Event Signal)
Definition qp.h:149
Hierarchical State Machine class (QHsm-style state machine implementation strategy)
Definition qp.h:316
QAsm super
Definition qp.h:318
uintptr_t uint
Definition qp.h:274
QStateHandler fun
Definition qp.h:268