File indexing completed on 2023-05-26 01:15:39
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0010 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0011 #include "FWCore/Utilities/interface/CRC16.h"
0012
0013 #include "EventFilter/HGCalRawToDigi/interface/HGCalECONDEmulator.h"
0014 #include "EventFilter/HGCalRawToDigi/interface/HGCalFrameGenerator.h"
0015 #include "EventFilter/HGCalRawToDigi/interface/HGCalRawDataPackingTools.h"
0016
0017 #include "CLHEP/Random/RandFlat.h"
0018 #include <iomanip>
0019
0020 namespace hgcal {
0021
0022
0023
0024
0025 template <typename T>
0026 void printWords(edm::MessageSender& os, const std::string& name, const std::vector<T> vec) {
0027 os << "Dump of the '" << name << "' words:\n";
0028 for (size_t i = 0; i < vec.size(); ++i)
0029 os << std::dec << std::setfill(' ') << std::setw(4) << i << ": 0x" << std::hex << std::setfill('0')
0030 << std::setw(sizeof(T) * 2) << vec.at(i) << "\n";
0031 }
0032
0033 static std::vector<uint64_t> to64bit(const std::vector<uint32_t>& in) {
0034 std::vector<uint64_t> out;
0035 for (size_t i = 0; i < in.size(); i += 2) {
0036 uint64_t word1 = (i < in.size()) ? in.at(i) : 0ul, word2 = (i + 1 < in.size()) ? in.at(i + 1) : 0ul;
0037 out.emplace_back(((word2 & 0xffffffff) << 32) | (word1 & 0xffffffff));
0038 }
0039 return out;
0040 }
0041
0042 static std::vector<uint64_t> to128bit(const std::vector<uint64_t>& in) {
0043 std::vector<uint64_t> out;
0044 for (size_t i = 0; i < in.size(); i += 2) {
0045 out.emplace_back(in.at(i));
0046 out.emplace_back((i + 1 < in.size()) ? in.at(i + 1) : 0u);
0047 }
0048 return out;
0049 }
0050
0051 HGCalFrameGenerator::HGCalFrameGenerator(const edm::ParameterSet& iConfig) {
0052 const auto slink_config = iConfig.getParameter<edm::ParameterSet>("slinkParams");
0053
0054 size_t econd_id = 0;
0055 std::vector<unsigned int> active_econds;
0056 for (const auto& econd : slink_config.getParameter<std::vector<edm::ParameterSet> >("ECONDs")) {
0057
0058 if (slink_config.getParameter<bool>("checkECONDsLimits")) {
0059 if (active_econds.size() > kMaxNumECONDs)
0060 throw cms::Exception("HGCalFrameGenerator")
0061 << "Too many active ECON-D set: " << active_econds.size() << " > " << kMaxNumECONDs << ".";
0062 if (econd_id >= kMaxNumECONDs)
0063 throw cms::Exception("HGCalFrameGenerator")
0064 << "Invalid ECON-D identifier: " << econd_id << " >= " << kMaxNumECONDs << ".";
0065 }
0066 if (econd.getParameter<bool>("active"))
0067 active_econds.emplace_back(econd_id);
0068
0069 econd_params_.insert(std::make_pair(econd_id, econd::EmulatorParameters(econd)));
0070 ++econd_id;
0071 }
0072
0073 slink_params_ = SlinkParameters{.active_econds = active_econds,
0074 .boe_marker = slink_config.getParameter<unsigned int>("boeMarker"),
0075 .eoe_marker = slink_config.getParameter<unsigned int>("eoeMarker"),
0076 .format_version = slink_config.getParameter<unsigned int>("formatVersion"),
0077 .num_capture_blocks = slink_config.getParameter<unsigned int>("numCaptureBlocks"),
0078 .store_header_trailer = slink_config.getParameter<bool>("storeHeaderTrailer")};
0079 }
0080
0081 edm::ParameterSetDescription HGCalFrameGenerator::description() {
0082 edm::ParameterSetDescription desc;
0083
0084 std::vector<edm::ParameterSet> econds_psets;
0085 for (size_t i = 0; i < 7; ++i)
0086 econds_psets.emplace_back();
0087
0088 edm::ParameterSetDescription slink_desc;
0089 slink_desc.addVPSet("ECONDs", econd::EmulatorParameters::description(), econds_psets)
0090 ->setComment("list of active ECON-Ds in S-link");
0091 slink_desc.add<unsigned int>("boeMarker", 0x55);
0092 slink_desc.add<unsigned int>("eoeMarker", 0xaa);
0093 slink_desc.add<unsigned int>("formatVersion", 3);
0094 slink_desc.add<unsigned int>("numCaptureBlocks", 1)
0095 ->setComment("number of capture blocks to emulate per S-link payload");
0096 slink_desc.add<bool>("checkECONDsLimits", true)->setComment("check the maximal number of ECON-Ds per S-link");
0097 slink_desc.add<bool>("storeHeaderTrailer", true)->setComment("also store the S-link header and trailer words");
0098 desc.add<edm::ParameterSetDescription>("slinkParams", slink_desc);
0099
0100 return desc;
0101 }
0102
0103 void HGCalFrameGenerator::setRandomEngine(CLHEP::HepRandomEngine& rng) { rng_ = &rng; }
0104
0105 void HGCalFrameGenerator::setEmulator(econd::Emulator& emul) { emul_ = &emul; }
0106
0107
0108
0109
0110
0111 HGCalFrameGenerator::HeaderBits HGCalFrameGenerator::generateStatusBits(unsigned int econd_id) const {
0112 if (!rng_)
0113 throw cms::Exception("HGCalFrameGenerator") << "Random number generator not initialised.";
0114 const auto& econd_params = econd_params_.at(econd_id);
0115
0116 return HeaderBits{
0117 .bitO = CLHEP::RandFlat::shoot(rng_) < econd_params.error_prob.bitO,
0118 .bitB = CLHEP::RandFlat::shoot(rng_) < econd_params.error_prob.bitB,
0119 .bitE = CLHEP::RandFlat::shoot(rng_) < econd_params.error_prob.bitE,
0120 .bitT = CLHEP::RandFlat::shoot(rng_) < econd_params.error_prob.bitT,
0121 .bitH = CLHEP::RandFlat::shoot(rng_) < econd_params.error_prob.bitH,
0122 .bitS = CLHEP::RandFlat::shoot(rng_) < econd_params.error_prob.bitS,
0123 };
0124 }
0125
0126 econd::ERxChannelEnable HGCalFrameGenerator::generateEnabledChannels(unsigned int econd_id) const {
0127 const auto& econd_params = econd_params_.at(econd_id);
0128 econd::ERxChannelEnable chmap(econd_params.num_channels_per_erx, false);
0129 for (size_t i = 0; i < chmap.size(); i++)
0130
0131 chmap[i] = CLHEP::RandFlat::shoot(rng_) <= econd_params.chan_surv_prob;
0132 return chmap;
0133 }
0134
0135 std::vector<uint32_t> HGCalFrameGenerator::generateERxData(
0136 unsigned int econd_id,
0137 const econd::ERxInput& input_event,
0138 std::vector<econd::ERxChannelEnable>& enabled_channels) const {
0139 const auto& econd_params = econd_params_.at(econd_id);
0140 std::vector<uint32_t> erx_data;
0141 enabled_channels.clear();
0142 for (const auto& jt : input_event) {
0143 const auto chmap =
0144 generateEnabledChannels(econd_id);
0145
0146
0147 uint8_t stat = 0b111 , hamming_check = 0;
0148 bool bit_e = false;
0149 auto erx_header = econd::eRxSubPacketHeader(stat, hamming_check, bit_e, jt.second.cm0, jt.second.cm1, chmap);
0150 erx_data.insert(erx_data.end(), erx_header.begin(), erx_header.end());
0151 if (jt.second.adc.size() < econd_params.num_channels_per_erx) {
0152 edm::LogError("HGCalFrameGenerator:generateERxData")
0153 << "Data multiplicity too low (" << jt.second.adc.size() << ") to emulate "
0154 << econd_params.num_channels_per_erx << " ECON-D channel(s).";
0155 continue;
0156 }
0157
0158 const auto erx_chan_data = econd::produceERxData(chmap,
0159 jt.second,
0160 true,
0161 true,
0162 true,
0163 econd_params.characterisation_mode);
0164 erx_data.insert(erx_data.end(), erx_chan_data.begin(), erx_chan_data.end());
0165 enabled_channels.emplace_back(chmap);
0166 }
0167 LogDebug("HGCalFrameGenerator").log([&erx_data](auto& log) { printWords(log, "erx", erx_data); });
0168 return erx_data;
0169 }
0170
0171 uint32_t HGCalFrameGenerator::computeCRC(const std::vector<uint32_t>& event_header) const {
0172 uint32_t crc = 0x12345678;
0173 return crc;
0174 }
0175
0176
0177
0178
0179
0180 std::vector<uint64_t> HGCalFrameGenerator::produceECONEvent(unsigned int econd_id, unsigned int cb_id) const {
0181 if (!emul_)
0182 throw cms::Exception("HGCalFrameGenerator")
0183 << "ECON-D emulator was not properly set to the frame generator. Please ensure you are calling the "
0184 "HGCalFrameGenerator::setEmulator method.";
0185
0186 std::vector<uint64_t> econd_event;
0187
0188 const auto event = emul_->next();
0189 const auto& econd_params = econd_params_.at(econd_id);
0190 auto header_bits = generateStatusBits(econd_id);
0191 std::vector<econd::ERxChannelEnable> enabled_ch_per_erx;
0192 auto erx_payload = generateERxData(econd_id, event.second, enabled_ch_per_erx);
0193
0194
0195 const uint8_t hamming = 0, rr = 0;
0196 auto econd_header =
0197 econd::eventPacketHeader(econd_params.header_marker,
0198 erx_payload.size() + 1 ,
0199 econd_params.passthrough_mode,
0200 econd_params.expected_mode,
0201
0202 (header_bits.bitH & 0x1) << 1 | (header_bits.bitT & 0x1),
0203 (header_bits.bitE & 0x1) << 2 | (header_bits.bitB & 0x1) << 1 |
0204 (header_bits.bitO & 0x1),
0205 econd_params.matching_ebo_numbers,
0206 econd_params.bo_truncated,
0207 hamming,
0208 std::get<1>(event.first),
0209 std::get<0>(event.first),
0210 std::get<2>(event.first),
0211 header_bits.bitS,
0212 rr);
0213 LogDebug("HGCalFrameGenerator").log([&econd_header](auto& log) { printWords(log, "econ-d header", econd_header); });
0214 auto econd_header_64bit = to64bit(econd_header);
0215 econd_event.insert(econd_event.end(), econd_header_64bit.begin(), econd_header_64bit.end());
0216 LogDebug("HGCalFrameGenerator") << econd_header.size()
0217 << " word(s) of event packet header prepend. New size of ECON frame: "
0218 << econd_event.size();
0219 const auto erx_payload_64bit = to64bit(erx_payload);
0220 econd_event.insert(econd_event.end(), erx_payload_64bit.begin(), erx_payload_64bit.end());
0221 LogDebug("HGCalFrameGenerator") << erx_payload.size() << " word(s) of eRx payloads inserted.";
0222
0223 std::vector<uint64_t> econd_footer;
0224 if (econd_params.add_econd_crc)
0225 econd_footer.emplace_back(computeCRC(econd_header));
0226 if (econd_params.add_idle_word) {
0227 const uint8_t buffer_status = 0, error_status = 0, reset_request = 0;
0228 econd_footer.emplace_back(
0229 econd::buildIdleWord(buffer_status, error_status, reset_request, econd_params.programmable_pattern));
0230 }
0231 econd_event.insert(econd_event.end(), econd_footer.begin(), econd_footer.end());
0232
0233 last_slink_emul_info_.captureBlockEmulatedInfo(cb_id).addECONDEmulatedInfo(
0234 econd_id,
0235 HGCalECONDEmulatorInfo(header_bits.bitO,
0236 header_bits.bitT,
0237 header_bits.bitE,
0238 header_bits.bitT,
0239 header_bits.bitH,
0240 header_bits.bitS,
0241 enabled_ch_per_erx));
0242 last_emul_event_ = event;
0243 return econd_event;
0244 }
0245
0246 std::vector<uint64_t> HGCalFrameGenerator::produceCaptureBlockEvent(unsigned int cb_id) const {
0247 std::vector<uint64_t> cb_event;
0248
0249 std::vector<backend::ECONDPacketStatus> econd_statuses(kMaxNumECONDs, backend::ECONDPacketStatus::InactiveECOND);
0250 for (const auto& econd : econd_params_) {
0251 const auto& econd_id = econd.first;
0252 if (!econd.second.active)
0253 continue;
0254 econd_statuses[econd_id] =
0255 backend::ECONDPacketStatus::Normal;
0256 const auto econd_payload = produceECONEvent(econd_id, cb_id);
0257 cb_event.insert(cb_event.end(), econd_payload.begin(), econd_payload.end());
0258 }
0259 const auto& eid = last_emul_event_.first;
0260 const uint64_t event_id = std::get<0>(eid), bx_id = std::get<1>(eid), orbit_id = std::get<2>(eid);
0261
0262 const auto l1a_header = to64bit(backend::buildCaptureBlockHeader(bx_id, event_id, orbit_id, econd_statuses));
0263 LogDebug("HGCalFrameGenerator").log([&l1a_header](auto& log) { printWords(log, "l1a", l1a_header); });
0264 cb_event.insert(cb_event.begin(), l1a_header.begin(), l1a_header.end());
0265 return to128bit(cb_event);
0266 }
0267
0268 std::vector<uint64_t> HGCalFrameGenerator::produceSlinkEvent(unsigned int fed_id) const {
0269 last_slink_emul_info_.clear();
0270
0271 std::vector<uint64_t> slink_event;
0272 for (unsigned int cb_id = 0; cb_id < slink_params_.num_capture_blocks; ++cb_id) {
0273 const auto cb_payload = produceCaptureBlockEvent(cb_id);
0274 slink_event.insert(slink_event.end(),
0275 cb_payload.begin(),
0276 cb_payload.end());
0277 }
0278
0279 if (slink_params_.store_header_trailer) {
0280
0281 const uint32_t content_id = backend::buildSlinkContentId(backend::SlinkEmulationFlag::Subsystem, 0, 0);
0282 const auto& eid = last_emul_event_.first;
0283 const uint64_t event_id = std::get<0>(eid), bx_id = std::get<1>(eid), orbit_id = std::get<2>(eid);
0284 const auto slink_header = to128bit(to64bit(backend::buildSlinkHeader(
0285 slink_params_.boe_marker, slink_params_.format_version, event_id, content_id, fed_id)));
0286 slink_event.insert(slink_event.begin(), slink_header.begin(), slink_header.end());
0287
0288
0289 const bool fed_crc_err = false, slinkrocket_crc_err = false, source_id_err = false, sync_lost = false,
0290 fragment_trunc = false;
0291 const uint16_t status =
0292 backend::buildSlinkRocketStatus(fed_crc_err, slinkrocket_crc_err, source_id_err, sync_lost, fragment_trunc);
0293
0294 const uint16_t daq_crc = 0, crc = 0;
0295 const uint32_t event_length = slink_event.size() - slink_header.size() - 1;
0296 const auto slink_trailer = to128bit(to64bit(
0297 backend::buildSlinkTrailer(slink_params_.eoe_marker, daq_crc, event_length, bx_id, orbit_id, crc, status)));
0298 slink_event.insert(slink_event.end(), slink_trailer.begin(), slink_trailer.end());
0299
0300 LogDebug("HGCalFrameGenerator").log([&slink_header, &slink_trailer](auto& log) {
0301 printWords(log, "slink header", slink_header);
0302 log << "\n";
0303 printWords(log, "slink trailer", slink_trailer);
0304 });
0305 }
0306
0307 return to128bit(slink_event);
0308 }
0309 }