The ringFragmentSource program provides a mostly pre-packaged program that efficiently gets data from a ring buffer and efficiently submits it to an event builder. Since event data in a ring buffer may have arbitrary format, the user must supply software to extract the timestamp from each event. This software is supplied in the form of a shared object library.
A pre-packaged timestamp extraction library for the S800 is supplied and will be maintained in $DAQROOT/lib/libS800TimeExtractor.so
In addition to the standard ring client framework command options, the following switches are are required.
--ring
=ring-uriDefines the ring from which data will be acquired. This can be local (tcp://localhost/ringname), or remote (tcp://somwhere.nscl.msu.edu/ringname)
--timestampextactor
=file-pathSpecifies the path to the shared library you have built that extracts timestamps from ring events. For the s800 pre-built extractor this should be $DAQHOST/lib/libS800TimeExtractor.so
This section describes how to write timestamp extractors. The source code for the s800 timestamp extractor is also given as an annotated example.
Timestamp extractors must provide an entry point named
timestamp
. This function takes a single
argument; the pointer to the Physics Ring Item which must
be analzed. The function must return a 64 bit timestamp as
its result (uint64_t).
If the timestamp extractor is written in C++, you must declare
the timestamp
function as extern "C". You do not need
to do this if timestamp
is writte in C.
Let's look at the timestamp extractor for the S800. We are not going to bother with the s800.h header file. The actual values of each symbol defined in that file are unimportant. We'll just explain the meaning of the symbols it defines that we need.
Example 52-7. S800 timestamp extractor (s800timestamp.c
#include "s800.h" #include <DataFormat.h> #include <assert.h> #include <stdint.h> uint64_t timestamp(pPhysicsEventItem item) { pS800event pFullEvent; pS800timestamp pTimestamp; ppacket pNextPacket; uint16_t* pWords; int64_t nRemaining; int nPktSize; pFullEvent = (pS800event)(item->s_body); assert(pFullEvent->s_type == S800_PACKET); uint16_t versionWord = pFullEvent->s_version; versionWord = (versionWord & S800_OUTERVSNMASK) >> S800_OUTERVSNSHIFT; assert(versionWord == S800_OUTERVERSION); nRemaining = pFullEvent->s_size * sizeof(uint16_t); pNextPacket= &(pFullEvent->s_firstPacket); nRemaining -= sizeof(S800event) - sizeof(packet); while(nRemaining > 0) { if (pNextPacket->s_type == S800_TIMESTAMP_PACKET) { pTimestamp = (pS800timestamp)pNextPacket; return (pTimestamp->s_timestamp); } nPktSize = pNextPacket->s_size; pWords = (uint16_t*)pNextPacket; pNextPacket = (ppacket)(pWords + nPktSize); nRemaining -= nPktSize*sizeof(uint16_t); } assert(0); }
Before annotating the example, a few words about the event format. The S800 ring item body leads off with a 32 bit event size. The entire S800 event is encapsyualted in an S800 packet consisting of a word count and a 16 bit constant: S800_PACKET. The s800 packet includes a 16bit version word. The most significant four bits of that word are the overall event format while the bottom 12 bits are the experiment format version.
Following that, a set of 'packets' appear. Each packet has a 16 bit word size a 16 bit type and a payload whose size, when added to the size of the packet header equals the packet size word. One of these packets of type, S800_TIMESTAMP_PACKET constains the timestamp.
The numbers in the list of comments below refer to the corresponding numers in the program listing.
The typecast makes that pointer (normally a void*) a pointer to a struct that represents the outermost layer of an S800 event.
This drastic action is taken becaus if we cannot ensure that the version is one we know about, we can't ensure that the correct timestamp can be extracted from the events. Even worse than failing later on would be to send events with bad timestamp values.