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.
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.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().(1) static void interrupt tmrISR(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); outportb(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.
1.5.4