QP-nano
qfn.c
Go to the documentation of this file.
00001 /*****************************************************************************
00002 * Product: QF-nano implemenation
00003 * Last Updated for Version: 4.3.00
00004 * Date of the Last Update:  Oct 29, 2011
00005 *
00006 *                    Q u a n t u m     L e a P s
00007 *                    ---------------------------
00008 *                    innovating embedded systems
00009 *
00010 * Copyright (C) 2002-2011 Quantum Leaps, LLC. All rights reserved.
00011 *
00012 * This software may be distributed and modified under the terms of the GNU
00013 * General Public License version 2 (GPL) as published by the Free Software
00014 * Foundation and appearing in the file GPL.TXT included in the packaging of
00015 * this file. Please note that GPL Section 2[b] requires that all works based
00016 * on this software must also be made publicly available under the terms of
00017 * the GPL ("Copyleft").
00018 *
00019 * Alternatively, this software may be distributed and modified under the
00020 * terms of Quantum Leaps commercial licenses, which expressly supersede
00021 * the GPL and are specifically designed for licensees interested in
00022 * retaining the proprietary status of their code.
00023 *
00024 * Contact information:
00025 * Quantum Leaps Web site:  http://www.quantum-leaps.com
00026 * e-mail:                  info@quantum-leaps.com
00027 *****************************************************************************/
00028 #include "qpn_port.h"                                       /* QP-nano port */
00029 
00030 Q_DEFINE_THIS_MODULE(qfn)
00031 
00032 
00038 /* Global-scope objects ----------------------------------------------------*/
00039 uint8_t volatile QF_readySet_;                      /* ready-set of QF-nano */
00040 
00041 /* local objects -----------------------------------------------------------*/
00042 static uint8_t const Q_ROM Q_ROM_VAR l_pow2Lkup[] = {
00043     0x00U, 0x01U, 0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U
00044 };
00045 
00046 /*..........................................................................*/
00047 #if (Q_PARAM_SIZE != 0)
00048 void QActive_post(QActive *me, QSignal sig, QParam par)
00049 #else
00050 void QActive_post(QActive *me, QSignal sig)
00051 #endif
00052 {
00053     QActiveCB const Q_ROM *ao = &QF_active[me->prio];
00054 
00055             /* the queue must be able to accept the event (cannot overflow) */
00056     Q_ASSERT(me->nUsed < Q_ROM_BYTE(ao->end));
00057 
00058     QF_INT_LOCK();
00059                                 /* insert event into the ring buffer (FIFO) */
00060     ((QEvent *)Q_ROM_PTR(ao->queue))[me->head].sig = sig;
00061 #if (Q_PARAM_SIZE != 0)
00062     ((QEvent *)Q_ROM_PTR(ao->queue))[me->head].par = par;
00063 #endif
00064     if (me->head == (uint8_t)0) {
00065         me->head = Q_ROM_BYTE(ao->end);                    /* wrap the head */
00066     }
00067     --me->head;
00068     ++me->nUsed;
00069     if (me->nUsed == (uint8_t)1) {              /* is this the first event? */
00070         QF_readySet_ |= Q_ROM_BYTE(l_pow2Lkup[me->prio]);    /* set the bit */
00071 #ifdef QK_PREEMPTIVE
00072         sig = QK_schedPrio_();          /* reuse 'sig' to hold the priority */
00073         if (sig != 0) {
00074             QK_sched_(sig);             /* check for synchronous preemption */
00075         }
00076 #endif
00077     }
00078     QF_INT_UNLOCK();
00079 }
00080 /*..........................................................................*/
00081 #if (Q_PARAM_SIZE != 0)
00082 void QActive_postISR(QActive *me, QSignal sig, QParam par)
00083 #else
00084 void QActive_postISR(QActive *me, QSignal sig)
00085 #endif
00086 {
00087 #ifdef QF_ISR_NEST
00088 #ifdef QF_ISR_KEY_TYPE
00089     QF_ISR_KEY_TYPE key;
00090 #endif
00091 #endif
00092     QActiveCB const Q_ROM *ao = &QF_active[me->prio];
00093 
00094             /* the queue must be able to accept the event (cannot overflow) */
00095     Q_ASSERT(me->nUsed < Q_ROM_BYTE(ao->end));
00096 
00097 #ifdef QF_ISR_NEST
00098 #ifdef QF_ISR_KEY_TYPE
00099     QF_ISR_LOCK(key);
00100 #else
00101     QF_INT_LOCK();
00102 #endif
00103 #endif
00104                                 /* insert event into the ring buffer (FIFO) */
00105     ((QEvent *)Q_ROM_PTR(ao->queue))[me->head].sig = sig;
00106 #if (Q_PARAM_SIZE != 0)
00107     ((QEvent *)Q_ROM_PTR(ao->queue))[me->head].par = par;
00108 #endif
00109     if (me->head == (uint8_t)0) {
00110         me->head = Q_ROM_BYTE(ao->end);                    /* wrap the head */
00111     }
00112     --me->head;
00113     ++me->nUsed;
00114     if (me->nUsed == (uint8_t)1) {              /* is this the first event? */
00115         QF_readySet_ |= Q_ROM_BYTE(l_pow2Lkup[me->prio]);    /* set the bit */
00116     }
00117 
00118 #ifdef QF_ISR_NEST
00119 #ifdef QF_ISR_KEY_TYPE
00120     QF_ISR_UNLOCK(key);
00121 #else
00122     QF_INT_UNLOCK();
00123 #endif
00124 #endif
00125 }
00126 
00127 /*--------------------------------------------------------------------------*/
00128 #if (QF_TIMEEVT_CTR_SIZE != 0)
00129 
00130 /*..........................................................................*/
00131 void QF_tickISR(void) {
00132     uint8_t p = (uint8_t)QF_MAX_ACTIVE;
00133     QActiveCB const Q_ROM *ao = &QF_active[(uint8_t)QF_MAX_ACTIVE];
00134     do {
00135         QActive *a = (QActive *)Q_ROM_PTR(ao->act);
00136         if (a->tickCtr != (QTimeEvtCtr)0) {
00137             --a->tickCtr;
00138             if (a->tickCtr == (QTimeEvtCtr)0) {
00139 #if (Q_PARAM_SIZE != 0)
00140                 QActive_postISR(a, (QSignal)Q_TIMEOUT_SIG, (QParam)0);
00141 #else
00142                 QActive_postISR(a, (QSignal)Q_TIMEOUT_SIG);
00143 #endif
00144             }
00145         }
00146         --ao;
00147         --p;
00148     } while (p != (uint8_t)0);
00149 }
00150 
00151 #if (QF_TIMEEVT_CTR_SIZE > 1)
00152 /*..........................................................................*/
00153 void QActive_arm(QActive *me, QTimeEvtCtr tout) {
00154     QF_INT_LOCK();
00155     me->tickCtr = tout;
00156     QF_INT_UNLOCK();
00157 }
00158 /*..........................................................................*/
00159 void QActive_disarm(QActive *me) {
00160     QF_INT_LOCK();
00161     me->tickCtr = (QTimeEvtCtr)0;
00162     QF_INT_UNLOCK();
00163 }
00164 #endif                                     /* #if (QF_TIMEEVT_CTR_SIZE > 1) */
00165 
00166 #endif                                    /* #if (QF_TIMEEVT_CTR_SIZE != 0) */
00167 
00168 /*--------------------------------------------------------------------------*/
00169 #ifndef QK_PREEMPTIVE
00170 
00171 void QF_run(void) {
00172     static uint8_t const Q_ROM Q_ROM_VAR log2Lkup[] = {
00173         0U, 1U, 2U, 2U, 3U, 3U, 3U, 3U, 4U, 4U, 4U, 4U, 4U, 4U, 4U, 4U
00174     };
00175     static uint8_t const Q_ROM Q_ROM_VAR invPow2Lkup[] = {
00176         0xFFU, 0xFEU, 0xFDU, 0xFBU, 0xF7U, 0xEFU, 0xDFU, 0xBFU, 0x7FU
00177     };
00178     uint8_t p;
00179     QActive *a;
00180     QActiveCB const Q_ROM *ao;
00181 
00182                          /* set priorities all registered active objects... */
00183     for (p = (uint8_t)1; p <= (uint8_t)QF_MAX_ACTIVE; ++p) {
00184         a = (QActive *)Q_ROM_PTR(QF_active[p].act);
00185         Q_ASSERT(a != (QActive *)0);    /* QF_active[p] must be initialized */
00186         a->prio = p;               /* set the priority of the active object */
00187     }
00188          /* trigger initial transitions in all registered active objects... */
00189     for (p = (uint8_t)1; p <= (uint8_t)QF_MAX_ACTIVE; ++p) {
00190         a = (QActive *)Q_ROM_PTR(QF_active[p].act);
00191 #ifndef QF_FSM_ACTIVE
00192         QHsm_init((QHsm *)a);         /* take the initial transition in HSM */
00193 #else
00194         QFsm_init((QFsm *)a);         /* take the initial transition in FSM */
00195 #endif
00196     }
00197 
00198     QF_onStartup();                              /* invoke startup callback */
00199 
00200     for (;;) {                      /* the event loop of the vanilla kernel */
00201         QF_INT_LOCK();
00202         if (QF_readySet_ != (uint8_t)0) {
00203 #if (QF_MAX_ACTIVE > 4)
00204             if ((QF_readySet_ & 0xF0) != 0U) {        /* upper nibble used? */
00205                 p = (uint8_t)(Q_ROM_BYTE(log2Lkup[QF_readySet_ >> 4]) + 4);
00206             }
00207             else                    /* upper nibble of QF_readySet_ is zero */
00208 #endif
00209             {
00210                 p = Q_ROM_BYTE(log2Lkup[QF_readySet_]);
00211             }
00212             ao = &QF_active[p];
00213             a = (QActive *)Q_ROM_PTR(ao->act);
00214             Q_ASSERT(a->nUsed > 0);        /* some events must be available */
00215             --a->nUsed;
00216             if (a->nUsed == (uint8_t)0) {          /* queue becoming empty? */
00217                 QF_readySet_ &= Q_ROM_BYTE(invPow2Lkup[p]);/* clear the bit */
00218             }
00219             Q_SIG(a) =
00220                 ((QEvent *)Q_ROM_PTR(ao->queue))[a->tail].sig;
00221 #if (Q_PARAM_SIZE != 0)
00222             Q_PAR(a) =
00223                 ((QEvent *)Q_ROM_PTR(ao->queue))[a->tail].par;
00224 #endif
00225             if (a->tail == (uint8_t)0) {                    /* wrap around? */
00226                 a->tail = Q_ROM_BYTE(ao->end);
00227             }
00228             --a->tail;
00229             QF_INT_UNLOCK();
00230 
00231 #ifndef QF_FSM_ACTIVE
00232             QHsm_dispatch((QHsm *)a);                    /* dispatch to HSM */
00233 #else
00234             QFsm_dispatch((QFsm *)a);                    /* dispatch to FSM */
00235 #endif
00236         }
00237         else {
00238             QF_onIdle();                                      /* see NOTE01 */
00239         }
00240     }
00241 }
00242 
00243 #endif                                             /* #ifndef QK_PREEMPTIVE */
00244 
00245 /*****************************************************************************
00246 * NOTE01:
00247 * QF_onIdle() must be called with interrupts locked because the determination
00248 * of the idle condition (no events in the queues) can be changed by any
00249 * interrupt. The QF_onIdle() MUST enable interrups internally, ideally
00250 * atomically with putting the CPU into a low-power mode.
00251 */