NSCL Ring buffer DAQ tutorial | ||
---|---|---|
Prev | Chapter 4. Creating a Readout program from a spectrodaq classic readout program | Next |
This section will provide a guide to the modifications you will need to make to a skeleton.cpp and files it depends on to be able to use it with the RingDaq readout framework.
The primary modifications are needed in readevt
and the set of headers and stem from the fact that
spectrodaq.h no longer exists as RingDaq
by definition does not use spectrodaq, and the fact that therefore
DAQWordBufferPtr
objects also no longer
exist. DAQWordBufferPtr
objects are
replaced by ordinary pointers to ordinary memory.
Since a DAQWordBufferPtr
does a good job
of imitating an ordinary pointer, these modifications should have
minimal impact on your actual code.
I'm going to show two fairly empty readevt
functions and what you have to do to them. The first is the
'standard' version, where data are taken into DAQWordBufferPtr
objects directly, while the second uses the
DAQWordBufferPtr::CopyIn
function and a
local buffer to improve the SPDAQ performance.
Let's look at the relevant pieces of the first case. Many of the standard comments have been removed for the sake of brevity, as is the standard body.
Example 4-3. A readout classic readevt
... #include <spectrodaq.h>... #include <daqinterface.h>
... WORD #ifdef __unix__ readevt (DAQWordBufferPtr& bufpt)
#else readevt (WORD* bufpt) #endif { #ifdef __unix__ DAQWordBufferPtr _sbufpt = bufpt;
#else WORD *_sbufpt = bufpt; #endif LOGICAL reject; reject = FALSE; { // code here that invokes putbufw a bunch of times explicitly or // implicitly. ... } IF(reject) return 0; #ifdef __unix__ return bufpt.GetIndex() - _sbufpt.GetIndex();
#else return (bufpt - _sbufpt); #endif }
DAQWordBufferPtr
readevt
is passed a reference
to a DAQWordBufferPtr
.
Data then get stored via that object.
DAQWordBufferPtr::GetIndex
method returns the offset of the 'pointer' in the
underlying buffer. This line therefore determines
how many words have been read by readevt
In fact the non __unix__ version of
readevt
is actually almost correct
for the RingDaq. Here's how this code fragment would be
modified:
Example 4-4. skeleton.cpp modified for RingDaq
...WORD readevt (WORD* bufpt)
{ WORD *_sbufpt = bufpt; LOGICAL reject; reject = FALSE; { // readout code that uses putbufw etc. ... } IF(reject) return 0; return (bufpt - _sbufpt);
}
readevt
has been modified to take a WORD* rather than
a DAQWordPtr&
paramter.
putbufl and its compatriots are pre-processor macros
that only require that the bufpt
variable be in scope and have pointer-like semantics.
Now lets look at the case where readevt
reads data into a local buffer and then uses DAQWordBuferPtr::CopyIn
to transfer it to the spectrodaq buffer. Typically
readevt
functions have the following form:
Example 4-5. Classic readout using CopyIn
static WORD localBuffer[8192];... WORD #ifdef __unix__ readevt (DAQWordBufferPtr& bufpt) #else readevt (WORD* bufpt) #endif { #ifdef __unix__ DAQWordBufferPtr _sbufpt = bufpt; #else WORD *_sbufpt = bufpt; #endif LOGICAL reject; reject = FALSE; { WORD* localbufpt = localbuffer;
// code here that invokes localputbufw a bunch of times explicitly or // implicitly. putting data into localbuffer. ... int nWords = localbufpt - localBuffer;
bufpt.CopyIn(localBuffer, 0, nWords);
bufpt += nWords;
} IF(reject) return 0; #ifdef __unix__ return bufpt.GetIndex() - _sbufpt.GetIndex(); #else return (bufpt - _sbufpt); #endif }
Key features of this scheme are:
readevt
functions that follow
this pattern declare a local buffer into which
data are first read.
putbufw
usually named something like localputbufw
are used to put data into this local buffer.
DAQWordBufferPtr::CopyIn
method.
DAQWordBufferPtr
object
is advanced so that the size calculation done by the
framework code is done correctly (or in some cases
nWords
is simply returned at that point).
With RingDaq, since readevt
is recdeiving
an ordinary pointer parameter, there are no efficiency gains to be
had by using a local buffer. In order to avoid having to recast all
the readout code in terms of e.g. putbufw
the
following trick can be used:
Example 4-6. Converting Classic readout with local buffers to RingDaq
#include <stdint.h>
... readevt (uint16_t bufpt) WORD *_sbufpt = bufpt; LOGICAL reject; reject = FALSE; { WORD* localbufpt = bufpt;
// code here that invokes localputbufw a bunch of times explicitly or // implicitly. putting data into localbuffer. ... bufpt = localbuffer;
} IF(reject) return 0; return (bufpt - _sbufpt); }
localbufpt
is just initialized
to point to the buffer passed in to readevt
this allows macros like localputbufw
to function properly without source code modification.
bufpt
to the value of
localbufpt
is all that is then needed
to make the size computation performed by the
framework code function correctly.