Declaring State Machine Objects
While state handler functions specify the state machine behavior, and as such are represented in code only (ROM), they require a state machine object (RAM) to remember the current active state and the current event. These state machine objects are represented in QP-nano as C structures derived from the QActive structure, which is provided in QP-nano header file qpn.h. The "derivation of structures" means simply, that you need to literally embed the QActive structure as the first member of the derived structure. Listing Two shows the declaration of the Pelican structure. By a convention, I always name the parent structure member super_.
typedef struct PelicanTag Pelican; /* type definition for Pelican */ struct PelicanTag { QActive super_; /* derived from QActive */ uint8_t pedFlashCtr__; /* private pedestrian flash counter */ };
Looking at Listing Two, you should convince yourself that the "derivation of structures" simply means aligning the QActive object at the beginning of every Pelican object in memory. Such alignment allows treating every pointer to Pelican as a pointer to QActive at the same time, so any function designed to work with a pointer to QActive will work correctly if you pass to it a pointer to Pelican. In other words, all functions that QP-nano provides for QActive objects will work just fine for the derived Pelican (or Pedestrian) objects. You can think of this mechanism as single inheritance implemented in C.
Actually, when you look at the declaration of the QActive structure in the qpn.h header file, you will notice, that QActive itself is also derived from another structure QHsm. The QHsm structure represents a Hierarchical State Machine (HSM) and stores the current active state and the current event. QActive adds to this an event queue and a timer, which are both necessary elements of an independently executing state machine. In UML, such independently executing entities are called active objects, which explains the origin of the name QActive. The memory cost of QActive object is 6 to 10 bytes of RAM, depending on the size of the pointer-to-function and the configured size of the timer counter.
Of course, it doesn't matter what else you add in the derived structure after the super_ member. In Listing Two, I've declared additionally the pedFlashCtr__ counter, which the Pelican state machine uses for counting the number of flashes of the "don't walk" signal in the pedsFlash state (Figure 2).