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.
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 (<bazin@nscl.msu.edu>). 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.
Packets provide a predictable structure on the buffer which makes it easier to write analysis software.
Each packet's readout and its corresponding SpecTcl unpacker can be maintained indepdendently of other packets, making it easy to compose the software of an experiment from existing modules.
Packets document the contents of a buffer.
Packet bodies can in turn have a sub-packet structure to provide whatever depth of structure is desired/required to organize the data.
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.
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.
CDocumentedPacketConstructs 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.
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> //class CAENcard; class CDocumentedPacket; //
class CMyEventSegment : public CEventSegment { private: int m_nSlot; int m_nPedestal; CAENcard* m_pModule; CDocumentedPacket* m_pPacket; //
public: CMyEventSegment(int nSlot, int nPedestal, int id, STD(string) name); //
~CMyEventSegment(); virtual void Initialize(); virtual unsigned short* Read(unsigned short* rBuffer); virtual void Clear(); virtual unsigned int MaxSize() {return 0;} }; #endif

string class.

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.

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.

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> //. . . CMyEventSegment::CMyEventSegment(int nSlot, int nPedestal, int id, string name) : m_nSlot(nSlot), m_nPedestal(nPedestal), m_pModule(new CAENcard(nSlot)), m_pPacket(0) //
{ // 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, //
string("CAEN V775 event data"), string("1.0")); }

CDocumentedPacket objects is known to the compiler>

m_pPacket pointer is initialized to null.
We will not bother to allocated the packet unless the card is really
a V775.

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:
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); //
bytesRead = m_pModule->readEvent(rBuffer);
rBuffer += bytesRead/sizeof(short); //
rBuffer = m_pPacket->End(rBuffer); //
break;
}
}
return rBuffer;
}


CDocumentedPacket::End
function needs to know where the packet ends to properly close the
packet, we compute the location of the next free event.

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.