May 24, 2006
UML Statecharts at $10.99Coding a Statechart in C
Contrary to popular belief, you don't need big code-synthesizing tools to translate UML statecharts to efficient and highly maintainable code. The implementation strategy I use to hand-code the PELICAN crossing statechart in Figure 2 in portable C is based on QP-nano, a generic "event processor" from my company Quantum Leaps. Actually QP-nano is more than just an event processor; it is a complete platform for executing concurrent state machines. Besides the optimized hierarchical event processor, QP-nano also provides event passing mechanism, event queuing, time event generation (timers), and a simple non-preemptive, prioritized scheduler to execute state machines in run-to-completion (RTC) fashion. All these services require about 1300 bytes of code (ROM) and just a few bytes of RAM on the 8051.
QP-nano has been designed for small systems with limited RAM. In this minimal version, events are represented as structures containing the byte-wide enumerated type of the event, such as TIMEOUT or PED_WAITING, which in the UML is called the "signal." Optionally, QP-nano lets every event have a single scalar event parameter. Event parameters are useful to convey the quantitative information associated with the event. For example, an ADC conversion might generate an event with the signal ADC_READY and the parameter containing the value produced by the ADC.
Each state in QP-nano is represented as a C function called a "state handler" function. The job of QP-nano is to invoke these state handler functions in the right order to process events according to the UML semantics.
A state handler function is a regular C function that takes the state machine pointer as the argument and returns a pointer to another state handler function, which is typedefed as QSTATE in the QP-nano header file qpn.h. You need to structure your state handler functions such that they return the pointer to the superstate handler, if they don't handle the current event, or a NULL-pointer, if they handle the current event. QP-nano uses this information to "learn" about the nesting of states to process events hierarchically and correctly execute state transitions.
To determine what elements belong a given state handler function, you first need to look up the state in the diagram and follow around the state's boundary. You need to implement all transitions originating at the boundary, any entry and exit actions defined directly in this state, as well as all internal transitions enlisted directly in the state. Additionally, if there is an initial transition embedded directly in the state, you need to implement it as well. You don't worry about any substates nested in the given state. These substates are implemented in their own state handler functions.
Take, for example, the state carsGreen in Figure 2. This state has one transition TIMEOUT originating at its boundary, an exit action and the initial transition to the substate carsGreenNoPed. The state carsGreen nests directly inside carsEnabled.
|
|
||||||||||||||||||||||||||||||
|
|
|
|