#include <DataFormat.h> typedef struct _RingItemHeader { uint32_t s_size; uint32_t s_type; } RingItemHeader, *pRingItemHeader; typedef struct _BodyHeader { uint32_t s_size; uint64_t s_timestamp; uint32_t s_sourceId; uint32_t s_barrier; } BodyHeader, *pBodyHeader; typedef struct _RingItem { RingItemHeader s_header; union { struct { uint32_t s_mbz; uint8_t s_body[1]; } u_noBodyHeader; struct { BodyHeader s_bodyHeader; uint8_t s_body[]; } u_hasBodyHeader; } s_body; } RingItem, *pRingItem; typedef struct _StateChangeItemBody { uint32_t s_runNumber; uint32_t s_timeOffset; uint32_t s_Timestamp; uint32_t s_offsetDivisor; char s_title[TITLE_MAXSIZE+1]; } StateChangeItemBody, *pStateChangeItemBody; typedef struct _StateChangeItem { RingItemHeader s_header; union { struct { uint32_t s_mbz; StateChangeItemBody s_body; } u_noBodyHeader; struct { BodyHeader s_bodyHeader; StateChangeItemBody s_body; } u_hasBodyHeader; } s_body; } StateChangeItem, *pStateChangeItem; typedef struct _ScalerItemBody { uint32_t s_intervalStartOffset; uint32_t s_intervalEndOffset; uint32_t s_timestamp; uint32_t s_intervalDivisor; uint32_t s_scalerCount; uint32_t s_isIncremental; uint32_t s_scalers[1]; } ScalerItemBody, *pScalerItemBody; typedef struct _ScalerItem { RingItemHeader s_header; union { struct { uint32_t s_mbz; ScalerItemBody s_body; } u_noBodyHeader; struct { BodyHeader s_bodyHeader; ScalerItemBody s_body; } u_hasBodyHeader; } s_body; } ScalerItem, *pScalerItem; typedef struct _TextItemBody { uint32_t s_timeOffset; uint32_t s_timestamp; uint32_t s_stringCount; uint32_t s_offsetDivisor; char s_strings[]; } TextItemBody, *pTextItemBody; typedef struct _TextItem { RingItemHeader s_header; union { struct { uint32_t s_mbz; TextItemBody s_body; } u_noBodyHeader; struct { BodyHeader s_bodyHeader; TextItemBody s_body; } u_hasBodyHeader; } s_body; } TextItem, *pTextItem; typedef struct _PhysicsEventItem { RingItemHeader s_header; union { struct { uint32_t s_mbz; uint16_t s_body[]; } u_noBodyHeader; struct { BodyHeader s_bodyHeader; uint16_t s_body[]; } u_hasBodyHeader; } s_body; } PhysicsEventItem, *pPhysicsEventItem; typedef struct __PhysicsEventCountItemBody { uint32_t s_timeOffset; uint32_t s_offsetDivisor; uint32_t s_timestamp; uint64_t s_eventCount; } PhysicsEventCountItemBody, *pPhysicsEventCountItemBody; typedef struct _PhysicsEventCountItem { RingItemHeader s_header; union { struct { uint32_t s_mbz; PhysicsEventCountItemBody s_body; } u_noBodyHeader; struct { BodyHeader s_bodyHeader; PhysicsEventCountItemBody s_body; } u_hasBodyHeader; } s_body; } PhysicsEventCountItem, *pPhysicsEventCountItem; typedef struct _EventBuilderFragment { RingItemHeader s_header; BodyHeader s_bodyHeader; uint8_t s_body[]; } EventBuilderFragment, *pEventBuilderFragment; typedef struct _DataFormat { RingItemHeader s_header; uint32_t s_mbz; uint16_t s_majorVersion; uint16_t s_minorVersion; } DataFormat, *pDataFormat; typedef struct _GlomParameters { RingItemHeader s_header; uint32_t s_mbz; uint64_t s_coincidenceTicks; uint16_t s_isBuilding; uint16_t s_timestampPolicy; } GlomParameters, *pGlomParameters; typedef strucst _AbnormalEndItem { RingItemHeader s_header; uint32_t s_mbz; // Empty body header. } AbnormalEndItem, *pAbnormalEndItem; pPhysicsEventItem formatEventItem(size_t nWords, void* pPayload); pPhysicsEventCountItem formatTriggerCountItem(uint32_t runTime, time_t stamp, uint64_t triggerCount); pScalerItem formatScalerItem(unsigned scalerCount, time_t timestamp, uint32_t btime, uint32_t etime, void* pCounters); pScalerItem formatNonIncrTSScalerItem(unsigned scalerCount, time_t timestamp, uint32_t btime, uint32_t etime, uint64_t eventTimestamp, void* pCounters, uint32_t timebaseDivisor); pTextItem formatTextItem(unsigned nStrings, time_t stamp, uint32_t runTime, const char** pStrings, int type); pStateChangeItem formatStateChange(time_t stamp, uint32_t offset, uint32_t runNumber, const char* pTitle, int type); pDataFormat formatDataFormat(); pGlomParameters formatGlomParameters(uint64_t coincidenceWindow, int isBuilding, int timestampPolicy); pEventBuilderFragment formatEVBFragment( uint64_t timestamp, uint32_t sourceId, uint32_t barrier, uint32_t payloadSize, const void* pPayload ); pEventBuilderFragment formatEVBFragmentUnknown ( uint64_t timestamp, uint32_t sourceId, uint32_t barrier, uint32_t payloadSize, const void* pPayload ); pPhysicsEventItem formatTimestampedEventItem( uint64_t timestamp, uint32_t sourceId, uint32_t barrier, uint32_t payloadSize, const void* pPayload ); pPhysicsEventCountItem formatTimestampedTriggerCountItem ( uint64_t timestamp, uint32_t sourceId, uint32_t barrier, uint32_t runTime, uint32_t offsetDivisor, time_t stamp, uint64_t triggerCount ); pScalerItem formatTimestampedScalerItem( uint64_t timestamp, uint32_t sourceId, uint32_t barrier, int isIncremental, uint32_t timeIntervalDivisor, uint32_t timeofday, uint32_t btime, uint32_t etime, uint32_t nScalers, void* pCounters ); pTextItem formatTimestampedTextItem( uint64_t timestamp, uint32_t sourceId, uint32_t barrier, unsigned nStrings, time_t stamp, uint32_t runTime, const char**pStrings, int type, uint32_t timeIntervalDivisor ); pStateChangeItem formatTimestampedStateChange( uint64_t timestamp, uint32_t sourceId, uint32_t barrier, time_t stamp, uint32_t offset, uint32_t runNumber, uint32_t offsetDivisor, const char* pTitle, int type ); pAbnormalEndItem formatAbnormalEndItem(); void* bodyPointer(pRingItem pItem);
This header describes the format of data placed in NSCL ring
buffers. Each item consists of an envelope and a payload.
The envelope,
RingItemHeader contains a size:
uint32_t s_size;
which is the total size of the item (inlcuding the header) in
bytes, and an item type
uint32_t s_type;
which indicates what the item contains. The payload immediately
follows the header and varies in structure depending on the
value in s_type
.
Items are placed in rings in native machine byte ordering. While the data type is 32 bits long, only the least significant 16 bits are nonzero. This allows a determination of the endianness of the system that generated the item.
Starting with NSCLDAQ 11.0, ring items may have an additional BodyHeader. The first field of this is the size of the body header (allowing for future expansion). If the body header size is 0 there is no body header. The body header is intended to carry information relevant to data that requires an event builder for assembly.
STRUCTURES below describes each of the ring items defined
at this time. CONSTANTS defines the set of values that
s_type
can take (once converted to
the localh host's endian-ness).
The following ring items have been defined:
This structure appears at beginning of each ring item. The type pRingItemHeader represents a pointer to a RingItemHeader. RingItemHeader structs contain the following fields:
s_size
The size in bytes of the entire ring item. The size includes the size of the RingItemHeader as well.
s_type
Contains the ring item type. See the section
CONSTANTS below for valid ring item types. While
the s_type
field is
uint32_t, the most significant 16
bits of this field are always zero, and the least
significant bits are always non-zero allowing
code to determinethe endianness of data in this
item (including the size).
Contains data about the event as a fragment of a larger event. The type pBodyHeader represents a pointer to this type.
The body header has the following fiels:
s_size
Contains the size of the ring item header. note that if this field is 0 there are no more fields (the item has no body header). This possibility in general means that ring items are described best by unions. See the documentation about the remaining ring item structures for more information.
s_timestamp
The timestamp of the event in ticks of the clock that defines event building.
s_sourceId
The id of the source that produced this item.
s_barrier;
If nonzero, this item is part of a barrier synchronization event.
This is a generic ring item. The type pRingItem defines a pointer to a ring item. This item has the following structure:
typedef struct _RingItem { RingItemHeader s_header; union { struct { uint32_t s_mbz; uint8_t s_body[1]; } u_noBodyHeader; struct { BodyHeader s_bodyHeader; uint8_t s_body[]; } u_hasBodyHeader; } s_body; } RingItem, *pRingItem;
The s_header
is the
RingItemHeader decribed above. The
union that follows provides support for ring items
that have (u_hasBodyHeader
)
and do not have (u_noBodyHeader
)
body headers.
The s_mbz
field is zero indicating
that the item has not body header.
The s_bodyHeader
is the
full body header.
In both branches of the union, the field
s_body
is where the actual
payload (body) of the ring item actually
is.
These contain information about a run state change. They have the following form:
typedef struct _StateChangeItem { RingItemHeader s_header; union { struct { uint32_t s_mbz; /* Must be zero - no body header*/ StateChangeItemBody s_body; } u_noBodyHeader; struct { BodyHeader s_bodyHeader; StateChangeItemBody s_body; } u_hasBodyHeader; } s_body; } StateChangeItem, *pStateChangeItem;
As you can see this is a union whose inner struture
depends on whether or not there is a body header
(u_hasBodyHeader
) or
not (u_noBodyHeader
).
You can tell which version of the union to use by examining
the s_mbz
field. If this is
zero use u_noBodyHeader
otherwise
use u_hasBodyHeader
The s_header
field is the
ring item header. If there is a Body header is is
s_bodyHeader
Regardless of which branch of the union you select, the
payload of the ring item is a StateChangeItemBody
in s_body
which has the following
structure:
typedef struct _StateChangeItemBody { uint32_t s_runNumber; uint32_t s_timeOffset; uint32_t s_Timestamp; uint32_t s_offsetDivisor; char s_title[TITLE_MAXSIZE+1]; } StateChangeItemBody, *pStateChangeItemBody;
s_runNumber
is the number of the
run that is undergoig a transition. s_timeoffset
together with s_offsetDivisor
determine when relative to the start of the run this state change
occured. s_timeoffset
is a time
offset in unites of 1/s_offsetDivisor
seconds.
The unix time_t for the absolute time at
which this occured is truncated to 32 bits and stored
in s_Timestamp
(note that
on 64 bit systems time_t is 64 bits
but on 32 bit systems 32 bits making it intrinsically
non-portable). This 32 bit time is good into the year
2038. s_offsetDivisor
stores the units of s_Timestamp
in 1/seconds. Thus s_Timestamp/s_offsetDivisor
is the offset in to the run in floating point seconds
(floating point values are also not as portable as fixed
length integers).
s_title
is the run title.
The title string is a null terminated string at most
TITLE_MAXSIZE non null characters long.
The additional char allocated ensures the
title has a null terminator. See CONSTANTS
below for more information about TITLE_MAXSIZE.
The ScalerItem item contains a set of periodically read scaler items. Starting in NSCLDAQ-11.0 these may or may not be incremental and may have interval start/stop time values that have a sub-second resolution.
As with most ring item data, the actual structure of this is represented as a union:
typedef struct _ScalerItem { RingItemHeader s_header; union { struct { uint32_t s_mbz; /* Must be zero .. no header */ ScalerItemBody s_body; } u_noBodyHeader; struct { BodyHeader s_bodyHeader; ScalerItemBody s_body; } u_hasBodyHeader; } s_body; } ScalerItem, *pScalerItem;
The union has the standard branches that most RingItems
have, u_noBodyHeader
when
s_mbz
is zero indicating a lack
of a body header and
s_hasBodyHeader
when it is
the size of an action BodyHeader struct.
Regardless, s_body
has the
actual scaler data body and looks like this:
typedef struct _ScalerItemBody { uint32_t s_intervalStartOffset; uint32_t s_intervalEndOffset; uint32_t s_timestamp; uint32_t s_intervalDivisor; /* 11.0 sub second time intervals */ uint32_t s_scalerCount; uint32_t s_isIncremental; /* 11.0 non-incremental scaler flag */ uint32_t s_scalers[1]; } ScalerItemBody, *pScalerItemBody;
The fields s_intervalStartOffset
,
s_intervalEndOffset
and
s_intervalDivisor
allow you to
determine the time relative to the beginning of the run at which
the counting interval started and ended. Dividing the offsets
by the divisor produces seconds (if done in floating point
arithmetic).
s_timetamp
provides the unix
time of day (trucated time_t) of the end of the
counting interval.
The s_isIncremental
is non-zero
if the the scalers are zeroed at the start of each interval.
Otherwise it is assumed that history is required to be able
to compute rates.
Finally s_scalerCount
is the
number of scalers in item and s_scales
is the location of the first element of the array of 32
bit wide scalers.
TextItem items contain a set of text strings that are used for documentation purposes or to allow the data acquisition system to track a set of slow controls parameters. As with almost all ringt items, the top level structure is a union:
typedef struct _TextItem { RingItemHeader s_header; union { struct { uint32_t s_mbz; /* Must be zero (no body header) */ TextItemBody s_body; } u_noBodyHeader; struct { BodyHeader s_bodyHeader; TextItemBody s_body; } u_hasBodyHeader; } s_body; } TextItem, *pTextItem;
The TextItemBody has the following shape:
typedef struct _TextItemBody { uint32_t s_timeOffset; uint32_t s_timestamp; uint32_t s_stringCount; uint32_t s_offsetDivisor; char s_strings[]; } TextItemBody, *pTextItemBody;
The s_timeOffset
and
s_offsetDivisor
are used to
represent the time at which this item was emitted relative
to the start of the run. s_timeOffset
is the offset. Doing a floating point by s_offsetDivisor
produces the seconds into the run at which the item was emitted.
s_timestamp
is the truncated
time_t that represents the absolute time at
which this item was emitted.
s_stringCount
is the number
of strings in the body. s_strings
points to the first byte of an array of bytes that contain
the null terminated strings carried by the item. The
format of these strings is entirely up to the emitter.
This item represents the response of a readout subsystem to a trigger. This may be passed as an event fragment to an event building pipeline. The struture of the item is the normal union shape:
typedef struct _PhysicsEventItem { RingItemHeader s_header; union { struct { uint32_t s_mbz; uint16_t s_body[]; /* Aribrtary length body */ } u_noBodyHeader; struct { BodyHeader s_bodyHeader; uint16_t s_body[]; } u_hasBodyHeader; } s_body; } PhysicsEventItem, *pPhysicsEventItem;
s_body
is the first word of the
event body. The size of the body can be determined from the
s_size
field of the
s_header
ring item header.
Typically, the readout frameworks place a word or longword
into the s_body
that contains
the length of the event.
This ring item (new starting in NSCLDAQ-11.0) describes the oldest version of NSCLDAQ that is capable of handling this form of data in the ring buffer. The structure of this item is:
typedef struct _DataFormat { RingItemHeader s_header; uint32_t s_mbz; /* No body header */ uint16_t s_majorVersion; /* FORMAT_MAJOR */ uint16_t s_minorVersion; /* FORMAT_MINOR */ } DataFormat, *pDataFormat;
As the s_mbz
implies,
This item does not have a body header. All data submitted
to a single ring buffer is assumed to be in a compatible
format. The s_majorVersion
and
s_minorVersion
fields are the
major and minor versions of the oldest NSCLDAQ that can
deal with this data. For example for NSCLDAQ-11.0
s_majorVersion
is 11
while s_minorVersion
is
0
This ring item provides counts of the number of triggers a readout subsystem has responded to. This can be used to keep track of trigger rates and, for software that samples data, the fraction of data that has ben seen.
The structure of this data item is the usual union:
typedef struct _PhysicsEventCountItem { RingItemHeader s_header; union { struct { uint32_t s_mbz; /* Must be zero - no body header*/ PhysicsEventCountItemBody s_body; } u_noBodyHeader; struct { BodyHeader s_bodyHeader; PhysicsEventCountItemBody s_body; } u_hasBodyHeader; } s_body; } PhysicsEventCountItem, *pPhysicsEventCountItem;
The union is used so that individual contributors of fragments to the event builder can create uniquely identifiable trigger count items.
The s_body
field of both branches
of the union has the following shape:
typedef struct __PhysicsEventCountItemBody { uint32_t s_timeOffset; uint32_t s_offsetDivisor; uint32_t s_timestamp; uint64_t s_eventCount; /* Maybe 4Gevents is too small ;-) */ } PhysicsEventCountItemBody, *pPhysicsEventCountItemBody;
The time into the run is determined in the usual way
from s_timeOffset
and
s_offsetDivisor
. Furthermore,
s_timestamp
provides the
truncated time_t value that identifies the
absolute time at which this item was emitted.
s_eventCount
are the number
of triggers that have been responded to since the start
of the run.
An event builder fragment item is produced in event builder monitor rings. These rings allow users to monitor the ordered data data from the ordering stage of the event builder pipeline. These data are produced by the teering program, and are also inputs to glom.
Since the event builder operates on timestamps and needs to know about barriers and event sources all event fragments have a body header:
typedef struct _EventBuilderFragment { RingItemHeader s_header; BodyHeader s_bodyHeader; uint8_t s_body[]; /* Really s_payload bytes of data.. */ } EventBuilderFragment, *pEventBuilderFragment;
s_body
is the first byte of
the payload of the fragment. The size of the fragment
can be determined from s_header.s_size
(specifically
s_header.s_size - sizeof(RingItemHeader) - sizeof(BodyHeader))).
It is also not unusual for the structure of the body to
describe the size of the s_body
independent
of the rest of the item..
This item type is produced by the glom stage of the event building pipeline. glom is the stage that can glue (or glom) ordered event fragments into full events.
This event item captures the values of the run time parameters handed to ghlom at startup time so that consumers of this data know what they mean,
typedef struct _GlomParameters { RingItemHeader s_header; uint32_t s_mbz; uint64_t s_coincidenceTicks; uint16_t s_isBuilding; uint16_t s_timestampPolicy; } GlomParameters, *pGlomParameters;
As you can see by the s_mbz
field,
this item does not have a ring body header. The
s_isBuilding
, is non zero if
glom is gluing events together and zero otherwise.
s_coincidenceTicks
is therefore
only meaningful if s_isBuilding
is nonzero. It represents the timestamp interval that
glom considers defines a fragment coincidence window.
Finally the s_timestampPolicy
contains the timestamp policy that glom used to determine
how timestamp fields in body headers of built events should
be chosen. This is one of GLOM_TIMESTAMP_FIRST,
GLOM_TIMESTAMP_LAST or GLOM_TIMESTAMP_AVERAGE.
typedef strucst _AbnormalEndItem { RingItemHeader s_header; uint32_t s_mbz; // Empty body header. } AbnormalEndItem, *pAbnormalEndItem;
This can be emitted to let downstream software know that a run was ended prematurely. When emitted no more data shouild be emitted for the current run.
DataFormat.h provides constant definitions for the possible item type values as well as other definitions:
static const uint16_t FORMAT_MAJOR = 11;
This is the value that should normally be put in the
s_majorVersion
member of the
DataFormat ringitems.
At the time of writing the value is as shown above,
however check the DataFormat.h
file you are using in case this has been updated.
static const uint16_t FORMAT_MINOR = 0;
This is the value that should normally be put in the
s_majorVersion
member of the
DataFormat ringitems.
At the time of writing the value is as shown above.
Since data format changes require a change in the major
version number of NSCLDAQ I would expect this value
to be zero.
static const uint32_t BEGIN_RUN = 1;
The s_type
value in the
RingItemHeader of a state change item
that documents the start of a run.
static const uint32_t END_RUN = 2;
The s_type
value in the
RingItemHeader of a state change item
that documents the end of a run.
static const uint32_t PAUSE_RUN = 3;
The s_type
value in the
RingItemHeader of a state change item
that documents a pause in a run.
static const uint32_t RESUME_RUN = 4;
The s_type
value in the
RingItemHeader of a state change item
that documents a resume from a paused run.
static const uint32_t ABNORMAL_ENDRUN = 5;
Ring items of this type indcate a run ended abnormally. This should be treated, in most respects, like the end of run marker.
static const uint32_t PACKET_TYPES = 10;
The s_type
value in the
RingItemHeader of a text list ring item
that contains information about the types of
packets that may appear in events.
static const uint32_t MONITORED_VARIABLES = 11;
The s_type
value in the
RingItemHeader of a text list ring item
that contains a set of monitored variable values.
Each string in items of this type will be a
Tcl set command that will recreate the value of
the variable at the time the item was created.
static const uint32_t RING_FORMAT = 12;
The s_type
value in the
RingItemHeader of a
DataFormat ring item. These items
describe the format of the items in the ring in terms
of the first version of NSCLDAQ capable of decoding
them.
static const uint32_t PERIODIC_SCALERS = 20;
The s_type
value in the
RingItemHeader of a
ScalerItem ring item. These items
contain data from periodically read scalers.
static const uint32_t PHYSICS_EVENT = 30;
The s_type
value in the
RingItemHeader of a
PhysicsEventItem ring item.
These items contain physics event data.
static const uint32_t PHYSICS_EVENT_COUNT = 31;
The s_type
value in the
RingItemHeader of a
PhysicsEventCountItem ring item.
these items contain information about the number
of triggers that have been accepted thus far into
the run.
static const uint32_t EVB_FRAGMENT = 40;
The s_type
value in the
RingItemHeader of a
EventBuilderFragment ring item.
These are used to encapsulate event fragments
that have been ordered by the time ordering phase
of the event builder pipeline. Note that
These are typically only visible in the
order monitoring ring.
Items of this type are believed to have payloads that look like ring items.
static const uint32_t EVB_UNKNOWN_PAYLOAD = 41;
The s_type
value in the
RingItemHeader of a
EventBuilderFragment whose payload
looks like it probably is not a ring item.
Note that form of the payload of
an event builder fragment
can only be guessed at not known with certainty.
static const uint32_t EVB_GLOM_INFO = 42;
The s_type
value in the
RingItemHeader of a
GlomParameters ring item. This type
of ring item is used by the glomming
phase of the event builder to describe the
parameters being used to build events.
static const uint32_t FIRST_USER_ITEM_CODE = 32768;
There is nothing sacred about the specifific set of
ring items defined by DataFormat.h
users can define application specific ring items.
In order to do so without present and future
collisions in ring item types with standardf
values, users should allocate ring item types from
types that are no less than
FIRST_USER_ITEM_CODE
.
static const uint16_t GLOM_TIMESTAMP_FIRST = 0;
A possible value for the timestamp policy of the glom format ring item. This value means the output event timestamps are filled in from the fragment with the smallest timestamp value.
static const uint16_t GLOM_TIMESTAMP_LAST = 0;
A possible value for the timestamp policy of the glom format ring item. This value means the output event timestamps are filled in from the fragment with the largest timestamp value.
static const uint16_t GLOM_TIMESTAMP_AVERAGE = 0;
A possible value for the timestamp policy of the glom format ring item. This value means the output event timestamps are filled in from the average of all timestamps in fragments in the event.
Defines the maximum number of characters in a Run State change item's title field.