Overriding and extending Run State Transitions in Production Readout and HPPreadout

Thanks to Constantine Vaman for inspiring this note. This note should work with any version of the production readout or the high performance production readout skeletons.

Background and Motivation

The Production readout framework is a flexible event segemnt based readout system. While it is very clear how to do simple, and even complex event readout applications, it is less clear how to hook into run state transitions.

This application note will describe how to hook into the run state transitions.

In the production readout software, run states are managed by Tcl commands. While there is a state transition manager much like Readout classic, a natural way to hook into the run state transitions is to redefine the actions taken for each Tcl command that controls a run state transition.

The classes that are responsible for implementing these commands are all derived from StateTransitionCommand. They are (just add .h to the class name to get the header filename):

CBeginCommand   - Begins a run.
CEndCommand     - Ends a run.
CPauseCommand   - Temporarily pauses a run.
CResumeCommand  - Resumes a paused run.

Each run state transition command has a pair of virtual member functions that are intended as hooks to provide functionality both beofre and after the state transition managed by the command. The base classes implement no-op versions of these functions. The prototypes of these functions are:


int ExecutePreFunction()
int ExecutePostFunction()

While the functions return an int, the return value is currently ignored. We can say that if the return value is ever used, a 0 return value will be considered a success, while nonzero values will be considered errors.

What to do

You must do the following:

For example, to hook into the end command; you could define


#ifndef __MYEND_H
#define __MYEND_H
#include  

class CTCLInterpreter;

class MyEnd : public CEndCommand
{
public:
  MyEnd(CTCLInterpreter& interp);
  virtual ~MyEnd();
  
private:
  MyEnd(const MyEnd& rhs);
  MyEnd& operator=(const MyEnd& rhs);
  int operator==(const MyEnd& rhs) const;
  int operator!=(const MyEnd& rhs) const;


public:
  virtual int ExecutePreFunction();
  virtual int ExecutePostFunction();
	
};

#endif

And implement as follows

// MyEnd implementation.
// Delegate excpet for the pre/post functions:

#include 
#include "MyEnd.h"
#include "TCLInterpreter.h"
#include 


MyEnd::MyEnd(CTCLInterpreter& rInterp) :
  CEndCommand()
{
  Bind(rInterp);
  Register();
}

MyEnd::~MyEnd()
{
}


int
MyEnd::ExecutePreFunction()
{
  cerr << "Beginning to end the run\n";
  return 0;
}
int
MyEnd::ExecutePostFunction() 
{
  cerr << "Finished with the end run command\n";
  return 0;
}
Then to Skeleton.cpp
#include "MyEnd.h"

...

void
CMyExperiment::AddUserCommands(CExperiment& rExperiment, 
				   CInterpreterStartup& rStartup,
				   CInterpreterCore&    rCore)
{
   CReadoutMain::AddUserCommands(rExperiment, rStartup, rCore);
   
   CTCLInterpreter& rInterp(rStartup.Interp());

   new MyEnd(rInterp);
    ^^^  Add this line
  
   // Add your command definitions after this comment.  rInterp
   // is a reference to the interpreter.
}

Full example

Full sample code is available for download. Last modified: Thu Sep 7 16:32:32 EDT 2006