State charts can provide you with software quality insurance

Statecharts [1][2] are a well known design method to develop embedded systems. Several articles have been written explaining state machines, their visual representation in UML and how to implement them in different programming languages.

It is also well known that the later a bug was found in the development process the more expensive it is to fix it with costs that rise dramatically and when tracked graphically, exhibit hockey stick like increases, with the development phase on the x-axis and cost per defect on the y-axis. However, statechart models can be used to increase software quality in the different development phases.

Reasons why all embedded developers should know statecharts
Statecharts allow designing the dynamic behaviour of a device: Parts of an embedded device can be often modelled as state machine due to the reactive nature of embedded devices. Devices react to some kind of external or internal stimuli which leads to an action and, eventually, to a change of state.

Statecharts provide a good level of abstraction: Many people with different technical background understand statechart diagrams. This is important because for the development of an embedded system often different engineering disciplines come together.

Figure 1: A statechart has a good level of abstraction and is much easier to understand than the corresponding C-code.

Therefore statecharts are a very good basis to discuss the modelled behaviour or requirements in design reviews with colleagues or customers. Compare the following simple statechart of Figure 1 above to my C implementation of it (Click here to download). The state chart is much easier to understand.

Reason #1: Statecharts are useful in all development phases. Statecharts allow finding defects already in the design phase. To decrease cost of poor quality it is important to find defects as early as possible in the development process.

During the design usually defects related to unclear, incomplete or missing requirements are found. Such defects can lead to very costly redesigns or even to the reconstruction of the system if they are found not before the system test. Statecharts open a number of possibilities to find defects early in the process.

Reason #2: Statecharts allow simulation of the modelled behavior. It is easily possible to execute a statechart in a simulator and allow the user to send events to the machine and observe how the statechart reacts to the sent stimuli. This way the user can interactively test the model and improve it where necessary.

Reason #3: Robustness of statecharts can be automatically checked on model level. In the hardware design or PCB layout automatic design rule checks are very common. For software designs this is not yet common. Software design rules needs to be defined, hand made checks are time-consuming and the result is very dependent on the reviewer.

In practice a tool is needed to ensure that checks are really performed. For UML statecharts the OMG has specified a set of well-formedness rules within the UML specification [4]. These rules as well as a number of additional rules [5] can be automatically performed by a model checker.

The following enumeration lists possible rules:

State related:
- State names must be unique and shall conform to a defined naming schema (e.g. start with a capital S, must not contain spaces to be a valid C-name)
- States must be connected by a sequence of transitions outgoing from an initial state (connectivity).
- States should have not only incoming or even no transitions at all (isolated states).
- Composite states should have more than one child state. If only one child state is defined the composition is superfluous and just creates unnecessary complexity.
- Initial states must be defined on every state hierarchy and must have exactly one outgoing transition.
- Final states must only have incoming transitions.

Choice related:
- A choice must have only one incoming transition
- A choice should have at least two outgoing transitions otherwise it is useless and should be replaced with a normal transition.
- Every outgoing transition from a choice must have a guard defined
- One default transition must be specified for a choice state - i.e. the guard is defined as 'else' (default from choice).

Some rules seem to be trivial but are nevertheless very useful to check. Other rules are very difficult to check on source code level (if possible at all) but can be easily checked on model level.

Figure 2: Example of state chart with a number of different model problems

Figure 2 above shows a statechart with several defects. Do you find them all? A model checker can find them automatically. They include:

- The state name of the composite state is missing.
- There is no default state on the top-level.
- S2 is not reachable as transitions triggered by the same event (here ev1) but located deeper in the state hierarchy have priority.
- The two transitions triggered by ev11 leaving S11 are ambiguous as one has no guard defined and the other one has.
- No default transition leaving the choice state is defined.

Reason #4: Automatic code-generation reduces coding errors. Once the statechart was checked the implementation can start. It is highly recommended not to code the statemachine by hand but let a tool generate the code for you. Automatic code generation has many benefits especially if a model checker is integrated in the generator and can perform a large number of checks automatically.

Especially composite state charts can be tricky to code by hand. And latest when transitions or states have to be added because of an additional requirement one wishes to have a generator at hand taking over all the error-prone placement of entry, exit and action code associated with states or transitions.

It is important of course that the code generator was developed for the embedded domain. (i.e. it produces efficient but readable code which can be understood from the developer). A number of requirements for such a generator were listed in [3].

Automatic code generation does not make source code analysis (SCA) needless. SCA technology has been evolving for more than two decades, and well known tools such as PCLint are used by embedded software developers in virtually every industry. Both model checking and SCA complement each other quite well. It is important to mention that a code generator shall generate code that is not in conflict with used SCA tools.

Reason #5: Test cases can be automatically derived from the model. There are several articles about testing state machines, but the one written by Martin Gomez [6] nicely summarizes the usually used approach:

"The beauty of coding even simple algorithms as state machines is that the test plan almost writes itself. All you have to do is to go through every state transition. I usually do it with a highlighter in hand, crossing off the arrows on the state transition diagram as they successfully pass their tests ... This requires a fair amount of patience and coffee, because even a mid-size state machine can have 100 different transitions. However, the number of transitions is an excellent measure of the system's complexity."

Based on a statechart model a tool can take over this time consuming manual task of defining routes through the statechart ensuring 100% transition coverage. Implementing the test cases is a task that you still have to do. But a good code generator can also support you there by automatically generate trace code if you need it for test purposes or post mortem analysis.

For the trivial example in Figure 1, above a path with 100% coverage is as follows:

Summary
As you have seen there are many good reasons to create statechart models in your next project and use them throughout the development process. Several good general purpose UML tools exist to efficiently model state machines. (It is not recommended to just draw them with a general purpose drawing tool).

The model can then be used for design reviews, advanced model checking, code- and testcase generation as described above. I strongly vote for automatic source code generation based on the graphical UML model and not creating code directly by hand. This ensures consistency between design and code.

Peter Mueller has been an embedded systems developer for nearly 15 years, involved in projects in the area of public transportation, instrumentation and process automation. During this time Peter was involved in several initiatives to improve the embedded software quality. He can be reached at pmueller@sinelabore.com.