A boost::statechart example

How would you transform a statechart (David Harel statechart, or UML state diagram if you like) into executable C++ code? You can use one of the many free and commercial tools that are able to generate very efficient C or C++ code from statecharts, but you can also do so without needing such a tool: you might also consider using the Boost statechart library.

For a simple example, consider the following scenario :
Assume a controller has one push button switch wired to an input, and one lamp wired to an output. The first time the button is pressed the lamp must come on. The next time the button is pressed, the lamp must turn off. On the next press the lamp comes on, etc. etc. Don’t forget to allow for the button to be released before it is pressed again.

Sounds easy, doesn’t it? However, often the required behavior is not so trivial (when we’d like to restore previous state, or when reactions depend on the active state in many orthogonal regions). In this case, I typically use a statechart design. IMO this method scales up very well to large and complicated systems.

A possible solution for our example looks like this: We have two orthogonal regions, one region with two states for button pressed/released and another region with light on/off.
The statechart

As with many of the Boost libraries, boost::statechart is header-only and uses templates quite heavily. In general, the documentation is quite good, so don’t be afraid to read it. There is also an excellent tutorial for those just starting out, with plenty of examples.

So without further ado, here’s the source code that implements the statechart from above:

#include <boost/statechart/event.hpp>
#include <boost/statechart/state_machine.hpp>
#include <boost/statechart/simple_state.hpp>
#include <boost/statechart/state.hpp>
#include <boost/statechart/transition.hpp>
#include <boost/mpl/list.hpp>
#include <iostream>

using namespace std;

namespace sc = boost::statechart;
namespace mpl = boost::mpl;

struct EvPressButton : sc::event<EvPressButton>
{
  EvPressButton()
  {
    cout << "Button is pressed" << endl;
  }
};

struct EvReleaseButton : sc::event<EvReleaseButton>
{
  EvReleaseButton()
  {
    cout << "Button is released" << endl;
  }
};

struct EvToggleLight : sc::event<EvToggleLight> {};

struct Active;
struct Switch : sc::state_machine<Switch, Active> {};

struct ButtonReleased;
struct ButtonPressed;
struct LightOff;
struct LightOn;

struct Active: sc::simple_state<Active, Switch,mpl::list<ButtonReleased, LightOff> > {};
struct ButtonPressed : sc::state<ButtonPressed, Active::orthogonal<0> >
{
  typedef sc::transition<EvReleaseButton, ButtonReleased> reactions;
  ButtonPressed(my_context ctx) : my_base(ctx)
  {
    post_event(EvToggleLight());
  }
};

struct ButtonReleased : sc::simple_state<ButtonReleased, Active::orthogonal<0> >
{
  typedef sc::transition<EvPressButton, ButtonPressed> reactions;
};

struct LightOff : sc::simple_state<LightOff, Active::orthogonal<1> >
{
  typedef sc::transition<EvToggleLight, LightOn> reactions;
  LightOff()
  {
    cout << "Light is off" << endl;
  }
};

struct LightOn : sc::simple_state<LightOn, Active::orthogonal<1> >
{
  typedef sc::transition<EvToggleLight, LightOff> reactions;
  LightOn()
  {
    cout << "Light is on" << endl;
  }
};

int main()
{
  Switch sw;
  sw.initiate();
  for (int i = 0; i < 5; i++)
  {
    sw.process_event(EvPressButton());
    sw.process_event(EvReleaseButton());
  }
  return 0;
}

The output:

Light is off
Button is pressed
Light is on
Button is released
Button is pressed
Light is off
Button is released
Button is pressed
Light is on
Button is released
Button is pressed
Light is off
Button is released
Button is pressed
Light is on
Button is released

Which looks about right, I think. 🙂