diff --git a/README.MD b/README.MD
index 8c9e25f..d258790 100644
--- a/README.MD
+++ b/README.MD
@@ -15,23 +15,4 @@ Open any of the examples and upload to an ESP32.
- Typically `QF::run()` should be executed as a last instruction before QP takes charge of executing the framework. As such, it should not return and instead give control to the scheduler of the host. However, the ESP32 framework (esp-idf) already runs the scheduler [before](https://github.com/espressif/arduino-esp32/blob/8ee5f0a11e5423a018e0f89146e05074466274db/cores/esp32/main.cpp#L55) `void setup()` and `void loop()`. This means that instead of running `QF::run()` in a loop, it suffices to execute it once as the last instruction in `void setup()`.
-## QPSY
-
-[QSPY](https://www.state-machine.com/qtools/qspy.html) can be activated by defining `QS_ON`in `bsp.cpp` of both examples
-
-Example of how to communicate with esp32 target with qspy enabled.
-
-```bash
-qspy -c YOUR_SERIAL_PORT -b 115200
-```
-
-## QView
-
-DPP example can be tested with [QView™](https://www.state-machine.com/qtools/qview.html) example located in `examples/dpp_bsp-esp32/qview`. There are two bat scripts (Windows) which can run the QView scripts.
-
-
-Note: QSpy must be running before using QView.
-
-
-
-
+- No more QSpy on this port
\ No newline at end of file
diff --git a/examples/blinky_bsp-esp32/blinky.hpp b/examples/blinky_bsp-esp32/blinky.hpp
index c81c1ed..aefffd1 100644
--- a/examples/blinky_bsp-esp32/blinky.hpp
+++ b/examples/blinky_bsp-esp32/blinky.hpp
@@ -1,21 +1,40 @@
-//.$file${.::blinky.hpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+//$file${.::blinky.hpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
//
// Model: blinky_bsp-esp32.qm
// File: ${.::blinky.hpp}
//
-// This code has been generated by QM 5.1.1 .
+// This code has been generated by QM 7.0.1 .
// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
//
-// This program is open source software: you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as published
-// by the Free Software Foundation.
+// Copyright (c) 2005 Quantum Leaps, LLC. All rights reserved.
//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-// for more details.
+// ____________________________________
+// / /
+// / GGGGGGG PPPPPPPP LL /
+// / GG GG PP PP LL /
+// / GG PP PP LL /
+// / GG GGGGG PPPPPPPP LL /
+// / GG GG PP LL /
+// / GGGGGGG PP LLLLLLL /
+// /___________________________________/
//
-//.$endhead${.::blinky.hpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+// This generated code is open-source software licensed under the GNU
+// General Public License (GPL) as published by the Free Software Foundation
+// (see ).
+//
+// NOTE:
+// The GPL does NOT permit the incorporation of this code into proprietary
+// programs. Please contact Quantum Leaps for commercial licensing options,
+// which expressly supersede the GPL and are designed explicitly for
+// closed-source distribution.
+//
+// Quantum Leaps contact information:
+//
+//
+//
+//$endhead${.::blinky.hpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#ifndef BLINKY_HPP
#define BLINKY_HPP
@@ -25,9 +44,12 @@ enum BlinkySignals {
};
// genearate declarations of all opaque AO pointers
-//.$declare${AOs::AO_Blinky} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+//$declare${AOs::AO_Blinky} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+
+//${AOs::AO_Blinky} ..........................................................
extern QP::QActive * const AO_Blinky;
-//.$enddecl${AOs::AO_Blinky} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//$enddecl${AOs::AO_Blinky} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//...
#endif // BLINKY_HPP
+
diff --git a/examples/blinky_bsp-esp32/blinky_bsp-esp32.ino b/examples/blinky_bsp-esp32/blinky_bsp-esp32.ino
index a2079a5..f1f9de2 100644
--- a/examples/blinky_bsp-esp32/blinky_bsp-esp32.ino
+++ b/examples/blinky_bsp-esp32/blinky_bsp-esp32.ino
@@ -1,41 +1,69 @@
-//.$file${.::blinky_bsp-esp32.ino} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+//$file${.::blinky_bsp-esp32.ino} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
//
// Model: blinky_bsp-esp32.qm
// File: ${.::blinky_bsp-esp32.ino}
//
-// This code has been generated by QM 5.1.1 .
+// This code has been generated by QM 7.0.1 .
// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
//
-// This program is open source software: you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as published
-// by the Free Software Foundation.
+// Copyright (c) 2005 Quantum Leaps, LLC. All rights reserved.
//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-// for more details.
+// ____________________________________
+// / /
+// / GGGGGGG PPPPPPPP LL /
+// / GG GG PP PP LL /
+// / GG PP PP LL /
+// / GG GGGGG PPPPPPPP LL /
+// / GG GG PP LL /
+// / GGGGGGG PP LLLLLLL /
+// /___________________________________/
//
-//.$endhead${.::blinky_bsp-esp32.ino} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+// This generated code is open-source software licensed under the GNU
+// General Public License (GPL) as published by the Free Software Foundation
+// (see ).
+//
+// NOTE:
+// The GPL does NOT permit the incorporation of this code into proprietary
+// programs. Please contact Quantum Leaps for commercial licensing options,
+// which expressly supersede the GPL and are designed explicitly for
+// closed-source distribution.
+//
+// Quantum Leaps contact information:
+//
+//
+//
+//$endhead${.::blinky_bsp-esp32.ino} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#include "qpcpp.hpp" // QP-C++ framework
#include "blinky.hpp" // Blinky application interface
#include "bsp.hpp" // Board Support Package (BSP)
using namespace QP;
-static constexpr unsigned stack_size = 1000;
-
+static constexpr unsigned stack_size = 1700;
//............................................................................
void setup() {
QF::init(); // initialize the framework
BSP::init(); // initialize the BSP
+ // initialize event pools
+ static QF_MPOOL_EL(QP::QEvt) smlPoolSto[20];
+ QP::QF::poolInit(smlPoolSto, sizeof(smlPoolSto), sizeof(smlPoolSto[0]));
+
+ // initialize publish-subscribe
+ static QP::QSubscrList subscrSto[10];
+ QP::QActive::psInit(subscrSto, Q_DIM(subscrSto));
+
// statically allocate event queues for the AOs and start them...
- static QEvt const *blinky_queueSto[30];
+ static QP::QEvtPtr blinky_queueSto[30];
+ static StackType_t stack[stack_size];
AO_Blinky->start(1U, // priority
- blinky_queueSto, // queu storage for evets
+ blinky_queueSto, // queue storage for events
Q_DIM(blinky_queueSto), //len of queue
- nullptr, // No static stack
- stack_size);
- QF::run(); // Normally QF Run is located in a loop
+ stack,
+ sizeof(stack));
+
+ QF::run(); // Normally QF Run is located in a loop
//but since using Arduino SDK not necessary
// Called once to call QF::OnStartup and produce the QS trace
}
@@ -46,8 +74,9 @@ void loop() {
//============================================================================
// generate declarations and definitions of all AO classes (state machines)...
-//.$declare${AOs::Blinky} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-//.${AOs::Blinky} ............................................................
+//$declare${AOs::Blinky} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+
+//${AOs::Blinky} .............................................................
class Blinky : public QP::QActive {
private:
QP::QTimeEvt m_timeEvt;
@@ -62,26 +91,28 @@ protected:
Q_STATE_DECL(initial);
Q_STATE_DECL(off);
Q_STATE_DECL(on);
-};
-//.$enddecl${AOs::Blinky} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//.$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-//. Check for the minimum required QP version
-#if (QP_VERSION < 690U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U))
-#error qpcpp version 6.9.0 or higher required
+}; // class Blinky
+//$enddecl${AOs::Blinky} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+// Check for the minimum required QP version
+#if (QP_VERSION < 730U) || (QP_VERSION != ((QP_RELEASE^4294967295U)%0x2710U))
+#error qpcpp version 7.3.0 or higher required
#endif
-//.$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//.$define${AOs::Blinky} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-//.${AOs::Blinky} ............................................................
+//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//$define${AOs::Blinky} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+
+//${AOs::Blinky} .............................................................
Blinky Blinky::instance;
-//.${AOs::Blinky::Blinky} ....................................................
+
+//${AOs::Blinky::Blinky} .....................................................
Blinky::Blinky()
: QActive(Q_STATE_CAST(&Blinky::initial)),
m_timeEvt(this, TIMEOUT_SIG, 0U)
{}
-//.${AOs::Blinky::SM} ........................................................
+//${AOs::Blinky::SM} .........................................................
Q_STATE_DEF(Blinky, initial) {
- //.${AOs::Blinky::SM::initial}
+ //${AOs::Blinky::SM::initial}
(void)e; // unused parameter
m_timeEvt.armX(BSP::TICKS_PER_SEC/2, BSP::TICKS_PER_SEC/2);
@@ -93,17 +124,18 @@ Q_STATE_DEF(Blinky, initial) {
return tran(&off);
}
-//.${AOs::Blinky::SM::off} ...................................................
+
+//${AOs::Blinky::SM::off} ....................................................
Q_STATE_DEF(Blinky, off) {
QP::QState status_;
switch (e->sig) {
- //.${AOs::Blinky::SM::off}
+ //${AOs::Blinky::SM::off}
case Q_ENTRY_SIG: {
BSP::ledOff();
status_ = Q_RET_HANDLED;
break;
}
- //.${AOs::Blinky::SM::off::TIMEOUT}
+ //${AOs::Blinky::SM::off::TIMEOUT}
case TIMEOUT_SIG: {
status_ = tran(&on);
break;
@@ -115,17 +147,18 @@ Q_STATE_DEF(Blinky, off) {
}
return status_;
}
-//.${AOs::Blinky::SM::on} ....................................................
+
+//${AOs::Blinky::SM::on} .....................................................
Q_STATE_DEF(Blinky, on) {
QP::QState status_;
switch (e->sig) {
- //.${AOs::Blinky::SM::on}
+ //${AOs::Blinky::SM::on}
case Q_ENTRY_SIG: {
BSP::ledOn();
status_ = Q_RET_HANDLED;
break;
}
- //.${AOs::Blinky::SM::on::TIMEOUT}
+ //${AOs::Blinky::SM::on::TIMEOUT}
case TIMEOUT_SIG: {
status_ = tran(&off);
break;
@@ -137,13 +170,15 @@ Q_STATE_DEF(Blinky, on) {
}
return status_;
}
-//.$enddef${AOs::Blinky} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//$enddef${AOs::Blinky} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//...
//============================================================================
// generate definitions of all AO opaque pointers...
-//.$define${AOs::AO_Blinky} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-//.${AOs::AO_Blinky} .........................................................
+//$define${AOs::AO_Blinky} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+
+//${AOs::AO_Blinky} ..........................................................
QP::QActive * const AO_Blinky = &Blinky::instance;
-//.$enddef${AOs::AO_Blinky} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//$enddef${AOs::AO_Blinky} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//...
+
diff --git a/examples/blinky_bsp-esp32/blinky_bsp-esp32.qm b/examples/blinky_bsp-esp32/blinky_bsp-esp32.qm
index 79733bc..1138bf9 100644
--- a/examples/blinky_bsp-esp32/blinky_bsp-esp32.qm
+++ b/examples/blinky_bsp-esp32/blinky_bsp-esp32.qm
@@ -1,5 +1,5 @@
-
+
This is a little more advanced Blinky example for the Arduino ESP32 board. The example demonstrates:
1. One active object class "Blinky" (inside the package "AOs")
@@ -47,7 +47,7 @@ QS_SIG_DICTIONARY(TIMEOUT_SIG, nullptr);
-
+
@@ -58,7 +58,7 @@ QS_SIG_DICTIONARY(TIMEOUT_SIG, nullptr);
-
+
@@ -74,13 +74,12 @@ QS_SIG_DICTIONARY(TIMEOUT_SIG, nullptr);
#ifndef BSP_HPP
#define BSP_HPP
-class BSP {
-public:
+namespace BSP {
enum { TICKS_PER_SEC = CONFIG_FREERTOS_HZ} ;
- static void init(void);
- static void ledOff(void);
- static void ledOn(void);
-};
+ void init(void);
+ void ledOff(void);
+ void ledOn(void);
+}
#endif // BSP_HPP
@@ -92,13 +91,11 @@ public:
#include "Arduino.h"
#include "esp_freertos_hooks.h"
-using namespace QP;
-static constexpr unsigned LED_BUILTIN = 13;
-// QS facilities
+// If current ESP32 board does not define LED_BUILTIN
+#ifndef LED_BUILTIN
+#define LED_BUILTIN 2U
+#endif
-// un-comment if QS instrumentation needed
-//#define QS_ON
-// BSP functions
static void tickHook_ESP32(void); /*Tick hook for QP */
static uint8_t const l_TickHook = static_cast<uint8_t>(0);
@@ -106,76 +103,16 @@ static void tickHook_ESP32(void)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* process time events for rate 0 */
- QF::TICK_FROM_ISR(&xHigherPriorityTaskWoken, &l_TickHook);
+ QP::QTimeEvt::TICK_FROM_ISR(&xHigherPriorityTaskWoken, &l_TickHook);
/* notify FreeRTOS to perform context switch from ISR, if needed */
if(xHigherPriorityTaskWoken) {
portYIELD_FROM_ISR();
}
}
-
-//............................................................................
-void BSP::init(void) {
- // initialize the hardware used in this sketch...
- // NOTE: interrupts are configured and started later in QF::onStartup()
- pinMode(LED_BUILTIN, OUTPUT);
- Serial.begin(115200); // run serial port at 115200 baud rate
- QS_INIT(nullptr);
-#ifdef QS_ON
- // setup the QS filters...
- QS_GLB_FILTER(QP::QS_SM_RECORDS); // state machine records
- QS_GLB_FILTER(QP::QS_AO_RECORDS); // active object records
- QS_GLB_FILTER(QP::QS_UA_RECORDS); // all user records
-#endif
-}
//............................................................................
-void BSP::ledOff(void) {
- digitalWrite(LED_BUILTIN, LOW);
- Serial.println("led off");
-}
-//............................................................................
-void BSP::ledOn(void) {
- digitalWrite(LED_BUILTIN, HIGH);
- Serial.println("led on");
-}
-
-//............................................................................
-void QSpy_Task(void *) {
- while(1)
- {
- // transmit QS outgoing data (QS-TX)
- uint16_t len = Serial.availableForWrite();
- if (len > 0U) { // any space available in the output buffer?
- uint8_t const *buf = QS::getBlock(&len);
- if (buf) {
- Serial.write(buf, len); // asynchronous and non-blocking
- }
- }
-
- // receive QS incoming data (QS-RX)
- len = Serial.available();
- if (len > 0U) {
- do {
- QP::QS::rxPut(Serial.read());
- } while (--len > 0U);
- QS::rxParse();
- }
- delay(100);
- };
-}
-
-void QF::onStartup(void) {
+void QP::QF::onStartup(void) {
esp_register_freertos_tick_hook_for_cpu(tickHook_ESP32, QP_CPU_NUM);
QS_OBJ_DICTIONARY(&l_TickHook);
-#ifdef QS_ON
- xTaskCreatePinnedToCore(
- QSpy_Task, /* Function to implement the task */
- "QSPY", /* Name of the task */
- 10000, /* Stack size in words */
- NULL, /* Task input parameter */
- configMAX_PRIORITIES-1, /* Priority of the task */
- NULL, /* Task handle. */
- QP_CPU_NUM); /* Core where the task should run */
-#endif
}
//............................................................................
extern "C" Q_NORETURN Q_onAssert(char const * const module, int location) {
@@ -184,59 +121,34 @@ extern "C" Q_NORETURN Q_onAssert(char const * const module, int locati
//
(void)module;
(void)location;
- Serial.print("QP Assert module:");
+ Serial.print("QP Assert module: ");
Serial.print(module);
- Serial.print(",");
+ Serial.print("@ ");
Serial.println(location);
QF_INT_DISABLE(); // disable all interrupts
for (;;) { // sit in an endless loop for now
}
}
-
-//----------------------------------------------------------------------------
-// QS callbacks...
//............................................................................
-bool QP::QS::onStartup(void const * arg) {
- static uint8_t qsTxBuf[1024]; // buffer for QS transmit channel (QS-TX)
- static uint8_t qsRxBuf[128]; // buffer for QS receive channel (QS-RX)
- initBuf (qsTxBuf, sizeof(qsTxBuf));
- rxInitBuf(qsRxBuf, sizeof(qsRxBuf));
- return true; // return success
-}
-//............................................................................
-void QP::QS::onCommand(uint8_t cmdId, uint32_t param1,
- uint32_t param2, uint32_t param3)
-{
- (void)cmdId;
- (void)param1;
- (void)param2;
- (void)param3;
-}
-//............................................................................
-void QP::QS::onCleanup(void) {
-}
-//............................................................................
-QP::QSTimeCtr QP::QS::onGetTime(void) {
- return millis();
+namespace BSP {
+void init(void) {
+ // initialize the hardware used in this sketch...
+ // NOTE: interrupts are configured and started later in QF::onStartup()
+ pinMode(LED_BUILTIN, OUTPUT);
+ Serial.begin(115200); // run serial port at 115200 baud rate
+ QS_INIT(nullptr);
}
//............................................................................
-void QP::QS::onFlush(void) {
-#ifdef QS_ON
- uint16_t len = 0xFFFFU; // big number to get as many bytes as available
- uint8_t const *buf = QS::getBlock(&len); // get continguous block of data
- while (buf != nullptr) { // data available?
- Serial.write(buf, len); // might poll until all bytes fit
- len = 0xFFFFU; // big number to get as many bytes as available
- buf = QS::getBlock(&len); // try to get more data
- }
- Serial.flush(); // wait for the transmission of outgoing data to complete
-#endif // QS_ON
+void ledOff(void) {
+ digitalWrite(LED_BUILTIN, LOW);
+ Serial.println("led off");
}
//............................................................................
-void QP::QS::onReset(void) {
- esp_restart();
+void ledOn(void) {
+ digitalWrite(LED_BUILTIN, HIGH);
+ Serial.println("led on");
}
-
+} // namespace BSP
#ifndef BLINKY_HPP
@@ -260,21 +172,30 @@ $declare${AOs::AO_Blinky}
#include "bsp.hpp" // Board Support Package (BSP)
using namespace QP;
-static constexpr unsigned stack_size = 1000;
-
+static constexpr unsigned stack_size = 1700;
//............................................................................
void setup() {
QF::init(); // initialize the framework
BSP::init(); // initialize the BSP
+ // initialize event pools
+ static QF_MPOOL_EL(QP::QEvt) smlPoolSto[20];
+ QP::QF::poolInit(smlPoolSto, sizeof(smlPoolSto), sizeof(smlPoolSto[0]));
+
+ // initialize publish-subscribe
+ static QP::QSubscrList subscrSto[10];
+ QP::QActive::psInit(subscrSto, Q_DIM(subscrSto));
+
// statically allocate event queues for the AOs and start them...
- static QEvt const *blinky_queueSto[30];
+ static QP::QEvtPtr blinky_queueSto[30];
+ static StackType_t stack[stack_size];
AO_Blinky->start(1U, // priority
- blinky_queueSto, // queu storage for evets
+ blinky_queueSto, // queue storage for events
Q_DIM(blinky_queueSto), //len of queue
- nullptr, // No static stack
- stack_size);
- QF::run(); // Normally QF Run is located in a loop
+ stack,
+ sizeof(stack));
+
+ QF::run(); // Normally QF Run is located in a loop
//but since using Arduino SDK not necessary
// Called once to call QF::OnStartup and produce the QS trace
}
diff --git a/examples/blinky_bsp-esp32/bsp.cpp b/examples/blinky_bsp-esp32/bsp.cpp
index 67aa8de..667e12d 100644
--- a/examples/blinky_bsp-esp32/bsp.cpp
+++ b/examples/blinky_bsp-esp32/bsp.cpp
@@ -1,34 +1,51 @@
-//.$file${.::bsp.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+//$file${.::bsp.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
//
// Model: blinky_bsp-esp32.qm
// File: ${.::bsp.cpp}
//
-// This code has been generated by QM 5.1.1 .
+// This code has been generated by QM 7.0.1 .
// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
//
-// This program is open source software: you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as published
-// by the Free Software Foundation.
+// Copyright (c) 2005 Quantum Leaps, LLC. All rights reserved.
//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-// for more details.
+// ____________________________________
+// / /
+// / GGGGGGG PPPPPPPP LL /
+// / GG GG PP PP LL /
+// / GG PP PP LL /
+// / GG GGGGG PPPPPPPP LL /
+// / GG GG PP LL /
+// / GGGGGGG PP LLLLLLL /
+// /___________________________________/
//
-//.$endhead${.::bsp.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+// This generated code is open-source software licensed under the GNU
+// General Public License (GPL) as published by the Free Software Foundation
+// (see ).
+//
+// NOTE:
+// The GPL does NOT permit the incorporation of this code into proprietary
+// programs. Please contact Quantum Leaps for commercial licensing options,
+// which expressly supersede the GPL and are designed explicitly for
+// closed-source distribution.
+//
+// Quantum Leaps contact information:
+//
+//
+//
+//$endhead${.::bsp.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#include "qpcpp.hpp" // QP-C++ framework
#include "blinky.hpp" // Blinky application interface
#include "bsp.hpp" // Board Support Package (BSP)
#include "Arduino.h"
#include "esp_freertos_hooks.h"
-using namespace QP;
-static constexpr unsigned LED_BUILTIN = 13;
-// QS facilities
+// If current ESP32 board does not define LED_BUILTIN
+#ifndef LED_BUILTIN
+#define LED_BUILTIN 2U
+#endif
-// un-comment if QS instrumentation needed
-//#define QS_ON
-// BSP functions
static void tickHook_ESP32(void); /*Tick hook for QP */
static uint8_t const l_TickHook = static_cast(0);
@@ -36,76 +53,16 @@ static void tickHook_ESP32(void)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* process time events for rate 0 */
- QTimeEvt::TICK_X_FROM_ISR(0U, &xHigherPriorityTaskWoken, &l_TickHook);
+ QP::QTimeEvt::TICK_FROM_ISR(&xHigherPriorityTaskWoken, &l_TickHook);
/* notify FreeRTOS to perform context switch from ISR, if needed */
if(xHigherPriorityTaskWoken) {
portYIELD_FROM_ISR();
}
}
-
-//............................................................................
-void BSP::init(void) {
- // initialize the hardware used in this sketch...
- // NOTE: interrupts are configured and started later in QF::onStartup()
- pinMode(LED_BUILTIN, OUTPUT);
- Serial.begin(115200); // run serial port at 115200 baud rate
- QS_INIT(nullptr);
-#ifdef QS_ON
- // setup the QS filters...
- QS_GLB_FILTER(QP::QS_SM_RECORDS); // state machine records
- QS_GLB_FILTER(QP::QS_AO_RECORDS); // active object records
- QS_GLB_FILTER(QP::QS_UA_RECORDS); // all user records
-#endif
-}
-//............................................................................
-void BSP::ledOff(void) {
- digitalWrite(LED_BUILTIN, LOW);
- Serial.println("led off");
-}
-//............................................................................
-void BSP::ledOn(void) {
- digitalWrite(LED_BUILTIN, HIGH);
- Serial.println("led on");
-}
-
//............................................................................
-void QSpy_Task(void *) {
- while(1)
- {
- // transmit QS outgoing data (QS-TX)
- uint16_t len = Serial.availableForWrite();
- if (len > 0U) { // any space available in the output buffer?
- uint8_t const *buf = QS::getBlock(&len);
- if (buf) {
- Serial.write(buf, len); // asynchronous and non-blocking
- }
- }
-
- // receive QS incoming data (QS-RX)
- len = Serial.available();
- if (len > 0U) {
- do {
- QP::QS::rxPut(Serial.read());
- } while (--len > 0U);
- QS::rxParse();
- }
- delay(100);
- };
-}
-
-void QF::onStartup(void) {
+void QP::QF::onStartup(void) {
esp_register_freertos_tick_hook_for_cpu(tickHook_ESP32, QP_CPU_NUM);
QS_OBJ_DICTIONARY(&l_TickHook);
-#ifdef QS_ON
- xTaskCreatePinnedToCore(
- QSpy_Task, /* Function to implement the task */
- "QSPY", /* Name of the task */
- 10000, /* Stack size in words */
- NULL, /* Task input parameter */
- configMAX_PRIORITIES-1, /* Priority of the task */
- NULL, /* Task handle. */
- QP_CPU_NUM); /* Core where the task should run */
-#endif
}
//............................................................................
extern "C" Q_NORETURN Q_onAssert(char const * const module, int location) {
@@ -114,55 +71,31 @@ extern "C" Q_NORETURN Q_onAssert(char const * const module, int location) {
//
(void)module;
(void)location;
- Serial.print("QP Assert module:");
+ Serial.print("QP Assert module: ");
Serial.print(module);
- Serial.print(",");
+ Serial.print("@ ");
Serial.println(location);
QF_INT_DISABLE(); // disable all interrupts
for (;;) { // sit in an endless loop for now
}
}
-
-//----------------------------------------------------------------------------
-// QS callbacks...
-//............................................................................
-bool QP::QS::onStartup(void const * arg) {
- static uint8_t qsTxBuf[1024]; // buffer for QS transmit channel (QS-TX)
- static uint8_t qsRxBuf[128]; // buffer for QS receive channel (QS-RX)
- initBuf (qsTxBuf, sizeof(qsTxBuf));
- rxInitBuf(qsRxBuf, sizeof(qsRxBuf));
- return true; // return success
-}
-//............................................................................
-void QP::QS::onCommand(uint8_t cmdId, uint32_t param1,
- uint32_t param2, uint32_t param3)
-{
- (void)cmdId;
- (void)param1;
- (void)param2;
- (void)param3;
-}
//............................................................................
-void QP::QS::onCleanup(void) {
+namespace BSP {
+void init(void) {
+ // initialize the hardware used in this sketch...
+ // NOTE: interrupts are configured and started later in QF::onStartup()
+ pinMode(LED_BUILTIN, OUTPUT);
+ Serial.begin(115200); // run serial port at 115200 baud rate
+ QS_INIT(nullptr);
}
//............................................................................
-QP::QSTimeCtr QP::QS::onGetTime(void) {
- return millis();
+void ledOff(void) {
+ digitalWrite(LED_BUILTIN, LOW);
+ Serial.println("led off");
}
//............................................................................
-void QP::QS::onFlush(void) {
-#ifdef QS_ON
- uint16_t len = 0xFFFFU; // big number to get as many bytes as available
- uint8_t const *buf = QS::getBlock(&len); // get continguous block of data
- while (buf != nullptr) { // data available?
- Serial.write(buf, len); // might poll until all bytes fit
- len = 0xFFFFU; // big number to get as many bytes as available
- buf = QS::getBlock(&len); // try to get more data
- }
- Serial.flush(); // wait for the transmission of outgoing data to complete
-#endif // QS_ON
+void ledOn(void) {
+ digitalWrite(LED_BUILTIN, HIGH);
+ Serial.println("led on");
}
-//............................................................................
-void QP::QS::onReset(void) {
- esp_restart();
-}
\ No newline at end of file
+} // namespace BSP
diff --git a/examples/blinky_bsp-esp32/bsp.hpp b/examples/blinky_bsp-esp32/bsp.hpp
index c1e667a..140b77d 100644
--- a/examples/blinky_bsp-esp32/bsp.hpp
+++ b/examples/blinky_bsp-esp32/bsp.hpp
@@ -1,30 +1,49 @@
-//.$file${.::bsp.hpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+//$file${.::bsp.hpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
//
// Model: blinky_bsp-esp32.qm
// File: ${.::bsp.hpp}
//
-// This code has been generated by QM 5.1.1 .
+// This code has been generated by QM 7.0.1 .
// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
//
-// This program is open source software: you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as published
-// by the Free Software Foundation.
+// Copyright (c) 2005 Quantum Leaps, LLC. All rights reserved.
//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-// for more details.
+// ____________________________________
+// / /
+// / GGGGGGG PPPPPPPP LL /
+// / GG GG PP PP LL /
+// / GG PP PP LL /
+// / GG GGGGG PPPPPPPP LL /
+// / GG GG PP LL /
+// / GGGGGGG PP LLLLLLL /
+// /___________________________________/
//
-//.$endhead${.::bsp.hpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+// This generated code is open-source software licensed under the GNU
+// General Public License (GPL) as published by the Free Software Foundation
+// (see ).
+//
+// NOTE:
+// The GPL does NOT permit the incorporation of this code into proprietary
+// programs. Please contact Quantum Leaps for commercial licensing options,
+// which expressly supersede the GPL and are designed explicitly for
+// closed-source distribution.
+//
+// Quantum Leaps contact information:
+//
+//
+//
+//$endhead${.::bsp.hpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#ifndef BSP_HPP
#define BSP_HPP
-class BSP {
-public:
+namespace BSP {
enum { TICKS_PER_SEC = CONFIG_FREERTOS_HZ} ;
- static void init(void);
- static void ledOff(void);
- static void ledOn(void);
-};
+ void init(void);
+ void ledOff(void);
+ void ledOn(void);
+}
#endif // BSP_HPP
+
diff --git a/examples/blinky_bsp-esp32/qp_config.hpp b/examples/blinky_bsp-esp32/qp_config.hpp
new file mode 100644
index 0000000..8891edf
--- /dev/null
+++ b/examples/blinky_bsp-esp32/qp_config.hpp
@@ -0,0 +1,199 @@
+//============================================================================
+// QP configuration file (generic)
+// Last updated for version: 7.3.0
+// Last updated on: 2023-10-30
+//
+// Q u a n t u m L e a P s
+// ------------------------
+// Modern Embedded Software
+//
+// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
+//
+// This software is dual-licensed under the terms of the open source GNU
+// General Public License version 3 (or any later version), or alternatively,
+// under the terms of one of the closed source Quantum Leaps commercial
+// licenses.
+//
+// The terms of the open source GNU General Public License version 3
+// can be found at:
+//
+// The terms of the closed source Quantum Leaps commercial licenses
+// can be found at:
+//
+// Redistributions in source code must retain this top-level comment block.
+// Plagiarizing this software to sidestep the license obligations is illegal.
+//
+// Contact information:
+//
+//
+//============================================================================
+#ifndef QP_CONFIG_HPP_
+#define QP_CONFIG_HPP_
+
+//-------- <<< Use Configuration Wizard in Context Menu >>> -----------------
+
+// NOTE: Requires command-line macro: QP_CONFIG
+// This qp_config.h header file is activated only when the macro
+// QP_CONFIG is defined on the command-line to the compiler
+// -------------------------------------------
+
+// QP API compatibility version (QP_API_VERSION)
+// <0=> 0 (Maximum compatibility)
+// <580=>580 (QP 5.8.0 or newer)
+// <660=>660 (QP 6.6.0 or newer)
+// <691=>691 (QP 6.9.1 or newer)
+// <700=>700 (QP 7.0.0 or newer)
+// <9999=>9999 (Latest only)
+// QP API backwards compatibility with the QP/C API version.
+// Lower QP_API_VERSION values enable backwards compatibility
+// with lower (older) QP API versions.
+// For example, QP_API_VERSION==691 will enable the compatibility
+// layer with QP version 6.9.1 and newer, but not older than 6.9.1.
+// QP_API_VERSION==0 enables the maximum currently supported
+// backwards compatibility. Conversely, QP_API_VERSION==9999 means
+// that no backwards compatibility layer should be enabled.
+// Default: 0 (All supported)
+#define QP_API_VERSION 0
+
+//..........................................................................
+// QP Functional Safety (FuSa) Subsystem (Q_UNSAFE)
+// The QP FuSa Subsystem consists of the following facilities:
+// - Software assertions as a recommended technique
+// (called Failure Assertion Programming (FAP) in IEC 61508)
+// - Software Self-Monitoring (SSM), which encompasses such techniques:
+// * Duplicate Inverse Storage for critical variables
+// * Memory Markers for critical objects (e.g., events)
+// * Hard-limits for all loops
+// * Memory Isolation by means of Memory Protection Unit (MPU)
+
+// Disable QP FuSa in development
+// Disable assertions and other self monitoring features
+// in development build configurations (NDEBUG undefined).
+// VIOLATES functional safety standards. NOT recommended !!!
+//#ifndef NDEBUG
+//#define Q_UNSAFE
+//#endif
+//
+
+// Disable QP FuSa in production release
+// Disable assertions and other self monitoring features
+// in the release build configurations (NDEBUG defined).
+// VIOLATES functional safety standards. NOT recommended !!!
+//#ifdef NDEBUG
+//#define Q_UNSAFE
+//#endif
+//
+
+//
+
+//..........................................................................
+// QEP Event Processor
+// Events and state machines.
+
+// Event signal size (Q_SIGNAL_SIZE)
+// <1U=>1
+// <2U=>2 (default)
+// <4U=>4
+// Size of the QEvt signal for QEP/QF [bytes]
+// Default: 2
+#define Q_SIGNAL_SIZE 2U
+
+//
+
+//..........................................................................
+// QF Framework
+// Active Object framework
+
+// Maximum # Active Objects (QF_MAX_ACTIVE) <1-64>
+// Maximum # Active Objects in the system <1..64>
+// Default: 32
+#define QF_MAX_ACTIVE 8U
+
+// Maximum # event pools (QF_MAX_EPOOL)
+// <0=>0 no event pools
+// <1=>1 <2=>2 <3=>3 (default) <4=>4 <5=>5
+// <6=>6 <7=>7 <8=>8 <9=>9 <10=>10 <11=>11
+// <12=>12 <13=>13 <14=>14 <15=>15
+// Maximum # Event Pools <1..15>
+// Default: 3
+#define QF_MAX_EPOOL 3U
+
+// Maximum # clock tick rates (QF_MAX_TICK_RATE)
+// <0=>0 no time events
+// <1=>1 (default) <2=>2 <3=>3 <4=>4 <5=>5
+// <6=>6 <7=>7 <8=>8 <9=>9 <10=>10 <11=>11
+// <12=>12 <13=>13 <14=>14 <15=>15
+// Maximum # clock tick rates for time events <1..15>
+// Default: 1
+#define QF_MAX_TICK_RATE 1U
+
+// Dynamic Event Constructor (QEVT_DYN_CTOR)
+// Dynamic Event Constructor (RAII)
+//#define QEVT_DYN_CTOR
+//
+
+// Provide destructors for QP classes
+// Destructors for classes
+//#define Q_XTOR
+//
+
+// Active Object stop API (QACTIVE_CAN_STOP)
+// Enable Active Object stop API (Not recommended)
+//#define QACTIVE_CAN_STOP
+//
+
+// Event size (QF_EVENT_SIZ_SIZE)
+// <1U=>1
+// <2U=>2 (default)
+// <4U=>4
+// Size of the dynamic events for QF [bytes]
+// Default: 2 (64K bytes maximum event size)
+#define QF_EVENT_SIZ_SIZE 2U
+
+// Time event counter size (QF_TIMEEVT_CTR_SIZE)
+// <1U=>1
+// <2U=>2
+// <4U=>4 (default)
+// Size of the QTimeEvt counter [bytes]
+// Default: 4 (2^32 dynamic range)
+#define QF_TIMEEVT_CTR_SIZE 4U
+
+// Event queue counter size (QF_EQUEUE_CTR_SIZE)
+// <1U=>1 (default)
+// <2U=>2
+// <4U=>4
+// Size of event queue counter [bytes]
+// Default: 1 (255 events maximum in a queue)
+#define QF_EQUEUE_CTR_SIZE 1U
+
+// Memory pool counter size (QF_MPOOL_CTR_SIZE)
+// <1U=>1
+// <2U=>2 (default)
+// <4U=>4
+// Size of memory pool counter [bytes]
+// Default: 2 (64K blocks maximum in a pool)
+#define QF_MPOOL_CTR_SIZE 2U
+
+// Memory block size (QF_MPOOL_SIZ_SIZE)
+// <1U=>1
+// <2U=>2 (default)
+// <4U=>4
+// Size of memory pool block [bytes]
+// Default: 2 (64K bytes maximum block size)
+#define QF_MPOOL_SIZ_SIZE 2U
+
+//
+
+// Select the CPU at which the QP Framework will be attached
+#define QP_PINNED_TO_CORE_0
+//#define QP_PINNED_TO_CORE_1
+
+// Select QACTIVE_THREAD_TYPE
+// <0U=> Dynamic thread
+// <1U=> Static thread
+#define QP_STATIC_THREAD 0U
+//------------- <<< end of configuration section >>> -----------------------
+
+#endif // QP_CONFIG_HPP_
diff --git a/examples/dpp_bsp-esp32/bsp.cpp b/examples/dpp_bsp-esp32/bsp.cpp
index 08c1de4..a82a47c 100644
--- a/examples/dpp_bsp-esp32/bsp.cpp
+++ b/examples/dpp_bsp-esp32/bsp.cpp
@@ -1,138 +1,122 @@
-//.$file${.::bsp.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+//$file${.::bsp.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
//
// Model: dpp_bsp-esp32.qm
// File: ${.::bsp.cpp}
//
-// This code has been generated by QM 5.1.1 .
+// This code has been generated by QM 7.0.1 .
// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
//
-// This program is open source software: you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as published
-// by the Free Software Foundation.
+// Copyright (c) 2005 Quantum Leaps, LLC. All rights reserved.
//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-// for more details.
+// ____________________________________
+// / /
+// / GGGGGGG PPPPPPPP LL /
+// / GG GG PP PP LL /
+// / GG PP PP LL /
+// / GG GGGGG PPPPPPPP LL /
+// / GG GG PP LL /
+// / GGGGGGG PP LLLLLLL /
+// /___________________________________/
//
-//.$endhead${.::bsp.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+// This generated code is open-source software licensed under the GNU
+// General Public License (GPL) as published by the Free Software Foundation
+// (see ).
+//
+// NOTE:
+// The GPL does NOT permit the incorporation of this code into proprietary
+// programs. Please contact Quantum Leaps for commercial licensing options,
+// which expressly supersede the GPL and are designed explicitly for
+// closed-source distribution.
+//
+// Quantum Leaps contact information:
+//
+//
+//
+//$endhead${.::bsp.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#include "qpcpp.hpp" // QP-C++ framework
#include "dpp.hpp" // DPP application
#include "bsp.hpp" // Board Support Package
#include
#include "esp_freertos_hooks.h"
-#ifndef LED_BUILTIN //If current ESP32 board does not define LED_BUILTIN
-static constexpr unsigned LED_BUILTIN=13U;
+//If current ESP32 board does not define LED_BUILTIN
+#ifndef LED_BUILTIN
+#define LED_BUILTIN 2U
#endif
-using namespace QP;
-static uint8_t const l_TickHook = static_cast(0);
-
-//............................................................................
-// QS facilities
-
-// un-comment if QS instrumentation needed
-//#define QS_ON
-
-enum AppRecords { // application-specific QS trace records
- PHILO_STAT = QP::QS_USER,
-};
-
-static QP::QSpyId const l_TIMER_ID = { 0U }; // QSpy source ID
-
//----------------------------------------------------------------------------
// BSP functions
-
-static void tickHook_ESP32(void); /*Tick hook for QP */
-
static void tickHook_ESP32(void)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* process time events for rate 0 */
- QTimeEvt::tickFromISR_(0U,&xHigherPriorityTaskWoken, &l_TickHook);
+ QP::QTimeEvt::TICK_FROM_ISR(&xHigherPriorityTaskWoken, &l_TIMER_ID);
/* notify FreeRTOS to perform context switch from ISR, if needed */
if(xHigherPriorityTaskWoken) {
portYIELD_FROM_ISR();
}
-#ifndef QS_ON
- if (Serial.available() > 0) {
- switch (Serial.read()) { // read the incoming byte
- case 'p':
- case 'P':
- static QEvt const pauseEvt = { PAUSE_SIG, 0U, 0U};
- QF::PUBLISH(&pauseEvt, &l_TIMER_ID);
- break;
- case 's':
- case 'S':
- static QEvt const serveEvt = { SERVE_SIG, 0U, 0U};
- QF::PUBLISH(&serveEvt, &l_TIMER_ID);
- break;
- }
+}
+//............................................................................
+void QP::QF::onStartup(void) {
+ esp_register_freertos_tick_hook_for_cpu(tickHook_ESP32, QP_CPU_NUM);
+}
+//............................................................................
+extern "C" Q_NORETURN Q_onAssert(char const * const module, int location) {
+ //
+ // NOTE: add here your application-specific error handling
+ //
+ (void)module;
+ (void)location;
+ Serial.print("QP Assert module: ");
+ Serial.print(module);
+ Serial.print("@ ");
+ Serial.println(location);
+ QF_INT_DISABLE(); // disable all interrupts
+ for (;;) { // sit in an endless loop for now
}
-#endif
}
-
-void BSP::init(void) {
+//............................................................................
+namespace BSP {
+void init(void) {
// initialize the hardware used in this sketch...
// NOTE: interrupts are configured and started later in QF::onStartup()
pinMode(LED_BUILTIN, OUTPUT);
randomSeed(1234); // seed the Random Number Generator
Serial.begin(115200); // set the highest stanard baud rate of 115200 bps
- QS_INIT(nullptr);
-#ifdef QS_ON
- // output QS dictionaries
- QS_OBJ_DICTIONARY(&l_TIMER_ID);
- QS_USR_DICTIONARY(PHILO_STAT);
-
- // setup the QS filters...
- QS_GLB_FILTER(QP::QS_SM_RECORDS); // state machine records
- QS_GLB_FILTER(QP::QS_AO_RECORDS); // active object records
- QS_GLB_FILTER(QP::QS_UA_RECORDS); // all user records
-#else
Serial.print("QP-C++: ");
Serial.print(QP_VERSION_STR);
Serial.println("");
-#endif
}
//............................................................................
-void BSP::displayPhilStat(uint8_t n, char_t const *stat) {
-#ifdef QS_ON
- QS_BEGIN_ID(PHILO_STAT, AO_Philo[n]->m_prio) // app-specific record begin
- QS_U8(1, n); // Philo number
- QS_STR(stat); // Philo status
- QS_END()
-#else
+void displayPhilStat(uint8_t n, char_t const *stat) {
+
Serial.print("Philosopher ");
Serial.write(48+n);
Serial.print(" ");
Serial.println(stat);
-#endif
}
//............................................................................
-void BSP::displayPaused(uint8_t paused) {
+void displayPaused(uint8_t paused) {
char const *msg = paused ? "Paused ON" : "Paused OFF";
-#ifndef QS_ON
- Serial.println(msg);
-#endif
}
//............................................................................
-void BSP::ledOff(void) {
+void ledOff(void) {
digitalWrite(LED_BUILTIN, LOW);
}
//............................................................................
-void BSP::ledOn(void) {
+void ledOn(void) {
digitalWrite(LED_BUILTIN, HIGH);
}
-
//............................................................................
static uint32_t l_rnd; // random seed
-void BSP::randomSeed(uint32_t seed) {
+void randomSeed(uint32_t seed) {
l_rnd = seed;
}
//............................................................................
-uint32_t BSP::random(void) { // a very cheap pseudo-random-number generator
+uint32_t random(void) { // a very cheap pseudo-random-number generator
// "Super-Duper" Linear Congruential Generator (LCG)
// LCG(2^32, 3*7*11*13*23, 0, seed)
//
@@ -140,105 +124,4 @@ uint32_t BSP::random(void) { // a very cheap pseudo-random-number generator
l_rnd = rnd; // set for the next time
return (rnd >> 8);
}
-
-//............................................................................
-void QSpy_Task(void *) {
- while(1)
- {
- // transmit QS outgoing data (QS-TX)
- uint16_t len = Serial.availableForWrite();
- if (len > 0U) { // any space available in the output buffer?
- uint8_t const *buf = QS::getBlock(&len);
- if (buf) {
- Serial.write(buf, len); // asynchronous and non-blocking
- }
- }
-
- // receive QS incoming data (QS-RX)
- len = Serial.available();
- if (len > 0U) {
- do {
- QP::QS::rxPut(Serial.read());
- } while (--len > 0U);
- QS::rxParse();
- }
- delay(100);
- };
-}
-
-void QF::onStartup(void) {
- esp_register_freertos_tick_hook_for_cpu(tickHook_ESP32, QP_CPU_NUM);
- QS_OBJ_DICTIONARY(&l_TickHook);
-#ifdef QS_ON
- xTaskCreatePinnedToCore(
- QSpy_Task, /* Function to implement the task */
- "QSPY", /* Name of the task */
- 10000, /* Stack size in words */
- NULL, /* Task input parameter */
- configMAX_PRIORITIES-1, /* Priority of the task */
- NULL, /* Task handle. */
- QP_CPU_NUM); /* Core where the task should run */
-#endif
-}
-//............................................................................
-
-//............................................................................
-extern "C" Q_NORETURN Q_onAssert(char const * const module, int location) {
- //
- // NOTE: add here your application-specific error handling
- //
- (void)module;
- (void)location;
- Serial.print("QP Assert module:");
- Serial.print(module);
- Serial.print(",");
- Serial.println(location);
- QF_INT_DISABLE(); // disable all interrupts
- for (;;) { // sit in an endless loop for now
- }
-}
-
-//----------------------------------------------------------------------------
-// QS callbacks...
-//............................................................................
-bool QP::QS::onStartup(void const * arg) {
- static uint8_t qsTxBuf[1024]; // buffer for QS transmit channel (QS-TX)
- static uint8_t qsRxBuf[128]; // buffer for QS receive channel (QS-RX)
- initBuf (qsTxBuf, sizeof(qsTxBuf));
- rxInitBuf(qsRxBuf, sizeof(qsRxBuf));
- return true; // return success
-}
-//............................................................................
-void QP::QS::onCommand(uint8_t cmdId, uint32_t param1,
- uint32_t param2, uint32_t param3)
-{
-}
-//............................................................................
-void QP::QS::onCleanup(void) {
-}
-//............................................................................
-QP::QSTimeCtr QP::QS::onGetTime(void) {
-#ifdef QS_ON
- return millis();
-#else
- return 0;
-#endif
-
-}
-//............................................................................
-void QP::QS::onFlush(void) {
-#ifdef QS_ON
- uint16_t len = 0xFFFFU; // big number to get as many bytes as available
- uint8_t const *buf = QS::getBlock(&len); // get continguous block of data
- while (buf != nullptr) { // data available?
- Serial.write(buf, len); // might poll until all bytes fit
- len = 0xFFFFU; // big number to get as many bytes as available
- buf = QS::getBlock(&len); // try to get more data
- }
- Serial.flush(); // wait for the transmission of outgoing data to complete
-#endif // QS_ON
-}
-//............................................................................
-void QP::QS::onReset(void) {
- esp_restart();
-}
+} // namespace BSP
diff --git a/examples/dpp_bsp-esp32/bsp.hpp b/examples/dpp_bsp-esp32/bsp.hpp
index 59d6c50..903d921 100644
--- a/examples/dpp_bsp-esp32/bsp.hpp
+++ b/examples/dpp_bsp-esp32/bsp.hpp
@@ -1,39 +1,55 @@
-//.$file${.::bsp.hpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+//$file${.::bsp.hpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
//
// Model: dpp_bsp-esp32.qm
// File: ${.::bsp.hpp}
//
-// This code has been generated by QM 5.1.1 .
+// This code has been generated by QM 7.0.1 .
// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
//
-// This program is open source software: you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as published
-// by the Free Software Foundation.
+// Copyright (c) 2005 Quantum Leaps, LLC. All rights reserved.
//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-// for more details.
+// ____________________________________
+// / /
+// / GGGGGGG PPPPPPPP LL /
+// / GG GG PP PP LL /
+// / GG PP PP LL /
+// / GG GGGGG PPPPPPPP LL /
+// / GG GG PP LL /
+// / GGGGGGG PP LLLLLLL /
+// /___________________________________/
//
-//.$endhead${.::bsp.hpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+// This generated code is open-source software licensed under the GNU
+// General Public License (GPL) as published by the Free Software Foundation
+// (see ).
+//
+// NOTE:
+// The GPL does NOT permit the incorporation of this code into proprietary
+// programs. Please contact Quantum Leaps for commercial licensing options,
+// which expressly supersede the GPL and are designed explicitly for
+// closed-source distribution.
+//
+// Quantum Leaps contact information:
+//
+//
+//
+//$endhead${.::bsp.hpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#ifndef BSP_HPP
#define BSP_HPP
-class BSP {
-public:
+namespace BSP {
enum { TICKS_PER_SEC = CONFIG_FREERTOS_HZ} ;
- static void init(void);
- static void displayPaused(uint8_t const paused);
- static void displayPhilStat(uint8_t const n, char_t const *stat);
- static void terminate(int16_t const result);
+ void init(void);
+ void displayPaused(uint8_t const paused);
+ void displayPhilStat(uint8_t const n, char_t const *stat);
- static void randomSeed(uint32_t const seed); // random seed
- static uint32_t random(void); // pseudo-random generator
- static QP::QTimeEvtCtr think_rnd_time();
- static QP::QTimeEvtCtr eat_rnd_time();
+ void randomSeed(uint32_t const seed); // random seed
+ uint32_t random(void); // pseudo-random generator
- static void ledOff(void);
- static void ledOn(void);
+ void ledOff(void);
+ void ledOn(void);
};
#endif // BSP_HPP
+
diff --git a/examples/dpp_bsp-esp32/dpp.hpp b/examples/dpp_bsp-esp32/dpp.hpp
index e045ab4..3c21b07 100644
--- a/examples/dpp_bsp-esp32/dpp.hpp
+++ b/examples/dpp_bsp-esp32/dpp.hpp
@@ -1,21 +1,40 @@
-//.$file${.::dpp.hpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+//$file${.::dpp.hpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
//
// Model: dpp_bsp-esp32.qm
// File: ${.::dpp.hpp}
//
-// This code has been generated by QM 5.1.1 .
+// This code has been generated by QM 7.0.1 .
// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
//
-// This program is open source software: you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as published
-// by the Free Software Foundation.
+// Copyright (c) 2005 Quantum Leaps, LLC. All rights reserved.
//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-// for more details.
+// ____________________________________
+// / /
+// / GGGGGGG PPPPPPPP LL /
+// / GG GG PP PP LL /
+// / GG PP PP LL /
+// / GG GGGGG PPPPPPPP LL /
+// / GG GG PP LL /
+// / GGGGGGG PP LLLLLLL /
+// /___________________________________/
//
-//.$endhead${.::dpp.hpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+// This generated code is open-source software licensed under the GNU
+// General Public License (GPL) as published by the Free Software Foundation
+// (see ).
+//
+// NOTE:
+// The GPL does NOT permit the incorporation of this code into proprietary
+// programs. Please contact Quantum Leaps for commercial licensing options,
+// which expressly supersede the GPL and are designed explicitly for
+// closed-source distribution.
+//
+// Quantum Leaps contact information:
+//
+//
+//
+//$endhead${.::dpp.hpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#ifndef DPP_HPP
#define DPP_HPP
@@ -33,23 +52,29 @@ enum Signals {
};
// generate declarations all event classes
-//.$declare${Events} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-//.${Events::TableEvt} .......................................................
+//$declare${Events} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+
+//${Events::TableEvt} ........................................................
class TableEvt : public QP::QEvt {
public:
uint8_t philoNum;
-};
-//.$enddecl${Events} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+}; // class TableEvt
+//$enddecl${Events} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// number of philosophers
enum { N_PHILO = 5 };
// generate declarations of all opaque pointers...
-//.$declare${AOs::AO_Philo[N_PHILO]} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+//$declare${AOs::AO_Philo[N_PHILO]} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+
+//${AOs::AO_Philo[N_PHILO]} ..................................................
extern QP::QActive * const AO_Philo[N_PHILO];
-//.$enddecl${AOs::AO_Philo[N_PHILO]} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//.$declare${AOs::AO_Table} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+//$enddecl${AOs::AO_Philo[N_PHILO]} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//$declare${AOs::AO_Table} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+
+//${AOs::AO_Table} ...........................................................
extern QP::QActive * const AO_Table;
-//.$enddecl${AOs::AO_Table} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//$enddecl${AOs::AO_Table} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#endif // DPP_HPP
+
diff --git a/examples/dpp_bsp-esp32/dpp_bsp-esp32.ino b/examples/dpp_bsp-esp32/dpp_bsp-esp32.ino
index b6160db..d16db1d 100644
--- a/examples/dpp_bsp-esp32/dpp_bsp-esp32.ino
+++ b/examples/dpp_bsp-esp32/dpp_bsp-esp32.ino
@@ -1,27 +1,46 @@
-//.$file${.::dpp_bsp-esp32.ino} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+//$file${.::dpp_bsp-esp32.ino} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
//
// Model: dpp_bsp-esp32.qm
// File: ${.::dpp_bsp-esp32.ino}
//
-// This code has been generated by QM 5.1.1 .
+// This code has been generated by QM 7.0.1 .
// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
//
-// This program is open source software: you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as published
-// by the Free Software Foundation.
+// Copyright (c) 2005 Quantum Leaps, LLC. All rights reserved.
//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-// for more details.
+// ____________________________________
+// / /
+// / GGGGGGG PPPPPPPP LL /
+// / GG GG PP PP LL /
+// / GG PP PP LL /
+// / GG GGGGG PPPPPPPP LL /
+// / GG GG PP LL /
+// / GGGGGGG PP LLLLLLL /
+// /___________________________________/
//
-//.$endhead${.::dpp_bsp-esp32.ino} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+// This generated code is open-source software licensed under the GNU
+// General Public License (GPL) as published by the Free Software Foundation
+// (see ).
+//
+// NOTE:
+// The GPL does NOT permit the incorporation of this code into proprietary
+// programs. Please contact Quantum Leaps for commercial licensing options,
+// which expressly supersede the GPL and are designed explicitly for
+// closed-source distribution.
+//
+// Quantum Leaps contact information:
+//
+//
+//
+//$endhead${.::dpp_bsp-esp32.ino} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#include "qpcpp.hpp" // QP-C++ framework
#include "dpp.hpp" // DPP application
#include "bsp.hpp" // Board Support Package
using namespace QP;
-static constexpr unsigned stack_size = 1000;
+static constexpr unsigned stack_size = 2048;
Q_DEFINE_THIS_FILE
@@ -43,16 +62,23 @@ void setup() {
// start Philos
static QP::QEvt const *philoQueueSto[10][N_PHILO];
+ static StackType_t philoStack[10][stack_size];
for (uint8_t n = 0U; n < N_PHILO; ++n) {
AO_Philo[n]->start((uint_fast8_t)(n + 1U), // priority
- philoQueueSto[n], Q_DIM(philoQueueSto[n]),
- (void *)0, stack_size);
+ philoQueueSto[n],
+ Q_DIM(philoQueueSto[n]),
+ philoStack[n],
+ stack_size);
}
// start Table
static QP::QEvt const *tableQueueSto[N_PHILO];
- AO_Table->start((uint_fast8_t)(N_PHILO + 1U), // priority
- tableQueueSto, Q_DIM(tableQueueSto),
- (void *)0, stack_size);
+ static StackType_t tableStack[stack_size];
+ AO_Table->start(
+ (uint_fast8_t)(N_PHILO + 1U), // priority
+ tableQueueSto,
+ Q_DIM(tableQueueSto),
+ tableStack,
+ stack_size);
QF::run(); // run the QF/C++ framework
}
diff --git a/examples/dpp_bsp-esp32/dpp_bsp-esp32.qm b/examples/dpp_bsp-esp32/dpp_bsp-esp32.qm
index 4f99518..6635b41 100644
--- a/examples/dpp_bsp-esp32/dpp_bsp-esp32.qm
+++ b/examples/dpp_bsp-esp32/dpp_bsp-esp32.qm
@@ -1,5 +1,5 @@
-
+
This is the Dining Philosopher Problem (DPP) example for the Arduino-ESP32 board. The example demonstrates:
1. Multiple active objects (5 Philosophers and 1 Table AO)
@@ -109,8 +109,8 @@ Q_ASSERT(Q_EVT_CAST(TableEvt)->philoNum != PHILO_ID(this));
-
-
+
+
@@ -140,7 +140,7 @@ Q_ASSERT(Q_EVT_CAST(TableEvt)->philoNum != PHILO_ID(this));
-
+
@@ -165,8 +165,8 @@ Q_ASSERT(Q_EVT_CAST(TableEvt)->philoNum != PHILO_ID(this));
-
-
+
+
@@ -338,7 +338,7 @@ if (m_isHungry[m] && (m_fork[n] == FREE)) {
-
+
@@ -380,8 +380,8 @@ m_fork[n] = FREE;
-
-
+
+
@@ -406,73 +406,22 @@ m_fork[n] = FREE;
-
-
- #include "qpcpp.hpp" // QP-C++ framework
-#include "dpp.hpp" // DPP application
-#include "bsp.hpp" // Board Support Package
-
-using namespace QP;
-static constexpr unsigned stack_size = 1000;
-
-Q_DEFINE_THIS_FILE
-
-//............................................................................
-void setup() {
- QF::init(); // initialize the framework
- BSP::init(); // initialize the Board Support Package
-
- // init publish-subscribe
- static QSubscrList subscrSto[MAX_PUB_SIG];
- QF::psInit(subscrSto, Q_DIM(subscrSto));
-
- // initialize event pools...
- static QF_MPOOL_EL(TableEvt) smlPoolSto[2*N_PHILO];
- QF::poolInit(smlPoolSto,
- sizeof(smlPoolSto), sizeof(smlPoolSto[0]));
-
- // start all active objects...
-
- // start Philos
- static QP::QEvt const *philoQueueSto[10][N_PHILO];
- for (uint8_t n = 0U; n < N_PHILO; ++n) {
- AO_Philo[n]->start((uint_fast8_t)(n + 1U), // priority
- philoQueueSto[n], Q_DIM(philoQueueSto[n]),
- (void *)0, stack_size);
- }
- // start Table
- static QP::QEvt const *tableQueueSto[N_PHILO];
- AO_Table->start((uint_fast8_t)(N_PHILO + 1U), // priority
- tableQueueSto, Q_DIM(tableQueueSto),
- (void *)0, stack_size);
- QF::run(); // run the QF/C++ framework
-}
-
-//............................................................................
-void loop() {
-}
-
-
#ifndef BSP_HPP
#define BSP_HPP
-class BSP {
-public:
+namespace BSP {
enum { TICKS_PER_SEC = CONFIG_FREERTOS_HZ} ;
- static void init(void);
- static void displayPaused(uint8_t const paused);
- static void displayPhilStat(uint8_t const n, char_t const *stat);
- static void terminate(int16_t const result);
-
- static void randomSeed(uint32_t const seed); // random seed
- static uint32_t random(void); // pseudo-random generator
- static QP::QTimeEvtCtr think_rnd_time();
- static QP::QTimeEvtCtr eat_rnd_time();
-
- static void ledOff(void);
- static void ledOn(void);
+ void init(void);
+ void displayPaused(uint8_t const paused);
+ void displayPhilStat(uint8_t const n, char_t const *stat);
+
+ void randomSeed(uint32_t const seed); // random seed
+ uint32_t random(void); // pseudo-random generator
+
+ void ledOff(void);
+ void ledOn(void);
};
#endif // BSP_HPP
@@ -486,116 +435,82 @@ public:
#include <Arduino.h>
#include "esp_freertos_hooks.h"
-#ifndef LED_BUILTIN //If current ESP32 board does not define LED_BUILTIN
-static constexpr unsigned LED_BUILTIN=13U;
+//If current ESP32 board does not define LED_BUILTIN
+#ifndef LED_BUILTIN
+#define LED_BUILTIN 2U
#endif
-using namespace QP;
-
-//............................................................................
-// QS facilities
-
-// un-comment if QS instrumentation needed
-//#define QS_ON
-
-enum AppRecords { // application-specific QS trace records
- PHILO_STAT = QP::QS_USER,
-};
-
-static QP::QSpyId const l_TIMER_ID = { 0U }; // QSpy source ID
-
//----------------------------------------------------------------------------
// BSP functions
-
-static void tickHook_ESP32(void); /*Tick hook for QP */
-
static void tickHook_ESP32(void)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* process time events for rate 0 */
- QF::TICK_FROM_ISR(&xHigherPriorityTaskWoken, &l_TIMER_ID);
+ QP::QTimeEvt::TICK_FROM_ISR(&xHigherPriorityTaskWoken, &l_TIMER_ID);
/* notify FreeRTOS to perform context switch from ISR, if needed */
if(xHigherPriorityTaskWoken) {
portYIELD_FROM_ISR();
}
-#ifndef QS_ON
- if (Serial.available() > 0) {
- switch (Serial.read()) { // read the incoming byte
- case 'p':
- case 'P':
- static QEvt const pauseEvt = { PAUSE_SIG, 0U, 0U};
- QF::PUBLISH(&pauseEvt, &l_TIMER_ID);
- break;
- case 's':
- case 'S':
- static QEvt const serveEvt = { SERVE_SIG, 0U, 0U};
- QF::PUBLISH(&serveEvt, &l_TIMER_ID);
- break;
- }
+}
+//............................................................................
+void QP::QF::onStartup(void) {
+ esp_register_freertos_tick_hook_for_cpu(tickHook_ESP32, QP_CPU_NUM);
+}
+//............................................................................
+extern "C" Q_NORETURN Q_onAssert(char const * const module, int location) {
+ //
+ // NOTE: add here your application-specific error handling
+ //
+ (void)module;
+ (void)location;
+ Serial.print("QP Assert module: ");
+ Serial.print(module);
+ Serial.print("@ ");
+ Serial.println(location);
+ QF_INT_DISABLE(); // disable all interrupts
+ for (;;) { // sit in an endless loop for now
}
-#endif
}
-
-void BSP::init(void) {
+//............................................................................
+namespace BSP {
+void init(void) {
// initialize the hardware used in this sketch...
// NOTE: interrupts are configured and started later in QF::onStartup()
pinMode(LED_BUILTIN, OUTPUT);
randomSeed(1234); // seed the Random Number Generator
Serial.begin(115200); // set the highest stanard baud rate of 115200 bps
- QS_INIT(nullptr);
-#ifdef QS_ON
- // output QS dictionaries
- QS_OBJ_DICTIONARY(&l_TIMER_ID);
- QS_USR_DICTIONARY(PHILO_STAT);
-
- // setup the QS filters...
- QS_GLB_FILTER(QP::QS_SM_RECORDS); // state machine records
- QS_GLB_FILTER(QP::QS_AO_RECORDS); // active object records
- QS_GLB_FILTER(QP::QS_UA_RECORDS); // all user records
-#else
Serial.print("QP-C++: ");
Serial.print(QP_VERSION_STR);
Serial.println("");
-#endif
}
//............................................................................
-void BSP::displayPhilStat(uint8_t n, char_t const *stat) {
-#ifdef QS_ON
- QS_BEGIN_ID(PHILO_STAT, AO_Philo[n]->m_prio) // app-specific record begin
- QS_U8(1, n); // Philo number
- QS_STR(stat); // Philo status
- QS_END()
-#else
+void displayPhilStat(uint8_t n, char_t const *stat) {
+
Serial.print("Philosopher ");
Serial.write(48+n);
Serial.print(" ");
Serial.println(stat);
-#endif
}
//............................................................................
-void BSP::displayPaused(uint8_t paused) {
+void displayPaused(uint8_t paused) {
char const *msg = paused ? "Paused ON" : "Paused OFF";
-#ifndef QS_ON
- Serial.println(msg);
-#endif
}
//............................................................................
-void BSP::ledOff(void) {
+void ledOff(void) {
digitalWrite(LED_BUILTIN, LOW);
}
//............................................................................
-void BSP::ledOn(void) {
+void ledOn(void) {
digitalWrite(LED_BUILTIN, HIGH);
}
-
//............................................................................
static uint32_t l_rnd; // random seed
-void BSP::randomSeed(uint32_t seed) {
+void randomSeed(uint32_t seed) {
l_rnd = seed;
}
//............................................................................
-uint32_t BSP::random(void) { // a very cheap pseudo-random-number generator
+uint32_t random(void) { // a very cheap pseudo-random-number generator
// "Super-Duper" Linear Congruential Generator (LCG)
// LCG(2^32, 3*7*11*13*23, 0, seed)
//
@@ -603,108 +518,7 @@ uint32_t BSP::random(void) { // a very cheap pseudo-random-number generator
l_rnd = rnd; // set for the next time
return (rnd >> 8);
}
-
-//............................................................................
-void QSpy_Task(void *) {
- while(1)
- {
- // transmit QS outgoing data (QS-TX)
- uint16_t len = Serial.availableForWrite();
- if (len > 0U) { // any space available in the output buffer?
- uint8_t const *buf = QS::getBlock(&len);
- if (buf) {
- Serial.write(buf, len); // asynchronous and non-blocking
- }
- }
-
- // receive QS incoming data (QS-RX)
- len = Serial.available();
- if (len > 0U) {
- do {
- QP::QS::rxPut(Serial.read());
- } while (--len > 0U);
- QS::rxParse();
- }
- delay(100);
- };
-}
-
-void QF::onStartup(void) {
- esp_register_freertos_tick_hook_for_cpu(tickHook_ESP32, QP_CPU_NUM);
-#ifdef QS_ON
- xTaskCreatePinnedToCore(
- QSpy_Task, /* Function to implement the task */
- "QSPY", /* Name of the task */
- 10000, /* Stack size in words */
- NULL, /* Task input parameter */
- configMAX_PRIORITIES-1, /* Priority of the task */
- NULL, /* Task handle. */
- QP_CPU_NUM); /* Core where the task should run */
-#endif
-}
-//............................................................................
-
-//............................................................................
-extern "C" Q_NORETURN Q_onAssert(char const * const module, int location) {
- //
- // NOTE: add here your application-specific error handling
- //
- (void)module;
- (void)location;
- Serial.print("QP Assert module:");
- Serial.print(module);
- Serial.print(",");
- Serial.println(location);
- QF_INT_DISABLE(); // disable all interrupts
- for (;;) { // sit in an endless loop for now
- }
-}
-
-//----------------------------------------------------------------------------
-// QS callbacks...
-//............................................................................
-bool QP::QS::onStartup(void const * arg) {
- static uint8_t qsTxBuf[1024]; // buffer for QS transmit channel (QS-TX)
- static uint8_t qsRxBuf[128]; // buffer for QS receive channel (QS-RX)
- initBuf (qsTxBuf, sizeof(qsTxBuf));
- rxInitBuf(qsRxBuf, sizeof(qsRxBuf));
- return true; // return success
-}
-//............................................................................
-void QP::QS::onCommand(uint8_t cmdId, uint32_t param1,
- uint32_t param2, uint32_t param3)
-{
-}
-//............................................................................
-void QP::QS::onCleanup(void) {
-}
-//............................................................................
-QP::QSTimeCtr QP::QS::onGetTime(void) {
-#ifdef QS_ON
- return millis();
-#else
- return 0;
-#endif
-
-}
-//............................................................................
-void QP::QS::onFlush(void) {
-#ifdef QS_ON
- uint16_t len = 0xFFFFU; // big number to get as many bytes as available
- uint8_t const *buf = QS::getBlock(&len); // get continguous block of data
- while (buf != nullptr) { // data available?
- Serial.write(buf, len); // might poll until all bytes fit
- len = 0xFFFFU; // big number to get as many bytes as available
- buf = QS::getBlock(&len); // try to get more data
- }
- Serial.flush(); // wait for the transmission of outgoing data to complete
-#endif // QS_ON
-}
-//............................................................................
-void QP::QS::onReset(void) {
- esp_restart();
-}
-
+} // namespace BSP
@@ -807,5 +621,58 @@ static char const * const EATING = "eating ";
$define${AOs::Table}
+
+
+ #include "qpcpp.hpp" // QP-C++ framework
+#include "dpp.hpp" // DPP application
+#include "bsp.hpp" // Board Support Package
+
+using namespace QP;
+static constexpr unsigned stack_size = 2048;
+
+Q_DEFINE_THIS_FILE
+
+//............................................................................
+void setup() {
+ QF::init(); // initialize the framework
+ BSP::init(); // initialize the Board Support Package
+
+ // init publish-subscribe
+ static QSubscrList subscrSto[MAX_PUB_SIG];
+ QF::psInit(subscrSto, Q_DIM(subscrSto));
+
+ // initialize event pools...
+ static QF_MPOOL_EL(TableEvt) smlPoolSto[2*N_PHILO];
+ QF::poolInit(smlPoolSto,
+ sizeof(smlPoolSto), sizeof(smlPoolSto[0]));
+
+ // start all active objects...
+
+ // start Philos
+ static QP::QEvt const *philoQueueSto[10][N_PHILO];
+ static StackType_t philoStack[10][stack_size];
+ for (uint8_t n = 0U; n < N_PHILO; ++n) {
+ AO_Philo[n]->start((uint_fast8_t)(n + 1U), // priority
+ philoQueueSto[n],
+ Q_DIM(philoQueueSto[n]),
+ philoStack[n],
+ stack_size);
+ }
+ // start Table
+ static QP::QEvt const *tableQueueSto[N_PHILO];
+ static StackType_t tableStack[stack_size];
+ AO_Table->start(
+ (uint_fast8_t)(N_PHILO + 1U), // priority
+ tableQueueSto,
+ Q_DIM(tableQueueSto),
+ tableStack,
+ stack_size);
+ QF::run(); // run the QF/C++ framework
+}
+
+//............................................................................
+void loop() {
+}
+
diff --git a/examples/dpp_bsp-esp32/philo.cpp b/examples/dpp_bsp-esp32/philo.cpp
index 3e8dd81..b5745bc 100644
--- a/examples/dpp_bsp-esp32/philo.cpp
+++ b/examples/dpp_bsp-esp32/philo.cpp
@@ -1,21 +1,40 @@
-//.$file${.::philo.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+//$file${.::philo.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
//
// Model: dpp_bsp-esp32.qm
// File: ${.::philo.cpp}
//
-// This code has been generated by QM 5.1.1 .
+// This code has been generated by QM 7.0.1 .
// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
//
-// This program is open source software: you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as published
-// by the Free Software Foundation.
+// Copyright (c) 2005 Quantum Leaps, LLC. All rights reserved.
//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-// for more details.
+// ____________________________________
+// / /
+// / GGGGGGG PPPPPPPP LL /
+// / GG GG PP PP LL /
+// / GG PP PP LL /
+// / GG GGGGG PPPPPPPP LL /
+// / GG GG PP LL /
+// / GGGGGGG PP LLLLLLL /
+// /___________________________________/
//
-//.$endhead${.::philo.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+// This generated code is open-source software licensed under the GNU
+// General Public License (GPL) as published by the Free Software Foundation
+// (see ).
+//
+// NOTE:
+// The GPL does NOT permit the incorporation of this code into proprietary
+// programs. Please contact Quantum Leaps for commercial licensing options,
+// which expressly supersede the GPL and are designed explicitly for
+// closed-source distribution.
+//
+// Quantum Leaps contact information:
+//
+//
+//
+//$endhead${.::philo.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#include "qpcpp.hpp" // QP-C++ framework
#include "dpp.hpp" // DPP application
#include "bsp.hpp" // Board Support Package
@@ -23,8 +42,9 @@
Q_DEFINE_THIS_FILE
// generate declaration of the active object ---------------------------------
-//.$declare${AOs::Philo} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-//.${AOs::Philo} .............................................................
+//$declare${AOs::Philo} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+
+//${AOs::Philo} ..............................................................
class Philo : public QP::QActive {
private:
QP::QTimeEvt m_timeEvt;
@@ -40,18 +60,19 @@ class Philo : public QP::QActive {
Q_STATE_DECL(thinking);
Q_STATE_DECL(hungry);
Q_STATE_DECL(eating);
-};
-//.$enddecl${AOs::Philo} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+}; // class Philo
+//$enddecl${AOs::Philo} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// generate definition of the opaque pointer to the AO -----------------------
-//.$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-//. Check for the minimum required QP version
-#if (QP_VERSION < 690U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U))
-#error qpcpp version 6.9.0 or higher required
+//$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+// Check for the minimum required QP version
+#if (QP_VERSION < 730U) || (QP_VERSION != ((QP_RELEASE^4294967295U)%0x2710U))
+#error qpcpp version 7.3.0 or higher required
#endif
-//.$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//.$define${AOs::AO_Philo[N_PHILO]} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-//.${AOs::AO_Philo[N_PHILO]} .................................................
+//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//$define${AOs::AO_Philo[N_PHILO]} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+
+//${AOs::AO_Philo[N_PHILO]} ..................................................
QP::QActive * const AO_Philo[N_PHILO] = { // "opaque" pointers to Philo AO
&Philo::inst[0],
&Philo::inst[1],
@@ -59,7 +80,7 @@ QP::QActive * const AO_Philo[N_PHILO] = { // "opaque" pointers to Philo AO
&Philo::inst[3],
&Philo::inst[4]
};
-//.$enddef${AOs::AO_Philo[N_PHILO]} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//$enddef${AOs::AO_Philo[N_PHILO]} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// helper function to provide a randomized think time for Philos
inline QP::QTimeEvtCtr think_time() {
@@ -79,18 +100,20 @@ inline uint8_t PHILO_ID(Philo const * const philo) {
}
// generate definition of the AO --------------------------------------------
-//.$define${AOs::Philo} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-//.${AOs::Philo} .............................................................
+//$define${AOs::Philo} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+
+//${AOs::Philo} ..............................................................
Philo Philo::inst[N_PHILO];
-//.${AOs::Philo::Philo} ......................................................
+
+//${AOs::Philo::Philo} .......................................................
Philo::Philo()
: QActive(Q_STATE_CAST(&Philo::initial)),
m_timeEvt(this, TIMEOUT_SIG, 0U)
{}
-//.${AOs::Philo::SM} .........................................................
+//${AOs::Philo::SM} ..........................................................
Q_STATE_DEF(Philo, initial) {
- //.${AOs::Philo::SM::initial}
+ //${AOs::Philo::SM::initial}
(void)e; // unused parameter
subscribe(EAT_SIG);
@@ -121,28 +144,29 @@ Q_STATE_DEF(Philo, initial) {
}
return tran(&thinking);
}
-//.${AOs::Philo::SM::thinking} ...............................................
+
+//${AOs::Philo::SM::thinking} ................................................
Q_STATE_DEF(Philo, thinking) {
QP::QState status_;
switch (e->sig) {
- //.${AOs::Philo::SM::thinking}
+ //${AOs::Philo::SM::thinking}
case Q_ENTRY_SIG: {
m_timeEvt.armX(think_time(), 0U);
status_ = Q_RET_HANDLED;
break;
}
- //.${AOs::Philo::SM::thinking}
+ //${AOs::Philo::SM::thinking}
case Q_EXIT_SIG: {
(void)m_timeEvt.disarm();
status_ = Q_RET_HANDLED;
break;
}
- //.${AOs::Philo::SM::thinking::TIMEOUT}
+ //${AOs::Philo::SM::thinking::TIMEOUT}
case TIMEOUT_SIG: {
status_ = tran(&hungry);
break;
}
- //.${AOs::Philo::SM::thinking::EAT, DONE}
+ //${AOs::Philo::SM::thinking::EAT, DONE}
case EAT_SIG: // intentionally fall through
case DONE_SIG: {
// EAT or DONE must be for other Philos than this one
@@ -150,7 +174,7 @@ Q_STATE_DEF(Philo, thinking) {
status_ = Q_RET_HANDLED;
break;
}
- //.${AOs::Philo::SM::thinking::TEST}
+ //${AOs::Philo::SM::thinking::TEST}
case TEST_SIG: {
status_ = Q_RET_HANDLED;
break;
@@ -162,11 +186,12 @@ Q_STATE_DEF(Philo, thinking) {
}
return status_;
}
-//.${AOs::Philo::SM::hungry} .................................................
+
+//${AOs::Philo::SM::hungry} ..................................................
Q_STATE_DEF(Philo, hungry) {
QP::QState status_;
switch (e->sig) {
- //.${AOs::Philo::SM::hungry}
+ //${AOs::Philo::SM::hungry}
case Q_ENTRY_SIG: {
TableEvt *pe = Q_NEW(TableEvt, HUNGRY_SIG);
pe->philoNum = PHILO_ID(this);
@@ -174,9 +199,9 @@ Q_STATE_DEF(Philo, hungry) {
status_ = Q_RET_HANDLED;
break;
}
- //.${AOs::Philo::SM::hungry::EAT}
+ //${AOs::Philo::SM::hungry::EAT}
case EAT_SIG: {
- //.${AOs::Philo::SM::hungry::EAT::[Q_EVT_CAST(TableEvt)->philoNum=~}
+ //${AOs::Philo::SM::hungry::EAT::[Q_EVT_CAST(TableEvt)->philoNum=~}
if (Q_EVT_CAST(TableEvt)->philoNum == PHILO_ID(this)) {
status_ = tran(&eating);
}
@@ -185,7 +210,7 @@ Q_STATE_DEF(Philo, hungry) {
}
break;
}
- //.${AOs::Philo::SM::hungry::DONE}
+ //${AOs::Philo::SM::hungry::DONE}
case DONE_SIG: {
/* DONE must be for other Philos than this one */
Q_ASSERT(Q_EVT_CAST(TableEvt)->philoNum != PHILO_ID(this));
@@ -199,17 +224,18 @@ Q_STATE_DEF(Philo, hungry) {
}
return status_;
}
-//.${AOs::Philo::SM::eating} .................................................
+
+//${AOs::Philo::SM::eating} ..................................................
Q_STATE_DEF(Philo, eating) {
QP::QState status_;
switch (e->sig) {
- //.${AOs::Philo::SM::eating}
+ //${AOs::Philo::SM::eating}
case Q_ENTRY_SIG: {
m_timeEvt.armX(eat_time(), 0U);
status_ = Q_RET_HANDLED;
break;
}
- //.${AOs::Philo::SM::eating}
+ //${AOs::Philo::SM::eating}
case Q_EXIT_SIG: {
TableEvt *pe = Q_NEW(TableEvt, DONE_SIG);
pe->philoNum = PHILO_ID(this);
@@ -218,12 +244,12 @@ Q_STATE_DEF(Philo, eating) {
status_ = Q_RET_HANDLED;
break;
}
- //.${AOs::Philo::SM::eating::TIMEOUT}
+ //${AOs::Philo::SM::eating::TIMEOUT}
case TIMEOUT_SIG: {
status_ = tran(&thinking);
break;
}
- //.${AOs::Philo::SM::eating::EAT, DONE}
+ //${AOs::Philo::SM::eating::EAT, DONE}
case EAT_SIG: // intentionally fall through
case DONE_SIG: {
// EAT or DONE must be for other Philos than this one
@@ -238,4 +264,4 @@ Q_STATE_DEF(Philo, eating) {
}
return status_;
}
-//.$enddef${AOs::Philo} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//$enddef${AOs::Philo} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/examples/dpp_bsp-esp32/qp_config.hpp b/examples/dpp_bsp-esp32/qp_config.hpp
new file mode 100644
index 0000000..8891edf
--- /dev/null
+++ b/examples/dpp_bsp-esp32/qp_config.hpp
@@ -0,0 +1,199 @@
+//============================================================================
+// QP configuration file (generic)
+// Last updated for version: 7.3.0
+// Last updated on: 2023-10-30
+//
+// Q u a n t u m L e a P s
+// ------------------------
+// Modern Embedded Software
+//
+// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
+//
+// This software is dual-licensed under the terms of the open source GNU
+// General Public License version 3 (or any later version), or alternatively,
+// under the terms of one of the closed source Quantum Leaps commercial
+// licenses.
+//
+// The terms of the open source GNU General Public License version 3
+// can be found at:
+//
+// The terms of the closed source Quantum Leaps commercial licenses
+// can be found at:
+//
+// Redistributions in source code must retain this top-level comment block.
+// Plagiarizing this software to sidestep the license obligations is illegal.
+//
+// Contact information:
+//
+//
+//============================================================================
+#ifndef QP_CONFIG_HPP_
+#define QP_CONFIG_HPP_
+
+//-------- <<< Use Configuration Wizard in Context Menu >>> -----------------
+
+// NOTE: Requires command-line macro: QP_CONFIG
+// This qp_config.h header file is activated only when the macro
+// QP_CONFIG is defined on the command-line to the compiler
+// -------------------------------------------
+
+// QP API compatibility version (QP_API_VERSION)
+// <0=> 0 (Maximum compatibility)
+// <580=>580 (QP 5.8.0 or newer)
+// <660=>660 (QP 6.6.0 or newer)
+// <691=>691 (QP 6.9.1 or newer)
+// <700=>700 (QP 7.0.0 or newer)
+// <9999=>9999 (Latest only)
+// QP API backwards compatibility with the QP/C API version.
+// Lower QP_API_VERSION values enable backwards compatibility
+// with lower (older) QP API versions.
+// For example, QP_API_VERSION==691 will enable the compatibility
+// layer with QP version 6.9.1 and newer, but not older than 6.9.1.
+// QP_API_VERSION==0 enables the maximum currently supported
+// backwards compatibility. Conversely, QP_API_VERSION==9999 means
+// that no backwards compatibility layer should be enabled.
+// Default: 0 (All supported)
+#define QP_API_VERSION 0
+
+//..........................................................................
+// QP Functional Safety (FuSa) Subsystem (Q_UNSAFE)
+// The QP FuSa Subsystem consists of the following facilities:
+// - Software assertions as a recommended technique
+// (called Failure Assertion Programming (FAP) in IEC 61508)
+// - Software Self-Monitoring (SSM), which encompasses such techniques:
+// * Duplicate Inverse Storage for critical variables
+// * Memory Markers for critical objects (e.g., events)
+// * Hard-limits for all loops
+// * Memory Isolation by means of Memory Protection Unit (MPU)
+
+// Disable QP FuSa in development
+// Disable assertions and other self monitoring features
+// in development build configurations (NDEBUG undefined).
+// VIOLATES functional safety standards. NOT recommended !!!
+//#ifndef NDEBUG
+//#define Q_UNSAFE
+//#endif
+//
+
+// Disable QP FuSa in production release
+// Disable assertions and other self monitoring features
+// in the release build configurations (NDEBUG defined).
+// VIOLATES functional safety standards. NOT recommended !!!
+//#ifdef NDEBUG
+//#define Q_UNSAFE
+//#endif
+//
+
+//
+
+//..........................................................................
+// QEP Event Processor
+// Events and state machines.
+
+// Event signal size (Q_SIGNAL_SIZE)
+// <1U=>1
+// <2U=>2 (default)
+// <4U=>4
+// Size of the QEvt signal for QEP/QF [bytes]
+// Default: 2
+#define Q_SIGNAL_SIZE 2U
+
+//
+
+//..........................................................................
+// QF Framework
+// Active Object framework
+
+// Maximum # Active Objects (QF_MAX_ACTIVE) <1-64>
+// Maximum # Active Objects in the system <1..64>
+// Default: 32
+#define QF_MAX_ACTIVE 8U
+
+// Maximum # event pools (QF_MAX_EPOOL)
+// <0=>0 no event pools
+// <1=>1 <2=>2 <3=>3 (default) <4=>4 <5=>5
+// <6=>6 <7=>7 <8=>8 <9=>9 <10=>10 <11=>11
+// <12=>12 <13=>13 <14=>14 <15=>15
+// Maximum # Event Pools <1..15>
+// Default: 3
+#define QF_MAX_EPOOL 3U
+
+// Maximum # clock tick rates (QF_MAX_TICK_RATE)
+// <0=>0 no time events
+// <1=>1 (default) <2=>2 <3=>3 <4=>4 <5=>5
+// <6=>6 <7=>7 <8=>8 <9=>9 <10=>10 <11=>11
+// <12=>12 <13=>13 <14=>14 <15=>15
+// Maximum # clock tick rates for time events <1..15>
+// Default: 1
+#define QF_MAX_TICK_RATE 1U
+
+// Dynamic Event Constructor (QEVT_DYN_CTOR)
+// Dynamic Event Constructor (RAII)
+//#define QEVT_DYN_CTOR
+//
+
+// Provide destructors for QP classes
+// Destructors for classes
+//#define Q_XTOR
+//
+
+// Active Object stop API (QACTIVE_CAN_STOP)
+// Enable Active Object stop API (Not recommended)
+//#define QACTIVE_CAN_STOP
+//
+
+// Event size (QF_EVENT_SIZ_SIZE)
+// <1U=>1
+// <2U=>2 (default)
+// <4U=>4
+// Size of the dynamic events for QF [bytes]
+// Default: 2 (64K bytes maximum event size)
+#define QF_EVENT_SIZ_SIZE 2U
+
+// Time event counter size (QF_TIMEEVT_CTR_SIZE)
+// <1U=>1
+// <2U=>2
+// <4U=>4 (default)
+// Size of the QTimeEvt counter [bytes]
+// Default: 4 (2^32 dynamic range)
+#define QF_TIMEEVT_CTR_SIZE 4U
+
+// Event queue counter size (QF_EQUEUE_CTR_SIZE)
+// <1U=>1 (default)
+// <2U=>2
+// <4U=>4
+// Size of event queue counter [bytes]
+// Default: 1 (255 events maximum in a queue)
+#define QF_EQUEUE_CTR_SIZE 1U
+
+// Memory pool counter size (QF_MPOOL_CTR_SIZE)
+// <1U=>1
+// <2U=>2 (default)
+// <4U=>4
+// Size of memory pool counter [bytes]
+// Default: 2 (64K blocks maximum in a pool)
+#define QF_MPOOL_CTR_SIZE 2U
+
+// Memory block size (QF_MPOOL_SIZ_SIZE)
+// <1U=>1
+// <2U=>2 (default)
+// <4U=>4
+// Size of memory pool block [bytes]
+// Default: 2 (64K bytes maximum block size)
+#define QF_MPOOL_SIZ_SIZE 2U
+
+//
+
+// Select the CPU at which the QP Framework will be attached
+#define QP_PINNED_TO_CORE_0
+//#define QP_PINNED_TO_CORE_1
+
+// Select QACTIVE_THREAD_TYPE
+// <0U=> Dynamic thread
+// <1U=> Static thread
+#define QP_STATIC_THREAD 0U
+//------------- <<< end of configuration section >>> -----------------------
+
+#endif // QP_CONFIG_HPP_
diff --git a/examples/dpp_bsp-esp32/qview/dpp.py b/examples/dpp_bsp-esp32/qview/dpp.py
deleted file mode 100644
index b0ea9f8..0000000
--- a/examples/dpp_bsp-esp32/qview/dpp.py
+++ /dev/null
@@ -1,103 +0,0 @@
-# This is an example of QView customization for a specific application
-# (DPP in this case). This example animates the Phil images on the
-# QView canvas. Additionally, there is a button in the middle of the screen,
-# which, when clicked once pauses the DPP ("forks" are not being served).
-# A second click on the button, "un-pauses" the DPP ("forks" are served
-# to all hungry Philosophers).
-#
-# This version of the DPP customization uses the application-specific
-# packet QS_USER_00 (PHILO_STAT) produced when the status of a Philo changes.
-#
-
-class DPP:
- def __init__(self):
-
- # add commands to the Custom menu...
- QView.custom_menu.add_command(label="Custom command",
- command=self.cust_command)
-
- # configure the custom QView.canvas...
- QView.show_canvas() # make the canvas visible
- QView.canvas.configure(width=400, height=260)
-
- # tuple of activity images (correspond to self._philo_state)
- self._act_img = (
- PhotoImage(file=HOME_DIR + "/img/thinking.gif"),
- PhotoImage(file=HOME_DIR + "/img/hungry.gif"),
- PhotoImage(file=HOME_DIR + "/img/eating.gif"),
- )
- # tuple of philo canvas images (correspond to self._philo_obj)
- self._philo_img = (\
- QView.canvas.create_image(190, 57, image=self._act_img[0]),
- QView.canvas.create_image(273, 100, image=self._act_img[0]),
- QView.canvas.create_image(237, 185, image=self._act_img[0]),
- QView.canvas.create_image(146, 185, image=self._act_img[0]),
- QView.canvas.create_image(107, 100, image=self._act_img[0])
- )
-
- # button images for UP and DOWN
- self.img_UP = PhotoImage(file=HOME_DIR + "/img/BTN_UP.gif")
- self.img_DWN = PhotoImage(file=HOME_DIR + "/img/BTN_DWN.gif")
-
- # images of a button for pause/serve
- self.btn = QView.canvas.create_image(200, 120, image=self.img_UP)
- QView.canvas.tag_bind(self.btn, "", self.cust_pause)
-
- # request target reset on startup...
- # NOTE: Normally, for an embedded application you would like
- # to start with resetting the Target, to start clean with
- # Qs dictionaries, etc.
- reset_target()
-
- # on_reset() callback
- def on_reset(self):
- # clear the lists
- self._philo_obj = [0, 0, 0, 0, 0]
- self._philo_state = [0, 0, 0]
-
- # on_run() callback
- def on_run(self):
- glb_filter("QS_USER_00")
-
- # NOTE: the name of object for current_obj() must match the
- # QS Object Dictionaries produced by the application.
- current_obj(OBJ_AO, "Table::inst")
-
- # turn lists into tuples for better performance
- self._philo_obj = tuple(self._philo_obj)
- self._philo_state = tuple(self._philo_state)
-
-
- # example of a custom command
- def cust_command(self):
- command(1, 12345)
-
- # example of a custom interaction with a canvas object (pause/serve)
- def cust_pause(self, event):
- if QView.canvas.itemcget(self.btn, "image") != str(self.img_UP):
- QView.canvas.itemconfig(self.btn, image=self.img_UP)
- post("SERVE_SIG")
- QView.print_text("Table SERVING")
- else:
- QView.canvas.itemconfig(self.btn, image=self.img_DWN)
- post("PAUSE_SIG")
- QView.print_text("Table PAUSED")
-
- # intercept the QS_USER_00 application-specific packet
- # this packet has the following structure (see bsp.c:displayPhilStat()):
- # record-ID, seq-num, Timestamp, format-byte, Philo-num,
- # format-bye, Zero-terminated string (status)
- def QS_USER_00(self, packet):
- # unpack: Timestamp->data[0], Philo-num->data[1], status->data[3]
- data = qunpack("xxTxBxZ", packet)
- i = data[1]
- j = ("t", "h", "e").index(data[2][0]) # the first letter
-
- # animate the given philo image according to its activity
- QView.canvas.itemconfig(self._philo_img[i], image=self._act_img[j])
-
- # print a message to the text view
- QView.print_text("%010d Philo %1d is %s"%(data[0], i, data[2]))
-
-#=============================================================================
-QView.customize(DPP()) # set the QView customization
diff --git a/examples/dpp_bsp-esp32/qview/dpp1.py b/examples/dpp_bsp-esp32/qview/dpp1.py
deleted file mode 100644
index 20d0412..0000000
--- a/examples/dpp_bsp-esp32/qview/dpp1.py
+++ /dev/null
@@ -1,147 +0,0 @@
-# This is an example of QView customization for a specific application
-# (DPP in this case). This example animates the Phil images on the
-# QView canvas. Additionally, there is a button in the middle of the screen,
-# which, when clicked once pauses the DPP ("forks" are not being served).
-# A second click on the button, "un-pauses" the DPP ("forks" are served
-# to all hungry Philosophers).
-#
-# This version of the DPP customization uses the standard QS_QEP_STATE_ENTRY
-# packet, which provides information about the current states of the dining
-# Philosophers. The example also demonstrates how to intercept the QS
-# "dictionary" records QS_OBJ_DICT and QS_FUN_DICT to extract the information
-# about the addresses of the Philosopher objects and the states of their
-# state machines.
-#
-
-class DPP:
- def __init__(self):
-
- # add commands to the Custom menu...
- QView.custom_menu.add_command(label="Custom command",
- command=self.cust_command)
-
- # configure the custom QView.canvas...
- QView.show_canvas() # make the canvas visible
- QView.canvas.configure(width=400, height=260)
-
- # tuple of activity images (correspond to self._philo_state)
- self._act_img = (
- PhotoImage(file=HOME_DIR + "/img/thinking.gif"),
- PhotoImage(file=HOME_DIR + "/img/hungry.gif"),
- PhotoImage(file=HOME_DIR + "/img/eating.gif"),
- )
- # tuple of philo canvas images (correspond to self._philo_obj)
- self._philo_img = (\
- QView.canvas.create_image(190, 57, image=self._act_img[0]),
- QView.canvas.create_image(273, 100, image=self._act_img[0]),
- QView.canvas.create_image(237, 185, image=self._act_img[0]),
- QView.canvas.create_image(146, 185, image=self._act_img[0]),
- QView.canvas.create_image(107, 100, image=self._act_img[0])
- )
-
- # button images for UP and DOWN
- self.img_UP = PhotoImage(file=HOME_DIR + "/img/BTN_UP.gif")
- self.img_DWN = PhotoImage(file=HOME_DIR + "/img/BTN_DWN.gif")
-
- # images of a button for pause/serve
- self.btn = QView.canvas.create_image(200, 120, image=self.img_UP)
- QView.canvas.tag_bind(self.btn, "", self.cust_pause)
-
- # request target reset on startup...
- # NOTE: Normally, for an embedded application you would like
- # to start with resetting the Target, to start clean with
- # Qs dictionaries, etc.
- reset_target()
-
- # on_reset() callback invoked when Target-reset packet is received
- # NOTE: the QS dictionaries are not known at this time yet, so
- # this callback shouild generally not set filters or current objects
- def on_reset(self):
- # (re)set the lists
- self._philo_obj = [0, 0, 0, 0, 0]
- self._philo_state = [0, 0, 0]
-
- # on_run() callback invoked when the QF_RUN packet is received
- # NOTE: the QS dictionaries are typically known at this time yet, so
- # this callback can set filters or current objects
- def on_run(self):
- glb_filter("QS_QEP_TRAN")
-
- # NOTE: the name of object for current_obj() must match the
- # QS Object Dictionaries produced by the application.
- current_obj(OBJ_AO, "Table::inst")
-
- # turn lists into tuples for better performance
- self._philo_obj = tuple(self._philo_obj)
- self._philo_state = tuple(self._philo_state)
-
-
- # example of a custom command
- def cust_command(self):
- command(1, 12345)
-
- # example of a custom interaction with a canvas object (pause/serve)
- def cust_pause(self, event):
- if QView.canvas.itemcget(self.btn, "image") != str(self.img_UP):
- QView.canvas.itemconfig(self.btn, image=self.img_UP)
- post("SERVE_SIG")
- QView.print_text("Table SERVING")
- else:
- QView.canvas.itemconfig(self.btn, image=self.img_DWN)
- post("PAUSE_SIG")
- QView.print_text("Table PAUSED")
-
- # intercept the QS_OBJ_DICT stadard packet
- # this packet has the following structure:
- # record-ID, seq-num, Object-ptr, Zero-terminated string
- def QS_OBJ_DICT(self, packet):
- data = qunpack("xxOZ", packet)
- try:
- # NOTE: the names of objects must match the QS Object Dictionaries
- # produced by the application.
- i = ("Philo::inst[0]",
- "Philo::inst[1]",
- "Philo::inst[2]",
- "Philo::inst[3]",
- "Philo::inst[4]").index(data[1])
- self._philo_obj[i] = data[0]
- except:
- pass # dictionary for a different object
-
- # intercept the QS_FUN_DICT stadard packet
- # this packet has the following structure:
- # record-ID, seq-num, Function-ptr, Zero-terminated string
- def QS_FUN_DICT(self, packet):
- data = qunpack("xxFZ", packet)
- try:
- # NOTE: the names of states must match the QS Object Dictionaries
- # produced by the application.
- j = ("Philo::thinking",
- "Philo::hungry",
- "Philo::eating").index(data[1])
- self._philo_state[j] = data[0]
- except:
- pass # dictionary for a different state
-
- # intercept the QS_QEP_TRAN stadard packet
- # this packet has the following structure:
- # record-ID, seq-num, Timestamp, Signal, Object-ptr,
- # Function-ptr (source state), Function-ptr (new active state)
- def QS_QEP_TRAN(self, packet):
- data = qunpack("xxTSOFF", packet)
- try:
- i = self._philo_obj.index(data[2])
- j = self._philo_state.index(data[4])
-
- # animate the given philo image according to its activity
- QView.canvas.itemconfig(self._philo_img[i],
- image=self._act_img[j])
- # print a message to the text view
- QView.print_text("%010d Philo %d is %s"\
- %(data[0], i, ("thinking", "hungry", "eating")[j]))
- except:
- pass # state-entry in a different object
-
-#=============================================================================
-# instantiate the DPP class and set it as the QView customization
-QView.customize(DPP())
diff --git a/examples/dpp_bsp-esp32/qview/img/BTN_DWN.gif b/examples/dpp_bsp-esp32/qview/img/BTN_DWN.gif
deleted file mode 100644
index 36d8c79..0000000
Binary files a/examples/dpp_bsp-esp32/qview/img/BTN_DWN.gif and /dev/null differ
diff --git a/examples/dpp_bsp-esp32/qview/img/BTN_UP.gif b/examples/dpp_bsp-esp32/qview/img/BTN_UP.gif
deleted file mode 100644
index 3246ff9..0000000
Binary files a/examples/dpp_bsp-esp32/qview/img/BTN_UP.gif and /dev/null differ
diff --git a/examples/dpp_bsp-esp32/qview/img/eating.gif b/examples/dpp_bsp-esp32/qview/img/eating.gif
deleted file mode 100644
index 632b9d2..0000000
Binary files a/examples/dpp_bsp-esp32/qview/img/eating.gif and /dev/null differ
diff --git a/examples/dpp_bsp-esp32/qview/img/hungry.gif b/examples/dpp_bsp-esp32/qview/img/hungry.gif
deleted file mode 100644
index dc144db..0000000
Binary files a/examples/dpp_bsp-esp32/qview/img/hungry.gif and /dev/null differ
diff --git a/examples/dpp_bsp-esp32/qview/img/thinking.gif b/examples/dpp_bsp-esp32/qview/img/thinking.gif
deleted file mode 100644
index ec684ee..0000000
Binary files a/examples/dpp_bsp-esp32/qview/img/thinking.gif and /dev/null differ
diff --git a/examples/dpp_bsp-esp32/qview/qspy.bat b/examples/dpp_bsp-esp32/qview/qspy.bat
deleted file mode 100644
index 624af68..0000000
--- a/examples/dpp_bsp-esp32/qview/qspy.bat
+++ /dev/null
@@ -1,5 +0,0 @@
-@setlocal
-
-qspy.exe -c COM3 -b 115200
-
-@endlocal
diff --git a/examples/dpp_bsp-esp32/qview/qview-dpp.bat b/examples/dpp_bsp-esp32/qview/qview-dpp.bat
deleted file mode 100644
index 70e6717..0000000
--- a/examples/dpp_bsp-esp32/qview/qview-dpp.bat
+++ /dev/null
@@ -1,8 +0,0 @@
-@setlocal
-
-if "%QTOOLS%"=="" (
- set QTOOLS=C:\qp\qtools
-)
-python %QTOOLS%\qview\qview.py dpp.py
-
-@endlocal
diff --git a/examples/dpp_bsp-esp32/qview/qview-dpp.lnk b/examples/dpp_bsp-esp32/qview/qview-dpp.lnk
deleted file mode 100644
index 5cb99eb..0000000
Binary files a/examples/dpp_bsp-esp32/qview/qview-dpp.lnk and /dev/null differ
diff --git a/examples/dpp_bsp-esp32/qview/qview-dpp1.bat b/examples/dpp_bsp-esp32/qview/qview-dpp1.bat
deleted file mode 100644
index a15f585..0000000
--- a/examples/dpp_bsp-esp32/qview/qview-dpp1.bat
+++ /dev/null
@@ -1,8 +0,0 @@
-@setlocal
-
-if "%QTOOLS%"=="" (
- set QTOOLS=C:\qp\qtools
-)
-python %QTOOLS%\qview\qview.py dpp1.py
-
-@endlocal
diff --git a/examples/dpp_bsp-esp32/qview/qview-dpp1.lnk b/examples/dpp_bsp-esp32/qview/qview-dpp1.lnk
deleted file mode 100644
index 41e1e3d..0000000
Binary files a/examples/dpp_bsp-esp32/qview/qview-dpp1.lnk and /dev/null differ
diff --git a/examples/dpp_bsp-esp32/table.cpp b/examples/dpp_bsp-esp32/table.cpp
index 9fd72fe..d254443 100644
--- a/examples/dpp_bsp-esp32/table.cpp
+++ b/examples/dpp_bsp-esp32/table.cpp
@@ -1,21 +1,40 @@
-//.$file${.::table.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+//$file${.::table.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
//
// Model: dpp_bsp-esp32.qm
// File: ${.::table.cpp}
//
-// This code has been generated by QM 5.1.1 .
+// This code has been generated by QM 7.0.1 .
// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
//
-// This program is open source software: you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as published
-// by the Free Software Foundation.
+// Copyright (c) 2005 Quantum Leaps, LLC. All rights reserved.
//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-// for more details.
+// ____________________________________
+// / /
+// / GGGGGGG PPPPPPPP LL /
+// / GG GG PP PP LL /
+// / GG PP PP LL /
+// / GG GGGGG PPPPPPPP LL /
+// / GG GG PP LL /
+// / GGGGGGG PP LLLLLLL /
+// /___________________________________/
//
-//.$endhead${.::table.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+// This generated code is open-source software licensed under the GNU
+// General Public License (GPL) as published by the Free Software Foundation
+// (see ).
+//
+// NOTE:
+// The GPL does NOT permit the incorporation of this code into proprietary
+// programs. Please contact Quantum Leaps for commercial licensing options,
+// which expressly supersede the GPL and are designed explicitly for
+// closed-source distribution.
+//
+// Quantum Leaps contact information:
+//
+//
+//
+//$endhead${.::table.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#include "qpcpp.hpp" // QP-C++ framework
#include "dpp.hpp" // DPP application
#include "bsp.hpp" // Board Support Package
@@ -23,8 +42,9 @@
Q_DEFINE_THIS_FILE
// generate declaration of the active object ---------------------------------
-//.$declare${AOs::Table} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-//.${AOs::Table} .............................................................
+//$declare${AOs::Table} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+
+//${AOs::Table} ..............................................................
class Table : public QP::QActive {
private:
uint8_t m_fork[N_PHILO];
@@ -41,20 +61,21 @@ class Table : public QP::QActive {
Q_STATE_DECL(active);
Q_STATE_DECL(serving);
Q_STATE_DECL(paused);
-};
-//.$enddecl${AOs::Table} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+}; // class Table
+//$enddecl${AOs::Table} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// generate definition of the opaque pointer to the AO -----------------------
-//.$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-//. Check for the minimum required QP version
-#if (QP_VERSION < 690U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U))
-#error qpcpp version 6.9.0 or higher required
+//$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+// Check for the minimum required QP version
+#if (QP_VERSION < 730U) || (QP_VERSION != ((QP_RELEASE^4294967295U)%0x2710U))
+#error qpcpp version 7.3.0 or higher required
#endif
-//.$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//.$define${AOs::AO_Table} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-//.${AOs::AO_Table} ..........................................................
+//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//$define${AOs::AO_Table} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+
+//${AOs::AO_Table} ...........................................................
QP::QActive * const AO_Table = &Table::inst; // "opaque" AO pointer
-//.$enddef${AOs::AO_Table} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//$enddef${AOs::AO_Table} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// helper function to provide the RIGHT neighbour of a Philo[n]
inline uint8_t RIGHT(uint8_t const n) {
@@ -75,10 +96,12 @@ static char const * const EATING = "eating ";
// generate definition of the AO ---------------------------------------------
-//.$define${AOs::Table} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-//.${AOs::Table} .............................................................
+//$define${AOs::Table} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+
+//${AOs::Table} ..............................................................
Table Table::inst;
-//.${AOs::Table::Table} ......................................................
+
+//${AOs::Table::Table} .......................................................
Table::Table()
: QActive(Q_STATE_CAST(&Table::initial))
{
@@ -88,9 +111,9 @@ Table::Table()
}
}
-//.${AOs::Table::SM} .........................................................
+//${AOs::Table::SM} ..........................................................
Q_STATE_DEF(Table, initial) {
- //.${AOs::Table::SM::initial}
+ //${AOs::Table::SM::initial}
(void)e; // unused parameter
subscribe(DONE_SIG);
@@ -115,16 +138,17 @@ Q_STATE_DEF(Table, initial) {
QS_SIG_DICTIONARY(HUNGRY_SIG, nullptr);
return tran(&serving);
}
-//.${AOs::Table::SM::active} .................................................
+
+//${AOs::Table::SM::active} ..................................................
Q_STATE_DEF(Table, active) {
QP::QState status_;
switch (e->sig) {
- //.${AOs::Table::SM::active::TEST}
+ //${AOs::Table::SM::active::TEST}
case TEST_SIG: {
status_ = Q_RET_HANDLED;
break;
}
- //.${AOs::Table::SM::active::EAT}
+ //${AOs::Table::SM::active::EAT}
case EAT_SIG: {
Q_ERROR();
status_ = Q_RET_HANDLED;
@@ -137,11 +161,12 @@ Q_STATE_DEF(Table, active) {
}
return status_;
}
-//.${AOs::Table::SM::active::serving} ........................................
+
+//${AOs::Table::SM::active::serving} .........................................
Q_STATE_DEF(Table, serving) {
QP::QState status_;
switch (e->sig) {
- //.${AOs::Table::SM::active::serving}
+ //${AOs::Table::SM::active::serving}
case Q_ENTRY_SIG: {
for (uint8_t n = 0U; n < N_PHILO; ++n) { // give permissions to eat...
if (m_isHungry[n]
@@ -160,7 +185,7 @@ Q_STATE_DEF(Table, serving) {
status_ = Q_RET_HANDLED;
break;
}
- //.${AOs::Table::SM::active::serving::HUNGRY}
+ //${AOs::Table::SM::active::serving::HUNGRY}
case HUNGRY_SIG: {
uint8_t n = Q_EVT_CAST(TableEvt)->philoNum;
// phil ID must be in range and he must be not hungry
@@ -168,7 +193,7 @@ Q_STATE_DEF(Table, serving) {
BSP::displayPhilStat(n, HUNGRY);
uint8_t m = LEFT(n);
- //.${AOs::Table::SM::active::serving::HUNGRY::[bothfree]}
+ //${AOs::Table::SM::active::serving::HUNGRY::[bothfree]}
if ((m_fork[m] == FREE) && (m_fork[n] == FREE)) {
m_fork[m] = USED;
m_fork[n] = USED;
@@ -178,14 +203,14 @@ Q_STATE_DEF(Table, serving) {
BSP::displayPhilStat(n, EATING);
status_ = Q_RET_HANDLED;
}
- //.${AOs::Table::SM::active::serving::HUNGRY::[else]}
+ //${AOs::Table::SM::active::serving::HUNGRY::[else]}
else {
m_isHungry[n] = true;
status_ = Q_RET_HANDLED;
}
break;
}
- //.${AOs::Table::SM::active::serving::DONE}
+ //${AOs::Table::SM::active::serving::DONE}
case DONE_SIG: {
uint8_t n = Q_EVT_CAST(TableEvt)->philoNum;
// phil ID must be in range and he must be not hungry
@@ -223,13 +248,13 @@ Q_STATE_DEF(Table, serving) {
status_ = Q_RET_HANDLED;
break;
}
- //.${AOs::Table::SM::active::serving::EAT}
+ //${AOs::Table::SM::active::serving::EAT}
case EAT_SIG: {
Q_ERROR();
status_ = Q_RET_HANDLED;
break;
}
- //.${AOs::Table::SM::active::serving::PAUSE}
+ //${AOs::Table::SM::active::serving::PAUSE}
case PAUSE_SIG: {
status_ = tran(&paused);
break;
@@ -241,28 +266,29 @@ Q_STATE_DEF(Table, serving) {
}
return status_;
}
-//.${AOs::Table::SM::active::paused} .........................................
+
+//${AOs::Table::SM::active::paused} ..........................................
Q_STATE_DEF(Table, paused) {
QP::QState status_;
switch (e->sig) {
- //.${AOs::Table::SM::active::paused}
+ //${AOs::Table::SM::active::paused}
case Q_ENTRY_SIG: {
BSP::displayPaused(1U);
status_ = Q_RET_HANDLED;
break;
}
- //.${AOs::Table::SM::active::paused}
+ //${AOs::Table::SM::active::paused}
case Q_EXIT_SIG: {
BSP::displayPaused(0U);
status_ = Q_RET_HANDLED;
break;
}
- //.${AOs::Table::SM::active::paused::SERVE}
+ //${AOs::Table::SM::active::paused::SERVE}
case SERVE_SIG: {
status_ = tran(&serving);
break;
}
- //.${AOs::Table::SM::active::paused::HUNGRY}
+ //${AOs::Table::SM::active::paused::HUNGRY}
case HUNGRY_SIG: {
uint8_t n = Q_EVT_CAST(TableEvt)->philoNum;
// philo ID must be in range and he must be not hungry
@@ -272,7 +298,7 @@ Q_STATE_DEF(Table, paused) {
status_ = Q_RET_HANDLED;
break;
}
- //.${AOs::Table::SM::active::paused::DONE}
+ //${AOs::Table::SM::active::paused::DONE}
case DONE_SIG: {
uint8_t n = Q_EVT_CAST(TableEvt)->philoNum;
// phil ID must be in range and he must be not hungry
@@ -295,4 +321,5 @@ Q_STATE_DEF(Table, paused) {
}
return status_;
}
-//.$enddef${AOs::Table} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//$enddef${AOs::Table} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/library.properties b/library.properties
index 6662f06..aea7446 100644
--- a/library.properties
+++ b/library.properties
@@ -1,9 +1,9 @@
-name=QPESP32
-version=0.2.1
-author=Victor Chavez
-maintainer=Victor Chavez
+name=QPCPP_ESP32
+version=8.0.2
+author=NguyenDB
+maintainer=NguyenDB
sentence=QP/C++ Port for ESP32.
-paragraph=QP/C++ Port for the ESP32. Based on v7.2.2 from QP/C++
+paragraph=QP/C++ Port for the ESP32. Based on v8.0.2 from QP/C++
category=Device Control
url=https://www.state-machine.com/arduino/
architectures=*
diff --git a/src/qassert.h b/src/qassert.h
deleted file mode 100644
index 43aafec..0000000
--- a/src/qassert.h
+++ /dev/null
@@ -1,395 +0,0 @@
-/*$file${include::qassert.h} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
-/*
-* Model: qpc.qm
-* File: ${include::qassert.h}
-*
-* This code has been generated by QM 5.2.5 .
-* DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
-*
-* This code is covered by the following QP license:
-* License # : LicenseRef-QL-dual
-* Issued to : Any user of the QP/C real-time embedded framework
-* Framework(s) : qpc
-* Support ends : 2023-12-31
-* License scope:
-*
-* Copyright (C) 2005 Quantum Leaps, LLC .
-*
-* SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
-*
-* This software is dual-licensed under the terms of the open source GNU
-* General Public License version 3 (or any later version), or alternatively,
-* under the terms of one of the closed source Quantum Leaps commercial
-* licenses.
-*
-* The terms of the open source GNU General Public License version 3
-* can be found at:
-*
-* The terms of the closed source Quantum Leaps commercial licenses
-* can be found at:
-*
-* Redistributions in source code must retain this top-level comment block.
-* Plagiarizing this software to sidestep the license obligations is illegal.
-*
-* Contact information:
-*
-*
-*/
-/*$endhead${include::qassert.h} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-/*! @file
-* @brief Customizable and memory-efficient Design by Contract (DbC)
-* for embedded systems
-*
-* @note
-* This header file can be used in C, C++, and mixed C/C++ programs.
-*
-* @note
-* The preprocessor switch #Q_NASSERT disables checking assertions.
-* However, it is generally **not** advisable to disable assertions,
-* **especially** in the production code. Instead, the assertion
-* handler Q_onAssert() should be very carefully designed and tested.
-*/
-#ifndef QASSERT_H_
-#define QASSERT_H_
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-#ifndef Q_NASSERT
-/*$declare${DbC::active} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
-
-/*${DbC::active::Q_DEFINE_THIS_MODULE} .....................................*/
-/*! Define the user-specified module name for assertions in this file.
-*
-* @details
-* Macro to be placed at the top of each C/C++ module to define the
-* single instance of the module name string to be used in reporting
-* assertions in this module. This macro takes the user-supplied parameter
-* `name_` instead of `__FILE__` to precisely control the name of the
-* module.
-*
-* @param[in] name_ string constant representing the module name
-*
-* @note
-* This macro should **not** be terminated by a semicolon.
-*/
-#define Q_DEFINE_THIS_MODULE(name_) \
- static char const Q_this_module_[] = name_;
-
-/*${DbC::active::Q_ASSERT_ID} ..............................................*/
-/*! General-purpose assertion with user-specified ID number.
-*
-* @details
-* Evaluates the Boolean expression `expr_` and does nothing else when
-* it evaluates to 'true'. However, when `expr_` evaluates to 'false',
-* the Q_ASSERT_ID() macro calls the no-return function Q_onAssert().
-*
-* @param[in] id_ ID number (unique within the module) of the assertion
-* @param[in] expr_ Boolean expression to check
-*
-* @attention
-* When assertions are disabled (by defining the ::Q_NASSERT macro), the
-* Q_ASSERT_ID() macro expands to nothing, and consequently the Boolean
-* expression `expr_` is **not** evaluated and the callback function
-* Q_onAssert() is **not** called.
-*/
-#define Q_ASSERT_ID(id_, expr_) ((expr_) \
- ? ((void)0) : Q_onAssert(&Q_this_module_[0], (id_)))
-
-/*${DbC::active::Q_ERROR_ID} ...............................................*/
-/*! Assertion with user-specified ID for a wrong path through the code
-*
-* @details
-* Calls the Q_onAssert() callback if ever executed. This assertion
-* takes the user-supplied parameter `id_` to identify the location of
-* this assertion within the file. This avoids the volatility of using
-* line numbers, which change whenever a line of code is added or removed
-* upstream from the assertion.
-*
-* @param[in] id_ ID number (unique within the module) of the assertion
-*
-* @note
-* Does noting if assertions are disabled with the ::Q_NASSERT switch.
-*/
-#define Q_ERROR_ID(id_) Q_onAssert(&Q_this_module_[0], (id_))
-
-/*${DbC::active::Q_ALLEGE_ID} ..............................................*/
-/*! General purpose assertion with user-specified ID number that
-* **always** evaluates the `expr_` expression.
-*
-* @details
-* Like the Q_ASSERT_ID() macro, except it **always** evaluates the
-* `expr_` expression even when assertions are disabled with the
-* ::Q_NASSERT macro. However, when the ::Q_NASSERT macro is defined, the
-* Q_onAssert() callback is **not** called, even if `expr_` evaluates
-* to FALSE.
-*
-* @param[in] id_ ID number (unique within the module) of the assertion
-* @param[in] expr_ Boolean expression to check
-*/
-#define Q_ALLEGE_ID(id_, expr_) Q_ASSERT_ID((id_), (expr_))
-/*$enddecl${DbC::active} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-#else
-/*$declare${DbC::inactive} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
-
-/*${DbC::inactive::Q_DEFINE_THIS_MODULE} ...................................*/
-/*! inactive version of Q_DEFINE_THIS_MODULE() */
-#define Q_DEFINE_THIS_MODULE(name_)
-
-/*${DbC::inactive::Q_ASSERT_ID} ............................................*/
-/*! inactive version of Q_ASSERT_ID() */
-#define Q_ASSERT_ID(id_, expr_) ((void)0)
-
-/*${DbC::inactive::Q_ERROR_ID} .............................................*/
-/*! inactive version of Q_ERROR_ID() */
-#define Q_ERROR_ID(id_) ((void)0)
-
-/*${DbC::inactive::Q_ALLEGE_ID} ............................................*/
-/*! inactive version of Q_ALLEGE_ID()
-*
-* @attention
-* The expression `expr_` **is** evaluated, even though assertion
-* callback Q_onAssert() is NOT called when `expr_` evaluates to
-* false.
-*/
-#define Q_ALLEGE_ID(id_, expr_) ((void)(expr_))
-/*$enddecl${DbC::inactive} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-#endif
-
-/*$declare1${DbC} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
-
-/*${DbC::Q_DEFINE_THIS_FILE} ...............................................*/
-/*! Define the file name (with `__FILE__`) for assertions in this file
-*
-* @details
-* Macro to be placed at the top of each C/C++ module to define the
-* single instance of the file name string to be used in reporting
-* assertions in this module.
-*
-* @note
-* The file name string literal is defined by means of the standard
-* preprocessor macro `__FILE__`. However, please note that, depending
-* on the compiler, the `__FILE__` macro might contain the whole path name
-* to the file, which might be inconvenient to log assertions.
-*
-* @attention
-* This macro should **not** be terminated by a semicolon.
-*
-* @sa Q_DEFINE_THIS_MODULE()
-*/
-#define Q_DEFINE_THIS_FILE Q_DEFINE_THIS_MODULE(__FILE__)
-
-/*${DbC::Q_ASSERT} .........................................................*/
-/*! General-purpose assertion (with __LINE__ used as location in the file)
-*
-* @details
-* Equivalent to Q_ASSERT_ID(), except it uses __LINE__ to identify the
-* assertion within a file.
-*
-* @param[in] expr_ Boolean expression to check
-*
-* @sa Q_ASSERT_ID()
-*/
-#define Q_ASSERT(expr_) Q_ASSERT_ID(__LINE__, (expr_))
-
-/*${DbC::Q_ERROR} ..........................................................*/
-/*! Assertion for a wrong path through the code
-*
-* @details
-* Calls the Q_onAssert() callback if ever executed.
-*
-* @note
-* This macro identifies the problem location with the line number,
-* which might change as the code is modified.
-*
-* @sa Q_ERROR_ID()
-*/
-#define Q_ERROR() Q_ERROR_ID(__LINE__)
-
-/*${DbC::Q_REQUIRE_ID} .....................................................*/
-/*! Assertion for checking **preconditions**.
-*
-* @details
-* Equivalent to Q_ASSERT_ID(), except the name provides a better
-* documentation of the intention of this assertion.
-*
-* @param[in] id_ ID number (unique within the module) of the assertion
-* @param[in] expr_ Boolean expression
-*/
-#define Q_REQUIRE_ID(id_, expr_) Q_ASSERT_ID((id_), (expr_))
-
-/*${DbC::Q_REQUIRE} ........................................................*/
-/*! Assertion for checking preconditions (based on __LINE__).
-*
-* @details
-* Equivalent to Q_ASSERT(), except the name provides a better documentation
-* of the intention of this assertion.
-*
-* @param[in] expr_ Boolean expression
-*/
-#define Q_REQUIRE(expr_) Q_ASSERT(expr_)
-
-/*${DbC::Q_ENSURE_ID} ......................................................*/
-/*! Assertion for checking postconditions.
-*
-* @details
-* Equivalent to Q_ASSERT_ID(), except the name provides a better documentation
-* of the intention of this assertion.
-*
-* @param[in] id_ ID number (unique within the module) of the assertion
-* @param[in] expr_ Boolean expression
-*/
-#define Q_ENSURE_ID(id_, expr_) Q_ASSERT_ID((id_), (expr_))
-
-/*${DbC::Q_ENSURE} .........................................................*/
-/*! Assertion for checking postconditions.
-*
-* @details
-* Equivalent to Q_ASSERT(), except the name provides a better documentation
-* of the intention of this assertion.
-*
-* @param[in] expr_ Boolean expression
-*/
-#define Q_ENSURE(expr_) Q_ASSERT(expr_)
-
-/*${DbC::Q_INVARIANT_ID} ...................................................*/
-/*! Assertion for checking invariants.
-*
-* @details
-* Equivalent to Q_ASSERT_ID(), except the name provides a better
-* documentation of the intention of this assertion.
-*
-* @param[in] id_ ID number (unique within the module) of the assertion
-* @param[in] expr_ Boolean expression
-*/
-#define Q_INVARIANT_ID(id_, expr_) Q_ASSERT_ID((id_), (expr_))
-
-/*${DbC::Q_INVARIANT} ......................................................*/
-/*! Assertion for checking invariants.
-*
-* @details
-* Equivalent to Q_ASSERT(), except the name provides a better documentation
-* of the intention of this assertion.
-*
-* @param[in] expr_ Boolean expression
-*/
-#define Q_INVARIANT(expr_) Q_ASSERT(expr_)
-
-/*${DbC::Q_ALLEGE} .........................................................*/
-/*! General purpose assertion with user-specified ID number that
-* **always** evaluates the `expr_` expression.
-*
-* @details
-* Equivalent to Q_ALLEGE_ID(), except it identifies the problem location
-* with the line number `__LINE__`, which might change as the code is modified.
-*
-* @param[in] expr_ Boolean expression to check
-*
-* @sa Q_ALLEGE_ID()
-*/
-#define Q_ALLEGE(expr_) Q_ALLEGE_ID(__LINE__, (expr_))
-
-/*${DbC::Q_ASSERT_STATIC} ..................................................*/
-/*! Static (compile-time) assertion.
-*
-* @details
-* This type of assertion deliberately causes a compile-time error when
-* the `expr_` Boolean expression evaluates to FALSE. The macro exploits
-* the fact that in C/C++ a dimension of an array cannot be negative.
-* The compile-time assertion has no runtime side effects.
-*
-* @param[in] expr_ Compile-time Boolean expression
-*
-* @note
-* The static assertion macro is provided for backwards compatibility with
-* older C standards. Newer C11 supports `_Static_assert()`, which should
-* be used instead of Q_ASSERT_STATIC().
-*/
-#define Q_ASSERT_STATIC(expr_) extern char Q_static_assert_[(expr_) ? 1 : -1]
-
-/*${DbC::Q_NORETURN} .......................................................*/
-#ifndef Q_NORETURN
-/*! No-return function specifier for the Q_onAssert() callback function.
-*
-* @details
-* If the `Q_NORETURN` macro is undefined, the default definition uses
-* the C99 specifier `_Noreturn`.
-*
-* @note
-* The `Q_NORETURN` macro can be defined in the QP port (typically in
-* `qep_port.h` or `qep_port.hpp`). If such definition is porvided
-* the default won't be used.
-*
-* @trace
-* @tr{PQA01_4}
-*/
-#define Q_NORETURN _Noreturn void
-#endif /* ndef Q_NORETURN */
-
-/*${DbC::int_t} ............................................................*/
-#ifndef QP_VERSION
-/*! typedef for assertions-ids and line numbers in assertions.
-*
-* @details
-* This typedef specifies integer type for exclusive use in assertions.
-* Use of this type, rather than plain 'int', is in compliance
-* with the MISRA-C 2012 Dir 4.6 (adv).
-*/
-typedef int int_t;
-#endif /* ndef QP_VERSION */
-
-/*${DbC::Q_onAssert} .......................................................*/
-/*! Callback function invoked in case of an assertion failure.
-*
-* @details
-* This callback function needs to be defined in the application to perform
-* any corrective action after a non-recoverable error has been detected.
-* The Q_onAssert() function is the last line of defense after the
-* system failure and its implementation shouild be very **carefully**
-* designed and **tested** under various fault conditions, including but
-* not limited to: stack overflow, stack corruption, or calling Q_onAssert()
-* from an interrupt.
-*
-* @param[in] module name of the file/module in which the assertion failed
-* (constant, zero-terminated C string)
-* @param[in] location location of the assertion within the module. This could
-* be a line number or a user-specified ID-number.
-*
-* @returns
-* This callback function should **not return** (see ::Q_NORETURN),
-* as continuation after an assertion failure does not make sense.
-*
-* @note
-* During debugging, Q_onAssert() is an ideal place to put a breakpoint.
-* For deployment, tt is typically a **bad idea** to implement Q_onAssert()
-* as an endless loop that ties up the CPU (denial of service).
-*
-* Called by the following: Q_ASSERT_ID(), Q_ERROR_ID(), Q_REQUIRE_ID(),
-* Q_ENSURE_ID(), Q_INVARIANT_ID() and Q_ALLEGE_ID() as well as:
-* Q_ASSERT(), Q_ERROR(), Q_REQUIRE(), Q_ENSURE(), Q_INVARIANT(),
-* and Q_ALLEGE().
-*
-* @trace
-* @tr{PQA01_4}
-*/
-Q_NORETURN Q_onAssert(
- char const * module,
- int_t location);
-
-/*${DbC::Q_DIM} ............................................................*/
-#ifndef QP_VERSION
-/*! Helper macro to calculate static dimension of a 1-dim `array_`
-*
-* @param array_ 1-dimensional array
-* @returns the length of the array (number of elements it can hold)
-*/
-#define Q_DIM(array_) (sizeof(array_) / sizeof((array_)[0U]))
-#endif /* ndef QP_VERSION */
-/*$enddecl${DbC} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-
-#ifdef __cplusplus
- }
-#endif
-
-#endif /* QASSERT_H_ */
diff --git a/src/qep.hpp b/src/qep.hpp
deleted file mode 100644
index e578321..0000000
--- a/src/qep.hpp
+++ /dev/null
@@ -1,982 +0,0 @@
-//$file${include::qep.hpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-//
-// Model: qpcpp.qm
-// File: ${include::qep.hpp}
-//
-// This code has been generated by QM 5.2.5 .
-// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
-//
-// This code is covered by the following QP license:
-// License # : LicenseRef-QL-dual
-// Issued to : Any user of the QP/C++ real-time embedded framework
-// Framework(s) : qpcpp
-// Support ends : 2023-12-31
-// License scope:
-//
-// Copyright (C) 2005 Quantum Leaps, LLC .
-//
-// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
-//
-// This software is dual-licensed under the terms of the open source GNU
-// General Public License version 3 (or any later version), or alternatively,
-// under the terms of one of the closed source Quantum Leaps commercial
-// licenses.
-//
-// The terms of the open source GNU General Public License version 3
-// can be found at:
-//
-// The terms of the closed source Quantum Leaps commercial licenses
-// can be found at:
-//
-// Redistributions in source code must retain this top-level comment block.
-// Plagiarizing this software to sidestep the license obligations is illegal.
-//
-// Contact information:
-//
-//
-//
-//$endhead${include::qep.hpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//! @file
-//! @brief QEP/C++ platform-independent public interface.
-//!
-//! @tr{RQP001} @tr{RQP101}
-
-#ifndef QEP_HPP_
-#define QEP_HPP_
-
-//============================================================================
-//! The current QP version as an unsigned number
-//
-// @details
-// ::QP_VERSION is a decimal constant, where XX is a 1-digit or 2-digit
-// major version number, Y is a 1-digit minor version number, and Z is
-// a 1-digit release number.
-//
-#define QP_VERSION 722U
-
-//! The current QP version as a zero terminated string literal.
-//
-// @details
-// ::QP_VERSION_STR is of the form "XX.Y.Z", where XX is a 1-or 2-digit
-// major version number, Y is a 1-digit minor version number, and Z is
-// a 1-digit release number.
-//
-#define QP_VERSION_STR "7.2.2"
-
-//! Encrypted current QP release (7.2.2) and date (2023-03-01)
-#define QP_RELEASE 0x76BAD85DU
-
-//============================================================================
-// Global namespace...
-//$declare${glob-types} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-
-//${glob-types::int_t} .......................................................
-//! alias for line numbers in assertions and return from QF::run()
-using int_t = int;
-
-//${glob-types::enum_t} ......................................................
-//! alias for enumerations used for event signals
-using enum_t = int;
-
-//${glob-types::float32_t} ...................................................
-//! alias for 32-bit IEEE 754 floating point numbers
-//!
-//! @note
-//! QP does not use floating-point types anywhere in the internal
-//! implementation, except in QS software tracing, where utilities for
-//! output of floating-point numbers are provided for application-specific
-//! trace records.
-using float32_t = float;
-
-//${glob-types::float64_t} ...................................................
-//! alias for 64-bit IEEE 754 floating point numbers
-//!
-//! @note
-//! QP does not use floating-point types anywhere in the internal
-//! implementation, except in QS software tracing, where utilities for
-//! output of floating-point numbers are provided for application-specific
-//! trace records.
-using float64_t = double;
-//$enddecl${glob-types} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//$declare${QEP-config} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-
-//${QEP-config::Q_SIGNAL_SIZE} ...............................................
-#ifndef Q_SIGNAL_SIZE
-//! The size (in bytes) of the signal of an event. Valid values:
-//! 1U, 2U, or 4U; default 2U
-//!
-//! @details
-//! This macro can be defined in the QEP port file (qep_port.hpp) to
-//! configure the QP::QSignal type. When the macro is not defined, the
-//! default of 2 bytes is applied.
-#define Q_SIGNAL_SIZE 2U
-#endif // ndef Q_SIGNAL_SIZE
-//$enddecl${QEP-config} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//============================================================================
-//$declare${QEP} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-namespace QP {
-
-//${QEP::versionStr[]} .......................................................
-//! the current QP version number string based on QP_VERSION_STR
-constexpr char const versionStr[] {QP_VERSION_STR};
-
-//${QEP::QSignal} ............................................................
-#if (Q_SIGNAL_SIZE == 2U)
-//! QSignal represents the signal of an event
-//!
-//! @details
-//! The relationship between an event and a signal is as follows. A signal
-//! in UML is the specification of an asynchronous stimulus that triggers
-//! reactions, and as such is an essential part of an event. (The signal
-//! conveys the type of the occurrence--what happened?) However, an event
-//! can also contain additional quantitative information about the
-//! occurrence in form of event parameters.
-using QSignal = std::uint16_t;
-#endif // (Q_SIGNAL_SIZE == 2U)
-
-//${QEP::QSignal} ............................................................
-#if (Q_SIGNAL_SIZE == 1U)
-using QSignal = std::uint8_t;
-#endif // (Q_SIGNAL_SIZE == 1U)
-
-//${QEP::QSignal} ............................................................
-#if (Q_SIGNAL_SIZE == 4U)
-using QSignal = std::uint32_t;
-#endif // (Q_SIGNAL_SIZE == 4U)
-
-//${QEP::QEvt} ...............................................................
-//! Event class
-//!
-//! @details
-//! QP::QEvt represents events without parameters and serves as the
-//! base class for derivation of events with parameters.
-//!
-//! @note
-//! When #Q_EVT_CTOR and #Q_EVT_VIRTUAL are NOT defined, the QP::QEvt is
-//! a POD (Plain Old Data). Otherwise, it is a class with constructors
-//! and virtual destructor.
-//!
-//! @usage
-//! The following example illustrates how to add an event parameter by
-//! inheriting from the QP::QEvt class.
-//! @include qep_qevt.cpp
-class QEvt {
-public:
-
- //! signal of the event instance
- //! @tr{RQP002}
- QSignal sig;
-
- //! pool ID (0 for static, immutable event)
- //! @tr{RQP003}
- std::uint8_t poolId_;
-
- //! reference counter (only used for dynamic, mutable events)
- //! @tr{RQP003}
- std::uint8_t volatile refCtr_;
-
-public:
-
-#ifdef Q_EVT_CTOR
- //! QP::QEvt constructor when the macro #Q_EVT_CTOR is defined
- explicit QEvt(QSignal s) noexcept
- : sig(s)
- // poolId_/refCtr_ intentionally uninitialized
- {}
-#endif // def Q_EVT_CTOR
-
-#ifdef Q_EVT_CTOR
- //! QP::QEvt constructor (overload for static, immutable events)
- constexpr QEvt(
- QSignal s,
- std::uint8_t /* dummy */) noexcept
- : sig(s),
- poolId_(0U),
- refCtr_(0U)
- {}
-#endif // def Q_EVT_CTOR
-
-#ifdef Q_EVT_VIRTUAL
- //! QP::QEvt virtual destructor when the macro #Q_EVT_VIRTUAL is defined
- virtual ~QEvt() noexcept {
- // empty
- }
-#endif // def Q_EVT_VIRTUAL
-}; // class QEvt
-
-//${QEP::QState} .............................................................
-//! Type returned from state-handler functions
-using QState = std::uint_fast8_t;
-
-//${QEP::QStateHandler} ......................................................
-//! Pointer to state-handler function
-using QStateHandler = QState (*)(void * const me, QEvt const * const e);
-
-//${QEP::QActionHandler} .....................................................
-//! Pointer to an action-handler function
-using QActionHandler = QState (*)(void * const me);
-
-//${QEP::QXThread} ...........................................................
-//! forward declaration
-class QXThread;
-
-//${QEP::QXThreadHandler} ....................................................
-//! Pointer to an extended thread-handler function
-using QXThreadHandler = void (*)(QXThread * const me);
-
-//${QEP::QMState} ............................................................
-//! State object for the QP::QMsm class (QM State Machine).
-//!
-//! @details
-//! This class groups together the attributes of a QP::QMsm state, such as
-//! the parent state (state nesting), the associated state handler function
-//! and the exit action handler function. These attributes are used inside
-//! the QP::QMsm::dispatch() and QP::QMsm::init() functions.
-//!
-//! @attention
-//! The QP::QMState class is only intended for the QM code generator and
-//! should not be used in hand-crafted code.
-struct QMState {
- QMState const * superstate; //!< superstate of this state
- QStateHandler const stateHandler; //!< state handler function
- QActionHandler const entryAction; //!< entry action handler function
- QActionHandler const exitAction; //!< exit action handler function
- QActionHandler const initAction; //!< init action handler function
-};
-
-//${QEP::QMTranActTable} .....................................................
-//! Transition-Action Table for the QP::QMsm State Machine.
-struct QMTranActTable {
- QMState const * target; //!< target of the transition
- QActionHandler const act[1]; //!< array of actions
-};
-
-//${QEP::QHsmAttr} ...........................................................
-//! Attribute of for the QP::QHsm class (Hierarchical State Machine)
-//!
-//! @details
-//! This union represents possible values stored in the 'state' and 'temp'
-//! attributes of the QP::QHsm class.
-union QHsmAttr {
- QStateHandler fun; //!< pointer to a state handler function
- QActionHandler act; //!< pointer to an action-handler function
- QXThreadHandler thr; //!< pointer to an thread-handler function
- QMState const *obj; //!< pointer to QMState object
- QMTranActTable const *tatbl; //!< transition-action table
-};
-
-//${QEP::Q_USER_SIG} .........................................................
-//! Type returned from state-handler functions
-constexpr enum_t Q_USER_SIG {4};
-
-//${QEP::QHsm} ...............................................................
-//! Hierarchical State Machine abstract base class (ABC)
-//!
-//! @details
-//! QP::QHsm represents a Hierarchical State Machine (HSM) with full support
-//! for hierarchical nesting of states, entry/exit actions, and initial
-//! transitions in any composite state. QHsm inherits QP::QMsm without adding
-//! new attributes, so it takes the same amount of RAM as QP::QMsm.
-//!
-//! QP::QHsm is also the base class for the QP::QMsm state machine, which
-//! provides better efficiency, but requires the use of the QM modeling tool
-//! to generate code.
-//!
-//! @note
-//! QP::QHsm is not intended to be instantiated directly, but rather serves as
-//! the base class for derivation of state machines in the application code.
-//!
-//! @usage
-//! The following example illustrates how to derive a state machine class
-//! from QP::QHsm.
-//! @include qep_qhsm.cpp
-class QHsm {
-private:
-
- //! current active state (the state-variable)
- QHsmAttr m_state;
-
- //! temporary: transition chain, target state, etc.
- QHsmAttr m_temp;
-
-public:
-
- //! Maximum nesting depth of states in HSM
- static constexpr std::int_fast8_t MAX_NEST_DEPTH_{6};
-
-private:
-
- // friends...
- friend class QMsm;
- friend class QActive;
- friend class QMActive;
- friend class QXThread;
- friend class QXMutex;
- friend class QXSemaphore;
-
-#ifdef Q_UTEST
- friend class QHsmDummy;
-#endif // def Q_UTEST
-
-#ifdef Q_UTEST
- friend class QActiveDummy;
-#endif // def Q_UTEST
-
-public:
-
- //! Reserved signals by the HSM-style state machine
- //! implementation strategy.
- enum ReservedSig : QSignal {
- Q_EMPTY_SIG, //!< signal to execute the default case
- Q_ENTRY_SIG, //!< signal for entry actions
- Q_EXIT_SIG, //!< signal for exit actions
- Q_INIT_SIG //!< signal for nested initial transitions
- };
-
- //! All possible return values from state-handlers
- enum QStateRet : std::uint_fast8_t {
- // unhandled and need to "bubble up"
- Q_RET_SUPER, //!< event passed to superstate to handle
- Q_RET_SUPER_SUB, //!< event passed to submachine superstate
- Q_RET_UNHANDLED, //!< event unhandled due to a guard
-
- // handled and do not need to "bubble up"
- Q_RET_HANDLED, //!< event handled (internal transition)
- Q_RET_IGNORED, //!< event silently ignored (bubbled up to top)
-
- // entry/exit
- Q_RET_ENTRY, //!< state entry action executed
- Q_RET_EXIT, //!< state exit action executed
-
- // no side effects
- Q_RET_NULL, //!< return value without any effect
-
- // transitions need to execute transition-action table in QP::QMsm
- Q_RET_TRAN, //!< regular transition
- Q_RET_TRAN_INIT, //!< initial transition in a state or submachine
- Q_RET_TRAN_EP, //!< entry-point transition into a submachine
-
- // transitions that additionally clobber QHsm.m_state
- Q_RET_TRAN_HIST, //!< transition to history of a given state
- Q_RET_TRAN_XP //!< exit-point transition out of a submachine
- };
-
-protected:
-
- //! protected constructor of QHsm
- explicit QHsm(QStateHandler const initial) noexcept;
-
-public:
-
-#ifdef Q_HSM_XTOR
- //! virtual destructor
- virtual ~QHsm() noexcept {
- // empty
- }
-#endif // def Q_HSM_XTOR
-
- //! Executes the top-most initial transition in QP::QHsm
- //!
- //! @details
- //! Executes the top-most initial transition in a HSM.
- //!
- //! @param[in] e pointer to an extra parameter (might be NULL)
- //! @param[in] qs_id QS-id of this state machine (for QS local filter)
- //!
- //! @note
- //! Must be called exactly __once__ before the QP::QHsm::dispatch().
- //!
- //! @tr{RQP103} @tr{RQP120I} @tr{RQP120D}
- virtual void init(
- void const * const e,
- std::uint_fast8_t const qs_id);
-
- //! overloaded init(qs_id)
- //!
- //! @details
- //! Executes the top-most initial transition in a HSM (overloaded).
- //!
- //! @param[in] qs_id QS-id of this state machine (for QS local filter)
- //!
- //! @attention
- //! QHsm::init() must be called exactly **once** before
- //! QHsm::dispatch()
- virtual void init(std::uint_fast8_t const qs_id) {
- init(nullptr, qs_id);
- }
-
- //! Dispatches an event to QP::QHsm
- //!
- //! @details
- //! Dispatches an event for processing to a hierarchical state machine.
- //! The event dispatching represents one run-to-completion (RTC) step.
- //!
- //! @param[in] e pointer to the event to be dispatched to the HSM
- //! @param[in] qs_id QS-id of this state machine (for QS local filter)
- //!
- //! @attention
- //! This state machine must be initialized by calling QP::QHsm::init()
- //! exactly **once** before calling QP::QHsm::dispatch().
- //!
- //! @tr{RQP103}
- //! @tr{RQP120A} @tr{RQP120B} @tr{RQP120C} @tr{RQP120D} @tr{RQP120E}
- virtual void dispatch(
- QEvt const * const e,
- std::uint_fast8_t const qs_id);
-
- //! The top-state handler
- //!
- //! @details
- //! The QHsm::top() state handler is the ultimate root of state
- //! hierarchy in all HSMs derived from QP::QHsm.
- //!
- //! @param[in] me pointer to the HSM instance
- //! @param[in] e pointer to the event to be dispatched to the HSM
- //!
- //! @returns
- //! Always returns #Q_RET_IGNORED, which means that the top state ignores
- //! all events.
- //!
- //! @note
- //! The parameters to this state handler are not used. They are provided
- //! for conformance with the state-handler function signature
- //! QP::QStateHandler.
- //!
- //! @tr{RQP103} @tr{RQP120T}
- static QState top(
- void * const me,
- QEvt const * const e) noexcept;
-
- //! Obtain the current state (state handler function)
- //!
- //! @note used in the QM code generation
- QStateHandler state() const noexcept {
- return m_state.fun;
- }
-
-#ifdef Q_SPY
- //! Get the current state handler of the QP::QHsm
- virtual QStateHandler getStateHandler() noexcept {
- return m_state.fun;
- }
-#endif // def Q_SPY
-
- //! Tests if a given state is part of the current active state
- //! configuration
- //!
- //! @details
- //! Tests if a state machine derived from QHsm is-in a given state.
- //!
- //! @note
- //! For a HSM, to "be in a state" means also to be in a superstate of
- //! of the state.
- //!
- //! @param[in] s pointer to the state-handler function to be tested
- //!
- //! @returns
- //! 'true' if the HSM is in the `state` and 'false' otherwise
- //!
- //! @tr{RQP103}
- //! @tr{RQP120S}
- bool isIn(QStateHandler const s) noexcept;
-
- //! Obtain the current active child state of a given parent
- //!
- //! @note used in the QM code generation
- QStateHandler childState(QStateHandler const parent) noexcept;
-
-protected:
-
- //! Helper function to specify a state transition
- QState tran(QStateHandler const target) noexcept {
- m_temp.fun = target;
- return Q_RET_TRAN;
- }
-
- //! Helper function to specify a transition to history
- QState tran_hist(QStateHandler const hist) noexcept {
- m_temp.fun = hist;
- return Q_RET_TRAN_HIST;
- }
-
- //! Helper function to specify the superstate of a given state
- QState super(QStateHandler const superstate) noexcept {
- m_temp.fun = superstate;
- return Q_RET_SUPER;
- }
-
- //! Helper function to specify a regular state transition
- //! in a QM state-handler
- QState qm_tran(void const * const tatbl) noexcept {
- m_temp.tatbl = static_cast(tatbl);
- return Q_RET_TRAN;
- }
-
- //! Helper function to specify an initial state transition
- //! in a QM state-handler
- QState qm_tran_init(void const * const tatbl) noexcept {
- m_temp.tatbl = static_cast(tatbl);
- return Q_RET_TRAN_INIT;
- }
-
- //! Helper function to specifiy a transition to history
- //! in a QM state-handler
- QState qm_tran_hist(
- QMState const * const hist,
- void const * const tatbl) noexcept
- {
- m_state.obj = hist;
- m_temp.tatbl = static_cast(tatbl);
- return Q_RET_TRAN_HIST;
- }
-
- //! Helper function to specify a transition to an entry point
- //! to a submachine state in a QM state-handler
- QState qm_tran_ep(void const * const tatbl) noexcept {
- m_temp.tatbl = static_cast(tatbl);
- return Q_RET_TRAN_EP;
- }
-
- //! Helper function to specify a transition to an exit point
- //! from a submachine state in a QM state-handler
- QState qm_tran_xp(
- QActionHandler const xp,
- void const * const tatbl) noexcept
- {
- m_state.act = xp;
- m_temp.tatbl = static_cast(tatbl);
- return Q_RET_TRAN_XP;
- }
-
-#ifdef Q_SPY
- //! Helper function to specify a state entry in a QM state-handler
- QState qm_entry(QMState const * const s) noexcept {
- m_temp.obj = s;
- return Q_RET_ENTRY;
- }
-#endif // def Q_SPY
-
-#ifndef Q_SPY
- //! Helper function to specify a state entry in a QM state-handler
- QState qm_entry(QMState const * const s) noexcept {
- static_cast(s); // unused parameter
- return Q_RET_ENTRY;
- }
-#endif // ndef Q_SPY
-
-#ifdef Q_SPY
- //! Helper function to specify a state exit in a QM state-handler
- QState qm_exit(QMState const * const s) noexcept {
- m_temp.obj = s;
- return Q_RET_EXIT;
- }
-#endif // def Q_SPY
-
-#ifndef Q_SPY
- //! Helper function to specify a state exit in a QM state-handler
- QState qm_exit(QMState const * const s) noexcept {
- static_cast(s); // unused parameter
- return Q_RET_EXIT;
- }
-#endif // ndef Q_SPY
-
- //! Helper function to specify a submachine exit in a QM state-handler
- QState qm_sm_exit(QMState const * const s) noexcept {
- m_temp.obj = s;
- return Q_RET_EXIT;
- }
-
- //! Helper function to call in a QM state-handler when it passes
- //! the event to the host submachine state to handle an event.
- QState qm_super_sub(QMState const * const s) noexcept {
- m_temp.obj = s;
- return Q_RET_SUPER_SUB;
- }
-
-private:
-
- //! @details
- //! helper function to execute transition sequence in a hierarchical
- //! state machine (HSM).
- //!
- //! @param[in,out] path array of pointers to state-handler functions
- //! to execute the entry actions
- //! @param[in] qs_id QS-id of this state machine (for QS local filter)
- //!
- //! @returns
- //! the depth of the entry path stored in the `path` parameter.
- //!
- //! @tr{RQP103}
- //! @tr{RQP120E} @tr{RQP120F}
- std::int_fast8_t hsm_tran(
- QStateHandler (&path)[MAX_NEST_DEPTH_],
- std::uint_fast8_t const qs_id);
-}; // class QHsm
-
-//${QEP::QMsm} ...............................................................
-//! QM State Machine implementation strategy
-//!
-//! @details
-//! QP::QMsm (QM State Machine) provides a more efficient state machine
-//! implementation strategy than QHsm, but requires the use of the QM
-//! modeling tool, but are the fastest and need the least run-time
-//! support (the smallest event-processor taking up the least code space).
-//!
-//! @note
-//! QP::QMsm is not intended to be instantiated directly, but rather serves as
-//! the base class for derivation of state machines in the application code.
-//!
-//! @usage
-//! The following example illustrates how to derive a state machine class
-//! from QP::QMsm:
-//! @include qep_qmsm.cpp
-class QMsm : public QP::QHsm {
-private:
-
- //! the top state object for the QP::QMsm
- static QMState const msm_top_s;
-
- // friends...
- friend class QMActive;
-
-public:
-
- //! maximum depth of implemented entry levels for transitions to history
- static constexpr std::int_fast8_t MAX_ENTRY_DEPTH_{4};
-
-public:
-
- //! Performs the second step of SM initialization by triggering
- //! the top-most initial transition.
- //!
- //! @details
- //! Executes the top-most initial transition in a MSM.
- //!
- //! @param[in] e pointer to an extra parameter (might be nullptr)
- //! @param[in] qs_id QS-id of this state machine (for QS local filter)
- //!
- //! @attention
- //! QMsm::init() must be called exactly **once** before QMsm::dispatch()
- void init(
- void const * const e,
- std::uint_fast8_t const qs_id) override;
-
-protected:
-
- //! Protected constructor
- //! @details
- //! Performs the first step of initialization by assigning the initial
- //! pseudostate to the currently active state of the state machine.
- //!
- //! @param[in] initial the top-most initial transition for the MSM.
- //!
- //! @note
- //! The constructor is protected to prevent direct instantiating of the
- //! QP::QMsm objects. This class is intended for subclassing only.
- //!
- //! @sa
- //! The QP::QMsm example illustrates how to use the QMsm constructor
- //! in the constructor initializer list of the derived state machines.
- explicit QMsm(QStateHandler const initial) noexcept
- : QHsm(initial)
- {
- m_state.obj = &msm_top_s;
- m_temp.fun = initial;
- }
-
-public:
-
- //! overloaded init(qs_id)
- //!
- //! @details
- //! Executes the top-most initial transition in a MSM (overloaded).
- //!
- //! @param[in] qs_id QS-id of this state machine (for QS local filter)
- //!
- //! @attention
- //! QMsm::init() must be called exactly **once** before QMsm::dispatch()
- void init(std::uint_fast8_t const qs_id) override {
- QMsm::init(nullptr, qs_id);
- }
-
- //! Dispatches an event to a MSM
- //!
- //! @details
- //! Dispatches an event for processing to a meta state machine (MSM).
- //! The processing of an event represents one run-to-completion (RTC) step.
- //!
- //! @param[in] e pointer to the event to be dispatched to the MSM
- //! @param[in] qs_id QS-id of this state machine (for QS local filter)
- //!
- //! @note
- //! Must be called after QMsm::init().
- void dispatch(
- QEvt const * const e,
- std::uint_fast8_t const qs_id) override;
-
- //! Tests if a given state is part of the active state configuration
- //!
- //! @details
- //! Tests if a state machine derived from QMsm is-in a given state.
- //!
- //! @note
- //! For a MSM, to "be-in" a state means also to "be-in" a superstate of
- //! of the state.
- //!
- //! @param[in] st pointer to the QMState object that corresponds to the
- //! tested state.
- //! @returns
- //! 'true' if the MSM is in the \c st and 'false' otherwise
- bool isInState(QMState const * const st) const noexcept;
-
-private:
-
- //! disallow inherited top() function in QP::QMsm and subclasses
- //! @sa QMsm::msm_top_s
- static QStateHandler top(
- void * const me,
- QEvt const * const e) noexcept = delete;
-
-public:
-
- //! Return the current active state object (read only)
- QMState const * stateObj() const noexcept {
- return m_state.obj;
- }
-
- //! Obtain the current active child state of a given parent (read only)
- //!
- //! @details
- //! Finds the child state of the given `parent`, such that this child
- //! state is an ancestor of the currently active state. The main purpose
- //! of this function is to support **shallow history** transitions in
- //! state machines derived from QHsm.
- //!
- //! @param[in] parent pointer to the state-handler function
- //!
- //! @returns
- //! the child of a given `parent` state, which is an ancestor of the
- //! currently active state
- //!
- //! @note
- //! this function is designed to be called during state transitions, so it
- //! does not necessarily start in a stable state configuration.
- //! However, the function establishes stable state configuration upon exit.
- //!
- //! @tr{RQP103}
- //! @tr{RQP120H}
- QMState const * childStateObj(QMState const * const parent) const noexcept;
-
-protected:
-
-#ifdef Q_SPY
- //! Get the current state handler of the QMsm
- QStateHandler getStateHandler() noexcept override {
- return m_state.obj->stateHandler;
- }
-#endif // def Q_SPY
-
-private:
-
- //! Internal helper function to execute a transition-action table
- //!
- //! @details
- //! Helper function to execute transition sequence in a tran-action table.
- //!
- //! @param[in] tatbl pointer to the transition-action table
- //! @param[in] qs_id QS-id of this state machine (for QS local filter)
- //!
- //! @returns
- //! the status of the last action from the transition-action table.
- //!
- //! @note
- //! This function is for internal use inside the QEP event processor and
- //! should **not** be called directly from the applications.
- QState execTatbl_(
- QMTranActTable const * const tatbl,
- std::uint_fast8_t const qs_id);
-
- //! Internal helper function to exit current state to transition source
- //!
- //! @details
- //! Helper function to exit the current state configuration to the
- //! transition source, which is a hierarchical state machine might be a
- //! superstate of the current state.
- //!
- //! @param[in] s pointer to the current state
- //! @param[in] ts pointer to the transition source state
- //! @param[in] qs_id QS-id of this state machine (for QS local filter)
- void exitToTranSource_(
- QMState const * s,
- QMState const * const ts,
- std::uint_fast8_t const qs_id);
-
- //! Internal helper function to enter state history
- //!
- //! @details
- //! Static helper function to execute the segment of transition to history
- //! after entering the composite state and
- //!
- //! @param[in] hist pointer to the history substate
- //! @param[in] qs_id QS-id of this state machine (for QS local filter)
- //!
- //! @returns
- //! ::Q_RET_INIT, if an initial transition has been executed in the last
- //! entered state or ::Q_RET_NULL if no such transition was taken.
- QState enterHistory_(
- QMState const * const hist,
- std::uint_fast8_t const qs_id);
-}; // class QMsm
-
-} // namespace QP
-//$enddecl${QEP} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//============================================================================
-//$declare${QEP-macros} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-
-//${QEP-macros::Q_STATE_DECL} ................................................
-//! Macro to generate a declaration of a state-handler, state-caller and
-//! a state-object for a given state in a subclass of QP::QHsm.
-#define Q_STATE_DECL(state_) \
- QP::QState state_ ## _h(QP::QEvt const * const e); \
- static QP::QState state_(void * const me, QP::QEvt const * const e)
-
-//${QEP-macros::Q_STATE_DEF} .................................................
-//! Macro to generate a declaration of a state-handler, state-caller and
-//! a state-object for a given state in a subclass of QP::QHsm.
-#define Q_STATE_DEF(subclass_, state_) \
- QP::QState subclass_::state_(void * const me, QP::QEvt const * const e) { \
- return static_cast(me)->state_ ## _h(e); } \
- QP::QState subclass_::state_ ## _h(QP::QEvt const * const e)
-
-//${QEP-macros::Q_HANDLED} ...................................................
-//! Macro to specify that the event was handled
-#define Q_HANDLED() (Q_RET_HANDLED)
-
-//${QEP-macros::Q_UNHANDLED} .................................................
-//! Macro to specify that the event was NOT handled
-//! due to a guard condition evaluating to 'false'
-#define Q_UNHANDLED() (Q_RET_UNHANDLED)
-
-//${QEP-macros::Q_EVT_CAST} ..................................................
-//! Perform downcast of an event onto a subclass of QEvt `class_`
-//!
-//! @details
-//! This macro encapsulates the downcast of QEvt pointers, which violates
-//! MISRA-C 2004 rule 11.4(advisory). This macro helps to localize this
-//! deviation.
-#define Q_EVT_CAST(subclass_) (static_cast(e))
-
-//${QEP-macros::Q_STATE_CAST} ................................................
-//! Macro to perform casting to QStateHandler.
-//!
-//! @details
-//! This macro encapsulates the cast of a specific state handler function
-//! pointer to QStateHandler, which violates MISRA-C 2004 rule 11.4(advisory).
-//! This macro helps to localize this deviation.
-#define Q_STATE_CAST(handler_) \
- (reinterpret_cast(handler_))
-
-//${QEP-macros::Q_ACTION_CAST} ...............................................
-//! Macro to perform casting to QActionHandler.
-//!
-//! @details
-//! This macro encapsulates the cast of a specific action handler function
-//! pointer to QActionHandler, which violates MISRA-C2004 rule 11.4(advisory).
-//! This macro helps to localize this deviation.
-#define Q_ACTION_CAST(act_) \
- (reinterpret_cast(act_))
-
-//${QEP-macros::QM_STATE_DECL} ...............................................
-//! Macro to generate a declaration of a state-handler, state-caller and
-//! a state-object for a given state in a subclass of QP::QMsm.
-#define QM_STATE_DECL(state_) \
- QP::QState state_ ## _h(QP::QEvt const * const e); \
- static QP::QState state_(void * const me, QP::QEvt const * const e); \
- static QP::QMState const state_ ## _s
-
-//${QEP-macros::QM_SM_STATE_DECL} ............................................
-//! Macro to generate a declaration of a state-handler, state-caller and
-//! a state-object for a given *submachine* state in a subclass of QP::QMsm.
-#define QM_SM_STATE_DECL(subm_, state_) \
- QP::QState state_ ## _h(QP::QEvt const * const e);\
- static QP::QState state_(void * const me, QP::QEvt const * const e); \
- static SM_ ## subm_ const state_ ## _s
-
-//${QEP-macros::QM_ACTION_DECL} ..............................................
-//! Macro to generate a declaration of an action-handler and action-caller
-//! in a subclass of QP::QMsm.
-#define QM_ACTION_DECL(action_) \
- QP::QState action_ ## _h(); \
- static QP::QState action_(void * const me)
-
-//${QEP-macros::QM_STATE_DEF} ................................................
-//! Macro to generate a definition of a state-caller and state-handler
-//! for a given state in a subclass of QP::QMsm.
-#define QM_STATE_DEF(subclass_, state_) \
- QP::QState subclass_::state_(void * const me, QP::QEvt const * const e) { \
- return static_cast(me)->state_ ## _h(e); } \
- QP::QState subclass_::state_ ## _h(QP::QEvt const * const e)
-
-//${QEP-macros::QM_ACTION_DEF} ...............................................
-//! Macro to generate a definition of an action-caller and action-handler
-//! in a subclass of QP::QMsm.
-#define QM_ACTION_DEF(subclass_, action_) \
- QP::QState subclass_::action_(void * const me) { \
- return static_cast(me)->action_ ## _h(); } \
- QP::QState subclass_::action_ ## _h()
-
-//${QEP-macros::QM_HANDLED} ..................................................
-//! Macro for a QM action-handler when it handles the event.
-#define QM_HANDLED() (Q_RET_HANDLED)
-
-//${QEP-macros::QM_UNHANDLED} ................................................
-//! Macro for a QM action-handler when it does not handle the event
-//! due to a guard condition evaluating to false.
-#define QM_UNHANDLED() (Q_RET_HANDLED)
-
-//${QEP-macros::QM_SUPER} ....................................................
-//! Macro for a QM action-handler when it passes the event to the superstate
-#define QM_SUPER() (Q_RET_SUPER)
-
-//${QEP-macros::QM_STATE_NULL} ...............................................
-//! Macro to provide strictly-typed zero-state to use for submachines.
-//! Applicable to suclasses of QP::QMsm.
-#define QM_STATE_NULL (nullptr)
-
-//${QEP-macros::Q_ACTION_NULL} ...............................................
-//! Macro to provide strictly-typed zero-action to terminate action lists
-//! in the transition-action-tables in QP::QMsm.
-#define Q_ACTION_NULL (nullptr)
-
-//${QEP-macros::Q_UNUSED_PAR} ................................................
-//! Helper macro to clearly mark unused parameters of functions.
-#define Q_UNUSED_PAR(par_) (static_cast(par_))
-
-//${QEP-macros::Q_DIM} .......................................................
-//! Helper macro to calculate static dimension of a 1-dim `array_`
-//!
-//! @param[in] array_ 1-dimensional array
-//!
-//! @returns
-//! the length of the array (number of elements it can hold)
-#define Q_DIM(array_) (sizeof(array_) / sizeof((array_)[0U]))
-
-//${QEP-macros::Q_UINT2PTR_CAST} .............................................
-//! Perform cast from unsigned integer `uint_` to pointer of type `type_`
-//!
-//! @details
-//! This macro encapsulates the cast to (type_ *), which QP ports or
-//! application might use to access embedded hardware registers.
-//! Such uses can trigger PC-Lint "Note 923: cast from int to pointer"
-//! and this macro helps to encapsulate this deviation.
-#define Q_UINT2PTR_CAST(type_, uint_) (reinterpret_cast(uint_))
-
-//${QEP-macros::QEVT_INITIALIZER} ............................................
-//! Initializer of static constant QEvt instances
-//!
-//! @details
-//! This macro encapsulates the ugly casting of enumerated signals
-//! to QSignal and constants for QEvt.poolID and QEvt.refCtr_.
-#define QEVT_INITIALIZER(sig_) { static_cast(sig_), 0U, 0U }
-//$enddecl${QEP-macros} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-#endif // QEP_HPP_
diff --git a/src/qep_hsm.cpp b/src/qep_hsm.cpp
index 4afcf5e..3e693ea 100644
--- a/src/qep_hsm.cpp
+++ b/src/qep_hsm.cpp
@@ -1,628 +1,577 @@
-//$file${src::qf::qep_hsm.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-//
-// Model: qpcpp.qm
-// File: ${src::qf::qep_hsm.cpp}
-//
-// This code has been generated by QM 5.2.5 .
-// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
+//============================================================================
+// QP/C++ Real-Time Embedded Framework (RTEF)
+// Version 8.0.2
//
-// This code is covered by the following QP license:
-// License # : LicenseRef-QL-dual
-// Issued to : Any user of the QP/C++ real-time embedded framework
-// Framework(s) : qpcpp
-// Support ends : 2023-12-31
-// License scope:
+// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved.
//
-// Copyright (C) 2005 Quantum Leaps, LLC .
+// Q u a n t u m L e a P s
+// ------------------------
+// Modern Embedded Software
//
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
//
-// This software is dual-licensed under the terms of the open source GNU
-// General Public License version 3 (or any later version), or alternatively,
-// under the terms of one of the closed source Quantum Leaps commercial
-// licenses.
-//
-// The terms of the open source GNU General Public License version 3
-// can be found at:
-//
-// The terms of the closed source Quantum Leaps commercial licenses
-// can be found at:
+// This software is dual-licensed under the terms of the open-source GNU
+// General Public License (GPL) or under the terms of one of the closed-
+// source Quantum Leaps commercial licenses.
//
// Redistributions in source code must retain this top-level comment block.
// Plagiarizing this software to sidestep the license obligations is illegal.
//
-// Contact information:
+// NOTE:
+// The GPL does NOT permit the incorporation of this code into proprietary
+// programs. Please contact Quantum Leaps for commercial licensing options,
+// which expressly supersede the GPL and are designed explicitly for
+// closed-source distribution.
+//
+// Quantum Leaps contact information:
//
//
-//
-//$endhead${src::qf::qep_hsm.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//! @file
-//! @brief QP::QHsm implementation
-//!
-//! @tr{RQP103} @tr{RQP104} @tr{RQP120} @tr{RQP130}
-
+//============================================================================
#define QP_IMPL // this is QP implementation
-#include "qep_port.hpp" // QEP port
+#include "qp_port.hpp" // QP port
+#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
#ifdef Q_SPY // QS software tracing enabled?
#include "qs_port.hpp" // QS port
#include "qs_pkg.hpp" // QS facilities for pre-defined trace records
#else
#include "qs_dummy.hpp" // disable the QS software tracing
#endif // Q_SPY
-#include "qassert.h" // QP embedded systems-friendly assertions
-
-//============================================================================
-//$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-// Check for the minimum required QP version
-#if (QP_VERSION < 700U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U))
-#error qpcpp version 7.0.0 or higher required
-#endif
-//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//$define${QEP::versionStr[]} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-namespace QP {
-
-} // namespace QP
-//$enddef${QEP::versionStr[]} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-//============================================================================
// unnamed namespace for local definitions with internal linkage
namespace {
+
Q_DEFINE_THIS_MODULE("qep_hsm")
-//----------------------------------------------------------------------------
-//! Immutable events corresponding to the reserved signals.
-//!
-//! @details
-//! Static, immutable reserved events that the QEP event processor sends
-//! to state handler functions of QHsm-style state machine to execute entry
-//! actions, exit actions, and initial transitions.
-//!
+// maximum depth of state nesting in a QHsm (including the top level)
+// must be >= 3
+static constexpr std::int_fast8_t QHSM_MAX_NEST_DEPTH_ {6};
+
+//! @cond INTERNAL
+
+// immutable events corresponding to the reserved signals.
static QP::QEvt const l_reservedEvt_[4] {
-#ifdef Q_EVT_CTOR // Is the QEvt constructor provided?
- QP::QEvt(static_cast(QP::QHsm::Q_EMPTY_SIG), 0U),
- QP::QEvt(static_cast(QP::QHsm::Q_ENTRY_SIG), 0U),
- QP::QEvt(static_cast(QP::QHsm::Q_EXIT_SIG), 0U),
- QP::QEvt(static_cast(QP::QHsm::Q_INIT_SIG), 0U)
-#else // QEvt is a POD (Plain Old Datatype)
- { static_cast(QP::QHsm::Q_EMPTY_SIG), 0U, 0U },
- { static_cast(QP::QHsm::Q_ENTRY_SIG), 0U, 0U },
- { static_cast(QP::QHsm::Q_EXIT_SIG), 0U, 0U },
- { static_cast(QP::QHsm::Q_INIT_SIG), 0U, 0U }
-#endif
+ QP::QEvt(static_cast(QP::QHsm::Q_EMPTY_SIG)),
+ QP::QEvt(static_cast(QP::QHsm::Q_ENTRY_SIG)),
+ QP::QEvt(static_cast(QP::QHsm::Q_EXIT_SIG)),
+ QP::QEvt(static_cast(QP::QHsm::Q_INIT_SIG))
};
-//----------------------------------------------------------------------------
-// inline helper functions
+//! @endcond
-//............................................................................
-//! helper function to trigger reserved event in an QHsm
-//!
-//! @param[in] state state handler function
-//! @param[in] sig reserved signal to trigger
-static inline QP::QState hsm_reservedEvt_(
- QP::QHsm * const me,
- QP::QStateHandler const state,
- enum QP::QHsm::ReservedSig const sig)
-{
- return (*state)(me, &l_reservedEvt_[sig]);
-}
+} // unnamed namespace
-//............................................................................
-//! Helper function to execute entry into a given state in a
-//! hierarchical state machine (HSM).
-//!
-//! @param[in] state state handler function
-//! @param[in] qs_id QS-id of this state machine (for QS local filter)
-static inline void hsm_state_entry_(
- QP::QHsm * const me,
- QP::QStateHandler const state,
- std::uint_fast8_t const qs_id)
-{
-#ifdef Q_SPY
- if ((*state)(me, &l_reservedEvt_[QP::QHsm::Q_ENTRY_SIG])
- == QP::QHsm::Q_RET_HANDLED)
- {
- QS_CRIT_STAT_
- QS_BEGIN_PRE_(QP::QS_QEP_STATE_ENTRY, qs_id)
- QS_OBJ_PRE_(me);
- QS_FUN_PRE_(state);
- QS_END_PRE_()
- }
-#else
- Q_UNUSED_PAR(qs_id);
- static_cast((*state)(me, &l_reservedEvt_[QP::QHsm::Q_ENTRY_SIG]));
-#endif // Q_SPY
-}
+//============================================================================
+//! @cond INTERNAL
+
+// internal helper macro to pass a reserved event into the state handler
+#define QHSM_RESERVED_EVT_(state_, sig_) \
+ ((*(state_))(this, &l_reservedEvt_[(sig_)]))
-//............................................................................
-//! Helper function to execute exit from a given state in a
-//! hierarchical state machine (HSM).
-//!
-//! @param[in] state state handler function
-//! @param[in] qs_id QS-id of this state machine (for QS local filter)
-//!
-//! @returns
-//! 'true' if the exit action has been found in the state and
-//! 'flase' otherwise.
-static inline bool hsm_state_exit_(
- QP::QHsm * const me,
- QP::QStateHandler const state,
- std::uint_fast8_t const qs_id)
-{
#ifdef Q_SPY
- bool isHandled;
- if ((*state)(me, &l_reservedEvt_[QP::QHsm::Q_EXIT_SIG])
- == QP::QHsm::Q_RET_HANDLED)
- {
- QS_CRIT_STAT_
- QS_BEGIN_PRE_(QP::QS_QEP_STATE_EXIT, qs_id)
- QS_OBJ_PRE_(me);
- QS_FUN_PRE_(state);
- QS_END_PRE_()
- isHandled = true;
- }
- else {
- isHandled = false;
- }
- return isHandled;
+// helper macro to trace state action (entry/exit)
+#define QS_STATE_ACT_(rec_, state_) \
+ QS_CRIT_ENTRY(); \
+ QS_BEGIN_PRE((rec_), qsId) \
+ QS_OBJ_PRE(this); \
+ QS_FUN_PRE(state_); \
+ QS_END_PRE() \
+ QS_CRIT_EXIT()
+
+// internal helper macro to top-most init
+#define QS_TOP_INIT_(rec_, trg_) \
+ QS_CRIT_ENTRY(); \
+ QS_BEGIN_PRE((rec_), qsId) \
+ QS_TIME_PRE(); \
+ QS_OBJ_PRE(this); \
+ QS_FUN_PRE(trg_); \
+ QS_END_PRE() \
+ QS_CRIT_EXIT()
+
+// internal helper macro to trace transition segment
+#define QS_TRAN_SEG_(rec_, src_, trg_) \
+ QS_CRIT_ENTRY(); \
+ QS_BEGIN_PRE((rec_), qsId) \
+ QS_OBJ_PRE(this); \
+ QS_FUN_PRE(src_); \
+ QS_FUN_PRE(trg_); \
+ QS_END_PRE() \
+ QS_CRIT_EXIT()
+
+// internal helper macro to trace transition action
+#define QS_TRAN_ACT_(rec_, state_) \
+ QS_CRIT_ENTRY(); \
+ QS_BEGIN_PRE((rec_), qsId) \
+ QS_SIG_PRE(e->sig); \
+ QS_OBJ_PRE(this); \
+ QS_FUN_PRE(state_); \
+ QS_END_PRE() \
+ QS_CRIT_EXIT()
+
+// internal helper macro to trace transition begin/end
+#define QS_TRAN0_(rec_, trg_) \
+ QS_CRIT_ENTRY(); \
+ QS_BEGIN_PRE((rec_), qsId) \
+ QS_TIME_PRE(); \
+ QS_SIG_PRE(e->sig); \
+ QS_OBJ_PRE(this); \
+ QS_FUN_PRE(trg_); \
+ QS_END_PRE() \
+ QS_CRIT_EXIT()
+
+// internal helper macro to trace regulsr transition
+#define QS_TRAN_END_(rec_, src_, trg_) \
+ QS_CRIT_ENTRY(); \
+ QS_BEGIN_PRE((rec_), qsId) \
+ QS_TIME_PRE(); \
+ QS_SIG_PRE(e->sig); \
+ QS_OBJ_PRE(this); \
+ QS_FUN_PRE(src_); \
+ QS_FUN_PRE(trg_); \
+ QS_END_PRE() \
+ QS_CRIT_EXIT()
+
#else
- Q_UNUSED_PAR(qs_id);
- return (*state)(me, &l_reservedEvt_[QP::QHsm::Q_EXIT_SIG]);
-#endif // Q_SPY
-}
+#define QS_STATE_ACT_(rec_, state_) (static_cast(0))
+#define QS_TOP_INIT_(rec_, trg_) (static_cast(0))
+#define QS_TRAN_SEG_(rec_, src_, trg_) (static_cast(0))
+#define QS_TRAN_ACT_(rec_, state_) (static_cast(0))
+#define QS_TRAN0_(rec_, trg_) (static_cast(0))
+#define QS_TRAN_END_(rec_, src_, trg_) (static_cast(0))
+#endif
-} // unnamed namespace
+//! @endcond
-//$define${QEP::QHsm} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
namespace QP {
-//${QEP::QHsm} ...............................................................
-
-//${QEP::QHsm::QHsm} .........................................................
-QHsm::QHsm(QStateHandler const initial) noexcept{
- m_state.fun = Q_STATE_CAST(&top);
+//............................................................................
+QHsm::QHsm(QStateHandler const initial) noexcept
+: QAsm()
+{
+ m_state.fun = ⊤
m_temp.fun = initial;
}
-//${QEP::QHsm::init} .........................................................
+//............................................................................
void QHsm::init(
void const * const e,
- std::uint_fast8_t const qs_id)
+ std::uint_fast8_t const qsId)
{
- #ifdef Q_SPY
+ QF_CRIT_STAT
+
+ // produce QS dictionary for QP::QHsm::top()
+#ifdef Q_SPY
+ QS_CRIT_ENTRY();
+ bool isDone = true;
if ((QS::priv_.flags & 0x01U) == 0U) {
QS::priv_.flags |= 0x01U;
+ isDone = false;
+ }
+ QS_CRIT_EXIT();
+ if (!isDone) {
QS_FUN_DICTIONARY(&QP::QHsm::top);
}
- #else
- Q_UNUSED_PAR(qs_id);
- #endif
+#else
+ Q_UNUSED_PAR(qsId);
+#endif // def Q_SPY
QStateHandler t = m_state.fun;
- //! @pre ctor must have been executed and initial tran NOT taken
- Q_REQUIRE_ID(200, (m_temp.fun != nullptr)
- && (t == Q_STATE_CAST(&top)));
+ QF_CRIT_ENTRY();
+ Q_REQUIRE_INCRIT(200,
+ (m_temp.fun != nullptr)
+ && (t == Q_STATE_CAST(&top)));
+ QF_CRIT_EXIT();
- // execute the top-most initial transition
+ // execute the top-most initial tran.
QState r = (*m_temp.fun)(this, Q_EVT_CAST(QEvt));
- // the top-most initial transition must be taken
- Q_ASSERT_ID(210, r == Q_RET_TRAN);
+ QF_CRIT_ENTRY();
+ // the top-most initial tran. must be taken
+ Q_ASSERT_INCRIT(210, r == Q_RET_TRAN);
+ QF_CRIT_EXIT();
- QS_CRIT_STAT_
- QS_BEGIN_PRE_(QS_QEP_STATE_INIT, qs_id)
- QS_OBJ_PRE_(this); // this state machine object
- QS_FUN_PRE_(t); // the source state
- QS_FUN_PRE_(m_temp.fun); // the target of the initial transition
- QS_END_PRE_()
+ QS_TRAN_SEG_(QS_QEP_STATE_INIT, t, m_temp.fun);
// drill down into the state hierarchy with initial transitions...
- do {
- QStateHandler path[MAX_NEST_DEPTH_]; // tran entry path array
- std::int_fast8_t ip = 0; // entry path index
-
- path[0] = m_temp.fun;
- static_cast(hsm_reservedEvt_(this, m_temp.fun, Q_EMPTY_SIG));
- while (m_temp.fun != t) {
- ++ip;
- Q_ASSERT_ID(220, ip < MAX_NEST_DEPTH_);
- path[ip] = m_temp.fun;
- static_cast(hsm_reservedEvt_(this, m_temp.fun, Q_EMPTY_SIG));
- }
- m_temp.fun = path[0];
-
- // retrace the entry path in reverse (desired) order...
- do {
- hsm_state_entry_(this, path[ip], qs_id); // enter path[ip]
- --ip;
- } while (ip >= 0);
-
- t = path[0]; // current state becomes the new source
-
- r = hsm_reservedEvt_(this, t, Q_INIT_SIG); // execute initial tran.
-
- #ifdef Q_SPY
- if (r == Q_RET_TRAN) {
- QS_BEGIN_PRE_(QS_QEP_STATE_INIT, qs_id)
- QS_OBJ_PRE_(this); // this state machine object
- QS_FUN_PRE_(t); // the source state
- QS_FUN_PRE_(m_temp.fun); // the target of the initial tran.
- QS_END_PRE_()
- }
- #endif // Q_SPY
+ QStateHandler path[QHSM_MAX_NEST_DEPTH_]; // tran. entry path array
+ path[0] = m_temp.fun;
+ static_cast(QHSM_RESERVED_EVT_(m_temp.fun, Q_EMPTY_SIG));
+
+ std::int_fast8_t ip = 1; // tran. entry path index (also the loop bound)
+ for (; (m_temp.fun != t) && (ip < QHSM_MAX_NEST_DEPTH_); ++ip) {
+ path[ip] = m_temp.fun;
+ static_cast(QHSM_RESERVED_EVT_(m_temp.fun, Q_EMPTY_SIG));
+ }
+ QF_CRIT_ENTRY();
+ // must NOT be too many state nesting levels or "malformed" HSM
+ Q_ASSERT_INCRIT(220, ip <= QHSM_MAX_NEST_DEPTH_);
+ QF_CRIT_EXIT();
- } while (r == Q_RET_TRAN);
+ m_temp.fun = path[0];
+ enter_target_(&path[0], ip - 1, qsId);
+ t = path[0];
- QS_BEGIN_PRE_(QS_QEP_INIT_TRAN, qs_id)
- QS_TIME_PRE_(); // time stamp
- QS_OBJ_PRE_(this); // this state machine object
- QS_FUN_PRE_(t); // the new active state
- QS_END_PRE_()
+ QS_TOP_INIT_(QS_QEP_INIT_TRAN, t);
m_state.fun = t; // change the current active state
- m_temp.fun = t; // mark the configuration as stable
+#ifdef Q_UNSAFE
+ Q_UNUSED_PAR(r);
+#endif
}
-//${QEP::QHsm::dispatch} .....................................................
+//............................................................................
void QHsm::dispatch(
QEvt const * const e,
- std::uint_fast8_t const qs_id)
+ std::uint_fast8_t const qsId)
{
- #ifndef Q_SPY
- Q_UNUSED_PAR(qs_id);
- #endif
+#ifndef Q_SPY
+ Q_UNUSED_PAR(qsId);
+#endif
+
+ QStateHandler s = m_state.fun;
+ QStateHandler t = s;
+ QF_CRIT_STAT
+
+ QF_CRIT_ENTRY();
+ Q_REQUIRE_INCRIT(300,
+ (e != nullptr)
+ && (s != nullptr));
+ QF_CRIT_EXIT();
+
+ QS_TRAN0_(QS_QEP_DISPATCH, s);
+
+ QState r = Q_RET_SUPER;
- QStateHandler t = m_state.fun;
- QS_CRIT_STAT_
-
- //! @pre the current state must be initialized and
- //! the state configuration must be stable
- Q_REQUIRE_ID(400, (t != nullptr)
- && (t == m_temp.fun));
-
- QS_BEGIN_PRE_(QS_QEP_DISPATCH, qs_id)
- QS_TIME_PRE_(); // time stamp
- QS_SIG_PRE_(e->sig); // the signal of the event
- QS_OBJ_PRE_(this); // this state machine object
- QS_FUN_PRE_(t); // the current state
- QS_END_PRE_()
-
- QStateHandler s;
- QState r;
// process the event hierarchically...
- //! @tr{RQP120A}
- do {
+ m_temp.fun = s;
+ std::int_fast8_t ip = QHSM_MAX_NEST_DEPTH_;
+ // NOTE: ip is the fixed loop upper bound
+ for (; ip > 0; --ip) {
s = m_temp.fun;
r = (*s)(this, e); // invoke state handler s
if (r == Q_RET_UNHANDLED) { // unhandled due to a guard?
-
- QS_BEGIN_PRE_(QS_QEP_UNHANDLED, qs_id)
- QS_SIG_PRE_(e->sig); // the signal of the event
- QS_OBJ_PRE_(this); // this state machine object
- QS_FUN_PRE_(s); // the current state
- QS_END_PRE_()
-
- r = hsm_reservedEvt_(this, s, Q_EMPTY_SIG); // find superstate of s
+ QS_TRAN_ACT_(QS_QEP_UNHANDLED, s);
+ r = QHSM_RESERVED_EVT_(s, Q_EMPTY_SIG); // superstate of s
}
- } while (r == Q_RET_SUPER);
-
- // regular transition taken?
- //! @tr{RQP120E}
- if (r >= Q_RET_TRAN) {
- QStateHandler path[MAX_NEST_DEPTH_];
-
- path[0] = m_temp.fun; // save the target of the transition
- path[1] = t;
- path[2] = s;
-
- // exit current state to transition source s...
- //! @tr{RQP120C}
- for (; t != s; t = m_temp.fun) {
- // exit handled?
- if (hsm_state_exit_(this, t, qs_id)) {
- // find superstate of t
- static_cast(hsm_reservedEvt_(this, t, Q_EMPTY_SIG));
- }
+ if (r != Q_RET_SUPER) { // event NOT "bubbled up"
+ break;
}
+ }
+ QF_CRIT_ENTRY();
+ Q_ASSERT_INCRIT(310, ip > 0);
+ QF_CRIT_EXIT();
- std::int_fast8_t ip = hsm_tran(path, qs_id); // the HSM transition
-
- #ifdef Q_SPY
- if (r == Q_RET_TRAN_HIST) {
-
- QS_BEGIN_PRE_(QS_QEP_TRAN_HIST, qs_id)
- QS_OBJ_PRE_(this); // this state machine object
- QS_FUN_PRE_(t); // the source of the transition
- QS_FUN_PRE_(path[0]); // the target of the tran. to history
- QS_END_PRE_()
-
- }
- #endif // Q_SPY
-
- // execute state entry actions in the desired order...
- //! @tr{RQP120B}
- for (; ip >= 0; --ip) {
- hsm_state_entry_(this, path[ip], qs_id); // enter path[ip]
+ if (r >= Q_RET_TRAN) { // tran. (regular or history) taken?
+#ifdef Q_SPY
+ if (r == Q_RET_TRAN_HIST) { // tran. to history?
+ QS_TRAN_SEG_(QS_QEP_TRAN_HIST, s, m_temp.fun);
}
- t = path[0]; // stick the target into register
- m_temp.fun = t; // update the next state
-
- // drill into the target hierarchy...
- //! @tr{RQP120I}
- while (hsm_reservedEvt_(this, t, Q_INIT_SIG) == Q_RET_TRAN) {
-
- QS_BEGIN_PRE_(QS_QEP_STATE_INIT, qs_id)
- QS_OBJ_PRE_(this); // this state machine object
- QS_FUN_PRE_(t); // the source (pseudo)state
- QS_FUN_PRE_(m_temp.fun); // the target of the transition
- QS_END_PRE_()
+#endif // Q_SPY
- ip = 0;
- path[0] = m_temp.fun;
+ QStateHandler path[QHSM_MAX_NEST_DEPTH_];
+ path[0] = m_temp.fun; // tran. target
+ path[1] = t; // current state
+ path[2] = s; // tran. source
- // find superstate
- static_cast(hsm_reservedEvt_(this, m_temp.fun, Q_EMPTY_SIG));
-
- while (m_temp.fun != t) {
- ++ip;
- path[ip] = m_temp.fun;
- // find superstate
- static_cast(
- hsm_reservedEvt_(this, m_temp.fun, Q_EMPTY_SIG));
+ // exit current state to tran. source s...
+ while (t != s) {
+ // exit from t
+ if (QHSM_RESERVED_EVT_(t, Q_EXIT_SIG) == Q_RET_HANDLED) {
+ QS_STATE_ACT_(QS_QEP_STATE_EXIT, t);
+ // find superstate of t
+ static_cast(QHSM_RESERVED_EVT_(t, Q_EMPTY_SIG));
}
- m_temp.fun = path[0];
-
- // entry path must not overflow
- Q_ASSERT_ID(410, ip < MAX_NEST_DEPTH_);
-
- // retrace the entry path in reverse (correct) order...
- do {
- hsm_state_entry_(this, path[ip], qs_id); // enter path[ip]
- --ip;
- } while (ip >= 0);
+ t = m_temp.fun;
+ }
- t = path[0];
+ // take the tran...
+ ip = tran_simple_(&path[0], qsId);
+ if (ip < -1) { // not a simple tran.?
+ ip = tran_complex_(&path[0], qsId);
}
- QS_BEGIN_PRE_(QS_QEP_TRAN, qs_id)
- QS_TIME_PRE_(); // time stamp
- QS_SIG_PRE_(e->sig); // the signal of the event
- QS_OBJ_PRE_(this); // this state machine object
- QS_FUN_PRE_(s); // the source of the transition
- QS_FUN_PRE_(t); // the new active state
- QS_END_PRE_()
+ enter_target_(&path[0], ip, qsId);
+ t = path[0];
+ QS_TRAN_END_(QS_QEP_TRAN, s, t);
}
-
- #ifdef Q_SPY
+#ifdef Q_SPY
else if (r == Q_RET_HANDLED) {
-
- QS_BEGIN_PRE_(QS_QEP_INTERN_TRAN, qs_id)
- QS_TIME_PRE_(); // time stamp
- QS_SIG_PRE_(e->sig); // the signal of the event
- QS_OBJ_PRE_(this); // this state machine object
- QS_FUN_PRE_(s); // the source state
- QS_END_PRE_()
-
+ QS_TRAN0_(QS_QEP_INTERN_TRAN, s);
}
else {
-
- QS_BEGIN_PRE_(QS_QEP_IGNORED, qs_id)
- QS_TIME_PRE_(); // time stamp
- QS_SIG_PRE_(e->sig); // the signal of the event
- QS_OBJ_PRE_(this); // this state machine object
- QS_FUN_PRE_(m_state.fun);// the current state
- QS_END_PRE_()
-
+ QS_TRAN0_(QS_QEP_IGNORED, m_state.fun);
}
- #else
- Q_UNUSED_PAR(qs_id); // when Q_SPY not defined
- #endif // Q_SPY
+#endif // Q_SPY
m_state.fun = t; // change the current active state
- m_temp.fun = t; // mark the configuration as stable
-}
-
-//${QEP::QHsm::top} ..........................................................
-QState QHsm::top(
- void * const me,
- QEvt const * const e) noexcept
-{
- Q_UNUSED_PAR(me);
- Q_UNUSED_PAR(e);
- return Q_RET_IGNORED; // the top state ignores all events
}
-//${QEP::QHsm::isIn} .........................................................
-bool QHsm::isIn(QStateHandler const s) noexcept {
- //! @pre state configuration must be stable
- Q_REQUIRE_ID(600, m_temp.fun == m_state.fun);
-
- bool inState = false; // assume that this HSM is not in 'state'
+//............................................................................
+bool QHsm::isIn(QStateHandler const state) noexcept {
+ bool inState = false; // assume that this HSM is not in 'state'
// scan the state hierarchy bottom-up
- QState r;
- do {
- // do the states match?
- if (m_temp.fun == s) {
- inState = true; // 'true' means that match found
- r = Q_RET_IGNORED; // cause breaking out of the loop
+ QStateHandler s = m_state.fun;
+ QState r = Q_RET_SUPER;
+ while (r != Q_RET_IGNORED) {
+ if (s == state) { // do the states match?
+ inState = true; // 'true' means that match found
+ break; // break out of the for-loop
}
- else {
- r = hsm_reservedEvt_(this, m_temp.fun, Q_EMPTY_SIG);
- }
- } while (r != Q_RET_IGNORED); // QHsm::top() state not reached
- m_temp.fun = m_state.fun; // restore the stable state configuration
-
+ r = QHSM_RESERVED_EVT_(s, Q_EMPTY_SIG);
+ s = m_temp.fun;
+ }
return inState; // return the status
}
-//${QEP::QHsm::childState} ...................................................
+//............................................................................
QStateHandler QHsm::childState(QStateHandler const parent) noexcept {
- QStateHandler child = m_state.fun; // start with the current state
- bool isFound = false; // start with the child not found
-
- // establish stable state configuration
- m_temp.fun = m_state.fun;
- QState r;
- do {
- // is this the parent of the current child?
+#ifndef Q_UNSAFE
+ bool isFound = false; // assume the child state NOT found
+#endif
+
+ QStateHandler child = m_state.fun; // start with current state
+ m_temp.fun = child; // establish stable state configuration
+ QState r = Q_RET_SUPER;
+ while (r != Q_RET_IGNORED) {
+ // have the parent of the current child?
if (m_temp.fun == parent) {
- isFound = true; // child is found
- r = Q_RET_IGNORED; // cause breaking out of the loop
- }
- else {
- child = m_temp.fun;
- r = hsm_reservedEvt_(this, m_temp.fun, Q_EMPTY_SIG);
+#ifndef Q_UNSAFE
+ isFound = true; // indicate that child state was found
+#endif
+ break;
}
- } while (r != Q_RET_IGNORED); // QHsm::top() state not reached
- m_temp.fun = m_state.fun; // establish stable state configuration
-
- //! @post the child must be confirmed
- Q_ENSURE_ID(810, isFound);
-
- #ifdef Q_NASSERT
- Q_UNUSED_PAR(isFound);
- #endif
+ child = m_temp.fun;
+ r = QHSM_RESERVED_EVT_(child, Q_EMPTY_SIG);
+ }
+ QF_CRIT_STAT
+ QF_CRIT_ENTRY();
+ Q_ASSERT_INCRIT(590, isFound);
+ QF_CRIT_EXIT();
- return child; // return the child
+ return child;
}
-//${QEP::QHsm::hsm_tran} .....................................................
-std::int_fast8_t QHsm::hsm_tran(
- QStateHandler (&path)[MAX_NEST_DEPTH_],
- std::uint_fast8_t const qs_id)
+//............................................................................
+//! @private @memberof QHsm
+std::int_fast8_t QHsm::tran_simple_(
+ QStateHandler * const path,
+ std::uint_fast8_t const qsId)
{
- #ifndef Q_SPY
- Q_UNUSED_PAR(qs_id);
- #endif
+#ifndef Q_SPY
+ Q_UNUSED_PAR(qsId);
+#endif
- std::int_fast8_t ip = -1; // transition entry path index
QStateHandler t = path[0];
QStateHandler const s = path[2];
+ std::int_fast8_t ip = 0; // tran. entry path index
+ QS_CRIT_STAT
- // (a) check source==target (transition to self)
+ // (a) check source==target (tran. to self)...
if (s == t) {
- // exit the source
- static_cast(hsm_state_exit_(this, s, qs_id));
+ // exit source s
+ if (QHSM_RESERVED_EVT_(s, Q_EXIT_SIG) == Q_RET_HANDLED) {
+ QS_STATE_ACT_(QS_QEP_STATE_EXIT, s);
+ }
ip = 0; // enter the target
}
else {
- // superstate of target
- static_cast(hsm_reservedEvt_(this, t, Q_EMPTY_SIG));
+ // find superstate of target
+ static_cast(QHSM_RESERVED_EVT_(t, Q_EMPTY_SIG));
+
t = m_temp.fun;
- // (b) check source==target->super
+ // (b) check source==target->super...
if (s == t) {
ip = 0; // enter the target
}
else {
- // superstate of src
- static_cast(hsm_reservedEvt_(this, s, Q_EMPTY_SIG));
+ // find superstate of src
+ static_cast(QHSM_RESERVED_EVT_(s, Q_EMPTY_SIG));
- // (c) check source->super==target->super
+ // (c) check source->super==target->super...
if (m_temp.fun == t) {
- // exit the source
- static_cast(hsm_state_exit_(this, s, qs_id));
+ // exit source s
+ if (QHSM_RESERVED_EVT_(s, Q_EXIT_SIG) == Q_RET_HANDLED) {
+ QS_STATE_ACT_(QS_QEP_STATE_EXIT, s);
+ }
ip = 0; // enter the target
}
- else {
- // (d) check source->super==target
- if (m_temp.fun == path[0]) {
- // exit the source
- static_cast(hsm_state_exit_(this, s, qs_id));
+ // (d) check source->super==target...
+ else if (m_temp.fun == path[0]) {
+ // exit source s
+ if (QHSM_RESERVED_EVT_(s, Q_EXIT_SIG) == Q_RET_HANDLED) {
+ QS_STATE_ACT_(QS_QEP_STATE_EXIT, s);
}
- else {
- // (e) check rest of source==target->super->super..
- // and store the entry path along the way
- std::int_fast8_t iq = 0; // indicate that LCA was found
- ip = 1; // enter target and its superstate
- path[1] = t; // save the superstate of target
- t = m_temp.fun; // save source->super
-
- // find target->super->super
- QState r = hsm_reservedEvt_(this, path[1], Q_EMPTY_SIG);
- while (r == Q_RET_SUPER) {
- ++ip;
- path[ip] = m_temp.fun; // store the entry path
- if (m_temp.fun == s) { // is it the source?
- // indicate that the LCA was found
- iq = 1;
-
- // entry path must not overflow
- Q_ASSERT_ID(510, ip < MAX_NEST_DEPTH_);
- --ip; // do not enter the source
- r = Q_RET_HANDLED; // terminate the loop
- }
- // it is not the source, keep going up
- else {
- r = hsm_reservedEvt_(this, m_temp.fun, Q_EMPTY_SIG);
- }
- }
+ ip = -1; // do not enter the target
+ }
+ else {
+ path[1] = t; // save the superstate of target
+ ip = -2; // cause execution of complex tran.
+ }
+ }
+ }
+ return ip;
+}
- // the LCA not found yet?
- if (iq == 0) {
- // entry path must not overflow
- Q_ASSERT_ID(520, ip < MAX_NEST_DEPTH_);
-
- // exit the source
- static_cast(hsm_state_exit_(this, s, qs_id));
-
- // (f) check the rest of source->super
- // == target->super->super...
- //
- iq = ip;
- r = Q_RET_IGNORED; // indicate LCA NOT found
- do {
- // is this the LCA?
- if (t == path[iq]) {
- r = Q_RET_HANDLED; // indicate LCA found
- ip = iq - 1; // do not enter LCA
- iq = -1; // cause termination of the loop
- }
- else {
- --iq; // try lower superstate of target
- }
- } while (iq >= 0);
-
- // LCA not found yet?
- if (r != Q_RET_HANDLED) {
- // (g) check each source->super->...
- // for each target->super...
- //
- r = Q_RET_IGNORED; // keep looping
- do {
- // exit from t handled?
- if (hsm_state_exit_(this, t, qs_id)) {
- // find superstate of t
- static_cast(
- hsm_reservedEvt_(this, t, Q_EMPTY_SIG));
- }
- t = m_temp.fun; // set to super of t
- iq = ip;
- do {
- // is this LCA?
- if (t == path[iq]) {
- ip = iq - 1; // do not enter LCA
- iq = -1; // break out of inner loop
- r = Q_RET_HANDLED; // break outer loop
- }
- else {
- --iq;
- }
- } while (iq >= 0);
- } while (r != Q_RET_HANDLED);
- }
- }
+//............................................................................
+//! @private @memberof QHsm
+std::int_fast8_t QHsm::tran_complex_(
+ QStateHandler * const path,
+ std::uint_fast8_t const qsId)
+{
+#ifndef Q_SPY
+ Q_UNUSED_PAR(qsId);
+#endif
+
+ // (e) check rest of source==target->super->super..
+ // and store the entry path along the way
+ std::int_fast8_t iq = 0; // indicate that LCA was found
+ std::int_fast8_t ip = 1; // enter target and its superstate
+ QStateHandler const s = path[2]; // source state
+ QStateHandler t = m_temp.fun; // source->super
+ QF_CRIT_STAT
+
+ // find target->super->super...
+ // note: ip is the fixed upper loop bound
+ QState r = QHSM_RESERVED_EVT_(path[1], Q_EMPTY_SIG);
+ while ((r == Q_RET_SUPER) && (ip < (QHSM_MAX_NEST_DEPTH_ - 1))) {
+ ++ip;
+ path[ip] = m_temp.fun; // store the entry path
+ if (m_temp.fun == s) { // is it the source?
+ iq = 1; // indicate that the LCA found
+ --ip; // do not enter the source
+ break; // terminate the loop
+ }
+ r = QHSM_RESERVED_EVT_(m_temp.fun, Q_EMPTY_SIG);
+ }
+ QF_CRIT_ENTRY();
+ Q_INVARIANT_INCRIT(711, ip < (QHSM_MAX_NEST_DEPTH_ - 1));
+ QF_CRIT_EXIT();
+
+ // the LCA not found yet?
+ if (iq == 0) {
+
+ // exit source s
+#ifndef Q_SPY
+ static_cast(QHSM_RESERVED_EVT_(s, Q_EXIT_SIG));
+#else
+ if (QHSM_RESERVED_EVT_(s, Q_EXIT_SIG) == Q_RET_HANDLED) {
+ QS_STATE_ACT_(QS_QEP_STATE_EXIT, s);
+ }
+#endif // def Q_SPY
+
+ // (f) check the rest of
+ // source->super == target->super->super...
+ iq = ip;
+ r = Q_RET_IGNORED; // indicate that the LCA NOT found
+ // note: iq is the fixed upper loop bound
+ do {
+ if (t == path[iq]) { // is this the LCA?
+ r = Q_RET_HANDLED; // indicate the LCA found
+ ip = iq - 1; // do not enter the LCA
+ break; // terminate the loop
+ }
+ --iq; // try lower superstate of target
+ } while (iq >= 0);
+
+ if (r != Q_RET_HANDLED) { // the LCA still not found?
+ // (g) check each source->super->...
+ // for each target->super...
+ r = Q_RET_SUPER; // keep looping
+ while (r != Q_RET_HANDLED) {
+ // exit from t
+ if (QHSM_RESERVED_EVT_(t, Q_EXIT_SIG) == Q_RET_HANDLED) {
+ QS_STATE_ACT_(QS_QEP_STATE_EXIT, t);
+ // find superstate of t
+ static_cast(QHSM_RESERVED_EVT_(t, Q_EMPTY_SIG));
}
+ t = m_temp.fun; // set to super of t
+ iq = ip;
+ do {
+ if (t == path[iq]) { // is this the LCA?
+ ip = iq - 1; // do not enter the LCA
+ r = Q_RET_HANDLED; // break outer loop
+ break; // terminate the inner loop
+ }
+ --iq; // try lower superstate of target
+ } while (iq >= 0);
}
}
}
return ip;
+}
+
+//............................................................................
+//! @private @memberof QHsm
+void QHsm::enter_target_(
+ QStateHandler * const path,
+ std::int_fast8_t const depth,
+ std::uint_fast8_t const qsId)
+{
+#ifndef Q_SPY
+ Q_UNUSED_PAR(qsId);
+#endif
+
+ QF_CRIT_STAT
+
+ QF_CRIT_ENTRY();
+ Q_REQUIRE_INCRIT(800, depth < QHSM_MAX_NEST_DEPTH_);
+ QF_CRIT_EXIT();
+
+ std::int_fast8_t ip = depth;
+ // execute state entry actions in the desired order...
+ // note: ip is the fixed upper loop bound
+ for (; ip >= 0; --ip) {
+ // enter path[ip]
+ if (QHSM_RESERVED_EVT_(path[ip], Q_ENTRY_SIG)
+ == Q_RET_HANDLED)
+ {
+ QS_STATE_ACT_(QS_QEP_STATE_ENTRY, path[ip]);
+ }
+ }
+ QStateHandler t = path[0];
+ m_temp.fun = t; // update the next state
+
+ // drill into the target hierarchy...
+ while (QHSM_RESERVED_EVT_(t, Q_INIT_SIG) == Q_RET_TRAN) {
+
+ QS_TRAN_SEG_(QS_QEP_STATE_INIT, t, m_temp.fun);
+
+ ip = 0;
+ path[0] = m_temp.fun;
+
+ // find superstate
+ static_cast(QHSM_RESERVED_EVT_(m_temp.fun, Q_EMPTY_SIG));
+
+ // note: ip is the fixed upper loop bound
+ while ((m_temp.fun != t) && (ip < (QHSM_MAX_NEST_DEPTH_ - 1))) {
+ ++ip;
+ path[ip] = m_temp.fun;
+ // find superstate
+ static_cast(QHSM_RESERVED_EVT_(
+ m_temp.fun, Q_EMPTY_SIG));
+ }
+ QF_CRIT_ENTRY();
+ // too many state nesting levels or "malformed" HSM
+ Q_INVARIANT_INCRIT(891, ip < QHSM_MAX_NEST_DEPTH_);
+ QF_CRIT_EXIT();
+
+ m_temp.fun = path[0];
+ // retrace the entry path in reverse (correct) order...
+ // note: ip is the fixed upper loop bound
+ do {
+ // enter path[ip]
+ if (QHSM_RESERVED_EVT_(path[ip], Q_ENTRY_SIG) == Q_RET_HANDLED) {
+ QS_STATE_ACT_(QS_QEP_STATE_ENTRY, path[ip]);
+ }
+ --ip;
+ } while (ip >= 0);
+
+ t = path[0]; // current state becomes the new source
+ }
}
} // namespace QP
-//$enddef${QEP::QHsm} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/qep_msm.cpp b/src/qep_msm.cpp
index 7799bf2..7c2d259 100644
--- a/src/qep_msm.cpp
+++ b/src/qep_msm.cpp
@@ -1,72 +1,54 @@
-//$file${src::qf::qep_msm.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-//
-// Model: qpcpp.qm
-// File: ${src::qf::qep_msm.cpp}
-//
-// This code has been generated by QM 5.2.5 .
-// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
+//============================================================================
+// QP/C++ Real-Time Embedded Framework (RTEF)
+// Version 8.0.2
//
-// This code is covered by the following QP license:
-// License # : LicenseRef-QL-dual
-// Issued to : Any user of the QP/C++ real-time embedded framework
-// Framework(s) : qpcpp
-// Support ends : 2023-12-31
-// License scope:
+// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved.
//
-// Copyright (C) 2005 Quantum Leaps, LLC .
+// Q u a n t u m L e a P s
+// ------------------------
+// Modern Embedded Software
//
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
//
-// This software is dual-licensed under the terms of the open source GNU
-// General Public License version 3 (or any later version), or alternatively,
-// under the terms of one of the closed source Quantum Leaps commercial
-// licenses.
-//
-// The terms of the open source GNU General Public License version 3
-// can be found at:
-//
-// The terms of the closed source Quantum Leaps commercial licenses
-// can be found at:
+// This software is dual-licensed under the terms of the open-source GNU
+// General Public License (GPL) or under the terms of one of the closed-
+// source Quantum Leaps commercial licenses.
//
// Redistributions in source code must retain this top-level comment block.
// Plagiarizing this software to sidestep the license obligations is illegal.
//
-// Contact information:
+// NOTE:
+// The GPL does NOT permit the incorporation of this code into proprietary
+// programs. Please contact Quantum Leaps for commercial licensing options,
+// which expressly supersede the GPL and are designed explicitly for
+// closed-source distribution.
+//
+// Quantum Leaps contact information:
//
//
-//
-//$endhead${src::qf::qep_msm.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//! @file
-//! @brief QP::QMsm implementation
-
+//============================================================================
#define QP_IMPL // this is QP implementation
-#include "qep_port.hpp" // QEP port
+#include "qp_port.hpp" // QP port
+#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
#ifdef Q_SPY // QS software tracing enabled?
#include "qs_port.hpp" // QS port
#include "qs_pkg.hpp" // QS facilities for pre-defined trace records
#else
#include "qs_dummy.hpp" // disable the QS software tracing
#endif // Q_SPY
-#include "qassert.h" // QP embedded systems-friendly assertions
// unnamed namespace for local definitions with internal linkage
namespace {
+
Q_DEFINE_THIS_MODULE("qep_msm")
-} // unnamed namespace
-//============================================================================
-//$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-// Check for the minimum required QP version
-#if (QP_VERSION < 700U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U))
-#error qpcpp version 7.0.0 or higher required
-#endif
-//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// maximum depth of entry levels in a MSM for tran. to history.
+static constexpr std::int_fast8_t QMSM_MAX_ENTRY_DEPTH_ {4};
-//$define${QEP::QMsm} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-namespace QP {
+//! @cond INTERNAL
-//${QEP::QMsm} ...............................................................
-QMState const QMsm::msm_top_s = {
+// top-state object for QMsm-style state machines
+constexpr QP::QMState l_msm_top_s = {
nullptr,
nullptr,
nullptr,
@@ -74,422 +56,387 @@ QMState const QMsm::msm_top_s = {
nullptr
};
+} // unnamed namespace
+
+#ifdef Q_SPY
+// helper macro to trace state action (entry/exit)
+#define QS_STATE_ACT_(rec_, state_) \
+ QS_CRIT_ENTRY(); \
+ QS_BEGIN_PRE((rec_), qsId) \
+ QS_OBJ_PRE(this); \
+ QS_FUN_PRE(state_); \
+ QS_END_PRE() \
+ QS_CRIT_EXIT()
+
+// internal helper macro to top-most init
+#define QS_TOP_INIT_(rec_, trg_) \
+ QS_CRIT_ENTRY(); \
+ QS_BEGIN_PRE((rec_), qsId) \
+ QS_TIME_PRE(); \
+ QS_OBJ_PRE(this); \
+ QS_FUN_PRE(trg_); \
+ QS_END_PRE() \
+ QS_CRIT_EXIT()
+
+// internal helper macro to trace transition segment
+#define QS_TRAN_SEG_(rec_, src_, trg_) \
+ QS_CRIT_ENTRY(); \
+ QS_BEGIN_PRE((rec_), qsId) \
+ QS_OBJ_PRE(this); \
+ QS_FUN_PRE(src_); \
+ QS_FUN_PRE(trg_); \
+ QS_END_PRE() \
+ QS_CRIT_EXIT()
+
+// internal helper macro to trace transition begin/end
+#define QS_TRAN0_(rec_, trg_) \
+ QS_CRIT_ENTRY(); \
+ QS_BEGIN_PRE((rec_), qsId) \
+ QS_TIME_PRE(); \
+ QS_SIG_PRE(e->sig); \
+ QS_OBJ_PRE(this); \
+ QS_FUN_PRE(trg_); \
+ QS_END_PRE() \
+ QS_CRIT_EXIT()
+
+// internal helper macro to trace regulsr transition
+#define QS_TRAN_END_(rec_, src_, trg_) \
+ QS_CRIT_ENTRY(); \
+ QS_BEGIN_PRE((rec_), qsId) \
+ QS_TIME_PRE(); \
+ QS_SIG_PRE(e->sig); \
+ QS_OBJ_PRE(this); \
+ QS_FUN_PRE(src_); \
+ QS_FUN_PRE(trg_); \
+ QS_END_PRE() \
+ QS_CRIT_EXIT()
+
+#else
+#define QS_STATE_ACT_(rec_, state_) (static_cast(0))
+#define QS_TOP_INIT_(rec_, trg_) (static_cast(0))
+#define QS_TRAN_SEG_(rec_, src_, trg_) (static_cast(0))
+#define QS_TRAN0_(rec_, trg_) (static_cast(0))
+#define QS_TRAN_END_(rec_, src_, trg_) (static_cast(0))
+#endif
+
+//! @endcond
+
+//============================================================================
+namespace QP {
+
+//............................................................................
+QMsm::QMsm(QStateHandler const initial) noexcept
+ : QAsm()
+{
+ m_state.obj = &l_msm_top_s; // the current state (top)
+ m_temp.fun = initial; // the initial tran. handler
+}
-//${QEP::QMsm::init} .........................................................
+//............................................................................
void QMsm::init(
void const * const e,
- std::uint_fast8_t const qs_id)
+ std::uint_fast8_t const qsId)
{
- //! @pre the top-most initial transition must be initialized, and the
- //! initial transition must not be taken yet.
- Q_REQUIRE_ID(200, (m_temp.fun != nullptr)
- && (m_state.obj == &msm_top_s));
+#ifndef Q_SPY
+ Q_UNUSED_PAR(qsId);
+#endif
+
+ QF_CRIT_STAT
+ QF_CRIT_ENTRY();
+ Q_REQUIRE_INCRIT(200,
+ (m_temp.fun != nullptr)
+ && (m_state.obj == &l_msm_top_s));
+ QF_CRIT_EXIT();
// execute the top-most initial tran.
QState r = (*m_temp.fun)(this, Q_EVT_CAST(QEvt));
- // initial tran. must be taken
- Q_ASSERT_ID(210, r == Q_RET_TRAN_INIT);
+ QF_CRIT_ENTRY();
+ // the top-most initial tran. must be taken
+ Q_ASSERT_INCRIT(210, r == Q_RET_TRAN_INIT);
+ QF_CRIT_EXIT();
- QS_CRIT_STAT_
- QS_BEGIN_PRE_(QS_QEP_STATE_INIT, qs_id)
- QS_OBJ_PRE_(this); // this state machine object
- QS_FUN_PRE_(m_state.obj->stateHandler); // source handler
- QS_FUN_PRE_(m_temp.tatbl->target->stateHandler); // target handler
- QS_END_PRE_()
+ QS_TRAN_SEG_(QS_QEP_STATE_INIT,
+ m_state.obj->stateHandler, m_temp.tatbl->target->stateHandler);
// set state to the last tran. target
m_state.obj = m_temp.tatbl->target;
// drill down into the state hierarchy with initial transitions...
- do {
- r = execTatbl_(m_temp.tatbl, qs_id); // execute the tran-action table
- } while (r >= Q_RET_TRAN_INIT);
-
- QS_BEGIN_PRE_(QS_QEP_INIT_TRAN, qs_id)
- QS_TIME_PRE_(); // time stamp
- QS_OBJ_PRE_(this); // this state machine object
- QS_FUN_PRE_(m_state.obj->stateHandler); // the new current state
- QS_END_PRE_()
+ while (r >= Q_RET_TRAN_INIT) {
+ // execute the tran. table
+ r = execTatbl_(m_temp.tatbl, qsId);
+ }
- Q_UNUSED_PAR(qs_id); // when Q_SPY not defined
+ QS_TOP_INIT_(QS_QEP_INIT_TRAN, m_state.obj->stateHandler);
}
-//${QEP::QMsm::dispatch} .....................................................
+//............................................................................
void QMsm::dispatch(
QEvt const * const e,
- std::uint_fast8_t const qs_id)
+ std::uint_fast8_t const qsId)
{
- QMState const *s = m_state.obj; // store the current state
- //! @pre current state must be initialized
- Q_REQUIRE_ID(300, s != nullptr);
-
- QS_CRIT_STAT_
- QS_BEGIN_PRE_(QS_QEP_DISPATCH, qs_id)
- QS_TIME_PRE_(); // time stamp
- QS_SIG_PRE_(e->sig); // the signal of the event
- QS_OBJ_PRE_(this); // this state machine object
- QS_FUN_PRE_(s->stateHandler); // the current state handler
- QS_END_PRE_()
+#ifndef Q_SPY
+ Q_UNUSED_PAR(qsId);
+#endif
- // scan the state hierarchy up to the top state...
+ QMState const *s = m_state.obj; // store the current state
QMState const *t = s;
- QState r;
- do {
+
+ QF_CRIT_STAT
+ QF_CRIT_ENTRY();
+ Q_REQUIRE_INCRIT(300,
+ (e != nullptr)
+ && (s != nullptr));
+ QF_CRIT_EXIT();
+
+ QS_TRAN0_(QS_QEP_DISPATCH, s->stateHandler);
+
+ // scan the state hierarchy up to the top state...
+ QState r = Q_RET_SUPER;
+ while (t != nullptr) {
r = (*t->stateHandler)(this, e); // call state handler function
- // event handled? (the most frequent case)
- if (r >= Q_RET_HANDLED) {
+ if (r >= Q_RET_HANDLED) { // event handled? (the most frequent case)
break; // done scanning the state hierarchy
}
- // event unhandled and passed to the superstate?
- else if (r == Q_RET_SUPER) {
- t = t->superstate; // advance to the superstate
+#ifdef Q_SPY
+ if (r == Q_RET_UNHANDLED) { // event unhandled due to a guard?
+ QS_CRIT_ENTRY();
+ QS_BEGIN_PRE(QS_QEP_UNHANDLED, qsId)
+ QS_SIG_PRE(e->sig);
+ QS_OBJ_PRE(this);
+ QS_FUN_PRE(t->stateHandler);
+ QS_END_PRE()
+ QS_CRIT_EXIT();
}
- // event unhandled and passed to a submachine superstate?
- else if (r == Q_RET_SUPER_SUB) {
- t = m_temp.obj; // current host state of the submachie
- }
- // event unhandled due to a guard?
- else if (r == Q_RET_UNHANDLED) {
-
- QS_BEGIN_PRE_(QS_QEP_UNHANDLED, qs_id)
- QS_SIG_PRE_(e->sig); // the signal of the event
- QS_OBJ_PRE_(this); // this state machine object
- QS_FUN_PRE_(t->stateHandler); // the current state
- QS_END_PRE_()
+#endif
+ t = t->superstate; // advance to the superstate
+ }
- t = t->superstate; // advance to the superstate
- }
- else {
- // no other return value should be produced
- Q_ERROR_ID(310);
- }
- } while (t != nullptr);
-
- // any kind of transition taken?
- if (r >= Q_RET_TRAN) {
- #ifdef Q_SPY
- QMState const * const ts = t; // transition source for QS tracing
-
- // the transition source state must not be nullptr
- Q_ASSERT_ID(320, ts != nullptr);
- #endif // Q_SPY
-
- do {
- // save the transition-action table before it gets clobbered
- QMTranActTable const * const tatbl = m_temp.tatbl;
- QHsmAttr tmp; // temporary to save intermediate values
-
- // was TRAN, TRAN_INIT, or TRAN_EP taken?
- if (r <= Q_RET_TRAN_EP) {
- m_temp.obj = nullptr; // clear
- exitToTranSource_(s, t, qs_id);
- r = execTatbl_(tatbl, qs_id);
- s = m_state.obj;
- }
- // was a transition segment to history taken?
- else if (r == Q_RET_TRAN_HIST) {
- tmp.obj = m_state.obj; // save history
- m_state.obj = s; // restore the original state
- exitToTranSource_(s, t, qs_id);
- static_cast(execTatbl_(tatbl, qs_id));
- r = enterHistory_(tmp.obj, qs_id);
- s = m_state.obj;
- }
- // was a transition segment to an exit point taken?
- else if (r == Q_RET_TRAN_XP) {
- tmp.act = m_state.act; // save XP action
- m_state.obj = s; // restore the original state
- r = (*tmp.act)(this); // execute the XP action
- if (r == Q_RET_TRAN) { // XP -> TRAN ?
- #ifdef Q_SPY
- tmp.tatbl = m_temp.tatbl; // save m_temp
- #endif // Q_SPY
- exitToTranSource_(s, t, qs_id);
- // take the tran-to-XP segment inside submachine
- static_cast(execTatbl_(tatbl, qs_id));
- s = m_state.obj;
- #ifdef Q_SPY
- m_temp.tatbl = tmp.tatbl; // restore m_temp
- #endif // Q_SPY
- }
- else if (r == Q_RET_TRAN_HIST) { // XP -> HIST ?
- tmp.obj = m_state.obj; // save the history
- m_state.obj = s; // restore the original state
- #ifdef Q_SPY
- s = m_temp.obj; // save m_temp
- #endif // Q_SPY
- exitToTranSource_(m_state.obj, t, qs_id);
- // take the tran-to-XP segment inside submachine
- static_cast(execTatbl_(tatbl, qs_id));
- #ifdef Q_SPY
- m_temp.obj = s; // restore me->temp
- #endif // Q_SPY
- s = m_state.obj;
- m_state.obj = tmp.obj; // restore the history
- }
- else {
- // TRAN_XP must NOT be followed by any other tran type
- Q_ASSERT_ID(330, r < Q_RET_TRAN);
- }
- }
- else {
- // no other return value should be produced
- Q_ERROR_ID(340);
- }
+ if (r >= Q_RET_TRAN) { // any kind of tran. taken?
+ QF_CRIT_ENTRY();
+ // the tran. source state must not be NULL
+ Q_ASSERT_INCRIT(330, t != nullptr);
+ QF_CRIT_EXIT();
- t = s; // set target to the current state
+#ifdef Q_SPY
+ QMState const * const ts = t; // tran. source for QS tracing
+#endif // Q_SPY
- } while (r >= Q_RET_TRAN);
+ if (r == Q_RET_TRAN_HIST) { // was it tran. to history?
+ QMState const * const hist = m_state.obj; // save history
+ m_state.obj = s; // restore the original state
- QS_BEGIN_PRE_(QS_QEP_TRAN, qs_id)
- QS_TIME_PRE_(); // time stamp
- QS_SIG_PRE_(e->sig); // the signal of the event
- QS_OBJ_PRE_(this); // this state machine object
- QS_FUN_PRE_(ts->stateHandler); // the transition source
- QS_FUN_PRE_(s->stateHandler); // the new active state
- QS_END_PRE_()
- }
+ QS_TRAN_SEG_(QS_QEP_TRAN_HIST,
+ t->stateHandler, hist->stateHandler);
- #ifdef Q_SPY
- // was the event handled?
- else if (r == Q_RET_HANDLED) {
- // internal tran. source can't be nullptr
- Q_ASSERT_ID(340, t != nullptr);
+ // save the tran-action table before it gets clobbered
+ QMTranActTable const *tatbl = m_temp.tatbl;
+ exitToTranSource_(s, t, qsId);
+ static_cast(execTatbl_(tatbl, qsId));
+ r = enterHistory_(hist, qsId);
+ s = m_state.obj;
+ t = s; // set target to the current state
+ }
- QS_BEGIN_PRE_(QS_QEP_INTERN_TRAN, qs_id)
- QS_TIME_PRE_(); // time stamp
- QS_SIG_PRE_(e->sig); // the signal of the event
- QS_OBJ_PRE_(this); // this state machine object
- QS_FUN_PRE_(t->stateHandler); // the source state
- QS_END_PRE_()
+ while (r >= Q_RET_TRAN) {
+ // save the tran-action table before it gets clobbered
+ QMTranActTable const *tatbl = m_temp.tatbl;
+ m_temp.obj = nullptr; // clear
+ exitToTranSource_(s, t, qsId);
+ r = execTatbl_(tatbl, qsId);
+ s = m_state.obj;
+ t = s; // set target to the current state
+ }
+ QS_TRAN_END_(QS_QEP_TRAN, ts->stateHandler, s->stateHandler);
}
- // event bubbled to the 'top' state?
- else if (t == nullptr) {
-
- QS_BEGIN_PRE_(QS_QEP_IGNORED, qs_id)
- QS_TIME_PRE_(); // time stamp
- QS_SIG_PRE_(e->sig); // the signal of the event
- QS_OBJ_PRE_(this); // this state machine object
- QS_FUN_PRE_(s->stateHandler); // the current state
- QS_END_PRE_()
-
+#ifdef Q_SPY
+ else if (r == Q_RET_HANDLED) { // was the event handled?
+ QF_CRIT_ENTRY();
+ // internal tran. source can't be NULL
+ Q_ASSERT_INCRIT(380, t != nullptr);
+ QF_CRIT_EXIT();
+
+ QS_TRAN0_(QS_QEP_INTERN_TRAN, t->stateHandler);
}
- #endif // Q_SPY
-
+ else if (t == nullptr) { // event bubbled to the 'top' state?
+ QS_TRAN0_(QS_QEP_IGNORED, s->stateHandler);
+ }
+#endif // Q_SPY
else {
// empty
}
-
- Q_UNUSED_PAR(qs_id); // when Q_SPY not defined
}
-//${QEP::QMsm::isInState} ....................................................
-bool QMsm::isInState(QMState const * const st) const noexcept {
- bool inState = false; // assume that this MSM is not in 'state'
+//............................................................................
+bool QMsm::isIn(QStateHandler const state) noexcept {
+ bool inState = false; // assume that this SM is not in 'state'
- for (QMState const *s = m_state.obj;
- s != nullptr;
- s = s->superstate)
- {
- if (s == st) {
- inState = true; // match found, return 'true'
+ QMState const *s = m_state.obj;
+ while (s != nullptr) {
+ if (s->stateHandler == state) { // match found?
+ inState = true;
break;
}
+ s = s->superstate; // advance to the superstate
}
+
return inState;
}
-//${QEP::QMsm::childStateObj} ................................................
-QMState const * QMsm::childStateObj(QMState const * const parent) const noexcept {
- QMState const *child = m_state.obj;
- bool isFound = false; // start with the child not found
- QMState const *s;
+//............................................................................
+QMState const * QMsm::childStateObj(QMState const * const parent)
+ const noexcept
+{
+ QMState const *s = m_state.obj; // start with current state
+ QMState const *child = s;
+ bool isFound = false; // assume the child NOT found
- for (s = m_state.obj; s != nullptr; s = s->superstate) {
+ while (s != nullptr) {
if (s == parent) {
isFound = true; // child is found
break;
}
- else {
- child = s;
- }
- }
- if (!isFound) { // still not found?
- for (s = m_temp.obj; s != nullptr; s = s->superstate) {
- if (s == parent) {
- isFound = true; // child is found
- break;
- }
- else {
- child = s;
- }
- }
+ child = s;
+ s = s->superstate;
}
+ QF_CRIT_STAT
+ QF_CRIT_ENTRY();
+ Q_ASSERT_INCRIT(590, isFound);
+ QF_CRIT_EXIT();
- //! @post the child must be found
- Q_ENSURE_ID(810, isFound);
-
- #ifdef Q_NASSERT
+#ifdef Q_UNSAFE
Q_UNUSED_PAR(isFound);
- #endif
+#endif
return child; // return the child
}
-//${QEP::QMsm::execTatbl_} ...................................................
+//............................................................................
QState QMsm::execTatbl_(
QMTranActTable const * const tatbl,
- std::uint_fast8_t const qs_id)
+ std::uint_fast8_t const qsId)
{
- //! @pre the transition-action table pointer must not be nullptr
- Q_REQUIRE_ID(400, tatbl != nullptr);
+#ifndef Q_SPY
+ Q_UNUSED_PAR(qsId);
+#endif
+
+ QF_CRIT_STAT
+ QF_CRIT_ENTRY();
+ // precondition:
+ // - the tran-action table pointer must not be NULL
+ Q_REQUIRE_INCRIT(600, tatbl != nullptr);
+ QF_CRIT_EXIT();
QState r = Q_RET_NULL;
- QS_CRIT_STAT_
- for (QActionHandler const *a = &tatbl->act[0]; *a != nullptr; ++a) {
+ QActionHandler const *a = &tatbl->act[0];
+ while (*a != nullptr) {
r = (*(*a))(this); // call the action through the 'a' pointer
- #ifdef Q_SPY
+ ++a;
+#ifdef Q_SPY
if (r == Q_RET_ENTRY) {
-
- QS_BEGIN_PRE_(QS_QEP_STATE_ENTRY, qs_id)
- QS_OBJ_PRE_(this); // this state machine object
- QS_FUN_PRE_(m_temp.obj->stateHandler); // entered state handler
- QS_END_PRE_()
+ QS_STATE_ACT_(QS_QEP_STATE_ENTRY, m_temp.obj->stateHandler);
}
else if (r == Q_RET_EXIT) {
-
- QS_BEGIN_PRE_(QS_QEP_STATE_EXIT, qs_id)
- QS_OBJ_PRE_(this); // this state machine object
- QS_FUN_PRE_(m_temp.obj->stateHandler); // exited state handler
- QS_END_PRE_()
+ QS_STATE_ACT_(QS_QEP_STATE_EXIT, m_temp.obj->stateHandler);
}
else if (r == Q_RET_TRAN_INIT) {
-
- QS_BEGIN_PRE_(QS_QEP_STATE_INIT, qs_id)
- QS_OBJ_PRE_(this); // this state machine object
- QS_FUN_PRE_(tatbl->target->stateHandler); // source
- QS_FUN_PRE_(m_temp.tatbl->target->stateHandler); // target
- QS_END_PRE_()
- }
- else if (r == Q_RET_TRAN_EP) {
-
- QS_BEGIN_PRE_(QS_QEP_TRAN_EP, qs_id)
- QS_OBJ_PRE_(this); // this state machine object
- QS_FUN_PRE_(tatbl->target->stateHandler); // source
- QS_FUN_PRE_(m_temp.tatbl->target->stateHandler); // target
- QS_END_PRE_()
- }
- else if (r == Q_RET_TRAN_XP) {
-
- QS_BEGIN_PRE_(QS_QEP_TRAN_XP, qs_id)
- QS_OBJ_PRE_(this); // this state machine object
- QS_FUN_PRE_(tatbl->target->stateHandler); // source
- QS_FUN_PRE_(m_temp.tatbl->target->stateHandler); // target
- QS_END_PRE_()
+ QS_TRAN_SEG_(QS_QEP_STATE_INIT,
+ tatbl->target->stateHandler,
+ m_temp.tatbl->target->stateHandler);
}
else {
// empty
}
- #endif // Q_SPY
+#endif // Q_SPY
}
+ QF_CRIT_ENTRY();
+ Q_ASSERT_INCRIT(690, *a == nullptr);
+ QF_CRIT_EXIT();
- Q_UNUSED_PAR(qs_id); // when Q_SPY not defined
m_state.obj = (r >= Q_RET_TRAN)
? m_temp.tatbl->target
: tatbl->target;
return r;
}
-//${QEP::QMsm::exitToTranSource_} ............................................
+//............................................................................
void QMsm::exitToTranSource_(
- QMState const * s,
+ QMState const * const cs,
QMState const * const ts,
- std::uint_fast8_t const qs_id)
+ std::uint_fast8_t const qsId)
{
+#ifndef Q_SPY
+ Q_UNUSED_PAR(qsId);
+#endif
+ QS_CRIT_STAT
+
// exit states from the current state to the tran. source state
+ QMState const *s = cs;
while (s != ts) {
// exit action provided in state 's'?
if (s->exitAction != nullptr) {
// execute the exit action
- (*s->exitAction)(this);
+ static_cast((*s->exitAction)(this));
- QS_CRIT_STAT_
- QS_BEGIN_PRE_(QS_QEP_STATE_EXIT, qs_id)
- QS_OBJ_PRE_(this); // this state machine object
- QS_FUN_PRE_(s->stateHandler); // the exited state handler
- QS_END_PRE_()
+ QS_STATE_ACT_(QS_QEP_STATE_EXIT, m_temp.obj->stateHandler);
}
-
s = s->superstate; // advance to the superstate
-
- // reached the top of a submachine?
- if (s == nullptr) {
- s = m_temp.obj; // the superstate from QM_SM_EXIT()
- Q_ASSERT_ID(510, s != nullptr);
- }
}
- Q_UNUSED_PAR(qs_id); // when Q_SPY not defined
}
-//${QEP::QMsm::enterHistory_} ................................................
+//............................................................................
QState QMsm::enterHistory_(
QMState const * const hist,
- std::uint_fast8_t const qs_id)
+ std::uint_fast8_t const qsId)
{
- QMState const *s = hist;
- QMState const *ts = m_state.obj; // transition source
- QMState const *epath[MAX_ENTRY_DEPTH_];
-
- QS_CRIT_STAT_
-
- QS_BEGIN_PRE_(QS_QEP_TRAN_HIST, qs_id)
- QS_OBJ_PRE_(this); // this state machine object
- QS_FUN_PRE_(ts->stateHandler); // source state handler
- QS_FUN_PRE_(hist->stateHandler); // target state handler
- QS_END_PRE_()
+#ifndef Q_SPY
+ Q_UNUSED_PAR(qsId);
+#endif
- std::int_fast8_t i = 0; // entry path index
- while (s != ts) {
+ // record the entry path from current state to history
+ QMState const *epath[QMSM_MAX_ENTRY_DEPTH_];
+ QMState const *s = hist;
+ std::int_fast8_t i = 0; // tran. entry path index & fixed upper loop bound
+ while ((s != m_state.obj) && (i < QMSM_MAX_ENTRY_DEPTH_)) {
if (s->entryAction != nullptr) {
- Q_ASSERT_ID(620, i < MAX_ENTRY_DEPTH_);
epath[i] = s;
++i;
}
s = s->superstate;
- if (s == nullptr) {
- ts = s; // force exit from the for-loop
- }
}
+ QF_CRIT_STAT
+ QF_CRIT_ENTRY();
+ Q_ASSERT_INCRIT(810, i <= QMSM_MAX_ENTRY_DEPTH_);
+ QF_CRIT_EXIT();
// retrace the entry path in reverse (desired) order...
- while (i > 0) {
- --i;
+ // NOTE: i the fixed upper loop bound
+ for (i = i - 1; i >= 0; --i) {
// run entry action in epath[i]
- (*epath[i]->entryAction)(this);
+ static_cast((*epath[i]->entryAction)(this));
- QS_BEGIN_PRE_(QS_QEP_STATE_ENTRY, qs_id)
- QS_OBJ_PRE_(this);
- QS_FUN_PRE_(epath[i]->stateHandler); // entered state handler
- QS_END_PRE_()
+ QS_STATE_ACT_(QS_QEP_STATE_ENTRY, epath[i]->stateHandler);
}
- m_state.obj = hist; // set current state to the transition target
+ m_state.obj = hist; // set current state to the tran. target
// initial tran. present?
- QState r;
+ QState r = Q_RET_NULL;
if (hist->initAction != nullptr) {
- r = (*hist->initAction)(this); // execute the transition action
- }
- else {
- r = Q_RET_NULL;
- }
+ r = (*hist->initAction)(this); // execute the tran. action
- Q_UNUSED_PAR(qs_id); // when Q_SPY not defined
+ QS_TRAN_SEG_(QS_QEP_STATE_INIT,
+ hist->stateHandler, m_temp.tatbl->target->stateHandler);
+ }
return r;
}
+//............................................................................
+QMState const * QMsm::topQMState() const noexcept {
+ return &l_msm_top_s;
+}
+
} // namespace QP
-//$enddef${QEP::QMsm} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/qep_port.hpp b/src/qep_port.hpp
deleted file mode 100644
index 60f5c1e..0000000
--- a/src/qep_port.hpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/// @file
-/// @brief QEP/C++ port, generic C++11 compiler
-/// @cond
-///***************************************************************************
-/// Last updated for version 6.8.0
-/// Last updated on 2022-03-20
-///
-/// Q u a n t u m L e a P s
-/// ------------------------
-/// Modern Embedded Software
-///
-/// Copyright (C) 2022 Victor Chavez.
-/// Copyright (C) 2005-2020 Quantum Leaps. All rights reserved.
-///
-/// This program is open source software: you can redistribute it and/or
-/// modify it under the terms of the GNU General Public License as published
-/// by the Free Software Foundation, either version 3 of the License, or
-/// (at your option) any later version.
-///
-/// Alternatively, this program may be distributed and modified under the
-/// terms of Quantum Leaps commercial licenses, which expressly supersede
-/// the GNU General Public License and are specifically designed for
-/// licensees interested in retaining the proprietary status of their code.
-///
-/// This program is distributed in the hope that it will be useful,
-/// but WITHOUT ANY WARRANTY; without even the implied warranty of
-/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-/// GNU General Public License for more details.
-///
-/// You should have received a copy of the GNU General Public License
-/// along with this program. If not, see .
-///
-/// Contact information:
-///
-///
-///***************************************************************************
-/// @endcond
-
-#ifndef QEP_PORT_HPP
-#define QEP_PORT_HPP
-
-#include // Exact-width types. C++11 Standard
-
-// enable QP/Spy software tracing instrumentation
-#define Q_SPY 1U
-
-#include "qep.hpp" // QEP platform-independent public interface
-
-//! no-return function specifier (GCC)
-#define Q_NORETURN __attribute__ ((noreturn)) void
-
-#endif // QEP_PORT_HPP
diff --git a/src/qequeue.hpp b/src/qequeue.hpp
index 03fd257..029526c 100644
--- a/src/qequeue.hpp
+++ b/src/qequeue.hpp
@@ -1,334 +1,111 @@
-//$file${include::qequeue.hpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-//
-// Model: qpcpp.qm
-// File: ${include::qequeue.hpp}
-//
-// This code has been generated by QM 5.2.5 .
-// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
+//============================================================================
+// QP/C++ Real-Time Embedded Framework (RTEF)
+// Version 8.0.2
//
-// This code is covered by the following QP license:
-// License # : LicenseRef-QL-dual
-// Issued to : Any user of the QP/C++ real-time embedded framework
-// Framework(s) : qpcpp
-// Support ends : 2023-12-31
-// License scope:
+// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved.
//
-// Copyright (C) 2005 Quantum Leaps, LLC .
+// Q u a n t u m L e a P s
+// ------------------------
+// Modern Embedded Software
//
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
//
-// This software is dual-licensed under the terms of the open source GNU
-// General Public License version 3 (or any later version), or alternatively,
-// under the terms of one of the closed source Quantum Leaps commercial
-// licenses.
-//
-// The terms of the open source GNU General Public License version 3
-// can be found at:
-//
-// The terms of the closed source Quantum Leaps commercial licenses
-// can be found at:
+// This software is dual-licensed under the terms of the open-source GNU
+// General Public License (GPL) or under the terms of one of the closed-
+// source Quantum Leaps commercial licenses.
//
// Redistributions in source code must retain this top-level comment block.
// Plagiarizing this software to sidestep the license obligations is illegal.
//
-// Contact information:
+// NOTE:
+// The GPL does NOT permit the incorporation of this code into proprietary
+// programs. Please contact Quantum Leaps for commercial licensing options,
+// which expressly supersede the GPL and are designed explicitly for
+// closed-source distribution.
+//
+// Quantum Leaps contact information:
//
//
-//
-//$endhead${include::qequeue.hpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//! @file
-//! @brief platform-independent fast "raw" thread-safe event queue interface
-//!
-//! @details
-//! This header file must be included in all QF ports that use native QF
-//! event queue for active objects. Also, this file needs to be included
-//! in the QP/C++ library when the application uses QActive::defer() /
-//! QActive::recall(). Finally, this file is also needed when the "raw"
-//! thread-safe queues are used for communication between active objects
-//! and non-framework entities, such as ISRs, device drivers, or legacy
-//! code.
-
+//============================================================================
#ifndef QEQUEUE_HPP_
#define QEQUEUE_HPP_
#ifndef QF_EQUEUE_CTR_SIZE
-
- //! The size (in bytes) of the ring-buffer counters used in the
- //! native QF event queue implementation. Valid values: 1U, 2U, or 4U;
- //! default 1U.
- //! @details
- //! This macro can be defined in the QF port file (qf_port.hpp) to
- //! configure the QP::QEQueueCtr type. Here the macro is not defined
- //! so the default of 1 byte is chosen.
#define QF_EQUEUE_CTR_SIZE 1U
#endif
namespace QP {
#if (QF_EQUEUE_CTR_SIZE == 1U)
-
- //! The data type to store the ring-buffer counters based on
- //! the macro #QF_EQUEUE_CTR_SIZE.
- //! @details
- //! The dynamic range of this data type determines the maximum length
- //! of the ring buffer managed by the native QF event queue.
using QEQueueCtr = std::uint8_t;
#elif (QF_EQUEUE_CTR_SIZE == 2U)
using QEQueueCtr = std::uint16_t;
-#elif (QF_EQUEUE_CTR_SIZE == 4U)
- using QEQueueCtr = std::uint32_t;
#else
- #error "QF_EQUEUE_CTR_SIZE defined incorrectly, expected 1U, 2U, or 4U"
+ #error QF_EQUEUE_CTR_SIZE defined incorrectly, expected 1U or 2U
#endif
+class QEvt; // forward declaration
+
} // namespace QP
//============================================================================
-//$declare${QF::QEQueue} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
namespace QP {
-//${QF::QEQueue} .............................................................
-//! Native QF Event Queue class
-//!
-//! @details
-//! This structure describes the native QF event queue, which can be used as
-//! the event queue for active objects, or as a simple "raw" event queue for
-//! thread-safe event passing among non-framework entities, such as ISRs,
-//! device drivers, or other third-party components.
-//!
-//! The native QF event queue is configured by defining the macro
-//! #QF_EQUEUE_TYPE as QP::QEQueue in the specific QF port header file.
-//!
-//! The QP::QEQueue class contains only data members for managing an event
-//! queue, but does not contain the storage for the queue buffer, which must
-//! be provided externally during the queue initialization.
-//!
-//! The event queue can store only event pointers, not the whole events. The
-//! internal implementation uses the standard ring-buffer plus one external
-//! location that optimizes the queue operation for the most frequent case
-//! of empty queue.
-//!
-//! The QP::QEQueue class is used with two sets of functions. One set is for
-//! the active object event queue, which needs to block the active object
-//! task when the event queue is empty and unblock it when events are posted
-//! to the queue. The interface for the native active object event queue
-//! consists of the following functions: QActive::post(), QActive::postLIFO(),
-//! and QActive::get_(). Additionally the function QEQueue::init() is used
-//! to initialize the queue.
-//!
-//! The other set of functions, uses this class as a simple "raw" event
-//! queue to pass events between entities other than active objects, such as
-//! ISRs. The "raw" event queue is not capable of blocking on the get()
-//! operation, but is still thread-safe because it uses QF critical section
-//! to protect its integrity. The interface for the "raw" thread-safe queue
-//! consists of the following functions: QP::QEQueue::post(),
-//! QP::QEQueue::postLIFO(), and QP::QEQueue::get(). Additionally the
-//! function QP::QEQueue::init() is used to initialize the queue.
-//!
-//! @note
-//! Most event queue operations (both the active object queues and the "raw"
-//! queues) internally use the QF critical section. You should be careful
-//! not to invoke those operations from other critical sections when nesting
-//! of critical sections is not supported.
class QEQueue {
private:
-
- //! pointer to event at the front of the queue
- //!
- //! @details
- //! All incoming and outgoing events pass through the m_frontEvt location.
- //! When the queue is empty (which is most of the time), the extra
- //! m_frontEvt location allows to bypass the ring buffer altogether,
- //! greatly optimizing the performance of the queue. Only bursts of events
- //! engage the ring buffer.
- //!
- //! The additional role of this attribute is to indicate the empty status
- //! of the queue. The queue is empty if the m_frontEvt location is nullptr.
QEvt const * volatile m_frontEvt;
-
- //! pointer to the start of the ring buffer
- QEvt const ** m_ring;
-
- //! offset of the end of the ring buffer from the start of the buffer
+ QEvt const * * m_ring;
QEQueueCtr m_end;
-
- //! offset to where next event will be inserted into the buffer
QEQueueCtr volatile m_head;
-
- //! offset of where next event will be extracted from the buffer
QEQueueCtr volatile m_tail;
-
- //! number of free events in the ring buffer
QEQueueCtr volatile m_nFree;
-
- //! minimum number of free events ever in the ring buffer.
- //! @note this attribute remembers the low-watermark of the ring buffer,
- //! which provides a valuable information for sizing event queues.
- //! @sa QP::QF::getQueueMin().
QEQueueCtr m_nMin;
+
+ // friends...
friend class QActive;
friend class QTicker;
friend class QXMutex;
friend class QXThread;
public:
-
- //! public default constructor
- QEQueue() noexcept;
-
- //! Initializes the native QF event queue
- //!
- //! @details
- //! Initialize the event queue by giving it the storage for the
- //! ring buffer.
- //!
- //! @param[in] qSto an array of pointers to QP::QEvt to serve as the
- //! ring buffer for the event queue
- //! @param[in] qLen the length of the qSto[] buffer (in QP::QEvt pointers)
- //!
- //! @note
- //! The actual capacity of the queue is qLen + 1, because of the extra
- //! location forntEvt.
- //!
- //! @note
- //! This function is also used to initialize the event queues of active
- //! objects in the built-int QV, QK and QXK kernels, as well as other
- //! QP ports to OSes/RTOSes that do provide a suitable message queue.
+ QEQueue() noexcept
+ : m_frontEvt(nullptr),
+ m_ring(nullptr),
+ m_end(0U),
+ m_head(0U),
+ m_tail(0U),
+ m_nFree(0U),
+ m_nMin(0U)
+ {}
void init(
- QEvt const * qSto[],
+ QEvt const * * const qSto,
std::uint_fast16_t const qLen) noexcept;
-
- //! Posts (FIFO) an event to the "raw" thread-safe QF event queue
- //!
- //! @details
- //! Post an event to the "raw" thread-safe event queue using the
- //! First-In-First-Out (FIFO) order.
- //!
- //! @param[in] e pointer to the event to be posted to the queue
- //! @param[in] margin number of required free slots in the queue after
- //! posting the event. The special value
- //! QF::NO_MARGIN means that this function will
- //! assert if posting
- //! @param[in] qs_id QS-id of this state machine (for QS local filter)
- //!
- //! @note
- //! The QF::NO_MARGIN value of the `margin` argument is special and
- //! denotes situation when the post() operation is assumed to succeed
- //! (event delivery guarantee). An assertion fires, when the event cannot
- //! be delivered in this case.
- //!
- //! @returns 'true' (success) when the posting succeeded with the provided
- //! margin and 'false' (failure) when the posting fails.
- //!
- //! @note
- //! This function can be called from any task context or ISR context.
- //!
- //! @sa QP::QEQueue::postLIFO(), QP::QEQueue::get()
bool post(
QEvt const * const e,
std::uint_fast16_t const margin,
- std::uint_fast8_t const qs_id) noexcept;
-
- //! Posts (LIFO) an event to the "raw" thread-safe QF event queue
- //!
- //! @details
- //! Post an event to the "raw" thread-safe event queue using the
- //! Last-In-First-Out (LIFO) order.
- //!
- //! @param[in] e pointer to the event to be posted to the queue
- //! @param[in] qs_id QS-id of this state machine (for QS local filter)
- //!
- //! @attention
- //! The LIFO policy should be used only with great __caution__,
- //! because it alters the order of events in the queue.
- //!
- //! @note
- //! This function can be called from any task context or ISR context.
- //!
- //! @note
- //! This function is used for the "raw" thread-safe queues and __not__
- //! for the queues of active objects.
- //!
- //! @sa
- //! QEQueue::post(), QEQueue::get(), QActive::defer()
+ std::uint_fast8_t const qsId) noexcept;
void postLIFO(
QEvt const * const e,
- std::uint_fast8_t const qs_id) noexcept;
-
- //! Gets an event from the "raw" thread-safe QF event queue
- //!
- //! @details
- //! Retrieves an event from the front of the "raw" thread-safe queue and
- //! returns a pointer to this event to the caller.
- //!
- //! @param[in] qs_id QS-id of this state machine (for QS local filter)
- //!
- //! @returns
- //! pointer to event at the front of the queue, if the queue is
- //! not empty and NULL if the queue is empty.
- //!
- //! @note
- //! this function is used for the "raw" thread-safe queues and **not**
- //! for the queues of active objects.
- //!
- //! @sa
- //! QEQueue::post(), QEQueue::postLIFO(), QActive::recall()
- QEvt const * get(std::uint_fast8_t const qs_id) noexcept;
-
- //! Gets the number of free slots currently in "raw" thread-safe
- //! QF event queue
- //!
- //! @note
- //! This operation needs to be used with caution because the
- //! number of free entries can change unexpectedly. The main intent for
- //! using this operation is in conjunction with event deferral. In this
- //! case the queue is accessed only from a single thread (by a single AO),
- //! so the number of free entries cannot change unexpectedly.
- //!
- //! @sa QP::QMActive::defer(), QP::QMActive::recall()
+ std::uint_fast8_t const qsId) noexcept;
+ QEvt const * get(std::uint_fast8_t const qsId) noexcept;
QEQueueCtr getNFree() const noexcept {
return m_nFree;
}
-
- //! "raw" thread-safe QF event queue operation for obtaining the minimum
- //! number of free entries ever in the queue (a.k.a. "low-watermark").
- //!
- //! @details
- //! This operation needs to be used with caution because the
- //! "low-watermark" can change unexpectedly. The main intent for using
- //! this operation is to get an idea of queue usage to size the queue
- //! adequately.
- //!
- //! @returns the minimum number of free entries ever in the queue
- //! since init.
QEQueueCtr getNMin() const noexcept {
return m_nMin;
}
-
- //! "raw" thread-safe QF event queue operation to find out if the queue
- //! is empty
- //! @note
- //! This operation needs to be used with caution because the
- //! queue status can change unexpectedly. The main intent for using
- //! this operation is in conjunction with event deferral. In this case
- //! the queue is accessed only from a single thread (by a single AO),
- //! so no other entity can post events to the queue.
- //!
- //! @sa QP::QMActive::defer(), QP::QMActive::recall()
bool isEmpty() const noexcept {
return m_frontEvt == nullptr;
}
private:
-
- //! disallow copying of QP::QEQueue
QEQueue(QEQueue const & other) = delete;
-
- //! disallow copying of QP::QEQueue
QEQueue & operator=(QEQueue const & other) = delete;
+ void postFIFO_(
+ QEvt const * const e,
+ void const * const sender);
}; // class QEQueue
} // namespace QP
-//$enddecl${QF::QEQueue} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#endif // QEQUEUE_HPP_
diff --git a/src/qf.hpp b/src/qf.hpp
deleted file mode 100644
index aabb9f4..0000000
--- a/src/qf.hpp
+++ /dev/null
@@ -1,1880 +0,0 @@
-//$file${include::qf.hpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-//
-// Model: qpcpp.qm
-// File: ${include::qf.hpp}
-//
-// This code has been generated by QM 5.2.5 .
-// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
-//
-// This code is covered by the following QP license:
-// License # : LicenseRef-QL-dual
-// Issued to : Any user of the QP/C++ real-time embedded framework
-// Framework(s) : qpcpp
-// Support ends : 2023-12-31
-// License scope:
-//
-// Copyright (C) 2005 Quantum Leaps, LLC .
-//
-// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
-//
-// This software is dual-licensed under the terms of the open source GNU
-// General Public License version 3 (or any later version), or alternatively,
-// under the terms of one of the closed source Quantum Leaps commercial
-// licenses.
-//
-// The terms of the open source GNU General Public License version 3
-// can be found at:
-//
-// The terms of the closed source Quantum Leaps commercial licenses
-// can be found at:
-//
-// Redistributions in source code must retain this top-level comment block.
-// Plagiarizing this software to sidestep the license obligations is illegal.
-//
-// Contact information:
-//
-//
-//
-//$endhead${include::qf.hpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//! @file
-//! @brief QF/C++ platform-independent public interface.
-
-#ifndef QF_HPP_
-#define QF_HPP_
-
-#ifdef Q_EVT_CTOR
-#include // for placement new
-#include // for va_list
-#endif // Q_EVT_CTOR
-
-//============================================================================
-// Global namespace...
-//$declare${QF-config} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-
-//${QF-config::QF_MAX_ACTIVE} ................................................
-#ifndef QF_MAX_ACTIVE
-//! Maximum number of active objects (configurable value in qf_port.hpp)
-//! Valid values: [1U..64U]; default 32U
-#define QF_MAX_ACTIVE 32U
-#endif // ndef QF_MAX_ACTIVE
-
-//${QF-config::QF_MAX_ACTIVE exceeds the maximu~} ............................
-#if (QF_MAX_ACTIVE > 64U)
-#error QF_MAX_ACTIVE exceeds the maximum of 64U;
-#endif // (QF_MAX_ACTIVE > 64U)
-
-//${QF-config::QF_MAX_TICK_RATE} .............................................
-#ifndef QF_MAX_TICK_RATE
-//! Maximum number of clock rates (configurable value in qf_port.hpp)
-//! Valid values: [0U..15U]; default 1U
-#define QF_MAX_TICK_RATE 1U
-#endif // ndef QF_MAX_TICK_RATE
-
-//${QF-config::QF_MAX_TICK_RATE exceeds the max~} ............................
-#if (QF_MAX_TICK_RATE > 15U)
-#error QF_MAX_TICK_RATE exceeds the maximum of 15U;
-#endif // (QF_MAX_TICK_RATE > 15U)
-
-//${QF-config::QF_MAX_EPOOL} .................................................
-#ifndef QF_MAX_EPOOL
-//! Maximum number of event pools (configurable value in qf_port.hpp)
-//! Valid values: [0U..15U]; default 3U
-//!
-//! @note
-//! #QF_MAX_EPOOL set to zero means that dynamic events are NOT configured
-//! and should not be used in the application.
-#define QF_MAX_EPOOL 3U
-#endif // ndef QF_MAX_EPOOL
-
-//${QF-config::QF_MAX_EPOOL exceeds the maximum~} ............................
-#if (QF_MAX_EPOOL > 15U)
-#error QF_MAX_EPOOL exceeds the maximum of 15U;
-#endif // (QF_MAX_EPOOL > 15U)
-
-//${QF-config::QF_TIMEEVT_CTR_SIZE} ..........................................
-#ifndef QF_TIMEEVT_CTR_SIZE
-//! Size of the QTimeEvt counter (configurable value in qf_port.hpp)
-//! Valid values: 1U, 2U, or 4U; default 4U
-#define QF_TIMEEVT_CTR_SIZE 4U
-#endif // ndef QF_TIMEEVT_CTR_SIZE
-
-//${QF-config::QF_TIMEEVT_CTR_SIZE defined inco~} ............................
-#if (QF_TIMEEVT_CTR_SIZE != 1U) && (QF_TIMEEVT_CTR_SIZE != 2U) && (QF_TIMEEVT_CTR_SIZE != 4U)
-#error QF_TIMEEVT_CTR_SIZE defined incorrectly, expected 1U, 2U, or 4U;
-#endif // (QF_TIMEEVT_CTR_SIZE != 1U) && (QF_TIMEEVT_CTR_SIZE != 2U) && (QF_TIMEEVT_CTR_SIZE != 4U)
-
-//${QF-config::QF_EVENT_SIZ_SIZE} ............................................
-#ifndef QF_EVENT_SIZ_SIZE
-//! Size of the event-size (configurable value in qf_port.hpp)
-//! Valid values: 1U, 2U, or 4U; default 2U
-#define QF_EVENT_SIZ_SIZE 2U
-#endif // ndef QF_EVENT_SIZ_SIZE
-
-//${QF-config::QF_EVENT_SIZ_SIZE defined incorr~} ............................
-#if (QF_EVENT_SIZ_SIZE != 1U) && (QF_EVENT_SIZ_SIZE != 2U) && (QF_EVENT_SIZ_SIZE != 4U)
-#error QF_EVENT_SIZ_SIZE defined incorrectly, expected 1U, 2U, or 4U;
-#endif // (QF_EVENT_SIZ_SIZE != 1U) && (QF_EVENT_SIZ_SIZE != 2U) && (QF_EVENT_SIZ_SIZE != 4U)
-//$enddecl${QF-config} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-//============================================================================
-//$declare${QF-types} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-namespace QP {
-
-//${QF-types::QPSetBits} .....................................................
-#if (8U < QF_MAX_ACTIVE) && (QF_MAX_ACTIVE <= 16U)
-//! bitmask for the internal representation of QPSet elements
-using QPSetBits = std::uint16_t;
-#endif // (8U < QF_MAX_ACTIVE) && (QF_MAX_ACTIVE <= 16U)
-
-//${QF-types::QPSetBits} .....................................................
-#if (16 < QF_MAX_ACTIVE)
-using QPSetBits = std::uint32_t;
-#endif // (16 < QF_MAX_ACTIVE)
-
-//${QF-types::QPSetBits} .....................................................
-#if (QF_MAX_ACTIVE <= 8U)
-using QPSetBits = std::uint8_t;
-#endif // (QF_MAX_ACTIVE <= 8U)
-
-//${QF-types::QTimeEvtCtr} ...................................................
-#if (QF_TIMEEVT_CTR_SIZE== 2U)
-//! Data type to store the block-size defined based on the macro
-//! #QF_TIMEEVT_CTR_SIZE.
-//!
-//! @details
-//! The dynamic range of this data type determines the maximum block
-//! size that can be managed by the pool.
-using QTimeEvtCtr = std::uint16_t;
-#endif // (QF_TIMEEVT_CTR_SIZE== 2U)
-
-//${QF-types::QTimeEvtCtr} ...................................................
-#if (QF_TIMEEVT_CTR_SIZE== 1U)
-using QTimeEvtCtr = std::uint8_t;
-#endif // (QF_TIMEEVT_CTR_SIZE== 1U)
-
-//${QF-types::QTimeEvtCtr} ...................................................
-#if (QF_TIMEEVT_CTR_SIZE== 4U)
-using QTimeEvtCtr = std::uint32_t;
-#endif // (QF_TIMEEVT_CTR_SIZE== 4U)
-
-//${QF-types::QPrioSpec} .....................................................
-//! Priority specification for Active Objects in QP
-//!
-//! @details
-//! Active Object priorities in QP are integer numbers in the range
-//! [1..#QF_MAX_ACTIVE], whereas the special priority number 0 is reserved
-//! for the lowest-priority idle thread. The QP framework uses the *direct*
-//! priority numbering, in which higher numerical values denote higher
-//! urgency. For example, an AO with priority 32 has higher urgency than
-//! an AO with priority 23.
-//!
-//! QP::QPrioSpec allows an application developer to assign **two**
-//! priorities to a given AO (see also Q_PRIO()):
-//!
-//! 1. The "QF-priority", which resides in the least-significant byte
-//! of the QP::QPrioSpec data type. The "QF-priority" must be **unique**
-//! for each thread in the system and higher numerical values represent
-//! higher urgency (direct pirority numbering).
-//!
-//! 2. The "preemption-threshold" priority, which resides in the most-
-//! significant byte of the ::QPrioSpec data type. The second priority
-//! cannot be lower than the "QF-priority", but does NOT need to be
-//! unuque.
-//!
-//! In the QP native preemptive kernels, like QK and QXK, the "preemption-
-//! threshold" priority is used as to implement the "preemption-threshold
-//! scheduling" (PTS). It determines the conditions under which a given
-//! thread can be *preempted* by other threads. Specifically, a given
-//! thread can be preempted only by another thread with a *higher*
-//! priority than the "preemption-threshold" of the original thread.
-//!
-//! 
-//!
-//! @note
-//! For backwards-compatibility, QP::QPrioSpec data type might contain only
-//! the "QF-priority" component (and the "preemption-threshold" component
-//! left at zero). In that case, the "preemption-threshold" will be assumed
-//! to be the same as the "QF-priority". This corresponds exactly to the
-//! previous semantics of AO priority.
-//!
-//! @remark
-//! When QP runs on top of 3rd-party kernels/RTOSes or general-purpose
-//! operating systems, sthe second priority can have different meaning,
-//! depending on the specific RTOS/GPOS used.
-using QPrioSpec = std::uint16_t;
-
-//${QF-types::QSchedStatus} ..................................................
-//! The scheduler lock status used in some real-time kernels
-using QSchedStatus = std::uint_fast16_t;
-
-//${QF-types::QPSet} .........................................................
-//! Priority Set of up to #QF_MAX_ACTIVE elements
-//!
-//! @details
-//! The priority set represents the set of active objects that are ready to
-//! run and need to be considered by the scheduling algorithm. The set is
-//! capable of storing up to #QF_MAX_ACTIVE priority levels, which can be
-//! configured in the rage 1..64, inclusive.
-class QPSet {
-public:
-
-#if (QF_MAX_ACTIVE <= 32)
- //! bitmask with a bit for each element
- QPSetBits volatile m_bits;
-#endif // (QF_MAX_ACTIVE <= 32)
-
-#if (32 < QF_MAX_ACTIVE)
- //! bitmasks with a bit for each element
- QPSetBits volatile m_bits[2];
-#endif // (32 < QF_MAX_ACTIVE)
-
-public:
-
- //! Make the priority set empty
- void setEmpty() noexcept {
- #if (QF_MAX_ACTIVE <= 32U)
- m_bits = 0U;
- #else
- m_bits[0] = 0U;
- m_bits[1] = 0U;
- #endif
- }
-
- //! Return 'true' if the priority set is empty
- bool isEmpty() const noexcept {
- #if (QF_MAX_ACTIVE <= 32U)
- return (m_bits == 0U);
- #else
- return (m_bits[0] == 0U) ? (m_bits[1] == 0U) : false;
- #endif
- }
-
- //! Return 'true' if the priority set is NOT empty
- bool notEmpty() const noexcept {
- #if (QF_MAX_ACTIVE <= 32U)
- return (m_bits != 0U);
- #else
- return (m_bits[0] != 0U) ? true : (m_bits[1] != 0U);
- #endif
- }
-
- //! Return 'true' if the priority set has the element n.
- bool hasElement(std::uint_fast8_t const n) const noexcept {
- #if (QF_MAX_ACTIVE <= 32U)
- return (m_bits & (1U << (n - 1U))) != 0U;
- #else
- return (n <= 32U)
- ? ((m_bits[0] & (static_cast(1) << (n - 1U))) != 0U)
- : ((m_bits[1] & (static_cast(1) << (n - 33U))) != 0U);
- #endif
- }
-
- //! insert element `n` into the set (n = 1..QF_MAX_ACTIVE)
- void insert(std::uint_fast8_t const n) noexcept {
- #if (QF_MAX_ACTIVE <= 32U)
- m_bits = (m_bits | (1U << (n - 1U)));
- #else
- if (n <= 32U) {
- m_bits[0] = (m_bits[0]
- | (static_cast(1) << (n - 1U)));
- }
- else {
- m_bits[1] = (m_bits[1]
- | (static_cast(1) << (n - 33U)));
- }
- #endif
- }
-
- //! Remove element `n` from the set (n = 1U..64U)
- void remove(std::uint_fast8_t const n) noexcept {
- #if (QF_MAX_ACTIVE <= 32U)
- m_bits = (m_bits & static_cast(
- ~(static_cast(1) << (n - 1U))));
- #else
- if (n <= 32U) {
- (m_bits[0] = (m_bits[0]
- & ~(static_cast(1) << (n - 1U))));
- }
- else {
- (m_bits[1] = (m_bits[1]
- & ~(static_cast(1) << (n - 33U))));
- }
- #endif
- }
-
- //! Find the maximum element in the set, returns zero if the set is empty
- std::uint_fast8_t findMax() const noexcept {
- #if (QF_MAX_ACTIVE <= 32U)
- return QF_LOG2(m_bits);
- #else
- return (m_bits[1] != 0U)
- ? (QF_LOG2(m_bits[1]) + 32U)
- : (QF_LOG2(m_bits[0]));
- #endif
- }
-
-#ifndef QF_LOG2
- //! Log-base-2 calculation when hardware acceleration
- //! is NOT provided (#QF_LOG2 not defined).
- std::uint_fast8_t QF_LOG2(QP::QPSetBits x) const noexcept;
-#endif // ndef QF_LOG2
-}; // class QPSet
-
-//${QF-types::QSubscrList} ...................................................
-//! Subscriber List (for publish-subscribe)
-//!
-//! @details
-//! This data type represents a set of Active Objects that subscribe to
-//! a given signal. The set is represented as priority-set, where each bit
-//! corresponds to the unique QF-priority of an AO (see QP::QPrioSpec).
-using QSubscrList = QPSet;
-
-} // namespace QP
-//$enddecl${QF-types} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//$declare${QF::QActive} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-namespace QP {
-
-//${QF::QActive} .............................................................
-//! QP::QActive active object class (based on the QP::QHsm-style
-//! implementation strategy)
-//!
-//! @details
-//! Active objects are encapsulated tasks (each containing an event queue and
-//! a state machine) that communicate with one another asynchronously by
-//! sending and receiving events. Within an active object, events are
-//! processed in a run-to-completion (RTC) fashion, while QF encapsulates
-//! all the details of thread-safe event exchange and queuing.
-//!
-//! QP::QActive represents an active object that uses the QP::QHsm-style
-//! implementation strategy for state machines. This strategy is tailored
-//! to manual coding, but it is also supported by the QM modeling tool.
-//! The resulting code is slower than in the QP::QMsm-style implementation
-//! strategy.
-//!
-//! @note
-//! QP::QActive is not intended to be instantiated directly, but rather serves
-//! as the abstract base class for derivation of active objects in the
-//! applications.
-//!
-//! @sa QP::QMActive
-//!
-//! @usage
-//! The following example illustrates how to derive an active object from
-//! QP::QActive.
-//! @include qf_qactive.cpp
-class QActive : public QP::QHsm {
-public:
-
-#ifdef QF_EQUEUE_TYPE
- //! OS-dependent event-queue type
- //!
- //! @details
- //! The type of the queue depends on the underlying operating system or
- //! a kernel. Many kernels support "message queues" that can be adapted
- //! to deliver QF events to the active object. Alternatively, QF provides
- //! a native event queue implementation that can be used as well.
- //!
- //! @note
- //! The native QF event queue is configured by defining the macro
- //! #QF_EQUEUE_TYPE as QP::QEQueue.
- QF_EQUEUE_TYPE m_eQueue;
-#endif // def QF_EQUEUE_TYPE
-
-#ifdef QF_OS_OBJECT_TYPE
- //! OS-dependent per-thread object
- //!
- //! @details
- //! This data might be used in various ways, depending on the QF port.
- //! In some ports m_osObject is used to block the calling thread when
- //! the native QF queue is empty. In other QF ports the OS-dependent
- //! object might be used differently.
- QF_OS_OBJECT_TYPE m_osObject;
-#endif // def QF_OS_OBJECT_TYPE
-
-#ifdef QF_THREAD_TYPE
- //! OS-dependent representation of the thread of the active object
- //!
- //! @details
- //! This data might be used in various ways, depending on the QF port.
- //! In some ports m_thread is used store the thread handle. In other ports
- //! m_thread can be a pointer to the Thread-Local-Storage (TLS).
- QF_THREAD_TYPE m_thread;
-#endif // def QF_THREAD_TYPE
-
- //! QF-priority [1..#QF_MAX_ACTIVE] of this AO.
- //! @sa QP::QPrioSpec
- std::uint8_t m_prio;
-
- //! preemption-threshold [1..#QF_MAX_ACTIVE] of this AO.
- //! @sa QP::QPrioSpec
- std::uint8_t m_pthre;
-
-private:
- friend class QTimeEvt;
- friend class QTicker;
-
-#ifdef QXK_HPP_
- friend class QXThread;
-#endif // def QXK_HPP_
-
-#ifdef QXK_HPP_
- friend class QXMutex;
-#endif // def QXK_HPP_
-
-#ifdef QXK_HPP_
- friend class QXSemaphore;
-#endif // def QXK_HPP_
-
-#ifdef Q_UTEST
- friend class QActiveDummy;
-#endif // def Q_UTEST
- friend class GuiQActive;
- friend class GuiQMActive;
-
-public:
-
- //! Internal array of registered active objects
- static QActive * registry_[QF_MAX_ACTIVE + 1U];
-
- //! pointer to the array of all subscriber AOs for a given event signal
- static QSubscrList * subscrList_;
-
- //! The maximum published signal (the size of the subscrList_ array)
- static enum_t maxPubSignal_;
-
-protected:
-
- //! protected constructor (abstract class)
- QActive(QStateHandler const initial) noexcept;
-
-public:
-
- //! Starts execution of an active object and registers the object
- //! with the framework
- //!
- //! @details
- //! Starts execution of the AO and registers the AO with the framework.
- //!
- //! @param[in] prioSpec priority specification of the AO containing the
- //! QF-priority and (optionally) preemption-threshold of this AO
- //! (for preemptive kernels that support it). See also QP::QPrioSpec.
- //! @param[in] qSto pointer to the storage for the ring buffer of the
- //! event queue
- //! @param[in] qLen length of the event queue [# QP::QEvt* pointers]
- //! @param[in] stkSto pointer to the stack storage (might be nullptr)
- //! @param[in] stkSize stack size [bytes]
- //! @param[in] par pointer to an extra parameter (might be nullptr)
- //!
- //! @usage
- //! The following example shows starting an AO when a per-task stack
- //! is needed:
- //! @include qf_start.cpp
- virtual void start(
- QPrioSpec const prioSpec,
- QEvt const * * const qSto,
- std::uint_fast16_t const qLen,
- void * const stkSto,
- std::uint_fast16_t const stkSize,
- void const * const par);
-
- //! Overloaded start function (no initialization parameter)
- virtual void start(
- QPrioSpec const prioSpec,
- QEvt const * * const qSto,
- std::uint_fast16_t const qLen,
- void * const stkSto,
- std::uint_fast16_t const stkSize)
- {
- this->start(prioSpec, qSto, qLen, stkSto, stkSize, nullptr);
- }
-
-#ifdef QF_ACTIVE_STOP
- //! Stops execution of an active object and removes it from the
- //! framework's supervision
- //!
- //! @attention
- //! QActive::stop() must be called only from the AO that is about
- //! to stop its execution. By that time, any pointers or references
- //! to the AO are considered invalid (dangling) and it becomes
- //! illegal for the rest of the application to post events to the AO.
- void stop();
-#endif // def QF_ACTIVE_STOP
-
- //! Posts an event `e` directly to the event queue of the active object
- //! using the First-In-First-Out (FIFO) policy.
- //!
- //! @details
- //! Direct event posting is the simplest asynchronous communication
- //! method available in QF.
- //!
- //! @param[in] e pointer to the event to be posted
- //! @param[in] margin number of required free slots in the queue
- //! after posting the event or QF::NO_MARGIN.
- //! @param[in] sender pointer to a sender object (used in QS only)
- //!
- //! @returns
- //! 'true' (success) if the posting succeeded (with the provided margin)
- //! and 'false' (failure) when the posting fails.
- //!
- //! @attention
- //! For `margin` == QF::NO_MARGIN, this function will assert internally
- //! if the event posting fails. In that case, it is unnecessary to check
- //! the retrun value from this function.
- //!
- //! @note
- //! This function might be implemented differentyl in various QP/C++
- //! ports. The provided implementation assumes that the QP::QEQueue
- //! class is used for the QP::QActive event queue.
- //!
- //! @usage
- //! @include qf_post.cpp
- //!
- //! @sa
- //! QActive::postLIFO()
- virtual bool post_(
- QEvt const * const e,
- std::uint_fast16_t const margin,
- void const * const sender) noexcept;
-
- //! Posts an event `e` directly to the event queue of the active object
- //! using the Last-In-First-Out (LIFO) policy.
- //!
- //! @details
- //! The LIFO policy should be used only for self-posting and with caution,
- //! because it alters order of events in the queue.
- //!
- //! @param[in] e pointer to the event to be posted
- //!
- //! @attention
- //! This function asserts internally if the posting fails.
- //!
- //! @note
- //! This function might be implemented differentyl in various QP/C++
- //! ports. The provided implementation assumes that the QP::QEQueue
- //! class is used for the QActive event queue.
- //!
- //! @sa
- //! QActive::post()
- virtual void postLIFO(QEvt const * const e) noexcept;
-
- //! Get an event from the event queue of an active object
- //!
- //! @details
- //! The behavior of this function depends on the kernel used in the
- //! QF port. For built-in kernels (Vanilla or QK) the function can be
- //! called only when the queue is not empty, so it doesn't block. For
- //! a blocking kernel/OS the function can block and wait for delivery
- //! of an event.
- //!
- //! @returns
- //! A pointer to the received event. The returned pointer is guaranteed
- //! to be valid (can't be nullptr).
- //!
- //! @note
- //! This function might be implemented differentyl in various QP/C++
- //! ports. The provided implementation assumes that the QP::QEQueue
- //! class is used for the QActive event queue.
- QEvt const * get_() noexcept;
-
- //! Subscribes for delivery of signal `sig` to the active object
- //!
- //! @details
- //! This function is part of the Publish-Subscribe event delivery
- //! mechanism available in QF. Subscribing to an event means that the
- //! framework will start posting all published events with a given signal
- //! `sig` to the event queue of the active object.
- //!
- //! @param[in] sig event signal to subscribe
- //!
- //! The following example shows how the Table active object subscribes
- //! to three signals in the initial transition:
- //! @include qf_subscribe.cpp
- //!
- //! @sa
- //! QActive::publish_(), QActive::unsubscribe(), and
- //! QActive::unsubscribeAll()
- void subscribe(enum_t const sig) const noexcept;
-
- //! Unsubscribes from the delivery of signal `sig` to the active object
- //!
- //! @details
- //! This function is part of the Publish-Subscribe event delivery
- //! mechanism available in QF. Un-subscribing from an event means that
- //! the framework will stop posting published events with a given signal
- //! `sig` to the event queue of the active object.
- //!
- //! @param[in] sig event signal to unsubscribe
- //!
- //! @note
- //! Due to the latency of event queues, an active object should NOT
- //! assume that a given signal `sig` will never be dispatched to the
- //! state machine of the active object after un-subscribing from that
- //! signal. The event might be already in the queue, or just about to
- //! be posted and the un-subscribe operation will not flush such events.
- //!
- //! @note
- //! Un-subscribing from a signal that has never been subscribed in the
- //! first place is considered an error and QF will raise an assertion.
- //!
- //! @sa
- //! QActive::publish_(), QActive::subscribe(), and
- //! QActive::unsubscribeAll()
- void unsubscribe(enum_t const sig) const noexcept;
-
- //! Unsubscribes from the delivery of all signals to the active object
- //!
- //! @details
- //! This function is part of the Publish-Subscribe event delivery
- //! mechanism available in QF. Un-subscribing from all events means that
- //! the framework will stop posting any published events to the event
- //! queue of the active object.
- //!
- //! @note
- //! Due to the latency of event queues, an active object should NOT
- //! assume that no events will ever be dispatched to the state machine of
- //! the active object after un-subscribing from all events.
- //! The events might be already in the queue, or just about to be posted
- //! and the un-subscribe operation will not flush such events. Also, the
- //! alternative event-delivery mechanisms, such as direct event posting or
- //! time events, can be still delivered to the event queue of the active
- //! object.
- //!
- //! @sa
- //! QActive::publish_(), QActive::subscribe(), and QActive::unsubscribe()
- void unsubscribeAll() const noexcept;
-
- //! Defer an event to a given separate event queue
- //!
- //! @details
- //! This function is part of the event deferral support. An active object
- //! uses this function to defer an event `e` to the QF-supported native
- //! event queue `eq`. QF correctly accounts for another outstanding
- //! reference to the event and will not recycle the event at the end of
- //! the RTC step. Later, the active object might recall one event at a
- //! time from the event queue.
- //!
- //! @param[in] eq pointer to a "raw" thread-safe queue to recall
- //! an event from.
- //! @param[in] e pointer to the event to be deferred
- //!
- //! @returns
- //! 'true' (success) when the event could be deferred and 'false'
- //! (failure) if event deferral failed due to overflowing the queue.
- //!
- //! An active object can use multiple event queues to defer events of
- //! different kinds.
- //!
- //! @sa
- //! QActive::recall(), QP::QEQueue, QActive::flushDeferred()
- bool defer(
- QEQueue * const eq,
- QEvt const * const e) const noexcept;
-
- //! Recall a deferred event from a given event queue
- //!
- //! @details
- //! This function is part of the event deferral support. An active object
- //! uses this function to recall a deferred event from a given QF
- //! event queue. Recalling an event means that it is removed from the
- //! deferred event queue `eq` and posted (LIFO) to the event queue of
- //! the active object.
- //!
- //! @param[in] eq pointer to a "raw" thread-safe queue to recall
- //! an event from.
- //!
- //! @returns
- //! 'true' if an event has been recalled and 'false' if not.
- //!
- //! @note
- //! An active object can use multiple event queues to defer events of
- //! different kinds.
- //!
- //! @sa
- //! QActive::recall(), QActive::postLIFO_(), QP::QEQueue
- bool recall(QEQueue * const eq) noexcept;
-
- //! Flush the specified deferred queue 'eq'
- //!
- //! @details
- //! This function is part of the event deferral support. An active object
- //! can use this function to flush a given QF event queue. The function
- //! makes sure that the events are not leaked.
- //!
- //! @param[in] eq pointer to a "raw" thread-safe queue to flush.
- //!
- //! @returns
- //! the number of events actually flushed from the queue.
- //!
- //! @sa
- //! QActive::defer(), QActive::recall(), QP::QEQueue
- std::uint_fast16_t flushDeferred(QEQueue * const eq) const noexcept;
-
- //! Get the priority of the active object.
- std::uint_fast8_t getPrio() const noexcept {
- return static_cast(m_prio);
- }
-
-protected:
-
- //! Set the priority of the active object.
- void setPrio(QPrioSpec const prio) noexcept {
- m_prio = static_cast(prio & 0xFFU);
- m_pthre = static_cast(prio >> 8U);
- }
-
-public:
-
- //! Generic setting of additional attributes (useful in QP ports)
- void setAttr(
- std::uint32_t attr1,
- void const * attr2 = nullptr);
-
-#ifdef QF_OS_OBJECT_TYPE
- //! accessor to the OS-object for extern "C" functions, such as
- //! the QK or QXK schedulers
- QF_OS_OBJECT_TYPE & getOsObject() noexcept {
- return m_osObject;
- }
-#endif // def QF_OS_OBJECT_TYPE
-
-#ifdef QF_THREAD_TYPE
- //! accessor to the Thread for extern "C" functions, such as
- //! the QK or QXK schedulers
- QF_THREAD_TYPE & getThread() noexcept {
- return m_thread;
- }
-#endif // def QF_THREAD_TYPE
-
- //! Publish-subscribe initialization
- //!
- //! @details
- //! This function initializes the publish-subscribe facilities of QF and must
- //! be called exactly once before any subscriptions/publications occur in
- //! the application.
- //!
- //! @param[in] subscrSto pointer to the array of subscriber lists
- //! @param[in] maxSignal the dimension of the subscriber array and at
- //! the same time the maximum signal that can be
- //! published or subscribed.
- //!
- //! The array of subscriber-lists is indexed by signals and provides a mapping
- //! between the signals and subscriber-lists. The subscriber-lists are
- //! bitmasks of type QP::QSubscrList, each bit in the bit mask corresponding
- //! to the unique priority of an active object. The size of the
- //! QP::QSubscrList bitmask depends on the value of the #QF_MAX_ACTIVE macro.
- //!
- //! @note
- //! The publish-subscribe facilities are optional, meaning that you might
- //! choose not to use publish-subscribe. In that case calling QF::psInit()
- //! and using up memory for the subscriber-lists is unnecessary.
- //!
- //! @sa
- //! QP::QSubscrList
- //!
- //! @usage
- //! The following example shows the typical initialization sequence of QF:
- //! @include qf_main.cpp
- static void psInit(
- QSubscrList * const subscrSto,
- enum_t const maxSignal) noexcept;
-
- //! Publish event to all subscribers of a given signal `e->sig`
- //!
- //! @details
- //! This function posts (using the FIFO policy) the event @a e to **all**
- //! active objects that have subscribed to the signal @a e->sig, which is
- //! called _multicasting_. The multicasting performed in this function is
- //! very efficient based on reference-counting inside the published event
- //! ("zero-copy" event multicasting). This function is designed to be
- //! callable from any part of the system, including ISRs, device drivers,
- //! and active objects.
- //!
- //! @note
- //! To avoid any unexpected re-ordering of events posted into AO queues,
- //! the event multicasting is performed with scheduler **locked**.
- //! However, the scheduler is locked only up to the priority level of
- //! the highest-priority subscriber, so any AOs of even higher priority,
- //! which did not subscribe to this event are *not* affected.
- static void publish_(
- QEvt const * const e,
- void const * const sender,
- std::uint_fast8_t const qs_id) noexcept;
-
- //! Thread routine for executing an active object `act`
- static void thread_(QActive * act);
-
- //! Register this active object to be managed by the framework
- //!
- //! @details
- //! This function adds a given active object to the active objects
- //! managed by the QF framework. It should not be called by the
- //! application directly, only through the function QActive::start().
- //!
- //! @note
- //! The priority of the active object a should be set before calling
- //! this function.
- //!
- //! @sa QActive::unregister_()
- void register_() noexcept;
-
- //! Un-register the active object from the framework.
- //!
- //! @details
- //! This function un-registers a given active object from the active objects
- //! managed by the QF framework. It should not be called by the QP ports.
- //!
- //! @param[in] a pointer to the active object to remove from the
- //! framework.
- //!
- //! @note
- //! The active object that is removed from the framework can no longer
- //! participate in any event exchange.
- //!
- //! @sa QActive::register_()
- void unregister_() noexcept;
-
-#ifdef QF_ISR_API
- //! the "FromISR" variant used in the QP port to "FreeRTOS"
- virtual bool postFromISR_(
- QEvt const * const e,
- std::uint_fast16_t const margin,
- void * par,
- void const * const sender) noexcept;
-#endif // def QF_ISR_API
-
-#ifdef QF_ISR_API
- //! the "FromISR" variant used in the QP port to "FreeRTOS"
- static void publishFromISR_(
- QEvt const * e,
- void * par,
- void const * sender) noexcept;
-#endif // def QF_ISR_API
-}; // class QActive
-
-} // namespace QP
-//$enddecl${QF::QActive} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//$declare${QF::QMActive} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-namespace QP {
-
-//${QF::QMActive} ............................................................
-//! QMActive active object (based on QP::QMsm implementation)
-//!
-//! @details
-//! QP::QMActive represents an active object that uses the QP::QMsm-style
-//! state machine implementation strategy. This strategy requires the use of
-//! the QM modeling tool to generate state machine code automatically, but
-//! the code is faster than in the QP::QHsm-style implementation strategy
-//! and needs less run-time support (smaller event-processor).
-//!
-//! @note
-//! QP::QMActive is not intended to be instantiated directly, but rather
-//! serves as the base class for derivation of active objects in the
-//! applications.
-//!
-//! @sa QP::QActive
-//!
-//! @usage
-//! The following example illustrates how to derive an active object from
-//! QP::QMActive.
-//! @include qf_qmactive.cpp
-class QMActive : public QP::QActive {
-public:
-
- //! inherited from QP::QHsm, but disallowed in QP::QMActive
- using QHsm::isIn;
-
- //! inherited from QP::QHsm, but disallowed in QP::QMActive
- using QHsm::state;
-
- //! inherited from QP::QHsm, but disallowed in QP::QMActive
- using QHsm::childState;
-
-protected:
-
- //! protected constructor (abstract class)
- QMActive(QStateHandler const initial) noexcept
- : QActive(initial)
- {
- m_temp.fun = initial;
- }
-
-public:
-
- //! delegate to QP::QMsm::init()
- void init(
- void const * const e,
- std::uint_fast8_t const qs_id) override;
-
- //! delegate to QP::QMsm::init()
- void init(std::uint_fast8_t const qs_id) override;
-
- //! delegate to QMsm::dispatch()
- void dispatch(
- QEvt const * const e,
- std::uint_fast8_t const qs_id) override;
-
- //! Tests if a given state is part of the active state configuration
- bool isInState(QMState const * const st) const noexcept;
-
- //! Return the current active state object (read only)
- QMState const * stateObj() const noexcept {
- return m_state.obj;
- }
-
- //! Return the current active state object (read only)
- QMState const * childStateObj(QMState const * const parent) const noexcept;
-
-#ifdef Q_SPY
- //! Get the current state handler of the QP::QMsm
- QStateHandler getStateHandler() noexcept override;
-#endif // def Q_SPY
-}; // class QMActive
-
-} // namespace QP
-//$enddecl${QF::QMActive} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//$declare${QF::QTimeEvt} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-namespace QP {
-
-//${QF::QTimeEvt} ............................................................
-//! Time Event class (inherits QP:QEvt)
-//!
-//! @details
-//! Time events are special QF events equipped with the notion of time
-//! passage. The basic usage model of the time events is as follows. An
-//! active object allocates one or more QTimeEvt objects (provides the
-//! storage for them). When the active object needs to arrange for a timeout,
-//! it arms one of its time events to fire either just once (one-shot) or
-//! periodically. Each time event times out independently from the others,
-//! so a QF application can make multiple parallel timeout requests (from the
-//! same or different active objects). When QF detects that the appropriate
-//! moment has arrived, it inserts the time event directly into the
-//! recipient's event queue. The recipient then processes the time event just
-//! like any other event.
-//!
-//! Time events, as any other QF events derive from the QP::QEvt base
-//! class. Typically, you will use a time event as-is, but you can also
-//! further derive more specialized time events from it by adding some more
-//! data members and/or specialized functions that operate on the specialized
-//! time events.
-//!
-//! Internally, the armed time events are organized into a bi-directional
-//! linked list. This linked list is scanned in every invocation of the
-//! QTimeEvt::tick_() function. Only armed (timing out) time events are in the
-//! list, so only armed time events consume CPU cycles.
-//!
-//! @note
-//! QF manages the time events in the macro TICK_X(), which must be called
-//! periodically, from the clock tick ISR or from the special QP::QTicker
-//! active object.
-//!
-//! @note
-//! Even though QP::QTimeEvt is a subclass of QP::QEvt, QP::QTimeEvt instances
-//! can NOT be allocated dynamically from event pools. In other words, it is
-//! illegal to allocate QP::QTimeEvt instances with the Q_NEW() or Q_NEW_X()
-//! macros.
-class QTimeEvt : public QP::QEvt {
-private:
-
- //! link to the next time event in the list
- QTimeEvt * volatile m_next;
-
- //! the active object that receives the time events
- //!
- //! @details
- //! The m_act pointer is reused inside the QP implementation to hold
- //! the head of the list of newly armed time events.
- void * m_act;
-
- //! the internal down-counter of the time event
- //!
- //! @details
- //! The down-counter is decremented by 1 in every TICK_X()
- //! invocation. The time event fires (gets posted or published) when
- //! the down-counter reaches zero.
- QTimeEvtCtr volatile m_ctr;
-
- //! the interval for the periodic time event (zero for the one-shot
- //! time event)
- //!
- //! @details
- //! The value of the interval is re-loaded to the internal
- //! down-counter when the time event expires, so that the time event
- //! keeps timing out periodically.
- QTimeEvtCtr m_interval;
-
-public:
-
- //! heads of linked lists of time events, one for every clock tick rate
- static QTimeEvt timeEvtHead_[QF_MAX_TICK_RATE];
-
-private:
- friend class QXThread;
-
-public:
-
- //! The Time Event constructor
- QTimeEvt(
- QActive * const act,
- enum_t const sgnl,
- std::uint_fast8_t const tickRate = 0U);
-
- //! Arm a time event (one shot or periodic) for event posting
- //!
- //! @details
- //! Arms a time event to fire in a specified number of clock ticks and
- //! with a specified interval. If the interval is zero, the time event
- //! is armed for one shot ('one-shot' time event). The time event gets
- //! directly posted (using the FIFO policy) into the event queue of the
- //! host active object. After posting, a one-shot time event gets
- //! automatically disarmed while a periodic time event (interval != 0)
- //! is automatically re-armed.
- //!
- //! A time event can be disarmed at any time by calling
- //! QP::QTimeEvt::disarm(). Also, a time event can be re-armed to fire
- //! in a different number of clock ticks by calling QP::QTimeEvt::rearm().
- //!
- //! @param[in] nTicks number of clock ticks (at the associated rate)
- //! to rearm the time event with.
- //! @param[in] interval interval (in clock ticks) for periodic time event.
- //!
- //! @attention
- //! Arming an already armed time event is __not__ allowed and is
- //! considered a programming error. The QP/C++ framework will assert
- //! if it detects an attempt to arm an already armed time event.
- //!
- //! @usage
- //! The following example shows how to arm a one-shot time event from a
- //! state machine of an active object:
- //! @include qf_state.cpp
- void armX(
- QTimeEvtCtr const nTicks,
- QTimeEvtCtr const interval = 0U) noexcept;
-
- //! Disarm a time event
- //!
- //! @details
- //! Disarm the time event so it can be safely reused.
- //!
- //! @returns
- //! 'true' if the time event was truly disarmed, that is, it was running.
- //! The return of 'false' means that the time event was not truly
- //! disarmed because it was not running. The 'false' return is only
- //! possible for one-shot time events that have been automatically
- //! disarmed upon expiration. In that case the 'false' return means that
- //! the time event has already been posted or published and should be
- //! expected in the active object's state machine.
- //!
- //! @note
- //! there is no harm in disarming an already disarmed time event
- bool disarm() noexcept;
-
- //! Rearm a time event
- //!
- //! @details
- //! Rearms a time event with a new number of clock ticks. This function
- //! can be used to adjust the current period of a periodic time event
- //! or to prevent a one-shot time event from expiring (e.g., a watchdog
- //! time event). Rearming a periodic timer leaves the interval unchanged
- //! and is a convenient method to adjust the phasing of a periodic
- //! time event.
- //!
- //! @param[in] nTicks number of clock ticks (at the associated rate)
- //! to rearm the time event with.
- //!
- //! @returns
- //! 'true' if the time event was running as it was re-armed. The 'false'
- //! return means that the time event was not truly rearmed because it was
- //! not running. The 'false' return is only possible for one-shot time
- //! events that have been automatically disarmed upon expiration. In that
- //! case the 'false' return means that the time event has already been
- //! posted and should be expected in the active object's state machine.
- bool rearm(QTimeEvtCtr const nTicks) noexcept;
-
- //! Check the "was disarmed" status of a time event
- //!
- //! @details
- //! Useful for checking whether a one-shot time event was disarmed in the
- //! QTimeEvt_disarm() operation.
- //!
- //! @returns
- //! 'true' if the time event was truly disarmed in the last
- //! QTimeEvt::disarm() operation. The 'false' return means that the time
- //! event was not truly disarmed, because it was not running at that time.
- //! The 'false' return is only possible for one-shot time events that
- //! have been automatically disarmed upon expiration. In this case the
- //! 'false' return means that the time event has already been posted or
- //! published and should be expected in the active object's event queue.
- //!
- //! @note
- //! This function has a **side effect** of setting the "was disarmed"
- //! status, which means that the second and subsequent times this
- //! function is called the function will return 'true'.
- bool wasDisarmed() noexcept;
-
- //! Gets the active object associated with the time event
- void const * getAct() const noexcept {
- return m_act;
- }
-
- //! Gets the current count of the time event
- QTimeEvtCtr getCtr() const noexcept {
- return m_ctr;
- }
-
- //! Gets the interval of the time event
- QTimeEvtCtr getInterval() const noexcept {
- return m_interval;
- }
-
- //! Processes all armed time events at every clock tick
- //!
- //! @details
- //! This function must be called periodically from a time-tick ISR or from
- //! a task so that QF can manage the timeout events assigned to the given
- //! system clock tick rate.
- //!
- //! @param[in] tickRate system clock tick rate serviced [1..15].
- //! @param[in] sender pointer to a sender object (used in QS only).
- //!
- //! @attention
- //! this function should be called only via the macros TICK_X() or TICK()
- //!
- //! @note
- //! the calls to QTimeEvt::tick_() with different `tickRate` parameter can
- //! preempt each other. For example, higher clock tick rates might be
- //! serviced from interrupts while others from tasks (active objects).
- static void tick_(
- std::uint_fast8_t const tickRate,
- void const * const sender) noexcept;
-
-#ifdef Q_UTEST
- //! Processes one clock tick for QUTest
- static void tick1_(
- std::uint_fast8_t const tickRate,
- void const * const sender);
-#endif // def Q_UTEST
-
-#ifdef QF_ISR_API
- //! the "FromISR" variant used in the QP port to "FreeRTOS"
- static void tickFromISR_(
- std::uint_fast8_t const tickRate,
- void * par,
- void const * sender) noexcept;
-#endif // def QF_ISR_API
-
- //! Returns true if all time events are inactive and false
- //! any time event is active
- //!
- //! @details
- //! Find out if any time events are armed at the given clock tick rate.
- //!
- //! @param[in] tickRate system clock tick rate to find out about.
- //!
- //! @returns
- //! 'true' if no time events are armed at the given tick rate and
- //! 'false' otherwise.
- //!
- //! @note
- //! This function should be called in critical section.
- static bool noActive(std::uint_fast8_t const tickRate) noexcept;
-
- //! encapsulate the cast the m_act attribute to QActive*
- QActive * toActive() noexcept {
- return static_cast(m_act);
- }
-
- //! encapsulate the cast the `QTimeEvt.m_act` attribute
- QTimeEvt * toTimeEvt() noexcept {
- return static_cast(m_act);
- }
-
-private:
-
- //! private default constructor only for friends
- //!
- //! @note
- //! private default ctor for internal use only
- QTimeEvt();
-
- //! private copy constructor to disallow copying of QTimeEvts
- QTimeEvt(QTimeEvt const & other) = delete;
-
- //! disallow copying of QP::QTimeEvt
- QTimeEvt & operator=(QTimeEvt const & other) = delete;
-}; // class QTimeEvt
-
-} // namespace QP
-//$enddecl${QF::QTimeEvt} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//$declare${QF::QTicker} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-namespace QP {
-
-//${QF::QTicker} .............................................................
-//! "Ticker" Active Object class (inherits QP::QActive)
-//!
-//! @details
-//! QP::QTicker is an efficient active object specialized to process
-//! QF system clock tick at a specified tick frequency [0..#QF_MAX_TICK_RATE].
-//! Placing system clock tick processing in an active object allows you
-//! to remove the non-deterministic TICK_X() processing from the interrupt
-//! level and move it into the thread-level, where you can prioritize it
-//! as low as you wish.
-//!
-//! @usage
-//! The following example illustrates use of QP::QTicker active objects:
-//! @include qf_ticker.cpp
-class QTicker : public QP::QActive {
-public:
-
- //! constructor
- explicit QTicker(std::uint_fast8_t const tickRate) noexcept;
- void init(
- void const * const e,
- std::uint_fast8_t const qs_id) override;
- void init(std::uint_fast8_t const qs_id) override;
- void dispatch(
- QEvt const * const e,
- std::uint_fast8_t const qs_id) override;
- bool post_(
- QEvt const * const e,
- std::uint_fast16_t const margin,
- void const * const sender) noexcept override;
-}; // class QTicker
-
-} // namespace QP
-//$enddecl${QF::QTicker} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-//$declare${QF::QF-base} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-namespace QP {
-namespace QF {
-
-//${QF::QF-base::intLock_} ...................................................
-//! Interrupt lock up-down counter (used in some QF ports)
-extern std::uint_fast8_t volatile intLock_;
-
-//${QF::QF-base::intNest_} ...................................................
-//! Interrupt nesting up-down counter (used in some QF ports)
-extern std::uint_fast8_t volatile intNest_;
-
-//${QF::QF-base::init} .......................................................
-//! QF initialization
-//!
-//! @details
-//! Initializes QF and must be called exactly once before any other QF
-//! function. Typcially, QP::QF::init() is called from main() even before
-//! initializing the Board Support Package (BSP).
-//!
-//! @note
-//! QP::QF::init() clears the internal QF variables, so that the framework
-//! can start correctly even if the startup code fails to clear the
-//! uninitialized data (as is required by the C Standard).
-void init();
-
-//${QF::QF-base::stop} .......................................................
-//! Function invoked by the application layer to stop the QF
-//! application and return control to the OS/Kernel
-//!
-//! @details
-//! This function stops the QF application. After calling this function,
-//! QF attempts to gracefully stop the application. This graceful shutdown
-//! might take some time to complete. The typical use of this function is
-//! for terminating the QF application to return back to the operating
-//! system or for handling fatal errors that require shutting down
-//! (and possibly re-setting) the system.
-//!
-//! @attention
-//! After calling QF::stop() the application must terminate and cannot
-//! continue. In particular, QF::stop() is **not** intended to be followed
-//! by a call to QF::init() to "resurrect" the application.
-//!
-//! @sa QP::QF::onCleanup()
-void stop();
-
-//${QF::QF-base::run} ........................................................
-//! Transfers control to QF to run the application
-//!
-//! @details
-//! QF::run() is typically called from your startup code after you
-//! initialize the QF and start at least one active object with
-//! QActive::start().
-//!
-//! @returns
-//! In QK, the QP::QF::run() function does not return.
-int_t run();
-
-//${QF::QF-base::onStartup} ..................................................
-//! Startup QF callback (defined in applications/ports)
-//!
-//! @details
-//! The purpose of the QF::onStartup() callback is to configure and enable
-//! hardware interrupts. The callback is invoked from QF::run(), right before
-//! starting the underlying real-time kernel. By that time, the application
-//! is considered ready to receive and service interrupts.
-//!
-//! This function is application-specific and is not implemented in QF, but
-//! rather in the Board Support Package (BSP) for the given application.
-void onStartup();
-
-//${QF::QF-base::onCleanup} ..................................................
-//! Cleanup QF callback (defined in applications/ports)
-void onCleanup();
-
-//${QF::QF-base::getQueueMin} ................................................
-//! This function returns the minimum of free entries of the given
-//! event queue of an active object (indicated by priority `prio`)
-//!
-//! @details
-//! Queries the minimum of free ever present in the given event queue of
-//! an active object with priority `prio`, since the active object
-//! was started.
-//!
-//! @note
-//! QF::getQueueMin() is available only when the native QF event queue
-//! implementation is used. Requesting the queue minimum of an unused
-//! priority level raises an assertion in the QF. (A priority level
-//! becomes used in QF after the call to QActive::register_().)
-//!
-//! @param[in] prio Priority of the active object, whose queue is queried
-//!
-//! @returns
-//! the minimum of free ever present in the given event queue of an active
-//! object with priority `prio`, since the active object was started.
-std::uint_fast16_t getQueueMin(std::uint_fast8_t const prio) noexcept;
-
-//${QF::QF-base::psInit} .....................................................
-//! Publish-subscribe initialization
-//!
-//! @deprecated
-//! superseded by QActive::psInit()
-inline void psInit(
- QSubscrList * const subscrSto,
- enum_t const maxSignal) noexcept
-{
- QActive::psInit(subscrSto, maxSignal);
-}
-
-//${QF::QF-base::publish_} ...................................................
-//! Publish event to all subscribers of a given signal `e->sig`
-//!
-//! @deprecated
-//! superseded by QActive::publish_()
-inline void publish_(
- QEvt const * const e,
- void const * const sender,
- std::uint_fast8_t const qs_id) noexcept
-{
- QActive::publish_(e, sender, qs_id);
-}
-
-//${QF::QF-base::tick_} ......................................................
-//! Processes all armed time events at every clock tick
-//!
-//! @deprecated
-//! superseded by QTimeEvt::tick_()
-inline void tick_(
- std::uint_fast8_t const tickRate,
- void const * const sender) noexcept
-{
- QTimeEvt::tick_(tickRate, sender);
-}
-
-//${QF::QF-base::NO_MARGIN} ..................................................
-//! Special value of margin that causes asserting failure in case
-//! event allocation or event posting fails
-constexpr std::uint_fast16_t NO_MARGIN {0xFFFFU};
-
-} // namespace QF
-} // namespace QP
-//$enddecl${QF::QF-base} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//$declare${QF::QF-dyn} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-namespace QP {
-namespace QF {
-
-//${QF::QF-dyn::poolInit} ....................................................
-//! Event pool initialization for dynamic allocation of events.
-//!
-//! @details
-//! This function initializes one event pool at a time and must be called
-//! exactly once for each event pool before the pool can be used.
-//!
-//! @param[in] poolSto pointer to the storage for the event pool
-//! @param[in] poolSize size of the storage for the pool in bytes
-//! @param[in] evtSize the block-size of the pool in bytes, which
-//! determines the maximum size of events that
-//! can be allocated from the pool
-//! @note
-//! You might initialize many event pools by making many consecutive calls
-//! to the QF::poolInit() function. However, for the simplicity of the
-//! internal implementation, you must initialize event pools in the
-//! ascending order of the event size.
-//!
-//! @note
-//! The actual number of events available in the pool might be actually
-//! less than (`poolSize / evtSize`) due to the internal alignment of
-//! the blocks that the pool might perform. You can always check the
-//! capacity of the pool by calling QF::getPoolMin().
-//!
-//! @note
-//! The dynamic allocation of events is optional, meaning that you might
-//! choose not to use dynamic events. In that case calling
-//! QF::poolInit() and using up memory for the memory blocks is
-//! unnecessary.
-//!
-//! @sa QF initialization example for QF::init()
-void poolInit(
- void * const poolSto,
- std::uint_fast32_t const poolSize,
- std::uint_fast16_t const evtSize) noexcept;
-
-//${QF::QF-dyn::newX_} .......................................................
-//! Internal QF implementation of creating new dynamic mutable event
-//!
-//! @details
-//! Allocates an event dynamically from one of the QF event pools.
-//!
-//! @param[in] evtSize the size (in bytes) of the event to allocate
-//! @param[in] margin the number of un-allocated events still available
-//! in a given event pool after the allocation
-//! completes. The special value QF::NO_MARGIN
-//! means that this function will assert if allocation
-//! fails.
-//! @param[in] sig the signal to be assigned to the allocated event
-//!
-//! @returns
-//! pointer to the newly allocated event. This pointer can be nullptr
-//! only if margin!=0 and the event cannot be allocated with the
-//! specified margin still available in the given pool.
-//!
-//! @note
-//! The internal QF function QF::newX_() raises an assertion when
-//! the margin argument is QF::NO_MARGIN and allocation of the event
-//! turns out to be impossible due to event pool depletion, or incorrect
-//! (too big) size of the requested event.
-//!
-//! @note
-//! The application code should not call this function directly.
-//! The only allowed use is thorough the macros Q_NEW() or Q_NEW_X().
-QEvt * newX_(
- std::uint_fast16_t const evtSize,
- std::uint_fast16_t const margin,
- enum_t const sig) noexcept;
-
-//${QF::QF-dyn::gc} ..........................................................
-//! Recycle a dynamic event
-//!
-//! @details
-//! This function implements a garbage collector for dynamic events.
-//! Only dynamic events are candidates for recycling. (A dynamic event
-//! is one that is allocated from an event pool, which is determined as
-//! non-zero `e->poolId_` attribute.) Next, the function decrements the
-//! reference counter of the event (`e->refCtr_`), and recycles the event
-//! only if the counter drops to zero (meaning that no more references
-//! are outstanding for this event). The dynamic event is recycled by
-//! returning it to the pool from which it was originally allocated.
-//!
-//! @param[in] e pointer to the event to recycle
-//!
-//! @note
-//! QF invokes the garbage collector at all appropriate contexts, when
-//! an event can become garbage (automatic garbage collection), so the
-//! application code should have no need to call QF::gc() directly.
-//! The QF::gc() function is exposed only for special cases when your
-//! application sends dynamic events to the "raw" thread-safe queues
-//! (see QP::QEQueue). Such queues are processed outside of QF and the
-//! automatic garbage collection is **NOT** performed for these events.
-//! In this case you need to call QF::gc() explicitly.
-void gc(QEvt const * const e) noexcept;
-
-//${QF::QF-dyn::poolGetMaxBlockSize} .........................................
-//! Obtain the block size of any registered event pools
-std::uint_fast16_t poolGetMaxBlockSize() noexcept;
-
-//${QF::QF-dyn::newRef_} .....................................................
-//! Internal QF implementation of creating new event reference
-//!
-//! @details
-//! Creates and returns a new reference to the current event e
-//!
-//! @param[in] e pointer to the current event
-//! @param[in] evtRef the event reference
-//!
-//! @returns
-//! the newly created reference to the event `e`
-//!
-//! @note
-//! The application code should not call this function directly.
-//! The only allowed use is thorough the macro Q_NEW_REF().
-QEvt const * newRef_(
- QEvt const * const e,
- QEvt const * const evtRef) noexcept;
-
-//${QF::QF-dyn::deleteRef_} ..................................................
-//! Internal QF implementation of deleting event reference
-//!
-//! @details
-//! Deletes an existing reference to the event e
-//!
-//! @param[in] evtRef the event reference
-//!
-//! @note
-//! The application code should not call this function directly.
-//! The only allowed use is thorough the macro Q_DELETE_REF().
-void deleteRef_(QEvt const * const evtRef) noexcept;
-
-//${QF::QF-dyn::getPoolMin} ..................................................
-//! This function returns the minimum of free entries of the given
-//! event pool
-//!
-//! @details
-//! This function obtains the minimum number of free blocks in the given
-//! event pool since this pool has been initialized by a call to
-//! QP::QF::poolInit().
-//!
-//! @param[in] poolId event pool ID in the range 1..QF::maxPool_, where
-//! QF::maxPool_ is the number of event pools
-//! initialized with the function QF::poolInit().
-//! @returns
-//! the minimum number of unused blocks in the given event pool.
-std::uint_fast16_t getPoolMin(std::uint_fast8_t const poolId) noexcept;
-
-//${QF::QF-dyn::newXfromISR_} ................................................
-#ifdef QF_ISR_API
-//! the "FromISR" variant used in the QP port to "FreeRTOS"
-QEvt * newXfromISR_(
- std::uint_fast16_t const evtSize,
- std::uint_fast16_t const margin,
- enum_t const sig) noexcept;
-#endif // def QF_ISR_API
-
-//${QF::QF-dyn::gcFromISR} ...................................................
-#ifdef QF_ISR_API
-//! the "FromISR" variant used in the QP port to "FreeRTOS"
-void gcFromISR(QEvt const * e) noexcept;
-#endif // def QF_ISR_API
-
-} // namespace QF
-} // namespace QP
-//$enddecl${QF::QF-dyn} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-//============================================================================
-extern "C" {
-//$declare${QF-extern-C} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-
-//${QF-extern-C::QF_onContextSw} .............................................
-#ifdef QF_ON_CONTEXT_SW
-//! QF context switch callback used in built-in kernels
-//!
-//! @details
-//! This callback function provides a mechanism to perform additional
-//! custom operations when one of the built-in kernels switches context
-//! from one thread to another.
-//!
-//! @param[in] prev pointer to the previous thread (active object)
-//! (prev==0 means that `prev` was the QK idle loop)
-//! @param[in] next pointer to the next thread (active object)
-//! (next==0) means that `next` is the QK idle loop)
-//! @attention
-//! QF_onContextSw() is invoked with interrupts **disabled** and must also
-//! return with interrupts **disabled**.
-//!
-//! @note
-//! This callback is enabled by defining the macro #QF_ON_CONTEXT_SW.
-//!
-//! @include qf_oncontextsw.cpp
-void QF_onContextSw(
- QP::QActive * prev,
- QP::QActive * next);
-#endif // def QF_ON_CONTEXT_SW
-//$enddecl${QF-extern-C} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-} // extern "C"
-
-//============================================================================
-// Global namespace...
-//$declare${QF-macros} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-
-//${QF-macros::Q_PRIO} .......................................................
-//! Create a QP::QPrioSpec object to specify priority of an AO or a thread
-#define Q_PRIO(prio_, pthre_) (static_cast((prio_) | (pthre_) << 8U))
-
-//${QF-macros::Q_NEW} ........................................................
-#ifndef Q_EVT_CTOR
-//! Allocate a dynamic event (case when QP::QEvt is a POD)
-//!
-//! @details
-//! The macro calls the internal QF function QF::newX_() with
-//! margin == QF::NO_MARGIN, which causes an assertion when the event
-//! cannot be successfully allocated.
-//!
-//! @param[in] evtT_ event type (class name) of the event to allocate
-//! @param[in] sig_ signal to assign to the newly allocated event
-//!
-//! @returns a valid event pointer cast to the type `evtT_`.
-//!
-//! @note
-//! If #Q_EVT_CTOR is defined, the Q_NEW() macro becomes variadic and
-//! takes all the arguments needed by the constructor of the event
-//! class being allocated. The constructor is then called by means
-//! of the placement-new operator.
-//!
-//! @usage
-//! The following example illustrates dynamic allocation of an event:
-//! @include qf_post.cpp
-#define Q_NEW(evtT_, sig_) (static_cast( \
- QP::QF::newX_(sizeof(evtT_), QP::QF::NO_MARGIN, (sig_))))
-#endif // ndef Q_EVT_CTOR
-
-//${QF-macros::Q_NEW} ........................................................
-#ifdef Q_EVT_CTOR
-//! Allocate a dynamic event (case when QP::QEvt is not a POD)
-#define Q_NEW(evtT_, sig_, ...) \
- (new(QP::QF::newX_(sizeof(evtT_), QP::QF::NO_MARGIN, (sig_))) \
- evtT_((sig_), ##__VA_ARGS__))
-#endif // def Q_EVT_CTOR
-
-//${QF-macros::Q_NEW_X} ......................................................
-#ifndef Q_EVT_CTOR
-//! Non-asserting allocate a dynamic event (case when QP::QEvt is a POD).
-//!
-//! @details
-//! This macro allocates a new event and sets the pointer `e_`, while
-//! leaving at least `margin_` of events still available in the pool
-//!
-//! @param[out] e_ pointer to the newly allocated event
-//! @param[in] evtT_ event type (class name) of the event to allocate
-//! @param[in] margin_ number of events that must remain available
-//! in the given pool after this allocation. The
-//! special value QF::NO_MARGIN causes asserting
-//! failure in case event allocation fails.
-//! @param[in] sig_ signal to assign to the newly allocated event
-//!
-//! @returns an event pointer cast to the type `evtT_` or NULL if the
-//! event cannot be allocated with the specified `margin`.
-//!
-//! @note
-//! If #Q_EVT_CTOR is defined, the Q_NEW_X() macro becomes variadic and
-//! takes all the arguments needed by the constructor of the event
-//! class being allocated. The constructor is then called by means
-//! of the placement-new operator.
-//!
-//! @usage
-//! The following example illustrates dynamic allocation of an event:
-//! @include qf_postx.cpp
-#define Q_NEW_X(e_, evtT_, margin_, sig_) \
- ((e_) = static_cast(QP::QF::newX_( \
- sizeof(evtT_), (margin_), (sig_))))
-#endif // ndef Q_EVT_CTOR
-
-//${QF-macros::Q_NEW_X} ......................................................
-#ifdef Q_EVT_CTOR
-//! Non-asserting allocate a dynamic event
-//! (case when QP::QEvt is not a POD)
-#define Q_NEW_X(e_, evtT_, margin_, sig_, ...) do { \
- (e_) = static_cast( \
- QP::QF::newX_(sizeof(evtT_), (margin_), (sig_))); \
- if ((e_) != nullptr) { \
- new((e_)) evtT_((sig_), ##__VA_ARGS__); \
- } \
-} while (false)
-#endif // def Q_EVT_CTOR
-
-//${QF-macros::Q_NEW_REF} ....................................................
-//! Create a new reference of the current event `e`
-//!
-//! @details
-//! The current event processed by an active object is available only for
-//! the duration of the run-to-completion (RTC) step. After that step, the
-//! current event is no longer available and the framework might recycle
-//! (garbage-collect) the event. The macro Q_NEW_REF() explicitly creates
-//! a new reference to the current event that can be stored and used beyond
-//! the current RTC step, until the reference is explicitly recycled by
-//! means of the macro Q_DELETE_REF().
-//!
-//! @param[in,out] evtRef_ event reference to create
-//! @param[in] evtT_ event type (class name) of the event reference
-//!
-//! @usage
-//! The example **defer** in the directory `examples/win32/defer` illustrates
-//! the use of Q_NEW_REF()
-//!
-//! @sa Q_DELETE_REF()
-#define Q_NEW_REF(evtRef_, evtT_) \
- ((evtRef_) = static_cast(QP::QF::newRef_(e, (evtRef_))))
-
-//${QF-macros::Q_DELETE_REF} .................................................
-//! Delete the event reference
-//!
-//! @details
-//! Every event reference created with the macro Q_NEW_REF() needs to be
-//! eventually deleted by means of the macro Q_DELETE_REF() to avoid leaking
-//! the event.
-//!
-//! @param[in,out] evtRef_ event reference to delete
-//!
-//! @usage
-//! The example **defer** in the directory `examples/win32/defer` illustrates
-//! the use of Q_DELETE_REF()
-//!
-//! @sa Q_NEW_REF()
-#define Q_DELETE_REF(evtRef_) do { \
- QP::QF::deleteRef_((evtRef_)); \
- (evtRef_) = 0U; \
-} while (false)
-
-//${QF-macros::PUBLISH} ......................................................
-#ifdef Q_SPY
-//! Invoke the event publishing facility QActive::publish_().
-//!
-//! @details
-//! This macro is the recommended way of publishing events, because it
-//! provides the vital information for software tracing and avoids any
-//! overhead when the tracing is disabled.
-//!
-//! @param[in] e_ pointer to the posted event
-//! @param[in] sender_ pointer to the sender object (actually used
-//! only when #Q_SPY is defined)
-//!
-//! @note
-//! The pointer to the `sender_` object is not necessarily a pointer
-//! to an active object. In fact, if QActive::PUBLISH() is called from an
-//! interrupt or other context, you can create a unique object just to
-//! unambiguously identify the sender of the event.
-//!
-//! @sa QActive::publish_()
-#define PUBLISH(e_, sender_) \
- publish_((e_), (sender_), (sender_)->getPrio())
-#endif // def Q_SPY
-
-//${QF-macros::PUBLISH} ......................................................
-#ifndef Q_SPY
-#define PUBLISH(e_, dummy) publish_((e_), nullptr, 0U)
-#endif // ndef Q_SPY
-
-//${QF-macros::POST} .........................................................
-#ifdef Q_SPY
-//! Invoke the direct event posting facility QActive::post_()
-//!
-//! @details
-//! This macro asserts if the queue overflows and cannot accept the event.
-//!
-//! @param[in] e_ pointer to the event to post
-//! @param[in] sender_ pointer to the sender object.
-//!
-//! @note
-//! The `sendedr_` parameter is actually only used when QS tracing
-//! is enabled (macro #Q_SPY is defined). When QS software tracing is
-//! disenabled, the POST() macro does not pass the `sender_` parameter,
-//1 so the overhead of passing this extra parameter is entirely avoided.
-//!
-//! @note
-//! the pointer to the sender object is not necessarily a pointer to an
-//! active object. In fact, if POST() is called from an interrupt or
-//! other context, you can create a unique object just to unambiguously
-//! identify the sender of the event.
-//!
-//! @sa QActive::post_()
-#define POST(e_, sender_) post_((e_), QP::QF::NO_MARGIN, (sender_))
-#endif // def Q_SPY
-
-//${QF-macros::POST} .........................................................
-#ifndef Q_SPY
-#define POST(e_, dummy) post_((e_), QP::QF::NO_MARGIN, nullptr)
-#endif // ndef Q_SPY
-
-//${QF-macros::POST_X} .......................................................
-#ifdef Q_SPY
-//! Invoke the direct event posting facility QActive::post_()
-//! without delivery guarantee
-//!
-//! @details
-//! This macro does not assert if the queue overflows and cannot accept
-//! the event with the specified margin of free slots remaining.
-//!
-//! @param[in] e_ pointer to the event to post
-//! @param[in] margin_ the minimum free slots in the queue, which
-//! must still be available after posting the event.
-//! The special value QF::NO_MARGIN causes
-//! asserting failure in case event posting fails.
-//! @param[in] sender_ pointer to the sender object.
-//!
-//! @returns
-//! 'true' if the posting succeeded, and 'false' if the posting
-//! failed due to insufficient margin of free entries available in
-//! the queue.
-//!
-//! @note
-//! The `sender_` parameter is actually only used when QS tracing
-//! is enabled (macro #Q_SPY is defined). When QS software tracing is
-//! disabled, the POST_X() macro does not pass the `sender_` parameter,
-//! so the overhead of passing this extra parameter is entirely avoided.
-//!
-//! @note
-//! The pointer to the sender object is not necessarily a pointer
-//! to an active object. In fact, if POST_X() is called from an
-//! interrupt or other context, you can create a unique object just to
-//! unambiguously identify the sender of the event.
-//!
-//! @usage
-//! @include qf_postx.cpp
-#define POST_X(e_, margin_, sender_) \
- post_((e_), (margin_), (sender_))
-#endif // def Q_SPY
-
-//${QF-macros::POST_X} .......................................................
-#ifndef Q_SPY
-#define POST_X(e_, margin_, dummy) post_((e_), (margin_), nullptr)
-#endif // ndef Q_SPY
-
-//${QF-macros::TICK_X} .......................................................
-#ifdef Q_SPY
-//! Invoke the system clock tick processing QTimeEvt::tick_()
-//!
-//! @details
-//! This macro is the recommended way of invoking clock tick processing,
-//! because it provides the vital information for software tracing and
-//! avoids any overhead when the tracing is disabled.
-//!
-//! @param[in] tickRate_ clock tick rate to be serviced through this call
-//! @param[in] sender_ pointer to the sender object. This parameter
-//! is actually only used when QS software tracing is enabled
-//! (macro #Q_SPY is defined)
-//! @note
-//! When QS software tracing is disabled, the macro calls
-//! QTimeEvt::tick_() without the `sender` parameter, so the overhead
-//! of passing this extra parameter is entirely avoided.
-//!
-//! @note
-//! The pointer to the sender object is not necessarily a pointer
-//! to an active object. In fact, when TICK_X() is called from
-//! an interrupt, you would create a unique object just to unambiguously
-//! identify the ISR as the sender of the time events.
-//!
-//! @sa QTimeEvt::tick_()
-#define TICK_X(tickRate_, sender_) tick_((tickRate_), (sender_))
-#endif // def Q_SPY
-
-//${QF-macros::TICK_X} .......................................................
-#ifndef Q_SPY
-#define TICK_X(tickRate_, dummy) tick_((tickRate_), nullptr)
-#endif // ndef Q_SPY
-
-//${QF-macros::TICK} .........................................................
-//! Invoke the system clock tick processing for rate 0
-//! @sa TICK_X()
-#define TICK(sender_) TICK_X(0U, (sender_))
-
-//${QF-macros::QF_CRIT_EXIT_NOP} .............................................
-#ifndef QF_CRIT_EXIT_NOP
-//! No-operation for exiting a critical section
-//!
-//! @details
-//! In some QF ports the critical section exit takes effect only on the
-//! next machine instruction. If this next instruction is another entry
-//! to a critical section, the critical section won't be really exited,
-//! but rather the two adjecent critical sections would be merged.
-//! The QF_CRIT_EXIT_NOP() macro contains minimal code required to
-//! prevent such merging of critical sections in such merging of
-//! critical sections in QF ports, in which it can occur.
-#define QF_CRIT_EXIT_NOP() (static_cast(0))
-#endif // ndef QF_CRIT_EXIT_NOP
-//$enddecl${QF-macros} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-#endif // QF_HPP_
diff --git a/src/qf_act.cpp b/src/qf_act.cpp
index bf98f6f..60e67a5 100644
--- a/src/qf_act.cpp
+++ b/src/qf_act.cpp
@@ -1,45 +1,112 @@
-//$file${src::qf::qf_act.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+//============================================================================
+// QP/C++ Real-Time Embedded Framework (RTEF)
+// Version 8.0.2
//
-// Model: qpcpp.qm
-// File: ${src::qf::qf_act.cpp}
+// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved.
//
-// This code has been generated by QM 5.2.5 .
-// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
-//
-// This code is covered by the following QP license:
-// License # : LicenseRef-QL-dual
-// Issued to : Any user of the QP/C++ real-time embedded framework
-// Framework(s) : qpcpp
-// Support ends : 2023-12-31
-// License scope:
-//
-// Copyright (C) 2005 Quantum Leaps, LLC .
+// Q u a n t u m L e a P s
+// ------------------------
+// Modern Embedded Software
//
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
//
-// This software is dual-licensed under the terms of the open source GNU
-// General Public License version 3 (or any later version), or alternatively,
-// under the terms of one of the closed source Quantum Leaps commercial
-// licenses.
-//
-// The terms of the open source GNU General Public License version 3
-// can be found at:
-//
-// The terms of the closed source Quantum Leaps commercial licenses
-// can be found at:
+// This software is dual-licensed under the terms of the open-source GNU
+// General Public License (GPL) or under the terms of one of the closed-
+// source Quantum Leaps commercial licenses.
//
// Redistributions in source code must retain this top-level comment block.
// Plagiarizing this software to sidestep the license obligations is illegal.
//
-// Contact information:
+// NOTE:
+// The GPL does NOT permit the incorporation of this code into proprietary
+// programs. Please contact Quantum Leaps for commercial licensing options,
+// which expressly supersede the GPL and are designed explicitly for
+// closed-source distribution.
+//
+// Quantum Leaps contact information:
//
//
-//
-//$endhead${src::qf::qf_act.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//! @file
-//! @deprecated
-//! Empty file kept only for backwards compatibility.
-//! @sa qf_qact.cpp
-
-extern char const dummy; // declaration
-char const dummy = '\0'; // definition
+//============================================================================
+#define QP_IMPL // this is QP implementation
+#include "qp_port.hpp" // QP port
+#include "qp_pkg.hpp" // QP package-scope interface
+#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
+#ifdef Q_SPY // QS software tracing enabled?
+ #include "qs_port.hpp" // QS port
+ #include "qs_pkg.hpp" // QS facilities for pre-defined trace records
+#else
+ #include "qs_dummy.hpp" // disable the QS software tracing
+#endif // Q_SPY
+
+// unnamed namespace for local definitions with internal linkage
+namespace {
+//Q_DEFINE_THIS_MODULE("qf_act")
+} // unnamed namespace
+
+namespace QP {
+
+// QP version string embedded in the binary image
+char const versionStr[] = "QP/C++ " QP_VERSION_STR;
+
+QActive * QActive::registry_[QF_MAX_ACTIVE + 1U];
+
+namespace QF {
+
+QF::Attr priv_;
+
+void bzero_(
+ void * const start,
+ std::uint_fast16_t const len) noexcept
+{
+ std::uint8_t *ptr = static_cast(start);
+ for (std::uint_fast16_t n = len; n > 0U; --n) {
+ *ptr = 0U;
+ ++ptr;
+ }
+}
+
+} // namespace QF
+
+//............................................................................
+#ifndef QF_LOG2
+std::uint_fast8_t QF_LOG2(QP::QPSetBits const bitmask) noexcept {
+ static constexpr std::uint8_t log2LUT[16] = {
+ 0U, 1U, 2U, 2U, 3U, 3U, 3U, 3U,
+ 4U, 4U, 4U, 4U, 4U, 4U, 4U, 4U
+ };
+ std::uint_fast8_t n = 0U;
+ QP::QPSetBits x = bitmask;
+ QP::QPSetBits tmp;
+
+#if (QF_MAX_ACTIVE > 16U)
+ tmp = static_cast(x >> 16U);
+ if (tmp != 0U) {
+ n += 16U;
+ x = tmp;
+ }
+#endif
+#if (QF_MAX_ACTIVE > 8U)
+ tmp = (x >> 8U);
+ if (tmp != 0U) {
+ n += 8U;
+ x = tmp;
+ }
+#endif
+ tmp = (x >> 4U);
+ if (tmp != 0U) {
+ n += 4U;
+ x = tmp;
+ }
+ return n + log2LUT[x];
+}
+#endif // ndef QF_LOG2
+
+//............................................................................
+#ifndef Q_UNSAFE
+QPtrDis::QPtrDis(void const * const ptr) noexcept
+ : m_ptr_dis(static_cast(~Q_PTR2UINT_CAST_(ptr)))
+{}
+#endif
+
+} // namespace QP
+
diff --git a/src/qf_actq.cpp b/src/qf_actq.cpp
deleted file mode 100644
index daa48a8..0000000
--- a/src/qf_actq.cpp
+++ /dev/null
@@ -1,437 +0,0 @@
-//$file${src::qf::qf_actq.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-//
-// Model: qpcpp.qm
-// File: ${src::qf::qf_actq.cpp}
-//
-// This code has been generated by QM 5.2.5 .
-// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
-//
-// This code is covered by the following QP license:
-// License # : LicenseRef-QL-dual
-// Issued to : Any user of the QP/C++ real-time embedded framework
-// Framework(s) : qpcpp
-// Support ends : 2023-12-31
-// License scope:
-//
-// Copyright (C) 2005 Quantum Leaps, LLC .
-//
-// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
-//
-// This software is dual-licensed under the terms of the open source GNU
-// General Public License version 3 (or any later version), or alternatively,
-// under the terms of one of the closed source Quantum Leaps commercial
-// licenses.
-//
-// The terms of the open source GNU General Public License version 3
-// can be found at:
-//
-// The terms of the closed source Quantum Leaps commercial licenses
-// can be found at:
-//
-// Redistributions in source code must retain this top-level comment block.
-// Plagiarizing this software to sidestep the license obligations is illegal.
-//
-// Contact information:
-//
-//
-//
-//$endhead${src::qf::qf_actq.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//! @file
-//! @brief QP::QActive native queue operations (based on QP::QEQueue)
-//!
-//! @attention
-//! This qf_actq.cpp source file is only included in the build when the
-//! macro #QF_EQUEUE_TYPE is defined as QEQueue. This means that the QP
-//! port uses the QP::QEQueue for active objects and so this implementation
-//! applies to the QP port.
-
-#define QP_IMPL // this is QP implementation
-#include "qf_port.hpp" // QF port
-#include "qf_pkg.hpp" // QF package-scope interface
-#include "qassert.h" // QP embedded systems-friendly assertions
-#ifdef Q_SPY // QS software tracing enabled?
- #include "qs_port.hpp" // QS port
- #include "qs_pkg.hpp" // QS facilities for pre-defined trace records
-#else
- #include "qs_dummy.hpp" // disable the QS software tracing
-#endif // Q_SPY
-
-//============================================================================
-// unnamed namespace for local definitions with internal linkage
-namespace {
-Q_DEFINE_THIS_MODULE("qf_actq")
-} // unnamed namespace
-
-//============================================================================
-//$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-// Check for the minimum required QP version
-#if (QP_VERSION < 700U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U))
-#error qpcpp version 7.0.0 or higher required
-#endif
-//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-//$define${QF::QActive::post_} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-namespace QP {
-
-//${QF::QActive::post_} ......................................................
-bool QActive::post_(
- QEvt const * const e,
- std::uint_fast16_t const margin,
- void const * const sender) noexcept
-{
- Q_UNUSED_PAR(sender); // when Q_SPY not defined
-
- //! @pre event pointer must be valid
- Q_REQUIRE_ID(100, e != nullptr);
-
- QF_CRIT_STAT_
- QF_CRIT_E_();
- QEQueueCtr nFree = m_eQueue.m_nFree; // get into the temporary
-
- // test-probe#1 for faking queue overflow
- QS_TEST_PROBE_DEF(&QActive::post_)
- QS_TEST_PROBE_ID(1,
- nFree = 0U;
- )
-
- bool status;
- if (margin == QF::NO_MARGIN) {
- if (nFree > 0U) {
- status = true; // can post
- }
- else {
- status = false; // cannot post
- Q_ERROR_CRIT_(110); // must be able to post the event
- }
- }
- else if (nFree > static_cast(margin)) {
- status = true; // can post
- }
- else {
- status = false; // cannot post, but don't assert
- }
-
- // is it a dynamic event?
- if (e->poolId_ != 0U) {
- QEvt_refCtr_inc_(e); // increment the reference counter
- }
-
- if (status) { // can post the event?
-
- --nFree; // one free entry just used up
- m_eQueue.m_nFree = nFree; // update the original
- if (m_eQueue.m_nMin > nFree) {
- m_eQueue.m_nMin = nFree; // update minimum so far
- }
-
- QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_POST, m_prio)
- QS_TIME_PRE_(); // timestamp
- QS_OBJ_PRE_(sender); // the sender object
- QS_SIG_PRE_(e->sig); // the signal of the event
- QS_OBJ_PRE_(this); // this active object
- QS_2U8_PRE_(e->poolId_, e->refCtr_); // pool-Id & ref-ctr
- QS_EQC_PRE_(nFree); // number of free entries
- QS_EQC_PRE_(m_eQueue.m_nMin); // min number of free entries
- QS_END_NOCRIT_PRE_()
-
- #ifdef Q_UTEST
- // callback to examine the posted event under the same conditions
- // as producing the #QS_QF_ACTIVE_POST trace record, which are:
- // the local filter for this AO ('me->prio') is set
- //
- if (QS_LOC_CHECK_(m_prio)) {
- QS::onTestPost(sender, this, e, status);
- }
- #endif
- // empty queue?
- if (m_eQueue.m_frontEvt == nullptr) {
- m_eQueue.m_frontEvt = e; // deliver event directly
- QACTIVE_EQUEUE_SIGNAL_(this); // signal the event queue
- }
- // queue is not empty, insert event into the ring-buffer
- else {
- // insert event pointer e into the buffer (FIFO)
- m_eQueue.m_ring[m_eQueue.m_head] = e;
-
- // need to wrap head?
- if (m_eQueue.m_head == 0U) {
- m_eQueue.m_head = m_eQueue.m_end; // wrap around
- }
- // advance the head (counter clockwise)
- m_eQueue.m_head = (m_eQueue.m_head - 1U);
- }
-
- QF_CRIT_X_();
- }
- else { // cannot post the event
-
- QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_POST_ATTEMPT, m_prio)
- QS_TIME_PRE_(); // timestamp
- QS_OBJ_PRE_(sender); // the sender object
- QS_SIG_PRE_(e->sig); // the signal of the event
- QS_OBJ_PRE_(this); // this active object
- QS_2U8_PRE_(e->poolId_, e->refCtr_); // pool-Id & ref-ctr
- QS_EQC_PRE_(nFree); // number of free entries
- QS_EQC_PRE_(margin); // margin requested
- QS_END_NOCRIT_PRE_()
-
- #ifdef Q_UTEST
- // callback to examine the posted event under the same conditions
- // as producing the #QS_QF_ACTIVE_POST trace record, which are:
- // the local filter for this AO ('me->prio') is set
- //
- if (QS_LOC_CHECK_(m_prio)) {
- QS::onTestPost(sender, this, e, status);
- }
- #endif
-
- QF_CRIT_X_();
-
- #if (QF_MAX_EPOOL > 0U)
- QF::gc(e); // recycle the event to avoid a leak
- #endif
- }
-
- return status;
-}
-
-} // namespace QP
-//$enddef${QF::QActive::post_} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//$define${QF::QActive::postLIFO} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-namespace QP {
-
-//${QF::QActive::postLIFO} ...................................................
-void QActive::postLIFO(QEvt const * const e) noexcept {
- QF_CRIT_STAT_
- QF_CRIT_E_();
- QEQueueCtr nFree = m_eQueue.m_nFree;
-
- QS_TEST_PROBE_DEF(&QActive::postLIFO)
- QS_TEST_PROBE_ID(1,
- nFree = 0U;
- )
-
- // the queue must be able to accept the event (cannot overflow)
- Q_ASSERT_CRIT_(210, nFree != 0U);
-
- // is it a dynamic event?
- if (e->poolId_ != 0U) {
- QEvt_refCtr_inc_(e); // increment the reference counter
- }
-
- --nFree; // one free entry just used up
- m_eQueue.m_nFree = nFree; // update the original
- if (m_eQueue.m_nMin > nFree) {
- m_eQueue.m_nMin = nFree; // update minimum so far
- }
-
- QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_POST_LIFO, m_prio)
- QS_TIME_PRE_(); // timestamp
- QS_SIG_PRE_(e->sig); // the signal of this event
- QS_OBJ_PRE_(this); // this active object
- QS_2U8_PRE_(e->poolId_, e->refCtr_); // pool-Id & ref-ctr
- QS_EQC_PRE_(nFree); // number of free entries
- QS_EQC_PRE_(m_eQueue.m_nMin); // min number of free entries
- QS_END_NOCRIT_PRE_()
-
- #ifdef Q_UTEST
- // callback to examine the posted event under the same conditions
- // as producing the #QS_QF_ACTIVE_POST trace record, which are:
- // the local filter for this AO ('me->prio') is set
- //
- if (QS_LOC_CHECK_(m_prio)) {
- QS::onTestPost(nullptr, this, e, true);
- }
- #endif
-
- QEvt const * const frontEvt = m_eQueue.m_frontEvt;
- m_eQueue.m_frontEvt = e; // deliver the event directly to the front
-
- // was the queue empty?
- if (frontEvt == nullptr) {
- QACTIVE_EQUEUE_SIGNAL_(this); // signal the event queue
- }
- // queue was not empty, leave the event in the ring-buffer
- else {
- m_eQueue.m_tail = (m_eQueue.m_tail + 1U);
- if (m_eQueue.m_tail == m_eQueue.m_end) { // need to wrap the tail?
- m_eQueue.m_tail = 0U; // wrap around
- }
-
- m_eQueue.m_ring[m_eQueue.m_tail] = frontEvt;
- }
- QF_CRIT_X_();
-
-}
-
-} // namespace QP
-//$enddef${QF::QActive::postLIFO} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//$define${QF::QActive::get_} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-namespace QP {
-
-//${QF::QActive::get_} .......................................................
-QEvt const * QActive::get_() noexcept {
- QF_CRIT_STAT_
- QF_CRIT_E_();
- QACTIVE_EQUEUE_WAIT_(this); // wait for event to arrive directly
-
- // always remove evt from the front
- QEvt const * const e = m_eQueue.m_frontEvt;
- QEQueueCtr const nFree = m_eQueue.m_nFree + 1U;
- m_eQueue.m_nFree = nFree; // upate the number of free
-
- // any events in the ring buffer?
- if (nFree <= m_eQueue.m_end) {
-
- // remove event from the tail
- m_eQueue.m_frontEvt = m_eQueue.m_ring[m_eQueue.m_tail];
- if (m_eQueue.m_tail == 0U) { // need to wrap?
- m_eQueue.m_tail = m_eQueue.m_end; // wrap around
- }
- m_eQueue.m_tail = (m_eQueue.m_tail - 1U);
-
- QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_GET, m_prio)
- QS_TIME_PRE_(); // timestamp
- QS_SIG_PRE_(e->sig); // the signal of this event
- QS_OBJ_PRE_(this); // this active object
- QS_2U8_PRE_(e->poolId_, e->refCtr_); // pool-Id & ref-ctr
- QS_EQC_PRE_(nFree); // number of free entries
- QS_END_NOCRIT_PRE_()
- }
- else {
- // the queue becomes empty
- m_eQueue.m_frontEvt = nullptr;
-
- // all entries in the queue must be free (+1 for fronEvt)
- Q_ASSERT_CRIT_(310, nFree == (m_eQueue.m_end + 1U));
-
- QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_GET_LAST, m_prio)
- QS_TIME_PRE_(); // timestamp
- QS_SIG_PRE_(e->sig); // the signal of this event
- QS_OBJ_PRE_(this); // this active object
- QS_2U8_PRE_(e->poolId_, e->refCtr_); // pool-Id & ref-ctr
- QS_END_NOCRIT_PRE_()
- }
- QF_CRIT_X_();
- return e;
-}
-
-} // namespace QP
-//$enddef${QF::QActive::get_} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-//$define${QF::QF-base::getQueueMin} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-namespace QP {
-namespace QF {
-
-//${QF::QF-base::getQueueMin} ................................................
-std::uint_fast16_t getQueueMin(std::uint_fast8_t const prio) noexcept {
- Q_REQUIRE_ID(400, (prio <= QF_MAX_ACTIVE)
- && (QActive::registry_[prio] != nullptr));
- QF_CRIT_STAT_
- QF_CRIT_E_();
- std::uint_fast16_t const min = static_cast(
- QActive::registry_[prio]->m_eQueue.getNMin());
- QF_CRIT_X_();
-
- return min;
-}
-
-} // namespace QF
-} // namespace QP
-//$enddef${QF::QF-base::getQueueMin} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-//============================================================================
-//$define${QF::QTicker} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-namespace QP {
-
-//${QF::QTicker} .............................................................
-
-//${QF::QTicker::QTicker} ....................................................
-QTicker::QTicker(std::uint_fast8_t const tickRate) noexcept
-: QActive(nullptr)
-{
- // reuse m_head for tick-rate
- m_eQueue.m_head = static_cast(tickRate);
-}
-
-//${QF::QTicker::init} .......................................................
-void QTicker::init(
- void const * const e,
- std::uint_fast8_t const qs_id)
-{
- Q_UNUSED_PAR(e);
- Q_UNUSED_PAR(qs_id);
- m_eQueue.m_tail = 0U;
-}
-
-//${QF::QTicker::init} .......................................................
-void QTicker::init(std::uint_fast8_t const qs_id) {
- QTicker::init(nullptr, qs_id);
-}
-
-//${QF::QTicker::dispatch} ...................................................
-void QTicker::dispatch(
- QEvt const * const e,
- std::uint_fast8_t const qs_id)
-{
- Q_UNUSED_PAR(e);
- Q_UNUSED_PAR(qs_id);
-
- QF_CRIT_STAT_
- QF_CRIT_E_();
- QEQueueCtr nTicks = m_eQueue.m_tail; // # ticks since the last call
- m_eQueue.m_tail = 0U; // clear the # ticks
- QF_CRIT_X_();
-
- for (; nTicks > 0U; --nTicks) {
- QTimeEvt::TICK_X(static_cast(m_eQueue.m_head),
- this);
- }
-}
-
-//${QF::QTicker::post_} ......................................................
-bool QTicker::post_(
- QEvt const * const e,
- std::uint_fast16_t const margin,
- void const * const sender) noexcept
-{
- Q_UNUSED_PAR(e);
- Q_UNUSED_PAR(margin);
- Q_UNUSED_PAR(sender); // when Q_SPY not defined
-
- QF_CRIT_STAT_
- QF_CRIT_E_();
- if (m_eQueue.m_frontEvt == nullptr) {
-
- #ifdef Q_EVT_CTOR
- static QEvt const tickEvt(0U, 0U);
- #else
- static QEvt const tickEvt = { 0U, 0U, 0U };
- #endif // Q_EVT_CTOR
-
- m_eQueue.m_frontEvt = &tickEvt; // deliver event directly
- m_eQueue.m_nFree = (m_eQueue.m_nFree - 1U); // one less free event
-
- QACTIVE_EQUEUE_SIGNAL_(this); // signal the event queue
- }
-
- // account for one more tick event
- m_eQueue.m_tail = (m_eQueue.m_tail + 1U);
-
- QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_POST, m_prio)
- QS_TIME_PRE_(); // timestamp
- QS_OBJ_PRE_(sender); // the sender object
- QS_SIG_PRE_(0U); // the signal of the event
- QS_OBJ_PRE_(this); // this active object
- QS_2U8_PRE_(0U, 0U); // pool-Id & ref-ctr
- QS_EQC_PRE_(0U); // number of free entries
- QS_EQC_PRE_(0U); // min number of free entries
- QS_END_NOCRIT_PRE_()
-
- QF_CRIT_X_();
-
- return true; // the event is always posted correctly
-}
-
-} // namespace QP
-//$enddef${QF::QTicker} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/qf_defer.cpp b/src/qf_defer.cpp
index 189731e..75eae08 100644
--- a/src/qf_defer.cpp
+++ b/src/qf_defer.cpp
@@ -1,49 +1,36 @@
-//$file${src::qf::qf_defer.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+//============================================================================
+// QP/C++ Real-Time Embedded Framework (RTEF)
+// Version 8.0.2
//
-// Model: qpcpp.qm
-// File: ${src::qf::qf_defer.cpp}
+// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved.
//
-// This code has been generated by QM 5.2.5 .
-// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
-//
-// This code is covered by the following QP license:
-// License # : LicenseRef-QL-dual
-// Issued to : Any user of the QP/C++ real-time embedded framework
-// Framework(s) : qpcpp
-// Support ends : 2023-12-31
-// License scope:
-//
-// Copyright (C) 2005 Quantum Leaps, LLC .
+// Q u a n t u m L e a P s
+// ------------------------
+// Modern Embedded Software
//
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
//
-// This software is dual-licensed under the terms of the open source GNU
-// General Public License version 3 (or any later version), or alternatively,
-// under the terms of one of the closed source Quantum Leaps commercial
-// licenses.
-//
-// The terms of the open source GNU General Public License version 3
-// can be found at:
-//
-// The terms of the closed source Quantum Leaps commercial licenses
-// can be found at:
+// This software is dual-licensed under the terms of the open-source GNU
+// General Public License (GPL) or under the terms of one of the closed-
+// source Quantum Leaps commercial licenses.
//
// Redistributions in source code must retain this top-level comment block.
// Plagiarizing this software to sidestep the license obligations is illegal.
//
-// Contact information:
+// NOTE:
+// The GPL does NOT permit the incorporation of this code into proprietary
+// programs. Please contact Quantum Leaps for commercial licensing options,
+// which expressly supersede the GPL and are designed explicitly for
+// closed-source distribution.
+//
+// Quantum Leaps contact information:
//
//
-//
-//$endhead${src::qf::qf_defer.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//! @file
-//! @brief QActive::defer(), QActive::recall(), and
-//! QActive::flushDeferred() definitions.
-
+//============================================================================
#define QP_IMPL // this is QP implementation
-#include "qf_port.hpp" // QF port
-#include "qf_pkg.hpp" // QF package-scope interface
-#include "qassert.h" // QP embedded systems-friendly assertions
+#include "qp_port.hpp" // QP port
+#include "qp_pkg.hpp" // QP package-scope interface
+#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
#ifdef Q_SPY // QS software tracing enabled?
#include "qs_port.hpp" // QS port
#include "qs_pkg.hpp" // QS facilities for pre-defined trace records
@@ -56,111 +43,101 @@ namespace {
Q_DEFINE_THIS_MODULE("qf_defer")
} // unnamed namespace
-//$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-// Check for the minimum required QP version
-#if (QP_VERSION < 700U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U))
-#error qpcpp version 7.0.0 or higher required
-#endif
-//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-//$define${QF::QActive::defer} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
namespace QP {
-//${QF::QActive::defer} ......................................................
+//............................................................................
bool QActive::defer(
QEQueue * const eq,
QEvt const * const e) const noexcept
{
bool const status = eq->post(e, 0U, m_prio);
- QS_CRIT_STAT_
- QS_BEGIN_PRE_(QS_QF_ACTIVE_DEFER, m_prio)
- QS_TIME_PRE_(); // time stamp
- QS_OBJ_PRE_(this); // this active object
- QS_OBJ_PRE_(eq); // the deferred queue
- QS_SIG_PRE_(e->sig); // the signal of the event
- QS_2U8_PRE_(e->poolId_, e->refCtr_); // pool Id & ref Count
- QS_END_PRE_()
+ QS_CRIT_STAT
+ QS_CRIT_ENTRY();
+ QS_BEGIN_PRE(QS_QF_ACTIVE_DEFER, m_prio)
+ QS_TIME_PRE(); // time stamp
+ QS_OBJ_PRE(this); // this active object
+ QS_OBJ_PRE(eq); // the deferred queue
+ QS_SIG_PRE(e->sig); // the signal of the event
+ QS_2U8_PRE(e->poolNum_, e->refCtr_);
+ QS_END_PRE()
+ QS_CRIT_EXIT();
return status;
}
-} // namespace QP
-//$enddef${QF::QActive::defer} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//$define${QF::QActive::recall} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-namespace QP {
-
-//${QF::QActive::recall} .....................................................
+//............................................................................
bool QActive::recall(QEQueue * const eq) noexcept {
QEvt const * const e = eq->get(m_prio); // get evt from deferred queue
- bool recalled;
+ QF_CRIT_STAT
- // event available?
- if (e != nullptr) {
- QActive::postLIFO(e); // post it to the _front_ of the AO's queue
+ bool recalled;
+ if (e != nullptr) { // event available?
+ postLIFO(e); // post it to the _front_ of the AO's queue
- QF_CRIT_STAT_
- QF_CRIT_E_();
+ QF_CRIT_ENTRY();
- // is it a dynamic event?
- if (e->poolId_ != 0U) {
+ if (e->poolNum_ != 0U) { // is it a mutable event?
// after posting to the AO's queue the event must be referenced
// at least twice: once in the deferred event queue (eq->get()
// did NOT decrement the reference counter) and once in the
// AO's event queue.
- Q_ASSERT_CRIT_(210, e->refCtr_ >= 2U);
+ Q_ASSERT_INCRIT(205, e->refCtr_ >= 2U);
// we need to decrement the reference counter once, to account
// for removing the event from the deferred event queue.
QEvt_refCtr_dec_(e); // decrement the reference counter
}
- QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_RECALL, m_prio)
- QS_TIME_PRE_(); // time stamp
- QS_OBJ_PRE_(this); // this active object
- QS_OBJ_PRE_(eq); // the deferred queue
- QS_SIG_PRE_(e->sig); // the signal of the event
- QS_2U8_PRE_(e->poolId_, e->refCtr_); // pool Id & ref Count
- QS_END_NOCRIT_PRE_()
+ QS_BEGIN_PRE(QS_QF_ACTIVE_RECALL, m_prio)
+ QS_TIME_PRE(); // time stamp
+ QS_OBJ_PRE(this); // this active object
+ QS_OBJ_PRE(eq); // the deferred queue
+ QS_SIG_PRE(e->sig); // the signal of the event
+ QS_2U8_PRE(e->poolNum_, e->refCtr_);
+ QS_END_PRE()
+
+ QF_CRIT_EXIT();
- QF_CRIT_X_();
recalled = true;
}
else {
- QS_CRIT_STAT_
+ QS_CRIT_ENTRY();
- QS_BEGIN_PRE_(QS_QF_ACTIVE_RECALL_ATTEMPT, m_prio)
- QS_TIME_PRE_(); // time stamp
- QS_OBJ_PRE_(this); // this active object
- QS_OBJ_PRE_(eq); // the deferred queue
- QS_END_PRE_()
+ QS_BEGIN_PRE(QS_QF_ACTIVE_RECALL_ATTEMPT, m_prio)
+ QS_TIME_PRE(); // time stamp
+ QS_OBJ_PRE(this); // this active object
+ QS_OBJ_PRE(eq); // the deferred queue
+ QS_END_PRE()
+
+ QS_CRIT_EXIT();
recalled = false;
}
return recalled;
-
}
-} // namespace QP
-//$enddef${QF::QActive::recall} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//$define${QF::QActive::flushDeferred} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-namespace QP {
-
-//${QF::QActive::flushDeferred} ..............................................
-std::uint_fast16_t QActive::flushDeferred(QEQueue * const eq) const noexcept {
+//............................................................................
+std::uint_fast16_t QActive::flushDeferred(
+ QEQueue * const eq,
+ std::uint_fast16_t const num) const noexcept
+{
std::uint_fast16_t n = 0U;
- for (QEvt const *e = eq->get(m_prio);
- e != nullptr;
- e = eq->get(m_prio))
- {
- ++n; // count the flushed event
- #if (QF_MAX_EPOOL > 0U)
- QF::gc(e); // garbage collect
- #endif
+ while (n < num) {
+ QEvt const * const e = eq->get(m_prio);
+ if (e != nullptr) {
+ ++n; // count one more flushed event
+#if (QF_MAX_EPOOL > 0U)
+ QF::gc(e); // garbage collect
+#endif
+ }
+ else {
+ break;
+ }
}
+
return n;
}
} // namespace QP
-//$enddef${QF::QActive::flushDeferred} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/qf_dyn.cpp b/src/qf_dyn.cpp
index f7701ae..b064ebb 100644
--- a/src/qf_dyn.cpp
+++ b/src/qf_dyn.cpp
@@ -1,48 +1,36 @@
-//$file${src::qf::qf_dyn.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-//
-// Model: qpcpp.qm
-// File: ${src::qf::qf_dyn.cpp}
-//
-// This code has been generated by QM 5.2.5 .
-// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
+//============================================================================
+// QP/C++ Real-Time Embedded Framework (RTEF)
+// Version 8.0.2
//
-// This code is covered by the following QP license:
-// License # : LicenseRef-QL-dual
-// Issued to : Any user of the QP/C++ real-time embedded framework
-// Framework(s) : qpcpp
-// Support ends : 2023-12-31
-// License scope:
+// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved.
//
-// Copyright (C) 2005 Quantum Leaps, LLC .
+// Q u a n t u m L e a P s
+// ------------------------
+// Modern Embedded Software
//
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
//
-// This software is dual-licensed under the terms of the open source GNU
-// General Public License version 3 (or any later version), or alternatively,
-// under the terms of one of the closed source Quantum Leaps commercial
-// licenses.
-//
-// The terms of the open source GNU General Public License version 3
-// can be found at:
-//
-// The terms of the closed source Quantum Leaps commercial licenses
-// can be found at:
+// This software is dual-licensed under the terms of the open-source GNU
+// General Public License (GPL) or under the terms of one of the closed-
+// source Quantum Leaps commercial licenses.
//
// Redistributions in source code must retain this top-level comment block.
// Plagiarizing this software to sidestep the license obligations is illegal.
//
-// Contact information:
+// NOTE:
+// The GPL does NOT permit the incorporation of this code into proprietary
+// programs. Please contact Quantum Leaps for commercial licensing options,
+// which expressly supersede the GPL and are designed explicitly for
+// closed-source distribution.
+//
+// Quantum Leaps contact information:
//
//
-//
-//$endhead${src::qf::qf_dyn.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//! @file
-//! @brief QF/C++ dynamic event management
-
+//============================================================================
#define QP_IMPL // this is QP implementation
-#include "qf_port.hpp" // QF port
-#include "qf_pkg.hpp" // QF package-scope interface
-#include "qassert.h" // QP embedded systems-friendly assertions
+#include "qp_port.hpp" // QP port
+#include "qp_pkg.hpp" // QP package-scope interface
+#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
#ifdef Q_SPY // QS software tracing enabled?
#include "qs_port.hpp" // QS port
#include "qs_pkg.hpp" // QS facilities for pre-defined trace records
@@ -50,260 +38,270 @@
#include "qs_dummy.hpp" // disable the QS software tracing
#endif // Q_SPY
-#if (QF_MAX_EPOOL > 0U) // dynamic events configured?
+#if (QF_MAX_EPOOL > 0U) // mutable events configured?
// unnamed namespace for local definitions with internal linkage
namespace {
Q_DEFINE_THIS_MODULE("qf_dyn")
} // unnamed namespace
-//============================================================================
-//$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-// Check for the minimum required QP version
-#if (QP_VERSION < 700U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U))
-#error qpcpp version 7.0.0 or higher required
-#endif
-//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-//$define${QF::QF-pkg::maxPool_} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-namespace QP {
-namespace QF {
-
-//${QF::QF-pkg::maxPool_} ....................................................
-std::uint_fast8_t maxPool_;
-
-} // namespace QF
-} // namespace QP
-//$enddef${QF::QF-pkg::maxPool_} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//$define${QF::QF-pkg::ePool_[QF_MAX_EPOOL]} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-namespace QP {
-namespace QF {
-
-//${QF::QF-pkg::ePool_[QF_MAX_EPOOL]} ........................................
-#if (QF_MAX_EPOOL > 0U)
-QF_EPOOL_TYPE_ ePool_[QF_MAX_EPOOL];
-#endif // (QF_MAX_EPOOL > 0U)
-
-} // namespace QF
-} // namespace QP
-//$enddef${QF::QF-pkg::ePool_[QF_MAX_EPOOL]} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-//============================================================================
-//$define${QF::QF-dyn} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
namespace QP {
namespace QF {
-//${QF::QF-dyn::poolInit} ....................................................
+//............................................................................
void poolInit(
void * const poolSto,
std::uint_fast32_t const poolSize,
std::uint_fast16_t const evtSize) noexcept
{
- //! @pre cannot exceed the number of available memory pools
- Q_REQUIRE_ID(200, QF::maxPool_ < QF_MAX_EPOOL);
+ std::uint_fast8_t const poolNum = priv_.maxPool_;
+
+ // see precondition{qf_dyn,200} and precondition{qf_dyn,201}
+ QF_CRIT_STAT
+ QF_CRIT_ENTRY();
- //! @pre QF event pools must be initialized in ascending order of evtSize
- if (QF::maxPool_ > 0U) {
- Q_REQUIRE_ID(201,
- QF_EPOOL_EVENT_SIZE_(QF::ePool_[QF::maxPool_ - 1U]) < evtSize);
+ Q_REQUIRE_INCRIT(100, poolNum < QF_MAX_EPOOL);
+ if (poolNum > 0U) {
+ Q_REQUIRE_INCRIT(110,
+ QF_EPOOL_EVENT_SIZE_(priv_.ePool_[poolNum - 1U]) < evtSize);
}
+ priv_.maxPool_ = poolNum + 1U; // one more pool
- QF_EPOOL_INIT_(QF::ePool_[QF::maxPool_], poolSto, poolSize, evtSize);
- ++QF::maxPool_; // one more pool
+ QF_CRIT_EXIT();
- #ifdef Q_SPY
+ // perform the port-dependent initialization of the event-pool
+ QF_EPOOL_INIT_(priv_.ePool_[poolNum], poolSto, poolSize, evtSize);
+
+#ifdef Q_SPY
// generate the object-dictionary entry for the initialized pool
- char obj_name[9] = "EvtPool?";
- obj_name[7] = static_cast(
- static_cast('0')
- + static_cast(QF::maxPool_));
- QS::obj_dict_pre_(&QF::ePool_[QF::maxPool_ - 1U], &obj_name[0]);
- #endif // Q_SPY
+ {
+ std::uint8_t obj_name[9] = "EvtPool?";
+ obj_name[7] = static_cast(
+ static_cast('0')
+ + static_cast(poolNum + 1U));
+ QS::obj_dict_pre_(&priv_.ePool_[poolNum],
+ reinterpret_cast(&obj_name[0]));
+ }
+#endif // Q_SPY
+}
+
+//............................................................................
+std::uint_fast16_t poolGetMaxBlockSize() noexcept {
+ QF_CRIT_STAT
+ QF_CRIT_ENTRY();
+ std::uint_fast16_t const max_size =
+ QF_EPOOL_EVENT_SIZE_(priv_.ePool_[priv_.maxPool_ - 1U]);
+ QF_CRIT_EXIT();
+
+ return max_size;
+}
+
+//............................................................................
+std::uint_fast16_t getPoolMin(std::uint_fast8_t const poolNum) noexcept {
+ QF_CRIT_STAT
+ QF_CRIT_ENTRY();
+
+ Q_REQUIRE_INCRIT(300, (poolNum <= QF_MAX_EPOOL)
+ && (0U < poolNum) && (poolNum <= priv_.maxPool_));
+
+ std::uint_fast16_t const min = static_cast(
+ priv_.ePool_[poolNum - 1U].getNMin());
+
+ QF_CRIT_EXIT();
+
+ return min;
}
-//${QF::QF-dyn::newX_} .......................................................
+//............................................................................
QEvt * newX_(
std::uint_fast16_t const evtSize,
std::uint_fast16_t const margin,
enum_t const sig) noexcept
{
- std::uint_fast8_t idx;
+ QF_CRIT_STAT
+ QF_CRIT_ENTRY();
- // find the pool id that fits the requested event size ...
- for (idx = 0U; idx < QF::maxPool_; ++idx) {
- if (evtSize <= QF_EPOOL_EVENT_SIZE_(QF::ePool_[idx])) {
+ // find the pool id that fits the requested event size...
+ std::uint8_t poolNum = 0U; // zero-based poolNum initially
+ for (; poolNum < priv_.maxPool_; ++poolNum) {
+ if (evtSize <= QF_EPOOL_EVENT_SIZE_(priv_.ePool_[poolNum])) {
break;
}
}
- // cannot run out of registered pools
- Q_ASSERT_ID(310, idx < QF::maxPool_);
-
- // get e -- platform-dependent
- QEvt *e;
-
- #ifdef Q_SPY
- QF_EPOOL_GET_(QF::ePool_[idx], e, ((margin != QF::NO_MARGIN) ? margin : 0U),
- static_cast(QS_EP_ID) + idx + 1U);
- #else
- QF_EPOOL_GET_(QF::ePool_[idx], e, ((margin != QF::NO_MARGIN) ? margin : 0U),
- 0U);
- #endif
-
- // was e allocated correctly?
- QS_CRIT_STAT_
- if (e != nullptr) {
- e->sig = static_cast(sig); // set the signal
- e->poolId_ = static_cast(idx + 1U); // store pool ID
- e->refCtr_ = 0U; // initialize the reference counter to 0
-
- QS_BEGIN_PRE_(QS_QF_NEW,
- static_cast(QS_EP_ID)
- + static_cast(e->poolId_))
- QS_TIME_PRE_(); // timestamp
- QS_EVS_PRE_(evtSize); // the size of the evt
- QS_SIG_PRE_(sig); // the signal of the evt
- QS_END_PRE_()
+
+ // precondition:
+ // - cannot run out of registered pools
+ Q_REQUIRE_INCRIT(400, poolNum < priv_.maxPool_);
+
+ ++poolNum; // convert to 1-based poolNum
+
+ QF_CRIT_EXIT();
+
+ // get event `e` out of the event pool (port-dependent)...
+ QEvt *e = nullptr;
+#ifdef Q_SPY
+ QF_EPOOL_GET_(priv_.ePool_[poolNum - 1U], e,
+ ((margin != NO_MARGIN) ? margin : 0U),
+ static_cast(QS_EP_ID) + poolNum);
+#else
+ QF_EPOOL_GET_(priv_.ePool_[poolNum - 1U], e,
+ ((margin != NO_MARGIN) ? margin : 0U), 0U);
+#endif
+
+ if (e != nullptr) { // was e allocated correctly?
+ e->sig = static_cast(sig); // set the signal
+ e->poolNum_ = poolNum;
+ e->refCtr_ = 0U; // initialize the reference counter to 0
+
+ QS_CRIT_ENTRY();
+ QS_BEGIN_PRE(QS_QF_NEW,
+ static_cast(QS_EP_ID) + poolNum)
+ QS_TIME_PRE(); // timestamp
+ QS_EVS_PRE(evtSize); // the size of the event
+ QS_SIG_PRE(sig); // the signal of the event
+ QS_END_PRE()
+ QS_CRIT_EXIT();
}
- else {
+ else { // event was not allocated
+
+ QF_CRIT_ENTRY();
// This assertion means that the event allocation failed,
// and this failure cannot be tolerated. The most frequent
// reason is an event leak in the application.
- Q_ASSERT_ID(320, margin != QF::NO_MARGIN);
-
- QS_BEGIN_PRE_(QS_QF_NEW_ATTEMPT,
- static_cast(QS_EP_ID) + idx + 1U)
- QS_TIME_PRE_(); // timestamp
- QS_EVS_PRE_(evtSize); // the size of the evt
- QS_SIG_PRE_(sig); // the signal of the evt
- QS_END_PRE_()
+ Q_ASSERT_INCRIT(420, margin != NO_MARGIN);
+
+ QS_BEGIN_PRE(QS_QF_NEW_ATTEMPT,
+ static_cast(QS_EP_ID) + poolNum)
+ QS_TIME_PRE(); // timestamp
+ QS_EVS_PRE(evtSize); // the size of the event
+ QS_SIG_PRE(sig); // the signal of the event
+ QS_END_PRE()
+
+ QF_CRIT_EXIT();
}
- return e; // can't be NULL if we can't tolerate bad allocation
+
+ // the returned event e is guaranteed to be valid (not NULL)
+ // if we can't tolerate failed allocation
+ return e;
}
-//${QF::QF-dyn::gc} ..........................................................
+//............................................................................
void gc(QEvt const * const e) noexcept {
- // is it a dynamic event?
- if (e->poolId_ != 0U) {
- QF_CRIT_STAT_
- QF_CRIT_E_();
-
- // isn't this the last reference?
- if (e->refCtr_ > 1U) {
-
- QS_BEGIN_NOCRIT_PRE_(QS_QF_GC_ATTEMPT,
- static_cast(QS_EP_ID)
- + static_cast(e->poolId_))
- QS_TIME_PRE_(); // timestamp
- QS_SIG_PRE_(e->sig); // the signal of the event
- QS_2U8_PRE_(e->poolId_, e->refCtr_); // pool Id & refCtr
- QS_END_NOCRIT_PRE_()
+ QF_CRIT_STAT
+ QF_CRIT_ENTRY();
+
+ Q_REQUIRE_INCRIT(500, e != nullptr);
+
+ std::uint_fast8_t const poolNum = e->poolNum_;
+
+ if (poolNum != 0U) { // is it a pool event (mutable)?
+
+ if (e->refCtr_ > 1U) { // isn't this the last reference?
+ QS_BEGIN_PRE(QS_QF_GC_ATTEMPT,
+ static_cast(QS_EP_ID) + poolNum)
+ QS_TIME_PRE(); // timestamp
+ QS_SIG_PRE(e->sig); // the signal of the event
+ QS_2U8_PRE(poolNum, e->refCtr_);
+ QS_END_PRE()
+
+ Q_ASSERT_INCRIT(505, e->refCtr_ > 0U);
QEvt_refCtr_dec_(e); // decrement the ref counter
- QF_CRIT_X_();
+ QF_CRIT_EXIT();
}
- // this is the last reference to this event, recycle it
- else {
- std::uint_fast8_t const idx =
- static_cast(e->poolId_) - 1U;
-
- QS_BEGIN_NOCRIT_PRE_(QS_QF_GC,
- static_cast(QS_EP_ID)
- + static_cast(e->poolId_))
- QS_TIME_PRE_(); // timestamp
- QS_SIG_PRE_(e->sig); // the signal of the event
- QS_2U8_PRE_(e->poolId_, e->refCtr_);
- QS_END_NOCRIT_PRE_()
-
- QF_CRIT_X_();
-
- // pool ID must be in range
- Q_ASSERT_ID(410, idx < QF::maxPool_);
-
- #ifdef Q_EVT_XTOR
- // explicitly exectute the destructor'
- // NOTE: casting 'const' away is legitimate,
- // because it's a pool event
- QF_CONST_CAST_(QEvt*, e)->~QEvt(); // xtor,
- #endif
-
- #ifdef Q_SPY
- // cast 'const' away, which is OK, because it's a pool event
- QF_EPOOL_PUT_(QF::ePool_[idx], QF_CONST_CAST_(QEvt*, e),
- static_cast(QS_EP_ID)
- + static_cast(e->poolId_));
- #else
- QF_EPOOL_PUT_(QF::ePool_[idx], QF_CONST_CAST_(QEvt*, e), 0U);
- #endif
+ else { // this is the last reference to this event, recycle it
+
+ QS_BEGIN_PRE(QS_QF_GC,
+ static_cast(QS_EP_ID) + poolNum)
+ QS_TIME_PRE(); // timestamp
+ QS_SIG_PRE(e->sig); // the signal of the event
+ QS_2U8_PRE(poolNum, e->refCtr_);
+ QS_END_PRE()
+
+ // pool number must be in range
+ Q_ASSERT_INCRIT(510, (poolNum <= priv_.maxPool_)
+ && (poolNum <= QF_MAX_EPOOL));
+ QF_CRIT_EXIT();
+
+ // NOTE: casting 'const' away is legit because it's a pool event
+#ifdef Q_SPY
+ QF_EPOOL_PUT_(priv_.ePool_[poolNum - 1U],
+ QF_CONST_CAST_(QEvt*, e),
+ static_cast(QS_EP_ID) + poolNum);
+#else
+ QF_EPOOL_PUT_(priv_.ePool_[poolNum - 1U],
+ QF_CONST_CAST_(QEvt*, e), 0U);
+#endif
}
}
+ else {
+ QF_CRIT_EXIT();
+ }
}
-//${QF::QF-dyn::poolGetMaxBlockSize} .........................................
-std::uint_fast16_t poolGetMaxBlockSize() noexcept {
- return QF_EPOOL_EVENT_SIZE_(QF::ePool_[QF::maxPool_ - 1U]);
-}
-
-//${QF::QF-dyn::newRef_} .....................................................
+//............................................................................
QEvt const * newRef_(
QEvt const * const e,
QEvt const * const evtRef) noexcept
{
- //! @pre the event must be dynamic and the provided event reference
- //! must not be already in use
- Q_REQUIRE_ID(500, (e->poolId_ != 0U)
- && (evtRef == nullptr));
+#ifdef Q_UNSAFE
+ Q_UNUSED_PAR(evtRef);
+#endif
+
+ QF_CRIT_STAT
+ QF_CRIT_ENTRY();
- QF_CRIT_STAT_
- QF_CRIT_E_();
+ Q_REQUIRE_INCRIT(600, e != nullptr);
+ std::uint_fast8_t const poolNum = e->poolNum_;
+ Q_UNUSED_PAR(poolNum); // might be unused
+
+ Q_REQUIRE_INCRIT(610, (poolNum != 0U)
+ && (evtRef == nullptr));
+
+ Q_ASSERT_INCRIT(605, e->refCtr_ < (2U * QF_MAX_ACTIVE));
QEvt_refCtr_inc_(e); // increments the ref counter
- QS_BEGIN_NOCRIT_PRE_(QS_QF_NEW_REF,
- static_cast(QS_EP_ID)
- + static_cast(e->poolId_))
- QS_TIME_PRE_(); // timestamp
- QS_SIG_PRE_(e->sig); // the signal of the event
- QS_2U8_PRE_(e->poolId_, e->refCtr_); // pool Id & ref Count
- QS_END_NOCRIT_PRE_()
+ QS_BEGIN_PRE(QS_QF_NEW_REF,
+ static_cast(QS_EP_ID) + poolNum)
+ QS_TIME_PRE(); // timestamp
+ QS_SIG_PRE(e->sig); // the signal of the event
+ QS_2U8_PRE(poolNum, e->refCtr_);
+ QS_END_PRE()
- QF_CRIT_X_();
+ QF_CRIT_EXIT();
return e;
}
-//${QF::QF-dyn::deleteRef_} ..................................................
+//............................................................................
void deleteRef_(QEvt const * const evtRef) noexcept {
- QS_CRIT_STAT_
- QS_BEGIN_PRE_(QS_QF_DELETE_REF,
- static_cast(QS_EP_ID)
- + static_cast(evtRef->poolId_))
- QS_TIME_PRE_(); // timestamp
- QS_SIG_PRE_(evtRef->sig); // the signal of the event
- QS_2U8_PRE_(evtRef->poolId_, evtRef->refCtr_); // pool Id & ref Count
- QS_END_PRE_()
-
- #if (QF_MAX_EPOOL > 0U)
- gc(evtRef); // recycle the referenced event
- #endif
-}
+ QF_CRIT_STAT
+ QF_CRIT_ENTRY();
-//${QF::QF-dyn::getPoolMin} ..................................................
-std::uint_fast16_t getPoolMin(std::uint_fast8_t const poolId) noexcept {
- //! @pre the poolId must be in range
- Q_REQUIRE_ID(400, (QF::maxPool_ <= QF_MAX_EPOOL)
- && (0U < poolId) && (poolId <= QF::maxPool_));
- QF_CRIT_STAT_
- QF_CRIT_E_();
- std::uint_fast16_t const min = static_cast(
- QF::ePool_[poolId - 1U].getNMin());
- QF_CRIT_X_();
+ QEvt const * const e = evtRef;
+ Q_REQUIRE_INCRIT(700, e != nullptr);
- return min;
+#ifdef Q_SPY
+ std::uint_fast8_t const poolNum = e->poolNum_;
+
+ QS_BEGIN_PRE(QS_QF_DELETE_REF,
+ static_cast(QS_EP_ID) + poolNum)
+ QS_TIME_PRE(); // timestamp
+ QS_SIG_PRE(e->sig); // the signal of the event
+ QS_2U8_PRE(poolNum, e->refCtr_);
+ QS_END_PRE()
+#endif // def Q_SPY
+
+ QF_CRIT_EXIT();
+
+#if (QF_MAX_EPOOL > 0U)
+ gc(e); // recycle the referenced event
+#endif
}
} // namespace QF
} // namespace QP
-//$enddef${QF::QF-dyn} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-#endif // (QF_MAX_EPOOL > 0U) dynamic events configured
+#endif // (QF_MAX_EPOOL > 0U) mutable events configured
diff --git a/src/qf_mem.cpp b/src/qf_mem.cpp
index e37f5f4..ef9f282 100644
--- a/src/qf_mem.cpp
+++ b/src/qf_mem.cpp
@@ -1,51 +1,39 @@
-//$file${src::qf::qf_mem.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+//============================================================================
+// QP/C++ Real-Time Embedded Framework (RTEF)
+// Version 8.0.2
//
-// Model: qpcpp.qm
-// File: ${src::qf::qf_mem.cpp}
+// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved.
//
-// This code has been generated by QM 5.2.5 .
-// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
-//
-// This code is covered by the following QP license:
-// License # : LicenseRef-QL-dual
-// Issued to : Any user of the QP/C++ real-time embedded framework
-// Framework(s) : qpcpp
-// Support ends : 2023-12-31
-// License scope:
-//
-// Copyright (C) 2005 Quantum Leaps, LLC .
+// Q u a n t u m L e a P s
+// ------------------------
+// Modern Embedded Software
//
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
//
-// This software is dual-licensed under the terms of the open source GNU
-// General Public License version 3 (or any later version), or alternatively,
-// under the terms of one of the closed source Quantum Leaps commercial
-// licenses.
-//
-// The terms of the open source GNU General Public License version 3
-// can be found at:
-//
-// The terms of the closed source Quantum Leaps commercial licenses
-// can be found at:
+// This software is dual-licensed under the terms of the open-source GNU
+// General Public License (GPL) or under the terms of one of the closed-
+// source Quantum Leaps commercial licenses.
//
// Redistributions in source code must retain this top-level comment block.
// Plagiarizing this software to sidestep the license obligations is illegal.
//
-// Contact information:
+// NOTE:
+// The GPL does NOT permit the incorporation of this code into proprietary
+// programs. Please contact Quantum Leaps for commercial licensing options,
+// which expressly supersede the GPL and are designed explicitly for
+// closed-source distribution.
+//
+// Quantum Leaps contact information:
//
//
-//
-//$endhead${src::qf::qf_mem.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-//! @file
-//! @brief QF/C++ memory management services
-
+//============================================================================
#define QP_IMPL // this is QP implementation
-#include "qf_port.hpp" // QF port
-#include "qf_pkg.hpp" // QF package-scope interface
-#include "qassert.h" // QP embedded systems-friendly assertions
+#include "qp_port.hpp" // QP port
+#include "qp_pkg.hpp" // QP package-scope interface
+#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
#ifdef Q_SPY // QS software tracing enabled?
#include "qs_port.hpp" // QS port
- #include "qs_pkg.hpp" // QS facilities for pre-defined trace records
+ #include "qs_pkg.hpp" // QS package-scope internal interface
#else
#include "qs_dummy.hpp" // disable the QS software tracing
#endif // Q_SPY
@@ -55,190 +43,179 @@ namespace {
Q_DEFINE_THIS_MODULE("qf_mem")
} // unnamed namespace
-//$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-// Check for the minimum required QP version
-#if (QP_VERSION < 700U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U))
-#error qpcpp version 7.0.0 or higher required
-#endif
-//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-//$define${QF::QMPool} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
namespace QP {
-//${QF::QMPool} ..............................................................
-
-//${QF::QMPool::QMPool} ......................................................
-QMPool::QMPool()
- : m_start(nullptr),
- m_end(nullptr),
- m_free_head(nullptr),
- m_blockSize(0U),
- m_nTot(0U),
- m_nFree(0U),
- m_nMin(0U)
-{}
-
-//${QF::QMPool::init} ........................................................
+//............................................................................
void QMPool::init(
void * const poolSto,
- std::uint_fast32_t poolSize,
- std::uint_fast16_t blockSize) noexcept
+ std::uint_fast32_t const poolSize,
+ std::uint_fast16_t const blockSize) noexcept
{
- //! @pre The memory block must be valid and
- //! the poolSize must fit at least one free block and
- //! the blockSize must not be too close to the top of the dynamic range
- Q_REQUIRE_ID(100, (poolSto != nullptr)
- && (poolSize >= static_cast(sizeof(QFreeBlock)))
- && (static_cast(blockSize + sizeof(QFreeBlock))
- > blockSize));
-
- m_free_head = poolSto;
-
- // round up the blockSize to fit an integer number of pointers...
- //start with one
- m_blockSize = static_cast(sizeof(QFreeBlock));
-
- //# free blocks in a memory block
- std::uint_fast16_t nblocks = 1U;
- while (m_blockSize < static_cast(blockSize)) {
- m_blockSize += static_cast(sizeof(QFreeBlock));
- ++nblocks;
- }
- // use rounded-up value
- blockSize = static_cast(m_blockSize);
+ QF_CRIT_STAT
+ QF_CRIT_ENTRY();
- // the whole pool buffer must fit at least one rounded-up block
- Q_ASSERT_ID(110, poolSize >= blockSize);
+ Q_REQUIRE_INCRIT(100, poolSto != nullptr);
- // chain all blocks together in a free-list...
+ m_freeHead = static_cast(poolSto);
+
+ // find # free links in a memory block, see NOTE1
+ m_blockSize = static_cast(2U * sizeof(void *));
+ std::uint_fast16_t inext = 2U;
+ while (m_blockSize < static_cast(blockSize)) {
+ m_blockSize += static_cast(sizeof(void *));
+ ++inext;
+ }
- // don't count the last block
- poolSize -= static_cast(blockSize);
- m_nTot = 1U; // one (the last) block in the pool
+ // the pool buffer must fit at least one rounded-up block
+ Q_ASSERT_INCRIT(110, poolSize >= m_blockSize);
// start at the head of the free list
- QFreeBlock *fb = static_cast(m_free_head);
+ void * *pfb = m_freeHead; // pointer to free block
+ std::uint32_t nTot = 1U; // the last block already in the list
// chain all blocks together in a free-list...
- while (poolSize >= blockSize) {
- fb->m_next = &fb[nblocks]; // setup the next link
- fb = fb->m_next; // advance to next block
- // reduce the available pool size
- poolSize -= static_cast(blockSize);
- ++m_nTot; // increment the number of blocks so far
+ for (std::uint_fast32_t size = poolSize - m_blockSize;
+ size >= static_cast(m_blockSize);
+ size -= static_cast(m_blockSize))
+ {
+ pfb[0] = &pfb[inext]; // set the next link to next free block
+ pfb = static_cast(pfb[0]); // advance to the next block
+ ++nTot; // one more free block in the pool
}
+ pfb[0] = nullptr; // the last link points to NULL
- fb->m_next = nullptr; // the last link points to NULL
- m_nFree = m_nTot; // all blocks are free
- m_nMin = m_nTot; // the minimum number of free blocks
- m_start = poolSto; // the original start this pool buffer
- m_end = fb; // the last block in this pool
+ // dynamic range check
+#if (QF_MPOOL_CTR_SIZE == 1U)
+ Q_ASSERT_INCRIT(190, nTot < 0xFFU);
+#elif (QF_MPOOL_CTR_SIZE == 2U)
+ Q_ASSERT_INCRIT(190, nTot < 0xFFFFU);
+#endif
+
+ m_nTot = static_cast(nTot);
+ m_nFree = m_nTot; // all blocks are free
+ m_start = static_cast