The high performance production readout framework is a flexible framework for building data sources. Data sources built on top of this framework have the following capabilities:
Flexible, modular construction of the event readout
Support for documenting event packets for buffer analysis and buffer dumping programs.
Command processing based on an extended Tcl interpreter.
Capable of serving as a Tcl Server.
Support for the creation and logging of variables that are invariant through the course of a run (run state variables).
Support for the creation and periodic logging of variables that will vary through the course of a run (run variables).
Support for user written event and scaler triggers.
Acess to the NSCL DAQ device support library which supports both generic access to CAMAC and VME as well as packaged support for popular modules in use at the NSCL.
The high performance readout framework consists of two components. The largest component, which implements experiment independent code consists of a set of linkable libraries and headers that are installed in the NSCL DAQ installation directories. The experiment dependent code is distributed as a skeleton of C++ files and headers and a Makefile that build a Readout executable from this skeleton and the libraries.
The NSCL must support not only new experiment development, but many existing, stable experimental setups. To do this we have chosen to install several versions of the NSCL DAQ software on each system simultaneously. Older software gets less support attention, newer software serves as the basis of additional developments.
The NSCL Data acqusition system software is installed at the NSCL in subdirectories under /usr/opt/daq. Each version of the software lives in its own directory tree below this top level directory. For example, nscldaq V7.4 lives in /usr/opt/daq/7.4. In addition, a symbolic link /usr/opt/daq/current points to the directory that contains what is considered the most recent, stable version of the system. /usr/opt/daq/current can point to different directories over time as newer versions of the software become stable. Therefore Makefiles written by the DAQ system installer and by you should refer to the specific version of the DAQ software you are compiling and linking against to ensure that your builds will continue to work as the NSCLDAQ software evolves.
Complicating matters is the version of gnu compilers that are used to build both your software and the NSCL DAQ software. The code generated by the gnu gcc/g++ 3.0 and later compilers is not compatible with code generated by earlier compilers. Additionally, the 3.0 and later compilers are much stricter linguistically than the earlier compilers, requireing source code changes for users porting between these two compilers.
At the NSCL, version 8.0 is the bridge for porting your code between to the gcc 3.x compilers. Therefore, two versions of nscldaq V8.0 are installed at the nscl: /usr/opt/daq/8.0 is an installation compiled against the gcc/g++ 2.95 compilers and /usr/opt/daq/8.0gcc3.3 is a version compiled against the gcc/g++3.3 compilers.
Notwithstanding this discussion of versions, for new application development, you should get all of your skeleton files from the /usr/opt/daq/current directory tree. If you are developing software at an institution that does not follow this installation system, you should contact your local site support staff to determine which directory is the the appropriate top-level nscldaq installation directory. In order to make the rest of this document installation independent, we will use $DAQROOT to refer to the top level installation directory of the DAQ software (/usr/opt/daq/current at the NSCL).
The skeleton files for the high performance production readout framework are located in $DAQROOT/HPpReadoutSkeleton. To start working with this skeleton, you should copy the files from this directory to an empty directory in your account. For example:
cd ~
mkdir readout
cd readout
cp $DAQROOT/HPpReadoutSkeleton/* .
The following files make up the readout skeleton:
Table 2-1. High Performance Production Readout Skeleton file manifest
| Filename | Purpose |
|---|---|
| Skeleton.cpp | This contains the implementation of the class that encapsulates user modifications to the skeleton code. Member functions of this class will require modification. |
| Makefile | This file is a description file for the unix make program. In general you will have to modify this file to incorporate your software into the build of Readout |
| CTradtionalEventSegment.cpp | Prior to the use of the production family of event source frameworks, a more primitive Readout Classic framework was used. CTraditionalEventSegment.cpp implements an event segment that allows you to incorporate the readout software from the high performance readout classic framework as an event segment in the high performance production readout framework. |
| CTraditionalScalerReadout.cpp | Allows the incorporation of scaler readouts from a high performance classic readout as a scaler bank in the high performance production readout framework. |
Data sources are built by adding experiment specific code to the readout framework and modifying skeleton files to make the readout framework aware of this new code. The new code implementation files are then added to the Makefile and make is used to build a specific implementation of the framework as an executable named Readout.
The bulk of your programming effort to build a data source will go into creating one or more event segments. Event segments are the readout frameworks's way to modularize the readout.
There is no hard fast rule about what should constitute an event segment, however as you think about how to divide a real experiment readout problem into event segments, you should seriously consider the following suggestions. Following them will make your life easier, and will make the data format sensible.
Event segments should not involve overlapping hardware
Event segments should represent some human identifiable part of the detector system
If you are generating event packets
each event segment should generate one or more complete
event packets, and should use the
CDocumentedPacket class to
manage packet documentation, and data encapsulation.
An event segment is an object that is responsible for managing an independent part of the hardware of an experiment. An event segment is responsible for:
Initializing the hardware prior to the start of data taking.
Responding to event triggers by reading out the part of the event that has been digitized by the hardware for which the event segment is taking responsibility.
Clearing the hardware following the readout of an event if necessary.
An event segment is an instance of a class that inherits from the framework
class CEventSegment. The header for this class should be
included in all event segment headers via:
#include <CEventSegment.h>
The framework Makefile will ensure that $DAQROOT/HPpReadoutIncludes
is
searched for header files so that the proper version of this
header can be included by the preprocessor.
The key part of this header is shown below:
Example 2-1. The CEventSegment Abstract Base Class
class CEventSegment
{
public:
virtual void Initialize () = 0; //
virtual unsigned short* Read (unsigned short* rBuffer) = 0; //
virtual void Clear () = 0; //
virtual unsigned int MaxSize () = 0; //
};
#endif
The CEventSegment class has a set of
pure virtual methods. Pure virtual methods are those
that are declared as
type function(args...) = 0;
Pure virtual methods describe an interface which must be implemented by classes
that inherit from CEventSegment. Pure virtual
methods are a mechanism to ensure that a class that inherits from the base class
that defines them must attempt to live up to specific responsibilities that the
base class does not know how to implement. CEventSegment
and any other class that has pure virtual methods are known as
Abstract Base Classes. Abstract base classes cannot generate
objects. Only classes that inherit from theM and fulfill the responsibilities defined
by all pure virtual methods can generate objects.
Let's look at the responsibilities for event segments as defined by
CEventSegment's pure virtual methods.

Initialize is called by the framework prior to
enabling data taking. This function should initialize all hardware
managed by the event segment, and prepare it for data taking.

Read is called in response to a trigger.
This function should read the part of the event generated by the event
segment. rBuffer is a pointer to some buffer space into which
the event segment can be read. The storage available to the event is at
least the size of a buffer body. Read should return a pointer
to the next free chunk of the buffer. For example, an event segment that
just puts 10 words in the buffer that count from 0 to 9 might look like the
code below.
unsigned short*
CMyEventSegment::Read(unsigned short* rBuffer)
{
for (int i=; i < 10; i++) {
*rBuffer++ = i;
}
return rBuffer;
}


MaxSize function is obsolete. It is still present
for compatibility purposes. It should be implemented as shown below:
unsigned int
CMyEventSegment::MaxSize()
{
return 0; // Or any other value you want.
}
Once you have written an event segment you need to arrange for an object of its type to be created and called. To do this you must construct your event segment and register it with the framework. Event segment objects are called in the order in which they are registered.
The Skeleton.cpp skeleton file contains functions that
are expected to set up the event readout. Suppose you have created an event segment
class named CMyEventSegment, you would register this event
segment by modifying the function
CMyExperiment::SetupReadout to read
as shown below:
void
CMyExperiment::SetupReadout(CExperiment& rExperiment)
{
CReadoutMain::SetupReadout(rExperiment);
// Insert your code below this comment.
rExperiment.AddEventSegment(new CMyEventSegment);
}
The call to
rExperiment.AddEventSegment adds a new object to the end
of the list of event segments managed by the framework. If you had additional
event segments to register you would add as many calls to
rExperiment.AddEventSegment as needed to register them all.