LCOV - code coverage report
Current view: top level - mu2e-pcie-utils/dtcInterfaceLib - DTC.h (source / functions) Coverage Total Hit
Test: mu2edaq.info.cleaned Lines: 0.0 % 28 0
Test Date: 2026-10-29 01:38:59 Functions: 0.0 % 11 0

            Line data    Source code
       1              : #ifndef DTC_H
       2              : #define DTC_H
       3              : 
       4              : #include <array>
       5              : #include <chrono>
       6              : #include <list>
       7              : #include <map>
       8              : #include <memory>
       9              : #include <vector>
      10              : 
      11              : // #include "artdaq-core-mu2e/Overlays/DTC_Packets.h"
      12              : #include "artdaq-core-mu2e/Overlays/DTC_Packets/DTC_DCSReplyPacket.h"
      13              : #include "artdaq-core-mu2e/Overlays/DTC_Packets/DTC_DCSRequestPacket.h"
      14              : #include "artdaq-core-mu2e/Overlays/DTC_Packets/DTC_DMAPacket.h"
      15              : #include "artdaq-core-mu2e/Overlays/DTC_Packets/DTC_DataBlock.h"
      16              : #include "artdaq-core-mu2e/Overlays/DTC_Packets/DTC_DataHeaderPacket.h"
      17              : #include "artdaq-core-mu2e/Overlays/DTC_Packets/DTC_DataPacket.h"
      18              : #include "artdaq-core-mu2e/Overlays/DTC_Packets/DTC_DataRequestPacket.h"
      19              : #include "artdaq-core-mu2e/Overlays/DTC_Packets/DTC_DataStatus.h"
      20              : #include "artdaq-core-mu2e/Overlays/DTC_Packets/DTC_Event.h"
      21              : #include "artdaq-core-mu2e/Overlays/DTC_Packets/DTC_EventHeader.h"
      22              : #include "artdaq-core-mu2e/Overlays/DTC_Packets/DTC_HeartbeatPacket.h"
      23              : #include "artdaq-core-mu2e/Overlays/DTC_Packets/DTC_PacketType.h"
      24              : #include "artdaq-core-mu2e/Overlays/DTC_Packets/DTC_SubEvent.h"
      25              : #include "artdaq-core-mu2e/Overlays/DTC_Packets/DTC_SubEventHeader.h"
      26              : 
      27              : #include "CFOandDTC_DMAs.h"
      28              : #include "DTC_Registers.h"
      29              : 
      30              : // #include "artdaq-core-mu2e/Overlays/DTC_Types.h"
      31              : #include "artdaq-core-mu2e/Overlays/DTC_Types/DTC_CharacterNotInTableError.h"
      32              : #include "artdaq-core-mu2e/Overlays/DTC_Types/DTC_DCSOperationType.h"
      33              : #include "artdaq-core-mu2e/Overlays/DTC_Types/DTC_DDRFlags.h"
      34              : #include "artdaq-core-mu2e/Overlays/DTC_Types/DTC_DebugType.h"
      35              : #include "artdaq-core-mu2e/Overlays/DTC_Types/DTC_EVBStatsType.h"
      36              : #include "artdaq-core-mu2e/Overlays/DTC_Types/DTC_EVBStatus.h"
      37              : #include "artdaq-core-mu2e/Overlays/DTC_Types/DTC_EventMode.h"
      38              : #include "artdaq-core-mu2e/Overlays/DTC_Types/DTC_EventWindowTag.h"
      39              : #include "artdaq-core-mu2e/Overlays/DTC_Types/DTC_FIFOFullErrorFlags.h"
      40              : #include "artdaq-core-mu2e/Overlays/DTC_Types/DTC_IICDDRBusAddress.h"
      41              : #include "artdaq-core-mu2e/Overlays/DTC_Types/DTC_IICSERDESBusAddress.h"
      42              : #include "artdaq-core-mu2e/Overlays/DTC_Types/DTC_LinkEnableMode.h"
      43              : #include "artdaq-core-mu2e/Overlays/DTC_Types/DTC_LinkStatus.h"
      44              : #include "artdaq-core-mu2e/Overlays/DTC_Types/DTC_Link_ID.h"
      45              : #include "artdaq-core-mu2e/Overlays/DTC_Types/DTC_OscillatorType.h"
      46              : #include "artdaq-core-mu2e/Overlays/DTC_Types/DTC_PLL_ID.h"
      47              : #include "artdaq-core-mu2e/Overlays/DTC_Types/DTC_PRBSMode.h"
      48              : #include "artdaq-core-mu2e/Overlays/DTC_Types/DTC_ROC_Emulation_Type.h"
      49              : #include "artdaq-core-mu2e/Overlays/DTC_Types/DTC_RXBufferStatus.h"
      50              : #include "artdaq-core-mu2e/Overlays/DTC_Types/DTC_RXStatus.h"
      51              : #include "artdaq-core-mu2e/Overlays/DTC_Types/DTC_SERDESLoopbackMode.h"
      52              : #include "artdaq-core-mu2e/Overlays/DTC_Types/DTC_SERDESRXDisparityError.h"
      53              : #include "artdaq-core-mu2e/Overlays/DTC_Types/DTC_SerdesClockSpeed.h"
      54              : #include "artdaq-core-mu2e/Overlays/DTC_Types/DTC_SimMode.h"
      55              : #include "artdaq-core-mu2e/Overlays/DTC_Types/DTC_Subsystem.h"
      56              : #include "artdaq-core-mu2e/Overlays/DTC_Types/Exceptions.h"
      57              : #include "artdaq-core-mu2e/Overlays/DTC_Types/Utilities.h"
      58              : 
      59              : namespace DTCLib
      60              : {
      61              : 
      62              : typedef uint16_t roc_data_t;
      63              : typedef uint16_t roc_address_t;
      64              : 
      65              : /// <summary>
      66              : /// The DTC class implements the data transfers to the DTC card. It derives from DTC_Registers, the class representing
      67              : /// the DTC register space.
      68              : /// </summary>
      69              : class DTC : public DTC_Registers
      70              : {
      71              :   public:
      72              :         /// <summary>
      73              :         /// Construct an instance of the DTC class
      74              :         /// </summary>
      75              :         /// <param name="mode">The desired simulation mode for the DTC (Default: Disabled)</param>
      76              :         /// <param name="dtc">The DTC card to use (default: -1: Use environment variable or 0 if env. var. unset)</param>
      77              :         /// <param name="rocMask">Which ROCs should be active. Each hex digit corresponds to a Link, and the number indicates
      78              :         /// how many ROCs are active on that link. (Default: 0x1)</param> <param name="expectedDesignVersion">Expected DTC
      79              :         /// Firmware Design Version. If set, will throw an exception if the DTC firmware does not match (Default: "")</param>
      80              :         /// <param name="skipInit">Whether to skip full initialization of the DTC</param>
      81              :         /// <param name="simMemoryFile">Name of the simulated DDR memory file if mu2esim is used</param>
      82              :         explicit DTC(DTC_SimMode mode = DTC_SimMode_Disabled, int dtc = -1, unsigned rocMask = 0x1, std::string expectedDesignVersion = "", bool skipInit = false, std::string simMemoryFile = "mu2esim.bin", const std::string& uid = "");
      83              :         virtual ~DTC();
      84              : 
      85              :         //
      86              :         // DMA Functions
      87              :         //
      88              :         // Data read-out
      89              :         /// <summary>
      90              :         /// Reads data from the DTC, and returns all data blocks with the same event window tag. If event window tag is specified, will look
      91              :         /// for data with that event window tag.
      92              :         /// </summary>
      93              :         /// <param name="when">Desired event window tag for readout. Default means use whatever event window tag is next</param>
      94              :         /// <returns>A vector of DTC_Event objects, but only one DTC_Event is expected</returns>
      95              :         std::vector<std::unique_ptr<DTC_Event>> GetData(DTC_EventWindowTag when = DTC_EventWindowTag(), bool matchEventWindowTag = false);
      96              : 
      97              :         /// <summary>
      98              :         /// Reads data from the DTC, and returns the first Sub Event found. If event window tag is specified, will look
      99              :         /// to match the found Sub Event with the specified event window tag.
     100              :         /// </summary>
     101              :         /// <param name="when">Desired event window tag for readout. Default means use whatever event window tag is next</param>
     102              :         /// <returns>A vector of DTC_SubEvent objects, but only one DTC_SubEvent is expected</returns>
     103              :         std::vector<std::unique_ptr<DTC_SubEvent>> GetSubEventData(DTC_EventWindowTag when = DTC_EventWindowTag(), bool matchEventWindowTag = false);
     104              :         std::vector<std::shared_ptr<DTC_Event>>    GetSubEventDataAsEvents(DTC_EventWindowTag when = DTC_EventWindowTag(), bool matchEventWindowTag = false, const size_t vectorBundleTarget = 1, const size_t retries = 3);
     105              : 
     106              :         std::vector<std::shared_ptr<DTC_Event>> GetEVBDataAsEvents(DTC_EventWindowTag when = DTC_EventWindowTag(), bool matchEventWindowTag = false, const size_t retries = 3);
     107            0 :         uint64_t                                GetEVBChunksParsed() const { return evbChunksParsed_; }                  ///< cumulative FAFA chunks parsed by GetEVBDataAsEvents
     108            0 :         uint64_t                                GetEVBFramingErrors() const { return evbFramingErrors_; }                ///< cumulative FAFA framing / record errors in GetEVBDataAsEvents
     109            0 :         uint64_t                                GetEVBSplitSubeventsJoined() const { return evbSplitSubeventsJoined_; }  ///< subevents reassembled from more than one record (> ~64 KB)
     110              :         /// FAFA chunk word-count histogram, remote sources only (chunk_src != local MAC): index = words, 0..8191
     111              :         const std::vector<uint64_t>& GetEVBRemoteChunkSizeHistogram() const { return evbRemoteChunkSizeHistogram_; }
     112              :         std::string                  FormatEVBRemoteChunkSizes() const;  ///< count, median, mean, share under 64 words, top sizes
     113              :         // EVB event assembly (see otsdaq-mu2e/docs/EVB3_software_DMA_parsing.md section 4)
     114              :         /// Drain-only: GetEVBDataAsEvents walks the FAFA chunks (counting bytes and chunk sizes) but skips
     115              :         /// reassembly, subevent validation and event completion, and returns no events.  Measures how much
     116              :         /// of the EVB-mode throughput limit is the software assembly path.
     117            0 :         void     SetEVBDrainOnly(bool drainOnly) { evbDrainOnly_ = drainOnly; }
     118              :         bool     GetEVBDrainOnly() const { return evbDrainOnly_; }
     119            0 :         uint64_t GetEVBDrainedBytes() const { return evbDrainedBytes_; }  ///< chunk payload bytes seen (both modes)
     120            0 :         uint64_t GetEVBDMABuffersRead() const { return evbDMABuffersRead_; }
     121              :         /// Step profile of GetEVBDataAsEvents: wall time (steady_clock ns) accumulated per step over all
     122              :         /// calls since ResetEVBAssembly, plus call/record counts.  Always on; one clock read per step
     123              :         /// boundary (about 25 ns each, ~0.1 us per call), negligible against the ~60 us a DMA buffer takes.
     124              :         struct EVBReadProfile
     125              :         {
     126              :                 uint64_t calls{0};             ///< GetEVBDataAsEvents calls
     127              :                 uint64_t callsWithData{0};     ///< calls where read_data returned a buffer
     128              :                 uint64_t recordsExtracted{0};  ///< subevent records validated and staged (Step 4)
     129              :                 uint64_t timeoutScanNs{0};     ///< Step 0: open-tag timeout / overflow scan
     130              :                 uint64_t readDataNs{0};        ///< Step 1: device read_data (includes waiting up to 1 ms when idle)
     131              :                 uint64_t chunkWalkNs{0};       ///< Step 3: FAFA chunk walk incl. copy into per-source reassembly
     132              :                 uint64_t registerReadNs{0};    ///< Step 2b: dest-node count and local MAC reads, once per run
     133              :                 uint64_t recordScanNs{0};      ///< Step 4b: record framing, split join, header consistency, pre-parse checks
     134              :                 uint64_t subeventSetupNs{0};   ///< Step 4c: per-record DTC_Event alloc + memcpy + SetupEvent + IsCorrupt
     135              :                 uint64_t stagingNs{0};         ///< Step 4d: last-good copy, per-tag staging copy, reassembly erase
     136              :                 uint64_t eventReleaseNs{0};    ///< Step 5: assemble N-subevent event, SetupEvent, release
     137              :                 uint64_t releaseBufferNs{0};   ///< read_release of the DMA buffer (RAII on return)
     138              :                 uint64_t totalNs{0};           ///< whole call, entry to return
     139              :         };
     140              :         const EVBReadProfile&     GetEVBReadProfile() const { return evbReadProfile_; }
     141              :         std::string               FormatEVBReadProfile() const;                                              ///< one line per step: ms, share of call time, per-call / per-record cost
     142              :         void                      SetEVBEventTimeout(std::chrono::milliseconds t) { evbEventTimeout_ = t; }  ///< max age of an incomplete event, first subevent arrival to now, before GetEVBDataAsEvents throws (default 2000 ms)
     143            0 :         std::chrono::milliseconds GetEVBEventTimeout() const { return evbEventTimeout_; }
     144            0 :         size_t                    GetEVBOpenTagCount() const { return evbPendingTags_.size(); }  ///< tags holding at least one but not yet all N subevents
     145            0 :         uint64_t                  GetEVBEventsReleased() const { return evbEventsReleased_; }    ///< complete N-subevent events returned so far
     146            0 :         uint8_t                   GetEVBNumSources() const { return evbNumSources_; }            ///< N used for completion (EVB destination-node count)
     147              :         /// Reset all EVB assembly state and counters.  Call at run start.
     148            0 :         void ResetEVBAssembly()
     149              :         {
     150            0 :                 evbPerSourceReassembly_.clear();
     151            0 :                 evbLastGoodRecord_.clear();
     152            0 :                 evbPendingTags_.clear();
     153            0 :                 evbHaveReleasedTag_      = false;
     154            0 :                 evbLastReleasedTag_      = 0;
     155            0 :                 evbEventsReleased_       = 0;
     156            0 :                 evbChunksParsed_         = 0;
     157            0 :                 evbFramingErrors_        = 0;
     158            0 :                 evbSplitSubeventsJoined_ = 0;
     159            0 :                 evbRemoteChunkSizeHistogram_.assign(8192, 0);
     160            0 :                 evbDrainedBytes_   = 0;
     161            0 :                 evbDMABuffersRead_ = 0;
     162            0 :                 evbReadProfile_    = EVBReadProfile{};
     163            0 :                 evbSourcesKnown_   = false;
     164            0 :         }
     165              : 
     166              :         /// <summary>
     167              :         /// Read a file into the DTC memory. Will truncate the file so that it fits in the DTC memory.
     168              :         /// </summary>
     169              :         /// <param name="file">File name to read into DTC memory</param>
     170              :         /// <param name="goForever">Whether readout should loop through the file</param>
     171              :         /// <param name="overwriteEnvrionment">Whether to use file instead of DTCLIB_SIM_FILE</param>
     172              :         /// <param name="outputFileName">Name of binary file to write expected output (Default: "", no file created)</param>
     173              :         /// <param name="skipVerify">Skip the verify stage of WriteSimFileToDTC</param>
     174              :         void WriteSimFileToDTC(std::string file, bool goForever, bool overwriteEnvrionment = false, std::string outputFileName = "", bool skipVerify = false);
     175              :         /// <summary>
     176              :         /// Read the DTC memory and determine whether the file was written correctly.
     177              :         /// </summary>
     178              :         /// <param name="file">File to verify against</param>
     179              :         /// <param name="rawOutputFilename">Default: "". If set, file to write data retrieved from the DTC to</param>
     180              :         /// <returns>True if file is in DTC memory without errors</returns>
     181              :         bool VerifySimFileInDTC(std::string file, std::string rawOutputFilename = "");
     182              : 
     183              :         // DCS Register R/W
     184              :         /// <summary>
     185              :         /// Sends a DCS Request Packet with fields filled in such that the given ROC register will be read out.
     186              :         /// This function reads from the main ROC register space, use ReadExtROCRegister to access other firmware blocks'
     187              :         /// register spaces.
     188              :         /// </summary>
     189              :         /// <param name="link">Link of the ROC to read</param>
     190              :         /// <param name="address">Address of the register</param>
     191              :         /// <param name="tmo_ms">Timeout, in milliseconds, for read (will retry until timeout is expired or data received)</param>
     192              :         /// <returns>Value of the ROC register from a DCS Reply packet</returns>
     193              :         roc_data_t ReadROCRegister(const DTC_Link_ID& link, const roc_address_t address, int tmo_ms);
     194              :         /// <summary>
     195              :         /// Sends a DCS Request Packet with the fields filled in such that the given ROC register will be written.
     196              :         /// This function writes to the main ROC register space, use WriteExtROCRegister to access other firmware blocks'
     197              :         /// register spaces.
     198              :         /// </summary>
     199              :         /// <param name="link">Link of the ROC to write to</param>
     200              :         /// <param name="address">Address of the register</param>
     201              :         /// <param name="data">Value to write</param>
     202              :         /// <param name="requestAck">Whether to request acknowledement of this operation</param>
     203              :         /// <param name="ack_tmo_ms">Timeout, in milliseconds, for ack (will retry until timeout is expired or ack received)</param>
     204              :         bool WriteROCRegister(const DTC_Link_ID& link, const roc_address_t address, const roc_data_t data, bool requestAck, int ack_tmo_ms);
     205              : 
     206              :         /// <summary>
     207              :         /// Perform a "double operation" read of ROC registers
     208              :         /// </summary>
     209              :         /// <param name="link">Link of the ROC to read</param>
     210              :         /// <param name="address1">First address to read</param>
     211              :         /// <param name="address2">Second address to read</param>
     212              :         /// <param name="tmo_ms">Timeout, in milliseconds, for read (will retry until timeout is expired or data received)</param>
     213              :         /// <returns>Pair of register values, first is from the first address, second from the second</returns>
     214              :         std::pair<roc_data_t, roc_data_t> ReadROCRegisters(const DTC_Link_ID& link, const roc_address_t address1, const roc_address_t address2, int tmo_ms);
     215              :         /// <summary>
     216              :         /// Perform a "double operation" write to ROC registers
     217              :         /// </summary>
     218              :         /// <param name="link">Link of the ROC to write to</param>
     219              :         /// <param name="address1">First address to write</param>
     220              :         /// <param name="data1">Value to write to first register</param>
     221              :         /// <param name="address2">Second address to write</param>
     222              :         /// <param name="data2">Value to write to second register</param>
     223              :         /// <param name="requestAck">Whether to request acknowledement of this operation</param>
     224              :         /// <param name="ack_tmo_ms">Timeout, in milliseconds, for ack (will retry until timeout is expired or ack received)</param>
     225              :         bool WriteROCRegisters(const DTC_Link_ID& link, const roc_address_t address1, const roc_data_t data1, const roc_address_t address2, const roc_data_t data2, bool requestAck, int ack_tmo_ms);
     226              :         /// <summary>
     227              :         /// Perform a ROC block read
     228              :         /// </summary>
     229              :         /// <param name="data">vector of data by reference to read</param>
     230              :         /// <param name="link">Link of the ROC to read</param>
     231              :         /// <param name="address">Address of the block</param>
     232              :         /// <param name="wordCount">Number of words to read</param>
     233              :         /// <returns>Vector of words returned by block read</returns>
     234              :         /// <param name="incrementAddress">Whether to increment the address pointer for block reads/writes</param>
     235              :         /// <param name="tmo_ms">Timeout, in milliseconds, for read (will retry until timeout is expired or data received)</param>
     236              :         void ReadROCBlock(std::vector<roc_data_t>& data, const DTC_Link_ID& link, const roc_address_t address, const uint16_t wordCount, bool incrementAddress, int tmo_ms);
     237              :         /// <summary>
     238              :         /// Perform a ROC block write
     239              :         /// </summary>
     240              :         /// <param name="link">Link of the ROC to write</param>
     241              :         /// <param name="address">Address of the block</param>
     242              :         /// <param name="blockData">Vector of words to write</param>
     243              :         /// <param name="requestAck">Whether to request acknowledement of this operation</param>
     244              :         /// <param name="incrementAddress">Whether to increment the address pointer for block reads/writes</param>
     245              :         /// <param name="ack_tmo_ms">Timeout, in milliseconds, for ack (will retry until timeout is expired or ack received)</param>
     246              :         bool WriteROCBlock(const DTC_Link_ID& link, const roc_address_t address, const std::vector<roc_data_t>& blockData, bool requestAck, bool incrementAddress, int ack_tmo_ms);
     247              : 
     248              :         /// <summary>
     249              :         /// Sends a DCS Request Packet with fields filled in such that the given ROC firmware block register will be read out.
     250              :         /// This funcion reads from firmware blocks' register spaces.
     251              :         /// </summary>
     252              :         /// <param name="link">Link of the ROC to read</param>
     253              :         /// <param name="block">Block ID to read from</param>
     254              :         /// <param name="address">Address of the register</param>
     255              :         /// <param name="tmo_ms">Timeout, in milliseconds, for read (will retry until timeout is expired or data received)</param>
     256              :         /// <returns>Value of the ROC register from a DCS Reply packet</returns>
     257              :         uint16_t ReadExtROCRegister(const DTC_Link_ID& link, const roc_address_t block, const roc_address_t address, int tmo_ms = 0);
     258              :         /// <summary>
     259              :         /// Sends a DCS Request Packet with fields filled in such that the given ROC firmware block register will be written.
     260              :         /// This funcion writes to firmware blocks' register spaces.
     261              :         /// </summary>
     262              :         /// <param name="link">Link of the ROC to write to</param>
     263              :         /// <param name="block">Block ID to write to</param>
     264              :         /// <param name="address">Address of the register</param>
     265              :         /// <param name="data">Value to write</param>
     266              :         /// <param name="requestAck">Whether to request acknowledement of this operation</param>
     267              :         /// <param name="ack_tmo_ms">Timeout, in milliseconds, for ack (will retry until timeout is expired or ack received)</param>
     268              :         bool WriteExtROCRegister(const DTC_Link_ID& link, const roc_address_t block, const roc_address_t address, const roc_data_t data, bool requestAck, int ack_tmo_ms);
     269              :         /// <summary>
     270              :         /// Dump all known registers from the given ROC, via DCS Request packets.
     271              :         /// </summary>
     272              :         /// <param name="link">Link of the ROC</param>
     273              :         /// <returns>JSON-formatted register dump</returns>
     274              :         std::string ROCRegDump(const DTC_Link_ID& link);
     275              : 
     276              :         // Broadcast Readout
     277              :         /// <summary>
     278              :         /// DEPRECATED
     279              :         /// Sends a Readout Request broadcast to given Link.
     280              :         /// </summary>
     281              :         /// <param name="link">Link to send to</param>
     282              :         /// <param name="when">Timestamp for the Readout Request</param>
     283              :         /// <param name="quiet">Whether to not print the JSON representation of the Readout Request (Default: true, no JSON
     284              :         /// printed)</param>
     285              :         void SendHeartbeatPacket(const DTC_Link_ID& link, const DTC_EventWindowTag& when, bool quiet = true);
     286              :         /// <summary>
     287              :         /// Send a DCS Request Packet to the given ROC. Use the Read/Write ROC Register functions for more convinient register
     288              :         /// access.
     289              :         /// </summary>
     290              :         /// <param name="link">Link of the ROC</param>
     291              :         /// <param name="type">Operation to perform</param>
     292              :         /// <param name="address">Target address</param>
     293              :         /// <param name="data">Data to write, if operation is write</param>
     294              :         /// <param name="address2">Second Target address</param>
     295              :         /// <param name="data2">Data to write to second address, if operation is write</param>
     296              :         /// <param name="quiet">Whether to not print the JSON representation of the Readout Request (Default: true, no JSON
     297              :         /// printed)</param>
     298              :         /// <param name="requestAck">Whether to request acknowledement of this operation</param>
     299              :         void SendDCSRequestPacket(const DTC_Link_ID& link, const DTC_DCSOperationType type, const roc_address_t address, const roc_data_t data = 0x0, const roc_address_t address2 = 0x0, const roc_data_t data2 = 0, bool quiet = true, bool requestAck = false);
     300              : 
     301              :         /// <summary>
     302              :         /// Writes a packet to the DTC on the DCS channel
     303              :         /// </summary>
     304              :         /// <param name="packet">Packet to write</param>
     305              :         void WriteDMAPacket(const DTC_DMAPacket& packet);
     306              :         /// <summary>
     307              :         /// Writes the given data buffer to the DTC's DDR memory, via the DAQ channel.
     308              :         /// </summary>
     309              :         /// <param name="buf">DMA buffer to write. Must have an inclusive 64-bit byte count at the beginning, followed by an
     310              :         /// exclusive 64-bit block count.</param> <param name="sz">Size ofthe data in the buffer</param>
     311              :         void WriteDetectorEmulatorData(mu2e_databuff_t* buf, size_t sz);
     312              :         /**
     313              :          * @brief Read the next DMA from the DAQ channel. If no data is present, will return nullptr
     314              :          * @param tmo_ms Timeout
     315              :          * @return A DTC_Event representing the data in a single DMA, or nullptr if no data/timeout
     316              :          */
     317              :         std::unique_ptr<DTC_Event> ReadNextDAQDMA(int tmo_ms);
     318              :         /**
     319              :          * @brief Read SubEvents from the next DMA buffer(s) from the DAQ channel. Multiple subevents may be returned
     320              :          * from a single buffer. If a subevent spans multiple DMA buffers, this function blocks until complete.
     321              :          * @param output Vector to append extracted SubEvents to
     322              :          * @param tmo_ms Timeout
     323              :          * @return True if one or more SubEvents were extracted, false if no data/timeout
     324              :          */
     325              :         bool ReadNextDAQSubEventDMA(std::vector<std::unique_ptr<DTC_SubEvent>>& output, int tmo_ms);
     326              :         /// <summary>
     327              :         /// DCS packets are read one-at-a-time, this function reads the next one from the DTC
     328              :         /// </summary>
     329              :         /// <param name="tmo_ms">Timeout, in milliseconds, for read (will retry until timeout is expired or data received)</param>
     330              :         /// <returns>Pointer to read DCSReplyPacket. Will be nullptr if no data available.</returns>
     331              :         std::unique_ptr<DTC_DCSReplyPacket> ReadNextDCSPacket(int tmo_ms);
     332              : 
     333              :         /// <summary>
     334              :         //      ------------
     335              :         /// As of May 2024 RAR, force user to decide which type of buffers this process owns
     336              :         //              DCS buffers is generally safer for multiple processes to access because of the lockout
     337              :         //              DAQ/DATA buffers should only be released by the 'owner' of the DMA channel.
     338              :         // -------------
     339              :         //              Releases all buffers to the hardware, from both the DAQ and DCS channels
     340              :         /// </summary>
     341              :         // void ReleaseAllBuffers()
     342              :         // {
     343              :         //      ReleaseAllBuffers(DTC_DMA_Engine_DAQ);
     344              :         //      ReleaseAllBuffers(DTC_DMA_Engine_DCS);
     345              :         // }
     346              : 
     347              :         /// <summary>
     348              :         /// Release all buffers to the hardware on the given channel
     349              :         /// </summary>
     350              :         /// <param name="channel">Channel to release</param>
     351              :         void ReleaseAllBuffers(const DTC_DMA_Engine& channel);
     352              : 
     353              :   private:
     354              :         std::unique_ptr<DTC_DataPacket> ReadNextPacket(const DTC_DMA_Engine& channel, int tmo_ms);
     355              :         int                             ReadBuffer(const DTC_DMA_Engine& channel, int retries = 10);
     356              :         /// <summary>
     357              :         /// This function releases all buffers except for the one containing currentReadPtr. Should only be called when done
     358              :         /// with data in other buffers!
     359              :         /// </summary>
     360              :         /// <param name="channel">Channel to release</param>
     361              :         void ReleaseBuffers(const DTC_DMA_Engine& channel);
     362              :         void WriteDataPacket(const DTC_DataPacket& packet);
     363              : 
     364              :         // struct DMAInfo
     365              :         // {
     366              :         //      std::deque<mu2e_databuff_t*> buffer;
     367              :         //      uint32_t bufferIndex;
     368              :         //      void* currentReadPtr;
     369              :         //      void* lastReadPtr;
     370              :         //      DMAInfo()
     371              :         //              : buffer(), bufferIndex(0), currentReadPtr(nullptr), lastReadPtr(nullptr) {}
     372              :         //      ~DMAInfo()
     373              :         //      {
     374              :         //              buffer.clear();
     375              :         //              currentReadPtr = nullptr;
     376              :         //              lastReadPtr = nullptr;
     377              :         //      }
     378              :         // };
     379              :         // int GetCurrentBuffer(DMAInfo* info);
     380              :         // uint16_t GetBufferByteCount(DMAInfo* info, size_t index);
     381              :         CFOandDTC_DMAs::DMAInfo daqDMAInfo_;
     382              :         CFOandDTC_DMAs::DMAInfo dcsDMAInfo_;
     383              : 
     384              :         // State for GetSubEventDataAsEvents v3: extracted events buffer
     385              :         std::vector<std::shared_ptr<DTCLib::DTC_Event>> extractedEvents_{};
     386              : 
     387              :         bool   needToFinishEvent_{false};
     388              :         size_t currentEventSize_{0};
     389              :         size_t subEventByteCount_{0};
     390              :         size_t extractedSubeventBytes_{0};
     391              : 
     392              :         DTC_SubEventHeader lastGoodSubEventHeader_{};
     393              :         bool               hasLastGoodSubEventHeader_{false};
     394              :         uint64_t           totalEventsParsed_{0};  ///< Lifetime count of successfully-parsed subevents; included in diagnostic prints so we can tell whether parsing ever made progress
     395              : 
     396              :         // Standing buffer to assemble the on-wire header prefix one QW at a time.
     397              :         // On-wire layout: [EventHeader 1 QW][SubEventHeader 6 QWs] = 7 QWs total.
     398              :         // QW0 = event header; QW1..6 = subevent header.
     399              :         static constexpr size_t                  kSubEventHeaderQws = sizeof(DTC_SubEventHeader) / sizeof(uint64_t) + 1;
     400              :         std::array<uint64_t, kSubEventHeaderQws> subEventHeaderBuf_{};
     401              :         size_t                                   subEventHeaderQwsFilled_{0};  ///< Number of QWs currently filled in subEventHeaderBuf_
     402              : 
     403              :         std::array<uint64_t, 8> lastBufferTailQwords_{};  ///< Last up to 8 qwords of the most recently processed DMA buffer; saved at every return path for cross-buffer exception diagnostics
     404              :         size_t                  lastBufferTailCount_{0};  ///< Valid entry count in lastBufferTailQwords_
     405              : 
     406              :         bool lastDMABufferWasFull_{false};  ///< True when dmaBytes == MAX_TRANSFER_SIZE (max sub-transfer with tlast); next buffer starts a new sub-transfer with prefix
     407              :         bool lastDMABufferWasMax_{false};   ///< True when dmaBytes == sizeof(mu2e_databuff_t) (buffer physically full, no tlast); next buffer is raw continuation (no prefix)
     408              : 
     409              :         std::string lastDMABufferIndex_{};  ///< String representation of the index of the last DMA buffer processed, for diagnostics
     410              : 
     411              :         // // State for GetSubEventData v2: cross-buffer pending subevent assembly
     412              :         uint64_t             totalSubEventsParsed_{0};       ///< Lifetime count of successfully-parsed subevents; included in diagnostic prints so we can tell whether parsing ever made progress
     413              :         std::vector<uint8_t> pendingSubEventBytes_{};        ///< Partial subevent bytes carried over from the previous DMA buffer
     414              :         size_t               pendingSubEventTotalBytes_{0};  ///< Expected total byte count of the pending subevent (0 = header not yet complete)
     415              :         // bool                 lastDMABufferWasFull_{false};   ///< True when the last DMA buffer was completely full (dmaBytes==sizeof(mu2e_databuff_t)); used for payloadBytes/tlast calculation
     416              :         bool pendingPrefixConsumed_{false};  ///< True when the previous buffer ended with a prefix-only (0 subevent bytes after the prefix); next buffer starts with raw subevent header data at offset 0
     417              : 
     418              :         // State for GetEVBDataAsEvents: per-source FAFA chunk reassembly
     419              :         std::map<uint8_t /*chunk_src*/, std::vector<uint8_t>> evbPerSourceReassembly_;
     420              :         std::map<uint8_t /*chunk_src*/, std::vector<uint8_t>> evbLastGoodRecord_;  ///< last cleanly-parsed record per source, dumped alongside a bad one for comparison
     421              :         // Per-tag event assembly: a tag is complete when all N source DTCs have delivered their subevent
     422              :         struct EVBPendingTag
     423              :         {
     424              :                 std::chrono::steady_clock::time_point                     firstArrival;  ///< when the first subevent for this tag was staged
     425              :                 std::map<uint8_t /*source_dtc_id*/, std::vector<uint8_t>> subevents;     ///< raw subevent bytes (record header stripped), keyed by source
     426              :         };
     427              :         std::map<uint64_t /*event window tag*/, EVBPendingTag> evbPendingTags_;
     428            0 :         std::chrono::milliseconds                              evbEventTimeout_{2000};
     429              :         size_t                                                 evbMaxOpenTags_{1024};
     430              :         bool                                                   evbDrainOnly_{false};
     431              :         uint64_t                                               evbDrainedBytes_{0};
     432              :         uint64_t                                               evbDMABuffersRead_{0};
     433              :         EVBReadProfile                                         evbReadProfile_;
     434              :         uint8_t                                                evbNumSources_{1};
     435              :         bool                                                   evbSourcesKnown_{false};
     436              :         uint8_t                                                evbLocalMac_{0};
     437              :         bool                                                   evbHaveReleasedTag_{false};
     438              :         uint64_t                                               evbLastReleasedTag_{0};
     439              :         uint64_t                                               evbEventsReleased_{0};
     440              :         uint64_t                                               evbChunksParsed_{0};
     441            0 :         std::vector<uint64_t>                                  evbRemoteChunkSizeHistogram_ = std::vector<uint64_t>(8192, 0);
     442              :         uint64_t                                               evbFramingErrors_{0};
     443              :         uint64_t                                               evbSplitSubeventsJoined_{0};
     444              : 
     445              :         uint8_t lastDTCErrorBitsValue_ = 0;
     446              : };
     447              : }  // namespace DTCLib
     448              : #endif
        

Generated by: LCOV version 2.0-1