QP-nano  6.9.0
Real-Time Embedded Framework
Simple Blinky Application

The ultra-simple Blinky example is the embedded systems' equivalent of the venerable "Hello World!" program, that is, the simplest possible working QP application that does "something". In the case of Blinky, this "something" is blinking an LED at the rate of 1Hz, where an LED turns on and remains on for 0.5 seconds on then turns off and remains off for 0.5 seconds.

Blinky on EK-TM4C123GLX (TivaC LaunchPad)

The ultra-simple Blinky application, which consists of just one active object named Blinky, is intentionally kept small and illustrates only the most basic QP features, such as:

  • defining a simple Blinky active object (AO) class;
  • hand-coding the simple state machine of the Blinky AO;
  • using a periodic time event;
  • initializing the QP framework; and
  • starting an AO.

State Machine

The very simple state machine of the Blinky AO is shown in the figure below:

State Machine of the Blinky AO
  • 1 The top-most initial transition in this state machine arms a QP time event (QTimeEvt_armX()) to deliver the TIMEOUT signal every half second, so that the LED can stay on for one half second and off for the other half.

  • 2 The initial transition leads to state "off", which turns the LED off in the entry action (BSP_ledOff()).

  • 3 When the TIMEOUT event arrives in the "off" state, the "off" state transitions to the "on" state

  • 4 The "on" state turns the LED on in the entry action (BSP_ledOn()).

  • 5 When the TIMEOUT event arrives in the "on" state, the "on" state transitions back to "off", which cases execution of the entry action, in which the LED is turned off. From that point on the cycle repeats forever because the TIMEOUT events keep getting generated at the pre-determined rate.

State Machine Code

The Blinky state machine shown above is implemented in the blinky.c source file, as shown in the listing below. The code has been specifically organized not to access target resources directly, but instead encapsulate all such access in the calls to the BSP (Board Support Package). So for example, instead of turning the LED on and off by writing to a specific GPIO register on an embedded board, the code calls the BSP functions BSP_ledOn() and BSP_ledOff(). These functions can then be defined differently for each Target board (or even a desktop workstation), without the need to change the state machine code.

Note
The Blinky source code (blinky.c) is actually the same on all platforms, including Windows and the embedded boards. The only difference is in the Board Support Package (bsp.c), which is specific for the target.
1/*****************************************************************************
2* Product: Simple Blinky example
3* Last updated for version 5.4.0
4* Last updated on 2015-05-18
5*
6* Q u a n t u m L e a P s
7* ---------------------------
8* innovating embedded systems
9*
10* Copyright (C) Quantum Leaps, www.state-machine.com.
11*
12* This program is open source software: you can redistribute it and/or
13* modify it under the terms of the GNU General Public License as published
14* by the Free Software Foundation, either version 3 of the License, or
15* (at your option) any later version.
16*
17* Alternatively, this program may be distributed and modified under the
18* terms of Quantum Leaps commercial licenses, which expressly supersede
19* the GNU General Public License and are specifically designed for
20* licensees interested in retaining the proprietary status of their code.
21*
22* This program is distributed in the hope that it will be useful,
23* but WITHOUT ANY WARRANTY; without even the implied warranty of
24* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25* GNU General Public License for more details.
26*
27* You should have received a copy of the GNU General Public License
28* along with this program. If not, see <www.gnu.org/licenses/>.
29*
30* Contact information:
31* <www.state-machine.com/licensing>
32* <info@state-machine.com>
33*****************************************************************************/
34#include "qpn.h"
35#include "blinky.h"
36#include "bsp.h"
37
38//Q_DEFINE_THIS_FILE
39
40/*..........................................................................*/
41typedef struct BlinkyTag { /* the Blinky active object */
42 QActive super; /* inherit QActive */
43} Blinky;
44
45/* hierarchical state machine ... */
46static QState Blinky_initial(Blinky * const me);
47static QState Blinky_off (Blinky * const me);
48static QState Blinky_on (Blinky * const me);
49
50/* Global objects ----------------------------------------------------------*/
51Blinky AO_Blinky; /* the single instance of the Blinky AO */
52
53/*..........................................................................*/
54void Blinky_ctor(void) {
55 Blinky * const me = &AO_Blinky;
56 QActive_ctor(&me->super, Q_STATE_CAST(&Blinky_initial));
57}
58
59/* HSM definition ----------------------------------------------------------*/
60QState Blinky_initial(Blinky * const me) {
61 QActive_armX((QActive *)me, 0U,
62 BSP_TICKS_PER_SEC/2U, BSP_TICKS_PER_SEC/2U);
63 return Q_TRAN(&Blinky_off);
64}
65/*..........................................................................*/
66QState Blinky_off(Blinky * const me) {
67 QState status;
68 switch (Q_SIG(me)) {
69 case Q_ENTRY_SIG: {
70 BSP_ledOff();
71 status = Q_HANDLED();
72 break;
73 }
74 case Q_TIMEOUT_SIG: {
75 status = Q_TRAN(&Blinky_on);
76 break;
77 }
78 default: {
79 status = Q_SUPER(&QHsm_top);
80 break;
81 }
82 }
83 return status;
84}
85/*..........................................................................*/
86QState Blinky_on(Blinky * const me) {
87 QState status;
88 switch (Q_SIG(me)) {
89 case Q_ENTRY_SIG: {
90 BSP_ledOn();
91 status = Q_HANDLED();
92 break;
93 }
94 case Q_TIMEOUT_SIG: {
95 status = Q_TRAN(&Blinky_off);
96 break;
97 }
98 default: {
99 status = Q_SUPER(&QHsm_top);
100 break;
101 }
102 }
103 return status;
104}
#define Q_HANDLED()
Definition: qepn.h:370
#define Q_STATE_CAST(handler_)
Definition: qepn.h:340
#define Q_TRAN(target_)
Definition: qepn.h:346
#define Q_SIG(me_)
Definition: qepn.h:143
#define Q_ENTRY_SIG
Definition: qepn.h:382
uint_fast8_t QState
Definition: qepn.h:155
#define Q_SUPER(super_)
Definition: qepn.h:364
#define Q_TIMEOUT_SIG
Definition: qepn.h:391
QP-nano public interface including backwards-compatibility layer.
Definition: qfn.h:122
void QActive_ctor(QActive *const me, QStateHandler initial)
Definition: qfn.c:99
void QActive_armX(QActive *const me, uint_fast8_t const tickRate, QTimeEvtCtr const nTicks, QTimeEvtCtr const interval)
Definition: qfn.c:462
QState QHsm_top(void const *const me)
Definition: qepn.c:172

As you can see, the structure of the state machine is very clearly recognizable in this code. Please refer to the Application Note A Crash Course in UML State Machines for exact explanation of the state machine coding techniques.

Defining Active Object (AO) Class

  • hand-coding the simple state machine of the Blinky AO;
  • using a periodic time event;
  • initializing the QP framework; and
  • starting an AO.

Dining Philosophers Problem (DPP)