12-Apr-2016, KAB, JCF
artdaq BoardReaders are the processes that are responsible for configuring detector electronics and reading out data fragments. The following diagram shows the process types and some of the DAQ functions that are provided in artdaq. The boxes that are shown in green are part of what is provided by artdaq. The boxes shown in orange correspond to plugins that each experiment develops for their particular needs.
In the case of the BoardReader, individual experiments develop one or more "FragmentGenerator" plugins that communicate with electronics hardware. The BoardReader code takes care of communicating with Run Control, sending the data to the EventBuilders, etc. And, it calls the appropriate methods in its FragmentGenerator based on the commands that it receives from Run Control. The number of BoardReaders in a DAQ system is easily re-configurable, and typically there is one BoardReader per electronics module.The task of creating a FragmentGenerator boils down to creating a C++ class that implements a well-defined set of methods. The characteristics of such a class include the following:
- It should inherit from CommandableFragmentGenerator (which defines the expected interface and provides some utility methods)
- Its constructor should accept a fhicl::ParameterSet that contains all of the configuration data that is needed, both for configuring itself and all upstream hardware, firmware, and software. And, the bulk of such configuration should be done in the constructor. FragmentGenerators are constructed when BoardReaders received the "init" (i.e. "initialization" or "configuration" message from Run Control).
- It should implement "start", "stop", and "stopNoMutex" methods. These methods are called when a data taking run begins (start) and when a run is ended (stopNoMutex and stop). The stopNoMutex method can be used to send end-of-run commands to the hardware that are asynchronous with the readout of the data. (The stop command is never sent while the "getNext_" method [described below] is active.)
- It should implement a "getNext_" method that reads out the data and formats the data from each "event" (experiment-specific definition) into an artdaq::Fragment. A couple of notes on the getNext_ method:
- its argument is a vector of artdaq::Fragments that is used to return zero, one, or more fragments of data
- its return code is a boolean that indicates whether data taking has finished or not. In this case, "data taking" means a data taking run, not just an individual event. Generally, a getNext_ method returns "false" when A) an end-run has been requested and B) existing data in the pipeline has been processed.
- it should not block forever (or even for very long). It is quite acceptable to return a zero-length array of artdaq::Fragments and a return code of "true". This means that there is no data available at the moment, and the BoardReader should call "getNext_" again. A non-blocking getNext_ method allows runs to be ended gracefully even when no data is flowing.
- as part of creating the artdaq::Fragments, getNext_ methods need to create and fill a "sequence ID" in the artdaq::Fragment header. This integer uniquely identifies each fragment from a given BoardReader, and it is used to route the fragment to the correct EventBuilder. The getNext_ method also fills a "fragment ID" field in the artdaq::Fragment header, and this integer identifies the source of the fragment (which BoardReader and which physical part of the detector). In a smoothly running system, the BoardReaders generate one, and only one, fragment with a given combination of sequenceID and fragmentID per run. EventBuilders group fragments with the same sequenceID into full events. The determination of sequenceIDs is experiment-dependent, but of course, the different types of FragmentGenerator used by an experiment must use consistent methods for assigning sequenceIDs so that full events can successfully be built.
- There are other operations that FragmentGenerators can implement, but those are optional, and are described elsewhere.