Dining Philosophers Problem (DPP) example for the QP active object framework. Demonstrates: event-driven programming, hierarchical state machines in C++, modeling and graphical state machine design, code generation, preemptive multitasking, software tracing, power saving mode, direct event posting, publish-subscribe. More information available in the [[/users/QL/notebook|Quantum Leaps Notebook pages]]. See also [[http://www.state-machine.com|state-machine.com]].
bsp.cpp
00001 ////////////////////////////////////////////////////////////////////////////// 00002 // Product: DPP example, configurable Vanilla/QK kernel 00003 // Last Updated for Version: 4.5.02 00004 // Date of the Last Update: Sep 04, 2012 00005 // 00006 // Q u a n t u m L e a P s 00007 // --------------------------- 00008 // innovating embedded systems 00009 // 00010 // Copyright (C) 2002-2012 Quantum Leaps, LLC. All rights reserved. 00011 // 00012 // This program is open source software: you can redistribute it and/or 00013 // modify it under the terms of the GNU General Public License as published 00014 // by the Free Software Foundation, either version 2 of the License, or 00015 // (at your option) any later version. 00016 // 00017 // Alternatively, this program may be distributed and modified under the 00018 // terms of Quantum Leaps commercial licenses, which expressly supersede 00019 // the GNU General Public License and are specifically designed for 00020 // licensees interested in retaining the proprietary status of their code. 00021 // 00022 // This program is distributed in the hope that it will be useful, 00023 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00024 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00025 // GNU General Public License for more details. 00026 // 00027 // You should have received a copy of the GNU General Public License 00028 // along with this program. If not, see <http://www.gnu.org/licenses/>. 00029 // 00030 // Contact information: 00031 // Quantum Leaps Web sites: http://www.quantum-leaps.com 00032 // http://www.state-machine.com 00033 // e-mail: info@quantum-leaps.com 00034 ////////////////////////////////////////////////////////////////////////////// 00035 #include "qp_port.h" 00036 #include "dpp.h" 00037 #include "bsp.h" 00038 #include "LPC17xx.h" 00039 #ifdef Q_SPY 00040 #include "mbed.h" // mbed is used only for the built-in serial 00041 #endif 00042 00043 ////////////////////////////////////////////////////////////////////////////// 00044 namespace DPP { 00045 00046 Q_DEFINE_THIS_FILE 00047 00048 enum ISR_Priorities { // ISR priorities starting from the highest urgency 00049 GPIOPORTA_PRIO, 00050 SYSTICK_PRIO 00051 // ... 00052 }; 00053 00054 // Local-scope objects ------------------------------------------------------- 00055 static uint32_t l_rnd; // random seed 00056 00057 #define LED_PORT LPC_GPIO1 00058 #define LED1_BIT (1U << 18) 00059 #define LED2_BIT (1U << 20) 00060 #define LED3_BIT (1U << 21) 00061 #define LED4_BIT (1U << 23) 00062 00063 #ifdef Q_SPY 00064 QP::QSTimeCtr l_tickTime; 00065 QP::QSTimeCtr l_tickPeriod; 00066 static uint8_t l_SysTick_Handler; 00067 00068 #define QSPY_BAUD_RATE 115200U 00069 00070 enum AppRecords { // application-specific trace records 00071 PHILO_STAT = QP::QS_USER 00072 }; 00073 00074 Serial l_qspy(USBTX, USBRX); 00075 #endif 00076 00077 //............................................................................ 00078 extern "C" void SysTick_Handler(void) { 00079 QK_ISR_ENTRY(); // inform the QK kernel of entering the ISR 00080 00081 #ifdef Q_SPY 00082 uint32_t volatile dummy = SysTick->CTRL; // clear the COUNTFLAG in SysTick 00083 l_tickTime += l_tickPeriod; // account for the clock rollover 00084 #endif 00085 00086 QP::QF::TICK(&l_SysTick_Handler); // process all armed time events 00087 00088 QK_ISR_EXIT(); // inform the QK kernel of exiting the ISR 00089 } 00090 00091 //............................................................................ 00092 void BSP_init(void) { 00093 // set the system clock as specified in lm3s_config.h (20MHz from PLL) 00094 SystemInit(); 00095 00096 // set LED port to output 00097 LED_PORT->FIODIR |= (LED1_BIT | LED2_BIT | LED3_BIT | LED4_BIT); 00098 00099 // clear the LEDs 00100 LED_PORT->FIOCLR = (LED1_BIT | LED2_BIT | LED3_BIT | LED4_BIT); 00101 00102 // initialize the QS software tracing... 00103 Q_ALLEGE(QS_INIT(static_cast<void *>(0))); 00104 QS_RESET(); 00105 QS_OBJ_DICTIONARY(&l_SysTick_Handler); 00106 } 00107 //............................................................................ 00108 void BSP_terminate(int16_t const result) { 00109 (void)result; 00110 } 00111 //............................................................................ 00112 void BSP_displayPhilStat(uint8_t const n, char_t const * const stat) { 00113 // represent LEDs in a const array for convenience 00114 static uint32_t const led[] = { LED1_BIT, LED2_BIT, LED3_BIT, LED4_BIT }; 00115 if (n < 3) { 00116 if (stat[0] == 'e') { 00117 LED_PORT->FIOSET = led[n]; 00118 } 00119 else { 00120 LED_PORT->FIOCLR = led[n]; 00121 } 00122 } 00123 00124 QS_BEGIN(PHILO_STAT, AO_Philo[n]) // application-specific record begin 00125 QS_U8(1U, n); // Philosopher number 00126 QS_STR(stat); // Philosopher status 00127 QS_END() 00128 } 00129 //............................................................................ 00130 void BSP_displayPaused(uint8_t const paused) { 00131 (void)paused; 00132 } 00133 //............................................................................ 00134 uint32_t BSP_random(void) { // a very cheap pseudo-random-number generator 00135 // "Super-Duper" Linear Congruential Generator (LCG) 00136 // LCG(2^32, 3*7*11*13*23, 0, seed) 00137 // 00138 l_rnd = l_rnd * (3U*7U*11U*13U*23U); 00139 return l_rnd >> 8; 00140 } 00141 //............................................................................ 00142 void BSP_randomSeed(uint32_t const seed) { 00143 l_rnd = seed; 00144 } 00145 00146 //............................................................................ 00147 extern "C" void Q_onAssert(char_t const * const file, int_t const line) { 00148 (void)file; // avoid compiler warning 00149 (void)line; // avoid compiler warning 00150 QF_INT_DISABLE(); // make sure that all interrupts are disabled 00151 // light up all LEDs 00152 LED_PORT->FIOSET = (LED1_BIT | LED2_BIT | LED3_BIT | LED4_BIT); 00153 00154 for (;;) { // NOTE: replace the loop with reset for final version 00155 } 00156 } 00157 00158 } // namespace DPP 00159 ////////////////////////////////////////////////////////////////////////////// 00160 00161 namespace QP { 00162 00163 //............................................................................ 00164 void QF::onStartup(void) { 00165 // set up the SysTick timer to fire at BSP_TICKS_PER_SEC rate 00166 (void)SysTick_Config(SystemCoreClock / DPP::BSP_TICKS_PER_SEC); 00167 00168 // set priorities of all interrupts in the system... 00169 NVIC_SetPriority(SysTick_IRQn, DPP::SYSTICK_PRIO); 00170 NVIC_SetPriority(EINT0_IRQn, DPP::GPIOPORTA_PRIO); 00171 00172 NVIC_EnableIRQ(EINT0_IRQn); 00173 } 00174 //............................................................................ 00175 void QF::onCleanup(void) { 00176 } 00177 //............................................................................ 00178 #ifdef QK_PREEMPTIVE 00179 00180 void QK::onIdle(void) { 00181 00182 QF_INT_DISABLE(); 00183 LED_PORT->FIOSET = LED4_BIT; // turn the LED4 on 00184 __NOP(); // delay a bit to see some light intensity 00185 __NOP(); 00186 __NOP(); 00187 __NOP(); 00188 LED_PORT->FIOCLR = LED4_BIT; // turn the LED4 off 00189 QF_INT_ENABLE(); 00190 00191 #ifdef Q_SPY 00192 if (DPP::l_qspy.writeable()) { 00193 00194 QF_INT_DISABLE(); 00195 uint16_t b = QS::getByte(); 00196 QF_INT_ENABLE(); 00197 00198 if (b != QS_EOD) { 00199 DPP::l_qspy.putc((uint8_t)b); 00200 } 00201 } 00202 #else 00203 // Put the CPU and peripherals to the low-power mode. You might need to 00204 // customize the clock management for your application, see the datasheet 00205 // for your particular Cortex-M3 MCU. 00206 // 00207 // Specifially for the mbed board, see the articles: 00208 // * "Power Management" http://mbed.org/cookbook/Power-Management; and 00209 // * "Interface Powerdown" at 00210 // http://mbed.org/users/simon/notebook/interface-powerdown/ 00211 // 00212 __WFI(); 00213 #endif 00214 } 00215 00216 #else // non-preemptive Vanilla kernel 00217 00218 void QF::onIdle(void) { // NOTE: called with interrupts DISABLED 00219 00220 LED_PORT->FIOSET = LED4_BIT; // turn the LED4 on 00221 __NOP(); // delay a bit to see some light intensity 00222 __NOP(); 00223 __NOP(); 00224 __NOP(); 00225 LED_PORT->FIOCLR = LED4_BIT; // turn the LED4 off 00226 00227 #ifdef Q_SPY 00228 QF_INT_ENABLE(); 00229 if (DPP::l_qspy.writeable()) { 00230 00231 QF_INT_DISABLE(); 00232 uint16_t b = QS::getByte(); 00233 QF_INT_ENABLE(); 00234 00235 if (b != QS_EOD) { 00236 DPP::l_qspy.putc((uint8_t)b); 00237 } 00238 } 00239 #else 00240 // Put the CPU and peripherals to the low-power mode. You might need to 00241 // customize the clock management for your application, see the datasheet 00242 // for your particular Cortex-M3 MCU. 00243 // 00244 // Specifially for the mbed board, see the articles: 00245 // * "Power Management" http://mbed.org/cookbook/Power-Management; and 00246 // * "Interface Powerdown" at 00247 // http://mbed.org/users/simon/notebook/interface-powerdown/ 00248 // 00249 __WFI(); 00250 QF_INT_ENABLE(); 00251 #endif 00252 } 00253 00254 #endif // QK_PREEMPTIVE 00255 00256 //---------------------------------------------------------------------------- 00257 #ifdef Q_SPY 00258 //............................................................................ 00259 bool QS::onStartup(void const *arg) { 00260 static uint8_t qsBuf[6*256]; // buffer for Quantum Spy 00261 initBuf(qsBuf, sizeof(qsBuf)); 00262 00263 DPP::l_qspy.baud(QSPY_BAUD_RATE); 00264 00265 DPP::l_tickPeriod = SystemCoreClock / DPP::BSP_TICKS_PER_SEC; 00266 DPP::l_tickTime = DPP::l_tickPeriod; // to start the timestamp at zero 00267 00268 // setup the QS filters... 00269 QS_FILTER_ON(QS_ALL_RECORDS); 00270 00271 // QS_FILTER_OFF(QS_QEP_STATE_EMPTY); 00272 // QS_FILTER_OFF(QS_QEP_STATE_ENTRY); 00273 // QS_FILTER_OFF(QS_QEP_STATE_EXIT); 00274 // QS_FILTER_OFF(QS_QEP_STATE_INIT); 00275 // QS_FILTER_OFF(QS_QEP_INIT_TRAN); 00276 // QS_FILTER_OFF(QS_QEP_INTERN_TRAN); 00277 // QS_FILTER_OFF(QS_QEP_TRAN); 00278 // QS_FILTER_OFF(QS_QEP_IGNORED); 00279 00280 // QS_FILTER_OFF(QS_QF_ACTIVE_ADD); 00281 // QS_FILTER_OFF(QS_QF_ACTIVE_REMOVE); 00282 // QS_FILTER_OFF(QS_QF_ACTIVE_SUBSCRIBE); 00283 // QS_FILTER_OFF(QS_QF_ACTIVE_UNSUBSCRIBE); 00284 // QS_FILTER_OFF(QS_QF_ACTIVE_POST_FIFO); 00285 // QS_FILTER_OFF(QS_QF_ACTIVE_POST_LIFO); 00286 // QS_FILTER_OFF(QS_QF_ACTIVE_GET); 00287 // QS_FILTER_OFF(QS_QF_ACTIVE_GET_LAST); 00288 // QS_FILTER_OFF(QS_QF_EQUEUE_INIT); 00289 // QS_FILTER_OFF(QS_QF_EQUEUE_POST_FIFO); 00290 // QS_FILTER_OFF(QS_QF_EQUEUE_POST_LIFO); 00291 // QS_FILTER_OFF(QS_QF_EQUEUE_GET); 00292 // QS_FILTER_OFF(QS_QF_EQUEUE_GET_LAST); 00293 // QS_FILTER_OFF(QS_QF_MPOOL_INIT); 00294 // QS_FILTER_OFF(QS_QF_MPOOL_GET); 00295 // QS_FILTER_OFF(QS_QF_MPOOL_PUT); 00296 // QS_FILTER_OFF(QS_QF_PUBLISH); 00297 // QS_FILTER_OFF(QS_QF_NEW); 00298 // QS_FILTER_OFF(QS_QF_GC_ATTEMPT); 00299 // QS_FILTER_OFF(QS_QF_GC); 00300 // QS_FILTER_OFF(QS_QF_TICK); 00301 // QS_FILTER_OFF(QS_QF_TIMEEVT_ARM); 00302 // QS_FILTER_OFF(QS_QF_TIMEEVT_AUTO_DISARM); 00303 // QS_FILTER_OFF(QS_QF_TIMEEVT_DISARM_ATTEMPT); 00304 // QS_FILTER_OFF(QS_QF_TIMEEVT_DISARM); 00305 // QS_FILTER_OFF(QS_QF_TIMEEVT_REARM); 00306 // QS_FILTER_OFF(QS_QF_TIMEEVT_POST); 00307 QS_FILTER_OFF(QS_QF_CRIT_ENTRY); 00308 QS_FILTER_OFF(QS_QF_CRIT_EXIT); 00309 QS_FILTER_OFF(QS_QF_ISR_ENTRY); 00310 QS_FILTER_OFF(QS_QF_ISR_EXIT); 00311 00312 return true; // return success 00313 } 00314 //............................................................................ 00315 void QS::onCleanup(void) { 00316 } 00317 //............................................................................ 00318 QSTimeCtr QS::onGetTime(void) { // invoked with interrupts locked 00319 if ((SysTick->CTRL & 0x00000100U) == 0U) { // COUNTFLAG no set? 00320 return DPP::l_tickTime - (QSTimeCtr)SysTick->VAL; 00321 } 00322 else { // the rollover occured, but the SysTick_ISR did not run yet 00323 return DPP::l_tickTime + DPP::l_tickPeriod - (QSTimeCtr)SysTick->VAL; 00324 } 00325 } 00326 //............................................................................ 00327 void QS::onFlush(void) { 00328 uint16_t b; 00329 QF_INT_DISABLE(); 00330 while ((b = QS::getByte()) != QS_EOD) { 00331 while (!DPP::l_qspy.writeable()) { // wait until serial is writable 00332 } 00333 DPP::l_qspy.putc((uint8_t)b); 00334 } 00335 QF_INT_ENABLE(); 00336 } 00337 #endif // Q_SPY 00338 //---------------------------------------------------------------------------- 00339 00340 } // namespace QP
Generated on Sat Jul 23 2022 13:10:38 by 1.7.2