improved Zephyr port and examples
This commit is contained in:
MMS 2022-08-12 15:24:06 -04:00
parent f16303644b
commit 4cdb28e10d
10 changed files with 119 additions and 89 deletions

View File

@ -7,7 +7,7 @@
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8 DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "QP/C++" PROJECT_NAME = "QP/C++"
PROJECT_NUMBER = 7.0.1 PROJECT_NUMBER = 7.0.2
PROJECT_BRIEF = "Real-Time Embedded Framework" PROJECT_BRIEF = "Real-Time Embedded Framework"
PROJECT_LOGO = ../../ql-doxygen/images/logo_ql.png PROJECT_LOGO = ../../ql-doxygen/images/logo_ql.png
OUTPUT_DIRECTORY = OUTPUT_DIRECTORY =

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -1,8 +1,12 @@
# QPCPP Zephyr application
# SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
CONFIG_QPCPP=y
CONFIG_CPLUSPLUS=y CONFIG_CPLUSPLUS=y
CONFIG_ASSERT=y
CONFIG_ASSERT_LEVEL=2
CONFIG_NUM_COOP_PRIORITIES=29 CONFIG_NUM_COOP_PRIORITIES=29
CONFIG_NUM_PREEMPT_PRIORITIES=40 CONFIG_NUM_PREEMPT_PRIORITIES=40
CONFIG_GPIO=y
CONFIG_REBOOT=y CONFIG_REBOOT=y
# for QSPY...
CONFIG_SERIAL=y
CONFIG_UART_INTERRUPT_DRIVEN=y

View File

@ -22,8 +22,8 @@
// <www.state-machine.com> // <www.state-machine.com>
// <info@state-machine.com> // <info@state-machine.com>
//============================================================================ //============================================================================
//! @date Last updated on: 2022-08-05 //! @date Last updated on: 2022-08-12
//! @version Last updated for: @ref qpcpp_7_0_1 //! @version Last updated for: @ref qpcpp_7_0_2
//! //!
//! @file //! @file
//! @brief DPP example (BSP) //! @brief DPP example (BSP)
@ -68,7 +68,7 @@ static struct k_timer QF_tick_timer;
PHILO_STAT = QP::QS_USER, PHILO_STAT = QP::QS_USER,
PAUSED_STAT, PAUSED_STAT,
COMMAND_STAT, COMMAND_STAT,
CONTEXT_SW TEST_MSG
}; };
#endif #endif
@ -103,22 +103,20 @@ void BSP::init(void) {
// object dictionaries... // object dictionaries...
QS_OBJ_DICTIONARY(AO_Table); QS_OBJ_DICTIONARY(AO_Table);
QS_OBJ_DICTIONARY(AO_Philo[0]); for (int n = 0; n < N_PHILO; ++n) {
QS_OBJ_DICTIONARY(AO_Philo[1]); QS_OBJ_ARR_DICTIONARY(AO_Philo[n], n);
QS_OBJ_DICTIONARY(AO_Philo[2]); }
QS_OBJ_DICTIONARY(AO_Philo[3]);
QS_OBJ_DICTIONARY(AO_Philo[4]);
QS_OBJ_DICTIONARY(&timerID);
QS_USR_DICTIONARY(PHILO_STAT); QS_USR_DICTIONARY(PHILO_STAT);
QS_USR_DICTIONARY(PAUSED_STAT); QS_USR_DICTIONARY(PAUSED_STAT);
QS_USR_DICTIONARY(COMMAND_STAT); QS_USR_DICTIONARY(COMMAND_STAT);
QS_USR_DICTIONARY(CONTEXT_SW); QS_USR_DICTIONARY(TEST_MSG);
// setup the QS filters... // setup the QS filters...
QS_GLB_FILTER(QP::QS_SM_RECORDS); // state machine records 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_AO_RECORDS); // active object records
QS_GLB_FILTER(QP::QS_UA_RECORDS); // all user records QS_GLB_FILTER(QP::QS_UA_RECORDS); // all user records
QS_GLB_FILTER(TEST_MSG);
} }
//............................................................................ //............................................................................
void BSP::ledOn(void) { void BSP::ledOn(void) {
@ -136,6 +134,7 @@ void BSP::displayPhilStat(uint8_t n, char const *stat) {
else { else {
ledOff(); ledOff();
} }
Q_PRINTK("Philo[%d]->%s\n", n, stat);
QS_BEGIN_ID(PHILO_STAT, AO_Philo[n]->m_prio) // app-specific record begin QS_BEGIN_ID(PHILO_STAT, AO_Philo[n]->m_prio) // app-specific record begin
QS_U8(1, n); // Philosopher number QS_U8(1, n); // Philosopher number
@ -144,7 +143,7 @@ void BSP::displayPhilStat(uint8_t n, char const *stat) {
} }
//............................................................................ //............................................................................
void BSP::displayPaused(uint8_t paused) { void BSP::displayPaused(uint8_t paused) {
static_cast<void>(paused); // unused parameter Q_UNUSED_PAR(paused);
} }
//............................................................................ //............................................................................
uint32_t BSP::random(void) { // a very cheap pseudo-random-number generator uint32_t BSP::random(void) { // a very cheap pseudo-random-number generator
@ -167,7 +166,7 @@ void BSP::randomSeed(uint32_t seed) {
//............................................................................ //............................................................................
void BSP::terminate(int16_t result) { void BSP::terminate(int16_t result) {
(void)result; Q_UNUSED_PAR(result);
} }
} // namespace DPP } // namespace DPP
@ -179,9 +178,11 @@ namespace QP {
// QF callbacks ============================================================== // QF callbacks ==============================================================
void QF::onStartup(void) { void QF::onStartup(void) {
k_timer_start(&QF_tick_timer, K_MSEC(1), K_MSEC(1)); k_timer_start(&QF_tick_timer, K_MSEC(1), K_MSEC(1));
Q_PRINTK("QF::onStartup()");
} }
//............................................................................ //............................................................................
void QF::onCleanup(void) { void QF::onCleanup(void) {
Q_PRINTK("QF::onCleanup()");
} }
// QS callbacks ============================================================== // QS callbacks ==============================================================
@ -189,52 +190,53 @@ void QF::onCleanup(void) {
#include <drivers/uart.h> #include <drivers/uart.h>
static const struct device *uart_console_dev; // select the Zephyr shell UART
// NOTE: you can change this to other UART peripheral if desired
static struct device const *uart_dev =
DEVICE_DT_GET(DT_CHOSEN(zephyr_shell_uart));
//............................................................................ //............................................................................
static K_THREAD_STACK_DEFINE(qspy_stack, 1024); // stack storage void QS::doOutput(void) {
static k_thread qspy_thread_handler; std::uint16_t len = 0xFFFFU; // big number to get all available bytes
static void qspy_thread(void *p1, void *p2, void *p3){
while (true) {
// transmit bytes...
std::uint16_t len = 0xFFFFU; // get as many bytes as available
QS_CRIT_STAT_ QS_CRIT_STAT_
QS_CRIT_E_(); QS_CRIT_E_();
std::uint8_t const *buf = QS::getBlock(&len); std::uint8_t const *buf = QS::getBlock(&len);
QS_CRIT_X_(); QS_CRIT_X_();
for (; len != 0U; --len, ++buf) {
uart_poll_out(uart_console_dev, *buf);
}
// receive bytes... // transmit the bytes via the UART...
std::uint8_t b; for (; len != 0U; --len, ++buf) {
while (uart_poll_in(uart_console_dev, &b) == 0) { uart_poll_out(uart_dev, *buf);
QS::rxPut(b);
}
QS::rxParse();
} }
} }
//............................................................................
static void uart_cb(const struct device *dev, void *user_data) {
if (!uart_irq_update(uart_dev)) {
return;
}
if (uart_irq_rx_ready(uart_dev)) {
std::uint8_t buf[32];
int n = uart_fifo_read(uart_dev, buf, sizeof(buf));
for (std::uint8_t const *p = buf; n > 0; --n, ++p) {
QS::rxPut(*p);
}
}
}
//............................................................................
bool QS::onStartup(void const *arg) { bool QS::onStartup(void const *arg) {
static uint8_t qsTxBuf[2*1024]; // buffer for QS transmit channel static uint8_t qsTxBuf[2*1024]; // buffer for QS transmit channel
static uint8_t qsRxBuf[256]; // buffer for QS receive channel static uint8_t qsRxBuf[256]; // buffer for QS receive channel
Q_REQUIRE(uart_dev != NULL);
initBuf (qsTxBuf, sizeof(qsTxBuf)); initBuf (qsTxBuf, sizeof(qsTxBuf));
rxInitBuf(qsRxBuf, sizeof(qsRxBuf)); rxInitBuf(qsRxBuf, sizeof(qsRxBuf));
uart_console_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_console));
Q_ASSERT(uart_console_dev != NULL); // configure interrupt and callback to receive data
k_thread_create(&qspy_thread_handler, uart_irq_callback_user_data_set(uart_dev, &uart_cb, nullptr);
qspy_stack, uart_irq_rx_enable(uart_dev);
K_THREAD_STACK_SIZEOF(qspy_stack),
&qspy_thread,
nullptr, // p1
nullptr, // p2
nullptr, // p3
QF_MAX_ACTIVE, // lowest priority
K_ESSENTIAL, // thread options
K_NO_WAIT); // start immediately
//TODO assert if could not create thread
return true; // return success return true; // return success
} }
//............................................................................ //............................................................................
@ -242,19 +244,17 @@ void QS::onCleanup(void) {
} }
//............................................................................ //............................................................................
QSTimeCtr QS::onGetTime(void) { // NOTE: invoked with interrupts DISABLED QSTimeCtr QS::onGetTime(void) { // NOTE: invoked with interrupts DISABLED
return k_uptime_get_32(); return k_cycle_get_32();
} }
//............................................................................ //............................................................................
void QS::onFlush(void) { void QS::onFlush(void) {
uint16_t len = 0xFFFFU; // big number to get as many bytes as available std::uint16_t len = 0xFFFFU; // to get as many bytes as available
uint8_t const *buf = QS::getBlock(&len); // get continguous block of data std::uint8_t const *buf;
while (buf != nullptr) { // data available? while ((buf = QS::getBlock(&len)) != nullptr) { // QS-TX data available?
for(auto i = 0;i!=len;i++) for (; len != 0U; --len, ++buf) {
{ uart_poll_out(uart_dev, *buf);
uart_poll_out(uart_console_dev,buf[i]);
} }
len = 0xFFFFU; // big number to get as many bytes as available len = 0xFFFFU; // to get as many bytes as available
buf = QS::getBlock(&len); // try to get more data
} }
} }
//............................................................................ //............................................................................
@ -268,10 +268,10 @@ extern "C" void assert_failed(char const *module, int loc);
void QS::onCommand(uint8_t cmdId, uint32_t param1, void QS::onCommand(uint8_t cmdId, uint32_t param1,
uint32_t param2, uint32_t param3) uint32_t param2, uint32_t param3)
{ {
(void)cmdId; Q_UNUSED_PAR(cmdId);
(void)param1; Q_UNUSED_PAR(param1);
(void)param2; Q_UNUSED_PAR(param2);
(void)param3; Q_UNUSED_PAR(param3);
} }
#endif // Q_SPY #endif // Q_SPY
@ -286,8 +286,8 @@ Q_NORETURN Q_onAssert(char const * const module, int_t const loc) {
// //
// NOTE: add here your application-specific error handling // NOTE: add here your application-specific error handling
// //
printk("\nASSERTION in %s:%d\n", module, loc);
QS_ASSERTION(module, loc, static_cast<uint32_t>(10000U)); QS_ASSERTION(module, loc, static_cast<uint32_t>(10000U));
Q_PRINTK("\nASSERTION in %s:%d\n", module, loc);
#ifndef NDEBUG #ifndef NDEBUG
k_panic(); // debug build: halt the system for error search... k_panic(); // debug build: halt the system for error search...

View File

@ -32,7 +32,8 @@ zephyr_library_sources(
${QPCPP_DIR}/zephyr/qf_port.cpp ${QPCPP_DIR}/zephyr/qf_port.cpp
) )
if(CONFIG_QSPY) # QSPY option...
if(QSPY)
target_compile_definitions(app PUBLIC Q_SPY) target_compile_definitions(app PUBLIC Q_SPY)
zephyr_library_compile_definitions(Q_SPY) zephyr_library_compile_definitions(Q_SPY)
@ -46,6 +47,6 @@ zephyr_library_sources(
${QPCPP_DIR}/include/qstamp.cpp ${QPCPP_DIR}/include/qstamp.cpp
) )
endif() # CONFIG_QSPY endif() # QSPY
endif() # CONFIG_QPCPP endif() # CONFIG_QPCPP

View File

@ -9,12 +9,6 @@ menuconfig QPCPP
if QPCPP if QPCPP
config QSPY
bool "QSPY Tracing"
default n
help
Enables the QSPY Tracing for QP
module = QPCPP module = QPCPP
module-str = QPCPP module-str = QPCPP

View File

@ -1,4 +1,6 @@
# qpcpp Zephyr Module [![QP Zephyr Module](../doxygen/images/qp-zephyr.jpg)](https://www.state-machine.com/qpcpp/zephyr.html)
# About the QPCPP Zephyr Module
This directory defines the This directory defines the
[QP/C++ Real-Time Embedded Framework](https://github.com/QuantumLeaps/qpcpp) [QP/C++ Real-Time Embedded Framework](https://github.com/QuantumLeaps/qpcpp)
as a [Zephyr module](https://docs.zephyrproject.org/latest/develop/modules.html). as a [Zephyr module](https://docs.zephyrproject.org/latest/develop/modules.html).
@ -7,22 +9,32 @@ as a [Zephyr module](https://docs.zephyrproject.org/latest/develop/modules.html)
Example of use is provided in the related repository Example of use is provided in the related repository
[qpcpp-zephyr-app](https://github.com/QuantumLeaps/qpcpp-zephyr-app) [qpcpp-zephyr-app](https://github.com/QuantumLeaps/qpcpp-zephyr-app)
To create your own QP-Zephyr project, you can clone that repository
and customize it to your needs:
```bash
git clone https://github.com/QuantumLeaps/qpcpp-zephyr-app <my-project> --recurse-submodules --depth 1
```
where `<my-project>` is the name of your project.
## Configuring the QPCPP Zephyr Module ## Configuring the QPCPP Zephyr Module
The `Kconfig` file provides configuration `CONFIG_QPCPP` to activate The `Kconfig` file provides configuration `CONFIG_QPCPP` to activate the QPCPP module
the QPCPP module in Zephyr. To do so, you need to add the following in Zephyr. To do so, you need to add the following line to your `prj.conf`:
line to your `prj.conf`:
```ini ```ini
CONFIG_QPCPP=y CONFIG_QPCPP=y
``` ```
## Configuring the QSPY Software Tracing ## Option for Activating QSPY Software Tracing
If you wish to enable The QP/C++ Zephyr Module supports the
[QSPY Software Tracing](https://www.state-machine.com/qtools/qpspy.html), [QSPY Software Tracing](https://www.state-machine.com/qtools/qpspy.html)
`Kconfig` file provides configuration `CONFIG_QSPY`, which you can option and will add the appropriate macros and files to build the "QSPY"
use in your `prj.conf`: configuration.
```ini If you wish to enable "QSPY" you can provide the option "QSPY"
CONFIG_QSPY=y in the command-line for the build. For example:
```bash
west build -b nucleo_h743zi -- -DQSPY=ON
``` ```

View File

@ -22,8 +22,8 @@
// <www.state-machine.com> // <www.state-machine.com>
// <info@state-machine.com> // <info@state-machine.com>
//============================================================================ //============================================================================
//! @date Last updated on: 2022-08-06 //! @date Last updated on: 2022-08-12
//! @version Last updated for: @ref qpcpp_7_0_1 //! @version Last updated for: @ref qpcpp_7_0_2
//! //!
//! @file //! @file
//! @brief QF/C++ port to Zephyr RTOS kernel, all supported compilers //! @brief QF/C++ port to Zephyr RTOS kernel, all supported compilers
@ -67,7 +67,18 @@ void QF::init(void) {
//............................................................................ //............................................................................
int_t QF::run(void) { int_t QF::run(void) {
onStartup(); onStartup();
#ifdef Q_SPY
// lower the priority of the main thread to the level of idle
k_thread_priority_set(k_current_get(),
CONFIG_NUM_PREEMPT_PRIORITIES - 1);
// perform QS work
while (true) {
QS::rxParse(); // parse any QS-RX bytes
QS::doOutput(); // perform the QS-TX output
}
#else
return 0; // return from the main Zephyr thread return 0; // return from the main Zephyr thread
#endif
} }
//............................................................................ //............................................................................
void QF::stop(void) { void QF::stop(void) {

View File

@ -22,8 +22,8 @@
// <www.state-machine.com> // <www.state-machine.com>
// <info@state-machine.com> // <info@state-machine.com>
//============================================================================ //============================================================================
//! @date Last updated on: 2022-08-06 //! @date Last updated on: 2022-08-12
//! @version Last updated for: @ref qpcpp_7_0_1 //! @version Last updated for: @ref qpcpp_7_0_2
//! //!
//! @file //! @file
//! @brief QF/C++ port to Zephyr RTOS kernel, all supported compilers //! @brief QF/C++ port to Zephyr RTOS kernel, all supported compilers
@ -61,6 +61,14 @@ extern struct k_spinlock spinlock;
} // namespace QF } // namespace QF
} // namespace QP } // namespace QP
// Q_PRINTK() macro to avoid conflicts with Zephyr's printk()
// when Q_SPY configuation is used
#ifndef Q_SPY
#define Q_PRINTK(fmt_, ...) printk(fmt_, ##__VA_ARGS__)
#else
#define Q_PRINTK(dummy, ...) (static_cast<void>(0))
#endif
//============================================================================ //============================================================================
// interface used only inside QF, but not in applications // interface used only inside QF, but not in applications
// //