LDMX Software
packing::ECONDEventPacket Class Reference

Single ECON-D event packet. More...

#include <ECONDEventPacket.h>

Public Types

enum  Corruption : std::size_t {
  BAD_HEADER_MARKER = 0 , BAD_LENGTH = 1 , BAD_HEADER_CRC = 2 , BAD_CRC32 = 3 ,
  BAD_PAYLOAD = 4 , TRUNCATED = 5 , N_CORRUPTION = 6
}
 index of corruption flags More...
 

Public Member Functions

 ECONDEventPacket (std::size_t n_links)
 construct an event packet with the number of eRx "links"
 
bool isEmpty () const
 payload length of zero, no link sub-packets
 
bool isCorrupt () const
 any of the corruption flags are set
 
bool from (std::span< const uint32_t > data)
 parse into the packet from the passed data span
 

Public Attributes

std::array< bool, N_CORRUPTION > corruption_ {}
 corruption flags indexed by Corruption
 
uint32_t header_marker_ {0}
 9b header marker
 
uint32_t payload_length_ {0}
 payload length in 32b words (not including the two header words)
 
bool passthrough_ {false}
 P: pass through mode.
 
bool expected_ {false}
 E: HGCROC event header/trailer expected.
 
uint32_t ht_ {0}
 H/T: status of HGCROC header/trailer reconstruction.
 
uint32_t ebo_ {0}
 E/B/O: status of event/BX/orbit reconstruction.
 
bool match_ {false}
 M: transmitted E/B/O matches the L1A FIFO.
 
bool truncated_ {false}
 T: packet truncated for buffer overflow.
 
uint32_t hamming_ {0}
 6b Hamming code of the header
 
uint32_t bx_ {0}
 bunch crossing
 
uint32_t l1a_ {0}
 6b L1A (event) number
 
uint32_t orbit_ {0}
 3b orbit number
 
bool subpacket_error_ {false}
 S: error in a link sub-packet.
 
uint32_t reset_request_ {0}
 RR: reset request.
 
uint32_t crc8_ {0}
 transmitted 8b header CRC
 
std::vector< ECONDLinkSubpacket > links_
 storage of unpacked link data
 

Static Public Attributes

static const uint32_t HEADER_MARKER_SPEC {0xaa << 1}
 spec default and common CMS header markers (8b marker + 0)
 
static const uint32_t HEADER_MARKER_CMS {0xf3 << 1}
 

Private Member Functions

std::size_t unpackLinkSubpacket (std::span< const uint32_t > data, ECONDLinkSubpacket &link) const
 Unpack a eRx ("link") sub-packet.
 
 enableLogging ("ECONDEventPacket")
 handle to logging source
 

Detailed Description

Single ECON-D event packet.

The ECON-D is the CONcentrator mezzanine for the Data path and it has many different configuration modes. The two most important to us for decoding are

  1. "Pass Through" mode - all 37 sample words are copied from the link, the link headers from the ROC are overwritten by ECOND link headers
  2. "Regular" mode - the ECOND event format is written which can include zero-suppression of multiple varieties including full eliminating channels that are empty

The format is described in Section 18 of the ECON-D specification (ECON-D_specification_working_doc_v1.4_5jan2023.pdf).

Note
Ported from pflib::packing::ECONDEventPacket with bounds checks added so that corrupted packets are flagged instead of read past.

Definition at line 64 of file ECONDEventPacket.h.

Member Enumeration Documentation

◆ Corruption

index of corruption flags

Enumerator
BAD_HEADER_MARKER 

9b header marker is not the ECOND spec or common CMS config

BAD_LENGTH 

stored payload length does not equal packet length

BAD_HEADER_CRC 

8b header CRC mismatch

BAD_CRC32 

32b sub-packet CRC mismatch

BAD_PAYLOAD 

link sub-packets do not fit or do not end at the CRC word

TRUNCATED 

T flag set, link sub-packets not transmitted.

N_CORRUPTION 

number of corruption flags

Definition at line 67 of file ECONDEventPacket.h.

67 : std::size_t {
71 BAD_LENGTH = 1,
75 BAD_CRC32 = 3,
77 BAD_PAYLOAD = 4,
79 TRUNCATED = 5,
81 N_CORRUPTION = 6
82 };
@ TRUNCATED
T flag set, link sub-packets not transmitted.
@ BAD_HEADER_CRC
8b header CRC mismatch
@ BAD_HEADER_MARKER
9b header marker is not the ECOND spec or common CMS config
@ BAD_PAYLOAD
link sub-packets do not fit or do not end at the CRC word
@ BAD_LENGTH
stored payload length does not equal packet length
@ BAD_CRC32
32b sub-packet CRC mismatch
@ N_CORRUPTION
number of corruption flags

Constructor & Destructor Documentation

◆ ECONDEventPacket()

packing::ECONDEventPacket::ECONDEventPacket ( std::size_t n_links)
explicit

construct an event packet with the number of eRx "links"

Definition at line 214 of file ECONDEventPacket.cxx.

214: links_(n_links) {}
std::vector< ECONDLinkSubpacket > links_
storage of unpacked link data

Member Function Documentation

◆ from()

bool packing::ECONDEventPacket::from ( std::span< const uint32_t > data)

parse into the packet from the passed data span

The span should start at the first ECON-D header word and contain the full packet (as given by the DAQ capture header length). This function never reads outside of the span. On corruption, the corresponding flag is set and parsing stops early.

Returns
true if the packet is not corrupt

Definition at line 221 of file ECONDEventPacket.cxx.

221 {
222 corruption_.fill(false);
223 std::fill(links_.begin(), links_.end(), ECONDLinkSubpacket{});
224 payload_length_ = 0;
225
226 if (data.size() < 2) {
227 ldmx_log(debug) << "packet of " << data.size()
228 << " words is too short for the two header words";
229 corruption_[BAD_LENGTH] = true;
230 if (data.empty()) return false;
231 }
232
233 ldmx_log(trace) << "econd header one: " << Hex(data[0]);
234 header_marker_ = ((data[0] >> 23) & MASK<9>);
236 (header_marker_ != HEADER_MARKER_CMS);
238 // most likely not an ECON-D header at all
239 ldmx_log(debug) << "Bad header marker from ECOND 0x" << std::hex
240 << (header_marker_ >> 1) << " + 0b"
241 << (header_marker_ & 0b1) << std::dec << " in word "
242 << Hex(data[0]);
243 return false;
244 }
245 if (corruption_[BAD_LENGTH]) return false;
246
247 payload_length_ = ((data[0] >> 14) & MASK<9>);
248 passthrough_ = ((data[0] >> 13) & MASK<1>) == 1;
249 expected_ = ((data[0] >> 12) & MASK<1>) == 1;
250 ht_ = ((data[0] >> 10) & MASK<2>);
251 ebo_ = ((data[0] >> 8) & MASK<2>);
252 match_ = ((data[0] >> 7) & MASK<1>) == 1;
253 truncated_ = ((data[0] >> 6) & MASK<1>) == 1;
254 hamming_ = (data[0] & MASK<6>);
255
256 ldmx_log(trace) << "econd header two: " << Hex(data[1]);
257 bx_ = ((data[1] >> 20) & MASK<12>);
258 l1a_ = ((data[1] >> 14) & MASK<6>);
259 orbit_ = ((data[1] >> 11) & MASK<3>);
260 subpacket_error_ = ((data[1] >> 10) & MASK<1>) == 1;
261 reset_request_ = ((data[1] >> 8) & MASK<2>);
262 crc8_ = (data[1] & MASK<8>);
263 ldmx_log(trace) << " length=" << payload_length_ << " P=" << passthrough_
264 << " BX=" << bx_ << " L1A=" << l1a_ << " Orb=" << orbit_;
265
266 corruption_[BAD_LENGTH] = (data.size() != (payload_length_ + 2));
267 if (corruption_[BAD_LENGTH]) {
268 ldmx_log(debug) << "stored payload length " << payload_length_
269 << " does not match the packet length (" << data.size()
270 << " - 2)";
271 if (data.size() < (payload_length_ + 2)) return false;
272 }
273
274 // 8b CRC over both header words without the Hamming and the CRC
275 uint64_t header_crc_base = (data[0] >> 6);
276 header_crc_base <<= 30;
277 header_crc_base |= (data[1] >> 8);
278 uint8_t header_crc_val = utility::econdCrc8(header_crc_base);
279 corruption_[BAD_HEADER_CRC] = (header_crc_val != crc8_);
281 ldmx_log(debug) << "Event header 8b CRC does not match transmitted value: "
282 << std::bitset<8>(header_crc_val)
283 << " != " << std::bitset<8>(crc8_);
284 }
285
286 if (isEmpty()) {
287 ldmx_log(trace) << "empty packet, no link sub-packets";
288 return not isCorrupt();
289 }
290
291 // the last payload word is the CRC over all link sub-packets
292 auto payload{data.subspan(2, payload_length_)};
293 auto subpackets{payload.first(payload_length_ - 1)};
294 uint32_t crc_val = utility::crc32(subpackets);
295 uint32_t target = payload.back();
296 corruption_[BAD_CRC32] = (crc_val != target);
297 if (corruption_[BAD_CRC32]) {
298 ldmx_log(debug)
299 << "CRC over all link sub-packets does not match transmitted value "
300 << Hex(crc_val) << " != " << Hex(target);
301 }
302
303 if (corruption_[BAD_HEADER_CRC]) return false;
304
305 if (truncated_) {
306 ldmx_log(debug) << "Buffer control detected insufficient space so it did "
307 "not transfer link packets.";
308 corruption_[TRUNCATED] = true;
309 return false;
310 }
311
312 std::size_t offset{0};
313 for (auto& link : links_) {
314 auto length = unpackLinkSubpacket(subpackets.subspan(offset), link);
315 if (length == 0) {
316 corruption_[BAD_PAYLOAD] = true;
317 return false;
318 }
319 offset += length;
320 }
321
322 if (offset != subpackets.size()) {
323 ldmx_log(debug) << "link sub-packets end at " << offset
324 << " but the CRC word is at " << subpackets.size();
325 corruption_[BAD_PAYLOAD] = true;
326 }
327
328 return not isCorrupt();
329}
std::array< bool, N_CORRUPTION > corruption_
corruption flags indexed by Corruption
bool subpacket_error_
S: error in a link sub-packet.
uint32_t payload_length_
payload length in 32b words (not including the two header words)
uint32_t ht_
H/T: status of HGCROC header/trailer reconstruction.
bool passthrough_
P: pass through mode.
bool match_
M: transmitted E/B/O matches the L1A FIFO.
bool truncated_
T: packet truncated for buffer overflow.
uint32_t reset_request_
RR: reset request.
bool isEmpty() const
payload length of zero, no link sub-packets
uint32_t header_marker_
9b header marker
bool isCorrupt() const
any of the corruption flags are set
std::size_t unpackLinkSubpacket(std::span< const uint32_t > data, ECONDLinkSubpacket &link) const
Unpack a eRx ("link") sub-packet.
uint32_t hamming_
6b Hamming code of the header
uint32_t ebo_
E/B/O: status of event/BX/orbit reconstruction.
uint32_t crc8_
transmitted 8b header CRC
static const uint32_t HEADER_MARKER_SPEC
spec default and common CMS header markers (8b marker + 0)
uint32_t l1a_
6b L1A (event) number
bool expected_
E: HGCROC event header/trailer expected.
uint32_t bx_
bunch crossing
uint32_t orbit_
3b orbit number

References BAD_CRC32, BAD_HEADER_CRC, BAD_HEADER_MARKER, BAD_LENGTH, BAD_PAYLOAD, bx_, corruption_, crc8_, ebo_, expected_, hamming_, header_marker_, HEADER_MARKER_SPEC, ht_, isCorrupt(), isEmpty(), l1a_, links_, match_, orbit_, passthrough_, payload_length_, reset_request_, subpacket_error_, TRUNCATED, truncated_, and unpackLinkSubpacket().

◆ isCorrupt()

bool packing::ECONDEventPacket::isCorrupt ( ) const

any of the corruption flags are set

Definition at line 216 of file ECONDEventPacket.cxx.

216 {
217 return std::any_of(corruption_.begin(), corruption_.end(),
218 [](bool c) { return c; });
219}

References corruption_.

Referenced by from().

◆ isEmpty()

bool packing::ECONDEventPacket::isEmpty ( ) const
inline

payload length of zero, no link sub-packets

Definition at line 130 of file ECONDEventPacket.h.

130{ return payload_length_ == 0; }

References payload_length_.

Referenced by from().

◆ unpackLinkSubpacket()

std::size_t packing::ECONDEventPacket::unpackLinkSubpacket ( std::span< const uint32_t > data,
ECONDLinkSubpacket & link ) const
private

Unpack a eRx ("link") sub-packet.

Parameters
[in]datawords from the start of the sub-packet to the CRC word (not included)
[out]linksub-packet to update with unpacked data
Returns
length of data in 32b words that was unpacked, 0 if the sub-packet does not fit into data

Definition at line 37 of file ECONDEventPacket.cxx.

38 {
39 if (data.empty()) {
40 ldmx_log(debug) << "no words left for link sub-packet";
41 return 0;
42 }
43 ldmx_log(trace) << "link header " << Hex(data[0]);
44 link.stat_ = ((data[0] >> 29) & MASK<3>);
45 if (link.badStat()) {
46 std::bitset<3> bits = link.stat_;
47 std::string names;
48 for (std::size_t i{0}; i < 3; i++) {
49 if (!bits.test(i)) names += std::string(" ") + LINK_STAT_BIT_NAMES[i];
50 }
51 ldmx_log(debug) << "bad link Stat bits 0b" << bits << " -> [" << names
52 << " ] mismatched";
53 }
54 link.hamming_ = ((data[0] >> 26) & MASK<3>);
55 link.is_empty_ = ((data[0] >> 25) & MASK<1>) == 1;
56 link.adc_cm0_ = ((data[0] >> 15) & MASK<10>);
57 link.adc_cm1_ = ((data[0] >> 5) & MASK<10>);
58 ldmx_log(trace) << " is_empty=" << link.is_empty_
59 << " CM0=" << link.adc_cm0_ << " CM1=" << link.adc_cm1_;
60
61 if (link.is_empty_) {
62 // F=1: single-word header, no channel map or channel data
63 // E=1 means unmasked Stat error bits caused the suppression
64 link.error_caused_empty_ = ((data[0] >> 4) & MASK<1>) == 1;
65 ldmx_log(trace) << "is empty, E=" << link.error_caused_empty_;
66 return 1;
67 }
68
69 if (data.size() < 2) {
70 ldmx_log(debug) << "link sub-packet missing channel map";
71 return 0;
72 }
73 ldmx_log(trace) << "chan map lower 32 " << Hex(data[1]);
74 link.channel_map_ =
75 ((data[0] & MASK<5>) << 32) | static_cast<uint64_t>(data[1]);
76 ldmx_log(trace) << "is not empty, channel_map="
77 << std::bitset<37>(link.channel_map_);
78
79 // two header words (including channel map)
80 std::size_t length{2};
81
82 int bits_left_in_current_word{32};
83 for (std::size_t i_chan{0}; i_chan < 37; i_chan++) {
84 // calib is the 19th channel in the sub-packet
85 uint32_t* ch = &(link.calib_);
86 if (i_chan < 18) {
87 ch = &(link.channels_[i_chan]);
88 } else if (i_chan > 18) {
89 ch = &(link.channels_[i_chan - 1]);
90 }
91
92 if (passthrough_) {
93 // channels are transparently copied from the link
94 if (length >= data.size()) {
95 ldmx_log(debug) << "pass through sub-packet ran out of words at ch "
96 << i_chan;
97 return 0;
98 }
99 *ch = data[length];
100 length++;
101 continue;
102 }
103
104 // skip channels that are not passed
105 if (((link.channel_map_ >> i_chan) & 1) == 0) {
106 *ch = 0;
107 continue;
108 }
109
110 if (length >= data.size()) {
111 ldmx_log(debug) << "sub-packet ran out of words at ch " << i_chan;
112 return 0;
113 }
114
115 // the code cannot span words, the format is byte aligned
116 auto code{(data[length] >> (bits_left_in_current_word - 4)) & MASK<4>};
117 // direct transcription of the table in Fig 20 of the ECOND Spec
118 int nbits{32}, extra{0};
119 bool has_adctm1{true}, has_toa{true};
120 bool tc{false}, tp{false};
121 if (code == 0b0000) {
122 // TOA ZS
123 has_toa = false;
124 nbits = 24;
125 } else if (code == 0b0001) {
126 // ADC(-1) and TOA ZS
127 has_adctm1 = false;
128 has_toa = false;
129 extra = 2;
130 nbits = 16;
131 } else if (code == 0b0010) {
132 // No ZS or ...
133 tp = true;
134 has_toa = false;
135 nbits = 24;
136 } else if (code == 0b0011) {
137 // ADC(-1) ZS
138 has_adctm1 = false;
139 nbits = 24;
140 } else if ((code >> 2) == 0b01) {
141 // full pass ZS in ADC mode
142 } else if ((code >> 2) == 0b11) {
143 // pass ZS because in TOT mode
144 tc = true;
145 tp = true;
146 } else {
147 // 0b10: known invalid
148 ldmx_log(debug) << "ECOND eRx known invalid code "
149 << std::bitset<2>(code >> 2);
150 tc = true;
151 }
152
153 // get the channel data from the current and perhaps the next word
154 uint64_t chan_data{0};
155 if (bits_left_in_current_word < nbits) {
156 int runon_length = nbits - bits_left_in_current_word;
157 if (length + 1 >= data.size()) {
158 ldmx_log(debug) << "sub-packet ran out of words at ch " << i_chan;
159 return 0;
160 }
161 chan_data = ((data[length] & ((1ul << bits_left_in_current_word) - 1ul))
162 << runon_length);
163 length++;
164 bits_left_in_current_word = 32;
165 chan_data +=
166 ((data[length] >> (bits_left_in_current_word - runon_length)) &
167 ((1ul << runon_length) - 1ul));
168 bits_left_in_current_word -= runon_length;
169 } else {
170 chan_data = ((data[length] >> (bits_left_in_current_word - nbits)) &
171 ((1ul << nbits) - 1ul));
172 bits_left_in_current_word -= nbits;
173 }
174
175 // measurements that do not exist are negative
176 int adc_tm1{-1}, toa{-1};
177 chan_data >>= extra;
178 if (has_toa) {
179 toa = (chan_data & MASK<10>);
180 chan_data >>= 10;
181 }
182 int main_sample = (chan_data & MASK<10>);
183 chan_data >>= 10;
184 if (has_adctm1) {
185 adc_tm1 = (chan_data & MASK<10>);
186 }
187 ldmx_log(trace) << " ch " << i_chan << " code=" << std::bitset<4>(code)
188 << " ADC(t-1)=" << adc_tm1 << " ADC/TOT=" << main_sample
189 << " TOA=" << toa;
190
191 *ch = packSample(tc, tp, adc_tm1, main_sample, toa);
192
193 if (bits_left_in_current_word == 0) {
194 length++;
195 bits_left_in_current_word = 32;
196 }
197 }
198
199 // sub-packets are 32b-word-aligned
200 if (bits_left_in_current_word < 32) {
201 length++;
202 }
203
204 if (length > data.size()) {
205 ldmx_log(debug) << "sub-packet length " << length << " exceeds "
206 << data.size() << " remaining words";
207 return 0;
208 }
209
210 ldmx_log(trace) << "eRx final length " << length;
211 return length;
212}

References packing::ECONDLinkSubpacket::adc_cm0_, packing::ECONDLinkSubpacket::adc_cm1_, packing::ECONDLinkSubpacket::badStat(), packing::ECONDLinkSubpacket::calib_, packing::ECONDLinkSubpacket::channel_map_, packing::ECONDLinkSubpacket::channels_, packing::ECONDLinkSubpacket::error_caused_empty_, packing::ECONDLinkSubpacket::hamming_, packing::ECONDLinkSubpacket::is_empty_, passthrough_, and packing::ECONDLinkSubpacket::stat_.

Referenced by from().

Member Data Documentation

◆ bx_

uint32_t packing::ECONDEventPacket::bx_ {0}

bunch crossing

Definition at line 106 of file ECONDEventPacket.h.

106{0};

Referenced by from().

◆ corruption_

std::array<bool, N_CORRUPTION> packing::ECONDEventPacket::corruption_ {}

corruption flags indexed by Corruption

Definition at line 85 of file ECONDEventPacket.h.

85{};

Referenced by from(), and isCorrupt().

◆ crc8_

uint32_t packing::ECONDEventPacket::crc8_ {0}

transmitted 8b header CRC

Definition at line 116 of file ECONDEventPacket.h.

116{0};

Referenced by from().

◆ ebo_

uint32_t packing::ECONDEventPacket::ebo_ {0}

E/B/O: status of event/BX/orbit reconstruction.

Definition at line 98 of file ECONDEventPacket.h.

98{0};

Referenced by from().

◆ expected_

bool packing::ECONDEventPacket::expected_ {false}

E: HGCROC event header/trailer expected.

Definition at line 94 of file ECONDEventPacket.h.

94{false};

Referenced by from().

◆ hamming_

uint32_t packing::ECONDEventPacket::hamming_ {0}

6b Hamming code of the header

Definition at line 104 of file ECONDEventPacket.h.

104{0};

Referenced by from().

◆ header_marker_

uint32_t packing::ECONDEventPacket::header_marker_ {0}

9b header marker

Definition at line 88 of file ECONDEventPacket.h.

88{0};

Referenced by from().

◆ HEADER_MARKER_CMS

const uint32_t packing::ECONDEventPacket::HEADER_MARKER_CMS {0xf3 << 1}
static

Definition at line 149 of file ECONDEventPacket.h.

149{0xf3 << 1};

◆ HEADER_MARKER_SPEC

const uint32_t packing::ECONDEventPacket::HEADER_MARKER_SPEC {0xaa << 1}
static

spec default and common CMS header markers (8b marker + 0)

Definition at line 148 of file ECONDEventPacket.h.

148{0xaa << 1};

Referenced by from().

◆ ht_

uint32_t packing::ECONDEventPacket::ht_ {0}

H/T: status of HGCROC header/trailer reconstruction.

Definition at line 96 of file ECONDEventPacket.h.

96{0};

Referenced by from().

◆ l1a_

uint32_t packing::ECONDEventPacket::l1a_ {0}

6b L1A (event) number

Definition at line 108 of file ECONDEventPacket.h.

108{0};

Referenced by from().

◆ links_

std::vector<ECONDLinkSubpacket> packing::ECONDEventPacket::links_

storage of unpacked link data

This is very space in-efficient since we store zero words for any channel or measurement that was zero suppressed.

Definition at line 124 of file ECONDEventPacket.h.

Referenced by from().

◆ match_

bool packing::ECONDEventPacket::match_ {false}

M: transmitted E/B/O matches the L1A FIFO.

Definition at line 100 of file ECONDEventPacket.h.

100{false};

Referenced by from().

◆ orbit_

uint32_t packing::ECONDEventPacket::orbit_ {0}

3b orbit number

Definition at line 110 of file ECONDEventPacket.h.

110{0};

Referenced by from().

◆ passthrough_

bool packing::ECONDEventPacket::passthrough_ {false}

P: pass through mode.

Definition at line 92 of file ECONDEventPacket.h.

92{false};

Referenced by from(), and unpackLinkSubpacket().

◆ payload_length_

uint32_t packing::ECONDEventPacket::payload_length_ {0}

payload length in 32b words (not including the two header words)

Definition at line 90 of file ECONDEventPacket.h.

90{0};

Referenced by from(), and isEmpty().

◆ reset_request_

uint32_t packing::ECONDEventPacket::reset_request_ {0}

RR: reset request.

Definition at line 114 of file ECONDEventPacket.h.

114{0};

Referenced by from().

◆ subpacket_error_

bool packing::ECONDEventPacket::subpacket_error_ {false}

S: error in a link sub-packet.

Definition at line 112 of file ECONDEventPacket.h.

112{false};

Referenced by from().

◆ truncated_

bool packing::ECONDEventPacket::truncated_ {false}

T: packet truncated for buffer overflow.

Definition at line 102 of file ECONDEventPacket.h.

102{false};

Referenced by from().


The documentation for this class was generated from the following files: