1 /*****************************************************************************
2 * Product: QK-nano implemenation
3 * Last Updated for Version: 4.0.03
4 * Date of the Last Update: Dec 26, 2008
6 * Q u a n t u m L e a P s
7 * ---------------------------
8 * innovating embedded systems
10 * Copyright (C) 2002-2008 Quantum Leaps, LLC. All rights reserved.
12 * This software may be distributed and modified under the terms of the GNU
13 * General Public License version 2 (GPL) as published by the Free Software
14 * Foundation and appearing in the file GPL.TXT included in the packaging of
15 * this file. Please note that GPL Section 2[b] requires that all works based
16 * on this software must also be made publicly available under the terms of
17 * the GPL ("Copyleft").
19 * Alternatively, this software may be distributed and modified under the
20 * terms of Quantum Leaps commercial licenses, which expressly supersede
21 * the GPL and are specifically designed for licensees interested in
22 * retaining the proprietary status of their code.
24 * Contact information:
25 * Quantum Leaps Web site: http://www.quantum-leaps.com
27 *****************************************************************************/
28 #include "qpn_port.h" /* QP-nano port */
30 Q_DEFINE_THIS_MODULE(qkn)
35 * QK-nano implementation.
39 #error "The required header file qkn.h is not included in qpn_port.h"
42 /* Global-scope objects ----------------------------------------------------*/
43 /* start with the QK scheduler locked */
44 uint8_t volatile QK_currPrio_ = (uint8_t)(QF_MAX_ACTIVE + 1);
47 uint8_t volatile QK_intNest_; /* start with nesting level of 0 */
51 uint8_t volatile QK_ceilingPrio_; /* ceiling priority of a mutex */
54 /* local objects -----------------------------------------------------------*/
55 static QActive *l_act; /* ptr to AO */
57 /*..........................................................................*/
59 static uint8_t p; /* declared static to save stack space */
61 /* set priorities all registered active objects... */
62 for (p = (uint8_t)1; p <= (uint8_t)QF_MAX_ACTIVE; ++p) {
63 l_act = (QActive *)Q_ROM_PTR(QF_active[p].act);
64 Q_ASSERT(l_act != (QActive *)0);/* QF_active[p] must be initialized */
65 l_act->prio = p; /* set the priority of the active object */
67 /* trigger initial transitions in all registered active objects... */
68 for (p = (uint8_t)1; p <= (uint8_t)QF_MAX_ACTIVE; ++p) {
69 l_act = (QActive *)Q_ROM_PTR(QF_active[p].act);
71 QHsm_init((QHsm *)l_act); /* initial tran. */
73 QFsm_init((QFsm *)l_act); /* initial tran. */
78 QK_currPrio_ = (uint8_t)0; /* set the priority for the QK idle loop */
79 QK_SCHEDULE_(); /* process all events produced so far */
82 QF_onStartup(); /* invoke startup callback */
84 for (;;) { /* enter the QK idle loop */
85 QK_onIdle(); /* invoke the on-idle callback */
88 /*..........................................................................*/
89 /* NOTE: the QK scheduler is entered and exited with interrupts LOCKED */
90 void QK_schedule_(void) Q_REENTRANT {
91 static uint8_t const Q_ROM Q_ROM_VAR log2Lkup[] = {
92 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4
94 static uint8_t const Q_ROM Q_ROM_VAR invPow2Lkup[] = {
95 0xFF, 0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F
98 uint8_t pin; /* the initial QK-nano priority */
99 uint8_t p; /* new highest-priority active object ready to run */
101 /* determine the priority of the highest-priority AO ready to run */
102 #if (QF_MAX_ACTIVE > 4)
103 if ((QF_readySet_ & 0xF0) != 0) { /* upper nibble used? */
104 p = (uint8_t)(Q_ROM_BYTE(log2Lkup[QF_readySet_ >> 4]) + 4);
106 else /* upper nibble of QF_readySet_ is zero */
109 p = Q_ROM_BYTE(log2Lkup[QF_readySet_]);
112 #ifdef QK_MUTEX /* QK priority-ceiling mutexes allowed? */
113 if ((p > QK_currPrio_) && (p > QK_ceilingPrio_)) {
115 if (p > QK_currPrio_) { /* do we have a preemption? */
116 #endif /* QK_MUTEX */
118 pin = QK_currPrio_; /* save the initial priority */
120 QK_currPrio_ = p; /* new priority becomes the current priority */
121 QF_INT_UNLOCK(); /* unlock interrupts to launch a task */
123 /* dispatch to HSM (execute RTC step) */
124 #ifndef QF_FSM_ACTIVE
125 QHsm_dispatch((QHsm *)Q_ROM_PTR(QF_active[p].act));
127 QFsm_dispatch((QFsm *)Q_ROM_PTR(QF_active[p].act));
131 /* set cb and a again, in case they change over the RTC step */
132 l_act = (QActive *)Q_ROM_PTR(QF_active[p].act);
134 if ((--l_act->nUsed) == (uint8_t)0) {/*is queue becoming empty? */
135 /* clear the ready bit */
136 QF_readySet_ &= Q_ROM_BYTE(invPow2Lkup[p]);
139 Q_SIG(l_act) = ((QEvent *)Q_ROM_PTR(QF_active[p].queue))
141 #if (Q_PARAM_SIZE != 0)
142 Q_PAR(l_act) = ((QEvent *)Q_ROM_PTR(QF_active[p].queue))
145 if (l_act->tail == (uint8_t)0) { /* wrap around? */
146 l_act->tail = Q_ROM_BYTE(QF_active[p].end);/* wrap tail */
150 /* determine the highest-priority AO ready to run */
151 if (QF_readySet_ != (uint8_t)0) {
152 #if (QF_MAX_ACTIVE > 4)
153 if ((QF_readySet_ & 0xF0) != 0) { /* upper nibble used? */
154 p = (uint8_t)(Q_ROM_BYTE(log2Lkup[QF_readySet_ >> 4])+ 4);
156 else /* upper nibble of QF_readySet_ is zero */
159 p = Q_ROM_BYTE(log2Lkup[QF_readySet_]);
163 p = (uint8_t)0; /* break out of the loop */
166 #ifdef QK_MUTEX /* QK priority-ceiling mutexes allowed? */
167 } while ((p > pin) && (p > QK_ceilingPrio_));
170 #endif /* QK_MUTEX */
171 QK_currPrio_ = pin; /* restore the initial priority */
176 /*..........................................................................*/
177 QMutex QK_mutexLock(uint8_t prioCeiling) {
180 mutex = QK_ceilingPrio_; /* the original QK priority ceiling to return */
181 if (QK_ceilingPrio_ < prioCeiling) {
182 QK_ceilingPrio_ = prioCeiling; /* raise the QK priority ceiling */
187 /*..........................................................................*/
188 void QK_mutexUnlock(QMutex mutex) {
190 if (QK_ceilingPrio_ > mutex) {
191 QK_ceilingPrio_ = mutex; /* restore the saved priority ceiling */
196 #endif /* #ifdef QK_MUTEX */