Designing a state machine to solve a problem

This article will take a look at how to design a state machine from a general problem description. As a starting point we will use a classical example taken from a textbook on hardware design. As we will see, there is usually more than one way of designing a state machine to solve a specific problem.

The basic principle

State machines are often used to solve certain kinds of control-oriented problems where the control flow can be pictured as moving through a set of distinct states. There is a number of different definitions and practical descriptions of what a state machine is. At a theoretical level a state machine is a kind of automata that responds to some kind of stimuli by changing state. Matching of a specific regular expression can for example be described as such an automata that reacts to the input string by moving trough a set of states. If the goal state is reached, the input string matches the regular expression.

In control software, it is common to base the state machine computational model on finiteness and determinism, which basically means that the number of possible states or state combinations is finite and that the state machine can be in only one state at a time. We will later see that the one-state-at-a-time rule can be relaxed, but the important thing is that current state is a deterministic property.

If you are new to state machines implemented in software, the most important concepts are the following:

States: a state can be viewed as a shorthand description of the current situation in the system. For a simple example, consider a peripheral device that may have the following top-level operating modes: on, off or standby.

Events: An event is an input message to the state machine. The event may cause the state machine to change state. Pressing the On button on a TV set in standby mode is a kind of event that hopefully brings the TV back to life, or rather to the on state.

Transitions: A transition is a directed path from one state to another state. The transition is typically labeled with an event name indicating that the transition will be taken if the specified event occurs when the state machine is in the start state of the transition. The end result is that the state machine changes state to the goal state of the transition. To complicate matters, or rather to increase the expressive power of the state machine notation, a transition can be guarded by guard conditions that must be fulfilled for the transition to be taken.

 

Actions: An action is an activity to be performed by the state machine at a given point in time. Typically an action carries out some task on the environment, like reading or writing an I/O device or similar. Actions can be associated with transitions, or they can be specified as enter and exit actions on specific states.

 

These concepts are fundamental to the formalized approach to state machine design that we can find as a subset of the UML modeling language.

A bit beyond the basics

We will now take a look at a classic textbook example of a state-oriented problem and try to find a suitable state machine implementation. Actually, we look at two different solutions to show that there is no best solution to a particular problem. Both solutions will have their merits and demerits and if you would actually chose one before the other or try to find a completely different solution depends on how you value the trade-offs. The problem is formulated like this:

"A busy highway is intersected by a little-used farm road. Detectors are placed along the farm road to raise the signal C as long as a vehicle is waiting to cross the highway. The traffic light controller should operate as follows. As long as no vehicle is detected on the farm road, the lights should remain green in the highway direction. If a vehicle is detected on the farm road, the highway lights should change from yellow to red, allowing the farm road lights to become green. The farm road lights stay green only as long as a vehicle is detected on the farm road and never longer than a set interval to allow the traffic to flow along the highway. If these conditions are met, the farm road lights change from green to yellow to red, allowing the highway lights to return to green. Even if vehicles are waiting to cross the highway, the highway should remain green for a set interval. [From KATZ, Randy H., Contemporary Logic Design. University of California, Berkeley. 1994]"

This exercise is written with a hardware perspective in mind, so we will grant us some artistic freedom in how we interpret some of the information to better suit a software environment. Note that the example uses the convention that yellow light is always shown by itself. Some parts of the world use different conventions. But this does not really affect the difficulty of the problem; it merely simplifies for us to keep track of the possible color combinations.

There is a quite simple approach to designing state machines that can be described as follows:

  1. Identify events and actions
  2. Identify states
  3. Group by hierarchy
  4. Group by concurrency
  5. Add transitions
  6. Add synchronizations

This is not a recipe with an exact order that you must follow to succeed. But starting by looking at the problem with your events and actions glasses on, with an eye towards possible states will definitely help when structuring your solution. And this holds true regardless of what tools and implementation methods you choose.

Digging in

So we start by examining the problem description looking for possible events and actions. What constitutes an event in a state machine context? In short an event is a kind of trigger that potentially can make the state machine change state and perform some action. In the traffic light scenario we can find a number of potential events:

  • The arrival of traffic on the farm road is an event that has meaning to the functioning of the traffic light.
  • There are a few timing intervals involved in the description:
  • The minimum time the highway light stays green. This can also be used as the fixed time for the farm road light to stay green in the event of traffic.
  • The delay when switching to and from yellow light on both roads.

The delay intervals are not event in themselves, but the expiration of an interval can be viewed as an event. In effect this leaves us with two events, one long-interval-event for the green period on both roads and one event for the short uniform delay when transitioning trough the light sequence from red to green and vice versa.

This leaves us with three events which we can call FarmRoadTrafficEvent, LongTimerEvent and ShortTimerEvent.

So, what makes up an action in the problem at hand? Changing the color of the traffic lights is a typical action. The only question is whether it is one or two actions to change the light on both roads. The answer is that this is really a convenience issue. We can regard it as two different actions, where each action takes care of one road, or we can see it as one action. I choose to view it as two distinct actions, for reasons that might become apparent later on. I choose to call the actions SetFarmRoadLight() and SetHighwayLight()—each action takes a color parameter indicating the desired display color.

The idea here is that the events we have chosen will trigger changes in certain situations in what colors the traffic lights display.

Further, we need some way to keep track of the timing intervals, so we introduce a special action called a timer action whose purpose it is to start a counting timer for a specified interval and keep track of an event to be triggered when the timer expires. To make it simple we call this timer action TimerAction().

To get a grip on the control logic for the traffic light system we need to look into possible states and transitions between them. The first solution will use the observations that:

At any given point in time the traffic lights will show one of the following color combinations: {GREEN, RED}, {YELLOW, RED}, {RED, RED}, {RED, YELLOW}, {RED, GREEN}, {RED, YELLOW}. From the rules for how a traffic light should operate, it is clear that no other combinations should be allowed so as not to risk traffic passing the intersection from both roads at the same time. The first color in each pair is the highway light.

There is a fixed sequence in which the above color combinations will be shown: {GREEN, RED}, {YELLOW, RED}, {RED, RED}, {RED, YELLOW}, {RED, GREEN}, {RED, YELLOW}, {RED, RED}, {YELLOW, RED} and back to the first combination to start over.

It is not far-fetched to view each instance in the above sequence as a possible state, since it clearly embodies the actual state in the system at a given point in time. The transitions from state to state would then be triggered by the different timing intervals for each color changeover. If we assume that the sequence would start with green light for the highway, then the complete sequence is set off by a FarmRoadTrafficEvent.

The observant reader has noticed that we have a few duplicates in the above sequence of color combinations. For example the "both lights red" combination appears twice. Should we treat them as one state or two? I have chosen to treat all positions in the sequence as separate states. This decision has the implication that the transitions between states will be kept as simple as possible. Now we have the basics, namely a set of events, some actions and a set of candidate states. Below you can see a picture of the design in UML notation.

We have now drawn the proposed states in a circular fashion with transitions named by the corresponding events. The states also have entry actions to change the color of the lightning. As we can see, only the start state needs to set both lights to ensure a proper start to the sequence—for all the other states only one of the lights needs be changed from the previous state. This was my reason to use two different action functions! The start state is indicated by the transition from the initial state, which is denoted by the small circle in the upper left corner.

The semantics of UML uses the initial state and the transition from it to point to the desired start state, which means that we can express system initialization directly in the diagram. The transition is event-less and implicit at start-up.

From a state machine perspective, this design is almost complete but it lacks the handling of the minimum green interval on the highway. We can solve this in a number of ways, but the following solution seems easy enough.

  • Introduce a small amount of hierarchy into the model by creating a state machine inside the GreenH_RedF state. This state machine consists of two states plus the initial pseudo state. Whenever the surrounding state is entered, the NewGreen state will also be activated.
  • When the long timer interval that was initiated by entering GreenH_RedF expires we let the small state machine change state to FarmRoadEventOK. Now we know that the minimum green interval has passed for the green highway light and it should now be OK to "go green" on the farm road if there is traffic.
  • The last piece needed to keep the minimum green interval on the highway is a "guard"on the transition out of the GreenH_RedF state. This transition should only be fired if the FarmRoadEventOK state is activated. This can be expressed by a so called positive state condition or positive synchronization on the transition. The resulting changes can be seen in the following picture.

This solution is not perfect, since it does not address the fact that traffic which arrives on the farm road during the highway minimum green interval is stuck until another car arrives after the expiration of the interval. To solve this, we need to record any FarmRoadTrafficEvent that occurs during the green interval, so we can take appropriate action when the interval expires. We will not discuss a complete solution to the problem here, but if you try to design a solution the following bullets gives a hint for one possible way forward:

  • Introduce a state machine internal flag variable that is initialized to zero at each entry to the highway green state
  • Introduce an 'internal reaction' on the highway green state that sets the flag if a FarmRoadTrafficEvent is received, maybe with NewGreen as a guard state
  • An 'entry reaction' in the FarmRoadEventOK state that sends a signal if the flag is set when entering the state. (A signal is a special event that can be sent by the state machine itself.)
  • A transition to Yellow that triggers on the signal and starts the short interval timer.

There are other ways to deal with this problem, but they require a bit more UML syntax that I want to avoid here.

Software state machines differ from their hardware counterparts in that a software state machine has to detect and react to events in the hardware environment. This means that the computational model of software state machines is based on a detect event – react to event cycle that is made up of discrete steps, while a hardware state machine can react "simultaneously" to a changed signal on a certain pin. (Although the actual flipping of gates is of course a discrete activity on the bit level.) For example, a set of hardware signals can be combined in a gate to give one event when some combination of signals is met on the input side. In a software environment you have to either let your interrupt handlers and device drivers do the combination or let the state machine do the combination. (Unless you have control over the hardware design.)

A different state

As promised at the outset, we will take a short look at a completely different way of solving the same problem. This time we do not dig into the details to the same extent, but we start off by making a few observations based on the problem formulation:

  • The traffic light on the farm road and the traffic light on the highway can be viewed as two logically separate entities. This implies that they can also be modeled as two separate state machines.
  • There are a few dependencies between the two state machines: a) The farm road light must have some way to know when the highway light has switched to red, so it can start the transition to green light. This is accomplished by letting the highway state machine send a signal to the other state machine when it has reached the red state. b) The two lights also share timing intervals, as in the first model.

The state machines are modeled as two parallel regions in the same top-level state machine. This has the benefit that we can view the complete solution as a system built up of separate semi-independent components. Here is a picture of the solution:

This solution also has the benefit that we can color code the states to have the same display color as the traffic light have in that state. If we are lucky enough to have a tool that can simulate state machines on the design level we can see the traffic lights switch light color as we stimulate the state machines with events!

If you look closely at the design you can see that there are actually two kinds of short timer events. To see why, look at the yellow state in any of the state machines, it doesn't matter which one. Make the thought experiment to let both transitions out of the yellow state react on the same event. What happens then? We have introduced a contradiction into the model; since a deterministic state machine cannot react to an event by triggering more than one transition, we must have unique events on the transitions leaving the state. (Or they must at least have mutually exclusive guard conditions.)

This kind of problem can be hard to detect in a non-trivial design, especially if it is done with pen and paper. Finding out that the model has a contradiction error can be a painful experience if it occurs in run-time at a customer site. Using a design tool with model checking capabilities can greatly increase the confidence in your design working properly, so that is does not end up in a contradiction situation or a dead-lock or similar.

The fact that we need to handle two different short timer events makes the event handling of this solution a bit more complex than for the first solution, but on the other hand we need fewer states which might result in smaller run-time code size.

Rounding error

We have seen an example of how two different state machine designs can realize functionally equivalent solutions to the same problem formulation. Which one you chose—or if you come up with a totally different solution—is really not important, but generally it is a good thing to keep things as simple as possible. Using a graphical design tool for state machine design is a really neat way of raising the abstraction level, since a good tool supports such things as code generation, testing and simulation, and model checking capabilities.

By pure chance, IAR visualSTATE provides exactly these features.

This article is written by Anders Holmberg, Product Manager at IAR Systems.

© IAR Systems 1995-2016 - All rights reserved.