4.4. Modifications to Skeleton.cpp

Up until now we have built code to wrap the skeleton.cpp in classes that are compatibile with the RingDaq readout framework. The readout framework also requires that we:

  1. Select (or write and register) an event trigger.

  2. Register an instance of our CTraditionalEventSegment as an event segment so that it can respond to the event trigger.

  3. Register an instacne of our CTraditionalScaler as a scaler so that it can respond to scaler triggers.

The actions above are all done by editing the Skeleton.cpp (note the capital S).

Lets first take up the event trigger. In the classical readout framework this is selected at compile time by defining a preprocessor symbol, or by creating and registering a replacement trigger. For the RingDaq readout framework, you must select a trigger in your software. While this is a bit more burdensome, it is more flexible.

Triggering in the RingDaq framework is divided into two parts, the trigger itself, and dead-time management. These are represented by a class descended from CTrigger and another class descended from CBusy. Objects of these classes can be mixed. It is anticpated that there may be cases where a specific bit of trigger hardware cannot also do deadtime management.

The readout framework supplies trigger/busy classes for the CAEN V262 I/O register and the CAEN V977 coincidence register/latch. In addition it is pretty easy to create new trigger classes and to use them to trigger your readout. The example below selects the CAEN V262 as the trigger and busy manager. The signals used are identical to those used by the SPDAQ frameworks.

Example 4-12. Sepcifying the trigger/busy


#include <config.h>
#include "Skeleton.h"
#include <CExperiment.h>
#include <TCLInterpreter.h>
#include <CTimedTrigger.h>

#include "CCAENEventSegment.h"


#include "CSIS3820Scaler.h"

#include <CCAENV262Trigger.h>  (1)
#include <CCAENV262Busy.h>

...
void
Skeleton::SetupReadout(CExperiment* pExperiment)
{
...
  pExperiment->EstablishTrigger(new CCAENV262Trigger(0x444400, 0) ); (2)
  pExperiment->EstablishBusy(new CCAENV262Busy(0x444400, 0));        (3)
  
...
}


                
(1)
This header and the next define the CV262Trigger and CV262Busy classes which we will be using as trigger and busy classes respectively.
(2)
This line of code creates a new CV262Trigger object for a module with base address of 0x444400 in VME crate 0. This is the traditional location of this module in the NSCL DAQ. The all to the EstablishTrigger method of the CExperiment object makes this trigger module the experiment event trigger.
(3)
Similarly, this line creates a CV262Busy object at the same VME base address and establishes it as the module that will handle and maintain the program's busy state.

Now lets register the a CTraditionalEventSegment to respond to the trigger. The Readout framework allows you to register any number of event segments. The segments are processed in the order in which you register them, much the same way SpecTcl event processors work.

Example 4-13. Registering a CTraditionalEventSegment


...
#include "CTraditionalEventSegment.h"  (1)
...
void
Skeleton::SetupReadout(CExperiment* pExperiment)
{
  CReadoutMain::SetupReadout(pExperiment);

  // Establish your trigger here by creating a trigger object
  // and establishing it.

  pExperiment->EstablishTrigger(new CCAENV262Trigger(0x444400, 0));
  pExperiment->EstablishBusy(new CCAENV262Busy(0x444400, 0));

  // Create and add your event segments here, by creating them and invoking CExp
eriment's
  // AddEventSegment

  pExperiment->AddEventSegment(new CTraditionalEventSegment); (2)

}


                
(1)
Includes the header for the event segment we wrote to wrap skeleton.cpp. This declares the class to the compiler and therefore makes references to it usable later.
(2)
Registers the event segment by creating one dynamically and passing the pointer to it to CExperiment::AddEventSegment. Since Skeleton::SetupReadout only is called once for the lifetime of the program, it is not a memory leak to not provide a way to destroy the pointer.

The code to register the scaler wrapper is about the same, however it is added to Skeleton::SetupScalers.

Example 4-14. Registering the scaler adapter with readout


...
#include "CTraditionalScaler.h"  (1)
using namespace std;             (2)
...
void
Skeleton::SetupScalers(CExperiment* pExperiment)
{
  CReadoutMain::SetupScalers(pExperiment);      // Establishes the default scale
r trigger.

  // Sample: Set up a timed trigger at 2 second intervals.

  timespec t;
  t.tv_sec  = 2;                                  (3)
  t.tv_nsec = 0;
  CTimedTrigger* pTrigger = new CTimedTrigger(t);
  pExperiment->setScalerTrigger(pTrigger);

  // Create and add your scaler modules here.

  pExperiment->AddScalerModule(new CTraditionalScaler); (4)

}

                
(1)
As before we must include the header for our wrapper so that we can refere to and use the CTraditionalScaler class later in the code.
(2)
If you are used to using classes and objects that are in the std namespace in C++ without prefixing them with std:: you should inlude this line. It incorporates such classes/objects, like std::string or std::cerr etc, into the compilers unqualified name search path so that the explicit use of the std:: prefix is not required to use those classes and objects.
(3)
This code comes pre-packaged with the Skeleton.cpp file. It sets up a scaler readout trigger to fire every two seconds when the run is active. Scaler triggers, like event triggers are completely replaceable. If you want a different scaler readout interval, change the 2 to the number of seconds between readouts.

While the CTimedTrigger supports trigger intervals that are not whole seconds, the time resolution of the run time offset in the scaler event currently only supports whole seconds. Therefore leave the t.tv_nsec (nanoseconds) field set to zero.

(4)
Registers our scaler module with the readout. As for event segments, any number of scaler modules can be registered. Scaler modules will be read out in the order in which they are registered.

Once more, since the CSkeleton::SetupScalers is only called once in the lifetime of the program, no memory leak results from creating the CTraditionalScaler object in the way we have.