/*..........................................................................*/ void QTimeEvt_arm_(QTimeEvt *me, QActive *act, QTimeEvtCtr nTicks) { QF_CRIT_STAT_ Q_REQUIRE((nTicks > (QTimeEvtCtr)0) /* cannot arm a timer with 0 ticks */ && (me->super.sig >= (QSignal)Q_USER_SIG) /* valid signal */ && (me->prev == (QTimeEvt *)0) /* time evt must NOT be used */ && (act != (QActive *)0)); /* active object must be provided */ me->ctr = nTicks; me->prev = me; /* mark the timer in use */ me->act = act; QF_CRIT_ENTRY_(); QS_BEGIN_NOCRIT_(QS_QF_TIMEEVT_ARM, QS_teObj_, me) QS_TIME_(); /* timestamp */ QS_OBJ_(me); /* this time event object */ QS_OBJ_(act); /* the active object */ QS_TEC_(nTicks); /* the number of ticks */ QS_TEC_(me->interval); /* the interval */ QS_END_NOCRIT_() me->next = QF_timeEvtListHead_; if (QF_timeEvtListHead_ != (QTimeEvt *)0) { QF_timeEvtListHead_->prev = me; } QF_timeEvtListHead_ = me; QF_CRIT_EXIT_(); }
/*..........................................................................*/ uint8_t QTimeEvt_rearm(QTimeEvt * const me, QTimeEvtCtr const nTicks) { uint8_t isArmed; QF_CRIT_STAT_ Q_REQUIRE((nTicks != (QTimeEvtCtr)0) /* cannot arm a timer with 0 ticks */ && (me->act != (QActive *)0) /* active object must be valid */ && (me->super.sig >= (QSignal)Q_USER_SIG)); /* valid signal */ QF_CRIT_ENTRY_(); if (me->ctr == (QTimeEvtCtr)0) { /* is the time evt disarmed? */ isArmed = (uint8_t)0; if (QF_EVT_REF_CTR_(&me->super) == (uint8_t)0) { /* not linked? */ me->next = QF_timeEvtListHead_; QF_timeEvtListHead_ = me; QF_EVT_REF_CTR_INC_(&me->super); /* mark as linked */ } } else { /* the time event is armed */ isArmed = (uint8_t)1; } me->ctr = nTicks; /* re-load the tick counter (shift the phasing) */ QS_BEGIN_NOCRIT_(QS_QF_TIMEEVT_REARM, QS_teObj_, me) QS_TIME_(); /* timestamp */ QS_OBJ_(me); /* this time event object */ QS_OBJ_(me->act); /* the active object */ QS_TEC_(me->ctr); /* the number of ticks */ QS_TEC_(me->interval); /* the interval */ QS_U8_(isArmed); /* was the timer armed? */ QS_END_NOCRIT_() QF_CRIT_EXIT_(); return isArmed; }
//............................................................................ // NOTE: disarm a time evt (no harm in disarming an already disarmed time evt) uint8_t QTimeEvt::disarm(void) { uint8_t wasArmed; QF_INT_LOCK_KEY_ QF_INT_LOCK_(); if (m_prev != (QTimeEvt *)0) { // is the time event actually armed? wasArmed = (uint8_t)1; if (this == QF_timeEvtListHead_) { QF_timeEvtListHead_ = m_next; } else { if (m_next != (QTimeEvt *)0) { // not the last in the list? m_next->m_prev = m_prev; } m_prev->m_next = m_next; } m_prev = (QTimeEvt *)0; // mark the time event as disarmed QS_BEGIN_NOLOCK_(QS_QF_TIMEEVT_DISARM, QS::teObj_, this) QS_TIME_(); // timestamp QS_OBJ_(this); // this time event object QS_OBJ_(m_act); // the active object QS_TEC_(m_ctr); // the number of ticks QS_TEC_(m_interval); // the interval QS_END_NOLOCK_() }
/* NOTE: disarm a timer (no harm in disarming an already disarmed timer) */ uint8_t QTimeEvt_disarm(QTimeEvt * const me) { uint8_t wasArmed; QF_CRIT_STAT_ QF_CRIT_ENTRY_(); if (me->ctr != (QTimeEvtCtr)0) { /* is the time evt running? */ wasArmed = (uint8_t)1; QS_BEGIN_NOCRIT_(QS_QF_TIMEEVT_DISARM, QS_priv_.teObjFilter, me) QS_TIME_(); /* timestamp */ QS_OBJ_(me); /* this time event object */ QS_OBJ_(me->act); /* the target AO */ QS_TEC_(me->ctr); /* the number of ticks */ QS_TEC_(me->interval); /* the interval */ QS_U8_((uint8_t)(me->super.refCtr_ & (uint8_t)0x7F));/*tick rate*/ QS_END_NOCRIT_() me->ctr = (QTimeEvtCtr)0; /* schedule removal from the list */ } else { /* the time event was already not running */ wasArmed = (uint8_t)0; QS_BEGIN_NOCRIT_(QS_QF_TIMEEVT_DISARM_ATTEMPT, QS_priv_.teObjFilter, me) QS_TIME_(); /* timestamp */ QS_OBJ_(me); /* this time event object */ QS_OBJ_(me->act); /* the target AO */ QS_U8_((uint8_t)(me->super.refCtr_ & (uint8_t)0x7F));/*tick rate*/ QS_END_NOCRIT_() } QF_CRIT_EXIT_(); return wasArmed; }
/* NOTE: disarm a timer (no harm in disarming an already disarmed timer) */ uint8_t QTimeEvt_disarm(QTimeEvt *me) { uint8_t wasArmed; QF_INT_LOCK_KEY_ QF_INT_LOCK_(); if (me->prev != (QTimeEvt *)0) { /* is the time event actually armed? */ wasArmed = (uint8_t)1; if (me == QF_timeEvtListHead_) { QF_timeEvtListHead_ = me->next; } else { if (me->next != (QTimeEvt *)0) { /* not the last in the list? */ me->next->prev = me->prev; } me->prev->next = me->next; } me->prev = (QTimeEvt *)0; /* mark the time event as disarmed */ QS_BEGIN_NOLOCK_(QS_QF_TIMEEVT_DISARM, QS_teObj_, me) QS_TIME_(); /* timestamp */ QS_OBJ_(me); /* this time event object */ QS_OBJ_(me->act); /* the active object */ QS_TEC_(me->ctr); /* the number of ticks */ QS_TEC_(me->interval); /* the interval */ QS_END_NOLOCK_() }
/** * \description * Arms a time event to fire in a specified number of clock ticks and with * a specified interval. If the interval is zero, the time event is armed for * one shot ('one-shot' time event). The time event gets directly posted * (using the FIFO policy) into the event queue of the host active object. * * \arguments * \arg[in,out] \c me pointer (see \ref derivation) * \arg[in] \c nTicks number of clock ticks (at the associated rate) * to rearm the time event with. * \arg[in] \c interval interval (in clock ticks) for periodic time event. * * \note After posting, a one-shot time event gets automatically disarmed * while a periodic time event (interval != 0) is automatically re-armed. * * \note A time event can be disarmed at any time by calling the * QTimeEvt_disarm() function. Also, a time event can be re-armed to fire * in a different number of clock ticks by calling the QTimeEvt_rearm() * function. * * \usage * The following example shows how to arm a one-shot time event from a state * machine of an active object: * \include qf_state.c */ void QTimeEvt_armX(QTimeEvt * const me, QTimeEvtCtr const nTicks, QTimeEvtCtr const interval) { uint_fast8_t tickRate = (uint_fast8_t)me->super.refCtr_ & (uint_fast8_t)0x7F; QTimeEvtCtr ctr = me->ctr; QF_CRIT_STAT_ /** \pre the host AO must be valid, time evnet must be disarmed, * number of clock ticks cannot be zero, and the signal must be valid. */ Q_REQUIRE_ID(100, (me->act != (void *)0) && (ctr == (QTimeEvtCtr)0) && (nTicks != (QTimeEvtCtr)0) && (tickRate < (uint_fast8_t)QF_MAX_TICK_RATE) && (me->super.sig >= (QSignal)Q_USER_SIG)); QF_CRIT_ENTRY_(); me->ctr = nTicks; me->interval = interval; /* is the time event unlinked? * NOTE: For the duration of a single clock tick of the specified tick * rate a time event can be disarmed and yet still linked into the list, * because un-linking is performed exclusively in the QF_tickX() function. */ if ((me->super.refCtr_ & (uint8_t)0x80) == (uint8_t)0) { me->super.refCtr_ |= (uint8_t)0x80; /* mark as linked */ /* The time event is initially inserted into the separate * "freshly armed" link list based on QF_timeEvtHead_[tickRate].act. * Only later, inside the QF_tickX() function, the "freshly armed" * list is appended to the main list of armed time events based on * QF_timeEvtHead_[tickRate].next. Again, this is to keep any * changes to the main list exclusively inside the QF_tickX() * function. */ me->next = (QTimeEvt *)QF_timeEvtHead_[tickRate].act; QF_timeEvtHead_[tickRate].act = me; } QS_BEGIN_NOCRIT_(QS_QF_TIMEEVT_ARM, QS_priv_.teObjFilter, me) QS_TIME_(); /* timestamp */ QS_OBJ_(me); /* this time event object */ QS_OBJ_(me->act); /* the active object */ QS_TEC_(nTicks); /* the number of ticks */ QS_TEC_(interval); /* the interval */ QS_U8_((uint8_t)tickRate); /* tick rate */ QS_END_NOCRIT_() QF_CRIT_EXIT_(); }
void QF_tick(void) { /* see NOTE01 */ #else void QF_tick(void const *sender) { #endif QTimeEvt *t; QF_CRIT_STAT_ QF_CRIT_ENTRY_(); QS_BEGIN_NOCRIT_(QS_QF_TICK, (void *)0, (void *)0) QS_TEC_((QTimeEvtCtr)(++QS_tickCtr_)); /* the tick counter */ QS_END_NOCRIT_() t = QF_timeEvtListHead_; while (t != (QTimeEvt *)0) { --t->ctr; if (t->ctr == (QTimeEvtCtr)0) { /* is time evt about to expire? */ if (t->interval != (QTimeEvtCtr)0) { /* is it periodic timeout? */ t->ctr = t->interval; /* rearm the time event */ } else { /* one-shot timeout, disarm by removing it from the list */ if (t == QF_timeEvtListHead_) { QF_timeEvtListHead_ = t->next; } else { if (t->next != (QTimeEvt *)0) { /* not the last event? */ t->next->prev = t->prev; } t->prev->next = t->next; } t->prev = (QTimeEvt *)0; /* mark the event disarmed */ QS_BEGIN_NOCRIT_(QS_QF_TIMEEVT_AUTO_DISARM, QS_teObj_, t) QS_OBJ_(t); /* this time event object */ QS_OBJ_(t->act); /* the active object */ QS_END_NOCRIT_() } QS_BEGIN_NOCRIT_(QS_QF_TIMEEVT_POST, QS_teObj_, t) QS_TIME_(); /* timestamp */ QS_OBJ_(t); /* the time event object */ QS_SIG_(t->super.sig); /* signal of this time event */ QS_OBJ_(t->act); /* the active object */ QS_END_NOCRIT_() QF_CRIT_EXIT_();/* exit crit. section before calling QF service */ /* QACTIVE_POST() asserts internally if the queue overflows */ QACTIVE_POST(t->act, &t->super, sender); } else { static uint8_t volatile dummy; QF_CRIT_EXIT_(); dummy = (uint8_t)0; /* execute a few instructions, see NOTE02 */ } QF_CRIT_ENTRY_(); /* enter crit. section again to advance the link */ t = t->next; }
/*..........................................................................*/ void QF_tick(void) { /* see NOTE01 */ QTimeEvt *t; QF_INT_LOCK_KEY_ QF_INT_LOCK_(); QS_BEGIN_NOLOCK_(QS_QF_TICK, (void *)0, (void *)0) QS_TEC_(++QS_tickCtr_); /* the tick counter */ QS_END_NOLOCK_() t = QF_timeEvtListHead_; while (t != (QTimeEvt *)0) { --t->ctr; if (t->ctr == (QTimeEvtCtr)0) { /* is time evt about to expire? */ if (t->interval != (QTimeEvtCtr)0) { /* is it periodic timeout? */ t->ctr = t->interval; /* rearm the time event */ } else { /* one-shot timeout, disarm by removing it from the list */ if (t == QF_timeEvtListHead_) { QF_timeEvtListHead_ = t->next; } else { if (t->next != (QTimeEvt *)0) { /* not the last event? */ t->next->prev = t->prev; } t->prev->next = t->next; } t->prev = (QTimeEvt *)0; /* mark the event disarmed */ QS_BEGIN_NOLOCK_(QS_QF_TIMEEVT_AUTO_DISARM, QS_teObj_, t) QS_OBJ_(t); /* this time event object */ QS_OBJ_(t->act); /* the active object */ QS_END_NOLOCK_() } QS_BEGIN_NOLOCK_(QS_QF_TIMEEVT_POST, QS_teObj_, t) QS_TIME_(); /* timestamp */ QS_OBJ_(t); /* the time event object */ QS_SIG_(t->super.sig); /* signal of this time event */ QS_OBJ_(t->act); /* the active object */ QS_END_NOLOCK_() QF_INT_UNLOCK_();/* unlock interrupts before calling QF service */ /* postFIFO() asserts internally that the event was accepted */ QActive_postFIFO(t->act, (QEvent *)t); } else { static uint8_t volatile dummy; QF_INT_UNLOCK_(); dummy = (uint8_t)0; /* execute a few instructions, see NOTE02 */ } QF_INT_LOCK_(); /* lock interrupts again to advance the link */ t = t->next; }
/*..........................................................................*/ QTimeEvtCtr QTimeEvt_ctr(QTimeEvt const * const me) { QTimeEvtCtr ret; QF_CRIT_STAT_ QF_CRIT_ENTRY_(); ret = me->ctr; QS_BEGIN_NOCRIT_(QS_QF_TIMEEVT_CTR, QS_priv_.teObjFilter, me) QS_TIME_(); /* timestamp */ QS_OBJ_(me); /* this time event object */ QS_OBJ_(me->act); /* the target AO */ QS_TEC_(ret); /* the current counter */ QS_TEC_(me->interval); /* the interval */ QS_U8_((uint8_t)(me->super.refCtr_ & (uint8_t)0x7F)); /* tick rate */ QS_END_NOCRIT_() QF_CRIT_EXIT_(); return ret; }
/* NOTE: disarm a timer (no harm in disarming an already disarmed timer) */ uint8_t QTimeEvt_disarm(QTimeEvt *me) { uint8_t wasArmed; QF_INT_LOCK_KEY_ QF_INT_LOCK_(); if (me->prev__ != (QTimeEvt *)0) { /* is the time event actually armed? */ wasArmed = (uint8_t)1; if (me == QF_timeEvtListHead_) { QF_timeEvtListHead_ = me->next__; } else { if (me->next__ != (QTimeEvt *)0) { /* not the last in the list? */ me->next__->prev__ = me->prev__; } me->prev__->next__ = me->next__; } me->prev__ = (QTimeEvt *)0; /* mark the time event as disarmed */ QS_BEGIN_NOLOCK_(QS_QF_TIMEEVT_DISARM, QS_teObj_, me); QS_TIME_(); /* timestamp */ QS_OBJ_(me); /* this time event object */ QS_OBJ_(me->act__); /* the active object */ QS_TEC_(me->ctr__); /* the number of ticks */ QS_TEC_(me->interval__); /* the interval */ QS_END_NOLOCK_(); } else { /* the time event was not armed */ wasArmed = (uint8_t)0; QS_BEGIN_NOLOCK_(QS_QF_TIMEEVT_DISARM_ATTEMPT, QS_teObj_, me); QS_TIME_(); /* timestamp */ QS_OBJ_(me); /* this time event object */ QS_OBJ_(me->act__); /* the active object */ QS_END_NOLOCK_(); } QF_INT_UNLOCK_(); return wasArmed; }
void QF_tick(void const * const sender) #endif { QTimeEvt *t; QTimeEvt *prev = (QTimeEvt *)0; QF_CRIT_STAT_ QF_CRIT_ENTRY_(); QS_BEGIN_NOCRIT_(QS_QF_TICK, (void *)0, (void *)0) QS_TEC_((QTimeEvtCtr)(++QS_tickCtr_)); /* the tick counter */ QS_END_NOCRIT_() for (t = QF_timeEvtListHead_; t != (QTimeEvt *)0; t = t->next) { if (t->ctr == (QTimeEvtCtr)0) { /* time evt. scheduled for removal? */ if (t == QF_timeEvtListHead_) { QF_timeEvtListHead_ = t->next; } else { Q_ASSERT(prev != (QTimeEvt *)0); prev->next = t->next; } QF_EVT_REF_CTR_DEC_(&t->super); /* mark as not linked */ } else { --t->ctr; if (t->ctr == (QTimeEvtCtr)0) { /* is time evt about to expire? */ if (t->interval != (QTimeEvtCtr)0) { /* periodic time evt? */ t->ctr = t->interval; /* rearm the time event */ } else { QS_BEGIN_NOCRIT_(QS_QF_TIMEEVT_AUTO_DISARM, QS_teObj_, t) QS_OBJ_(t); /* this time event object */ QS_OBJ_(t->act); /* the active object */ QS_END_NOCRIT_() } QS_BEGIN_NOCRIT_(QS_QF_TIMEEVT_POST, QS_teObj_, t) QS_TIME_(); /* timestamp */ QS_OBJ_(t); /* the time event object */ QS_SIG_(t->super.sig); /* signal of this time event */ QS_OBJ_(t->act); /* the active object */ QS_END_NOCRIT_() QF_CRIT_EXIT_(); /* exit crit. section before posting */ /* QACTIVE_POST() asserts internally if the queue overflows */ QACTIVE_POST(t->act, &t->super, sender); QF_CRIT_ENTRY_(); /* re-enter crit. section to continue */ if (t->ctr == (QTimeEvtCtr)0) { /* still marked to expire? */ if (t == QF_timeEvtListHead_) { QF_timeEvtListHead_ = t->next; } else { Q_ASSERT(prev != (QTimeEvt *)0); prev->next = t->next; } QF_EVT_REF_CTR_DEC_(&t->super); /* mark as removed */ } else { prev = t; } } else { prev = t; } } }
void QF_tickX_(uint_fast8_t const tickRate, void const * const sender) #endif { QTimeEvt *prev = &QF_timeEvtHead_[tickRate]; QF_CRIT_STAT_ QF_CRIT_ENTRY_(); QS_BEGIN_NOCRIT_(QS_QF_TICK, (void *)0, (void *)0) QS_TEC_((QTimeEvtCtr)(++prev->ctr)); /* tick ctr */ QS_U8_((uint8_t)tickRate); /* tick rate */ QS_END_NOCRIT_() /* scan the linked-list of time events at this rate... */ for (;;) { QTimeEvt *t = prev->next; /* advance down the time evt. list */ /* end of the list? */ if (t == (QTimeEvt *)0) { /* any new time events armed since the last run of QF_tickX_()? */ if (QF_timeEvtHead_[tickRate].act != (void *)0) { /* sanity check */ Q_ASSERT_ID(110, prev != (QTimeEvt *)0); prev->next = (QTimeEvt *)QF_timeEvtHead_[tickRate].act; QF_timeEvtHead_[tickRate].act = (void *)0; t = prev->next; /* switch to the new list */ } else { break; /* all currently armed time evts. processed */ } } /* time event scheduled for removal? */ if (t->ctr == (QTimeEvtCtr)0) { prev->next = t->next; t->super.refCtr_ &= (uint8_t)0x7F; /* mark as unlinked */ /* do NOT advance the prev pointer */ QF_CRIT_EXIT_(); /* exit crit. section to reduce latency */ /* prevent merging critical sections, see NOTE1 below */ QF_CRIT_EXIT_NOP(); } else { --t->ctr; /* is time event about to expire? */ if (t->ctr == (QTimeEvtCtr)0) { QMActive *act = (QMActive *)t->act; /* temp. for volatile */ /* periodic time evt? */ if (t->interval != (QTimeEvtCtr)0) { t->ctr = t->interval; /* rearm the time event */ prev = t; /* advance to this time event */ } /* one-shot time event: automatically disarm */ else { prev->next = t->next; t->super.refCtr_ &= (uint8_t)0x7F; /* mark as unlinked */ /* do NOT advance the prev pointer */ QS_BEGIN_NOCRIT_(QS_QF_TIMEEVT_AUTO_DISARM, QS_priv_.teObjFilter, t) QS_OBJ_(t); /* this time event object */ QS_OBJ_(act); /* the target AO */ QS_U8_((uint8_t)tickRate); /* tick rate */ QS_END_NOCRIT_() } QS_BEGIN_NOCRIT_(QS_QF_TIMEEVT_POST, QS_priv_.teObjFilter, t) QS_TIME_(); /* timestamp */ QS_OBJ_(t); /* the time event object */ QS_SIG_(t->super.sig); /* signal of this time event */ QS_OBJ_(act); /* the target AO */ QS_U8_((uint8_t)tickRate); /* tick rate */ QS_END_NOCRIT_() QF_CRIT_EXIT_(); /* exit critical section before posting */ /* QACTIVE_POST() asserts internally if the queue overflows */ QACTIVE_POST(act, &t->super, sender); } else { prev = t; /* advance to this time event */ QF_CRIT_EXIT_(); /* exit crit. section to reduce latency */ /* prevent merging critical sections, see NOTE1 below */ QF_CRIT_EXIT_NOP(); } }