Overriding and Extending Run State Transitions in Readout Classic an HPReadout 
==============================================================================
Thanks to Constantine Vaman for inspiring the framework needed to do this.
Note that this application note refers to nscldaq-8.0-008, and nscldaq-8.1 
and later.  Prior versions of nscldaq do not have
ReadoutStateMachine::replaceState


These are scheduled to be installed at the NSCL 9/12/06.

Background and Motivation
=========================

The NSCL DAQ Readout classic framework provides callouts for most of
the experiment dependent needs for simple experiments.  In some cases,
however it is necessary to know about and take action in cases that
were not anticipated when the framework was designed.

The original inspiration for this application note was a need to take control
when the run ends, or is paused in order to flush events from a multievent
buffered system.

The Readout classic framework is a state machine.
The framework has the following states:

Name          What's going on
INACTIVE      System is not taking data (before the first run or after an end).
ACTIVE        System is taking data.
PAUSED        The run has been paused. No data taking is in progress, but the
              run is not closed.
EXITING       Readout is in the process of exiting.

Each state is represented by a class that is derived from the
State abstract base class (see State.h).

This application note shows how to extend the states described above 
and replace the default state machine actions with your modified states.


What to do
==========

ReadoutMain.cpp creates the statemachine in the lines that read:

    ReadoutStateMachine Run;
    gpStateMachine = &Run;

The constructor of the ReadoutStateMachine stocks the state machine
with the initial states described above.  A member function allows 
state processors to be replaced  The member function has the prototyp:

State* StateMachine::replaceState(std::string name, State* newstate)

The return value from this function is a pointer to the previous 
processor for that state or NULL If the state named does not exist.


Adding new states is therefore supported, but you will need to understand
how to create transitions to this state to make that state accessible.
That is beyond the scope of this note.

To replace a state, derive a subclass from the original state processor
and override any member functions for which you want to take action.
Be sure to invoke the base class processing for the overidden function.

The state processing classes are:

State Name            Class Name                 Header file
INACTIVE              Inactive                   Inactive.h
ACTIVE                Active                     Active.h
PAUSED                Paused                     Paused.h
EXITING               Exiting                    Exiting.h

In ReadoutMain.cpp, after the state machine has been created,
add code to replace the desired state for example:

    ReadoutStateMachine Run;
    gpStateMachine = &Run;

    Run.replaceState(string("ACTIVE"), new MyActive);
    ^---> New line

This added line replaces the ACTIVE state processor with MyActive.


Sample Implementation
=====================

A tarball for this example can be downloaded:

Click for sample tarball


The sample adds the capability to call a function named
toInactive() when the run stops being active (due to a pause or
end).  This is done by overriding the Active state with a state that
extends the Leave() member function.  The Leave() member function
is invoked by the state machine interpreter when the current state is
making a transition to a new state.

MyActive is defined as shown below:

#ifndef __MYACTIVE_H
#define __MYACTIVE_H

#ifdef HAVE_STD_NAMESPACE
using namespace std;
#endif
#include 

class StateMachine;

//
// We save ourselves a bundle of work by deriving from the existing
// active state.
//
class MyActive : public Active 
{
public:
  // The canonicals taht will be delegated to the base class.

  MyActive();
  MyActive(const MyActive& rhs);
  virtual ~MyActive();
  
  MyActive& operator=(const MyActive& rhs);
private:
  int operator==(const MyActive& rhs);
  int operator!=(const MyActive& rhs);
public:
  // Provide an override for Leave() so that we get control when leaving thestate.

  virtual void Leave(StateMachine& rMachine);
    
};


Note the override of the Leave member function.

The complete implementation of this class is:

// Implement the MyActive class:

#include 
#include "MyActive.h"
#include 

extern void toInactive();

// The canonicals just delegate:

MyActive::MyActive() : Active() {}
MyActive::MyActive(const MyActive& rhs) : Active(rhs) {}
MyActive::~MyActive() {}

MyActive&
MyActive::operator=(const MyActive& rhs) {
  Active::operator=(rhs);
  return *this;
}

/////////////////////////////

/* Leave just invokes our toInactive function and
   delegates the rest of the activities to active:

*/
void
MyActive::Leave(StateMachine& rMachine)
{
  toInactive();
  Active::Leave(rMachine);
}


The action is all in MyActive::Leave which invokes the toInactive function
and then invokes the base class behavior for Leave.

In ReadoutMain.cpp, we add an #include for the MyActive class and code
to substitute a MyActive state for the Active state:
   #include "MyActive.h"
   ^-----> New line

...


    ReadoutStateMachine Run;
    gpStateMachine = &Run;

    Run.replaceState(string("ACTIVE"), new MyActive);
    ^---> New line