1#include "Packing/ECONDEventPacket.h"
7#include "Packing/Utility/CRC.h"
8#include "Packing/Utility/Hex.h"
9#include "Packing/Utility/Mask.h"
12using packing::utility::MASK;
24uint32_t packSample(
bool tc,
bool tp,
int adc_tm1,
int main_sample,
int toa) {
25 uint32_t msb_meas = (adc_tm1 < 0) ? 0 : adc_tm1;
26 uint32_t lsb_meas = (toa < 0) ? 0 : toa;
27 return (
static_cast<uint32_t
>(tc) << 31) + (
static_cast<uint32_t
>(tp) << 30) +
28 ((msb_meas & MASK<10>) << 20) + ((main_sample & MASK<10>) << 10) +
29 (lsb_meas & MASK<10>);
33const std::array<const char*, 3> LINK_STAT_BIT_NAMES = {
"CRC",
"EBO",
"HT"};
40 ldmx_log(debug) <<
"no words left for link sub-packet";
43 ldmx_log(trace) <<
"link header " <<
Hex(data[0]);
44 link.
stat_ = ((data[0] >> 29) & MASK<3>);
46 std::bitset<3> bits = link.
stat_;
48 for (std::size_t i{0}; i < 3; i++) {
49 if (!bits.test(i)) names += std::string(
" ") + LINK_STAT_BIT_NAMES[i];
51 ldmx_log(debug) <<
"bad link Stat bits 0b" << bits <<
" -> [" << names
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_
69 if (data.size() < 2) {
70 ldmx_log(debug) <<
"link sub-packet missing channel map";
73 ldmx_log(trace) <<
"chan map lower 32 " <<
Hex(data[1]);
75 ((data[0] & MASK<5>) << 32) |
static_cast<uint64_t
>(data[1]);
76 ldmx_log(trace) <<
"is not empty, channel_map="
80 std::size_t length{2};
82 int bits_left_in_current_word{32};
83 for (std::size_t i_chan{0}; i_chan < 37; i_chan++) {
85 uint32_t* ch = &(link.
calib_);
88 }
else if (i_chan > 18) {
94 if (length >= data.size()) {
95 ldmx_log(debug) <<
"pass through sub-packet ran out of words at ch "
110 if (length >= data.size()) {
111 ldmx_log(debug) <<
"sub-packet ran out of words at ch " << i_chan;
116 auto code{(data[length] >> (bits_left_in_current_word - 4)) & MASK<4>};
118 int nbits{32}, extra{0};
119 bool has_adctm1{
true}, has_toa{
true};
120 bool tc{
false}, tp{
false};
121 if (code == 0b0000) {
125 }
else if (code == 0b0001) {
131 }
else if (code == 0b0010) {
136 }
else if (code == 0b0011) {
140 }
else if ((code >> 2) == 0b01) {
142 }
else if ((code >> 2) == 0b11) {
148 ldmx_log(debug) <<
"ECOND eRx known invalid code "
149 << std::bitset<2>(code >> 2);
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;
161 chan_data = ((data[length] & ((1ul << bits_left_in_current_word) - 1ul))
164 bits_left_in_current_word = 32;
166 ((data[length] >> (bits_left_in_current_word - runon_length)) &
167 ((1ul << runon_length) - 1ul));
168 bits_left_in_current_word -= runon_length;
170 chan_data = ((data[length] >> (bits_left_in_current_word - nbits)) &
171 ((1ul << nbits) - 1ul));
172 bits_left_in_current_word -= nbits;
176 int adc_tm1{-1}, toa{-1};
179 toa = (chan_data & MASK<10>);
182 int main_sample = (chan_data & MASK<10>);
185 adc_tm1 = (chan_data & MASK<10>);
187 ldmx_log(trace) <<
" ch " << i_chan <<
" code=" << std::bitset<4>(code)
188 <<
" ADC(t-1)=" << adc_tm1 <<
" ADC/TOT=" << main_sample
191 *ch = packSample(tc, tp, adc_tm1, main_sample, toa);
193 if (bits_left_in_current_word == 0) {
195 bits_left_in_current_word = 32;
200 if (bits_left_in_current_word < 32) {
204 if (length > data.size()) {
205 ldmx_log(debug) <<
"sub-packet length " << length <<
" exceeds "
206 << data.size() <<
" remaining words";
210 ldmx_log(trace) <<
"eRx final length " << length;
218 [](
bool c) { return c; });
226 if (data.size() < 2) {
227 ldmx_log(debug) <<
"packet of " << data.size()
228 <<
" words is too short for the two header words";
230 if (data.empty())
return false;
233 ldmx_log(trace) <<
"econd header one: " <<
Hex(data[0]);
239 ldmx_log(debug) <<
"Bad header marker from ECOND 0x" << std::hex
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;
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>);
262 crc8_ = (data[1] & MASK<8>);
269 <<
" does not match the packet length (" << data.size()
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);
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_);
287 ldmx_log(trace) <<
"empty packet, no link sub-packets";
294 uint32_t crc_val = utility::crc32(subpackets);
295 uint32_t target = payload.back();
299 <<
"CRC over all link sub-packets does not match transmitted value "
300 <<
Hex(crc_val) <<
" != " <<
Hex(target);
306 ldmx_log(debug) <<
"Buffer control detected insufficient space so it did "
307 "not transfer link packets.";
312 std::size_t offset{0};
313 for (
auto& link :
links_) {
322 if (offset != subpackets.size()) {
323 ldmx_log(debug) <<
"link sub-packets end at " << offset
324 <<
" but the CRC word is at " << subpackets.size();
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)
std::vector< ECONDLinkSubpacket > links_
storage of unpacked link data
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
@ 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
std::size_t unpackLinkSubpacket(std::span< const uint32_t > data, ECONDLinkSubpacket &link) const
Unpack a eRx ("link") sub-packet.
bool from(std::span< const uint32_t > data)
parse into the packet from the passed data span
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
ECONDEventPacket(std::size_t n_links)
construct an event packet with the number of eRx "links"
uint32_t orbit_
3b orbit number
Data from a single eRx ("link") sub-packet of an ECON-D event packet.
bool error_caused_empty_
E flag of an empty sub-packet: suppressed due to unmasked Stat errors.
bool badStat() const
any of the three Stat bits are bad (not 1)
std::array< uint32_t, 36 > channels_
sample words of the 36 normal channels
uint32_t hamming_
3-bit Hamming code of the sub-packet header
uint32_t calib_
sample word of the calibration channel
int adc_cm1_
ADC readout of common mode 1.
uint64_t channel_map_
37-bit channel map (bit 18 is the calibration channel)
bool is_empty_
F flag: sub-packet is a single header word without channel data.
int adc_cm0_
ADC readout of common mode 0.
uint32_t stat_
3-bit Stat field (HT, EBO, CRC match), all ones is good