2.5. Periodically read scalers

Most real experiments will need to monitor the rates in various detector systems, as well as maintain other counter based items such as the master trigger rate, and the accepted trigger rate, the beam current etc. These are conveniently managed through the periodic scaler readout system. The production readout framework allows you to specify a set of scalers that are read periodically. It is also possible to replace this periodic trigger with an external trigger. The reference section describes how to do this.

In this section we will:

2.5.1. Modifying the electronics to add a scaler module

The SIS 3820 is a 32 channel VME scaler. It is addressed via a settable base address. The address is set via rotary switches at the top part of the circuit board. See the SIS 3820 manual for more information about this module.

The SIS module is an address space hungry module. It requires 0x1000000 bytes of A32 address space. We have configured it for a base address of 0x38000000 which means that it spans the address range 0x38000000-0x38ffffff. This keeps it clear of both the V775 and V262. To test, we will just cable the TDC stops into the first set of channels for the module. We will not be looking at events.

Exercise for the reader: By selectively terminating the inputs of either the V775 or SIS 3820, you can bus the ribbon cable between the individual inputs of the TDC and the scaler. Do this by ensuring that only the last module on the physical bus has termination enabled.

2.5.2. Modifying the event source to read the scaler module

The production readout software allows you to devine any number of scaler modules. A scaler module is a set of scaler channels that are read via a class that inherits from the abstract base class CScaler. The key features of the header for this class are shown below:

Example 2-17. Key features of the CScaler ABC


class CScaler   
{ 

public:

  CScaler ();                      //!< Default constructor.

  virtual   void Initialize ()   = 0;
  virtual   void Read (STD(vector)<unsigned long>& Scalers)   = 0;
  virtual   void Clear ()   = 0;
  virtual   unsigned int size ()   = 0;
  
};

#endif

                
Note that this class is similar to the CEventSegment class. The main difference is that the CScaler class appends data to a standard template library vector container class, rather than to a buffer of unchecked memory.

We must write a class that will manage an SIS 3820 scaler module within the framework of the CScaler interface, and we must register an object of this class for our scaler with the framework so that its interfaces will be called at the appropriate time.

To write this class we will make use of the CSIS3820 class. CSIS3820 provides software support for the scaler module. The parts of the class we will use are shown below:

Example 2-18. Extract from the CSIS3820 header



/*!
   Controls an SIS3820 module.  The SIS3820 is a 32 channel latching
   VME scaler module.
*/
class CSIS3820 : public CModule32
{
public:
  
  enum OperatingMode {		         // (1)
    LatchingScaler     =  0x00000000,
    ReservedScaler1    =  0x10000000,
    MultiChannelScaler =  0x20000000,
    HistogrammingScaler=  0x30000000,
    ReservedScaler2    =  0x40000000,
    ReservedScaler3    =  0x50000000,
    ReservedScaler4    =  0x60000000,
    RamTestScaler      =  0x70000000 
  };
  
  enum LNESource {                     //  (2)
    LatchVMEOnly                = 0x00000000,
    LatchFP                     = 0x00000010,
    Latch10Mhz                  = 0x00000020,
    LatchChannelN               = 0x00000030,
    LatchPresetN                = 0x00000040,
    LatchReserved5              = 0x00000050,
    LatchReserved6              = 0x00000060,
    LatchReserved7              = 0x00000070
  };

public:

  CSIS3820(unsigned long base,       // (3)
	   int crate = 0)      ;


  void   Reset()                           const;  // (4)
  void   setOperatingMode(OperatingMode mode);     // (5)
  void setLatchSource(LNESource mode);             // (6)
  void Arm()                               const;  // (7)
  void Enable()                            const;  // (8)
  void ClearChannels()                     const;  // (9)
  void EnableClearOnLatch()                const;  // (10)
  void LatchAndRead(unsigned long* buffer) const;  // (11)
};


                
(1)
This enum defines symbolic names for the various scaler operating modes. We will use the scaler as a latching scaler, or in other words specify: CSIS3820::LatchingScaler in a call to setOperatingMode. When writing code it is best to use symbolic constants where practical, rather than using magic numbers whose meaning you will have to grope for when looking at the code later on.
(2)
The source of the scaler's Latch input can be programmed. This enum defines symbolically the possible sources of the latch. We will be latching via VME operations, and therefore selecting CSIS3820::LatchVMEOnly.
(3)
We will need to parameterize the construction of the scaler module object by giving it a base parameter (the base address), and a VME crate number (crate).
(4)
The Reset member function resets the module to its power up condition.
(5)
This function sets the module operating mode. As we have indicated previously, we will call this function with the mode parameter set at CSIS3820::LatchingScaler to set the operating mode to be that of a latching scaler.
(6)
This function sets the sources from which the scaler can receive a latch command. The latch command transfers the values of the counters into a register where the values will be constant until the next latch operation. This permits a safe read of the scaler channels.
(7)
In order to count pulses, the scaler must be armed. This function arms the module.
(8)
In order to count pulses, the scaler module must be enabled. This function enables the module.
(9)
Clears the counter values in the scaler. This will be used at initialization time to ensure that our first interval will count from zero.
(10)
The scaler software uses incremental scaler values. This is just a fancy way of saying that scalers should be cleared after each read. This makes scaler overflows less likely. EnableClearOnLatch tells the module hardware to clear the front end counters when they are transferred to the latched registers.
(11)
This function provides a VME latch and transfers the values of the latched scaler values to the buffer provided. buffer must point to at least 32 longwords worth of storage.

2.5.2.1. CMyScaler class header.

We will write a class named CMyScaler. This class will use the CSIS3820 class to communicate with the scaler. The header for this class is:

Example 2-19. Header for the CMyScaler class.


#ifndef __CSCALER_H
#include <CScaler.h>
#endif



class CSIS3820;

class CMyScaler : public CScaler
{
private:
  CSIS3820*  m_pModule;
public:
  CMyScaler(unsigned long base);
  ~CMyScaler();

  virtual   void Initialize ()  ;
  virtual   void Read (STD(vector)<unsigned long>& Scalers)  ;
  virtual   void Clear ()  ;
  virtual   unsigned int size ()  ;
  
};

                    
If you have followed along with our example so far, this header should hold no surprises.

2.5.2.2. CMyScaler class implementation.

The code to construct and destroy a CMyScaler object is shown below:

Example 2-20. Constructors and destructors for a CMyScaler object


#include <config.h>
#include "CMyScaler.h"
#include <CSIS3820.h>

#ifdef HAVE_STD_NAMESPACE
using namespace std;
#endif

CMyScaler::CMyScaler(unsigned long base) :
  m_pModule(new CSIS3820(base))
{

}
CMyScaler::˜CMyScaler()
{
  delete m_pModule;
}
                    
Once more this should hold no surprises.

Since our assumption is that the VME crate could have been turned off and on prior to each run the initialization of the scaler will be done in CMyScaler::Initialize:

Example 2-21. CMyScaler::Initialize implementation


void
CMyScaler::Initialize()
{
  m_pModule->Reset();                                    // (1)
  m_pModule-*gt'setOperatingMode(CSIS3820::LatchingScaler);
  m_pModule->setLatchSource(CSIS3820::LatchVMEOnly);     // (2)
  m_pModule->EnableClearOnLatch();

  Clear();                                               // (3)

  m_pModule->Arm();                                      // (4)
  m_pModule->Enable();

}

                    
(1)
Before programming the scaler it is reset to its power up state. Among other things, this also disarms and disables the scaler.
(2)
This segment of code initializes the module to be a latching scaler, with latch signals coming from VME commands. VME Latch commands will latch the counters to stable registers, and clear the counters for the next incremental scaler period.
(3)
We clear the scaler counters initially by invoking our own Clear member function. While we could have just done a:

m_pModule->ClearChannels();
                            
here, wherever possible avoid duplicating code sequences. Factor duplicated code sequences out into functions or member functions. This results in much more maintainable code in the long run.
(4)
Arming and enabling the scaler makes it able to count input pulses on all of its input channels.

The implementation of the Clear member is:


void
CMyScaler::Clear()
{
  m_pModule->ClearChannels();
}
                
This simply asks the modules to clear its front end counters.

To read the module we need to transfer data from the module using CSIS3820::LatchAndRead, however that transfers data to a plain memory buffer and we have to put our scalers into a vector. We therefore read the data into an internal buffer and transfer it to the vector as shown below:

Example 2-22. CMyScaler::Read implementation


void
CMyScaler::Read(vector<unsigned long>& Scalers)
{
  unsigned long data[32];

  m_pModule->LatchAndRead(data);
  for (int i =0; i < 32; i++) {
    Scalers.push_back(data[i]);
  }
}
                    

Finally, the size member is also obsolete for the CScaler class just as it is for the CEventSegment class:

Example 2-23. The CMyScaler::size implementation


unsigned int
CMyScaler::size()
{
  return 0;
}

                    

2.5.2.3. Registering a CMyScaler object with the framework

Now we need to register an object to readout the scaler we have installed. We will also need to build the new Readout program.

Edit Skeleton.cpp. Locate the header includes and add an include directive for our class header e.g.:


#include <CEventSegment.h>
#include "CMyEventSegment.h"
#include "CMyScaler.h"                 // <---- add this line.

                

Locate the implementation of SetupScalers. This function is called by the framework when it is able to accept registrations of scaler modules. Modify it as shown below:


void
CMyExperiment::SetupScalers(CExperiment& rExperiment)
{
   CReadoutMain::SetupScalers(rExperiment);

   // Insert your code below this comment.

   rExperiment.AddScalerModule(new CMyScaler(0x38000000));   // <---- Add this line.

   // For test,setup an LRS 1151 at 0x200c00

   //   CScaler* pScaler = new CVMEScalerLRS1151(0xc00200);
   //   rExperiment.AddScalerModule(pScaler);

}
                

Now edit the Makefile. Locate the definition of OBJECTS and add CMyScaler.o to the list of objects the program needs:


Objects=Skeleton.o CMyEventSegment.o CMyScaler.o
                

Use the make command to build your new event sourcde.

2.5.3. Testing the setup

Bufdump can dump formatted scaler buffers as well. This will give us a chance to see if our software works.

Start bufdump. Connect it to the online system. Establish a filter that accepts only scaler buffers. Tell it to get the next buffer from the source.

Start the readout program and begin a run (don't forget to move the ribbon cable from the inputs of the TDC to the inputs of the scaler). The default time interval for a scaler readout is 10 seconds. After 10 seconds you should get output that looks something like:


Scaler Buffer for interval 0-00:00:00 through 0-00:00:10
32 scalers follow:
Scaler           Increment           Rate over interval
     0              102910           10291.000000
     1                   0           0.000000
     2                   0           0.000000
     3                   0           0.000000
     4                   0           0.000000
     5                   0           0.000000
     6                   0           0.000000
     7                   0           0.000000
     8                   0           0.000000
     9                   0           0.000000
    10                   0           0.000000
    11                   0           0.000000
    12                   0           0.000000
    13                   0           0.000000
    14                   0           0.000000
    15                   0           0.000000
    16                   0           0.000000
    17                   0           0.000000
            

End the run and type the following command to the Readout program: set frequency 5. This sets the readout period to 5 seconds. Tell bufdump to request another buffer and start the run. You should now get something like:


Scaler Buffer for interval 0-00:00:00 through 0-00:00:05
32 scalers follow:
Scaler           Increment           Rate over interval
     0               51004           10200.800000
     1                   0           0.000000
     2                   0           0.000000
     3                   0           0.000000
     4                   0           0.000000
     5                   0           0.000000
     6                   0           0.000000
     7                   0           0.000000
     8                   0           0.000000
     9                   0           0.000000
    10                   0           0.000000
    11                   0           0.000000
    12                   0           0.000000
    13                   0           0.000000
    14                   0           0.000000
    15                   0           0.000000
    16                   0           0.000000
    17                   0           0.000000
    18                   0           0.000000
    19                   0           0.000000
    20                   0           0.000000
            
As expected the increment column is halved, but the rate column is constant.