diff --git a/src/common/kafka/AR51Serializer.cpp b/src/common/kafka/AR51Serializer.cpp index f542a086e933d9611243933e70128918607572d3..4984d2fdcea93349404523274bd60970ad81112c 100644 --- a/src/common/kafka/AR51Serializer.cpp +++ b/src/common/kafka/AR51Serializer.cpp @@ -25,7 +25,7 @@ AR51Serializer::AR51Serializer( } -nonstd::span<const uint8_t> & AR51Serializer::serialize(uint8_t * Data, int DataLength) { +nonstd::span<const uint8_t> & AR51Serializer::serialize(uint8_t *Data, int DataLength) { FBBuilder.Reset(); auto DataBuffer = FBBuilder.CreateVector(Data, DataLength); diff --git a/src/common/kafka/EV44Serializer.h b/src/common/kafka/EV44Serializer.h index 5c55cbc717751051b6489c1414e71d14d064b5eb..fb7601c95c9dcee667121f81c3b9cf90dc3aa763 100644 --- a/src/common/kafka/EV44Serializer.h +++ b/src/common/kafka/EV44Serializer.h @@ -84,6 +84,10 @@ public: TSCTimer ProduceTimer, DebugTimer; + // Counters for causes of calls to produce() + int64_t ProduceCausePulseChange; + int64_t ProduceCauseMaxEventsReached; + private: /// \todo should this not be predefined in terms of jumbo frame? size_t MaxEvents{0}; diff --git a/src/common/time/CMakeLists.txt b/src/common/time/CMakeLists.txt index 791e7acc56845bc2eaa4f161204e179e9187135a..4573fa489a1723f0992426ac3b00857b3d02a336 100644 --- a/src/common/time/CMakeLists.txt +++ b/src/common/time/CMakeLists.txt @@ -10,6 +10,7 @@ set(esstime_obj_SRC Timer.cpp TimeString.cpp TSCTimer.cpp + CheckTimer.cpp ) set(esstime_obj_INC @@ -17,6 +18,7 @@ ESSTime.h Timer.h TimeString.h TSCTimer.h +CheckTimer.h ) add_library(EssTimingLib OBJECT diff --git a/src/common/time/CheckTimer.cpp b/src/common/time/CheckTimer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f6be2245d7ea916353ea91c26be6a89a2cbbf2f0 --- /dev/null +++ b/src/common/time/CheckTimer.cpp @@ -0,0 +1,40 @@ +// Copyright (C) 2024 European Spallation Source, ERIC. See LICENSE file +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// \brief Implementation of the check timer class which uses the standard chrono +/// library to provide a high resolution timer. +//===----------------------------------------------------------------------===// + +#include <common/time/CheckTimer.h> + +/// +CheckTimer::CheckTimer(void) { + reset(); +} + +/// \param Timeout +CheckTimer::CheckTimer(uint64_t Timeout) : TimeoutNS(Timeout) { + reset(); +} + +/// Determine if a timeout has occured and reset timer +bool CheckTimer::timeout(void) { + if (timetsc() >= TimeoutNS) { + reset(); + return true; + } + return false; +} + +/// +void CheckTimer::reset(void) { + T0TimePoint = std::chrono::high_resolution_clock::now(); +} + +/// +uint64_t CheckTimer::timetsc(void) { + auto Now = std::chrono::high_resolution_clock::now(); + return std::chrono::duration_cast<std::chrono::nanoseconds>(Now - T0TimePoint).count(); +} diff --git a/src/common/time/CheckTimer.h b/src/common/time/CheckTimer.h new file mode 100644 index 0000000000000000000000000000000000000000..09b3736fd50574f57457ead2bdebda6313b17130 --- /dev/null +++ b/src/common/time/CheckTimer.h @@ -0,0 +1,37 @@ +// Copyright (C) 2024 European Spallation Source, ERIC. See LICENSE file +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// \brief platform independent equivalent replacement of wrapper for the cheap and fast time stamp counter (TSC) +/// +/// Uses the standard chrono library to provide a high resolution timer. +//===----------------------------------------------------------------------===// + +#pragma once + +#include <chrono> +#include <cstdint> + +class CheckTimer { + +public: + /// Create a check timer without timeout value + CheckTimer(void); + + /// Create a check timer with a timeout value in nanoseconds + CheckTimer(uint64_t TimeOut); + + // Has timeout occurred? Then reset timer + bool timeout(void); + + void reset(void); ///< record current time_point + + uint64_t timetsc(void); ///< time since T0 + +private: + std::chrono::high_resolution_clock::time_point T0TimePoint; + + // If timeout not set use this 'infinite' value + uint64_t TimeoutNS{0xffffffffffffffff}; +}; diff --git a/src/modules/bifrost/geometry/BifrostGeometry.cpp b/src/modules/bifrost/geometry/BifrostGeometry.cpp index 914729d746399a34e525d3c068afdf6658963d82..84a3ba4f2740986d5f56db7ab80d41c083aefd0b 100644 --- a/src/modules/bifrost/geometry/BifrostGeometry.cpp +++ b/src/modules/bifrost/geometry/BifrostGeometry.cpp @@ -16,7 +16,7 @@ namespace Caen { -BifrostGeometry::BifrostGeometry(Config &CaenConfiguration) { + BifrostGeometry::BifrostGeometry(Config &CaenConfiguration) { ESSGeom = new ESSGeometry(900, 15, 1, 1); setResolution(CaenConfiguration.Resolution); MaxRing = CaenConfiguration.MaxRing; @@ -124,4 +124,22 @@ uint32_t BifrostGeometry::calcPixel(DataParser::CaenReadout &Data) { return pixel; } +size_t BifrostGeometry::numSerializers() const { + return TripletsPerRing * (MaxRing + 1); // MaxRing is likely 2 (but [0, 1, 2] are all valid) +} + +size_t BifrostGeometry::calcSerializer(DataParser::CaenReadout &Data) const { + // FiberID = _physical_ Ring (logical_ring/2) + // Group == triplet number + return Data.FiberId / 2 * TripletsPerRing + Data.Group; +} + +std::string BifrostGeometry::serializerName(size_t Index) const { + auto ring_id = Index / TripletsPerRing; + auto tube_id = Index - ring_id * TripletsPerRing; + auto arc = tube_id / 3u; + auto triplet = (tube_id % 3u) + ring_id * 3u; + return fmt::format("arc={};triplet={}", arc, triplet); +} + } // namespace Caen diff --git a/src/modules/bifrost/geometry/BifrostGeometry.h b/src/modules/bifrost/geometry/BifrostGeometry.h index 1f7d552cc4a1141e40b14c1dd6ce6e1b9df52cc2..b0601b36d6f9601955a4a742aa5d6d10f29e443f 100644 --- a/src/modules/bifrost/geometry/BifrostGeometry.h +++ b/src/modules/bifrost/geometry/BifrostGeometry.h @@ -26,13 +26,13 @@ namespace Caen { class BifrostGeometry : public Geometry { public: - BifrostGeometry(Config &CaenConfiguration); + explicit BifrostGeometry(Config &CaenConfiguration); ///\brief virtual method inherited from base class - uint32_t calcPixel(DataParser::CaenReadout &Data); + uint32_t calcPixel(DataParser::CaenReadout &Data) override; ///\brief virtual method inherited from base class - bool validateData(DataParser::CaenReadout &Data); + bool validateData(DataParser::CaenReadout &Data) override; /// \brief return the global x-offset for the given identifiers /// \param Ring logical ring as defined in the ICD @@ -50,6 +50,10 @@ public: /// or (-1, -1.0) if invalid std::pair<int, double> calcUnitAndPos(int Group, int AmpA, int AmpB); + [[nodiscard]] size_t numSerializers() const override; + [[nodiscard]] size_t calcSerializer(DataParser::CaenReadout &Data) const override; + [[nodiscard]] std::string serializerName(size_t Index) const override; + const int UnitsPerGroup{3}; const int TripletsPerRing{15}; int UnitPixellation{100}; ///< Number of pixels along a single He tube. diff --git a/src/modules/caen/CaenBase.cpp b/src/modules/caen/CaenBase.cpp index d294f45a25ca764a9ecb498c3961691ecdd90c9a..05a8bee1430b1eda95cee419084e5834ca0cd958 100644 --- a/src/modules/caen/CaenBase.cpp +++ b/src/modules/caen/CaenBase.cpp @@ -8,17 +8,14 @@ #include <cinttypes> #include <common/RuntimeStat.h> -#include <common/debug/Log.h> -#include <common/debug/Trace.h> #include <common/detector/EFUArgs.h> #include <common/kafka/KafkaConfig.h> -#include <common/system/Socket.h> -#include <common/time/TSCTimer.h> #include <common/time/TimeString.h> #include <common/time/Timer.h> #include <modules/caen/CaenBase.h> #include <modules/caen/CaenInstrument.h> #include <unistd.h> +#include <common/time/CheckTimer.h> // #undef TRC_LEVEL // #define TRC_LEVEL TRC_L_DEB @@ -38,6 +35,7 @@ CaenBase::CaenBase(BaseSettings const &settings, Stats.create("receive.bytes", ITCounters.RxBytes); Stats.create("receive.dropped", ITCounters.FifoPushErrors); Stats.create("receive.fifo_seq_errors", Counters.FifoSeqErrors); + Stats.create("transmit.monitor_packets", Counters.TxRawReadoutPackets); // ESS Readout Stats.create("essheader.error_header", Counters.ErrorESSHeaders); @@ -129,7 +127,7 @@ CaenBase::CaenBase(BaseSettings const &settings, /// /// \brief Normal processing thread void CaenBase::processingThread() { - if (EFUSettings.KafkaTopic == "") { + if (EFUSettings.KafkaTopic.empty()) { XTRACE(INIT, ERR, "No kafka topic set, using DetectorName + _detector"); EFUSettings.KafkaTopic = EFUSettings.DetectorName + "_detector"; } @@ -142,32 +140,32 @@ void CaenBase::processingThread() { EventProducer.produce(DataBuffer, Timestamp); }; - Serializer = new EV44Serializer(KafkaBufferSize, "caen", Produce); - - Stats.create("produce.cause.pulse_change", - Serializer->stats().ProduceRefTimeTriggered); - Stats.create("produce.cause.max_events_reached", - Serializer->stats().ProduceTriggeredMaxEvents); - + // Create the instrument CaenInstrument Caen(Counters, EFUSettings); - Caen.setSerializer(Serializer); // would rather have this in CaenInstrument + // and its serializers + Serializers.reserve(Caen.Geom->numSerializers()); + for (size_t i=0; i < Caen.Geom->numSerializers(); ++i){ + Serializers.emplace_back(std::make_shared<EV44Serializer>(KafkaBufferSize, Caen.Geom->serializerName(i), Produce)); + } + // give the instrument shared pointers to the serializers + Caen.setSerializers(Serializers); - Producer EventProducerII(EFUSettings.KafkaBroker, "CAEN_debug", + // Create the raw-data monitor producer and serializer + Producer MonitorProducer(EFUSettings.KafkaBroker, EFUSettings.KafkaDebugTopic, KafkaCfg.CfgParms); - - auto ProduceII = [&EventProducerII](auto DataBuffer, auto Timestamp) { - EventProducerII.produce(DataBuffer, Timestamp); + auto ProduceMonitor = [&MonitorProducer](auto DataBuffer, auto Timestamp) { + MonitorProducer.produce(DataBuffer, Timestamp); }; - SerializerII = new EV44Serializer(KafkaBufferSize, "caen", ProduceII); - Caen.setSerializerII( - SerializerII); // would rather have this in CaenInstrument + MonitorSerializer = std::make_shared<AR51Serializer>(EFUSettings.DetectorName, ProduceMonitor); unsigned int DataIndex; - TSCTimer ProduceTimer(EFUSettings.UpdateIntervalSec * 1000000 * TSC_MHZ); RuntimeStat RtStat({ITCounters.RxPackets, Counters.Events, Counters.KafkaStats.produce_bytes_ok}); + // Create the periodic timer for producing messages, in case of low event rate + // TSCTimer ProduceTimer(EFUSettings.UpdateIntervalSec * 1000000 * TSC_MHZ); // x86 specific + CheckTimer ProduceTimer(EFUSettings.UpdateIntervalSec * 1'000'000'000); while (runThreads) { if (InputFifo.pop(DataIndex)) { // There is data in the FIFO - do processing @@ -202,6 +200,16 @@ void CaenBase::processingThread() { // Process readouts, generate (and produce) events Caen.processReadouts(); + // send monitoring data + if (ITCounters.RxPackets % EFUSettings.MonitorPeriod < + EFUSettings.MonitorSamples) { + XTRACE(PROCESS, DEB, "Serialize and stream monitor data for packet %lu", + ITCounters.RxPackets); + MonitorSerializer->serialize((uint8_t *)DataPtr, DataLen); + MonitorSerializer->produce(); + Counters.TxRawReadoutPackets++; + } + /// \todo This could be moved and done less frequently Counters.Parser = Caen.CaenParser.Stats; Counters.TimeStats = Caen.ESSReadoutParser.Packet.Time.Stats; @@ -213,21 +221,33 @@ void CaenBase::processingThread() { usleep(10); } - if (ProduceTimer.timeout()) { + if (ProduceTimer.timeout()){ // XTRACE(DATA, DEB, "Serializer timer timed out, producing message now"); RuntimeStatusMask = RtStat.getRuntimeStatusMask({ITCounters.RxPackets, Counters.Events, Counters.KafkaStats.produce_bytes_ok}); + // Produce messages if there are events + for (auto &Serializer: Serializers) { + Serializer->produce(); + } - Serializer->produce(); - SerializerII->produce(); + // update counter statistics Counters.ProduceCauseTimeout++; + Counters.ProduceCausePulseChange = std::transform_reduce( + Serializers.begin(), Serializers.end(), 0, std::plus<>(), + [](auto &Serializer) { return Serializer->ProduceCausePulseChange; } + ); + Counters.ProduceCauseMaxEventsReached = std::transform_reduce( + Serializers.begin(), Serializers.end(), 0, std::plus<>(), + [](auto &Serializer) { return Serializer->ProduceCauseMaxEventsReached; } + ); } + /// Kafka stats update - common to all detectors /// don't increment as Producer & Serializer keep absolute count Counters.KafkaStats = EventProducer.stats; } + XTRACE(INPUT, ALW, "Stopping processing thread."); - return; } } // namespace Caen diff --git a/src/modules/caen/CaenBase.h b/src/modules/caen/CaenBase.h index d18645d13d87fcd6129d98dec513b505013cc8fe..70bcea32e05d15c00957ed88ef4942421510d31b 100644 --- a/src/modules/caen/CaenBase.h +++ b/src/modules/caen/CaenBase.h @@ -11,6 +11,7 @@ #include <caen/CaenCounters.h> #include <common/detector/Detector.h> #include <common/kafka/EV44Serializer.h> +#include <common/kafka/AR51Serializer.h> namespace Caen { @@ -26,8 +27,8 @@ public: struct CaenCounters Counters; protected: - EV44Serializer *Serializer; - EV44Serializer *SerializerII; + std::vector<std::shared_ptr<EV44Serializer>> Serializers; + std::shared_ptr<AR51Serializer> MonitorSerializer; }; } // namespace Caen diff --git a/src/modules/caen/CaenCounters.h b/src/modules/caen/CaenCounters.h index cbe3aedb70d5ab0d5aa08d716283edd3fab89174..70b05bdade616fafcf57c7aebe867410ca7436c1 100644 --- a/src/modules/caen/CaenCounters.h +++ b/src/modules/caen/CaenCounters.h @@ -11,6 +11,7 @@ #include <cinttypes> #include <common/kafka/Producer.h> +#include <cstdint> #include <modules/caen/geometry/CDCalibration.h> #include <modules/caen/geometry/Geometry.h> #include <modules/caen/readout/DataParser.h> @@ -21,12 +22,12 @@ struct CaenCounters { // Processing Counters - accessed in processing thread // System counters - int64_t FifoSeqErrors; - int64_t ProcessingIdle; + int64_t FifoSeqErrors{0}; + int64_t ProcessingIdle{0}; // ESSReadout parser struct ESSReadout::ESSHeaderStats ReadoutStats; - int64_t ErrorESSHeaders; + int64_t ErrorESSHeaders{0}; // Caen DataParser struct DataParser::Stats Parser; @@ -36,17 +37,21 @@ struct CaenCounters { struct Geometry::Stats Geom; // Events - int64_t Events; - int64_t PixelErrors; - int64_t EventsUdder; + int64_t Events{0}; + int64_t PixelErrors{0}; + int64_t EventsUdder{0}; + int64_t TxRawReadoutPackets{0}; + int64_t SerializerErrors{0}; // Time - struct ESSReadout::ESSReferenceTime::Stats_t TimeStats; + struct ESSReadout::ESSReferenceTime::Stats_t TimeStats{}; // Identification of the cause of produce calls - int64_t ProduceCauseTimeout; + int64_t ProduceCauseTimeout{0}; + int64_t ProduceCausePulseChange{0}; + int64_t ProduceCauseMaxEventsReached{0}; // Kafka stats below are common to all detectors - struct Producer::ProducerStats KafkaStats; + struct Producer::ProducerStats KafkaStats{}; } __attribute__((aligned(64))); } // namespace Caen diff --git a/src/modules/caen/CaenInstrument.cpp b/src/modules/caen/CaenInstrument.cpp index 0ec6fbb50f1f4afa8b2d4a0248552d5d2f1525d2..79433fab36071560d8d451e437bd7e7d9b673f90 100644 --- a/src/modules/caen/CaenInstrument.cpp +++ b/src/modules/caen/CaenInstrument.cpp @@ -118,10 +118,8 @@ void CaenInstrument::processReadouts() { XTRACE(DATA, DEB, "Reference time is %" PRIi64, ESSReadoutParser.Packet.Time.getRefTimeUInt64()); /// \todo sometimes PrevPulseTime maybe? - Serializer->checkAndSetReferenceTime( - ESSReadoutParser.Packet.Time.getRefTimeUInt64()); - SerializerII->checkAndSetReferenceTime( - ESSReadoutParser.Packet.Time.getRefTimeUInt64()); + auto packet_ref_time = static_cast<int64_t>(ESSReadoutParser.Packet.Time.getRefTimeUInt64()); + for (auto & Serializer: Serializers) Serializer->checkAndSetReferenceTime(packet_ref_time); /// Traverse readouts, calculate pixels for (auto &Data : CaenParser.Result) { @@ -157,17 +155,22 @@ void CaenInstrument::processReadouts() { Data.TimeHigh, Data.TimeLow, TimeOfFlight, Data.DataSeqNum, Data.Group, Data.AmpA, Data.AmpB, Data.AmpC, Data.AmpD); - // Calculate pixelid and apply calibration + // Calculate pixel and apply calibration uint32_t PixelId = calcPixel(Data); + // Determine the correct serializer for this pixel + auto SerializerId = Geom->calcSerializer(Data); + if (PixelId == 0) { XTRACE(EVENT, WAR, "Pixel error"); counters.PixelErrors++; + } else if (SerializerId >= Serializers.size()) { + XTRACE(EVENT, WAR, "Serializer identification error"); + counters.SerializerErrors++; } else { XTRACE(EVENT, DEB, "Pixel %u, TOF %u", PixelId, TimeOfFlight); - Serializer->addEvent(TimeOfFlight, PixelId); + Serializers[SerializerId]->addEvent(static_cast<int32_t>(TimeOfFlight), static_cast<int32_t>(PixelId)); counters.Events++; - SerializerII->addEvent(Data.AmpA + Data.AmpB + Data.AmpC + Data.AmpD, 0); } } // for() diff --git a/src/modules/caen/CaenInstrument.h b/src/modules/caen/CaenInstrument.h index 2390204a0e724b561150e4bb1f78230531bb817b..9f099635795a1a8406281b90b3ea75e30a1b45b0 100644 --- a/src/modules/caen/CaenInstrument.h +++ b/src/modules/caen/CaenInstrument.h @@ -37,12 +37,9 @@ public: /// \brief Generates Events from Readouts, and adds them to a serializer void processReadouts(); - /// \brief Sets the serializer to send events to - void setSerializer(EV44Serializer *serializer) { Serializer = serializer; } - - /// \brief Sets the second serializer to send events to, recording Amp values - void setSerializerII(EV44Serializer *serializer) { - SerializerII = serializer; + /// \brief Set All serializers at once + void setSerializers(std::vector<std::shared_ptr<EV44Serializer>> &serializers) { + Serializers = serializers; } /// \brief Caen pixel calculations @@ -61,8 +58,7 @@ public: ESSReadout::Parser ESSReadoutParser; DataParser CaenParser; Geometry *Geom; - EV44Serializer *Serializer; - EV44Serializer *SerializerII; + std::vector<std::shared_ptr<EV44Serializer>> Serializers; std::shared_ptr<ReadoutFile> DumpFile; }; diff --git a/src/modules/caen/geometry/Geometry.h b/src/modules/caen/geometry/Geometry.h index d2f3404e0f44e0075b4e5fd5442ba7285c791953..cb76994e5a9699a130e21d6a39a888e53e219105 100644 --- a/src/modules/caen/geometry/Geometry.h +++ b/src/modules/caen/geometry/Geometry.h @@ -41,6 +41,16 @@ public: /// \param Data CaenReadout to check validity of. virtual bool validateData(DataParser::CaenReadout &Data) = 0; + /// \brief return the total number of serializers used by the geometry + [[nodiscard]] virtual size_t numSerializers() const = 0; + + /// \brief calculate the serializer index for the given readout + /// \param Data CaenReadout to calculate serializer index for + [[nodiscard]] virtual size_t calcSerializer(DataParser::CaenReadout &Data) const = 0; + + /// \brief return the name of the serializer at the given index + [[nodiscard]] virtual std::string serializerName(size_t Index) const = 0; + struct Stats { int64_t RingErrors{0}; int64_t RingMappingErrors{0}; diff --git a/src/modules/cspec/geometry/CspecGeometry.h b/src/modules/cspec/geometry/CspecGeometry.h index 725184823cfe39dc41215f6f231cb5db3ecdd268..0aa19ee419667332e0b7fdc6daa73830a48d98dc 100644 --- a/src/modules/cspec/geometry/CspecGeometry.h +++ b/src/modules/cspec/geometry/CspecGeometry.h @@ -22,9 +22,9 @@ namespace Caen { class CspecGeometry : public Geometry { public: - CspecGeometry(Config &CaenConfiguration); - uint32_t calcPixel(DataParser::CaenReadout &Data); - bool validateData(DataParser::CaenReadout &Data); + explicit CspecGeometry(Config &CaenConfiguration); + uint32_t calcPixel(DataParser::CaenReadout &Data) override; + bool validateData(DataParser::CaenReadout &Data) override; /// \brief return the global x-offset for the given identifiers int xOffset(int Ring, int Group); @@ -34,5 +34,17 @@ public: /// \brief return the position along the unit (tube for CSPEC) int posAlongUnit(int AmpA, int AmpB); + + + /// \brief return the total number of serializers used by the geometry + [[nodiscard]] inline size_t numSerializers() const override {return 1;} + + /// \brief calculate the serializer index for the given readout + /// \param Data CaenReadout to calculate serializer index for + [[nodiscard]] inline size_t calcSerializer(DataParser::CaenReadout &) const override {return 0;} + + /// \brief return the name of the serializer at the given index + [[nodiscard]] inline std::string serializerName(size_t) const override {return "caen";} + }; } // namespace Caen diff --git a/src/modules/loki/geometry/LokiGeometry.h b/src/modules/loki/geometry/LokiGeometry.h index 36a6985423ee155e9857081c033dd5c2dade0f64..a0a0cc0aa95d2a614680c0146ba5e8dd6ce85bad 100644 --- a/src/modules/loki/geometry/LokiGeometry.h +++ b/src/modules/loki/geometry/LokiGeometry.h @@ -29,7 +29,7 @@ namespace Caen { class LokiGeometry : public Geometry { public: - LokiGeometry(Config &CaenConfiguration); + explicit LokiGeometry(Config &CaenConfiguration); /// \brief return the position along the tube /// \param AmpA amplitude A from readout data @@ -54,13 +54,24 @@ public: void setCalibration(CDCalibration Calib) { CaenCDCalibration = Calib; } - uint32_t calcPixel(DataParser::CaenReadout &Data); - bool validateData(DataParser::CaenReadout &Data); + uint32_t calcPixel(DataParser::CaenReadout &Data) override; + bool validateData(DataParser::CaenReadout &Data) override; // Holds the parsed configuration Config Conf; const std::pair<int, float> InvalidPos{-1, -1.0}; + + /// \brief return the total number of serializers used by the geometry + [[nodiscard]] inline size_t numSerializers() const override {return 1;} + + /// \brief calculate the serializer index for the given readout + /// \param Data CaenReadout to calculate serializer index for + [[nodiscard]] inline size_t calcSerializer(DataParser::CaenReadout &) const override {return 0;} + + /// \brief return the name of the serializer at the given index + [[nodiscard]] inline std::string serializerName(size_t) const override {return "caen";} + }; } // namespace Caen diff --git a/src/modules/miracles/geometry/MiraclesGeometry.h b/src/modules/miracles/geometry/MiraclesGeometry.h index 00e957cfa25636a807a5bf7caec7da8a3504b60f..80fc69a35d145671484d7eacd9abedf1b2864e8a 100644 --- a/src/modules/miracles/geometry/MiraclesGeometry.h +++ b/src/modules/miracles/geometry/MiraclesGeometry.h @@ -23,9 +23,9 @@ namespace Caen { class MiraclesGeometry : public Geometry { public: - MiraclesGeometry(Config &CaenConfiguration); - uint32_t calcPixel(DataParser::CaenReadout &Data); - bool validateData(DataParser::CaenReadout &Data); + explicit MiraclesGeometry(Config &CaenConfiguration); + uint32_t calcPixel(DataParser::CaenReadout &Data) override; + bool validateData(DataParser::CaenReadout &Data) override; /// \brief return local x-coordinate from amplitudes int xCoord(int Ring, int Tube, int AmpA, int AmpB); @@ -37,5 +37,16 @@ public: /// \brief return the position along the tube int posAlongUnit(int AmpA, int AmpB); + + /// \brief return the total number of serializers used by the geometry + [[nodiscard]] inline size_t numSerializers() const override {return 1;} + + /// \brief calculate the serializer index for the given readout + /// \param Data CaenReadout to calculate serializer index for + [[nodiscard]] inline size_t calcSerializer(DataParser::CaenReadout &) const override {return 0;} + + /// \brief return the name of the serializer at the given index + [[nodiscard]] inline std::string serializerName(size_t) const override {return "caen";} + }; } // namespace Caen