RunStateMachine -- Run control state machine


package require RunStateMachine

set sm [RunstateMachineSingleton %AUTO%]

$sm method


Provides the run control state machine singleton. Constructing a RunstateMachineSingleton encapsulates a single instance of a RunStateMachine so that all clients are assured of interacting with the same state machine object.

The state machine object has a well defined set of states and allowed transitions between those states. See STATES below for the set of allowed states and transitions.

By itself the state machine is not worth very much. The value comes from the ability to register Callout bundles with the state machine. See the CALLOUT BUNDLES for more about what a callback bundle is and how to create one.


The RunstateMachineSingleton object wraps a single application wide RunstateMachine and exposes all of its methods to its client. The methods described here are therefore actually RunstateMachine methods.

The methods below designated as TYPEMETHODS do not require an object to invoke.


This typemethod returns a Tcl list whose elements are the legal states the machine can be in. These are described in the STATES section below.

::RunstateMachine::listTransitions state

This typemethod accepts the name of a state returned from ::RunstateMachine::listState and returns a list consisting of the names of the valid state that can be reached from that state.


Return the current state of the state machine. This will be a state in the list returned by ::RunstateMachine::listStates


Returns a list consisting of the names of the currently registererd callout bundles. See CALLOUT BUNDLES below for more information about callout bundles. The list is provided in registration order which also correspondes to the callout order.

addCalloutBundle bundle-name ?before-bundle?

Registers a new callout bundle with the state machine. See CALLOUT BUNDLES below for information about what a callout bundle is. The bundle-name is considerd to be the name of a namespace relative to the global namespace (e.g MyBundle is considered to be the namespace ::MyBundle).

The namespace is checked for the existence and proper parameterization of the required callback bundle procs as described in CALLOUT BUNDLES. An error is thrown if the namespace is determined to not be a valid callout bundle.

If before-bundle is provided it must be the name of an existing bundle (one that would be returned from listCalloutBundles). The bundle will be registerd just before before-bundle in the ordered list of bundles. This allows action depenencies between bundles to be properly scheduled.

removeCalloutBundle bundle-name

Removes the named callout bundle from the list of registered bundles. It is an error if bundle-name does not correspond to a registered callout bundle.

transition new-state

Attempts a transition from the current state to new-state. The leave and enter procs for the registered callback bundles are invoked.

leave is invoked prior to making the transition while enter is invoked after the transition has occurerd.

If new-state is not an allowed state transition, an error is thrown.


The RunstateMachine has a well defined set of state and allowed transtion between those states. The finite state automaton that is defined by these states and their allowed transitions is shown in simplified form in ReadoutShell's state diagram

These states and their allowed transitions are described textually below.


The system is not ready for use. In this state, data sources have not yet been started. You must also be in this state to modify the set of data sources known to the application.

Allowed target states for the transition method are; NotReady and Starting. Starting.


This state is entered to start the data sources that have been defined for use with the application. NotReady is an allowed target state and is normally entered if one or more data sources failed to tart up. Halted is the other valid target state and is entered if all data sources started correctly.


This state indicates the system is ready for use but there is no current data taking run. Valid transition targets are; NotReady, if a data source fails or Active if a run is successfully started.


This state indicates data taking is ongoing. Valid transitions are: Paused if the run is paused, Halted if the run is ended and NotReady if a data source fails.

Note that while not all data source providers support a Paused state this is not known or supported directly by the run state machine. Instead, the ReadoutGUI interrogates the data sources defined and removes the GUI elements that can trigger a transition to the Paused state if not all data sources support paused runs.


Indicates a data taking run is temporarily paused. This state can transition to: Halted if the run is stopped, Active if the run is resumed or NotReady if a data source fails.


In the transition diagram above, the text if a data source fails means a data source provider's check for that data source returns boolean false. Thus failure is defined by and limited to the ability of the data source provider to detect the failure.


The true value of the run state machine is the ability of components of the ReadoutGUI (including your extensions) to register Callout Bundles. You can think of a callout bundle as a generalization of the ReadoutShell's ReadoutCallouts.tcl mechanism.

A Callout bundle is a Tcl namespace. The namespace must contain three exportedproc definitions:

attach current-state

This proc is called when the bundle is registered with the state machine via addCalloutBundle

leave from-state to-state

This proc is called just before the state machine makes a transition from from-state to to-state

enter from-state to-state

This proc is called just after the state machine has made a transition from from-state to to-state.

The enter and leave procs for the callout bundles are invoked in the order in which the bundles were registered.


The sample code below shows the creation and registration of a callout bundle that does nothing. You can rename the namespace and fill in the procs shown below to build and register your own callout bundles.

Example 1. A do nothing RunstateMachine callout bundle

package require RunstateMachine                         (1)
namespace eval ::MyBundle  {
    variable  sm
    namespace export attach enter leave                 (2)

proc ::MyBundle::attach currentState {

proc ::MyBundle::leave {from to} {

proc ::MyBundle::enter {from to} {

set ::MyBundle::sm [RunstateMachineSingleton %AUTO]   (6)
$::MyBundle::sm    addCalloutBundle MyBundle          (7)
Requires the run state machine package. This is needed to get access to the state machine and then to register the bundle we're creating.
This code creates the namespace ::MyBundle it defines a variable sm to live in that namespace (to hold the state machine object command) and exports the required proc names from the namespace.
Defines the enter proc of the bundle. This will be called when the bundle is registered with the state machine. When called, currentState will be the state at the time the attach was done.
Defines the leave proc of the bundle. This will be called just before the state machine begins a transition. from will be the state at the time the transition is being started and to will be the target state.
Defines the enter proc of the bundle. This is called after the state machine completes its state transition. from is the old state and to is the new state.
Obtains the run state machine singleton and assigns it to the variable ::MyBundle::sm. This allows it to be used from within the bundle procs as well as for bundle registration purposes.
Registers the bundle with the state machine. Prior to returning from this call, ::MyBundle::attach will be called. From now on state transitions will result in calls first to the bundle's ::MyBundle::leave and then to the bundle's ::MyBundle::enter procs.