From b581d9c117fbdc1cdadb7d030bcde2c2e4aa35a1 Mon Sep 17 00:00:00 2001 From: Valerio Pastore Date: Thu, 11 Jan 2024 18:03:50 +0100 Subject: [PATCH 1/4] added doxy doc --- include/Base_Archiver.h | 72 +- include/Base_Configurator.h | 52 +- include/Base_DAQ.h | 180 ++++- include/Base_DAQ_Observer.h | 44 +- include/Base_Monitor.h | 58 +- include/Base_Packet.h | 1239 ++++++++++++++++++++++------------- include/Base_Provider.h | 73 ++- include/Base_Receiver.h | 54 +- 8 files changed, 1283 insertions(+), 489 deletions(-) diff --git a/include/Base_Archiver.h b/include/Base_Archiver.h index 8af7ae1..9634ba4 100755 --- a/include/Base_Archiver.h +++ b/include/Base_Archiver.h @@ -7,22 +7,86 @@ namespace inaf::oasbo::Archivers{ - +/** + * @brief The BaseArchiver class is an abstract base class for archivers. + * + * This class provides a common interface for archiving packets. Derived classes + * must implement the pure virtual functions defined in this class. + */ class BaseArchiver{ protected: - std::string dest; + std::string dest; /**< The destination of the archiver. */ public: + /** + * @brief Write a packet to the archiver. + * + * This function writes the given packet to the "archive". + * + * @param packet The packet to write. + * @return An integer indicating the success or failure of the write operation. + */ virtual int write(PacketLib::BasePacket &) = 0; - virtual int write(PacketLib::BasePacket &, std::string destination) = 0; + /** + * @brief Write a packet to the archiver with a specified destination. + * + * This function writes the given packet to the archiver with the specified destination. + * + * @param packet The packet to write. + * @param destination The destination where the packet should be written. + * @return An integer indicating the success or failure of the write operation. + */ + virtual int write(PacketLib::BasePacket &, std::string destination) = 0; + /** + * @brief Open the archiver. + * + * This function opens the archiver. + * + * @return An integer indicating the success or failure of the open operation. + */ virtual int open()=0; + + /** + * @brief Close the archiver. + * + * This function closes the archiver. + * + * @return An integer indicating the success or failure of the close operation. + */ virtual int close()=0; + + /** + * @brief Check if the archiver is open. + * + * This function checks if the archiver is open. + * + * @return A boolean value indicating whether the archiver is open or not. + */ virtual bool is_open()=0; + + /** + * @brief Set the destination of the archiver. + * + * This function sets the destination of the archiver. + * + * @param dest The destination to set. + */ virtual void setDest(std::string dest) = 0; - virtual void updateDest()=0; + + /** + * @brief Get the destination of the archiver. + * + * This function gets the destination of the archiver. + * + * @return The destination of the archiver. + */ virtual std::string getDest() = 0; + + /** + * @brief Destructor for the BaseArchiver class. + */ virtual ~BaseArchiver() = default; }; diff --git a/include/Base_Configurator.h b/include/Base_Configurator.h index 97b46e9..36c4900 100644 --- a/include/Base_Configurator.h +++ b/include/Base_Configurator.h @@ -5,18 +5,68 @@ namespace inaf::oasbo::Configurators { +/** + * @brief The BaseConfigurator class is an abstract base class for configurators in the DAQ system. + * + * It provides common functionality for reading and pushing configurations to a source, + * as well as inserting new configurations into the existing ones. + */ class BaseConfigurator{ protected: std::map config; public: + /** + * @brief Read the configuration from the source. + * + * @return int Returns 0 on success, or an error code on failure. + */ virtual int readConfigFromSource() = 0; + + /** + * @brief Read the configuration for the specified target. + * + * @param target The target for which to read the configuration. + * @return int Returns 0 on success, or an error code on failure. + */ virtual int readConfigFromSource(std::string target) = 0; + + /** + * @brief Push the configuration to the source. + * + * @return int Returns 0 on success, or an error code on failure. + */ virtual int pushConfigToSource() = 0; + + /** + * @brief Push the configuration for the specified target. + * + * @param target The target for which to push the configuration. + * @return int Returns 0 on success, or an error code on failure. + */ virtual int pushConfigToSource(std::string target) = 0; - virtual int insert(std::map, std::string target) = 0; + + /** + * @brief Insert new configurations into the existing ones. + * + * @param newConfig The new configurations to insert. + * @param target The target for which to insert the new configurations. + * @return int Returns 0 on success, or an error code on failure. + */ + virtual int insert(std::map newConfig, std::string target) = 0; + + /** + * @brief Get the current configuration. + * + * @return std::map The current configuration. + */ virtual std::map getConfig() {return this->config;} + /** + * @brief Convert the configuration to a string representation. + * + * @return std::string The string representation of the configuration. + */ std::string toString(){ std::string ret = ""; for( const std::pair n : config) { diff --git a/include/Base_DAQ.h b/include/Base_DAQ.h index 7852d6a..6008d6a 100755 --- a/include/Base_DAQ.h +++ b/include/Base_DAQ.h @@ -12,6 +12,16 @@ namespace inaf::oasbo::DAQ_observers { class BaseDAQ_Observer; } +/** + * @brief The BaseDAQ class represents the base class for a Data Acquisition (DAQ) system. + * + * This class provides a common interface and functionality for a DAQ system. The DAQ system is imagined as a state machine. + * This super class defines the states, sets the receiver, archiver, provider, monitor, and packet objects, and + * manages the observers and configurations. It also provides pure virtual functions for + * starting, stopping, switching states, delivering packets, and getting the state as a string. + * + * @note This class is meant to be inherited from and should not be instantiated directly. + */ namespace inaf::oasbo::DAQ { class BaseDAQ { public: @@ -20,47 +30,105 @@ public: }; protected: - Status currentState; - Status nextState; - bool changeStateFlag = false; - Receivers::BaseReceiver *receiver = nullptr; - Archivers::BaseArchiver *archiver = nullptr; - Providers::BaseProvider *provider = nullptr; - PacketMonitors::BasePacketMonitor *monitor = nullptr; - PacketLib::BasePacket *packet = nullptr; - std::vector observers; - std::vector configurations; + Status currentState; /**< The current state of the DAQ system. */ + Status nextState; /**< The next state of the DAQ system. */ + bool changeStateFlag = false; /**< Flag indicating if the state has changed. */ + Receivers::BaseReceiver *receiver = nullptr; /**< Pointer to the receiver object. */ + Archivers::BaseArchiver *archiver = nullptr; /**< Pointer to the archiver object. */ + Providers::BaseProvider *provider = nullptr; /**< Pointer to the provider object. */ + PacketMonitors::BasePacketMonitor *monitor = nullptr; /**< Pointer to the packet monitor object. */ + PacketLib::BasePacket *packet = nullptr; /**< Pointer to the packet object. */ + std::vector observers; /**< Vector of observers. */ + std::vector configurations; /**< Vector of configurations. */ public: + /** + * @brief Sets the receiver object. + * + * @param receiver The receiver object to set. + */ void setReceiver(Receivers::BaseReceiver &receiver) { this->receiver = &receiver; } + + /** + * @brief Sets the archiver object. + * + * @param archiver The archiver object to set. + */ void setArchiver(Archivers::BaseArchiver &archiver) { this->archiver = &archiver; } + + /** + * @brief Sets the provider object. + * + * @param provider The provider object to set. + */ void setProvider(Providers::BaseProvider &provider) { this->provider = &provider; } + + /** + * @brief Sets the packet monitor object. + * + * @param monitor The packet monitor object to set. + */ void setMonitor(PacketMonitors::BasePacketMonitor &monitor) { this->monitor = &monitor; } + + /** + * @brief Sets the packet object. + * + * @param packet The packet object to set. + */ void setPacket(PacketLib::BasePacket &packet) { this->packet = &packet; } + + /** + * @brief Sets the current state of the DAQ system. + * + * @param currentState The current state to set. + */ void setCurrentState(Status currentState) { this->currentState = currentState; } + + /** + * @brief Sets the next state of the DAQ system. + * + * @param nextState The next state to set. + */ void setNextState(Status nextState) { this->nextState = nextState; } + + /** + * @brief Sets the flag indicating if the state has changed. + * + * @param flag The flag value to set. + */ void setChangeStateFlag(bool flag) { this->changeStateFlag = flag; } + + /** + * @brief Registers an observer to the DAQ system. + * + * @param observer The observer to register. + */ void registerObserver( inaf::oasbo::DAQ_observers::BaseDAQ_Observer *observer) { observers.push_back(observer); } + /** + * @brief Removes an observer from the DAQ system. + * + * @param observer The observer to remove. + */ void removeObserver( inaf::oasbo::DAQ_observers::BaseDAQ_Observer *observer) { observers.erase( @@ -68,37 +136,125 @@ public: observers.end()); } + /** + * @brief Gets a pointer to the receiver object. + * + * @return Pointer to the receiver object. + */ Receivers::BaseReceiver* getReceiverPtr() { return this->receiver; } + + /** + * @brief Gets a pointer to the archiver object. + * + * @return Pointer to the archiver object. + */ Archivers::BaseArchiver* getArchiverPtr() { return this->archiver; } + + /** + * @brief Gets a pointer to the provider object. + * + * @return Pointer to the provider object. + */ Providers::BaseProvider* getProviderPtr() { return this->provider; } + + /** + * @brief Gets a pointer to the packet monitor object. + * + * @return Pointer to the packet monitor object. + */ PacketMonitors::BasePacketMonitor* getMonitorPtr() { return this->monitor; } + + /** + * @brief Gets a pointer to the packet object. + * + * @return Pointer to the packet object. + */ PacketLib::BasePacket* getPacketPrt() { return this->packet; } + + /** + * @brief Gets the current state of the DAQ system. + * + * @return The current state of the DAQ system. + */ Status getCurrentState() { return this->currentState; } + + /** + * @brief Gets the next state of the DAQ system. + * + * @return The next state of the DAQ system. + */ Status getNextState() { return this->nextState; } + + /** + * @brief Gets the flag indicating if the state has changed. + * + * @return The flag indicating if the state has changed. + */ int getChangeStateFlag() { return this->changeStateFlag; } + /** + * @brief Starts the DAQ system. + * + * @note This is a pure virtual function and must be implemented by derived classes. + */ virtual void start() = 0; + + /** + * @brief Stops the DAQ system. + * + * @note This is a pure virtual function and must be implemented by derived classes. + */ virtual void stop() = 0; - virtual void switchState(const Status) = 0; + + /** + * @brief Switches the state of the DAQ system. + * + * @param state The state to switch to. + * + * @note This is a pure virtual function and must be implemented by derived classes. + */ + virtual void switchState(const Status state) = 0; + + /** + * @brief Delivers a packet after received. It should probably call the provider to deliver the packet. + * + * @return The result of the packet delivery. + * + * @note This is a pure virtual function and must be implemented by derived classes. + */ virtual int deliverPacket() = 0; - virtual std::string getStateStr(const Status) = 0; + /** + * @brief Gets the string representation of a state. + * + * @param state The state to get the string representation of. + * @return The string representation of the state. + * + * @note This is a pure virtual function and must be implemented by derived classes. + */ + virtual std::string getStateStr(const Status state) = 0; + + /** + * @brief Destructor for the BaseDAQ class. + * + * Deletes the receiver, provider, archiver, monitor, packet, and observers. + */ virtual ~BaseDAQ() { delete receiver; delete provider; diff --git a/include/Base_DAQ_Observer.h b/include/Base_DAQ_Observer.h index 84a5118..70bfaef 100644 --- a/include/Base_DAQ_Observer.h +++ b/include/Base_DAQ_Observer.h @@ -1,9 +1,14 @@ - - #pragma once #include +/** + * @brief The BaseDAQ_Observer class is an abstract base class for DAQ system observers. + * + * This class defines the interface for observing the statistics and status of a BaseDAQ object. + * Subclasses of BaseDAQ_Observer must implement the pure virtual functions defined in this class. + * + */ namespace inaf::oasbo::DAQ_observers{ class BaseDAQ_Observer{ @@ -11,20 +16,55 @@ protected: inaf::oasbo::DAQ::BaseDAQ *dataAcquisition; public: + /** + * @brief Constructs a BaseDAQ_Observer object with the specified BaseDAQ object. + * + * @param dataAcquisition The BaseDAQ object to observe. + */ BaseDAQ_Observer(inaf::oasbo::DAQ::BaseDAQ &dataAcquisition) { this->dataAcquisition = &dataAcquisition; } + /** + * @brief Destroys the BaseDAQ_Observer object and removes itself from the observed BaseDAQ object. + */ virtual ~BaseDAQ_Observer() { this->dataAcquisition->removeObserver(this); } + /** + * @brief Updates the packet statistics of the observed BaseDAQ object. + */ virtual void updatePacketStats() = 0; + + /** + * @brief Updates the archiver statistics of the observed BaseDAQ object. + */ virtual void updateArchiverStats() = 0; + + /** + * @brief Updates the provider statistics of the observed BaseDAQ object. + */ virtual void updateProviderStats() = 0; + + /** + * @brief Updates the receiver statistics of the observed BaseDAQ object. + */ virtual void updateReceiverStats() = 0; + + /** + * @brief Updates all statistics of the observed BaseDAQ object. + */ virtual void updateAll() = 0; + + /** + * @brief Starts the observation on the BaseDAQ object. + */ virtual void start() = 0; + + /** + * @brief Stops the observation on the BaseDAQ object. + */ virtual void stop() = 0; }; diff --git a/include/Base_Monitor.h b/include/Base_Monitor.h index cd91583..e30d065 100644 --- a/include/Base_Monitor.h +++ b/include/Base_Monitor.h @@ -6,14 +6,61 @@ namespace inaf::oasbo::PacketMonitors{ +/** + * @brief The BasePacketMonitor class is an abstract base class for packet monitors in the DAQ system. + * + * This class provides a common interface for packet monitoring functionality. + * Derived classes must implement the monit(), printStats(), and reset() methods. + * The class also provides methods to access and retrieve statistics related to the monitored packets. + */ class BasePacketMonitor{ protected: - std::map stats; + std::map stats; /**< A map to store statistics related to the monitored packets. */ public: - virtual void monit(PacketLib::BasePacket &) = 0; - virtual void printStats()=0; + /** + * @brief Monitors a packet. + * + * This pure virtual method is used to monitor a packet. + * Derived classes must implement this method to define the monitoring behavior. + * + * @param packet The packet to be monitored. + */ + virtual void monit(PacketLib::BasePacket &packet) = 0; + + /** + * @brief Prints the statistics related to the monitored packets. + * + * This pure virtual method is used to print the statistics related to the monitored packets. + * Derived classes must implement this method to define the printing behavior. + */ + virtual void printStats() = 0; + + /** + * @brief Resets the statistics related to the monitored packets. + * + * This pure virtual method is used to reset the statistics related to the monitored packets. + * Derived classes must implement this method to define the resetting behavior. + */ virtual void reset() = 0; + + /** + * @brief Retrieves the statistics map. + * + * This method returns the map containing the statistics related to the monitored packets. + * + * @return The map containing the statistics related to the monitored packets. + */ virtual std::map getStatsMap() const { return stats;} + + /** + * @brief Retrieves a specific statistic. + * + * This method retrieves a specific statistic from the statistics map. + * If the statistic is not found, it returns std::nullopt. + * + * @param stat The name of the statistic to retrieve. + * @return An optional string containing the value of the statistic, or std::nullopt if the statistic is not found. + */ std::optional getStat(std::string stat) const { try { return this->stats.at(stat); @@ -22,9 +69,10 @@ public: } } + /** + * @brief Default destructor. + */ virtual ~BasePacketMonitor() = default; - - }; } diff --git a/include/Base_Packet.h b/include/Base_Packet.h index 463594f..e5a80c4 100644 --- a/include/Base_Packet.h +++ b/include/Base_Packet.h @@ -14,459 +14,806 @@ #include #include +namespace inaf::oasbo::Packets +{ + + /** + * @class BasePacketStructure + * @brief Represents the structure of a base packet. + * + * The BasePacketStructure class provides functionality to define and manipulate the structure of a base packet. + * It stores information about the fields, their sizes, offsets, and mappings between field names and indices. + * The class also provides methods to retrieve information about the structure, such as the byte size, field offsets, and field names. + * + * @note This is an abstract base class and should be derived to define specific packet structures. In particular, you should define + * the sourceReadingFunc function. + */ + class BasePacketStructure + { + protected: + /** + * @brief Type alias for the packet structure. + * + * This alias represents the structure of a packet. It is defined as a vector of tuples, where each tuple contains three elements: + * - The first element is of type uint and represents the field index. + * - The second element is of type std::string and represents the field name. + * - The third element is of type uint and represents the field bit size. + */ + using Structure = std::vector>; /**< Type alias for the packet structure. */ + + std::string source; /**< The source of the packet. */ + Structure structure; /**< The structure of the packet. */ + uint byteSize; /**< The size of the packet in bytes. */ + std::vector fieldSizes; /**< vector of the sizes of the fields in the packet. */ + std::unordered_map indexToOffsetsMap; /**< Mapping of field index to field offset. */ + std::unordered_map fieldNameToIndexMap; /**< Mapping of field name to field index. */ + std::unordered_map indexToFieldNameMap; /**< Mapping of field index to field name. */ + std::function sourceReadingFunc; /**< Function to read the packet source and return the structure. */ + + /** + * @brief Updates the field sizes based on the structure. + * @param structure The structure of the packet. + */ + void updateFieldSizes(const Structure &structure) + { + std::for_each(structure.begin(), structure.end(), + [&](const std::tuple &tup) + { + this->fieldSizes.push_back(std::get<2>(tup)); + }); + } -namespace inaf::oasbo::PacketLib { - -class BasePacketStructure { -protected: - using Structure = std::vector>; - - std::string source; - Structure structure; - uint byteSize; - std::vector fieldSizes; - std::unordered_map indexToOffsetsMap; - std::unordered_map fieldNameToIndexMap; - std::unordered_map indexToFieldNameMap; - std::function sourceReadingFunc; - - void updateFieldSizes(const Structure ¶msTuple) { - std::for_each(paramsTuple.begin(), paramsTuple.end(), - [&](const std::tuple &tup) { - this->fieldSizes.push_back(std::get<2>(tup)); - }); - } - void updateFieldOffsets(const Structure ¶msTuple) { - uint offset = 0; - for (size_t i = 0; i < paramsTuple.size(); i++) { - indexToOffsetsMap[i] = offset; - offset += std::get<2>(paramsTuple[i]); - } - } - void updateFieldNameAndIndexMap(const Structure ¶msTuple) { - std::for_each(paramsTuple.begin(), paramsTuple.end(), - [&](const std::tuple &tup) { - this->fieldNameToIndexMap[std::get<1>(tup)] = std::get<0>( - tup); - this->indexToFieldNameMap[std::get<0>(tup)] = std::get<1>( - tup); - }); - } - void updateStructure(std::string source) { - this->source = source; - this->structure = sourceReadingFunc(source); - updateFieldSizes(structure); - updateFieldOffsets(structure); - updateFieldNameAndIndexMap(structure); - uint bitSize = std::accumulate(fieldSizes.begin(), fieldSizes.end(), 0); - this->byteSize = bitSize % 8 == 0 ? bitSize / 8 : bitSize / 8 + 1; - } - -public: - virtual ~BasePacketStructure() = default; - - BasePacketStructure(std::string source, - std::function sourceReadingFunc) : - source(source), sourceReadingFunc(sourceReadingFunc) { - this->updateStructure(source); - } - ; - BasePacketStructure(const BasePacketStructure &other) { - this->source = other.source; - this->byteSize = other.byteSize; - this->fieldSizes = other.fieldSizes; - this->indexToOffsetsMap = other.indexToOffsetsMap; - this->fieldNameToIndexMap = other.fieldNameToIndexMap; - this->indexToFieldNameMap = other.indexToFieldNameMap; - this->sourceReadingFunc = other.sourceReadingFunc; - } - - void changeSource(std::string source) { - updateStructure(source); - } - uint getByteSize() { - return this->byteSize; - } - std::string getSource() { - return this->source; - } - std::optional bitOffsetOf(uint index) { - if (index <= this->numberOfFields()) { - return indexToOffsetsMap.at(index); - } else { - time_t now = time(nullptr) ; - std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") - << "]\t[Base Packet]\t" << "No field at " << index - << ", max is " << numberOfFields() << ", returning nullopt." - << std::endl; - return std::nullopt; - } - } - std::optional bitSizeOf(uint index) { - if (index <= this->numberOfFields()) { - return this->fieldSizes[index]; - } else { - time_t now = time(nullptr) ; - std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") - << "]\t[Base Packet]\t" << "No field at " << index - << ", max is " << numberOfFields() << ", returning nullopt." - << std::endl; - return std::nullopt; - } - } - - std::optional indexOfField(std::string fieldName) { - std::transform(fieldName.begin(), fieldName.end(), fieldName.begin(), - [](unsigned char c) { - return std::tolower(c); - }); - try { - return this->fieldNameToIndexMap.at(fieldName); - } catch (const std::out_of_range &oor) { - time_t now = time(nullptr) ; - std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") - << "]\t[Base Packet]\t" << "No field of name " << fieldName - << ", returning nullopt." << std::endl; - return std::nullopt; - } - } - - std::optional fieldNameOfIndex(uint index) { - try { - return this->indexToFieldNameMap.at(index); - } catch (const std::out_of_range &oor) { - time_t now = time(nullptr); - std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") - << "]\t[Base Packet]\t" << "No field at " << index - << ", max is " << numberOfFields() << ", returning nullopt." - << std::endl; - return std::nullopt; - } - } - uint numberOfFields() { - return this->fieldSizes.size(); - } - - std::unordered_map getFieldNameToIndexMap() const { - return this->fieldNameToIndexMap; - } - - std::unordered_map getIndexToOffsetsMap() const{ - return this->indexToOffsetsMap; - } - std::unordered_map getIndexToFieldNameMap() const { - return this->indexToFieldNameMap; - } - -}; - -template -class bit_iterator { - - using iterator_category = std::random_access_iterator_tag; - using value_type = ValueType; - using difference_type = std::ptrdiff_t; - using pointer = ValueType*; - using reference = ValueType&; - -public: - bit_iterator(const uint8_t *data, int offset, - BasePacketStructure *structure, - std::function func) : - m_data(data), m_offset(offset), m_structure(structure), m_func(func) { - } - - bit_iterator(const bit_iterator &other) : - m_data(other.m_data), m_offset(other.m_offset), m_structure( - other.m_structure), m_func(other.m_func) { - } - - bit_iterator& operator++() { - ++m_offset; - return *this; - } - - bit_iterator operator++(int) { - bit_iterator temp(*this); - ++m_offset; - return temp; - } - - bit_iterator& operator--() { - --m_offset; - return *this; - } - - bit_iterator operator--(int) { - bit_iterator temp(*this); - --m_offset; - return temp; - } - - bit_iterator operator+(int n) const { - return bit_iterator(m_data, m_offset + n, m_structure, m_func); - } - - bit_iterator operator-(int n) const { - return bit_iterator(m_data, m_offset - n, m_structure, m_func); - } - - int operator-(const bit_iterator &other) const { - return m_offset - other.m_offset; - } - - bool operator==(const bit_iterator &other) const { - return m_data == other.m_data && m_offset == other.m_offset; - } - - bool operator!=(const bit_iterator &other) const { - return !(*this == other); - } - - ValueType operator*() const { - auto offset = m_structure->bitOffsetOf(m_offset); // offset from the beginning of the byte - auto num_bits = m_structure->bitSizeOf(m_offset); - return m_func(m_data, offset.value(), num_bits.value()); - } - -private: - const uint8_t *m_data; - int m_offset; - BasePacketStructure *m_structure; - std::function m_func; -}; - -template -class BasePacketTempl { -protected: - BasePacketStructure *packetStructure; - uint8_t *memoryPointer; - - // This C++ function reads a binary value from a memory location pointed to by binaryPointer. - // The binary value is represented by num_bits number of bits starting from the offset-th bit in the memory. - // The function returns the value of the binary as a ValueType. - static ValueType _readValueFromMemoryAt_(const uint8_t *binaryPointer, - uint offset, uint num_bits) { - // Calculate the bit offset from the byte offset: - uint bit_offset = offset % 8; - // Calculate the byte offset from the bit offset: - uint byte_offset = offset / 8; - ValueType value = 0; - ValueType bit = 1; - - for (uint i = 0; i < num_bits; i++) { - // Calculate the byte and bit index of the current bit: - uint byte_index = byte_offset + (bit_offset + i) / 8; - uint bit_index = (bit_offset + i) % 8; - uint8_t byte = binaryPointer[byte_index]; - // Create a bit mask to isolate the desired bit: - uint8_t bit_mask = 1 << (7 - bit_index); - // Set the corresponding bit in the return value if the retrieved bit is 1: - value |= (byte & bit_mask) ? ( bit << (num_bits - i - 1)) : 0; - } - return value; - } - - size_t minBitsRequired(size_t value) const { - // Handle special cases - size_t bitsNeeded = 1; - - while (value != 0) { - bitsNeeded++; - value >>= 1; - } - - return bitsNeeded; - } - -public: - BasePacketTempl(BasePacketStructure &structure) { - this->packetStructure = new BasePacketStructure(structure); - this->memoryPointer = new uint8_t[structure.getByteSize()]; - } - - BasePacketTempl(const BasePacketTempl &other) { - this->packetStructure = new BasePacketStructure(other.getPacketStructure()); - this->memoryPointer = new uint8_t[other.packetStructure->getByteSize()]; - std::memcpy(this->memoryPointer, other.memoryPointer, - other.packetStructure->getByteSize()); - } - - virtual ~BasePacketTempl() = default; - - void updatePacketStructure(BasePacketStructure &structure) { - size_t newSize = structure.getByteSize(); - size_t oldSize = this->packetStructure->getByteSize(); - - uint8_t *buff = new uint8_t[newSize]; - std::memset(buff, 0, newSize); - std::memcpy(buff, memoryPointer, std::min(newSize, oldSize)); - delete this->memoryPointer; - - this->memoryPointer = new uint8_t[newSize]; - std::memcpy(memoryPointer, buff, newSize); - delete[] buff; - this->packetStructure = &structure; - } - - std::optional readValueFromMemoryAt(uint index) const { - auto offset = packetStructure->bitOffsetOf(index); // offset from the beginning of the byte - auto num_bits = packetStructure->bitSizeOf(index); //remaining bits to read - if (offset.has_value() && num_bits.has_value()) - return _readValueFromMemoryAt_(memoryPointer, offset.value(), - num_bits.value()); - else { - time_t now = time(nullptr) ; - std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") - << "]\t[Base Packet]\t" << "Error: No field at " << index - << ", max is " << packetStructure->numberOfFields() - << ", returning nullopt" << std::endl; - return std::nullopt; - } - } - - uint8_t const* getPointerToMemory() const { - return memoryPointer; - } - - int copyToMemory(const uint8_t *from, uint size) { - uint max_writable = this->packetStructure->getByteSize(); - if (size > max_writable) { - time_t now = time(nullptr) ; - std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") - << "]\t[Base Packet]\t" << "Error: you are trying to copy " - << size << " byte where the max size is: " << max_writable - << std::endl; - std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") - << "]\t[Base Packet]\t" << "\tI copy only until " - << max_writable << " byte" << std::endl; - std::memcpy(memoryPointer, from, max_writable); - return max_writable; - } else { - std::memcpy(memoryPointer, from, size); - return size; - } - } - - int copyToMemory(const uint8_t *from, uint size, uint offset) { - uint max_writable = this->packetStructure->getByteSize(); - if (offset > max_writable) { - time_t now = time(nullptr) ; - std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") - << "]\t[Base Packet]\t" - << "Error: you are trying to copy starting from " << offset - << " byte where the max size is: " << max_writable - << std::endl; - return -1; - } - if (size + offset > max_writable) { - time_t now = time(nullptr) ; - std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") - << "]\t[Base Packet]\t" << "Error: you are trying to copy " - << size + offset << " byte where the max size is: " - << max_writable << std::endl; - std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") - << "]\t[Base Packet]\t" << "\tI copy only until " - << max_writable << " byte" << std::endl; - int to_write = max_writable - offset; - std::memcpy(&memoryPointer[offset], from, to_write); - return to_write; - } else { - std::memcpy(&memoryPointer[offset], from, size); - return size; - } - } - - std::optional operator[](uint index) const { - return readValueFromMemoryAt(index); - } - - std::optional operator[](std::string fieldName) const { - std::transform(fieldName.begin(), fieldName.end(), fieldName.begin(), - [](unsigned char c) { - return std::tolower(c); - }); - auto index = packetStructure->indexOfField(fieldName); - if (index.has_value()) - return readValueFromMemoryAt(index.value()); - else - return std::nullopt; - } - - bit_iterator begin() const { - return bit_iterator(memoryPointer, 0, packetStructure, - &_readValueFromMemoryAt_); - } - - bit_iterator end() const { - return bit_iterator(memoryPointer, - packetStructure->numberOfFields(), packetStructure, - &_readValueFromMemoryAt_); - } - - std::optional writeValueIntoMemoryAtIndex(uint index, ValueType value) { - auto offset = this->packetStructure->bitOffsetOf(index); - auto numbits = this->packetStructure->bitSizeOf(index); - size_t min_req = minBitsRequired(value); - if (!offset.has_value() || !numbits.has_value()) - return std::nullopt; - if (numbits < min_req) { - time_t now = time(nullptr) ; - std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") - << "]\t[Base Packet]\t" << "Error: you are trying to write " - << value << " which requires at least " << min_req - << " bits in a field of size " << numbits << std::endl; - return std::nullopt; - } - - // Calculate the bit offset from the byte offset: - uint bitoffset = offset.value() % 8; - // Calculate the byte offset from the bit offset: - uint byteoffset = offset.value() / 8; - uint numbits_written = 0; - - for (size_t i = 0; i < numbits; i++) { - // Calculate the byte and bit index of the current bit: - uint byte_index = byteoffset + (bitoffset + i) / 8; - uint bit_index = (bitoffset + i) % 8; - // Create a bit mask to isolate the desired bit: - uint8_t bit_mask = 1 << (7 - bit_index); - // Set the corresponding bit in the binary array if the value is 1: - if ((value >> (numbits.value() - i - 1)) & 1) { - memoryPointer[byte_index] |= bit_mask; - numbits_written++; - } else { - memoryPointer[byte_index] &= ~bit_mask; + /** + * @brief Updates the field offsets based on the structure. + * @param structure The structure of the packet. + */ + void updateFieldOffsets(const Structure &structure) + { + uint offset = 0; + for (size_t i = 0; i < structure.size(); i++) + { + indexToOffsetsMap[i] = offset; + offset += std::get<2>(structure[i]); } } - return numbits_written; - } - uint getPacketStructureByteSize() const { - return packetStructure->getByteSize(); - } - BasePacketStructure& getPacketStructure() const { - return *(this->packetStructure); - } + /** + * @brief Updates the field name and index maps based on the structure. + * @param structure The structure of the packet. + */ + void updateFieldNameAndIndexMap(const Structure &structure) + { + std::for_each(structure.begin(), structure.end(), + [&](const std::tuple &tup) + { + this->fieldNameToIndexMap[std::get<1>(tup)] = std::get<0>(tup); + this->indexToFieldNameMap[std::get<0>(tup)] = std::get<1>(tup); + }); + } - virtual bool hasRecognizedHeader() const = 0; - virtual bool isRecognizedHeader(std::vector buff) const = 0; - virtual uint getHeaderSize() const = 0; - virtual uint getPayloadSize() const = 0; - virtual uint getTailSize() const = 0; -}; + /** + * @brief Updates the packet structure based on the source. + * @param source The source of the packet structure. + */ + void updateStructure(std::string source) + { + this->source = source; + this->structure = sourceReadingFunc(source); + updateFieldSizes(structure); + updateFieldOffsets(structure); + updateFieldNameAndIndexMap(structure); + uint bitSize = std::accumulate(fieldSizes.begin(), fieldSizes.end(), 0); + this->byteSize = bitSize % 8 == 0 ? bitSize / 8 : bitSize / 8 + 1; + } -using valueType = size_t; -class BasePacket: public BasePacketTempl { + public: + /** + * @brief Destructor. + */ + virtual ~BasePacketStructure() = default; + + /** + * @brief Constructor. + * @param source The source of the packet structure. + * @param sourceReadingFunc The function to read the packet source and return the structure. + */ + BasePacketStructure(std::string source, std::function sourceReadingFunc) : source(source), sourceReadingFunc(sourceReadingFunc) + { + this->updateStructure(source); + } -protected: + /** + * @brief Copy constructor. + * @param other The other BasePacketStructure object to copy from. + */ + BasePacketStructure(const BasePacketStructure &other) + { + this->source = other.source; + this->byteSize = other.byteSize; + this->fieldSizes = other.fieldSizes; + this->indexToOffsetsMap = other.indexToOffsetsMap; + this->fieldNameToIndexMap = other.fieldNameToIndexMap; + this->indexToFieldNameMap = other.indexToFieldNameMap; + this->sourceReadingFunc = other.sourceReadingFunc; + } -public: - BasePacket(BasePacketStructure &structure) : - BasePacketTempl(structure) { - } - virtual ~BasePacket() = default; + /** + * @brief Changes the source of the packet and updates the structure. + * @param source The new source of the packet structure. + */ + void changeSource(std::string source) + { + updateStructure(source); + } -}; -} + /** + * @brief Gets the size of the packet in bytes. + * @return The size of the packet in bytes. + */ + uint getByteSize() + { + return this->byteSize; + } + + /** + * @brief Gets the source of the packet structure. + * @return The source of the packet structure. + */ + std::string getSource() + { + return this->source; + } + + /** + * @brief Gets the bit offset of a field in the packet structure. + * @param index The index of the field. + * @return The bit offset of the field, or std::nullopt if the field does not exist. + */ + std::optional bitOffsetOf(uint index) + { + if (index <= this->numberOfFields()) + { + return indexToOffsetsMap.at(index); + } + else + { + time_t now = time(nullptr); + std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") + << "]\t[Base Packet]\t" + << "No field at " << index + << ", max is " << numberOfFields() << ", returning nullopt." + << std::endl; + return std::nullopt; + } + } + + /** + * @brief Gets the bit size of a field in the packet structure. + * @param index The index of the field. + * @return The bit size of the field, or std::nullopt if the field does not exist. + */ + std::optional bitSizeOf(uint index) + { + if (index <= this->numberOfFields()) + { + return this->fieldSizes[index]; + } + else + { + time_t now = time(nullptr); + std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") + << "]\t[Base Packet]\t" + << "No field at " << index + << ", max is " << numberOfFields() << ", returning nullopt." + << std::endl; + return std::nullopt; + } + } + + /** + * @brief Gets the index of a field in the packet structure based on its name. + * @param fieldName The name of the field. + * @return The index of the field, or std::nullopt if the field does not exist. + */ + std::optional indexOfField(std::string fieldName) + { + std::transform(fieldName.begin(), fieldName.end(), fieldName.begin(), + [](unsigned char c) + { + return std::tolower(c); + }); + try + { + return this->fieldNameToIndexMap.at(fieldName); + } + catch (const std::out_of_range &oor) + { + time_t now = time(nullptr); + std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") + << "]\t[Base Packet]\t" + << "No field of name " << fieldName + << ", returning nullopt." << std::endl; + return std::nullopt; + } + } + + /** + * @brief Gets the name of a field in the packet based on its index. + * @param index The index of the field. + * @return The name of the field, or std::nullopt if the field does not exist. + */ + std::optional fieldNameOfIndex(uint index) + { + try + { + return this->indexToFieldNameMap.at(index); + } + catch (const std::out_of_range &oor) + { + time_t now = time(nullptr); + std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") + << "]\t[Base Packet]\t" + << "No field at " << index + << ", max is " << numberOfFields() << ", returning nullopt." + << std::endl; + return std::nullopt; + } + } + + /** + * @brief Gets the number of fields in the packet. + * @return The number of fields in the packet. + */ + uint numberOfFields() + { + return this->fieldSizes.size(); + } + + /** + * @brief Gets the field name to index map. + * @return The field name to index map. + */ + std::unordered_map getFieldNameToIndexMap() const + { + return this->fieldNameToIndexMap; + } + + /** + * @brief Gets the index to offset map. + * @return The index to offset map. + */ + std::unordered_map getIndexToOffsetsMap() const + { + return this->indexToOffsetsMap; + } + + /** + * @brief Gets the index to field name map. + * @return The index to field name map. + */ + std::unordered_map getIndexToFieldNameMap() const + { + return this->indexToFieldNameMap; + } + }; + + /** + * @brief Represents an iterator that iterates over individual fields in the packet. + * + * The `bit_iterator` class provides a random access iterator interface for iterating over individual fields in the packet. + * It is templated on the value type of the packet fields. I.e. if the largest packet fields is 32-bit, then the value type should be at least uint32_t. + * + * @tparam ValueType The value type of the values returned by the iterator. The value + */ + template + class bit_iterator + { + + using iterator_category = std::random_access_iterator_tag; + using value_type = ValueType; + using difference_type = std::ptrdiff_t; + using pointer = ValueType *; + using reference = ValueType &; + + /** + * @brief Pointer to the packet data. + */ + const uint8_t *m_data; + /** + * @brief Current offset within the packet. + */ + int m_offset; + /** + * @brief Pointer to the BasePacketStructure. + */ + BasePacketStructure *m_structure; + + /** + * @brief Function to retrieve the value from data based on offset and size. + */ + std::function m_func; + + private: + const uint8_t *m_data; + int m_offset; + BasePacketStructure *m_structure; + std::function m_func; + + public: + bit_iterator(const uint8_t *data, int offset, + BasePacketStructure *structure, + std::function func) : m_data(data), m_offset(offset), m_structure(structure), m_func(func) + { + } + + bit_iterator(const bit_iterator &other) : m_data(other.m_data), m_offset(other.m_offset), m_structure( + other.m_structure), + m_func(other.m_func) + { + } + + bit_iterator &operator++() + { + ++m_offset; + return *this; + } + + bit_iterator operator++(int) + { + bit_iterator temp(*this); + ++m_offset; + return temp; + } + + bit_iterator &operator--() + { + --m_offset; + return *this; + } + + bit_iterator operator--(int) + { + bit_iterator temp(*this); + --m_offset; + return temp; + } + + bit_iterator operator+(int n) const + { + return bit_iterator(m_data, m_offset + n, m_structure, m_func); + } + + bit_iterator operator-(int n) const + { + return bit_iterator(m_data, m_offset - n, m_structure, m_func); + } + + int operator-(const bit_iterator &other) const + { + return m_offset - other.m_offset; + } + bool operator==(const bit_iterator &other) const + { + return m_data == other.m_data && m_offset == other.m_offset; + } + + bool operator!=(const bit_iterator &other) const + { + return !(*this == other); + } + + ValueType operator*() const + { + auto offset = m_structure->bitOffsetOf(m_offset); // offset from the beginning of the byte + auto num_bits = m_structure->bitSizeOf(m_offset); + return m_func(m_data, offset.value(), num_bits.value()); + } + }; + + /** + * @brief Represents a template class for handling packets with a specific structure. + * + * The `BasePacketTempl` class provides a generic template for handling packets with a specified structure. + * It includes methods for reading and writing values from/to memory, as well as other utility functions. + * + * @tparam ValueType The value type of the largest packet fields. i.e The value type should be at least uint32_t if the largest packet field is 32-bit. + */ + template + class BasePacketTempl + { + protected: + BasePacketStructure *packetStructure; /**< Pointer to the structure defining the packet. */ + uint8_t *memoryPointer; /**< Pointer to the memory containing packet data. */ + + /** + * @brief reads a binary value from a memory location pointed to by binaryPointer. + * The binary value is represented by num_bits bits starting from the offset-th bit in the memory. + * + * @param binaryPointer Pointer to the memory containing the binary value. + * @param offset The offset of the first bit of the binary value. + * @param num_bits The number of bits to read. + * @return ValueType The value read from memory. + */ + static ValueType _readValueFromMemoryAt_(const uint8_t *binaryPointer, + uint offset, uint num_bits) + { + // Calculate the bit offset from the byte offset: + uint bit_offset = offset % 8; + // Calculate the byte offset from the bit offset: + uint byte_offset = offset / 8; + ValueType value = 0; + ValueType bit = 1; + + for (uint i = 0; i < num_bits; i++) + { + // Calculate the byte and bit index of the current bit: + uint byte_index = byte_offset + (bit_offset + i) / 8; + uint bit_index = (bit_offset + i) % 8; + uint8_t byte = binaryPointer[byte_index]; + // Create a bit mask to isolate the desired bit: + uint8_t bit_mask = 1 << (7 - bit_index); + // Set the corresponding bit in the return value if the retrieved bit is 1: + value |= (byte & bit_mask) ? (bit << (num_bits - i - 1)) : 0; + } + return value; + } + + /** + * @brief Calculates the minimum number of bits required to represent a given value. + * + * @param value The value to calculate the minimum bits for. + * @return size_t The minimum number of bits required. + */ + size_t minBitsRequired(size_t value) const + { + // Handle special cases + size_t bitsNeeded = 1; + + while (value != 0) + { + bitsNeeded++; + value >>= 1; + } + + return bitsNeeded; + } + + public: + /** + * @brief Constructor for the BasePacketTempl class. + * + * @param structure The structure defining the packet. + */ + BasePacketTempl(BasePacketStructure &structure) + { + this->packetStructure = new BasePacketStructure(structure); + this->memoryPointer = new uint8_t[structure.getByteSize()]; + } + + /** + * @brief Copy constructor for the BasePacketTempl class. + * + * @param other The other BasePacketTempl object to copy. + */ + BasePacketTempl(const BasePacketTempl &other) + { + this->packetStructure = new BasePacketStructure(other.getPacketStructure()); + this->memoryPointer = new uint8_t[other.packetStructure->getByteSize()]; + std::memcpy(this->memoryPointer, other.memoryPointer, + other.packetStructure->getByteSize()); + } + + /** + * @brief Destructor for the BasePacketTempl class. + */ + virtual ~BasePacketTempl() = default; + + /** + * @brief Updates the packet structure. + * @param structure The new packet structure. + */ + void updatePacketStructure(BasePacketStructure &structure) + { + size_t newSize = structure.getByteSize(); + size_t oldSize = this->packetStructure->getByteSize(); + + uint8_t *buff = new uint8_t[newSize]; + std::memset(buff, 0, newSize); + std::memcpy(buff, memoryPointer, std::min(newSize, oldSize)); + delete this->memoryPointer; + + this->memoryPointer = new uint8_t[newSize]; + std::memcpy(memoryPointer, buff, newSize); + delete[] buff; + this->packetStructure = &structure; + } + + /** + * @brief Reads a value from the memory at a given index. + * @param index The index of the field to read. + * @return std::optional The value read from memory, or std::nullopt if the field does not exist. + */ + std::optional readValueFromMemoryAt(uint index) const + { + auto offset = packetStructure->bitOffsetOf(index); // offset from the beginning of the byte + auto num_bits = packetStructure->bitSizeOf(index); // remaining bits to read + if (offset.has_value() && num_bits.has_value()) + return _readValueFromMemoryAt_(memoryPointer, offset.value(), + num_bits.value()); + else + { + time_t now = time(nullptr); + std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") + << "]\t[Base Packet]\t" + << "Error: No field at " << index + << ", max is " << packetStructure->numberOfFields() + << ", returning nullopt" << std::endl; + return std::nullopt; + } + } + + /** + * @brief Returns a pointer to the memory in which stores the packet. + * + * This function returns a constant pointer to the memory. + * + * @return A constant pointer to the memory. + */ + uint8_t const *getPointerToMemory() const + { + return memoryPointer; + } + + /** + * @brief Copies data from a source memory location to the packet's memory. + * + * @param from Pointer to the source memory location. + * @param size Number of bytes to copy. + * @return int The number of bytes copied. + */ + int copyToMemory(const uint8_t *from, uint size) + { + uint max_writable = this->packetStructure->getByteSize(); + if (size > max_writable) + { + time_t now = time(nullptr); + std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") + << "]\t[Base Packet]\t" + << "Error: you are trying to copy " + << size << " byte where the max size is: " << max_writable + << std::endl; + std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") + << "]\t[Base Packet]\t" + << "\tI copy only until " + << max_writable << " byte" << std::endl; + std::memcpy(memoryPointer, from, max_writable); + return max_writable; + } + else + { + std::memcpy(memoryPointer, from, size); + return size; + } + } + + /** + * Copies data from the given memory location to the packet's memory buffer. + * + * @param from Pointer to the source memory location. + * @param size Number of bytes to copy. + * @param offset Offset in the packet's memory buffer to start copying to. + * @return The number of bytes copied. + */ + int copyToMemory(const uint8_t *from, uint size, uint offset) + { + uint max_writable = this->packetStructure->getByteSize(); + if (offset > max_writable) + { + time_t now = time(nullptr); + std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") + << "]\t[Base Packet]\t" + << "Error: you are trying to copy starting from " << offset + << " byte where the max size is: " << max_writable + << std::endl; + return -1; + } + if (size + offset > max_writable) + { + time_t now = time(nullptr); + std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") + << "]\t[Base Packet]\t" + << "Error: you are trying to copy " + << size + offset << " byte where the max size is: " + << max_writable << std::endl; + std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") + << "]\t[Base Packet]\t" + << "\tI copy only until " + << max_writable << " byte" << std::endl; + int to_write = max_writable - offset; + std::memcpy(&memoryPointer[offset], from, to_write); + return to_write; + } + else + { + std::memcpy(&memoryPointer[offset], from, size); + return size; + } + } + + /** + * @brief Accesses the value at the specified index in the packet. + * + * @param index The index of the value to access. + * @return An optional containing the value at the specified index, if it exists. + */ + std::optional operator[](uint index) const + { + return readValueFromMemoryAt(index); + } + + /** + * @brief Accesses the value of a field in the packet by its field name. + * + * @param fieldName The name of the field to access. + * @return An optional value of the specified field type. If the field does not exist, the optional will be empty. + */ + std::optional operator[](std::string fieldName) const + { + std::transform(fieldName.begin(), fieldName.end(), fieldName.begin(), + [](unsigned char c) + { + return std::tolower(c); + }); + auto index = packetStructure->indexOfField(fieldName); + if (index.has_value()) + return readValueFromMemoryAt(index.value()); + else + return std::nullopt; + } + + /** + * @brief Returns a constant bit iterator pointing to the beginning of the packet data. + * + * @return A constant bit iterator pointing to the beginning of the packet data. + */ + bit_iterator begin() const + { + return bit_iterator(memoryPointer, 0, packetStructure, + &_readValueFromMemoryAt_); + } + + /** + * @brief Returns a bit_iterator pointing to the end of the container. + * + * @return A bit_iterator pointing to the end of the container. + */ + bit_iterator end() const + { + return bit_iterator(memoryPointer, + packetStructure->numberOfFields(), packetStructure, + &_readValueFromMemoryAt_); + } + + /** + * Writes a value into memory at the specified index. + * + * @param index The index at which to write the value. + * @param value The value to be written. + * @return An optional containing number of fits written, if any. + */ + std::optional writeValueIntoMemoryAtIndex(uint index, ValueType value) + { + auto offset = this->packetStructure->bitOffsetOf(index); + auto numbits = this->packetStructure->bitSizeOf(index); + size_t min_req = minBitsRequired(value); + if (!offset.has_value() || !numbits.has_value()) + return std::nullopt; + if (numbits < min_req) + { + time_t now = time(nullptr); + std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") + << "]\t[Base Packet]\t" + << "Error: you are trying to write " + << value << " which requires at least " << min_req + << " bits in a field of size " << numbits << std::endl; + return std::nullopt; + } + + // Calculate the bit offset from the byte offset: + uint bitoffset = offset.value() % 8; + // Calculate the byte offset from the bit offset: + uint byteoffset = offset.value() / 8; + uint numbits_written = 0; + + for (size_t i = 0; i < numbits; i++) + { + // Calculate the byte and bit index of the current bit: + uint byte_index = byteoffset + (bitoffset + i) / 8; + uint bit_index = (bitoffset + i) % 8; + // Create a bit mask to isolate the desired bit: + uint8_t bit_mask = 1 << (7 - bit_index); + // Set the corresponding bit in the binary array if the value is 1: + if ((value >> (numbits.value() - i - 1)) & 1) + { + memoryPointer[byte_index] |= bit_mask; + numbits_written++; + } + else + { + memoryPointer[byte_index] &= ~bit_mask; + } + } + return numbits_written; + } + + /** + * @brief Get the byte size of the packet structure. + * + * @return The byte size of the packet structure. + */ + uint getPacketStructureByteSize() const + { + return packetStructure->getByteSize(); + } + /** + * @brief Returns the packet structure of the BasePacket. + * + * @return A reference to the packet structure. + */ + BasePacketStructure &getPacketStructure() const + { + return *(this->packetStructure); + } + + /** + * @brief Checks if the packet has a recognized header. + * @note This is a pure virtual function and must be implemented by derived classes. + * @return true if the packet has a recognized header, false otherwise. + */ + virtual bool hasRecognizedHeader() const = 0; + /** + * @brief Checks if the passed data has a recognized header. + * @param buff The data to check. + * @note This is a pure virtual function and must be implemented by derived classes. + * @return true if buff has a recognized header, false otherwise. + */ + virtual bool isRecognizedHeader(std::vector buff) const = 0; + + /** + * @brief Get the size of the header of the packet. + * @note This is a pure virtual function and must be implemented by derived classes. + * @return The size of the header as an unsigned integer. + */ + virtual uint getHeaderSize() const = 0; + /** + * @brief Get the size of the payload of the packet. + * @note This is a pure virtual function and must be implemented by derived classes. + * @return The size of the payload as an unsigned integer. + */ + virtual uint getPayloadSize() const = 0; + /** + * @brief Get the size of the tail of the packet. + * @note This is a pure virtual function and must be implemented by derived classes. + * @return The size of the tail as an unsigned integer. + */ + virtual uint getTailSize() const = 0; + }; + + using valueType = size_t; + /** + * @brief Represents a concrete class derived from BasePacketTempl with a specified value type. + * + * The `BasePacket` class is a concrete class derived from `BasePacketTempl` with a value type of `size_t`. + */ + class BasePacket : public BasePacketTempl + { + + protected: + public: + BasePacket(BasePacketStructure &structure) : BasePacketTempl(structure) + { + } + virtual ~BasePacket() = default; + }; +} diff --git a/include/Base_Provider.h b/include/Base_Provider.h index 695dd0c..b034a87 100644 --- a/include/Base_Provider.h +++ b/include/Base_Provider.h @@ -1,27 +1,74 @@ -/* - * - * Created on: Mar 1, 2021 - * Author: astrisw - * - */ - #pragma once #include #include namespace inaf::oasbo::Providers { +/** + * @brief The BaseProvider class is an abstract base class for providers in the DAQ system. + * + * This class defines the common interface for providers that write packets to a destination. + * Derived classes must implement the pure virtual functions defined in this class. + */ class BaseProvider{ protected: - std::string dest; + std::string dest; /**< The destination where packets are written to. */ + public: - virtual int write(PacketLib::BasePacket &) = 0; - virtual int write(PacketLib::BasePacket &, std::string dest) = 0; + /** + * @brief Writes a packet to the destination. + * + * @param packet The packet to be written. + * @return int Returns an integer indicating the success or failure of the write operation. + */ + virtual int write(PacketLib::BasePacket &packet) = 0; + + /** + * @brief Writes a packet to a specified destination. + * + * @param packet The packet to be written. + * @param dest The destination where the packet should be written to. + * @return int Returns an integer indicating the success or failure of the write operation. + */ + virtual int write(PacketLib::BasePacket &packet, std::string dest) = 0; - virtual int open()=0; - virtual int close()=0; + /** + * @brief Opens the provider. + * + * @return int Returns an integer indicating the success or failure of the open operation. + */ + virtual int open() = 0; + + /** + * @brief Closes the provider. + * + * @return int Returns an integer indicating the success or failure of the close operation. + */ + virtual int close() = 0; + + /** + * @brief Checks if the provider is open. + * + * @return bool Returns true if the provider is open, false otherwise. + */ virtual bool isOpen() = 0; + + /** + * @brief Sets the destination where packets should be written to. + * + * @param dest The destination to be set. + */ virtual void setDest(std::string dest) = 0; + + /** + * @brief Gets the current destination where packets are written to. + * + * @return std::string Returns the current destination. + */ virtual std::string getDest() = 0; + + /** + * @brief Default destructor. + */ virtual ~BaseProvider() = default; }; -} +} \ No newline at end of file diff --git a/include/Base_Receiver.h b/include/Base_Receiver.h index d16335b..924c5b8 100755 --- a/include/Base_Receiver.h +++ b/include/Base_Receiver.h @@ -1,9 +1,3 @@ -/* - * - * Created on: Mar 1, 2021 - * Author: astrisw - * - */ #pragma once @@ -12,18 +6,66 @@ namespace inaf::oasbo::Receivers{ +/** + * @brief The BaseReceiver class is an abstract base class for receivers in the DAQ system. + * + * This class provides a common interface for receiving data from clients. It defines pure virtual + * functions for getting and setting the host, connecting to and closing the connection with the client, + * checking if the receiver is connected to the client, and receiving data from the client. + * + * Derived classes must implement these functions according to their specific requirements. + */ class BaseReceiver{ protected: std::string host; public: + /** + * @brief Get the host address. + * + * @return The host address as a string. + */ virtual std::string getHost() = 0; + + /** + * @brief Set the host address. + * + * @param host The host address to set. + */ virtual void setHost(std::string host) = 0; + /** + * @brief Connect to the client. + * + * @return An integer indicating the success or failure of the operation. + */ virtual int connectToClient()=0; + + /** + * @brief Close the connection with the client. + * + * @return An integer indicating the success or failure of the operation. + */ virtual int closeConnectionToClient()=0; + + /** + * @brief Check if the receiver is connected to the client. + * + * @return true if the receiver is connected to the client, false otherwise. + */ virtual bool isConnectedToClient() const =0; + + /** + * @brief Receive data from the client. + * + * @param packet The received packet will be stored in this parameter. + * @return An integer indicating the success or failure of the operation. + */ virtual int receiveFromClient(PacketLib::BasePacket &) = 0; + + /** + * @brief Virtual destructor. + */ virtual ~BaseReceiver() = default; }; } -- GitLab From f81453c9f6d51b1cce2ce0507264c69f5dddc725 Mon Sep 17 00:00:00 2001 From: valerio pastore Date: Thu, 11 Jan 2024 19:41:59 +0100 Subject: [PATCH 2/4] . --- CMakeLists.txt | 11 +- include/Base_Archiver.h | 12 +- include/Base_Configurator.h | 15 +- include/Base_DAQ_Observer.h | 88 +-- include/Base_Monitor.h | 33 +- include/Base_Packet.h | 1423 +++++++++++++++++------------------ include/Base_Provider.h | 4 +- include/Base_Receiver.h | 7 +- 8 files changed, 754 insertions(+), 839 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ed0457f..915214f 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,11 @@ cmake_minimum_required(VERSION 3.9) project(Base_DAQ) - -set(CMAKE_CXX_EXTENSIONS OFF) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++20") +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") file(GLOB INCLUDE_FILES "include/*.h") -file(GLOB TCLAP "include/tclap") set(CMAKE_INSTALL_MESSAGE LAZY) @@ -15,8 +13,3 @@ install( FILES ${INCLUDE_FILES} DESTINATION "${CMAKE_INSTALL_PREFIX}/include/Base_DAQ" ) - -install( - DIRECTORY ${TCLAP} - DESTINATION "${CMAKE_INSTALL_PREFIX}/include" -) \ No newline at end of file diff --git a/include/Base_Archiver.h b/include/Base_Archiver.h index 9634ba4..4b86616 100755 --- a/include/Base_Archiver.h +++ b/include/Base_Archiver.h @@ -1,11 +1,9 @@ - #pragma once #include #include - -namespace inaf::oasbo::Archivers{ +namespace inaf::oasbo::Archivers { /** * @brief The BaseArchiver class is an abstract base class for archivers. @@ -13,9 +11,9 @@ namespace inaf::oasbo::Archivers{ * This class provides a common interface for archiving packets. Derived classes * must implement the pure virtual functions defined in this class. */ -class BaseArchiver{ +class BaseArchiver { protected: - std::string dest; /**< The destination of the archiver. */ + std::string dest; /**< The destination of the archiver. */ public: /** @@ -26,7 +24,7 @@ public: * @param packet The packet to write. * @return An integer indicating the success or failure of the write operation. */ - virtual int write(PacketLib::BasePacket &) = 0; + virtual int write(PacketLib::BasePacket&) = 0; /** * @brief Write a packet to the archiver with a specified destination. @@ -37,7 +35,7 @@ public: * @param destination The destination where the packet should be written. * @return An integer indicating the success or failure of the write operation. */ - virtual int write(PacketLib::BasePacket &, std::string destination) = 0; + virtual int write(PacketLib::BasePacket&, std::string destination) = 0; /** * @brief Open the archiver. diff --git a/include/Base_Configurator.h b/include/Base_Configurator.h index 36c4900..46f28b7 100644 --- a/include/Base_Configurator.h +++ b/include/Base_Configurator.h @@ -11,9 +11,9 @@ namespace inaf::oasbo::Configurators { * It provides common functionality for reading and pushing configurations to a source, * as well as inserting new configurations into the existing ones. */ -class BaseConfigurator{ +class BaseConfigurator { protected: - std::map config; + std::map config; public: /** @@ -53,23 +53,26 @@ public: * @param target The target for which to insert the new configurations. * @return int Returns 0 on success, or an error code on failure. */ - virtual int insert(std::map newConfig, std::string target) = 0; + virtual int insert(std::map newConfig, + std::string target) = 0; /** * @brief Get the current configuration. * * @return std::map The current configuration. */ - virtual std::map getConfig() {return this->config;} + virtual std::map getConfig() { + return this->config; + } /** * @brief Convert the configuration to a string representation. * * @return std::string The string representation of the configuration. */ - std::string toString(){ + std::string toString() { std::string ret = ""; - for( const std::pair n : config) { + for (const std::pair n : config) { ret += n.first + " : " + n.second + "\n"; } return ret; diff --git a/include/Base_DAQ_Observer.h b/include/Base_DAQ_Observer.h index 70bfaef..dbcffb6 100644 --- a/include/Base_DAQ_Observer.h +++ b/include/Base_DAQ_Observer.h @@ -9,63 +9,63 @@ * Subclasses of BaseDAQ_Observer must implement the pure virtual functions defined in this class. * */ -namespace inaf::oasbo::DAQ_observers{ +namespace inaf::oasbo::DAQ_observers { -class BaseDAQ_Observer{ +class BaseDAQ_Observer { protected: inaf::oasbo::DAQ::BaseDAQ *dataAcquisition; public: - /** - * @brief Constructs a BaseDAQ_Observer object with the specified BaseDAQ object. - * - * @param dataAcquisition The BaseDAQ object to observe. - */ - BaseDAQ_Observer(inaf::oasbo::DAQ::BaseDAQ &dataAcquisition) { - this->dataAcquisition = &dataAcquisition; - } + /** + * @brief Constructs a BaseDAQ_Observer object with the specified BaseDAQ object. + * + * @param dataAcquisition The BaseDAQ object to observe. + */ + BaseDAQ_Observer(inaf::oasbo::DAQ::BaseDAQ &dataAcquisition) { + this->dataAcquisition = &dataAcquisition; + } - /** - * @brief Destroys the BaseDAQ_Observer object and removes itself from the observed BaseDAQ object. - */ - virtual ~BaseDAQ_Observer() { - this->dataAcquisition->removeObserver(this); - } + /** + * @brief Destroys the BaseDAQ_Observer object and removes itself from the observed BaseDAQ object. + */ + virtual ~BaseDAQ_Observer() { + this->dataAcquisition->removeObserver(this); + } - /** - * @brief Updates the packet statistics of the observed BaseDAQ object. - */ - virtual void updatePacketStats() = 0; + /** + * @brief Updates the packet statistics of the observed BaseDAQ object. + */ + virtual void updatePacketStats() = 0; - /** - * @brief Updates the archiver statistics of the observed BaseDAQ object. - */ - virtual void updateArchiverStats() = 0; + /** + * @brief Updates the archiver statistics of the observed BaseDAQ object. + */ + virtual void updateArchiverStats() = 0; - /** - * @brief Updates the provider statistics of the observed BaseDAQ object. - */ - virtual void updateProviderStats() = 0; + /** + * @brief Updates the provider statistics of the observed BaseDAQ object. + */ + virtual void updateProviderStats() = 0; - /** - * @brief Updates the receiver statistics of the observed BaseDAQ object. - */ - virtual void updateReceiverStats() = 0; + /** + * @brief Updates the receiver statistics of the observed BaseDAQ object. + */ + virtual void updateReceiverStats() = 0; - /** - * @brief Updates all statistics of the observed BaseDAQ object. - */ - virtual void updateAll() = 0; + /** + * @brief Updates all statistics of the observed BaseDAQ object. + */ + virtual void updateAll() = 0; - /** - * @brief Starts the observation on the BaseDAQ object. - */ - virtual void start() = 0; + /** + * @brief Starts the observation on the BaseDAQ object. + */ + virtual void start() = 0; - /** - * @brief Stops the observation on the BaseDAQ object. - */ - virtual void stop() = 0; + /** + * @brief Stops the observation on the BaseDAQ object. + */ + virtual void stop() = 0; }; } diff --git a/include/Base_Monitor.h b/include/Base_Monitor.h index e30d065..26eb197 100644 --- a/include/Base_Monitor.h +++ b/include/Base_Monitor.h @@ -1,10 +1,9 @@ - #pragma once #include #include #include -namespace inaf::oasbo::PacketMonitors{ +namespace inaf::oasbo::PacketMonitors { /** * @brief The BasePacketMonitor class is an abstract base class for packet monitors in the DAQ system. @@ -13,7 +12,7 @@ namespace inaf::oasbo::PacketMonitors{ * Derived classes must implement the monit(), printStats(), and reset() methods. * The class also provides methods to access and retrieve statistics related to the monitored packets. */ -class BasePacketMonitor{ +class BasePacketMonitor { protected: std::map stats; /**< A map to store statistics related to the monitored packets. */ public: @@ -50,24 +49,26 @@ public: * * @return The map containing the statistics related to the monitored packets. */ - virtual std::map getStatsMap() const { return stats;} + virtual std::map getStatsMap() const { + return stats; + } - /** - * @brief Retrieves a specific statistic. - * - * This method retrieves a specific statistic from the statistics map. - * If the statistic is not found, it returns std::nullopt. - * - * @param stat The name of the statistic to retrieve. - * @return An optional string containing the value of the statistic, or std::nullopt if the statistic is not found. - */ - std::optional getStat(std::string stat) const { + /** + * @brief Retrieves a specific statistic. + * + * This method retrieves a specific statistic from the statistics map. + * If the statistic is not found, it returns std::nullopt. + * + * @param stat The name of the statistic to retrieve. + * @return An optional string containing the value of the statistic, or std::nullopt if the statistic is not found. + */ + std::optional getStat(std::string stat) const { try { return this->stats.at(stat); - } catch (const std::out_of_range &) { + } catch (const std::out_of_range&) { return std::nullopt; } - } + } /** * @brief Default destructor. diff --git a/include/Base_Packet.h b/include/Base_Packet.h index e5a80c4..9e5c823 100644 --- a/include/Base_Packet.h +++ b/include/Base_Packet.h @@ -1,4 +1,3 @@ - #pragma once #include @@ -14,806 +13,728 @@ #include #include -namespace inaf::oasbo::Packets -{ - +namespace inaf::oasbo::Packets { + +/** + * @class BasePacketStructure + * @brief Represents the structure of a base packet. + * + * The BasePacketStructure class provides functionality to define and manipulate the structure of a base packet. + * It stores information about the fields, their sizes, offsets, and mappings between field names and indices. + * The class also provides methods to retrieve information about the structure, such as the byte size, field offsets, and field names. + * + * @note This is an abstract base class and should be derived to define specific packet structures. In particular, you should define + * the sourceReadingFunc function. + */ +class BasePacketStructure { +protected: /** - * @class BasePacketStructure - * @brief Represents the structure of a base packet. - * - * The BasePacketStructure class provides functionality to define and manipulate the structure of a base packet. - * It stores information about the fields, their sizes, offsets, and mappings between field names and indices. - * The class also provides methods to retrieve information about the structure, such as the byte size, field offsets, and field names. + * @brief Type alias for the packet structure. * - * @note This is an abstract base class and should be derived to define specific packet structures. In particular, you should define - * the sourceReadingFunc function. - */ - class BasePacketStructure - { - protected: - /** - * @brief Type alias for the packet structure. - * - * This alias represents the structure of a packet. It is defined as a vector of tuples, where each tuple contains three elements: - * - The first element is of type uint and represents the field index. - * - The second element is of type std::string and represents the field name. - * - The third element is of type uint and represents the field bit size. - */ - using Structure = std::vector>; /**< Type alias for the packet structure. */ - - std::string source; /**< The source of the packet. */ - Structure structure; /**< The structure of the packet. */ - uint byteSize; /**< The size of the packet in bytes. */ - std::vector fieldSizes; /**< vector of the sizes of the fields in the packet. */ - std::unordered_map indexToOffsetsMap; /**< Mapping of field index to field offset. */ - std::unordered_map fieldNameToIndexMap; /**< Mapping of field name to field index. */ - std::unordered_map indexToFieldNameMap; /**< Mapping of field index to field name. */ - std::function sourceReadingFunc; /**< Function to read the packet source and return the structure. */ - - /** - * @brief Updates the field sizes based on the structure. - * @param structure The structure of the packet. - */ - void updateFieldSizes(const Structure &structure) - { - std::for_each(structure.begin(), structure.end(), - [&](const std::tuple &tup) - { - this->fieldSizes.push_back(std::get<2>(tup)); - }); - } - - /** - * @brief Updates the field offsets based on the structure. - * @param structure The structure of the packet. - */ - void updateFieldOffsets(const Structure &structure) - { - uint offset = 0; - for (size_t i = 0; i < structure.size(); i++) - { - indexToOffsetsMap[i] = offset; - offset += std::get<2>(structure[i]); - } - } - - /** - * @brief Updates the field name and index maps based on the structure. - * @param structure The structure of the packet. - */ - void updateFieldNameAndIndexMap(const Structure &structure) - { - std::for_each(structure.begin(), structure.end(), - [&](const std::tuple &tup) - { - this->fieldNameToIndexMap[std::get<1>(tup)] = std::get<0>(tup); - this->indexToFieldNameMap[std::get<0>(tup)] = std::get<1>(tup); - }); - } - - /** - * @brief Updates the packet structure based on the source. - * @param source The source of the packet structure. - */ - void updateStructure(std::string source) - { - this->source = source; - this->structure = sourceReadingFunc(source); - updateFieldSizes(structure); - updateFieldOffsets(structure); - updateFieldNameAndIndexMap(structure); - uint bitSize = std::accumulate(fieldSizes.begin(), fieldSizes.end(), 0); - this->byteSize = bitSize % 8 == 0 ? bitSize / 8 : bitSize / 8 + 1; - } - - public: - /** - * @brief Destructor. - */ - virtual ~BasePacketStructure() = default; - - /** - * @brief Constructor. - * @param source The source of the packet structure. - * @param sourceReadingFunc The function to read the packet source and return the structure. - */ - BasePacketStructure(std::string source, std::function sourceReadingFunc) : source(source), sourceReadingFunc(sourceReadingFunc) - { - this->updateStructure(source); - } + * This alias represents the structure of a packet. It is defined as a vector of tuples, where each tuple contains three elements: + * - The first element is of type uint and represents the field index. + * - The second element is of type std::string and represents the field name. + * - The third element is of type uint and represents the field bit size. + */ + using Structure = std::vector>; /**< Type alias for the packet structure. */ - /** - * @brief Copy constructor. - * @param other The other BasePacketStructure object to copy from. - */ - BasePacketStructure(const BasePacketStructure &other) - { - this->source = other.source; - this->byteSize = other.byteSize; - this->fieldSizes = other.fieldSizes; - this->indexToOffsetsMap = other.indexToOffsetsMap; - this->fieldNameToIndexMap = other.fieldNameToIndexMap; - this->indexToFieldNameMap = other.indexToFieldNameMap; - this->sourceReadingFunc = other.sourceReadingFunc; - } + std::string source; /**< The source of the packet. */ + Structure structure; /**< The structure of the packet. */ + uint byteSize; /**< The size of the packet in bytes. */ + std::vector fieldSizes; /**< vector of the sizes of the fields in the packet. */ + std::unordered_map indexToOffsetsMap; /**< Mapping of field index to field offset. */ + std::unordered_map fieldNameToIndexMap; /**< Mapping of field name to field index. */ + std::unordered_map indexToFieldNameMap; /**< Mapping of field index to field name. */ + std::function sourceReadingFunc; /**< Function to read the packet source and return the structure. */ - /** - * @brief Changes the source of the packet and updates the structure. - * @param source The new source of the packet structure. - */ - void changeSource(std::string source) - { - updateStructure(source); - } + /** + * @brief Updates the field sizes based on the structure. + * @param structure The structure of the packet. + */ + void updateFieldSizes(const Structure &structure) { + std::for_each(structure.begin(), structure.end(), + [&](const std::tuple &tup) { + this->fieldSizes.push_back(std::get<2>(tup)); + }); + } - /** - * @brief Gets the size of the packet in bytes. - * @return The size of the packet in bytes. - */ - uint getByteSize() - { - return this->byteSize; + /** + * @brief Updates the field offsets based on the structure. + * @param structure The structure of the packet. + */ + void updateFieldOffsets(const Structure &structure) { + uint offset = 0; + for (size_t i = 0; i < structure.size(); i++) { + indexToOffsetsMap[i] = offset; + offset += std::get<2>(structure[i]); } + } - /** - * @brief Gets the source of the packet structure. - * @return The source of the packet structure. - */ - std::string getSource() - { - return this->source; - } + /** + * @brief Updates the field name and index maps based on the structure. + * @param structure The structure of the packet. + */ + void updateFieldNameAndIndexMap(const Structure &structure) { + std::for_each(structure.begin(), structure.end(), + [&](const std::tuple &tup) { + this->fieldNameToIndexMap[std::get<1>(tup)] = std::get<0>( + tup); + this->indexToFieldNameMap[std::get<0>(tup)] = std::get<1>( + tup); + }); + } - /** - * @brief Gets the bit offset of a field in the packet structure. - * @param index The index of the field. - * @return The bit offset of the field, or std::nullopt if the field does not exist. - */ - std::optional bitOffsetOf(uint index) - { - if (index <= this->numberOfFields()) - { - return indexToOffsetsMap.at(index); - } - else - { - time_t now = time(nullptr); - std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") - << "]\t[Base Packet]\t" - << "No field at " << index - << ", max is " << numberOfFields() << ", returning nullopt." - << std::endl; - return std::nullopt; - } - } + /** + * @brief Updates the packet structure based on the source. + * @param source The source of the packet structure. + */ + void updateStructure(std::string source) { + this->source = source; + this->structure = sourceReadingFunc(source); + updateFieldSizes(structure); + updateFieldOffsets(structure); + updateFieldNameAndIndexMap(structure); + uint bitSize = std::accumulate(fieldSizes.begin(), fieldSizes.end(), 0); + this->byteSize = bitSize % 8 == 0 ? bitSize / 8 : bitSize / 8 + 1; + } + +public: + /** + * @brief Destructor. + */ + virtual ~BasePacketStructure() = default; - /** - * @brief Gets the bit size of a field in the packet structure. - * @param index The index of the field. - * @return The bit size of the field, or std::nullopt if the field does not exist. - */ - std::optional bitSizeOf(uint index) - { - if (index <= this->numberOfFields()) - { - return this->fieldSizes[index]; - } - else - { - time_t now = time(nullptr); - std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") - << "]\t[Base Packet]\t" - << "No field at " << index - << ", max is " << numberOfFields() << ", returning nullopt." - << std::endl; - return std::nullopt; - } - } + /** + * @brief Constructor. + * @param source The source of the packet structure. + * @param sourceReadingFunc The function to read the packet source and return the structure. + */ + BasePacketStructure(std::string source, + std::function sourceReadingFunc) : + source(source), sourceReadingFunc(sourceReadingFunc) { + this->updateStructure(source); + } - /** - * @brief Gets the index of a field in the packet structure based on its name. - * @param fieldName The name of the field. - * @return The index of the field, or std::nullopt if the field does not exist. - */ - std::optional indexOfField(std::string fieldName) - { - std::transform(fieldName.begin(), fieldName.end(), fieldName.begin(), - [](unsigned char c) - { - return std::tolower(c); - }); - try - { - return this->fieldNameToIndexMap.at(fieldName); - } - catch (const std::out_of_range &oor) - { - time_t now = time(nullptr); - std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") - << "]\t[Base Packet]\t" - << "No field of name " << fieldName - << ", returning nullopt." << std::endl; - return std::nullopt; - } - } + /** + * @brief Copy constructor. + * @param other The other BasePacketStructure object to copy from. + */ + BasePacketStructure(const BasePacketStructure &other) { + this->source = other.source; + this->byteSize = other.byteSize; + this->fieldSizes = other.fieldSizes; + this->indexToOffsetsMap = other.indexToOffsetsMap; + this->fieldNameToIndexMap = other.fieldNameToIndexMap; + this->indexToFieldNameMap = other.indexToFieldNameMap; + this->sourceReadingFunc = other.sourceReadingFunc; + } - /** - * @brief Gets the name of a field in the packet based on its index. - * @param index The index of the field. - * @return The name of the field, or std::nullopt if the field does not exist. - */ - std::optional fieldNameOfIndex(uint index) - { - try - { - return this->indexToFieldNameMap.at(index); - } - catch (const std::out_of_range &oor) - { - time_t now = time(nullptr); - std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") - << "]\t[Base Packet]\t" - << "No field at " << index - << ", max is " << numberOfFields() << ", returning nullopt." - << std::endl; - return std::nullopt; - } - } + /** + * @brief Changes the source of the packet and updates the structure. + * @param source The new source of the packet structure. + */ + void changeSource(std::string source) { + updateStructure(source); + } - /** - * @brief Gets the number of fields in the packet. - * @return The number of fields in the packet. - */ - uint numberOfFields() - { - return this->fieldSizes.size(); - } + /** + * @brief Gets the size of the packet in bytes. + * @return The size of the packet in bytes. + */ + uint getByteSize() { + return this->byteSize; + } - /** - * @brief Gets the field name to index map. - * @return The field name to index map. - */ - std::unordered_map getFieldNameToIndexMap() const - { - return this->fieldNameToIndexMap; - } + /** + * @brief Gets the source of the packet structure. + * @return The source of the packet structure. + */ + std::string getSource() { + return this->source; + } - /** - * @brief Gets the index to offset map. - * @return The index to offset map. - */ - std::unordered_map getIndexToOffsetsMap() const - { - return this->indexToOffsetsMap; - } + /** + * @brief Gets the bit offset of a field in the packet structure. + * @param index The index of the field. + * @return The bit offset of the field, or std::nullopt if the field does not exist. + */ + std::optional bitOffsetOf(uint index) { + if (index <= this->numberOfFields()) { + return indexToOffsetsMap.at(index); + } else { + time_t now = time(nullptr); + std::cerr << "[" + << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") + << "]\t[Base Packet]\t" << "No field at " << index + << ", max is " << numberOfFields() << ", returning nullopt." + << std::endl; + return std::nullopt; + } + } - /** - * @brief Gets the index to field name map. - * @return The index to field name map. - */ - std::unordered_map getIndexToFieldNameMap() const - { - return this->indexToFieldNameMap; - } - }; + /** + * @brief Gets the bit size of a field in the packet structure. + * @param index The index of the field. + * @return The bit size of the field, or std::nullopt if the field does not exist. + */ + std::optional bitSizeOf(uint index) { + if (index <= this->numberOfFields()) { + return this->fieldSizes[index]; + } else { + time_t now = time(nullptr); + std::cerr << "[" + << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") + << "]\t[Base Packet]\t" << "No field at " << index + << ", max is " << numberOfFields() << ", returning nullopt." + << std::endl; + return std::nullopt; + } + } /** - * @brief Represents an iterator that iterates over individual fields in the packet. - * - * The `bit_iterator` class provides a random access iterator interface for iterating over individual fields in the packet. - * It is templated on the value type of the packet fields. I.e. if the largest packet fields is 32-bit, then the value type should be at least uint32_t. - * - * @tparam ValueType The value type of the values returned by the iterator. The value - */ - template - class bit_iterator - { - - using iterator_category = std::random_access_iterator_tag; - using value_type = ValueType; - using difference_type = std::ptrdiff_t; - using pointer = ValueType *; - using reference = ValueType &; - - /** - * @brief Pointer to the packet data. - */ - const uint8_t *m_data; - /** - * @brief Current offset within the packet. - */ - int m_offset; - /** - * @brief Pointer to the BasePacketStructure. - */ - BasePacketStructure *m_structure; - - /** - * @brief Function to retrieve the value from data based on offset and size. - */ - std::function m_func; - - private: - const uint8_t *m_data; - int m_offset; - BasePacketStructure *m_structure; - std::function m_func; - - public: - bit_iterator(const uint8_t *data, int offset, - BasePacketStructure *structure, - std::function func) : m_data(data), m_offset(offset), m_structure(structure), m_func(func) - { - } + * @brief Gets the index of a field in the packet structure based on its name. + * @param fieldName The name of the field. + * @return The index of the field, or std::nullopt if the field does not exist. + */ + std::optional indexOfField(std::string fieldName) { + std::transform(fieldName.begin(), fieldName.end(), fieldName.begin(), + [](unsigned char c) { + return std::tolower(c); + }); + try { + return this->fieldNameToIndexMap.at(fieldName); + } catch (const std::out_of_range &oor) { + time_t now = time(nullptr); + std::cerr << "[" + << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") + << "]\t[Base Packet]\t" << "No field of name " << fieldName + << ", returning nullopt." << std::endl; + return std::nullopt; + } + } - bit_iterator(const bit_iterator &other) : m_data(other.m_data), m_offset(other.m_offset), m_structure( - other.m_structure), - m_func(other.m_func) - { - } + /** + * @brief Gets the name of a field in the packet based on its index. + * @param index The index of the field. + * @return The name of the field, or std::nullopt if the field does not exist. + */ + std::optional fieldNameOfIndex(uint index) { + try { + return this->indexToFieldNameMap.at(index); + } catch (const std::out_of_range &oor) { + time_t now = time(nullptr); + std::cerr << "[" + << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") + << "]\t[Base Packet]\t" << "No field at " << index + << ", max is " << numberOfFields() << ", returning nullopt." + << std::endl; + return std::nullopt; + } + } - bit_iterator &operator++() - { - ++m_offset; - return *this; - } + /** + * @brief Gets the number of fields in the packet. + * @return The number of fields in the packet. + */ + uint numberOfFields() { + return this->fieldSizes.size(); + } - bit_iterator operator++(int) - { - bit_iterator temp(*this); - ++m_offset; - return temp; - } + /** + * @brief Gets the field name to index map. + * @return The field name to index map. + */ + std::unordered_map getFieldNameToIndexMap() const { + return this->fieldNameToIndexMap; + } - bit_iterator &operator--() - { - --m_offset; - return *this; - } + /** + * @brief Gets the index to offset map. + * @return The index to offset map. + */ + std::unordered_map getIndexToOffsetsMap() const { + return this->indexToOffsetsMap; + } - bit_iterator operator--(int) - { - bit_iterator temp(*this); - --m_offset; - return temp; - } + /** + * @brief Gets the index to field name map. + * @return The index to field name map. + */ + std::unordered_map getIndexToFieldNameMap() const { + return this->indexToFieldNameMap; + } +}; + +/** + * @brief Represents an iterator that iterates over individual fields in the packet. + * + * The `bit_iterator` class provides a random access iterator interface for iterating over individual fields in the packet. + * It is templated on the value type of the packet fields. I.e. if the largest packet fields is 32-bit, then the value type should be at least uint32_t. + * + * @tparam ValueType The value type of the values returned by the iterator. The value + */ +template +class bit_iterator { + + using iterator_category = std::random_access_iterator_tag; + using value_type = ValueType; + using difference_type = std::ptrdiff_t; + using pointer = ValueType *; + using reference = ValueType &; + +private: - bit_iterator operator+(int n) const - { - return bit_iterator(m_data, m_offset + n, m_structure, m_func); - } + /** + * @brief Pointer to the packet data. + */ + const uint8_t *m_data; + /** + * @brief Current offset within the packet. + */ + int m_offset; + /** + * @brief Pointer to the BasePacketStructure. + */ + BasePacketStructure *m_structure; - bit_iterator operator-(int n) const - { - return bit_iterator(m_data, m_offset - n, m_structure, m_func); - } + /** + * @brief Function to retrieve the value from data based on offset and size. + */ + std::function m_func; + +public: + bit_iterator(const uint8_t *data, int offset, + BasePacketStructure *structure, + std::function func) : + m_data(data), m_offset(offset), m_structure(structure), m_func(func) { + } + + bit_iterator(const bit_iterator &other) : + m_data(other.m_data), m_offset(other.m_offset), m_structure( + other.m_structure), m_func(other.m_func) { + } + + bit_iterator& operator++() { + ++m_offset; + return *this; + } + + bit_iterator operator++(int) { + bit_iterator temp(*this); + ++m_offset; + return temp; + } + + bit_iterator& operator--() { + --m_offset; + return *this; + } + + bit_iterator operator--(int) { + bit_iterator temp(*this); + --m_offset; + return temp; + } + + bit_iterator operator+(int n) const { + return bit_iterator(m_data, m_offset + n, m_structure, m_func); + } + + bit_iterator operator-(int n) const { + return bit_iterator(m_data, m_offset - n, m_structure, m_func); + } + + int operator-(const bit_iterator &other) const { + return m_offset - other.m_offset; + } + + bool operator==(const bit_iterator &other) const { + return m_data == other.m_data && m_offset == other.m_offset; + } + + bool operator!=(const bit_iterator &other) const { + return !(*this == other); + } + + ValueType operator*() const { + auto offset = m_structure->bitOffsetOf(m_offset); // offset from the beginning of the byte + auto num_bits = m_structure->bitSizeOf(m_offset); + return m_func(m_data, offset.value(), num_bits.value()); + } +}; + +/** + * @brief Represents a template class for handling packets with a specific structure. + * + * The `BasePacketTempl` class provides a generic template for handling packets with a specified structure. + * It includes methods for reading and writing values from/to memory, as well as other utility functions. + * + * @tparam ValueType The value type of the largest packet fields. i.e The value type should be at least uint32_t if the largest packet field is 32-bit. + */ +template +class BasePacketTempl { +protected: + BasePacketStructure *packetStructure; /**< Pointer to the structure defining the packet. */ + uint8_t *memoryPointer; /**< Pointer to the memory containing packet data. */ - int operator-(const bit_iterator &other) const - { - return m_offset - other.m_offset; - } + /** + * @brief reads a binary value from a memory location pointed to by binaryPointer. + * The binary value is represented by num_bits bits starting from the offset-th bit in the memory. + * + * @param binaryPointer Pointer to the memory containing the binary value. + * @param offset The offset of the first bit of the binary value. + * @param num_bits The number of bits to read. + * @return ValueType The value read from memory. + */ + static ValueType _readValueFromMemoryAt_(const uint8_t *binaryPointer, + uint offset, uint num_bits) { + // Calculate the bit offset from the byte offset: + uint bit_offset = offset % 8; + // Calculate the byte offset from the bit offset: + uint byte_offset = offset / 8; + ValueType value = 0; + ValueType bit = 1; + + for (uint i = 0; i < num_bits; i++) { + // Calculate the byte and bit index of the current bit: + uint byte_index = byte_offset + (bit_offset + i) / 8; + uint bit_index = (bit_offset + i) % 8; + uint8_t byte = binaryPointer[byte_index]; + // Create a bit mask to isolate the desired bit: + uint8_t bit_mask = 1 << (7 - bit_index); + // Set the corresponding bit in the return value if the retrieved bit is 1: + value |= (byte & bit_mask) ? (bit << (num_bits - i - 1)) : 0; + } + return value; + } - bool operator==(const bit_iterator &other) const - { - return m_data == other.m_data && m_offset == other.m_offset; - } + /** + * @brief Calculates the minimum number of bits required to represent a given value. + * + * @param value The value to calculate the minimum bits for. + * @return size_t The minimum number of bits required. + */ + size_t minBitsRequired(size_t value) const { + // Handle special cases + size_t bitsNeeded = 1; - bool operator!=(const bit_iterator &other) const - { - return !(*this == other); + while (value != 0) { + bitsNeeded++; + value >>= 1; } - ValueType operator*() const - { - auto offset = m_structure->bitOffsetOf(m_offset); // offset from the beginning of the byte - auto num_bits = m_structure->bitSizeOf(m_offset); - return m_func(m_data, offset.value(), num_bits.value()); - } - }; + return bitsNeeded; + } +public: /** - * @brief Represents a template class for handling packets with a specific structure. - * - * The `BasePacketTempl` class provides a generic template for handling packets with a specified structure. - * It includes methods for reading and writing values from/to memory, as well as other utility functions. + * @brief Constructor for the BasePacketTempl class. * - * @tparam ValueType The value type of the largest packet fields. i.e The value type should be at least uint32_t if the largest packet field is 32-bit. - */ - template - class BasePacketTempl - { - protected: - BasePacketStructure *packetStructure; /**< Pointer to the structure defining the packet. */ - uint8_t *memoryPointer; /**< Pointer to the memory containing packet data. */ - - /** - * @brief reads a binary value from a memory location pointed to by binaryPointer. - * The binary value is represented by num_bits bits starting from the offset-th bit in the memory. - * - * @param binaryPointer Pointer to the memory containing the binary value. - * @param offset The offset of the first bit of the binary value. - * @param num_bits The number of bits to read. - * @return ValueType The value read from memory. - */ - static ValueType _readValueFromMemoryAt_(const uint8_t *binaryPointer, - uint offset, uint num_bits) - { - // Calculate the bit offset from the byte offset: - uint bit_offset = offset % 8; - // Calculate the byte offset from the bit offset: - uint byte_offset = offset / 8; - ValueType value = 0; - ValueType bit = 1; - - for (uint i = 0; i < num_bits; i++) - { - // Calculate the byte and bit index of the current bit: - uint byte_index = byte_offset + (bit_offset + i) / 8; - uint bit_index = (bit_offset + i) % 8; - uint8_t byte = binaryPointer[byte_index]; - // Create a bit mask to isolate the desired bit: - uint8_t bit_mask = 1 << (7 - bit_index); - // Set the corresponding bit in the return value if the retrieved bit is 1: - value |= (byte & bit_mask) ? (bit << (num_bits - i - 1)) : 0; - } - return value; - } - - /** - * @brief Calculates the minimum number of bits required to represent a given value. - * - * @param value The value to calculate the minimum bits for. - * @return size_t The minimum number of bits required. - */ - size_t minBitsRequired(size_t value) const - { - // Handle special cases - size_t bitsNeeded = 1; - - while (value != 0) - { - bitsNeeded++; - value >>= 1; - } + * @param structure The structure defining the packet. + */ + BasePacketTempl(BasePacketStructure &structure) { + this->packetStructure = new BasePacketStructure(structure); + this->memoryPointer = new uint8_t[structure.getByteSize()]; + } - return bitsNeeded; - } + /** + * @brief Copy constructor for the BasePacketTempl class. + * + * @param other The other BasePacketTempl object to copy. + */ + BasePacketTempl(const BasePacketTempl &other) { + this->packetStructure = new BasePacketStructure( + other.getPacketStructure()); + this->memoryPointer = new uint8_t[other.packetStructure->getByteSize()]; + std::memcpy(this->memoryPointer, other.memoryPointer, + other.packetStructure->getByteSize()); + } - public: - /** - * @brief Constructor for the BasePacketTempl class. - * - * @param structure The structure defining the packet. - */ - BasePacketTempl(BasePacketStructure &structure) - { - this->packetStructure = new BasePacketStructure(structure); - this->memoryPointer = new uint8_t[structure.getByteSize()]; - } + /** + * @brief Destructor for the BasePacketTempl class. + */ + virtual ~BasePacketTempl() = default; - /** - * @brief Copy constructor for the BasePacketTempl class. - * - * @param other The other BasePacketTempl object to copy. - */ - BasePacketTempl(const BasePacketTempl &other) - { - this->packetStructure = new BasePacketStructure(other.getPacketStructure()); - this->memoryPointer = new uint8_t[other.packetStructure->getByteSize()]; - std::memcpy(this->memoryPointer, other.memoryPointer, - other.packetStructure->getByteSize()); - } + /** + * @brief Updates the packet structure. + * @param structure The new packet structure. + */ + void updatePacketStructure(BasePacketStructure &structure) { + size_t newSize = structure.getByteSize(); + size_t oldSize = this->packetStructure->getByteSize(); - /** - * @brief Destructor for the BasePacketTempl class. - */ - virtual ~BasePacketTempl() = default; - - /** - * @brief Updates the packet structure. - * @param structure The new packet structure. - */ - void updatePacketStructure(BasePacketStructure &structure) - { - size_t newSize = structure.getByteSize(); - size_t oldSize = this->packetStructure->getByteSize(); - - uint8_t *buff = new uint8_t[newSize]; - std::memset(buff, 0, newSize); - std::memcpy(buff, memoryPointer, std::min(newSize, oldSize)); - delete this->memoryPointer; - - this->memoryPointer = new uint8_t[newSize]; - std::memcpy(memoryPointer, buff, newSize); - delete[] buff; - this->packetStructure = &structure; - } + uint8_t *buff = new uint8_t[newSize]; + std::memset(buff, 0, newSize); + std::memcpy(buff, memoryPointer, std::min(newSize, oldSize)); + delete this->memoryPointer; - /** - * @brief Reads a value from the memory at a given index. - * @param index The index of the field to read. - * @return std::optional The value read from memory, or std::nullopt if the field does not exist. - */ - std::optional readValueFromMemoryAt(uint index) const - { - auto offset = packetStructure->bitOffsetOf(index); // offset from the beginning of the byte - auto num_bits = packetStructure->bitSizeOf(index); // remaining bits to read - if (offset.has_value() && num_bits.has_value()) - return _readValueFromMemoryAt_(memoryPointer, offset.value(), - num_bits.value()); - else - { - time_t now = time(nullptr); - std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") - << "]\t[Base Packet]\t" - << "Error: No field at " << index - << ", max is " << packetStructure->numberOfFields() - << ", returning nullopt" << std::endl; - return std::nullopt; - } - } + this->memoryPointer = new uint8_t[newSize]; + std::memcpy(memoryPointer, buff, newSize); + delete[] buff; + this->packetStructure = &structure; + } - /** - * @brief Returns a pointer to the memory in which stores the packet. - * - * This function returns a constant pointer to the memory. - * - * @return A constant pointer to the memory. - */ - uint8_t const *getPointerToMemory() const - { - return memoryPointer; - } + /** + * @brief Reads a value from the memory at a given index. + * @param index The index of the field to read. + * @return std::optional The value read from memory, or std::nullopt if the field does not exist. + */ + std::optional readValueFromMemoryAt(uint index) const { + auto offset = packetStructure->bitOffsetOf(index); // offset from the beginning of the byte + auto num_bits = packetStructure->bitSizeOf(index); // remaining bits to read + if (offset.has_value() && num_bits.has_value()) + return _readValueFromMemoryAt_(memoryPointer, offset.value(), + num_bits.value()); + else { + time_t now = time(nullptr); + std::cerr << "[" + << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") + << "]\t[Base Packet]\t" << "Error: No field at " << index + << ", max is " << packetStructure->numberOfFields() + << ", returning nullopt" << std::endl; + return std::nullopt; + } + } - /** - * @brief Copies data from a source memory location to the packet's memory. - * - * @param from Pointer to the source memory location. - * @param size Number of bytes to copy. - * @return int The number of bytes copied. - */ - int copyToMemory(const uint8_t *from, uint size) - { - uint max_writable = this->packetStructure->getByteSize(); - if (size > max_writable) - { - time_t now = time(nullptr); - std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") - << "]\t[Base Packet]\t" - << "Error: you are trying to copy " - << size << " byte where the max size is: " << max_writable - << std::endl; - std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") - << "]\t[Base Packet]\t" - << "\tI copy only until " - << max_writable << " byte" << std::endl; - std::memcpy(memoryPointer, from, max_writable); - return max_writable; - } - else - { - std::memcpy(memoryPointer, from, size); - return size; - } - } + /** + * @brief Returns a pointer to the memory in which stores the packet. + * + * This function returns a constant pointer to the memory. + * + * @return A constant pointer to the memory. + */ + uint8_t const* getPointerToMemory() const { + return memoryPointer; + } - /** - * Copies data from the given memory location to the packet's memory buffer. - * - * @param from Pointer to the source memory location. - * @param size Number of bytes to copy. - * @param offset Offset in the packet's memory buffer to start copying to. - * @return The number of bytes copied. - */ - int copyToMemory(const uint8_t *from, uint size, uint offset) - { - uint max_writable = this->packetStructure->getByteSize(); - if (offset > max_writable) - { - time_t now = time(nullptr); - std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") - << "]\t[Base Packet]\t" - << "Error: you are trying to copy starting from " << offset - << " byte where the max size is: " << max_writable - << std::endl; - return -1; - } - if (size + offset > max_writable) - { - time_t now = time(nullptr); - std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") - << "]\t[Base Packet]\t" - << "Error: you are trying to copy " - << size + offset << " byte where the max size is: " - << max_writable << std::endl; - std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") - << "]\t[Base Packet]\t" - << "\tI copy only until " - << max_writable << " byte" << std::endl; - int to_write = max_writable - offset; - std::memcpy(&memoryPointer[offset], from, to_write); - return to_write; - } - else - { - std::memcpy(&memoryPointer[offset], from, size); - return size; - } - } + /** + * @brief Copies data from a source memory location to the packet's memory. + * + * @param from Pointer to the source memory location. + * @param size Number of bytes to copy. + * @return int The number of bytes copied. + */ + int copyToMemory(const uint8_t *from, uint size) { + uint max_writable = this->packetStructure->getByteSize(); + if (size > max_writable) { + time_t now = time(nullptr); + std::cerr << "[" + << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") + << "]\t[Base Packet]\t" << "Error: you are trying to copy " + << size << " byte where the max size is: " << max_writable + << std::endl; + std::cerr << "[" + << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") + << "]\t[Base Packet]\t" << "\tI copy only until " + << max_writable << " byte" << std::endl; + std::memcpy(memoryPointer, from, max_writable); + return max_writable; + } else { + std::memcpy(memoryPointer, from, size); + return size; + } + } - /** - * @brief Accesses the value at the specified index in the packet. - * - * @param index The index of the value to access. - * @return An optional containing the value at the specified index, if it exists. - */ - std::optional operator[](uint index) const - { - return readValueFromMemoryAt(index); - } + /** + * Copies data from the given memory location to the packet's memory buffer. + * + * @param from Pointer to the source memory location. + * @param size Number of bytes to copy. + * @param offset Offset in the packet's memory buffer to start copying to. + * @return The number of bytes copied. + */ + int copyToMemory(const uint8_t *from, uint size, uint offset) { + uint max_writable = this->packetStructure->getByteSize(); + if (offset > max_writable) { + time_t now = time(nullptr); + std::cerr << "[" + << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") + << "]\t[Base Packet]\t" + << "Error: you are trying to copy starting from " << offset + << " byte where the max size is: " << max_writable + << std::endl; + return -1; + } + if (size + offset > max_writable) { + time_t now = time(nullptr); + std::cerr << "[" + << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") + << "]\t[Base Packet]\t" << "Error: you are trying to copy " + << size + offset << " byte where the max size is: " + << max_writable << std::endl; + std::cerr << "[" + << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") + << "]\t[Base Packet]\t" << "\tI copy only until " + << max_writable << " byte" << std::endl; + int to_write = max_writable - offset; + std::memcpy(&memoryPointer[offset], from, to_write); + return to_write; + } else { + std::memcpy(&memoryPointer[offset], from, size); + return size; + } + } - /** - * @brief Accesses the value of a field in the packet by its field name. - * - * @param fieldName The name of the field to access. - * @return An optional value of the specified field type. If the field does not exist, the optional will be empty. - */ - std::optional operator[](std::string fieldName) const - { - std::transform(fieldName.begin(), fieldName.end(), fieldName.begin(), - [](unsigned char c) - { - return std::tolower(c); - }); - auto index = packetStructure->indexOfField(fieldName); - if (index.has_value()) - return readValueFromMemoryAt(index.value()); - else - return std::nullopt; - } + /** + * @brief Accesses the value at the specified index in the packet. + * + * @param index The index of the value to access. + * @return An optional containing the value at the specified index, if it exists. + */ + std::optional operator[](uint index) const { + return readValueFromMemoryAt(index); + } - /** - * @brief Returns a constant bit iterator pointing to the beginning of the packet data. - * - * @return A constant bit iterator pointing to the beginning of the packet data. - */ - bit_iterator begin() const - { - return bit_iterator(memoryPointer, 0, packetStructure, - &_readValueFromMemoryAt_); - } + /** + * @brief Accesses the value of a field in the packet by its field name. + * + * @param fieldName The name of the field to access. + * @return An optional value of the specified field type. If the field does not exist, the optional will be empty. + */ + std::optional operator[](std::string fieldName) const { + std::transform(fieldName.begin(), fieldName.end(), fieldName.begin(), + [](unsigned char c) { + return std::tolower(c); + }); + auto index = packetStructure->indexOfField(fieldName); + if (index.has_value()) + return readValueFromMemoryAt(index.value()); + else + return std::nullopt; + } - /** - * @brief Returns a bit_iterator pointing to the end of the container. - * - * @return A bit_iterator pointing to the end of the container. - */ - bit_iterator end() const - { - return bit_iterator(memoryPointer, - packetStructure->numberOfFields(), packetStructure, - &_readValueFromMemoryAt_); - } + /** + * @brief Returns a constant bit iterator pointing to the beginning of the packet data. + * + * @return A constant bit iterator pointing to the beginning of the packet data. + */ + bit_iterator begin() const { + return bit_iterator(memoryPointer, 0, packetStructure, + &_readValueFromMemoryAt_); + } - /** - * Writes a value into memory at the specified index. - * - * @param index The index at which to write the value. - * @param value The value to be written. - * @return An optional containing number of fits written, if any. - */ - std::optional writeValueIntoMemoryAtIndex(uint index, ValueType value) - { - auto offset = this->packetStructure->bitOffsetOf(index); - auto numbits = this->packetStructure->bitSizeOf(index); - size_t min_req = minBitsRequired(value); - if (!offset.has_value() || !numbits.has_value()) - return std::nullopt; - if (numbits < min_req) - { - time_t now = time(nullptr); - std::cerr << "[" << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") - << "]\t[Base Packet]\t" - << "Error: you are trying to write " - << value << " which requires at least " << min_req - << " bits in a field of size " << numbits << std::endl; - return std::nullopt; - } + /** + * @brief Returns a bit_iterator pointing to the end of the container. + * + * @return A bit_iterator pointing to the end of the container. + */ + bit_iterator end() const { + return bit_iterator(memoryPointer, + packetStructure->numberOfFields(), packetStructure, + &_readValueFromMemoryAt_); + } - // Calculate the bit offset from the byte offset: - uint bitoffset = offset.value() % 8; - // Calculate the byte offset from the bit offset: - uint byteoffset = offset.value() / 8; - uint numbits_written = 0; - - for (size_t i = 0; i < numbits; i++) - { - // Calculate the byte and bit index of the current bit: - uint byte_index = byteoffset + (bitoffset + i) / 8; - uint bit_index = (bitoffset + i) % 8; - // Create a bit mask to isolate the desired bit: - uint8_t bit_mask = 1 << (7 - bit_index); - // Set the corresponding bit in the binary array if the value is 1: - if ((value >> (numbits.value() - i - 1)) & 1) - { - memoryPointer[byte_index] |= bit_mask; - numbits_written++; - } - else - { - memoryPointer[byte_index] &= ~bit_mask; - } + /** + * Writes a value into memory at the specified index. + * + * @param index The index at which to write the value. + * @param value The value to be written. + * @return An optional containing number of fits written, if any. + */ + std::optional writeValueIntoMemoryAtIndex(uint index, + ValueType value) { + auto offset = this->packetStructure->bitOffsetOf(index); + auto numbits = this->packetStructure->bitSizeOf(index); + size_t min_req = minBitsRequired(value); + if (!offset.has_value() || !numbits.has_value()) + return std::nullopt; + if (numbits < min_req) { + time_t now = time(nullptr); + std::cerr << "[" + << std::put_time(localtime(&now), "%Y-%m-%d %H:%M:%S") + << "]\t[Base Packet]\t" << "Error: you are trying to write " + << value << " which requires at least " << min_req + << " bits in a field of size " << numbits << std::endl; + return std::nullopt; + } + + // Calculate the bit offset from the byte offset: + uint bitoffset = offset.value() % 8; + // Calculate the byte offset from the bit offset: + uint byteoffset = offset.value() / 8; + uint numbits_written = 0; + + for (size_t i = 0; i < numbits; i++) { + // Calculate the byte and bit index of the current bit: + uint byte_index = byteoffset + (bitoffset + i) / 8; + uint bit_index = (bitoffset + i) % 8; + // Create a bit mask to isolate the desired bit: + uint8_t bit_mask = 1 << (7 - bit_index); + // Set the corresponding bit in the binary array if the value is 1: + if ((value >> (numbits.value() - i - 1)) & 1) { + memoryPointer[byte_index] |= bit_mask; + numbits_written++; + } else { + memoryPointer[byte_index] &= ~bit_mask; } - return numbits_written; - } - - /** - * @brief Get the byte size of the packet structure. - * - * @return The byte size of the packet structure. - */ - uint getPacketStructureByteSize() const - { - return packetStructure->getByteSize(); - } - /** - * @brief Returns the packet structure of the BasePacket. - * - * @return A reference to the packet structure. - */ - BasePacketStructure &getPacketStructure() const - { - return *(this->packetStructure); } + return numbits_written; + } - /** - * @brief Checks if the packet has a recognized header. - * @note This is a pure virtual function and must be implemented by derived classes. - * @return true if the packet has a recognized header, false otherwise. - */ - virtual bool hasRecognizedHeader() const = 0; - /** - * @brief Checks if the passed data has a recognized header. - * @param buff The data to check. - * @note This is a pure virtual function and must be implemented by derived classes. - * @return true if buff has a recognized header, false otherwise. - */ - virtual bool isRecognizedHeader(std::vector buff) const = 0; - - /** - * @brief Get the size of the header of the packet. - * @note This is a pure virtual function and must be implemented by derived classes. - * @return The size of the header as an unsigned integer. - */ - virtual uint getHeaderSize() const = 0; - /** - * @brief Get the size of the payload of the packet. - * @note This is a pure virtual function and must be implemented by derived classes. - * @return The size of the payload as an unsigned integer. - */ - virtual uint getPayloadSize() const = 0; - /** - * @brief Get the size of the tail of the packet. - * @note This is a pure virtual function and must be implemented by derived classes. - * @return The size of the tail as an unsigned integer. - */ - virtual uint getTailSize() const = 0; - }; - - using valueType = size_t; - /** - * @brief Represents a concrete class derived from BasePacketTempl with a specified value type. + /** + * @brief Get the byte size of the packet structure. * - * The `BasePacket` class is a concrete class derived from `BasePacketTempl` with a value type of `size_t`. + * @return The byte size of the packet structure. */ - class BasePacket : public BasePacketTempl - { + uint getPacketStructureByteSize() const { + return packetStructure->getByteSize(); + } + /** + * @brief Returns the packet structure of the BasePacket. + * + * @return A reference to the packet structure. + */ + BasePacketStructure& getPacketStructure() const { + return *(this->packetStructure); + } - protected: - public: - BasePacket(BasePacketStructure &structure) : BasePacketTempl(structure) - { - } - virtual ~BasePacket() = default; - }; + /** + * @brief Checks if the packet has a recognized header. + * @note This is a pure virtual function and must be implemented by derived classes. + * @return true if the packet has a recognized header, false otherwise. + */ + virtual bool hasRecognizedHeader() const = 0; + /** + * @brief Checks if the passed data has a recognized header. + * @param buff The data to check. + * @note This is a pure virtual function and must be implemented by derived classes. + * @return true if buff has a recognized header, false otherwise. + */ + virtual bool isRecognizedHeader(std::vector buff) const = 0; + + /** + * @brief Get the size of the header of the packet. + * @note This is a pure virtual function and must be implemented by derived classes. + * @return The size of the header as an unsigned integer. + */ + virtual uint getHeaderSize() const = 0; + /** + * @brief Get the size of the payload of the packet. + * @note This is a pure virtual function and must be implemented by derived classes. + * @return The size of the payload as an unsigned integer. + */ + virtual uint getPayloadSize() const = 0; + /** + * @brief Get the size of the tail of the packet. + * @note This is a pure virtual function and must be implemented by derived classes. + * @return The size of the tail as an unsigned integer. + */ + virtual uint getTailSize() const = 0; +}; + +using valueType = size_t; +/** + * @brief Represents a concrete class derived from BasePacketTempl with a specified value type. + * + * The `BasePacket` class is a concrete class derived from `BasePacketTempl` with a value type of `size_t`. + */ +class BasePacket: public BasePacketTempl { + +protected: +public: + BasePacket(BasePacketStructure &structure) : + BasePacketTempl(structure) { + } + virtual ~BasePacket() = default; +}; } diff --git a/include/Base_Provider.h b/include/Base_Provider.h index b034a87..6816491 100644 --- a/include/Base_Provider.h +++ b/include/Base_Provider.h @@ -9,7 +9,7 @@ namespace inaf::oasbo::Providers { * This class defines the common interface for providers that write packets to a destination. * Derived classes must implement the pure virtual functions defined in this class. */ -class BaseProvider{ +class BaseProvider { protected: std::string dest; /**< The destination where packets are written to. */ @@ -71,4 +71,4 @@ public: */ virtual ~BaseProvider() = default; }; -} \ No newline at end of file +} diff --git a/include/Base_Receiver.h b/include/Base_Receiver.h index 924c5b8..4b9a8b6 100755 --- a/include/Base_Receiver.h +++ b/include/Base_Receiver.h @@ -1,10 +1,9 @@ - #pragma once #include #include -namespace inaf::oasbo::Receivers{ +namespace inaf::oasbo::Receivers { /** * @brief The BaseReceiver class is an abstract base class for receivers in the DAQ system. @@ -15,7 +14,7 @@ namespace inaf::oasbo::Receivers{ * * Derived classes must implement these functions according to their specific requirements. */ -class BaseReceiver{ +class BaseReceiver { protected: std::string host; public: @@ -61,7 +60,7 @@ public: * @param packet The received packet will be stored in this parameter. * @return An integer indicating the success or failure of the operation. */ - virtual int receiveFromClient(PacketLib::BasePacket &) = 0; + virtual int receiveFromClient(PacketLib::BasePacket&) = 0; /** * @brief Virtual destructor. -- GitLab From e1983e5655deebb48c56018c8414f85f204137c8 Mon Sep 17 00:00:00 2001 From: valerio pastore Date: Thu, 11 Jan 2024 20:47:27 +0100 Subject: [PATCH 3/4] update base arch --- include/Base_Archiver.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/Base_Archiver.h b/include/Base_Archiver.h index 4b86616..8e7a2ca 100755 --- a/include/Base_Archiver.h +++ b/include/Base_Archiver.h @@ -24,7 +24,7 @@ public: * @param packet The packet to write. * @return An integer indicating the success or failure of the write operation. */ - virtual int write(PacketLib::BasePacket&) = 0; + virtual int write(Packets::BasePacket&) = 0; /** * @brief Write a packet to the archiver with a specified destination. @@ -35,7 +35,7 @@ public: * @param destination The destination where the packet should be written. * @return An integer indicating the success or failure of the write operation. */ - virtual int write(PacketLib::BasePacket&, std::string destination) = 0; + virtual int write(Packets::BasePacket&, std::string destination) = 0; /** * @brief Open the archiver. -- GitLab From a00f9a27afbf5f75dab7db2368b9b9b6fcb395e1 Mon Sep 17 00:00:00 2001 From: valerio pastore Date: Thu, 11 Jan 2024 20:51:59 +0100 Subject: [PATCH 4/4] . --- include/Base_DAQ.h | 6 +++--- include/Base_Monitor.h | 2 +- include/Base_Provider.h | 4 ++-- include/Base_Receiver.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/Base_DAQ.h b/include/Base_DAQ.h index 6008d6a..6c44560 100755 --- a/include/Base_DAQ.h +++ b/include/Base_DAQ.h @@ -37,7 +37,7 @@ protected: Archivers::BaseArchiver *archiver = nullptr; /**< Pointer to the archiver object. */ Providers::BaseProvider *provider = nullptr; /**< Pointer to the provider object. */ PacketMonitors::BasePacketMonitor *monitor = nullptr; /**< Pointer to the packet monitor object. */ - PacketLib::BasePacket *packet = nullptr; /**< Pointer to the packet object. */ + Packets::BasePacket *packet = nullptr; /**< Pointer to the packet object. */ std::vector observers; /**< Vector of observers. */ std::vector configurations; /**< Vector of configurations. */ @@ -83,7 +83,7 @@ public: * * @param packet The packet object to set. */ - void setPacket(PacketLib::BasePacket &packet) { + void setPacket(Packets::BasePacket &packet) { this->packet = &packet; } @@ -177,7 +177,7 @@ public: * * @return Pointer to the packet object. */ - PacketLib::BasePacket* getPacketPrt() { + Packets::BasePacket* getPacketPrt() { return this->packet; } diff --git a/include/Base_Monitor.h b/include/Base_Monitor.h index 26eb197..6fb91a4 100644 --- a/include/Base_Monitor.h +++ b/include/Base_Monitor.h @@ -24,7 +24,7 @@ public: * * @param packet The packet to be monitored. */ - virtual void monit(PacketLib::BasePacket &packet) = 0; + virtual void monit(Packets::BasePacket &packet) = 0; /** * @brief Prints the statistics related to the monitored packets. diff --git a/include/Base_Provider.h b/include/Base_Provider.h index 6816491..5278696 100644 --- a/include/Base_Provider.h +++ b/include/Base_Provider.h @@ -20,7 +20,7 @@ public: * @param packet The packet to be written. * @return int Returns an integer indicating the success or failure of the write operation. */ - virtual int write(PacketLib::BasePacket &packet) = 0; + virtual int write(Packets::BasePacket &packet) = 0; /** * @brief Writes a packet to a specified destination. @@ -29,7 +29,7 @@ public: * @param dest The destination where the packet should be written to. * @return int Returns an integer indicating the success or failure of the write operation. */ - virtual int write(PacketLib::BasePacket &packet, std::string dest) = 0; + virtual int write(Packets::BasePacket &packet, std::string dest) = 0; /** * @brief Opens the provider. diff --git a/include/Base_Receiver.h b/include/Base_Receiver.h index 4b9a8b6..0f161ba 100755 --- a/include/Base_Receiver.h +++ b/include/Base_Receiver.h @@ -60,7 +60,7 @@ public: * @param packet The received packet will be stored in this parameter. * @return An integer indicating the success or failure of the operation. */ - virtual int receiveFromClient(PacketLib::BasePacket&) = 0; + virtual int receiveFromClient(Packets::BasePacket&) = 0; /** * @brief Virtual destructor. -- GitLab