Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
#include "EventFilter/Phase2TrackerRawToDigi/interface/Phase2TrackerFEDBuffer.h"
#include "EventFilter/Phase2TrackerRawToDigi/interface/utils.h"
#include "FWCore/Utilities/interface/Exception.h"
#include "FWCore/MessageLogger/interface/MessageLogger.h"

namespace Phase2Tracker {

  // implementation of Phase2TrackerFEDBuffer
  Phase2TrackerFEDBuffer::Phase2TrackerFEDBuffer(const uint8_t* fedBuffer, const size_t fedBufferSize)
      : buffer_(fedBuffer), bufferSize_(fedBufferSize) {
    LogTrace("Phase2TrackerFEDBuffer") << "content of buffer with size: " << int(fedBufferSize) << std::endl;
    for (size_t i = 0; i < fedBufferSize; i += 8) {
      uint64_t word = read64(i, buffer_);
      LogTrace("Phase2TrackerFEDBuffer") << " word " << std::setfill(' ') << std::setw(2) << i / 8 << " | " << std::hex
                                         << std::setw(16) << std::setfill('0') << word << std::dec << std::endl;
    }
    LogTrace("Phase2TrackerFEDBuffer") << std::endl;

    // reserve all channels (should be 16x16 in our case)
    channels_.reserve(MAX_FE_PER_FED * MAX_CBC_PER_FE);
    // first 64 bits word is for DAQ header
    daqHeader_ = FEDDAQHeader(buffer_);
    // last 64 bit word is daq trailer
    daqTrailer_ = FEDDAQTrailer(buffer_ + bufferSize_ - 8);
    // tracker header follows daq header
    trackerHeader_ = Phase2TrackerFEDHeader(buffer_ + 8);
    // get pointer to payload
    payloadPointer_ = getPointerToPayload();
    // fill list of Phase2TrackerFEDChannels and get pointers to trigger and comissioning data
    findChannels();
  }

  Phase2TrackerFEDBuffer::~Phase2TrackerFEDBuffer() {}

  void Phase2TrackerFEDBuffer::findChannels() {
    // each FED can be connectd to up to 16 frontends (read from header)
    // each fronted can be connected to up to 16 CBC
    // in raw mode, a header of 16bits tells which CBC are activated on this FE
    // in ZS mode, one byte is used to tell how many clusters are present in the current CBC
    // one channel corresponds to one CBC chip, undependently of the mode

    // offset of beginning of current channel
    size_t offsetBeginningOfChannel = 0;

    // iterate over all FEs to see if they are active
    std::vector<bool>::iterator FE_it;
    std::vector<bool> status = trackerHeader_.frontendStatus();

    if (readoutMode() == READOUT_MODE_PROC_RAW) {
      for (FE_it = status.begin(); FE_it < status.end(); FE_it++) {
        // if the current fronted is on, fill channels and advance pointer to end of channel
        if (*FE_it) {
          // read first FEDCH_PER_FEUNIT bits to know which CBC are on
          uint16_t cbc_status = static_cast<uint16_t>(*(payloadPointer_ + (offsetBeginningOfChannel ^ 7)) << 8);
          cbc_status += static_cast<uint16_t>(*(payloadPointer_ + ((offsetBeginningOfChannel + 1) ^ 7)));

          // advance pointer by FEDCH_PER_FEUNIT bits
          offsetBeginningOfChannel += MAX_CBC_PER_FE / 8;
          for (int i = 0; i < MAX_CBC_PER_FE; i++) {
            // if CBC is ON, fill channel and advance pointer. else, push back empty channel
            if ((cbc_status >> i) & 0x1) {
              // Warning: STRIPS_PADDING+STRIPS_PER_CBC should always be an entire number of bytes
              channels_.push_back(Phase2TrackerFEDChannel(
                  payloadPointer_, offsetBeginningOfChannel, (STRIPS_PADDING + STRIPS_PER_CBC) / 8));
              offsetBeginningOfChannel += (STRIPS_PADDING + STRIPS_PER_CBC) / 8;
            } else {
              channels_.push_back(Phase2TrackerFEDChannel(nullptr, 0, 0));
            }
          }
        } else {
          // else fill with FEDCH_PER_FEUNIT null channels, don't advance the channel pointer
          channels_.insert(channels_.end(), size_t(MAX_CBC_PER_FE), Phase2TrackerFEDChannel(payloadPointer_, 0, 0));
        }
      }
    } else if (readoutMode() == READOUT_MODE_ZERO_SUPPRESSED) {
      for (FE_it = status.begin(); FE_it < status.end(); FE_it++) {
        if (*FE_it) {
          for (int i = 0; i < MAX_CBC_PER_FE; i++) {
            // read first byte to get number of clusters and skip it
            uint8_t n_clusters = static_cast<uint8_t>(*(payloadPointer_ + offsetBeginningOfChannel));
            offsetBeginningOfChannel += 1;
            // each channel contains 2 bytes per cluster
            channels_.push_back(Phase2TrackerFEDChannel(payloadPointer_, offsetBeginningOfChannel, 2 * n_clusters));
            // skip clusters
            offsetBeginningOfChannel += 2 * n_clusters;
          }
        } else {
          // else fill with FEDCH_PER_FEUNIT null channels, don't advance the channel pointer
          channels_.insert(channels_.end(), size_t(MAX_CBC_PER_FE), Phase2TrackerFEDChannel(payloadPointer_, 0, 0));
        }
      }
    } else {
      // TODO: throw exception for unrecognised readout mode
      // check done at Phase2TrackerFEDHeader::readoutMode()
    }
    // round the offset to the next 64 bits word
    int words64 = (offsetBeginningOfChannel + 8 - 1) / 8;  // size in 64 bit
    int payloadSize = words64 * 8;                         // size in bytes
    triggerPointer_ = payloadPointer_ + payloadSize;

    // get diff size in bytes:
    // fedBufferSize - (DAQHeader+TrackHeader+PayloadSize+TriggerSize+DAQTrailer)
    int bufferDiff = bufferSize_ - 8 - trackerHeader_.getTrackerHeaderSize() - payloadSize - TRIGGER_SIZE - 8;

    // check if condition data is supposed to be there:
    if (trackerHeader_.getConditionData()) {
      condDataPointer_ = triggerPointer_ + TRIGGER_SIZE;
      // diff must be equal to condition data size
      if (bufferDiff <= 0) {
        std::ostringstream ss;
        ss << "[Phase2Tracker::Phase2TrackerFEDBuffer::" << __func__ << "] "
           << "\n";
        ss << "FED Buffer Size does not match data => missing condition data? : "
           << "\n";
        ss << "Expected Buffer Size " << bufferSize_ << " bytes"
           << "\n";
        ss << "Computed Buffer Size " << bufferSize_ + bufferDiff << " bytes"
           << "\n";
        throw cms::Exception("Phase2TrackerFEDBuffer") << ss.str();
      }
    } else {
      // put a null pointer to indicate lack of condition data
      condDataPointer_ = nullptr;
      // check buffer size :
      if (bufferDiff != 0) {
        std::ostringstream ss;
        ss << "[Phase2Tracker::Phase2TrackerFEDBuffer::" << __func__ << "] "
           << "\n";
        ss << "FED Buffer Size does not match data => corrupted buffer? : "
           << "\n";
        ss << "Expected Buffer Size " << bufferSize_ << " bytes"
           << "\n";
        ss << "Computed Buffer Size " << bufferSize_ + bufferDiff << " bytes"
           << "\n";
        throw cms::Exception("Phase2TrackerFEDBuffer") << ss.str();
      }
    }
  }

  std::map<uint32_t, uint32_t> Phase2TrackerFEDBuffer::conditionData() const {
    std::map<uint32_t, uint32_t> cdata;
    // check if there is condition data
    if (condDataPointer_) {
      const uint8_t* pointer = condDataPointer_;
      const uint8_t* stop = buffer_ + bufferSize_ - 8;
      // first read the size
      uint32_t size = 0;
      // somehow the size is not inverted
      //for (int i=0;i<4;++i) size += *(pointer-4+(i^7)) << (i*8);
      size = *reinterpret_cast<const uint32_t*>(pointer);
      LogTrace("Phase2TrackerFEDBuffer") << "Condition Data size = " << size << std::endl;
      pointer += 8;
      // now the conditions
      while (pointer < stop) {
        // somehow the data is not inverted
        uint32_t data = 0;
        //for (int i = 0, j=3 ; i<4; i++,j--)
        //{ data += (*(pointer+i) << j*8); }
        data = *reinterpret_cast<const uint32_t*>(pointer);
        pointer += 4;

        uint32_t key = 0;
        for (int i = 0, j = 3; i < 4; i++, j--) {
          key += (*(pointer + i) << j * 8);
        }
        pointer += 4;

        cdata[key] = data;
      }
      // final check: cdata size == size
      if (cdata.size() != size) {
        std::ostringstream ss;
        ss << "[Phase2Tracker::Phase2TrackerFEDBuffer::" << __func__ << "] "
           << "\n";
        ss << "Number of condition data does not match the announced value!"
           << "\n";
        ss << "Expected condition data Size " << size << " entries"
           << "\n";
        ss << "Computed condition data Size " << cdata.size() << " entries"
           << "\n";
        throw cms::Exception("Phase2TrackerFEDBuffer") << ss.str();
      }
    }
    // REMOVE THIS : inject fake cond data for tests
    /*
      cdata[0x0011] = 0x0001;
      cdata[0x0012] = 0x0002;
      */
    // add trigger data
    cdata[0x0B0000FF] = (TRIGGER_SIZE > 0) ? (*triggerPointer_) : 0x00000000;
    return cdata;
  }

  FEDReadoutMode Phase2TrackerFEDBuffer::readoutMode() const { return trackerHeader_.getReadoutMode(); }

}  // namespace Phase2Tracker