├── .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 |
--------------------------------------------------------------------------------