QP/C  6.9.3
Real-Time Embedded Framework
qep_msm.c
Go to the documentation of this file.
1 
40 #define QP_IMPL /* this is QP implementation */
41 #include "qep_port.h" /* QEP port */
42 #include "qassert.h" /* QP embedded systems-friendly assertions */
43 #ifdef Q_SPY /* QS software tracing enabled? */
44  #include "qs_port.h" /* QS port */
45  #include "qs_pkg.h" /* QS facilities for pre-defined trace records */
46 #else
47  #include "qs_dummy.h" /* disable the QS software tracing */
48 #endif /* Q_SPY */
49 
50 Q_DEFINE_THIS_MODULE("qep_msm")
51 
52 /****************************************************************************/
54 enum {
57 };
58 
59 static struct QMState const l_msm_top_s = {
60  (struct QMState *)0,
61  Q_STATE_CAST(0),
62  Q_ACTION_CAST(0),
63  Q_ACTION_CAST(0),
64  Q_ACTION_CAST(0)
65 };
66 
74 #define QEP_ACT_PTR_INC_(act_) (++(act_))
75 
79 #ifdef Q_SPY
80 static QState QMsm_execTatbl_(QHsm * const me,
81  struct QMTranActTable const *tatbl,
82  uint_fast8_t const qs_id);
83 #else
84 static QState QMsm_execTatbl_(QHsm * const me,
85  struct QMTranActTable const *tatbl);
86 #endif
87 
91 #ifdef Q_SPY
92 static void QMsm_exitToTranSource_(QHsm * const me, QMState const *cs,
93  QMState const *ts,
94  uint_fast8_t const qs_id);
95 #else
96 static void QMsm_exitToTranSource_(QHsm * const me, QMState const *cs,
97  QMState const *ts);
98 #endif
99 
103 #ifdef Q_SPY
104 static QState QMsm_enterHistory_(QHsm * const me, QMState const * const hist,
105  uint_fast8_t const qs_id);
106 #else
107 static QState QMsm_enterHistory_(QHsm * const me, QMState const * const hist);
108 #endif
109 
110 /****************************************************************************/
135 void QMsm_ctor(QMsm * const me, QStateHandler initial) {
136  static struct QHsmVtable const vtable = { /* QHsm virtual table */
137  &QMsm_init_,
139 #ifdef Q_SPY
141 #endif
142  };
143  /* do not call the QHsm_ctor() here */
144  me->super.vptr = &vtable;
145  me->super.state.obj = &l_msm_top_s; /* the current state (top) */
146  me->super.temp.fun = initial; /* the initial transition handler */
147 }
148 
149 /****************************************************************************/
162 #ifdef Q_SPY
163 void QMsm_init_(QHsm * const me, void const * const e,
164  uint_fast8_t const qs_id)
165 #else
166 void QMsm_init_(QHsm * const me, void const * const e)
167 #endif
168 {
169  QState r;
171 
176  Q_REQUIRE_ID(200, (me->vptr != (struct QHsmVtable *)0)
177  && (me->temp.fun != Q_STATE_CAST(0))
178  && (me->state.obj == &l_msm_top_s));
179 
180  /* execute the top-most initial tran. */
181  r = (*me->temp.fun)(me, Q_EVT_CAST(QEvt));
182 
183  /* the top-most initial transition must be taken */
184  Q_ASSERT_ID(210, r == (QState)Q_RET_TRAN_INIT);
185 
187  QS_OBJ_PRE_(me); /* this state machine object */
188  QS_FUN_PRE_(me->state.obj->stateHandler); /* source state */
189  QS_FUN_PRE_(me->temp.tatbl->target->stateHandler);/*target state */
190  QS_END_PRE_()
191 
192  /* set state to the last tran. target */
193  me->state.obj = me->temp.tatbl->target;
194 
195  /* drill down into the state hierarchy with initial transitions... */
196  /* execute the tran. table */
197  do {
198 #ifdef Q_SPY
199  r = QMsm_execTatbl_(me, me->temp.tatbl, qs_id);
200 #else
201  r = QMsm_execTatbl_(me, me->temp.tatbl);
202 #endif
203  } while (r >= (QState)Q_RET_TRAN_INIT);
204 
206  QS_TIME_PRE_(); /* time stamp */
207  QS_OBJ_PRE_(me); /* this state machine object */
208  QS_FUN_PRE_(me->state.obj->stateHandler); /* the new current state */
209  QS_END_PRE_()
210 }
211 
212 /****************************************************************************/
227 #ifdef Q_SPY
228 void QMsm_dispatch_(QHsm * const me, QEvt const * const e,
229  uint_fast8_t const qs_id)
230 #else
231 void QMsm_dispatch_(QHsm * const me, QEvt const * const e)
232 #endif
233 {
234  QMState const *s = me->state.obj; /* store the current state */
235  QMState const *t = s;
236  QState r;
238 
240  Q_REQUIRE_ID(300, s != (QMState *)0);
241 
243  QS_TIME_PRE_(); /* time stamp */
244  QS_SIG_PRE_(e->sig); /* the signal of the event */
245  QS_OBJ_PRE_(me); /* this state machine object */
246  QS_FUN_PRE_(s->stateHandler); /* the current state handler */
247  QS_END_PRE_()
248 
249  /* scan the state hierarchy up to the top state... */
250  do {
251  r = (*t->stateHandler)(me, e); /* call state handler function */
252 
253  /* event handled? (the most frequent case) */
254  if (r >= (QState)Q_RET_HANDLED) {
255  break; /* done scanning the state hierarchy */
256  }
257  /* event unhandled and passed to the superstate? */
258  else if (r == (QState)Q_RET_SUPER) {
259  t = t->superstate; /* advance to the superstate */
260  }
261  /* event unhandled and passed to a submachine superstate? */
262  else if (r == (QState)Q_RET_SUPER_SUB) {
263  t = me->temp.obj; /* current host state of the submachie */
264  }
265  /* event unhandled due to a guard? */
266  else if (r == (QState)Q_RET_UNHANDLED) {
267 
269  QS_SIG_PRE_(e->sig); /* the signal of the event */
270  QS_OBJ_PRE_(me); /* this state machine object */
271  QS_FUN_PRE_(t->stateHandler); /* the current state */
272  QS_END_PRE_()
273 
274  t = t->superstate; /* advance to the superstate */
275  }
276  else {
277  /* no other return value should be produced */
278  Q_ERROR_ID(310);
279  }
280  } while (t != (QMState *)0);
281 
282 
283  /* any kind of transition taken? */
284  if (r >= (QState)Q_RET_TRAN) {
285 #ifdef Q_SPY
286  QMState const *ts = t; /* transition source for QS tracing */
287 
288  /* the transition source state must not be NULL */
289  Q_ASSERT_ID(320, ts != (QMState *)0);
290 #endif /* Q_SPY */
291 
292  do {
293  /* save the transition-action table before it gets clobbered */
294  struct QMTranActTable const *tatbl = me->temp.tatbl;
295  union QHsmAttr tmp; /* temporary to save intermediate values */
296 
297  /* was TRAN, TRAN_INIT, or TRAN_EP taken? */
298  if (r <= (QState)Q_RET_TRAN_EP) {
299 #ifdef Q_SPY
300  QMsm_exitToTranSource_(me, s, t, qs_id);
301  r = QMsm_execTatbl_(me, tatbl, qs_id);
302 #else
303  QMsm_exitToTranSource_(me, s, t);
304  r = QMsm_execTatbl_(me, tatbl);
305 #endif
306  s = me->state.obj;
307  }
308  /* was a transition segment to history taken? */
309  else if (r == (QState)Q_RET_TRAN_HIST) {
310  tmp.obj = me->state.obj; /* save history */
311  me->state.obj = s; /* restore the original state */
312 #ifdef Q_SPY
313  QMsm_exitToTranSource_(me, s, t, qs_id);
314  (void)QMsm_execTatbl_(me, tatbl, qs_id);
315  r = QMsm_enterHistory_(me, tmp.obj, qs_id);
316 #else
317  QMsm_exitToTranSource_(me, s, t);
318  (void)QMsm_execTatbl_(me, tatbl);
319  r = QMsm_enterHistory_(me, tmp.obj);
320 #endif
321  s = me->state.obj;
322  }
323  /* was a transition segment to an exit point taken? */
324  else if (r == (QState)Q_RET_TRAN_XP) {
325  tmp.act = me->state.act; /* save XP action */
326  me->state.obj = s; /* restore the original state */
327  r = (*tmp.act)(me); /* execute the XP action */
328  if (r == (QState)Q_RET_TRAN) { /* XP -> TRAN ? */
329 #ifdef Q_SPY
330  tmp.tatbl = me->temp.tatbl; /* save me->temp */
331  QMsm_exitToTranSource_(me, s, t, qs_id);
332  /* take the tran-to-XP segment inside submachine */
333  (void)QMsm_execTatbl_(me, tatbl, qs_id);
334 #else
335  QMsm_exitToTranSource_(me, s, t);
336  /* take the tran-to-XP segment inside submachine */
337  (void)QMsm_execTatbl_(me, tatbl);
338 #endif /* Q_SPY */
339  s = me->state.obj;
340 #ifdef Q_SPY
341  me->temp.tatbl = tmp.tatbl; /* restore me->temp */
342 #endif /* Q_SPY */
343  }
344  else if (r == (QState)Q_RET_TRAN_HIST) { /* XP -> HIST ? */
345  tmp.obj = me->state.obj; /* save the history */
346  me->state.obj = s; /* restore the original state */
347 #ifdef Q_SPY
348  s = me->temp.obj; /* save me->temp */
349  QMsm_exitToTranSource_(me, me->state.obj, t, qs_id);
350  /* take the tran-to-XP segment inside submachine */
351  (void)QMsm_execTatbl_(me, tatbl, qs_id);
352 #else
353  QMsm_exitToTranSource_(me, me->state.obj, t);
354  /* take the tran-to-XP segment inside submachine */
355  (void)QMsm_execTatbl_(me, tatbl);
356 #endif /* Q_SPY */
357 #ifdef Q_SPY
358  me->temp.obj = s; /* restore me->temp */
359 #endif /* Q_SPY */
360  s = me->state.obj;
361  me->state.obj = tmp.obj; /* restore the history */
362  }
363  else {
364  /* TRAN_XP must NOT be followed by any other tran type */
365  Q_ASSERT_ID(330, r < (QState)Q_RET_TRAN);
366  }
367  }
368  else {
369  /* no other return value should be produced */
370  Q_ERROR_ID(340);
371  }
372 
373  t = s; /* set target to the current state */
374 
375  } while (r >= (QState)Q_RET_TRAN);
376 
377  QS_BEGIN_PRE_(QS_QEP_TRAN, qs_id)
378  QS_TIME_PRE_(); /* time stamp */
379  QS_SIG_PRE_(e->sig); /* the signal of the event */
380  QS_OBJ_PRE_(me); /* this state machine object */
381  QS_FUN_PRE_(ts->stateHandler); /* the transition source */
382  QS_FUN_PRE_(s->stateHandler); /* the new active state */
383  QS_END_PRE_()
384  }
385 
386 #ifdef Q_SPY
387  /* was the event handled? */
388  else if (r == (QState)Q_RET_HANDLED) {
389  /* internal tran. source can't be NULL */
390  Q_ASSERT_ID(340, t != (QMState *)0);
391 
393  QS_TIME_PRE_(); /* time stamp */
394  QS_SIG_PRE_(e->sig); /* the signal of the event */
395  QS_OBJ_PRE_(me); /* this state machine object */
396  QS_FUN_PRE_(t->stateHandler); /* the source state */
397  QS_END_PRE_()
398 
399  }
400  /* event bubbled to the 'top' state? */
401  else if (t == (QMState *)0) {
402 
404  QS_TIME_PRE_(); /* time stamp */
405  QS_SIG_PRE_(e->sig); /* the signal of the event */
406  QS_OBJ_PRE_(me); /* this state machine object */
407  QS_FUN_PRE_(s->stateHandler); /* the current state */
408  QS_END_PRE_()
409 
410  }
411 #endif /* Q_SPY */
412  else {
413  /* empty */
414  }
415 }
416 
417 /****************************************************************************/
418 #ifdef Q_SPY
420  return me->state.obj->stateHandler;
421 }
422 #endif
423 
424 /****************************************************************************/
441 #ifdef Q_SPY
442 static QState QMsm_execTatbl_(QHsm * const me,
443  struct QMTranActTable const *tatbl,
444  uint_fast8_t const qs_id)
445 #else
446 static QState QMsm_execTatbl_(QHsm * const me,
447  struct QMTranActTable const *tatbl)
448 #endif
449 {
450  QActionHandler const *a;
451  QState r = (QState)Q_RET_NULL;
453 
455  Q_REQUIRE_ID(400, tatbl != (struct QMTranActTable *)0);
456 
457  for (a = &tatbl->act[0]; *a != Q_ACTION_CAST(0); QEP_ACT_PTR_INC_(a)) {
458  r = (*(*a))(me); /* call the action through the 'a' pointer */
459 #ifdef Q_SPY
460  if (r == (QState)Q_RET_ENTRY) {
461 
463  QS_OBJ_PRE_(me); /* this state machine object */
464  QS_FUN_PRE_(me->temp.obj->stateHandler);/*entered state handler */
465  QS_END_PRE_()
466  }
467  else if (r == (QState)Q_RET_EXIT) {
468 
470  QS_OBJ_PRE_(me); /* this state machine object */
471  QS_FUN_PRE_(me->temp.obj->stateHandler); /* exited state handler*/
472  QS_END_PRE_()
473  }
474  else if (r == (QState)Q_RET_TRAN_INIT) {
475 
477  QS_OBJ_PRE_(me); /* this state machine object */
478  QS_FUN_PRE_(tatbl->target->stateHandler); /* source */
479  QS_FUN_PRE_(me->temp.tatbl->target->stateHandler);/* target */
480  QS_END_PRE_()
481  }
482  else if (r == (QState)Q_RET_TRAN_EP) {
483 
485  QS_OBJ_PRE_(me); /* this state machine object */
486  QS_FUN_PRE_(tatbl->target->stateHandler); /* source */
487  QS_FUN_PRE_(me->temp.tatbl->target->stateHandler);/* target */
488  QS_END_PRE_()
489  }
490  else if (r == (QState)Q_RET_TRAN_XP) {
491 
493  QS_OBJ_PRE_(me); /* this state machine object */
494  QS_FUN_PRE_(tatbl->target->stateHandler); /* source */
495  QS_FUN_PRE_(me->temp.tatbl->target->stateHandler);/* target */
496  QS_END_PRE_()
497  }
498  else {
499  /* empty */
500  }
501 #endif /* Q_SPY */
502  }
503 
504  me->state.obj = (r >= (QState)Q_RET_TRAN)
505  ? me->temp.tatbl->target
506  : tatbl->target;
507  return r;
508 }
509 
510 /****************************************************************************/
523 #ifdef Q_SPY
524 static void QMsm_exitToTranSource_(QHsm * const me, QMState const *cs,
525  QMState const *ts,
526  uint_fast8_t const qs_id)
527 #else
528 static void QMsm_exitToTranSource_(QHsm * const me, QMState const *cs,
529  QMState const *ts)
530 #endif
531 {
532  QMState const *s = cs;
533 
534  /* exit states from the current state to the tran. source state */
535  while (s != ts) {
536  /* exit action provided in state 's'? */
537  if (s->exitAction != Q_ACTION_CAST(0)) {
539 
540  (void)(*s->exitAction)(me); /* execute the exit action */
541 
543  QS_OBJ_PRE_(me); /* this state machine object */
544  QS_FUN_PRE_(s->stateHandler); /* the exited state handler */
545  QS_END_PRE_()
546  }
547 
548  s = s->superstate; /* advance to the superstate */
549 
550  if (s == (QMState *)0) { /* reached the top of a submachine? */
551  s = me->temp.obj; /* the superstate from QM_SM_EXIT() */
552  Q_ASSERT_ID(510, s != (QMState *)0); /* must be valid */
553  }
554  }
555 }
556 
557 /****************************************************************************/
572 #ifdef Q_SPY
573 static QState QMsm_enterHistory_(QHsm * const me, QMState const *const hist,
574  uint_fast8_t const qs_id)
575 #else
576 static QState QMsm_enterHistory_(QHsm * const me, QMState const *const hist)
577 #endif
578 {
579  QMState const *s = hist;
580  QMState const *ts = me->state.obj; /* transition source */
581  QMState const *epath[QMSM_MAX_ENTRY_DEPTH_];
582  QState r;
583  uint_fast8_t i = 0U; /* transition entry path index */
585 
587  QS_OBJ_PRE_(me); /* this state machine object */
588  QS_FUN_PRE_(ts->stateHandler); /* source state handler */
589  QS_FUN_PRE_(hist->stateHandler); /* target state handler */
590  QS_END_PRE_()
591 
592  while (s != ts) {
593  if (s->entryAction != Q_ACTION_CAST(0)) {
594  epath[i] = s;
595  ++i;
596  Q_ASSERT_ID(620, i <= Q_DIM(epath));
597  }
598  s = s->superstate;
599  if (s == (QMState *)0) {
600  ts = s; /* force exit from the for-loop */
601  }
602  }
603 
604  /* retrace the entry path in reverse (desired) order... */
605  while (i > 0U) {
606  --i;
607  (void)(*epath[i]->entryAction)(me); /* run entry action in epath[i] */
608 
610  QS_OBJ_PRE_(me);
611  QS_FUN_PRE_(epath[i]->stateHandler); /* entered state handler */
612  QS_END_PRE_()
613  }
614 
615  me->state.obj = hist; /* set current state to the transition target */
616 
617  /* initial tran. present? */
618  if (hist->initAction != Q_ACTION_CAST(0)) {
619  r = (*hist->initAction)(me); /* execute the transition action */
620  }
621  else {
622  r = (QState)Q_RET_NULL;
623  }
624  return r;
625 }
626 
627 /****************************************************************************/
642 bool QMsm_isInState(QMsm const * const me, QMState const * const state) {
643  bool inState = false; /* assume that this MSM is not in 'state' */
644  QMState const *s;
645 
646  for (s = me->super.state.obj; s != (QMState *)0; s = s->superstate) {
647  if (s == state) {
648  inState = true; /* match found, return 'true' */
649  break;
650  }
651  }
652  return inState;
653 }
654 
655 /****************************************************************************/
673 QMState const *QMsm_childStateObj_(QMsm const * const me,
674  QMState const * const parent)
675 {
676  QMState const *child = me->super.state.obj;
677  bool isFound = false; /* start with the child not found */
678  QMState const *s;
679 
680  for (s = me->super.state.obj;
681  s != (QMState *)0;
682  s = s->superstate)
683  {
684  if (s == parent) {
685  isFound = true; /* child is found */
686  break;
687  }
688  else {
689  child = s;
690  }
691  }
692 
694  Q_ENSURE_ID(810, isFound != false);
695 #ifdef Q_NASSERT
696  (void)isFound; /* avoid compiler warning about unused variable */
697 #endif
698 
699  return child; /* return the child */
700 }
701 
unsigned int uint_fast8_t
Definition: 16bit/stdint.h:36
Customizable and memory-efficient assertions for embedded systems.
#define Q_DEFINE_THIS_MODULE(name_)
Definition: qassert.h:120
#define Q_ASSERT_ID(id_, test_)
Definition: qassert.h:155
#define Q_ENSURE_ID(id_, test_)
Definition: qassert.h:298
#define Q_REQUIRE_ID(id_, test_)
Definition: qassert.h:279
#define Q_DIM(array_)
Definition: qassert.h:337
#define Q_ERROR_ID(id_)
Definition: qassert.h:211
@ Q_RET_ENTRY
Definition: qep.h:608
@ Q_RET_HANDLED
Definition: qep.h:604
@ Q_RET_TRAN_XP
Definition: qep.h:621
@ Q_RET_TRAN_INIT
Definition: qep.h:616
@ Q_RET_TRAN
Definition: qep.h:615
@ Q_RET_UNHANDLED
Definition: qep.h:601
@ Q_RET_SUPER
Definition: qep.h:599
@ Q_RET_NULL
Definition: qep.h:612
@ Q_RET_TRAN_HIST
Definition: qep.h:620
@ Q_RET_SUPER_SUB
Definition: qep.h:600
@ Q_RET_TRAN_EP
Definition: qep.h:617
@ Q_RET_EXIT
Definition: qep.h:609
struct QMState const * superstate
Definition: qep.h:467
QActionHandler const act[1]
Definition: qep.h:478
QMTranActTable const * tatbl
Definition: qep.h:255
#define Q_STATE_CAST(handler_)
Definition: qep.h:228
QState(* QStateHandler)(void *const me, QEvt const *const e)
Definition: qep.h:210
#define Q_ACTION_CAST(action_)
Definition: qep.h:237
QActionHandler const entryAction
Definition: qep.h:469
#define Q_EVT_CAST(class_)
Definition: qep.h:190
QActionHandler const initAction
Definition: qep.h:471
QActionHandler const exitAction
Definition: qep.h:470
struct QMState const * target
Definition: qep.h:477
QStateHandler const stateHandler
Definition: qep.h:468
uint_fast8_t QState
Definition: qep.h:204
QStateHandler fun
Definition: qep.h:251
struct QMState const * obj
Definition: qep.h:254
QState(* QActionHandler)(void *const me)
Definition: qep.h:213
QActionHandler act
Definition: qep.h:252
Definition: qep.h:466
Definition: qep.h:250
#define QEP_ACT_PTR_INC_(act_)
Definition: qep_msm.c:74
static struct QMState const l_msm_top_s
Definition: qep_msm.c:59
@ QMSM_MAX_ENTRY_DEPTH_
Definition: qep_msm.c:56
QEP/C port, generic C11 compiler.
#define QS_CRIT_STAT_
Definition: qs.h:501
#define QS_TIME_PRE_()
Definition: qs.h:262
@ QS_QEP_STATE_INIT
Definition: qs.h:69
@ QS_QEP_TRAN_HIST
Definition: qs.h:145
@ QS_QEP_TRAN_EP
Definition: qs.h:146
@ QS_QEP_STATE_EXIT
Definition: qs.h:68
@ QS_QEP_INIT_TRAN
Definition: qs.h:70
@ QS_QEP_INTERN_TRAN
Definition: qs.h:71
@ QS_QEP_TRAN_XP
Definition: qs.h:147
@ QS_QEP_STATE_ENTRY
Definition: qs.h:67
@ QS_QEP_UNHANDLED
Definition: qs.h:75
@ QS_QEP_TRAN
Definition: qs.h:72
@ QS_QEP_DISPATCH
Definition: qs.h:74
@ QS_QEP_IGNORED
Definition: qs.h:73
Internal (package scope) QS/C interface.
#define QS_BEGIN_PRE_(rec_, qs_id_)
Definition: qs_pkg.h:51
#define QS_OBJ_PRE_(obj_)
Definition: qs_pkg.h:116
#define QS_FUN_PRE_(fun_)
Definition: qs_pkg.h:131
#define QS_END_PRE_()
Definition: qs_pkg.h:63
Definition: qep.h:151
QSignal sig
Definition: qep.h:152
Definition: qep.h:282
struct QHsmVtable const * vptr
Definition: qep.h:283
union QHsmAttr state
Definition: qep.h:284
union QHsmAttr temp
Definition: qep.h:285
Definition: qep.h:450
QHsm super
Definition: qep.h:451
QStateHandler QMsm_getStateHandler_(QHsm *const me)
Definition: qep_msm.c:419
QMState const * QMsm_childStateObj_(QMsm const *const me, QMState const *const parent)
Definition: qep_msm.c:673
static void QMsm_exitToTranSource_(QHsm *const me, QMState const *cs, QMState const *ts, uint_fast8_t const qs_id)
Definition: qep_msm.c:524
void QMsm_init_(QHsm *const me, void const *const e, uint_fast8_t const qs_id)
Definition: qep_msm.c:163
void QMsm_dispatch_(QHsm *const me, QEvt const *const e, uint_fast8_t const qs_id)
Definition: qep_msm.c:228
static QState QMsm_enterHistory_(QHsm *const me, QMState const *const hist, uint_fast8_t const qs_id)
Definition: qep_msm.c:573
bool QMsm_isInState(QMsm const *const me, QMState const *const state)
Definition: qep_msm.c:642
void QMsm_ctor(QMsm *const me, QStateHandler initial)
Definition: qep_msm.c:135
static QState QMsm_execTatbl_(QHsm *const me, struct QMTranActTable const *tatbl, uint_fast8_t const qs_id)
Definition: qep_msm.c:442