NSCL DAQ Software Documentation | ||
---|---|---|
Prev | Chapter 11. Using NSCLDAQ with a CAEN V785 Peak-Sensing ADC and CAEN V262 IO Register | Next |
The software modifications needed to make the system work can be divided into a few tasks:
Defining which pieces of hardware are being used.
Defining what to do with the hardware when readout is triggered
Defining the conditions for triggering readout
In order to tell the software about our electronics, we are going to develop a C++ class for our module. That class will be a derived class but we don't need to concern ourselves with the details of the parent class. Like all of the software tailoring we need to do, most of the details are hidden and we need only to fill in a few holes.
The following commands will make a new directory and copy the skeleton files to it:
mkdir -p ~/experiment/readout cd ~/experiment/readout cp $DAQROOT/skeletons/sbs/* .
Now that we have obtained a copy of the Skeleton file we can begin to think about the modifications we need to make. We need to tell the software what kind of module we are using, how to initialize it, how to clear it, and how to read it. We will do this by creating a class called by MyEventSegment. In that class we will also define a timestamp for our data so that the Readout program will produce a body header. For lack of anything better to in this setup, we will use the event counter as the timestamp. We will not have to write custom software for the trigger condition because a class is already provided by NSCLDAQ that we will make use of.
In order to follow good coding practice and to make our code as versatile as possible, we will write our class in two separate files, a header file and an implementation file. Start by creating a file called MyEventSement.h. It should look like this:
Example 11-1. Header for MyEventSegment
#ifndef MYEVENTSEGMENT_H #define MYEVENTSEGMENT_H #include <CEventSegment.h> #include <CDocumentedPacket.h> #include <CAENcard.h> /*! \brief A class to read out a V785 * * This class derives from the CEventSegment class and defines the basic * functionality we desire of the V785 during read. It will format the data in * a documented packet before sending it out. * */ class MyEventSegment : public CEventSegment { private: CDocumentedPacket m_myPacket; CAENcard m_module; public: MyEventSegment(short slot, unsigned short Id); virtual void initialize(); virtual void clear(); virtual size_t read(void* pBuffer, size_t maxwords); private: uint64_t extractEventCount(uint16_t* pEOE); }; #endif
The header defines the class, its internal data and the services it exports to the readout framework. Refer to the circled numbers in the listing above when reading the following explanation
We will also create an implementation file: MyEventSegment.cpp. This file will implement the member functions that were defined by MyEventSegment.h above. The contents of this file are shown below:
Example 11-2. Impementation of CMyEventSegment
#include <config.h> #include <string> #include <stdint.h> #ifdef HAVE_STD_NAMESPACE using namespace std; #endif // Set the polling limit for a timeout static unsigned int CAENTIMEOUT = 100; #include "MyEventSegment.h" // Packet version -should be changed whenever major changes are made // to the packet structure. static const char* pPacketVersion = "1.0"; //constructor set Packet details MyEventSegment::MyEventSegment(short slot, unsigned short Id): m_myPacket(Id,"My Packet","Sample documented packet",pPacketVersion), m_module(slot) { } // Is called right after the module is created. All one time Setup // should be done now. void MyEventSegment::initialize() { m_module.reset(); clear(); } // Is called after reading data buffer void MyEventSegment::clear() { // Clear data buffer m_module.clearData(); } //Is called to readout data on m_module size_t MyEventSegment::read(void* pBuffer, size_t maxsize) { // Loop waits for data to become ready for(int i=0;i<CAENTIMEOUT; i++) { // If data is ready stop looping if(m_module.dataPresent()) { break; } } size_t nShorts = 0; // Tests again that data is ready if(m_module.dataPresent()) { // Opens a new Packet uint16_t* pBufBegin = reinterpret_cast<uint16_t*>(pBuffer); uint16_t* pBuf = m_myPacket.Begin(pBufBegin); // Reads data into the Packet int nBytesRead = m_module.readEvent(pBuf); // Closes the open Packet uint16_t* pBufEnd = m_myPacket.End(pBuf+nBytesRead/sizeof(uint16_t)); (11) nShorts = (pBufEnd-pBufBegin); (12) // set the timestamp setTimestamp(extractEventCount(pBufEnd-2)); (13) } return nShorts; (14) } // Extract the lower 24-bits of the end of event word uint64_t MyEventSegment::extractEventCount(uint16_t* pEOE) { uint64_t count = *(pEOE)<<16; count |= *(pEOE+1); return (count&0x00ffffff); (15) }
The numbers below refer to the circled numbers in the example above.
Once you have created one or more event segments, you must register them with the Readout software. Whenever the Readout software must do something to its event segments, it calls the appropriate member function in each event segment that has been registered, in the order in which it has been registered.
Edit Skeleton.cpp. Towards the top of that file, after all the other #include statements, add:
#include <CCAENV262Trigger.h> #include "MyEventSegment.h"
This is necessary because we will be creating an object of class MyEventSegment. We have also included a predefined class for the CCAENV262 IO register. We use this device as a trigger interface.
Next, locate the function CMyExperiment::SetupReadout() Modify it to create an instance of MyEventSegment and register it to the experiment. In this method we will also instantiate our trigger instance. We provide the base address as the argument to the CCAENV262Trigger constructor which should have been set using the jumper switches on the board to be 0x00100000.
void CMyExperiment::SetupReadout(CExperiment* pExperiment) { assert(pExperiment!=0); CReadoutMain::SetupReadout(pExperiment); pExperiment->AddEventSegment(new MyEventSegment(10, 0xff00)); // Register a the trigger module that is situated at base address // 0x00100000. pExperiment->EstablishTrigger(new CCAENV262Trigger(0x00100000)); }
This code creates a new event segment for a CAEN V785 in slot 10, which will be read out into a packet with ID 0xff00.
Now that the source code for the Readout program is complete, we need to compile it into an executable.
First, edit the Makefile supplied with the skeleton code so that it knows about your additional program files. Locate the line that reads:
Objects=Skeleton.o
and modify it so that it reads:
Objects=Skeleton.o MyEventSegment.o
Save this edit, exit the editor and type:
make
This will attempt to compile your readout software into an executable program called Readout. If the make command fails, fix the compilation errors indicated by it and retry until you get an error free compilation