CMS 3D CMS Logo

HGCalFrameGenerator.cc
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * This is a part of HGCAL offline software.
4  * Authors:
5  * Laurent Forthomme, CERN
6  *
7  ****************************************************************************/
8 
12 
16 
17 #include "CLHEP/Random/RandFlat.h"
18 #include <iomanip>
19 
20 namespace hgcal {
21  //--------------------------------------------------
22  // bit-casting utilities
23  //--------------------------------------------------
24 
25  template <typename T>
26  void printWords(edm::MessageSender& os, const std::string& name, const std::vector<T> vec) {
27  os << "Dump of the '" << name << "' words:\n";
28  for (size_t i = 0; i < vec.size(); ++i)
29  os << std::dec << std::setfill(' ') << std::setw(4) << i << ": 0x" << std::hex << std::setfill('0')
30  << std::setw(sizeof(T) * 2) << vec.at(i) << "\n";
31  }
32 
33  static std::vector<uint64_t> to64bit(const std::vector<uint32_t>& in) {
34  std::vector<uint64_t> out;
35  for (size_t i = 0; i < in.size(); i += 2) {
36  uint64_t word1 = (i < in.size()) ? in.at(i) : 0ul, word2 = (i + 1 < in.size()) ? in.at(i + 1) : 0ul;
37  out.emplace_back(((word2 & 0xffffffff) << 32) | (word1 & 0xffffffff));
38  }
39  return out;
40  }
41 
42  static std::vector<uint64_t> to128bit(const std::vector<uint64_t>& in) {
43  std::vector<uint64_t> out;
44  for (size_t i = 0; i < in.size(); i += 2) {
45  out.emplace_back(in.at(i));
46  out.emplace_back((i + 1 < in.size()) ? in.at(i + 1) : 0u);
47  }
48  return out;
49  }
50 
52  const auto slink_config = iConfig.getParameter<edm::ParameterSet>("slinkParams");
53 
54  size_t econd_id = 0;
55  std::vector<unsigned int> active_econds;
56  for (const auto& econd : slink_config.getParameter<std::vector<edm::ParameterSet> >("ECONDs")) {
57  // a bit of user input validation
58  if (slink_config.getParameter<bool>("checkECONDsLimits")) {
59  if (active_econds.size() > kMaxNumECONDs)
60  throw cms::Exception("HGCalFrameGenerator")
61  << "Too many active ECON-D set: " << active_econds.size() << " > " << kMaxNumECONDs << ".";
62  if (econd_id >= kMaxNumECONDs)
63  throw cms::Exception("HGCalFrameGenerator")
64  << "Invalid ECON-D identifier: " << econd_id << " >= " << kMaxNumECONDs << ".";
65  }
66  if (econd.getParameter<bool>("active"))
67  active_econds.emplace_back(econd_id);
68 
69  econd_params_.insert(std::make_pair(econd_id, econd::EmulatorParameters(econd)));
70  ++econd_id;
71  }
72 
73  slink_params_ = SlinkParameters{.active_econds = active_econds,
74  .boe_marker = slink_config.getParameter<unsigned int>("boeMarker"),
75  .eoe_marker = slink_config.getParameter<unsigned int>("eoeMarker"),
76  .format_version = slink_config.getParameter<unsigned int>("formatVersion"),
77  .num_capture_blocks = slink_config.getParameter<unsigned int>("numCaptureBlocks"),
78  .store_header_trailer = slink_config.getParameter<bool>("storeHeaderTrailer")};
79  }
80 
83 
84  std::vector<edm::ParameterSet> econds_psets;
85  for (size_t i = 0; i < 7; ++i)
86  econds_psets.emplace_back();
87 
89  slink_desc.addVPSet("ECONDs", econd::EmulatorParameters::description(), econds_psets)
90  ->setComment("list of active ECON-Ds in S-link");
91  slink_desc.add<unsigned int>("boeMarker", 0x55);
92  slink_desc.add<unsigned int>("eoeMarker", 0xaa);
93  slink_desc.add<unsigned int>("formatVersion", 3);
94  slink_desc.add<unsigned int>("numCaptureBlocks", 1)
95  ->setComment("number of capture blocks to emulate per S-link payload");
96  slink_desc.add<bool>("checkECONDsLimits", true)->setComment("check the maximal number of ECON-Ds per S-link");
97  slink_desc.add<bool>("storeHeaderTrailer", true)->setComment("also store the S-link header and trailer words");
98  desc.add<edm::ParameterSetDescription>("slinkParams", slink_desc);
99 
100  return desc;
101  }
102 
103  void HGCalFrameGenerator::setRandomEngine(CLHEP::HepRandomEngine& rng) { rng_ = &rng; }
104 
106 
107  //--------------------------------------------------
108  // emulation part
109  //--------------------------------------------------
110 
112  if (!rng_)
113  throw cms::Exception("HGCalFrameGenerator") << "Random number generator not initialised.";
114  const auto& econd_params = econd_params_.at(econd_id);
115  // first sample on header status bits
116  return HeaderBits{
117  .bitO = CLHEP::RandFlat::shoot(rng_) < econd_params.error_prob.bitO,
118  .bitB = CLHEP::RandFlat::shoot(rng_) < econd_params.error_prob.bitB,
119  .bitE = CLHEP::RandFlat::shoot(rng_) < econd_params.error_prob.bitE,
120  .bitT = CLHEP::RandFlat::shoot(rng_) < econd_params.error_prob.bitT,
121  .bitH = CLHEP::RandFlat::shoot(rng_) < econd_params.error_prob.bitH,
122  .bitS = CLHEP::RandFlat::shoot(rng_) < econd_params.error_prob.bitS,
123  };
124  }
125 
127  const auto& econd_params = econd_params_.at(econd_id);
128  econd::ERxChannelEnable chmap(econd_params.num_channels_per_erx, false);
129  for (size_t i = 0; i < chmap.size(); i++)
130  // randomly choosing the channels to be shot at
131  chmap[i] = CLHEP::RandFlat::shoot(rng_) <= econd_params.chan_surv_prob;
132  return chmap;
133  }
134 
136  unsigned int econd_id,
137  const econd::ERxInput& input_event,
138  std::vector<econd::ERxChannelEnable>& enabled_channels) const {
139  const auto& econd_params = econd_params_.at(econd_id);
140  std::vector<uint32_t> erx_data;
141  enabled_channels.clear();
142  for (const auto& jt : input_event) { // one per eRx
143  const auto chmap =
144  generateEnabledChannels(econd_id); // generate a list of probable channels to be filled with emulated content
145 
146  // insert eRx header (common mode, channels map, ...)
147  uint8_t stat = 0b111 /*possibly emulate*/, hamming_check = 0;
148  bool bit_e = false; // did unmasked stat error bits associated with the eRx cause the sub-packet to be supressed?
149  auto erx_header = econd::eRxSubPacketHeader(stat, hamming_check, bit_e, jt.second.cm0, jt.second.cm1, chmap);
150  erx_data.insert(erx_data.end(), erx_header.begin(), erx_header.end());
151  if (jt.second.adc.size() < econd_params.num_channels_per_erx) {
152  edm::LogError("HGCalFrameGenerator:generateERxData")
153  << "Data multiplicity too low (" << jt.second.adc.size() << ") to emulate "
154  << econd_params.num_channels_per_erx << " ECON-D channel(s).";
155  continue;
156  }
157  // insert eRx payloads (integrating all readout channels)
158  const auto erx_chan_data = econd::produceERxData(chmap,
159  jt.second,
160  true, // passZS
161  true, // passZSm1
162  true, // hasToA
163  econd_params.characterisation_mode);
164  erx_data.insert(erx_data.end(), erx_chan_data.begin(), erx_chan_data.end());
165  enabled_channels.emplace_back(chmap);
166  }
167  LogDebug("HGCalFrameGenerator").log([&erx_data](auto& log) { printWords(log, "erx", erx_data); });
168  return erx_data;
169  }
170 
171  uint32_t HGCalFrameGenerator::computeCRC(const std::vector<uint32_t>& event_header) const {
172  uint32_t crc = 0x12345678; //TODO: implement 32-bit Bluetooth CRC in the future
173  return crc;
174  }
175 
176  //--------------------------------------------------
177  // payload creation utilities
178  //--------------------------------------------------
179 
180  std::vector<uint64_t> HGCalFrameGenerator::produceECONEvent(unsigned int econd_id, unsigned int cb_id) const {
181  if (!emul_)
182  throw cms::Exception("HGCalFrameGenerator")
183  << "ECON-D emulator was not properly set to the frame generator. Please ensure you are calling the "
184  "HGCalFrameGenerator::setEmulator method.";
185 
186  std::vector<uint64_t> econd_event;
187 
188  const auto event = emul_->next();
189  const auto& econd_params = econd_params_.at(econd_id);
190  auto header_bits = generateStatusBits(econd_id);
191  std::vector<econd::ERxChannelEnable> enabled_ch_per_erx;
192  auto erx_payload = generateERxData(econd_id, event.second, enabled_ch_per_erx);
193 
194  // ECON-D event content was just created, now prepend packet header
195  const uint8_t hamming = 0, rr = 0;
196  auto econd_header =
197  econd::eventPacketHeader(econd_params.header_marker,
198  erx_payload.size() + 1 /*CRC*/,
199  econd_params.passthrough_mode,
200  econd_params.expected_mode,
201  // HGCROC Event reco status across all active eRx E-B-O:
202  (header_bits.bitH & 0x1) << 1 | (header_bits.bitT & 0x1), // HDR/TRL numbers
203  (header_bits.bitE & 0x1) << 2 | (header_bits.bitB & 0x1) << 1 |
204  (header_bits.bitO & 0x1), // Event/BX/Orbit numbers
205  econd_params.matching_ebo_numbers,
206  econd_params.bo_truncated,
207  hamming, // Hamming for event header
208  std::get<1>(event.first), // BX
209  std::get<0>(event.first), // event id (L1A)
210  std::get<2>(event.first), // orbit
211  header_bits.bitS, // OR of "Stat" bits for all active eRx
212  rr);
213  LogDebug("HGCalFrameGenerator").log([&econd_header](auto& log) { printWords(log, "econ-d header", econd_header); });
214  auto econd_header_64bit = to64bit(econd_header);
215  econd_event.insert(econd_event.end(), econd_header_64bit.begin(), econd_header_64bit.end());
216  LogDebug("HGCalFrameGenerator") << econd_header.size()
217  << " word(s) of event packet header prepend. New size of ECON frame: "
218  << econd_event.size();
219  const auto erx_payload_64bit = to64bit(erx_payload);
220  econd_event.insert(econd_event.end(), erx_payload_64bit.begin(), erx_payload_64bit.end());
221  LogDebug("HGCalFrameGenerator") << erx_payload.size() << " word(s) of eRx payloads inserted.";
222 
223  std::vector<uint64_t> econd_footer;
224  if (econd_params.add_econd_crc)
225  econd_footer.emplace_back(computeCRC(econd_header));
226  if (econd_params.add_idle_word) {
227  const uint8_t buffer_status = 0, error_status = 0, reset_request = 0;
228  econd_footer.emplace_back(
229  econd::buildIdleWord(buffer_status, error_status, reset_request, econd_params.programmable_pattern));
230  }
231  econd_event.insert(econd_event.end(), econd_footer.begin(), econd_footer.end());
232  // bookkeeping of last event + metadata
234  econd_id,
235  HGCalECONDEmulatorInfo(header_bits.bitO,
236  header_bits.bitT,
237  header_bits.bitE,
238  header_bits.bitT,
239  header_bits.bitH,
240  header_bits.bitS,
241  enabled_ch_per_erx));
243  return econd_event;
244  }
245 
246  std::vector<uint64_t> HGCalFrameGenerator::produceCaptureBlockEvent(unsigned int cb_id) const {
247  std::vector<uint64_t> cb_event;
248  // build all ECON-Ds payloads and add them to the capture block payload
249  std::vector<backend::ECONDPacketStatus> econd_statuses(kMaxNumECONDs, backend::ECONDPacketStatus::InactiveECOND);
250  for (const auto& econd : econd_params_) { // for each ECON-D payload to be emulated
251  const auto& econd_id = econd.first;
252  if (!econd.second.active)
253  continue; // status is already inactive
254  econd_statuses[econd_id] =
255  backend::ECONDPacketStatus::Normal; //TODO: also implement/emulate other ECON-D packet issues
256  const auto econd_payload = produceECONEvent(econd_id, cb_id);
257  cb_event.insert(cb_event.end(), econd_payload.begin(), econd_payload.end());
258  }
259  const auto& eid = last_emul_event_.first;
260  const uint64_t event_id = std::get<0>(eid), bx_id = std::get<1>(eid), orbit_id = std::get<2>(eid);
261  // prepend the header to the capture block payload
262  const auto l1a_header = to64bit(backend::buildCaptureBlockHeader(bx_id, event_id, orbit_id, econd_statuses));
263  LogDebug("HGCalFrameGenerator").log([&l1a_header](auto& log) { printWords(log, "l1a", l1a_header); });
264  cb_event.insert(cb_event.begin(), l1a_header.begin(), l1a_header.end());
265  return to128bit(cb_event);
266  }
267 
268  std::vector<uint64_t> HGCalFrameGenerator::produceSlinkEvent(unsigned int fed_id) const {
269  last_slink_emul_info_.clear(); // clear the metadata of the latest emulated S-link payload
270 
271  std::vector<uint64_t> slink_event; // prepare the output S-link payload (will be "converted" to 128-bit)
272  for (unsigned int cb_id = 0; cb_id < slink_params_.num_capture_blocks; ++cb_id) {
273  const auto cb_payload = produceCaptureBlockEvent(cb_id);
274  slink_event.insert(slink_event.end(),
275  cb_payload.begin(),
276  cb_payload.end()); // concatenate the capture block to the full S-link payload
277  }
278 
280  // build the S-link header words
281  const uint32_t content_id = backend::buildSlinkContentId(backend::SlinkEmulationFlag::Subsystem, 0, 0);
282  const auto& eid = last_emul_event_.first;
283  const uint64_t event_id = std::get<0>(eid), bx_id = std::get<1>(eid), orbit_id = std::get<2>(eid);
284  const auto slink_header = to128bit(to64bit(backend::buildSlinkHeader(
285  slink_params_.boe_marker, slink_params_.format_version, event_id, content_id, fed_id)));
286  slink_event.insert(slink_event.begin(), slink_header.begin(), slink_header.end()); // prepend S-link header
287 
288  // build the S-link trailer words
289  const bool fed_crc_err = false, slinkrocket_crc_err = false, source_id_err = false, sync_lost = false,
290  fragment_trunc = false;
291  const uint16_t status =
292  backend::buildSlinkRocketStatus(fed_crc_err, slinkrocket_crc_err, source_id_err, sync_lost, fragment_trunc);
293 
294  const uint16_t daq_crc = 0, crc = 0;
295  const uint32_t event_length = slink_event.size() - slink_header.size() - 1;
296  const auto slink_trailer = to128bit(to64bit(
297  backend::buildSlinkTrailer(slink_params_.eoe_marker, daq_crc, event_length, bx_id, orbit_id, crc, status)));
298  slink_event.insert(slink_event.end(), slink_trailer.begin(), slink_trailer.end()); // append S-link trailer
299 
300  LogDebug("HGCalFrameGenerator").log([&slink_header, &slink_trailer](auto& log) {
301  printWords(log, "slink header", slink_header);
302  log << "\n";
303  printWords(log, "slink trailer", slink_trailer);
304  });
305  }
306 
307  return to128bit(slink_event);
308  }
309 } // namespace hgcal
void setComment(std::string const &value)
T getParameter(std::string const &) const
Definition: ParameterSet.h:303
econd::ECONDInput last_emul_event_
ParameterDescriptionBase * addVPSet(U const &iLabel, ParameterSetDescription const &validator, std::vector< ParameterSet > const &defaults)
std::map< unsigned int, econd::EmulatorParameters > econd_params_
std::vector< uint64_t > produceECONEvent(unsigned int econd_id, unsigned int cb_id=0) const
void setEmulator(econd::Emulator &)
Set the emulation source for ECON-D frames.
std::vector< uint32_t > produceERxData(const ERxChannelEnable &, const ERxData &, bool passZS, bool passZSm1, bool hasToA, bool char_mode)
std::vector< uint32_t > buildCaptureBlockHeader(uint32_t bunch_crossing, uint32_t event_counter, uint32_t orbit_counter, const std::vector< ECONDPacketStatus > &econd_statuses)
std::vector< uint32_t > eRxSubPacketHeader(uint8_t stat, uint8_t ham, bool bitE, uint16_t common_mode0, uint16_t common_mode1, const ERxChannelEnable &channel_enable)
HeaderBits generateStatusBits(unsigned int) const
CLHEP::HepRandomEngine * rng_
std::vector< uint64_t > produceCaptureBlockEvent(unsigned int cb_id) const
std::map< ERxId_t, ERxData > ERxInput
eRx data maps
Definition: SlinkTypes.h:29
uint32_t buildSlinkContentId(SlinkEmulationFlag, uint8_t l1a_subtype, uint16_t l1a_fragment_cnt)
std::vector< uint32_t > generateERxData(unsigned int, const econd::ERxInput &, std::vector< econd::ERxChannelEnable > &) const
HGCalCaptureBlockEmulatorInfo & captureBlockEmulatedInfo(unsigned int)
Log< level::Error, false > LogError
econd::ERxChannelEnable generateEnabledChannels(unsigned int) const
std::vector< bool > ERxChannelEnable
list of channels enabled in eRx
Definition: SlinkTypes.h:38
std::vector< uint64_t > produceSlinkEvent(unsigned int fed_id) const
Produce a S-link event from an emulated event.
Pure virtual base class for a ECON-D event emulator implementation.
static std::vector< uint64_t > to128bit(const std::vector< uint64_t > &in)
static edm::ParameterSetDescription description()
List of S-link operational parameters for emulation.
ParameterDescriptionBase * add(U const &iLabel, T const &value)
std::vector< uint32_t > buildSlinkHeader(uint8_t boe, uint8_t v, uint64_t global_event_id, uint32_t content_id, uint32_t fed_id)
uint32_t computeCRC(const std::vector< uint32_t > &) const
32bit CRC
uint32_t buildIdleWord(uint8_t bufStat, uint8_t err, uint8_t rr, uint32_t progPattern)
HGCalSlinkEmulatorInfo last_slink_emul_info_
virtual ECONDInput next()=0
Fetch the next ECON-D event.
uint16_t buildSlinkRocketStatus(bool fed_crc_err, bool slinkrocket_crc_err, bool source_id_err, bool sync_lost, bool fragment_trunc)
static edm::ParameterSetDescription description()
unsigned long long uint64_t
Definition: Time.h:13
void addECONDEmulatedInfo(unsigned int, const HGCalECONDEmulatorInfo &)
void setRandomEngine(CLHEP::HepRandomEngine &rng)
Set the random number generator engine.
std::vector< uint32_t > buildSlinkTrailer(uint8_t eoe, uint16_t daqcrc, uint32_t event_length, uint16_t bxid, uint32_t orbit_id, uint16_t crc, uint16_t status)
static std::vector< uint64_t > to64bit(const std::vector< uint32_t > &in)
HGCalFrameGenerator(const edm::ParameterSet &)
void printWords(edm::MessageSender &os, const std::string &name, const std::vector< T > vec)
std::vector< uint32_t > eventPacketHeader(uint16_t header, uint16_t payload, bool bitP, bool bitE, uint8_t ht, uint8_t ebo, bool bitM, bool bitT, uint8_t hamming, uint16_t bx, uint16_t l1a, uint8_t orb, bool bitS, uint8_t RR)
static constexpr size_t kMaxNumECONDs
long double T
Definition: event.py:1
#define LogDebug(id)