State machine communication

From Tekkotsu Wiki

Jump to: navigation, search

A common problem in state machine programming is how to share information among state nodes, or between multiple invocations of the same state node. There are several solutions.

Contents

This article is part of the State Machines series.


State Signaling

State signaling is the preferred method of communicating among state nodes when one simply needs to transmit information from a node to its successor. (If the information must be available to many nodes then a shared variable is more convenient; see the next section.) State signaling is also a way of combining control flow with information transmission.

How it works: to send information of type T, the transmitting node calls postStateSignal<T>, which posts a DataEvent<T> containing the information. A SignalTrans<T> transition, abbreviated =S<T>=>, connects the transmitting and receiving nodes; it fires in response to the DataEvent. The receiving node's doStart() method can examine the event variable and call extractSignal<T> to retrieve the information. Example:

$nodeclass SignalDemo : StateNode {

  $nodeclass Sender : StateNode : doStart {
    cout << "Transmitting an integer value." << endl;
    postStateSignal<int>(5);
  }

  $nodeclass Receiver : StateNode : doStart {
    int value = extractSignal<int>(event);
    cout << "Received value " << value << endl;
  }

  virtual void setup() {
    $statemachine{
      Sender =S<int>=> Receiver
    }
  }

}

Shared Variables

When information must be shared among multiple nodes in a state machine, the preferred solution is shared variables. The state machine shorthand makes these very easy to set up. Variables are declared in the parent state node using a $provide directive, and can then be referenced by any of the descendant nodes using $reference.

See the article on State machine shorthand: $provide and $reference for an example of how to set up and use shared variables.

Static Variables

Static variables are another approach to shared variables. They're less elegant and a bit more cumbersome to use, but they allow completely arbitrary patterns of communication. In the example below, th

// File CountButtonPresses.h.fsm

$nodeclass CountButtonPresses : StateNode {
  static int count;

  virtual void doStart() {
    erouter->addListener(this, EventBase::buttonEGID, RobotInfo::GreenButOffset, EventBase:activateETID);
  }

  virtual void doEvent() { ++count; }

}
// File CountButtonPresses.cc

int CountButtonPresses::count = 0;

A user program that made use of the CountButtonPresses class could access its counter by referring to CountButtonPresses::count.