added README.md to lesson #39
MMS 3 years ago
parent f9c3f62e1b
commit e6ee7ca655

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

@ -7,8 +7,7 @@
void delay(int iter);
void delay(int iter) {
int volatile counter;
counter = 0;
int volatile counter = 0;
while (counter < iter) { // delay loop
++counter;
}

@ -716,7 +716,7 @@
</option>
<option>
<name>IlinkMapFile</name>
<state>0</state>
<state>1</state>
</option>
<option>
<name>IlinkLogFile</name>

@ -0,0 +1,41 @@
## Brought to you by:
[![Quantum Leaps](https://www.state-machine.com/attachments/logo_ql_400.png)](https://www.state-machine.com)
---------------------------------------------------------------------
[![TimeBomb model in QM](../img/thumbnail-39.jpg)](https://youtu.be/FCymm6PBtOs)
# About this example:
This is a model of a "TimeBomb" presented in
[lesson #39 "Optimal State Machine Implementation in C](https://youtu.be/FCymm6PBtOs)
of the ["Modern Embedded Programming" video course](https://www.youtube.com/playlist?list=PLPW8O6W-1chwyTzI3BHwBLbGQoPFxPAPM).
The "TimeBomb" state machine is independent from any specific board,
but assumes the presence of a few LEDs, which are controlled via a BSP
(Board Support Package)
This example demonstrates:
- Active object (TimeBomb) with state machine
- Board Support Package abstraction for portability
# TimbeBomb state machine
The TimeBomb state machine has been drawn in the freeware
[QM modeling tool](https://github.com/QuantumLeaps/qm):
[![TimeBomb model in QM](../img/TimeBomb.png)](https://github.com/QuantumLeaps/qm)
# Building the example:
To build this example, you will need the QP/C framework installed on your computer and the KEIL uVision toolset (could be the free edition).
# Running the example:
This example can be run on the TivaC LaunchPad board, but should
be also easy to port to other boards.
For more QM examples for QP/C see:
https://www.state-machine.com/qpc/exa.html
# How to Help this Project?
If you like this project, please give it a star (in the upper-right corner of your browser window):
![GitHub star](../img/github-star.jpg)

@ -1,27 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<model version="5.1.1" links="1">
<model version="5.2.2" links="1">
<documentation>About this example:
-------------------
Simple &quot;Blinky&quot; console application for workstations (Windows, Linux, MacOS)
(see &quot;QM Tutorial&quot; at: https://www.state-machine.com/qm/gs_tut.html)
This is a model of a &quot;TimeBomb&quot; presented in lesson #39 of the
&quot;Modern Embedded Programming&quot; video course. The &quot;TimeBomb&quot; state
machine is independent from any specific board, but assumes the
presence of a few LEDs, which are controlled via a BSP (Board
Support Package)
This example demonstrates:
- Active object (Blinky) with state machine
- Active object (TimeBomb) with state machine
- Board Support Package abstraction for portability
- BSP implementation for desktop OS (Windows, Linux, MacOS)
- Platform-independent main() function
- Makefile to build the generated code on desktop OS (Windows, Linux, MacOS)
- Customized tools for building the generated code directly from QM
Building the example:
---------------------
To build this example, you will need the QP/C framework installed on your computer and the GNU-GCC compiler. Both of them will be available if you install the QP-bundle from:
https://www.state-machine.com/#Downloads
To build this example, you will need the QP/C framework installed on your computer and the KEIL uVision toolset (could be the free edition).
Running the example:
--------------------
This example is a simple console application, which you can run from a terminal.
This example can be run on the TivaC LaunchPad board, but should
be also easy to port to other boards.
For more QM examples for QP/C see:
https://www.state-machine.com/qpc/exa.html</documentation>
@ -107,375 +105,8 @@ https://www.state-machine.com/qpc/exa.html</documentation>
<entry box="1,2,17,3"/>
</state_glyph>
</state>
<state_diagram size="68,80"/>
<state_diagram size="50,74"/>
</statechart>
</class>
<!--${AOs::Blinky_ctor}-->
<operation name="Blinky_ctor" type="void" visibility="0x00" properties="0x01">
<documentation>The Blinky &quot;constructor&quot; is provided outside of the Blinky class, so that it can be used independently from the class. This is part of the &quot;opaque pointer&quot; design idiom.</documentation>
<code>Blinky *me = (Blinky *)AO_Blinky;
QActive_ctor(&amp;me-&gt;super, Q_STATE_CAST(&amp;Blinky_initial));
QTimeEvt_ctorX(&amp;me-&gt;timeEvt, &amp;me-&gt;super, TIMEOUT_SIG, 0U);</code>
</operation>
</package>
<!--${.}-->
<directory name=".">
<!--${.::blinky.c}-->
<file name="blinky.c">
<text>#include &quot;qpc.h&quot; /* QP/C framework API */
#include &quot;bsp.h&quot; /* Board Support Package interface */
/* ask QM to declare the Blinky class --------------------------------------*/
$declare${AOs::Blinky}
/* instantiate the Blinky active object ------------------------------------*/
static Blinky l_blinky;
QActive * const AO_Blinky = &amp;l_blinky.super;
/* ask QM to define the Blinky class ---------------------------------------*/
$define${AOs::Blinky_ctor}
$define${AOs::Blinky}</text>
</file>
<!--${.::bsp.h}-->
<file name="bsp.h">
<text>#ifndef BSP_H
#define BSP_H
/* a very simple Board Support Package (BSP) -------------------------------*/
enum { BSP_TICKS_PER_SEC = 100 }; /* number of clock ticks in a second */
void BSP_init(void);
void BSP_ledOff(void);
void BSP_ledOn(void);
/* define the event signals used in the application ------------------------*/
enum BlinkySignals {
TIMEOUT_SIG = Q_USER_SIG, /* offset the first signal by Q_USER_SIG */
MAX_SIG /* keep last (the number of signals) */
};
/* active object(s) used in this application -------------------------------*/
extern QActive * const AO_Blinky; /* opaque pointer to the Blinky AO */
$declare${AOs::Blinky_ctor}
#endif /* BSP_H */</text>
</file>
<!--${.::bsp.c}-->
<file name="bsp.c">
<text>/* Board Support Package implementation for desktop OS (Windows, Linux, MacOS) */
#include &quot;qpc.h&quot; /* QP/C framework API */
#include &quot;bsp.h&quot; /* Board Support Package interface */
#include &lt;stdio.h&gt; /* for printf()/fprintf() */
#include &lt;stdlib.h&gt; /* for exit() */
void BSP_init(void) {
printf(&quot;Simple Blinky example\n&quot;
&quot;QP/C version: %s\n&quot;
&quot;Press Ctrl-C to quit...\n&quot;,
QP_VERSION_STR);
}
void BSP_ledOff(void) { printf(&quot;LED OFF\n&quot;); }
void BSP_ledOn(void) { printf(&quot;LED ON\n&quot;); }
/* callback functions needed by the framework ------------------------------*/
void QF_onStartup(void) {}
void QF_onCleanup(void) {}
void QF_onClockTick(void) {
QF_TICK_X(0U, (void *)0); /* QF clock tick processing for rate 0 */
}
void Q_onAssert(char const * const module, int loc) {
fprintf(stderr, &quot;Assertion failed in %s:%d&quot;, module, loc);
exit(-1);
}</text>
</file>
<!--${.::main.c}-->
<file name="main.c">
<text>#include &quot;qpc.h&quot; /* QP/C framework API */
#include &quot;bsp.h&quot; /* Board Support Package interface */
Q_DEFINE_THIS_FILE
/* the main function -------------------------------------------------------*/
int main() {
static QEvt const *blinky_queueSto[10]; /* event queue buffer for Blinky */
QF_init(); /* initialize the framework */
BSP_init(); /* initialize the BSP */
/* instantiate and start the Blinky active object */
Blinky_ctor(); /* in C you must explicitly call the Blinky constructor */
QACTIVE_START(AO_Blinky, /* active object to start */
1U, /* priority of the active object */
blinky_queueSto, /* event queue buffer */
Q_DIM(blinky_queueSto), /* the length of the buffer */
(void *)0, 0U, /* private stack (not used) */
(QEvt *)0); /* initialization event (not used) */
return QF_run(); /* let the framework run the application */
}</text>
</file>
<!--${.::Makefile}-->
<file name="Makefile">
<text># Makefile for building QP/C application on Windows and POSIX hosts
#
# examples of invoking this Makefile:
# building configurations: Debug (default), Release, and Spy
# make
# make CONF=rel
# make CONF=spy
# make clean # cleanup the build
# make CONF=spy clean # cleanup the build
#
# NOTE:
# To use this Makefile on Windows, you will need the GNU make utility, which
# is included in the QTools collection for Windows, see:
# https://sourceforge.net/projects/qpc/files/QTools/
#
#-----------------------------------------------------------------------------
# project name:
#
PROJECT := blinky
#-----------------------------------------------------------------------------
# project directories:
#
# list of all source directories used by this project
VPATH := . \
# list of all include directories needed by this project
INCLUDES := -I. \
# location of the QP/C framework (if not provided in an env. variable)
ifeq ($(QPC),)
QPC := ../../..
endif
#-----------------------------------------------------------------------------
# project files:
#
# C source files...
C_SRCS := \
blinky.c \
bsp.c \
main.c
# C++ source files...
CPP_SRCS :=
LIB_DIRS :=
LIBS :=
# defines...
# QP_API_VERSION controls the QP API compatibility; 9999 means the latest API
DEFINES := -DQP_API_VERSION=9999
ifeq (,$(CONF))
CONF := dbg
endif
#-----------------------------------------------------------------------------
# add QP/C framework (depends on the OS this Makefile runs on):
#
ifeq ($(OS),Windows_NT)
# NOTE:
# For Windows hosts, you can choose:
# - the single-threaded QP/C port (win32-qv) or
# - the multithreaded QP/C port (win32).
#
QP_PORT_DIR := $(QPC)/ports/win32-qv
#QP_PORT_DIR := $(QPC)/ports/win32
LIB_DIRS += -L$(QP_PORT_DIR)/$(CONF)
LIBS += -lqp -lws2_32
else
# NOTE:
# For POSIX hosts (Linux, MacOS), you can choose:
# - the single-threaded QP/C port (win32-qv) or
# - the multithreaded QP/C port (win32).
#
QP_PORT_DIR := $(QPC)/ports/posix-qv
#QP_PORT_DIR := $(QPC)/ports/posix
C_SRCS += \
qep_hsm.c \
qep_msm.c \
qf_act.c \
qf_actq.c \
qf_defer.c \
qf_dyn.c \
qf_mem.c \
qf_ps.c \
qf_qact.c \
qf_qeq.c \
qf_qmact.c \
qf_time.c \
qf_port.c
QS_SRCS := \
qs.c \
qs_64bit.c \
qs_rx.c \
qs_fp.c \
qs_port.c
LIBS += -lpthread
endif
#============================================================================
# Typically you should not need to change anything below this line
VPATH += $(QPC)/src/qf $(QP_PORT_DIR)
INCLUDES += -I$(QPC)/include -I$(QPC)/src -I$(QP_PORT_DIR)
#-----------------------------------------------------------------------------
# GNU toolset:
#
# NOTE:
# GNU toolset (MinGW) is included in the QTools collection for Windows, see:
# http://sourceforge.net/projects/qpc/files/QTools/
# It is assumed that %QTOOLS%\bin directory is added to the PATH
#
CC := gcc
CPP := g++
LINK := gcc # for C programs
#LINK := g++ # for C++ programs
#-----------------------------------------------------------------------------
# basic utilities (depends on the OS this Makefile runs on):
#
ifeq ($(OS),Windows_NT)
MKDIR := mkdir
RM := rm
TARGET_EXT := .exe
else ifeq ($(OSTYPE),cygwin)
MKDIR := mkdir -p
RM := rm -f
TARGET_EXT := .exe
else
MKDIR := mkdir -p
RM := rm -f
TARGET_EXT :=
endif
#-----------------------------------------------------------------------------
# build configurations...
ifeq (rel, $(CONF)) # Release configuration ..................................
BIN_DIR := build_rel
# gcc options:
CFLAGS = -c -O3 -fno-pie -std=c99 -pedantic -Wall -Wextra -W \
$(INCLUDES) $(DEFINES) -DNDEBUG
CPPFLAGS = -c -O3 -fno-pie -std=c++11 -pedantic -Wall -Wextra \
-fno-rtti -fno-exceptions \
$(INCLUDES) $(DEFINES) -DNDEBUG
else ifeq (spy, $(CONF)) # Spy configuration ................................
BIN_DIR := build_spy
C_SRCS += $(QS_SRCS)
VPATH += $(QPC)/src/qs
# gcc options:
CFLAGS = -c -g -O -fno-pie -std=c99 -pedantic -Wall -Wextra -W \
$(INCLUDES) $(DEFINES) -DQ_SPY
CPPFLAGS = -c -g -O -fno-pie -std=c++11 -pedantic -Wall -Wextra \
-fno-rtti -fno-exceptions \
$(INCLUDES) $(DEFINES) -DQ_SPY
else # default Debug configuration .........................................
BIN_DIR := build
# gcc options:
CFLAGS = -c -g -O -fno-pie -std=c99 -pedantic -Wall -Wextra -W \
$(INCLUDES) $(DEFINES)
CPPFLAGS = -c -g -O -fno-pie -std=c++11 -pedantic -Wall -Wextra \
-fno-rtti -fno-exceptions \
$(INCLUDES) $(DEFINES)
endif # .....................................................................
LINKFLAGS := -no-pie
#-----------------------------------------------------------------------------
C_OBJS := $(patsubst %.c,%.o, $(C_SRCS))
CPP_OBJS := $(patsubst %.cpp,%.o, $(CPP_SRCS))
TARGET_EXE := $(BIN_DIR)/$(PROJECT)$(TARGET_EXT)
C_OBJS_EXT := $(addprefix $(BIN_DIR)/, $(C_OBJS))
C_DEPS_EXT := $(patsubst %.o,%.d, $(C_OBJS_EXT))
CPP_OBJS_EXT := $(addprefix $(BIN_DIR)/, $(CPP_OBJS))
CPP_DEPS_EXT := $(patsubst %.o,%.d, $(CPP_OBJS_EXT))
# create $(BIN_DIR) if it does not exist
ifeq (&quot;$(wildcard $(BIN_DIR))&quot;,&quot;&quot;)
$(shell $(MKDIR) $(BIN_DIR))
endif
#-----------------------------------------------------------------------------
# rules
#
all: $(TARGET_EXE)
$(TARGET_EXE) : $(C_OBJS_EXT) $(CPP_OBJS_EXT)
$(CC) $(CFLAGS) $(QPC)/include/qstamp.c -o $(BIN_DIR)/qstamp.o
$(LINK) $(LINKFLAGS) $(LIB_DIRS) -o $@ $^ $(BIN_DIR)/qstamp.o $(LIBS)
$(BIN_DIR)/%.d : %.c
$(CC) -MM -MT $(@:.d=.o) $(CFLAGS) $&lt; &gt; $@
$(BIN_DIR)/%.d : %.cpp
$(CPP) -MM -MT $(@:.d=.o) $(CPPFLAGS) $&lt; &gt; $@
$(BIN_DIR)/%.o : %.c
$(CC) $(CFLAGS) $&lt; -o $@
$(BIN_DIR)/%.o : %.cpp
$(CPP) $(CPPFLAGS) $&lt; -o $@
.PHONY : clean show
# include dependency files only if our goal depends on their existence
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(MAKECMDGOALS),show)
-include $(C_DEPS_EXT) $(CPP_DEPS_EXT)
endif
endif
.PHONY : clean show
clean :
-$(RM) $(BIN_DIR)/*.o \
$(BIN_DIR)/*.d \
$(TARGET_EXE)
show :
@echo PROJECT = $(PROJECT)
@echo TARGET_EXE = $(TARGET_EXE)
@echo VPATH = $(VPATH)
@echo C_SRCS = $(C_SRCS)
@echo CPP_SRCS = $(CPP_SRCS)
@echo C_DEPS_EXT = $(C_DEPS_EXT)
@echo C_OBJS_EXT = $(C_OBJS_EXT)
@echo C_DEPS_EXT = $(C_DEPS_EXT)
@echo CPP_DEPS_EXT = $(CPP_DEPS_EXT)
@echo CPP_OBJS_EXT = $(CPP_OBJS_EXT)
@echo LIB_DIRS = $(LIB_DIRS)
@echo LIBS = $(LIBS)
@echo DEFINES = $(DEFINES)
</text>
</file>
</directory>
</model>

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<session version="5.2.1">
<item name="license"></item>
<group name="locked"/>
<group name="settings">
<item name="tabs">1</item>
<item name="windows">0</item>
<item name="grid">3</item>
<item name="backups">0</item>
</group>
<group name="windows">
<item id="AOs::TimeBomb::SM">0,0,583,1275,*</item>
</group>
<group name="search">
<item name="options">2032128</item>
<item name="replace">0</item>
</group>
<group name="vars"/>
<group name="tools">
<group name="tool">
<item name="icon">0</item>
<item name="title"></item>
<item name="command"></item>
<item name="args"></item>
<item name="dir"></item>
<item name="options">0</item>
</group>
<group name="tool">
<item name="icon">0</item>
<item name="title"></item>
<item name="command"></item>
<item name="args"></item>
<item name="dir"></item>
<item name="options">0</item>
</group>
<group name="tool">
<item name="icon">0</item>
<item name="title"></item>
<item name="command"></item>
<item name="args"></item>
<item name="dir"></item>
<item name="options">0</item>
</group>
<group name="tool">
<item name="icon">0</item>
<item name="title"></item>
<item name="command"></item>
<item name="args"></item>
<item name="dir"></item>
<item name="options">0</item>
</group>
<group name="tool">
<item name="icon">0</item>
<item name="title"></item>
<item name="command"></item>
<item name="args"></item>
<item name="dir"></item>
<item name="options">0</item>
</group>
</group>
</session>
Loading…
Cancel
Save