/*..........................................................................*/ void QFsm_init_(QFsm * const me, QEvt const * const e) { QS_CRIT_STAT_ Q_REQUIRE((me->vptr != (QMsmVtbl const *)0) /* ctor must be executed */ && (me->temp.fun != Q_STATE_CAST(0)) /* ctor must be executed */ && (me->state.fun == Q_STATE_CAST(0)));/*init tran. NOT taken */ QS_BEGIN_(QS_QEP_STATE_INIT, QS_priv_.smObjFilter, me) QS_OBJ_(me); /* this state machine object */ QS_FUN_(Q_STATE_CAST(0)); /* source state (not defined for a FSM) */ QS_FUN_(me->temp.fun); /* the target of the transition */ QS_END_() /* execute the top-most initial transition */ Q_ALLEGE((*me->temp.fun)(me, e) == (QState)Q_RET_TRAN);/* must be taken */ (void)QEP_TRIG_(me->temp.fun, Q_ENTRY_SIG); /* enter the target */ me->state.fun = me->temp.fun; /* record the new active state */ QS_BEGIN_(QS_QEP_INIT_TRAN, QS_priv_.smObjFilter, me) QS_TIME_(); /* time stamp */ QS_OBJ_(me); /* this state machine object */ QS_FUN_(me->state.fun); /* the new active state */ QS_END_() }
/*..........................................................................*/ void QFsm_dispatch(QFsm *me, QEvent const *e) { QStateHandler s = me->state; /* save the current state */ QS_INT_LOCK_KEY_ QState r = (*s)(me, e); /* call the event handler */ if (r == Q_RET_TRAN) { /* transition taken? */ QS_BEGIN_(QS_QEP_TRAN, QS_smObj_, me) QS_TIME_(); /* time stamp */ QS_SIG_(e->sig); /* the signal of the event */ QS_OBJ_(me); /* this state machine object */ QS_FUN_(s); /* the source of the transition */ QS_FUN_(me->state); /* the new active state */ QS_END_() (void)QEP_TRIG_(s, Q_EXIT_SIG); /* exit the source */ (void)QEP_TRIG_(me->state, Q_ENTRY_SIG); /* enter the target */ } else { /* transition not taken */ #ifdef Q_SPY if (r == Q_RET_HANDLED) { QS_BEGIN_(QS_QEP_INTERN_TRAN, QS_smObj_, me) QS_TIME_(); /* time stamp */ QS_SIG_(e->sig); /* the signal of the event */ QS_OBJ_(me); /* this state machine object */ QS_FUN_(s); /* the state that handled the event */ QS_END_() } else {
//............................................................................ void QMsm::dispatch(QEvt const * const e) { QMState const *s = m_state.obj; // store the current state QMState const *t; QState r = Q_RET_HANDLED; QS_CRIT_STAT_ Q_REQUIRE(s != (QMState const *)0); // must be initialized QS_BEGIN_(QS_QEP_DISPATCH, QS::priv_.smObjFilter, this) QS_TIME_(); // time stamp QS_SIG_(e->sig); // the signal of the event QS_OBJ_(this); // this state machine object QS_FUN_(s->stateHandler); // the current state handler QS_END_() for (t = s; t != static_cast<QMState const *>(0); t = t->parent) { r = (*t->stateHandler)(this, e); if (r != Q_RET_SUPER) { if (r == Q_RET_UNHANDLED) { // unhandled due to a guard? QS_BEGIN_(QS_QEP_UNHANDLED, QS::priv_.smObjFilter, this) QS_SIG_(e->sig); // the signal of the event QS_OBJ_(this); // this state machine object QS_FUN_(t->stateHandler); // the current state QS_END_() } else { break; // event handled--break out of the loop } }
/*..........................................................................*/ void QHsm_init(QHsm *me, QEvent const *e) { QHsmState s; /* this state machine must be initialized with QHsm_ctor_() */ Q_REQUIRE(((QFsm *)me)->state__.fsm != (QState)0); s = &QHsm_top; /* an HSM starts in the top state */ /* trigger the initial transition */ (*((QFsm *)me)->state__.fsm)((QFsm *)me, e); do { /* drill into the target... */ QHsmState path[QEP_MAX_NEST_DEPTH_]; int8_t ip = (int8_t)0; /* transition entry path index */ QHsmState t = ((QFsm *)me)->state__.hsm; QS_BEGIN_(QS_QEP_STATE_INIT, QS_smObj_, me); QS_OBJ_(me); /* this state machine object */ QS_FUN_(s); /* the source state */ QS_FUN_(((QFsm *)me)->state__.hsm); /* the target */ QS_END_(); path[0] = t; for (t = QEP_TRIG_(t, QEP_EMPTY_SIG_); t != s; t = QEP_TRIG_(t, QEP_EMPTY_SIG_)) { path[++ip] = t; } /* entry path must not overflow */ Q_ASSERT(ip < (int8_t)QEP_MAX_NEST_DEPTH_); do { /* retrace the entry path in reverse (desired) order... */ /* enter path[ip] */ if (QEP_TRIG_(path[ip], Q_ENTRY_SIG) == (QHsmState)0) { QS_BEGIN_(QS_QEP_STATE_ENTRY, QS_smObj_, me); QS_OBJ_(me); /* this state machine object */ QS_FUN_(path[ip]); /* the entered state */ QS_END_(); } } while (--ip >= (int8_t)0); s = ((QFsm *)me)->state__.hsm; } while (QEP_TRIG_(s, Q_INIT_SIG) == (QHsmState)0); QS_BEGIN_(QS_QEP_INIT_TRAN, QS_smObj_, me); QS_TIME_(); /* time stamp */ QS_OBJ_(me); /* this state machine object */ QS_FUN_(((QFsm *)me)->state__.hsm); /* the new active state */ QS_END_(); }
/*..........................................................................*/ void QHsm_init(QHsm * const me, QEvt const * const e) { QStateHandler t = me->state.fun; QS_CRIT_STAT_ Q_REQUIRE((me->vptr != (QMsmVtbl const *)0) /* ctor must be executed */ && (me->temp.fun != Q_STATE_CAST(0)) /* ctor must be executed */ && (t == Q_STATE_CAST(&QHsm_top))); /*initial tran. NOT taken */ /* the top-most initial transition must be taken */ Q_ALLEGE((*me->temp.fun)(me, e) == (QState)Q_RET_TRAN); do { /* drill into the target... */ QStateHandler path[QEP_MAX_NEST_DEPTH_]; int_t ip = (int_t)0; /* transition entry path index */ QS_BEGIN_(QS_QEP_STATE_INIT, QS_priv_.smObjFilter, me) QS_OBJ_(me); /* this state machine object */ QS_FUN_(t); /* the source state */ QS_FUN_(me->temp.fun); /* the target of the initial transition */ QS_END_() path[0] = me->temp.fun; (void)QEP_TRIG_(me->temp.fun, QEP_EMPTY_SIG_); while (me->temp.fun != t) { ++ip; path[ip] = me->temp.fun; (void)QEP_TRIG_(me->temp.fun, QEP_EMPTY_SIG_); } me->temp.fun = path[0]; /* entry path must not overflow */ Q_ASSERT(ip < (int_t)QEP_MAX_NEST_DEPTH_); do { /* retrace the entry path in reverse (desired) order... */ QEP_ENTER_(path[ip]); /* enter path[ip] */ --ip; } while (ip >= (int_t)0); t = path[0]; /* current state becomes the new source */ } while (QEP_TRIG_(t, Q_INIT_SIG) == (QState)Q_RET_TRAN); QS_BEGIN_(QS_QEP_INIT_TRAN, QS_priv_.smObjFilter, me) QS_TIME_(); /* time stamp */ QS_OBJ_(me); /* this state machine object */ QS_FUN_(t); /* the new active state */ QS_END_() me->state.fun = t; /* change the current active state */ me->temp.fun = t; /* mark the configuration as stable */ }
/*..........................................................................*/ QEvt *QF_newX_(uint_t const evtSize, uint_t const margin, enum_t const sig) { QEvt *e; uint_t idx; QS_CRIT_STAT_ /* find the pool index that fits the requested event size ... */ for (idx = (uint_t)0; idx < QF_maxPool_; ++idx) { if (evtSize <= QF_EPOOL_EVENT_SIZE_(QF_pool_[idx])) { break; } } Q_ASSERT(idx < QF_maxPool_); /* cannot run out of registered pools */ QS_BEGIN_(QS_QF_NEW, (void *)0, (void *)0) QS_TIME_(); /* timestamp */ QS_EVS_((QEvtSize)evtSize); /* the size of the event */ QS_SIG_((QSignal)sig); /* the signal of the event */ QS_END_() QF_EPOOL_GET_(QF_pool_[idx], e, margin); /* get e -- platform-dependent */ if (e != (QEvt *)0) { /* was e allocated correctly? */ e->sig = (QSignal)sig; /* set signal for this event */ e->poolId_ = (uint8_t)(idx + (uint_t)1); /* store the pool ID */ e->refCtr_ = (uint8_t)0; /* set the reference counter to 0 */ } else { /* event cannot be allocated */ Q_ASSERT(margin != (uint_t)0); /* must tollerate bad allocation */ } return e; /* can't be NULL if we can't tollerate bad allocation */ }
//............................................................................ QEvent *QF::new_(uint16_t evtSize, QSignal sig) { // find the pool id that fits the requested event size ... uint8_t id = (uint8_t)0; while (evtSize > QF_EPOOL_EVENT_SIZE_(QF_pool_[id])) { ++id; Q_ASSERT(id < QF_maxPool_); // cannot run out of registered pools } QS_INT_LOCK_KEY_ QS_BEGIN_(QS_QF_NEW, (void *)0, (void *)0) QS_TIME_(); // timestamp QS_EVS_(evtSize); // the size of the event QS_SIG_(sig); // the signal of the event QS_END_() QEvent *e; QF_EPOOL_GET_(QF_pool_[id], e); Q_ASSERT(e != (QEvent *)0); // pool must not run out of events e->sig = sig; // set signal for this event // store the dynamic attributes of the event: // the pool ID and the reference counter == 0 e->dynamic_ = (uint8_t)((id + 1) << 6); return e; }
//............................................................................ void QHsm::init(QEvent const *e) { QStateHandler t; QS_INT_LOCK_KEY_ // the top-most initial transition must be taken Q_ALLEGE((*m_state)(this, e) == Q_RET_TRAN); t = (QStateHandler)&QHsm::top; // HSM starts in the top state do { // drill into the target... QStateHandler path[QEP_MAX_NEST_DEPTH_]; int8_t ip = (int8_t)0; // transition entry path index QS_BEGIN_(QS_QEP_STATE_INIT, QS::smObj_, this) QS_OBJ_(this); // this state machine object QS_FUN_(t); // the source state QS_FUN_(m_state); // the target of the initial transition QS_END_() path[0] = m_state; (void)QEP_TRIG_(m_state, QEP_EMPTY_SIG_); while (m_state != t) { ++ip; path[ip] = m_state; (void)QEP_TRIG_(m_state, QEP_EMPTY_SIG_); } m_state = path[0]; // entry path must not overflow Q_ASSERT(ip < (int8_t)QEP_MAX_NEST_DEPTH_); do { // retrace the entry path in reverse (desired) order... QEP_ENTER_(path[ip]); // enter path[ip] --ip; } while (ip >= (int8_t)0); t = path[0]; // current state becomes the new source } while (QEP_TRIG_(t, Q_INIT_SIG) == Q_RET_TRAN); m_state = t; QS_BEGIN_(QS_QEP_INIT_TRAN, QS::smObj_, this) QS_TIME_(); // time stamp QS_OBJ_(this); // this state machine object QS_FUN_(m_state); // the new active state QS_END_() }
/*..........................................................................*/ void QFsm_init(QFsm *me, QEvent const *e) { QState initial; Q_REQUIRE(me->state__.fsm != (QState)0); /* must be initialized */ initial = me->state__.fsm; /* save the initial pseudostate */ QS_BEGIN_(QS_QEP_STATE_INIT, QS_smObj_, me); QS_OBJ_(me); /* this state machine object */ QS_FUN_((QState)0); /* the source (not defined for a FSM) */ QS_FUN_(me->state__.fsm); /* the target of the transition */ QS_END_(); (*initial)(me, e); /* trigger the initial transition */ Q_ASSERT(initial != me->state__.fsm); /* cannot stay in the initial */ (*me->state__.fsm)(me, &QEP_reservedEvt_[Q_ENTRY_SIG]); /* enter target */ QS_BEGIN_(QS_QEP_INIT_TRAN, QS_smObj_, me); QS_TIME_(); /* time stamp */ QS_OBJ_(me); /* this state machine object */ QS_FUN_(me->state__.fsm); /* the new active state */ QS_END_(); }
/*..........................................................................*/ void QMPool_init(QMPool * const me, void * const poolSto, uint32_t poolSize, QMPoolSize blockSize) { QFreeBlock *fb; uint32_t nblocks; QS_CRIT_STAT_ /* The memory block must be valid * and the poolSize must fit at least one free block * and the blockSize must not be too close to the top of the dynamic range */ Q_REQUIRE((poolSto != (void *)0) && (poolSize >= (uint32_t)sizeof(QFreeBlock)) && ((QMPoolSize)(blockSize + (QMPoolSize)sizeof(QFreeBlock)) > blockSize)); me->free_head = poolSto; /* round up the blockSize to fit an integer # free blocks, no division */ me->blockSize = (QMPoolSize)sizeof(QFreeBlock); /* start with just one */ nblocks = (uint32_t)1; /* # free blocks that fit in one memory block */ while (me->blockSize < blockSize) { me->blockSize += (QMPoolSize)sizeof(QFreeBlock); ++nblocks; } blockSize = me->blockSize; /* use the rounded-up value from now on */ /* the pool buffer must fit at least one rounded-up block */ Q_ASSERT(poolSize >= (uint32_t)blockSize); /* chain all blocks together in a free-list... */ poolSize -= (uint32_t)blockSize; /* don't count the last block */ me->nTot = (QMPoolCtr)1; /* the last block already in the pool */ fb = (QFreeBlock *)me->free_head; /* start at the head of the free list */ while (poolSize >= (uint32_t)blockSize) { fb->next = &QF_PTR_AT_(fb, nblocks);/*point next link to next block */ fb = fb->next; /* advance to the next block */ poolSize -= (uint32_t)blockSize; /* reduce the available pool size */ ++me->nTot; /* increment the number of blocks so far */ } fb->next = (QFreeBlock *)0; /* the last link points to NULL */ me->nFree = me->nTot; /* all blocks are free */ me->nMin = me->nTot; /* the minimum number of free blocks */ me->start = poolSto; /* the original start this pool buffer */ me->end = fb; /* the last block in this pool */ QS_BEGIN_(QS_QF_MPOOL_INIT, QS_priv_.mpObjFilter, me->start) QS_OBJ_(me->start); /* the memory managed by this pool */ QS_MPC_(me->nTot); /* the total number of blocks */ QS_END_() }
/** * @description * Executes the top-most initial transition in a MSM. * * @param[in,out] me pointer (see @ref oop) * @param[in] e pointer to the initialization event (might be NULL) * * @note Must be called only ONCE after the QMsm_ctor(). */ void QMsm_init_(QMsm * const me, QEvt const * const e) { QState r; QS_CRIT_STAT_ /** @pre the virtual pointer must be initialized, the top-most initial * transition must be initialized, and the initial transition must not * be taken yet. */ Q_REQUIRE_ID(200, (me->vptr != (QMsmVtbl const *)0) && (me->temp.fun != Q_STATE_CAST(0)) && (me->state.obj == &l_msm_top_s)); r = (*me->temp.fun)(me, e); /* the action of the top-most initial tran. */ /* the top-most initial transition must be taken */ Q_ASSERT_ID(210, r == (QState)Q_RET_TRAN_INIT); QS_BEGIN_(QS_QEP_STATE_INIT, QS_priv_.smObjFilter, me) QS_OBJ_(me); /* this state machine object */ QS_FUN_(me->state.obj->stateHandler); /* source state handler*/ QS_FUN_(me->temp.tatbl->target->stateHandler);/*target state handler*/ QS_END_() /* set state to the last tran. target */ me->state.obj = me->temp.tatbl->target; /* drill down into the state hierarchy with initial transitions... */ do { r = QMsm_execTatbl_(me, me->temp.tatbl); /* execute the tran. table */ } while (r >= (QState)Q_RET_TRAN_INIT); QS_BEGIN_(QS_QEP_INIT_TRAN, QS_priv_.smObjFilter, me) QS_TIME_(); /* time stamp */ QS_OBJ_(me); /* this state machine object */ QS_FUN_(me->state.obj->stateHandler); /* the new current state */ QS_END_() }
/*..........................................................................*/ void QEQueue_init(QEQueue * const me, QEvt const *qSto[], QEQueueCtr const qLen) { QS_CRIT_STAT_ me->frontEvt = (QEvt const *)0; /* no events in the queue */ me->ring = &qSto[0]; /* the beginning of the ring buffer */ me->end = qLen; me->head = (QEQueueCtr)0; me->tail = (QEQueueCtr)0; me->nFree = qLen; me->nMin = qLen; QS_BEGIN_(QS_QF_EQUEUE_INIT, QS_eqObj_, me) QS_OBJ_(qSto); /* this QEQueue object */ QS_EQC_(qLen); /* the length of the queue */ QS_END_() }
/*..........................................................................*/ QEvent const *QActive_get_(QActive *me) { INT8U err; QEvent const *e = (QEvent *)OSQPend((OS_EVENT *)me->eQueue, 0, &err); QS_INT_LOCK_KEY_ Q_ASSERT(err == OS_NO_ERR); QS_BEGIN_(QS_QF_ACTIVE_GET, QS_aoObj_, me) QS_TIME_(); /* timestamp */ QS_SIG_(e->sig); /* the signal of this event */ QS_OBJ_(me); /* this active object */ QS_U8_(EVT_POOL_ID(e)); /* the pool Id of the event */ QS_U8_(EVT_REF_CTR(e)); /* the ref count of the event */ QS_EQC_(0); /* number of free entries (unknown) */ QS_END_() return e; }
//**************************************************************************** /// @description /// Allocates an event dynamically from one of the QF event pools. /// /// @param[in] evtSize the size (in bytes) of the event to allocate /// @param[in] margin the number of un-allocated events still available /// in a given event pool after the allocation completes /// @param[in] sig the signal to be assigned to the allocated event /// /// @returns pointer to the newly allocated event. This pointer can be NULL /// only if margin!=0 and the event cannot be allocated with the specified /// margin still available in the given pool. /// /// @note The internal QF function QP::QF::newX_() raises an assertion when /// the margin argument is 0 and allocation of the event turns out to be /// impossible due to event pool depletion, or incorrect (too big) size /// of the requested event. /// /// @note The application code should not call this function directly. /// The only allowed use is thorough the macros Q_NEW() or Q_NEW_X(). /// QEvt *QF::newX_(uint_fast16_t const evtSize, uint_fast16_t const margin, enum_t const sig) { uint_fast8_t idx; // find the pool id that fits the requested event size ... for (idx = static_cast<uint_fast8_t>(0); idx < QF_maxPool_; ++idx) { if (evtSize <= QF_EPOOL_EVENT_SIZE_(QF_pool_[idx])) { break; } } // cannot run out of registered pools Q_ASSERT_ID(310, idx < QF_maxPool_); QS_CRIT_STAT_ QS_BEGIN_(QS_QF_NEW, static_cast<void *>(0), static_cast<void *>(0)) QS_TIME_(); // timestamp QS_EVS_(static_cast<QEvtSize>(evtSize)); // the size of the event QS_SIG_(static_cast<QSignal>(sig)); // the signal of the event QS_END_() QEvt *e; QF_EPOOL_GET_(QF_pool_[idx], e, margin); // get e -- platform-dependent // was e allocated correctly? if (e != static_cast<QEvt const *>(0)) { e->sig = static_cast<QSignal>(sig); // set the signal // store pool ID e->poolId_ = static_cast<uint8_t>( idx + static_cast<uint_fast8_t>(1)); // initialize the reference counter to 0 e->refCtr_ = static_cast<uint8_t>(0); } else { // event was not allocated, assert that the caller provided non-zero // margin, which means that they can tollerate bad allocation Q_ASSERT_ID(320, margin != static_cast<uint_fast16_t>(0)); } return e; }
/*..........................................................................*/ void QHsm_dispatch(QHsm *me, QEvent const *e) { QStateHandler path[QEP_MAX_NEST_DEPTH_]; QStateHandler s; QStateHandler t; QState r; QS_INT_LOCK_KEY_ t = me->state; /* save the current state */ QS_BEGIN_(QS_QEP_DISPATCH, QS_smObj_, me) QS_TIME_(); /* time stamp */ QS_SIG_(e->sig); /* the signal of the event */ QS_OBJ_(me); /* this state machine object */ QS_FUN_(t); /* the current state */ QS_END_() do { /* process the event hierarchically... */ s = me->state; r = (*s)(me, e); /* invoke state handler s */ } while (r == Q_RET_SUPER); if (r == Q_RET_TRAN) { /* transition taken? */ #ifdef Q_SPY QStateHandler src = s; /* save the transition source for tracing */ #endif int8_t ip = (int8_t)(-1); /* transition entry path index */ int8_t iq; /* helper transition entry path index */ path[0] = me->state; /* save the target of the transition */ path[1] = t; while (t != s) { /* exit current state to transition source s... */ if (QEP_TRIG_(t, Q_EXIT_SIG) == Q_RET_HANDLED) {/*exit handled? */ QS_BEGIN_(QS_QEP_STATE_EXIT, QS_smObj_, me) QS_OBJ_(me); /* this state machine object */ QS_FUN_(t); /* the exited state */ QS_END_() (void)QEP_TRIG_(t, QEP_EMPTY_SIG_); /* find superstate of t */ } t = me->state; /* me->state holds the superstate */ } t = path[0]; /* target of the transition */ if (s == t) { /* (a) check source==target (transition to self) */ QEP_EXIT_(s) /* exit the source */ ip = (int8_t)0; /* enter the target */ } else { (void)QEP_TRIG_(t, QEP_EMPTY_SIG_); /* superstate of target */ t = me->state; if (s == t) { /* (b) check source==target->super */ ip = (int8_t)0; /* enter the target */ } else { (void)QEP_TRIG_(s, QEP_EMPTY_SIG_); /* superstate of src */ /* (c) check source->super==target->super */ if (me->state == t) { QEP_EXIT_(s) /* exit the source */ ip = (int8_t)0; /* enter the target */ } else { /* (d) check source->super==target */ if (me->state == path[0]) { QEP_EXIT_(s) /* exit the source */ } else { /* (e) check rest of source==target->super->super.. * and store the entry path along the way */ iq = (int8_t)0; /* indicate that LCA not found */ ip = (int8_t)1; /* enter target and its superstate */ path[1] = t; /* save the superstate of target */ t = me->state; /* save source->super */ /* find target->super->super */ r = QEP_TRIG_(path[1], QEP_EMPTY_SIG_); while (r == Q_RET_SUPER) { ++ip; path[ip] = me->state; /* store the entry path */ if (me->state == s) { /* is it the source? */ iq = (int8_t)1; /* indicate that LCA found */ /* entry path must not overflow */ Q_ASSERT(ip < (int8_t)QEP_MAX_NEST_DEPTH_); --ip; /* do not enter the source */ r = Q_RET_HANDLED; /* terminate the loop */ } else { /* it is not the source, keep going up */ r = QEP_TRIG_(me->state, QEP_EMPTY_SIG_); } } if (iq == (int8_t)0) { /* the LCA not found yet? */ /* entry path must not overflow */ Q_ASSERT(ip < (int8_t)QEP_MAX_NEST_DEPTH_); QEP_EXIT_(s) /* exit the source */ /* (f) check the rest of source->super * == target->super->super... */ iq = ip; r = Q_RET_IGNORED; /* indicate LCA NOT found */ do { if (t == path[iq]) { /* is this the LCA? */ r = Q_RET_HANDLED;/* indicate LCA found */ ip = (int8_t)(iq - 1);/*do not enter LCA*/ iq = (int8_t)(-1);/* terminate the loop */ } else { --iq; /* try lower superstate of target */ } } while (iq >= (int8_t)0); if (r != Q_RET_HANDLED) { /* LCA not found yet? */ /* (g) check each source->super->... * for each target->super... */ r = Q_RET_IGNORED; /* keep looping */ do { /* exit t unhandled? */ if (QEP_TRIG_(t, Q_EXIT_SIG) == Q_RET_HANDLED) { QS_BEGIN_(QS_QEP_STATE_EXIT, QS_smObj_, me) QS_OBJ_(me); QS_FUN_(t); QS_END_() (void)QEP_TRIG_(t, QEP_EMPTY_SIG_); } t = me->state; /* set to super of t */ iq = ip; do { if (t == path[iq]) {/* is this LCA? */ /* do not enter LCA */ ip = (int8_t)(iq - 1); iq = (int8_t)(-1);/*break inner */ r = Q_RET_HANDLED;/*break outer */ } else { --iq; } } while (iq >= (int8_t)0); } while (r != Q_RET_HANDLED); } } } } } } /* retrace the entry path in reverse (desired) order... */ for (; ip >= (int8_t)0; --ip) { QEP_ENTER_(path[ip]) /* enter path[ip] */ } t = path[0]; /* stick the target into register */ me->state = t; /* update the current state */ /* drill into the target hierarchy... */ while (QEP_TRIG_(t, Q_INIT_SIG) == Q_RET_TRAN) { QS_BEGIN_(QS_QEP_STATE_INIT, QS_smObj_, me) QS_OBJ_(me); /* this state machine object */ QS_FUN_(t); /* the source (pseudo)state */ QS_FUN_(me->state); /* the target of the transition */ QS_END_() ip = (int8_t)0; path[0] = me->state; (void)QEP_TRIG_(me->state, QEP_EMPTY_SIG_); /* find superstate */ while (me->state != t) { ++ip; path[ip] = me->state; (void)QEP_TRIG_(me->state, QEP_EMPTY_SIG_);/*find superstate*/ } me->state = path[0]; /* entry path must not overflow */ Q_ASSERT(ip < (int8_t)QEP_MAX_NEST_DEPTH_); do { /* retrace the entry path in reverse (correct) order... */ QEP_ENTER_(path[ip]) /* enter path[ip] */ --ip; } while (ip >= (int8_t)0); t = path[0]; } QS_BEGIN_(QS_QEP_TRAN, QS_smObj_, me) QS_TIME_(); /* time stamp */ QS_SIG_(e->sig); /* the signal of the event */ QS_OBJ_(me); /* this state machine object */ QS_FUN_(src); /* the source of the transition */ QS_FUN_(t); /* the new active state */ QS_END_() }
/** * @description * Dispatches an event for processing to a meta state machine (MSM). * The processing of an event represents one run-to-completion (RTC) step. * * @param[in,out] me pointer (see @ref oop) * @param[in] e pointer to the event to be dispatched to the MSM * * @note * This function should be called only via the virtual table (see * QMSM_DISPATCH()) and should NOT be called directly in the applications. */ void QMsm_dispatch_(QMsm * const me, QEvt const * const e) { QMState const *s = me->state.obj; /* store the current state */ QMState const *t = s; QState r = (QState)Q_RET_SUPER; QS_CRIT_STAT_ /** @pre current state must be initialized */ Q_REQUIRE_ID(300, s != (QMState const *)0); QS_BEGIN_(QS_QEP_DISPATCH, QS_priv_.smObjFilter, me) QS_TIME_(); /* time stamp */ QS_SIG_(e->sig); /* the signal of the event */ QS_OBJ_(me); /* this state machine object */ QS_FUN_(s->stateHandler); /* the current state handler */ QS_END_() /* scan the state hierarchy up to the top state... */ do { r = (*t->stateHandler)(me, e); /* call state handler function */ /* event handled? (the most frequent case) */ if (r >= (QState)Q_RET_HANDLED) { break; /* done scanning the state hierarchy */ } /* event unhandled and passed to the superstate? */ else if (r == (QState)Q_RET_SUPER) { t = t->superstate; /* advance to the superstate */ } /* event unhandled and passed to a submachine superstate? */ else if (r == (QState)Q_RET_SUPER_SUB) { t = me->temp.obj; /* current host state of the submachie */ } /* event unhandled due to a guard? */ else if (r == (QState)Q_RET_UNHANDLED) { QS_BEGIN_(QS_QEP_UNHANDLED, QS_priv_.smObjFilter, me) QS_SIG_(e->sig); /* the signal of the event */ QS_OBJ_(me); /* this state machine object */ QS_FUN_(t->stateHandler); /* the current state */ QS_END_() t = t->superstate; /* advance to the superstate */ } else { /* no other return value should be produced */ Q_ERROR_ID(310); } } while (t != (QMState const *)0); /* any kind of transition taken? */ if (r >= (QState)Q_RET_TRAN) { #ifdef Q_SPY QMState const *ts = t; /* transition source for QS tracing */ /* the transition source state must not be NULL */ Q_ASSERT_ID(320, ts != (QMState const *)0); #endif /* Q_SPY*/ do { /* save the transition-action table before it gets clobbered */ QMTranActTable const *tatbl = me->temp.tatbl; /* was a regular state transition segment taken? */ if (r == (QState)Q_RET_TRAN) { QMsm_exitToTranSource_(me, s, t); r = QMsm_execTatbl_(me, tatbl); } /* was an initial transition segment taken? */ else if (r == (QState)Q_RET_TRAN_INIT) { r = QMsm_execTatbl_(me, tatbl); } /* was a transition segment to history taken? */ else if (r == (QState)Q_RET_TRAN_HIST) { QMState const *hist = me->state.obj; /* save history */ me->state.obj = s; /* restore the original state */ QMsm_exitToTranSource_(me, s, t); (void)QMsm_execTatbl_(me, tatbl); r = QMsm_enterHistory_(me, hist); } /* was a transition segment to an entry point taken? */ else if (r == (QState)Q_RET_TRAN_EP) { r = QMsm_execTatbl_(me, tatbl); } /* was a transition segment to an exit point taken? */ else if (r == (QState)Q_RET_TRAN_XP) { QActionHandler const act = me->state.act; /* save XP action */ me->state.obj = s; /* restore the original state */ r = (*act)(me); /* execute the XP action */ if (r == (QState)Q_RET_TRAN) { QMsm_exitToTranSource_(me, s, t); /* take the tran-to-XP segment inside submachine */ (void)QMsm_execTatbl_(me, tatbl); me->state.obj = s; /* restore original state (history) */ #ifdef Q_SPY t = me->temp.tatbl->target; /* store for tracing */ #endif /* Q_SPY */ /* take the XP-Segment from submachine-state */ r = QMsm_execTatbl_(me, me->temp.tatbl); QS_BEGIN_(QS_QEP_TRAN_XP, QS_priv_.smObjFilter, me) QS_OBJ_(me); /* this state machine object */ QS_FUN_(s); /* source handler */ QS_FUN_(t); /* target handler */ QS_END_() } }
/*..........................................................................*/ void QHsm_dispatch(QHsm *me, QEvent const *e) { QHsmState s; QHsmState t = ((QFsm *)me)->state__.hsm; QHsmState path[QEP_MAX_NEST_DEPTH_]; path[2] = t; /* save the current state in case a transition is taken */ do { /* process the event hierarchically... */ s = t; t = (QHsmState)((*s)(me, e)); /* invoke state handler s */ } while (t != (QHsmState)0); if (((QFsm *)me)->tran__ != Q_TRAN_NONE_TYPE) { /* transition taken? */ struct QTran_ *stran; if ((((QFsm *)me)->tran__ & Q_TRAN_STA_TYPE) != 0) {/* static tran? */ stran = ((QFsm *)me)->state__.tran; } else { path[0] = ((QFsm *)me)->state__.hsm; /* save the new state */ stran = (struct QTran_ *)0; } ((QFsm *)me)->state__.hsm = path[2]; /* restore current state */ path[1] = s; /* save the transition source */ /* exit current state to the transition source path[1]... */ for (s = path[2]; s != path[1]; ) { t = QEP_TRIG_(s, Q_EXIT_SIG); if (t != (QHsmState)0) { /* exit action unhandled */ s = t; /* t points to superstate */ } else { /* exit action handled */ QS_BEGIN_(QS_QEP_STATE_EXIT, QS_smObj_, me); QS_OBJ_(me); /* this state machine object */ QS_FUN_(s); /* the exited state */ QS_END_(); s = QEP_TRIG_(s, QEP_EMPTY_SIG_);/* find out the superstate */ } } if (stran != (struct QTran_ *)0) { /* static transition? */ uint16_t a = (uint16_t)stran->actions[0]; if (a != (uint16_t)0) { /* transition initialized? */ QHsmState const *c = stran->chain; for (a = (uint16_t)((uint16_t)(a | (stran->actions[1] << 8)) >> 1); a != (uint16_t)0; a >>= 2) { uint8_t sig = (uint8_t)(a & 0x3); (void)(*(*c))(me, &QEP_reservedEvt_[sig]); QS_BEGIN_(sig + (uint8_t)QS_QEP_STATE_EMPTY, QS_smObj_, me); QS_OBJ_(me); /* this state machine object */ QS_FUN_(*c); /* entered/exited/initialized state */ if (sig == (QSignal)Q_INIT_SIG) { QS_FUN_(((QFsm *)me)->state__.hsm); /* target */ } QS_END_(); ++c; /* advance in the chain of the stored actions */ } ((QFsm *)me)->state__.hsm = *c; /* set the new state */ } else { /* the static transition object not initialized yet */
/** * \description * Dispatches an event for processing to a hierarchical state machine (HSM). * The processing of an event represents one run-to-completion (RTC) step. * * \arguments * \arg[in,out] \c me pointer (see \ref derivation) * \arg[in] \c e pointer to the event to be dispatched to the HSM * * \note * This function should be called only via the virtual table (see * QMSM_DISPATCH()) and should NOT be called directly in the applications. */ void QHsm_dispatch_(QHsm * const me, QEvt const * const e) { QStateHandler t = me->state.fun; QStateHandler s; QState r; QS_CRIT_STAT_ /** \pre the state configuration must be stable */ Q_REQUIRE_ID(100, t == me->temp.fun); QS_BEGIN_(QS_QEP_DISPATCH, QS_priv_.smObjFilter, me) QS_TIME_(); /* time stamp */ QS_SIG_(e->sig); /* the signal of the event */ QS_OBJ_(me); /* this state machine object */ QS_FUN_(t); /* the current state */ QS_END_() /* process the event hierarchically... */ do { s = me->temp.fun; r = (*s)(me, e); /* invoke state handler s */ if (r == (QState)Q_RET_UNHANDLED) { /* unhandled due to a guard? */ QS_BEGIN_(QS_QEP_UNHANDLED, QS_priv_.smObjFilter, me) QS_SIG_(e->sig); /* the signal of the event */ QS_OBJ_(me); /* this state machine object */ QS_FUN_(s); /* the current state */ QS_END_() r = QEP_TRIG_(s, QEP_EMPTY_SIG_); /* find superstate of s */ } } while (r == (QState)Q_RET_SUPER); /* transition taken? */ if (r >= (QState)Q_RET_TRAN) { QStateHandler path[QHSM_MAX_NEST_DEPTH_]; int_fast8_t ip; path[0] = me->temp.fun; /* save the target of the transition */ path[1] = t; path[2] = s; /* exit current state to transition source s... */ for (; t != s; t = me->temp.fun) { if (QEP_TRIG_(t, Q_EXIT_SIG) == (QState)Q_RET_HANDLED) { QS_BEGIN_(QS_QEP_STATE_EXIT, QS_priv_.smObjFilter, me) QS_OBJ_(me); /* this state machine object */ QS_FUN_(t); /* the exited state */ QS_END_() (void)QEP_TRIG_(t, QEP_EMPTY_SIG_); /* find superstate of t */ } } ip = QHsm_tran_(me, path); #ifdef Q_SPY if (r == (QState)Q_RET_TRAN_HIST) { QS_BEGIN_(QS_QEP_TRAN_HIST, QS_priv_.smObjFilter, me) QS_OBJ_(me); /* this state machine object */ QS_FUN_(t); /* the source of the transition */ QS_FUN_(path[0]);/* the target of the tran. to history */ QS_END_() }
/*..........................................................................*/ void QHsm_execTran(QHsm *me, QHsmState path[], struct QTran_ *tran) { QHsmState s; QHsmState t = path[0]; /* target of the transition */ QHsmState const src = path[1]; /* source of the transition */ uint16_t actions = (uint16_t)0; /* actions bitmask for static tran. */ uint8_t ic = (uint8_t)0; /* static-transition chain index */ int8_t ip = (int8_t)(-1); /* transition entry path index */ int8_t iq; /* helper transition entry path index */ if (src == t) { /* (a) check source == target (transition to self) */ QEP_EXIT_AND_REC_(src); /* exit the source */ ++ip; /* enter the target */ } else { t = QEP_TRIG_(t, QEP_EMPTY_SIG_);/* put superstate of target into t */ if (src == t) { /* (b) check source == target->super */ ++ip; /* enter the target */ } else { s = QEP_TRIG_(src, QEP_EMPTY_SIG_);/*superstate of source into s*/ if (s == t) { /* (c) check source->super == target->super */ QEP_EXIT_AND_REC_(src); /* exit the source */ ++ip; /* enter the target */ } else { if (s == path[0]) { /* (d) check source->super == target */ QEP_EXIT_AND_REC_(src); /* exit the source */ } else { /* (e) check rest of source == target->super->super... * and store the entry path along the way */ iq = (int8_t)0; /* indicate that LCA not found */ ++ip; /* enter the target */ path[++ip] = t; /* enter the superstate of target */ t = QEP_TRIG_(t, QEP_EMPTY_SIG_); while (t != (QHsmState)0) { path[++ip] = t; /* store the entry path */ if (t == src) { /* is it the source? */ iq = (int8_t)1; /* indicate that the LCA found */ /* entry path must not overflow */ Q_ASSERT(ip < (int8_t)QEP_MAX_NEST_DEPTH_); --ip; /* do not enter the source */ t = (QHsmState)0; /* terminate the loop */ } else { /* it is not the source, keep going up */ t = QEP_TRIG_(t, QEP_EMPTY_SIG_); } } if (iq == (int8_t)0) { /* the LCA not found yet? */ /* entry path must not overflow */ Q_ASSERT(ip < (int8_t)QEP_MAX_NEST_DEPTH_); QEP_EXIT_AND_REC_(src); /* exit source */ /* (f) check the rest of source->super * == target->super->super... */ iq = ip; do { if (s == path[iq]) { /* is this the LCA? */ t = s; /* indicate that the LCA is found */ ip = (int8_t)(iq - 1); /* do not enter LCA */ iq = (int8_t)(-1); /* terminate the loop */ } else { --iq; /* try lower superstate of target */ } } while (iq >= (int8_t)0); if (t == (QHsmState)0) { /* the LCA not found yet? */ /* (g) check each source->super->... * for each target->super... */ do { t = QEP_TRIG_(s, Q_EXIT_SIG); /* exit s */ if (t != (QHsmState)0) { /* exit unhandled */ s = t; /* t points to superstate of s */ } else { /* exit action handled */ QS_BEGIN_(QS_QEP_STATE_EXIT, QS_smObj_, me); QS_OBJ_(me); QS_FUN_(s); QS_END_(); if (tran != (struct QTran_ *)0) { QEP_REC_(s, Q_EXIT_SIG); } s = QEP_TRIG_(s, QEP_EMPTY_SIG_); } iq = ip; do { if (s == path[iq]) {/* is this the LCA? */ /* do not enter the LCA */ ip = (int8_t)(iq - 1); iq = (int8_t)(-1);/*break inner loop*/ s = (QHsmState)0; /* and outer loop */ } else { --iq; } } while (iq >= (int8_t)0); } while (s != (QHsmState)0); } } } } } } /* retrace the entry path in reverse (desired) order... */ for (; ip >= (int8_t)0; --ip) { QEP_ENTER_AND_REC_(path[ip]); /* enter path[ip] */ } s = path[0]; /* stick the target into register */ ((QFsm *)me)->state__.hsm = s; /* update the current state */ while (QEP_TRIG_(s, Q_INIT_SIG) == (QHsmState)0) { /* drill into target */ t = ((QFsm *)me)->state__.hsm; QS_BEGIN_(QS_QEP_STATE_INIT, QS_smObj_, me); QS_OBJ_(me); /* this state machine object */ QS_FUN_(s); /* the source (pseudo)state */ QS_FUN_(t); /* the target of the transition */ QS_END_(); if (tran != (struct QTran_ *)0) { /* static tranistion? */ QEP_REC_(s, Q_INIT_SIG); } /* store the entry path to s */ path[0] = t; ip = (int8_t)0; for (t = QEP_TRIG_(t, QEP_EMPTY_SIG_); t != s; t = QEP_TRIG_(t, QEP_EMPTY_SIG_)) { path[++ip] = t; } /* entry path must not overflow */ Q_ASSERT(ip < (int8_t)QEP_MAX_NEST_DEPTH_); do { /* retrace the entry path in reverse (correct) order... */ QEP_ENTER_AND_REC_(path[ip]); /* enter path[ip] */ --ip; } while (ip >= (int8_t)0); s = ((QFsm *)me)->state__.hsm; } if (tran != (struct QTran_ *)0) { /* static transition? */ /* transition chain must not overflow */ Q_ENSURE(ic < (uint8_t)Q_DIM(tran->chain)); tran->chain[ic] = s; /* store the ultimate target of the transition */ actions = (uint16_t)(actions >> (15 - (ic << 1))); tran->actions[1] = (uint8_t)(actions >> 8); tran->actions[0] = (uint8_t)(actions | 0x1); }