Orion
high-rate readout
fragformat.hpp
Go to the documentation of this file.
1 // ╭─╮╭─╴╷╭─╮┌─╮
2 // ╰─╯╵ ╵╰─╯╵ ╵
8 #pragma once
9 
10 #include <cassert>
11 #include <vector>
12 #include <span>
13 
14 #include "itk/logger.hpp"
15 #include "fragheader.hpp"
16 
17 namespace itk::fragment {
18 
19 extern itk::Logger log;
20 
21 
22 FelixPacket make_packet(uint64_t fid, std::span<const uint64_t> data, uint8_t status) {
23  FelixPacket pkt;
24 
25  pkt.fid = fid;
26  pkt.time = 0;
27  pkt.data = reinterpret_cast<const uint8_t*>(data.data());
28  pkt.size = data.size()*8;
29  pkt.status = status;
30 
31  return pkt;
32 }
33 
34 
35 namespace ROD { // Read-Out Driver
36 
41  struct PayloadData {
42  std::vector<uint32_t> data;
43  std::vector<uint32_t> status;
44 
45  inline uint32_t get_data_size() { return data.size(); }
46 
47  inline uint32_t get_status_size() { return status.size(); }
48 
49  template<typename T>
50  void write(T& out) {
51  out.write(data);
52  out.write(status);
53  }
54 }; // PayloadData
55 
56 
62 public:
63  std::vector<FelixPacket> packets;
64  std::vector<uint32_t> status;
65 
66  uint64_t start_time = 0; // timestamp from ROB
67  uint32_t source_id = 0; // source id from ROB
68 
69  inline uint32_t get_data_size() {
70  uint32_t size = 0;
71  for (auto& packet : packets) size += get_packet_size(packet);
72  return size;
73  }
74 
75  inline uint32_t get_status_size() { return status.size(); }
76 
77  template<typename T>
78  inline void write(T& out) {
79  log.debug("PacketPayload.data");
80  write_packets(out);
81  log.debug("PacketPayload.status");
82  out.write(status);
83  }
84 
85  template<typename T>
86  void write(T& out, FelixPacket& packet) {
87 
88  FLX::Header header;
89 
90  header.format_type = 0x0;
91 
92  header.felix_status = packet.status;
93 
94  header.elink_id = (packet.fid >> 16); // Vlink[1].ElinkID[19]
95  // log.debug("packet.fid: 0x{:016x} | link_id: 0x{:x}", packet.fid, uint32_t(header.elink_id));
96  auto felix_source = packet.fid >> 36;
97  if (felix_source != source_id) {
98  // flag wrong felix device
99  }
100 
101  header.timestamp = packet.time - start_time;
102 
103  auto data32 = reinterpret_cast<const uint32_t*>(packet.data);
104  auto packet_size = packet.size;
105 
106  while (packet_size) {
107  uint32_t size32;
108  if (packet_size < FLX::MAX_DATA32_SIZE*4) {
109  size32 = (packet_size + 3)/4;
110  header.padding_bytes = size32*4 - packet_size;
111  packet_size = 0;
112  // log.debug("padding_bytes: {}", uint8_t(header.padding_bytes));
113  } else {
114  size32 = FLX::MAX_DATA32_SIZE;
115  header.padding_bytes = 0;
116  packet_size -= FLX::MAX_DATA32_SIZE*4;
117  }
118 
119  header.fragment_size = size32 + FLX::HEADER_SIZE;
120  out.write_rec(header);
121  out.write(data32, size32);
122  data32 += size32;
123  }
124  }
125 
126  inline uint32_t get_packet_size(FelixPacket& packet) {
127  return sizeof(FLX::Header)/4 + (packet.size + 3)/4;
128  }
129 
130  template<typename T>
131  void write_packets(T& out) {
132  for (auto& packet : packets) write(out, packet);
133  }
134 
135 }; // PayloadPackets
136 
137 
142 template<typename Payload>
143 class Fragment {
144 public:
145  Header header;
146  Payload payload;
147  Trailer trailer;
148 
149  inline uint32_t get_size() {
150  return ROD::HEADER_SIZE + ROD::TRAILER_SIZE +
151  payload.get_data_size() + payload.get_status_size();
152  }
153 
154  template<typename T>
155  void write(T& out) {
156 
157  log.debug("ROD.Header");
158  out.write_rec(header);
159 
160  log.debug("ROD.Payload");
161  payload.write(out);
162 
163  trailer.data_size = payload.get_data_size();
164  trailer.status_size = payload.get_status_size();
165  trailer.status_pos = 1; // 1 - data before status
166 
167  log.debug("ROD.Trailer");
168  out.write_rec(trailer);
169  }
170 }; // Fragment
171 
172 } // ROD
173 
174 
175 namespace ROB { // Read-Out Buffer
176 
181 template<int n, typename RODFragment>
182 class Fragment {
183 public:
184 
185  ROB::Header<n> header;
186  RODFragment rod;
187 
188  uint32_t get_size() {
189  uint32_t frag_size = header.HEADER_SIZE + rod.get_size();
190  if (header.checksum_type) frag_size += 1;
191  return frag_size;
192  }
193 
194  template<typename T>
195  void write(T& out) {
196  auto start_pos = out.get_size();
197  // header.checksum_type = ROB::CHECKSUM_NONE;
198  header.checksum_type = CHECKSUM_CRC16;
199  uint32_t subdet_id = 0x16;
200  uint32_t module_id = 0x0001;
201  header.source_id = subdet_id << 16 | module_id;
202  header.fragment_size = get_size();
203 
204  // writing ROB fragment
205 
206  log.debug("ROB.Header");
207  out.write_rec(header); // writing ROB header
208 
209  rod.write(out); // writing ROD fragment
210 
211  if (header.checksum_type) {
212  uint32_t checksum = calc_checksum(header.checksum_type);
213  log.debug("ROB.CheckSum: 0x{:08x}", checksum);
214  out.write(checksum); // writing checksum
215  }
216  auto end_pos = out.get_size();
217  assert(end_pos - start_pos == header.fragment_size);
218  if (end_pos - start_pos != header.fragment_size) {
219  log.error("start: {}, end: {}, frag_size: {}", start_pos, end_pos, int(header.fragment_size));
220  }
221  }
222 
223  uint32_t checksum_CRC16() {
224  return 0x11223344;
225  }
226 
227  uint32_t checksum_Adler32() {
228  return 0x55667788;
229  }
230 
231  uint32_t calc_checksum(uint32_t type) {
232  if (type == CHECKSUM_CRC16) return checksum_CRC16();
233  if (type == CHECKSUM_ADLER32) return checksum_Adler32();
234  return 0xFFFFFFFF;
235  }
236 
237 }; // Fragment
238 
239 } // ROB
240 
241 
242 
243 class FragWriter {
244 public:
245  FragWriter() = default;
246 
247  inline size_t get_size() {
248  return frag.size();
249  }
250 
251  inline void write(uint32_t data) {
252  log.trace("{:3}: write: 0x{:08x}", frag.size(), data);
253  frag.push_back(data);
254  }
255 
256  inline void write(const uint32_t* data, size_t size) {
257  for (uint32_t i = 0; i < size; i++) write(data[i]);
258  }
259 
260  inline void write(const void* ptr, size_t size) {
261  auto buff = reinterpret_cast<const uint32_t*>(ptr);
262  write(buff, size);
263  }
264 
265  inline void write(const std::span<const uint32_t> buff) {
266  write(buff.data(), buff.size());
267  }
268 
269  template<class T>
270  inline void write_rec(const T& rec) {
271  assert(sizeof(rec) % 4 == 0);
272  auto ptr = reinterpret_cast<const uint32_t*>(&rec);
273  write(ptr, sizeof(rec)/4);
274  }
275 
276  std::vector<uint32_t> frag;
277 
278 }; // FragWriter
279 
280 
281 
282 
283 template<typename DataCallback>
284 class FragReader {
285 public:
286  DataCallback& cb_data;
287 
288  FragReader(DataCallback& cb_data) : cb_data(cb_data) {}
289 
290  inline uint32_t read() {
291  // log.trace("read: 0x{:08x}", data);
292  // frag.push_back(data);
293  return 0;
294  }
295 
296  template<int n>
297  inline std::array<uint32_t, n> read() {
298  return {};
299  }
300 
301  template<typename T>
302  void read_rob(T& buff) {
303  // log.trace("read ROB | frag_size: {}", buff.size());
304  if (buff.size() < ROB::BASE_HEADER_SIZE) {
305  // Too short ROB fragment
306  }
307  if (buff[0] != ROB::HEADER_MARKER) {
308  // incorrect ROB marker
309  }
310 
311  assert(buff.size() > ROB::BASE_HEADER_SIZE);
312  assert(buff[0] == ROB::HEADER_MARKER);
313 
314  // ROB::BaseHeader& header = *reinterpret_cast<ROB::BaseHeader*>(buff.data());
315  ROB::BaseHeader& header = *reinterpret_cast<ROB::BaseHeader*>(buff.data());
316 
317  // Header sizes
318  auto generic_size = ROD::HEADER_SIZE + header.status_size + 1;
319 
320  // Fragment consistency should be properly handled beforehand.
321  // These assertions are added just to ensure that fragment is consistent.
322 
323  assert(header.fragment_size <= buff.size() && "Truncated fragment");
324  assert(header.header_size <= header.fragment_size && "Inconsistent fragment and header sizes");
325  assert(generic_size <= header.header_size && "Incorrect header sizes");
326 
327  auto checksum_type = header.status[header.status_size];
328  auto checksum_size = (checksum_type ? 1 : 0);
329 
330  auto specific_size = header.header_size - generic_size;
331 
332  std::span<const uint32_t> specific {
333  buff.data() + generic_size,
334  header.header_size - generic_size
335  };
336 
337  std::span<const uint32_t> payload {
338  buff.data() + header.header_size,
339  header.fragment_size - header.header_size - checksum_size
340  };
341 
342  read_rod(payload);
343  }
344 
345  template<typename T>
346  void read_rod(T& buff) {
347  // log.trace("read ROD | frag_size: {}", buff.size());
348  if (buff.size() < ROD::HEADER_SIZE) {
349  // Too short ROD fragment
350  }
351  if (buff[0] != ROD::HEADER_MARKER) {
352  // Incorrect ROD marker
353  }
354 
355  assert(buff.size() >= ROD::HEADER_SIZE);
356  assert(buff[0] == ROD::HEADER_MARKER);
357 
358  auto& header = *reinterpret_cast<const ROD::Header*>(buff.data());
359 
360  auto& trailer = *reinterpret_cast<const ROD::Trailer*>(
361  (buff.data() + buff.size() - ROD::TRAILER_SIZE));
362 
363  std::span<const uint32_t> data {
364  buff.data() + ROD::HEADER_SIZE + (trailer.status_pos & 0x1 ? 0 : trailer.status_size),
365  trailer.data_size
366  };
367 
368  std::span<const uint32_t> status {
369  buff.data() + ROD::HEADER_SIZE + (trailer.status_pos & 0x1 ? trailer.data_size : 0),
370  trailer.status_size
371  };
372 
373  read_packets(data);
374  }
375 
376  template<typename T>
377  void read_packets(T& buff) {
378 
379  // log.trace("read packets | size: {}", buff.size());
380  // for (auto data : buff) log.trace(" 0x{:08x}", data);
381 
382  auto buff_data = buff.data();
383  int buff_size = buff.size();
384 
385  while (buff_size > 0) {
386  assert(buff_size >= FLX::HEADER_SIZE);
387 
388  uint64_t rob_fid = 0x1000000000000000L;
389 
390  const FLX::Header& header = *reinterpret_cast<const FLX::Header*>(buff_data);
391 
392  if (header.fragment_size < FLX::HEADER_SIZE) {
393  log.error("too small fragment size: {}", header.fragment_size);
394  break;
395  }
396 
397  // log.info("buff_size: {}, fragment_size: {}", buff_size, int(header.fragment_size));
398 
399  auto data = reinterpret_cast<const uint8_t*>(buff_data + FLX::HEADER_SIZE);
400  uint32_t size = (header.fragment_size - FLX::HEADER_SIZE)*4 - header.padding_bytes;
401 
402  uint64_t fid = rob_fid | (uint64_t(header.elink_id) << 16);
403  uint8_t status = header.felix_status;
404 
405  cb_data.on_data(fid, data, size, status);
406 
407  buff_data += header.fragment_size;
408  buff_size -= header.fragment_size;
409  }
410  }
411 
412  std::vector<uint32_t> frag;
413 
414 }; // FragReader
415 
416 
417 } // itk::fragment
Definition: fragformat.hpp:284
Definition: fragformat.hpp:243
Definition: fragformat.hpp:182
Definition: fragformat.hpp:143
Definition: fragformat.hpp:61
Logger class definition, wrapper around CoreLogger, adds templated methods for different logging leve...
Definition: logger.hpp:108
void error(fmt::format_string< Args... > fmt, Args &&...args)
Logs a message with error level.
Definition: logger.hpp:164
void debug(fmt::format_string< Args... > fmt, Args &&...args)
Logs a message with debug level.
Definition: logger.hpp:140
void trace(fmt::format_string< Args... > fmt, Args &&...args)
Logs a message with trace level.
Definition: logger.hpp:132
Fragment headers.
uint32_t checksum_type
status elements
Definition: fragheader.hpp:10
@ CHECKSUM_CRC16
CRC-16/CCITT checksum.
Definition: fragheader.hpp:192
@ CHECKSUM_ADLER32
Adler-32 checksum.
Definition: fragheader.hpp:195
uint32_t status[n]
number of status elements
Definition: fragheader.hpp:9
uint16_t size
Definition: fragheader.hpp:5
uint32_t source_id
format version major[16].minor[16]
Definition: fragheader.hpp:3
Logger definitions.
Definition: fragheader.hpp:87
uint32_t timestamp
SWROD status.
Definition: fragheader.hpp:101
uint32_t fragment_size
Definition: fragheader.hpp:95
uint8_t format_type
Virtual[1].ElinkID[19].
Definition: fragheader.hpp:99
uint8_t felix_status
bytes added to align to word
Definition: fragheader.hpp:97
uint8_t padding_bytes
size of fragment in words
Definition: fragheader.hpp:96
uint32_t elink_id
FELIX status.
Definition: fragheader.hpp:98
Felix Packet structure.
Definition: fragheader.hpp:26
uint64_t time
FELIX ID.
Definition: fragheader.hpp:28
const uint8_t * data
timestamp in BC
Definition: fragheader.hpp:29
Definition: fragheader.hpp:206
uint32_t fragment_size
header marker
Definition: fragheader.hpp:208
uint32_t status[0]
number of status elements
Definition: fragheader.hpp:213
uint32_t status_size
origin of the fragment [sub-detector id, module id]
Definition: fragheader.hpp:212
uint32_t header_size
size of fragment in words
Definition: fragheader.hpp:209
Definition: fragheader.hpp:225
uint32_t fragment_size
header marker
Definition: fragheader.hpp:230
static constexpr uint32_t HEADER_SIZE
ROB header size.
Definition: fragheader.hpp:227
uint32_t checksum_type
status elements
Definition: fragheader.hpp:236
uint32_t source_id
format version major[16].minor[16]
Definition: fragheader.hpp:233
Definition: fragheader.hpp:153
Definition: fragformat.hpp:41
Definition: fragheader.hpp:172
uint32_t data_size
number of status elements
Definition: fragheader.hpp:174
uint32_t status_pos
number of data elements
Definition: fragheader.hpp:175