This section will present:
Note that throughout, this page and examples, we will make use of the data and functions that are defined in the CCAENV1x90Data namespace. These definitions can be incorporated in your code as follows:
In your implementation software add the header:
This header file is located in the DAQ library include file directory (e.g. /usr/opt/daq/{version}/include) where {version} is the version of the daq client software you are using (The first version that supports this module is 7.4 e.g. /usr/opt/daq/7.4/include).
You will need to modify your SpecTcl Makefile to search this directory for headers. To do this locate the definition of USERCXXFLAGS in your Makefile (SpecTcl 2.2 and later), and add the appropriate -I switch for example:
USERCXXFLAGS=-I/usr/opt/daq/7.4/include
Get help from the computer group if you are using versions of SpecTcl that pre-date 2.2 if needed.
Refer to figures 6.1 through 6.7 of the hardware manual when reading this section. These figures depict the data that the module produces.
The data from the TDC consists of a series of long words. Bits 27-31 of each longwords describe the longword type. The longword types produced by the module include:
- Global Header: Each event begins with a global header longword. This longword contains the Event number and the module virtual slot number that was programmed when the module object was constructed. The function CCAENV1x90Data::isGlobalHeader will return true if the longword passed to it is a global header. The functions CCAENV1x90Data::TriggerNumber and CCAENV1x90::BoardNumber will return the event number and the virtual slot number respectively for global headers.
- Global Trailer: Each event ends with a global trailer longword global trailer words contain the event word coutn, slot address and some status information about the event. CCAENV1x90Data::isGlobalTrailer will determine if a longword passed to it is a global trailer. Once you know a longword is a global trailer you can call CCAENV1x90Data::BoardNumber to get the virtual slot number, CCAENV1x90Data::EventSize to get the number of longwords that comprise the event, CCAENV1x90Data::Overflow to determine if the buffer overflow status bit is set in the trailer, CCAENV1x90Data::Error to determine if the TDC error status bit is set, and CCAENV1x90Data::Lost to determine if the trigger lost bit is set in the status field.
- TDC Chip header. If CCAENV1x90::EnableTDCEncapsulation has been called to enable it, the data from each TDC chip is encapsulated in TDC Chip header and chip trailer longwords. The chip header includes the TDC number (0-3), The event ID (only 12 bits), and the bunch id. You can determine if a longword is a TDC chip header if by calling CCAENV1x90Data::isTDCHeader. Once you know the longword is a TDC header you can call: CCAENV1x90Data::TDCChip to get the chip number associated with the header, CCAENV1x90Data::EventId to get the evnet id, and CCAENV1x90Data::BunchId to get the bunch id. field.
- TDC Chip Trailer. IF CCAENV1x90::EnableTDCEncapsulation was called to enable it, the data from each TDC chip is followed by a TDC Chip trailer longword. The chip trailer contains the TDC chip number, the Event Id, and the number of words (0-32767) produced by the chip. You can determine if a longword is a TDC Chip trailer by calling CCAENV1x90Data::isTDCTrailer. If you have a trailer longword, you can additionally call: CCAENV1x90Data::TDCChip toget the chip number, CCAENV1x90Data::EventId to get the event number and CCAENV1x90Data::TDCWordCount to get the number of longwords produced by the chip.
- TDC Measurement. No event would be complete without actual data. TDC measurement longwords contain the data from one channel of the TDC. Note that since the V1x90 is a multihit TDC you may get more than one data word from each channel. TDC Data words contain a channel number (channel numbers are unique within a module, not unique within a chip), an indicator of whether or not the measurement is a leading or a trailing edge measurement, and the measurment itself. The function CCAENV1x90Data::isMeasurement determines if the longword passed to it is a measurement. Once this is determined, you may call: CCAENV1x90Data::isTrailing to determine if the measurement is a trailing edge measurement, CCAENV1x90Data::ChannelNumber to determine the channel from which the data comes, and CCAENV1x90Data::ChannelValue to get the measurement. See section 6.2.1.1 in the hardware manual for the format of this measurement.
- TDC Error. The TDC does extensive error monitoring. This word will summarize any errors detected by a chip during the event. The longword contains the TDC Channel number, and the error bits CCAENV1x90Data defines individual masks for each error bit (e.g. CCAENV1x90Data::HITLOST_0_FIFO). CCAENV1x90Data::isTDCError returns true when passed a TDC error longword. Once you have determined a longword is a TDC error, you may call CCAENV1x90Data::TDCErrorBits to retrieve the error bitmask.
- Trigger Time tag: In some operation modes, the TDC may insert a Trigger time tag word. This longword contains the time of the trigger relative to the count reset time. CCAENV1x90Data::isTriggerTimeTag determines if its parameter is a trigger time tag word. If it is, CCASENV1x980::ExtendedTriggerTime can be called to retrieve the trigger time.
By far the worst issue an unpacker for this module will have to face is the multihit nature of the module. Assuming that you need to histogram all of the raw hits from each channel, the simplest way to deal with this is to define parameter sets for each channl, one parameter for the first hit, another for the second and so on. A 'summed' spectrum over all the hits can be created using a gamma spectrum. Individual hit spectra can also be produced to support gating on e.g. the second hit in channel 5. An or gate of all of these for a channel produces a gate for the multiple hit containing at least one hit inside the slice. If you are using TreeParam, you can create hit arrays to effectively manage these parameters.
In our sample code we will create hit parameters limited to 16 hits per channel.
This section assumes that:
- Channel 0 will have exactly one hit. That hit is the time of the gate. While the TDC can subtract the gate time from the hit time, the gate timing is only known by the module to 25ns. It is better to extend the matching window to cover the gate time and digitize the gate as well. Having done that time relative to the gate can be gotten by subtracting the hit times from the gate time in software.
- We are unpacking an event that consists solely of the data from one TDC module.
- That the TDC moudule has been assigned virtual slot 2.
- That the TDC Module is a v1290N (16 channels).
- That each channel will be allowed to accept at most 4 hits.
- That TDC Chip header/trailers are enabled.
- The module is not in pair or both mode (there are only either leading or trailing edge hits.
In order to focus attention on the process of unpacking the data:
- Error checking will consist of ignoring the event completely.
- TDC error words will be ignored completely.
- We will not check for truncated events (events that are smaller than claimed by the global trailer.
- Hits from channel 0 will be stored in param 0,1,2,3 from 1 in 4,5,6,7 etc.
- Hits in excess of 4 per channel will be ignored.
We will create a custom event processor to handle this module. The event processor will be a class that is defined in the header v1290processor.h, implemented in v1290processor.cpp, and hooked into SpecTcl via code added to MySpecTclApp.cpp. The class will be called C1290Processor.
To hook this unpacker into SpecTcl, we must include the v1290processor.h header This is shown below:
#include "MySpecTclApp.h"
#include "EventProcessor.h"
#include "TCLAnalyzer.h"
#include <Event.h>
#include "v1290processor.h"
We will also need to create an instance of a C1290Processor object and add it to the list of event processors that are executed by SpecTcl for each event. We will assume that the constructor of the event processor will require two parameters:
- nSlot - The virtual slot number that is decoded.
- nFirst- The number of the first parameter into which this module will unpack.
This will allow the unpacker to be used in other environments.
To do this we need to make the following changes to CMySpecTclApp::CreateAnalysisPipeline
void
CMySpecTclApp::CreateAnalysisPipeline(CAnalyzer& rAnalyzer)
{
#ifdef WITHF77UNPACKER
RegisterEventProcessor(legacyunpacker);
#endif
RegisterEventProcessor(*(new C1290Processor(2, 0)));
}
The event processor class header must:
- Declare any data it must retain between events.
- Declare functions it intends to implement from the base class definition.
- Declare a constructor if necessary.
In our case, we will need to keep the Virtual slot number and the base parameter id. To do this we will need to implement a constructor. We will also need to implement the function call operator (operator()) to unpack the data for each event. This leads to the following as the contents of v1290processor.h
#ifndef __V1290PROCESSOR_H
#define __V1290PROCESSOR_H // (1)
#include <EventProcessor.h>
class C1290Processor : public CEventProcessor
{
private:
unsigned int m_nVsn;
unsigned int m_nBaseParameter;
public:
C1290Processor(unsigned int nSLot,
unsigned int nBase);
virtual Bool_t operator()(const Address_t pEvent,
CEvent& rEvent,
CAnalyzer& rAnalyzer,
CBufferDecoder& rDecoder);
};
#endif
- This ifdef/define pair ensures that if the header is included twice it is non functional the second time. In complex software this is a must. In simple software this is still recommended.
- This starts the class definition. The class has the CEventProcessor as its base class.
- m_nVsn will be the virtual slot number of the module.
- m_nBaseParameter will be the number of the first parameter used by this unpacker/event processor.
- This constructor will be defined to intialize m_nVsn and m_nBaseParameter from its actual arguments.
- This function will be called once for each event. pEvent will point to the raw event data, while rEvent is the 'array' of parameters that need to be filled in from the unpacked data. The other parameters are not needed by this and most event processors.
Let's now take up the implementation of the unpacking class (v1290processor.cpp). The constructor implementation is shown below:
C1290Processor::C1290Processor(unsigned int nSlot,
unsigned int nBase) :
m_nVsn(nSlot),
m_nBaseParameter(nBase)
{
}
- This begins the implementation of the C1290Processor class constructor. This function will be called whenever a C1290Processor object is created. The colon at the end of what looks like a nearly normal function header indicates that this constructor, in turn, will call other constructors. The constructor ivocations (2,3) follow the colon as a comma spearated list.
- This is a constructor invocation for the m_nVsn member data of the class. m_nVsn is initialized to the value of the nSlot parameter.
- This is a constructor invocation for the m_vBaseParameter member data. m_nBaseParameter is initialized to the value of the nBase parameter.
The unpacking operator is a bit more interesting. There are several things we need to do:
- Establish a translating pointer to the event so that we don't have to worry about byte order differences between this system and the system that wrote the data (the data may have been taken on linux systems but being analyzed on a Mac OS-X system).
- Determine and report the size of the event to the analyzer framework.
- Process the longwords in the event one by one doing the appropriate thing for each longword.
Bool_t
C1290Processor::operator()(void* pEvent,
CEvent& rEvent,
CAnalyzer& rAnalyzer,
CBufferDecoder& rDecoder)
{
TranslatorPointer<UShort_t> pw(*(rDecoder.getBufferTranslator()),
pEvent);
UShort_t nWords = *pw++;
CTclAnalyzer& rAna(static_cast<CTclAnalyzer&>(rAnalyzer));
rAna.SetEventSize(nWords*sizeof(UShort_t));
ULong_t nLongs = (nWords-1)*sizeof(UShort_t)/sizeof(ULong_t); (4)
int nSlot = -1;
bool FormatOk;
long hits[128][MAXHITSPERCHANNEL];
long nHits[128];
for(int i=0; i < 128; i++) {
nHits[i] = 0;
}
while (nLongs) {
ULong_t data = *pw;
++pw;
data |= *pw << 16;
++pw;
nLongs--;
if(CCAENV1x90Data::isGlobalHeader(data)) {
nSlot = CCAENV1x90Data::BoardNumber(data);
}
if(CCAENV1x90Data::isTDCHeader(data)) {
}
if(CCAENV1x90Data::isTDCTrailer(data)) {
}
if(CCAENV1x90Data::isTDCError(data)) {
}
if(CCAENV1x90Data::isMeasurement(data)) {
int nChannel = CCAENV1x90Data::ChannelNumber(data, false);
long nValue = CCAENV1x90Data::ChannelValue(data, false);
if(nSlot == m_nVsn) {
if(nHits[nChannel] < MAXHITSPERCHANNEL) {
hits[nChannel][nHits[nChannel]] = nValue;
nHits[nChannel]++;
}
}
}
if(CCAENV1x90Data::isGlobalTrailer(data)) {
if(nLongs) {
FormatOk = false;
} else {
FormatOk = (nSlot == m_nVsn);
}
}
}
if(FormatOk) {
if(nHits[0] == 1) {
long nGateTime = hits[0][0];
int nParam = m_nBaseParameter;
for(int nChan = 1; nChan < 128; nChan++) {
for(int ihit = 0; ihit < nHits[nChan]; ihit++) {
rEvent[nParam + ihit] = nGateTime - hits[nChan][ihit];
}
nParam += MAXHITSPERCHANNEL;
}
}
}
return kfTRUE;
}
- This line establishes a translating buffer pointer for the event. Translating buffer pointers automatically handle differences in byte ordering between systems. Using translating buffer pointers allows data taken at the NSCL on Intel Linux systems to be analyzed transparently on e.g. MAC OS-X or Sun Solaris systems, where the internal bytes of a word are ordered differently.
- The first word of the event is the size of the event in words. We keep a copy of this to be able to determine when we have reached the end of the event.
- SpecTcl needs to know how large each event is in bytes. It uses this event size to determine where the next event in a multi-event buffer starts. The event size is given to SpecTcl by calling the analyzer's SetEventSize member function. This pair of lines casts the analyzer to its actual type (a CTclAnalyzer) and invokes that member function.
- The TDC module produces longword data. This line calculates the number of longwords of data in the event (exclusing the word count).
- Several pieces of information will be produced by the first phase of unpacking (the data decode). These are the module's virtual slot number (nSlot). A determination that the event is properly formatted (FormatOk). The hits (hits) will be stored in an array of MAXHITSPERCHANNEL for each of the 128 channels in the module. For each channel, we also save the number of hits (nHits). This array is zeroed since initially we have no hits.
- This line reconstructs a longword of data from the buffer.
- If the data longword from the TDC is a global header, the board number (virtual slot) is decoded and saved in nSlot.
- If the data longword is a measurement (Tdc value). The channel and value are decoded. If, for that channel, MAXHITSPERCHANNEL hits have not yet been decoded, the next hit position for that channel is used to store the hit time and the number of hits for that channel is incremented.
- If the longword is a global trailer, two sanity checks are performed. If the number of longs is not yet zero, the event is badly formatted (this will not be the case if the tdc data is mixed with data from other devices). If the module's virtual slot does not match the slot we are decodeing, this indicates we have unpacked data from the wrong module and the unpacked data should not be converted to parameters.
- The decoded hits are stored in parameters only if FormatOk is true.
- We also require there be exactly one hit in channel 0, the digitization of the trigger time. This is saved in nGateTime.
- Each hit is then put in an associated parameter after its time relative to the trigger time is computed.
- The unpacking function returns true indicating that other event processors in the pipeline can be called, and the event histogrammed.
Generated on Wed Sep 17 08:38:10 2008 for NSCL Device support. by
1.5.1