Example #1
0
/**
* \description
* This function initializes one event pool at a time and must be called
* exactly once for each event pool before the pool can be used.
*
* \arguments
* \arg[in] \c poolSto  pointer to the storage for the event pool
* \arg[in] \c poolSize size of the storage for the pool in bytes
* \arg[in] \c evtSize  the block-size of the pool in bytes, which determines
*             the maximum size of events that can be allocated from the pool.
*
* \note
* You might initialize many event pools by making many consecutive calls
* to the QF_poolInit() function. However, for the simplicity of the internal
* implementation, you must initialize event pools in the ascending order of
* the event size.
*
* Many RTOSes provide fixed block-size heaps, a.k.a. memory pools that can
* be adapted for QF event pools. In case such support is missing, QF provides
* a native QF event pool implementation. The macro #QF_EPOOL_TYPE_ determines
* the type of event pool used by a particular QF port. See structure ::QMPool
* for more information.
*
* \note The actual number of events available in the pool might be actually
* less than (\a poolSize / \a evtSize) due to the internal alignment
* of the blocks that the pool might perform. You can always check the
* capacity of the pool by calling QF_getPoolMin().
*
* \note The dynamic allocation of events is optional, meaning that you
* might choose not to use dynamic events. In that case calling QF_poolInit()
* and using up memory for the memory blocks is unnecessary.
*
* \sa QF initialization example for QF_init()
*/
void QF_poolInit(void * const poolSto, uint_fast16_t const poolSize,
                 uint_fast16_t const evtSize)
{
    /** \pre cannot exceed the number of available memory pools */
    Q_REQUIRE_ID(100, QF_maxPool_ < (uint_fast8_t)Q_DIM(QF_pool_));
    /** \pre please initialize event pools in ascending order of evtSize: */
    Q_REQUIRE_ID(101, (QF_maxPool_ == (uint_fast8_t)0)
        || (QF_EPOOL_EVENT_SIZE_(QF_pool_[QF_maxPool_ - (uint_fast8_t)1])
            < evtSize));

    /* perform the platform-dependent initialization of the pool */
    QF_EPOOL_INIT_(QF_pool_[QF_maxPool_],
                   poolSto, poolSize, evtSize);
    ++QF_maxPool_; /* one more pool */
}
Example #2
0
//****************************************************************************
/// @description
/// This function is part of the Publish-Subscribe event delivery mechanism
/// available in QF. Un-subscribing from all events means that the framework
/// will stop posting any published events to the event queue of the active
/// object.
///
/// @note Due to the latency of event queues, an active object should NOT
/// assume that no events will ever be dispatched to the state machine of
/// the active object after un-subscribing from all events.
/// The events might be already in the queue, or just about to be posted
/// and the un-subscribe operation will not flush such events. Also, the
/// alternative event-delivery mechanisms, such as direct event posting or
/// time events, can be still delivered to the event queue of the active
/// object.
///
/// @sa QP::QF::publish_(), QP::QMActive::subscribe(), and
/// QP::QMActive::unsubscribe()
///
void QMActive::unsubscribeAll(void) const {
    uint_fast8_t const p = m_prio;

    Q_REQUIRE_ID(500, (static_cast<uint_fast8_t>(0) < p)
                      && (p <= static_cast<uint_fast8_t>(QF_MAX_ACTIVE))
                      && (QF::active_[p] == this));

    uint_fast8_t const i =
        static_cast<uint_fast8_t>(QF_div8Lkup[p]);

    enum_t sig;
    for (sig = Q_USER_SIG; sig < QF_maxSignal_; ++sig) {
        QF_CRIT_STAT_
        QF_CRIT_ENTRY_();
        if ((QF_PTR_AT_(QF_subscrList_, sig).m_bits[i]
             & QF_pwr2Lkup[p]) != static_cast<uint8_t>(0))
        {

            QS_BEGIN_NOCRIT_(QS_QF_ACTIVE_UNSUBSCRIBE,
                             QS::priv_.aoObjFilter, this)
                QS_TIME_();     // timestamp
                QS_SIG_(sig);   // the signal of this event
                QS_OBJ_(this);  // this active object
            QS_END_NOCRIT_()

            // clear the priority bit
            QF_PTR_AT_(QF_subscrList_, sig).m_bits[i] &= QF_invPwr2Lkup[p];
        }
        QF_CRIT_EXIT_();
    }
}
Example #3
0
//****************************************************************************
// @description
// Starts execution of the AO and registers the AO with the framework.
//
// @param[in] prio    priority at which to start the active object
// @param[in] qSto    pointer to the storage for the ring buffer of the
//                    event queue (used only with the built-in QP::QEQueue)
// @param[in] qLen    length of the event queue (in events)
// @param[in] stkSto  pointer to the stack storage (used only when
//                    per-AO stack is needed)
// @param[in] stkSize stack size (in bytes)
// @param[in] ie      pointer to the optional initialization event
//                    (might be NULL).
//
void QMActive::start(uint_fast8_t const prio,
                     QEvt const *qSto[], uint_fast16_t const qLen,
                     void * const stkSto, uint_fast16_t const stkSize,
                     QEvt const * const ie)
{
    Q_REQUIRE_ID(200, (!QXK_ISR_CONTEXT_()) /* don't start AO's in an ISR! */
                      && (prio <= (uint_fast8_t)QF_MAX_ACTIVE)
                      && (qSto != static_cast<QEvt const **>(0))
                      && (qLen != static_cast<uint_fast16_t>(0))
                      && (stkSto != static_cast<void *>(0))
                      && (stkSize != static_cast<uint_fast16_t>(0)));

    m_eQueue.init(qSto, qLen);   // initialize QEQueue of this AO

    // initialize the stack of the private thread
    QXK_stackInit_(this,
                   static_cast<QXThreadHandler>(&thread_ao),
                   stkSto, stkSize);

    m_prio = prio;               // set the QF priority of this AO
    QF::add_(this);              // make QF aware of this AO

    this->init(ie); // take the top-most initial tran. (virtual)
    QS_FLUSH();     // flush the trace buffer to the host

    QF_CRIT_STAT_
    QF_CRIT_ENTRY_();
    QXK_attr_.readySet.insert(m_prio);
    if (QXK_attr_.curr != static_cast<QMActive *>(0)) { // is QXK running?
        QXK_sched_();
    }
    QF_CRIT_EXIT_();
}
Example #4
0
//****************************************************************************
void QXThread::start(uint_fast8_t const prio,
                       QEvt const *qSto[], uint_fast16_t const qLen,
                       void * const stkSto, uint_fast16_t const stkSize,
                       QEvt const * const /*ie*/)
{
    QF_CRIT_STAT_

    Q_REQUIRE_ID(300, (!QXK_ISR_CONTEXT_()) /* don't start AO's in an ISR! */
        && (prio <= static_cast<uint_fast8_t>(QF_MAX_ACTIVE))
        && (stkSto != static_cast<void *>(0))
        && (stkSize != static_cast<uint_fast16_t>(0))
        && (m_state.act == static_cast<QActionHandler>(0)));

    // is storage for the queue buffer provided?
    if (qSto != static_cast<QEvt const **>(0)) {
        m_eQueue.init(qSto, qLen);
    }

    // "naked" threads provide their thread function in place of
    // the top-most initial transition 'me->super.temp.act'
    QXK_stackInit_(this, reinterpret_cast<QXThreadHandler>(m_temp.act),
                   stkSto, stkSize);

    m_prio = prio;
    QF::add_(this); // make QF aware of this naked thread

    QF_CRIT_ENTRY_();
    QXK_attr_.readySet.insert(m_prio);

    // is QXK running?
    if (QXK_attr_.curr != static_cast<QMActive *>(0)) {
        QXK_sched_();
    }
    QF_CRIT_EXIT_();
}
Example #5
0
/* QActive functions =======================================================*/
void QActive_start_(QActive * const me, uint_fast8_t prio,
                    QEvt const *qSto[], uint_fast16_t qLen,
                    void *stkSto, uint_fast16_t stkSize,
                    QEvt const *ie)
{
    DWORD threadId;
    int   win32Prio;
    void *fudgedQSto;
    uint_fast16_t fudgedQLen;

    Q_REQUIRE_ID(700, ((uint_fast8_t)0 < prio) /* priority must be in range */
                 && (prio <= (uint_fast8_t)QF_MAX_ACTIVE)
                 && (qSto != (QEvt const **)0) /* queue storage must be... */
                 && (qLen > (uint_fast16_t)0)  /* ...provided */
                 && (stkSto == (void *)0));    /* statck storage must NOT...
                                               * ... be provided */

    me->prio = prio; /* set QF priority of this AO before adding it to QF */
    QF_add_(me);     /* make QF aware of this active object */

    /* ignore the original storage for the event queue 'qSto' and
    * instead allocate an oversized "fudged" storage for the queue.
    * See also NOTE2 in qf_port.h.
    */
    Q_ASSERT_ID(710, (uint32_t)qLen * QF_WIN32_FUDGE_FACTOR < USHRT_MAX);
    fudgedQLen = qLen * QF_WIN32_FUDGE_FACTOR; /* fudge the queue length */
    fudgedQSto = calloc(fudgedQLen, sizeof(QEvt *)); /* new queue storage */
    Q_ASSERT_ID(720, fudgedQSto != (void *)0); /* allocation must succeed */
    QEQueue_init(&me->eQueue, (QEvt const **)fudgedQSto, fudgedQLen);

    /* save osObject as integer, in case it contains the Win32 priority */
    win32Prio = (me->osObject != (void *)0)
                ? (int)me->osObject
                : THREAD_PRIORITY_NORMAL;

    /* create the Win32 "event" to throttle the AO's event queue */
    me->osObject = CreateEvent(NULL, FALSE, FALSE, NULL);

    QMSM_INIT(&me->super, ie); /* take the top-most initial tran. */
    QS_FLUSH(); /* flush the QS trace buffer to the host */

    /* stack size not provided? */
    if (stkSize == 0U) {
        stkSize = 1024U; /* NOTE: will be rounded up to the nearest page */
    }

    /* create a Win32 thread for the AO;
    * The thread is created with THREAD_PRIORITY_NORMAL
    */
    me->thread = CreateThread(NULL, stkSize,
                              &ao_thread, me, 0, &threadId);
    Q_ASSERT_ID(730, me->thread != (HANDLE)0); /* thread must be created */

    /* was the thread priority provided? */
    if (win32Prio != 0) {
        SetThreadPriority(me->thread, win32Prio);
    }
}
Example #6
0
//****************************************************************************
//! unblock (resume) a given "naked" thread
void QXThread::unblock(void) const {
    QF_CRIT_STAT_

    // the unblocked thread must be a "naked" thread (no state)
    Q_REQUIRE_ID(800, m_state.act == (QActionHandler)0);

    QF_CRIT_ENTRY_();
    unblock_();
    QF_CRIT_EXIT_();
}
Example #7
0
/*..........................................................................*/
void QActive_start_(QActive * const me, uint_fast8_t prio,
                    QEvt const *qSto[], uint_fast16_t qLen,
                    void *stkSto, uint_fast16_t stkSize,
                    QEvt const *ie)
{
    pthread_t thread;
    pthread_attr_t attr;
    struct sched_param param;

    /* p-threads allocate stack internally */
    Q_REQUIRE_ID(600, stkSto == (void *)0);

    QEQueue_init(&me->eQueue, qSto, qLen);
    pthread_cond_init(&me->osObject, 0);

    me->prio = (uint8_t)prio;
    QF_add_(me); /* make QF aware of this active object */

    QMSM_INIT(&me->super, ie); /* take the top-most initial tran. */
    QS_FLUSH(); /* flush the QS trace buffer to the host */

    pthread_attr_init(&attr);

    /* SCHED_FIFO corresponds to real-time preemptive priority-based scheduler
    * NOTE: This scheduling policy requires the superuser privileges
    */
    pthread_attr_setschedpolicy(&attr, SCHED_FIFO);

    /* see NOTE04 */
    param.sched_priority = prio
                           + (sched_get_priority_max(SCHED_FIFO)
                              - QF_MAX_ACTIVE - 3);

    pthread_attr_setschedparam(&attr, &param);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    if (stkSize == 0U) {
        /* set the allowed minimum */
        stkSize = (uint_fast16_t)PTHREAD_STACK_MIN;
    }
    pthread_attr_setstacksize(&attr, (size_t)stkSize);

    if (pthread_create(&thread, &attr, &thread_routine, me) != 0) {
        /* Creating the p-thread with the SCHED_FIFO policy failed. Most
        * probably this application has no superuser privileges, so we just
        * fall back to the default SCHED_OTHER policy and priority 0.
        */
        pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
        param.sched_priority = 0;
        pthread_attr_setschedparam(&attr, &param);
        Q_ALLEGE(pthread_create(&thread, &attr, &thread_routine, me)== 0);
    }
    pthread_attr_destroy(&attr);
    me->thread = (uint8_t)1;
}
Example #8
0
//****************************************************************************
//! block (suspend) the current "naked" thread
void QXThread::block(void) {
    QF_CRIT_STAT_

    QF_CRIT_ENTRY_();
    QXThread *thr = static_cast<QXThread *>(QXK_attr_.curr);
    Q_REQUIRE_ID(700, (!QXK_ISR_CONTEXT_()) /* can't block inside an ISR */
        /* this must be a "naked" thread (no state) */
        && (thr->m_state.act == static_cast<QActionHandler>(0)));
    thr->block_();
    QF_CRIT_EXIT_();
}
Example #9
0
/**
* \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_();
}
Example #10
0
//****************************************************************************
//! obtain a message from the private message queue (block if no messages)
void const *QXThread::queueGet(uint_fast16_t const nTicks,
                               uint_fast8_t const tickRate)
{
    QEQueueCtr nFree;
    QEvt const *e;
    QF_CRIT_STAT_

    QF_CRIT_ENTRY_();
    QXThread *thr = static_cast<QXThread *>(QXK_attr_.curr);

    Q_REQUIRE_ID(900, (!QXK_ISR_CONTEXT_()) /* can't block inside an ISR */
        /* this must be a "naked" thread (no state) */
        && (thr->m_state.act == (QActionHandler)0));

    // is the queue empty? -- block and wait for event(s)
    if (thr->m_eQueue.m_frontEvt == static_cast<QEvt *>(0)) {
        thr->m_temp.obj = reinterpret_cast<QMState const *>(&thr->m_eQueue);
        thr->teArm_(static_cast<enum_t>(QXK_QUEUE_SIG), nTicks, tickRate);
        QXK_attr_.readySet.remove(thr->m_prio);
        QXK_sched_();
        QF_CRIT_EXIT_();
        QF_CRIT_EXIT_NOP();
        QF_CRIT_ENTRY_();
    }

    // is the queue not empty?
    if (thr->m_eQueue.m_frontEvt != static_cast<QEvt *>(0)) {
        e = thr->m_eQueue.m_frontEvt; // always remove from the front
        // volatile into tmp
        nFree= thr->m_eQueue.m_nFree + static_cast<QEQueueCtr>(1);
        thr->m_eQueue.m_nFree = nFree; // update the number of free

        // any events in the ring buffer?
        if (nFree <= thr->m_eQueue.m_end) {

            // remove event from the tail
            thr->m_eQueue.m_frontEvt =
                QF_PTR_AT_(thr->m_eQueue.m_ring, thr->m_eQueue.m_tail);
            if (thr->m_eQueue.m_tail == static_cast<QEQueueCtr>(0)) {
                thr->m_eQueue.m_tail = thr->m_eQueue.m_end;  // wrap
            }
            --thr->m_eQueue.m_tail;

            QS_BEGIN_NOCRIT_(QP::QS_QF_ACTIVE_GET, QP::QS::priv_.aoObjFilter,
                             thr)
                QS_TIME_();                   // timestamp
                QS_SIG_(e->sig);              // the signal of this event
                QS_OBJ_(&thr);                // this active object
                QS_2U8_(e->poolId_, e->refCtr_); // pool Id & ref Count
                QS_EQC_(nFree);               // number of free entries
            QS_END_NOCRIT_()
        }
Example #11
0
//****************************************************************************
// @description
// The preferred way of calling this function is from within the active
// object that needs to stop. In other words, an active object should stop
// itself rather than being stopped by someone else. This policy works
// best, because only the active object itself "knows" when it has reached
// the appropriate state for the shutdown.
//
// @note
// By the time the AO calls QP::QActive::stop(), it should have unsubscribed
// from all events and no more events should be directly-posted to it.
//
void QMActive::stop(void) {
    QF_CRIT_STAT_

    /// @pre QActive_stop() must be called from the AO that wants to stop.
    Q_REQUIRE_ID(300, (!QXK_ISR_CONTEXT_()) /* don't stop AO's from an ISR! */
                      && (this == QXK_attr_.curr));

    QF::remove_(this); // remove this active object from the QF

    QF_CRIT_ENTRY_();
    QXK_attr_.readySet.remove(m_prio);
    QXK_sched_();
    QF_CRIT_EXIT_();
}
Example #12
0
//****************************************************************************
/// @description
/// QP::QF::run() is typically called from your startup code after you
/// initialize the QF and start at least one active object or "naked" thread
/// (with QP::QMActive::start() or QP::QXThread::start(), respectively).
///
/// @returns QP::QF::run() typically does not return in embedded applications.
/// However, when QP runs on top of an operating system, QP::QF::run() might
/// return and in this case the return represents the error code (0 for
/// success). Typically the value returned from QP::QF::run() is subsequently
/// passed on as return from main().
///
int_t QF::run(void) {
    /// @pre QXK_init() must be called __before__ QP::QF::run() to initialize
    /// the QXK idle thread.
    Q_REQUIRE_ID(100, active_[0] == &l_idleThread);

    // switch to the highest-priority task
    QF_INT_DISABLE();
    QXK_attr_.curr = &l_idleThread; // mark QXK as running
    uint_fast8_t p = QXK_attr_.readySet.findMax(); // next priority to run
    QXK_attr_.next = active_[p];
    QXK_start_(); // start QXK multitasking (NOTE: enables interrupts)

    /* the QXK start should not return, but just in case... */
    Q_ERROR_ID(110);

    return static_cast<int_t>(0);
}
Example #13
0
//****************************************************************************
/// @description
/// This function removes a given active object from the active objects
/// managed by the QF framework. It should not be called by the application
/// directly, only through the function QP::QMActive::stop().
///
/// @param[in]  a  pointer to the active object to remove from the framework.
///
/// @note The active object that is removed from the framework can no longer
/// participate in the publish-subscribe event exchange.
///
/// @sa QP::QF::add_()
///
void QF::remove_(QMActive const * const a) {
    uint_fast8_t p = a->m_prio;

    Q_REQUIRE_ID(200, (static_cast<uint_fast8_t>(0) < p)
                      && (p <= static_cast<uint_fast8_t>(QF_MAX_ACTIVE))
                      && (active_[p] == a));

    QF_CRIT_STAT_
    QF_CRIT_ENTRY_();

    active_[p] = static_cast<QMActive *>(0); // free-up the priority level

    QS_BEGIN_NOCRIT_(QS_QF_ACTIVE_REMOVE, QS::priv_.aoObjFilter, a)
        QS_TIME_();   // timestamp
        QS_OBJ_(a);   // the active object
        QS_U8_(p);    // the priority of the active object
    QS_END_NOCRIT_()

    QF_CRIT_EXIT_();
}
Example #14
0
/*..........................................................................*/
int_t QF_run(void) {
    /* CMSIS-RTX must be initialized and started from the starupt code */
    Q_REQUIRE_ID(200, osKernelRunning());

    /* call-back to the application to configure and start interrupts.
    * In the RTX port, QF_onStartup() typically also calls QF_setRtxTicker().
    */
    QF_onStartup();

    /* CMSIS-RTOS starts thread execution with the function main().
    * This main thread will continue executing after osKernelStart().
    */
    for (;;) {  /* loop of the ticker thread */
        QF_onRtxTicker(); /* call-back to the app to handle the tick */
        osDelay(l_tickerPeriod); /* delay for the configurable period */
    }
#if defined (__GNUC__)
    return (int_t)0; /* dummy return to make the compiler happy */
#endif
}
Example #15
0
/*..........................................................................*/
void QActive_start_(QActive * const me, uint_fast8_t prio,
                    QEvt const *qSto[], uint_fast16_t qLen,
                    void *stkSto, uint_fast16_t stkSize,
                    QEvt const *ie)
{
    /*
    * The following os_thread_def_AO object specifies the attributes of the
    * RTX thread for Active Objects. This object is allocated on the stack,
    * because it only serves to create the specific task for this AO.
    */
    osThreadDef_t os_thread_def_AO;

    /* no stack storage because RTX pre-allocates stacks internally,
    * but the queue storage and size must be provided
    */
    Q_REQUIRE_ID(510, (stkSto == (void *)0)
                      && (qSto != (QEvt const **)0)
                      && (qLen > (uint_fast16_t)0));

    /* create the QP event queue for the AO */
    QEQueue_init(&me->eQueue, qSto, qLen);

    me->prio = prio;  /* save the QF priority */
    QF_add_(me);      /* make QF aware of this active object */
    QMSM_INIT(&me->super, ie);  /* thake the top-most initial tran. */
    QS_FLUSH(); /* flush the trace buffer to the host */

    /* create the RTX thread for the AO... */
    os_thread_def_AO.pthread   = &ao_thread;  /* RTX thread routine for AOs */
    os_thread_def_AO.instances = (uint32_t)1; /* # instances of this thread */
    os_thread_def_AO.stacksize = (uint32_t)stkSize; /* stack size [BYTES!] */
    os_thread_def_AO.tpriority =
        (me->osObject != (uint32_t)0)    /* RTX priority provided? */
            ? (osPriority)(me->osObject) /* use the provided value */
            : osPriorityNormal;          /* use the default */
    me->thread = osThreadCreate(&os_thread_def_AO, (void *)me);

    /* ensure that the thread was created correctly */
    Q_ENSURE_ID(520, me->thread != (osThreadId)0);
}
Example #16
0
/*..........................................................................*/
void QF_init(void) {
    /* CMSIS-RTX must be initialized and started from the starupt code. */
    Q_REQUIRE_ID(100, osKernelRunning());

    /* Special consideration for Cortex-M systems with the hardware FPU... */
#ifdef __TARGET_FPU_VFP
    /* Enable access to Floating-point coprocessor in NVIC_CPACR */
    (*((uint32_t volatile *)0xE000ED88U)) |= ((3U << 10*2) | (3U << 11*2));

    /* Explictily Disable the automatic FPU state preservation and
     * the FPU lazy stacking in SCB_FPCCR
     */
    (*((uint32_t volatile *)0xE000EF34U)) &= ~((1U << 31) | (1U << 30));
#endif /* __TARGET_FPU_VFP */

    /* The main thread will be used as the ticker thread; save its ID */
    l_tickerThreadId = osThreadGetId();

    /* set the default period of the ticker thread...
    * NOTE: can be changed later in QF_setRtxTicker()
    */
    l_tickerPeriod = 100000U;  /* [microseconds] */
}
Example #17
0
/**
* @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_()
}
Example #18
0
//****************************************************************************/
/// @description
/// This function is part of the Publish-Subscribe event delivery mechanism
/// available in QF. Subscribing to an event means that the framework will
/// start posting all published events with a given signal @p sig to the
/// event queue of the active object.
///
/// @param[in] sig event signal to subscribe
///
/// The following example shows how the Table active object subscribes
/// to three signals in the initial transition:
/// @include qf_subscribe.c
///
/// @sa QP::QF::publish_(), QP::QMActive::unsubscribe(), and
/// QP::QMActive::unsubscribeAll()
///
void QMActive::subscribe(enum_t const sig) const {
    uint_fast8_t p = m_prio;
    Q_REQUIRE_ID(300, (Q_USER_SIG <= sig)
              && (sig < QF_maxSignal_)
              && (static_cast<uint_fast8_t>(0) < p)
              && (p <= static_cast<uint_fast8_t>(QF_MAX_ACTIVE))
              && (QF::active_[p] == this));

    uint_fast8_t const i =
         static_cast<uint_fast8_t>(QF_div8Lkup[p]);

    QF_CRIT_STAT_
    QF_CRIT_ENTRY_();

    QS_BEGIN_NOCRIT_(QS_QF_ACTIVE_SUBSCRIBE, QS::priv_.aoObjFilter, this)
        QS_TIME_();    // timestamp
        QS_SIG_(sig);  // the signal of this event
        QS_OBJ_(this); // this active object
    QS_END_NOCRIT_()

    // set the priority bit
    QF_PTR_AT_(QF_subscrList_, sig).m_bits[i] |= QF_pwr2Lkup[p];
    QF_CRIT_EXIT_();
}
Example #19
0
//****************************************************************************
// must be called from within a critical section
void QXThread::block_(void) const {
    /// @pre the thread holding the lock cannot block!
    Q_REQUIRE_ID(100,  m_prio != QXK_attr_.lockPrio);
    QXK_attr_.readySet.remove(m_prio);
    QXK_sched_();
}
Example #20
0
/**
* \description
* Constructor for the ::QEvt class provided when the switch #Q_EVT_CTOR
* is defined.
*
* \arguments
* \arg[in,out] \c me   pointer (see \ref derivation)
* \arg[in]     \c sig  signal to be assigned to the event
*/
QEvt *QEvt_ctor(QEvt * const me, enum_t const sig) {
    /** \pre the me pointer must be valid */
    Q_REQUIRE_ID(200, me != (QEvt *)0);
    me->sig = (QSignal)sig;
    return me;
}
Example #21
0
void QF::publish_(QEvt const * const e) {
#else
void QF::publish_(QEvt const * const e, void const * const sender) {
#endif
    /// @pre the published signal must be within the configured range
    Q_REQUIRE_ID(100, static_cast<enum_t>(e->sig) < QF_maxSignal_);

    QF_CRIT_STAT_
    QF_CRIT_ENTRY_();

    QS_BEGIN_NOCRIT_(QS_QF_PUBLISH,
        static_cast<void *>(0), static_cast<void *>(0))
        QS_TIME_();                      // the timestamp
        QS_OBJ_(sender);                 // the sender object
        QS_SIG_(e->sig);                 // the signal of the event
        QS_2U8_(e->poolId_, e->refCtr_); // pool Id & refCtr of the evt
    QS_END_NOCRIT_()

    // is it a dynamic event?
    if (e->poolId_ != static_cast<uint8_t>(0)) {
        QF_EVT_REF_CTR_INC_(e); // increment the reference counter, NOTE01
    }
    QF_CRIT_EXIT_();

    QF_SCHED_STAT_TYPE_ lockStat;
    lockStat.m_lockPrio = static_cast<uint_fast8_t>(0xFF); // uninitialized

#if (QF_MAX_ACTIVE <= 8)
    uint_fast8_t tmp = static_cast<uint_fast8_t>(
                           QF_PTR_AT_(QF_subscrList_, e->sig).m_bits[0]);

    while (tmp != static_cast<uint8_t>(0)) {
        uint_fast8_t p = static_cast<uint_fast8_t>(QF_LOG2(tmp));

        // clear the subscriber bit
        tmp &= static_cast<uint_fast8_t>(QF_invPwr2Lkup[p]);

        // has the scheduler been locked yet?
        if (lockStat.m_lockPrio == static_cast<uint_fast8_t>(0xFF)) {
            QF_SCHED_LOCK_(&lockStat, p);
        }

        // the priority of the AO must be registered with the framework
        Q_ASSERT_ID(110, active_[p] != static_cast<QMActive *>(0));

        // POST() asserts internally if the queue overflows
        (void)active_[p]->POST(e, sender);
    }
#else
    uint_fast8_t i = static_cast<uint_fast8_t>(QF_SUBSCR_LIST_SIZE);

    // go through all bytes in the subscription list
    do {
        --i;
        uint_fast8_t tmp = static_cast<uint_fast8_t>(
                              QF_PTR_AT_(QF_subscrList_, e->sig).m_bits[i]);
        while (tmp != static_cast<uint_fast8_t>(0)) {
            uint_fast8_t p = static_cast<uint_fast8_t>(QF_LOG2(tmp));

            // clear the subscriber bit
            tmp &= static_cast<uint_fast8_t>(QF_invPwr2Lkup[p]);

            // adjust the priority
            p += static_cast<uint_fast8_t>(i << 3);

            // has the scheduler been locked yet?
            if (lockStat.m_lockPrio == static_cast<uint_fast8_t>(0xFF)) {
                QF_SCHED_LOCK_(&lockStat, p);
            }

            // the priority level be registered with the framework
            Q_ASSERT(active_[p] != static_cast<QMActive *>(0));

            // POST() asserts internally if the queue overflows
            (void)active_[p]->POST(e, sender);
        }
    } while (i != static_cast<uint_fast8_t>(0));
#endif

    // was the scheduler locked?
    if (lockStat.m_lockPrio <= static_cast<uint_fast8_t>(QF_MAX_ACTIVE)) {
        QF_SCHED_UNLOCK_(&lockStat); // unlock the scheduler
    }

    // run the garbage collector
    gc(e);

    // NOTE: QP::QF::publish_() increments the reference counter to prevent
    // premature recycling of the event while the multicasting is still
    // in progress. At the end of the function, the garbage collector step
    // decrements the reference counter and recycles the event if the
    // counter drops to zero. This covers the case when the event was
    // published without any subscribers.
}
Example #22
0
/**
* \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_()

        }
Example #23
0
/**
* @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_()
                }
            }