Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-05 08:16:19

0001 #ifndef Fun4All_TpcTimeFrameBuilder_H
0002 #define Fun4All_TpcTimeFrameBuilder_H
0003 
0004 #include <algorithm>
0005 #include <cstdint>
0006 #include <deque>
0007 #include <functional>
0008 #include <iostream>
0009 #include <limits>
0010 #include <list>
0011 #include <map>
0012 #include <optional>
0013 #include <queue>
0014 #include <set>
0015 #include <string>
0016 #include <utility>
0017 #include <vector>
0018 
0019 class Packet;
0020 class TpcRawHit;
0021 class PHTimer;
0022 class TH1;
0023 class TH2;
0024 class TTree;
0025 
0026 // NOLINTNEXTLINE(hicpp-special-member-functions)
0027 class TpcTimeFrameBuilder
0028 {
0029  public:
0030   explicit TpcTimeFrameBuilder(const int packet_id);
0031   virtual ~TpcTimeFrameBuilder();
0032 
0033   int ProcessPacket(Packet *);
0034   bool isMoreDataRequired(const uint64_t &gtm_bco) const;
0035   void CleanupUsedPackets(const uint64_t &bclk);
0036   std::vector<TpcRawHit *> &getTimeFrame(const uint64_t &gtm_bco);
0037 
0038   void setVerbosity(const int i);
0039   void setFastBCOSkip(bool fastBCOSkip = true)
0040   {
0041     m_fastBCOSkip = fastBCOSkip;
0042   }
0043 
0044   // enable saving of digital current debug TTree with file name `name`
0045   void SaveDigitalCurrentDebugTTree(const std::string &name);
0046 
0047  protected:
0048   // Length for the 256-bit wide Round Robin Multiplexer for the data stream
0049   static const size_t DAM_DMA_WORD_LENGTH = 16;
0050 
0051   static const uint16_t FEE_PACKET_MAGIC_KEY_1 = 0xfe;
0052   static const uint16_t FEE_PACKET_MAGIC_KEY_2 = 0xed;
0053   static const uint16_t FEE_PACKET_MAGIC_KEY_3_DC = 0xdcdc; // Digital Current word[3]
0054 
0055   static const uint16_t FEE_MAGIC_KEY = 0xba00;
0056   static const uint16_t GTM_MAGIC_KEY = 0xbb00;
0057   static const uint16_t GTM_LVL1_ACCEPT_MAGIC_KEY = 0xbbf0;
0058   static const uint16_t GTM_ENDAT_MAGIC_KEY = 0xbbf1;
0059   static const uint16_t GTM_MODEBIT_MAGIC_KEY = 0xbbf2;
0060 
0061   static const uint16_t MAX_FEECOUNT = 26;              // that many FEEs
0062   static const uint16_t MAX_SAMPA = 8;                  // that many FEEs
0063   static const uint16_t MAX_CHANNELS = MAX_SAMPA * 32;  // that many channels per FEE
0064                                                         //  static const uint16_t  HEADER_LENGTH  = 5;
0065   static const uint16_t HEADER_LENGTH = 7;
0066   static const uint16_t MAX_PACKET_LENGTH = 1025;
0067 
0068   static const uint16_t GL1_BCO_MATCH_WINDOW = 256;  // BCOs
0069 
0070   int m_hitFormat = -1;
0071 
0072   uint16_t reverseBits(const uint16_t x) const;
0073   std::pair<uint16_t, uint16_t> crc16_parity(const uint32_t fee, const uint16_t l) const;
0074 
0075   //! DMA word structure
0076   struct dma_word
0077   {
0078     uint16_t dma_header = 0;
0079     uint16_t data[DAM_DMA_WORD_LENGTH - 1] = {0};
0080   };
0081 
0082   int decode_gtm_data(const dma_word &gtm_word);
0083   int process_fee_data(unsigned int fee_id);
0084   void process_fee_data_waveform(const unsigned int & fee_id, std::deque<uint16_t>& data_buffer);
0085   void process_fee_data_digital_current(const unsigned int & fee_id, std::deque<uint16_t>& data_buffer);
0086 
0087   struct gtm_payload
0088   {
0089     uint16_t pkt_type = 0;
0090     bool is_endat = false;
0091     bool is_lvl1 = false;
0092     bool is_modebit = false;
0093     uint64_t bco = 0;
0094     uint32_t lvl1_count = 0;
0095     uint32_t endat_count = 0;
0096     uint64_t last_bco = 0;
0097     uint8_t modebits = 0;
0098     uint8_t userbits = 0;
0099   };
0100 
0101   struct fee_payload
0102   {
0103     uint16_t fee_id = 0;
0104     uint16_t adc_length = 0;
0105     uint16_t sampa_address = 0;
0106     uint16_t sampa_channel = 0;
0107     uint16_t channel = 0;
0108     uint16_t type = 0;
0109     uint16_t user_word = 0;
0110     uint32_t bx_timestamp = 0;
0111     uint64_t gtm_bco = 0;
0112 
0113     uint16_t data_crc = 0;
0114     uint16_t calc_crc = 0;
0115     
0116     uint16_t data_parity = 0;
0117     uint16_t calc_parity = 0;
0118 
0119     std::vector<std::pair<uint16_t, std::vector<uint16_t>>> waveforms;
0120   };
0121 
0122   struct digital_current_payload
0123   {
0124     static const int MAX_CHANNELS = 8;
0125 
0126     uint64_t gtm_bco {std::numeric_limits<uint64_t>::max()};
0127     uint32_t bx_timestamp_predicted {std::numeric_limits<uint32_t>::max()};
0128 
0129     uint16_t fee {std::numeric_limits<uint16_t>::max()};
0130     uint16_t pkt_length {std::numeric_limits<uint16_t>::max()};
0131     uint16_t channel {std::numeric_limits<uint16_t>::max()};
0132     // uint16_t sampa_max_channel {std::numeric_limits<uint16_t>::max()};
0133     uint16_t sampa_address {std::numeric_limits<uint16_t>::max()};
0134     uint32_t bx_timestamp {0};
0135     uint32_t current[MAX_CHANNELS] {0};
0136     uint32_t nsamples[MAX_CHANNELS] {0};
0137     uint16_t data_crc {std::numeric_limits<uint16_t>::max()};
0138     uint16_t calc_crc = {std::numeric_limits<uint16_t>::max()};
0139     // uint16_t type {std::numeric_limits<uint16_t>::max()};
0140   };
0141 
0142   class DigitalCurrentDebugTTree
0143   {
0144    public:
0145     explicit DigitalCurrentDebugTTree(const std::string &name);
0146     virtual ~DigitalCurrentDebugTTree();
0147 
0148     void fill(const digital_current_payload &payload);
0149 
0150    private:
0151     digital_current_payload m_payload;
0152 
0153     std::string m_name;
0154     TTree *m_tDigitalCurrent = nullptr;
0155   };
0156   DigitalCurrentDebugTTree * m_digitalCurrentDebugTTree = nullptr;
0157 
0158   // -------------------------
0159   // GTM Matcher
0160   // Initially developped by Hugo Pereira Da Costa as `MicromegasBcoMatchingInformation`
0161   // -------------------------
0162   class BcoMatchingInformation
0163   {
0164    public:
0165     //! constructor
0166     explicit BcoMatchingInformation(const std::string &name);
0167 
0168     //!@name accessor
0169     //@{
0170 
0171     //! verbosity
0172     int verbosity() const
0173     {
0174       return m_verbosity;
0175     }
0176 
0177     //! true if matching information is verified
0178     /**
0179      * matching information is verified if at least one match
0180      * between gtm_bco and fee_bco is found
0181      */
0182     bool is_verified() const
0183     {
0184       return m_verified_from_modebits || m_verified_from_data;
0185     }
0186 
0187     //! matching between fee bco and lvl1 bco
0188     using m_gtm_fee_bco_matching_pair_t = std::pair<uint64_t, uint32_t>;
0189     using m_fee_gtm_bco_matching_pair_t = std::pair<uint32_t, uint64_t>;
0190 
0191     //! get reference bco
0192     const std::optional<m_gtm_fee_bco_matching_pair_t> &get_reference_bco() const
0193     {
0194       return m_bco_reference;
0195     }
0196 
0197     //! whether FEE data has moved pass the given gtm_bco
0198     bool isMoreDataRequired(const uint64_t &gtm_bco) const;
0199 
0200     //! get predicted fee_bco from gtm_bco
0201     std::optional<uint32_t> get_predicted_fee_bco(uint64_t) const;
0202 
0203     //! multiplier
0204     double get_gtm_clock_multiplier()
0205     {
0206       return m_multiplier;
0207     }
0208 
0209     //! print gtm bco information
0210     void print_gtm_bco_information() const;
0211 
0212     //@}
0213 
0214     //!@name modifiers
0215     //@{
0216 
0217     //! verbosity
0218     void set_verbosity(int value)
0219     {
0220       m_verbosity = value;
0221     }
0222 
0223     /// set gtm clock multiplier
0224     void set_gtm_clock_multiplier(double value)
0225     {
0226       m_multiplier = value;
0227     }
0228 
0229     /// set gtm clock with rollover correction
0230     uint64_t get_gtm_rollover_correction(const uint64_t &gtm_bco) const;
0231 
0232     //! find reference from data
0233     std::optional<uint64_t> find_reference_heartbeat(const fee_payload &HeartBeatPacket);
0234 
0235     //! save all GTM BCO clocks from packet data
0236     void save_gtm_bco_information(const gtm_payload &gtm_tagger);
0237 
0238     //! find gtm bco matching a given fee
0239     std::optional<uint64_t> find_gtm_bco(uint32_t /*fee_gtm*/);
0240 
0241     //! cleanup
0242     void cleanup();
0243 
0244     //! cleanup
0245     void cleanup(uint64_t /*ref_bco*/);
0246 
0247     m_gtm_fee_bco_matching_pair_t find_dc_read_bco() const
0248     {
0249       return m_gtm_bco_dc_read;
0250     }
0251     //@}
0252 
0253     /* see: https://git.racf.bnl.gov/gitea/Instrumentation/sampa_data/src/branch/fmtv2/README.md */
0254     enum SampaDataType
0255     {
0256       HEARTBEAT_T = 0b000,
0257       TRUNCATED_DATA_T = 0b001,
0258       TRUNCATED_TRIG_EARLY_DATA_T = 0b011,
0259       NORMAL_DATA_T = 0b100,
0260       LARGE_DATA_T = 0b101,
0261       TRIG_EARLY_DATA_T = 0b110,
0262       TRIG_EARLY_LARGE_DATA_T = 0b111,
0263     };
0264 
0265     // Command   | OLD Mode-Bit | New Mode-Number | Function
0266     // ======================================================
0267     // NOP       |     0b000    |             0x0 | No Operation
0268     // BX_SYNC   |     0b001    |             0x1 | SAMPA Beam-crossing sync
0269     // H_BEAT    |     0b010    |             0x2 | Generates Heartbeat frame
0270     // TRIG      |     0b100    |             0x3 | Trigger data when FEM user bit is 0b01, otherwise the level 1 accept is used when FEM user bit is 0b00
0271     // CLK_SYNC  |     N/A      |             0x4 | Reset and align 40 MHz and 20 MHz clocks to SAMPA
0272     // SAMPA_RST |     N/A      |             0x5 | Hard reset SAMPA
0273     // DC_START  |     N/A      |             0x6 | Start digital current reading
0274     // DC_STOP   |     N/A      |             0x7 | Stop and send digital current packet
0275     enum ModeBitType
0276     {
0277       BX_COUNTER_SYNC_T = 0x1,
0278       ELINK_HEARTBEAT_T = 0x2,
0279       DC_STOP_SEND_T = 0x7
0280       // SAMPA_EVENT_TRIGGER_T = 2,
0281       // CLEAR_LV1_LAST_T = 6,
0282       // CLEAR_LV1_ENDAT_T = 7
0283     };
0284 
0285     // get the difference between two BCO WITHOUT rollover corrections
0286     template <class T>
0287     inline static constexpr T get_bco_diff(
0288         const T &first, const T &second)
0289     {
0290       return first < second ? (second - first) : (first - second);
0291     }
0292 
0293     // get the difference between two BCO with rollover corrections
0294     inline static constexpr uint32_t get_fee_bco_diff(
0295         const uint32_t &first, const uint32_t &second)  // NOLINT(misc-unused-parameters)
0296     {
0297       const uint32_t diff_raw = get_bco_diff(first, second);
0298 
0299       return (diff_raw < (1U << (m_FEE_CLOCK_BITS / 2))) ? diff_raw : (1U << m_FEE_CLOCK_BITS) - diff_raw;
0300     }
0301 
0302    private:
0303     std::string m_name;
0304 
0305     //! verbosity
0306     unsigned int m_verbosity = 0;
0307 
0308     //! verified
0309     bool m_verified_from_modebits = false;
0310 
0311     bool m_verified_from_data = false;
0312 
0313     //! list of available bco, sorted in time with rollover corrected
0314     std::list<uint64_t> m_gtm_bco_trig_list;
0315 
0316     //! last digital current readout GTM BCO
0317     m_gtm_fee_bco_matching_pair_t m_gtm_bco_dc_read = {0, 0};
0318 
0319     //! list of available GTM -> FEE bco mapping for synchronization
0320     std::optional<m_gtm_fee_bco_matching_pair_t> m_bco_reference = std::nullopt;
0321 
0322     // std::optional< std::pair< uint64_t, uint32_t > > m_bco_reference_candidate = std::nullopt;
0323     //! not yet matched heart beats
0324     std::list<m_gtm_fee_bco_matching_pair_t> m_bco_reference_candidate_list;
0325     static constexpr unsigned int m_max_bco_reference_candidate_list_size = 16;
0326 
0327     // //! list of heart beat GTM BCO that is still to be matched
0328     // std::queue<uint64_t> m_heartbeat_gtm_bco_queue;
0329     // static constexpr unsigned int m_max_heartbeat_queue_size = 16;
0330 
0331     //! list of available GTM -> FEE bco mapping for trigger association
0332     std::map<uint64_t, uint32_t> m_gtm_bco_trigger_map;
0333 
0334     std::list<m_fee_gtm_bco_matching_pair_t> m_bco_matching_list;
0335 
0336     //! keep track or  fee_bco for which no gtm_bco is found
0337     std::set<uint32_t> m_orphans;
0338 
0339     // define limit for matching two lvl1 and EnDAT tagger BCOs
0340     static constexpr int m_max_lv1_endat_bco_diff = 16;
0341 
0342     // define limit for matching two fee_bco
0343     static constexpr unsigned int m_max_fee_bco_diff = 64;
0344 
0345     // define limit for matching gtm_bco from lvl1 to enddat
0346 
0347     // define limit for matching fee_bco to fee_bco_predicted
0348     static constexpr unsigned int m_max_gtm_bco_diff = 256;
0349 
0350     //   // needed to avoid memory leak. Assumes that we will not be assembling more than 50 events at the same time
0351     static constexpr unsigned int m_max_matching_data_size = 10;
0352 
0353     //! max time in GTM BCO for FEE data to sync over to datastream
0354     static constexpr unsigned int m_max_fee_sync_time = 1024 * 8;
0355 
0356     static constexpr unsigned int m_FEE_CLOCK_BITS = 20;
0357     static constexpr unsigned int m_GTM_CLOCK_BITS = 40;
0358 
0359     double m_multiplier = 0;
0360 
0361     TH1 *m_hNorm = nullptr;
0362     TH1 *m_hFEEClockAdjustment_MatchedReference = nullptr;
0363     TH1 *m_hFEEClockAdjustment_MatchedNew = nullptr;
0364     TH1 *m_hFEEClockAdjustment_Unmatched = nullptr;
0365     TH1 *m_hGTMNewEventSpacing = nullptr;
0366     TH1 *m_hFindGTMBCO_MatchedExisting_BCODiff = nullptr;
0367     TH1 *m_hFindGTMBCO_MatchedNew_BCODiff = nullptr;
0368 
0369   };  //   class BcoMatchingInformation
0370 
0371  private:
0372   std::vector<std::deque<uint16_t>> m_feeData;
0373 
0374   int m_verbosity = 0;
0375   int m_packet_id = 0;
0376 
0377   //! common prefix for QA histograms
0378   std::string m_HistoPrefix;
0379 
0380   //! GTM BCO -> TpcRawHit
0381   //! Map to store TpcRawHit pointers indexed by GTM BCO values
0382   //! This is used to organize hits into time frames based on their BCO values
0383   std::map<uint64_t, std::vector<TpcRawHit *>> m_timeFrameMap;
0384   static const size_t kMaxRawHitLimit = 10000;  // 10k hits per event > 256ch/fee * 26fee
0385   std::queue<uint64_t> m_UsedTimeFrameSet;
0386 
0387   //! fast skip mode when searching for particular GL1 BCO over long segment of files
0388   bool m_fastBCOSkip = false;
0389 
0390   //! map bco_information_t to packet id
0391   std::vector<BcoMatchingInformation> m_bcoMatchingInformation_vec;
0392 
0393   //! QA area
0394 
0395   PHTimer *m_packetTimer = nullptr;
0396 
0397   TH1 *m_hNorm = nullptr;
0398   TH2 *m_hFEEDataStream = nullptr;
0399   TH1 *m_hFEEChannelPacketCount = nullptr;
0400   TH2 *m_hFEESAMPAADC = nullptr;
0401   TH1 *m_hFEESAMPAHeartBeatSync = nullptr;
0402 
0403   TH1 *h_PacketLength = nullptr;
0404   TH1 *h_PacketLength_Padding = nullptr;
0405   TH1 *h_PacketLength_Residual = nullptr;
0406 
0407   TH1 *h_GTMClockDiff_Matched = nullptr;
0408   TH1 *h_GTMClockDiff_Unmatched = nullptr;
0409   TH1 *h_GTMClockDiff_Dropped = nullptr;
0410   TH1 *h_TimeFrame_Matched_Size = nullptr;
0411 
0412   TH2 *h_ProcessPacket_Time = nullptr;
0413 };
0414 
0415 #endif