Building Applications with QP (qp_dpp Example)
Description
The qp_dpp example program demonstrates the use of the QP active object framework. The example is based on the classic Dining Philosophers Problem (DPP), which was originally posed and solved by Edsger Dijkstra back in 1971. The qp_dpp
example program for mbed is relatively simple and can be tested only with a couple of LEDs on the mbed board. Still, DPP contains six concurrent active objects (encapsulated, concurrent state machines) that exchange events via publish-subscribe and direct event posting mechanisms. The application uses five time events (timers), as well as dynamic and static events. Additionally, the qp_dpp
example shows how to use the professional QP-Spy software tracing system available in the QP framework with the mbed virtual COM port.
Information
The Application Note: Dining Philosophers Problem describes the design and implementation of the qp_dpp
example.
Running the qp_dpp
Example
You compile and download the qp_dpp
program to the mbed board in the usual way. When qp_dpp
starts executing, you should see the LED1, LED2, and LED3 blink (the LEDs are counted from the left, see picture below). These three LEDs indicate the "eating" status of the Dining Philosophers 0, 1, and 2, respectively (the remaining Philosophers 3 and 4 are not shown).
The right-most LED4 is used to visualize the status of the idle processing. This LED4 is turned rapidly on and off in the idle loop, which human eye perceives as a continuous glow. The intensity of this glow represents the wasted CPU cycles (see also the section "Power Saving Demonstration" below).
Code Generation Demonstration
All state machine code in the qp_dpp
program has been generated automatically by the free QM modeling tool. Unfortunately, the QM model of the DPP application could not be included in the qp_dpp example program, where it belongs, because the mbed archive accepts only .h and .cpp source files. Therefore, you need to download the DPP model file separately, as described in the box below.
Downloading the QM model
Please right-click on the link below and and select "Save link as..." option to save the dpp.qm
model file to your computer.
Please refer to the Graphical Modeling and Code Generation notebook page for more information.
Software Tracing Demonstration
The qp_dpp
program also produces output to the serial port connected to the mbed USB interface. This output is then available through the virtual COM port on the host workstation.
The data produced by the qp_dpp
program contains very detailed, timestamped information about the program execution. The data is produced by specially designed instrumenation of the QP framework code and available to the application code as well, which is conceptually like peppering the code with the printf()
statements, but with much less overhead imposed on the target system. This way of obtaining information about a live system without the need to stopping the software execution is called software tracing. This technique is particularly important for the mbed platform, because the online development system offers no traditional single-step debugger.
The minimal overhead of the software tracing instrumentation comes from several factors, but most importantly from avoiding formatting the data to ASCII in the time-critical code on the target, and instead sending raw binary data. This implies that the software tracing instrumentation requires a special application on the host to receive, decompress and format the data in human-readable ASCII form. In case of the QP framework, the host application is called QSPY.
Downloading the QSPY application
The QSPY host application is available for download from SourceForge at:
sourceforge.net/projects/qpc/files/QSPY/
The ZIP file you download contains pre-compiled QSPY for Windows and Linux hosts. Please read the provided README file to find the executable for your platform.
QSPY is a console application that you invoke from a command line (please make sure that the directory with the QSPY executable is on the PATH). QSPY outputs human-readable tracing data to the console and also to a file, if you choose so. The reference manual of QSPY is available online at state-machine.com/doxygen/qspy.
The command line to invoke QSPY for receiving data from the qp_dpp
program on Windows looks as follows:
qspy -b115200 -cCOM7
Most likely you need to adjust the -c parameter to the virtual COM port number of the mbed board. On Windows, you can discover this by running Device Manager.
The following screen shot shows the QSPY output from the qp_dpp
example:
You can greatly improve the output by starting QSPY before resetting the mbed board. In that case, you get a much more readable output, like the following screen shot:
The reason is that the qp_dpp
program outputs special symbolic information during the initialization. This symbolic information allows the QSPY host application to map binary addresses of various objects to their names, just like a source-level debugger uses information stored in the ELF file to show names of functions and variables. Of course, when you start QSPY after the initialization of the board, the symbolic information is not available and QSPY can only show cryptic hexadecimal addresses.
Application-Specific Software Trace
The last screen of the QSPY output contains special trace records highlighted with red boarders. These are trace records showing the status of the Dining Philosophers and are generated from the qp_dpp
application, as opposed to be generated by the QP framework. This demonstrates how you can use the QP software tracing instead of the expensive printf()
in your own code. The following code snippet shows how the qp_dpp
program generates the output (file bsp.cpp
):
void BSP_displyPhilStat(uint8_t n, char const *stat) { . . . QS_BEGIN(PHILO_STAT, AO_Philo[n]) // application-specific record QS_U8(1, n); // Philosopher number QS_STR(stat); // Philosopher status QS_END() }
More Information about QP Software Tracing
Of course, this short description can barely scratch the surface of the QP software tracing system. For more information, such as filtering the data, generating accurate time stamps, application-specific tracing, MATLAB interface, and many more, please refer to Chapter 11 of the "Practical UML Statecharts in C/C++" book and the QSPY online manual.
Power Saving Demonstration
Event-driven framework, like QP, can very easily detect a situation when no events are available for processing (called the idle condition). The QP framework provides the idle callback function QK::onIdle()
, which allows you to customize the response of the system to the idle condition.
When software tracing is enabled, the idle callback is ideal place to perform the transfer of the tracing data to the host. This minimizes the impact of software tracing on the system, because tracing takes only the CPU cycles that the application does not need anyway.
However, when software tracing is disabled, the idle callback is the ideal place to put the system into a low-power sleep mode. You can actually try it, because the basic code for putting the CPU to sleep is already in place, but is inactive as long as software tracing is used.
You disable software tracing and enable low-power sleep mode by commenting out the define Q_SPY
macro in the file qp_config.h
:
qp_config.h
#ifndef qp_config_h #define qp_config_h // enable the Q-SPY software tracing instrumentation //#define Q_SPY // enable preemptive QK kernel #define QK_PREEMPTIVE // The maximum number of active objects in the application (could be up to 63) #define QF_MAX_ACTIVE 16 #endif // qp_config_h
After you modify qp_config.h
, you can recompile the qp_dpp
program and load it to your mbed board. This time, when you run the code, you will see no intensity of LED4, which means that far fewer CPU cycles are wasted in the idle loop. (Actually, LED4 still blinks, but only 100 times per second instead of millions times per second, as before).
Information
Power management of the mbed board is also discussed in the following articles:
Preemptive Multitasking Demonstration
Finally, the qp_dpp
demonstrates the preemptive QK multitasking kernel on mbed. As any preemptive kernel, QK must be informed about entering and exiting every interrupt service routine (ISR), but QK perfectly accepts ISRs written in C, while most other kernels require writing ISRs (or at least ISR "wrappers") in assembly.
The one thing you should remember when writing ISRs is to call the macro QK_ISR_ENTRY()
at the beginning of every ISR, and the macro QK_ISR_EXIT()
at the end of every ISR. The following code snipped illustrates the use of these macro in the SysTick_Handler()
:
extern "C" void SysTick_Handler(void) { QK_ISR_ENTRY(); // inform the QK kernel of entering the ISR #ifdef Q_SPY uint32_t volatile dummy = SysTick->CTRL; // clear the COUNTFLAG in SysTick l_tickTime += l_tickPeriod; // account for the clock rollover #endif QF::tick(); // process all armed time events QK_ISR_EXIT(); // inform the QK kernel of exiting the ISR }
More Information
Of course, the simple DPP example barely scratches the surface of QP/QM capabilities. The active object model of computation with advanced hierarchical state machines underlying QP is very powerful and uniquely suitable for programming complex behavior, such as in robotics. For an example of an advanced QP application for mbed, please refer to the article "Design and implementation of software architecture behavioral-based robot control system using Active Object Computing Model"
The ultimate resource for QP/QM is the state-machine.com website, which provides the latest updates, resources, and support for QP.
5 comments on Building Applications with QP (qp_dpp Example):
Please log in to post comments.
When I comment out the #define Q_SPY line of code I get this error when I try to compile:
What does that mean? How can I fix it?