├── .gitignore ├── LICENSE ├── QP-Arduino_GPL_Exception.txt ├── README.org ├── examples ├── blinky-sam │ ├── blinky-sam.ino │ └── blinky-sam.qm ├── blinky2-sam │ ├── blinky2-sam.ino │ └── blinky2-sam.qm ├── blinky_bsp-sam │ ├── blinky.hpp │ ├── blinky_bsp-sam.ino │ ├── blinky_bsp-sam.qm │ ├── bsp.cpp │ └── bsp.hpp ├── blinky_bsp-teensy4 │ ├── .blinky_bsp-teeny4 │ ├── blinky.hpp │ ├── blinky_bsp-teensy4.ino │ ├── blinky_bsp-teeny4.qm │ ├── bsp.cpp │ └── bsp.hpp ├── dpp_bsp-sam │ ├── .dpp_bsp-sam │ ├── bsp.cpp │ ├── bsp.hpp │ ├── dpp.hpp │ ├── dpp_bsp-sam.ino │ ├── dpp_bsp-sam.qm │ ├── philo.cpp │ ├── qview │ │ ├── dpp.py │ │ ├── dpp1.py │ │ ├── img │ │ │ ├── BTN_DWN.gif │ │ │ ├── BTN_UP.gif │ │ │ ├── eating.gif │ │ │ ├── hungry.gif │ │ │ └── thinking.gif │ │ ├── qview-dpp.bat │ │ ├── qview-dpp.lnk │ │ ├── qview-dpp1.bat │ │ └── qview-dpp1.lnk │ └── table.cpp └── dpp_bsp-teensy4 │ ├── .dpp_bsp-teensy4 │ ├── bsp.cpp │ ├── bsp.hpp │ ├── dpp.hpp │ ├── dpp_bsp-teensy4.ino │ ├── dpp_bsp-teensy4.qm │ ├── philo.cpp │ ├── qview │ ├── dpp.py │ ├── dpp1.py │ ├── img │ │ ├── BTN_DWN.gif │ │ ├── BTN_UP.gif │ │ ├── eating.gif │ │ ├── hungry.gif │ │ └── thinking.gif │ ├── qview-dpp.bat │ ├── qview-dpp.lnk │ ├── qview-dpp1.bat │ └── qview-dpp1.lnk │ └── table.cpp ├── extras └── img │ ├── logo_ql_400.png │ └── logo_qp-arduino.png ├── library.properties ├── platformio.ini └── src ├── qp-arduino ├── qassert.h ├── qep.hpp ├── qep_hsm.cpp ├── qep_msm.cpp ├── qep_port.hpp ├── qequeue.hpp ├── qf.hpp ├── qf_act.cpp ├── qf_actq.cpp ├── qf_defer.cpp ├── qf_dyn.cpp ├── qf_mem.cpp ├── qf_pkg.hpp ├── qf_port.hpp ├── qf_ps.cpp ├── qf_qact.cpp ├── qf_qeq.cpp ├── qf_qmact.cpp ├── qf_time.cpp ├── qmpool.hpp ├── qpset.hpp ├── qs.cpp ├── qs.hpp ├── qs_dummy.hpp ├── qs_fp.cpp ├── qs_pkg.hpp ├── qs_port.hpp ├── qs_rx.cpp ├── qstamp.cpp ├── qstamp.hpp ├── qv.cpp ├── qv.hpp ├── qv_port.cpp └── qv_port.hpp └── qpcpp.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.obj 2 | *.o 3 | *.d 4 | *.lib 5 | *.a 6 | *.elf 7 | *.err 8 | *.hex 9 | *.exe 10 | *.EXE 11 | *.map 12 | *.dep 13 | *.pdf 14 | *.PDF 15 | *.Hbp 16 | *.nav 17 | *.tps 18 | *.tws 19 | *.tmp 20 | *.log 21 | *.chm 22 | *.zip 23 | *.pdb 24 | *.ncb 25 | *.suo 26 | *.chw 27 | *.sfr 28 | *.user 29 | *.avrsuo 30 | *.Debug 31 | *.Release 32 | lint*.txt 33 | *.Miro 34 | *.bak 35 | *.qlc 36 | JLink*.* 37 | 38 | eclipse/ 39 | test/ 40 | test_ports/ 41 | dbg/ 42 | rel/ 43 | spy/ 44 | settings/ 45 | .settings/ 46 | targetConfigs/ 47 | 48 | Debug/ 49 | Release/ 50 | Spy/ 51 | 52 | lib/ 53 | obj/ 54 | output/ 55 | 56 | doxygen/html/ 57 | lint/*.txt 58 | lint/MISRA_Exemplar_Suite_test/*.txt 59 | 60 | .DS_Store 61 | .venv 62 | venv 63 | .pio 64 | -------------------------------------------------------------------------------- /QP-Arduino_GPL_Exception.txt: -------------------------------------------------------------------------------- 1 | QP/C++ FRAMEWORK EXCEPTION FOR ARDUINO 2 | 3 | Version 3.0, December 22, 2021 4 | 5 | Copyright (c) 2005-2021 Quantum Leaps, LLC. 6 | 7 | Everyone is permitted to copy and distribute verbatim copies of this 8 | license document, but changing it is not allowed. 9 | 10 | This QP/C++ Framework Exception for Arduino ("Exception") 11 | is an additional permission under section 7 of the GNU General Public 12 | License, version 3 ("GPLv3"). It applies to the QP/C++ 13 | source code (the "QP Frameworks") that is distributed as part of the 14 | QP-Arduino Support Package. 15 | 16 | When you use QP Frameworks inside your program, the QP Frameworks' code 17 | is combined with your code of the program. The purpose of this Exception 18 | is to allow non-GPL (including proprietary) programs to use, in this way, 19 | the QP Frameworks' code covered by this Exception. 20 | 21 | 0. Definitions. 22 | "QP Frameworks" are lightweight real-time embedded frameworks (RTEFs) 23 | as well as all supporting ports and examples, as distributed from: 24 | and 25 | 26 | 27 | "Arduino-Certified Board" means any board with an Arduino-supported 28 | CPU that bears an official Arduino logo and/or is officially certified 29 | under the Arduino Certified Program 30 | (see ). 31 | 32 | "Target Code" refers to output from any compiler and linker in 33 | executable form suitable for execution by an embedded microcontroller. 34 | 35 | 36 | 1. Grant of Additional Permission 37 | As a special Exception, the copyright holder of QP Frameworks gives you 38 | permission to propagate a work of Target Code formed by combining 39 | the QP Frameworks with your own source code without the requirement 40 | to expose your proprietary source code, provided that all Target Code 41 | will execute on Arduino-Certified Board(s). 42 | 43 | 2. No Weakening of GPL 44 | The availability of this Exception does not imply any general 45 | presumption that third-party software is unaffected by the copyleft 46 | requirements of the GPLv3 license. 47 | -------------------------------------------------------------------------------- /examples/blinky-sam/blinky-sam.ino: -------------------------------------------------------------------------------- 1 | //.$file${.::blinky-sam.ino} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 2 | // 3 | // Model: blinky-sam.qm 4 | // File: ${.::blinky-sam.ino} 5 | // 6 | // This code has been generated by QM 5.1.3 . 7 | // DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. 8 | // 9 | // This program is open source software: you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License as published 11 | // by the Free Software Foundation. 12 | // 13 | // This program is distributed in the hope that it will be useful, but 14 | // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | // for more details. 17 | // 18 | //.$endhead${.::blinky-sam.ino} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 19 | #include "qpcpp.hpp" // QP-C++ framework 20 | 21 | using namespace QP; 22 | 23 | enum BlinkySignals { 24 | TIMEOUT_SIG = Q_USER_SIG, 25 | MAX_SIG 26 | }; 27 | 28 | enum { 29 | TICKS_PER_SEC = 100 // number of system clock ticks per second 30 | }; 31 | 32 | //============================================================================ 33 | // genearate declarations of all opaque AO pointers 34 | //.$declare${AOs::AO_Blinky} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 35 | extern QP::QActive * const AO_Blinky; 36 | //.$enddecl${AOs::AO_Blinky} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 37 | //... 38 | 39 | //............................................................................ 40 | void setup() { 41 | QF::init(); // initialize the framework 42 | 43 | // initialize the hardware used in this sketch... 44 | // NOTE: interrupts are configured and started later in QF::onStartup() 45 | pinMode(LED_BUILTIN, OUTPUT); 46 | 47 | // statically allocate event queue buffer for the Blinky AO 48 | static QEvt const *blinky_queueSto[10]; 49 | AO_Blinky->start(1U, // priority 50 | blinky_queueSto, Q_DIM(blinky_queueSto), 51 | (void *)0, 0U); // no stack 52 | } 53 | 54 | //............................................................................ 55 | void loop() { 56 | QF::run(); // run the QF/C++ framework 57 | } 58 | 59 | //============================================================================ 60 | // QF callbacks... 61 | 62 | // ATSAM3X timer used for the system clock tick 63 | // NOTE: re-define the macros to use a different timer/channel 64 | #define TIMER TC1 65 | #define TIMER_CLCK_HZ 650000 66 | #define TIMER_CHANNEL 0 67 | #define TIMER_IRQn TC3_IRQn 68 | #define TIMER_HANDLER TC3_Handler 69 | 70 | // interrupts................................................................. 71 | void TIMER_HANDLER(void) { 72 | TC_GetStatus(TIMER, TIMER_CHANNEL); // clear the interrupt source 73 | QF::TICK_X(0, nullptr); // process time events for tick rate 0 74 | } 75 | //............................................................................ 76 | void QF::onStartup(void) { 77 | // configure the timer-counter channel........ 78 | pmc_set_writeprotect(false); // disable write protection 79 | pmc_enable_periph_clk(TIMER_IRQn); // enable peripheral clock 80 | TC_Configure(TIMER, TIMER_CHANNEL, 81 | TC_CMR_WAVE // WAVE mode 82 | | TC_CMR_WAVSEL_UP_RC // count-up with trigger on RC compare 83 | | TC_CMR_TCCLKS_TIMER_CLOCK4); // internal Clock4 84 | TC_SetRC(TIMER, TIMER_CHANNEL, 85 | TIMER_CLCK_HZ / TICKS_PER_SEC); // set the RC compare value 86 | TC_Start(TIMER, TIMER_CHANNEL); 87 | // enable interrrupt for RC compare 88 | TIMER->TC_CHANNEL[TIMER_CHANNEL].TC_IER = TC_IER_CPCS; 89 | TIMER->TC_CHANNEL[TIMER_CHANNEL].TC_IDR = ~TC_IER_CPCS; 90 | pmc_set_writeprotect(true); // enable write protection 91 | 92 | // explicitly set the NVIC priorities for all kernel AWARE interrupts 93 | NVIC_SetPriority(TIMER_IRQn, QF_AWARE_ISR_CMSIS_PRI); 94 | // ... 95 | 96 | // enable the interrupt in the NVIC 97 | NVIC_EnableIRQ(TIMER_IRQn); 98 | // ... 99 | } 100 | //............................................................................ 101 | void QV::onIdle(void) { // called with interrupts DISABLED 102 | #ifdef NDEBUG 103 | // Put the CPU and peripherals to the low-power mode. You might 104 | // need to customize the clock management for your application, 105 | // see the datasheet for your particular MCU. 106 | QV_CPU_SLEEP(); // atomically go to sleep and enable interrupts 107 | #else 108 | QF_INT_ENABLE(); // simply re-enable interrupts 109 | #endif 110 | } 111 | //............................................................................ 112 | extern "C" Q_NORETURN Q_onAssert(char const * const module, int location) { 113 | // 114 | // NOTE: add here your application-specific error handling 115 | // 116 | (void)module; 117 | (void)location; 118 | 119 | QF_INT_DISABLE(); // disable all interrupts 120 | digitalWrite(LED_BUILTIN, HIGH); // turn the LED on 121 | for (;;) { // sit in an endless loop for now 122 | } 123 | } 124 | 125 | //============================================================================ 126 | // dummy QS callbacks... 127 | 128 | //............................................................................ 129 | void QP::QS::onCleanup(void) { 130 | } 131 | //............................................................................ 132 | QP::QSTimeCtr QP::QS::onGetTime(void) { 133 | return 0U; 134 | } 135 | //............................................................................ 136 | void QP::QS::onFlush(void) { 137 | } 138 | //............................................................................ 139 | void QP::QS::onReset(void) { 140 | } 141 | 142 | //============================================================================ 143 | // generate declarations and definitions of all AO classes (state machines)... 144 | //.$declare${AOs::Blinky} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 145 | //.${AOs::Blinky} ............................................................ 146 | class Blinky : public QP::QActive { 147 | private: 148 | QP::QTimeEvt m_timeEvt; 149 | 150 | public: 151 | static Blinky instance; 152 | 153 | public: 154 | Blinky(); 155 | 156 | protected: 157 | Q_STATE_DECL(initial); 158 | Q_STATE_DECL(off); 159 | Q_STATE_DECL(on); 160 | }; 161 | //.$enddecl${AOs::Blinky} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 162 | //.$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 163 | //. Check for the minimum required QP version 164 | #if (QP_VERSION < 690U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U)) 165 | #error qpcpp version 6.9.0 or higher required 166 | #endif 167 | //.$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 168 | //.$define${AOs::Blinky} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 169 | //.${AOs::Blinky} ............................................................ 170 | Blinky Blinky::instance; 171 | //.${AOs::Blinky::Blinky} .................................................... 172 | Blinky::Blinky() 173 | : QActive(Q_STATE_CAST(&Blinky::initial)), 174 | m_timeEvt(this, TIMEOUT_SIG, 0U) 175 | {} 176 | 177 | //.${AOs::Blinky::SM} ........................................................ 178 | Q_STATE_DEF(Blinky, initial) { 179 | //.${AOs::Blinky::SM::initial} 180 | m_timeEvt.armX(TICKS_PER_SEC/2, TICKS_PER_SEC/2); 181 | (void)e; // unused parameter 182 | return tran(&off); 183 | } 184 | //.${AOs::Blinky::SM::off} ................................................... 185 | Q_STATE_DEF(Blinky, off) { 186 | QP::QState status_; 187 | switch (e->sig) { 188 | //.${AOs::Blinky::SM::off} 189 | case Q_ENTRY_SIG: { 190 | digitalWrite(LED_BUILTIN, LOW); // turn the LED off 191 | status_ = Q_RET_HANDLED; 192 | break; 193 | } 194 | //.${AOs::Blinky::SM::off::TIMEOUT} 195 | case TIMEOUT_SIG: { 196 | status_ = tran(&on); 197 | break; 198 | } 199 | default: { 200 | status_ = super(&top); 201 | break; 202 | } 203 | } 204 | return status_; 205 | } 206 | //.${AOs::Blinky::SM::on} .................................................... 207 | Q_STATE_DEF(Blinky, on) { 208 | QP::QState status_; 209 | switch (e->sig) { 210 | //.${AOs::Blinky::SM::on} 211 | case Q_ENTRY_SIG: { 212 | digitalWrite(LED_BUILTIN, HIGH); // turn the LED on 213 | status_ = Q_RET_HANDLED; 214 | break; 215 | } 216 | //.${AOs::Blinky::SM::on::TIMEOUT} 217 | case TIMEOUT_SIG: { 218 | status_ = tran(&off); 219 | break; 220 | } 221 | default: { 222 | status_ = super(&top); 223 | break; 224 | } 225 | } 226 | return status_; 227 | } 228 | //.$enddef${AOs::Blinky} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 229 | //... 230 | 231 | //============================================================================ 232 | // generate definitions of all AO opaque pointers... 233 | //.$define${AOs::AO_Blinky} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 234 | //.${AOs::AO_Blinky} ......................................................... 235 | QP::QActive * const AO_Blinky = &Blinky::instance; 236 | //.$enddef${AOs::AO_Blinky} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 237 | //... 238 | -------------------------------------------------------------------------------- /examples/blinky-sam/blinky-sam.qm: -------------------------------------------------------------------------------- 1 | 2 | 3 | This is the simple Blinky example for the Arduino DUE board. The example demonstrates: 4 | 5 | 1. One active object class "Blinky" (inside the package "AOs") 6 | 2. A simple state machine 7 | 8 | ---- 9 | # Board configuration: 10 | 11 | The external LED needs to be connected between the pins GND and 13, with the short LEG leg at the GND pin. 12 | 13 | ---- 14 | # More info 15 | 16 | This example places all the code inside the blinky.ino "sketch". The Blinky state machine calls the Arduino services directly (e.g., digitalWrite() to turn the LED on and off). 17 | 18 | This structure of the code is approprate only for very small applications. More advanced projects should use the concept of the Board Support Package (BSP) to insulate the state machines from interacting directly with the hardware. (See also blinky_bsp and other *_bsp examples.) 19 | 20 | 21 | 22 | 23 | 24 | static class instance (Singleton) 25 | 26 | 27 | : QActive(Q_STATE_CAST(&Blinky::initial)), 28 | m_timeEvt(this, TIMEOUT_SIG, 0U) 29 | 30 | 31 | 32 | m_timeEvt.armX(TICKS_PER_SEC/2, TICKS_PER_SEC/2); 33 | (void)e; // unused parameter 34 | 35 | 36 | 37 | 38 | 39 | digitalWrite(LED_BUILTIN, LOW); // turn the LED off 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | digitalWrite(LED_BUILTIN, HIGH); // turn the LED on 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | the opaque pointer to the Blinky AO 65 | = &Blinky::instance; 66 | 67 | 68 | 69 | 70 | #include "qpcpp.hpp" // QP-C++ framework 71 | 72 | using namespace QP; 73 | 74 | enum BlinkySignals { 75 | TIMEOUT_SIG = Q_USER_SIG, 76 | MAX_SIG 77 | }; 78 | 79 | enum { 80 | TICKS_PER_SEC = 100 // number of system clock ticks per second 81 | }; 82 | 83 | //============================================================================ 84 | // genearate declarations of all opaque AO pointers 85 | $declare${AOs::AO_Blinky} 86 | //... 87 | 88 | //............................................................................ 89 | void setup() { 90 | QF::init(); // initialize the framework 91 | 92 | // initialize the hardware used in this sketch... 93 | // NOTE: interrupts are configured and started later in QF::onStartup() 94 | pinMode(LED_BUILTIN, OUTPUT); 95 | 96 | // statically allocate event queue buffer for the Blinky AO 97 | static QEvt const *blinky_queueSto[10]; 98 | AO_Blinky->start(1U, // priority 99 | blinky_queueSto, Q_DIM(blinky_queueSto), 100 | (void *)0, 0U); // no stack 101 | } 102 | 103 | //............................................................................ 104 | void loop() { 105 | QF::run(); // run the QF/C++ framework 106 | } 107 | 108 | //============================================================================ 109 | // QF callbacks... 110 | 111 | // ATSAM3X timer used for the system clock tick 112 | // NOTE: re-define the macros to use a different timer/channel 113 | #define TIMER TC1 114 | #define TIMER_CLCK_HZ 650000 115 | #define TIMER_CHANNEL 0 116 | #define TIMER_IRQn TC3_IRQn 117 | #define TIMER_HANDLER TC3_Handler 118 | 119 | // interrupts................................................................. 120 | void TIMER_HANDLER(void) { 121 | TC_GetStatus(TIMER, TIMER_CHANNEL); // clear the interrupt source 122 | QF::TICK_X(0, nullptr); // process time events for tick rate 0 123 | } 124 | //............................................................................ 125 | void QF::onStartup(void) { 126 | // configure the timer-counter channel........ 127 | pmc_set_writeprotect(false); // disable write protection 128 | pmc_enable_periph_clk(TIMER_IRQn); // enable peripheral clock 129 | TC_Configure(TIMER, TIMER_CHANNEL, 130 | TC_CMR_WAVE // WAVE mode 131 | | TC_CMR_WAVSEL_UP_RC // count-up with trigger on RC compare 132 | | TC_CMR_TCCLKS_TIMER_CLOCK4); // internal Clock4 133 | TC_SetRC(TIMER, TIMER_CHANNEL, 134 | TIMER_CLCK_HZ / TICKS_PER_SEC); // set the RC compare value 135 | TC_Start(TIMER, TIMER_CHANNEL); 136 | // enable interrrupt for RC compare 137 | TIMER->TC_CHANNEL[TIMER_CHANNEL].TC_IER = TC_IER_CPCS; 138 | TIMER->TC_CHANNEL[TIMER_CHANNEL].TC_IDR = ~TC_IER_CPCS; 139 | pmc_set_writeprotect(true); // enable write protection 140 | 141 | // explicitly set the NVIC priorities for all kernel AWARE interrupts 142 | NVIC_SetPriority(TIMER_IRQn, QF_AWARE_ISR_CMSIS_PRI); 143 | // ... 144 | 145 | // enable the interrupt in the NVIC 146 | NVIC_EnableIRQ(TIMER_IRQn); 147 | // ... 148 | } 149 | //............................................................................ 150 | void QV::onIdle(void) { // called with interrupts DISABLED 151 | #ifdef NDEBUG 152 | // Put the CPU and peripherals to the low-power mode. You might 153 | // need to customize the clock management for your application, 154 | // see the datasheet for your particular MCU. 155 | QV_CPU_SLEEP(); // atomically go to sleep and enable interrupts 156 | #else 157 | QF_INT_ENABLE(); // simply re-enable interrupts 158 | #endif 159 | } 160 | //............................................................................ 161 | extern "C" Q_NORETURN Q_onAssert(char const * const module, int location) { 162 | // 163 | // NOTE: add here your application-specific error handling 164 | // 165 | (void)module; 166 | (void)location; 167 | 168 | QF_INT_DISABLE(); // disable all interrupts 169 | digitalWrite(LED_BUILTIN, HIGH); // turn the LED on 170 | for (;;) { // sit in an endless loop for now 171 | } 172 | } 173 | 174 | //============================================================================ 175 | // dummy QS callbacks... 176 | 177 | //............................................................................ 178 | void QP::QS::onCleanup(void) { 179 | } 180 | //............................................................................ 181 | QP::QSTimeCtr QP::QS::onGetTime(void) { 182 | return 0U; 183 | } 184 | //............................................................................ 185 | void QP::QS::onFlush(void) { 186 | } 187 | //............................................................................ 188 | void QP::QS::onReset(void) { 189 | } 190 | 191 | //============================================================================ 192 | // generate declarations and definitions of all AO classes (state machines)... 193 | $declare${AOs::Blinky} 194 | $define${AOs::Blinky} 195 | //... 196 | 197 | //============================================================================ 198 | // generate definitions of all AO opaque pointers... 199 | $define${AOs::AO_Blinky} 200 | //... 201 | 202 | 203 | 204 | 205 | -------------------------------------------------------------------------------- /examples/blinky_bsp-sam/blinky.hpp: -------------------------------------------------------------------------------- 1 | //.$file${.::blinky.hpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 2 | // 3 | // Model: blinky_bsp-sam.qm 4 | // File: ${.::blinky.hpp} 5 | // 6 | // This code has been generated by QM 5.1.3 . 7 | // DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. 8 | // 9 | // This program is open source software: you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License as published 11 | // by the Free Software Foundation. 12 | // 13 | // This program is distributed in the hope that it will be useful, but 14 | // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | // for more details. 17 | // 18 | //.$endhead${.::blinky.hpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 19 | #ifndef BLINKY_HPP 20 | #define BLINKY_HPP 21 | 22 | enum BlinkySignals { 23 | TIMEOUT_SIG = QP::Q_USER_SIG, 24 | MAX_SIG 25 | }; 26 | 27 | // genearate declarations of all opaque AO pointers 28 | //.$declare${AOs::AO_Blinky} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 29 | extern QP::QActive * const AO_Blinky; 30 | //.$enddecl${AOs::AO_Blinky} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 31 | //... 32 | 33 | #endif // BLINKY_HPP 34 | -------------------------------------------------------------------------------- /examples/blinky_bsp-sam/blinky_bsp-sam.ino: -------------------------------------------------------------------------------- 1 | //.$file${.::blinky_bsp-sam.ino} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 2 | // 3 | // Model: blinky_bsp-sam.qm 4 | // File: ${.::blinky_bsp-sam.ino} 5 | // 6 | // This code has been generated by QM 5.1.3 . 7 | // DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. 8 | // 9 | // This program is open source software: you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License as published 11 | // by the Free Software Foundation. 12 | // 13 | // This program is distributed in the hope that it will be useful, but 14 | // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | // for more details. 17 | // 18 | //.$endhead${.::blinky_bsp-sam.ino} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 19 | #include "qpcpp.hpp" // QP-C++ framework 20 | #include "blinky.hpp" // Blinky application interface 21 | #include "bsp.hpp" // Board Support Package (BSP) 22 | 23 | using namespace QP; 24 | 25 | //............................................................................ 26 | void setup() { 27 | QF::init(); // initialize the framework 28 | BSP::init(); // initialize the BSP 29 | 30 | // statically allocate event queues for the AOs and start them... 31 | static QEvt const *blinky_queueSto[10]; 32 | AO_Blinky->start(1U, // priority 33 | blinky_queueSto, Q_DIM(blinky_queueSto), 34 | (void *)0, 0U); // no stack 35 | //... 36 | } 37 | 38 | //............................................................................ 39 | void loop() { 40 | QF::run(); // run the QF/C++ framework 41 | } 42 | 43 | //============================================================================ 44 | // generate declarations and definitions of all AO classes (state machines)... 45 | //.$declare${AOs::Blinky} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 46 | //.${AOs::Blinky} ............................................................ 47 | class Blinky : public QP::QActive { 48 | private: 49 | QP::QTimeEvt m_timeEvt; 50 | 51 | public: 52 | static Blinky instance; 53 | 54 | public: 55 | Blinky(); 56 | 57 | protected: 58 | Q_STATE_DECL(initial); 59 | Q_STATE_DECL(off); 60 | Q_STATE_DECL(on); 61 | }; 62 | //.$enddecl${AOs::Blinky} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 63 | //.$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 64 | //. Check for the minimum required QP version 65 | #if (QP_VERSION < 690U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U)) 66 | #error qpcpp version 6.9.0 or higher required 67 | #endif 68 | //.$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 69 | //.$define${AOs::Blinky} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 70 | //.${AOs::Blinky} ............................................................ 71 | Blinky Blinky::instance; 72 | //.${AOs::Blinky::Blinky} .................................................... 73 | Blinky::Blinky() 74 | : QActive(Q_STATE_CAST(&Blinky::initial)), 75 | m_timeEvt(this, TIMEOUT_SIG, 0U) 76 | {} 77 | 78 | //.${AOs::Blinky::SM} ........................................................ 79 | Q_STATE_DEF(Blinky, initial) { 80 | //.${AOs::Blinky::SM::initial} 81 | (void)e; // unused parameter 82 | m_timeEvt.armX(BSP::TICKS_PER_SEC/2, BSP::TICKS_PER_SEC/2); 83 | 84 | QS_OBJ_DICTIONARY(&Blinky::instance); 85 | QS_SIG_DICTIONARY(TIMEOUT_SIG, nullptr); 86 | 87 | QS_FUN_DICTIONARY(&Blinky::off); 88 | QS_FUN_DICTIONARY(&Blinky::on); 89 | 90 | return tran(&off); 91 | } 92 | //.${AOs::Blinky::SM::off} ................................................... 93 | Q_STATE_DEF(Blinky, off) { 94 | QP::QState status_; 95 | switch (e->sig) { 96 | //.${AOs::Blinky::SM::off} 97 | case Q_ENTRY_SIG: { 98 | BSP::ledOff(); 99 | status_ = Q_RET_HANDLED; 100 | break; 101 | } 102 | //.${AOs::Blinky::SM::off::TIMEOUT} 103 | case TIMEOUT_SIG: { 104 | status_ = tran(&on); 105 | break; 106 | } 107 | default: { 108 | status_ = super(&top); 109 | break; 110 | } 111 | } 112 | return status_; 113 | } 114 | //.${AOs::Blinky::SM::on} .................................................... 115 | Q_STATE_DEF(Blinky, on) { 116 | QP::QState status_; 117 | switch (e->sig) { 118 | //.${AOs::Blinky::SM::on} 119 | case Q_ENTRY_SIG: { 120 | BSP::ledOn(); 121 | status_ = Q_RET_HANDLED; 122 | break; 123 | } 124 | //.${AOs::Blinky::SM::on::TIMEOUT} 125 | case TIMEOUT_SIG: { 126 | status_ = tran(&off); 127 | break; 128 | } 129 | default: { 130 | status_ = super(&top); 131 | break; 132 | } 133 | } 134 | return status_; 135 | } 136 | //.$enddef${AOs::Blinky} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 137 | //... 138 | 139 | //============================================================================ 140 | // generate definitions of all AO opaque pointers... 141 | //.$define${AOs::AO_Blinky} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 142 | //.${AOs::AO_Blinky} ......................................................... 143 | QP::QActive * const AO_Blinky = &Blinky::instance; 144 | //.$enddef${AOs::AO_Blinky} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 145 | //... 146 | -------------------------------------------------------------------------------- /examples/blinky_bsp-sam/bsp.cpp: -------------------------------------------------------------------------------- 1 | //.$file${.::bsp.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 2 | // 3 | // Model: blinky_bsp-sam.qm 4 | // File: ${.::bsp.cpp} 5 | // 6 | // This code has been generated by QM 5.1.3 . 7 | // DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. 8 | // 9 | // This program is open source software: you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License as published 11 | // by the Free Software Foundation. 12 | // 13 | // This program is distributed in the hope that it will be useful, but 14 | // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | // for more details. 17 | // 18 | //.$endhead${.::bsp.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 19 | #include "qpcpp.hpp" // QP-C++ framework 20 | #include "blinky.hpp" // Blinky application interface 21 | #include "bsp.hpp" // Board Support Package (BSP) 22 | 23 | using namespace QP; 24 | 25 | //---------------------------------------------------------------------------- 26 | // QS facilities 27 | 28 | // un-comment if QS instrumentation needed 29 | //#define QS_ON 30 | 31 | static QP::QSpyId const l_TIMER_ID = { 0U }; // QSpy source ID 32 | 33 | //---------------------------------------------------------------------------- 34 | // BSP functions 35 | 36 | //............................................................................ 37 | void BSP::init(void) { 38 | // initialize the hardware used in this sketch... 39 | // NOTE: interrupts are configured and started later in QF::onStartup() 40 | pinMode(LED_BUILTIN, OUTPUT); 41 | 42 | #ifdef QS_ON 43 | QS_INIT(nullptr); 44 | 45 | // output QS dictionaries... 46 | QS_OBJ_DICTIONARY(&l_TIMER_ID); 47 | 48 | // setup the QS filters... 49 | QS_GLB_FILTER(QP::QS_SM_RECORDS); // state machine records 50 | QS_GLB_FILTER(QP::QS_AO_RECORDS); // active object records 51 | QS_GLB_FILTER(QP::QS_UA_RECORDS); // all user records 52 | #endif 53 | } 54 | //............................................................................ 55 | void BSP::ledOff(void) { 56 | digitalWrite(LED_BUILTIN, LOW); 57 | } 58 | //............................................................................ 59 | void BSP::ledOn(void) { 60 | digitalWrite(LED_BUILTIN, HIGH); 61 | } 62 | 63 | //---------------------------------------------------------------------------- 64 | // QF callbacks... 65 | 66 | // ATSAM3X timer used for the system clock tick 67 | // 68 | // NOTE: The usual source of system clock tick in ARM Cortex-M (SysTick timer) 69 | // is aready used by the Arduino library. Therefore, this code uses a different 70 | // hardware timer of the ATSAM MCU for providing the system clock tick. 71 | // 72 | // NOTE: You can re-define the macros to use a different ATSAM timer/channel. 73 | // 74 | #define TIMER TC1 75 | #define TIMER_CLCK_HZ 650000 76 | #define TIMER_CHANNEL 0 77 | #define TIMER_IRQn TC3_IRQn 78 | #define TIMER_HANDLER TC3_Handler 79 | 80 | // interrupts................................................................. 81 | void TIMER_HANDLER(void) { 82 | TC_GetStatus(TIMER, TIMER_CHANNEL); // clear the interrupt source 83 | QF::TICK_X(0U, &l_TIMER_ID); // process time events for tick rate 0 84 | } 85 | //............................................................................ 86 | void QF::onStartup(void) { 87 | // configure the timer-counter channel........ 88 | pmc_set_writeprotect(false); // disable write protection 89 | pmc_enable_periph_clk(TIMER_IRQn); // enable peripheral clock 90 | TC_Configure(TIMER, TIMER_CHANNEL, 91 | TC_CMR_WAVE // WAVE mode 92 | | TC_CMR_WAVSEL_UP_RC // count-up with trigger on RC compare 93 | | TC_CMR_TCCLKS_TIMER_CLOCK4); // internal Clock4 94 | TC_SetRC(TIMER, TIMER_CHANNEL, 95 | TIMER_CLCK_HZ / BSP::TICKS_PER_SEC); // set the RC compare value 96 | TC_Start(TIMER, TIMER_CHANNEL); 97 | // enable interrrupt for RC compare 98 | TIMER->TC_CHANNEL[TIMER_CHANNEL].TC_IER = TC_IER_CPCS; 99 | TIMER->TC_CHANNEL[TIMER_CHANNEL].TC_IDR = ~TC_IER_CPCS; 100 | pmc_set_writeprotect(true); // enable write protection 101 | 102 | // explicitly set the NVIC priorities for all "kernel AWARE" interrupts 103 | // NOTE: This is important! 104 | NVIC_SetPriority(TIMER_IRQn, QF_AWARE_ISR_CMSIS_PRI); 105 | // ... 106 | 107 | // enable the interrupts in the NVIC 108 | NVIC_EnableIRQ(TIMER_IRQn); 109 | // ... 110 | } 111 | 112 | //............................................................................ 113 | void QV::onIdle(void) { // called with interrupts DISABLED 114 | #ifdef NDEBUG 115 | // Put the CPU and peripherals to the low-power mode. You might 116 | // need to customize the clock management for your application, 117 | // see the datasheet for your particular MCU. 118 | QV_CPU_SLEEP(); // atomically go to sleep and enable interrupts 119 | #else 120 | QF_INT_ENABLE(); // simply re-enable interrupts 121 | 122 | #ifdef QS_ON 123 | 124 | // transmit QS outgoing data (QS-TX) 125 | uint16_t len = Serial.availableForWrite(); 126 | if (len > 0U) { // any space available in the output buffer? 127 | uint8_t const *buf = QS::getBlock(&len); 128 | if (buf) { 129 | Serial.write(buf, len); // asynchronous and non-blocking 130 | } 131 | } 132 | 133 | // receive QS incoming data (QS-RX) 134 | len = Serial.available(); 135 | if (len > 0U) { 136 | do { 137 | QP::QS::rxPut(Serial.read()); 138 | } while (--len > 0U); 139 | QS::rxParse(); 140 | } 141 | 142 | #endif // QS_ON 143 | 144 | #endif 145 | } 146 | //............................................................................ 147 | extern "C" Q_NORETURN Q_onAssert(char const * const module, int location) { 148 | // 149 | // NOTE: add here your application-specific error handling 150 | // 151 | (void)module; 152 | (void)location; 153 | 154 | QF_INT_DISABLE(); // disable all interrupts 155 | BSP::ledOn(); // trun the LED on 156 | for (;;) { // sit in an endless loop for now 157 | } 158 | } 159 | 160 | //---------------------------------------------------------------------------- 161 | // QS callbacks... 162 | #ifdef QS_ON 163 | 164 | //............................................................................ 165 | bool QP::QS::onStartup(void const * arg) { 166 | static uint8_t qsTxBuf[1024]; // buffer for QS transmit channel (QS-TX) 167 | static uint8_t qsRxBuf[128]; // buffer for QS receive channel (QS-RX) 168 | initBuf (qsTxBuf, sizeof(qsTxBuf)); 169 | rxInitBuf(qsRxBuf, sizeof(qsRxBuf)); 170 | Serial.begin(115200); // run serial port at 115200 baud rate 171 | return true; // return success 172 | } 173 | //............................................................................ 174 | void QP::QS::onCommand(uint8_t cmdId, uint32_t param1, 175 | uint32_t param2, uint32_t param3) 176 | { 177 | (void)cmdId; 178 | (void)param1; 179 | (void)param2; 180 | (void)param3; 181 | } 182 | 183 | #endif // QS_ON 184 | 185 | //............................................................................ 186 | void QP::QS::onCleanup(void) { 187 | } 188 | //............................................................................ 189 | QP::QSTimeCtr QP::QS::onGetTime(void) { 190 | return millis(); 191 | } 192 | //............................................................................ 193 | void QP::QS::onFlush(void) { 194 | #ifdef QS_ON 195 | uint16_t len = 0xFFFFU; // big number to get as many bytes as available 196 | uint8_t const *buf = QS::getBlock(&len); // get continguous block of data 197 | while (buf != nullptr) { // data available? 198 | Serial.write(buf, len); // might poll until all bytes fit 199 | len = 0xFFFFU; // big number to get as many bytes as available 200 | buf = QS::getBlock(&len); // try to get more data 201 | } 202 | Serial.flush(); // wait for the transmission of outgoing data to complete 203 | #endif // QS_ON 204 | } 205 | //............................................................................ 206 | void QP::QS::onReset(void) { 207 | NVIC_SystemReset(); 208 | } 209 | -------------------------------------------------------------------------------- /examples/blinky_bsp-sam/bsp.hpp: -------------------------------------------------------------------------------- 1 | //.$file${.::bsp.hpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 2 | // 3 | // Model: blinky_bsp-sam.qm 4 | // File: ${.::bsp.hpp} 5 | // 6 | // This code has been generated by QM 5.1.3 . 7 | // DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. 8 | // 9 | // This program is open source software: you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License as published 11 | // by the Free Software Foundation. 12 | // 13 | // This program is distributed in the hope that it will be useful, but 14 | // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | // for more details. 17 | // 18 | //.$endhead${.::bsp.hpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 19 | #ifndef BSP_HPP 20 | #define BSP_HPP 21 | 22 | class BSP { 23 | public: 24 | enum { TICKS_PER_SEC = 100} ; 25 | static void init(void); 26 | static void ledOff(void); 27 | static void ledOn(void); 28 | }; 29 | 30 | #endif // BSP_HPP 31 | -------------------------------------------------------------------------------- /examples/blinky_bsp-teensy4/.blinky_bsp-teeny4: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 1 7 | 0 8 | 3 9 | 0 10 | 11 | 12 | 0,0,932,625,* 13 | 14 | 15 | 2032128 16 | 0 17 | 18 | 19 | 20 | 21 | 0 22 | 23 | 24 | 25 | 26 | 0 27 | 28 | 29 | 0 30 | 31 | 32 | 33 | 34 | 0 35 | 36 | 37 | 0 38 | 39 | 40 | 41 | 42 | 0 43 | 44 | 45 | 0 46 | 47 | 48 | 49 | 50 | 0 51 | 52 | 53 | 0 54 | 55 | 56 | 57 | 58 | 0 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /examples/blinky_bsp-teensy4/blinky.hpp: -------------------------------------------------------------------------------- 1 | //.$file${.::blinky.hpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 2 | // 3 | // Model: blinky_bsp-teeny4.qm 4 | // File: ${.::blinky.hpp} 5 | // 6 | // This code has been generated by QM 5.1.3 . 7 | // DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. 8 | // 9 | // This program is open source software: you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License as published 11 | // by the Free Software Foundation. 12 | // 13 | // This program is distributed in the hope that it will be useful, but 14 | // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | // for more details. 17 | // 18 | //.$endhead${.::blinky.hpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 19 | #ifndef BLINKY_HPP 20 | #define BLINKY_HPP 21 | 22 | enum BlinkySignals { 23 | TIMEOUT_SIG = QP::Q_USER_SIG, 24 | MAX_SIG 25 | }; 26 | 27 | // genearate declarations of all opaque AO pointers 28 | //.$declare${AOs::AO_Blinky} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 29 | extern QP::QActive * const AO_Blinky; 30 | //.$enddecl${AOs::AO_Blinky} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 31 | //... 32 | 33 | #endif // BLINKY_HPP 34 | -------------------------------------------------------------------------------- /examples/blinky_bsp-teensy4/blinky_bsp-teensy4.ino: -------------------------------------------------------------------------------- 1 | //.$file${.::blinky_bsp-teensy4.ino} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 2 | // 3 | // Model: blinky_bsp-teeny4.qm 4 | // File: ${.::blinky_bsp-teensy4.ino} 5 | // 6 | // This code has been generated by QM 5.1.3 . 7 | // DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. 8 | // 9 | // This program is open source software: you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License as published 11 | // by the Free Software Foundation. 12 | // 13 | // This program is distributed in the hope that it will be useful, but 14 | // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | // for more details. 17 | // 18 | //.$endhead${.::blinky_bsp-teensy4.ino} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 19 | #include "qpcpp.hpp" // QP-C++ framework 20 | #include "blinky.hpp" // Blinky application interface 21 | #include "bsp.hpp" // Board Support Package (BSP) 22 | 23 | using namespace QP; 24 | 25 | //............................................................................ 26 | void setup() { 27 | QF::init(); // initialize the framework 28 | BSP::init(); // initialize the BSP 29 | 30 | // statically allocate event queues for the AOs and start them... 31 | static QEvt const *blinky_queueSto[10]; 32 | AO_Blinky->start(1U, // priority 33 | blinky_queueSto, Q_DIM(blinky_queueSto), 34 | (void *)0, 0U); // no stack 35 | //... 36 | } 37 | 38 | //............................................................................ 39 | void loop() { 40 | QF::run(); // run the QF/C++ framework 41 | } 42 | 43 | //============================================================================ 44 | // generate declarations and definitions of all AO classes (state machines)... 45 | //.$declare${AOs::Blinky} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 46 | //.${AOs::Blinky} ............................................................ 47 | class Blinky : public QP::QActive { 48 | private: 49 | QP::QTimeEvt m_timeEvt; 50 | 51 | public: 52 | static Blinky instance; 53 | 54 | public: 55 | Blinky(); 56 | 57 | protected: 58 | Q_STATE_DECL(initial); 59 | Q_STATE_DECL(off); 60 | Q_STATE_DECL(on); 61 | }; 62 | //.$enddecl${AOs::Blinky} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 63 | //.$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 64 | //. Check for the minimum required QP version 65 | #if (QP_VERSION < 690U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U)) 66 | #error qpcpp version 6.9.0 or higher required 67 | #endif 68 | //.$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 69 | //.$define${AOs::Blinky} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 70 | //.${AOs::Blinky} ............................................................ 71 | Blinky Blinky::instance; 72 | //.${AOs::Blinky::Blinky} .................................................... 73 | Blinky::Blinky() 74 | : QActive(Q_STATE_CAST(&Blinky::initial)), 75 | m_timeEvt(this, TIMEOUT_SIG, 0U) 76 | {} 77 | 78 | //.${AOs::Blinky::SM} ........................................................ 79 | Q_STATE_DEF(Blinky, initial) { 80 | //.${AOs::Blinky::SM::initial} 81 | m_timeEvt.armX(BSP::TICKS_PER_SEC/2, BSP::TICKS_PER_SEC/2); 82 | (void)e; // unused parameter 83 | return tran(&off); 84 | } 85 | //.${AOs::Blinky::SM::off} ................................................... 86 | Q_STATE_DEF(Blinky, off) { 87 | QP::QState status_; 88 | switch (e->sig) { 89 | //.${AOs::Blinky::SM::off} 90 | case Q_ENTRY_SIG: { 91 | BSP::ledOff(); 92 | status_ = Q_RET_HANDLED; 93 | break; 94 | } 95 | //.${AOs::Blinky::SM::off::TIMEOUT} 96 | case TIMEOUT_SIG: { 97 | status_ = tran(&on); 98 | break; 99 | } 100 | default: { 101 | status_ = super(&top); 102 | break; 103 | } 104 | } 105 | return status_; 106 | } 107 | //.${AOs::Blinky::SM::on} .................................................... 108 | Q_STATE_DEF(Blinky, on) { 109 | QP::QState status_; 110 | switch (e->sig) { 111 | //.${AOs::Blinky::SM::on} 112 | case Q_ENTRY_SIG: { 113 | BSP::ledOn(); 114 | status_ = Q_RET_HANDLED; 115 | break; 116 | } 117 | //.${AOs::Blinky::SM::on::TIMEOUT} 118 | case TIMEOUT_SIG: { 119 | status_ = tran(&off); 120 | break; 121 | } 122 | default: { 123 | status_ = super(&top); 124 | break; 125 | } 126 | } 127 | return status_; 128 | } 129 | //.$enddef${AOs::Blinky} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 130 | //... 131 | 132 | //============================================================================ 133 | // generate definitions of all AO opaque pointers... 134 | //.$define${AOs::AO_Blinky} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 135 | //.${AOs::AO_Blinky} ......................................................... 136 | QP::QActive * const AO_Blinky = &Blinky::instance; 137 | //.$enddef${AOs::AO_Blinky} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 138 | //... 139 | -------------------------------------------------------------------------------- /examples/blinky_bsp-teensy4/bsp.cpp: -------------------------------------------------------------------------------- 1 | //.$file${.::bsp.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 2 | // 3 | // Model: blinky_bsp-teeny4.qm 4 | // File: ${.::bsp.cpp} 5 | // 6 | // This code has been generated by QM 5.1.3 . 7 | // DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. 8 | // 9 | // This program is open source software: you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License as published 11 | // by the Free Software Foundation. 12 | // 13 | // This program is distributed in the hope that it will be useful, but 14 | // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | // for more details. 17 | // 18 | //.$endhead${.::bsp.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 19 | #include "qpcpp.hpp" // QP-C++ framework 20 | #include "blinky.hpp" // Blinky application interface 21 | #include "bsp.hpp" // Board Support Package (BSP) 22 | 23 | using namespace QP; 24 | 25 | //---------------------------------------------------------------------------- 26 | // QS facilities 27 | 28 | // un-comment if QS instrumentation needed 29 | //#define QS_ON 30 | 31 | static QP::QSpyId const l_TIMER_ID = { 0U }; // QSpy source ID 32 | 33 | //---------------------------------------------------------------------------- 34 | // BSP functions 35 | 36 | //............................................................................ 37 | void BSP::init(void) { 38 | // initialize the hardware used in this sketch... 39 | // NOTE: interrupts are configured and started later in QF::onStartup() 40 | pinMode(LED_BUILTIN, OUTPUT); 41 | 42 | #ifdef QS_ON 43 | QS_INIT(nullptr); 44 | 45 | // output QS dictionaries... 46 | QS_OBJ_DICTIONARY(&l_TIMER_ID); 47 | 48 | // setup the QS filters... 49 | QS_GLB_FILTER(QP::QS_SM_RECORDS); // state machine records 50 | QS_GLB_FILTER(QP::QS_AO_RECORDS); // active object records 51 | QS_GLB_FILTER(QP::QS_UA_RECORDS); // all user records 52 | #endif 53 | } 54 | //............................................................................ 55 | void BSP::ledOff(void) { 56 | digitalWrite(LED_BUILTIN, LOW); 57 | } 58 | //............................................................................ 59 | void BSP::ledOn(void) { 60 | digitalWrite(LED_BUILTIN, HIGH); 61 | } 62 | 63 | //---------------------------------------------------------------------------- 64 | // QF callbacks... 65 | 66 | // 67 | // NOTE: The usual source of system clock tick in ARM Cortex-M (SysTick timer) 68 | // is aready used by the Arduino library. Therefore, this code uses a different 69 | // hardware Timer1 of the Teensy 4 board for providing the system clock tick. 70 | // 71 | // NOTE: You can re-define the macros to use a different ATSAM timer/channel. 72 | // 73 | #include // Teensy Timer1 interface 74 | 75 | #define TIMER1_CLCK_HZ 1000000 76 | #define TIMER_HANDLER T1_Handler 77 | 78 | // interrupts................................................................. 79 | void TIMER_HANDLER(void) { 80 | QF::TICK_X(0, &l_TIMER_ID); // process time events for tick rate 0 81 | } 82 | //............................................................................ 83 | void QF::onStartup(void) { 84 | // configure the timer-counter channel........ 85 | Timer1.initialize(TIMER1_CLCK_HZ / BSP::TICKS_PER_SEC); 86 | Timer1.attachInterrupt(TIMER_HANDLER); 87 | // ... 88 | } 89 | //............................................................................ 90 | void QV::onIdle(void) { // called with interrupts DISABLED 91 | #ifdef NDEBUG 92 | // Put the CPU and peripherals to the low-power mode. You might 93 | // need to customize the clock management for your application, 94 | // see the datasheet for your particular MCU. 95 | QV_CPU_SLEEP(); // atomically go to sleep and enable interrupts 96 | #else 97 | QF_INT_ENABLE(); // simply re-enable interrupts 98 | 99 | #ifdef QS_ON 100 | 101 | // transmit QS outgoing data (QS-TX) 102 | uint16_t len = Serial.availableForWrite(); 103 | if (len > 0U) { // any space available in the output buffer? 104 | uint8_t const *buf = QS::getBlock(&len); 105 | if (buf) { 106 | Serial.write(buf, len); // asynchronous and non-blocking 107 | } 108 | } 109 | 110 | // receive QS incoming data (QS-RX) 111 | len = Serial.available(); 112 | if (len > 0U) { 113 | do { 114 | QP::QS::rxPut(Serial.read()); 115 | } while (--len > 0U); 116 | QS::rxParse(); 117 | } 118 | 119 | #endif // QS_ON 120 | 121 | #endif 122 | } 123 | //............................................................................ 124 | extern "C" Q_NORETURN Q_onAssert(char const * const module, int location) { 125 | // 126 | // NOTE: add here your application-specific error handling 127 | // 128 | (void)module; 129 | (void)location; 130 | 131 | QF_INT_DISABLE(); // disable all interrupts 132 | BSP::ledOn(); // trun the LED on 133 | for (;;) { // freeze in an endless loop for now... 134 | } 135 | } 136 | 137 | //---------------------------------------------------------------------------- 138 | // QS callbacks... 139 | #ifdef QS_ON 140 | 141 | //............................................................................ 142 | bool QP::QS::onStartup(void const * arg) { 143 | static uint8_t qsTxBuf[1024]; // buffer for QS transmit channel (QS-TX) 144 | static uint8_t qsRxBuf[128]; // buffer for QS receive channel (QS-RX) 145 | initBuf (qsTxBuf, sizeof(qsTxBuf)); 146 | rxInitBuf(qsRxBuf, sizeof(qsRxBuf)); 147 | Serial.begin(115200); // run serial port at 115200 baud rate 148 | return true; // return success 149 | } 150 | //............................................................................ 151 | void QP::QS::onCommand(uint8_t cmdId, uint32_t param1, 152 | uint32_t param2, uint32_t param3) 153 | { 154 | } 155 | 156 | #endif // QS_ON 157 | 158 | //............................................................................ 159 | void QP::QS::onCleanup(void) { 160 | } 161 | //............................................................................ 162 | QP::QSTimeCtr QP::QS::onGetTime(void) { 163 | return millis(); 164 | } 165 | //............................................................................ 166 | void QP::QS::onFlush(void) { 167 | #ifdef QS_ON 168 | uint16_t len = 0xFFFFU; // big number to get as many bytes as available 169 | uint8_t const *buf = QS::getBlock(&len); // get continguous block of data 170 | while (buf != nullptr) { // data available? 171 | Serial.write(buf, len); // might poll until all bytes fit 172 | len = 0xFFFFU; // big number to get as many bytes as available 173 | buf = QS::getBlock(&len); // try to get more data 174 | } 175 | Serial.flush(); // wait for the transmission of outgoing data to complete 176 | #endif // QS_ON 177 | } 178 | //............................................................................ 179 | void QP::QS::onReset(void) { 180 | //??? TBD for Teensy 181 | } 182 | -------------------------------------------------------------------------------- /examples/blinky_bsp-teensy4/bsp.hpp: -------------------------------------------------------------------------------- 1 | //.$file${.::bsp.hpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 2 | // 3 | // Model: blinky_bsp-teeny4.qm 4 | // File: ${.::bsp.hpp} 5 | // 6 | // This code has been generated by QM 5.1.3 . 7 | // DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. 8 | // 9 | // This program is open source software: you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License as published 11 | // by the Free Software Foundation. 12 | // 13 | // This program is distributed in the hope that it will be useful, but 14 | // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | // for more details. 17 | // 18 | //.$endhead${.::bsp.hpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 19 | #ifndef BSP_HPP 20 | #define BSP_HPP 21 | 22 | class BSP { 23 | public: 24 | enum { TICKS_PER_SEC = 100} ; 25 | static void init(void); 26 | static void ledOff(void); 27 | static void ledOn(void); 28 | }; 29 | 30 | #endif // BSP_HPP 31 | -------------------------------------------------------------------------------- /examples/dpp_bsp-sam/.dpp_bsp-sam: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 1 7 | 0 8 | 3 9 | 0 10 | 11 | 12 | 0,0,640,480 13 | 363,318,640,480 14 | 407,0,596,300 15 | 0,0,1003,765,* 16 | 0,0,1003,765 17 | 0,33,1003,765 18 | 0,498,596,300 19 | 0,0,596,300 20 | 21 | 22 | 2032128 23 | 0 24 | 25 | 26 | 27 | 28 | 0 29 | 30 | 31 | 32 | 33 | 0 34 | 35 | 36 | 0 37 | 38 | 39 | 40 | 41 | 0 42 | 43 | 44 | 0 45 | 46 | 47 | 48 | 49 | 0 50 | 51 | 52 | 0 53 | 54 | 55 | 56 | 57 | 0 58 | 59 | 60 | 0 61 | 62 | 63 | 64 | 65 | 0 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /examples/dpp_bsp-sam/bsp.hpp: -------------------------------------------------------------------------------- 1 | //.$file${.::bsp.hpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 2 | // 3 | // Model: dpp_bsp-sam.qm 4 | // File: ${.::bsp.hpp} 5 | // 6 | // This code has been generated by QM 5.1.3 . 7 | // DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. 8 | // 9 | // This program is open source software: you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License as published 11 | // by the Free Software Foundation. 12 | // 13 | // This program is distributed in the hope that it will be useful, but 14 | // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | // for more details. 17 | // 18 | //.$endhead${.::bsp.hpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 19 | #ifndef BSP_HPP 20 | #define BSP_HPP 21 | 22 | class BSP { 23 | public: 24 | enum { TICKS_PER_SEC = 100} ; 25 | static void init(void); 26 | static void displayPaused(uint8_t const paused); 27 | static void displayPhilStat(uint8_t const n, char_t const *stat); 28 | static void terminate(int16_t const result); 29 | 30 | static void randomSeed(uint32_t const seed); // random seed 31 | static uint32_t random(void); // pseudo-random generator 32 | static QP::QTimeEvtCtr think_rnd_time(); 33 | static QP::QTimeEvtCtr eat_rnd_time(); 34 | 35 | static void ledOff(void); 36 | static void ledOn(void); 37 | }; 38 | 39 | #endif // BSP_HPP 40 | -------------------------------------------------------------------------------- /examples/dpp_bsp-sam/dpp.hpp: -------------------------------------------------------------------------------- 1 | //.$file${.::dpp.hpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 2 | // 3 | // Model: dpp_bsp-sam.qm 4 | // File: ${.::dpp.hpp} 5 | // 6 | // This code has been generated by QM 5.1.3 . 7 | // DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. 8 | // 9 | // This program is open source software: you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License as published 11 | // by the Free Software Foundation. 12 | // 13 | // This program is distributed in the hope that it will be useful, but 14 | // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | // for more details. 17 | // 18 | //.$endhead${.::dpp.hpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 19 | #ifndef DPP_HPP 20 | #define DPP_HPP 21 | 22 | enum Signals { 23 | EAT_SIG = QP::Q_USER_SIG, // published by Table to let a Philosopher eat 24 | DONE_SIG, // published by Philosopher when done eating 25 | PAUSE_SIG, // published by BSP to pause the application 26 | SERVE_SIG, // published by BSP to serve re-start serving forks 27 | TEST_SIG, // published by BSP to test the application 28 | MAX_PUB_SIG, // the last published signal 29 | 30 | TIMEOUT_SIG, // timeout used by Time Events 31 | HUNGRY_SIG, // posted direclty to Table from hungry Philo 32 | MAX_SIG // the last signal 33 | }; 34 | 35 | // generate declarations all event classes 36 | //.$declare${Events} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 37 | //.${Events::TableEvt} ....................................................... 38 | class TableEvt : public QP::QEvt { 39 | public: 40 | uint8_t philoNum; 41 | }; 42 | //.$enddecl${Events} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 43 | 44 | // number of philosophers 45 | enum { N_PHILO = 5 }; 46 | 47 | // generate declarations of all opaque pointers... 48 | //.$declare${AOs::AO_Philo[N_PHILO]} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 49 | extern QP::QActive * const AO_Philo[N_PHILO]; 50 | //.$enddecl${AOs::AO_Philo[N_PHILO]} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 51 | //.$declare${AOs::AO_Table} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 52 | extern QP::QActive * const AO_Table; 53 | //.$enddecl${AOs::AO_Table} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 54 | 55 | #endif // DPP_HPP 56 | -------------------------------------------------------------------------------- /examples/dpp_bsp-sam/dpp_bsp-sam.ino: -------------------------------------------------------------------------------- 1 | //.$file${.::dpp_bsp-sam.ino} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 2 | // 3 | // Model: dpp_bsp-sam.qm 4 | // File: ${.::dpp_bsp-sam.ino} 5 | // 6 | // This code has been generated by QM 5.1.3 . 7 | // DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. 8 | // 9 | // This program is open source software: you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License as published 11 | // by the Free Software Foundation. 12 | // 13 | // This program is distributed in the hope that it will be useful, but 14 | // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | // for more details. 17 | // 18 | //.$endhead${.::dpp_bsp-sam.ino} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 19 | #include "qpcpp.hpp" // QP-C++ framework 20 | #include "dpp.hpp" // DPP application 21 | #include "bsp.hpp" // Board Support Package 22 | 23 | using namespace QP; 24 | 25 | Q_DEFINE_THIS_FILE 26 | 27 | //............................................................................ 28 | void setup() { 29 | QF::init(); // initialize the framework 30 | BSP::init(); // initialize the Board Support Package 31 | 32 | // init publish-subscribe 33 | static QSubscrList subscrSto[MAX_PUB_SIG]; 34 | QF::psInit(subscrSto, Q_DIM(subscrSto)); 35 | 36 | // initialize event pools... 37 | static QF_MPOOL_EL(TableEvt) smlPoolSto[2*N_PHILO]; 38 | QF::poolInit(smlPoolSto, 39 | sizeof(smlPoolSto), sizeof(smlPoolSto[0])); 40 | 41 | // start all active objects... 42 | 43 | // start Philos 44 | static QP::QEvt const *philoQueueSto[10][N_PHILO]; 45 | for (uint8_t n = 0U; n < N_PHILO; ++n) { 46 | AO_Philo[n]->start((uint_fast8_t)(n + 1U), // priority 47 | philoQueueSto[n], Q_DIM(philoQueueSto[n]), 48 | (void *)0, 0U); 49 | } 50 | // start Table 51 | static QP::QEvt const *tableQueueSto[N_PHILO]; 52 | AO_Table->start((uint_fast8_t)(N_PHILO + 1U), // priority 53 | tableQueueSto, Q_DIM(tableQueueSto), 54 | (void *)0, 0U); 55 | } 56 | 57 | //............................................................................ 58 | void loop() { 59 | QF::run(); // run the QF/C++ framework 60 | } 61 | -------------------------------------------------------------------------------- /examples/dpp_bsp-sam/philo.cpp: -------------------------------------------------------------------------------- 1 | //.$file${.::philo.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 2 | // 3 | // Model: dpp_bsp-sam.qm 4 | // File: ${.::philo.cpp} 5 | // 6 | // This code has been generated by QM 5.1.3 . 7 | // DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. 8 | // 9 | // This program is open source software: you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License as published 11 | // by the Free Software Foundation. 12 | // 13 | // This program is distributed in the hope that it will be useful, but 14 | // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | // for more details. 17 | // 18 | //.$endhead${.::philo.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 19 | #include "qpcpp.hpp" // QP-C++ framework 20 | #include "dpp.hpp" // DPP application 21 | #include "bsp.hpp" // Board Support Package 22 | 23 | Q_DEFINE_THIS_FILE 24 | 25 | // generate declaration of the active object --------------------------------- 26 | //.$declare${AOs::Philo} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 27 | //.${AOs::Philo} ............................................................. 28 | class Philo : public QP::QActive { 29 | private: 30 | QP::QTimeEvt m_timeEvt; 31 | 32 | public: 33 | static Philo inst[N_PHILO]; 34 | 35 | public: 36 | Philo(); 37 | 38 | protected: 39 | Q_STATE_DECL(initial); 40 | Q_STATE_DECL(thinking); 41 | Q_STATE_DECL(hungry); 42 | Q_STATE_DECL(eating); 43 | }; 44 | //.$enddecl${AOs::Philo} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 45 | 46 | // generate definition of the opaque pointer to the AO ----------------------- 47 | //.$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 48 | //. Check for the minimum required QP version 49 | #if (QP_VERSION < 690U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U)) 50 | #error qpcpp version 6.9.0 or higher required 51 | #endif 52 | //.$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 53 | //.$define${AOs::AO_Philo[N_PHILO]} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 54 | //.${AOs::AO_Philo[N_PHILO]} ................................................. 55 | QP::QActive * const AO_Philo[N_PHILO] = { // "opaque" pointers to Philo AO 56 | &Philo::inst[0], 57 | &Philo::inst[1], 58 | &Philo::inst[2], 59 | &Philo::inst[3], 60 | &Philo::inst[4] 61 | }; 62 | //.$enddef${AOs::AO_Philo[N_PHILO]} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 63 | 64 | // helper function to provide a randomized think time for Philos 65 | inline QP::QTimeEvtCtr think_time() { 66 | return static_cast((BSP::random() % BSP::TICKS_PER_SEC) 67 | + (BSP::TICKS_PER_SEC/2U)); 68 | } 69 | 70 | // helper function to provide a randomized eat time for Philos 71 | inline QP::QTimeEvtCtr eat_time() { 72 | return static_cast((BSP::random() % BSP::TICKS_PER_SEC) 73 | + BSP::TICKS_PER_SEC); 74 | } 75 | 76 | // helper function to provide the ID of Philo 77 | inline uint8_t PHILO_ID(Philo const * const philo) { 78 | return static_cast(philo - &Philo::inst[0]); 79 | } 80 | 81 | // generate definition of the AO -------------------------------------------- 82 | //.$define${AOs::Philo} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 83 | //.${AOs::Philo} ............................................................. 84 | Philo Philo::inst[N_PHILO]; 85 | //.${AOs::Philo::Philo} ...................................................... 86 | Philo::Philo() 87 | : QActive(Q_STATE_CAST(&Philo::initial)), 88 | m_timeEvt(this, TIMEOUT_SIG, 0U) 89 | {} 90 | 91 | //.${AOs::Philo::SM} ......................................................... 92 | Q_STATE_DEF(Philo, initial) { 93 | //.${AOs::Philo::SM::initial} 94 | (void)e; // unused parameter 95 | 96 | subscribe(EAT_SIG); 97 | subscribe(TEST_SIG); 98 | 99 | // QS dictionaries only once for all Philos... 100 | static bool registered = false; 101 | if (!registered) { // first time through? 102 | registered = true; 103 | 104 | QS_OBJ_DICTIONARY(&Philo::inst[0]); 105 | QS_OBJ_DICTIONARY(&Philo::inst[0].m_timeEvt); 106 | QS_OBJ_DICTIONARY(&Philo::inst[1]); 107 | QS_OBJ_DICTIONARY(&Philo::inst[1].m_timeEvt); 108 | QS_OBJ_DICTIONARY(&Philo::inst[2]); 109 | QS_OBJ_DICTIONARY(&Philo::inst[2].m_timeEvt); 110 | QS_OBJ_DICTIONARY(&Philo::inst[3]); 111 | QS_OBJ_DICTIONARY(&Philo::inst[3].m_timeEvt); 112 | QS_OBJ_DICTIONARY(&Philo::inst[4]); 113 | QS_OBJ_DICTIONARY(&Philo::inst[4].m_timeEvt); 114 | 115 | QS_FUN_DICTIONARY(&Philo::initial); 116 | QS_FUN_DICTIONARY(&Philo::thinking); 117 | QS_FUN_DICTIONARY(&Philo::hungry); 118 | QS_FUN_DICTIONARY(&Philo::eating); 119 | 120 | QS_SIG_DICTIONARY(TIMEOUT_SIG, nullptr); 121 | } 122 | return tran(&thinking); 123 | } 124 | //.${AOs::Philo::SM::thinking} ............................................... 125 | Q_STATE_DEF(Philo, thinking) { 126 | QP::QState status_; 127 | switch (e->sig) { 128 | //.${AOs::Philo::SM::thinking} 129 | case Q_ENTRY_SIG: { 130 | m_timeEvt.armX(think_time(), 0U); 131 | status_ = Q_RET_HANDLED; 132 | break; 133 | } 134 | //.${AOs::Philo::SM::thinking} 135 | case Q_EXIT_SIG: { 136 | (void)m_timeEvt.disarm(); 137 | status_ = Q_RET_HANDLED; 138 | break; 139 | } 140 | //.${AOs::Philo::SM::thinking::TIMEOUT} 141 | case TIMEOUT_SIG: { 142 | status_ = tran(&hungry); 143 | break; 144 | } 145 | //.${AOs::Philo::SM::thinking::EAT, DONE} 146 | case EAT_SIG: // intentionally fall through 147 | case DONE_SIG: { 148 | // EAT or DONE must be for other Philos than this one 149 | Q_ASSERT(Q_EVT_CAST(TableEvt)->philoNum != PHILO_ID(this)); 150 | status_ = Q_RET_HANDLED; 151 | break; 152 | } 153 | //.${AOs::Philo::SM::thinking::TEST} 154 | case TEST_SIG: { 155 | status_ = Q_RET_HANDLED; 156 | break; 157 | } 158 | default: { 159 | status_ = super(&top); 160 | break; 161 | } 162 | } 163 | return status_; 164 | } 165 | //.${AOs::Philo::SM::hungry} ................................................. 166 | Q_STATE_DEF(Philo, hungry) { 167 | QP::QState status_; 168 | switch (e->sig) { 169 | //.${AOs::Philo::SM::hungry} 170 | case Q_ENTRY_SIG: { 171 | TableEvt *pe = Q_NEW(TableEvt, HUNGRY_SIG); 172 | pe->philoNum = PHILO_ID(this); 173 | AO_Table->POST(pe, this); 174 | status_ = Q_RET_HANDLED; 175 | break; 176 | } 177 | //.${AOs::Philo::SM::hungry::EAT} 178 | case EAT_SIG: { 179 | //.${AOs::Philo::SM::hungry::EAT::[Q_EVT_CAST(TableEvt)->philoNum=~} 180 | if (Q_EVT_CAST(TableEvt)->philoNum == PHILO_ID(this)) { 181 | status_ = tran(&eating); 182 | } 183 | else { 184 | status_ = Q_RET_UNHANDLED; 185 | } 186 | break; 187 | } 188 | //.${AOs::Philo::SM::hungry::DONE} 189 | case DONE_SIG: { 190 | /* DONE must be for other Philos than this one */ 191 | Q_ASSERT(Q_EVT_CAST(TableEvt)->philoNum != PHILO_ID(this)); 192 | status_ = Q_RET_HANDLED; 193 | break; 194 | } 195 | default: { 196 | status_ = super(&top); 197 | break; 198 | } 199 | } 200 | return status_; 201 | } 202 | //.${AOs::Philo::SM::eating} ................................................. 203 | Q_STATE_DEF(Philo, eating) { 204 | QP::QState status_; 205 | switch (e->sig) { 206 | //.${AOs::Philo::SM::eating} 207 | case Q_ENTRY_SIG: { 208 | m_timeEvt.armX(eat_time(), 0U); 209 | status_ = Q_RET_HANDLED; 210 | break; 211 | } 212 | //.${AOs::Philo::SM::eating} 213 | case Q_EXIT_SIG: { 214 | TableEvt *pe = Q_NEW(TableEvt, DONE_SIG); 215 | pe->philoNum = PHILO_ID(this); 216 | QP::QF::PUBLISH(pe, this); 217 | (void)m_timeEvt.disarm(); 218 | status_ = Q_RET_HANDLED; 219 | break; 220 | } 221 | //.${AOs::Philo::SM::eating::TIMEOUT} 222 | case TIMEOUT_SIG: { 223 | status_ = tran(&thinking); 224 | break; 225 | } 226 | //.${AOs::Philo::SM::eating::EAT, DONE} 227 | case EAT_SIG: // intentionally fall through 228 | case DONE_SIG: { 229 | // EAT or DONE must be for other Philos than this one 230 | Q_ASSERT(Q_EVT_CAST(TableEvt)->philoNum != PHILO_ID(this)); 231 | status_ = Q_RET_HANDLED; 232 | break; 233 | } 234 | default: { 235 | status_ = super(&top); 236 | break; 237 | } 238 | } 239 | return status_; 240 | } 241 | //.$enddef${AOs::Philo} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 242 | -------------------------------------------------------------------------------- /examples/dpp_bsp-sam/qview/dpp.py: -------------------------------------------------------------------------------- 1 | # This is an example of QView customization for a specific application 2 | # (DPP in this case). This example animates the Phil images on the 3 | # QView canvas. Additionally, there is a button in the middle of the screen, 4 | # which, when clicked once pauses the DPP ("forks" are not being served). 5 | # A second click on the button, "un-pauses" the DPP ("forks" are served 6 | # to all hungry Philosophers). 7 | # 8 | # This version of the DPP customization uses the application-specific 9 | # packet QS_USER_00 (PHILO_STAT) produced when the status of a Philo changes. 10 | # 11 | 12 | class DPP: 13 | def __init__(self): 14 | 15 | # add commands to the Custom menu... 16 | QView.custom_menu.add_command(label="Custom command", 17 | command=self.cust_command) 18 | 19 | # configure the custom QView.canvas... 20 | QView.show_canvas() # make the canvas visible 21 | QView.canvas.configure(width=400, height=260) 22 | 23 | # tuple of activity images (correspond to self._philo_state) 24 | self._act_img = ( 25 | PhotoImage(file=HOME_DIR + "/img/thinking.gif"), 26 | PhotoImage(file=HOME_DIR + "/img/hungry.gif"), 27 | PhotoImage(file=HOME_DIR + "/img/eating.gif"), 28 | ) 29 | # tuple of philo canvas images (correspond to self._philo_obj) 30 | self._philo_img = (\ 31 | QView.canvas.create_image(190, 57, image=self._act_img[0]), 32 | QView.canvas.create_image(273, 100, image=self._act_img[0]), 33 | QView.canvas.create_image(237, 185, image=self._act_img[0]), 34 | QView.canvas.create_image(146, 185, image=self._act_img[0]), 35 | QView.canvas.create_image(107, 100, image=self._act_img[0]) 36 | ) 37 | 38 | # button images for UP and DOWN 39 | self.img_UP = PhotoImage(file=HOME_DIR + "/img/BTN_UP.gif") 40 | self.img_DWN = PhotoImage(file=HOME_DIR + "/img/BTN_DWN.gif") 41 | 42 | # images of a button for pause/serve 43 | self.btn = QView.canvas.create_image(200, 120, image=self.img_UP) 44 | QView.canvas.tag_bind(self.btn, "", self.cust_pause) 45 | 46 | # request target reset on startup... 47 | # NOTE: Normally, for an embedded application you would like 48 | # to start with resetting the Target, to start clean with 49 | # Qs dictionaries, etc. 50 | reset_target() 51 | 52 | # on_reset() callback 53 | def on_reset(self): 54 | # clear the lists 55 | self._philo_obj = [0, 0, 0, 0, 0] 56 | self._philo_state = [0, 0, 0] 57 | 58 | # on_run() callback 59 | def on_run(self): 60 | glb_filter("QS_USER_00") 61 | 62 | # NOTE: the name of object for current_obj() must match the 63 | # QS Object Dictionaries produced by the application. 64 | current_obj(OBJ_AO, "Table::inst") 65 | 66 | # turn lists into tuples for better performance 67 | self._philo_obj = tuple(self._philo_obj) 68 | self._philo_state = tuple(self._philo_state) 69 | 70 | 71 | # example of a custom command 72 | def cust_command(self): 73 | command(1, 12345) 74 | 75 | # example of a custom interaction with a canvas object (pause/serve) 76 | def cust_pause(self, event): 77 | if QView.canvas.itemcget(self.btn, "image") != str(self.img_UP): 78 | QView.canvas.itemconfig(self.btn, image=self.img_UP) 79 | post("SERVE_SIG") 80 | QView.print_text("Table SERVING") 81 | else: 82 | QView.canvas.itemconfig(self.btn, image=self.img_DWN) 83 | post("PAUSE_SIG") 84 | QView.print_text("Table PAUSED") 85 | 86 | # intercept the QS_USER_00 application-specific packet 87 | # this packet has the following structure (see bsp.c:displayPhilStat()): 88 | # record-ID, seq-num, Timestamp, format-byte, Philo-num, 89 | # format-bye, Zero-terminated string (status) 90 | def QS_USER_00(self, packet): 91 | # unpack: Timestamp->data[0], Philo-num->data[1], status->data[3] 92 | data = qunpack("xxTxBxZ", packet) 93 | i = data[1] 94 | j = ("t", "h", "e").index(data[2][0]) # the first letter 95 | 96 | # animate the given philo image according to its activity 97 | QView.canvas.itemconfig(self._philo_img[i], image=self._act_img[j]) 98 | 99 | # print a message to the text view 100 | QView.print_text("%010d Philo %1d is %s"%(data[0], i, data[2])) 101 | 102 | #============================================================================= 103 | QView.customize(DPP()) # set the QView customization 104 | -------------------------------------------------------------------------------- /examples/dpp_bsp-sam/qview/dpp1.py: -------------------------------------------------------------------------------- 1 | # This is an example of QView customization for a specific application 2 | # (DPP in this case). This example animates the Phil images on the 3 | # QView canvas. Additionally, there is a button in the middle of the screen, 4 | # which, when clicked once pauses the DPP ("forks" are not being served). 5 | # A second click on the button, "un-pauses" the DPP ("forks" are served 6 | # to all hungry Philosophers). 7 | # 8 | # This version of the DPP customization uses the standard QS_QEP_STATE_ENTRY 9 | # packet, which provides information about the current states of the dining 10 | # Philosophers. The example also demonstrates how to intercept the QS 11 | # "dictionary" records QS_OBJ_DICT and QS_FUN_DICT to extract the information 12 | # about the addresses of the Philosopher objects and the states of their 13 | # state machines. 14 | # 15 | 16 | class DPP: 17 | def __init__(self): 18 | 19 | # add commands to the Custom menu... 20 | QView.custom_menu.add_command(label="Custom command", 21 | command=self.cust_command) 22 | 23 | # configure the custom QView.canvas... 24 | QView.show_canvas() # make the canvas visible 25 | QView.canvas.configure(width=400, height=260) 26 | 27 | # tuple of activity images (correspond to self._philo_state) 28 | self._act_img = ( 29 | PhotoImage(file=HOME_DIR + "/img/thinking.gif"), 30 | PhotoImage(file=HOME_DIR + "/img/hungry.gif"), 31 | PhotoImage(file=HOME_DIR + "/img/eating.gif"), 32 | ) 33 | # tuple of philo canvas images (correspond to self._philo_obj) 34 | self._philo_img = (\ 35 | QView.canvas.create_image(190, 57, image=self._act_img[0]), 36 | QView.canvas.create_image(273, 100, image=self._act_img[0]), 37 | QView.canvas.create_image(237, 185, image=self._act_img[0]), 38 | QView.canvas.create_image(146, 185, image=self._act_img[0]), 39 | QView.canvas.create_image(107, 100, image=self._act_img[0]) 40 | ) 41 | 42 | # button images for UP and DOWN 43 | self.img_UP = PhotoImage(file=HOME_DIR + "/img/BTN_UP.gif") 44 | self.img_DWN = PhotoImage(file=HOME_DIR + "/img/BTN_DWN.gif") 45 | 46 | # images of a button for pause/serve 47 | self.btn = QView.canvas.create_image(200, 120, image=self.img_UP) 48 | QView.canvas.tag_bind(self.btn, "", self.cust_pause) 49 | 50 | # request target reset on startup... 51 | # NOTE: Normally, for an embedded application you would like 52 | # to start with resetting the Target, to start clean with 53 | # Qs dictionaries, etc. 54 | reset_target() 55 | 56 | # on_reset() callback invoked when Target-reset packet is received 57 | # NOTE: the QS dictionaries are not known at this time yet, so 58 | # this callback shouild generally not set filters or current objects 59 | def on_reset(self): 60 | # (re)set the lists 61 | self._philo_obj = [0, 0, 0, 0, 0] 62 | self._philo_state = [0, 0, 0] 63 | 64 | # on_run() callback invoked when the QF_RUN packet is received 65 | # NOTE: the QS dictionaries are typically known at this time yet, so 66 | # this callback can set filters or current objects 67 | def on_run(self): 68 | glb_filter("QS_QEP_TRAN") 69 | 70 | # NOTE: the name of object for current_obj() must match the 71 | # QS Object Dictionaries produced by the application. 72 | current_obj(OBJ_AO, "Table::inst") 73 | 74 | # turn lists into tuples for better performance 75 | self._philo_obj = tuple(self._philo_obj) 76 | self._philo_state = tuple(self._philo_state) 77 | 78 | 79 | # example of a custom command 80 | def cust_command(self): 81 | command(1, 12345) 82 | 83 | # example of a custom interaction with a canvas object (pause/serve) 84 | def cust_pause(self, event): 85 | if QView.canvas.itemcget(self.btn, "image") != str(self.img_UP): 86 | QView.canvas.itemconfig(self.btn, image=self.img_UP) 87 | post("SERVE_SIG") 88 | QView.print_text("Table SERVING") 89 | else: 90 | QView.canvas.itemconfig(self.btn, image=self.img_DWN) 91 | post("PAUSE_SIG") 92 | QView.print_text("Table PAUSED") 93 | 94 | # intercept the QS_OBJ_DICT stadard packet 95 | # this packet has the following structure: 96 | # record-ID, seq-num, Object-ptr, Zero-terminated string 97 | def QS_OBJ_DICT(self, packet): 98 | data = qunpack("xxOZ", packet) 99 | try: 100 | # NOTE: the names of objects must match the QS Object Dictionaries 101 | # produced by the application. 102 | i = ("Philo::inst[0]", 103 | "Philo::inst[1]", 104 | "Philo::inst[2]", 105 | "Philo::inst[3]", 106 | "Philo::inst[4]").index(data[1]) 107 | self._philo_obj[i] = data[0] 108 | except: 109 | pass # dictionary for a different object 110 | 111 | # intercept the QS_FUN_DICT stadard packet 112 | # this packet has the following structure: 113 | # record-ID, seq-num, Function-ptr, Zero-terminated string 114 | def QS_FUN_DICT(self, packet): 115 | data = qunpack("xxFZ", packet) 116 | try: 117 | # NOTE: the names of states must match the QS Object Dictionaries 118 | # produced by the application. 119 | j = ("Philo::thinking", 120 | "Philo::hungry", 121 | "Philo::eating").index(data[1]) 122 | self._philo_state[j] = data[0] 123 | except: 124 | pass # dictionary for a different state 125 | 126 | # intercept the QS_QEP_TRAN stadard packet 127 | # this packet has the following structure: 128 | # record-ID, seq-num, Timestamp, Signal, Object-ptr, 129 | # Function-ptr (source state), Function-ptr (new active state) 130 | def QS_QEP_TRAN(self, packet): 131 | data = qunpack("xxTSOFF", packet) 132 | try: 133 | i = self._philo_obj.index(data[2]) 134 | j = self._philo_state.index(data[4]) 135 | 136 | # animate the given philo image according to its activity 137 | QView.canvas.itemconfig(self._philo_img[i], 138 | image=self._act_img[j]) 139 | # print a message to the text view 140 | QView.print_text("%010d Philo %d is %s"\ 141 | %(data[0], i, ("thinking", "hungry", "eating")[j])) 142 | except: 143 | pass # state-entry in a different object 144 | 145 | #============================================================================= 146 | # instantiate the DPP class and set it as the QView customization 147 | QView.customize(DPP()) 148 | -------------------------------------------------------------------------------- /examples/dpp_bsp-sam/qview/img/BTN_DWN.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantumLeaps/qp-arduino/bbc8f4ed8ff2075969c5a076e72ce0aa9240c0e8/examples/dpp_bsp-sam/qview/img/BTN_DWN.gif -------------------------------------------------------------------------------- /examples/dpp_bsp-sam/qview/img/BTN_UP.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantumLeaps/qp-arduino/bbc8f4ed8ff2075969c5a076e72ce0aa9240c0e8/examples/dpp_bsp-sam/qview/img/BTN_UP.gif -------------------------------------------------------------------------------- /examples/dpp_bsp-sam/qview/img/eating.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantumLeaps/qp-arduino/bbc8f4ed8ff2075969c5a076e72ce0aa9240c0e8/examples/dpp_bsp-sam/qview/img/eating.gif -------------------------------------------------------------------------------- /examples/dpp_bsp-sam/qview/img/hungry.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantumLeaps/qp-arduino/bbc8f4ed8ff2075969c5a076e72ce0aa9240c0e8/examples/dpp_bsp-sam/qview/img/hungry.gif -------------------------------------------------------------------------------- /examples/dpp_bsp-sam/qview/img/thinking.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantumLeaps/qp-arduino/bbc8f4ed8ff2075969c5a076e72ce0aa9240c0e8/examples/dpp_bsp-sam/qview/img/thinking.gif -------------------------------------------------------------------------------- /examples/dpp_bsp-sam/qview/qview-dpp.bat: -------------------------------------------------------------------------------- 1 | @setlocal 2 | 3 | if "%QTOOLS%"=="" ( 4 | set QTOOLS=C:\qp\qtools 5 | ) 6 | python3 %QTOOLS%\qview\qview.py dpp.py 7 | 8 | @endlocal 9 | -------------------------------------------------------------------------------- /examples/dpp_bsp-sam/qview/qview-dpp.lnk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantumLeaps/qp-arduino/bbc8f4ed8ff2075969c5a076e72ce0aa9240c0e8/examples/dpp_bsp-sam/qview/qview-dpp.lnk -------------------------------------------------------------------------------- /examples/dpp_bsp-sam/qview/qview-dpp1.bat: -------------------------------------------------------------------------------- 1 | @setlocal 2 | 3 | if "%QTOOLS%"=="" ( 4 | set QTOOLS=C:\qp\qtools 5 | ) 6 | python3 %QTOOLS%\qview\qview.py dpp1.py 7 | 8 | @endlocal 9 | -------------------------------------------------------------------------------- /examples/dpp_bsp-sam/qview/qview-dpp1.lnk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantumLeaps/qp-arduino/bbc8f4ed8ff2075969c5a076e72ce0aa9240c0e8/examples/dpp_bsp-sam/qview/qview-dpp1.lnk -------------------------------------------------------------------------------- /examples/dpp_bsp-teensy4/.dpp_bsp-teensy4: -------------------------------------------------------------------------------- 1 | 2 | 3 | GPL 4 | 5 | 6 | 1 7 | 0 8 | 3 9 | 0 10 | 11 | 12 | 0,0,640,480 13 | 0,0,932,625,* 14 | 336,0,596,300 15 | -71,0,1003,765 16 | 0,0,1003,765 17 | 0,358,596,300 18 | 0,0,596,300 19 | 20 | 21 | 2032128 22 | 0 23 | 24 | 25 | 26 | 27 | 0 28 | 29 | 30 | 31 | 32 | 0 33 | 34 | 35 | 0 36 | 37 | 38 | 39 | 40 | 0 41 | 42 | 43 | 0 44 | 45 | 46 | 47 | 48 | 0 49 | 50 | 51 | 0 52 | 53 | 54 | 55 | 56 | 0 57 | 58 | 59 | 0 60 | 61 | 62 | 63 | 64 | 0 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /examples/dpp_bsp-teensy4/bsp.cpp: -------------------------------------------------------------------------------- 1 | //.$file${.::bsp.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 2 | // 3 | // Model: dpp_bsp-teensy4.qm 4 | // File: ${.::bsp.cpp} 5 | // 6 | // This code has been generated by QM 5.1.3 . 7 | // DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. 8 | // 9 | // This program is open source software: you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License as published 11 | // by the Free Software Foundation. 12 | // 13 | // This program is distributed in the hope that it will be useful, but 14 | // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | // for more details. 17 | // 18 | //.$endhead${.::bsp.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 19 | #include "qpcpp.hpp" // QP-C++ framework 20 | #include "dpp.hpp" // DPP application 21 | #include "bsp.hpp" // Board Support Package 22 | 23 | using namespace QP; 24 | 25 | //............................................................................ 26 | // QS facilities 27 | 28 | // un-comment if QS instrumentation needed 29 | #define QS_ON 30 | 31 | enum AppRecords { // application-specific QS trace records 32 | PHILO_STAT = QP::QS_USER, 33 | }; 34 | 35 | static QP::QSpyId const l_TIMER_ID = { 0U }; // QSpy source ID 36 | 37 | //---------------------------------------------------------------------------- 38 | // BSP functions 39 | 40 | void BSP::init(void) { 41 | // initialize the hardware used in this sketch... 42 | // NOTE: interrupts are configured and started later in QF::onStartup() 43 | pinMode(LED_BUILTIN, OUTPUT); 44 | 45 | randomSeed(1234); // seed the Random Number Generator 46 | 47 | #ifdef QS_ON 48 | QS_INIT(0); 49 | 50 | // output QS dictionaries 51 | QS_OBJ_DICTIONARY(&l_TIMER_ID); 52 | QS_USR_DICTIONARY(PHILO_STAT); 53 | 54 | // setup the QS filters... 55 | QS_GLB_FILTER(QP::QS_SM_RECORDS); // state machine records 56 | QS_GLB_FILTER(QP::QS_AO_RECORDS); // active object records 57 | QS_GLB_FILTER(QP::QS_UA_RECORDS); // all user records 58 | 59 | #else 60 | 61 | Serial.begin(115200); // set the highest standard baud rate of 115200 bps 62 | Serial.print("QP-C++: "); 63 | Serial.print(QP_VERSION_STR); 64 | Serial.println(""); 65 | 66 | #endif 67 | } 68 | //............................................................................ 69 | void BSP::displayPhilStat(uint8_t n, char_t const *stat) { 70 | digitalWrite(LED_BUILTIN, (stat[0] == 'e') ? HIGH : LOW); 71 | 72 | #ifdef QS_ON 73 | QS_BEGIN_ID(PHILO_STAT, AO_Philo[n]->m_prio) // app-specific record begin 74 | QS_U8(1, n); // Philo number 75 | QS_STR(stat); // Philo status 76 | QS_END() 77 | #else 78 | Serial.print("Philosopher "); 79 | Serial.print(n, DEC); 80 | Serial.print(" "); 81 | Serial.println(stat); 82 | #endif 83 | } 84 | //............................................................................ 85 | void BSP::displayPaused(uint8_t paused) { 86 | char const *msg = paused ? "Paused ON" : "Paused OFF"; 87 | #ifndef QS_ON 88 | Serial.println(msg); 89 | #endif 90 | } 91 | //............................................................................ 92 | void BSP::ledOff(void) { 93 | digitalWrite(LED_BUILTIN, LOW); 94 | } 95 | //............................................................................ 96 | void BSP::ledOn(void) { 97 | digitalWrite(LED_BUILTIN, HIGH); 98 | } 99 | 100 | //............................................................................ 101 | static uint32_t l_rnd; // random seed 102 | 103 | void BSP::randomSeed(uint32_t seed) { 104 | l_rnd = seed; 105 | } 106 | //............................................................................ 107 | uint32_t BSP::random(void) { // a very cheap pseudo-random-number generator 108 | // "Super-Duper" Linear Congruential Generator (LCG) 109 | // LCG(2^32, 3*7*11*13*23, 0, seed) 110 | // 111 | uint32_t rnd = l_rnd * (3U*7U*11U*13U*23U); 112 | l_rnd = rnd; // set for the next time 113 | return (rnd >> 8); 114 | } 115 | 116 | //---------------------------------------------------------------------------- 117 | // QF callbacks... 118 | 119 | // 120 | // NOTE: The usual source of system clock tick in ARM Cortex-M (SysTick timer) 121 | // is aready used by the Arduino library. Therefore, this code uses a different 122 | // hardware Timer1 of the Teensy 4 board for providing the system clock tick. 123 | // 124 | // NOTE: You can re-define the macros to use a different ATSAM timer/channel. 125 | // 126 | #include // Teensy Timer1 interface 127 | 128 | #define TIMER1_CLCK_HZ 1000000 129 | #define TIMER_HANDLER T1_Handler 130 | 131 | // interrupts................................................................. 132 | void TIMER_HANDLER(void) { 133 | QF::TICK_X(0, &l_TIMER_ID); // process time events for tick rate 0 134 | 135 | #ifndef QS_ON 136 | if (Serial.available() > 0) { 137 | switch (Serial.read()) { // read the incoming byte 138 | case 'p': 139 | case 'P': 140 | static QEvt const pauseEvt = { PAUSE_SIG, 0U, 0U}; 141 | QF::PUBLISH(&pauseEvt, &l_TIMER_ID); 142 | break; 143 | case 's': 144 | case 'S': 145 | static QEvt const serveEvt = { SERVE_SIG, 0U, 0U}; 146 | QF::PUBLISH(&serveEvt, &l_TIMER_ID); 147 | break; 148 | } 149 | } 150 | #endif 151 | } 152 | //............................................................................ 153 | void QF::onStartup(void) { 154 | // configure the timer-counter channel........ 155 | Timer1.initialize(TIMER1_CLCK_HZ / BSP::TICKS_PER_SEC); 156 | Timer1.attachInterrupt(TIMER_HANDLER); 157 | // ... 158 | } 159 | //............................................................................ 160 | void QV::onIdle(void) { // called with interrupts DISABLED 161 | #ifdef NDEBUG 162 | // Put the CPU and peripherals to the low-power mode. You might 163 | // need to customize the clock management for your application, 164 | // see the datasheet for your particular MCU. 165 | QV_CPU_SLEEP(); // atomically go to sleep and enable interrupts 166 | #else 167 | QF_INT_ENABLE(); // simply re-enable interrupts 168 | 169 | #ifdef QS_ON 170 | 171 | // transmit QS outgoing data (QS-TX) 172 | uint16_t len = Serial.availableForWrite(); 173 | if (len > 0U) { // any space available in the output buffer? 174 | uint8_t const *buf = QS::getBlock(&len); 175 | if (buf) { 176 | Serial.write(buf, len); // asynchronous and non-blocking 177 | } 178 | } 179 | 180 | // receive QS incoming data (QS-RX) 181 | len = Serial.available(); 182 | if (len > 0U) { 183 | do { 184 | QP::QS::rxPut(Serial.read()); 185 | } while (--len > 0U); 186 | QS::rxParse(); 187 | } 188 | 189 | #endif // QS_ON 190 | 191 | #endif 192 | } 193 | //............................................................................ 194 | extern "C" Q_NORETURN Q_onAssert(char const * const module, int location) { 195 | // 196 | // NOTE: add here your application-specific error handling 197 | // 198 | (void)module; 199 | (void)location; 200 | 201 | QF_INT_DISABLE(); // disable all interrupts 202 | BSP::ledOn(); // trun the LED on 203 | for (;;) { // freeze in an endless loop for now... 204 | } 205 | } 206 | 207 | //---------------------------------------------------------------------------- 208 | // QS callbacks... 209 | #ifdef QS_ON 210 | 211 | //............................................................................ 212 | bool QP::QS::onStartup(void const * arg) { 213 | static uint8_t qsTxBuf[1024]; // buffer for QS transmit channel (QS-TX) 214 | static uint8_t qsRxBuf[128]; // buffer for QS receive channel (QS-RX) 215 | initBuf (qsTxBuf, sizeof(qsTxBuf)); 216 | rxInitBuf(qsRxBuf, sizeof(qsRxBuf)); 217 | Serial.begin(115200); // run serial port at 115200 baud rate 218 | return true; // return success 219 | } 220 | //............................................................................ 221 | void QP::QS::onCommand(uint8_t cmdId, uint32_t param1, 222 | uint32_t param2, uint32_t param3) 223 | { 224 | } 225 | 226 | #endif // QS_ON 227 | 228 | //............................................................................ 229 | void QP::QS::onCleanup(void) { 230 | } 231 | //............................................................................ 232 | QP::QSTimeCtr QP::QS::onGetTime(void) { 233 | return millis(); 234 | } 235 | //............................................................................ 236 | void QP::QS::onFlush(void) { 237 | #ifdef QS_ON 238 | uint16_t len = 0xFFFFU; // big number to get as many bytes as available 239 | uint8_t const *buf = QS::getBlock(&len); // get continguous block of data 240 | while (buf != nullptr) { // data available? 241 | Serial.write(buf, len); // might poll until all bytes fit 242 | len = 0xFFFFU; // big number to get as many bytes as available 243 | buf = QS::getBlock(&len); // try to get more data 244 | } 245 | Serial.flush(); // wait for the transmission of outgoing data to complete 246 | #endif // QS_ON 247 | } 248 | //............................................................................ 249 | void QP::QS::onReset(void) { 250 | //??? TBD for Teensy 251 | } 252 | -------------------------------------------------------------------------------- /examples/dpp_bsp-teensy4/bsp.hpp: -------------------------------------------------------------------------------- 1 | //.$file${.::bsp.hpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 2 | // 3 | // Model: dpp_bsp-teensy4.qm 4 | // File: ${.::bsp.hpp} 5 | // 6 | // This code has been generated by QM 5.1.3 . 7 | // DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. 8 | // 9 | // This program is open source software: you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License as published 11 | // by the Free Software Foundation. 12 | // 13 | // This program is distributed in the hope that it will be useful, but 14 | // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | // for more details. 17 | // 18 | //.$endhead${.::bsp.hpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 19 | #ifndef BSP_HPP 20 | #define BSP_HPP 21 | 22 | class BSP { 23 | public: 24 | enum { TICKS_PER_SEC = 100} ; 25 | static void init(void); 26 | static void displayPaused(uint8_t const paused); 27 | static void displayPhilStat(uint8_t const n, char_t const *stat); 28 | static void terminate(int16_t const result); 29 | 30 | static void randomSeed(uint32_t const seed); // random seed 31 | static uint32_t random(void); // pseudo-random generator 32 | static QP::QTimeEvtCtr think_rnd_time(); 33 | static QP::QTimeEvtCtr eat_rnd_time(); 34 | 35 | static void ledOff(void); 36 | static void ledOn(void); 37 | }; 38 | 39 | #endif // BSP_HPP 40 | -------------------------------------------------------------------------------- /examples/dpp_bsp-teensy4/dpp.hpp: -------------------------------------------------------------------------------- 1 | //.$file${.::dpp.hpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 2 | // 3 | // Model: dpp_bsp-teensy4.qm 4 | // File: ${.::dpp.hpp} 5 | // 6 | // This code has been generated by QM 5.1.3 . 7 | // DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. 8 | // 9 | // This program is open source software: you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License as published 11 | // by the Free Software Foundation. 12 | // 13 | // This program is distributed in the hope that it will be useful, but 14 | // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | // for more details. 17 | // 18 | //.$endhead${.::dpp.hpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 19 | #ifndef DPP_HPP 20 | #define DPP_HPP 21 | 22 | enum Signals { 23 | EAT_SIG = QP::Q_USER_SIG, // published by Table to let a Philosopher eat 24 | DONE_SIG, // published by Philosopher when done eating 25 | PAUSE_SIG, // published by BSP to pause the application 26 | SERVE_SIG, // published by BSP to serve re-start serving forks 27 | TEST_SIG, // published by BSP to test the application 28 | MAX_PUB_SIG, // the last published signal 29 | 30 | TIMEOUT_SIG, // timeout used by Time Events 31 | HUNGRY_SIG, // posted direclty to Table from hungry Philo 32 | MAX_SIG // the last signal 33 | }; 34 | 35 | // generate declarations all event classes 36 | //.$declare${Events} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 37 | //.${Events::TableEvt} ....................................................... 38 | class TableEvt : public QP::QEvt { 39 | public: 40 | uint8_t philoNum; 41 | }; 42 | //.$enddecl${Events} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 43 | 44 | // number of philosophers 45 | enum { N_PHILO = 5 }; 46 | 47 | // generate declarations of all opaque pointers... 48 | //.$declare${AOs::AO_Philo[N_PHILO]} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 49 | extern QP::QActive * const AO_Philo[N_PHILO]; 50 | //.$enddecl${AOs::AO_Philo[N_PHILO]} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 51 | //.$declare${AOs::AO_Table} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 52 | extern QP::QActive * const AO_Table; 53 | //.$enddecl${AOs::AO_Table} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 54 | 55 | #endif // DPP_HPP 56 | -------------------------------------------------------------------------------- /examples/dpp_bsp-teensy4/dpp_bsp-teensy4.ino: -------------------------------------------------------------------------------- 1 | //.$file${.::dpp_bsp-teensy4.ino} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 2 | // 3 | // Model: dpp_bsp-teensy4.qm 4 | // File: ${.::dpp_bsp-teensy4.ino} 5 | // 6 | // This code has been generated by QM 5.1.3 . 7 | // DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. 8 | // 9 | // This program is open source software: you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License as published 11 | // by the Free Software Foundation. 12 | // 13 | // This program is distributed in the hope that it will be useful, but 14 | // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | // for more details. 17 | // 18 | //.$endhead${.::dpp_bsp-teensy4.ino} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 19 | #include "qpcpp.hpp" // QP-C++ framework 20 | #include "dpp.hpp" // DPP application 21 | #include "bsp.hpp" // Board Support Package 22 | 23 | using namespace QP; 24 | 25 | 26 | //............................................................................ 27 | void setup() { 28 | QF::init(); // initialize the framework 29 | BSP::init(); // initialize the Board Support Package 30 | 31 | // init publish-subscribe 32 | static QSubscrList subscrSto[MAX_PUB_SIG]; 33 | QF::psInit(subscrSto, Q_DIM(subscrSto)); 34 | 35 | // initialize event pools... 36 | static QF_MPOOL_EL(TableEvt) smlPoolSto[2*N_PHILO]; 37 | QF::poolInit(smlPoolSto, 38 | sizeof(smlPoolSto), sizeof(smlPoolSto[0])); 39 | 40 | // start all active objects... 41 | 42 | // start Philos 43 | static QP::QEvt const *philoQueueSto[10][N_PHILO]; 44 | for (uint8_t n = 0U; n < N_PHILO; ++n) { 45 | AO_Philo[n]->start((uint_fast8_t)(n + 1U), // priority 46 | philoQueueSto[n], Q_DIM(philoQueueSto[n]), 47 | (void *)0, 0U); 48 | } 49 | // start Table 50 | static QP::QEvt const *tableQueueSto[N_PHILO]; 51 | AO_Table->start((uint_fast8_t)(N_PHILO + 1U), // priority 52 | tableQueueSto, Q_DIM(tableQueueSto), 53 | (void *)0, 0U); 54 | } 55 | 56 | //............................................................................ 57 | void loop() { 58 | QF::run(); // run the QF/C++ framework 59 | } 60 | -------------------------------------------------------------------------------- /examples/dpp_bsp-teensy4/philo.cpp: -------------------------------------------------------------------------------- 1 | //.$file${.::philo.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 2 | // 3 | // Model: dpp_bsp-teensy4.qm 4 | // File: ${.::philo.cpp} 5 | // 6 | // This code has been generated by QM 5.1.3 . 7 | // DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. 8 | // 9 | // This program is open source software: you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License as published 11 | // by the Free Software Foundation. 12 | // 13 | // This program is distributed in the hope that it will be useful, but 14 | // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | // for more details. 17 | // 18 | //.$endhead${.::philo.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 19 | #include "qpcpp.hpp" // QP-C++ framework 20 | #include "dpp.hpp" // DPP application 21 | #include "bsp.hpp" // Board Support Package 22 | 23 | Q_DEFINE_THIS_FILE 24 | 25 | // generate declaration of the active object --------------------------------- 26 | //.$declare${AOs::Philo} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 27 | //.${AOs::Philo} ............................................................. 28 | class Philo : public QP::QActive { 29 | private: 30 | QP::QTimeEvt m_timeEvt; 31 | 32 | public: 33 | static Philo inst[N_PHILO]; 34 | 35 | public: 36 | Philo(); 37 | 38 | protected: 39 | Q_STATE_DECL(initial); 40 | Q_STATE_DECL(thinking); 41 | Q_STATE_DECL(hungry); 42 | Q_STATE_DECL(eating); 43 | }; 44 | //.$enddecl${AOs::Philo} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 45 | 46 | // generate definition of the opaque pointer to the AO ----------------------- 47 | //.$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 48 | //. Check for the minimum required QP version 49 | #if (QP_VERSION < 690U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U)) 50 | #error qpcpp version 6.9.0 or higher required 51 | #endif 52 | //.$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 53 | //.$define${AOs::AO_Philo[N_PHILO]} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 54 | //.${AOs::AO_Philo[N_PHILO]} ................................................. 55 | QP::QActive * const AO_Philo[N_PHILO] = { // "opaque" pointers to Philo AO 56 | &Philo::inst[0], 57 | &Philo::inst[1], 58 | &Philo::inst[2], 59 | &Philo::inst[3], 60 | &Philo::inst[4] 61 | }; 62 | //.$enddef${AOs::AO_Philo[N_PHILO]} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 63 | 64 | // helper function to provide a randomized think time for Philos 65 | inline QP::QTimeEvtCtr think_time() { 66 | return static_cast((BSP::random() % BSP::TICKS_PER_SEC) 67 | + (BSP::TICKS_PER_SEC/2U)); 68 | } 69 | 70 | // helper function to provide a randomized eat time for Philos 71 | inline QP::QTimeEvtCtr eat_time() { 72 | return static_cast((BSP::random() % BSP::TICKS_PER_SEC) 73 | + BSP::TICKS_PER_SEC); 74 | } 75 | 76 | // helper function to provide the ID of Philo 77 | inline uint8_t PHILO_ID(Philo const * const philo) { 78 | return static_cast(philo - &Philo::inst[0]); 79 | } 80 | 81 | // generate definition of the AO -------------------------------------------- 82 | //.$define${AOs::Philo} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 83 | //.${AOs::Philo} ............................................................. 84 | Philo Philo::inst[N_PHILO]; 85 | //.${AOs::Philo::Philo} ...................................................... 86 | Philo::Philo() 87 | : QActive(Q_STATE_CAST(&Philo::initial)), 88 | m_timeEvt(this, TIMEOUT_SIG, 0U) 89 | {} 90 | 91 | //.${AOs::Philo::SM} ......................................................... 92 | Q_STATE_DEF(Philo, initial) { 93 | //.${AOs::Philo::SM::initial} 94 | (void)e; // unused parameter 95 | 96 | subscribe(EAT_SIG); 97 | subscribe(TEST_SIG); 98 | 99 | // QS dictionaries only once for all Philos... 100 | static bool registered = false; 101 | if (!registered) { // first time through? 102 | registered = true; 103 | 104 | #ifdef QS_ON 105 | QS_OBJ_DICTIONARY(&Philo::inst[0]); 106 | QS_OBJ_DICTIONARY(&Philo::inst[0].m_timeEvt); 107 | QS_OBJ_DICTIONARY(&Philo::inst[1]); 108 | QS_OBJ_DICTIONARY(&Philo::inst[1].m_timeEvt); 109 | QS_OBJ_DICTIONARY(&Philo::inst[2]); 110 | QS_OBJ_DICTIONARY(&Philo::inst[2].m_timeEvt); 111 | QS_OBJ_DICTIONARY(&Philo::inst[3]); 112 | QS_OBJ_DICTIONARY(&Philo::inst[3].m_timeEvt); 113 | QS_OBJ_DICTIONARY(&Philo::inst[4]); 114 | QS_OBJ_DICTIONARY(&Philo::inst[4].m_timeEvt); 115 | 116 | QS_FUN_DICTIONARY(&Philo::initial); 117 | QS_FUN_DICTIONARY(&Philo::thinking); 118 | QS_FUN_DICTIONARY(&Philo::hungry); 119 | QS_FUN_DICTIONARY(&Philo::eating); 120 | 121 | QS_SIG_DICTIONARY(TIMEOUT_SIG, nullptr); 122 | #endif 123 | } 124 | return tran(&thinking); 125 | } 126 | //.${AOs::Philo::SM::thinking} ............................................... 127 | Q_STATE_DEF(Philo, thinking) { 128 | QP::QState status_; 129 | switch (e->sig) { 130 | //.${AOs::Philo::SM::thinking} 131 | case Q_ENTRY_SIG: { 132 | m_timeEvt.armX(think_time(), 0U); 133 | status_ = Q_RET_HANDLED; 134 | break; 135 | } 136 | //.${AOs::Philo::SM::thinking} 137 | case Q_EXIT_SIG: { 138 | (void)m_timeEvt.disarm(); 139 | status_ = Q_RET_HANDLED; 140 | break; 141 | } 142 | //.${AOs::Philo::SM::thinking::TIMEOUT} 143 | case TIMEOUT_SIG: { 144 | status_ = tran(&hungry); 145 | break; 146 | } 147 | //.${AOs::Philo::SM::thinking::EAT, DONE} 148 | case EAT_SIG: // intentionally fall through 149 | case DONE_SIG: { 150 | // EAT or DONE must be for other Philos than this one 151 | Q_ASSERT(Q_EVT_CAST(TableEvt)->philoNum != PHILO_ID(this)); 152 | status_ = Q_RET_HANDLED; 153 | break; 154 | } 155 | //.${AOs::Philo::SM::thinking::TEST} 156 | case TEST_SIG: { 157 | status_ = Q_RET_HANDLED; 158 | break; 159 | } 160 | default: { 161 | status_ = super(&top); 162 | break; 163 | } 164 | } 165 | return status_; 166 | } 167 | //.${AOs::Philo::SM::hungry} ................................................. 168 | Q_STATE_DEF(Philo, hungry) { 169 | QP::QState status_; 170 | switch (e->sig) { 171 | //.${AOs::Philo::SM::hungry} 172 | case Q_ENTRY_SIG: { 173 | TableEvt *pe = Q_NEW(TableEvt, HUNGRY_SIG); 174 | pe->philoNum = PHILO_ID(this); 175 | AO_Table->POST(pe, this); 176 | status_ = Q_RET_HANDLED; 177 | break; 178 | } 179 | //.${AOs::Philo::SM::hungry::EAT} 180 | case EAT_SIG: { 181 | //.${AOs::Philo::SM::hungry::EAT::[Q_EVT_CAST(TableEvt)->philoNum=~} 182 | if (Q_EVT_CAST(TableEvt)->philoNum == PHILO_ID(this)) { 183 | status_ = tran(&eating); 184 | } 185 | else { 186 | status_ = Q_RET_UNHANDLED; 187 | } 188 | break; 189 | } 190 | //.${AOs::Philo::SM::hungry::DONE} 191 | case DONE_SIG: { 192 | /* DONE must be for other Philos than this one */ 193 | Q_ASSERT(Q_EVT_CAST(TableEvt)->philoNum != PHILO_ID(this)); 194 | status_ = Q_RET_HANDLED; 195 | break; 196 | } 197 | default: { 198 | status_ = super(&top); 199 | break; 200 | } 201 | } 202 | return status_; 203 | } 204 | //.${AOs::Philo::SM::eating} ................................................. 205 | Q_STATE_DEF(Philo, eating) { 206 | QP::QState status_; 207 | switch (e->sig) { 208 | //.${AOs::Philo::SM::eating} 209 | case Q_ENTRY_SIG: { 210 | m_timeEvt.armX(eat_time(), 0U); 211 | status_ = Q_RET_HANDLED; 212 | break; 213 | } 214 | //.${AOs::Philo::SM::eating} 215 | case Q_EXIT_SIG: { 216 | TableEvt *pe = Q_NEW(TableEvt, DONE_SIG); 217 | pe->philoNum = PHILO_ID(this); 218 | QP::QF::PUBLISH(pe, this); 219 | (void)m_timeEvt.disarm(); 220 | status_ = Q_RET_HANDLED; 221 | break; 222 | } 223 | //.${AOs::Philo::SM::eating::TIMEOUT} 224 | case TIMEOUT_SIG: { 225 | status_ = tran(&thinking); 226 | break; 227 | } 228 | //.${AOs::Philo::SM::eating::EAT, DONE} 229 | case EAT_SIG: // intentionally fall through 230 | case DONE_SIG: { 231 | // EAT or DONE must be for other Philos than this one 232 | Q_ASSERT(Q_EVT_CAST(TableEvt)->philoNum != PHILO_ID(this)); 233 | status_ = Q_RET_HANDLED; 234 | break; 235 | } 236 | default: { 237 | status_ = super(&top); 238 | break; 239 | } 240 | } 241 | return status_; 242 | } 243 | //.$enddef${AOs::Philo} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 244 | -------------------------------------------------------------------------------- /examples/dpp_bsp-teensy4/qview/dpp.py: -------------------------------------------------------------------------------- 1 | # This is an example of QView customization for a specific application 2 | # (DPP in this case). This example animates the Phil images on the 3 | # QView canvas. Additionally, there is a button in the middle of the screen, 4 | # which, when clicked once pauses the DPP ("forks" are not being served). 5 | # A second click on the button, "un-pauses" the DPP ("forks" are served 6 | # to all hungry Philosophers). 7 | # 8 | # This version of the DPP customization uses the application-specific 9 | # packet QS_USER_00 (PHILO_STAT) produced when the status of a Philo changes. 10 | # 11 | 12 | class DPP: 13 | def __init__(self): 14 | 15 | # add commands to the Custom menu... 16 | QView.custom_menu.add_command(label="Custom command", 17 | command=self.cust_command) 18 | 19 | # configure the custom QView.canvas... 20 | QView.show_canvas() # make the canvas visible 21 | QView.canvas.configure(width=400, height=260) 22 | 23 | # tuple of activity images (correspond to self._philo_state) 24 | self._act_img = ( 25 | PhotoImage(file=HOME_DIR + "/img/thinking.gif"), 26 | PhotoImage(file=HOME_DIR + "/img/hungry.gif"), 27 | PhotoImage(file=HOME_DIR + "/img/eating.gif"), 28 | ) 29 | # tuple of philo canvas images (correspond to self._philo_obj) 30 | self._philo_img = (\ 31 | QView.canvas.create_image(190, 57, image=self._act_img[0]), 32 | QView.canvas.create_image(273, 100, image=self._act_img[0]), 33 | QView.canvas.create_image(237, 185, image=self._act_img[0]), 34 | QView.canvas.create_image(146, 185, image=self._act_img[0]), 35 | QView.canvas.create_image(107, 100, image=self._act_img[0]) 36 | ) 37 | 38 | # button images for UP and DOWN 39 | self.img_UP = PhotoImage(file=HOME_DIR + "/img/BTN_UP.gif") 40 | self.img_DWN = PhotoImage(file=HOME_DIR + "/img/BTN_DWN.gif") 41 | 42 | # images of a button for pause/serve 43 | self.btn = QView.canvas.create_image(200, 120, image=self.img_UP) 44 | QView.canvas.tag_bind(self.btn, "", self.cust_pause) 45 | 46 | # request target reset on startup... 47 | # NOTE: Normally, for an embedded application you would like 48 | # to start with resetting the Target, to start clean with 49 | # Qs dictionaries, etc. 50 | reset_target() 51 | 52 | # on_reset() callback 53 | def on_reset(self): 54 | # clear the lists 55 | self._philo_obj = [0, 0, 0, 0, 0] 56 | self._philo_state = [0, 0, 0] 57 | 58 | # on_run() callback 59 | def on_run(self): 60 | glb_filter("QS_USER_00") 61 | 62 | # NOTE: the name of object for current_obj() must match the 63 | # QS Object Dictionaries produced by the application. 64 | current_obj(OBJ_AO, "Table::inst") 65 | 66 | # turn lists into tuples for better performance 67 | self._philo_obj = tuple(self._philo_obj) 68 | self._philo_state = tuple(self._philo_state) 69 | 70 | 71 | # example of a custom command 72 | def cust_command(self): 73 | command(1, 12345) 74 | 75 | # example of a custom interaction with a canvas object (pause/serve) 76 | def cust_pause(self, event): 77 | if QView.canvas.itemcget(self.btn, "image") != str(self.img_UP): 78 | QView.canvas.itemconfig(self.btn, image=self.img_UP) 79 | post("SERVE_SIG") 80 | QView.print_text("Table SERVING") 81 | else: 82 | QView.canvas.itemconfig(self.btn, image=self.img_DWN) 83 | post("PAUSE_SIG") 84 | QView.print_text("Table PAUSED") 85 | 86 | # intercept the QS_USER_00 application-specific packet 87 | # this packet has the following structure (see bsp.c:displayPhilStat()): 88 | # record-ID, seq-num, Timestamp, format-byte, Philo-num, 89 | # format-bye, Zero-terminated string (status) 90 | def QS_USER_00(self, packet): 91 | # unpack: Timestamp->data[0], Philo-num->data[1], status->data[3] 92 | data = qunpack("xxTxBxZ", packet) 93 | i = data[1] 94 | j = ("t", "h", "e").index(data[2][0]) # the first letter 95 | 96 | # animate the given philo image according to its activity 97 | QView.canvas.itemconfig(self._philo_img[i], image=self._act_img[j]) 98 | 99 | # print a message to the text view 100 | QView.print_text("%010d Philo %1d is %s"%(data[0], i, data[2])) 101 | 102 | #============================================================================= 103 | QView.customize(DPP()) # set the QView customization 104 | -------------------------------------------------------------------------------- /examples/dpp_bsp-teensy4/qview/dpp1.py: -------------------------------------------------------------------------------- 1 | # This is an example of QView customization for a specific application 2 | # (DPP in this case). This example animates the Phil images on the 3 | # QView canvas. Additionally, there is a button in the middle of the screen, 4 | # which, when clicked once pauses the DPP ("forks" are not being served). 5 | # A second click on the button, "un-pauses" the DPP ("forks" are served 6 | # to all hungry Philosophers). 7 | # 8 | # This version of the DPP customization uses the standard QS_QEP_STATE_ENTRY 9 | # packet, which provides information about the current states of the dining 10 | # Philosophers. The example also demonstrates how to intercept the QS 11 | # "dictionary" records QS_OBJ_DICT and QS_FUN_DICT to extract the information 12 | # about the addresses of the Philosopher objects and the states of their 13 | # state machines. 14 | # 15 | 16 | class DPP: 17 | def __init__(self): 18 | 19 | # add commands to the Custom menu... 20 | QView.custom_menu.add_command(label="Custom command", 21 | command=self.cust_command) 22 | 23 | # configure the custom QView.canvas... 24 | QView.show_canvas() # make the canvas visible 25 | QView.canvas.configure(width=400, height=260) 26 | 27 | # tuple of activity images (correspond to self._philo_state) 28 | self._act_img = ( 29 | PhotoImage(file=HOME_DIR + "/img/thinking.gif"), 30 | PhotoImage(file=HOME_DIR + "/img/hungry.gif"), 31 | PhotoImage(file=HOME_DIR + "/img/eating.gif"), 32 | ) 33 | # tuple of philo canvas images (correspond to self._philo_obj) 34 | self._philo_img = (\ 35 | QView.canvas.create_image(190, 57, image=self._act_img[0]), 36 | QView.canvas.create_image(273, 100, image=self._act_img[0]), 37 | QView.canvas.create_image(237, 185, image=self._act_img[0]), 38 | QView.canvas.create_image(146, 185, image=self._act_img[0]), 39 | QView.canvas.create_image(107, 100, image=self._act_img[0]) 40 | ) 41 | 42 | # button images for UP and DOWN 43 | self.img_UP = PhotoImage(file=HOME_DIR + "/img/BTN_UP.gif") 44 | self.img_DWN = PhotoImage(file=HOME_DIR + "/img/BTN_DWN.gif") 45 | 46 | # images of a button for pause/serve 47 | self.btn = QView.canvas.create_image(200, 120, image=self.img_UP) 48 | QView.canvas.tag_bind(self.btn, "", self.cust_pause) 49 | 50 | # request target reset on startup... 51 | # NOTE: Normally, for an embedded application you would like 52 | # to start with resetting the Target, to start clean with 53 | # Qs dictionaries, etc. 54 | reset_target() 55 | 56 | # on_reset() callback invoked when Target-reset packet is received 57 | # NOTE: the QS dictionaries are not known at this time yet, so 58 | # this callback shouild generally not set filters or current objects 59 | def on_reset(self): 60 | # (re)set the lists 61 | self._philo_obj = [0, 0, 0, 0, 0] 62 | self._philo_state = [0, 0, 0] 63 | 64 | # on_run() callback invoked when the QF_RUN packet is received 65 | # NOTE: the QS dictionaries are typically known at this time yet, so 66 | # this callback can set filters or current objects 67 | def on_run(self): 68 | glb_filter("QS_QEP_TRAN") 69 | 70 | # NOTE: the name of object for current_obj() must match the 71 | # QS Object Dictionaries produced by the application. 72 | current_obj(OBJ_AO, "Table::inst") 73 | 74 | # turn lists into tuples for better performance 75 | self._philo_obj = tuple(self._philo_obj) 76 | self._philo_state = tuple(self._philo_state) 77 | 78 | 79 | # example of a custom command 80 | def cust_command(self): 81 | command(1, 12345) 82 | 83 | # example of a custom interaction with a canvas object (pause/serve) 84 | def cust_pause(self, event): 85 | if QView.canvas.itemcget(self.btn, "image") != str(self.img_UP): 86 | QView.canvas.itemconfig(self.btn, image=self.img_UP) 87 | post("SERVE_SIG") 88 | QView.print_text("Table SERVING") 89 | else: 90 | QView.canvas.itemconfig(self.btn, image=self.img_DWN) 91 | post("PAUSE_SIG") 92 | QView.print_text("Table PAUSED") 93 | 94 | # intercept the QS_OBJ_DICT stadard packet 95 | # this packet has the following structure: 96 | # record-ID, seq-num, Object-ptr, Zero-terminated string 97 | def QS_OBJ_DICT(self, packet): 98 | data = qunpack("xxOZ", packet) 99 | try: 100 | # NOTE: the names of objects must match the QS Object Dictionaries 101 | # produced by the application. 102 | i = ("Philo::inst[0]", 103 | "Philo::inst[1]", 104 | "Philo::inst[2]", 105 | "Philo::inst[3]", 106 | "Philo::inst[4]").index(data[1]) 107 | self._philo_obj[i] = data[0] 108 | except: 109 | pass # dictionary for a different object 110 | 111 | # intercept the QS_FUN_DICT stadard packet 112 | # this packet has the following structure: 113 | # record-ID, seq-num, Function-ptr, Zero-terminated string 114 | def QS_FUN_DICT(self, packet): 115 | data = qunpack("xxFZ", packet) 116 | try: 117 | # NOTE: the names of states must match the QS Object Dictionaries 118 | # produced by the application. 119 | j = ("Philo::thinking", 120 | "Philo::hungry", 121 | "Philo::eating").index(data[1]) 122 | self._philo_state[j] = data[0] 123 | except: 124 | pass # dictionary for a different state 125 | 126 | # intercept the QS_QEP_TRAN stadard packet 127 | # this packet has the following structure: 128 | # record-ID, seq-num, Timestamp, Signal, Object-ptr, 129 | # Function-ptr (source state), Function-ptr (new active state) 130 | def QS_QEP_TRAN(self, packet): 131 | data = qunpack("xxTSOFF", packet) 132 | try: 133 | i = self._philo_obj.index(data[2]) 134 | j = self._philo_state.index(data[4]) 135 | 136 | # animate the given philo image according to its activity 137 | QView.canvas.itemconfig(self._philo_img[i], 138 | image=self._act_img[j]) 139 | # print a message to the text view 140 | QView.print_text("%010d Philo %d is %s"\ 141 | %(data[0], i, ("thinking", "hungry", "eating")[j])) 142 | except: 143 | pass # state-entry in a different object 144 | 145 | #============================================================================= 146 | # instantiate the DPP class and set it as the QView customization 147 | QView.customize(DPP()) 148 | -------------------------------------------------------------------------------- /examples/dpp_bsp-teensy4/qview/img/BTN_DWN.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantumLeaps/qp-arduino/bbc8f4ed8ff2075969c5a076e72ce0aa9240c0e8/examples/dpp_bsp-teensy4/qview/img/BTN_DWN.gif -------------------------------------------------------------------------------- /examples/dpp_bsp-teensy4/qview/img/BTN_UP.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantumLeaps/qp-arduino/bbc8f4ed8ff2075969c5a076e72ce0aa9240c0e8/examples/dpp_bsp-teensy4/qview/img/BTN_UP.gif -------------------------------------------------------------------------------- /examples/dpp_bsp-teensy4/qview/img/eating.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantumLeaps/qp-arduino/bbc8f4ed8ff2075969c5a076e72ce0aa9240c0e8/examples/dpp_bsp-teensy4/qview/img/eating.gif -------------------------------------------------------------------------------- /examples/dpp_bsp-teensy4/qview/img/hungry.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantumLeaps/qp-arduino/bbc8f4ed8ff2075969c5a076e72ce0aa9240c0e8/examples/dpp_bsp-teensy4/qview/img/hungry.gif -------------------------------------------------------------------------------- /examples/dpp_bsp-teensy4/qview/img/thinking.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantumLeaps/qp-arduino/bbc8f4ed8ff2075969c5a076e72ce0aa9240c0e8/examples/dpp_bsp-teensy4/qview/img/thinking.gif -------------------------------------------------------------------------------- /examples/dpp_bsp-teensy4/qview/qview-dpp.bat: -------------------------------------------------------------------------------- 1 | @setlocal 2 | 3 | if "%QTOOLS%"=="" ( 4 | set QTOOLS=C:\qp\qtools 5 | ) 6 | python3 %QTOOLS%\qview\qview.py dpp.py 7 | 8 | @endlocal 9 | -------------------------------------------------------------------------------- /examples/dpp_bsp-teensy4/qview/qview-dpp.lnk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantumLeaps/qp-arduino/bbc8f4ed8ff2075969c5a076e72ce0aa9240c0e8/examples/dpp_bsp-teensy4/qview/qview-dpp.lnk -------------------------------------------------------------------------------- /examples/dpp_bsp-teensy4/qview/qview-dpp1.bat: -------------------------------------------------------------------------------- 1 | @setlocal 2 | 3 | if "%QTOOLS%"=="" ( 4 | set QTOOLS=C:\qp\qtools 5 | ) 6 | python3 %QTOOLS%\qview\qview.py dpp1.py 7 | 8 | @endlocal 9 | -------------------------------------------------------------------------------- /examples/dpp_bsp-teensy4/qview/qview-dpp1.lnk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantumLeaps/qp-arduino/bbc8f4ed8ff2075969c5a076e72ce0aa9240c0e8/examples/dpp_bsp-teensy4/qview/qview-dpp1.lnk -------------------------------------------------------------------------------- /extras/img/logo_ql_400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantumLeaps/qp-arduino/bbc8f4ed8ff2075969c5a076e72ce0aa9240c0e8/extras/img/logo_ql_400.png -------------------------------------------------------------------------------- /extras/img/logo_qp-arduino.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantumLeaps/qp-arduino/bbc8f4ed8ff2075969c5a076e72ce0aa9240c0e8/extras/img/logo_qp-arduino.png -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=qp-arduino 2 | version=6.9.6 3 | author=Quantum Leaps 4 | maintainer=Peter Polidoro 5 | sentence=QP/C++ Real-Time Embedded Framework for Arduino. 6 | paragraph=The QP/C++ real-time framework is like a modern real-time operating system (RTOS) specifically designed for executing event-driven, encapsulated state machines (Active Objects). It enables you to build responsive, robust, and truly concurrent Arduino programs. 7 | category=Device Control 8 | url=https://www.state-machine.com/arduino/ 9 | architectures=* 10 | includes=qpcpp.hpp 11 | -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | [platformio] 2 | ;src_dir = examples/blinky_bsp-teensy4 3 | src_dir = examples/dpp_bsp-teensy4 4 | lib_dir = src 5 | default_envs = teensy41 6 | 7 | [common_env_data] 8 | build_flags = 9 | -Isrc 10 | lib_deps_external = 11 | https://github.com/PaulStoffregen/TimerOne.git 12 | lib_deps_local = 13 | src/qp-arduino 14 | 15 | [env] 16 | lib_ldf_mode = off 17 | build_flags = 18 | ${common_env_data.build_flags} 19 | monitor_filters = 20 | send_on_enter 21 | colorize 22 | monitor_speed = 115200 23 | lib_deps = 24 | ${common_env_data.lib_deps_external} 25 | ${common_env_data.lib_deps_local} 26 | 27 | [env:teensy41] 28 | platform = teensy 29 | framework = arduino 30 | board = teensy41 31 | upload_protocol = teensy-cli 32 | 33 | ;;; Install platformio in virtual environment 34 | ; sudo apt install -y python3-venv 35 | ; cd qp-arduino 36 | ; rm -rf .venv 37 | ; mkdir .venv 38 | ; python3 -m venv .venv 39 | ; source .venv/bin/activate 40 | ; pip install platformio 41 | ; deactivate 42 | 43 | ;;; Compile and upload example 44 | ; source .venv/bin/activate 45 | ; rm -rf .pio 46 | ; pio run -e teensy41 --target upload --upload-port /dev/ttyACM0 47 | -------------------------------------------------------------------------------- /src/qp-arduino/qep_port.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// @brief QEP/C++ port, GCC-ARM compiler 3 | /// @cond 4 | ///*************************************************************************** 5 | /// Last updated for version 6.9.4 6 | /// Last updated on 2022-01-14 7 | /// 8 | /// Q u a n t u m L e a P s 9 | /// ------------------------ 10 | /// Modern Embedded Software 11 | /// 12 | /// Copyright (C) 2005-2022 Quantum Leaps. All rights reserved. 13 | /// 14 | /// This program is open source software: you can redistribute it and/or 15 | /// modify it under the terms of the GNU General Public License as published 16 | /// by the Free Software Foundation, either version 3 of the License, or 17 | /// (at your option) any later version. 18 | /// 19 | /// Alternatively, this program may be distributed and modified under the 20 | /// terms of Quantum Leaps commercial licenses, which expressly supersede 21 | /// the GNU General Public License and are specifically designed for 22 | /// licensees interested in retaining the proprietary status of their code. 23 | /// 24 | /// This program is distributed in the hope that it will be useful, 25 | /// but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 | /// GNU General Public License for more details. 28 | /// 29 | /// You should have received a copy of the GNU General Public License 30 | /// along with this program. If not, see . 31 | /// 32 | /// Contact information: 33 | /// 34 | /// 35 | ///*************************************************************************** 36 | /// @endcond 37 | 38 | #ifndef QEP_PORT_HPP 39 | #define QEP_PORT_HPP 40 | 41 | // enable QP/Spy software tracing instrumentation 42 | #define Q_SPY 1U 43 | 44 | //! no-return function specifier (GCC-ARM compiler) 45 | #define Q_NORETURN __attribute__ ((noreturn)) void 46 | 47 | #include // Exact-width types. C++11 Standard 48 | 49 | #include "qep.hpp" // QEP platform-independent public interface 50 | 51 | #endif // QEP_PORT_HPP 52 | -------------------------------------------------------------------------------- /src/qp-arduino/qf_act.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// @brief QP::QActive services and QF support code 3 | /// @ingroup qf 4 | /// @cond 5 | ///*************************************************************************** 6 | /// Last updated for version 6.9.1 7 | /// Last updated on 2020-09-18 8 | /// 9 | /// Q u a n t u m L e a P s 10 | /// ------------------------ 11 | /// Modern Embedded Software 12 | /// 13 | /// Copyright (C) 2005-2020 Quantum Leaps. All rights reserved. 14 | /// 15 | /// This program is open source software: you can redistribute it and/or 16 | /// modify it under the terms of the GNU General Public License as published 17 | /// by the Free Software Foundation, either version 3 of the License, or 18 | /// (at your option) any later version. 19 | /// 20 | /// Alternatively, this program may be distributed and modified under the 21 | /// terms of Quantum Leaps commercial licenses, which expressly supersede 22 | /// the GNU General Public License and are specifically designed for 23 | /// licensees interested in retaining the proprietary status of their code. 24 | /// 25 | /// This program is distributed in the hope that it will be useful, 26 | /// but WITHOUT ANY WARRANTY; without even the implied warranty of 27 | /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 | /// GNU General Public License for more details. 29 | /// 30 | /// You should have received a copy of the GNU General Public License 31 | /// along with this program. If not, see . 32 | /// 33 | /// Contact information: 34 | /// 35 | /// 36 | ///*************************************************************************** 37 | /// @endcond 38 | 39 | #define QP_IMPL // this is QP implementation 40 | #include "qf_port.hpp" // QF port 41 | #include "qf_pkg.hpp" // QF package-scope interface 42 | #include "qassert.h" // QP embedded systems-friendly assertions 43 | #ifdef Q_SPY // QS software tracing enabled? 44 | #include "qs_port.hpp" // QS port 45 | #include "qs_pkg.hpp" // QS facilities for pre-defined trace records 46 | #else 47 | #include "qs_dummy.hpp" // disable the QS software tracing 48 | #endif // Q_SPY 49 | 50 | //**************************************************************************** 51 | /// @description 52 | /// macro to encapsulate pointer increment, which violates MISRA-C:2004 53 | /// required rule 17.4 (pointer arithmetic used). 54 | /// 55 | /// @param[in] p_ pointer to be incremented. 56 | /// 57 | #define QF_PTR_INC_(p_) (++(p_)) 58 | 59 | namespace QP { 60 | 61 | Q_DEFINE_THIS_MODULE("qf_act") 62 | 63 | // public objects ************************************************************ 64 | QActive *QF::active_[QF_MAX_ACTIVE + 1U]; // to be used by QF ports only 65 | 66 | //**************************************************************************** 67 | /// @description 68 | /// This function adds a given active object to the active objects managed 69 | /// by the QF framework. It should not be called by the application directly, 70 | /// only through the function QP::QActive::start(). 71 | /// 72 | /// @param[in] a pointer to the active object to add to the framework. 73 | /// 74 | /// @note The priority of the active object @p a should be set before calling 75 | /// this function. 76 | /// 77 | /// @sa QP::QF::remove_() 78 | /// 79 | void QF::add_(QActive * const a) noexcept { 80 | std::uint_fast8_t const p = static_cast(a->m_prio); 81 | 82 | Q_REQUIRE_ID(100, (0U < p) && (p <= QF_MAX_ACTIVE) 83 | && (active_[p] == nullptr)); 84 | QF_CRIT_STAT_ 85 | QF_CRIT_E_(); 86 | active_[p] = a; // registger the active object at this priority 87 | QF_CRIT_X_(); 88 | } 89 | 90 | //**************************************************************************** 91 | /// @description 92 | /// This function removes a given active object from the active objects 93 | /// managed by the QF framework. It should not be called by the QP ports. 94 | /// 95 | /// @param[in] a pointer to the active object to remove from the framework. 96 | /// 97 | /// @note 98 | /// The active object that is removed from the framework can no longer 99 | /// participate in the publish-subscribe event exchange. 100 | /// 101 | /// @sa QP::QF::add_() 102 | /// 103 | void QF::remove_(QActive * const a) noexcept { 104 | std::uint_fast8_t const p = static_cast(a->m_prio); 105 | 106 | Q_REQUIRE_ID(200, (0U < p) && (p <= QF_MAX_ACTIVE) 107 | && (active_[p] == a)); 108 | 109 | QF_CRIT_STAT_ 110 | QF_CRIT_E_(); 111 | active_[p] = nullptr; // free-up the priority level 112 | a->m_state.fun = nullptr; // invalidate the state 113 | QF_CRIT_X_(); 114 | } 115 | 116 | //**************************************************************************** 117 | /// @description 118 | /// Clears a memory buffer by writing zeros byte-by-byte. 119 | /// 120 | /// @param[in] start pointer to the beginning of a memory buffer. 121 | /// @param[in] len length of the memory buffer to clear (in bytes) 122 | /// 123 | /// @note The main application of this function is clearing the internal QF 124 | /// variables upon startup. This is done to avoid problems with non-standard 125 | /// startup code provided with some compilers and toolsets (e.g., TI DSPs or 126 | /// Microchip MPLAB), which does not zero the uninitialized variables, as 127 | /// required by the ANSI C standard. 128 | /// 129 | void QF::bzero(void * const start, std::uint_fast16_t const len) noexcept { 130 | std::uint8_t *ptr = static_cast(start); 131 | for (std::uint_fast16_t n = len; n > 0U; --n) { 132 | *ptr = 0U; 133 | QF_PTR_INC_(ptr); 134 | } 135 | } 136 | 137 | } // namespace QP 138 | 139 | // Log-base-2 calculations ... 140 | #ifndef QF_LOG2 141 | 142 | //! function that returns (log2(x) + 1), where @p x is a 32-bit bitmask 143 | /// 144 | /// @description 145 | /// This function returns the 1-based number of the most significant 1-bit 146 | /// of a 32-bit bitmask. This function can be replaced in the QP ports, if 147 | /// the CPU has special instructions, such as CLZ (count leading zeros). 148 | /// 149 | extern "C" { 150 | 151 | std::uint_fast8_t QF_LOG2(QP::QPSetBits x) noexcept { 152 | static std::uint8_t const log2LUT[16] = { 153 | 0U, 1U, 2U, 2U, 3U, 3U, 3U, 3U, 154 | 4U, 4U, 4U, 4U, 4U, 4U, 4U, 4U 155 | }; 156 | std::uint_fast8_t n = 0U; 157 | QP::QPSetBits t; 158 | 159 | #if (QF_MAX_ACTIVE > 16U) 160 | t = static_cast(x >> 16U); 161 | if (t != 0U) { 162 | n += 16U; 163 | x = t; 164 | } 165 | #endif 166 | #if (QF_MAX_ACTIVE > 8U) 167 | t = (x >> 8U); 168 | if (t != 0U) { 169 | n += 8U; 170 | x = t; 171 | } 172 | #endif 173 | t = (x >> 4U); 174 | if (t != 0U) { 175 | n += 4U; 176 | x = t; 177 | } 178 | return n + log2LUT[x]; 179 | } 180 | 181 | } // extern "C" 182 | 183 | #endif // QF_LOG2 184 | 185 | -------------------------------------------------------------------------------- /src/qp-arduino/qf_defer.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// @brief QP::QActive::defer() and QP::QActive::recall() definitions. 3 | /// @ingroup qf 4 | /// @cond 5 | ///*************************************************************************** 6 | /// Last updated for version 6.9.1 7 | /// Last updated on 2020-09-17 8 | /// 9 | /// Q u a n t u m L e a P s 10 | /// ------------------------ 11 | /// Modern Embedded Software 12 | /// 13 | /// Copyright (C) 2005-2020 Quantum Leaps. All rights reserved. 14 | /// 15 | /// This program is open source software: you can redistribute it and/or 16 | /// modify it under the terms of the GNU General Public License as published 17 | /// by the Free Software Foundation, either version 3 of the License, or 18 | /// (at your option) any later version. 19 | /// 20 | /// Alternatively, this program may be distributed and modified under the 21 | /// terms of Quantum Leaps commercial licenses, which expressly supersede 22 | /// the GNU General Public License and are specifically designed for 23 | /// licensees interested in retaining the proprietary status of their code. 24 | /// 25 | /// This program is distributed in the hope that it will be useful, 26 | /// but WITHOUT ANY WARRANTY; without even the implied warranty of 27 | /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 | /// GNU General Public License for more details. 29 | /// 30 | /// You should have received a copy of the GNU General Public License 31 | /// along with this program. If not, see . 32 | /// 33 | /// Contact information: 34 | /// 35 | /// 36 | ///*************************************************************************** 37 | /// @endcond 38 | 39 | #define QP_IMPL // this is QP implementation 40 | #include "qf_port.hpp" // QF port 41 | #include "qf_pkg.hpp" // QF package-scope interface 42 | #include "qassert.h" // QP embedded systems-friendly assertions 43 | #ifdef Q_SPY // QS software tracing enabled? 44 | #include "qs_port.hpp" // QS port 45 | #include "qs_pkg.hpp" // QS facilities for pre-defined trace records 46 | #else 47 | #include "qs_dummy.hpp" // disable the QS software tracing 48 | #endif // Q_SPY 49 | 50 | namespace QP { 51 | 52 | Q_DEFINE_THIS_MODULE("qf_defer") 53 | 54 | //**************************************************************************** 55 | /// @description 56 | /// This function is part of the event deferral support. An active object 57 | /// uses this function to defer an event @p e to the QF-supported native 58 | /// event queue @p eq. QF correctly accounts for another outstanding 59 | /// reference to the event and will not recycle the event at the end of 60 | /// the RTC step. Later, the active object might recall one event at a 61 | /// time from the event queue. 62 | /// 63 | /// @param[in] eq pointer to a "raw" thread-safe queue to recall 64 | /// an event from. 65 | /// @param[in] e pointer to the event to be deferred 66 | /// 67 | /// @returns 68 | /// 'true' (success) when the event could be deferred and 'false' 69 | /// (failure) if event deferral failed due to overflowing the queue. 70 | /// 71 | /// An active object can use multiple event queues to defer events of 72 | /// different kinds. 73 | /// 74 | /// @sa 75 | /// QP::QActive::recall(), QP::QEQueue, QP::QActive::flushDeferred() 76 | /// 77 | bool QActive::defer(QEQueue * const eq, QEvt const * const e) const noexcept { 78 | bool const status = eq->post(e, 0U, m_prio); 79 | QS_CRIT_STAT_ 80 | 81 | QS_BEGIN_PRE_(QS_QF_ACTIVE_DEFER, m_prio) 82 | QS_TIME_PRE_(); // time stamp 83 | QS_OBJ_PRE_(this); // this active object 84 | QS_OBJ_PRE_(eq); // the deferred queue 85 | QS_SIG_PRE_(e->sig); // the signal of the event 86 | QS_2U8_PRE_(e->poolId_, e->refCtr_); // pool Id & ref Count 87 | QS_END_PRE_() 88 | 89 | return status; 90 | } 91 | 92 | //**************************************************************************** 93 | /// @description 94 | /// This function is part of the event deferral support. An active object 95 | /// uses this function to recall a deferred event from a given QF 96 | /// event queue. Recalling an event means that it is removed from the 97 | /// deferred event queue @p eq and posted (LIFO) to the event queue of 98 | /// the active object. 99 | /// 100 | /// @param[in] eq pointer to a "raw" thread-safe queue to recall 101 | /// an event from. 102 | /// 103 | /// @returns 104 | /// 'true' if an event has been recalled and 'false' if not. 105 | /// 106 | /// @note 107 | /// An active object can use multiple event queues to defer events of 108 | /// different kinds. 109 | /// 110 | /// @sa 111 | /// QP::QActive::recall(), QP::QEQueue, QP::QActive::postLIFO_() 112 | /// 113 | bool QActive::recall(QEQueue * const eq) noexcept { 114 | QEvt const * const e = eq->get(m_prio); // get evt from deferred queue 115 | bool recalled; 116 | 117 | // event available? 118 | if (e != nullptr) { 119 | QActive::postLIFO(e); // post it to the _front_ of the AO's queue 120 | 121 | QF_CRIT_STAT_ 122 | QF_CRIT_E_(); 123 | 124 | // is it a dynamic event? 125 | if (e->poolId_ != 0U) { 126 | 127 | // after posting to the AO's queue the event must be referenced 128 | // at least twice: once in the deferred event queue (eq->get() 129 | // did NOT decrement the reference counter) and once in the 130 | // AO's event queue. 131 | Q_ASSERT_CRIT_(210, e->refCtr_ >= 2U); 132 | 133 | // we need to decrement the reference counter once, to account 134 | // for removing the event from the deferred event queue. 135 | QF_EVT_REF_CTR_DEC_(e); // decrement the reference counter 136 | } 137 | 138 | QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_RECALL, m_prio) 139 | QS_TIME_PRE_(); // time stamp 140 | QS_OBJ_PRE_(this); // this active object 141 | QS_OBJ_PRE_(eq); // the deferred queue 142 | QS_SIG_PRE_(e->sig); // the signal of the event 143 | QS_2U8_PRE_(e->poolId_, e->refCtr_); // pool Id & ref Count 144 | QS_END_NOCRIT_PRE_() 145 | 146 | QF_CRIT_X_(); 147 | recalled = true; 148 | } 149 | else { 150 | QS_CRIT_STAT_ 151 | 152 | QS_BEGIN_PRE_(QS_QF_ACTIVE_RECALL_ATTEMPT, m_prio) 153 | QS_TIME_PRE_(); // time stamp 154 | QS_OBJ_PRE_(this); // this active object 155 | QS_OBJ_PRE_(eq); // the deferred queue 156 | QS_END_PRE_() 157 | 158 | recalled = false; 159 | } 160 | return recalled; 161 | } 162 | 163 | //**************************************************************************** 164 | /// @description 165 | /// This function is part of the event deferral support. An active object 166 | /// can use this function to flush a given QF event queue. The function makes 167 | /// sure that the events are not leaked. 168 | /// 169 | /// @param[in] eq pointer to a "raw" thread-safe queue to flush. 170 | /// 171 | /// @returns 172 | /// the number of events actually flushed from the queue. 173 | /// 174 | /// 175 | /// @sa 176 | /// QP::QActive::defer(), QP::QActive::recall(), QP::QEQueue 177 | /// 178 | std::uint_fast16_t QActive::flushDeferred(QEQueue * const eq) const noexcept { 179 | std::uint_fast16_t n = 0U; 180 | for (QEvt const *e = eq->get(m_prio); 181 | e != nullptr; 182 | e = eq->get(m_prio)) 183 | { 184 | QF::gc(e); // garbage collect 185 | ++n; // count the flushed event 186 | } 187 | return n; 188 | } 189 | 190 | } // namespace QP 191 | 192 | -------------------------------------------------------------------------------- /src/qp-arduino/qf_pkg.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// @ingroup qf 3 | /// @brief Internal (package scope) QF/C++ interface. 4 | /// @cond 5 | ///*************************************************************************** 6 | /// Last updated for version 6.9.1 7 | /// Last updated on 2020-09-17 8 | /// 9 | /// Q u a n t u m L e a P s 10 | /// ------------------------ 11 | /// Modern Embedded Software 12 | /// 13 | /// Copyright (C) 2005-2020 Quantum Leaps. All rights reserved. 14 | /// 15 | /// This program is open source software: you can redistribute it and/or 16 | /// modify it under the terms of the GNU General Public License as published 17 | /// by the Free Software Foundation, either version 3 of the License, or 18 | /// (at your option) any later version. 19 | /// 20 | /// Alternatively, this program may be distributed and modified under the 21 | /// terms of Quantum Leaps commercial licenses, which expressly supersede 22 | /// the GNU General Public License and are specifically designed for 23 | /// licensees interested in retaining the proprietary status of their code. 24 | /// 25 | /// This program is distributed in the hope that it will be useful, 26 | /// but WITHOUT ANY WARRANTY; without even the implied warranty of 27 | /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 | /// GNU General Public License for more details. 29 | /// 30 | /// You should have received a copy of the GNU General Public License 31 | /// along with this program. If not, see . 32 | /// 33 | /// Contact information: 34 | /// 35 | /// 36 | ///*************************************************************************** 37 | /// @endcond 38 | 39 | #ifndef QF_PKG_HPP 40 | #define QF_PKG_HPP 41 | 42 | //! helper macro to cast const away from an event pointer @p e_ 43 | #define QF_EVT_CONST_CAST_(e_) const_cast(e_) 44 | 45 | // QF-specific critical section... 46 | #ifndef QF_CRIT_STAT_TYPE 47 | //! This is an internal macro for defining the critical section 48 | //! status type. 49 | /// @description 50 | /// The purpose of this macro is to enable writing the same code for the 51 | /// case when critical section status type is defined and when it is not. 52 | /// If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro 53 | /// provides the definition of the critical section status variable. 54 | /// Otherwise this macro is empty. 55 | /// @sa #QF_CRIT_STAT_TYPE 56 | #define QF_CRIT_STAT_ 57 | 58 | //! This is an internal macro for entering a critical section. 59 | /// @description 60 | /// The purpose of this macro is to enable writing the same code for the 61 | /// case when critical section status type is defined and when it is not. 62 | /// If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro 63 | /// invokes QF_CRIT_ENTRY() passing the key variable as the parameter. 64 | /// Otherwise QF_CRIT_ENTRY() is invoked with a dummy parameter. 65 | /// @sa QF_CRIT_ENTRY() 66 | #define QF_CRIT_E_() QF_CRIT_ENTRY(dummy) 67 | 68 | //! This is an internal macro for exiting a critical section. 69 | /// @description 70 | /// The purpose of this macro is to enable writing the same code for the 71 | /// case when critical section status type is defined and when it is not. 72 | /// If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro 73 | /// invokes QF_CRIT_EXIT() passing the key variable as the parameter. 74 | /// Otherwise QF_CRIT_EXIT() is invoked with a dummy parameter. 75 | /// @sa QF_CRIT_EXIT() 76 | /// 77 | #define QF_CRIT_X_() QF_CRIT_EXIT(dummy) 78 | 79 | #elif (!defined QF_CRIT_STAT_) 80 | #define QF_CRIT_STAT_ QF_CRIT_STAT_TYPE critStat_; 81 | #define QF_CRIT_E_() QF_CRIT_ENTRY(critStat_) 82 | #define QF_CRIT_X_() QF_CRIT_EXIT(critStat_) 83 | #endif // QF_CRIT_STAT_TYPE 84 | 85 | // Assertions inside the crticial section ------------------------------------ 86 | #ifdef Q_NASSERT // Q_NASSERT defined--assertion checking disabled 87 | 88 | #define Q_ASSERT_CRIT_(id_, test_) ((void)0) 89 | #define Q_REQUIRE_CRIT_(id_, test_) ((void)0) 90 | #define Q_ERROR_CRIT_(id_) ((void)0) 91 | 92 | #else // Q_NASSERT not defined--assertion checking enabled 93 | 94 | #define Q_ASSERT_CRIT_(id_, test_) do {\ 95 | if ((test_)) {} else { \ 96 | QF_CRIT_X_(); \ 97 | Q_onAssert(&Q_this_module_[0], static_cast(id_)); \ 98 | } \ 99 | } while (false) 100 | 101 | #define Q_REQUIRE_CRIT_(id_, test_) Q_ASSERT_CRIT_((id_), (test_)) 102 | 103 | #define Q_ERROR_CRIT_(id_) do { \ 104 | QF_CRIT_X_(); \ 105 | Q_onAssert(&Q_this_module_[0], static_cast(id_)); \ 106 | } while (false) 107 | 108 | #endif // Q_NASSERT 109 | 110 | 111 | namespace QP { 112 | 113 | // package-scope objects ----------------------------------------------------- 114 | extern QF_EPOOL_TYPE_ QF_pool_[QF_MAX_EPOOL]; //!< allocate event pools 115 | extern std::uint_fast8_t QF_maxPool_; //!< # of initialized event pools 116 | extern QSubscrList *QF_subscrList_; //!< the subscriber list array 117 | extern enum_t QF_maxPubSignal_; //!< the maximum published signal 118 | 119 | //............................................................................ 120 | //! Structure representing a free block in the Native QF Memory Pool 121 | /// @sa QP::QMPool 122 | struct QFreeBlock { 123 | QFreeBlock * volatile m_next; //!< link to the next free block 124 | }; 125 | 126 | //............................................................................ 127 | // The following flags and bitmasks are for the fields of the @c refCtr_ 128 | // attribute of the QP::QTimeEvt class (inherited from QEvt). This attribute 129 | // is NOT used for reference counting in time events, because the @c poolId_ 130 | // attribute is zero ("static events"). 131 | // 132 | constexpr std::uint8_t TE_IS_LINKED = 1U << 7U; // flag 133 | constexpr std::uint8_t TE_WAS_DISARMED = 1U << 6U; // flag 134 | constexpr std::uint8_t TE_TICK_RATE = 0x0FU; // bitmask 135 | 136 | //**************************************************************************** 137 | // internal helper inline functions 138 | 139 | //! return the Pool-ID of an event @p e 140 | inline std::uint8_t QF_EVT_POOL_ID_ (QEvt const * const e) noexcept { 141 | return e->poolId_; 142 | } 143 | 144 | //! return the Reference Conter of an event @p e 145 | inline std::uint8_t QF_EVT_REF_CTR_ (QEvt const * const e) noexcept { 146 | return e->refCtr_; 147 | } 148 | 149 | //! increment the refCtr_ of an event @p e 150 | inline void QF_EVT_REF_CTR_INC_(QEvt const * const e) noexcept { 151 | ++(QF_EVT_CONST_CAST_(e))->refCtr_; 152 | } 153 | 154 | //! decrement the refCtr_ of an event @p e 155 | inline void QF_EVT_REF_CTR_DEC_(QEvt const * const e) noexcept { 156 | --(QF_EVT_CONST_CAST_(e))->refCtr_; 157 | } 158 | 159 | } // namespace QP 160 | 161 | //! macro to test that a pointer @p x_ is in range between @p min_ and @p max_ 162 | /// @description 163 | /// This macro is specifically and exclusively used for checking the range 164 | /// of a block pointer returned to the pool. Such a check must rely on the 165 | /// pointer arithmetic not compliant with the MISRA-C++:2008 rules ??? and 166 | /// ???. Defining a specific macro for this purpose allows to selectively 167 | /// disable the warnings for this particular case. 168 | #define QF_PTR_RANGE_(x_, min_, max_) (((min_) <= (x_)) && ((x_) <= (max_))) 169 | 170 | //! access element at index @p i_ from the base pointer @p base_ 171 | #define QF_PTR_AT_(base_, i_) (base_[i_]) 172 | 173 | #endif // QF_PKG_HPP 174 | -------------------------------------------------------------------------------- /src/qp-arduino/qf_port.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// @brief QF/C++ port to ARM Cortex-M, cooperative QV kernel, GNU-ARM toolset 3 | /// @cond 4 | ///*************************************************************************** 5 | /// Last updated for version 6.9.2 6 | /// Last updated on 2021-01-28 7 | /// 8 | /// Q u a n t u m L e a P s 9 | /// ------------------------ 10 | /// Modern Embedded Software 11 | /// 12 | /// Copyright (C) 2005-2021 Quantum Leaps. All rights reserved. 13 | /// 14 | /// This program is open source software: you can redistribute it and/or 15 | /// modify it under the terms of the GNU General Public License as published 16 | /// by the Free Software Foundation, either version 3 of the License, or 17 | /// (at your option) any later version. 18 | /// 19 | /// Alternatively, this program may be distributed and modified under the 20 | /// terms of Quantum Leaps commercial licenses, which expressly supersede 21 | /// the GNU General Public License and are specifically designed for 22 | /// licensees interested in retaining the proprietary status of their code. 23 | /// 24 | /// This program is distributed in the hope that it will be useful, 25 | /// but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 | /// GNU General Public License for more details. 28 | /// 29 | /// You should have received a copy of the GNU General Public License 30 | /// along with this program. If not, see . 31 | /// 32 | /// Contact information: 33 | /// 34 | /// 35 | ///*************************************************************************** 36 | /// @endcond 37 | 38 | #ifndef QF_PORT_HPP 39 | #define QF_PORT_HPP 40 | 41 | // The maximum number of system clock tick rates 42 | #define QF_MAX_TICK_RATE 2U 43 | 44 | // QF interrupt disable/enable and log2()... 45 | #if (__ARM_ARCH == 6) // Cortex-M0/M0+/M1(v6-M, v6S-M)? 46 | 47 | // The maximum number of active objects in the application, see NOTE1 48 | #define QF_MAX_ACTIVE 8U 49 | 50 | // Cortex-M0/M0+/M1(v6-M, v6S-M) interrupt disabling policy, see NOTE2 51 | #define QF_INT_DISABLE() __asm volatile ("cpsid i") 52 | #define QF_INT_ENABLE() __asm volatile ("cpsie i") 53 | 54 | // QF critical section entry/exit (unconditional interrupt disabling) 55 | //#define QF_CRIT_STAT_TYPE not defined 56 | #define QF_CRIT_ENTRY(dummy) QF_INT_DISABLE() 57 | #define QF_CRIT_EXIT(dummy) QF_INT_ENABLE() 58 | 59 | // CMSIS threshold for "QF-aware" interrupts, see NOTE2 and NOTE4 60 | #define QF_AWARE_ISR_CMSIS_PRI 0 61 | 62 | // hand-optimized LOG2 in assembly for Cortex-M0/M0+/M1(v6-M, v6S-M) 63 | #define QF_LOG2(n_) QF_qlog2((n_)) 64 | 65 | #else // Cortex-M3/M4/M7 66 | 67 | // The maximum number of active objects in the application, see NOTE1 68 | #define QF_MAX_ACTIVE 16U 69 | 70 | // Cortex-M3/M4/M7 alternative interrupt disabling with PRIMASK 71 | #define QF_PRIMASK_DISABLE() __asm volatile ("cpsid i") 72 | #define QF_PRIMASK_ENABLE() __asm volatile ("cpsie i") 73 | 74 | // Cortex-M3/M4/M7 interrupt disabling policy, see NOTE3 and NOTE4 75 | #define QF_INT_DISABLE() __asm volatile (\ 76 | "cpsid i\n" "msr BASEPRI,%0\n" "cpsie i" :: "r" (QF_BASEPRI) : ) 77 | #define QF_INT_ENABLE() __asm volatile (\ 78 | "msr BASEPRI,%0" :: "r" (0) : ) 79 | 80 | // QF critical section entry/exit (unconditional interrupt disabling) 81 | //#define QF_CRIT_STAT_TYPE not defined 82 | #define QF_CRIT_ENTRY(dummy) QF_INT_DISABLE() 83 | #define QF_CRIT_EXIT(dummy) QF_INT_ENABLE() 84 | 85 | // BASEPRI threshold for "QF-aware" interrupts, see NOTE3 86 | #define QF_BASEPRI 0x3F 87 | 88 | // CMSIS threshold for "QF-aware" interrupts, see NOTE5 89 | #define QF_AWARE_ISR_CMSIS_PRI (QF_BASEPRI >> (8 - __NVIC_PRIO_BITS)) 90 | 91 | // Cortex-M3/M4/M7 provide the CLZ instruction for fast LOG2 92 | #define QF_LOG2(n_) (static_cast( \ 93 | 32U - __builtin_clz(static_cast(n_)))) 94 | 95 | #endif 96 | 97 | #define QF_CRIT_EXIT_NOP() __asm volatile ("isb") 98 | 99 | #include "qep_port.hpp" // QEP port 100 | 101 | #if (__ARM_ARCH == 6) // Cortex-M0/M0+/M1(v6-M, v6S-M)? 102 | // hand-optimized quick LOG2 in assembly 103 | extern "C" uint_fast8_t QF_qlog2(uint32_t x); 104 | #endif // Cortex-M0/M0+/M1(v6-M, v6S-M) 105 | 106 | #include "qv_port.hpp" // QV port 107 | #include "qf.hpp" // QF platform-independent public interface 108 | #include "Arduino.h" // Main include file for the Arduino SDK 109 | 110 | //**************************************************************************** 111 | // NOTE1: 112 | // The maximum number of active objects QF_MAX_ACTIVE can be increased 113 | // up to 64, if necessary. Here it is set to a lower level to save some RAM. 114 | // 115 | // NOTE2: 116 | // On Cortex-M0/M0+/M1 (architecture v6-M, v6S-M), the interrupt disabling 117 | // policy uses the PRIMASK register to disable interrupts globally. The 118 | // QF_AWARE_ISR_CMSIS_PRI level is zero, meaning that all interrupts are 119 | // "QF-aware". 120 | // 121 | // NOTE3: 122 | // On Cortex-M3/M4/M7, the interrupt disable/enable policy uses the BASEPRI 123 | // register (which is not implemented in Cortex-M0/M0+/M1) to disable 124 | // interrupts only with priority lower than the threshold specified by the 125 | // QF_BASEPRI macro. The interrupts with priorities above QF_BASEPRI (i.e., 126 | // with numerical priority values lower than QF_BASEPRI) are NOT disabled in 127 | // this method. These free-running interrupts have very low ("zero") latency, 128 | // but they are not allowed to call any QF services, because QF is unaware 129 | // of them ("QF-unaware" interrutps). Consequently, only interrupts with 130 | // numerical values of priorities eqal to or higher than QF_BASEPRI 131 | // ("QF-aware" interrupts ), can call QF services. 132 | // 133 | // NOTE4: 134 | // The QF_AWARE_ISR_CMSIS_PRI macro is useful as an offset for enumerating 135 | // the "QF-aware" interrupt priorities in the applications, whereas the 136 | // numerical values of the "QF-aware" interrupts must be greater or equal to 137 | // QF_AWARE_ISR_CMSIS_PRI. The values based on QF_AWARE_ISR_CMSIS_PRI can be 138 | // passed directly to the CMSIS function NVIC_SetPriority(), which shifts 139 | // them by (8 - __NVIC_PRIO_BITS) into the correct bit position, while 140 | // __NVIC_PRIO_BITS is the CMSIS macro defining the number of implemented 141 | // priority bits in the NVIC. Please note that the macro QF_AWARE_ISR_CMSIS_PRI 142 | // is intended only for applications and is not used inside the QF port, which 143 | // remains generic and not dependent on the number of implemented priority bits 144 | // implemented in the NVIC. 145 | // 146 | // NOTE5: 147 | // The selective disabling of "QF-aware" interrupts with the BASEPRI register 148 | // has a problem on ARM Cortex-M7 core r0p1 (see SDEN-1068427, errata 149 | // 837070). The workaround recommended by ARM is to surround MSR BASEPRI with 150 | // the CPSID i/CPSIE i pair, which is implemented in the QF_INT_DISABLE() 151 | // macro. This workaround works also for Cortex-M3/M4 cores. 152 | // 153 | 154 | #endif // QF_PORT_HPP 155 | 156 | -------------------------------------------------------------------------------- /src/qp-arduino/qf_qact.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// @brief QP::QActive::QActive() definition 3 | /// @cond 4 | ///*************************************************************************** 5 | /// Last updated for version 6.8.0 6 | /// Last updated on 2020-01-13 7 | /// 8 | /// Q u a n t u m L e a P s 9 | /// ------------------------ 10 | /// Modern Embedded Software 11 | /// 12 | /// Copyright (C) 2005-2020 Quantum Leaps. All rights reserved. 13 | /// 14 | /// This program is open source software: you can redistribute it and/or 15 | /// modify it under the terms of the GNU General Public License as published 16 | /// by the Free Software Foundation, either version 3 of the License, or 17 | /// (at your option) any later version. 18 | /// 19 | /// Alternatively, this program may be distributed and modified under the 20 | /// terms of Quantum Leaps commercial licenses, which expressly supersede 21 | /// the GNU General Public License and are specifically designed for 22 | /// licensees interested in retaining the proprietary status of their code. 23 | /// 24 | /// This program is distributed in the hope that it will be useful, 25 | /// but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 | /// GNU General Public License for more details. 28 | /// 29 | /// You should have received a copy of the GNU General Public License 30 | /// along with this program. If not, see . 31 | /// 32 | /// Contact information: 33 | /// 34 | /// 35 | ///*************************************************************************** 36 | /// @endcond 37 | 38 | #define QP_IMPL // this is QP implementation 39 | #include "qf_port.hpp" // QF port 40 | 41 | namespace QP { 42 | 43 | //**************************************************************************** 44 | QActive::QActive(QStateHandler const initial) noexcept 45 | : QHsm(initial), 46 | m_prio(0U) 47 | { 48 | m_state.fun = Q_STATE_CAST(&QHsm::top); 49 | 50 | #ifdef QF_OS_OBJECT_TYPE 51 | QF::bzero(&m_osObject, sizeof(m_osObject)); 52 | #endif 53 | 54 | #ifdef QF_THREAD_TYPE 55 | QF::bzero(&m_thread, sizeof(m_thread)); 56 | #endif 57 | } 58 | 59 | } // namespace QP 60 | 61 | -------------------------------------------------------------------------------- /src/qp-arduino/qf_qmact.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// @brief QMActive::QMActive() and virtual functions 3 | /// @cond 4 | ///*************************************************************************** 5 | /// Last updated for version 6.9.2 6 | /// Last updated on 2020-12-17 7 | /// 8 | /// Q u a n t u m L e a P s 9 | /// ------------------------ 10 | /// Modern Embedded Software 11 | /// 12 | /// Copyright (C) 2005-2020 Quantum Leaps. All rights reserved. 13 | /// 14 | /// This program is open source software: you can redistribute it and/or 15 | /// modify it under the terms of the GNU General Public License as published 16 | /// by the Free Software Foundation, either version 3 of the License, or 17 | /// (at your option) any later version. 18 | /// 19 | /// Alternatively, this program may be distributed and modified under the 20 | /// terms of Quantum Leaps commercial licenses, which expressly supersede 21 | /// the GNU General Public License and are specifically designed for 22 | /// licensees interested in retaining the proprietary status of their code. 23 | /// 24 | /// This program is distributed in the hope that it will be useful, 25 | /// but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 | /// GNU General Public License for more details. 28 | /// 29 | /// You should have received a copy of the GNU General Public License 30 | /// along with this program. If not, see . 31 | /// 32 | /// Contact information: 33 | /// 34 | /// 35 | ///*************************************************************************** 36 | /// @endcond 37 | 38 | #define QP_IMPL // this is QP implementation 39 | #include "qf_port.hpp" // QF port 40 | #include "qassert.h" // QP embedded systems-friendly assertions 41 | 42 | //! Internal macro to cast a QP::QMActive pointer @p qact_ to QP::QMsm* 43 | /// @note 44 | /// Casting pointer to pointer pointer violates the MISRA-C++ 2008 Rule 5-2-7, 45 | /// cast from pointer to pointer. Additionally this cast violates the MISRA- 46 | /// C++ 2008 Rule 5-2-8 Unusual pointer cast (incompatible indirect types). 47 | /// Encapsulating these violations in a macro allows to selectively suppress 48 | /// this specific deviation. 49 | #define QF_QMACTIVE_TO_QMSM_CAST_(qact_) \ 50 | reinterpret_cast((qact_)) 51 | 52 | //! Internal macro to cast a QP::QMActive pointer @p qact_ to QP::QMsm const * 53 | #define QF_QMACTIVE_TO_QMSM_CONST_CAST_(qact_) \ 54 | reinterpret_cast((qact_)) 55 | 56 | namespace QP { 57 | 58 | //Q_DEFINE_THIS_MODULE("qf_qmact") 59 | 60 | //............................................................................ 61 | QMActive::QMActive(QStateHandler const initial) noexcept 62 | : QActive(initial) 63 | { 64 | m_temp.fun = initial; 65 | } 66 | 67 | //............................................................................ 68 | void QMActive::init(void const * const e, std::uint_fast8_t const qs_id) { 69 | m_state.obj = &QMsm::msm_top_s; 70 | QF_QMACTIVE_TO_QMSM_CAST_(this)->QMsm::init(e, qs_id); 71 | } 72 | //............................................................................ 73 | void QMActive::init(std::uint_fast8_t const qs_id) { 74 | QF_QMACTIVE_TO_QMSM_CAST_(this)->QMsm::init(qs_id); 75 | } 76 | //............................................................................ 77 | void QMActive::dispatch(QEvt const * const e, std::uint_fast8_t const qs_id) { 78 | QF_QMACTIVE_TO_QMSM_CAST_(this)->QMsm::dispatch(e, qs_id); 79 | } 80 | 81 | //............................................................................ 82 | bool QMActive::isInState(QMState const * const st) const noexcept { 83 | return QF_QMACTIVE_TO_QMSM_CONST_CAST_(this)->QMsm::isInState(st); 84 | } 85 | //............................................................................ 86 | QMState const *QMActive::childStateObj(QMState const * const parent) 87 | const noexcept 88 | { 89 | return QF_QMACTIVE_TO_QMSM_CONST_CAST_(this)->QMsm::childStateObj(parent); 90 | } 91 | 92 | //............................................................................ 93 | #ifdef Q_SPY 94 | QStateHandler QMActive::getStateHandler() noexcept { 95 | return QF_QMACTIVE_TO_QMSM_CAST_(this)->QMsm::getStateHandler(); 96 | } 97 | #endif 98 | 99 | } // namespace QP 100 | 101 | -------------------------------------------------------------------------------- /src/qp-arduino/qmpool.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// @brief platform-independent memory pool QP::QMPool interface. 3 | /// @ingroup qf 4 | /// @cond 5 | ///*************************************************************************** 6 | /// Last updated for version 6.9.1 7 | /// Last updated on 2020-09-14 8 | /// 9 | /// Q u a n t u m L e a P s 10 | /// ------------------------ 11 | /// Modern Embedded Software 12 | /// 13 | /// Copyright (C) 2005-2020 Quantum Leaps. All rights reserved. 14 | /// 15 | /// This program is open source software: you can redistribute it and/or 16 | /// modify it under the terms of the GNU General Public License as published 17 | /// by the Free Software Foundation, either version 3 of the License, or 18 | /// (at your option) any later version. 19 | /// 20 | /// Alternatively, this program may be distributed and modified under the 21 | /// terms of Quantum Leaps commercial licenses, which expressly supersede 22 | /// the GNU General Public License and are specifically designed for 23 | /// licensees interested in retaining the proprietary status of their code. 24 | /// 25 | /// This program is distributed in the hope that it will be useful, 26 | /// but WITHOUT ANY WARRANTY; without even the implied warranty of 27 | /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 | /// GNU General Public License for more details. 29 | /// 30 | /// You should have received a copy of the GNU General Public License 31 | /// along with this program. If not, see . 32 | /// 33 | /// Contact information: 34 | /// 35 | /// 36 | ///*************************************************************************** 37 | /// @endcond 38 | 39 | #ifndef QMPOOL_HPP 40 | #define QMPOOL_HPP 41 | 42 | #ifndef QF_MPOOL_SIZ_SIZE 43 | //! macro to override the default QP::QMPoolSize size. 44 | /// Valid values 1U, 2U, or 4U; default 2U 45 | #define QF_MPOOL_SIZ_SIZE 2U 46 | #endif 47 | 48 | #ifndef QF_MPOOL_CTR_SIZE 49 | //! macro to override the default QMPoolCtr size. 50 | //! Valid values 1U, 2U, or 4U; default 2U 51 | #define QF_MPOOL_CTR_SIZE 2 52 | #endif 53 | 54 | namespace QP { 55 | #if (QF_MPOOL_SIZ_SIZE == 1U) 56 | using QMPoolSize = std::uint8_t; 57 | #elif (QF_MPOOL_SIZ_SIZE == 2U) 58 | //! The data type to store the block-size based on the macro 59 | //! #QF_MPOOL_SIZ_SIZE. 60 | /// @description 61 | /// The dynamic range of this data type determines the maximum size 62 | /// of blocks that can be managed by the native QF event pool. 63 | using QMPoolSize = std::uint16_t; 64 | #elif (QF_MPOOL_SIZ_SIZE == 4U) 65 | using QMPoolSize = std::uint32_t; 66 | #else 67 | #error "QF_MPOOL_SIZ_SIZE defined incorrectly, expected 1U, 2U, or 4U" 68 | #endif 69 | 70 | #if (QF_MPOOL_CTR_SIZE == 1U) 71 | using QMPoolCtr = std::uint8_t; 72 | #elif (QF_MPOOL_CTR_SIZE == 2U) 73 | //! The data type to store the block-counter based on the macro 74 | //! #QF_MPOOL_CTR_SIZE. 75 | /// @description 76 | /// The dynamic range of this data type determines the maximum number 77 | /// of blocks that can be stored in the pool. 78 | using QMPoolCtr = std::uint16_t; 79 | #elif (QF_MPOOL_CTR_SIZE == 4U) 80 | using QMPoolCtr = std::uint32_t; 81 | #else 82 | #error "QF_MPOOL_CTR_SIZE defined incorrectly, expected 1U, 2U, or 4U" 83 | #endif 84 | 85 | //**************************************************************************** 86 | //! Native QF memory pool class 87 | /// @description 88 | /// A fixed block-size memory pool is a very fast and efficient data 89 | /// structure for dynamic allocation of fixed block-size chunks of memory. 90 | /// A memory pool offers fast and deterministic allocation and recycling of 91 | /// memory blocks and is not subject to fragmenation.@n 92 | /// @n 93 | /// The QP::QMPool class describes the native QF memory pool, which can be 94 | /// used as the event pool for dynamic event allocation, or as a fast, 95 | /// deterministic fixed block-size heap for any other objects in your 96 | /// application. 97 | /// 98 | /// @note 99 | /// The QP::QMPool class contains only data members for managing a memory 100 | /// pool, but does not contain the pool storage, which must be provided 101 | /// externally during the pool initialization. 102 | /// 103 | /// @note 104 | /// The native QF event pool is configured by defining the macro 105 | /// #QF_EPOOL_TYPE_ as QP::QMPool in the specific QF port header file. 106 | class QMPool { 107 | private: 108 | 109 | //! start of the memory managed by this memory pool 110 | void *m_start; 111 | 112 | //! end of the memory managed by this memory pool 113 | void *m_end; 114 | 115 | //! head of linked list of free blocks 116 | void * volatile m_free_head; 117 | 118 | //! maximum block size (in bytes) 119 | QMPoolSize m_blockSize; 120 | 121 | //! total number of blocks 122 | QMPoolCtr m_nTot; 123 | 124 | //! number of free blocks remaining 125 | QMPoolCtr volatile m_nFree; 126 | 127 | //! minimum number of free blocks ever present in this pool 128 | /// @note 129 | /// This attribute remembers the low watermark of the pool, 130 | /// which provides a valuable information for sizing event pools. 131 | /// 132 | /// @sa QP::QF::getPoolMin(). 133 | QMPoolCtr m_nMin; 134 | 135 | public: 136 | QMPool(void); //!< public default constructor 137 | 138 | //! Initializes the native QF event pool 139 | void init(void * const poolSto, std::uint_fast32_t poolSize, 140 | std::uint_fast16_t blockSize) noexcept; 141 | 142 | //! Obtains a memory block from a memory pool. 143 | void *get(std::uint_fast16_t const margin, 144 | std::uint_fast8_t const qs_id) noexcept; 145 | 146 | //! Returns a memory block back to a memory pool. 147 | void put(void * const b, std::uint_fast8_t const qs_id) noexcept; 148 | 149 | //! return the fixed block-size of the blocks managed by this pool 150 | QMPoolSize getBlockSize(void) const noexcept { 151 | return m_blockSize; 152 | } 153 | 154 | // duplicated API to be used exclusively inside ISRs (useful in some QP ports) 155 | #ifdef QF_ISR_API 156 | void *getFromISR(std::uint_fast16_t const margin, 157 | std::uint_fast8_t const qs_id) noexcept; 158 | void putFromISR(void * const b, 159 | std::uint_fast8_t const qs_id) noexcept; 160 | #endif // QF_ISR_API 161 | 162 | private: 163 | //! disallow copying of QMPools 164 | QMPool(QMPool const &) = delete; 165 | 166 | //!< disallow assigning of QMPools 167 | QMPool &operator=(QMPool const &) = delete; 168 | 169 | friend class QF; 170 | friend class QS; 171 | }; 172 | 173 | } // namespace QP 174 | 175 | //! Memory pool element to allocate correctly aligned storage for QP::QMPool 176 | #define QF_MPOOL_EL(type_) \ 177 | struct { void *sto_[((sizeof(type_) - 1U)/sizeof(void*)) + 1U]; } 178 | 179 | #endif // QMPOOL_HPP 180 | 181 | -------------------------------------------------------------------------------- /src/qp-arduino/qpset.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// @brief platform-independent priority sets of 8 or 64 elements. 3 | /// @ingroup qf 4 | /// @cond 5 | ///*************************************************************************** 6 | /// Last updated for version 6.8.2 7 | /// Last updated on 2020-07-18 8 | /// 9 | /// Q u a n t u m L e a P s 10 | /// ------------------------ 11 | /// Modern Embedded Software 12 | /// 13 | /// Copyright (C) 2005-2019 Quantum Leaps. All rights reserved. 14 | /// 15 | /// This program is open source software: you can redistribute it and/or 16 | /// modify it under the terms of the GNU General Public License as published 17 | /// by the Free Software Foundation, either version 3 of the License, or 18 | /// (at your option) any later version. 19 | /// 20 | /// Alternatively, this program may be distributed and modified under the 21 | /// terms of Quantum Leaps commercial licenses, which expressly supersede 22 | /// the GNU General Public License and are specifically designed for 23 | /// licensees interested in retaining the proprietary status of their code. 24 | /// 25 | /// This program is distributed in the hope that it will be useful, 26 | /// but WITHOUT ANY WARRANTY; without even the implied warranty of 27 | /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 | /// GNU General Public License for more details. 29 | /// 30 | /// You should have received a copy of the GNU General Public License 31 | /// along with this program. If not, see . 32 | /// 33 | /// Contact information: 34 | /// 35 | /// 36 | ///*************************************************************************** 37 | /// @endcond 38 | 39 | #ifndef QPSET_HPP 40 | #define QPSET_HPP 41 | 42 | #ifndef QF_MAX_ACTIVE 43 | // default value when NOT defined 44 | #define QF_MAX_ACTIVE 32U 45 | #endif 46 | 47 | namespace QP { 48 | 49 | #if (QF_MAX_ACTIVE < 1U) || (64U < QF_MAX_ACTIVE) 50 | #error "QF_MAX_ACTIVE out of range. Valid range is 1U..64U" 51 | #elif (QF_MAX_ACTIVE <= 8U) 52 | using QPSetBits = std::uint8_t; 53 | #elif (QF_MAX_ACTIVE <= 16U) 54 | using QPSetBits = std::uint16_t; 55 | #else 56 | //! bitmask for the internal representation of QPSet elements 57 | using QPSetBits = std::uint32_t; 58 | #endif 59 | 60 | //**************************************************************************** 61 | // Log-base-2 calculations ... 62 | #ifndef QF_LOG2 63 | extern "C" std::uint_fast8_t QF_LOG2(QPSetBits x) noexcept; 64 | #endif // QF_LOG2 65 | 66 | //**************************************************************************** 67 | #if (QF_MAX_ACTIVE <= 32) 68 | //! Priority Set of up to 32 elements */ 69 | /// 70 | /// The priority set represents the set of active objects that are ready to 71 | /// run and need to be considered by the scheduling algorithm. The set is 72 | /// capable of storing up to 32 priority levels. QP::QPSet is specifically 73 | /// declared as a POD (Plain Old Data) for ease of initialization and 74 | /// interfacing with plain "C" code. 75 | /// 76 | struct QPSet { 77 | 78 | QPSetBits volatile m_bits; //!< bitmask with a bit for each element 79 | 80 | //! Makes the priority set @p me_ empty. 81 | void setEmpty(void) noexcept { 82 | m_bits = 0U; 83 | } 84 | 85 | //! Evaluates to true if the priority set is empty 86 | bool isEmpty(void) const noexcept { 87 | return (m_bits == 0U); 88 | } 89 | 90 | //! Evaluates to true if the priority set is not empty 91 | bool notEmpty(void) const noexcept { 92 | return (m_bits != 0U); 93 | } 94 | 95 | //! the function evaluates to TRUE if the priority set has the element n. 96 | bool hasElement(std::uint_fast8_t const n) const noexcept { 97 | return (m_bits & (1U << (n - 1U))) != 0U; 98 | } 99 | 100 | //! insert element @p n into the set, n = 1..QF_MAX_ACTIVE 101 | void insert(std::uint_fast8_t const n) noexcept { 102 | m_bits |= (1U << (n - 1U)); 103 | } 104 | 105 | //! remove element @p n from the set, n = 1..QF_MAX_ACTIVE 106 | /// @note 107 | /// intentionally misspelled ("rmove") to avoid collision with 108 | /// the C++ standard library facility "remove" 109 | void rmove(std::uint_fast8_t const n) noexcept { 110 | m_bits &= 111 | static_cast(~(static_cast(1) << (n - 1U))); 112 | } 113 | 114 | std::uint_fast8_t findMax(void) const noexcept { 115 | return QF_LOG2(m_bits); 116 | } 117 | }; 118 | 119 | #else // QF_MAX_ACTIVE > 32U 120 | 121 | //! Priority Set of up to 64 elements 122 | /// 123 | /// The priority set represents the set of active objects that are ready to 124 | /// run and need to be considered by the scheduling algorithm. The set is 125 | /// capable of storing up to 64 priority levels. QP::QPSet is specifically 126 | /// declared as a POD (Plain Old Data) for ease of initialization and 127 | /// interfacing with plain "C" code. 128 | /// 129 | struct QPSet { 130 | 131 | //! Two 32-bit bitmasks with a bit for each element 132 | std::uint32_t volatile m_bits[2]; 133 | 134 | //! Makes the priority set @p me_ empty. 135 | void setEmpty(void) noexcept { 136 | m_bits[0] = 0U; 137 | m_bits[1] = 0U; 138 | } 139 | 140 | //! Evaluates to true if the priority set is empty 141 | // the following logic avoids UB in volatile access for MISRA compliantce 142 | bool isEmpty(void) const noexcept { 143 | return (m_bits[0] == 0U) ? (m_bits[1] == 0U) : false; 144 | } 145 | 146 | //! Evaluates to true if the priority set is not empty 147 | // the following logic avoids UB in volatile access for MISRA compliantce 148 | bool notEmpty(void) const noexcept { 149 | return (m_bits[0] != 0U) ? true : (m_bits[1] != 0U); 150 | } 151 | 152 | //! the function evaluates to TRUE if the priority set has the element n. 153 | bool hasElement(std::uint_fast8_t const n) const noexcept { 154 | return (n <= 32U) 155 | ? ((m_bits[0] & (static_cast(1) << (n - 1U))) 156 | != 0U) 157 | : ((m_bits[1] & (static_cast(1) << (n - 33U))) 158 | != 0U); 159 | } 160 | 161 | //! insert element @p n into the set, n = 1..64 162 | void insert(std::uint_fast8_t const n) noexcept { 163 | if (n <= 32U) { 164 | m_bits[0] |= (static_cast(1) << (n - 1U)); 165 | } 166 | else { 167 | m_bits[1] |= (static_cast(1) << (n - 33U)); 168 | } 169 | } 170 | 171 | //! remove element @p n from the set, n = 1..64 172 | /// @note 173 | /// intentionally misspelled ("rmove") to avoid collision with 174 | /// the C++ standard library facility "remove" 175 | void rmove(std::uint_fast8_t const n) noexcept { 176 | if (n <= 32U) { 177 | (m_bits[0] &= ~(static_cast(1) << (n - 1U))); 178 | } 179 | else { 180 | (m_bits[1] &= ~(static_cast(1) << (n - 33U))); 181 | } 182 | } 183 | 184 | //! find the maximum element in the set, returns zero if the set is empty 185 | std::uint_fast8_t findMax(void) const noexcept { 186 | return (m_bits[1] != 0U) 187 | ? (QF_LOG2(m_bits[1]) + 32U) 188 | : (QF_LOG2(m_bits[0])); 189 | } 190 | }; 191 | 192 | #endif // QF_MAX_ACTIVE 193 | 194 | } // namespace QP 195 | 196 | #endif // QPSET_HPP 197 | 198 | -------------------------------------------------------------------------------- /src/qp-arduino/qs_dummy.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// @brief Dummy definitions of the QS macros that avoid code generation from 3 | /// the QS instrumentation. 4 | /// @ingroup qs qpspy 5 | /// @cond 6 | ///*************************************************************************** 7 | /// Last updated for version 6.9.1 8 | /// Last updated on 2020-09-30 9 | /// 10 | /// Q u a n t u m L e a P s 11 | /// ------------------------ 12 | /// Modern Embedded Software 13 | /// 14 | /// Copyright (C) 2005-2020 Quantum Leaps. All rights reserved. 15 | /// 16 | /// This program is open source software: you can redistribute it and/or 17 | /// modify it under the terms of the GNU General Public License as published 18 | /// by the Free Software Foundation, either version 3 of the License, or 19 | /// (at your option) any later version. 20 | /// 21 | /// Alternatively, this program may be distributed and modified under the 22 | /// terms of Quantum Leaps commercial licenses, which expressly supersede 23 | /// the GNU General Public License and are specifically designed for 24 | /// licensees interested in retaining the proprietary status of their code. 25 | /// 26 | /// This program is distributed in the hope that it will be useful, 27 | /// but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | /// GNU General Public License for more details. 30 | /// 31 | /// You should have received a copy of the GNU General Public License 32 | /// along with this program. If not, see . 33 | /// 34 | /// Contact information: 35 | /// 36 | /// 37 | ///*************************************************************************** 38 | /// @endcond 39 | 40 | #ifndef QS_DUMMY_HPP 41 | #define QS_DUMMY_HPP 42 | 43 | #ifdef Q_SPY 44 | #error "Q_SPY must NOT be defined to include qs_dummy.hpp" 45 | #endif 46 | 47 | #define QS_INIT(arg_) (true) 48 | #define QS_EXIT() static_cast(0) 49 | #define QS_DUMP() static_cast(0) 50 | #define QS_GLB_FILTER(rec_) static_cast(0) 51 | #define QS_LOC_FILTER(qs_id_) static_cast(0) 52 | 53 | #define QS_GET_BYTE(pByte_) (0xFFFFU) 54 | #define QS_GET_BLOCK(pSize_) (nullptr) 55 | 56 | #define QS_BEGIN_ID(rec_, qs_id_) if (false) { 57 | #define QS_END() } 58 | #define QS_BEGIN_NOCRIT(rec_, qs_id_) if (false) { 59 | #define QS_END_NOCRIT() } 60 | 61 | #define QS_I8(width_, data_) static_cast(0) 62 | #define QS_U8(width_, data_) static_cast(0) 63 | #define QS_I16(width_, data_) static_cast(0) 64 | #define QS_U16(width_, data_) static_cast(0) 65 | #define QS_I32(width_, data_) static_cast(0) 66 | #define QS_U32(width_, data_) static_cast(0) 67 | #define QS_F32(width_, data_) static_cast(0) 68 | #define QS_F64(width_, data_) static_cast(0) 69 | #define QS_U64(width_, data_) static_cast(0) 70 | #define QS_STR(str_) static_cast(0) 71 | #define QS_MEM(mem_, size_) static_cast(0) 72 | #define QS_SIG(sig_, obj_) static_cast(0) 73 | #define QS_OBJ(obj_) static_cast(0) 74 | #define QS_FUN(fun_) static_cast(0) 75 | 76 | #define QS_SIG_DICTIONARY(sig_, obj_) static_cast(0) 77 | #define QS_OBJ_DICTIONARY(obj_) static_cast(0) 78 | #define QS_FUN_DICTIONARY(fun_) static_cast(0) 79 | #define QS_USR_DICTIONARY(rec_) static_cast(0) 80 | #define QS_ASSERTION(module_, loc_, delay_) static_cast(0) 81 | #define QS_FLUSH() static_cast(0) 82 | 83 | #define QS_TEST_PROBE_DEF(fun_) 84 | #define QS_TEST_PROBE(code_) 85 | #define QS_TEST_PROBE_ID(id_, code_) 86 | #define QS_TEST_PAUSE() static_cast(0) 87 | 88 | #define QS_OUTPUT() static_cast(0) 89 | #define QS_RX_INPUT() static_cast(0) 90 | 91 | //**************************************************************************** 92 | // internal QS macros used only in the QP components 93 | 94 | #ifdef QP_IMPL 95 | // predefined QS trace records 96 | #define QS_BEGIN_PRE_(rec_, qs_id_) if (false) { 97 | #define QS_END_PRE_() } 98 | #define QS_BEGIN_NOCRIT_PRE_(rec_, qs_id_) if (false) { 99 | #define QS_END_NOCRIT_PRE_() } 100 | #define QS_U8_PRE_(data_) static_cast(0) 101 | #define QS_2U8_PRE_(data1_, data2_) static_cast(0) 102 | #define QS_U16_PRE_(data_) static_cast(0) 103 | #define QS_U32_PRE_(data_) static_cast(0) 104 | #define QS_TIME_PRE_() static_cast(0) 105 | #define QS_SIG_PRE_(sig_) static_cast(0) 106 | #define QS_EVS_PRE_(size_) static_cast(0) 107 | #define QS_OBJ_PRE_(obj_) static_cast(0) 108 | #define QS_FUN_PRE_(fun_) static_cast(0) 109 | #define QS_EQC_PRE_(ctr_) static_cast(0) 110 | #define QS_MPC_PRE_(ctr_) static_cast(0) 111 | #define QS_MPS_PRE_(size_) static_cast(0) 112 | #define QS_TEC_PRE_(ctr_) static_cast(0) 113 | 114 | #define QS_CRIT_STAT_ 115 | #define QF_QS_CRIT_ENTRY() static_cast(0) 116 | #define QF_QS_CRIT_EXIT() static_cast(0) 117 | #define QF_QS_ISR_ENTRY(isrnest_, prio_) static_cast(0) 118 | #define QF_QS_ISR_EXIT(isrnest_, prio_) static_cast(0) 119 | #define QF_QS_ACTION(act_) static_cast(0) 120 | #endif // QP_IMPL 121 | 122 | #endif // QS_DUMMY_HPP 123 | 124 | -------------------------------------------------------------------------------- /src/qp-arduino/qs_fp.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// @brief QS floating point output implementation 3 | /// @ingroup qs 4 | /// @cond 5 | ///*************************************************************************** 6 | /// Last updated for version 6.9.2 7 | /// Last updated on 2021-01-13 8 | /// 9 | /// Q u a n t u m L e a P s 10 | /// ------------------------ 11 | /// Modern Embedded Software 12 | /// 13 | /// Copyright (C) 2005-2021 Quantum Leaps. All rights reserved. 14 | /// 15 | /// This program is open source software: you can redistribute it and/or 16 | /// modify it under the terms of the GNU General Public License as published 17 | /// by the Free Software Foundation, either version 3 of the License, or 18 | /// (at your option) any later version. 19 | /// 20 | /// Alternatively, this program may be distributed and modified under the 21 | /// terms of Quantum Leaps commercial licenses, which expressly supersede 22 | /// the GNU General Public License and are specifically designed for 23 | /// licensees interested in retaining the proprietary status of their code. 24 | /// 25 | /// This program is distributed in the hope that it will be useful, 26 | /// but WITHOUT ANY WARRANTY; without even the implied warranty of 27 | /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 | /// GNU General Public License for more details. 29 | /// 30 | /// You should have received a copy of the GNU General Public License 31 | /// along with this program. If not, see . 32 | /// 33 | /// Contact information: 34 | /// 35 | /// 36 | ///*************************************************************************** 37 | /// @endcond 38 | 39 | #define QP_IMPL // this is QF/QK implementation 40 | #include "qs_port.hpp" // QS port 41 | #include "qs_pkg.hpp" // QS package-scope internal interface 42 | 43 | namespace QP { 44 | 45 | //**************************************************************************** 46 | /// @note This function is only to be used through macros, never in the 47 | /// client code directly. 48 | /// 49 | void QS::f32_fmt_(std::uint8_t format, float32_t const d) noexcept { 50 | union F32Rep { 51 | float32_t f; 52 | std::uint32_t u; 53 | } fu32; // the internal binary representation 54 | std::uint8_t chksum_ = priv_.chksum; // put in a temporary (register) 55 | std::uint8_t * const buf_ = priv_.buf; // put in a temporary (register) 56 | QSCtr head_ = priv_.head; // put in a temporary (register) 57 | QSCtr const end_ = priv_.end; // put in a temporary (register) 58 | 59 | fu32.f = d; // assign the binary representation 60 | 61 | priv_.used += 5U; // 5 bytes about to be added 62 | QS_INSERT_ESC_BYTE_(format) // insert the format byte 63 | 64 | for (std::uint_fast8_t i = 4U; i != 0U; --i) { 65 | format = static_cast(fu32.u); 66 | QS_INSERT_ESC_BYTE_(format) 67 | fu32.u >>= 8U; 68 | } 69 | 70 | priv_.head = head_; // save the head 71 | priv_.chksum = chksum_; // save the checksum 72 | } 73 | 74 | //**************************************************************************** 75 | /// @note This function is only to be used through macros, never in the 76 | /// client code directly. 77 | /// 78 | void QS::f64_fmt_(std::uint8_t format, float64_t const d) noexcept { 79 | union F64Rep { 80 | float64_t d; 81 | std::uint32_t u[2]; 82 | } fu64; // the internal binary representation 83 | std::uint8_t chksum_ = priv_.chksum; 84 | std::uint8_t * const buf_ = priv_.buf; 85 | QSCtr head_ = priv_.head; 86 | QSCtr const end_ = priv_.end; 87 | std::uint32_t i; 88 | // static constant untion to detect endianness of the machine 89 | static union U32Rep { 90 | std::uint32_t u32; 91 | std::uint8_t u8; 92 | } const endian = { 1U }; 93 | 94 | fu64.d = d; // assign the binary representation 95 | 96 | // is this a big-endian machine? 97 | if (endian.u8 == 0U) { 98 | // swap fu64.u[0] <-> fu64.u[1]... 99 | i = fu64.u[0]; 100 | fu64.u[0] = fu64.u[1]; 101 | fu64.u[1] = i; 102 | } 103 | 104 | priv_.used += 9U; // 9 bytes about to be added 105 | QS_INSERT_ESC_BYTE_(format) // insert the format byte 106 | 107 | // output 4 bytes from fu64.u[0]... 108 | for (i = 4U; i != 0U; --i) { 109 | QS_INSERT_ESC_BYTE_(static_cast(fu64.u[0])) 110 | fu64.u[0] >>= 8U; 111 | } 112 | 113 | // output 4 bytes from fu64.u[1]... 114 | for (i = 4U; i != 0U; --i) { 115 | QS_INSERT_ESC_BYTE_(static_cast(fu64.u[1])) 116 | fu64.u[1] >>= 8U; 117 | } 118 | 119 | priv_.head = head_; // update the head 120 | priv_.chksum = chksum_; // update the checksum 121 | } 122 | 123 | } // namespace QP 124 | 125 | -------------------------------------------------------------------------------- /src/qp-arduino/qs_port.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// @brief QS/C++ port to ARM Cortex-M, generic compiler 3 | /// @cond 4 | ///*************************************************************************** 5 | /// Last updated for version 6.6.0 6 | /// Last updated on 2019-07-30 7 | /// 8 | /// Q u a n t u m L e a P s 9 | /// ------------------------ 10 | /// Modern Embedded Software 11 | /// 12 | /// Copyright (C) 2005-2019 Quantum Leaps. All rights reserved. 13 | /// 14 | /// This program is open source software: you can redistribute it and/or 15 | /// modify it under the terms of the GNU General Public License as published 16 | /// by the Free Software Foundation, either version 3 of the License, or 17 | /// (at your option) any later version. 18 | /// 19 | /// Alternatively, this program may be distributed and modified under the 20 | /// terms of Quantum Leaps commercial licenses, which expressly supersede 21 | /// the GNU General Public License and are specifically designed for 22 | /// licensees interested in retaining the proprietary status of their code. 23 | /// 24 | /// This program is distributed in the hope that it will be useful, 25 | /// but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 | /// GNU General Public License for more details. 28 | /// 29 | /// You should have received a copy of the GNU General Public License 30 | /// along with this program. If not, see . 31 | /// 32 | /// Contact information: 33 | /// 34 | /// 35 | ///*************************************************************************** 36 | /// @endcond 37 | 38 | #ifndef QS_PORT_HPP 39 | #define QS_PORT_HPP 40 | 41 | // QS time-stamp size in bytes 42 | #define QS_TIME_SIZE 4U 43 | 44 | // object pointer size in bytes 45 | #define QS_OBJ_PTR_SIZE 4U 46 | 47 | // function pointer size in bytes 48 | #define QS_FUN_PTR_SIZE 4U 49 | 50 | //**************************************************************************** 51 | // NOTE: QS might be used with or without other QP components, in which case 52 | // the separate definitions of the macros QF_CRIT_STAT_TYPE, QF_CRIT_ENTRY, 53 | // and QF_CRIT_EXIT are needed. In this port QS is configured to be used with 54 | // the other QP component, by simply including "qf_port.hpp" *before* "qs.hpp". 55 | // 56 | #include "qf_port.hpp" // use QS with QF 57 | #include "qs.hpp" // QS platform-independent public interface 58 | 59 | #endif // QS_PORT_HPP 60 | -------------------------------------------------------------------------------- /src/qp-arduino/qstamp.cpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// @brief Application build time-stamp 3 | /// @note 4 | /// This module needs to be re-compiled in every new software build. To achive 5 | /// this, it is recommended to delete the object file (qstamp.o or qstamp.obj) 6 | /// in the build directory before each build. (Most development tools allow 7 | /// you to specify a pre-build action, which is the ideal place to delete 8 | /// the qstamp object file.) 9 | 10 | #include "qstamp.hpp" 11 | 12 | namespace QP { 13 | 14 | //! the calendar date of the last translation of the form: "Mmm dd yyyy" 15 | char const BUILD_DATE[12] = __DATE__; 16 | 17 | //! the time of the last translation of the form: "hh:mm:ss" 18 | char const BUILD_TIME[9] = __TIME__; 19 | 20 | } // namespace QP 21 | 22 | -------------------------------------------------------------------------------- /src/qp-arduino/qstamp.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// @brief Application build time-stamp interface 3 | 4 | #ifndef QSTAMP_HPP 5 | #define QSTAMP_HPP 6 | 7 | namespace QP { 8 | 9 | extern char const BUILD_DATE[12]; 10 | extern char const BUILD_TIME[9]; 11 | 12 | } // namespace QP 13 | 14 | #endif // QSTAMP 15 | 16 | -------------------------------------------------------------------------------- /src/qp-arduino/qv.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// @brief QV/C++ platform-independent public interface. 3 | /// @ingroup qv 4 | /// @cond 5 | ///*************************************************************************** 6 | /// Last updated for version 6.9.1 7 | /// Last updated on 2020-09-15 8 | /// 9 | /// Q u a n t u m L e a P s 10 | /// ------------------------ 11 | /// Modern Embedded Software 12 | /// 13 | /// Copyright (C) 2005-2020 Quantum Leaps. All rights reserved. 14 | /// 15 | /// This program is open source software: you can redistribute it and/or 16 | /// modify it under the terms of the GNU General Public License as published 17 | /// by the Free Software Foundation, either version 3 of the License, or 18 | /// (at your option) any later version. 19 | /// 20 | /// Alternatively, this program may be distributed and modified under the 21 | /// terms of Quantum Leaps commercial licenses, which expressly supersede 22 | /// the GNU General Public License and are specifically designed for 23 | /// licensees interested in retaining the proprietary status of their code. 24 | /// 25 | /// This program is distributed in the hope that it will be useful, 26 | /// but WITHOUT ANY WARRANTY; without even the implied warranty of 27 | /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 | /// GNU General Public License for more details. 29 | /// 30 | /// You should have received a copy of the GNU General Public License 31 | /// along with this program. If not, see . 32 | /// 33 | /// Contact information: 34 | /// 35 | /// 36 | ///*************************************************************************** 37 | /// @endcond 38 | 39 | #ifndef QV_HPP 40 | #define QV_HPP 41 | 42 | #include "qequeue.hpp" // QV kernel uses the native QF event queue 43 | #include "qmpool.hpp" // QV kernel uses the native QF memory pool 44 | #include "qpset.hpp" // QV kernel uses the native QF priority set 45 | 46 | //**************************************************************************** 47 | // QF configuration for QK 48 | 49 | // QV event-queue used for AOs 50 | #define QF_EQUEUE_TYPE QEQueue 51 | 52 | 53 | //**************************************************************************** 54 | namespace QP { 55 | 56 | //! QV services. 57 | /// @description 58 | /// This class groups together QV services. It has only static members and 59 | /// should not be instantiated. 60 | /// 61 | // @note The QV ready set, etc. belong conceptually to the QV class (as static 62 | /// class members). However, to avoid C++ potential name-mangling problems in 63 | /// assembly language, these elements are defined outside of the QK class and 64 | /// use the extern "C" linkage specification. 65 | class QV { 66 | public: 67 | 68 | //! QV idle callback (customized in BSPs for QK) 69 | /// @description 70 | /// QV::onIdle() must be called with interrupts DISABLED because 71 | /// the determination of the idle condition (no events in the 72 | /// queues) can change at any time by an interrupt posting events 73 | /// to a queue. QV::onIdle() MUST enable interrupts internally, 74 | /// perhaps at the same time as putting the CPU into a power-saving 75 | /// mode. 76 | /// 77 | /// @sa QP::QK::onIdle() 78 | static void onIdle(void); 79 | }; 80 | 81 | } // namespace QP 82 | 83 | //**************************************************************************** 84 | extern "C" { 85 | extern QP::QPSet QV_readySet_; //!< ready set of AOs 86 | } // extern "C" 87 | 88 | //**************************************************************************** 89 | // interface used only inside QF, but not in applications 90 | 91 | #ifdef QP_IMPL 92 | 93 | // QV-specific scheduler locking (not needed in QV) 94 | #define QF_SCHED_STAT_ 95 | #define QF_SCHED_LOCK_(dummy) (static_cast(0)) 96 | #define QF_SCHED_UNLOCK_() (static_cast(0)) 97 | 98 | // QV-specific native event queue operations... 99 | #define QACTIVE_EQUEUE_WAIT_(me_) \ 100 | Q_ASSERT_ID(110, (me_)->m_eQueue.m_frontEvt != nullptr) 101 | #define QACTIVE_EQUEUE_SIGNAL_(me_) \ 102 | (QV_readySet_.insert(static_cast((me_)->m_prio))) 103 | 104 | // QV-specific native QF event pool operations... 105 | #define QF_EPOOL_TYPE_ QMPool 106 | #define QF_EPOOL_INIT_(p_, poolSto_, poolSize_, evtSize_) \ 107 | (p_).init((poolSto_), (poolSize_), (evtSize_)) 108 | #define QF_EPOOL_EVENT_SIZE_(p_) ((p_).getBlockSize()) 109 | #define QF_EPOOL_GET_(p_, e_, m_, qs_id_) \ 110 | ((e_) = static_cast((p_).get((m_), (qs_id_)))) 111 | #define QF_EPOOL_PUT_(p_, e_, qs_id_) ((p_).put((e_), (qs_id_))) 112 | 113 | #endif // QP_IMPL 114 | 115 | #endif // QV_HPP 116 | 117 | -------------------------------------------------------------------------------- /src/qp-arduino/qv_port.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 3 | * @brief QV/C++ port to ARM Cortex-M, GNU-ARM toolset 4 | * @cond 5 | ****************************************************************************** 6 | * Last updated for version 6.9.1 7 | * Last updated on 2020-09-23 8 | * 9 | * Q u a n t u m L e a P s 10 | * ------------------------ 11 | * Modern Embedded Software 12 | * 13 | * Copyright (C) 2005-2020 Quantum Leaps, LLC. All rights reserved. 14 | * 15 | * This program is open source software: you can redistribute it and/or 16 | * modify it under the terms of the GNU General Public License as published 17 | * by the Free Software Foundation, either version 3 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Alternatively, this program may be distributed and modified under the 21 | * terms of Quantum Leaps commercial licenses, which expressly supersede 22 | * the GNU General Public License and are specifically designed for 23 | * licensees interested in retaining the proprietary status of their code. 24 | * 25 | * This program is distributed in the hope that it will be useful, 26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 | * GNU General Public License for more details. 29 | * 30 | * You should have received a copy of the GNU General Public License 31 | * along with this program. If not, see . 32 | * 33 | * Contact information: 34 | * 35 | * 36 | ****************************************************************************** 37 | * @endcond 38 | */ 39 | /* This QV port is part of the interanl QP implementation */ 40 | #define QP_IMPL 1U 41 | #include "qf_port.hpp" 42 | 43 | extern "C" { 44 | 45 | #if (__ARM_ARCH == 6) /* Cortex-M0/M0+/M1 (v6-M, v6S-M)? */ 46 | 47 | /* 48 | * Hand-optimized quick LOG2 in assembly (M0/M0+ have no CLZ instruction) 49 | * 50 | * NOTE: 51 | * The inline GNU assembler does not accept mnemonics MOVS, LSRS and ADDS, 52 | * but for Cortex-M0/M0+/M1 the mnemonics MOV, LSR and ADD always set the 53 | * condition flags in the PSR. 54 | */ 55 | __attribute__ ((naked, optimize("-fno-stack-protector"))) 56 | uint_fast8_t QF_qlog2(uint32_t x) { 57 | __asm volatile ( 58 | " MOV r1,#0 \n" 59 | #if (QF_MAX_ACTIVE > 16U) 60 | " LSR r2,r0,#16 \n" 61 | " BEQ QF_qlog2_1 \n" 62 | " MOV r1,#16 \n" 63 | " MOV r0,r2 \n" 64 | "QF_qlog2_1: \n" 65 | #endif 66 | #if (QF_MAX_ACTIVE > 8U) 67 | " LSR r2,r0,#8 \n" 68 | " BEQ QF_qlog2_2 \n" 69 | " ADD r1, r1,#8 \n" 70 | " MOV r0, r2 \n" 71 | "QF_qlog2_2: \n" 72 | #endif 73 | " LSR r2,r0,#4 \n" 74 | " BEQ QF_qlog2_3 \n" 75 | " ADD r1,r1,#4 \n" 76 | " MOV r0,r2 \n" 77 | "QF_qlog2_3: \n" 78 | " LDR r2,=QF_qlog2_LUT \n" 79 | " LDRB r0,[r2,r0] \n" 80 | " ADD r0,r1,r0 \n" 81 | " BX lr \n" 82 | " .align \n" 83 | "QF_qlog2_LUT: \n" 84 | " .byte 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4" 85 | ); 86 | } 87 | 88 | #else /* NOT Cortex-M0/M0+/M1(v6-M, v6S-M)? */ 89 | 90 | #define SCnSCB_ICTR ((uint32_t volatile *)0xE000E004) 91 | #define SCB_SYSPRI ((uint32_t volatile *)0xE000ED14) 92 | #define NVIC_IP ((uint32_t volatile *)0xE000E400) 93 | 94 | /* 95 | * Initialize the exception priorities and IRQ priorities to safe values. 96 | * 97 | * Description: 98 | * On Cortex-M3/M4/M7, this QV port disables interrupts by means of the 99 | * BASEPRI register. However, this method cannot disable interrupt 100 | * priority zero, which is the default for all interrupts out of reset. 101 | * The following code changes the SysTick priority and all IRQ priorities 102 | * to the safe value QF_BASEPRI, wich the QF critical section can disable. 103 | * This avoids breaching of the QF critical sections in case the 104 | * application programmer forgets to explicitly set priorities of all 105 | * "kernel aware" interrupts. 106 | * 107 | * The interrupt priorities established in QV_init() can be later 108 | * changed by the application-level code. 109 | */ 110 | void QV_init(void) { 111 | uint32_t n; 112 | 113 | /* set exception priorities to QF_BASEPRI... 114 | * SCB_SYSPRI1: Usage-fault, Bus-fault, Memory-fault 115 | */ 116 | SCB_SYSPRI[1] |= (QF_BASEPRI << 16) | (QF_BASEPRI << 8) | QF_BASEPRI; 117 | 118 | /* SCB_SYSPRI2: SVCall */ 119 | SCB_SYSPRI[2] |= (QF_BASEPRI << 24); 120 | 121 | /* SCB_SYSPRI3: SysTick, PendSV, Debug */ 122 | SCB_SYSPRI[3] |= (QF_BASEPRI << 24) | (QF_BASEPRI << 16) | QF_BASEPRI; 123 | 124 | /* set all implemented IRQ priories to QF_BASEPRI... */ 125 | n = 8U + ((*SCnSCB_ICTR & 0x7U) << 3); /* (# NVIC_PRIO registers)/4 */ 126 | do { 127 | --n; 128 | NVIC_IP[n] = (QF_BASEPRI << 24) | (QF_BASEPRI << 16) 129 | | (QF_BASEPRI << 8) | QF_BASEPRI; 130 | } while (n != 0); 131 | } 132 | 133 | #endif /* NOT Cortex-M0/M0+/M1(v6-M, v6S-M)? */ 134 | 135 | } // extern "C" 136 | 137 | -------------------------------------------------------------------------------- /src/qp-arduino/qv_port.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// @brief QV/C++ port to ARM Cortex-M, GNU-ARM toolset 3 | /// @cond 4 | ///*************************************************************************** 5 | /// Last updated for version 6.9.1 6 | /// Last updated on 2020-09-23 7 | /// 8 | /// Q u a n t u m L e a P s 9 | /// ------------------------ 10 | /// Modern Embedded Software 11 | /// 12 | /// Copyright (C) 2005-2020 Quantum Leaps. All rights reserved. 13 | /// 14 | /// This program is open source software: you can redistribute it and/or 15 | /// modify it under the terms of the GNU General Public License as published 16 | /// by the Free Software Foundation, either version 3 of the License, or 17 | /// (at your option) any later version. 18 | /// 19 | /// Alternatively, this program may be distributed and modified under the 20 | /// terms of Quantum Leaps commercial licenses, which expressly supersede 21 | /// the GNU General Public License and are specifically designed for 22 | /// licensees interested in retaining the proprietary status of their code. 23 | /// 24 | /// This program is distributed in the hope that it will be useful, 25 | /// but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 | /// GNU General Public License for more details. 28 | /// 29 | /// You should have received a copy of the GNU General Public License 30 | /// along with this program. If not, see . 31 | /// 32 | /// Contact information: 33 | /// 34 | /// 35 | ///*************************************************************************** 36 | /// @endcond 37 | 38 | #ifndef QV_PORT_HPP 39 | #define QV_PORT_HPP 40 | 41 | #if (__ARM_ARCH == 6) // Cortex-M0/M0+/M1 (v6-M, v6S-M)? 42 | 43 | // macro to put the CPU to sleep inside QV::onIdle() 44 | #define QV_CPU_SLEEP() do { \ 45 | __asm volatile ("wfi"); \ 46 | QF_INT_ENABLE(); \ 47 | } while (false) 48 | 49 | #define QV_ARM_ERRATUM_838869() ((void)0) 50 | 51 | #else // Cortex-M3/M4/M7(v7-M) 52 | 53 | // macro to put the CPU to sleep inside QV::onIdle() 54 | #define QV_CPU_SLEEP() do { \ 55 | QF_PRIMASK_DISABLE(); \ 56 | QF_INT_ENABLE(); \ 57 | __asm volatile ("wfi"); \ 58 | QF_PRIMASK_ENABLE(); \ 59 | } while (false) 60 | 61 | // initialization of the QV kernel for Cortex-M3/M4/M4F 62 | #define QV_INIT() QV_init() 63 | extern "C" void QV_init(void); 64 | 65 | // The following macro implements the recommended workaround for the 66 | // ARM Erratum 838869. Specifically, for Cortex-M3/M4/M7 the DSB 67 | // (memory barrier) instruction needs to be added before exiting an ISR. 68 | // This macro should be inserted at the end of ISRs. 69 | // 70 | #define QV_ARM_ERRATUM_838869() \ 71 | __asm volatile ("dsb 0xf" ::: "memory") 72 | 73 | #endif 74 | 75 | #include "qv.hpp" // QV platform-independent public interface 76 | 77 | #endif // QV_PORT_HPP 78 | 79 | -------------------------------------------------------------------------------- /src/qpcpp.hpp: -------------------------------------------------------------------------------- 1 | /// @file 2 | /// @brief QP/C++ public interface including backwards-compatibility layer 3 | /// @ingroup qep qf qv qk qxk qs 4 | /// @cond 5 | ///*************************************************************************** 6 | /// Last updated for version 6.9.1 7 | /// Last updated on 2020-09-30 8 | /// 9 | /// Q u a n t u m L e a P s 10 | /// ------------------------ 11 | /// Modern Embedded Software 12 | /// 13 | /// Copyright (C) 2005-2020 Quantum Leaps. All rights reserved. 14 | /// 15 | /// This program is open source software: you can redistribute it and/or 16 | /// modify it under the terms of the GNU General Public License as published 17 | /// by the Free Software Foundation, either version 3 of the License, or 18 | /// (at your option) any later version. 19 | /// 20 | /// Alternatively, this program may be distributed and modified under the 21 | /// terms of Quantum Leaps commercial licenses, which expressly supersede 22 | /// the GNU General Public License and are specifically designed for 23 | /// licensees interested in retaining the proprietary status of their code. 24 | /// 25 | /// This program is distributed in the hope that it will be useful, 26 | /// but WITHOUT ANY WARRANTY; without even the implied warranty of 27 | /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 | /// GNU General Public License for more details. 29 | /// 30 | /// You should have received a copy of the GNU General Public License 31 | /// along with this program. If not, see . 32 | /// 33 | /// Contact information: 34 | /// 35 | /// 36 | ///*************************************************************************** 37 | /// @endcond 38 | 39 | #ifndef qpcpp_h 40 | #define qpcpp_h 41 | 42 | /// @description 43 | /// This header file must be included directly or indirectly 44 | /// in all application modules (*.cpp files) that use QP/C++. 45 | 46 | //**************************************************************************** 47 | #include "./qp-arduino/qf_port.hpp" // QF/C++ port from the port directory 48 | #include "./qp-arduino/qassert.h" // QP assertions 49 | #ifdef Q_SPY // software tracing enabled? 50 | #include "./qp-arduino/qs_port.hpp" // QS/C++ port from the port directory 51 | #else 52 | #include "./qp-arduino/qs_dummy.hpp" // QS/C++ dummy (inactive) interface 53 | #endif 54 | 55 | //**************************************************************************** 56 | #ifndef QP_API_VERSION 57 | 58 | //! Macro that specifies the backwards compatibility with the 59 | //! QP/C++ API version. 60 | /// @description 61 | /// For example, QP_API_VERSION=540 will cause generating the compatibility 62 | /// layer with QP/C++ version 5.4.0 and newer, but not older than 5.4.0. 63 | /// QP_API_VERSION=0 causes generation of the compatibility layer "from the 64 | /// begining of time", which is the maximum backwards compatibilty. This is 65 | /// the default.@n 66 | /// @n 67 | /// Conversely, QP_API_VERSION=9999 means that no compatibility layer should 68 | /// be generated. This setting is useful for checking if an application 69 | /// complies with the latest QP/C++ API. 70 | #define QP_API_VERSION 0 71 | 72 | #endif // QP_API_VERSION 73 | 74 | // QP/C++ API compatibility layer... 75 | 76 | //**************************************************************************** 77 | #if (QP_API_VERSION < 691) 78 | 79 | //! @deprecated enable the QS global filter 80 | #define QS_FILTER_ON(rec_) QS_GLB_FILTER((rec_)) 81 | 82 | //! @deprecated disable the QS global filter 83 | #define QS_FILTER_OFF(rec_) QS_GLB_FILTER(-(rec_)) 84 | 85 | //! @deprecated enable the QS local filter for SM (state machine) object 86 | #define QS_FILTER_SM_OBJ(obj_) (static_cast(0)) 87 | 88 | //! @deprecated enable the QS local filter for AO (active objects) 89 | #define QS_FILTER_AO_OBJ(obj_) (static_cast(0)) 90 | 91 | //! @deprecated enable the QS local filter for MP (memory pool) object 92 | #define QS_FILTER_MP_OBJ(obj_) (static_cast(0)) 93 | 94 | //! @deprecated enable the QS local filter for EQ (event queue) object 95 | #define QS_FILTER_EQ_OBJ(obj_) (static_cast(0)) 96 | 97 | //! @deprecated enable the QS local filter for TE (time event) object 98 | #define QS_FILTER_TE_OBJ(obj_) (static_cast(0)) 99 | 100 | #ifdef Q_SPY 101 | 102 | //! @deprecated local Filter for a generic application object @p obj_. 103 | #define QS_FILTER_AP_OBJ(obj_) \ 104 | (QP::QS::priv_.locFilter_AP = (obj_)) 105 | 106 | //! @deprecated begin of a user QS record, instead use QS_BEGIN_ID() 107 | #define QS_BEGIN(rec_, obj_) \ 108 | if (QS_GLB_FILTER_(rec_) && \ 109 | ((QP::QS::priv_.locFilter[QP::QS::AP_OBJ] == nullptr) \ 110 | || (QP::QS::priv_.locFilter_AP == (obj_)))) \ 111 | { \ 112 | QS_CRIT_STAT_ \ 113 | QS_CRIT_E_(); \ 114 | QP::QS::beginRec_(static_cast(rec_)); \ 115 | QS_TIME_PRE_(); 116 | 117 | //! @deprecated output hex-formatted std::uint32_t to the QS record 118 | #define QS_U32_HEX(width_, data_) \ 119 | (QP::QS::u32_fmt_(static_cast( \ 120 | (static_cast((width_) << 4)) \ 121 | | static_cast(0xFU)), (data_))) 122 | 123 | 124 | 125 | #else 126 | 127 | #define QS_FILTER_AP_OBJ(obj_) (static_cast(0)) 128 | #define QS_BEGIN(rec_, obj_) if (false) { 129 | #define QS_U32_HEX(width_, data_) (static_cast(0)) 130 | 131 | #endif 132 | 133 | //**************************************************************************** 134 | #if (QP_API_VERSION < 680) 135 | 136 | //! @deprecated 137 | //! Macro to specify a transition in the "me->" impl-strategy. 138 | /// Instead use the new impl-strategy without the "me->" pointer, where 139 | /// you call tran(Q_STATE_CAST(target_)). 140 | #define Q_TRAN(target_) (me->tran(Q_STATE_CAST(target_))) 141 | 142 | //! @deprecated 143 | //! Macro to specify a tran-to-history in the "me->" impl-strategy. 144 | /// Instead use the new impl-strategy without the "me->" pointer, where 145 | /// you call tran_hist(Q_STATE_CAST(hist_)). 146 | #define Q_TRAN_HIST(hist_) (me->tran_hist((hist_))) 147 | 148 | //! @deprecated 149 | //! Macro to specify the superstate in the "me->" impl-strategy. 150 | /// Instead use the new impl-strategy without the "me->" pointer, where 151 | /// you call super(state_)). 152 | #define Q_SUPER(state_) (me->super((state_))) 153 | 154 | //! @deprecated 155 | //! Macro to call in a QM state entry-handler. Applicable only to QMSMs. 156 | /// Instead use the new impl-strategy without the "me->" pointer, where 157 | /// the QM-generated code calls qm_entry(Q_STATE_CAST(state_)). 158 | #define QM_ENTRY(state_) (me->qm_entry((state_))) 159 | 160 | //! @deprecated 161 | //! Macro to call in a QM state exit-handler. Applicable only to QMSMs. 162 | /// Instead use the new impl-strategy without the "me->" pointer, where 163 | /// the QM-generated code calls qm_exit(Q_STATE_CAST(state_)). 164 | #define QM_EXIT(state_) (me->qm_exit((state_))) 165 | 166 | //! @deprecated 167 | //! Macro to call in a QM submachine exit-handler. Applicable only to QMSMs. 168 | /// Instead use the new impl-strategy without the "me->" pointer, where 169 | /// the QM-generated code calls qm_sm_exit(Q_STATE_CAST(state_)). 170 | #define QM_SM_EXIT(state_) (me->qm_sm_exit((state_))) 171 | 172 | //! @deprecated 173 | //! Macro to call in a QM state-handler when it executes a transition. 174 | /// Instead use the new impl-strategy without the "me->" pointer, where 175 | /// the QM-generated code calls qm_tran((tatbl_)). 176 | #define QM_TRAN(tatbl_) (me->qm_tran((tatbl_))) 177 | 178 | //! @deprecated 179 | //! Macro to call in a QM state-handler when it executes an initial tran. 180 | /// Instead use the new impl-strategy without the "me->" pointer, where 181 | /// the QM-generated code calls qm_tran_init((tatbl_)). 182 | #define QM_TRAN_INIT(tatbl_) (me->qm_tran_init((tatbl_))) 183 | 184 | //! @deprecated 185 | //! Macro to call in a QM state-handler when it executes a tran-to-history. 186 | /// Instead use the new impl-strategy without the "me->" pointer, where 187 | /// the QM-generated code calls qm_tran_hist((history_), (tatbl_)). 188 | #define QM_TRAN_HIST(history_, tatbl_) \ 189 | (me->qm_tran_hist((history_), (tatbl_))) 190 | 191 | //! @deprecated 192 | //! Macro to call in a QM state-handler when it executes an initial tran. 193 | /// Instead use the new impl-strategy without the "me->" pointer, where 194 | /// the QM-generated code calls qm_tran_ep((tatbl_)). 195 | #define QM_TRAN_EP(tatbl_) (me->qm_tran_ep((tatbl_))) 196 | 197 | //! @deprecated 198 | //! Macro to call in a QM state-handler when it executes a tran-to-exit-point. 199 | /// Instead use the new impl-strategy without the "me->" pointer, where 200 | /// the QM-generated code calls qm_tran_xp((xp_), (tatbl_)). 201 | #define QM_TRAN_XP(xp_, tatbl_) (me->qm_tran_xp((xp_), (tatbl_))) 202 | 203 | //! @deprecated 204 | //! Designates the superstate of a given state in a subclass of QP::QMsm. 205 | /// Instead use the new impl-strategy without the "me->" pointer, where 206 | /// the QM-generated code calls qm_super_sub((state_)). 207 | #define QM_SUPER_SUB(state_) (me->qm_super_sub((state_))) 208 | 209 | #endif // QP_API_VERSION < 680 210 | #endif // QP_API_VERSION < 691 211 | 212 | #endif // qpcpp_h 213 | 214 | --------------------------------------------------------------------------------