2.4. Event packets and larger systems.

By now you are hopefully wondering why bufdump prints the line:


Event trailer not part of any documented packets:
        
prior to each event. In this section we will introduce event packets a tool for providing structure on top of your data. We will then modify our event segment to put its data inside a packet.

2.4.1. What are packets

As you have seen, the production readout framework places no restriction on the format of the body of a buffer. Conventions have been adopted, however. These conventions are useful for larger systems. Especially systems which glue data together from more than one independent detector system.

The convention adopted at the NSCl for event bodies is that they should be composed of one or more packets. A packet is a chunk of data inside an event that has a word count, a uniquely assigned Identifying word, and a body. The word count includes itself and the identifying word.

Daniel Bazin at the NSCL serves as an authority for assigning packet ids for long lived devices (). He maintains a list of the currently assigned packet ids (also known as tags) at: http://groups.nscl.msu.edu/userinfo/daq/nscltags.html.

Dividing a buffer up into packets has several advantages.

2.4.2. Modifying the example to use packets.

We will modify our sample readout code to create the data within a packet. This would allow our event segment to be easily used with other event segments that follow the same convention, without any confusion about where the data from one segment ends and another begins.

2.4.2.1. The CDocumentedPacket class

The readout framework provides a class CDocumentedPacket to assist you in creating event packets. In addition to building the packet structure in the event buffer for you, CDocumentedPacket provides documentation entries in the buffers emitted at the beginning of a run describing the packets you can expect to see in the events that follow.

The key interfaces to CDocumentedPacket, extracted from the CDocumentedPacket.h header are shown below:

Figure 2-3. CDocumentedPacket key interfaces.


class CDocumentedPacket      
{ 
public:
  CDocumentedPacket (unsigned short nTag,
		     const STD(string)&  rName,
		     const STD(string)&  rDescription,
		     const STD(string)&  rVersion); 
  unsigned short* Begin (unsigned short* rPointer)  ;
  unsigned short* End (unsigned short* rBuffer)  ;
  
};


                    

These interfaces are as follows.

CDocumentedPacket

Constructs a documented packet:

Parameter: nTag

Data Type: unsigned shor

Meaning: The id of the packet to be generated by this object

Parameter: rName

Data Type: std::string

Meaning: A short name for the packet placed in the documentation buffer.

Parameter: rDescription

Data Type: std::string

Meaning: A long description for the packet which will be placed in the documentation buffer.

Parameter: rVersion

Data Type: std::string

Meaning: A version string for the packet. This will be placed in the documentation buffer

Begin

This should be called from within an event segment's Read function. It reserves space for the packet header and returns a pointer to the packet body. rPointer points to the location in the buffer at which you want the packet placed.

End

This should be called from within an event segment's Read function. It fills in the header of a packet that was opened with Begin. rBufer is a pointer to the first word following the packet body. The function returns a pointer to the next available word in the event buffer.

The strategy we will follow in the next few sections, therefore, will be to:

  • Add member data to CMyEventSegment so that it can contain a CDocumentedPacket.

  • Modify the constructor of CMyEventSegment so that it can accept a packet id, and a packet name and use these to initialize the CDocumentedPacket we added to the class

  • Modify the CMyEventSegment::Read to put the data read from the TDC into the packet.

2.4.2.2. Modifying the constructor of the event segment.

First we need to edit the file CMyEventSegment.h to add the new data member and modify the parameters for the constructor:

Example 2-13. Header for V755 event segment in a documented packet


#ifndef __CMYEVENTSEGMENT_H
#define __CMYEVENTSEGMENT_H

#include <CEventSegment.h>                    

#include <string>                          // (1)


class CAENcard;
class CDocumentedPacket;                   // (2)

class CMyEventSegment : public CEventSegment  
{
private:                                      
  int        m_nSlot;
  int        m_nPedestal;
  CAENcard*  m_pModule;  
  CDocumentedPacket* m_pPacket;               // (3)
public:
  CMyEventSegment(int nSlot, int nPedestal, 
		  int id,    STD(string) name); // (4)
  ~CMyEventSegment();

                                             
  virtual void         Initialize();         
  virtual unsigned short*       Read(unsigned short* rBuffer);
  virtual void         Clear();
  virtual unsigned int MaxSize() {return 0;} 
  
};
#endif

                    
(1)
Includes the string header. This defines the C++ standard library string class.
(2)
Since we will be adding a member to the class that is a pointer to a CDocumentedPacket we need to do a forward class declaration for that class. We don't need to include the header for this class in our header as the compiler does not need to see the internals of this class.
(3)
This line adds a new member datum m_pPacket which is a pointer to the documented packet we will create. The constructor will create this object, and the destructor will therefore destroy it.
(4)
We are adding two parameters to the constructor. id will be the packet id. name will be the name of the packet placed in the documentation buffer. The declaration STD(string), uses a compilation macro that either expands to std::string or string, depending on whether or not the compiler hides the string definition in an std namespace.

Next we need to modify the constructor so that it will create the CDocumented packet from the new parameters.

Example 2-14. CAEN V775 packetized readout event segment constructor


#include <CDocumentedPacket.h>         // (1)
. . .
CMyEventSegment::CMyEventSegment(int nSlot, int nPedestal,
				 int id,    string name) :
  m_nSlot(nSlot),
  m_nPedestal(nPedestal),
  m_pModule(new CAENcard(nSlot)),
  m_pPacket(0)                             // (2)
{
  // Be very unhappy if the module is not a
  // V775:

  int type = m_pModule->cardType();
  if (type != 775) {
    char errorMessage[100];
    delete m_pModule;
    sprintf(errorMessage, "Module in slot %d was is a %d should have been a 775\n",
	    m_nSlot, type);
    throw string(errorMessage);
  }
  m_pPacket = new CDocumentedPacket(id, name,    // (3)
				    string("CAEN V775 event data"),
				    string("1.0"));
}

                    
(1)
It is necessary to include the CDocumentedPacket.h header in this file so that the interfaces and physical layout of CDocumentedPacket objects is known to the compiler>
(2)
The m_pPacket pointer is initialized to null. We will not bother to allocated the packet unless the card is really a V775.
(3)
Now that we know that the constructor will succeed, we create the packet.

In addition to constructing the packet we must ensure that the packet is destroyed when our event segment is destroyed. The destructor for the CMyEventSegment class therefore becomes:

Example 2-15. CAEN V775 packetized event segment destructor


CMyEventSegment::~CMyEventSegment()
{
  delete m_pModule;
  delete m_pPacket;                            // <----- Added this line.
}

                    

2.4.2.3. Modifying the event segment's readout

When we read the event segment, we must begin and end the packet. The modified version of CMyEventSegment::Read is shown below:

Example 2-16. CAEN V775 Event Segement with packetization


unsigned short*
CMyEventSegment::Read(unsigned short* rBuffer)
{
  int bytesRead = 0;

  for (int i = 0; i < dataPresentTimeout; i++) {
    if(m_pModule->dataPresent()) {
      rBuffer = m_pPacket->Begin(rBuffer);          // (1)
      bytesRead = m_pModule->readEvent(rBuffer);
      rBuffer += bytesRead/sizeof(short);              // (2)
      rBuffer = m_pPacket->End(rBuffer);            // (3)
      break;
    }
  }

  return rBuffer;
}

                    
(1)
Before adding any data to the buffer for this segment, we begin the packet.
(2)
Since the CDocumentedPacket::End function needs to know where the packet ends to properly close the packet, we compute the location of the next free event.
(3)
This call closes the packet and fills in the unknown pieces of the header.

2.4.3. Effect on the data structure.

Lets see what all this does to our buffer structure. Start bufdump as before. This time, before starting a run, connect to the online system, set up the filter to accept both event buffers and packet-types buffers. The packet-types buffers are emitted at the beginning of a run, and describe the documented packets created by the readout segments.

Tell bufdump to get the next buffer, and only now start the run with your new packetizing event source. Bufdump should immediately dump something like the following:


Packet Type definitions buffer containing 1 packet descriptions
Name      Id         Description                Version   Instantiated
Detector1 0x8100     CAEN V775 event data         1.0     Mon May  8 07:26:33 2006
            

This is a formatted dump of the packet description buffer. Note that the name, Id, description and version match our parameters to the CDocumentedPacket constructor. Furthermore, the packet documentation describes when the CDocumentedPacket was created.

Now click the next buffer button again, to look at an event buffer. The first few events might look like:


Event Data buffer with 441 events
Event: 0  Size: 9 :
   Packet id 0x8100 : CAEN V775 event data Body size: 6 body:
0x5200 0x0100 0x5000 0x4467 0x5413 0xec97

Event: 1  Size: 9 :
   Packet id 0x8100 : CAEN V775 event data Body size: 6 body:
0x5200 0x0100 0x5000 0x4468 0x5413 0xec98

Event: 2  Size: 9 :
   Packet id 0x8100 : CAEN V775 event data Body size: 6 body:
0x5200 0x0100 0x5000 0x4467 0x5413 0xecdd

            
Note that the packet documentation buffer enables the bufdump program to recognize and correctly decode the packet in the event as having id 0x8100 and being a CAEN V775 event data Body packet. The size of the packet is given as well as the contents of the body which are about what we'd expect to see. If the event had several packets, each one would be identified and formatted in turn.

Some legacy software produces packets without using the CDocumentedPacket class. bufdump therefore reads in a packet definition file that describes the set of packet ids that have been allocated at the NSCL. The bufdump online help and the reference information later in this book describe how to incorporate additional packet definitions to bufdump as well as how to program plugins which know how to format the body of packets in an application specific way.