Skip to content
Snippets Groups Projects
Select Git revision
  • c3c14ff6073ac6697be3fdaf131f3ffcea07bc29
  • master default protected
  • nightly_master
  • online_much_readconf_cleanup protected
  • online_mvd_readconf_cleanup protected
  • jul25_patches
  • cleanup_rich_v25a
  • jul24_patches
  • nov23_patches
  • DC_2404
  • nighly_master
  • DC_Jan24
  • DC_Nov23
  • DC_Oct23
  • feb23_patches
  • L1Algo-dev9
  • dec21_patches protected
  • apr21_patches protected
  • dev_2025_47
  • RC2_jul25
  • dev_2025_46
  • dev_2025_45
  • dev_2025_44
  • dev_2025_43
  • dev_2025_42
  • dev_2025_41
  • dev_2025_40
  • dev_2025_39
  • dev_2025_38
  • dev_2025_37
  • dev_2025_36
  • dev_2025_35
  • dev_2025_34
  • dev_2025_33
  • dev_2025_32
  • dev_2025_31
  • dev_2025_30
  • RC_jul25
38 results

UnpackMS.cxx

Blame
  • UnpackMS.cxx 6.16 KiB
    /* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
       SPDX-License-Identifier: GPL-3.0-only
       Authors: Pierre-Alain Loizeau, Volker Friese [committer] */
    
    #include "UnpackMS.h"
    
    #include "StsXyterMessage.h"
    
    #include <cassert>
    #include <cmath>
    #include <utility>
    #include <vector>
    
    using std::unique_ptr;
    using std::vector;
    
    namespace cbm::algo::much
    {
    
      UnpackMS::UnpackMS(const UnpackPar& pars) : fParams(pars) {}
      UnpackMS::~UnpackMS() = default;
    
      // ----   Algorithm execution   ---------------------------------------------
      UnpackMS::Result_t UnpackMS::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
                                              const uint64_t tTimeslice) const
      {
    
        // --- Output data
        Result_t result = {};
    
        TimeSpec time;
    
        // --- Current Timeslice start time in epoch units. Note that it is always a multiple of epochs
        // --- and the epoch is a multiple of ns.
        const uint64_t epochLengthInNs = fkEpochLength * fkClockCycleNom / fkClockCycleDen;
        time.currentTsTime             = tTimeslice / epochLengthInNs;
    
        // --- Current TS_MSB epoch cycle
        auto const msTime = msDescr.idx;  // Unix time of MS in ns
        time.currentCycle = std::ldiv(msTime, fkCycleLength).quot;
        time.currentEpoch = 0;  // Needed to make each MS independent of the previous! Will be updated in message 1 if MS OK
        time.currentEpochTime =
          0;  // Needed to make each MS independent of the previous! Will be updated in message 1 if MS OK
    
        // --- Number of messages in microslice
        auto msSize = msDescr.size;
        if (msSize % sizeof(stsxyter::Message) != 0) {
          std::get<1>(result).fNumErrInvalidMsSize++;
          return result;
        }
        const uint32_t numMessages = msSize / sizeof(stsxyter::Message);
        if (numMessages < 2) {
          std::get<1>(result).fNumErrInvalidMsSize++;
          return result;
        }
    
        const uint32_t maxDigis = numMessages - 2;  // -2 for the TS_MSB and EPOCH messages
        std::get<0>(result).reserve(maxDigis);
    
        // --- Interpret MS content as sequence of SMX messages
        auto message = reinterpret_cast<const stsxyter::Message*>(msContent);
    
        // --- The first message in the MS is expected to be of type EPOCH and can be ignored.
        if (message[0].GetMessType() != stsxyter::MessType::Epoch) {
          std::get<1>(result).fNumErrInvalidFirstMessage++;
          return result;
        }
    
        // --- The second message must be of type ts_msb.
        if (message[1].GetMessType() != stsxyter::MessType::TsMsb) {
          std::get<1>(result).fNumErrInvalidFirstMessage++;
          return result;
        }
        ProcessTsmsbMessage(message[1], time);
    
        // --- Message loop
        for (uint32_t messageNr = 2; messageNr < numMessages; messageNr++) {
    
          // --- Action depending on message type
          switch (message[messageNr].GetMessType()) {
    
            case stsxyter::MessType::Hit: {
              ProcessHitMessage(message[messageNr], time, std::get<0>(result), std::get<1>(result));
              break;
            }
            case stsxyter::MessType::TsMsb: {
              ProcessTsmsbMessage(message[messageNr], time);
              break;
            }
            default: {
              std::get<1>(result).fNumNonHitOrTsbMessage++;
              break;
            }
    
          }  //? Message type
    
        }  //# Messages
    
        return result;
      }
      // --------------------------------------------------------------------------
    
    
      // -----   Process hit message   --------------------------------------------
      inline void UnpackMS::ProcessHitMessage(const stsxyter::Message& message, const TimeSpec& time,
                                              vector<CbmMuchDigi>& digiVec, UnpackMonitorData& monitor) const
      {
        // --- Check eLink and get parameters
        uint16_t elink = message.GetLinkIndexHitBinning();
        if (elink >= fParams.fElinkParams.size()) {
          monitor.fNumErrElinkOutOfRange++;
          return;
        }
        const UnpackElinkPar& elinkPar = fParams.fElinkParams.at(elink);
        uint16_t channel               = message.GetHitChannel();
    
        // --- Check for masked channel
        if (!elinkPar.fChanMask.empty() && elinkPar.fChanMask[channel] == true) {
          return;
        }
    
        uint32_t address = (elinkPar.fAddress)[channel];
    
        // --- Expand time stamp to time within timeslice (in clock cycle)
        uint64_t messageTime = message.GetHitTimeBinning() + time.currentEpochTime;
    
        // --- Convert time stamp from clock cycles to ns. Round to nearest full ns.
        messageTime = (messageTime * fkClockCycleNom + fkClockCycleDen / 2) / fkClockCycleDen;
    
        // --- Correct ASIC-wise offsets
        messageTime -= elinkPar.fTimeOffset;
    
        // --- Charge
        double charge = message.GetHitAdc();
    
        // --- Create output digi
        digiVec.emplace_back(address, charge, messageTime);
      }
      // --------------------------------------------------------------------------
    
    
      // -----   Process an epoch (TS_MSB) message   ------------------------------
      inline void UnpackMS::ProcessTsmsbMessage(const stsxyter::Message& message, TimeSpec& time) const
      {
        // The compression of time is based on the hierarchy epoch cycle - epoch - message time.
        // Cycles are counted from the start of Unix time and are multiples of an epoch (ts_msb).
        // The epoch number is counted within each cycle. The time in the hit message is expressed
        // in units of the readout clock cycle relative to the current epoch.
        // The ts_msb message indicates the start of a new epoch. Its basic information is the epoch
        // number within the current cycle. A cycle wrap resets the epoch number to zero, so it is
        // indicated by the epoch number being smaller than the previous one (epoch messages are
        // seemingly not consecutively in the data stream, but only if there are hit messages in between).
        auto epoch = message.GetTsMsbValBinning();
    
        // --- Cycle wrap
        if (epoch < time.currentEpoch) time.currentCycle++;
    
        // --- Update current epoch counter
        time.currentEpoch = epoch;
    
        // --- Calculate epoch time in clocks cycles relative to timeslice start time
        time.currentEpochTime = (time.currentCycle * fkEpochsPerCycle + epoch - time.currentTsTime) * fkEpochLength;
      }
      // --------------------------------------------------------------------------
    
    
    }  // namespace cbm::algo::much