====== The Sweeper Pre-unpacker ====== The purpose of the Sweeper Pre-unpacker is to “translate” the [[Sweeper USB DAQ data format|data format from the Sweeper EVB]] into a more intuitive format reflecting the physical variables measured in a experiment. In simple terms, the Pre-unpacker "receives" a pointer pointing to the fragment payload (fragment body) of the first fragment processed by the Sweeper EVB; reads and parses the data stream; and returns a C++ structure (**SweeperEvent**) which contains the physical (uncalibrated) variables to be analyzed. The beauty of this approach is that the user doesn't have to know the details about the data format from the Sweeper DAQ electronics (CCUSB and VMUSB controllers). Instead, all she/he has to do is reading the variables contained in the Pre-unpacker structure **SweeperEvent** (e.g. time, energy,...), calibrate them, and use them to calculate the physical quantities relevant for the analysis. ===== How the Sweeper Pre-unpacker works ===== In this section, we describe the Sweeper Pre-unpacker in some detail. The casual user can skip this part and go directly to the next section describing how to use the Pre-Unpacker. The complete code described in this section is encoded in the library **libSweeperUnpacker.so** which can be used by the user to unpack data from the Sweeper. In this way, the whole unpacking sequence is a black-box for the user. The Sweeper Pre-unpacker functions are enclosed under the namespace **Sweeper**. The pre-unpacking is done in two steps: (1) data from the Sweeper EVB are parsed and re-organized in the C++ structure **ParsedEVB** containing substructures encoding data from different electronic modules (e.g. Phillips 71xx ADC, Mesytec MTDC-32, etc.); (2) data from the structure **ParsedEVB** are re-organized into detector-related sub-structures contained in the structure **SweeperEvent**. Thus, the back-bone of the Pre-unpacker are the structures **ParsedEVB** and **SweeperEvent**. Note that the later is the only part of the whole Pre-unpacker that is relevant for the user. The functionality of the Pre-unpacker is schematically illustrated in the figure below. {{:wiki:diagram_preunpacker.png?1100|Schematic representation of libSweeperUnpacker}} The whole Pre-unpacker package is coded in three main files: **Sweeper.cpp**; **CSweeperParser.cpp**; and **CSweeperUnpacker.cpp**. The data parsing/unpacking sequence is described below: * The function ''unpack'', establishes the communication between the parsing and unpacking stages described above. This function receives two pointers, //pBegin// and //pEnd//. As illustrated in the [[Sweeper USB DAQ data format|data diagram]], the former points to the fragment body of the first fragment, whereas the later points to the end of fragment. * The function ''unpack'' passes the pointers //pBegin// and //pEnd// to the **CSweeperParser** function ''parse''. This function uses the NSCLDAQ class **FragmentIndex** to iterate through the two fragments from the Sweeper EVB. For each fragment, a pointer //pBody// pointing to the body of the ring item encoded in the fragment is created and sent to the CSweeperParser function ''parseData''. * The function ''parseData'' goes through the body data and searches for tags identifying the data from each module (see [[Sweeper USB DAQ data format|data diagram]]). Whenever a tag is found, ''parseData'' sends the pointer //pBody// to a specific function designed to decode data from a given module. As an example, when ''parseData'' finds the tag **0x0DDC**, it will call the function ''DecodeMTDC'' to parse the data from the Mesytec MTDC module containing time information. Once parsed, the time values from different detectors will be contained in a substructure (mtdc) of the structure **ParsedEVB**. * This sequence will be repeated for each fragment (one from CCUSB and the other from VMUSB). At the end, the structure **ParsedEVB** will contain all the information from the different electronic modules of the Sweeper Magnet. This structure is then sent back to the function ''unpack'' * The function ''unpack'' sends the complete structure **ParsedEVB** to the **CSweeperUnpacker** function ''Unpack''. * This function calls specific functions to pack the data from **ParsedEVB** into the detector substructures contained in the structure **SweeperEvent**. After filling all these substructures, ''Unpack'' gives **SweeperEvent** back to ''unpack'', which then returns this structure to the user. ===== Using the Sweeper Pre-unpacker ===== In order to include the Sweeper Pre-unpacker, the user needs to follow a series of steps (for more details, please contact the Sweeper Device Physicist Jorge Pereira ([[pereira@nscl.msu.edu]]) or DAQ expert Ron Fox ([[fox@nscl.msu.edu]]): * The analysis-software compiler must include the library **libSweeperUnpacker.so** along with some header files. Their current location (June 2017) is ''/user/sweeper/develop/unpacker/library/src'', for **libSweeperUnpacker.so**, and ''/user/sweeper/develop/unpacker/library/inc'' and ''/user/sweeper/develop/unpacker/library/inc/Sweeper'', for the header files. * In order to use the Sweeper ''unpack'' function and the structure **SweeperEvent**, the analysis code must include the header files **Sweeper.h** and **SweeperEvent.h**. * As described above, the user needs to provide two pointers (//pBegin// and //pEnd//) to the function ''unpack''. //pBegin// points to the fragment body of the first fragment, and //pEnd// points to the end of the fragment. The function ''unpack'' will return a **SweeperEvent** structure containing all the unpacked information needed for the analysis. The example below shows how to use the Sweeper Pre-unpacker in SpecTcl. The processor **CSweeperMapper** was created to call the Pre-unpacker function ''Sweeper::unpack''. This function returns the SweeperEvent-type structure **event** which contains all the detector-related substructures needed by the user. #include #include #include #include #include #include Bool_t CSweeperMapper::operator()(const Address_t pEvent, CEvent& rEvent, CAnalyzer& rAnalyzer, CBufferDecoder& rDecoder) { CTclAnalyzer& rAna((CTclAnalyzer&)rAnalyzer); TranslatorPointer p(*(rDecoder.getBufferTranslator()), pEvent); // Here I define the pointers pBegin and pEnd needed by the unpack function UShort_t *pBegin = (UShort_t*)pEvent; //pBegin points to the fragment payload (fragment body) of the first fragment UShort_t tWords = *p++; // Here I take the (self-inclusive) payload size UShort_t *pEnd = pBegin + tWords; // pEnd points to the end of the fragment // At least one member of the pipeline must tell the analyzer how // many bytes were in the raw event so it knows where to find the // next event. rAna.SetEventSize(tWords*sizeof(UShort_t)); // Set event size. // Function Sweeper::unpack is called here. The function returns the SweeperEvent-type structure event Sweeper::SweeperEvent event = Sweeper::unpack(pBegin, pEnd); } In the above example, all the unpacked data are encoded in the structure **event** (type **SweeperEvent**). Thus, all that the user needs to do is to handle the variables (organized in sub-structures) provided in the **event** structure. The list of **SweeperEvent** sub-structures and corresponding variables are described below: ==== Substructure fpic ==== This substructure contains information about the focal-plane ion chamber * **fpic.hasdata** (bool): logic variable which is TRUE when the structure contains valid data * **fpic.raw[0-15]** (uint16_t): energy array (Phillips 7164 ADC module) from each of the 16 detector pads ==== Substructure hodo ===== This substructure contains information about the energy from each crystal in the hodoscope. * **hodo.hasdata** (bool): logic variable which is TRUE when the structure contains valid data * **hodo.raw[0-24]** (uint16_t): energy array (Mesytec MADC-32) from each of the 25 crystals ==== Substructure segta ===== This substructure contains information about the energy from the segmented target. * **segta.hasdata** (bool): logic variable which is TRUE when the structure contains valid data * **segta.data[0-31]** (uint16_t): energy array (Mesytec MADC-32) from each of the channels in the segmented-target ==== Substructure mtdc ===== This structure contains information from the multi-hit Mesytech MTDC-32. This module was included in 2015 to replace the old Phillips TDC. * **mtdc.hasdata** (bool): logic variable which is TRUE when the structure contains valid data * **hits[0-31]** (uint16_t): array with number of "hits" for each channel * **raw[0-31]** (uint16_t): array with time of first hit of each channel * **data[0-31][maximum number-of-hits=31]** (uint16_t): array with times for each hit and channel In the current configuration (May 2017) the channel assignment is given by: ^ Channel ^ Source | | 0 | FP Thin SCI Left, Up (Sweeper trigger) | | 1 | FP Thin SCI Left, Down | | 2 | FP Thin SCI Right, Up | | 3 | FP Thin SCI Right, Down | | 4 | Free | | 5 | RF | | 6 | Pot SCI | | 7 | XF SCI | | 8 | FP Thin SCI Left, Up (Sweeper trigger) | | 9-10 | Free | | 11 | Time stamp from L3 module | | 12-14 | Free | | 15 | FP Thin SCI Left, Up (Sweeper trigger) | | 16-31 | Free | ==== Substructure crdc1 and crdc2 ===== * **crdc1(2).hasdata** (bool): logic variable which is TRUE when the structure for crdc1 (or 2) contains valid data * **crdc1(2).anode** (uint16_t): energy (Phillips 7164 ADC) from the detector anode * **crdc1(2).tac** (uint16_t): time (Ortec 456 TAC + Phillips 7164 ADC) from the detector anode * **crdc1(2).m_sampleBegin** (uint16_t): First sample number from last read pad * **crdc1(2).m_sampleWidth** (uint16_t): Sample width from last read pad * **crdc1(2).m_data[number-of-pads=112][number-of-samples]** (uint16_t): energy array for each pad and sample number ==== Substructure fpsci ===== This substructure contains energy and time information about the scintillators included in the Sweeper setup: Pot, XF, FP Thin, and FP Thick. Note that since the Phillips TDC was removed from the sweeper electronics (and replaced by the MTDC), the time information in this substructure is no longer available. * **fpsci.hasdatathin** (bool): logic variable which is TRUE when the structure contains valid data for the Thin scintillator * **fpsci.thin_de_lu** (uint16_t): energy (FERA module) from the FP thin left-up PMT * **fpsci.thin_de_ld** (uint16_t): energy (FERA module) from the FP thin left-down PMT * **fpsci.thin_de_ru** (uint16_t): energy (FERA module) from the FP thin right-up PMT * **fpsci.thin_de_rd** (uint16_t): energy (FERA module) from the FP thin right-down PMT * **fpsci.thin_t_lu** (uint16_t): time (Phillips TDC module) from the FP thin left-up PMT * **fpsci.thin_t_ld** (uint16_t): time (Phillips TDC module) from the FP thin left-down PMT * **fpsci.thin_t_ru** (uint16_t): time (Phillips TDC module) from the FP thin right-up PMT * **fpsci.thin_t_rd** (uint16_t): time (Phillips TDC module) from the FP thin right-down PMT * **fpsci.hasdatathick** (bool): logic variable which is TRUE when the structure contains valid data for the Thick scintillator. Note that this detector is currently not included * **fpsci.thick_de_lu** (uint16_t): energy (FERA module) from the FP thick left-up PMT * **fpsci.thick_de_ld** (uint16_t): energy (FERA module) from the FP thick left-down PMT * **fpsci.thick_de_ru** (uint16_t): energy (FERA module) from the FP thick right-up PMT * **fpsci.thick_de_rd** (uint16_t): energy (FERA module) from the FP thick right-down PMT * **fpsci.thick_t_lu** (uint16_t): time (Phillips TDC module) from the FP thick left-up PMT * **fpsci.thick_t_ld** (uint16_t): time (Phillips TDC module) from the FP thick left-down PMT * **fpsci.thick_t_ru** (uint16_t): time (Phillips TDC module) from the FP thick right-up PMT * **fpsci.thick_t_rd** (uint16_t): time (Phillips TDC module) from the FP thick right-down PMT * **fpsci.pote** (uint16_t): energy (FERA module) from the Pot scintillator ==== Substructure trigger (obsolete) ==== We could consider that this is an obsolete structure containing the bit pattern from the ULM module, and times for each trigger signal. Note that in general, these times are not included in the electronics, since the only trigger signal relevant for the Sweeper Magnet is "ext 2". The variables included in this structure are: * **trigger.hasdata** (bool): logic variable which is TRUE when the structure contains valid data * **trigger.registr** (uint16_t): a 16-bit work with the bit pattern from the ULM * **trigger.sweeper** (uint16_t): the time (from the Phillips TDC) for the trigger source from sweeper (not connected) * **trigger.external1** (uint16_t): the time (the Phillips TDC) from the trigger source from external 1 (not connected) * **trigger.external2** (uint16_t): the time (the Phillips TDC) from the trigger source from external 2 (from L3 trigger) * **trigger.secondary** (uint16_t): the time (the Phillips TDC) from the trigger source from secondary (not connected) ==== Substructure tof (obsolete) ===== This is an obsolete substructure containing time information from the Phillips TDC (currently discontinued) * **tof.hasdata** (bool): logic variable which is TRUE when the structure contains valid data * **tof.xfp** (uint16_t): time (Phillips TDC) from A1900 XF scintillator * **tof.rf** (uint16_t): time (Phillips TDC)from RF signal * **tof.pot** (uint16_t): time (Phillips TDC) from Pot scintillator