QP-nano  6.9.0
Real-Time Embedded Framework
qepn.c
Go to the documentation of this file.
1
40#include "qpn_conf.h" /* QP-nano configuration file (from the application) */
41#include "qfn_port.h" /* QF-nano port from the port directory */
42#include "qassert.h" /* embedded systems-friendly assertions */
43
45
46/****************************************************************************/
48
49/****************************************************************************/
50/****************************************************************************/
52#define QEP_EMPTY_SIG_ ((QSignal)0)
53
57#define QHSM_MAX_NEST_DEPTH_ ((int_fast8_t)5)
58
60static int_fast8_t QHsm_tran_(QHsm * const me,
62
63/****************************************************************************/
84void QHsm_ctor(QHsm * const me, QStateHandler initial) {
85 static QHsmVtable const vtable = { /* QHsm virtual table */
88 };
89 me->vptr = &vtable;
91 me->temp = initial;
92}
93
94/****************************************************************************/
105void QHsm_init_(QHsm * const me) {
106 QStateHandler t = me->state;
107 QState r;
108
113 Q_REQUIRE_ID(200, (me->vptr != (QHsmVtable const *)0)
114 && (me->temp != Q_STATE_CAST(0))
115 && (t == Q_STATE_CAST(&QHsm_top)));
116
117 r = (*me->temp)(me); /* execute the top-most initial transition */
118
119 /* the top-most initial transition must be taken */
120 Q_ASSERT_ID(210, r == Q_RET_TRAN);
121
122 /* drill down into the state hierarchy with initial transitions... */
123 do {
125 int_fast8_t ip = 0; /* transition entry path index */
126
127 path[0] = me->temp;
128 Q_SIG(me) = QEP_EMPTY_SIG_;
129 (void)(*me->temp)(me);
130 while (me->temp != t) {
131 ++ip;
132 Q_ASSERT_ID(220, ip < (int_fast8_t)Q_DIM(path));
133 path[ip] = me->temp;
134 (void)(*me->temp)(me);
135 }
136 me->temp = path[0];
137
138 /* retrace the entry path in reverse (desired) order... */
139 Q_SIG(me) = Q_ENTRY_SIG;
140 do {
141 (void)(*path[ip])(me); /* enter path[ip] */
142 --ip;
143 } while (ip >= 0);
144
145 t = path[0]; /* current state becomes the new source */
146
147 Q_SIG(me) = Q_INIT_SIG;
148 r = (*t)(me);
149 } while (r == Q_RET_TRAN);
150
151 me->state = t; /* change the current active state */
152 me->temp = t; /* mark the configuration as stable */
153}
154
155/****************************************************************************/
172QState QHsm_top(void const * const me) {
173 (void)me; /* suppress the "unused parameter" compiler warning */
174 return Q_RET_IGNORED; /* the top state ignores all events */
175}
176
177/****************************************************************************/
190void QHsm_dispatch_(QHsm * const me) {
191 QStateHandler t = me->state;
193 QState r;
194 int_fast8_t iq; /* helper transition entry path index */
195
199 Q_REQUIRE_ID(400, (t != Q_STATE_CAST(0))
200 && (t == me->temp));
201
202 /* process the event hierarchically... */
203 do {
204 s = me->temp;
205 r = (*s)(me); /* invoke state handler s */
206
207 if (r == Q_RET_UNHANDLED) { /* unhandled due to a guard? */
208 iq = (int_fast8_t)Q_SIG(me); /* save the original signal */
209 Q_SIG(me) = QEP_EMPTY_SIG_; /* find the superstate */
210 r = (*s)(me); /* invoke state handler s */
211 Q_SIG(me) = (QSignal)iq; /* restore the original signal */
212 }
213 } while (r == Q_RET_SUPER);
214
215 /* transition taken? */
216 if (r >= Q_RET_TRAN) {
217 QStateHandler path[QHSM_MAX_NEST_DEPTH_]; /* transition entry path */
218 int_fast8_t ip; /* transition entry path index */
219
220 path[0] = me->temp; /* save the target of the transition */
221 path[1] = t;
222 path[2] = s;
223
224 /* exit current state to transition source s... */
225 for (; t != s; t = me->temp) {
226 Q_SIG(me) = Q_EXIT_SIG; /* find superstate of t */
227
228 /* take the exit action and check if it was handled? */
229 if ((*t)(me) == Q_RET_HANDLED) {
230 Q_SIG(me) = QEP_EMPTY_SIG_;
231 (void)(*t)(me); /* find superstate of t */
232 }
233 }
234
235 ip = QHsm_tran_(me, path); /* take the state transition */
236
237 /* retrace the entry path in reverse (desired) order... */
238 Q_SIG(me) = Q_ENTRY_SIG;
239 for (; ip >= 0; --ip) {
240 (void)(*path[ip])(me); /* enter path[ip] */
241 }
242 t = path[0]; /* stick the target into register */
243 me->temp = t; /* update the current state */
244
245 /* drill into the target hierarchy... */
246 Q_SIG(me) = Q_INIT_SIG;
247 while ((*t)(me) == Q_RET_TRAN) {
248 ip = 0;
249
250 path[0] = me->temp;
251 Q_SIG(me) = QEP_EMPTY_SIG_;
252 (void)(*me->temp)(me); /* find the superstate */
253 while (me->temp != t) {
254 ++ip;
255 path[ip] = me->temp;
256 (void)(*me->temp)(me); /* find the superstate */
257 }
258 me->temp = path[0];
259
260 /* entry path must not overflow */
262
263 /* retrace the entry path in reverse (correct) order... */
264 Q_SIG(me) = Q_ENTRY_SIG;
265 do {
266 (void)(*path[ip])(me); /* enter path[ip] */
267 --ip;
268 } while (ip >= 0);
269
270 t = path[0];
271 Q_SIG(me) = Q_INIT_SIG;
272 }
273 }
274
275 me->state = t; /* change the current active state */
276 me->temp = t; /* mark the configuration as stable */
277}
278
279/****************************************************************************/
292static int_fast8_t QHsm_tran_(QHsm * const me,
294{
295 int_fast8_t ip = (int_fast8_t)(-1); /* transition entry path index */
296 int_fast8_t iq; /* helper transition entry path index */
297 QStateHandler t = path[0];
298 QStateHandler s = path[2];
299 QState r;
300
301 /* (a) check source==target (transition to self) */
302 if (s == t) {
303 Q_SIG(me) = Q_EXIT_SIG;
304 (void)(*s)(me); /* exit the source */
305 ip = 0; /* enter the target */
306 }
307 else {
308 Q_SIG(me) = QEP_EMPTY_SIG_;
309 (void)(*t)(me); /* find superstate of target */
310 t = me->temp;
311
312 /* (b) check source==target->super */
313 if (s == t) {
314 ip = 0; /* enter the target */
315 }
316 else {
317 Q_SIG(me) = QEP_EMPTY_SIG_;
318 (void)(*s)(me); /* find superstate of source */
319
320 /* (c) check source->super==target->super */
321 if (me->temp == t) {
322 Q_SIG(me) = Q_EXIT_SIG;
323 (void)(*s)(me); /* exit the source */
324 ip = 0; /* enter the target */
325 }
326 else {
327 /* (d) check source->super==target */
328 if (me->temp == path[0]) {
329 Q_SIG(me) = Q_EXIT_SIG;
330 (void)(*s)(me); /* exit the source */
331 }
332 else {
333 /* (e) check rest of source==target->super->super..
334 * and store the entry path along the way
335 */
336 iq = 0; /* indicate that LCA not found */
337 ip = 1; /* enter target and its superstate */
338 path[1] = t; /* save the superstate of target */
339 t = me->temp; /* save source->super */
340
341 /* find target->super->super... */
342 Q_SIG(me) = QEP_EMPTY_SIG_;
343 r = (*path[1])(me);
344 while (r == Q_RET_SUPER) {
345 ++ip;
346 path[ip] = me->temp; /* store the entry path */
347 if (me->temp == s) { /* is it the source? */
348 iq = 1; /* indicate that LCA found */
349
350 /* entry path must not overflow */
352 --ip; /* do not enter the source */
353 r = Q_RET_HANDLED; /* terminate loop */
354 }
355 /* it is not the source, keep going up */
356 else {
357 r = (*me->temp)(me); /* superstate of t */
358 }
359 }
360
361 /* the LCA not found yet? */
362 if (iq == 0) {
363
364 /* entry path must not overflow */
366
367 Q_SIG(me) = Q_EXIT_SIG;
368 (void)(*s)(me); /* exit the source */
369
370 /* (f) check the rest of source->super
371 * == target->super->super...
372 */
373 iq = ip;
374 r = Q_RET_IGNORED; /* LCA NOT found */
375 do {
376 if (t == path[iq]) { /* is this the LCA? */
377 r = Q_RET_HANDLED; /* LCA found */
378
379 /* do not enter LCA */
380 ip = (int_fast8_t)(iq - 1);
381 iq = -1; /* force loop termination */
382 }
383 else {
384 --iq; /* try lower superstate of target */
385 }
386 } while (iq >= 0);
387
388 /* LCA not found? */
389 if (r != Q_RET_HANDLED) {
390 /* (g) check each source->super->...
391 * for each target->super...
392 */
393 r = Q_RET_IGNORED; /* keep looping */
394 do {
395 /* exit t unhandled? */
396 Q_SIG(me) = Q_EXIT_SIG;
397 if ((*t)(me) == Q_RET_HANDLED) {
398 Q_SIG(me) = QEP_EMPTY_SIG_;
399 (void)(*t)(me); /* find super of t */
400 }
401 t = me->temp; /* set to super of t */
402 iq = ip;
403 do {
404 /* is this LCA? */
405 if (t == path[iq]) {
406 /* do not enter LCA */
407 ip = (int_fast8_t)(iq - 1);
408 iq = -1; /* break out of inner loop */
409 r = Q_RET_HANDLED; /* break */
410 }
411 else {
412 --iq;
413 }
414 } while (iq >= 0);
415 } while (r != Q_RET_HANDLED);
416 }
417 }
418 }
419 }
420 }
421 }
422 return ip;
423}
424
425/****************************************************************************/
451 QStateHandler const parent)
452{
453 QStateHandler child = me->state; /* start with the current state */
454 bool isFound = false; /* start with the child not found */
455 QState r;
456
457 /* establish stable state configuration */
458 me->temp = me->state;
459 do {
460 /* is this the parent of the current child? */
461 if (me->temp == parent) {
462 isFound = true; /* child is found */
463 r = Q_RET_IGNORED; /* break out of the loop */
464 }
465 else {
466 child = me->temp;
467 Q_SIG(me) = QEP_EMPTY_SIG_;
468 r = (*me->temp)(me); /* find the superstate */
469 }
470 } while (r != Q_RET_IGNORED); /* QHsm_top() state not reached */
471 me->temp = me->state; /* establish stable state configuration */
472
474 Q_ENSURE_ID(810, isFound != false);
475#ifdef Q_NASSERT
476 (void)isFound; /* avoid compiler warning about unused variable */
477#endif
478
479 return child; /* return the child */
480}
Customizable and memory-efficient assertions for embedded systems.
#define Q_DEFINE_THIS_MODULE(name_)
Definition: qassert.h:125
char char_t
Definition: qassert.h:77
#define Q_ROM
Definition: qassert.h:90
#define Q_ASSERT_ID(id_, test_)
Definition: qassert.h:160
#define Q_ENSURE_ID(id_, test_)
Definition: qassert.h:303
#define Q_REQUIRE_ID(id_, test_)
Definition: qassert.h:284
#define Q_DIM(array_)
Definition: qassert.h:342
#define QHSM_MAX_NEST_DEPTH_
Definition: qepn.c:57
#define QEP_EMPTY_SIG_
Definition: qepn.c:52
char_t const Q_ROM QP_versionStr[7]
Definition: qepn.c:47
#define Q_RET_UNHANDLED
Definition: qepn.h:284
#define Q_RET_IGNORED
Definition: qepn.h:291
#define QP_VERSION_STR
Definition: qepn.h:54
#define Q_RET_TRAN
Definition: qepn.h:306
uint8_t QSignal
Definition: qepn.h:93
#define Q_STATE_CAST(handler_)
Definition: qepn.h:340
#define Q_EXIT_SIG
Definition: qepn.h:385
#define Q_SIG(me_)
Definition: qepn.h:143
#define Q_ENTRY_SIG
Definition: qepn.h:382
#define Q_INIT_SIG
Definition: qepn.h:388
QState(* QStateHandler)(void *const me)
Definition: qepn.h:158
uint_fast8_t QState
Definition: qepn.h:155
#define Q_RET_SUPER
Definition: qepn.h:278
#define Q_RET_HANDLED
Definition: qepn.h:288
Definition: qepn.h:183
QState QHsm_top(void const *const me)
Definition: qepn.c:172
QStateHandler temp
Definition: qepn.h:186
void QHsm_ctor(QHsm *const me, QStateHandler initial)
Definition: qepn.c:84
QHsmVtable const * vptr
Definition: qepn.h:184
static int_fast8_t QHsm_tran_(QHsm *const me, QStateHandler path[QHSM_MAX_NEST_DEPTH_])
Definition: qepn.c:292
QStateHandler QHsm_childState_(QHsm *const me, QStateHandler const parent)
Definition: qepn.c:450
void QHsm_init_(QHsm *const me)
Definition: qepn.c:105
void QHsm_dispatch_(QHsm *const me)
Definition: qepn.c:190
QStateHandler state
Definition: qepn.h:185