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. 🙂

8 thoughts on “A boost::statechart example”

  1. Thanks for this example! Simple to help me get started and works.

    When I tried it, I found you are missing a semicolon on line 30:

    struct EvToggleLight : sc::event {}; // added semicolon

  2. Thanks for the example. One of my reasons for not using Boost Statecharts is that the examples seemed to become complicated pretty quickly. This helped a lot.

  3. I am getting the followin errors on compiling this example:

    > g++ light.cpp
    In file included from /usr/include/boost/cast.hpp:50,
    from /usr/include/boost/statechart/event.hpp:15,
    from light.cpp:1:
    /usr/include/boost/limits.hpp: In function `static long_long_type numeric_limits::min()’:
    /usr/include/boost/limits.hpp:47: `__LONG_LONG_MAX__’ undeclared (first use this function)
    /usr/include/boost/limits.hpp:47: (Each undeclared identifier is reported only once
    /usr/include/boost/limits.hpp:47: for each function it appears in.)
    In file included from light.cpp:2:
    /usr/include/boost/statechart/state_machine.hpp: In function `static class boost::statechart::detail::history_key boost::statechart::detail::history_key::make_history_key()’:
    /usr/include/boost/statechart/state_machine.hpp:186: parse error before `::’
    /usr/include/boost/statechart/state_machine.hpp: At top level:
    /usr/include/boost/statechart/state_machine.hpp:362: no class template named `iterator’ in `std’
    /usr/include/boost/statechart/state_machine.hpp: In method `void boost::statechart::state_machine::clear_shallow_history()’:
    /usr/include/boost/statechart/state_machine.hpp:453: parse error before `::’
    /usr/include/boost/statechart/state_machine.hpp:453: template argument 1 is invalid
    /usr/include/boost/statechart/state_machine.hpp:453: confused by earlier errors, bailing out

    1. Which GCC version are you using? I’ve just compiled the example successfully with boost 1.47 and LLVM GCC 4.2, but at least any GCC 4.x version should work as well. I’ve even used GCC 3.3 with boost statecharts and never ran into problems.

  4. Thanks! Like a previous commenter, I was a bit put off using Boost statecharts, but your example does help a lot to lower the “threshold”.

  5. Dirk Raffel,
    Good example, can you suggest a site where I can download a verison of the Boost Library for Visual C++ 12 desktop ? To using for learning the Boost Library State Chart functionality?
    Regards,
    Stephen

Leave a Reply