|
QP-nano
|
00001 /***************************************************************************** 00002 * Product: QK-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(qkn) 00031 00032 00038 #ifndef QK_PREEMPTIVE 00039 #error "The required header file qkn.h is not included in qpn_port.h" 00040 #endif 00041 00042 /* Global-scope objects ----------------------------------------------------*/ 00043 /* start with the QK scheduler locked */ 00044 uint8_t volatile QK_currPrio_ = (uint8_t)(QF_MAX_ACTIVE + 1); 00045 00046 #ifdef QF_ISR_NEST 00047 uint8_t volatile QK_intNest_; /* start with nesting level of 0 */ 00048 #endif 00049 00050 #ifdef QK_MUTEX 00051 uint8_t volatile QK_ceilingPrio_; /* ceiling priority of a mutex */ 00052 #endif 00053 00054 /*..........................................................................*/ 00055 static void initialize(void) { 00056 uint8_t p; 00057 QActive *a; 00058 /* set priorities all registered active objects... */ 00059 for (p = (uint8_t)1; p <= (uint8_t)QF_MAX_ACTIVE; ++p) { 00060 a = (QActive *)Q_ROM_PTR(QF_active[p].act); 00061 Q_ASSERT(a != (QActive *)0); /* QF_active[p] must be initialized */ 00062 a->prio = p; /* set the priority of the active object */ 00063 } 00064 /* trigger initial transitions in all registered active objects... */ 00065 for (p = (uint8_t)1; p <= (uint8_t)QF_MAX_ACTIVE; ++p) { 00066 a = (QActive *)Q_ROM_PTR(QF_active[p].act); 00067 #ifndef QF_FSM_ACTIVE 00068 QHsm_init((QHsm *)a); /* initial tran. */ 00069 #else 00070 QFsm_init((QFsm *)a); /* initial tran. */ 00071 #endif 00072 } 00073 00074 QF_INT_LOCK(); 00075 QK_currPrio_ = (uint8_t)0; /* set the priority for the QK idle loop */ 00076 p = QK_schedPrio_(); 00077 if (p != (uint8_t)0) { 00078 QK_sched_(p); /* process all events produced so far */ 00079 } 00080 QF_INT_UNLOCK(); 00081 } 00082 /*..........................................................................*/ 00083 void QF_run(void) { 00084 initialize(); 00085 QF_onStartup(); /* invoke startup callback */ 00086 00087 for (;;) { /* enter the QK idle loop */ 00088 QK_onIdle(); /* invoke the on-idle callback */ 00089 } 00090 } 00091 /* Local-scope objects -----------------------------------------------------*/ 00092 static uint8_t const Q_ROM Q_ROM_VAR l_log2Lkup[] = { 00093 0U, 1U, 2U, 2U, 3U, 3U, 3U, 3U, 4U, 4U, 4U, 4U, 4U, 4U, 4U, 4U 00094 }; 00095 00096 /*..........................................................................*/ 00097 /* NOTE: QK schePrio_() is entered and exited with interrupts LOCKED */ 00098 uint8_t QK_schedPrio_(void) Q_REENTRANT { 00099 uint8_t p; /* highest-priority active object ready to run */ 00100 00101 /* determine the priority of the highest-priority AO ready to run */ 00102 #if (QF_MAX_ACTIVE > 4) 00103 if ((QF_readySet_ & 0xF0) != 0) { /* upper nibble used? */ 00104 p = (uint8_t)(Q_ROM_BYTE(l_log2Lkup[QF_readySet_ >> 4]) + 4); 00105 } 00106 else /* upper nibble of QF_readySet_ is zero */ 00107 #endif 00108 { 00109 p = Q_ROM_BYTE(l_log2Lkup[QF_readySet_]); 00110 } 00111 00112 #ifdef QK_MUTEX /* QK priority-ceiling mutexes allowed? */ 00113 if ((p > QK_currPrio_) && (p > QK_ceilingPrio_)) { 00114 #else 00115 if (p > QK_currPrio_) { /* do we have a preemption? */ 00116 #endif /* QK_MUTEX */ 00117 return p; 00118 } 00119 else { 00120 return (uint8_t)0; 00121 } 00122 } 00123 /*..........................................................................*/ 00124 /* NOTE: QK_sched_() is entered and exited with interrupts LOCKED */ 00125 void QK_sched_(uint8_t p) Q_REENTRANT { 00126 static uint8_t const Q_ROM Q_ROM_VAR invPow2Lkup[] = { 00127 0xFFU, 0xFEU, 0xFDU, 0xFBU, 0xF7U, 0xEFU, 0xDFU, 0xBFU, 0x7FU 00128 }; 00129 00130 uint8_t pin = QK_currPrio_; /* save the initial priority */ 00131 do { 00132 QActive *a; 00133 QActiveCB const Q_ROM *ao; 00134 00135 QK_currPrio_ = p; /* new priority becomes the current priority */ 00136 QF_INT_UNLOCK(); /* it's safe to leave critical section */ 00137 00138 ao = &QF_active[p]; 00139 a = (QActive *)Q_ROM_PTR(ao->act); /* map p to AO */ 00140 00141 QF_INT_LOCK(); /* get ready to access the queue */ 00142 Q_ASSERT(a->nUsed > 0); /* some events must be available */ 00143 --a->nUsed; 00144 if (a->nUsed == (uint8_t)0) { /* queue becoming empty? */ 00145 QF_readySet_ &= Q_ROM_BYTE(invPow2Lkup[p]); /* clear the bit */ 00146 } 00147 Q_SIG(a) = 00148 ((QEvent *)Q_ROM_PTR(ao->queue))[a->tail].sig; 00149 #if (Q_PARAM_SIZE != 0) 00150 Q_PAR(a) = 00151 ((QEvent *)Q_ROM_PTR(ao->queue))[a->tail].par; 00152 #endif 00153 if (a->tail == (uint8_t)0) { /* wrap around? */ 00154 a->tail = Q_ROM_BYTE(ao->end); 00155 } 00156 --a->tail; 00157 QF_INT_UNLOCK(); /* unlock interrupts to launch a task */ 00158 00159 /* dispatch to HSM (execute RTC step) */ 00160 #ifndef QF_FSM_ACTIVE 00161 QHsm_dispatch((QHsm *)a); 00162 #else 00163 QFsm_dispatch((QFsm *)a); 00164 #endif 00165 00166 QF_INT_LOCK(); 00167 00168 /* determine the highest-priority AO ready to run */ 00169 #if (QF_MAX_ACTIVE > 4) 00170 if ((QF_readySet_ & 0xF0) != 0) { /* upper nibble used? */ 00171 p = (uint8_t)(Q_ROM_BYTE(l_log2Lkup[QF_readySet_ >> 4]) + 4); 00172 } 00173 else /* upper nibble of QF_readySet_ is zero */ 00174 #endif 00175 { 00176 p = Q_ROM_BYTE(l_log2Lkup[QF_readySet_]); 00177 } 00178 00179 #ifdef QK_MUTEX /* QK priority-ceiling mutexes allowed? */ 00180 } while ((p > pin) && (p > QK_ceilingPrio_)); 00181 #else 00182 } while (p > pin); 00183 #endif /* QK_MUTEX */ 00184 00185 QK_currPrio_ = pin; /* restore the initial priority */ 00186 } 00187 00188 #ifdef QK_MUTEX 00189 /*..........................................................................*/ 00190 QMutex QK_mutexLock(uint8_t prioCeiling) { 00191 uint8_t mutex; 00192 QF_INT_LOCK(); 00193 mutex = QK_ceilingPrio_; /* the original QK priority ceiling to return */ 00194 if (QK_ceilingPrio_ < prioCeiling) { 00195 QK_ceilingPrio_ = prioCeiling; /* raise the QK priority ceiling */ 00196 } 00197 QF_INT_UNLOCK(); 00198 return mutex; 00199 } 00200 /*..........................................................................*/ 00201 void QK_mutexUnlock(QMutex mutex) { 00202 QF_INT_LOCK(); 00203 if (QK_ceilingPrio_ > mutex) { 00204 QK_ceilingPrio_ = mutex; /* restore the saved priority ceiling */ 00205 mutex = = QK_schedPrio_(); /* reuse 'mutex' to hold priority */ 00206 if (mutex != (uint8_t)0) { 00207 QK_sched_(mutex); 00208 } 00209 } 00210 QF_INT_UNLOCK(); 00211 } 00212 #endif /* #ifdef QK_MUTEX */
1.7.5.1