From 3670bb62f395eecd94634f4004d3938500372ef2 Mon Sep 17 00:00:00 2001 From: tomeichlersmith Date: Mon, 11 Oct 2021 10:54:19 -0500 Subject: [PATCH] compiling draft of encoder for ecal --- src/Ecal/EcalRawDecoder.cxx | 15 ++-- src/Ecal/EcalRawEncoder.cxx | 154 +++++++++++++++++++++++++++++++----- 2 files changed, 144 insertions(+), 25 deletions(-) diff --git a/src/Ecal/EcalRawDecoder.cxx b/src/Ecal/EcalRawDecoder.cxx index 3cf19a6..45c6c19 100644 --- a/src/Ecal/EcalRawDecoder.cxx +++ b/src/Ecal/EcalRawDecoder.cxx @@ -232,13 +232,16 @@ void EcalRawDecoder::produce(framework::Event& event) { getCondition(EcalDetectorMap::CONDITIONS_OBJECT_NAME)}; ldmx::HgcrocDigiCollection digis; for (auto const& [eid, digi] : eid_to_samples) { - // TODO: This checking of existence should be temporary, - // the electronic ID mapping should be complete. - uint32_t did_raw{eid.raw()}; - if (detmap.exists(eid)) { - did_raw = detmap.get(eid).raw(); + // The electronics map returns an empty ID of the correct + // type when the electronics ID is not found. + // need to check if the electronics ID exists + // TODO: do we want to end processing if this happens? + if (!detmap.exists(eid)) { + std::stringstream ss; + ss << eid; + ldmx_log(warn) << "Electronic ID " << ss.str() << " not translated to a detector ID."; } - + uint32_t did_raw = detmap.get(eid).raw(); digis.addDigi(did_raw, digi); } diff --git a/src/Ecal/EcalRawEncoder.cxx b/src/Ecal/EcalRawEncoder.cxx index 5b9a4ab..74f90cb 100644 --- a/src/Ecal/EcalRawEncoder.cxx +++ b/src/Ecal/EcalRawEncoder.cxx @@ -33,23 +33,13 @@ void EcalRawEncoder::produce(framework::Event& event) { auto digis{event.getObject(input_name_, input_pass_)}; std::vector< - std::vector< - std::vector< + std::map // channel to sample > // links > // fpgas > // bunches sorted_samples(digis.getNumSamplesPerDigi()); - /** - * TODO need to resize to fit constraints on number of links and fpgas - for (auto& bunch : sorted_samples) { - bunch.resize(total_num_possible_fpga); - for (auto& fpga : bunch) { - fpga.resize(total_num_possible_links_per_fpga); - // channel to sample mapping we want to stay empty - } - } - */ /** * Translation @@ -72,7 +62,6 @@ void EcalRawEncoder::produce(framework::Event& event) { } } - /** * Encoding * @@ -84,9 +73,54 @@ void EcalRawEncoder::produce(framework::Event& event) { * the header information the calculate the CRC checksums. */ std::vector buffer; + static uint32_t word; // word to use for constructing buffer + uint32_t i_bx{0}; for (auto const& bunch : sorted_samples) { + /**TODO calculate bunch ID, read request, and orbit from sample ID, event number, and run number + * placeholder: + * bunch ID = event number + * read request = sample ID + * orbit = run number + */ + uint32_t bunch_id = event.getEventNumber(); + uint32_t rreq = i_bx; + uint32_t orbit = event.getEventHeader().getRun(); + // bunch lists the fpgs, links, and channels with their corresponding sample - for (auto const& fpga : bunch) { + for (auto const& [fpga_id, links] : bunch) { + /** + * Calculate lengths of link sub-packets + * + * Table 4 of ECal DAQ Specifications. + * + * Each ROC link has 3 header words, a common mode channel, and + * a trailing CRC checksum word. The 3 header words contain a readout map + * of which channels are included in the DAQ packet, so we end up with. + * + * len of link = 3 + 1 + channels.size() + 1; + */ + std::vector link_lengths; + for (auto const& [link_id, channels] : links) { + link_lengths.push_back(3+1+channels.size()+1); + } + + /** + * The total FPGA packet includes at least 2 header words, a trailing checksum word, + * and a single word for each four links. + * + * This means we add up the subpacket lengths into subpacket_total + * and then + * + * n_linkwords = (nlinks/4+(nlinks%4!=0)) + * total_length = 2 + n_linkwords + subpacket_total + 1; + */ + uint32_t n_linkwords = link_lengths.size()/4 + (link_lengths.size()%4 != 0); + uint32_t total_length{2 + n_linkwords + 1}; + for (uint32_t const& link_len : link_lengths) { + total_length += link_len; + } + + packing::utility::CRC fpga_crc; /** Encode Bunch Header * We have a few words of header material before the actual data. * This header material is assumed to be encoded as in Table 3 @@ -102,9 +136,51 @@ void EcalRawEncoder::produce(framework::Event& event) { * RID ok (1) | CDC ok (1) | LEN0 (6) * ... other listing of links ... */ - packing::utility::CRC fpga_crc; + word = 0; + word |= (1 << 12+1+6+8); // version + word |= (fpga_id & packing::utility::mask<8>) << 12+1+6; // FPGA + word |= (links.size() & packing::utility::mask<6>) << 12+1; // NLINKS + word |= (total_length & packing::utility::mask<12>); // LEN TODO + buffer.push_back(word); + fpga_crc << word; + + word = 0; + word |= (bunch_id & packing::utility::mask<12>) << 20; // BX ID + word |= (rreq & packing::utility::mask<10>) << 10; // RREQ + word |= (orbit & packing::utility::mask<10>); // OR + buffer.push_back(word); + fpga_crc << word; + + /** + * Encode lengths of link subpackets + */ + for (uint32_t i_linkword{0}; i_linkword < n_linkwords; i_linkword++) { + word = 0; + for (uint32_t i_linklen{0}; i_linklen < 4; i_linklen++) { + uint32_t i_link = 4*i_linkword + i_linklen; + if (i_link <= link_lengths.size()) { + // we have a link + word |= (((0b11 << 6) + (link_lengths.at(i_link) & packing::utility::mask<6>)) << 8*i_linklen); + } // do we have a link for this linklen subword? + } // loop through subwords in this word + buffer.push_back(word); + fpga_crc << word; + } // loop through words + // fpga lists the links and channels with their corresponding sample - for (auto const& link : fpga) { + for (auto const& [link_id, channels] : links) { + /** + * Prepare RO Map bitset + */ + std::bitset<40> ro_map; //starts as all 0s + ro_map.set(0); // special "header" word from ROC + ro_map.set(39); // trailing checksum from ROC + // each link maps the channels that were readout to their sample + for (auto const& [channel, sample] : channels) { + ro_map.set(channel); + } + + packing::utility::CRC link_crc; /** Encode Each Link in Sequence * Now we should be decoding each link serially * where each link was encoded as in Table 4 of @@ -113,14 +189,54 @@ void EcalRawEncoder::produce(framework::Event& event) { * ROC_ID (16) | CRC ok (1) | 00000 | RO Map (8) * RO Map (32) */ - packing::utility::CRC link_crc; - // each link maps the channels that were readout to their sample - for (auto const& [channel, sample] : link) { + word = 0; + word |= (link_id & packing::utility::mask<16>) << 16; + word |= 1 << 15; + // put first 8bits of RO Map in first header word + word |= (ro_map >> 32).to_ulong(); + + buffer.push_back(word); + fpga_crc << word; + link_crc << word; + + // next header word is end of RO map + word = (ro_map.to_ulong() & 0xFFFFFFFF); + buffer.push_back(word); + fpga_crc << word; + link_crc << word; + + // special "header" word from ROC + word = 0; + word |= 0b0101 << 28; + word |= (bunch_id & packing::utility::mask<12>) << 16; + word |= (rreq & packing::utility::mask<6> ) << 10; + word |= (orbit & packing::utility::mask<3>) << 7; + // skipping hamming error bits because we will set them all to false here + word |= 0b0101; + buffer.push_back(word); + fpga_crc << word; + link_crc << word; + + /** + * TODO: Common-Mode Channel + * Somewhere in here is where the common-mode channel + * would be inserted. I'm not sure if we should expect + * that the common mode channel also has a sample or it + * will be reserved and never should have a sample + */ + // put samples into buffer + for (auto const& [channel, sample] : channels) { + buffer.push_back(sample); + fpga_crc << sample; + link_crc << sample; } + buffer.push_back(link_crc.get()); + fpga_crc << link_crc.get(); } } + i_bx++; } event.add(output_name_, buffer);