From a4c6629cdf31c481518f0c69cdedf93fef692eaf Mon Sep 17 00:00:00 2001 From: Markus Fasel Date: Mon, 27 Jul 2020 16:49:21 +0200 Subject: [PATCH 1/5] [EMCAL-610, EMCAL-659] Output raw stream based on RawFileWriter - Replace usage of RawOutputPageHandler with RawFileWriter for output streaming - Initialize RawFileWriter using a single output file and a linear link assignment for C-RORC/Link ID untill final link assignment on production FLPs is fixed - Convert input handing from std::vectors to gsl::span --- .../include/EMCALSimulation/RawWriter.h | 35 ++++++----- Detectors/EMCAL/simulation/src/RawWriter.cxx | 60 +++++++++++++------ 2 files changed, 62 insertions(+), 33 deletions(-) diff --git a/Detectors/EMCAL/simulation/include/EMCALSimulation/RawWriter.h b/Detectors/EMCAL/simulation/include/EMCALSimulation/RawWriter.h index dd6427c56ea38..0e0afad12e85d 100644 --- a/Detectors/EMCAL/simulation/include/EMCALSimulation/RawWriter.h +++ b/Detectors/EMCAL/simulation/include/EMCALSimulation/RawWriter.h @@ -11,6 +11,8 @@ #ifndef ALICEO2_EMCAL_RAWWRITER_H #define ALICEO2_EMCAL_RAWWRITER_H +#include + #include #include #include @@ -20,9 +22,8 @@ #include "Rtypes.h" +#include "DetectorsRaw/RawFileWriter.h" #include "EMCALBase/Mapper.h" -#include "EMCALSimulation/DMAOutputStream.h" -#include "EMCALSimulation/RawOutputPageHandler.h" #include "DataFormatsEMCAL/Digit.h" #include "DataFormatsEMCAL/TriggerRecord.h" @@ -79,37 +80,39 @@ class RawWriter ~RawWriter() = default; void setRawFileName(const char* filename) { mRawFilename = filename; } - void setDigits(std::vector* digits) { mDigits = digits; } - void setTriggerRecords(std::vector* triggers); + void setDigits(gsl::span digits) { mDigits = digits; } + void setTriggerRecords(gsl::span triggers); void setNumberOfADCSamples(int nsamples) { mNADCSamples = nsamples; } void setPedestal(int pedestal) { mPedestal = pedestal; } void setGeometry(o2::emcal::Geometry* geo) { mGeometry = geo; } - bool hasNextTrigger() const { return mCurrentTrigger != mTriggers->end(); } + bool hasNextTrigger() const { return mCurrentTrigger != mTriggers.end(); } void init(); void process(); - void processNextTrigger(); + void processTimeFrame(gsl::span digits, gsl::span triggers); + bool processNextTrigger(); protected: std::vector findBunches(const std::vector& channelDigits); std::tuple getOnlineID(int towerID); + std::tuple getLinkAssignment(int ddlID); ChannelHeader createChannelHeader(int hardwareAddress, int payloadSize, bool isBadChannel); std::vector createRCUTrailer(int payloadsize, int feca, int fecb, double timesample, double l1phase); std::vector encodeBunchData(const std::vector& data); private: - int mNADCSamples = 15; ///< Number of time samples - int mPedestal = 0; ///< Pedestal - o2::emcal::Geometry* mGeometry = nullptr; ///< EMCAL geometry - std::string mRawFilename; ///< Rawfile name - std::array mMappers; ///< EMCAL mappers - std::vector* mDigits; ///< Digits input vector - must be in digitized format including the time response - std::vector* mTriggers; ///< Trigger records, separating the data from different triggers - std::vector mSRUdata; ///< Internal helper of digits assigned to SRUs - std::vector::iterator mCurrentTrigger; ///< Current trigger in the trigger records - std::unique_ptr mPageHandler; ///< Output page handler + int mNADCSamples = 15; ///< Number of time samples + int mPedestal = 0; ///< Pedestal + o2::emcal::Geometry* mGeometry = nullptr; ///< EMCAL geometry + std::string mRawFilename; ///< Rawfile name + std::array mMappers; ///< EMCAL mappers + gsl::span mDigits; ///< Digits input vector - must be in digitized format including the time response + gsl::span mTriggers; ///< Trigger records, separating the data from different triggers + std::vector mSRUdata; ///< Internal helper of digits assigned to SRUs + gsl::span::iterator mCurrentTrigger; ///< Current trigger in the trigger records + std::unique_ptr mRawWriter; ///< Raw writer ClassDefNV(RawWriter, 1); }; diff --git a/Detectors/EMCAL/simulation/src/RawWriter.cxx b/Detectors/EMCAL/simulation/src/RawWriter.cxx index 013cbdc7fad5d..1ea511911b038 100644 --- a/Detectors/EMCAL/simulation/src/RawWriter.cxx +++ b/Detectors/EMCAL/simulation/src/RawWriter.cxx @@ -14,19 +14,27 @@ #include "EMCALBase/Geometry.h" #include "EMCALBase/RCUTrailer.h" #include "EMCALSimulation/RawWriter.h" -#include "Headers/RAWDataHeader.h" using namespace o2::emcal; -void RawWriter::setTriggerRecords(std::vector* triggers) +void RawWriter::setTriggerRecords(gsl::span triggers) { mTriggers = triggers; - mCurrentTrigger = triggers->begin(); + mCurrentTrigger = triggers.begin(); } void RawWriter::init() { - mPageHandler = std::make_unique(mRawFilename.data()); + mRawWriter = std::make_unique(o2::header::gDataOriginEMC); + for (auto iddl = 0; iddl < 40; iddl++) { + // For EMCAL set + // - FEE ID = DDL ID + // - C-RORC and link increasing with DDL ID + // @TODO replace with link assignment on production FLPs, + // eventually storing in CCDB + auto [crorc, link] = getLinkAssignment(iddl); + mRawWriter->registerLink(iddl, crorc, link, 0, mRawFilename.data()); + } // initialize mappers std::array sides = {{'A', 'C'}}; for (auto iside = 0; iside < sides.size(); iside++) { @@ -43,15 +51,28 @@ void RawWriter::init() } } -void RawWriter::processNextTrigger() +void RawWriter::process() +{ + while (processNextTrigger()) + ; +} + +void RawWriter::processTimeFrame(gsl::span digitsbranch, gsl::span triggerbranch) +{ + setDigits(digitsbranch); + setTriggerRecords(triggerbranch); + process(); +} + +bool RawWriter::processNextTrigger() { - // initialize page handler when processing the first trigger - mPageHandler->initTrigger(mCurrentTrigger->getBCData()); + if (mCurrentTrigger == mTriggers.end()) + return false; for (auto srucont : mSRUdata) srucont.mChannels.clear(); std::vector* bunchDigits; int lasttower = -1; - for (auto& dig : gsl::span(&mDigits->data()[mCurrentTrigger->getFirstEntry()], mCurrentTrigger->getNumberOfObjects())) { + for (auto& dig : gsl::span(mDigits.data() + mCurrentTrigger->getFirstEntry(), mCurrentTrigger->getNumberOfObjects())) { auto tower = dig.getTower(); if (tower != lasttower) { lasttower = tower; @@ -72,13 +93,6 @@ void RawWriter::processNextTrigger() // Create and fill DMA pages for each channel std::vector payload; for (auto srucont : mSRUdata) { - // EMCAL does not set HBF triggers, only set trigger BC and orbit - o2::header::RAWDataHeaderV4 rawheader; - rawheader.triggerBC = mCurrentTrigger->getBCData().bc; - rawheader.triggerOrbit = mCurrentTrigger->getBCData().orbit; - // @TODO: Set trigger type - rawheader.feeId = srucont.mSRUid; - rawheader.linkID = srucont.mSRUid; for (const auto& [tower, channel] : srucont.mChannels) { // Find out hardware address of the channel @@ -109,9 +123,13 @@ void RawWriter::processNextTrigger() for (auto word : trailerwords) payload.emplace_back(word); - // write DMA page to stream - mPageHandler->addPageForLink(srucont.mSRUid, rawheader, payload); + // register output data + auto ddlid = srucont.mSRUid; + auto [crorc, link] = getLinkAssignment(ddlid); + mRawWriter->addData(ddlid, crorc, link, 0, mCurrentTrigger->getBCData(), payload); } + mCurrentTrigger++; + return true; } std::vector RawWriter::findBunches(const std::vector& channelDigits) @@ -168,6 +186,14 @@ std::tuple RawWriter::getOnlineID(int towerID) return std::make_tuple(sruID, row, col); } +std::tuple RawWriter::getLinkAssignment(int ddlID) +{ + // Temporary link assignment (till final link assignment is known - + // eventually taken from CCDB) + // - Link (0-5) and C-RORC ID linear with ddlID + return std::make_tuple(ddlID / 6, ddlID % 6); +} + std::vector RawWriter::encodeBunchData(const std::vector& data) { std::vector encoded; From 28a387365ca7a76c471ea6304db6f64896f4410a Mon Sep 17 00:00:00 2001 From: Markus Fasel Date: Mon, 27 Jul 2020 18:27:09 +0200 Subject: [PATCH 2/5] [EMCAL-610, EMCAL-661] Add stand-alone application for digits to raw conversion Stand alone application reading digits file and processing digits to raw conversion for each timeframe entry in the digits tree. Open points: - First IR need to be specified for methods in RawFileWriter - Raw writer settings to come from the CCDB --- Detectors/EMCAL/simulation/CMakeLists.txt | 5 ++ Detectors/EMCAL/simulation/src/RawCreator.cxx | 86 +++++++++++++++++++ Detectors/EMCAL/simulation/src/RawWriter.cxx | 2 +- 3 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 Detectors/EMCAL/simulation/src/RawCreator.cxx diff --git a/Detectors/EMCAL/simulation/CMakeLists.txt b/Detectors/EMCAL/simulation/CMakeLists.txt index db2953b1a0f8b..dfb2b600a5180 100644 --- a/Detectors/EMCAL/simulation/CMakeLists.txt +++ b/Detectors/EMCAL/simulation/CMakeLists.txt @@ -24,4 +24,9 @@ o2_target_root_dictionary(EMCALSimulation include/EMCALSimulation/SimParam.h include/EMCALSimulation/LabeledDigit.h) +o2_add_executable(rawcreator + COMPONENT_NAME emcal + PUBLIC_LINK_LIBRARIES O2::EMCALSimulation + SOURCES src/RawCreator.cxx) + o2_data_file(COPY data DESTINATION Detectors/EMC/simulation) diff --git a/Detectors/EMCAL/simulation/src/RawCreator.cxx b/Detectors/EMCAL/simulation/src/RawCreator.cxx new file mode 100644 index 0000000000000..6ccb75bd1650f --- /dev/null +++ b/Detectors/EMCAL/simulation/src/RawCreator.cxx @@ -0,0 +1,86 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#include +#include + +#include + +#include +#include +#include + +#include "DataFormatsEMCAL/Digit.h" +#include "DataFormatsEMCAL/TriggerRecord.h" +#include "EMCALBase/Geometry.h" +#include "EMCALSimulation/RawWriter.h" + +namespace bpo = boost::program_options; + +int main(int argc, const char** argv) +{ + bpo::variables_map vm; + bpo::options_description opt_general("Usage:\n " + std::string(argv[0]) + + " \n" + " Tool will encode emcal raw data from input file\n" + "Commands / Options"); + bpo::options_description opt_hidden(""); + bpo::options_description opt_all; + bpo::positional_options_description opt_pos; + + try { + auto add_option = opt_general.add_options(); + add_option("help,h", "Print this help message"); + add_option("verbose,v", bpo::value()->default_value(0), "Select verbosity level [0 = no output]"); + add_option("input-file,i", bpo::value()->required(), "Specifies digit input file."); + add_option("output-file,o", bpo::value()->required(), "Specifies raw ouput file."); + add_option("debug,d", bpo::value()->default_value(0), "Select debug output level [0 = no debug output]"); + + opt_all.add(opt_general).add(opt_hidden); + bpo::store(bpo::command_line_parser(argc, argv).options(opt_all).positional(opt_pos).run(), vm); + + if (vm.count("help") || argc == 1) { + std::cout << opt_general << std::endl; + exit(0); + } + + } catch (bpo::error& e) { + std::cerr << "ERROR: " << e.what() << std::endl + << std::endl; + std::cerr << opt_general << std::endl; + exit(1); + } catch (std::exception& e) { + std::cerr << e.what() << ", application will now exit" << std::endl; + exit(2); + } + + auto digitfilename = vm["input-file"].as(), + rawfilename = vm["output-file"].as(); + + std::unique_ptr digitfile(TFile::Open(digitfilename.data(), "READ")); + auto treereader = std::make_unique(static_cast(digitfile->Get("o2sim"))); + TTreeReaderValue> digitbranch(*treereader, "EMCALDigit"); + TTreeReaderValue> triggerbranch(*treereader, "EMCALDigitTRGR"); + + // @TODO Initialize start Interaction record for methods in RawFileReader + + o2::emcal::RawWriter rawwriter; + rawwriter.setRawFileName(rawfilename.data()); + rawwriter.setGeometry(o2::emcal::Geometry::GetInstanceFromRunNumber(300000)); + rawwriter.setNumberOfADCSamples(15); // @TODO Needs to come from CCDB + rawwriter.setPedestal(0); // @TODO Needs to come from CCDB + rawwriter.init(); + + // Loop over all entries in the tree, where each tree entry corresponds to a time frame + for (auto en : *treereader) { + rawwriter.processTimeFrame(*digitbranch, *triggerbranch); + } +} \ No newline at end of file diff --git a/Detectors/EMCAL/simulation/src/RawWriter.cxx b/Detectors/EMCAL/simulation/src/RawWriter.cxx index 1ea511911b038..d4f9775bb5e32 100644 --- a/Detectors/EMCAL/simulation/src/RawWriter.cxx +++ b/Detectors/EMCAL/simulation/src/RawWriter.cxx @@ -25,7 +25,7 @@ void RawWriter::setTriggerRecords(gsl::span triggers) void RawWriter::init() { - mRawWriter = std::make_unique(o2::header::gDataOriginEMC); + mRawWriter = std::make_unique(o2::header::gDataOriginEMC, false); for (auto iddl = 0; iddl < 40; iddl++) { // For EMCAL set // - FEE ID = DDL ID From 6b51a5c3712119b79f08eb311b2907b6ec968345 Mon Sep 17 00:00:00 2001 From: Markus Fasel Date: Tue, 18 Aug 2020 20:24:02 +0200 Subject: [PATCH 3/5] [EMCAL-610] Use carryOverMethod in order to append RCU trailer to each raw page CarryOverMethod cuts the payload in size - size of the RCU trailer and adds the RCU trailer from the last page, in which the payload size is adapted to the size in the page. --- .../include/EMCALSimulation/RawWriter.h | 4 +++ Detectors/EMCAL/simulation/src/RawWriter.cxx | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/Detectors/EMCAL/simulation/include/EMCALSimulation/RawWriter.h b/Detectors/EMCAL/simulation/include/EMCALSimulation/RawWriter.h index 0e0afad12e85d..4a74b207a4aa2 100644 --- a/Detectors/EMCAL/simulation/include/EMCALSimulation/RawWriter.h +++ b/Detectors/EMCAL/simulation/include/EMCALSimulation/RawWriter.h @@ -93,6 +93,10 @@ class RawWriter void processTimeFrame(gsl::span digits, gsl::span triggers); bool processNextTrigger(); + int carryOverMethod(const header::RDHAny* rdh, const gsl::span data, + const char* ptr, int maxSize, int splitID, + std::vector& trailer, std::vector& header) const; + protected: std::vector findBunches(const std::vector& channelDigits); std::tuple getOnlineID(int towerID); diff --git a/Detectors/EMCAL/simulation/src/RawWriter.cxx b/Detectors/EMCAL/simulation/src/RawWriter.cxx index d4f9775bb5e32..d0ef70692975f 100644 --- a/Detectors/EMCAL/simulation/src/RawWriter.cxx +++ b/Detectors/EMCAL/simulation/src/RawWriter.cxx @@ -26,6 +26,7 @@ void RawWriter::setTriggerRecords(gsl::span triggers) void RawWriter::init() { mRawWriter = std::make_unique(o2::header::gDataOriginEMC, false); + mRawWriter->setCarryOverCallBack(this); for (auto iddl = 0; iddl < 40; iddl++) { // For EMCAL set // - FEE ID = DDL ID @@ -244,4 +245,29 @@ std::vector RawWriter::createRCUTrailer(int payloadsize, int feca, int fec std::vector encoded(trailerwords.size() * sizeof(uint32_t)); memcpy(encoded.data(), trailerwords.data(), trailerwords.size() * sizeof(uint32_t)); return encoded; +} + + +int RawWriter::carryOverMethod(const header::RDHAny* rdh, const gsl::span data, + const char* ptr, int maxSize, int splitID, + std::vector& trailer, std::vector& header) const { + int offs = ptr - &data[0]; // offset wrt the head of the payload + // make sure ptr and end of the suggested block are within the payload + assert(offs >= 0 && size_t(offs + maxSize) <= data.size()); + + // Read trailer template from the end of payload + gsl::span payloadwords(reinterpret_cast(data.data()), data.size()/sizeof(uint32_t)); + auto rcutrailer = RCUTrailer::constructFromPayloadWords(payloadwords); + + int actualSize = maxSize - rcutrailer.getTrailerSize(); + // calculate payload size for RCU trailer: + // assume actualsize is in byte + // Payload size is defined as the number of 10bit words in 32-bit payload + // -> actualSize to be converted to size of 32 bit words + auto payloadsize = actualSize / sizeof(uint32_t) * 3; + rcutrailer.setPayloadSize(payloadsize); + auto trailerwords = rcutrailer.encode(); + trailer.resize(trailerwords.size() * sizeof(uint32_t)); + memcpy(trailer.data(), trailerwords.data(), trailer.size()); + return actualSize; } \ No newline at end of file From 805b996e52a9de3d6de7da1717faaba46690322c Mon Sep 17 00:00:00 2001 From: Markus Fasel Date: Wed, 19 Aug 2020 10:51:13 +0200 Subject: [PATCH 4/5] [EMCAL-610] Add option to split to multiple files - Add option to split to file per full detector, subdector or crorc+link - Change rawfile to output location in order to support multiple raw files - Add parising of the configuration file in order to configure tf handling - Add writing of the output config - Remove obsolete classes --- Detectors/EMCAL/simulation/CMakeLists.txt | 3 +- .../include/EMCALSimulation/DMAOutputStream.h | 126 -------------- .../EMCALSimulation/RawOutputPageHandler.h | 162 ------------------ .../include/EMCALSimulation/RawWriter.h | 21 ++- .../EMCAL/simulation/src/DMAOutputStream.cxx | 91 ---------- .../simulation/src/EMCALSimulationLinkDef.h | 2 - Detectors/EMCAL/simulation/src/RawCreator.cxx | 26 ++- .../simulation/src/RawOutputPageHandler.cxx | 83 --------- Detectors/EMCAL/simulation/src/RawWriter.cxx | 32 +++- 9 files changed, 62 insertions(+), 484 deletions(-) delete mode 100644 Detectors/EMCAL/simulation/include/EMCALSimulation/DMAOutputStream.h delete mode 100644 Detectors/EMCAL/simulation/include/EMCALSimulation/RawOutputPageHandler.h delete mode 100644 Detectors/EMCAL/simulation/src/DMAOutputStream.cxx delete mode 100644 Detectors/EMCAL/simulation/src/RawOutputPageHandler.cxx diff --git a/Detectors/EMCAL/simulation/CMakeLists.txt b/Detectors/EMCAL/simulation/CMakeLists.txt index dfb2b600a5180..6149eeda5bda5 100644 --- a/Detectors/EMCAL/simulation/CMakeLists.txt +++ b/Detectors/EMCAL/simulation/CMakeLists.txt @@ -11,7 +11,7 @@ o2_add_library(EMCALSimulation SOURCES src/Detector.cxx src/Digitizer.cxx src/DigitizerTask.cxx src/SpaceFrame.cxx src/SimParam.cxx src/LabeledDigit.cxx - src/RawWriter.cxx src/DMAOutputStream.cxx src/RawOutputPageHandler.cxx + src/RawWriter.cxx PUBLIC_LINK_LIBRARIES O2::EMCALBase O2::DetectorsBase O2::SimConfig O2::SimulationDataFormat O2::Headers O2::DetectorsRaw) o2_target_root_dictionary(EMCALSimulation @@ -19,7 +19,6 @@ o2_target_root_dictionary(EMCALSimulation include/EMCALSimulation/Digitizer.h include/EMCALSimulation/DigitizerTask.h include/EMCALSimulation/RawWriter.h - include/EMCALSimulation/DMAOutputStream.h include/EMCALSimulation/SpaceFrame.h include/EMCALSimulation/SimParam.h include/EMCALSimulation/LabeledDigit.h) diff --git a/Detectors/EMCAL/simulation/include/EMCALSimulation/DMAOutputStream.h b/Detectors/EMCAL/simulation/include/EMCALSimulation/DMAOutputStream.h deleted file mode 100644 index 8bbc036732338..0000000000000 --- a/Detectors/EMCAL/simulation/include/EMCALSimulation/DMAOutputStream.h +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#ifndef ALICEO2_EMCAL_DMAOUTPUTSTREAM_H -#define ALICEO2_EMCAL_DMAOUTPUTSTREAM_H - -#include -#include -#include - -#include - -#include "Rtypes.h" -#include "RStringView.h" - -#include "Headers/RAWDataHeader.h" - -namespace o2 -{ - -namespace emcal -{ - -/// \class DMAOutputStream -/// \brief Output stream of a payload to DMA raw files -/// \ingroup EMCALsimulation -/// \author Markus Fasel , Oak Ridge National Laboratory -/// \since Nov 6, 2019 -/// -/// Stream of output payload with variable size to DMA pages in -/// a binary raw file. The output payload can be larger than the -/// size of a DMA page (default: 8 kB) the output is split into -/// multiple pages. Page counter, memory size, page size and -/// stop bit are handled internally and are overwritten in the -/// raw data header provided. All other header information must be -/// handled externally. -class DMAOutputStream -{ - public: - using RawHeader = o2::header::RAWDataHeaderV4; - - class OutputFileException : public std::exception - { - public: - OutputFileException() = default; - OutputFileException(const std::string_view filename) : std::exception(), mFilePath(filename), mMessage("Path \"" + mFilePath + "\" invalid") {} - ~OutputFileException() noexcept final = default; - - const char* what() const noexcept final - { - return mMessage.data(); - } - - private: - std::string mFilePath = ""; - std::string mMessage = ""; - }; - - /// \brief Constructor - DMAOutputStream() = default; - - /// \brief Constructor - /// \param filename Name of the output file - DMAOutputStream(const char* filename); - - /// \brief Destructor - /// - /// Closing file I/O - ~DMAOutputStream(); - - /// \brief Open the output stream - /// \throw OutputFileException - /// - /// Opening output file I/O - void open(); - - /// \brief Set the name of the output file - /// \param filename Name of the output file - void setOutputFilename(const char* filename) { mFilename = filename; } - - /// \brief Write output payload to the output stream - /// \param header Raw data header - /// \param buffer Raw data payload - /// \return Current page count - /// - /// Converting output payload to DMA papges. If the payload is larger than - /// the pagesize - header size the payload is automatically split to multiple - /// pages. Page counter, memory size, page size and stop bit of the header are - /// handled internally and are overwritten from the header provided. All other - /// header information must be provided externally. - int writeData(RawHeader header, gsl::span buffer); - - /// \brief Write single raw data header - /// \param header raw data header - /// - /// Write header with no payload assinged. Function is used for writing - /// open/close header of the timeframe - void writeSingleHeader(const RawHeader& header); - - protected: - /// \brief Write DMA page - /// \param header Raw data header for page - /// \param payload Page payload (includes size of teh payload) - /// \param pagesize Size of the DMA page (not size of the payload) - /// - /// Expects that the size of the payload is smaller than the size ot the DMA - /// page. Parameter pagesize supporting variable page size. - void writeDMAPage(const RawHeader& header, gsl::span payload, int pagesize); - - private: - std::string mFilename = ""; ///< Name of the output file - std::ofstream mOutputFile; ///< Handler for output raw file - bool mInitialized = false; ///< Switch for whether the output stream is initialized - - ClassDefNV(DMAOutputStream, 1); -}; -} // namespace emcal -} // namespace o2 - -#endif \ No newline at end of file diff --git a/Detectors/EMCAL/simulation/include/EMCALSimulation/RawOutputPageHandler.h b/Detectors/EMCAL/simulation/include/EMCALSimulation/RawOutputPageHandler.h deleted file mode 100644 index 7417bfec6380e..0000000000000 --- a/Detectors/EMCAL/simulation/include/EMCALSimulation/RawOutputPageHandler.h +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include -#include -#include -#include -#include -#include - -namespace o2 -{ -namespace emcal -{ - -/// \class RawOutputPageHandler -/// \brief Handler for EMCAL raw page buffering, timeframe building and output streaming -/// \ingroup EMCALsimulation -/// \author Markus Fasel , Oak Ridge National Laboratory -/// \since March 22, 2020 -/// -/// # General -/// The raw format for EMCAL consists of separate superpages of timeframes arranged per -/// (DDL) link. Each timeframe consists of -/// - Empty RDH without payload indicating start of timeframe. Counters are reset -/// - Pages with RDH and payload for each trigger BC within the timeframe -/// - Empty RDH without payload indicating end of timeframe. Contains the number of pages -/// in the timeframe, the stop bit and the timeframe trigger. -/// At the start of data an empty timeframe (without pages) consisting only of star and stop -/// RDH will mark the beginning of the data stream. -/// -/// # Usage -/// For each new trigger the function initTrigger is to be called with the InteractionRecord -/// of the bunch crossing corresponding to the trigger. Pages created by the raw writer and added -/// via addPageForLink are buffered per link. The HBFUtils, provided from outside, decide on whether -/// a new timeframe is triggered. In case of a new timeframe raw timeframes are created for all -/// links with pages, containing all pages of a link and streamed to file (in initTrigger). In case -/// the buffer still contains pages when the destructor is called, the pages are streamed as remaining -/// pages of the last timeframe (in the destructor). -class RawOutputPageHandler -{ - public: - using RawHeader = o2::header::RAWDataHeaderV4; - - /// \class LinkIDException - /// \brief Exception handling invalid link IDs (outside the range of EMCAL links) - class LinkIDException : public std::exception - { - public: - /// \brief Constructor, defining - LinkIDException(int linkID); - - /// \brief Destructor - ~LinkIDException() noexcept final = default; - - /// \brief Access to error message of the exception - /// \return Error message of the exception - const char* what() const noexcept final { return mMessage.data(); } - - /// \brief Access to Link ID raising the exception - /// \return Link ID raising the exception - int getLinkID() const { return mLinkID; } - - private: - int mLinkID; ///< ID of the link raising the exception - std::string mMessage; ///< Error message; - }; - - /// \class RawPageBuffer - /// \brief Buffer for raw pages - /// - /// Internal helper class for buffering raw pages within a timeframe for a certain link. - /// The functionality consists of: - /// - add page: adding new page to the raw buffer - /// - getPages: access to all pages. Mainly used when building the timeframe - /// - flush: clear buffer (after timeframe building) - class RawPageBuffer - { - public: - /// \struct PageData - /// \brief Structure for a raw page (header and payload words) - struct PageData { - RawHeader mHeader; ///< Header template of the page, containing link ID, fee ID and trigger - std::vector mPage; ///< Payload page - }; - - /// \brief Constructor - RawPageBuffer() = default; - - /// \brief Destructor - ~RawPageBuffer() = default; - - /// \brief Adding new raw page to the page buffer - /// \brief header Template raw header, containing link/fee ID and trigger - /// \brief page Raw page (as char words) to be added to the buffer - void addPage(const RawHeader& header, const std::vector& page) { mPages.push_back({header, page}); } - - /// \brief Cleaning page buffer - void flush() { mPages.clear(); } - - /// \brief Access to pages in the buffer - /// \return vector with all pages in the buffer - const std::vector& getPages() const { return mPages; } - - private: - std::vector mPages; ///< Buffer for pages - }; - - /// \brief Constructor, initializing page handler with output filename and HBF utils - /// \param rawfilename Name of the output file - RawOutputPageHandler(const char* rawfilename); - - /// \brief Destructor - /// - /// In case buffers contain payload the page is streamed as last - /// timeframe for the links containing payload pages. - ~RawOutputPageHandler(); - - /// \brief Initialize new trigger - /// \param currentIR Interaction record of the collision triggering - /// - /// Initialize new trigger. In case the Timeframe changes with the trigger - /// the buffers belonging to the previous buffer are streamed to file. For - /// each link a separate timeframe is created, starting with empty open/close - /// raw data header. Timeframes are only created for links which buffer pages. - void initTrigger(const o2::InteractionRecord& currentIR); - - /// \brief Add new page for link to the page buffer - /// \param linkID ID of the link - /// \param header Template raw header of the page - /// \param dmapage Payload page - /// \throw LinkIDException in case link ID is invalid - void addPageForLink(int linkID, const RawHeader& header, const std::vector& dmapage); - - private: - /// \brief Write timeframe for an entire link - /// \param linkID ID of the link - /// \param pagebuffer Buffer with raw pages in timeframe belonging to the link - /// - /// Timeframes for raw data in EMCAL contain: - /// - Empty RDH, indicating start of timeframe. No payload assigned. Counters 0 - /// - Raw page for every trigger in the timeframe: Each raw page starts with a - /// RDH. In case the payload exceeds the 8 kB page it is split into multiple - /// pages. The page counter is calculated with respect to the first header in a - /// timeframe - /// - Empty RDH, closing the timeframe, containing the number of pages in the - /// timeframe - void writeTimeframe(int linkID, const RawPageBuffer& pagebuffer); - - int mCurrentTimeframe = -1; ///< Current timeframe ID (needed to detect whether a new timeframe starts) - std::map mRawPages; ///< Buffer with raw pages for all links - DMAOutputStream mOutputStream; ///< File output stream -}; -} // namespace emcal -} // namespace o2 \ No newline at end of file diff --git a/Detectors/EMCAL/simulation/include/EMCALSimulation/RawWriter.h b/Detectors/EMCAL/simulation/include/EMCALSimulation/RawWriter.h index 4a74b207a4aa2..a9e1c2632ef2f 100644 --- a/Detectors/EMCAL/simulation/include/EMCALSimulation/RawWriter.h +++ b/Detectors/EMCAL/simulation/include/EMCALSimulation/RawWriter.h @@ -75,12 +75,20 @@ union CaloBunchWord { class RawWriter { public: + enum class FileFor_t { + kFullDet, + kSubDet, + kLink + }; RawWriter() = default; - RawWriter(const char* rawfilename) { setRawFileName(rawfilename); } + RawWriter(const char* outputdir) { setOutputLocation(outputdir); } ~RawWriter() = default; - void setRawFileName(const char* filename) { mRawFilename = filename; } + o2::raw::RawFileWriter& getWriter() const { return *mRawWriter; } + + void setOutputLocation(const char* outputdir) { mOutputLocation = outputdir; } void setDigits(gsl::span digits) { mDigits = digits; } + void setFileFor(FileFor_t filefor) { mFileFor = filefor; } void setTriggerRecords(gsl::span triggers); void setNumberOfADCSamples(int nsamples) { mNADCSamples = nsamples; } void setPedestal(int pedestal) { mPedestal = pedestal; } @@ -90,12 +98,12 @@ class RawWriter void init(); void process(); - void processTimeFrame(gsl::span digits, gsl::span triggers); + void digitsToRaw(gsl::span digits, gsl::span triggers); bool processNextTrigger(); int carryOverMethod(const header::RDHAny* rdh, const gsl::span data, - const char* ptr, int maxSize, int splitID, - std::vector& trailer, std::vector& header) const; + const char* ptr, int maxSize, int splitID, + std::vector& trailer, std::vector& header) const; protected: std::vector findBunches(const std::vector& channelDigits); @@ -109,8 +117,9 @@ class RawWriter private: int mNADCSamples = 15; ///< Number of time samples int mPedestal = 0; ///< Pedestal + FileFor_t mFileFor = FileFor_t::kFullDet; ///< Granularity of the output files o2::emcal::Geometry* mGeometry = nullptr; ///< EMCAL geometry - std::string mRawFilename; ///< Rawfile name + std::string mOutputLocation; ///< Rawfile name std::array mMappers; ///< EMCAL mappers gsl::span mDigits; ///< Digits input vector - must be in digitized format including the time response gsl::span mTriggers; ///< Trigger records, separating the data from different triggers diff --git a/Detectors/EMCAL/simulation/src/DMAOutputStream.cxx b/Detectors/EMCAL/simulation/src/DMAOutputStream.cxx deleted file mode 100644 index 6211b0a9f6755..0000000000000 --- a/Detectors/EMCAL/simulation/src/DMAOutputStream.cxx +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "EMCALSimulation/DMAOutputStream.h" - -using namespace o2::emcal; - -DMAOutputStream::DMAOutputStream(const char* filename) : mFilename(filename) {} - -DMAOutputStream::~DMAOutputStream() -{ - if (mOutputFile.is_open()) - mOutputFile.close(); -} - -void DMAOutputStream::open() -{ - if (!mOutputFile.is_open()) { - if (!mFilename.length()) - throw OutputFileException(mFilename); - mOutputFile.open(mFilename, std::ios::out | std::ios::binary); - mInitialized = true; - } -} - -void DMAOutputStream::writeSingleHeader(const RawHeader& header) -{ - if (!mInitialized) - open(); - std::vector outputpage(sizeof(RawHeader)); - RawHeader* outputheader = reinterpret_cast(outputpage.data()); - *outputheader = header; - outputheader->memorySize = sizeof(RawHeader); - outputheader->offsetToNext = sizeof(RawHeader); - mOutputFile.write(outputpage.data(), outputpage.size()); -} - -int DMAOutputStream::writeData(RawHeader header, gsl::span buffer) -{ - if (!mInitialized) - open(); - - constexpr int PAGESIZE = 8192; - // Handling of the termination word (0x001d3082): The termination word is added to the payload - // but not included in the payload size (as done in the hardware). Therefore it has to be subtracted - // from the maximum possible payload size - constexpr int MAXNWORDS = PAGESIZE - sizeof(header) - sizeof(uint32_t); - bool writeNext = true; - int pagecounter = header.pageCnt, currentindex = 0; - while (writeNext) { - int sizeRemain = buffer.size() - currentindex; - int nwordspage = MAXNWORDS; - if (sizeRemain < MAXNWORDS) { - // Last page - nwordspage = sizeRemain; - writeNext = false; - } - header.pageCnt = pagecounter; - header.memorySize = nwordspage + sizeof(RawHeader); - header.offsetToNext = 8192; - - writeDMAPage(header, gsl::span(buffer.data() + currentindex, nwordspage), PAGESIZE); - - if (writeNext) { - currentindex += nwordspage; - } - pagecounter++; - } - return pagecounter; -} - -void DMAOutputStream::writeDMAPage(const RawHeader& header, gsl::span payload, int pagesize) -{ - std::vector dmapage(pagesize); - RawHeader* outheader = reinterpret_cast(dmapage.data()); - *outheader = header; - char* outpayload = dmapage.data() + sizeof(header); - memcpy(outpayload, payload.data(), payload.size()); - // Write termination character - uint32_t terminationCharacter = 0x001d3082; - char* terminationString = reinterpret_cast(&terminationCharacter); - memcpy(outpayload + payload.size(), terminationString, sizeof(uint32_t)); - mOutputFile.write(dmapage.data(), dmapage.size()); -} \ No newline at end of file diff --git a/Detectors/EMCAL/simulation/src/EMCALSimulationLinkDef.h b/Detectors/EMCAL/simulation/src/EMCALSimulationLinkDef.h index 21d1a42246d59..461faa35bf6c0 100644 --- a/Detectors/EMCAL/simulation/src/EMCALSimulationLinkDef.h +++ b/Detectors/EMCAL/simulation/src/EMCALSimulationLinkDef.h @@ -18,11 +18,9 @@ #pragma link C++ class o2::base::DetImpl < o2::emcal::Detector> + ; #pragma link C++ class o2::emcal::Digitizer + ; #pragma link C++ class o2::emcal::DigitizerTask + ; -#pragma link C++ class o2::emcal::DMAOutputStream + ; #pragma link C++ class o2::emcal::SimParam + ; #pragma link C++ class o2::emcal::LabeledDigit + ; #pragma link C++ class o2::emcal::RawWriter + ; -#pragma link C++ class o2::emcal::DMAOutputStream + ; #pragma link C++ class std::list < o2::emcal::LabeledDigit > +; diff --git a/Detectors/EMCAL/simulation/src/RawCreator.cxx b/Detectors/EMCAL/simulation/src/RawCreator.cxx index 6ccb75bd1650f..149f0f624281f 100644 --- a/Detectors/EMCAL/simulation/src/RawCreator.cxx +++ b/Detectors/EMCAL/simulation/src/RawCreator.cxx @@ -18,6 +18,8 @@ #include #include +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/StringUtils.h" #include "DataFormatsEMCAL/Digit.h" #include "DataFormatsEMCAL/TriggerRecord.h" #include "EMCALBase/Geometry.h" @@ -41,8 +43,10 @@ int main(int argc, const char** argv) add_option("help,h", "Print this help message"); add_option("verbose,v", bpo::value()->default_value(0), "Select verbosity level [0 = no output]"); add_option("input-file,i", bpo::value()->required(), "Specifies digit input file."); - add_option("output-file,o", bpo::value()->required(), "Specifies raw ouput file."); + add_option("file-for,f", bpo::value()->default_value("all"), "single file per: all,subdet,link"); + add_option("output-dir,o", bpo::value()->default_value("./"), "output directory for raw data"); add_option("debug,d", bpo::value()->default_value(0), "Select debug output level [0 = no debug output]"); + add_option("configKeyValues", bpo::value()->default_value(""), "comma-separated configKeyValues"); opt_all.add(opt_general).add(opt_hidden); bpo::store(bpo::command_line_parser(argc, argv).options(opt_all).positional(opt_pos).run(), vm); @@ -62,18 +66,29 @@ int main(int argc, const char** argv) exit(2); } + o2::conf::ConfigurableParam::updateFromString(vm["configKeyValues"].as()); + auto digitfilename = vm["input-file"].as(), - rawfilename = vm["output-file"].as(); + outputdir = vm["output-dir"].as(), + filefor = vm["file-for"].as(); std::unique_ptr digitfile(TFile::Open(digitfilename.data(), "READ")); auto treereader = std::make_unique(static_cast(digitfile->Get("o2sim"))); TTreeReaderValue> digitbranch(*treereader, "EMCALDigit"); TTreeReaderValue> triggerbranch(*treereader, "EMCALDigitTRGR"); - // @TODO Initialize start Interaction record for methods in RawFileReader + o2::emcal::RawWriter::FileFor_t granularity = o2::emcal::RawWriter::FileFor_t::kFullDet; + if (filefor == "all") { + granularity = o2::emcal::RawWriter::FileFor_t::kFullDet; + } else if (filefor == "subdet") { + granularity = o2::emcal::RawWriter::FileFor_t::kSubDet; + } else if (filefor == "link") { + granularity = o2::emcal::RawWriter::FileFor_t::kLink; + } o2::emcal::RawWriter rawwriter; - rawwriter.setRawFileName(rawfilename.data()); + rawwriter.setOutputLocation(outputdir.data()); + rawwriter.setFileFor(granularity); rawwriter.setGeometry(o2::emcal::Geometry::GetInstanceFromRunNumber(300000)); rawwriter.setNumberOfADCSamples(15); // @TODO Needs to come from CCDB rawwriter.setPedestal(0); // @TODO Needs to come from CCDB @@ -81,6 +96,7 @@ int main(int argc, const char** argv) // Loop over all entries in the tree, where each tree entry corresponds to a time frame for (auto en : *treereader) { - rawwriter.processTimeFrame(*digitbranch, *triggerbranch); + rawwriter.digitsToRaw(*digitbranch, *triggerbranch); } + rawwriter.getWriter().writeConfFile("EMC", "RAWDATA", o2::utils::concat_string(outputdir, "raw.cfg")); } \ No newline at end of file diff --git a/Detectors/EMCAL/simulation/src/RawOutputPageHandler.cxx b/Detectors/EMCAL/simulation/src/RawOutputPageHandler.cxx deleted file mode 100644 index 87019c239a00d..0000000000000 --- a/Detectors/EMCAL/simulation/src/RawOutputPageHandler.cxx +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include -#include -#include -#include - -using namespace o2::emcal; - -RawOutputPageHandler::RawOutputPageHandler(const char* rawfilename) : mOutputStream(rawfilename), mCurrentTimeframe(-1) -{ - // create page buffers for all (40) links - for (int ilink = 0; ilink < 40; ilink++) - mRawPages[ilink] = RawPageBuffer(); - mOutputStream.open(); -} - -RawOutputPageHandler::~RawOutputPageHandler() -{ - // write pages for last timeframe to file - for (const auto& [linkID, pagebuffer] : mRawPages) { - // only write pages for links which send data - if (pagebuffer.getPages().size()) - writeTimeframe(linkID, pagebuffer); - } -} - -void RawOutputPageHandler::initTrigger(const o2::InteractionRecord& irtrigger) -{ - auto currenttimeframe = raw::HBFUtils::Instance().getTF(irtrigger); - if (currenttimeframe != mCurrentTimeframe) { - // write pages to file - for (auto& [linkID, pagebuffer] : mRawPages) { - // only write pages for links which send data - if (pagebuffer.getPages().size()) - writeTimeframe(linkID, pagebuffer); - pagebuffer.flush(); - } - // set the new timeframe - mCurrentTimeframe = currenttimeframe; - } -} - -void RawOutputPageHandler::writeTimeframe(int linkID, const RawPageBuffer& pagebuffer) -{ - // write pages to file - // Write timeframe open - RawHeader timeframeheader; - timeframeheader.linkID = linkID; - mOutputStream.writeSingleHeader(timeframeheader); - int pagecounter = 1; - for (const auto& page : pagebuffer.getPages()) { - auto header = page.mHeader; - header.pageCnt = pagecounter; - pagecounter = mOutputStream.writeData(header, gsl::span(page.mPage.data(), page.mPage.size())); - } - - // end of timeframe - timeframeheader.pageCnt = pagecounter; - timeframeheader.stop = 1; - timeframeheader.triggerType = o2::trigger::TF; - mOutputStream.writeSingleHeader(timeframeheader); -} - -void RawOutputPageHandler::addPageForLink(int linkID, const RawHeader& header, const std::vector& page) -{ - if (linkID > 40) - throw LinkIDException(linkID); - mRawPages[linkID].addPage(header, page); -} - -RawOutputPageHandler::LinkIDException::LinkIDException(int linkID) : std::exception(), mLinkID(linkID), mMessage() -{ - mMessage = fmt::format("Link ID invalid: %d (max 40)", linkID); -} \ No newline at end of file diff --git a/Detectors/EMCAL/simulation/src/RawWriter.cxx b/Detectors/EMCAL/simulation/src/RawWriter.cxx index d0ef70692975f..f9d14cf42d2e1 100644 --- a/Detectors/EMCAL/simulation/src/RawWriter.cxx +++ b/Detectors/EMCAL/simulation/src/RawWriter.cxx @@ -8,6 +8,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include #include #include #include "DataFormatsEMCAL/Constants.h" @@ -34,7 +35,24 @@ void RawWriter::init() // @TODO replace with link assignment on production FLPs, // eventually storing in CCDB auto [crorc, link] = getLinkAssignment(iddl); - mRawWriter->registerLink(iddl, crorc, link, 0, mRawFilename.data()); + std::string rawfilename = mOutputLocation; + switch (mFileFor) { + case FileFor_t::kFullDet: + rawfilename += "/emcal.root"; + break; + case FileFor_t::kSubDet: { + std::string detstring; + if (iddl < 22) + detstring = "emcal"; + else + detstring = "dcal"; + rawfilename += fmt::format("/%s", detstring.data()); + break; + }; + case FileFor_t::kLink: + rawfilename += fmt::format("/emcal_%d_%d.root", crorc, link); + } + mRawWriter->registerLink(iddl, crorc, link, 0, rawfilename.data()); } // initialize mappers std::array sides = {{'A', 'C'}}; @@ -58,7 +76,7 @@ void RawWriter::process() ; } -void RawWriter::processTimeFrame(gsl::span digitsbranch, gsl::span triggerbranch) +void RawWriter::digitsToRaw(gsl::span digitsbranch, gsl::span triggerbranch) { setDigits(digitsbranch); setTriggerRecords(triggerbranch); @@ -247,22 +265,22 @@ std::vector RawWriter::createRCUTrailer(int payloadsize, int feca, int fec return encoded; } - int RawWriter::carryOverMethod(const header::RDHAny* rdh, const gsl::span data, - const char* ptr, int maxSize, int splitID, - std::vector& trailer, std::vector& header) const { + const char* ptr, int maxSize, int splitID, + std::vector& trailer, std::vector& header) const +{ int offs = ptr - &data[0]; // offset wrt the head of the payload // make sure ptr and end of the suggested block are within the payload assert(offs >= 0 && size_t(offs + maxSize) <= data.size()); // Read trailer template from the end of payload - gsl::span payloadwords(reinterpret_cast(data.data()), data.size()/sizeof(uint32_t)); + gsl::span payloadwords(reinterpret_cast(data.data()), data.size() / sizeof(uint32_t)); auto rcutrailer = RCUTrailer::constructFromPayloadWords(payloadwords); int actualSize = maxSize - rcutrailer.getTrailerSize(); // calculate payload size for RCU trailer: // assume actualsize is in byte - // Payload size is defined as the number of 10bit words in 32-bit payload + // Payload size is defined as the number of 10bit words in 32-bit payload // -> actualSize to be converted to size of 32 bit words auto payloadsize = actualSize / sizeof(uint32_t) * 3; rcutrailer.setPayloadSize(payloadsize); From c263d6c0be6109dad155cbcf18fd28b31196c7f0 Mon Sep 17 00:00:00 2001 From: Markus Fasel Date: Thu, 20 Aug 2020 17:43:25 +0200 Subject: [PATCH 5/5] [EMCAL-610] Adapt carryOverMethod in order to adapt payload size of the last RCU trailer Specify also using carryOverMethod for the last page --- Detectors/EMCAL/simulation/src/RawWriter.cxx | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Detectors/EMCAL/simulation/src/RawWriter.cxx b/Detectors/EMCAL/simulation/src/RawWriter.cxx index f9d14cf42d2e1..733953048a33b 100644 --- a/Detectors/EMCAL/simulation/src/RawWriter.cxx +++ b/Detectors/EMCAL/simulation/src/RawWriter.cxx @@ -28,6 +28,7 @@ void RawWriter::init() { mRawWriter = std::make_unique(o2::header::gDataOriginEMC, false); mRawWriter->setCarryOverCallBack(this); + mRawWriter->setApplyCarryOverToLastPage(true); for (auto iddl = 0; iddl < 40; iddl++) { // For EMCAL set // - FEE ID = DDL ID @@ -138,7 +139,7 @@ bool RawWriter::processNextTrigger() } // Create RCU trailer - auto trailerwords = createRCUTrailer(payload.size(), 16, 16, 100., 0.); + auto trailerwords = createRCUTrailer(payload.size() / 4, 16, 16, 100., 0.); for (auto word : trailerwords) payload.emplace_back(word); @@ -277,15 +278,24 @@ int RawWriter::carryOverMethod(const header::RDHAny* rdh, const gsl::span gsl::span payloadwords(reinterpret_cast(data.data()), data.size() / sizeof(uint32_t)); auto rcutrailer = RCUTrailer::constructFromPayloadWords(payloadwords); - int actualSize = maxSize - rcutrailer.getTrailerSize(); + int sizeNoTrailer = maxSize - rcutrailer.getTrailerSize(); // calculate payload size for RCU trailer: // assume actualsize is in byte - // Payload size is defined as the number of 10bit words in 32-bit payload + // Payload size is defined as the number of 32-bit payload words // -> actualSize to be converted to size of 32 bit words - auto payloadsize = actualSize / sizeof(uint32_t) * 3; + auto payloadsize = sizeNoTrailer / sizeof(uint32_t); rcutrailer.setPayloadSize(payloadsize); auto trailerwords = rcutrailer.encode(); trailer.resize(trailerwords.size() * sizeof(uint32_t)); memcpy(trailer.data(), trailerwords.data(), trailer.size()); + // Size to return differs between intermediate pages and last page + // - intermediate page: Size of the trailer needs to be removed as the trailer gets appended + // - last page: Size of the trailer needs to be included as the trailer gets replaced + int bytesLeft = data.size() - (ptr - &data[0]); + bool lastPage = bytesLeft <= maxSize; + int actualSize = maxSize; + if (!lastPage) { + actualSize = sizeNoTrailer; + } return actualSize; } \ No newline at end of file