-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathblink.qm
448 lines (375 loc) · 13.2 KB
/
blink.qm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
<?xml version="1.0" encoding="UTF-8"?>
<model version="5.1.0" links="1">
<documentation>About this example:
-------------------
Simple "Blinky" console application for workstations (Windows, Linux, MacOS)
(see "QM Tutorial" at: https://www.state-machine.com/qm/gs_tut.html)
This example demonstrates:
- Active object (Blinky) 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
Running the example:
--------------------
This example is a simple console application, which you can run from a terminal.
For more QM examples for QP/C see:
https://www.state-machine.com/qpc/exa.html</documentation>
<!--${qpc}-->
<framework name="qpc"/>
<!--${AOs}-->
<package name="AOs" stereotype="0x02">
<!--${AOs::Blinky}-->
<class name="Blinky" superclass="qpc::QActive">
<!--${AOs::Blinky::timeEvt}-->
<attribute name="timeEvt" type="QTimeEvt" visibility="0x02" properties="0x00"/>
<!--${AOs::Blinky::SM}-->
<statechart properties="0x01">
<!--${AOs::Blinky::SM::initial}-->
<initial target="../1">
<action>(void)par; /* unused parameter */
/* arm the private time event to expire in 1/2s
* and periodically every 1/2 second
*/
QTimeEvt_armX(&me->timeEvt,
BSP_TICKS_PER_SEC/2,
BSP_TICKS_PER_SEC/2);</action>
<initial_glyph conn="2,3,5,1,20,4,-4">
<action box="0,-2,6,2"/>
</initial_glyph>
</initial>
<!--${AOs::Blinky::SM::off}-->
<state name="off">
<entry>BSP_ledOff();</entry>
<!--${AOs::Blinky::SM::off::TIMEOUT}-->
<tran trig="TIMEOUT" target="../../2">
<tran_glyph conn="2,14,3,1,18,6,-2">
<action box="0,-2,8,2"/>
</tran_glyph>
</tran>
<state_glyph node="2,5,16,11">
<entry box="1,2,12,4"/>
</state_glyph>
</state>
<!--${AOs::Blinky::SM::on}-->
<state name="on">
<entry>BSP_ledOn();</entry>
<!--${AOs::Blinky::SM::on::TIMEOUT}-->
<tran trig="TIMEOUT" target="../../1">
<tran_glyph conn="2,28,3,1,20,-18,-4">
<action box="0,-2,8,2"/>
</tran_glyph>
</tran>
<state_glyph node="2,18,16,12">
<entry box="1,2,12,4"/>
</state_glyph>
</state>
<state_diagram size="26,32"/>
</statechart>
</class>
<!--${AOs::Blinky_ctor}-->
<operation name="Blinky_ctor" type="void" visibility="0x00" properties="0x01">
<documentation>The Blinky "constructor" is provided outside of the Blinky class, so that it can be used independently from the class. This is part of the "opaque pointer" design idiom.</documentation>
<code>Blinky *me = (Blinky *)AO_Blinky;
QActive_ctor(&me->super, Q_STATE_CAST(&Blinky_initial));
QTimeEvt_ctorX(&me->timeEvt, &me->super, TIMEOUT_SIG, 0U);</code>
</operation>
</package>
<!--${.}-->
<directory name=".">
<!--${.::blinky.c}-->
<file name="blinky.c">
<text>#include "qpc.h" /* QP/C framework API */
#include "bsp.h" /* 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 = &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 "qpc.h" /* QP/C framework API */
#include "bsp.h" /* Board Support Package interface */
#include <stdio.h> /* for printf()/fprintf() */
#include <stdlib.h> /* for exit() */
void BSP_init(void) {
printf("Simple Blinky example\n"
"QP/C version: %s\n"
"Press Ctrl-C to quit...\n",
QP_VERSION_STR);
}
void BSP_ledOff(void) { printf("LED OFF\n"); }
void BSP_ledOn(void) { printf("LED ON\n"); }
/* 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, "Assertion failed in %s:%d", module, loc);
exit(-1);
}</text>
</file>
<!--${.::main.c}-->
<file name="main.c">
<text>#include "qpc.h" /* QP/C framework API */
#include "bsp.h" /* 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 ("$(wildcard $(BIN_DIR))","")
$(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) $< > $@
$(BIN_DIR)/%.d : %.cpp
$(CPP) -MM -MT $(@:.d=.o) $(CPPFLAGS) $< > $@
$(BIN_DIR)/%.o : %.c
$(CC) $(CFLAGS) $< -o $@
$(BIN_DIR)/%.o : %.cpp
$(CPP) $(CPPFLAGS) $< -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>