This QP-nano Tutorial is adapted from Chapter 1 of Practical UML Statecharts in C/C++, Second Edition
by Miro Samek, the founder and president of Quantum Leaps, LLC.
Prev: 5. Elaborating State Machines of Active Objects
Next: 7. Coding Hierarchical State Machines
In QP-nano, event signals are enumerated just like in the full-version QP. The only limitation is that signal values in QP-nano cannot exceed 255, because signals are always represented in a single byte.
In QP-nano, you cannot specify arbitrary event parameters, so you don't derive events as in full-version QP. Instead, all events in QP-nano are simply instances of the QEvent structure, which contains the fixed-size scalar parameter configured according to your definition of Q_PARAM_SIZE (see Listing Listing 3-2(2)). On the other hand, active objects in QP-nano are derived from the QActive base structure, just like they are in the full-version QP (see Encapsulation and Single Inheritance in C). One of the main concerns with respect to active object structures is to keep them encapsulated. In all QP-nano examples, including the "Fly 'n' Shoot" game, I demonstrate a technique to keep the active object structures and state machines completely opaque. I describe this technique in the explanation section following Listing 6-1, which shows the header file game.h included by all components of the "Fly 'n' Shoot" application.
Because events are explicitly shared among most of the application components, it is convenient to declare them in the separate header file game.h shown Listing 6-1. The explanation section immediately following the listing illuminates the interesting points.
Listing 6-1 Signals, event structures, and active object interfaces defined in file game.h.
(1) enum GameSignals { /* signals used in the game */ (2) TIME_TICK_SIG = Q_USER_SIG, /* published from tick ISR */ PLAYER_TRIGGER_SIG, /* published by Player (ISR) to trigger the Missile */ PLAYER_QUIT_SIG, /* published by Player (ISR) to quit the game */ GAME_OVER_SIG, /* published by Ship when it finishes exploding */ PLAYER_SHIP_MOVE_SIG, /* posted by Player (ISR) to the Ship to move it */ BLINK_TIMEOUT_SIG, /* signal for Tunnel's blink timeout event */ SCREEN_TIMEOUT_SIG, /* signal for Tunnel's screen timeout event */ TAKE_OFF_SIG, /* from Tunnel to Ship to grant permission to take off */ HIT_WALL_SIG, /* from Tunnel to Ship when Ship hits the wall */ HIT_MINE_SIG, /* from Mine to Ship or Missile when it hits the mine */ SHIP_IMG_SIG, /* from Ship to the Tunnel to draw and check for hits */ MISSILE_IMG_SIG, /* from Missile the Tunnel to draw and check for hits */ MINE_IMG_SIG, /* sent by Mine to the Tunnel to draw the mine */ MISSILE_FIRE_SIG, /* sent by Ship to the Missile to fire */ DESTROYED_MINE_SIG, /* from Missile to Ship when Missile destroyed Mine */ EXPLOSION_SIG, /* from any exploding object to render the explosion */ MINE_PLANT_SIG, /* from Tunnel to the Mine to plant it */ MINE_DISABLED_SIG, /* from Mine to Tunnel when it becomes disabled */ MINE_RECYCLE_SIG, /* sent by Tunnel to Mine to recycle the mine */ SCORE_SIG /* from Ship to Tunnel to adjust game level based on score */ }; /* active objects ..........................................................*/ (3) extern struct TunnelTag AO_Tunnel; (4) extern struct ShipTag AO_Ship; (5) extern struct MissileTag AO_Missile; (6) void Tunnel_ctor (void); (7) void Ship_ctor (void); (8) void Missile_ctor(uint8_t speed); /* common constants and shared helper functions ............................*/ . . .
QF_active[] array (see Listing 3-1(12)).struct TunnelTag) do not need to be defined globally in the application header file. The QF_active[] array needs only pointers to the active objects (see Listing 3-1(9-11)), which the compiler can resolve without knowing the full definition of the active object structure.I never declare active object structures globally. Instead, I declare the active object structures in the file scope of the specific active object module (e.g., struct TunnelTag is declared in the tunnel.c file scope). That way, I can be sure that each active object remains fully encapsulated.
Missile_ctor() takes the Missile speed parameter. Listing 3-1(13-15) shows that the constructors are called right at the beginning of main().Listing 6-2 Generating and posting events from the ISRs in bsp.c for the ARM-Cortex board.
(1) static void interrupt ISR_tmr(void) { /* 80x86 enters ISRs with int. locked */ (2) QF_tick(); /* process all armed time events */ (3) QActive_postISR((QActive *)&AO_Tunnel, TIME_TICK_SIG, 0); (4) QActive_postISR((QActive *)&AO_Ship, TIME_TICK_SIG, 0); (5) QActive_postISR((QActive *)&AO_Missile, TIME_TICK_SIG, 0); outp(0x20, 0x20); /* write EOI to the master PIC */ } . . .
QF_tick() from the system clock tick ISR.TIME_TICK event to all active objects that need to receive it.Prev: 5. Elaborating State Machines of Active Objects
Next: 7. Coding Hierarchical State Machines
Copyright © 2002-2010 Quantum Leaps, LLC. All Rights Reserved.
http://www.quantum-leaps.com
1.6.3