Deploying the Application on the Toolstick
Deploying the application on the Toolstick requires only providing the board-specific initialization and the time-tick interrupt, which must call the QP-nano function QF_tick()
to generate the TIMEOUT
events. The PELICAN example contains a small board support package (bsp.c) for the Toolstick, which has been modeled largely after the standard PWM_demo application that comes on the Toolstick CD.
The code accompanying this article contains an extensive README file explaining all the examples included and the usual workarounds for minor bugs in the demo tools and their incompatibilities. I just wanted to mention here that I ended up using the 4-KB KickStart(tm) 8051 compiler from IAR Systems, instead of the 2-KB demo version of the Keil 8051 compiler that comes with the Toolstick. Finally, because the memory footprint is of primary interest in this article, here are the numbers I've obtained with the IAR 8051 compiler optimized for size: QP-nano: 1254 bytes of CODE, 1 byte of DATA; application totals: 2712 bytes of CODE, 16 bytes of DATA, 88 bytes of IDATA (including 64 bytes of stack), 1 byte of BIT memory.
Reuse of Behavior in UML Statecharts
Statecharts achieve reuse of actions and transitions through a combination of hierarchy and "programming-by-difference" semantics. States may have substates that inherit the actions and transitions of their superstates, just as classes have subclasses that inherit the attributes and operations of their superclasses.
For example, a state diagram of a pocket calculator can be vastly simplified by introducing an abstract superstate "on" that contains most of the calculator states inside (see Figure 4).
To understand how the high-level transitions apply, assume that the user presses the CANCEL
button while the calculator state machine is in the result
state. The state result
does not pre-scribe how to handle the CANCEL
event. However, the CANCEL
event is not silently discarded, as it would be the case in the traditional FSM. Rather, because result
is now nested inside the on
superstate, the state machine attempts to handle the event at the higher level of state hierarchy of the on
state. Because UML statecharts support entry and exit actions on states, the self-transition CANCEL
in the on
state requires in this case exiting the result
state, exiting the on
state, en-tering the on
state again, taking the initial transition within the on
state, and finally entering the begin
state.
In summary, the transition CANCEL
took the state machine from state result
to state begin
, properly exiting and entering all the states on the way. Identical argumentation can be made for every substate of the on
superstate, so the single CANCEL
transition in the on
superstate replaces all low-level transitions that would be necessary in the traditional "flat" FSM without hierarchy.
As you can see, the semantics of hierarchical state nesting is based on the "programming-by-difference" principle. All substates of the on
superstate need only define the differences from the superstate, and otherwise can reuse the behavior by simply ignoring the commonly handled events, such as CANCEL
or OFF
.
M.S.
Conclusions
UML-style state machines can help you produce efficient, maintainable, testable systems with well understood behavior, rather than creating the usual "spaghetti" code littered with convoluted ifs and elses. In this article I've demonstrated that the technique is applicable to quite small systems, starting from about 4KB of ROM, and some 128 bytes of RAM.
Contrary to widespread misconceptions, you don't need big UML tools to take full advantage of the hierarchical state nesting and the guaranteed initialization and cleanup of states, which are the most important features of UML statecharts. In fact, manual coding of a nontrivial PELICAN crossing statechart turned out to be a rather simple exercise in following just a few straightforward rules. The implementation technique based on an "event processor", such as QP-nano, results in concise, highly maintainable code that truly reflects the statechart structure without any repetitions. The resulting state machine representation in C is flexible, allowing even sweeping changes in the state machine structure to be accomplished quite easily, at any stage of the project.
Once you design a system with UML statecharts, you will not want to go back to the "spaghetti" code or even to the traditional RTOS. Welcome to the 21st century.
References
IAR Embedded Workbench for 8051: KickStart Version.
Miro Samek is the Founder and President of Quantum Leaps, a provider of real-time, state machine-based application frameworks for embedded real-time systems, and author of "Practical Statecharts in C/C++" (CMP Books, 2002).