diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a137b6e..0a1885a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,32 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - `DeviceHandlerBase`: New signature of `handleDeviceTm` which expects a `const SerializeIF&` and additional helper variant which expects `const uint8_t*` PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/671 +- Improvements for `AcceptsTelemetryIF` and `AcceptsTelecommandsIF`: + - Make functions `const` where it makes sense + - Add `const char* getName const` abstract function + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/684 +- Move some generic `StorageManagerIF` implementations from `LocalPool` to + interface itself so it can be re-used more easily. Also add new + abstract function `bool hasDataAtId(store_address_t storeId) const`. + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/685 + +## CFDP + +- Refactoring of CFDP stack which was done during implementation of the CFDP source and destination + handlers. + - New filesystem module, changes for filesystem abstraction `HasFileSystemIF` to better + fit requirements of CFDP + - New `HostFilesystem` implementation of the `HasFileSystemIF` + - New `cfdp::UserBase` class which is the abstraction for the CFDP user in an OBSW context. + - mib module for the CFDP stack + - PDU classes renamed from `...Serializer`/`...Deserializer` to `...Creator`/`...Reader` + respetively + - Renamed `TcDistributor` to `TcDistributorBase` to prevent confusion + - Refactored `TcDisitributorBase` to be more flexible and usable for CFDP distribution + - Renamed `CCSDSDistributor` to `CcsdsDistributor` and add feature which allows it + to remove the CCSDS header when routing a packet. This allows CCSDS agnostic receiver + implementation without an extra component + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/682 # [v5.0.0] 25.07.2022 diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ed024d0..2a0d140e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,7 +104,8 @@ if(FSFW_GENERATE_SECTIONS) option(FSFW_REMOVE_UNUSED_CODE "Remove unused code" ON) endif() -option(FSFW_BUILD_TESTS "Build unittest binary in addition to static library" +option(FSFW_BUILD_TESTS + "Build unittest binary in addition to static library. Requires Catch2" OFF) option(FSFW_CICD_BUILD "Build for CI/CD. This can disable problematic test" OFF) option(FSFW_BUILD_DOCS "Build documentation with Sphinx and Doxygen" OFF) @@ -115,7 +116,6 @@ endif() option(FSFW_WARNING_SHADOW_LOCAL_GCC "Enable -Wshadow=local warning in GCC" ON) # Options to exclude parts of the FSFW from compilation. option(FSFW_ADD_INTERNAL_TESTS "Add internal unit tests" ON) -option(FSFW_ADD_UNITTESTS "Add regular unittests. Requires Catch2" OFF) option(FSFW_ADD_HAL "Add Hardware Abstraction Layer" ON) if(UNIX) diff --git a/docs/api.rst b/docs/api.rst index d2ee6c69..dc73c2c7 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -4,6 +4,7 @@ API .. toctree:: :maxdepth: 4 + api/cfdp api/objectmanager api/task api/ipc diff --git a/docs/api/cfdp.rst b/docs/api/cfdp.rst new file mode 100644 index 00000000..335a2025 --- /dev/null +++ b/docs/api/cfdp.rst @@ -0,0 +1,8 @@ +CFDP API +================= + +``UserBase`` +----------------- + +.. doxygenclass:: cfdp::UserBase + :members: \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index 62b17192..700b0ee9 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -17,12 +17,12 @@ # -- Project information ----------------------------------------------------- -project = 'Flight Software Framework' -copyright = '2021, Institute of Space Systems (IRS)' -author = 'Institute of Space Systems (IRS)' +project = "Flight Software Framework" +copyright = "2021, Institute of Space Systems (IRS)" +author = "Institute of Space Systems (IRS)" # The full version, including alpha/beta/rc tags -release = '2.0.1' +release = "5.0.0" # -- General configuration --------------------------------------------------- @@ -30,17 +30,17 @@ release = '2.0.1' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = [ "breathe" ] +extensions = ["breathe"] breathe_default_project = "fsfw" # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # -- Options for HTML output ------------------------------------------------- @@ -48,9 +48,9 @@ exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'alabaster' +html_theme = "alabaster" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = [] \ No newline at end of file +html_static_path = [] diff --git a/docs/highlevel.rst b/docs/highlevel.rst index 3c9baae2..c77ff4c2 100644 --- a/docs/highlevel.rst +++ b/docs/highlevel.rst @@ -7,12 +7,14 @@ Structure ---------- The general structure is driven by the usage of interfaces provided by objects. -The FSFW uses C++11 as baseline. The intention behind this is that this C++ Standard should be -widely available, even with older compilers. -The FSFW uses dynamic allocation during the initialization but provides static containers during runtime. -This simplifies the instantiation of objects and allows the usage of some standard containers. -Dynamic Allocation after initialization is discouraged and different solutions are provided in the -FSFW to achieve that. The fsfw uses run-time type information but exceptions are not allowed. +The FSFW uses C++17 as baseline. +It also uses dynamic allocation during the initialization but provides +static containers during runtime. +This simplifies the instantiation of objects and allows the usage of some +standard containers. +Dynamic Allocation after initialization is discouraged and different solutions +are provided in the FSFW to achieve that. The fsfw uses run-time type +information but will not throw exceptions. Failure Handling ----------------- diff --git a/misc/defaultcfg/fsfwconfig/objects/FsfwFactory.cpp b/misc/defaultcfg/fsfwconfig/objects/FsfwFactory.cpp index 4d6e91f1..85a733b4 100644 --- a/misc/defaultcfg/fsfwconfig/objects/FsfwFactory.cpp +++ b/misc/defaultcfg/fsfwconfig/objects/FsfwFactory.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -41,13 +40,9 @@ void Factory::setStaticFrameworkObjectIds() { CommandingServiceBase::defaultPacketSource = objects::NO_OBJECT; CommandingServiceBase::defaultPacketDestination = objects::NO_OBJECT; - VerificationReporter::messageReceiver = objects::PUS_SERVICE_1_VERIFICATION; - DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT; DeviceHandlerBase::rawDataReceiverId = objects::PUS_SERVICE_2_DEVICE_ACCESS; DeviceHandlerFailureIsolation::powerConfirmationId = objects::NO_OBJECT; - - TmPacketBase::timeStamperId = objects::NO_OBJECT; } diff --git a/scripts/auto-formatter.sh b/scripts/auto-formatter.sh index 723add4f..f7507c55 100755 --- a/scripts/auto-formatter.sh +++ b/scripts/auto-formatter.sh @@ -12,7 +12,8 @@ cmake_fmt="cmake-format" file_selectors="-iname CMakeLists.txt" if command -v ${cmake_fmt} &> /dev/null; then ${cmake_fmt} -i CMakeLists.txt - find ./src ${file_selectors} | xargs ${cmake_fmt} -i + find ./src ${file_selectors} | xargs ${cmake_fmt} -i + find ./unittests ${file_selectors} | xargs ${cmake_fmt} -i else echo "No ${cmake_fmt} tool found, not formatting CMake files" fi diff --git a/scripts/helper.py b/scripts/helper.py index 0ced7186..484e5227 100755 --- a/scripts/helper.py +++ b/scripts/helper.py @@ -51,7 +51,7 @@ def main(): parser.add_argument( "-g", "--generators", - default = "Ninja", + default="Ninja", action="store", help="CMake generators", ) @@ -165,10 +165,18 @@ def create_tests_build_cfg(args): os.mkdir(UNITTEST_FOLDER_NAME) os.chdir(UNITTEST_FOLDER_NAME) if args.windows: - cmake_cmd = 'cmake -G "' + args.generators + '" -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON \ + cmake_cmd = ( + 'cmake -G "' + + args.generators + + '" -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON \ -DGCOVR_PATH="py -m gcovr" ..' + ) else: - cmake_cmd = 'cmake -G "' + args.generators + '" -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON ..' + cmake_cmd = ( + 'cmake -G "' + + args.generators + + '" -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON ..' + ) cmd_runner(cmake_cmd) os.chdir("..") diff --git a/src/fsfw/CMakeLists.txt b/src/fsfw/CMakeLists.txt index 1daad714..e645d34f 100644 --- a/src/fsfw/CMakeLists.txt +++ b/src/fsfw/CMakeLists.txt @@ -31,6 +31,7 @@ add_subdirectory(thermal) add_subdirectory(timemanager) add_subdirectory(tmtcpacket) add_subdirectory(tmtcservices) +add_subdirectory(filesystem) # Optional diff --git a/src/fsfw/cfdp.h b/src/fsfw/cfdp.h new file mode 100644 index 00000000..f6c01ad0 --- /dev/null +++ b/src/fsfw/cfdp.h @@ -0,0 +1,13 @@ +#ifndef FSFW_CFDP_H +#define FSFW_CFDP_H + +#include "cfdp/definitions.h" +#include "cfdp/handler/CfdpHandler.h" +#include "cfdp/handler/DestHandler.h" +#include "cfdp/handler/FaultHandlerBase.h" +#include "cfdp/helpers.h" +#include "cfdp/tlv/Lv.h" +#include "cfdp/tlv/StringLv.h" +#include "cfdp/tlv/Tlv.h" + +#endif // FSFW_CFDP_H diff --git a/src/fsfw/cfdp/CMakeLists.txt b/src/fsfw/cfdp/CMakeLists.txt index f2affbb4..f4d60201 100644 --- a/src/fsfw/cfdp/CMakeLists.txt +++ b/src/fsfw/cfdp/CMakeLists.txt @@ -1,4 +1,6 @@ -target_sources(${LIB_FSFW_NAME} PRIVATE CfdpHandler.cpp CfdpMessage.cpp) +target_sources(${LIB_FSFW_NAME} PRIVATE CfdpMessage.cpp CfdpDistributor.cpp + VarLenFields.cpp helpers.cpp) add_subdirectory(pdu) add_subdirectory(tlv) +add_subdirectory(handler) diff --git a/src/fsfw/cfdp/CfdpDistributor.cpp b/src/fsfw/cfdp/CfdpDistributor.cpp new file mode 100644 index 00000000..b233e67e --- /dev/null +++ b/src/fsfw/cfdp/CfdpDistributor.cpp @@ -0,0 +1,55 @@ +#include "CfdpDistributor.h" + +#include "fsfw/tcdistribution/definitions.h" + +CfdpDistributor::CfdpDistributor(CfdpDistribCfg cfg) + : TcDistributorBase(cfg.objectId, cfg.tcQueue), cfg(cfg) {} + +ReturnValue_t CfdpDistributor::registerTcDestination(const cfdp::EntityId& address, + AcceptsTelecommandsIF& tcDest) { + for (const auto& dest : tcDestinations) { + if (dest.id == address) { + return returnvalue::FAILED; + } + } + tcDestinations.emplace_back(address, tcDest.getName(), tcDest.getRequestQueue()); + return returnvalue::OK; +} + +ReturnValue_t CfdpDistributor::selectDestination(MessageQueueId_t& destId) { + auto accessorPair = cfg.tcStore.getData(currentMessage.getStorageId()); + if (accessorPair.first != returnvalue::OK) { + return accessorPair.first; + } + ReturnValue_t result = + pduReader.setReadOnlyData(accessorPair.second.data(), accessorPair.second.size()); + if (result != returnvalue::OK) { + return result; + } + result = pduReader.parseData(); + if (result != returnvalue::OK) { + return result; + } + cfdp::EntityId foundId; + pduReader.getDestId(foundId); + bool destFound = false; + for (const auto& dest : tcDestinations) { + if (dest.id == foundId) { + destId = dest.queueId; + destFound = true; + } + } + if (not destFound) { + // TODO: Warning and event? + return tmtcdistrib::NO_DESTINATION_FOUND; + } + // Packet was forwarded successfully, so do not delete it. + accessorPair.second.release(); + return returnvalue::OK; +} + +const char* CfdpDistributor::getName() const { return "CFDP Distributor"; } + +uint32_t CfdpDistributor::getIdentifier() const { return 0; } + +MessageQueueId_t CfdpDistributor::getRequestQueue() const { return tcQueue->getId(); } diff --git a/src/fsfw/cfdp/CfdpDistributor.h b/src/fsfw/cfdp/CfdpDistributor.h new file mode 100644 index 00000000..13d000eb --- /dev/null +++ b/src/fsfw/cfdp/CfdpDistributor.h @@ -0,0 +1,76 @@ +#ifndef FSFW_TCDISTRIBUTION_CFDPDISTRIBUTOR_H_ +#define FSFW_TCDISTRIBUTION_CFDPDISTRIBUTOR_H_ + +#include +#include + +#include "fsfw/cfdp/pdu/PduHeaderReader.h" +#include "fsfw/returnvalues/returnvalue.h" +#include "fsfw/tcdistribution/CfdpPacketChecker.h" +#include "fsfw/tcdistribution/TcDistributorBase.h" +#include "fsfw/tmtcpacket/cfdp/CfdpPacketStored.h" +#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h" +#include "fsfw/tmtcservices/VerificationReporter.h" + +struct CfdpDistribCfg { + CfdpDistribCfg(object_id_t objectId, StorageManagerIF& tcStore, MessageQueueIF* tcQueue) + : objectId(objectId), tcStore(tcStore), tcQueue(tcQueue) {} + + object_id_t objectId; + StorageManagerIF& tcStore; + MessageQueueIF* tcQueue; +}; + +/** + * This will be the primary component to perform PDU forwading procedures. This includes forwarding + * CFDP TC packets to registered source or destination handlers, and forwarding all telemetry + * generated by them to registered TM sinks. + * @ingroup tc_distribution + */ +class CfdpDistributor : public TcDistributorBase, public AcceptsTelecommandsIF { + public: + /** + * The ctor passes @c set_apid to the checker class and calls the + * TcDistribution ctor with a certain object id. + * @param setApid The APID of this receiving Application. + * @param setObjectId Object ID of the distributor itself + * @param setPacketSource Object ID of the source of TC packets. + * Must implement CcsdsDistributorIF. + */ + explicit CfdpDistributor(CfdpDistribCfg cfg); + + [[nodiscard]] const char* getName() const override; + [[nodiscard]] uint32_t getIdentifier() const override; + [[nodiscard]] MessageQueueId_t getRequestQueue() const override; + + /** + * Register a new CFDP entity which can receive PDUs. + * @param address + * @param tcDest + * @return + * - @c RETURN_FAILED: Entry already exists for the given address + */ + ReturnValue_t registerTcDestination(const cfdp::EntityId& address, AcceptsTelecommandsIF& tcDest); + + protected: + struct EntityInfo { + EntityInfo(cfdp::EntityId id, const char* name, MessageQueueId_t queueId) + : id(std::move(id)), name(name), queueId(queueId) {} + cfdp::EntityId id; + const char* name; + MessageQueueId_t queueId; + }; + PduHeaderReader pduReader; + ReturnValue_t lastTcError = returnvalue::OK; + ReturnValue_t lastTmError = returnvalue::OK; + // I don't think a regular OBSW will have more than 1 or 2 of these destinations, so I think + // it is okay to accept the overhead here + std::vector tcDestinations; + CfdpDistribCfg cfg; + + ReturnValue_t selectDestination(MessageQueueId_t& destId) override; + + private: +}; + +#endif /* FSFW_TCDISTRIBUTION_CFDPDISTRIBUTOR_H_ */ diff --git a/src/fsfw/cfdp/CfdpHandler.cpp b/src/fsfw/cfdp/CfdpHandler.cpp deleted file mode 100644 index 707328c5..00000000 --- a/src/fsfw/cfdp/CfdpHandler.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "fsfw/cfdp/CfdpHandler.h" - -#include "fsfw/cfdp/CfdpMessage.h" -#include "fsfw/ipc/CommandMessage.h" -#include "fsfw/ipc/QueueFactory.h" -#include "fsfw/storagemanager/storeAddress.h" -#include "fsfw/tmtcservices/AcceptsTelemetryIF.h" - -object_id_t CfdpHandler::packetSource = 0; -object_id_t CfdpHandler::packetDestination = 0; - -CfdpHandler::CfdpHandler(object_id_t setObjectId, CFDPDistributor* dist) - : SystemObject(setObjectId) { - auto mqArgs = MqArgs(setObjectId, static_cast(this)); - requestQueue = QueueFactory::instance()->createMessageQueue( - CFDP_HANDLER_MAX_RECEPTION, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs); - distributor = dist; -} - -CfdpHandler::~CfdpHandler() = default; - -ReturnValue_t CfdpHandler::initialize() { - ReturnValue_t result = SystemObject::initialize(); - if (result != returnvalue::OK) { - return result; - } - this->distributor->registerHandler(this); - return returnvalue::OK; -} - -ReturnValue_t CfdpHandler::handleRequest(store_address_t storeId) { -#if FSFW_VERBOSE_LEVEL >= 1 -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "CFDPHandler::handleRequest" << std::endl; -#else - sif::printDebug("CFDPHandler::handleRequest\n"); -#endif /* !FSFW_CPP_OSTREAM_ENABLED == 1 */ -#endif - - // TODO read out packet from store using storeId - - return returnvalue::OK; -} - -ReturnValue_t CfdpHandler::performOperation(uint8_t opCode) { - ReturnValue_t status = returnvalue::OK; - CommandMessage currentMessage; - for (status = this->requestQueue->receiveMessage(¤tMessage); status == returnvalue::OK; - status = this->requestQueue->receiveMessage(¤tMessage)) { - store_address_t storeId = CfdpMessage::getStoreId(¤tMessage); - this->handleRequest(storeId); - } - return returnvalue::OK; -} - -uint16_t CfdpHandler::getIdentifier() { return 0; } - -MessageQueueId_t CfdpHandler::getRequestQueue() { return this->requestQueue->getId(); } diff --git a/src/fsfw/cfdp/CfdpHandler.h b/src/fsfw/cfdp/CfdpHandler.h deleted file mode 100644 index 94bb529e..00000000 --- a/src/fsfw/cfdp/CfdpHandler.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef FSFW_CFDP_CFDPHANDLER_H_ -#define FSFW_CFDP_CFDPHANDLER_H_ - -#include "fsfw/ipc/MessageQueueIF.h" -#include "fsfw/objectmanager/SystemObject.h" -#include "fsfw/returnvalues/returnvalue.h" -#include "fsfw/tasks/ExecutableObjectIF.h" -#include "fsfw/tcdistribution/CFDPDistributor.h" -#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h" - -namespace Factory { -void setStaticFrameworkObjectIds(); -} - -class CfdpHandler : public ExecutableObjectIF, public AcceptsTelecommandsIF, public SystemObject { - friend void(Factory::setStaticFrameworkObjectIds)(); - - public: - CfdpHandler(object_id_t setObjectId, CFDPDistributor* distributor); - /** - * The destructor is empty. - */ - virtual ~CfdpHandler(); - - virtual ReturnValue_t handleRequest(store_address_t storeId); - - virtual ReturnValue_t initialize() override; - virtual uint16_t getIdentifier() override; - MessageQueueId_t getRequestQueue() override; - ReturnValue_t performOperation(uint8_t opCode) override; - - protected: - /** - * This is a complete instance of the telecommand reception queue - * of the class. It is initialized on construction of the class. - */ - MessageQueueIF* requestQueue = nullptr; - - CFDPDistributor* distributor = nullptr; - - /** - * The current CFDP packet to be processed. - * It is deleted after handleRequest was executed. - */ - CfdpPacketStored currentPacket; - - static object_id_t packetSource; - - static object_id_t packetDestination; - - private: - /** - * This constant sets the maximum number of packets accepted per call. - * Remember that one packet must be completely handled in one - * #handleRequest call. - */ - static const uint8_t CFDP_HANDLER_MAX_RECEPTION = 100; -}; - -#endif /* FSFW_CFDP_CFDPHANDLER_H_ */ diff --git a/src/fsfw/cfdp/FileSize.h b/src/fsfw/cfdp/FileSize.h index 756b0e0a..b0b48452 100644 --- a/src/fsfw/cfdp/FileSize.h +++ b/src/fsfw/cfdp/FileSize.h @@ -1,5 +1,7 @@ -#ifndef FSFW_SRC_FSFW_CFDP_FILESIZE_H_ -#define FSFW_SRC_FSFW_CFDP_FILESIZE_H_ +#ifndef FSFW_CFDP_FILESIZE_H_ +#define FSFW_CFDP_FILESIZE_H_ + +#include #include "fsfw/serialize/SerializeAdapter.h" #include "fsfw/serialize/SerializeIF.h" @@ -8,9 +10,11 @@ namespace cfdp { struct FileSize : public SerializeIF { public: - FileSize() : largeFile(false){}; + FileSize() = default; - FileSize(uint64_t fileSize, bool isLarge = false) { setFileSize(fileSize, isLarge); }; + explicit FileSize(uint64_t fileSize, bool isLarge = false) { setFileSize(fileSize, isLarge); }; + + [[nodiscard]] uint64_t value() const { return fileSize; } ReturnValue_t serialize(bool isLarge, uint8_t **buffer, size_t *size, size_t maxSize, Endianness streamEndianness) { @@ -27,7 +31,7 @@ struct FileSize : public SerializeIF { return SerializeAdapter::serialize(&fileSize, buffer, size, maxSize, streamEndianness); } - size_t getSerializedSize() const override { + [[nodiscard]] size_t getSerializedSize() const override { if (largeFile) { return 8; } else { @@ -50,20 +54,22 @@ struct FileSize : public SerializeIF { } } - ReturnValue_t setFileSize(uint64_t fileSize, bool largeFile) { + ReturnValue_t setFileSize(uint64_t fileSize_, std::optional largeFile_) { + if (largeFile_) { + largeFile = largeFile_.value(); + } if (not largeFile and fileSize > UINT32_MAX) { // TODO: emit warning here return returnvalue::FAILED; } - this->fileSize = fileSize; - this->largeFile = largeFile; + this->fileSize = fileSize_; return returnvalue::OK; } - bool isLargeFile() const { return largeFile; } - uint64_t getSize(bool *largeFile = nullptr) const { - if (largeFile != nullptr) { - *largeFile = this->largeFile; + [[nodiscard]] bool isLargeFile() const { return largeFile; } + uint64_t getSize(bool *largeFile_ = nullptr) const { + if (largeFile_ != nullptr) { + *largeFile_ = this->largeFile; } return fileSize; } @@ -75,4 +81,4 @@ struct FileSize : public SerializeIF { } // namespace cfdp -#endif /* FSFW_SRC_FSFW_CFDP_FILESIZE_H_ */ +#endif /* FSFW_CFDP_FILESIZE_H_ */ diff --git a/src/fsfw/cfdp/pdu/VarLenField.cpp b/src/fsfw/cfdp/VarLenFields.cpp similarity index 79% rename from src/fsfw/cfdp/pdu/VarLenField.cpp rename to src/fsfw/cfdp/VarLenFields.cpp index f0059270..b9e0b3a8 100644 --- a/src/fsfw/cfdp/pdu/VarLenField.cpp +++ b/src/fsfw/cfdp/VarLenFields.cpp @@ -1,6 +1,5 @@ -#include "VarLenField.h" +#include "VarLenFields.h" -#include "fsfw/FSFW.h" #include "fsfw/serialize/SerializeAdapter.h" #include "fsfw/serviceinterface.h" @@ -21,27 +20,27 @@ cfdp::VarLenField::VarLenField() : width(cfdp::WidthInBytes::ONE_BYTE) { value.o cfdp::WidthInBytes cfdp::VarLenField::getWidth() const { return width; } -ReturnValue_t cfdp::VarLenField::setValue(cfdp::WidthInBytes widthInBytes, size_t value) { +ReturnValue_t cfdp::VarLenField::setValue(cfdp::WidthInBytes widthInBytes, size_t value_) { switch (widthInBytes) { case (cfdp::WidthInBytes::ONE_BYTE): { - if (value > UINT8_MAX) { + if (value_ > UINT8_MAX) { return returnvalue::FAILED; } - this->value.oneByte = value; + this->value.oneByte = value_; break; } case (cfdp::WidthInBytes::TWO_BYTES): { - if (value > UINT16_MAX) { + if (value_ > UINT16_MAX) { return returnvalue::FAILED; } - this->value.twoBytes = value; + this->value.twoBytes = value_; break; } case (cfdp::WidthInBytes::FOUR_BYTES): { - if (value > UINT32_MAX) { + if (value_ > UINT32_MAX) { return returnvalue::FAILED; } - this->value.fourBytes = value; + this->value.fourBytes = value_; break; } default: { @@ -93,9 +92,9 @@ ReturnValue_t cfdp::VarLenField::serialize(uint8_t **buffer, size_t *size, size_ size_t cfdp::VarLenField::getSerializedSize() const { return width; } -ReturnValue_t cfdp::VarLenField::deSerialize(cfdp::WidthInBytes width, const uint8_t **buffer, +ReturnValue_t cfdp::VarLenField::deSerialize(cfdp::WidthInBytes width_, const uint8_t **buffer, size_t *size, Endianness streamEndianness) { - this->width = width; + this->width = width_; return deSerialize(buffer, size, streamEndianness); } @@ -118,3 +117,21 @@ ReturnValue_t cfdp::VarLenField::deSerialize(const uint8_t **buffer, size_t *siz } } } + +bool cfdp::VarLenField::operator<(const cfdp::VarLenField &other) const { + if (getWidth() < other.getWidth()) { + return true; + } else if (getWidth() == other.getWidth()) { + return getValue() < other.getValue(); + } else { + return false; + } +} + +bool cfdp::VarLenField::operator==(const cfdp::VarLenField &other) const { + return getWidth() == other.getWidth() and getValue() == other.getValue(); +} + +bool cfdp::VarLenField::operator!=(const cfdp::VarLenField &other) const { + return not(*this == other); +} diff --git a/src/fsfw/cfdp/VarLenFields.h b/src/fsfw/cfdp/VarLenFields.h new file mode 100644 index 00000000..37602c75 --- /dev/null +++ b/src/fsfw/cfdp/VarLenFields.h @@ -0,0 +1,107 @@ +#ifndef FSFW_CFDP_PDU_VARLENFIELD_H_ +#define FSFW_CFDP_PDU_VARLENFIELD_H_ + +#include +#include +#include + +#include "fsfw/cfdp/definitions.h" +#include "fsfw/serialize/SerializeIF.h" +#include "fsfw/serviceinterface.h" +#include "fsfw/util/UnsignedByteField.h" + +namespace cfdp { + +class VarLenField : public SerializeIF { + public: + union LengthFieldLen { + uint8_t oneByte; + uint16_t twoBytes; + uint32_t fourBytes; + uint64_t eightBytes; + }; + + VarLenField(); + template + explicit VarLenField(UnsignedByteField byteField); + + VarLenField(cfdp::WidthInBytes width, size_t value); + + bool operator==(const VarLenField &other) const; + bool operator!=(const VarLenField &other) const; + bool operator<(const VarLenField &other) const; + + ReturnValue_t setValue(cfdp::WidthInBytes, size_t value); + + ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const override; + + [[nodiscard]] size_t getSerializedSize() const override; + + ReturnValue_t deSerialize(cfdp::WidthInBytes width, const uint8_t **buffer, size_t *size, + Endianness streamEndianness); + + [[nodiscard]] cfdp::WidthInBytes getWidth() const; + [[nodiscard]] size_t getValue() const; + +#if FSFW_CPP_OSTREAM_ENABLED == 1 + friend std::ostream &operator<<(std::ostream &os, const VarLenField &id) { + os << "dec: " << id.getValue() << ", hex: " << std::hex << std::setw(id.getWidth()) + << std::setfill('0') << id.getValue() << std::dec << std::setfill('0'); + return os; + } +#endif + + private: + ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override; + + cfdp::WidthInBytes width; + LengthFieldLen value{}; +}; + +template +cfdp::VarLenField::VarLenField(UnsignedByteField byteField) + : width(static_cast(sizeof(T))) { + static_assert((sizeof(T) % 2) == 0); + setValue(width, byteField.getValue()); +} + +struct EntityId : public VarLenField { + public: + EntityId() : VarLenField() {} + template + explicit EntityId(UnsignedByteField byteField) : VarLenField(byteField) {} + EntityId(cfdp::WidthInBytes width, size_t entityId) : VarLenField(width, entityId) {} +}; + +struct TransactionSeqNum : public VarLenField { + public: + TransactionSeqNum() : VarLenField() {} + template + explicit TransactionSeqNum(UnsignedByteField byteField) : VarLenField(byteField) {} + TransactionSeqNum(cfdp::WidthInBytes width, size_t seqNum) : VarLenField(width, seqNum) {} +}; + +struct TransactionId { + TransactionId() = default; + TransactionId(EntityId entityId, TransactionSeqNum seqNum) + : entityId(std::move(entityId)), seqNum(std::move(seqNum)) {} + + bool operator==(const TransactionId &other) const { + return entityId == other.entityId and seqNum == other.seqNum; + } + +#if FSFW_CPP_OSTREAM_ENABLED == 1 + friend std::ostream &operator<<(std::ostream &os, const TransactionId &id) { + os << "Source ID { " << id.entityId << " }, Sequence Number " << id.seqNum.getValue(); + return os; + } +#endif + EntityId entityId; + TransactionSeqNum seqNum; +}; + +} // namespace cfdp + +#endif /* FSFW_CFDP_PDU_VARLENFIELD_H_ */ diff --git a/src/fsfw/cfdp/definitions.h b/src/fsfw/cfdp/definitions.h index 53022432..2d7a37fc 100644 --- a/src/fsfw/cfdp/definitions.h +++ b/src/fsfw/cfdp/definitions.h @@ -11,12 +11,16 @@ namespace cfdp { -static constexpr uint8_t VERSION_BITS = 0b00100000; +static constexpr char CFDP_VERSION_2_NAME[] = "CCSDS 727.0-B-5"; + +// Second version of the protocol, only this one is supported here +static constexpr uint8_t CFDP_VERSION_2 = 0b001; +static constexpr uint8_t VERSION_BITS = CFDP_VERSION_2 << 5; static constexpr uint8_t CFDP_CLASS_ID = CLASS_ID::CFDP; static constexpr ReturnValue_t INVALID_TLV_TYPE = returnvalue::makeCode(CFDP_CLASS_ID, 1); -static constexpr ReturnValue_t INVALID_DIRECTIVE_FIELDS = returnvalue::makeCode(CFDP_CLASS_ID, 2); +static constexpr ReturnValue_t INVALID_DIRECTIVE_FIELD = returnvalue::makeCode(CFDP_CLASS_ID, 2); static constexpr ReturnValue_t INVALID_PDU_DATAFIELD_LEN = returnvalue::makeCode(CFDP_CLASS_ID, 3); static constexpr ReturnValue_t INVALID_ACK_DIRECTIVE_FIELDS = returnvalue::makeCode(CFDP_CLASS_ID, 4); @@ -26,13 +30,14 @@ static constexpr ReturnValue_t METADATA_CANT_PARSE_OPTIONS = returnvalue::makeCode(CFDP_CLASS_ID, 5); static constexpr ReturnValue_t NAK_CANT_PARSE_OPTIONS = returnvalue::makeCode(CFDP_CLASS_ID, 6); static constexpr ReturnValue_t FINISHED_CANT_PARSE_FS_RESPONSES = - returnvalue::makeCode(CFDP_CLASS_ID, 6); + returnvalue::makeCode(CFDP_CLASS_ID, 7); static constexpr ReturnValue_t FILESTORE_REQUIRES_SECOND_FILE = returnvalue::makeCode(CFDP_CLASS_ID, 8); //! Can not parse filestore response because user did not pass a valid instance //! or remaining size is invalid static constexpr ReturnValue_t FILESTORE_RESPONSE_CANT_PARSE_FS_MESSAGE = returnvalue::makeCode(CFDP_CLASS_ID, 9); +static constexpr ReturnValue_t INVALID_PDU_FORMAT = returnvalue::makeCode(CFDP_CLASS_ID, 10); //! Checksum types according to the SANA Checksum Types registry //! https://sanaregistry.org/r/checksum_identifiers/ @@ -45,17 +50,17 @@ enum ChecksumType { NULL_CHECKSUM = 15 }; -enum PduType : bool { FILE_DIRECTIVE = 0, FILE_DATA = 1 }; +enum PduType : uint8_t { FILE_DIRECTIVE = 0, FILE_DATA = 1 }; -enum TransmissionModes : bool { ACKNOWLEDGED = 0, UNACKNOWLEDGED = 1 }; +enum TransmissionMode : uint8_t { ACKNOWLEDGED = 0, UNACKNOWLEDGED = 1 }; -enum SegmentMetadataFlag : bool { NOT_PRESENT = 0, PRESENT = 1 }; +enum SegmentMetadataFlag : bool { NOT_PRESENT = false, PRESENT = true }; -enum Direction : bool { TOWARDS_RECEIVER = 0, TOWARDS_SENDER = 1 }; +enum Direction : uint8_t { TOWARDS_RECEIVER = 0, TOWARDS_SENDER = 1 }; enum SegmentationControl : bool { - NO_RECORD_BOUNDARIES_PRESERVATION = 0, - RECORD_BOUNDARIES_PRESERVATION = 1 + NO_RECORD_BOUNDARIES_PRESERVATION = false, + RECORD_BOUNDARIES_PRESERVATION = true }; enum WidthInBytes : uint8_t { @@ -65,8 +70,9 @@ enum WidthInBytes : uint8_t { FOUR_BYTES = 4, }; -enum FileDirectives : uint8_t { +enum FileDirective : uint8_t { INVALID_DIRECTIVE = 0x0f, + // The _DIRECTIVE suffix is mandatory here because of some nameclash! EOF_DIRECTIVE = 0x04, FINISH = 0x05, ACK = 0x06, @@ -93,6 +99,14 @@ enum ConditionCode : uint8_t { CANCEL_REQUEST_RECEIVED = 0b1111 }; +enum FaultHandlerCode { + RESERVED = 0b0000, + NOTICE_OF_CANCELLATION = 0b0001, + NOTICE_OF_SUSPENSION = 0b0010, + IGNORE_ERROR = 0b0011, + ABANDON_TRANSACTION = 0b0100 +}; + enum AckTransactionStatus { UNDEFINED = 0b00, ACTIVE = 0b01, @@ -100,18 +114,18 @@ enum AckTransactionStatus { UNRECOGNIZED = 0b11 }; -enum FinishedDeliveryCode { DATA_COMPLETE = 0, DATA_INCOMPLETE = 1 }; +enum FileDeliveryCode { DATA_COMPLETE = 0, DATA_INCOMPLETE = 1 }; -enum FinishedFileStatus { +enum FileDeliveryStatus { DISCARDED_DELIBERATELY = 0, DISCARDED_FILESTORE_REJECTION = 1, RETAINED_IN_FILESTORE = 2, FILE_STATUS_UNREPORTED = 3 }; -enum PromptResponseRequired : bool { PROMPT_NAK = 0, PROMPT_KEEP_ALIVE = 1 }; +enum PromptResponseRequired : uint8_t { PROMPT_NAK = 0, PROMPT_KEEP_ALIVE = 1 }; -enum TlvTypes : uint8_t { +enum TlvType : uint8_t { FILESTORE_REQUEST = 0x00, FILESTORE_RESPONSE = 0x01, MSG_TO_USER = 0x02, diff --git a/src/fsfw/cfdp/handler/CMakeLists.txt b/src/fsfw/cfdp/handler/CMakeLists.txt new file mode 100644 index 00000000..2e7dceef --- /dev/null +++ b/src/fsfw/cfdp/handler/CMakeLists.txt @@ -0,0 +1,2 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE SourceHandler.cpp DestHandler.cpp + FaultHandlerBase.cpp UserBase.cpp CfdpHandler.cpp) diff --git a/src/fsfw/cfdp/handler/CfdpHandler.cpp b/src/fsfw/cfdp/handler/CfdpHandler.cpp new file mode 100644 index 00000000..1ea5501b --- /dev/null +++ b/src/fsfw/cfdp/handler/CfdpHandler.cpp @@ -0,0 +1,135 @@ +#include "CfdpHandler.h" + +#include "fsfw/cfdp/pdu/AckPduReader.h" +#include "fsfw/cfdp/pdu/PduHeaderReader.h" +#include "fsfw/globalfunctions/arrayprinter.h" +#include "fsfw/ipc/QueueFactory.h" +#include "fsfw/tmtcservices/TmTcMessage.h" + +using namespace returnvalue; +using namespace cfdp; + +CfdpHandler::CfdpHandler(const FsfwHandlerParams& fsfwParams, const CfdpHandlerCfg& cfdpCfg) + : SystemObject(fsfwParams.objectId), + destHandler( + DestHandlerParams(LocalEntityCfg(cfdpCfg.id, cfdpCfg.indicCfg, cfdpCfg.faultHandler), + cfdpCfg.userHandler, cfdpCfg.remoteCfgProvider, cfdpCfg.packetInfoList, + cfdpCfg.lostSegmentsList), + FsfwParams(fsfwParams.packetDest, nullptr, this, fsfwParams.tcStore, + fsfwParams.tmStore)) { + // TODO: Make queue params configurable, or better yet, expect it to be passed externally + msgQueue = QueueFactory::instance()->createMessageQueue(); + destHandler.setMsgQueue(*msgQueue); +} + +[[nodiscard]] const char* CfdpHandler::getName() const { return "CFDP Handler"; } + +[[nodiscard]] uint32_t CfdpHandler::getIdentifier() const { + return destHandler.getDestHandlerParams().cfg.localId.getValue(); +} + +[[nodiscard]] MessageQueueId_t CfdpHandler::getRequestQueue() const { return msgQueue->getId(); } + +ReturnValue_t CfdpHandler::initialize() { + ReturnValue_t result = destHandler.initialize(); + if (result != OK) { + return result; + } + tcStore = destHandler.getTcStore(); + tmStore = destHandler.getTmStore(); + + return SystemObject::initialize(); +} + +ReturnValue_t CfdpHandler::performOperation(uint8_t operationCode) { + // TODO: Receive TC packets and route them to source and dest handler, depending on which is + // correct or more appropriate + ReturnValue_t status; + ReturnValue_t result = OK; + TmTcMessage tmtcMsg; + for (status = msgQueue->receiveMessage(&tmtcMsg); status == returnvalue::OK; + status = msgQueue->receiveMessage(&tmtcMsg)) { + result = handleCfdpPacket(tmtcMsg); + if (result != OK) { + status = result; + } + } + auto& fsmRes = destHandler.performStateMachine(); + // TODO: Error handling? + while (fsmRes.callStatus == CallStatus::CALL_AGAIN) { + destHandler.performStateMachine(); + // TODO: Error handling? + } + return status; +} + +ReturnValue_t CfdpHandler::handleCfdpPacket(TmTcMessage& msg) { + auto accessorPair = tcStore->getData(msg.getStorageId()); + if (accessorPair.first != OK) { + return accessorPair.first; + } + PduHeaderReader reader(accessorPair.second.data(), accessorPair.second.size()); + ReturnValue_t result = reader.parseData(); + if (result != returnvalue::OK) { + return INVALID_PDU_FORMAT; + } + // The CFDP distributor should have taken care of ensuring the destination ID is correct + PduType type = reader.getPduType(); + // Only the destination handler can process these PDUs + if (type == PduType::FILE_DATA) { + // Disable auto-deletion of packet + accessorPair.second.release(); + PacketInfo info(type, msg.getStorageId()); + result = destHandler.passPacket(info); + } else { + // Route depending on PDU type and directive type if applicable. It retrieves directive type + // from the raw stream for better performance (with sanity and directive code check). + // The routing is based on section 4.5 of the CFDP standard which specifies the PDU forwarding + // procedure. + + // PDU header only. Invalid supplied data. A directive packet should have a valid data field + // with at least one byte being the directive code + const uint8_t* pduDataField = reader.getPduDataField(); + if (pduDataField == nullptr) { + return INVALID_PDU_FORMAT; + } + if (not FileDirectiveReader::checkFileDirective(pduDataField[0])) { + return INVALID_DIRECTIVE_FIELD; + } + auto directive = static_cast(pduDataField[0]); + + auto passToDestHandler = [&]() { + accessorPair.second.release(); + PacketInfo info(type, msg.getStorageId(), directive); + result = destHandler.passPacket(info); + }; + auto passToSourceHandler = [&]() { + + }; + if (directive == FileDirective::METADATA or directive == FileDirective::EOF_DIRECTIVE or + directive == FileDirective::PROMPT) { + // Section b) of 4.5.3: These PDUs should always be targeted towards the file receiver a.k.a. + // the destination handler + passToDestHandler(); + } else if (directive == FileDirective::FINISH or directive == FileDirective::NAK or + directive == FileDirective::KEEP_ALIVE) { + // Section c) of 4.5.3: These PDUs should always be targeted towards the file sender a.k.a. + // the source handler + passToSourceHandler(); + } else if (directive == FileDirective::ACK) { + // Section a): Recipient depends of the type of PDU that is being acknowledged. We can simply + // extract the PDU type from the raw stream. If it is an EOF PDU, this packet is passed to + // the source handler, for a Finished PDU, it is passed to the destination handler. + FileDirective ackedDirective; + if (not AckPduReader::checkAckedDirectiveField(pduDataField[1], ackedDirective)) { + return INVALID_ACK_DIRECTIVE_FIELDS; + } + if (ackedDirective == FileDirective::EOF_DIRECTIVE) { + passToSourceHandler(); + } else if (ackedDirective == FileDirective::FINISH) { + passToDestHandler(); + } + } + } + return result; +} diff --git a/src/fsfw/cfdp/handler/CfdpHandler.h b/src/fsfw/cfdp/handler/CfdpHandler.h new file mode 100644 index 00000000..d7472905 --- /dev/null +++ b/src/fsfw/cfdp/handler/CfdpHandler.h @@ -0,0 +1,65 @@ +#ifndef FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H +#define FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H + +#include + +#include "fsfw/cfdp/handler/DestHandler.h" +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/tasks/ExecutableObjectIF.h" +#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h" +#include "fsfw/tmtcservices/TmTcMessage.h" + +struct FsfwHandlerParams { + FsfwHandlerParams(object_id_t objectId, HasFileSystemIF& vfs, AcceptsTelemetryIF& packetDest, + StorageManagerIF& tcStore, StorageManagerIF& tmStore) + : objectId(objectId), vfs(vfs), packetDest(packetDest), tcStore(tcStore), tmStore(tmStore) {} + object_id_t objectId{}; + HasFileSystemIF& vfs; + AcceptsTelemetryIF& packetDest; + StorageManagerIF& tcStore; + StorageManagerIF& tmStore; +}; + +struct CfdpHandlerCfg { + CfdpHandlerCfg(cfdp::EntityId localId, cfdp::IndicationCfg indicationCfg, + cfdp::UserBase& userHandler, cfdp::FaultHandlerBase& userFaultHandler, + cfdp::PacketInfoListBase& packetInfo, cfdp::LostSegmentsListBase& lostSegmentsList, + cfdp::RemoteConfigTableIF& remoteCfgProvider) + : id(std::move(localId)), + indicCfg(indicationCfg), + packetInfoList(packetInfo), + lostSegmentsList(lostSegmentsList), + remoteCfgProvider(remoteCfgProvider), + userHandler(userHandler), + faultHandler(userFaultHandler) {} + + cfdp::EntityId id; + cfdp::IndicationCfg indicCfg; + cfdp::PacketInfoListBase& packetInfoList; + cfdp::LostSegmentsListBase& lostSegmentsList; + cfdp::RemoteConfigTableIF& remoteCfgProvider; + cfdp::UserBase& userHandler; + cfdp::FaultHandlerBase& faultHandler; +}; + +class CfdpHandler : public SystemObject, public ExecutableObjectIF, public AcceptsTelecommandsIF { + public: + explicit CfdpHandler(const FsfwHandlerParams& fsfwParams, const CfdpHandlerCfg& cfdpCfg); + + [[nodiscard]] const char* getName() const override; + [[nodiscard]] uint32_t getIdentifier() const override; + [[nodiscard]] MessageQueueId_t getRequestQueue() const override; + + ReturnValue_t initialize() override; + ReturnValue_t performOperation(uint8_t operationCode) override; + + private: + MessageQueueIF* msgQueue = nullptr; + cfdp::DestHandler destHandler; + StorageManagerIF* tcStore = nullptr; + StorageManagerIF* tmStore = nullptr; + + ReturnValue_t handleCfdpPacket(TmTcMessage& msg); +}; + +#endif // FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H diff --git a/src/fsfw/cfdp/handler/DestHandler.cpp b/src/fsfw/cfdp/handler/DestHandler.cpp new file mode 100644 index 00000000..8049cc0a --- /dev/null +++ b/src/fsfw/cfdp/handler/DestHandler.cpp @@ -0,0 +1,480 @@ +#include "DestHandler.h" + +#include + +#include + +#include "fsfw/FSFW.h" +#include "fsfw/cfdp/pdu/EofPduReader.h" +#include "fsfw/cfdp/pdu/FileDataReader.h" +#include "fsfw/cfdp/pdu/FinishedPduCreator.h" +#include "fsfw/cfdp/pdu/PduHeaderReader.h" +#include "fsfw/objectmanager.h" +#include "fsfw/tmtcservices/TmTcMessage.h" + +using namespace returnvalue; + +cfdp::DestHandler::DestHandler(DestHandlerParams params, FsfwParams fsfwParams) + : tlvVec(params.maxTlvsInOnePdu), + userTlvVec(params.maxTlvsInOnePdu), + dp(std::move(params)), + fp(fsfwParams), + tp(params.maxFilenameLen) { + tp.pduConf.direction = cfdp::Direction::TOWARDS_SENDER; +} + +const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() { + ReturnValue_t result; + uint8_t errorIdx = 0; + fsmRes.resetOfIteration(); + if (fsmRes.step == TransactionStep::IDLE) { + for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) { + if (infoIter->pduType == PduType::FILE_DIRECTIVE and + infoIter->directiveType == FileDirective::METADATA) { + result = handleMetadataPdu(*infoIter); + checkAndHandleError(result, errorIdx); + // Store data was deleted in PDU handler because a store guard is used + dp.packetListRef.erase(infoIter++); + } else { + infoIter++; + } + } + if (fsmRes.step == TransactionStep::IDLE) { + // To decrease the already high complexity of the software, all packets arriving before + // a metadata PDU are deleted. + for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) { + fp.tcStore->deleteData(infoIter->storeId); + infoIter++; + } + dp.packetListRef.clear(); + } + + if (fsmRes.step != TransactionStep::IDLE) { + fsmRes.callStatus = CallStatus::CALL_AGAIN; + } + return updateFsmRes(errorIdx); + } + if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) { + if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) { + for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) { + if (infoIter->pduType == PduType::FILE_DATA) { + result = handleFileDataPdu(*infoIter); + checkAndHandleError(result, errorIdx); + // Store data was deleted in PDU handler because a store guard is used + dp.packetListRef.erase(infoIter++); + } else if (infoIter->pduType == PduType::FILE_DIRECTIVE and + infoIter->directiveType == FileDirective::EOF_DIRECTIVE) { + // TODO: Support for check timer missing + result = handleEofPdu(*infoIter); + checkAndHandleError(result, errorIdx); + // Store data was deleted in PDU handler because a store guard is used + dp.packetListRef.erase(infoIter++); + } else { + infoIter++; + } + } + } + if (fsmRes.step == TransactionStep::TRANSFER_COMPLETION) { + result = handleTransferCompletion(); + checkAndHandleError(result, errorIdx); + } + if (fsmRes.step == TransactionStep::SENDING_FINISHED_PDU) { + result = sendFinishedPdu(); + checkAndHandleError(result, errorIdx); + finish(); + } + return updateFsmRes(errorIdx); + } + if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) { + // TODO: Will be implemented at a later stage +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "CFDP state machine for acknowledged mode not implemented yet" << std::endl; +#endif + } + return updateFsmRes(errorIdx); +} + +ReturnValue_t cfdp::DestHandler::passPacket(PacketInfo packet) { + if (dp.packetListRef.full()) { + return FAILED; + } + dp.packetListRef.push_back(packet); + return OK; +} + +ReturnValue_t cfdp::DestHandler::initialize() { + if (fp.tmStore == nullptr) { + fp.tmStore = ObjectManager::instance()->get(objects::TM_STORE); + if (fp.tmStore == nullptr) { + return FAILED; + } + } + + if (fp.tcStore == nullptr) { + fp.tcStore = ObjectManager::instance()->get(objects::TC_STORE); + if (fp.tcStore == nullptr) { + return FAILED; + } + } + + if (fp.msgQueue == nullptr) { + return FAILED; + } + return OK; +} + +ReturnValue_t cfdp::DestHandler::handleMetadataPdu(const PacketInfo& info) { + // Process metadata PDU + auto constAccessorPair = fp.tcStore->getData(info.storeId); + if (constAccessorPair.first != OK) { + // TODO: This is not a CFDP error. Event and/or warning? + return constAccessorPair.first; + } + cfdp::StringLv sourceFileName; + cfdp::StringLv destFileName; + MetadataInfo metadataInfo(tp.fileSize, sourceFileName, destFileName); + cfdp::Tlv* tlvArrayAsPtr = tlvVec.data(); + metadataInfo.setOptionsArray(&tlvArrayAsPtr, std::nullopt, tlvVec.size()); + MetadataPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), + metadataInfo); + ReturnValue_t result = reader.parseData(); + // TODO: The standard does not really specify what happens if this kind of error happens + // I think it might be a good idea to cache some sort of error code, which + // is translated into a warning and/or event by an upper layer + if (result != OK) { + return handleMetadataParseError(result, constAccessorPair.second.data(), + constAccessorPair.second.size()); + } + return startTransaction(reader, metadataInfo); +} + +ReturnValue_t cfdp::DestHandler::handleFileDataPdu(const cfdp::PacketInfo& info) { + // Process file data PDU + auto constAccessorPair = fp.tcStore->getData(info.storeId); + if (constAccessorPair.first != OK) { + // TODO: This is not a CFDP error. Event and/or warning? + return constAccessorPair.first; + } + cfdp::FileSize offset; + FileDataInfo fdInfo(offset); + FileDataReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), fdInfo); + ReturnValue_t result = reader.parseData(); + if (result != OK) { + return result; + } + size_t fileSegmentLen = 0; + const uint8_t* fileData = fdInfo.getFileData(&fileSegmentLen); + FileOpParams fileOpParams(tp.destName.data(), fileSegmentLen); + fileOpParams.offset = offset.value(); + if (dp.cfg.indicCfg.fileSegmentRecvIndicRequired) { + FileSegmentRecvdParams segParams; + segParams.offset = offset.value(); + segParams.id = tp.transactionId; + segParams.length = fileSegmentLen; + segParams.recContState = fdInfo.getRecordContinuationState(); + size_t segmentMetadatLen = 0; + auto* segMetadata = fdInfo.getSegmentMetadata(&segmentMetadatLen); + segParams.segmentMetadata = {segMetadata, segmentMetadatLen}; + dp.user.fileSegmentRecvdIndication(segParams); + } + result = dp.user.vfs.writeToFile(fileOpParams, fileData); + if (offset.value() + fileSegmentLen > tp.progress) { + tp.progress = offset.value() + fileSegmentLen; + } + if (result != returnvalue::OK) { + // TODO: Proper Error handling +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "File write error" << std::endl; +#endif + } else { + tp.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE; + } + return result; +} + +ReturnValue_t cfdp::DestHandler::handleEofPdu(const cfdp::PacketInfo& info) { + // Process EOF PDU + auto constAccessorPair = fp.tcStore->getData(info.storeId); + if (constAccessorPair.first != OK) { + // TODO: This is not a CFDP error. Event and/or warning? + return constAccessorPair.first; + } + EofInfo eofInfo(nullptr); + EofPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), eofInfo); + ReturnValue_t result = reader.parseData(); + if (result != OK) { + return result; + } + // TODO: Error handling + if (eofInfo.getConditionCode() == ConditionCode::NO_ERROR) { + tp.crc = eofInfo.getChecksum(); + uint64_t fileSizeFromEof = eofInfo.getFileSize().value(); + // CFDP 4.6.1.2.9: Declare file size error if progress exceeds file size + if (fileSizeFromEof > tp.progress) { + // TODO: File size error + } + tp.fileSize.setFileSize(fileSizeFromEof, std::nullopt); + } + if (dp.cfg.indicCfg.eofRecvIndicRequired) { + dp.user.eofRecvIndication(getTransactionId()); + } + if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) { + if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) { + fsmRes.step = TransactionStep::TRANSFER_COMPLETION; + } else if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) { + fsmRes.step = TransactionStep::SENDING_ACK_PDU; + } + } + return returnvalue::OK; +} + +ReturnValue_t cfdp::DestHandler::handleMetadataParseError(ReturnValue_t result, + const uint8_t* rawData, size_t maxSize) { + // TODO: try to extract destination ID for error + // TODO: Invalid metadata PDU. +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "Parsing Metadata PDU failed with code " << result << std::endl; +#else +#endif + PduHeaderReader headerReader(rawData, maxSize); + result = headerReader.parseData(); + if (result != OK) { + // TODO: Now this really should not happen. Warning or error, + // yield or cache appropriate returnvalue +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "Parsing Header failed" << std::endl; +#else +#endif + // TODO: Trigger appropriate event + return result; + } + cfdp::EntityId destId; + headerReader.getDestId(destId); + RemoteEntityCfg* remoteCfg; + if (not dp.remoteCfgTable.getRemoteCfg(destId, &remoteCfg)) { +// TODO: No remote config for dest ID. I consider this a configuration error, which is not +// covered by the standard. +// Warning or error, yield or cache appropriate returnvalue +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "No remote config exists for destination ID" << std::endl; +#else +#endif + // TODO: Trigger appropriate event + } + // TODO: Appropriate returnvalue? + return returnvalue::FAILED; +} + +ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader, MetadataInfo& info) { + if (fsmRes.state != CfdpStates::IDLE) { + // According to standard, discard metadata PDU if we are busy + return OK; + } + ReturnValue_t result = OK; + fsmRes.step = TransactionStep::TRANSACTION_START; + if (reader.getTransmissionMode() == TransmissionMode::UNACKNOWLEDGED) { + fsmRes.state = CfdpStates::BUSY_CLASS_1_NACKED; + } else if (reader.getTransmissionMode() == TransmissionMode::ACKNOWLEDGED) { + fsmRes.state = CfdpStates::BUSY_CLASS_2_ACKED; + } + tp.checksumType = info.getChecksumType(); + tp.closureRequested = info.isClosureRequested(); + size_t sourceNameSize = 0; + const uint8_t* sourceNamePtr = info.getSourceFileName().getValue(&sourceNameSize); + if (sourceNameSize > tp.sourceName.size()) { + // TODO: Warning, event etc. + return FAILED; + } + std::memcpy(tp.sourceName.data(), sourceNamePtr, sourceNameSize); + tp.sourceName[sourceNameSize] = '\0'; + size_t destNameSize = 0; + const uint8_t* destNamePtr = info.getDestFileName().getValue(&destNameSize); + if (destNameSize > tp.destName.size()) { + // TODO: Warning, event etc. + return FAILED; + } + std::memcpy(tp.destName.data(), destNamePtr, destNameSize); + tp.destName[destNameSize] = '\0'; + reader.fillConfig(tp.pduConf); + tp.pduConf.direction = Direction::TOWARDS_SENDER; + tp.transactionId.entityId = tp.pduConf.sourceId; + tp.transactionId.seqNum = tp.pduConf.seqNum; + if (not dp.remoteCfgTable.getRemoteCfg(tp.pduConf.sourceId, &tp.remoteCfg)) { + // TODO: Warning, event etc. +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "cfdp::DestHandler" << __func__ + << ": No remote configuration found for destination ID " + << tp.pduConf.sourceId.getValue() << std::endl; +#endif + return FAILED; + } + // If both dest name size and source name size are 0, we are dealing with a metadata only PDU, + // so there is no need to create a file or truncate an existing file + if (destNameSize > 0 and sourceNameSize > 0) { + FilesystemParams fparams(tp.destName.data()); + // TODO: Filesystem errors? + if (dp.user.vfs.fileExists(fparams)) { + dp.user.vfs.truncateFile(fparams); + } else { + result = dp.user.vfs.createFile(fparams); + if (result != OK) { + // TODO: Handle FS error. This is probably a case for the filestore rejection mechanism of + // CFDP. + // In any case, it does not really make sense to continue here + } + } + } + fsmRes.step = TransactionStep::RECEIVING_FILE_DATA_PDUS; + MetadataRecvdParams params(tp.transactionId, tp.pduConf.sourceId); + params.fileSize = tp.fileSize.getSize(); + params.destFileName = tp.destName.data(); + params.sourceFileName = tp.sourceName.data(); + params.msgsToUserArray = dynamic_cast(userTlvVec.data()); + params.msgsToUserLen = info.getOptionsLen(); + dp.user.metadataRecvdIndication(params); + return result; +} + +cfdp::CfdpStates cfdp::DestHandler::getCfdpState() const { return fsmRes.state; } + +ReturnValue_t cfdp::DestHandler::handleTransferCompletion() { + ReturnValue_t result; + if (tp.checksumType != ChecksumType::NULL_CHECKSUM) { + result = checksumVerification(); + if (result != OK) { + // TODO: Warning / error handling? + } + } else { + tp.conditionCode = ConditionCode::NO_ERROR; + } + result = noticeOfCompletion(); + if (result != OK) { + } + if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) { + if (tp.closureRequested) { + fsmRes.step = TransactionStep::SENDING_FINISHED_PDU; + } else { + finish(); + } + } else if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) { + fsmRes.step = TransactionStep::SENDING_FINISHED_PDU; + } + return OK; +} + +void cfdp::DestHandler::finish() { + tp.reset(); + dp.packetListRef.clear(); + fsmRes.state = CfdpStates::IDLE; + fsmRes.step = TransactionStep::IDLE; +} + +ReturnValue_t cfdp::DestHandler::checksumVerification() { + std::array buf{}; + // TODO: Checksum verification and notice of completion + etl::crc32 crcCalc; + uint64_t currentOffset = 0; + FileOpParams params(tp.destName.data(), tp.fileSize.value()); + while (currentOffset < tp.fileSize.value()) { + uint64_t readLen; + if (currentOffset + buf.size() > tp.fileSize.value()) { + readLen = tp.fileSize.value() - currentOffset; + } else { + readLen = buf.size(); + } + if (readLen > 0) { + params.offset = currentOffset; + params.size = readLen; + auto result = dp.user.vfs.readFromFile(params, buf.data(), buf.size()); + if (result != OK) { + // TODO: I think this is a case for a filestore rejection, but it might sense to print + // a warning or trigger an event because this should generally not happen + return FAILED; + } + crcCalc.add(buf.begin(), buf.begin() + readLen); + } + currentOffset += readLen; + } + + uint32_t value = crcCalc.value(); + if (value == tp.crc) { + tp.conditionCode = ConditionCode::NO_ERROR; + tp.deliveryCode = FileDeliveryCode::DATA_COMPLETE; + } else { + // TODO: Proper error handling +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "CRC check for file " << tp.destName.data() << " failed" << std::endl; +#endif + tp.conditionCode = ConditionCode::FILE_CHECKSUM_FAILURE; + } + return OK; +} + +ReturnValue_t cfdp::DestHandler::noticeOfCompletion() { + if (dp.cfg.indicCfg.transactionFinishedIndicRequired) { + TransactionFinishedParams params(tp.transactionId, tp.conditionCode, tp.deliveryCode, + tp.deliveryStatus); + dp.user.transactionFinishedIndication(params); + } + return OK; +} + +ReturnValue_t cfdp::DestHandler::sendFinishedPdu() { + FinishedInfo info(tp.conditionCode, tp.deliveryCode, tp.deliveryStatus); + FinishPduCreator finishedPdu(tp.pduConf, info); + store_address_t storeId; + uint8_t* dataPtr = nullptr; + ReturnValue_t result = + fp.tcStore->getFreeElement(&storeId, finishedPdu.getSerializedSize(), &dataPtr); + if (result != OK) { + // TODO: Error handling and event, this is a non CFDP specific error (most likely store is full) + return result; + } + size_t serLen = 0; + result = finishedPdu.serialize(dataPtr, serLen, finishedPdu.getSerializedSize()); + if (result != OK) { + // TODO: Error printout, this really should not happen + return result; + } + TmTcMessage msg(storeId); + result = fp.msgQueue->sendMessage(fp.packetDest.getReportReceptionQueue(), &msg); + if (result != OK) { + // TODO: Error handling and event, this is a non CFDP specific error (most likely store is full) + return result; + } + fsmRes.packetsSent++; + return OK; +} + +cfdp::DestHandler::TransactionStep cfdp::DestHandler::getTransactionStep() const { + return fsmRes.step; +} + +const cfdp::DestHandler::FsmResult& cfdp::DestHandler::updateFsmRes(uint8_t errors) { + fsmRes.errors = errors; + fsmRes.result = OK; + if (fsmRes.errors > 0) { + fsmRes.result = FAILED; + } + return fsmRes; +} + +const cfdp::TransactionId& cfdp::DestHandler::getTransactionId() const { return tp.transactionId; } + +void cfdp::DestHandler::checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx) { + if (result != OK and errorIdx < 3) { + fsmRes.errorCodes[errorIdx] = result; + errorIdx++; + } +} + +void cfdp::DestHandler::setMsgQueue(MessageQueueIF& queue) { fp.msgQueue = &queue; } + +void cfdp::DestHandler::setEventReporter(EventReportingProxyIF& reporter) { + fp.eventReporter = &reporter; +} + +const cfdp::DestHandlerParams& cfdp::DestHandler::getDestHandlerParams() const { return dp; } + +StorageManagerIF* cfdp::DestHandler::getTmStore() const { return fp.tmStore; } +StorageManagerIF* cfdp::DestHandler::getTcStore() const { return fp.tcStore; } diff --git a/src/fsfw/cfdp/handler/DestHandler.h b/src/fsfw/cfdp/handler/DestHandler.h new file mode 100644 index 00000000..5cef88d4 --- /dev/null +++ b/src/fsfw/cfdp/handler/DestHandler.h @@ -0,0 +1,202 @@ +#ifndef FSFW_CFDP_CFDPDESTHANDLER_H +#define FSFW_CFDP_CFDPDESTHANDLER_H + +#include +#include + +#include +#include + +#include "RemoteConfigTableIF.h" +#include "UserBase.h" +#include "defs.h" +#include "fsfw/cfdp/handler/mib.h" +#include "fsfw/cfdp/pdu/MetadataPduReader.h" +#include "fsfw/cfdp/pdu/PduConfig.h" +#include "fsfw/container/DynamicFIFO.h" +#include "fsfw/storagemanager/StorageManagerIF.h" +#include "fsfw/storagemanager/storeAddress.h" +#include "fsfw/tmtcservices/AcceptsTelemetryIF.h" + +namespace cfdp { + +struct PacketInfo { + PacketInfo(PduType type, store_address_t storeId, + std::optional directive = std::nullopt) + : pduType(type), directiveType(directive), storeId(storeId) {} + + PduType pduType = PduType::FILE_DATA; + std::optional directiveType = FileDirective::INVALID_DIRECTIVE; + store_address_t storeId = store_address_t::invalid(); + PacketInfo() = default; +}; + +template +using LostSegmentsList = etl::set, SIZE>; +template +using PacketInfoList = etl::list; +using LostSegmentsListBase = etl::iset>; +using PacketInfoListBase = etl::ilist; + +struct DestHandlerParams { + DestHandlerParams(LocalEntityCfg cfg, UserBase& user, RemoteConfigTableIF& remoteCfgTable, + PacketInfoListBase& packetList, + // TODO: This container can potentially take tons of space. For a better + // memory efficient implementation, an additional abstraction could be + // be used so users can use uint32_t as the pair type + LostSegmentsListBase& lostSegmentsContainer) + : cfg(std::move(cfg)), + user(user), + remoteCfgTable(remoteCfgTable), + packetListRef(packetList), + lostSegmentsContainer(lostSegmentsContainer) {} + + LocalEntityCfg cfg; + UserBase& user; + RemoteConfigTableIF& remoteCfgTable; + + PacketInfoListBase& packetListRef; + LostSegmentsListBase& lostSegmentsContainer; + uint8_t maxTlvsInOnePdu = 10; + size_t maxFilenameLen = 255; +}; + +struct FsfwParams { + FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue, + EventReportingProxyIF* eventReporter, StorageManagerIF& tcStore, + StorageManagerIF& tmStore) + : FsfwParams(packetDest, msgQueue, eventReporter) { + this->tcStore = &tcStore; + this->tmStore = &tmStore; + } + + FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue, + EventReportingProxyIF* eventReporter) + : packetDest(packetDest), msgQueue(msgQueue), eventReporter(eventReporter) {} + AcceptsTelemetryIF& packetDest; + MessageQueueIF* msgQueue; + EventReportingProxyIF* eventReporter = nullptr; + StorageManagerIF* tcStore = nullptr; + StorageManagerIF* tmStore = nullptr; +}; + +enum class CallStatus { DONE, CALL_AFTER_DELAY, CALL_AGAIN }; + +class DestHandler { + public: + enum class TransactionStep { + IDLE = 0, + TRANSACTION_START = 1, + RECEIVING_FILE_DATA_PDUS = 2, + SENDING_ACK_PDU = 3, + TRANSFER_COMPLETION = 4, + SENDING_FINISHED_PDU = 5 + }; + + struct FsmResult { + public: + ReturnValue_t result = returnvalue::OK; + CallStatus callStatus = CallStatus::CALL_AFTER_DELAY; + TransactionStep step = TransactionStep::IDLE; + CfdpStates state = CfdpStates::IDLE; + uint32_t packetsSent = 0; + uint8_t errors = 0; + std::array errorCodes = {}; + void resetOfIteration() { + result = returnvalue::OK; + callStatus = CallStatus::CALL_AFTER_DELAY; + packetsSent = 0; + errors = 0; + errorCodes.fill(returnvalue::OK); + } + }; + /** + * Will be returned if it is advisable to call the state machine operation call again + */ + ReturnValue_t PARTIAL_SUCCESS = returnvalue::makeCode(0, 2); + ReturnValue_t FAILURE = returnvalue::makeCode(0, 3); + explicit DestHandler(DestHandlerParams handlerParams, FsfwParams fsfwParams); + + /** + * + * @return + * - @c returnvalue::OK State machine OK for this execution cycle + * - @c CALL_FSM_AGAIN State machine should be called again. + */ + const FsmResult& performStateMachine(); + void setMsgQueue(MessageQueueIF& queue); + void setEventReporter(EventReportingProxyIF& reporter); + + ReturnValue_t passPacket(PacketInfo packet); + + ReturnValue_t initialize(); + + [[nodiscard]] CfdpStates getCfdpState() const; + [[nodiscard]] TransactionStep getTransactionStep() const; + [[nodiscard]] const TransactionId& getTransactionId() const; + [[nodiscard]] const DestHandlerParams& getDestHandlerParams() const; + [[nodiscard]] StorageManagerIF* getTcStore() const; + [[nodiscard]] StorageManagerIF* getTmStore() const; + + private: + struct TransactionParams { + // Initialize char vectors with length + 1 for 0 termination + explicit TransactionParams(size_t maxFileNameLen) + : sourceName(maxFileNameLen + 1), destName(maxFileNameLen + 1) {} + + void reset() { + pduConf = PduConfig(); + transactionId = TransactionId(); + std::fill(sourceName.begin(), sourceName.end(), '\0'); + std::fill(destName.begin(), destName.end(), '\0'); + fileSize.setFileSize(0, false); + conditionCode = ConditionCode::NO_ERROR; + deliveryCode = FileDeliveryCode::DATA_INCOMPLETE; + deliveryStatus = FileDeliveryStatus::DISCARDED_DELIBERATELY; + crc = 0; + progress = 0; + remoteCfg = nullptr; + closureRequested = false; + checksumType = ChecksumType::NULL_CHECKSUM; + } + + ChecksumType checksumType = ChecksumType::NULL_CHECKSUM; + bool closureRequested = false; + std::vector sourceName; + std::vector destName; + cfdp::FileSize fileSize; + TransactionId transactionId; + PduConfig pduConf; + ConditionCode conditionCode = ConditionCode::NO_ERROR; + FileDeliveryCode deliveryCode = FileDeliveryCode::DATA_INCOMPLETE; + FileDeliveryStatus deliveryStatus = FileDeliveryStatus::DISCARDED_DELIBERATELY; + uint32_t crc = 0; + uint64_t progress = 0; + RemoteEntityCfg* remoteCfg = nullptr; + }; + + std::vector tlvVec; + std::vector userTlvVec; + DestHandlerParams dp; + FsfwParams fp; + TransactionParams tp; + FsmResult fsmRes; + + ReturnValue_t startTransaction(MetadataPduReader& reader, MetadataInfo& info); + ReturnValue_t handleMetadataPdu(const PacketInfo& info); + ReturnValue_t handleFileDataPdu(const PacketInfo& info); + ReturnValue_t handleEofPdu(const PacketInfo& info); + ReturnValue_t handleMetadataParseError(ReturnValue_t result, const uint8_t* rawData, + size_t maxSize); + ReturnValue_t handleTransferCompletion(); + ReturnValue_t sendFinishedPdu(); + ReturnValue_t noticeOfCompletion(); + ReturnValue_t checksumVerification(); + const FsmResult& updateFsmRes(uint8_t errors); + void checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx); + void finish(); +}; + +} // namespace cfdp + +#endif // FSFW_CFDP_CFDPDESTHANDLER_H diff --git a/src/fsfw/cfdp/handler/FaultHandlerBase.cpp b/src/fsfw/cfdp/handler/FaultHandlerBase.cpp new file mode 100644 index 00000000..4e16692e --- /dev/null +++ b/src/fsfw/cfdp/handler/FaultHandlerBase.cpp @@ -0,0 +1,51 @@ +#include "FaultHandlerBase.h" + +namespace cfdp { + +FaultHandlerBase::FaultHandlerBase() = default; +FaultHandlerBase::~FaultHandlerBase() = default; + +bool FaultHandlerBase::getFaultHandler(cfdp::ConditionCode code, + cfdp::FaultHandlerCode& handler) const { + auto iter = faultHandlerMap.find(code); + if (iter == faultHandlerMap.end()) { + return false; + } + handler = iter->second; + return true; +} + +bool FaultHandlerBase::setFaultHandler(cfdp::ConditionCode code, cfdp::FaultHandlerCode handler) { + if (not faultHandlerMap.contains(code)) { + return false; + } + if (handler != FaultHandlerCode::NOTICE_OF_SUSPENSION and + handler != FaultHandlerCode::ABANDON_TRANSACTION and + handler != FaultHandlerCode::NOTICE_OF_CANCELLATION and + handler != FaultHandlerCode::IGNORE_ERROR) { + return false; + } + faultHandlerMap[code] = handler; + return true; +} + +bool FaultHandlerBase::reportFault(cfdp::TransactionId& id, cfdp::ConditionCode code) { + if (not faultHandlerMap.contains(code)) { + return false; + } + cfdp::FaultHandlerCode fh = faultHandlerMap[code]; + if (fh == cfdp::FaultHandlerCode::IGNORE_ERROR) { + ignoreCb(id, code); + } else if (fh == cfdp::FaultHandlerCode::ABANDON_TRANSACTION) { + abandonCb(id, code); + } else if (fh == cfdp::FaultHandlerCode::NOTICE_OF_CANCELLATION) { + noticeOfCancellationCb(id, code); + } else if (fh == cfdp::FaultHandlerCode::NOTICE_OF_SUSPENSION) { + noticeOfSuspensionCb(id, code); + } else { + // Should never happen, but use defensive programming + return false; + } + return true; +} +} // namespace cfdp diff --git a/src/fsfw/cfdp/handler/FaultHandlerBase.h b/src/fsfw/cfdp/handler/FaultHandlerBase.h new file mode 100644 index 00000000..39b8e180 --- /dev/null +++ b/src/fsfw/cfdp/handler/FaultHandlerBase.h @@ -0,0 +1,77 @@ +#ifndef FSFW_CFDP_FAULTHANDLERBASE_H +#define FSFW_CFDP_FAULTHANDLERBASE_H + +#include + +#include "fsfw/cfdp/VarLenFields.h" +#include "fsfw/cfdp/definitions.h" + +namespace cfdp { + +/** + * @brief Provides a way to implement the fault handling procedures as specified + * in chapter 4.8 of the CFDP standard. + * + * @details + * It is passed into the CFDP handlers as part of the local entity configuration and provides + * a way to specify custom user error handlers. + * + * It does so by mapping each applicable CFDP condition code to a fault handler which + * is denoted by the four @cfdp::FaultHandlerCodes. This code is used to dispatch + * to a user-provided callback function: + * + * 1. @FaultHandlerCodes::IGNORE_ERROR -> @ignore_cb + * 2. @FaultHandlerCodes::NOTICE_OF_CANCELLATION` -> @notice_of_cancellation_cb + * 3. @FaultHandlerCodes::NOTICE_OF_SUSPENSION` -> @notice_of_suspension_cb + * 4. @FaultHandlerCodes::ABANDON_TRANSACTION` -> @abandon_transaction_cb + * + * For each error reported by @reportError, the appropriate fault handler callback + * will be called. The user provides the callbacks by providing a custom class which implements + * these base class and all abstract fault handler callbacks. + */ +class FaultHandlerBase { + public: + virtual ~FaultHandlerBase(); + FaultHandlerBase(); + + /** + * Get the fault handler code for the given condition code + * @param code + * @param handler [out] Will be set to the approrpiate handler for the condition code if + * it is valid + * @return + * - true if the condition code is valid + * - false otherwise + */ + bool getFaultHandler(cfdp::ConditionCode code, cfdp::FaultHandlerCode& handler) const; + + bool setFaultHandler(cfdp::ConditionCode code, cfdp::FaultHandlerCode handler); + + bool reportFault(cfdp::TransactionId& id, cfdp::ConditionCode code); + + virtual void noticeOfSuspensionCb(cfdp::TransactionId& id, cfdp::ConditionCode code) = 0; + virtual void noticeOfCancellationCb(cfdp::TransactionId& id, cfdp::ConditionCode code) = 0; + virtual void abandonCb(cfdp::TransactionId& id, cfdp::ConditionCode code) = 0; + virtual void ignoreCb(cfdp::TransactionId& id, cfdp::ConditionCode code) = 0; + + private: + etl::flat_map faultHandlerMap = { + etl::pair{cfdp::ConditionCode::POSITIVE_ACK_LIMIT_REACHED, + cfdp::FaultHandlerCode::IGNORE_ERROR}, + etl::pair{cfdp::ConditionCode::KEEP_ALIVE_LIMIT_REACHED, + cfdp::FaultHandlerCode::IGNORE_ERROR}, + etl::pair{cfdp::ConditionCode::INVALID_TRANSMISSION_MODE, + cfdp::FaultHandlerCode::IGNORE_ERROR}, + etl::pair{cfdp::ConditionCode::FILE_CHECKSUM_FAILURE, cfdp::FaultHandlerCode::IGNORE_ERROR}, + etl::pair{cfdp::ConditionCode::FILE_SIZE_ERROR, cfdp::FaultHandlerCode::IGNORE_ERROR}, + etl::pair{cfdp::ConditionCode::NAK_LIMIT_REACHED, cfdp::FaultHandlerCode::IGNORE_ERROR}, + etl::pair{cfdp::ConditionCode::INACTIVITY_DETECTED, cfdp::FaultHandlerCode::IGNORE_ERROR}, + etl::pair{cfdp::ConditionCode::UNSUPPORTED_CHECKSUM_TYPE, + cfdp::FaultHandlerCode::IGNORE_ERROR}, + etl::pair{cfdp::ConditionCode::FILESTORE_REJECTION, cfdp::FaultHandlerCode::IGNORE_ERROR}, + etl::pair{cfdp::ConditionCode::CHECK_LIMIT_REACHED, cfdp::FaultHandlerCode::IGNORE_ERROR}}; +}; + +} // namespace cfdp + +#endif // FSFW_CFDP_FAULTHANDLERBASE_H diff --git a/src/fsfw/cfdp/handler/RemoteConfigTableIF.h b/src/fsfw/cfdp/handler/RemoteConfigTableIF.h new file mode 100644 index 00000000..d0e6121d --- /dev/null +++ b/src/fsfw/cfdp/handler/RemoteConfigTableIF.h @@ -0,0 +1,35 @@ +#ifndef FSFW_CFDP_HANDLER_REMOTECONFIGTABLEIF_H +#define FSFW_CFDP_HANDLER_REMOTECONFIGTABLEIF_H + +#include "fsfw/cfdp/handler/mib.h" + +namespace cfdp { + +class RemoteConfigTableIF { + public: + virtual ~RemoteConfigTableIF() = default; + virtual bool getRemoteCfg(const cfdp::EntityId& remoteId, cfdp::RemoteEntityCfg** cfg) = 0; +}; + +/** + * Helper class for the common case that there is exactly one remote entity + */ +class OneRemoteConfigProvider : public RemoteConfigTableIF { + public: + explicit OneRemoteConfigProvider(RemoteEntityCfg cfg) : cfg(std::move(cfg)) {} + + bool getRemoteCfg(const EntityId& remoteId, cfdp::RemoteEntityCfg** cfg_) override { + if (remoteId != cfg.remoteId) { + return false; + } + *cfg_ = &cfg; + return true; + } + + private: + RemoteEntityCfg cfg; +}; + +} // namespace cfdp + +#endif // FSFW_CFDP_HANDLER_REMOTECONFIGTABLEIF_H diff --git a/src/fsfw/cfdp/handler/SourceHandler.cpp b/src/fsfw/cfdp/handler/SourceHandler.cpp new file mode 100644 index 00000000..513b25f3 --- /dev/null +++ b/src/fsfw/cfdp/handler/SourceHandler.cpp @@ -0,0 +1 @@ +#include "SourceHandler.h" diff --git a/src/fsfw/cfdp/handler/SourceHandler.h b/src/fsfw/cfdp/handler/SourceHandler.h new file mode 100644 index 00000000..319cf258 --- /dev/null +++ b/src/fsfw/cfdp/handler/SourceHandler.h @@ -0,0 +1,6 @@ +#ifndef FSFW_CFDP_CFDPSOURCEHANDLER_H +#define FSFW_CFDP_CFDPSOURCEHANDLER_H + +class SourceHandler {}; + +#endif // FSFW_CFDP_CFDPSOURCEHANDLER_H diff --git a/src/fsfw/cfdp/handler/StatusReportIF.h b/src/fsfw/cfdp/handler/StatusReportIF.h new file mode 100644 index 00000000..1bf98628 --- /dev/null +++ b/src/fsfw/cfdp/handler/StatusReportIF.h @@ -0,0 +1,12 @@ +#ifndef FSFW_CFDP_HANDLER_STATUSREPORTIF_H +#define FSFW_CFDP_HANDLER_STATUSREPORTIF_H + +namespace cfdp { + +class StatusReportIF { + virtual ~StatusReportIF() = default; +}; + +} // namespace cfdp + +#endif // FSFW_CFDP_HANDLER_STATUSREPORTIF_H diff --git a/src/fsfw/cfdp/handler/UserBase.cpp b/src/fsfw/cfdp/handler/UserBase.cpp new file mode 100644 index 00000000..212396fb --- /dev/null +++ b/src/fsfw/cfdp/handler/UserBase.cpp @@ -0,0 +1,3 @@ +#include "UserBase.h" + +cfdp::UserBase::UserBase(HasFileSystemIF& vfs) : vfs(vfs) {} diff --git a/src/fsfw/cfdp/handler/UserBase.h b/src/fsfw/cfdp/handler/UserBase.h new file mode 100644 index 00000000..e367b4a8 --- /dev/null +++ b/src/fsfw/cfdp/handler/UserBase.h @@ -0,0 +1,101 @@ +#ifndef FSFW_CFDP_USERBASE_H +#define FSFW_CFDP_USERBASE_H + +#include +#include +#include + +#include "StatusReportIF.h" +#include "fsfw/cfdp/VarLenFields.h" +#include "fsfw/cfdp/tlv/FilestoreResponseTlv.h" +#include "fsfw/cfdp/tlv/MessageToUserTlv.h" +#include "fsfw/filesystem/HasFileSystemIF.h" + +namespace cfdp { + +struct TransactionFinishedParams { + TransactionFinishedParams(const TransactionId& id, ConditionCode code, FileDeliveryCode delivCode, + FileDeliveryStatus status) + : id(id), condCode(code), status(status), deliveryCode(delivCode) {} + + const TransactionId& id; + ConditionCode condCode; + FileDeliveryStatus status; + FileDeliveryCode deliveryCode; + std::vector fsResponses; + StatusReportIF* statusReport = nullptr; +}; + +struct MetadataRecvdParams { + MetadataRecvdParams(const TransactionId& id, const EntityId& sourceId) + : id(id), sourceId(sourceId) {} + const TransactionId& id; + const EntityId& sourceId; + uint64_t fileSize = 0; + const char* sourceFileName = ""; + const char* destFileName = ""; + size_t msgsToUserLen = 0; + const MessageToUserTlv* msgsToUserArray = nullptr; +}; + +struct FileSegmentRecvdParams { + TransactionId id; + size_t offset; + size_t length; + std::optional recContState = std::nullopt; + std::pair segmentMetadata; +}; + +/** + * @brief Base class which provides a user interface to interact with CFDP handlers. + * + * @details + * This class is also used to pass the Virtual Filestore (VFS) Implementation to the CFDP + * handlers so the filestore operations can be mapped to the underlying filestore. + * + * It is used by implementing it in a child class and then passing it to the CFDP + * handler objects. The base class provides default implementation for the user indication + * primitives specified in the CFDP standard. The user can override these implementations + * to provide custom indication handlers. + * + * Please note that for all indication callbacks, the passed transaction ID reference will + * become invalid shortly after the function has been executed. If the transaction ID is to be + * cached or used, create an own copy of it. + * @param vfs Virtual Filestore Object. Will be used for all file operations + */ +class UserBase { + friend class DestHandler; + + public: + explicit UserBase(HasFileSystemIF& vfs); + + virtual void transactionIndication(const TransactionId& id) = 0; + virtual void eofSentIndication(const TransactionId& id) = 0; + virtual void transactionFinishedIndication(const TransactionFinishedParams& params) = 0; + /** + * Will be called if metadata was received. + * + * IMPORTANT: The passed struct contains the messages to the user in form of a raw C array. + * The TLVs in these arrays are zero-copy types, which means that they point to the raw data + * inside the metadata packet directly. The metadata packet will be deleted from the TC store + * shortly after it was processed. If some of the data is to be cached and/or used after the + * function call, it needs to be copied into another user-provided buffer. + * @param params + */ + virtual void metadataRecvdIndication(const MetadataRecvdParams& params) = 0; + virtual void fileSegmentRecvdIndication(const FileSegmentRecvdParams& params) = 0; + virtual void reportIndication(const TransactionId& id, StatusReportIF& report) = 0; + virtual void suspendedIndication(const TransactionId& id, ConditionCode code) = 0; + virtual void resumedIndication(const TransactionId& id, size_t progress) = 0; + virtual void faultIndication(const TransactionId& id, ConditionCode code, size_t progress) = 0; + virtual void abandonedIndication(const TransactionId& id, ConditionCode code, + size_t progress) = 0; + virtual void eofRecvIndication(const TransactionId& id) = 0; + + private: + HasFileSystemIF& vfs; +}; + +} // namespace cfdp + +#endif // FSFW_CFDP_USERBASE_H diff --git a/src/fsfw/cfdp/handler/defs.h b/src/fsfw/cfdp/handler/defs.h new file mode 100644 index 00000000..9e837a96 --- /dev/null +++ b/src/fsfw/cfdp/handler/defs.h @@ -0,0 +1,9 @@ +#ifndef FSFW_CFDP_HANDLER_DEFS_H +#define FSFW_CFDP_HANDLER_DEFS_H + +namespace cfdp { + +enum class CfdpStates { IDLE, BUSY_CLASS_1_NACKED, BUSY_CLASS_2_ACKED, SUSPENDED }; + +} +#endif // FSFW_CFDP_HANDLER_DEFS_H diff --git a/src/fsfw/cfdp/handler/mib.h b/src/fsfw/cfdp/handler/mib.h new file mode 100644 index 00000000..553596a6 --- /dev/null +++ b/src/fsfw/cfdp/handler/mib.h @@ -0,0 +1,42 @@ +#ifndef FSFW_CFDP_MIB_H +#define FSFW_CFDP_MIB_H + +#include + +#include "FaultHandlerBase.h" +#include "fsfw/cfdp/pdu/PduConfig.h" + +namespace cfdp { + +struct IndicationCfg { + bool eofSentIndicRequired = true; + bool eofRecvIndicRequired = true; + bool fileSegmentRecvIndicRequired = true; + bool transactionFinishedIndicRequired = true; + bool suspendedIndicRequired = true; + bool resumedIndicRequired = true; +}; + +struct LocalEntityCfg { + LocalEntityCfg(EntityId localId, IndicationCfg indicationCfg, FaultHandlerBase& fhBase) + : localId(std::move(localId)), indicCfg(indicationCfg), fhBase(fhBase) {} + + EntityId localId; + IndicationCfg indicCfg; + FaultHandlerBase& fhBase; +}; + +struct RemoteEntityCfg { + explicit RemoteEntityCfg(EntityId id) : remoteId(std::move(id)) {} + EntityId remoteId; + size_t maxFileSegmentLen = 2048; + bool closureRequested = false; + bool crcOnTransmission = false; + TransmissionMode defaultTransmissionMode = TransmissionMode::UNACKNOWLEDGED; + ChecksumType defaultChecksum = ChecksumType::NULL_CHECKSUM; + const uint8_t version = CFDP_VERSION_2; +}; + +} // namespace cfdp + +#endif // FSFW_CFDP_MIB_H diff --git a/src/fsfw/cfdp/helpers.cpp b/src/fsfw/cfdp/helpers.cpp new file mode 100644 index 00000000..fdb7d5ff --- /dev/null +++ b/src/fsfw/cfdp/helpers.cpp @@ -0,0 +1,50 @@ +#include "helpers.h" + +const char* COND_CODE_STRINGS[14] = {"Unknown", + "No Error", + "Positive ACK Limit Reached", + "Keep Alive Limit Reached", + "Invalid Transmission Mode", + "Filestore Rejection", + "File Checksum Failure", + "File Size Error", + "NAK limit reached", + "Inactivity Detected", + "Check Limit Reached", + "Unsupported Checksum Type", + "Suspend Request Received", + "Cancel Request Received"}; + +const char* cfdp::getConditionCodeString(cfdp::ConditionCode code) { + switch (code) { + case NO_CONDITION_FIELD: + return COND_CODE_STRINGS[0]; + case NO_ERROR: + return COND_CODE_STRINGS[1]; + case POSITIVE_ACK_LIMIT_REACHED: + return COND_CODE_STRINGS[2]; + case KEEP_ALIVE_LIMIT_REACHED: + return COND_CODE_STRINGS[3]; + case INVALID_TRANSMISSION_MODE: + return COND_CODE_STRINGS[4]; + case FILESTORE_REJECTION: + return COND_CODE_STRINGS[5]; + case FILE_CHECKSUM_FAILURE: + return COND_CODE_STRINGS[6]; + case FILE_SIZE_ERROR: + return COND_CODE_STRINGS[7]; + case NAK_LIMIT_REACHED: + return COND_CODE_STRINGS[8]; + case INACTIVITY_DETECTED: + return COND_CODE_STRINGS[9]; + case CHECK_LIMIT_REACHED: + return COND_CODE_STRINGS[10]; + case UNSUPPORTED_CHECKSUM_TYPE: + return COND_CODE_STRINGS[11]; + case SUSPEND_REQUEST_RECEIVED: + return COND_CODE_STRINGS[12]; + case CANCEL_REQUEST_RECEIVED: + return COND_CODE_STRINGS[13]; + } + return "Unknown"; +} diff --git a/src/fsfw/cfdp/helpers.h b/src/fsfw/cfdp/helpers.h new file mode 100644 index 00000000..37428108 --- /dev/null +++ b/src/fsfw/cfdp/helpers.h @@ -0,0 +1,11 @@ +#ifndef FSFW_EXAMPLE_HOSTED_HELPER_H +#define FSFW_EXAMPLE_HOSTED_HELPER_H + +#include "definitions.h" + +namespace cfdp { + +const char* getConditionCodeString(cfdp::ConditionCode code); + +} +#endif // FSFW_EXAMPLE_HOSTED_HELPER_H diff --git a/src/fsfw/cfdp/pdu/AckInfo.cpp b/src/fsfw/cfdp/pdu/AckInfo.cpp index f35cfbb1..963f7cbb 100644 --- a/src/fsfw/cfdp/pdu/AckInfo.cpp +++ b/src/fsfw/cfdp/pdu/AckInfo.cpp @@ -1,12 +1,12 @@ #include "AckInfo.h" -AckInfo::AckInfo(cfdp::FileDirectives ackedDirective, cfdp::ConditionCode ackedConditionCode, +AckInfo::AckInfo(cfdp::FileDirective ackedDirective, cfdp::ConditionCode ackedConditionCode, cfdp::AckTransactionStatus transactionStatus, uint8_t directiveSubtypeCode) : ackedDirective(ackedDirective), ackedConditionCode(ackedConditionCode), transactionStatus(transactionStatus), directiveSubtypeCode(directiveSubtypeCode) { - if (ackedDirective == cfdp::FileDirectives::FINISH) { + if (ackedDirective == cfdp::FileDirective::FINISH) { this->directiveSubtypeCode = 0b0001; } else { this->directiveSubtypeCode = 0b0000; @@ -17,16 +17,16 @@ cfdp::ConditionCode AckInfo::getAckedConditionCode() const { return ackedConditi void AckInfo::setAckedConditionCode(cfdp::ConditionCode ackedConditionCode) { this->ackedConditionCode = ackedConditionCode; - if (ackedDirective == cfdp::FileDirectives::FINISH) { + if (ackedDirective == cfdp::FileDirective::FINISH) { this->directiveSubtypeCode = 0b0001; } else { this->directiveSubtypeCode = 0b0000; } } -cfdp::FileDirectives AckInfo::getAckedDirective() const { return ackedDirective; } +cfdp::FileDirective AckInfo::getAckedDirective() const { return ackedDirective; } -void AckInfo::setAckedDirective(cfdp::FileDirectives ackedDirective) { +void AckInfo::setAckedDirective(cfdp::FileDirective ackedDirective) { this->ackedDirective = ackedDirective; } diff --git a/src/fsfw/cfdp/pdu/AckInfo.h b/src/fsfw/cfdp/pdu/AckInfo.h index 572fc59f..23e4d6ab 100644 --- a/src/fsfw/cfdp/pdu/AckInfo.h +++ b/src/fsfw/cfdp/pdu/AckInfo.h @@ -6,14 +6,14 @@ class AckInfo { public: AckInfo(); - AckInfo(cfdp::FileDirectives ackedDirective, cfdp::ConditionCode ackedConditionCode, + AckInfo(cfdp::FileDirective ackedDirective, cfdp::ConditionCode ackedConditionCode, cfdp::AckTransactionStatus transactionStatus, uint8_t directiveSubtypeCode = 0); cfdp::ConditionCode getAckedConditionCode() const; void setAckedConditionCode(cfdp::ConditionCode ackedConditionCode); - cfdp::FileDirectives getAckedDirective() const; - void setAckedDirective(cfdp::FileDirectives ackedDirective); + cfdp::FileDirective getAckedDirective() const; + void setAckedDirective(cfdp::FileDirective ackedDirective); uint8_t getDirectiveSubtypeCode() const; void setDirectiveSubtypeCode(uint8_t directiveSubtypeCode); @@ -22,7 +22,7 @@ class AckInfo { void setTransactionStatus(cfdp::AckTransactionStatus transactionStatus); private: - cfdp::FileDirectives ackedDirective = cfdp::FileDirectives::INVALID_DIRECTIVE; + cfdp::FileDirective ackedDirective = cfdp::FileDirective::INVALID_DIRECTIVE; cfdp::ConditionCode ackedConditionCode = cfdp::ConditionCode::NO_CONDITION_FIELD; cfdp::AckTransactionStatus transactionStatus = cfdp::AckTransactionStatus::UNDEFINED; uint8_t directiveSubtypeCode = 0; diff --git a/src/fsfw/cfdp/pdu/AckPduCreator.cpp b/src/fsfw/cfdp/pdu/AckPduCreator.cpp new file mode 100644 index 00000000..f7623e57 --- /dev/null +++ b/src/fsfw/cfdp/pdu/AckPduCreator.cpp @@ -0,0 +1,33 @@ +#include "AckPduCreator.h" + +AckPduCreator::AckPduCreator(AckInfo &ackInfo, PduConfig &pduConf) + : FileDirectiveCreator(pduConf, cfdp::FileDirective::ACK, 2), ackInfo(ackInfo) {} + +size_t AckPduCreator::getSerializedSize() const { return FileDirectiveCreator::getWholePduSize(); } + +ReturnValue_t AckPduCreator::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + ReturnValue_t result = FileDirectiveCreator::serialize(buffer, size, maxSize, streamEndianness); + if (result != returnvalue::OK) { + return result; + } + cfdp::FileDirective ackedDirective = ackInfo.getAckedDirective(); + uint8_t directiveSubtypeCode = ackInfo.getDirectiveSubtypeCode(); + cfdp::ConditionCode ackedConditionCode = ackInfo.getAckedConditionCode(); + cfdp::AckTransactionStatus transactionStatus = ackInfo.getTransactionStatus(); + if (ackedDirective != cfdp::FileDirective::FINISH and + ackedDirective != cfdp::FileDirective::EOF_DIRECTIVE) { + // TODO: better returncode + return returnvalue::FAILED; + } + if (*size + 2 > maxSize) { + return SerializeIF::BUFFER_TOO_SHORT; + } + **buffer = ackedDirective << 4 | directiveSubtypeCode; + *buffer += 1; + *size += 1; + **buffer = ackedConditionCode << 4 | transactionStatus; + *buffer += 1; + *size += 1; + return returnvalue::OK; +} diff --git a/src/fsfw/cfdp/pdu/AckPduSerializer.h b/src/fsfw/cfdp/pdu/AckPduCreator.h similarity index 53% rename from src/fsfw/cfdp/pdu/AckPduSerializer.h rename to src/fsfw/cfdp/pdu/AckPduCreator.h index 68a049e2..c0a89cc3 100644 --- a/src/fsfw/cfdp/pdu/AckPduSerializer.h +++ b/src/fsfw/cfdp/pdu/AckPduCreator.h @@ -1,11 +1,11 @@ -#ifndef FSFW_SRC_FSFW_CFDP_PDU_ACKPDUSERIALIZER_H_ -#define FSFW_SRC_FSFW_CFDP_PDU_ACKPDUSERIALIZER_H_ +#ifndef FSFW_CFDP_PDU_ACKPDUSERIALIZER_H_ +#define FSFW_CFDP_PDU_ACKPDUSERIALIZER_H_ #include "AckInfo.h" -#include "FileDirectiveDeserializer.h" -#include "FileDirectiveSerializer.h" +#include "FileDirectiveCreator.h" +#include "FileDirectiveReader.h" -class AckPduSerializer : public FileDirectiveSerializer { +class AckPduCreator : public FileDirectiveCreator { public: /** * @brief Serializer to pack ACK PDUs @@ -16,9 +16,9 @@ class AckPduSerializer : public FileDirectiveSerializer { * @param transactionStatus * @param pduConf */ - AckPduSerializer(AckInfo& ackInfo, PduConfig& pduConf); + AckPduCreator(AckInfo& ackInfo, PduConfig& pduConf); - size_t getSerializedSize() const override; + [[nodiscard]] size_t getSerializedSize() const override; ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, Endianness streamEndianness) const override; @@ -27,4 +27,4 @@ class AckPduSerializer : public FileDirectiveSerializer { AckInfo& ackInfo; }; -#endif /* FSFW_SRC_FSFW_CFDP_PDU_ACKPDUSERIALIZER_H_ */ +#endif /* FSFW_CFDP_PDU_ACKPDUSERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/AckPduDeserializer.cpp b/src/fsfw/cfdp/pdu/AckPduDeserializer.cpp deleted file mode 100644 index 24357a38..00000000 --- a/src/fsfw/cfdp/pdu/AckPduDeserializer.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "AckPduDeserializer.h" - -AckPduDeserializer::AckPduDeserializer(const uint8_t* pduBuf, size_t maxSize, AckInfo& info) - : FileDirectiveDeserializer(pduBuf, maxSize), info(info) {} - -ReturnValue_t AckPduDeserializer::parseData() { - ReturnValue_t result = FileDirectiveDeserializer::parseData(); - if (result != returnvalue::OK) { - return result; - } - size_t currentIdx = FileDirectiveDeserializer::getHeaderSize(); - if (currentIdx + 2 > this->maxSize) { - return SerializeIF::BUFFER_TOO_SHORT; - } - if (not checkAndSetCodes(rawPtr[currentIdx], rawPtr[currentIdx + 1])) { - return cfdp::INVALID_ACK_DIRECTIVE_FIELDS; - } - return returnvalue::OK; -} - -bool AckPduDeserializer::checkAndSetCodes(uint8_t firstByte, uint8_t secondByte) { - uint8_t ackedDirective = static_cast(firstByte >> 4); - - if (ackedDirective != cfdp::FileDirectives::EOF_DIRECTIVE and - ackedDirective != cfdp::FileDirectives::FINISH) { - return false; - } - this->info.setAckedDirective(static_cast(ackedDirective)); - uint8_t directiveSubtypeCode = firstByte & 0x0f; - if (directiveSubtypeCode != 0b0000 and directiveSubtypeCode != 0b0001) { - return false; - } - this->info.setDirectiveSubtypeCode(directiveSubtypeCode); - this->info.setAckedConditionCode(static_cast(secondByte >> 4)); - this->info.setTransactionStatus(static_cast(secondByte & 0x0f)); - return true; -} diff --git a/src/fsfw/cfdp/pdu/AckPduReader.cpp b/src/fsfw/cfdp/pdu/AckPduReader.cpp new file mode 100644 index 00000000..7204ced0 --- /dev/null +++ b/src/fsfw/cfdp/pdu/AckPduReader.cpp @@ -0,0 +1,45 @@ +#include "AckPduReader.h" + +AckPduReader::AckPduReader(const uint8_t* pduBuf, size_t maxSize, AckInfo& info) + : FileDirectiveReader(pduBuf, maxSize), info(info) {} + +ReturnValue_t AckPduReader::parseData() { + ReturnValue_t result = FileDirectiveReader::parseData(); + if (result != returnvalue::OK) { + return result; + } + size_t currentIdx = FileDirectiveReader::getHeaderSize(); + if (currentIdx + 2 > this->maxSize) { + return SerializeIF::BUFFER_TOO_SHORT; + } + if (not checkAndSetCodes(pointers.rawPtr[currentIdx], pointers.rawPtr[currentIdx + 1])) { + return cfdp::INVALID_ACK_DIRECTIVE_FIELDS; + } + return returnvalue::OK; +} + +bool AckPduReader::checkAndSetCodes(uint8_t firstByte, uint8_t secondByte) { + cfdp::FileDirective directive; + if (not checkAckedDirectiveField(firstByte, directive)) { + return false; + } + this->info.setAckedDirective(directive); + uint8_t directiveSubtypeCode = firstByte & 0x0f; + if (directiveSubtypeCode != 0b0000 and directiveSubtypeCode != 0b0001) { + return false; + } + this->info.setDirectiveSubtypeCode(directiveSubtypeCode); + this->info.setAckedConditionCode(static_cast(secondByte >> 4)); + this->info.setTransactionStatus(static_cast(secondByte & 0x0f)); + return true; +} +bool AckPduReader::checkAckedDirectiveField(uint8_t firstPduDataByte, + cfdp::FileDirective& ackedDirective) { + uint8_t ackedDirectiveRaw = static_cast(firstPduDataByte >> 4); + if (ackedDirectiveRaw != cfdp::FileDirective::EOF_DIRECTIVE and + ackedDirectiveRaw != cfdp::FileDirective::FINISH) { + return false; + } + ackedDirective = (static_cast(ackedDirectiveRaw)); + return true; +} diff --git a/src/fsfw/cfdp/pdu/AckPduDeserializer.h b/src/fsfw/cfdp/pdu/AckPduReader.h similarity index 52% rename from src/fsfw/cfdp/pdu/AckPduDeserializer.h rename to src/fsfw/cfdp/pdu/AckPduReader.h index 0bb95071..8f8b515b 100644 --- a/src/fsfw/cfdp/pdu/AckPduDeserializer.h +++ b/src/fsfw/cfdp/pdu/AckPduReader.h @@ -2,18 +2,21 @@ #define FSFW_SRC_FSFW_CFDP_PDU_ACKPDUDESERIALIZER_H_ #include "AckInfo.h" -#include "fsfw/cfdp/pdu/FileDirectiveDeserializer.h" +#include "fsfw/cfdp/pdu/FileDirectiveReader.h" -class AckPduDeserializer : public FileDirectiveDeserializer { +class AckPduReader : public FileDirectiveReader { public: - AckPduDeserializer(const uint8_t* pduBuf, size_t maxSize, AckInfo& info); + AckPduReader(const uint8_t* pduBuf, size_t maxSize, AckInfo& info); /** * * @return * - cfdp::INVALID_DIRECTIVE_FIELDS: Invalid fields */ - ReturnValue_t parseData(); + ReturnValue_t parseData() override; + + static bool checkAckedDirectiveField(uint8_t firstPduDataByte, + cfdp::FileDirective& ackedDirective); private: bool checkAndSetCodes(uint8_t rawAckedByte, uint8_t rawAckedConditionCode); diff --git a/src/fsfw/cfdp/pdu/AckPduSerializer.cpp b/src/fsfw/cfdp/pdu/AckPduSerializer.cpp deleted file mode 100644 index b06f4f00..00000000 --- a/src/fsfw/cfdp/pdu/AckPduSerializer.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "AckPduSerializer.h" - -AckPduSerializer::AckPduSerializer(AckInfo &ackInfo, PduConfig &pduConf) - : FileDirectiveSerializer(pduConf, cfdp::FileDirectives::ACK, 2), ackInfo(ackInfo) {} - -size_t AckPduSerializer::getSerializedSize() const { - return FileDirectiveSerializer::getWholePduSize(); -} - -ReturnValue_t AckPduSerializer::serialize(uint8_t **buffer, size_t *size, size_t maxSize, - Endianness streamEndianness) const { - ReturnValue_t result = - FileDirectiveSerializer::serialize(buffer, size, maxSize, streamEndianness); - if (result != returnvalue::OK) { - return result; - } - cfdp::FileDirectives ackedDirective = ackInfo.getAckedDirective(); - uint8_t directiveSubtypeCode = ackInfo.getDirectiveSubtypeCode(); - cfdp::ConditionCode ackedConditionCode = ackInfo.getAckedConditionCode(); - cfdp::AckTransactionStatus transactionStatus = ackInfo.getTransactionStatus(); - if (ackedDirective != cfdp::FileDirectives::FINISH and - ackedDirective != cfdp::FileDirectives::EOF_DIRECTIVE) { - // TODO: better returncode - return returnvalue::FAILED; - } - if (*size + 2 > maxSize) { - return SerializeIF::BUFFER_TOO_SHORT; - } - **buffer = ackedDirective << 4 | directiveSubtypeCode; - *buffer += 1; - *size += 1; - **buffer = ackedConditionCode << 4 | transactionStatus; - *buffer += 1; - *size += 1; - return returnvalue::OK; -} diff --git a/src/fsfw/cfdp/pdu/CMakeLists.txt b/src/fsfw/cfdp/pdu/CMakeLists.txt index 4f345bdc..c08a4b29 100644 --- a/src/fsfw/cfdp/pdu/CMakeLists.txt +++ b/src/fsfw/cfdp/pdu/CMakeLists.txt @@ -1,30 +1,29 @@ target_sources( ${LIB_FSFW_NAME} PRIVATE PduConfig.cpp - VarLenField.cpp - HeaderSerializer.cpp - HeaderDeserializer.cpp - FileDirectiveDeserializer.cpp - FileDirectiveSerializer.cpp + HeaderCreator.cpp + HeaderReader.cpp + FileDirectiveReader.cpp + FileDirectiveCreator.cpp AckInfo.cpp - AckPduSerializer.cpp - AckPduDeserializer.cpp + AckPduCreator.cpp + AckPduReader.cpp EofInfo.cpp - EofPduSerializer.cpp - EofPduDeserializer.cpp + EofPduCreator.cpp + EofPduReader.cpp NakInfo.cpp - NakPduSerializer.cpp - NakPduDeserializer.cpp + NakPduCreator.cpp + NakPduReader.cpp FinishedInfo.cpp - FinishedPduSerializer.cpp - FinishedPduDeserializer.cpp + FinishedPduCreator.cpp + FinishedPduReader.cpp MetadataInfo.cpp - MetadataPduSerializer.cpp - MetadataPduDeserializer.cpp - KeepAlivePduSerializer.cpp - KeepAlivePduDeserializer.cpp - PromptPduSerializer.cpp - PromptPduDeserializer.cpp - FileDataSerializer.cpp - FileDataDeserializer.cpp + MetadataPduCreator.cpp + MetadataPduReader.cpp + KeepAlivePduCreator.cpp + KeepAlivePduReader.cpp + PromptPduCreator.cpp + PromptPduReader.cpp + FileDataCreator.cpp + FileDataReader.cpp FileDataInfo.cpp) diff --git a/src/fsfw/cfdp/pdu/EofInfo.h b/src/fsfw/cfdp/pdu/EofInfo.h index fa8adfd9..4b4fb057 100644 --- a/src/fsfw/cfdp/pdu/EofInfo.h +++ b/src/fsfw/cfdp/pdu/EofInfo.h @@ -7,16 +7,16 @@ struct EofInfo { public: - EofInfo(EntityIdTlv* faultLoc = nullptr); + explicit EofInfo(EntityIdTlv* faultLoc = nullptr); EofInfo(cfdp::ConditionCode conditionCode, uint32_t checksum, cfdp::FileSize fileSize, EntityIdTlv* faultLoc = nullptr); size_t getSerializedSize(bool fssLarge = false); - uint32_t getChecksum() const; - cfdp::ConditionCode getConditionCode() const; + [[nodiscard]] uint32_t getChecksum() const; + [[nodiscard]] cfdp::ConditionCode getConditionCode() const; - EntityIdTlv* getFaultLoc() const; + [[nodiscard]] EntityIdTlv* getFaultLoc() const; cfdp::FileSize& getFileSize(); void setChecksum(uint32_t checksum); void setConditionCode(cfdp::ConditionCode conditionCode); diff --git a/src/fsfw/cfdp/pdu/EofPduSerializer.cpp b/src/fsfw/cfdp/pdu/EofPduCreator.cpp similarity index 59% rename from src/fsfw/cfdp/pdu/EofPduSerializer.cpp rename to src/fsfw/cfdp/pdu/EofPduCreator.cpp index aafd332e..12a3e696 100644 --- a/src/fsfw/cfdp/pdu/EofPduSerializer.cpp +++ b/src/fsfw/cfdp/pdu/EofPduCreator.cpp @@ -1,21 +1,17 @@ -#include "EofPduSerializer.h" +#include "EofPduCreator.h" #include "fsfw/FSFW.h" -#include "fsfw/serviceinterface.h" -EofPduSerializer::EofPduSerializer(PduConfig &conf, EofInfo &info) - : FileDirectiveSerializer(conf, cfdp::FileDirectives::EOF_DIRECTIVE, 9), info(info) { - setDirectiveDataFieldLen(info.getSerializedSize(getLargeFileFlag())); +EofPduCreator::EofPduCreator(PduConfig &conf, EofInfo &info) + : FileDirectiveCreator(conf, cfdp::FileDirective::EOF_DIRECTIVE, 9), info(info) { + setDirectiveDataFieldLen(info.getSerializedSize(HeaderCreator::getLargeFileFlag())); } -size_t EofPduSerializer::getSerializedSize() const { - return FileDirectiveSerializer::getWholePduSize(); -} +size_t EofPduCreator::getSerializedSize() const { return FileDirectiveCreator::getWholePduSize(); } -ReturnValue_t EofPduSerializer::serialize(uint8_t **buffer, size_t *size, size_t maxSize, - Endianness streamEndianness) const { - ReturnValue_t result = - FileDirectiveSerializer::serialize(buffer, size, maxSize, streamEndianness); +ReturnValue_t EofPduCreator::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + ReturnValue_t result = FileDirectiveCreator::serialize(buffer, size, maxSize, streamEndianness); if (result != returnvalue::OK) { return result; } diff --git a/src/fsfw/cfdp/pdu/EofPduSerializer.h b/src/fsfw/cfdp/pdu/EofPduCreator.h similarity index 62% rename from src/fsfw/cfdp/pdu/EofPduSerializer.h rename to src/fsfw/cfdp/pdu/EofPduCreator.h index fbdcfe67..f098a5d2 100644 --- a/src/fsfw/cfdp/pdu/EofPduSerializer.h +++ b/src/fsfw/cfdp/pdu/EofPduCreator.h @@ -2,18 +2,20 @@ #define FSFW_SRC_FSFW_CFDP_PDU_EOFPDUSERIALIZER_H_ #include "EofInfo.h" -#include "fsfw/cfdp/pdu/FileDirectiveSerializer.h" +#include "fsfw/cfdp/pdu/FileDirectiveCreator.h" #include "fsfw/cfdp/tlv/EntityIdTlv.h" -class EofPduSerializer : public FileDirectiveSerializer { +class EofPduCreator : public FileDirectiveCreator { public: - EofPduSerializer(PduConfig& conf, EofInfo& info); + EofPduCreator(PduConfig& conf, EofInfo& info); - size_t getSerializedSize() const override; + [[nodiscard]] size_t getSerializedSize() const override; ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, Endianness streamEndianness) const override; + using FileDirectiveCreator::serialize; + private: EofInfo& info; }; diff --git a/src/fsfw/cfdp/pdu/EofPduDeserializer.h b/src/fsfw/cfdp/pdu/EofPduDeserializer.h deleted file mode 100644 index 8f62b25a..00000000 --- a/src/fsfw/cfdp/pdu/EofPduDeserializer.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef FSFW_SRC_FSFW_CFDP_PDU_EOFPDUDESERIALIZER_H_ -#define FSFW_SRC_FSFW_CFDP_PDU_EOFPDUDESERIALIZER_H_ - -#include "EofInfo.h" -#include "fsfw/cfdp/pdu/FileDirectiveDeserializer.h" - -class EofPduDeserializer : public FileDirectiveDeserializer { - public: - EofPduDeserializer(const uint8_t* pduBuf, size_t maxSize, EofInfo& eofInfo); - - virtual ReturnValue_t parseData() override; - - private: - EofInfo& info; -}; - -#endif /* FSFW_SRC_FSFW_CFDP_PDU_EOFPDUDESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/EofPduDeserializer.cpp b/src/fsfw/cfdp/pdu/EofPduReader.cpp similarity index 82% rename from src/fsfw/cfdp/pdu/EofPduDeserializer.cpp rename to src/fsfw/cfdp/pdu/EofPduReader.cpp index 1a70e225..c80c501c 100644 --- a/src/fsfw/cfdp/pdu/EofPduDeserializer.cpp +++ b/src/fsfw/cfdp/pdu/EofPduReader.cpp @@ -1,23 +1,23 @@ -#include "EofPduDeserializer.h" +#include "EofPduReader.h" #include "fsfw/FSFW.h" #include "fsfw/serviceinterface.h" -EofPduDeserializer::EofPduDeserializer(const uint8_t* pduBuf, size_t maxSize, EofInfo& eofInfo) - : FileDirectiveDeserializer(pduBuf, maxSize), info(eofInfo) {} +EofPduReader::EofPduReader(const uint8_t* pduBuf, size_t maxSize, EofInfo& eofInfo) + : FileDirectiveReader(pduBuf, maxSize), info(eofInfo) {} -ReturnValue_t EofPduDeserializer::parseData() { - ReturnValue_t result = FileDirectiveDeserializer::parseData(); +ReturnValue_t EofPduReader::parseData() { + ReturnValue_t result = FileDirectiveReader::parseData(); if (result != returnvalue::OK) { return result; } - const uint8_t* bufPtr = rawPtr; + const uint8_t* bufPtr = pointers.rawPtr; size_t expectedFileFieldLen = 4; if (this->getLargeFileFlag()) { expectedFileFieldLen = 8; } - size_t currentIdx = FileDirectiveDeserializer::getHeaderSize(); + size_t currentIdx = FileDirectiveReader::getHeaderSize(); size_t deserLen = maxSize; if (maxSize < currentIdx + 5 + expectedFileFieldLen) { return SerializeIF::STREAM_TOO_SHORT; diff --git a/src/fsfw/cfdp/pdu/EofPduReader.h b/src/fsfw/cfdp/pdu/EofPduReader.h new file mode 100644 index 00000000..456ea0dc --- /dev/null +++ b/src/fsfw/cfdp/pdu/EofPduReader.h @@ -0,0 +1,17 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_EOFPDUDESERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_EOFPDUDESERIALIZER_H_ + +#include "EofInfo.h" +#include "fsfw/cfdp/pdu/FileDirectiveReader.h" + +class EofPduReader : public FileDirectiveReader { + public: + EofPduReader(const uint8_t* pduBuf, size_t maxSize, EofInfo& eofInfo); + + ReturnValue_t parseData() override; + + private: + EofInfo& info; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_EOFPDUDESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/FileDataSerializer.cpp b/src/fsfw/cfdp/pdu/FileDataCreator.cpp similarity index 61% rename from src/fsfw/cfdp/pdu/FileDataSerializer.cpp rename to src/fsfw/cfdp/pdu/FileDataCreator.cpp index bdc2d42f..956752fb 100644 --- a/src/fsfw/cfdp/pdu/FileDataSerializer.cpp +++ b/src/fsfw/cfdp/pdu/FileDataCreator.cpp @@ -1,28 +1,31 @@ -#include "FileDataSerializer.h" +#include "FileDataCreator.h" #include -FileDataSerializer::FileDataSerializer(PduConfig& conf, FileDataInfo& info) - : HeaderSerializer(conf, cfdp::PduType::FILE_DATA, 0, info.getSegmentMetadataFlag()), - info(info) { +FileDataCreator::FileDataCreator(PduConfig& conf, FileDataInfo& info) + : HeaderCreator(conf, cfdp::PduType::FILE_DATA, 0, info.getSegmentMetadataFlag()), info(info) { update(); } -void FileDataSerializer::update() { +void FileDataCreator::update() { this->setSegmentMetadataFlag(info.getSegmentMetadataFlag()); this->setSegmentationControl(info.getSegmentationControl()); setPduDataFieldLen(info.getSerializedSize(this->getLargeFileFlag())); } -ReturnValue_t FileDataSerializer::serialize(uint8_t** buffer, size_t* size, size_t maxSize, - Endianness streamEndianness) const { - ReturnValue_t result = HeaderSerializer::serialize(buffer, size, maxSize, streamEndianness); +ReturnValue_t FileDataCreator::serialize(uint8_t** buffer, size_t* size, size_t maxSize, + Endianness streamEndianness) const { + if (buffer == nullptr or size == nullptr) { + return returnvalue::FAILED; + } + if (*size + getSerializedSize() > maxSize) { + return SerializeIF::BUFFER_TOO_SHORT; + } + ReturnValue_t result = HeaderCreator::serialize(buffer, size, maxSize, streamEndianness); if (result != returnvalue::OK) { return result; } - if (*size + this->getSerializedSize() > maxSize) { - return SerializeIF::BUFFER_TOO_SHORT; - } + const uint8_t* readOnlyPtr = nullptr; if (this->hasSegmentMetadataFlag()) { size_t segmentMetadataLen = info.getSegmentMetadataLen(); @@ -50,6 +53,6 @@ ReturnValue_t FileDataSerializer::serialize(uint8_t** buffer, size_t* size, size return returnvalue::OK; } -size_t FileDataSerializer::getSerializedSize() const { - return HeaderSerializer::getSerializedSize() + info.getSerializedSize(this->getLargeFileFlag()); +size_t FileDataCreator::getSerializedSize() const { + return HeaderCreator::getSerializedSize() + info.getSerializedSize(this->getLargeFileFlag()); } diff --git a/src/fsfw/cfdp/pdu/FileDataCreator.h b/src/fsfw/cfdp/pdu/FileDataCreator.h new file mode 100644 index 00000000..2ce8989d --- /dev/null +++ b/src/fsfw/cfdp/pdu/FileDataCreator.h @@ -0,0 +1,27 @@ +#ifndef FSFW_CFDP_PDU_FILEDATASERIALIZER_H_ +#define FSFW_CFDP_PDU_FILEDATASERIALIZER_H_ + +#include "../definitions.h" +#include "FileDataInfo.h" +#include "HeaderCreator.h" + +class FileDataCreator : public HeaderCreator { + public: + FileDataCreator(PduConfig& conf, FileDataInfo& info); + + void update(); + + ReturnValue_t serialize(uint8_t* buf, size_t& serLen, size_t maxSize) const { + return SerializeIF::serialize(buf, serLen, maxSize, SerializeIF::Endianness::NETWORK); + } + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + Endianness streamEndianness) const override; + + [[nodiscard]] size_t getSerializedSize() const override; + + private: + FileDataInfo& info; +}; + +#endif /* FSFW_CFDP_PDU_FILEDATASERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/FileDataInfo.cpp b/src/fsfw/cfdp/pdu/FileDataInfo.cpp index 39b6472d..19fc00cd 100644 --- a/src/fsfw/cfdp/pdu/FileDataInfo.cpp +++ b/src/fsfw/cfdp/pdu/FileDataInfo.cpp @@ -57,16 +57,16 @@ ReturnValue_t FileDataInfo::addSegmentMetadataInfo(cfdp::RecordContinuationState return returnvalue::OK; } -const uint8_t *FileDataInfo::getFileData(size_t *fileSize) const { - if (fileSize != nullptr) { - *fileSize = this->fileSize; +const uint8_t *FileDataInfo::getFileData(size_t *fileSize_) const { + if (fileSize_ != nullptr) { + *fileSize_ = this->fileSize; } return fileData; } -const uint8_t *FileDataInfo::getSegmentMetadata(size_t *segmentMetadataLen) { - if (segmentMetadataLen != nullptr) { - *segmentMetadataLen = this->segmentMetadataLen; +const uint8_t *FileDataInfo::getSegmentMetadata(size_t *segmentMetadataLen_) { + if (segmentMetadataLen_ != nullptr) { + *segmentMetadataLen_ = this->segmentMetadataLen; } return segmentMetadata; } diff --git a/src/fsfw/cfdp/pdu/FileDataInfo.h b/src/fsfw/cfdp/pdu/FileDataInfo.h index 7fd573db..36908d8b 100644 --- a/src/fsfw/cfdp/pdu/FileDataInfo.h +++ b/src/fsfw/cfdp/pdu/FileDataInfo.h @@ -6,25 +6,25 @@ class FileDataInfo { public: - FileDataInfo(cfdp::FileSize& offset); + explicit FileDataInfo(cfdp::FileSize& offset); FileDataInfo(cfdp::FileSize& offset, const uint8_t* fileData, size_t fileSize); - size_t getSerializedSize(bool largeFile = false) const; + [[nodiscard]] size_t getSerializedSize(bool largeFile = false) const; cfdp::FileSize& getOffset(); const uint8_t* getFileData(size_t* fileSize = nullptr) const; void setFileData(const uint8_t* fileData, size_t fileSize); - cfdp::SegmentMetadataFlag getSegmentMetadataFlag() const; - cfdp::SegmentationControl getSegmentationControl() const; - cfdp::RecordContinuationState getRecordContinuationState() const; + [[nodiscard]] cfdp::SegmentMetadataFlag getSegmentMetadataFlag() const; + [[nodiscard]] cfdp::SegmentationControl getSegmentationControl() const; + [[nodiscard]] cfdp::RecordContinuationState getRecordContinuationState() const; void setRecordContinuationState(cfdp::RecordContinuationState recContState); void setSegmentationControl(cfdp::SegmentationControl segCtrl); - size_t getSegmentMetadataLen() const; + [[nodiscard]] size_t getSegmentMetadataLen() const; void setSegmentMetadataLen(size_t len); void setSegmentMetadata(const uint8_t* ptr); - bool hasSegmentMetadata() const; + [[nodiscard]] bool hasSegmentMetadata() const; void setSegmentMetadataFlag(bool enable); ReturnValue_t addSegmentMetadataInfo(cfdp::RecordContinuationState recContState, const uint8_t* segmentMetadata, size_t segmentMetadataLen); diff --git a/src/fsfw/cfdp/pdu/FileDataDeserializer.cpp b/src/fsfw/cfdp/pdu/FileDataReader.cpp similarity index 55% rename from src/fsfw/cfdp/pdu/FileDataDeserializer.cpp rename to src/fsfw/cfdp/pdu/FileDataReader.cpp index 274f8b8a..9155ef28 100644 --- a/src/fsfw/cfdp/pdu/FileDataDeserializer.cpp +++ b/src/fsfw/cfdp/pdu/FileDataReader.cpp @@ -1,17 +1,16 @@ -#include "FileDataDeserializer.h" +#include "FileDataReader.h" -FileDataDeserializer::FileDataDeserializer(const uint8_t* pduBuf, size_t maxSize, - FileDataInfo& info) - : HeaderDeserializer(pduBuf, maxSize), info(info) {} +FileDataReader::FileDataReader(const uint8_t* pduBuf, size_t maxSize, FileDataInfo& info) + : PduHeaderReader(pduBuf, maxSize), info(info) {} -ReturnValue_t FileDataDeserializer::parseData() { - ReturnValue_t result = HeaderDeserializer::parseData(); +ReturnValue_t FileDataReader::parseData() { + ReturnValue_t result = PduHeaderReader::parseData(); if (result != returnvalue::OK) { return result; } - size_t currentIdx = HeaderDeserializer::getHeaderSize(); - const uint8_t* buf = rawPtr + currentIdx; - size_t remSize = HeaderDeserializer::getWholePduSize() - currentIdx; + size_t currentIdx = PduHeaderReader::getHeaderSize(); + const uint8_t* buf = pointers.rawPtr + currentIdx; + size_t remSize = PduHeaderReader::getWholePduSize() - currentIdx; if (remSize < 1) { return SerializeIF::STREAM_TOO_SHORT; } @@ -41,8 +40,8 @@ ReturnValue_t FileDataDeserializer::parseData() { return returnvalue::OK; } -SerializeIF::Endianness FileDataDeserializer::getEndianness() const { return endianness; } +SerializeIF::Endianness FileDataReader::getEndianness() const { return endianness; } -void FileDataDeserializer::setEndianness(SerializeIF::Endianness endianness) { - this->endianness = endianness; +void FileDataReader::setEndianness(SerializeIF::Endianness endianness_) { + endianness = endianness_; } diff --git a/src/fsfw/cfdp/pdu/FileDataDeserializer.h b/src/fsfw/cfdp/pdu/FileDataReader.h similarity index 63% rename from src/fsfw/cfdp/pdu/FileDataDeserializer.h rename to src/fsfw/cfdp/pdu/FileDataReader.h index 833c0561..aa962e2b 100644 --- a/src/fsfw/cfdp/pdu/FileDataDeserializer.h +++ b/src/fsfw/cfdp/pdu/FileDataReader.h @@ -3,14 +3,14 @@ #include "../definitions.h" #include "FileDataInfo.h" -#include "HeaderDeserializer.h" +#include "PduHeaderReader.h" -class FileDataDeserializer : public HeaderDeserializer { +class FileDataReader : public PduHeaderReader { public: - FileDataDeserializer(const uint8_t* pduBuf, size_t maxSize, FileDataInfo& info); + FileDataReader(const uint8_t* pduBuf, size_t maxSize, FileDataInfo& info); - ReturnValue_t parseData(); - SerializeIF::Endianness getEndianness() const; + ReturnValue_t parseData() override; + [[nodiscard]] SerializeIF::Endianness getEndianness() const; void setEndianness(SerializeIF::Endianness endianness = SerializeIF::Endianness::NETWORK); private: diff --git a/src/fsfw/cfdp/pdu/FileDataSerializer.h b/src/fsfw/cfdp/pdu/FileDataSerializer.h deleted file mode 100644 index 662b9b4d..00000000 --- a/src/fsfw/cfdp/pdu/FileDataSerializer.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef FSFW_SRC_FSFW_CFDP_PDU_FILEDATASERIALIZER_H_ -#define FSFW_SRC_FSFW_CFDP_PDU_FILEDATASERIALIZER_H_ - -#include "../definitions.h" -#include "FileDataInfo.h" -#include "HeaderSerializer.h" - -class FileDataSerializer : public HeaderSerializer { - public: - FileDataSerializer(PduConfig& conf, FileDataInfo& info); - - void update(); - - ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, - Endianness streamEndianness) const override; - - size_t getSerializedSize() const override; - - private: - FileDataInfo& info; -}; - -#endif /* FSFW_SRC_FSFW_CFDP_PDU_FILEDATADESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/FileDirectiveCreator.cpp b/src/fsfw/cfdp/pdu/FileDirectiveCreator.cpp new file mode 100644 index 00000000..20f93df9 --- /dev/null +++ b/src/fsfw/cfdp/pdu/FileDirectiveCreator.cpp @@ -0,0 +1,39 @@ +#include "FileDirectiveCreator.h" + +FileDirectiveCreator::FileDirectiveCreator(PduConfig &pduConf, cfdp::FileDirective directiveCode, + size_t directiveParamFieldLen) + : HeaderCreator(pduConf, cfdp::PduType::FILE_DIRECTIVE, directiveParamFieldLen + 1), + directiveCode(directiveCode) {} + +size_t FileDirectiveCreator::getSerializedSize() const { + return HeaderCreator::getSerializedSize() + 1; +} + +ReturnValue_t FileDirectiveCreator::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + if (buffer == nullptr or size == nullptr) { + return returnvalue::FAILED; + } + if (FileDirectiveCreator::getWholePduSize() > maxSize) { + return BUFFER_TOO_SHORT; + } + ReturnValue_t result = HeaderCreator::serialize(buffer, size, maxSize, streamEndianness); + if (result != returnvalue::OK) { + return result; + } + + if (*size >= maxSize) { + return BUFFER_TOO_SHORT; + } + **buffer = directiveCode; + *buffer += 1; + *size += 1; + return returnvalue::OK; +} + +void FileDirectiveCreator::setDirectiveDataFieldLen(size_t len) { + // Set length of data field plus 1 byte for the directive octet + HeaderCreator::setPduDataFieldLen(len + 1); +} + +cfdp::FileDirective FileDirectiveCreator::getDirectiveCode() const { return directiveCode; } diff --git a/src/fsfw/cfdp/pdu/FileDirectiveCreator.h b/src/fsfw/cfdp/pdu/FileDirectiveCreator.h new file mode 100644 index 00000000..9b7f2f52 --- /dev/null +++ b/src/fsfw/cfdp/pdu/FileDirectiveCreator.h @@ -0,0 +1,34 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_FILEDIRECTIVESERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_FILEDIRECTIVESERIALIZER_H_ + +#include "fsfw/cfdp/pdu/HeaderCreator.h" + +class FileDirectiveCreator : public HeaderCreator { + public: + FileDirectiveCreator(PduConfig& pduConf, cfdp::FileDirective directiveCode, + size_t directiveParamFieldLen); + + [[nodiscard]] cfdp::FileDirective getDirectiveCode() const; + + /** + * This only returns the size of the PDU header + 1 for the directive code octet. + * Use FileDirectiveCreator::getWholePduSize to get the full packet length, assuming + * the length fields was set correctly + * @return + */ + [[nodiscard]] size_t getSerializedSize() const override; + + [[nodiscard]] ReturnValue_t serialize(uint8_t* buffer, size_t& serLen, size_t maxSize) const { + return SerializeIF::serialize(buffer, serLen, maxSize, SerializeIF::Endianness::NETWORK); + } + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + Endianness streamEndianness) const override; + + void setDirectiveDataFieldLen(size_t len); + + private: + cfdp::FileDirective directiveCode = cfdp::FileDirective::INVALID_DIRECTIVE; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_FILEDIRECTIVESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/FileDirectiveDeserializer.cpp b/src/fsfw/cfdp/pdu/FileDirectiveDeserializer.cpp deleted file mode 100644 index 9d2a1e0a..00000000 --- a/src/fsfw/cfdp/pdu/FileDirectiveDeserializer.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "FileDirectiveDeserializer.h" - -FileDirectiveDeserializer::FileDirectiveDeserializer(const uint8_t *pduBuf, size_t maxSize) - : HeaderDeserializer(pduBuf, maxSize) {} - -cfdp::FileDirectives FileDirectiveDeserializer::getFileDirective() const { return fileDirective; } - -ReturnValue_t FileDirectiveDeserializer::parseData() { - ReturnValue_t result = HeaderDeserializer::parseData(); - if (result != returnvalue::OK) { - return result; - } - if (this->getPduDataFieldLen() < 1) { - return cfdp::INVALID_PDU_DATAFIELD_LEN; - } - if (FileDirectiveDeserializer::getWholePduSize() > maxSize) { - return SerializeIF::STREAM_TOO_SHORT; - } - size_t currentIdx = HeaderDeserializer::getHeaderSize(); - if (not checkFileDirective(rawPtr[currentIdx])) { - return cfdp::INVALID_DIRECTIVE_FIELDS; - } - setFileDirective(static_cast(rawPtr[currentIdx])); - return returnvalue::OK; -} - -size_t FileDirectiveDeserializer::getHeaderSize() const { - // return size of header plus the directive byte - return HeaderDeserializer::getHeaderSize() + 1; -} - -bool FileDirectiveDeserializer::checkFileDirective(uint8_t rawByte) { - if (rawByte < cfdp::FileDirectives::EOF_DIRECTIVE or - (rawByte > cfdp::FileDirectives::PROMPT and rawByte != cfdp::FileDirectives::KEEP_ALIVE)) { - // Invalid directive field. TODO: Custom returnvalue - return false; - } - return true; -} - -void FileDirectiveDeserializer::setFileDirective(cfdp::FileDirectives fileDirective) { - this->fileDirective = fileDirective; -} - -void FileDirectiveDeserializer::setEndianness(SerializeIF::Endianness endianness) { - this->endianness = endianness; -} - -SerializeIF::Endianness FileDirectiveDeserializer::getEndianness() const { return endianness; } diff --git a/src/fsfw/cfdp/pdu/FileDirectiveReader.cpp b/src/fsfw/cfdp/pdu/FileDirectiveReader.cpp new file mode 100644 index 00000000..f5fc6e58 --- /dev/null +++ b/src/fsfw/cfdp/pdu/FileDirectiveReader.cpp @@ -0,0 +1,49 @@ +#include "FileDirectiveReader.h" + +FileDirectiveReader::FileDirectiveReader(const uint8_t *pduBuf, size_t maxSize) + : PduHeaderReader(pduBuf, maxSize) {} + +cfdp::FileDirective FileDirectiveReader::getFileDirective() const { return fileDirective; } + +ReturnValue_t FileDirectiveReader::parseData() { + ReturnValue_t result = PduHeaderReader::parseData(); + if (result != returnvalue::OK) { + return result; + } + if (this->getPduDataFieldLen() < 1) { + return cfdp::INVALID_PDU_DATAFIELD_LEN; + } + if (FileDirectiveReader::getWholePduSize() > maxSize) { + return SerializeIF::STREAM_TOO_SHORT; + } + size_t currentIdx = PduHeaderReader::getHeaderSize(); + if (not checkFileDirective(pointers.rawPtr[currentIdx])) { + return cfdp::INVALID_DIRECTIVE_FIELD; + } + setFileDirective(static_cast(pointers.rawPtr[currentIdx])); + return returnvalue::OK; +} + +size_t FileDirectiveReader::getHeaderSize() const { + // return size of header plus the directive byte + return PduHeaderReader::getHeaderSize() + 1; +} + +bool FileDirectiveReader::checkFileDirective(uint8_t rawByte) { + if (rawByte < cfdp::FileDirective::EOF_DIRECTIVE or + (rawByte > cfdp::FileDirective::PROMPT and rawByte != cfdp::FileDirective::KEEP_ALIVE)) { + // Invalid directive field + return false; + } + return true; +} + +void FileDirectiveReader::setFileDirective(cfdp::FileDirective fileDirective_) { + fileDirective = fileDirective_; +} + +void FileDirectiveReader::setEndianness(SerializeIF::Endianness endianness_) { + endianness = endianness_; +} + +SerializeIF::Endianness FileDirectiveReader::getEndianness() const { return endianness; } diff --git a/src/fsfw/cfdp/pdu/FileDirectiveDeserializer.h b/src/fsfw/cfdp/pdu/FileDirectiveReader.h similarity index 57% rename from src/fsfw/cfdp/pdu/FileDirectiveDeserializer.h rename to src/fsfw/cfdp/pdu/FileDirectiveReader.h index 064cb64a..9e88e006 100644 --- a/src/fsfw/cfdp/pdu/FileDirectiveDeserializer.h +++ b/src/fsfw/cfdp/pdu/FileDirectiveReader.h @@ -2,7 +2,7 @@ #define FSFW_SRC_FSFW_CFDP_PDU_FILEDIRECTIVEDESERIALIZER_H_ #include "../definitions.h" -#include "fsfw/cfdp/pdu/HeaderDeserializer.h" +#include "fsfw/cfdp/pdu/PduHeaderReader.h" /** * @brief This class is used to deserialize a PDU file directive header from raw memory. @@ -11,28 +11,27 @@ * This is a zero-copy implementation and #parseData needs to be called to ensure the data is * valid. */ -class FileDirectiveDeserializer : public HeaderDeserializer { +class FileDirectiveReader : public PduHeaderReader { public: - FileDirectiveDeserializer(const uint8_t* pduBuf, size_t maxSize); + FileDirectiveReader(const uint8_t* pduBuf, size_t maxSize); /** * This needs to be called before accessing the PDU fields to avoid segmentation faults. * @return */ - virtual ReturnValue_t parseData(); - size_t getHeaderSize() const; + ReturnValue_t parseData() override; + [[nodiscard]] size_t getHeaderSize() const override; - cfdp::FileDirectives getFileDirective() const; + [[nodiscard]] cfdp::FileDirective getFileDirective() const; void setEndianness(SerializeIF::Endianness endianness); - SerializeIF::Endianness getEndianness() const; + [[nodiscard]] SerializeIF::Endianness getEndianness() const; + static bool checkFileDirective(uint8_t rawByte); protected: - bool checkFileDirective(uint8_t rawByte); - private: - void setFileDirective(cfdp::FileDirectives fileDirective); - cfdp::FileDirectives fileDirective = cfdp::FileDirectives::INVALID_DIRECTIVE; + void setFileDirective(cfdp::FileDirective fileDirective); + cfdp::FileDirective fileDirective = cfdp::FileDirective::INVALID_DIRECTIVE; SerializeIF::Endianness endianness = SerializeIF::Endianness::NETWORK; }; diff --git a/src/fsfw/cfdp/pdu/FileDirectiveSerializer.cpp b/src/fsfw/cfdp/pdu/FileDirectiveSerializer.cpp deleted file mode 100644 index 5845ba56..00000000 --- a/src/fsfw/cfdp/pdu/FileDirectiveSerializer.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "FileDirectiveSerializer.h" - -FileDirectiveSerializer::FileDirectiveSerializer(PduConfig &pduConf, - cfdp::FileDirectives directiveCode, - size_t directiveParamFieldLen) - : HeaderSerializer(pduConf, cfdp::PduType::FILE_DIRECTIVE, directiveParamFieldLen + 1), - directiveCode(directiveCode) {} - -size_t FileDirectiveSerializer::getSerializedSize() const { - return HeaderSerializer::getSerializedSize() + 1; -} - -ReturnValue_t FileDirectiveSerializer::serialize(uint8_t **buffer, size_t *size, size_t maxSize, - Endianness streamEndianness) const { - if (buffer == nullptr or size == nullptr) { - return returnvalue::FAILED; - } - if (FileDirectiveSerializer::getWholePduSize() > maxSize) { - return BUFFER_TOO_SHORT; - } - ReturnValue_t result = HeaderSerializer::serialize(buffer, size, maxSize, streamEndianness); - if (result != returnvalue::OK) { - return result; - } - - if (*size >= maxSize) { - return BUFFER_TOO_SHORT; - } - **buffer = directiveCode; - *buffer += 1; - *size += 1; - return returnvalue::OK; -} - -void FileDirectiveSerializer::setDirectiveDataFieldLen(size_t len) { - // Set length of data field plus 1 byte for the directive octet - HeaderSerializer::setPduDataFieldLen(len + 1); -} diff --git a/src/fsfw/cfdp/pdu/FileDirectiveSerializer.h b/src/fsfw/cfdp/pdu/FileDirectiveSerializer.h deleted file mode 100644 index 8f86a5e1..00000000 --- a/src/fsfw/cfdp/pdu/FileDirectiveSerializer.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef FSFW_SRC_FSFW_CFDP_PDU_FILEDIRECTIVESERIALIZER_H_ -#define FSFW_SRC_FSFW_CFDP_PDU_FILEDIRECTIVESERIALIZER_H_ - -#include "fsfw/cfdp/pdu/HeaderSerializer.h" - -class FileDirectiveSerializer : public HeaderSerializer { - public: - FileDirectiveSerializer(PduConfig& pduConf, cfdp::FileDirectives directiveCode, - size_t directiveParamFieldLen); - - /** - * This only returns the size of the PDU header + 1 for the directive code octet. - * Use FileDirectiveSerializer::getWholePduSize to get the full packet length, assuming - * the length fields was set correctly - * @return - */ - size_t getSerializedSize() const override; - - ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, - Endianness streamEndianness) const override; - - void setDirectiveDataFieldLen(size_t len); - - private: - cfdp::FileDirectives directiveCode = cfdp::FileDirectives::INVALID_DIRECTIVE; -}; - -#endif /* FSFW_SRC_FSFW_CFDP_PDU_FILEDIRECTIVESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/FinishedInfo.cpp b/src/fsfw/cfdp/pdu/FinishedInfo.cpp index ea4ffa89..2f986e85 100644 --- a/src/fsfw/cfdp/pdu/FinishedInfo.cpp +++ b/src/fsfw/cfdp/pdu/FinishedInfo.cpp @@ -2,9 +2,8 @@ FinishedInfo::FinishedInfo() {} -FinishedInfo::FinishedInfo(cfdp::ConditionCode conditionCode, - cfdp::FinishedDeliveryCode deliveryCode, - cfdp::FinishedFileStatus fileStatus) +FinishedInfo::FinishedInfo(cfdp::ConditionCode conditionCode, cfdp::FileDeliveryCode deliveryCode, + cfdp::FileDeliveryStatus fileStatus) : conditionCode(conditionCode), deliveryCode(deliveryCode), fileStatus(fileStatus) {} size_t FinishedInfo::getSerializedSize() const { @@ -83,13 +82,13 @@ void FinishedInfo::setConditionCode(cfdp::ConditionCode conditionCode) { this->conditionCode = conditionCode; } -cfdp::FinishedDeliveryCode FinishedInfo::getDeliveryCode() const { return deliveryCode; } +cfdp::FileDeliveryCode FinishedInfo::getDeliveryCode() const { return deliveryCode; } -void FinishedInfo::setDeliveryCode(cfdp::FinishedDeliveryCode deliveryCode) { +void FinishedInfo::setDeliveryCode(cfdp::FileDeliveryCode deliveryCode) { this->deliveryCode = deliveryCode; } -cfdp::FinishedFileStatus FinishedInfo::getFileStatus() const { return fileStatus; } +cfdp::FileDeliveryStatus FinishedInfo::getFileStatus() const { return fileStatus; } void FinishedInfo::setFilestoreResponsesArrayLen(size_t fsResponsesLen) { this->fsResponsesLen = fsResponsesLen; @@ -97,6 +96,6 @@ void FinishedInfo::setFilestoreResponsesArrayLen(size_t fsResponsesLen) { size_t FinishedInfo::getFsResponsesLen() const { return fsResponsesLen; } -void FinishedInfo::setFileStatus(cfdp::FinishedFileStatus fileStatus) { +void FinishedInfo::setFileStatus(cfdp::FileDeliveryStatus fileStatus) { this->fileStatus = fileStatus; } diff --git a/src/fsfw/cfdp/pdu/FinishedInfo.h b/src/fsfw/cfdp/pdu/FinishedInfo.h index 5768a298..49d7c64d 100644 --- a/src/fsfw/cfdp/pdu/FinishedInfo.h +++ b/src/fsfw/cfdp/pdu/FinishedInfo.h @@ -8,13 +8,13 @@ class FinishedInfo { public: FinishedInfo(); - FinishedInfo(cfdp::ConditionCode conditionCode, cfdp::FinishedDeliveryCode deliveryCode, - cfdp::FinishedFileStatus fileStatus); + FinishedInfo(cfdp::ConditionCode conditionCode, cfdp::FileDeliveryCode deliveryCode, + cfdp::FileDeliveryStatus fileStatus); - size_t getSerializedSize() const; + [[nodiscard]] size_t getSerializedSize() const; - bool hasFsResponses() const; - bool canHoldFsResponses() const; + [[nodiscard]] bool hasFsResponses() const; + [[nodiscard]] bool canHoldFsResponses() const; ReturnValue_t setFilestoreResponsesArray(FilestoreResponseTlv** fsResponses, size_t* fsResponsesLen, const size_t* maxFsResponseLen); @@ -22,20 +22,20 @@ class FinishedInfo { ReturnValue_t getFilestoreResonses(FilestoreResponseTlv*** fsResponses, size_t* fsResponsesLen, size_t* fsResponsesMaxLen); - size_t getFsResponsesLen() const; + [[nodiscard]] size_t getFsResponsesLen() const; void setFilestoreResponsesArrayLen(size_t fsResponsesLen); ReturnValue_t getFaultLocation(EntityIdTlv** entityId); - cfdp::ConditionCode getConditionCode() const; + [[nodiscard]] cfdp::ConditionCode getConditionCode() const; void setConditionCode(cfdp::ConditionCode conditionCode); - cfdp::FinishedDeliveryCode getDeliveryCode() const; - void setDeliveryCode(cfdp::FinishedDeliveryCode deliveryCode); - cfdp::FinishedFileStatus getFileStatus() const; - void setFileStatus(cfdp::FinishedFileStatus fileStatus); + [[nodiscard]] cfdp::FileDeliveryCode getDeliveryCode() const; + void setDeliveryCode(cfdp::FileDeliveryCode deliveryCode); + [[nodiscard]] cfdp::FileDeliveryStatus getFileStatus() const; + void setFileStatus(cfdp::FileDeliveryStatus fileStatus); private: cfdp::ConditionCode conditionCode = cfdp::ConditionCode::NO_CONDITION_FIELD; - cfdp::FinishedDeliveryCode deliveryCode = cfdp::FinishedDeliveryCode::DATA_COMPLETE; - cfdp::FinishedFileStatus fileStatus = cfdp::FinishedFileStatus::DISCARDED_DELIBERATELY; + cfdp::FileDeliveryCode deliveryCode = cfdp::FileDeliveryCode::DATA_COMPLETE; + cfdp::FileDeliveryStatus fileStatus = cfdp::FileDeliveryStatus::DISCARDED_DELIBERATELY; FilestoreResponseTlv** fsResponses = nullptr; size_t fsResponsesLen = 0; size_t fsResponsesMaxLen = 0; diff --git a/src/fsfw/cfdp/pdu/FinishedPduSerializer.cpp b/src/fsfw/cfdp/pdu/FinishedPduCreator.cpp similarity index 61% rename from src/fsfw/cfdp/pdu/FinishedPduSerializer.cpp rename to src/fsfw/cfdp/pdu/FinishedPduCreator.cpp index ccc86908..8ac22e0a 100644 --- a/src/fsfw/cfdp/pdu/FinishedPduSerializer.cpp +++ b/src/fsfw/cfdp/pdu/FinishedPduCreator.cpp @@ -1,22 +1,19 @@ -#include "FinishedPduSerializer.h" +#include "FinishedPduCreator.h" -FinishPduSerializer::FinishPduSerializer(PduConfig &conf, FinishedInfo &finishInfo) - : FileDirectiveSerializer(conf, cfdp::FileDirectives::FINISH, 0), finishInfo(finishInfo) { +FinishPduCreator::FinishPduCreator(PduConfig &conf, FinishedInfo &finishInfo) + : FileDirectiveCreator(conf, cfdp::FileDirective::FINISH, 0), finishInfo(finishInfo) { updateDirectiveFieldLen(); } -size_t FinishPduSerializer::getSerializedSize() const { - return FinishPduSerializer::getWholePduSize(); -} +size_t FinishPduCreator::getSerializedSize() const { return FinishPduCreator::getWholePduSize(); } -void FinishPduSerializer::updateDirectiveFieldLen() { +void FinishPduCreator::updateDirectiveFieldLen() { setDirectiveDataFieldLen(finishInfo.getSerializedSize()); } -ReturnValue_t FinishPduSerializer::serialize(uint8_t **buffer, size_t *size, size_t maxSize, - Endianness streamEndianness) const { - ReturnValue_t result = - FileDirectiveSerializer::serialize(buffer, size, maxSize, streamEndianness); +ReturnValue_t FinishPduCreator::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + ReturnValue_t result = FileDirectiveCreator::serialize(buffer, size, maxSize, streamEndianness); if (result != returnvalue::OK) { return result; } diff --git a/src/fsfw/cfdp/pdu/FinishedPduCreator.h b/src/fsfw/cfdp/pdu/FinishedPduCreator.h new file mode 100644 index 00000000..bef59ada --- /dev/null +++ b/src/fsfw/cfdp/pdu/FinishedPduCreator.h @@ -0,0 +1,24 @@ +#ifndef FSFW_CFDP_PDU_FINISHEDPDUSERIALIZER_H_ +#define FSFW_CFDP_PDU_FINISHEDPDUSERIALIZER_H_ + +#include "FinishedInfo.h" +#include "fsfw/cfdp/pdu/FileDataCreator.h" +#include "fsfw/cfdp/pdu/FileDirectiveCreator.h" + +class FinishPduCreator : public FileDirectiveCreator { + public: + FinishPduCreator(PduConfig& pduConf, FinishedInfo& finishInfo); + + void updateDirectiveFieldLen(); + + [[nodiscard]] size_t getSerializedSize() const override; + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + Endianness streamEndianness) const override; + using FileDirectiveCreator::serialize; + + private: + FinishedInfo& finishInfo; +}; + +#endif /* FSFW_CFDP_PDU_FINISHEDPDUSERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/FinishedPduDeserializer.h b/src/fsfw/cfdp/pdu/FinishedPduDeserializer.h deleted file mode 100644 index a34fc4cb..00000000 --- a/src/fsfw/cfdp/pdu/FinishedPduDeserializer.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef FSFW_SRC_FSFW_CFDP_PDU_FINISHEDPDUDESERIALIZER_H_ -#define FSFW_SRC_FSFW_CFDP_PDU_FINISHEDPDUDESERIALIZER_H_ - -#include "fsfw/cfdp/pdu/FileDirectiveDeserializer.h" -#include "fsfw/cfdp/pdu/FinishedInfo.h" - -class FinishPduDeserializer : public FileDirectiveDeserializer { - public: - FinishPduDeserializer(const uint8_t* pduBuf, size_t maxSize, FinishedInfo& info); - - ReturnValue_t parseData() override; - - FinishedInfo& getInfo(); - - private: - FinishedInfo& finishedInfo; - - ReturnValue_t parseTlvs(size_t remLen, size_t currentIdx, const uint8_t* buf, - cfdp::ConditionCode conditionCode); -}; - -#endif /* FSFW_SRC_FSFW_CFDP_PDU_FINISHEDPDUDESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/FinishedPduDeserializer.cpp b/src/fsfw/cfdp/pdu/FinishedPduReader.cpp similarity index 63% rename from src/fsfw/cfdp/pdu/FinishedPduDeserializer.cpp rename to src/fsfw/cfdp/pdu/FinishedPduReader.cpp index 7d16394e..08dd3a82 100644 --- a/src/fsfw/cfdp/pdu/FinishedPduDeserializer.cpp +++ b/src/fsfw/cfdp/pdu/FinishedPduReader.cpp @@ -1,25 +1,24 @@ -#include "FinishedPduDeserializer.h" +#include "FinishedPduReader.h" -FinishPduDeserializer::FinishPduDeserializer(const uint8_t* pduBuf, size_t maxSize, - FinishedInfo& info) - : FileDirectiveDeserializer(pduBuf, maxSize), finishedInfo(info) {} +FinishPduReader::FinishPduReader(const uint8_t* pduBuf, size_t maxSize, FinishedInfo& info) + : FileDirectiveReader(pduBuf, maxSize), finishedInfo(info) {} -ReturnValue_t FinishPduDeserializer::parseData() { - ReturnValue_t result = FileDirectiveDeserializer::parseData(); +ReturnValue_t FinishPduReader::parseData() { + ReturnValue_t result = FileDirectiveReader::parseData(); if (result != returnvalue::OK) { return result; } - size_t currentIdx = FileDirectiveDeserializer::getHeaderSize(); - const uint8_t* buf = rawPtr + currentIdx; - size_t remSize = FileDirectiveDeserializer::getWholePduSize() - currentIdx; + size_t currentIdx = FileDirectiveReader::getHeaderSize(); + const uint8_t* buf = pointers.rawPtr + currentIdx; + size_t remSize = FileDirectiveReader::getWholePduSize() - currentIdx; if (remSize < 1) { return SerializeIF::STREAM_TOO_SHORT; } uint8_t firstByte = *buf; - cfdp::ConditionCode condCode = static_cast((firstByte >> 4) & 0x0f); + auto condCode = static_cast((firstByte >> 4) & 0x0f); finishedInfo.setConditionCode(condCode); - finishedInfo.setDeliveryCode(static_cast(firstByte >> 2 & 0b1)); - finishedInfo.setFileStatus(static_cast(firstByte & 0b11)); + finishedInfo.setDeliveryCode(static_cast(firstByte >> 2 & 0b1)); + finishedInfo.setFileStatus(static_cast(firstByte & 0b11)); buf += 1; remSize -= 1; currentIdx += 1; @@ -29,17 +28,17 @@ ReturnValue_t FinishPduDeserializer::parseData() { return result; } -FinishedInfo& FinishPduDeserializer::getInfo() { return finishedInfo; } +FinishedInfo& FinishPduReader::getInfo() { return finishedInfo; } -ReturnValue_t FinishPduDeserializer::parseTlvs(size_t remLen, size_t currentIdx, const uint8_t* buf, - cfdp::ConditionCode conditionCode) { +ReturnValue_t FinishPduReader::parseTlvs(size_t remLen, size_t currentIdx, const uint8_t* buf, + cfdp::ConditionCode conditionCode) { ReturnValue_t result = returnvalue::OK; size_t fsResponsesIdx = 0; auto endianness = getEndianness(); FilestoreResponseTlv** fsResponseArray = nullptr; size_t fsResponseMaxArrayLen = 0; EntityIdTlv* faultLocation = nullptr; - cfdp::TlvTypes nextTlv = cfdp::TlvTypes::INVALID_TLV; + cfdp::TlvType nextTlv = cfdp::TlvType::INVALID_TLV; while (remLen > 0) { // Simply forward parse the TLV type. Every TLV type except the last one must be a Filestore // Response TLV, and even the last one can be a Filestore Response TLV if the fault @@ -47,8 +46,8 @@ ReturnValue_t FinishPduDeserializer::parseTlvs(size_t remLen, size_t currentIdx, if (currentIdx + 2 > maxSize) { return SerializeIF::STREAM_TOO_SHORT; } - nextTlv = static_cast(*buf); - if (nextTlv == cfdp::TlvTypes::FILESTORE_RESPONSE) { + nextTlv = static_cast(*buf); + if (nextTlv == cfdp::TlvType::FILESTORE_RESPONSE) { if (fsResponseArray == nullptr) { if (not finishedInfo.canHoldFsResponses()) { return cfdp::FINISHED_CANT_PARSE_FS_RESPONSES; @@ -64,7 +63,7 @@ ReturnValue_t FinishPduDeserializer::parseTlvs(size_t remLen, size_t currentIdx, return result; } fsResponsesIdx += 1; - } else if (nextTlv == cfdp::TlvTypes::ENTITY_ID) { + } else if (nextTlv == cfdp::TlvType::ENTITY_ID) { // This needs to be the last TLV and it should not be here if the condition code // is "No Error" or "Unsupported Checksum Type" if (conditionCode == cfdp::ConditionCode::NO_ERROR or diff --git a/src/fsfw/cfdp/pdu/FinishedPduReader.h b/src/fsfw/cfdp/pdu/FinishedPduReader.h new file mode 100644 index 00000000..791a2ef4 --- /dev/null +++ b/src/fsfw/cfdp/pdu/FinishedPduReader.h @@ -0,0 +1,22 @@ +#ifndef FSFW_CFDP_PDU_FINISHEDPDUDESERIALIZER_H_ +#define FSFW_CFDP_PDU_FINISHEDPDUDESERIALIZER_H_ + +#include "fsfw/cfdp/pdu/FileDirectiveReader.h" +#include "fsfw/cfdp/pdu/FinishedInfo.h" + +class FinishPduReader : public FileDirectiveReader { + public: + FinishPduReader(const uint8_t* pduBuf, size_t maxSize, FinishedInfo& info); + + ReturnValue_t parseData() override; + + FinishedInfo& getInfo(); + + private: + FinishedInfo& finishedInfo; + + ReturnValue_t parseTlvs(size_t remLen, size_t currentIdx, const uint8_t* buf, + cfdp::ConditionCode conditionCode); +}; + +#endif /* FSFW_CFDP_PDU_FINISHEDPDUDESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/FinishedPduSerializer.h b/src/fsfw/cfdp/pdu/FinishedPduSerializer.h deleted file mode 100644 index d66b25f2..00000000 --- a/src/fsfw/cfdp/pdu/FinishedPduSerializer.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef FSFW_SRC_FSFW_CFDP_PDU_FINISHEDPDUSERIALIZER_H_ -#define FSFW_SRC_FSFW_CFDP_PDU_FINISHEDPDUSERIALIZER_H_ - -#include "FinishedInfo.h" -#include "fsfw/cfdp/pdu/FileDataSerializer.h" -#include "fsfw/cfdp/pdu/FileDirectiveSerializer.h" - -class FinishPduSerializer : public FileDirectiveSerializer { - public: - FinishPduSerializer(PduConfig& pduConf, FinishedInfo& finishInfo); - - void updateDirectiveFieldLen(); - - size_t getSerializedSize() const override; - - ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, - Endianness streamEndianness) const override; - - private: - FinishedInfo& finishInfo; -}; - -#endif /* FSFW_SRC_FSFW_CFDP_PDU_FINISHEDPDUSERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/HeaderCreator.cpp b/src/fsfw/cfdp/pdu/HeaderCreator.cpp new file mode 100644 index 00000000..29688575 --- /dev/null +++ b/src/fsfw/cfdp/pdu/HeaderCreator.cpp @@ -0,0 +1,111 @@ +#include "HeaderCreator.h" + +HeaderCreator::HeaderCreator(PduConfig &pduConf, cfdp::PduType pduType, size_t initPduDataFieldLen, + cfdp::SegmentMetadataFlag segmentMetadataFlag, + cfdp::SegmentationControl segCtrl) + : pduType(pduType), + segmentMetadataFlag(segmentMetadataFlag), + segmentationCtrl(segCtrl), + pduDataFieldLen(initPduDataFieldLen), + pduConf(pduConf) {} + +ReturnValue_t HeaderCreator::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + if (buffer == nullptr or size == nullptr) { + return returnvalue::FAILED; + } + if (maxSize < this->getSerializedSize()) { + return BUFFER_TOO_SHORT; + } + **buffer = cfdp::VERSION_BITS | this->pduType << 4 | pduConf.direction << 3 | pduConf.mode << 2 | + pduConf.crcFlag << 1 | pduConf.largeFile; + *buffer += 1; + **buffer = (pduDataFieldLen & 0xff00) >> 8; + *buffer += 1; + **buffer = pduDataFieldLen & 0x00ff; + *buffer += 1; + **buffer = segmentationCtrl << 7 | pduConf.sourceId.getWidth() << 4 | segmentMetadataFlag << 3 | + pduConf.seqNum.getWidth(); + *buffer += 1; + *size += 4; + ReturnValue_t result = pduConf.sourceId.serialize(buffer, size, maxSize, streamEndianness); + if (result != returnvalue::OK) { + return result; + } + result = pduConf.seqNum.serialize(buffer, size, maxSize, streamEndianness); + if (result != returnvalue::OK) { + return result; + } + result = pduConf.destId.serialize(buffer, size, maxSize, streamEndianness); + if (result != returnvalue::OK) { + return result; + } + + return returnvalue::OK; +} + +size_t HeaderCreator::getSerializedSize() const { + return pduConf.seqNum.getWidth() + pduConf.sourceId.getWidth() * 2 + 4; +} + +ReturnValue_t HeaderCreator::deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) { + // We could implement this, but I prefer dedicated classes + return returnvalue::FAILED; +} + +size_t HeaderCreator::getWholePduSize() const { + // Return size of header plus the PDU data field length + return pduDataFieldLen + HeaderCreator::getSerializedSize(); +} + +size_t HeaderCreator::getPduDataFieldLen() const { return pduDataFieldLen; } + +void HeaderCreator::setPduDataFieldLen(size_t pduDataFieldLen_) { + pduDataFieldLen = pduDataFieldLen_; +} + +void HeaderCreator::setPduType(cfdp::PduType pduType_) { pduType = pduType_; } + +void HeaderCreator::setSegmentMetadataFlag(cfdp::SegmentMetadataFlag segmentMetadataFlag_) { + segmentMetadataFlag = segmentMetadataFlag_; +} + +cfdp::PduType HeaderCreator::getPduType() const { return pduType; } + +cfdp::Direction HeaderCreator::getDirection() const { return pduConf.direction; } + +cfdp::TransmissionMode HeaderCreator::getTransmissionMode() const { return pduConf.mode; } + +bool HeaderCreator::getCrcFlag() const { return pduConf.crcFlag; } + +bool HeaderCreator::getLargeFileFlag() const { return pduConf.largeFile; } + +cfdp::SegmentationControl HeaderCreator::getSegmentationControl() const { return segmentationCtrl; } + +cfdp::WidthInBytes HeaderCreator::getLenEntityIds() const { return pduConf.sourceId.getWidth(); } + +cfdp::WidthInBytes HeaderCreator::getLenSeqNum() const { return pduConf.seqNum.getWidth(); } + +cfdp::SegmentMetadataFlag HeaderCreator::getSegmentMetadataFlag() const { + return segmentMetadataFlag; +} + +void HeaderCreator::getSourceId(cfdp::EntityId &sourceId) const { sourceId = pduConf.sourceId; } + +void HeaderCreator::getDestId(cfdp::EntityId &destId) const { destId = pduConf.destId; } + +void HeaderCreator::setSegmentationControl(cfdp::SegmentationControl segmentationControl) { + this->segmentationCtrl = segmentationControl; +} + +void HeaderCreator::getTransactionSeqNum(cfdp::TransactionSeqNum &seqNum) const { + seqNum = pduConf.seqNum; +} + +bool HeaderCreator::hasSegmentMetadataFlag() const { + if (this->segmentMetadataFlag == cfdp::SegmentMetadataFlag::PRESENT) { + return true; + } + return false; +} diff --git a/src/fsfw/cfdp/pdu/HeaderSerializer.h b/src/fsfw/cfdp/pdu/HeaderCreator.h similarity index 63% rename from src/fsfw/cfdp/pdu/HeaderSerializer.h rename to src/fsfw/cfdp/pdu/HeaderCreator.h index 1de97d63..173a6239 100644 --- a/src/fsfw/cfdp/pdu/HeaderSerializer.h +++ b/src/fsfw/cfdp/pdu/HeaderCreator.h @@ -1,14 +1,14 @@ #ifndef FSFW_SRC_FSFW_CFDP_PDU_HEADERSERIALIZER_H_ #define FSFW_SRC_FSFW_CFDP_PDU_HEADERSERIALIZER_H_ -#include "../definitions.h" #include "PduConfig.h" #include "PduHeaderIF.h" +#include "fsfw/cfdp/definitions.h" #include "fsfw/serialize/SerializeIF.h" -class HeaderSerializer : public SerializeIF, public PduHeaderIF { +class HeaderCreator : public SerializeIF, public PduHeaderIF { public: - HeaderSerializer( + HeaderCreator( PduConfig& pduConf, cfdp::PduType pduType, size_t initPduDataFieldLen, cfdp::SegmentMetadataFlag segmentMetadataFlag = cfdp::SegmentMetadataFlag::NOT_PRESENT, cfdp::SegmentationControl segCtrl = @@ -23,7 +23,7 @@ class HeaderSerializer : public SerializeIF, public PduHeaderIF { * data field length was not properly. * @return */ - size_t getSerializedSize() const override; + [[nodiscard]] size_t getSerializedSize() const override; ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, Endianness streamEndianness) override; @@ -32,19 +32,19 @@ class HeaderSerializer : public SerializeIF, public PduHeaderIF { void setPduType(cfdp::PduType pduType); void setSegmentMetadataFlag(cfdp::SegmentMetadataFlag); - size_t getPduDataFieldLen() const override; - size_t getWholePduSize() const override; + [[nodiscard]] size_t getPduDataFieldLen() const override; + [[nodiscard]] size_t getWholePduSize() const override; - cfdp::PduType getPduType() const override; - cfdp::Direction getDirection() const override; - cfdp::TransmissionModes getTransmissionMode() const override; - bool getCrcFlag() const override; - bool getLargeFileFlag() const override; - cfdp::SegmentationControl getSegmentationControl() const override; - cfdp::WidthInBytes getLenEntityIds() const override; - cfdp::WidthInBytes getLenSeqNum() const override; - cfdp::SegmentMetadataFlag getSegmentMetadataFlag() const override; - bool hasSegmentMetadataFlag() const override; + [[nodiscard]] cfdp::PduType getPduType() const override; + [[nodiscard]] cfdp::Direction getDirection() const override; + [[nodiscard]] cfdp::TransmissionMode getTransmissionMode() const override; + [[nodiscard]] bool getCrcFlag() const override; + [[nodiscard]] bool getLargeFileFlag() const override; + [[nodiscard]] cfdp::SegmentationControl getSegmentationControl() const override; + [[nodiscard]] cfdp::WidthInBytes getLenEntityIds() const override; + [[nodiscard]] cfdp::WidthInBytes getLenSeqNum() const override; + [[nodiscard]] cfdp::SegmentMetadataFlag getSegmentMetadataFlag() const override; + [[nodiscard]] bool hasSegmentMetadataFlag() const override; void setSegmentationControl(cfdp::SegmentationControl); void getSourceId(cfdp::EntityId& sourceId) const override; diff --git a/src/fsfw/cfdp/pdu/HeaderDeserializer.cpp b/src/fsfw/cfdp/pdu/HeaderDeserializer.cpp deleted file mode 100644 index 2dbfed27..00000000 --- a/src/fsfw/cfdp/pdu/HeaderDeserializer.cpp +++ /dev/null @@ -1,128 +0,0 @@ -#include "HeaderDeserializer.h" - -#include - -#include - -HeaderDeserializer::HeaderDeserializer(const uint8_t *pduBuf, size_t maxSize) - : rawPtr(pduBuf), maxSize(maxSize) {} - -ReturnValue_t HeaderDeserializer::parseData() { - if (maxSize < 7) { - return SerializeIF::STREAM_TOO_SHORT; - } - return setData(const_cast(rawPtr), maxSize); -} - -ReturnValue_t HeaderDeserializer::setData(uint8_t *dataPtr, size_t maxSize, void *args) { - if (dataPtr == nullptr) { - // Allowed for now - this->fixedHeader = nullptr; - return returnvalue::OK; - } - this->fixedHeader = reinterpret_cast(const_cast(dataPtr)); - sourceIdRaw = static_cast(&fixedHeader->variableFieldsStart); - cfdp::WidthInBytes widthEntityIds = getLenEntityIds(); - cfdp::WidthInBytes widthSeqNum = getLenSeqNum(); - seqNumRaw = static_cast(sourceIdRaw) + static_cast(widthEntityIds); - destIdRaw = static_cast(seqNumRaw) + static_cast(widthSeqNum); - this->maxSize = maxSize; - return returnvalue::OK; -} - -size_t HeaderDeserializer::getHeaderSize() const { - if (fixedHeader != nullptr) { - return getLenEntityIds() * 2 + getLenSeqNum() + 4; - } - return 0; -} - -size_t HeaderDeserializer::getPduDataFieldLen() const { - uint16_t pduFiedlLen = (fixedHeader->pduDataFieldLenH << 8) | fixedHeader->pduDataFieldLenL; - return pduFiedlLen; -} - -size_t HeaderDeserializer::getWholePduSize() const { - return getPduDataFieldLen() + getHeaderSize(); -} - -cfdp::PduType HeaderDeserializer::getPduType() const { - return static_cast((fixedHeader->firstByte >> 4) & 0x01); -} - -cfdp::Direction HeaderDeserializer::getDirection() const { - return static_cast((fixedHeader->firstByte >> 3) & 0x01); -} - -cfdp::TransmissionModes HeaderDeserializer::getTransmissionMode() const { - return static_cast((fixedHeader->firstByte >> 2) & 0x01); -} - -bool HeaderDeserializer::getCrcFlag() const { return (fixedHeader->firstByte >> 1) & 0x01; } - -bool HeaderDeserializer::getLargeFileFlag() const { return fixedHeader->firstByte & 0x01; } - -cfdp::SegmentationControl HeaderDeserializer::getSegmentationControl() const { - return static_cast((fixedHeader->fourthByte >> 7) & 0x01); -} - -cfdp::WidthInBytes HeaderDeserializer::getLenEntityIds() const { - return static_cast((fixedHeader->fourthByte >> 4) & 0x07); -} - -cfdp::WidthInBytes HeaderDeserializer::getLenSeqNum() const { - return static_cast(fixedHeader->fourthByte & 0x07); -} - -cfdp::SegmentMetadataFlag HeaderDeserializer::getSegmentMetadataFlag() const { - return static_cast((fixedHeader->fourthByte >> 3) & 0x01); -} - -void HeaderDeserializer::getSourceId(cfdp::EntityId &sourceId) const { - assignVarLenField(dynamic_cast(&sourceId), getLenEntityIds(), - this->sourceIdRaw); -} - -void HeaderDeserializer::getDestId(cfdp::EntityId &destId) const { - assignVarLenField(dynamic_cast(&destId), getLenEntityIds(), this->destIdRaw); -} - -void HeaderDeserializer::getTransactionSeqNum(cfdp::TransactionSeqNum &seqNum) const { - assignVarLenField(dynamic_cast(&seqNum), getLenSeqNum(), this->seqNumRaw); -} - -void HeaderDeserializer::assignVarLenField(cfdp::VarLenField *field, cfdp::WidthInBytes width, - void *sourcePtr) const { - switch (width) { - case (cfdp::WidthInBytes::ONE_BYTE): { - uint8_t *fieldTyped = static_cast(sourcePtr); - field->setValue(width, *fieldTyped); - break; - } - case (cfdp::WidthInBytes::TWO_BYTES): { - uint16_t fieldTyped = 0; - size_t deserSize = 0; - SerializeAdapter::deSerialize(&fieldTyped, static_cast(sourcePtr), &deserSize, - SerializeIF::Endianness::NETWORK); - field->setValue(width, fieldTyped); - break; - } - case (cfdp::WidthInBytes::FOUR_BYTES): { - uint32_t fieldTyped = 0; - size_t deserSize = 0; - SerializeAdapter::deSerialize(&fieldTyped, static_cast(sourcePtr), &deserSize, - SerializeIF::Endianness::NETWORK); - field->setValue(width, fieldTyped); - break; - } - } -} - -size_t HeaderDeserializer::getMaxSize() const { return maxSize; } - -bool HeaderDeserializer::hasSegmentMetadataFlag() const { - if (this->getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::PRESENT) { - return true; - } - return false; -} diff --git a/src/fsfw/cfdp/pdu/HeaderReader.cpp b/src/fsfw/cfdp/pdu/HeaderReader.cpp new file mode 100644 index 00000000..9edf2394 --- /dev/null +++ b/src/fsfw/cfdp/pdu/HeaderReader.cpp @@ -0,0 +1,160 @@ +#include + +#include + +#include "PduHeaderReader.h" + +PduHeaderReader::PduHeaderReader(const uint8_t *pduBuf, size_t maxSize) { + setReadOnlyData(pduBuf, maxSize); +} + +ReturnValue_t PduHeaderReader::parseData() { + if (pointers.rawPtr == nullptr) { + return returnvalue::FAILED; + } + if (maxSize < 7) { + return SerializeIF::STREAM_TOO_SHORT; + } + pointers.fixedHeader = + reinterpret_cast(const_cast(pointers.rawPtr)); + sourceIdRaw = static_cast(&pointers.fixedHeader->variableFieldsStart); + cfdp::WidthInBytes widthEntityIds = getLenEntityIds(); + cfdp::WidthInBytes widthSeqNum = getLenSeqNum(); + seqNumRaw = static_cast(sourceIdRaw) + static_cast(widthEntityIds); + destIdRaw = static_cast(seqNumRaw) + static_cast(widthSeqNum); + if (getWholePduSize() > PduHeaderReader::getHeaderSize()) { + pointers.dataFieldStart = reinterpret_cast(destIdRaw) + widthEntityIds; + } else { + pointers.dataFieldStart = nullptr; + } + return returnvalue::OK; +} + +ReturnValue_t PduHeaderReader::setData(uint8_t *dataPtr, size_t maxSize_, void *args) { + if (dataPtr == nullptr) { + return returnvalue::FAILED; + } + if (maxSize_ < 7) { + return SerializeIF::STREAM_TOO_SHORT; + } + pointers.rawPtr = dataPtr; + maxSize = maxSize_; + return returnvalue::OK; +} + +size_t PduHeaderReader::getHeaderSize() const { + if (pointers.fixedHeader != nullptr) { + return getLenEntityIds() * 2 + getLenSeqNum() + 4; + } + return 0; +} + +size_t PduHeaderReader::getPduDataFieldLen() const { + return (pointers.fixedHeader->pduDataFieldLenH << 8) | pointers.fixedHeader->pduDataFieldLenL; +} + +size_t PduHeaderReader::getWholePduSize() const { + return getPduDataFieldLen() + PduHeaderReader::getHeaderSize(); +} + +cfdp::PduType PduHeaderReader::getPduType() const { + return static_cast((pointers.fixedHeader->firstByte >> 4) & 0x01); +} + +cfdp::Direction PduHeaderReader::getDirection() const { + return static_cast((pointers.fixedHeader->firstByte >> 3) & 0x01); +} + +cfdp::TransmissionMode PduHeaderReader::getTransmissionMode() const { + return static_cast((pointers.fixedHeader->firstByte >> 2) & 0x01); +} + +bool PduHeaderReader::getCrcFlag() const { return (pointers.fixedHeader->firstByte >> 1) & 0x01; } + +bool PduHeaderReader::getLargeFileFlag() const { return pointers.fixedHeader->firstByte & 0x01; } + +cfdp::SegmentationControl PduHeaderReader::getSegmentationControl() const { + return static_cast((pointers.fixedHeader->fourthByte >> 7) & 0x01); +} + +cfdp::WidthInBytes PduHeaderReader::getLenEntityIds() const { + return static_cast((pointers.fixedHeader->fourthByte >> 4) & 0x07); +} + +cfdp::WidthInBytes PduHeaderReader::getLenSeqNum() const { + return static_cast(pointers.fixedHeader->fourthByte & 0x07); +} + +cfdp::SegmentMetadataFlag PduHeaderReader::getSegmentMetadataFlag() const { + return static_cast((pointers.fixedHeader->fourthByte >> 3) & 0x01); +} + +void PduHeaderReader::getSourceId(cfdp::EntityId &sourceId) const { + assignVarLenField(dynamic_cast(&sourceId), getLenEntityIds(), + this->sourceIdRaw); +} + +void PduHeaderReader::getDestId(cfdp::EntityId &destId) const { + assignVarLenField(dynamic_cast(&destId), getLenEntityIds(), this->destIdRaw); +} + +void PduHeaderReader::getTransactionSeqNum(cfdp::TransactionSeqNum &seqNum) const { + assignVarLenField(dynamic_cast(&seqNum), getLenSeqNum(), this->seqNumRaw); +} + +void PduHeaderReader::assignVarLenField(cfdp::VarLenField *field, cfdp::WidthInBytes width, + void *sourcePtr) const { + switch (width) { + case (cfdp::WidthInBytes::ONE_BYTE): { + auto *fieldTyped = static_cast(sourcePtr); + field->setValue(width, *fieldTyped); + break; + } + case (cfdp::WidthInBytes::TWO_BYTES): { + uint16_t fieldTyped = 0; + size_t deserSize = 0; + SerializeAdapter::deSerialize(&fieldTyped, static_cast(sourcePtr), &deserSize, + SerializeIF::Endianness::NETWORK); + field->setValue(width, fieldTyped); + break; + } + case (cfdp::WidthInBytes::FOUR_BYTES): { + uint32_t fieldTyped = 0; + size_t deserSize = 0; + SerializeAdapter::deSerialize(&fieldTyped, static_cast(sourcePtr), &deserSize, + SerializeIF::Endianness::NETWORK); + field->setValue(width, fieldTyped); + break; + } + } +} + +size_t PduHeaderReader::getMaxSize() const { return maxSize; } + +bool PduHeaderReader::hasSegmentMetadataFlag() const { + if (this->getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::PRESENT) { + return true; + } + return false; +} + +ReturnValue_t PduHeaderReader::setReadOnlyData(const uint8_t *dataPtr, size_t maxSize_) { + return setData(const_cast(dataPtr), maxSize_, nullptr); +} +bool PduHeaderReader::isNull() const { + return pointers.rawPtr == nullptr or pointers.fixedHeader == nullptr; +} + +PduHeaderReader::operator bool() const { return not isNull(); } + +void PduHeaderReader::fillConfig(PduConfig &cfg) const { + cfg.largeFile = getLargeFileFlag(); + cfg.crcFlag = getCrcFlag(); + cfg.mode = getTransmissionMode(); + cfg.direction = getDirection(); + getTransactionSeqNum(cfg.seqNum); + getSourceId(cfg.sourceId); + getDestId(cfg.destId); +} + +const uint8_t *PduHeaderReader::getPduDataField() const { return pointers.dataFieldStart; } diff --git a/src/fsfw/cfdp/pdu/HeaderSerializer.cpp b/src/fsfw/cfdp/pdu/HeaderSerializer.cpp deleted file mode 100644 index 5721ad69..00000000 --- a/src/fsfw/cfdp/pdu/HeaderSerializer.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include "HeaderSerializer.h" - -#include "HeaderDeserializer.h" - -HeaderSerializer::HeaderSerializer(PduConfig &pduConf, cfdp::PduType pduType, - size_t initPduDataFieldLen, - cfdp::SegmentMetadataFlag segmentMetadataFlag, - cfdp::SegmentationControl segCtrl) - : pduType(pduType), - segmentMetadataFlag(segmentMetadataFlag), - segmentationCtrl(segCtrl), - pduDataFieldLen(initPduDataFieldLen), - pduConf(pduConf) {} - -ReturnValue_t HeaderSerializer::serialize(uint8_t **buffer, size_t *size, size_t maxSize, - Endianness streamEndianness) const { - if (buffer == nullptr or size == nullptr) { - return returnvalue::FAILED; - } - if (maxSize < this->getSerializedSize()) { - return BUFFER_TOO_SHORT; - } - **buffer = cfdp::VERSION_BITS | this->pduType << 4 | pduConf.direction << 3 | pduConf.mode << 2 | - pduConf.crcFlag << 1 | pduConf.largeFile; - *buffer += 1; - **buffer = (pduDataFieldLen & 0xff00) >> 8; - *buffer += 1; - **buffer = pduDataFieldLen & 0x00ff; - *buffer += 1; - **buffer = segmentationCtrl << 7 | pduConf.sourceId.getWidth() << 4 | segmentMetadataFlag << 3 | - pduConf.seqNum.getWidth(); - *buffer += 1; - *size += 4; - ReturnValue_t result = pduConf.sourceId.serialize(buffer, size, maxSize, streamEndianness); - if (result != returnvalue::OK) { - return result; - } - result = pduConf.seqNum.serialize(buffer, size, maxSize, streamEndianness); - if (result != returnvalue::OK) { - return result; - } - result = pduConf.destId.serialize(buffer, size, maxSize, streamEndianness); - if (result != returnvalue::OK) { - return result; - } - - return returnvalue::OK; -} - -size_t HeaderSerializer::getSerializedSize() const { - size_t shit = pduConf.seqNum.getWidth() + pduConf.sourceId.getWidth() * 2 + 4; - return shit; -} - -ReturnValue_t HeaderSerializer::deSerialize(const uint8_t **buffer, size_t *size, - Endianness streamEndianness) { - // We could implement this, but I prefer dedicated classes - return returnvalue::FAILED; -} - -size_t HeaderSerializer::getWholePduSize() const { - // Return size of header plus the PDU data field length - return pduDataFieldLen + HeaderSerializer::getSerializedSize(); -} - -size_t HeaderSerializer::getPduDataFieldLen() const { return pduDataFieldLen; } - -void HeaderSerializer::setPduDataFieldLen(size_t pduDataFieldLen) { - this->pduDataFieldLen = pduDataFieldLen; -} - -void HeaderSerializer::setPduType(cfdp::PduType pduType) { this->pduType = pduType; } - -void HeaderSerializer::setSegmentMetadataFlag(cfdp::SegmentMetadataFlag segmentMetadataFlag) { - this->segmentMetadataFlag = segmentMetadataFlag; -} - -cfdp::PduType HeaderSerializer::getPduType() const { return pduType; } - -cfdp::Direction HeaderSerializer::getDirection() const { return pduConf.direction; } - -cfdp::TransmissionModes HeaderSerializer::getTransmissionMode() const { return pduConf.mode; } - -bool HeaderSerializer::getCrcFlag() const { return pduConf.crcFlag; } - -bool HeaderSerializer::getLargeFileFlag() const { return pduConf.largeFile; } - -cfdp::SegmentationControl HeaderSerializer::getSegmentationControl() const { - return segmentationCtrl; -} - -cfdp::WidthInBytes HeaderSerializer::getLenEntityIds() const { return pduConf.sourceId.getWidth(); } - -cfdp::WidthInBytes HeaderSerializer::getLenSeqNum() const { return pduConf.seqNum.getWidth(); } - -cfdp::SegmentMetadataFlag HeaderSerializer::getSegmentMetadataFlag() const { - return segmentMetadataFlag; -} - -void HeaderSerializer::getSourceId(cfdp::EntityId &sourceId) const { sourceId = pduConf.sourceId; } - -void HeaderSerializer::getDestId(cfdp::EntityId &destId) const { destId = pduConf.destId; } - -void HeaderSerializer::setSegmentationControl(cfdp::SegmentationControl segmentationControl) { - this->segmentationCtrl = segmentationControl; -} - -void HeaderSerializer::getTransactionSeqNum(cfdp::TransactionSeqNum &seqNum) const { - seqNum = pduConf.seqNum; -} - -bool HeaderSerializer::hasSegmentMetadataFlag() const { - if (this->segmentMetadataFlag == cfdp::SegmentMetadataFlag::PRESENT) { - return true; - } - return false; -} diff --git a/src/fsfw/cfdp/pdu/KeepAlivePduCreator.cpp b/src/fsfw/cfdp/pdu/KeepAlivePduCreator.cpp new file mode 100644 index 00000000..40747751 --- /dev/null +++ b/src/fsfw/cfdp/pdu/KeepAlivePduCreator.cpp @@ -0,0 +1,25 @@ +#include "KeepAlivePduCreator.h" + +KeepAlivePduCreator::KeepAlivePduCreator(PduConfig &conf, cfdp::FileSize &progress) + : FileDirectiveCreator(conf, cfdp::FileDirective::KEEP_ALIVE, 4), progress(progress) { + updateDirectiveFieldLen(); +} + +size_t KeepAlivePduCreator::getSerializedSize() const { + return FileDirectiveCreator::getWholePduSize(); +} + +void KeepAlivePduCreator::updateDirectiveFieldLen() { + if (this->getLargeFileFlag()) { + this->setDirectiveDataFieldLen(8); + } +} + +ReturnValue_t KeepAlivePduCreator::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + ReturnValue_t result = FileDirectiveCreator::serialize(buffer, size, maxSize, streamEndianness); + if (result != returnvalue::OK) { + return result; + } + return progress.serialize(this->getLargeFileFlag(), buffer, size, maxSize, streamEndianness); +} diff --git a/src/fsfw/cfdp/pdu/KeepAlivePduCreator.h b/src/fsfw/cfdp/pdu/KeepAlivePduCreator.h new file mode 100644 index 00000000..aa4bf0fd --- /dev/null +++ b/src/fsfw/cfdp/pdu/KeepAlivePduCreator.h @@ -0,0 +1,22 @@ +#ifndef FSFW_CFDP_PDU_KEEPALIVEPDUSERIALIZER_H_ +#define FSFW_CFDP_PDU_KEEPALIVEPDUSERIALIZER_H_ + +#include "fsfw/cfdp/FileSize.h" +#include "fsfw/cfdp/pdu/FileDirectiveCreator.h" + +class KeepAlivePduCreator : public FileDirectiveCreator { + public: + KeepAlivePduCreator(PduConfig& conf, cfdp::FileSize& progress); + + void updateDirectiveFieldLen(); + + [[nodiscard]] size_t getSerializedSize() const override; + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + Endianness streamEndianness) const override; + + private: + cfdp::FileSize& progress; +}; + +#endif /* FSFW_CFDP_PDU_KEEPALIVEPDUSERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/KeepAlivePduDeserializer.cpp b/src/fsfw/cfdp/pdu/KeepAlivePduDeserializer.cpp deleted file mode 100644 index 79c908cf..00000000 --- a/src/fsfw/cfdp/pdu/KeepAlivePduDeserializer.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "KeepAlivePduDeserializer.h" - -KeepAlivePduDeserializer::KeepAlivePduDeserializer(const uint8_t* pduBuf, size_t maxSize, - cfdp::FileSize& progress) - : FileDirectiveDeserializer(pduBuf, maxSize), progress(progress) {} - -ReturnValue_t KeepAlivePduDeserializer::parseData() { - ReturnValue_t result = FileDirectiveDeserializer::parseData(); - if (result != returnvalue::OK) { - return result; - } - size_t currentIdx = FileDirectiveDeserializer::getHeaderSize(); - size_t remLen = FileDirectiveDeserializer::getWholePduSize() - currentIdx; - const uint8_t* buffer = rawPtr + currentIdx; - return progress.deSerialize(&buffer, &remLen, getEndianness()); -} - -cfdp::FileSize& KeepAlivePduDeserializer::getProgress() { return progress; } diff --git a/src/fsfw/cfdp/pdu/KeepAlivePduDeserializer.h b/src/fsfw/cfdp/pdu/KeepAlivePduDeserializer.h deleted file mode 100644 index e8b83ad6..00000000 --- a/src/fsfw/cfdp/pdu/KeepAlivePduDeserializer.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef FSFW_SRC_FSFW_CFDP_PDU_KEEPALIVEPDUDESERIALIZER_H_ -#define FSFW_SRC_FSFW_CFDP_PDU_KEEPALIVEPDUDESERIALIZER_H_ - -#include "fsfw/cfdp/FileSize.h" -#include "fsfw/cfdp/pdu/FileDirectiveDeserializer.h" - -class KeepAlivePduDeserializer : public FileDirectiveDeserializer { - public: - KeepAlivePduDeserializer(const uint8_t* pduBuf, size_t maxSize, cfdp::FileSize& progress); - - ReturnValue_t parseData() override; - - cfdp::FileSize& getProgress(); - - private: - cfdp::FileSize& progress; -}; - -#endif /* FSFW_SRC_FSFW_CFDP_PDU_KEEPALIVEPDUDESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/KeepAlivePduReader.cpp b/src/fsfw/cfdp/pdu/KeepAlivePduReader.cpp new file mode 100644 index 00000000..d3362cf9 --- /dev/null +++ b/src/fsfw/cfdp/pdu/KeepAlivePduReader.cpp @@ -0,0 +1,18 @@ +#include "KeepAlivePduReader.h" + +KeepAlivePduReader::KeepAlivePduReader(const uint8_t* pduBuf, size_t maxSize, + cfdp::FileSize& progress) + : FileDirectiveReader(pduBuf, maxSize), progress(progress) {} + +ReturnValue_t KeepAlivePduReader::parseData() { + ReturnValue_t result = FileDirectiveReader::parseData(); + if (result != returnvalue::OK) { + return result; + } + size_t currentIdx = FileDirectiveReader::getHeaderSize(); + size_t remLen = FileDirectiveReader::getWholePduSize() - currentIdx; + const uint8_t* buffer = pointers.rawPtr + currentIdx; + return progress.deSerialize(&buffer, &remLen, getEndianness()); +} + +cfdp::FileSize& KeepAlivePduReader::getProgress() { return progress; } diff --git a/src/fsfw/cfdp/pdu/KeepAlivePduReader.h b/src/fsfw/cfdp/pdu/KeepAlivePduReader.h new file mode 100644 index 00000000..38e061f1 --- /dev/null +++ b/src/fsfw/cfdp/pdu/KeepAlivePduReader.h @@ -0,0 +1,19 @@ +#ifndef FSFW_CFDP_PDU_KEEPALIVEREADER_H_ +#define FSFW_CFDP_PDU_KEEPALIVEREADER_H_ + +#include "fsfw/cfdp/FileSize.h" +#include "fsfw/cfdp/pdu/FileDirectiveReader.h" + +class KeepAlivePduReader : public FileDirectiveReader { + public: + KeepAlivePduReader(const uint8_t* pduBuf, size_t maxSize, cfdp::FileSize& progress); + + ReturnValue_t parseData() override; + + cfdp::FileSize& getProgress(); + + private: + cfdp::FileSize& progress; +}; + +#endif /* FSFW_CFDP_PDU_KEEPALIVEPDUREADER_H_ */ diff --git a/src/fsfw/cfdp/pdu/KeepAlivePduSerializer.cpp b/src/fsfw/cfdp/pdu/KeepAlivePduSerializer.cpp deleted file mode 100644 index 5db4664c..00000000 --- a/src/fsfw/cfdp/pdu/KeepAlivePduSerializer.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "KeepAlivePduSerializer.h" - -KeepAlivePduSerializer::KeepAlivePduSerializer(PduConfig &conf, cfdp::FileSize &progress) - : FileDirectiveSerializer(conf, cfdp::FileDirectives::KEEP_ALIVE, 4), progress(progress) { - updateDirectiveFieldLen(); -} - -size_t KeepAlivePduSerializer::getSerializedSize() const { - return FileDirectiveSerializer::getWholePduSize(); -} - -void KeepAlivePduSerializer::updateDirectiveFieldLen() { - if (this->getLargeFileFlag()) { - this->setDirectiveDataFieldLen(8); - } -} - -ReturnValue_t KeepAlivePduSerializer::serialize(uint8_t **buffer, size_t *size, size_t maxSize, - Endianness streamEndianness) const { - ReturnValue_t result = - FileDirectiveSerializer::serialize(buffer, size, maxSize, streamEndianness); - if (result != returnvalue::OK) { - return result; - } - return progress.serialize(this->getLargeFileFlag(), buffer, size, maxSize, streamEndianness); -} diff --git a/src/fsfw/cfdp/pdu/KeepAlivePduSerializer.h b/src/fsfw/cfdp/pdu/KeepAlivePduSerializer.h deleted file mode 100644 index d2499a79..00000000 --- a/src/fsfw/cfdp/pdu/KeepAlivePduSerializer.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef FSFW_SRC_FSFW_CFDP_PDU_KEEPALIVEPDUSERIALIZER_H_ -#define FSFW_SRC_FSFW_CFDP_PDU_KEEPALIVEPDUSERIALIZER_H_ - -#include "fsfw/cfdp/FileSize.h" -#include "fsfw/cfdp/pdu/FileDirectiveSerializer.h" - -class KeepAlivePduSerializer : public FileDirectiveSerializer { - public: - KeepAlivePduSerializer(PduConfig& conf, cfdp::FileSize& progress); - - void updateDirectiveFieldLen(); - - size_t getSerializedSize() const override; - - ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, - Endianness streamEndianness) const override; - - private: - cfdp::FileSize& progress; -}; - -#endif /* FSFW_SRC_FSFW_CFDP_PDU_KEEPALIVEPDUSERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/MetadataInfo.cpp b/src/fsfw/cfdp/pdu/MetadataInfo.cpp index 572460cd..d88bdd87 100644 --- a/src/fsfw/cfdp/pdu/MetadataInfo.cpp +++ b/src/fsfw/cfdp/pdu/MetadataInfo.cpp @@ -1,49 +1,52 @@ #include "MetadataInfo.h" MetadataInfo::MetadataInfo(bool closureRequested, cfdp::ChecksumType checksumType, - cfdp::FileSize& fileSize, cfdp::Lv& sourceFileName, - cfdp::Lv& destFileName) - : closureRequested(closureRequested), - checksumType(checksumType), - fileSize(fileSize), - sourceFileName(sourceFileName), - destFileName(destFileName) {} + cfdp::FileSize& fileSize, cfdp::StringLv& sourceFileName, + cfdp::StringLv& destFileName) + : MetadataInfo(fileSize, sourceFileName, destFileName) { + this->closureRequested = closureRequested; + this->checksumType = checksumType; +} -void MetadataInfo::setOptionsArray(cfdp::Tlv** optionsArray, size_t* optionsLen, - size_t* maxOptionsLen) { - this->optionsArray = optionsArray; - if (maxOptionsLen != nullptr) { - this->maxOptionsLen = *maxOptionsLen; +MetadataInfo::MetadataInfo(cfdp::FileSize& fileSize, cfdp::StringLv& sourceFileName, + cfdp::StringLv& destFileName) + : fileSize(fileSize), sourceFileName(sourceFileName), destFileName(destFileName) {} + +void MetadataInfo::setOptionsArray(cfdp::Tlv** optionsArray_, std::optional optionsLen_, + std::optional maxOptionsLen_) { + this->optionsArray = optionsArray_; + if (maxOptionsLen_) { + this->maxOptionsLen = maxOptionsLen_.value(); } - if (optionsLen != nullptr) { - this->optionsLen = *optionsLen; + if (optionsLen_) { + this->optionsLen = optionsLen_.value(); } } cfdp::ChecksumType MetadataInfo::getChecksumType() const { return checksumType; } -void MetadataInfo::setChecksumType(cfdp::ChecksumType checksumType) { - this->checksumType = checksumType; +void MetadataInfo::setChecksumType(cfdp::ChecksumType checksumType_) { + checksumType = checksumType_; } bool MetadataInfo::isClosureRequested() const { return closureRequested; } -void MetadataInfo::setClosureRequested(bool closureRequested) { - this->closureRequested = closureRequested; +void MetadataInfo::setClosureRequested(bool closureRequested_) { + closureRequested = closureRequested_; } -cfdp::Lv& MetadataInfo::getDestFileName() { return destFileName; } +cfdp::StringLv& MetadataInfo::getDestFileName() { return destFileName; } cfdp::FileSize& MetadataInfo::getFileSize() { return fileSize; } -ReturnValue_t MetadataInfo::getOptions(cfdp::Tlv*** optionsArray, size_t* optionsLen, +ReturnValue_t MetadataInfo::getOptions(cfdp::Tlv*** optionsArray_, size_t* optionsLen_, size_t* maxOptsLen) { - if (optionsArray == nullptr or this->optionsArray == nullptr) { + if (optionsArray_ == nullptr or optionsArray == nullptr) { return returnvalue::FAILED; } - *optionsArray = this->optionsArray; - if (optionsLen != nullptr) { - *optionsLen = this->optionsLen; + *optionsArray_ = optionsArray; + if (optionsLen_ != nullptr) { + *optionsLen_ = this->optionsLen; } if (maxOptsLen != nullptr) { *maxOptsLen = this->maxOptionsLen; @@ -81,18 +84,20 @@ size_t MetadataInfo::getSerializedSize(bool fssLarge) { return size; } -void MetadataInfo::setDestFileName(cfdp::Lv& destFileName) { this->destFileName = destFileName; } +void MetadataInfo::setDestFileName(cfdp::StringLv& destFileName_) { + this->destFileName = destFileName_; +} -void MetadataInfo::setSourceFileName(cfdp::Lv& sourceFileName) { - this->sourceFileName = sourceFileName; +void MetadataInfo::setSourceFileName(cfdp::StringLv& sourceFileName_) { + this->sourceFileName = sourceFileName_; } size_t MetadataInfo::getMaxOptionsLen() const { return maxOptionsLen; } -void MetadataInfo::setMaxOptionsLen(size_t maxOptionsLen) { this->maxOptionsLen = maxOptionsLen; } +void MetadataInfo::setMaxOptionsLen(size_t maxOptionsLen_) { this->maxOptionsLen = maxOptionsLen_; } size_t MetadataInfo::getOptionsLen() const { return optionsLen; } -void MetadataInfo::setOptionsLen(size_t optionsLen) { this->optionsLen = optionsLen; } +void MetadataInfo::setOptionsLen(size_t optionsLen_) { this->optionsLen = optionsLen_; } -cfdp::Lv& MetadataInfo::getSourceFileName() { return sourceFileName; } +cfdp::StringLv& MetadataInfo::getSourceFileName() { return sourceFileName; } diff --git a/src/fsfw/cfdp/pdu/MetadataInfo.h b/src/fsfw/cfdp/pdu/MetadataInfo.h index 9b90138c..95f4544a 100644 --- a/src/fsfw/cfdp/pdu/MetadataInfo.h +++ b/src/fsfw/cfdp/pdu/MetadataInfo.h @@ -1,45 +1,51 @@ #ifndef FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_ #define FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_ +#include + #include "fsfw/cfdp/FileSize.h" #include "fsfw/cfdp/definitions.h" #include "fsfw/cfdp/tlv/Lv.h" +#include "fsfw/cfdp/tlv/StringLv.h" #include "fsfw/cfdp/tlv/Tlv.h" class MetadataInfo { public: + MetadataInfo(cfdp::FileSize& fileSize, cfdp::StringLv& sourceFileName, + cfdp::StringLv& destFileName); MetadataInfo(bool closureRequested, cfdp::ChecksumType checksumType, cfdp::FileSize& fileSize, - cfdp::Lv& sourceFileName, cfdp::Lv& destFileName); + cfdp::StringLv& sourceFileName, cfdp::StringLv& destFileName); size_t getSerializedSize(bool fssLarge = false); - void setOptionsArray(cfdp::Tlv** optionsArray, size_t* optionsLen, size_t* maxOptionsLen); - cfdp::ChecksumType getChecksumType() const; + void setOptionsArray(cfdp::Tlv** optionsArray, std::optional optionsLen, + std::optional maxOptionsLen); + [[nodiscard]] cfdp::ChecksumType getChecksumType() const; void setChecksumType(cfdp::ChecksumType checksumType); - bool isClosureRequested() const; + [[nodiscard]] bool isClosureRequested() const; void setClosureRequested(bool closureRequested = false); - void setDestFileName(cfdp::Lv& destFileName); - void setSourceFileName(cfdp::Lv& sourceFileName); + void setDestFileName(cfdp::StringLv& destFileName); + void setSourceFileName(cfdp::StringLv& sourceFileName); - cfdp::Lv& getDestFileName(); - cfdp::Lv& getSourceFileName(); + cfdp::StringLv& getDestFileName(); + cfdp::StringLv& getSourceFileName(); cfdp::FileSize& getFileSize(); - bool hasOptions() const; - bool canHoldOptions() const; + [[nodiscard]] bool hasOptions() const; + [[nodiscard]] bool canHoldOptions() const; ReturnValue_t getOptions(cfdp::Tlv*** optionsArray, size_t* optionsLen, size_t* maxOptsLen); void setOptionsLen(size_t optionsLen); - size_t getOptionsLen() const; + [[nodiscard]] size_t getOptionsLen() const; void setMaxOptionsLen(size_t maxOptionsLen); - size_t getMaxOptionsLen() const; + [[nodiscard]] size_t getMaxOptionsLen() const; private: bool closureRequested = false; - cfdp::ChecksumType checksumType; + cfdp::ChecksumType checksumType = cfdp::ChecksumType::NULL_CHECKSUM; cfdp::FileSize& fileSize; - cfdp::Lv& sourceFileName; - cfdp::Lv& destFileName; + cfdp::StringLv& sourceFileName; + cfdp::StringLv& destFileName; cfdp::Tlv** optionsArray = nullptr; size_t optionsLen = 0; diff --git a/src/fsfw/cfdp/pdu/MetadataPduSerializer.cpp b/src/fsfw/cfdp/pdu/MetadataPduCreator.cpp similarity index 63% rename from src/fsfw/cfdp/pdu/MetadataPduSerializer.cpp rename to src/fsfw/cfdp/pdu/MetadataPduCreator.cpp index 041b9b84..536a48f4 100644 --- a/src/fsfw/cfdp/pdu/MetadataPduSerializer.cpp +++ b/src/fsfw/cfdp/pdu/MetadataPduCreator.cpp @@ -1,22 +1,21 @@ -#include "MetadataPduSerializer.h" +#include "MetadataPduCreator.h" -MetadataPduSerializer::MetadataPduSerializer(PduConfig &conf, MetadataInfo &info) - : FileDirectiveSerializer(conf, cfdp::FileDirectives::METADATA, 5), info(info) { +MetadataPduCreator::MetadataPduCreator(PduConfig &conf, MetadataInfo &info) + : FileDirectiveCreator(conf, cfdp::FileDirective::METADATA, 5), info(info) { updateDirectiveFieldLen(); } -void MetadataPduSerializer::updateDirectiveFieldLen() { +void MetadataPduCreator::updateDirectiveFieldLen() { setDirectiveDataFieldLen(info.getSerializedSize(getLargeFileFlag())); } -size_t MetadataPduSerializer::getSerializedSize() const { - return FileDirectiveSerializer::getWholePduSize(); +size_t MetadataPduCreator::getSerializedSize() const { + return FileDirectiveCreator::getWholePduSize(); } -ReturnValue_t MetadataPduSerializer::serialize(uint8_t **buffer, size_t *size, size_t maxSize, - Endianness streamEndianness) const { - ReturnValue_t result = - FileDirectiveSerializer::serialize(buffer, size, maxSize, streamEndianness); +ReturnValue_t MetadataPduCreator::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + ReturnValue_t result = FileDirectiveCreator::serialize(buffer, size, maxSize, streamEndianness); if (result != returnvalue::OK) { return result; } diff --git a/src/fsfw/cfdp/pdu/MetadataPduCreator.h b/src/fsfw/cfdp/pdu/MetadataPduCreator.h new file mode 100644 index 00000000..4486a79c --- /dev/null +++ b/src/fsfw/cfdp/pdu/MetadataPduCreator.h @@ -0,0 +1,23 @@ +#ifndef FSFW_CFDP_PDU_METADATAPDUCREATOR_H_ +#define FSFW_CFDP_PDU_METADATAPDUCREATOR_H_ + +#include "fsfw/cfdp/pdu/FileDirectiveCreator.h" +#include "fsfw/cfdp/pdu/MetadataInfo.h" + +class MetadataPduCreator : public FileDirectiveCreator { + public: + MetadataPduCreator(PduConfig& conf, MetadataInfo& info); + + void updateDirectiveFieldLen(); + + [[nodiscard]] size_t getSerializedSize() const override; + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + Endianness streamEndianness) const override; + using FileDirectiveCreator::serialize; + + private: + MetadataInfo& info; +}; + +#endif /* FSFW_CFDP_PDU_METADATAPDUCREATOR_H_ */ diff --git a/src/fsfw/cfdp/pdu/MetadataPduDeserializer.h b/src/fsfw/cfdp/pdu/MetadataPduDeserializer.h deleted file mode 100644 index 1a8f9315..00000000 --- a/src/fsfw/cfdp/pdu/MetadataPduDeserializer.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef FSFW_SRC_FSFW_CFDP_PDU_METADATAPDUDESERIALIZER_H_ -#define FSFW_SRC_FSFW_CFDP_PDU_METADATAPDUDESERIALIZER_H_ - -#include "fsfw/cfdp/pdu/FileDirectiveDeserializer.h" -#include "fsfw/cfdp/pdu/MetadataInfo.h" - -class MetadataPduDeserializer : public FileDirectiveDeserializer { - public: - MetadataPduDeserializer(const uint8_t* pduBuf, size_t maxSize, MetadataInfo& info); - - ReturnValue_t parseData() override; - - private: - MetadataInfo& info; -}; - -#endif /* FSFW_SRC_FSFW_CFDP_PDU_METADATAPDUDESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/MetadataPduDeserializer.cpp b/src/fsfw/cfdp/pdu/MetadataPduReader.cpp similarity index 70% rename from src/fsfw/cfdp/pdu/MetadataPduDeserializer.cpp rename to src/fsfw/cfdp/pdu/MetadataPduReader.cpp index be9f4ed7..66025140 100644 --- a/src/fsfw/cfdp/pdu/MetadataPduDeserializer.cpp +++ b/src/fsfw/cfdp/pdu/MetadataPduReader.cpp @@ -1,17 +1,16 @@ -#include "MetadataPduDeserializer.h" +#include "MetadataPduReader.h" -MetadataPduDeserializer::MetadataPduDeserializer(const uint8_t* pduBuf, size_t maxSize, - MetadataInfo& info) - : FileDirectiveDeserializer(pduBuf, maxSize), info(info) {} +MetadataPduReader::MetadataPduReader(const uint8_t* pduBuf, size_t maxSize, MetadataInfo& info) + : FileDirectiveReader(pduBuf, maxSize), info(info) {} -ReturnValue_t MetadataPduDeserializer::parseData() { - ReturnValue_t result = FileDirectiveDeserializer::parseData(); +ReturnValue_t MetadataPduReader::parseData() { + ReturnValue_t result = FileDirectiveReader::parseData(); if (result != returnvalue::OK) { return result; } - size_t currentIdx = FileDirectiveDeserializer::getHeaderSize(); - const uint8_t* buf = rawPtr + currentIdx; - size_t remSize = FileDirectiveDeserializer::getWholePduSize() - currentIdx; + size_t currentIdx = FileDirectiveReader::getHeaderSize(); + const uint8_t* buf = pointers.rawPtr + currentIdx; + size_t remSize = FileDirectiveReader::getWholePduSize() - currentIdx; if (remSize < 1) { return SerializeIF::STREAM_TOO_SHORT; } diff --git a/src/fsfw/cfdp/pdu/MetadataPduReader.h b/src/fsfw/cfdp/pdu/MetadataPduReader.h new file mode 100644 index 00000000..3e8c0f30 --- /dev/null +++ b/src/fsfw/cfdp/pdu/MetadataPduReader.h @@ -0,0 +1,17 @@ +#ifndef FSFW_CFDP_PDU_METADATAPDUREADER_H_ +#define FSFW_CFDP_PDU_METADATAPDUREADER_H_ + +#include "fsfw/cfdp/pdu/FileDirectiveReader.h" +#include "fsfw/cfdp/pdu/MetadataInfo.h" + +class MetadataPduReader : public FileDirectiveReader { + public: + MetadataPduReader(const uint8_t* pduBuf, size_t maxSize, MetadataInfo& info); + + ReturnValue_t parseData() override; + + private: + MetadataInfo& info; +}; + +#endif /* FSFW_CFDP_PDU_METADATAPDUREADER_H_ */ diff --git a/src/fsfw/cfdp/pdu/MetadataPduSerializer.h b/src/fsfw/cfdp/pdu/MetadataPduSerializer.h deleted file mode 100644 index cacf8a52..00000000 --- a/src/fsfw/cfdp/pdu/MetadataPduSerializer.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef FSFW_SRC_FSFW_CFDP_PDU_METADATAPDUSERIALIZER_H_ -#define FSFW_SRC_FSFW_CFDP_PDU_METADATAPDUSERIALIZER_H_ - -#include "fsfw/cfdp/pdu/FileDirectiveSerializer.h" -#include "fsfw/cfdp/pdu/MetadataInfo.h" - -class MetadataPduSerializer : public FileDirectiveSerializer { - public: - MetadataPduSerializer(PduConfig& conf, MetadataInfo& info); - - void updateDirectiveFieldLen(); - - size_t getSerializedSize() const override; - - ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, - Endianness streamEndianness) const override; - - private: - MetadataInfo& info; -}; - -#endif /* FSFW_SRC_FSFW_CFDP_PDU_METADATAPDUSERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/NakInfo.cpp b/src/fsfw/cfdp/pdu/NakInfo.cpp index 795004a9..14d06cb0 100644 --- a/src/fsfw/cfdp/pdu/NakInfo.cpp +++ b/src/fsfw/cfdp/pdu/NakInfo.cpp @@ -26,7 +26,7 @@ bool NakInfo::hasSegmentRequests() const { } bool NakInfo::canHoldSegmentRequests() const { - if (this->segmentRequests != nullptr and maxSegmentRequestsLen > 0) { + if (segmentRequests != nullptr and maxSegmentRequestsLen > 0) { return true; } return false; diff --git a/src/fsfw/cfdp/pdu/NakPduSerializer.cpp b/src/fsfw/cfdp/pdu/NakPduCreator.cpp similarity index 63% rename from src/fsfw/cfdp/pdu/NakPduSerializer.cpp rename to src/fsfw/cfdp/pdu/NakPduCreator.cpp index e8634df7..11f3aba9 100644 --- a/src/fsfw/cfdp/pdu/NakPduSerializer.cpp +++ b/src/fsfw/cfdp/pdu/NakPduCreator.cpp @@ -1,22 +1,19 @@ -#include "NakPduSerializer.h" +#include "NakPduCreator.h" -NakPduSerializer::NakPduSerializer(PduConfig &pduConf, NakInfo &nakInfo) - : FileDirectiveSerializer(pduConf, cfdp::FileDirectives::NAK, 0), nakInfo(nakInfo) { +NakPduCreator::NakPduCreator(PduConfig &pduConf, NakInfo &nakInfo) + : FileDirectiveCreator(pduConf, cfdp::FileDirective::NAK, 0), nakInfo(nakInfo) { updateDirectiveFieldLen(); } -void NakPduSerializer::updateDirectiveFieldLen() { +void NakPduCreator::updateDirectiveFieldLen() { this->setDirectiveDataFieldLen(nakInfo.getSerializedSize(getLargeFileFlag())); } -size_t NakPduSerializer::getSerializedSize() const { - return FileDirectiveSerializer::getWholePduSize(); -} +size_t NakPduCreator::getSerializedSize() const { return FileDirectiveCreator::getWholePduSize(); } -ReturnValue_t NakPduSerializer::serialize(uint8_t **buffer, size_t *size, size_t maxSize, - Endianness streamEndianness) const { - ReturnValue_t result = - FileDirectiveSerializer::serialize(buffer, size, maxSize, streamEndianness); +ReturnValue_t NakPduCreator::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + ReturnValue_t result = FileDirectiveCreator::serialize(buffer, size, maxSize, streamEndianness); if (result != returnvalue::OK) { return result; } diff --git a/src/fsfw/cfdp/pdu/NakPduSerializer.h b/src/fsfw/cfdp/pdu/NakPduCreator.h similarity index 65% rename from src/fsfw/cfdp/pdu/NakPduSerializer.h rename to src/fsfw/cfdp/pdu/NakPduCreator.h index 4009884b..bfcff78d 100644 --- a/src/fsfw/cfdp/pdu/NakPduSerializer.h +++ b/src/fsfw/cfdp/pdu/NakPduCreator.h @@ -1,14 +1,14 @@ -#ifndef FSFW_SRC_FSFW_CFDP_PDU_NAKPDUSERIALIZER_H_ -#define FSFW_SRC_FSFW_CFDP_PDU_NAKPDUSERIALIZER_H_ +#ifndef FSFW_CFDP_PDU_NAKPDUSERIALIZER_H_ +#define FSFW_CFDP_PDU_NAKPDUSERIALIZER_H_ #include #include "NakInfo.h" #include "fsfw/cfdp/FileSize.h" #include "fsfw/cfdp/definitions.h" -#include "fsfw/cfdp/pdu/FileDirectiveSerializer.h" +#include "fsfw/cfdp/pdu/FileDirectiveCreator.h" -class NakPduSerializer : public FileDirectiveSerializer { +class NakPduCreator : public FileDirectiveCreator { public: /** * @@ -18,9 +18,9 @@ class NakPduSerializer : public FileDirectiveSerializer { * @param [in] segmentRequests Pointer to the start of a list of segment requests * @param segmentRequestLen Length of the segment request list to be serialized */ - NakPduSerializer(PduConfig& PduConf, NakInfo& nakInfo); + NakPduCreator(PduConfig& PduConf, NakInfo& nakInfo); - size_t getSerializedSize() const override; + [[nodiscard]] size_t getSerializedSize() const override; ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, Endianness streamEndianness) const override; @@ -35,4 +35,4 @@ class NakPduSerializer : public FileDirectiveSerializer { NakInfo& nakInfo; }; -#endif /* FSFW_SRC_FSFW_CFDP_PDU_NAKPDUSERIALIZER_H_ */ +#endif /* FSFW_CFDP_PDU_NAKPDUSERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/NakPduDeserializer.h b/src/fsfw/cfdp/pdu/NakPduDeserializer.h deleted file mode 100644 index f0f43158..00000000 --- a/src/fsfw/cfdp/pdu/NakPduDeserializer.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef FSFW_SRC_FSFW_CFDP_PDU_NAKPDUDESERIALIZER_H_ -#define FSFW_SRC_FSFW_CFDP_PDU_NAKPDUDESERIALIZER_H_ - -#include "fsfw/cfdp/pdu/FileDirectiveDeserializer.h" -#include "fsfw/cfdp/pdu/NakInfo.h" - -class NakPduDeserializer : public FileDirectiveDeserializer { - public: - NakPduDeserializer(const uint8_t* pduBuf, size_t maxSize, NakInfo& info); - - /** - * This needs to be called before accessing the PDU fields to avoid segmentation faults. - * @return - */ - virtual ReturnValue_t parseData() override; - - private: - NakInfo& nakInfo; -}; - -#endif /* FSFW_SRC_FSFW_CFDP_PDU_NAKPDUDESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/NakPduDeserializer.cpp b/src/fsfw/cfdp/pdu/NakPduReader.cpp similarity index 73% rename from src/fsfw/cfdp/pdu/NakPduDeserializer.cpp rename to src/fsfw/cfdp/pdu/NakPduReader.cpp index 8acc9fc9..c67774c0 100644 --- a/src/fsfw/cfdp/pdu/NakPduDeserializer.cpp +++ b/src/fsfw/cfdp/pdu/NakPduReader.cpp @@ -1,16 +1,16 @@ -#include "NakPduDeserializer.h" +#include "NakPduReader.h" -NakPduDeserializer::NakPduDeserializer(const uint8_t* pduBuf, size_t maxSize, NakInfo& info) - : FileDirectiveDeserializer(pduBuf, maxSize), nakInfo(info) {} +NakPduReader::NakPduReader(const uint8_t* pduBuf, size_t maxSize, NakInfo& info) + : FileDirectiveReader(pduBuf, maxSize), nakInfo(info) {} -ReturnValue_t NakPduDeserializer::parseData() { - ReturnValue_t result = FileDirectiveDeserializer::parseData(); +ReturnValue_t NakPduReader::parseData() { + ReturnValue_t result = FileDirectiveReader::parseData(); if (result != returnvalue::OK) { return result; } - size_t currentIdx = FileDirectiveDeserializer::getHeaderSize(); - const uint8_t* buffer = rawPtr + currentIdx; - size_t remSize = FileDirectiveDeserializer::getWholePduSize() - currentIdx; + size_t currentIdx = FileDirectiveReader::getHeaderSize(); + const uint8_t* buffer = pointers.rawPtr + currentIdx; + size_t remSize = FileDirectiveReader::getWholePduSize() - currentIdx; if (remSize < 1) { return SerializeIF::STREAM_TOO_SHORT; } diff --git a/src/fsfw/cfdp/pdu/NakPduReader.h b/src/fsfw/cfdp/pdu/NakPduReader.h new file mode 100644 index 00000000..7e08229d --- /dev/null +++ b/src/fsfw/cfdp/pdu/NakPduReader.h @@ -0,0 +1,21 @@ +#ifndef FSFW_CFDP_PDU_NAKPDUDESERIALIZER_H_ +#define FSFW_CFDP_PDU_NAKPDUDESERIALIZER_H_ + +#include "fsfw/cfdp/pdu/FileDirectiveReader.h" +#include "fsfw/cfdp/pdu/NakInfo.h" + +class NakPduReader : public FileDirectiveReader { + public: + NakPduReader(const uint8_t* pduBuf, size_t maxSize, NakInfo& info); + + /** + * This needs to be called before accessing the PDU fields to avoid segmentation faults. + * @return + */ + ReturnValue_t parseData() override; + + private: + NakInfo& nakInfo; +}; + +#endif /* FSFW_CFDP_PDU_NAKPDUDESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/PduConfig.cpp b/src/fsfw/cfdp/pdu/PduConfig.cpp index d495f864..ccb20f51 100644 --- a/src/fsfw/cfdp/pdu/PduConfig.cpp +++ b/src/fsfw/cfdp/pdu/PduConfig.cpp @@ -1,12 +1,14 @@ #include "PduConfig.h" -PduConfig::PduConfig(cfdp::TransmissionModes mode, cfdp::TransactionSeqNum seqNum, - cfdp::EntityId sourceId, cfdp::EntityId destId, bool crcFlag, bool largeFile, +#include + +PduConfig::PduConfig(cfdp::EntityId sourceId, cfdp::EntityId destId, cfdp::TransmissionMode mode, + cfdp::TransactionSeqNum seqNum, bool crcFlag, bool largeFile, cfdp::Direction direction) : mode(mode), - seqNum(seqNum), - sourceId(sourceId), - destId(destId), + seqNum(std::move(seqNum)), + sourceId(std::move(sourceId)), + destId(std::move(destId)), crcFlag(crcFlag), largeFile(largeFile), direction(direction) {} diff --git a/src/fsfw/cfdp/pdu/PduConfig.h b/src/fsfw/cfdp/pdu/PduConfig.h index e5b52e52..70f37e38 100644 --- a/src/fsfw/cfdp/pdu/PduConfig.h +++ b/src/fsfw/cfdp/pdu/PduConfig.h @@ -1,36 +1,23 @@ #ifndef FSFW_SRC_FSFW_CFDP_PDU_PDUCONFIG_H_ #define FSFW_SRC_FSFW_CFDP_PDU_PDUCONFIG_H_ -#include "VarLenField.h" - -namespace cfdp { - -struct EntityId : public VarLenField { - public: - EntityId() : VarLenField() {} - EntityId(cfdp::WidthInBytes width, size_t entityId) : VarLenField(width, entityId) {} -}; - -struct TransactionSeqNum : public VarLenField { - public: - TransactionSeqNum() : VarLenField() {} - TransactionSeqNum(cfdp::WidthInBytes width, size_t seqNum) : VarLenField(width, seqNum) {} -}; - -} // namespace cfdp +#include "fsfw/cfdp/VarLenFields.h" +#include "fsfw/cfdp/definitions.h" class PduConfig { public: - PduConfig(cfdp::TransmissionModes mode, cfdp::TransactionSeqNum seqNum, cfdp::EntityId sourceId, - cfdp::EntityId destId, bool crcFlag = false, bool largeFile = false, + PduConfig() = default; + PduConfig(cfdp::EntityId sourceId, cfdp::EntityId destId, cfdp::TransmissionMode mode, + cfdp::TransactionSeqNum seqNum, bool crcFlag = false, bool largeFile = false, cfdp::Direction direction = cfdp::Direction::TOWARDS_RECEIVER); - cfdp::TransmissionModes mode; + + cfdp::TransmissionMode mode = cfdp::TransmissionMode::ACKNOWLEDGED; cfdp::TransactionSeqNum seqNum; cfdp::EntityId sourceId; cfdp::EntityId destId; - bool crcFlag; - bool largeFile; - cfdp::Direction direction; + bool crcFlag = false; + bool largeFile = false; + cfdp::Direction direction = cfdp::Direction::TOWARDS_RECEIVER; }; #endif /* FSFW_SRC_FSFW_CFDP_PDU_PDUCONFIG_H_ */ diff --git a/src/fsfw/cfdp/pdu/PduHeaderIF.h b/src/fsfw/cfdp/pdu/PduHeaderIF.h index f05d95a4..341b0335 100644 --- a/src/fsfw/cfdp/pdu/PduHeaderIF.h +++ b/src/fsfw/cfdp/pdu/PduHeaderIF.h @@ -3,8 +3,8 @@ #include -#include "../definitions.h" #include "PduConfig.h" +#include "fsfw/cfdp/definitions.h" /** * @brief Generic interface to access all fields of a PDU header @@ -13,20 +13,20 @@ */ class PduHeaderIF { public: - virtual ~PduHeaderIF(){}; + virtual ~PduHeaderIF() = default; - virtual size_t getWholePduSize() const = 0; - virtual size_t getPduDataFieldLen() const = 0; - virtual cfdp::PduType getPduType() const = 0; - virtual cfdp::Direction getDirection() const = 0; - virtual cfdp::TransmissionModes getTransmissionMode() const = 0; - virtual bool getCrcFlag() const = 0; - virtual bool getLargeFileFlag() const = 0; - virtual cfdp::SegmentationControl getSegmentationControl() const = 0; - virtual cfdp::WidthInBytes getLenEntityIds() const = 0; - virtual cfdp::WidthInBytes getLenSeqNum() const = 0; - virtual cfdp::SegmentMetadataFlag getSegmentMetadataFlag() const = 0; - virtual bool hasSegmentMetadataFlag() const = 0; + [[nodiscard]] virtual size_t getWholePduSize() const = 0; + [[nodiscard]] virtual size_t getPduDataFieldLen() const = 0; + [[nodiscard]] virtual cfdp::PduType getPduType() const = 0; + [[nodiscard]] virtual cfdp::Direction getDirection() const = 0; + [[nodiscard]] virtual cfdp::TransmissionMode getTransmissionMode() const = 0; + [[nodiscard]] virtual bool getCrcFlag() const = 0; + [[nodiscard]] virtual bool getLargeFileFlag() const = 0; + [[nodiscard]] virtual cfdp::SegmentationControl getSegmentationControl() const = 0; + [[nodiscard]] virtual cfdp::WidthInBytes getLenEntityIds() const = 0; + [[nodiscard]] virtual cfdp::WidthInBytes getLenSeqNum() const = 0; + [[nodiscard]] virtual cfdp::SegmentMetadataFlag getSegmentMetadataFlag() const = 0; + [[nodiscard]] virtual bool hasSegmentMetadataFlag() const = 0; virtual void getSourceId(cfdp::EntityId& sourceId) const = 0; virtual void getDestId(cfdp::EntityId& destId) const = 0; virtual void getTransactionSeqNum(cfdp::TransactionSeqNum& seqNum) const = 0; diff --git a/src/fsfw/cfdp/pdu/HeaderDeserializer.h b/src/fsfw/cfdp/pdu/PduHeaderReader.h similarity index 52% rename from src/fsfw/cfdp/pdu/HeaderDeserializer.h rename to src/fsfw/cfdp/pdu/PduHeaderReader.h index 4c237117..a2e122cd 100644 --- a/src/fsfw/cfdp/pdu/HeaderDeserializer.h +++ b/src/fsfw/cfdp/pdu/PduHeaderReader.h @@ -23,15 +23,16 @@ struct PduHeaderFixedStruct { * This is a zero-copy implementation and #parseData needs to be called to ensure the data is * valid. */ -class HeaderDeserializer : public RedirectableDataPointerIF, public PduHeaderIF { +class PduHeaderReader : public RedirectableDataPointerIF, public PduHeaderIF { public: + PduHeaderReader() = default; /** * Initialize a PDU header from raw data. This is a zero-copy implementation and #parseData * needs to be called to ensure the data is valid * @param pduBuf * @param maxSize */ - HeaderDeserializer(const uint8_t* pduBuf, size_t maxSize); + PduHeaderReader(const uint8_t* pduBuf, size_t maxSize); /** * This needs to be called before accessing the PDU fields to avoid segmentation faults. @@ -41,21 +42,30 @@ class HeaderDeserializer : public RedirectableDataPointerIF, public PduHeaderIF * - SerializeIF::BUFFER_TOO_SHORT if buffer is shorter than expected */ virtual ReturnValue_t parseData(); - size_t getHeaderSize() const; + explicit operator bool() const; + [[nodiscard]] bool isNull() const; - size_t getPduDataFieldLen() const override; - size_t getWholePduSize() const override; + /** + * Fill the provided PDU configuration from the fields detected by this reader. + * @param cfg + */ + void fillConfig(PduConfig& cfg) const; - cfdp::PduType getPduType() const override; - cfdp::Direction getDirection() const override; - cfdp::TransmissionModes getTransmissionMode() const override; - bool getCrcFlag() const override; - bool getLargeFileFlag() const override; - cfdp::SegmentationControl getSegmentationControl() const override; - cfdp::WidthInBytes getLenEntityIds() const override; - cfdp::WidthInBytes getLenSeqNum() const override; - cfdp::SegmentMetadataFlag getSegmentMetadataFlag() const override; - bool hasSegmentMetadataFlag() const override; + [[nodiscard]] virtual size_t getHeaderSize() const; + + [[nodiscard]] size_t getPduDataFieldLen() const override; + [[nodiscard]] size_t getWholePduSize() const override; + + [[nodiscard]] cfdp::PduType getPduType() const override; + [[nodiscard]] cfdp::Direction getDirection() const override; + [[nodiscard]] cfdp::TransmissionMode getTransmissionMode() const override; + [[nodiscard]] bool getCrcFlag() const override; + [[nodiscard]] bool getLargeFileFlag() const override; + [[nodiscard]] cfdp::SegmentationControl getSegmentationControl() const override; + [[nodiscard]] cfdp::WidthInBytes getLenEntityIds() const override; + [[nodiscard]] cfdp::WidthInBytes getLenSeqNum() const override; + [[nodiscard]] cfdp::SegmentMetadataFlag getSegmentMetadataFlag() const override; + [[nodiscard]] bool hasSegmentMetadataFlag() const override; void getSourceId(cfdp::EntityId& sourceId) const override; void getDestId(cfdp::EntityId& destId) const override; @@ -63,6 +73,9 @@ class HeaderDeserializer : public RedirectableDataPointerIF, public PduHeaderIF ReturnValue_t deserResult = returnvalue::OK; + [[nodiscard]] size_t getMaxSize() const; + [[nodiscard]] const uint8_t* getPduDataField() const; + /** * Can also be used to reset the pointer to a nullptr, but the getter functions will not * perform nullptr checks! @@ -71,16 +84,27 @@ class HeaderDeserializer : public RedirectableDataPointerIF, public PduHeaderIF * @param args * @return */ - ReturnValue_t setData(uint8_t* dataPtr, size_t maxSize, void* args = nullptr) override; - - size_t getMaxSize() const; + ReturnValue_t setReadOnlyData(const uint8_t* dataPtr, size_t maxSize); protected: - PduHeaderFixedStruct* fixedHeader = nullptr; - const uint8_t* rawPtr = nullptr; + struct Pointers { + PduHeaderFixedStruct* fixedHeader = nullptr; + const uint8_t* dataFieldStart = nullptr; + const uint8_t* rawPtr = nullptr; + }; + + Pointers pointers; size_t maxSize = 0; private: + /** + * This is a reader class and setting mutable data is forbidden. Use @setReadOnlyData instead. + * @param dataPtr + * @param maxSize + * @param args + * @return + */ + ReturnValue_t setData(uint8_t* dataPtr, size_t maxSize, void* args) override; void assignVarLenField(cfdp::VarLenField* field, cfdp::WidthInBytes width, void* sourcePtr) const; void* sourceIdRaw = nullptr; void* seqNumRaw = nullptr; diff --git a/src/fsfw/cfdp/pdu/PromptPduCreator.cpp b/src/fsfw/cfdp/pdu/PromptPduCreator.cpp new file mode 100644 index 00000000..f4141fdb --- /dev/null +++ b/src/fsfw/cfdp/pdu/PromptPduCreator.cpp @@ -0,0 +1,24 @@ +#include "PromptPduCreator.h" + +PromptPduCreator::PromptPduCreator(PduConfig &conf, cfdp::PromptResponseRequired responseRequired) + : FileDirectiveCreator(conf, cfdp::FileDirective::PROMPT, 1), + responseRequired(responseRequired) {} + +size_t PromptPduCreator::getSerializedSize() const { + return FileDirectiveCreator::getWholePduSize(); +} + +ReturnValue_t PromptPduCreator::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + ReturnValue_t result = FileDirectiveCreator::serialize(buffer, size, maxSize, streamEndianness); + if (result != returnvalue::OK) { + return result; + } + if (*size + 1 > maxSize) { + return SerializeIF::BUFFER_TOO_SHORT; + } + **buffer = responseRequired << 7; + *buffer += 1; + *size += 1; + return result; +} diff --git a/src/fsfw/cfdp/pdu/PromptPduSerializer.h b/src/fsfw/cfdp/pdu/PromptPduCreator.h similarity index 61% rename from src/fsfw/cfdp/pdu/PromptPduSerializer.h rename to src/fsfw/cfdp/pdu/PromptPduCreator.h index 51500224..ccecab6e 100644 --- a/src/fsfw/cfdp/pdu/PromptPduSerializer.h +++ b/src/fsfw/cfdp/pdu/PromptPduCreator.h @@ -1,13 +1,13 @@ #ifndef FSFW_SRC_FSFW_CFDP_PDU_PROMPTPDUSERIALIZER_H_ #define FSFW_SRC_FSFW_CFDP_PDU_PROMPTPDUSERIALIZER_H_ -#include "fsfw/cfdp/pdu/FileDirectiveSerializer.h" +#include "fsfw/cfdp/pdu/FileDirectiveCreator.h" -class PromptPduSerializer : public FileDirectiveSerializer { +class PromptPduCreator : public FileDirectiveCreator { public: - PromptPduSerializer(PduConfig& conf, cfdp::PromptResponseRequired responseRequired); + PromptPduCreator(PduConfig& conf, cfdp::PromptResponseRequired responseRequired); - size_t getSerializedSize() const override; + [[nodiscard]] size_t getSerializedSize() const override; ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, Endianness streamEndianness) const override; diff --git a/src/fsfw/cfdp/pdu/PromptPduDeserializer.cpp b/src/fsfw/cfdp/pdu/PromptPduDeserializer.cpp deleted file mode 100644 index 7e9e328d..00000000 --- a/src/fsfw/cfdp/pdu/PromptPduDeserializer.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "PromptPduDeserializer.h" - -PromptPduDeserializer::PromptPduDeserializer(const uint8_t *pduBuf, size_t maxSize) - : FileDirectiveDeserializer(pduBuf, maxSize) {} - -cfdp::PromptResponseRequired PromptPduDeserializer::getPromptResponseRequired() const { - return responseRequired; -} - -ReturnValue_t PromptPduDeserializer::parseData() { - ReturnValue_t result = FileDirectiveDeserializer::parseData(); - if (result != returnvalue::OK) { - return result; - } - size_t currentIdx = FileDirectiveDeserializer::getHeaderSize(); - if (FileDirectiveDeserializer::getWholePduSize() - currentIdx < 1) { - return SerializeIF::STREAM_TOO_SHORT; - } - responseRequired = static_cast((rawPtr[currentIdx] >> 7) & 0x01); - return returnvalue::OK; -} diff --git a/src/fsfw/cfdp/pdu/PromptPduReader.cpp b/src/fsfw/cfdp/pdu/PromptPduReader.cpp new file mode 100644 index 00000000..f554c3c9 --- /dev/null +++ b/src/fsfw/cfdp/pdu/PromptPduReader.cpp @@ -0,0 +1,21 @@ +#include "PromptPduReader.h" + +PromptPduReader::PromptPduReader(const uint8_t *pduBuf, size_t maxSize) + : FileDirectiveReader(pduBuf, maxSize) {} + +cfdp::PromptResponseRequired PromptPduReader::getPromptResponseRequired() const { + return responseRequired; +} + +ReturnValue_t PromptPduReader::parseData() { + ReturnValue_t result = FileDirectiveReader::parseData(); + if (result != returnvalue::OK) { + return result; + } + if (FileDirectiveReader::getWholePduSize() <= FileDirectiveReader::getHeaderSize()) { + return SerializeIF::STREAM_TOO_SHORT; + } + responseRequired = static_cast( + (pointers.rawPtr[FileDirectiveReader::getHeaderSize()] >> 7) & 0x01); + return returnvalue::OK; +} diff --git a/src/fsfw/cfdp/pdu/PromptPduDeserializer.h b/src/fsfw/cfdp/pdu/PromptPduReader.h similarity index 57% rename from src/fsfw/cfdp/pdu/PromptPduDeserializer.h rename to src/fsfw/cfdp/pdu/PromptPduReader.h index 9441f364..2afcb20e 100644 --- a/src/fsfw/cfdp/pdu/PromptPduDeserializer.h +++ b/src/fsfw/cfdp/pdu/PromptPduReader.h @@ -1,13 +1,13 @@ #ifndef FSFW_SRC_FSFW_CFDP_PDU_PROMPTPDUDESERIALIZER_H_ #define FSFW_SRC_FSFW_CFDP_PDU_PROMPTPDUDESERIALIZER_H_ -#include "fsfw/cfdp/pdu/FileDirectiveDeserializer.h" +#include "fsfw/cfdp/pdu/FileDirectiveReader.h" -class PromptPduDeserializer : public FileDirectiveDeserializer { +class PromptPduReader : public FileDirectiveReader { public: - PromptPduDeserializer(const uint8_t *pduBuf, size_t maxSize); + PromptPduReader(const uint8_t *pduBuf, size_t maxSize); - cfdp::PromptResponseRequired getPromptResponseRequired() const; + [[nodiscard]] cfdp::PromptResponseRequired getPromptResponseRequired() const; ReturnValue_t parseData() override; private: diff --git a/src/fsfw/cfdp/pdu/PromptPduSerializer.cpp b/src/fsfw/cfdp/pdu/PromptPduSerializer.cpp deleted file mode 100644 index e5d5bca7..00000000 --- a/src/fsfw/cfdp/pdu/PromptPduSerializer.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "PromptPduSerializer.h" - -PromptPduSerializer::PromptPduSerializer(PduConfig &conf, - cfdp::PromptResponseRequired responseRequired) - : FileDirectiveSerializer(conf, cfdp::FileDirectives::PROMPT, 1), - responseRequired(responseRequired) {} - -size_t PromptPduSerializer::getSerializedSize() const { - return FileDirectiveSerializer::getWholePduSize(); -} - -ReturnValue_t PromptPduSerializer::serialize(uint8_t **buffer, size_t *size, size_t maxSize, - Endianness streamEndianness) const { - ReturnValue_t result = - FileDirectiveSerializer::serialize(buffer, size, maxSize, streamEndianness); - if (result != returnvalue::OK) { - return result; - } - if (*size + 1 > maxSize) { - return SerializeIF::BUFFER_TOO_SHORT; - } - **buffer = this->responseRequired << 7; - *buffer += 1; - *size += 1; - return result; -} diff --git a/src/fsfw/cfdp/pdu/VarLenField.h b/src/fsfw/cfdp/pdu/VarLenField.h deleted file mode 100644 index 590c2dd5..00000000 --- a/src/fsfw/cfdp/pdu/VarLenField.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef FSFW_SRC_FSFW_CFDP_PDU_VARLENFIELD_H_ -#define FSFW_SRC_FSFW_CFDP_PDU_VARLENFIELD_H_ - -#include -#include - -#include "../definitions.h" -#include "fsfw/serialize/SerializeIF.h" - -namespace cfdp { - -class VarLenField : public SerializeIF { - public: - union LengthFieldLen { - uint8_t oneByte; - uint16_t twoBytes; - uint32_t fourBytes; - uint64_t eightBytes; - }; - - VarLenField(); - VarLenField(cfdp::WidthInBytes width, size_t value); - - ReturnValue_t setValue(cfdp::WidthInBytes, size_t value); - - ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, - Endianness streamEndianness) const override; - - size_t getSerializedSize() const override; - - ReturnValue_t deSerialize(cfdp::WidthInBytes width, const uint8_t **buffer, size_t *size, - Endianness streamEndianness); - - cfdp::WidthInBytes getWidth() const; - size_t getValue() const; - - private: - ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, - Endianness streamEndianness) override; - - cfdp::WidthInBytes width; - LengthFieldLen value; -}; - -} // namespace cfdp - -#endif /* FSFW_SRC_FSFW_CFDP_PDU_VARLENFIELD_H_ */ diff --git a/src/fsfw/cfdp/tlv/CMakeLists.txt b/src/fsfw/cfdp/tlv/CMakeLists.txt index cdf7b44a..617b1b0f 100644 --- a/src/fsfw/cfdp/tlv/CMakeLists.txt +++ b/src/fsfw/cfdp/tlv/CMakeLists.txt @@ -5,6 +5,7 @@ target_sources( FilestoreResponseTlv.cpp Lv.cpp Tlv.cpp + StringLv.cpp FlowLabelTlv.cpp MessageToUserTlv.cpp FaultHandlerOverrideTlv.cpp) diff --git a/src/fsfw/cfdp/tlv/EntityIdTlv.cpp b/src/fsfw/cfdp/tlv/EntityIdTlv.cpp index 87f55db8..d4c4d6a8 100644 --- a/src/fsfw/cfdp/tlv/EntityIdTlv.cpp +++ b/src/fsfw/cfdp/tlv/EntityIdTlv.cpp @@ -11,7 +11,7 @@ ReturnValue_t EntityIdTlv::serialize(uint8_t **buffer, size_t *size, size_t maxS if (maxSize < this->getSerializedSize()) { return BUFFER_TOO_SHORT; } - **buffer = cfdp::TlvTypes::ENTITY_ID; + **buffer = cfdp::TlvType::ENTITY_ID; *size += 1; *buffer += 1; size_t serLen = entityId.getSerializedSize(); @@ -28,8 +28,8 @@ ReturnValue_t EntityIdTlv::deSerialize(const uint8_t **buffer, size_t *size, if (*size < 3) { return STREAM_TOO_SHORT; } - cfdp::TlvTypes type = static_cast(**buffer); - if (type != cfdp::TlvTypes::ENTITY_ID) { + cfdp::TlvType type = static_cast(**buffer); + if (type != cfdp::TlvType::ENTITY_ID) { return cfdp::INVALID_TLV_TYPE; } *buffer += 1; @@ -54,6 +54,6 @@ ReturnValue_t EntityIdTlv::deSerialize(cfdp::Tlv &tlv, Endianness endianness) { uint8_t EntityIdTlv::getLengthField() const { return 1 + entityId.getSerializedSize(); } -cfdp::TlvTypes EntityIdTlv::getType() const { return cfdp::TlvTypes::ENTITY_ID; } +cfdp::TlvType EntityIdTlv::getType() const { return cfdp::TlvType::ENTITY_ID; } cfdp::EntityId &EntityIdTlv::getEntityId() { return entityId; } diff --git a/src/fsfw/cfdp/tlv/EntityIdTlv.h b/src/fsfw/cfdp/tlv/EntityIdTlv.h index 1443cc17..ac310899 100644 --- a/src/fsfw/cfdp/tlv/EntityIdTlv.h +++ b/src/fsfw/cfdp/tlv/EntityIdTlv.h @@ -27,7 +27,7 @@ class EntityIdTlv : public TlvIF { Endianness streamEndianness) override; uint8_t getLengthField() const override; - cfdp::TlvTypes getType() const override; + cfdp::TlvType getType() const override; cfdp::EntityId& getEntityId(); diff --git a/src/fsfw/cfdp/tlv/FaultHandlerOverrideTlv.cpp b/src/fsfw/cfdp/tlv/FaultHandlerOverrideTlv.cpp index bbcb61d2..90b71361 100644 --- a/src/fsfw/cfdp/tlv/FaultHandlerOverrideTlv.cpp +++ b/src/fsfw/cfdp/tlv/FaultHandlerOverrideTlv.cpp @@ -4,7 +4,7 @@ FaultHandlerOverrideTlv::FaultHandlerOverrideTlv(cfdp::ConditionCode conditionCo cfdp::FaultHandlerCode handlerCode) : conditionCode(conditionCode), handlerCode(handlerCode) {} -FaultHandlerOverrideTlv::FaultHandlerOverrideTlv() {} +FaultHandlerOverrideTlv::FaultHandlerOverrideTlv() = default; uint8_t FaultHandlerOverrideTlv::getLengthField() const { return 1; } @@ -32,8 +32,8 @@ ReturnValue_t FaultHandlerOverrideTlv::deSerialize(const uint8_t **buffer, size_ if (*size < 3) { return SerializeIF::STREAM_TOO_SHORT; } - auto detectedType = static_cast(**buffer); - if (detectedType != cfdp::TlvTypes::FAULT_HANDLER) { + auto detectedType = static_cast(**buffer); + if (detectedType != cfdp::TlvType::FAULT_HANDLER) { return cfdp::INVALID_TLV_TYPE; } *buffer += 1; @@ -51,4 +51,4 @@ ReturnValue_t FaultHandlerOverrideTlv::deSerialize(const uint8_t **buffer, size_ return returnvalue::OK; } -cfdp::TlvTypes FaultHandlerOverrideTlv::getType() const { return cfdp::TlvTypes::FAULT_HANDLER; } +cfdp::TlvType FaultHandlerOverrideTlv::getType() const { return cfdp::TlvType::FAULT_HANDLER; } diff --git a/src/fsfw/cfdp/tlv/FaultHandlerOverrideTlv.h b/src/fsfw/cfdp/tlv/FaultHandlerOverrideTlv.h index 9f2adbb3..9f5cd486 100644 --- a/src/fsfw/cfdp/tlv/FaultHandlerOverrideTlv.h +++ b/src/fsfw/cfdp/tlv/FaultHandlerOverrideTlv.h @@ -3,18 +3,6 @@ #include "TlvIF.h" -namespace cfdp { - -enum FaultHandlerCode { - RESERVED = 0b0000, - NOTICE_OF_CANCELLATION = 0b0001, - NOTICE_OF_SUSPENSION = 0b0010, - IGNORE_ERROR = 0b0011, - ABANDON_TRANSACTION = 0b0100 -}; - -} - class FaultHandlerOverrideTlv : public TlvIF { public: FaultHandlerOverrideTlv(); @@ -23,12 +11,12 @@ class FaultHandlerOverrideTlv : public TlvIF { ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, Endianness streamEndianness) const override; - size_t getSerializedSize() const override; + [[nodiscard]] size_t getSerializedSize() const override; ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, Endianness streamEndianness) override; - uint8_t getLengthField() const override; - cfdp::TlvTypes getType() const override; + [[nodiscard]] uint8_t getLengthField() const override; + [[nodiscard]] cfdp::TlvType getType() const override; private: cfdp::ConditionCode conditionCode = cfdp::ConditionCode::NO_CONDITION_FIELD; diff --git a/src/fsfw/cfdp/tlv/FilestoreRequestTlv.cpp b/src/fsfw/cfdp/tlv/FilestoreRequestTlv.cpp index 941e8f5d..1022a7d1 100644 --- a/src/fsfw/cfdp/tlv/FilestoreRequestTlv.cpp +++ b/src/fsfw/cfdp/tlv/FilestoreRequestTlv.cpp @@ -3,10 +3,10 @@ #include "fsfw/FSFW.h" FilestoreRequestTlv::FilestoreRequestTlv(cfdp::FilestoreActionCode actionCode, - cfdp::Lv &firstFileName) + cfdp::StringLv &firstFileName) : FilestoreTlvBase(actionCode, firstFileName) {} -FilestoreRequestTlv::FilestoreRequestTlv(cfdp::Lv &firstFileName) +FilestoreRequestTlv::FilestoreRequestTlv(cfdp::StringLv &firstFileName) : FilestoreTlvBase(cfdp::FilestoreActionCode::INVALID, firstFileName) {} void FilestoreRequestTlv::setSecondFileName(cfdp::Lv *secondFileName) { @@ -76,4 +76,4 @@ ReturnValue_t FilestoreRequestTlv::deSerializeFromValue(const uint8_t **buffer, return result; } -cfdp::TlvTypes FilestoreRequestTlv::getType() const { return cfdp::TlvTypes::FILESTORE_REQUEST; } +cfdp::TlvType FilestoreRequestTlv::getType() const { return cfdp::TlvType::FILESTORE_REQUEST; } diff --git a/src/fsfw/cfdp/tlv/FilestoreRequestTlv.h b/src/fsfw/cfdp/tlv/FilestoreRequestTlv.h index 5acb0ef4..02e639b8 100644 --- a/src/fsfw/cfdp/tlv/FilestoreRequestTlv.h +++ b/src/fsfw/cfdp/tlv/FilestoreRequestTlv.h @@ -9,9 +9,9 @@ class FilestoreRequestTlv : public cfdp::FilestoreTlvBase { public: - FilestoreRequestTlv(cfdp::FilestoreActionCode actionCode, cfdp::Lv &firstFileName); + FilestoreRequestTlv(cfdp::FilestoreActionCode actionCode, cfdp::StringLv &firstFileName); - FilestoreRequestTlv(cfdp::Lv &firstFileName); + explicit FilestoreRequestTlv(cfdp::StringLv &firstFileName); void setSecondFileName(cfdp::Lv *secondFileName); @@ -29,8 +29,8 @@ class FilestoreRequestTlv : public cfdp::FilestoreTlvBase { ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, Endianness streamEndianness) override; - uint8_t getLengthField() const override; - cfdp::TlvTypes getType() const override; + [[nodiscard]] uint8_t getLengthField() const override; + [[nodiscard]] cfdp::TlvType getType() const override; private: cfdp::Lv *secondFileName = nullptr; diff --git a/src/fsfw/cfdp/tlv/FilestoreResponseTlv.cpp b/src/fsfw/cfdp/tlv/FilestoreResponseTlv.cpp index 53aaaf8f..38b56077 100644 --- a/src/fsfw/cfdp/tlv/FilestoreResponseTlv.cpp +++ b/src/fsfw/cfdp/tlv/FilestoreResponseTlv.cpp @@ -1,10 +1,10 @@ #include "FilestoreResponseTlv.h" FilestoreResponseTlv::FilestoreResponseTlv(cfdp::FilestoreActionCode actionCode, uint8_t statusCode, - cfdp::Lv &firstFileName, cfdp::Lv *fsMsg) + cfdp::StringLv &firstFileName, cfdp::Lv *fsMsg) : FilestoreTlvBase(actionCode, firstFileName), statusCode(statusCode), filestoreMsg(fsMsg) {} -FilestoreResponseTlv::FilestoreResponseTlv(cfdp::Lv &firstFileName, cfdp::Lv *fsMsg) +FilestoreResponseTlv::FilestoreResponseTlv(cfdp::StringLv &firstFileName, cfdp::Lv *fsMsg) : FilestoreTlvBase(firstFileName), statusCode(0), filestoreMsg(fsMsg) {} uint8_t FilestoreResponseTlv::getLengthField() const { @@ -20,12 +20,12 @@ uint8_t FilestoreResponseTlv::getLengthField() const { return 1 + firstFileName.getSerializedSize() + optFieldsLen; } -void FilestoreResponseTlv::setSecondFileName(cfdp::Lv *secondFileName) { - this->secondFileName = secondFileName; +void FilestoreResponseTlv::setSecondFileName(cfdp::StringLv *secondFileName_) { + this->secondFileName = secondFileName_; } -void FilestoreResponseTlv::setFilestoreMessage(cfdp::Lv *filestoreMsg) { - this->filestoreMsg = filestoreMsg; +void FilestoreResponseTlv::setFilestoreMessage(cfdp::Lv *filestoreMsg_) { + this->filestoreMsg = filestoreMsg_; } ReturnValue_t FilestoreResponseTlv::serialize(uint8_t **buffer, size_t *size, size_t maxSize, @@ -112,4 +112,4 @@ ReturnValue_t FilestoreResponseTlv::deSerialize(const cfdp::Tlv &tlv, Endianness uint8_t FilestoreResponseTlv::getStatusCode() const { return statusCode; } -cfdp::TlvTypes FilestoreResponseTlv::getType() const { return cfdp::TlvTypes::FILESTORE_RESPONSE; } +cfdp::TlvType FilestoreResponseTlv::getType() const { return cfdp::TlvType::FILESTORE_RESPONSE; } diff --git a/src/fsfw/cfdp/tlv/FilestoreResponseTlv.h b/src/fsfw/cfdp/tlv/FilestoreResponseTlv.h index 7b68ba57..110f1bb4 100644 --- a/src/fsfw/cfdp/tlv/FilestoreResponseTlv.h +++ b/src/fsfw/cfdp/tlv/FilestoreResponseTlv.h @@ -4,17 +4,18 @@ #include "Lv.h" #include "TlvIF.h" #include "fsfw/cfdp/tlv/FilestoreTlvBase.h" +#include "fsfw/cfdp/tlv/StringLv.h" #include "fsfw/cfdp/tlv/Tlv.h" class FilestoreResponseTlv : public cfdp::FilestoreTlvBase { public: - FilestoreResponseTlv(cfdp::Lv& firstFileName, cfdp::Lv* fsMsg); + FilestoreResponseTlv(cfdp::StringLv& firstFileName, cfdp::Lv* fsMsg); FilestoreResponseTlv(cfdp::FilestoreActionCode actionCode, uint8_t statusCode, - cfdp::Lv& firstFileName, cfdp::Lv* fsMsg); + cfdp::StringLv& firstFileName, cfdp::Lv* fsMsg); - uint8_t getStatusCode() const; - void setSecondFileName(cfdp::Lv* secondFileName); + [[nodiscard]] uint8_t getStatusCode() const; + void setSecondFileName(cfdp::StringLv* secondFileName); void setFilestoreMessage(cfdp::Lv* filestoreMsg); ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, @@ -31,12 +32,12 @@ class FilestoreResponseTlv : public cfdp::FilestoreTlvBase { ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, Endianness streamEndianness) override; - uint8_t getLengthField() const override; - cfdp::TlvTypes getType() const override; + [[nodiscard]] uint8_t getLengthField() const override; + [[nodiscard]] cfdp::TlvType getType() const override; private: uint8_t statusCode; - cfdp::Lv* secondFileName = nullptr; + cfdp::StringLv* secondFileName = nullptr; cfdp::Lv* filestoreMsg = nullptr; ReturnValue_t deSerializeFromValue(const uint8_t** buffer, size_t* size, diff --git a/src/fsfw/cfdp/tlv/FilestoreTlvBase.h b/src/fsfw/cfdp/tlv/FilestoreTlvBase.h index c37cb0ad..a5974087 100644 --- a/src/fsfw/cfdp/tlv/FilestoreTlvBase.h +++ b/src/fsfw/cfdp/tlv/FilestoreTlvBase.h @@ -11,6 +11,7 @@ #include #include +#include "StringLv.h" #include "fsfw/FSFW.h" namespace cfdp { @@ -65,8 +66,8 @@ static constexpr uint8_t FSR_DENY_DIR_NOT_ALLOWED = 0b0010; class FilestoreTlvBase : public TlvIF { public: - FilestoreTlvBase(cfdp::Lv& firstFileName) : firstFileName(firstFileName){}; - FilestoreTlvBase(FilestoreActionCode actionCode, cfdp::Lv& firstFileName) + explicit FilestoreTlvBase(cfdp::StringLv& firstFileName) : firstFileName(firstFileName){}; + FilestoreTlvBase(FilestoreActionCode actionCode, cfdp::StringLv& firstFileName) : actionCode(actionCode), firstFileName(firstFileName){}; ReturnValue_t commonSerialize(uint8_t** buffer, size_t* size, size_t maxSize, @@ -101,7 +102,7 @@ class FilestoreTlvBase : public TlvIF { if (*size < 3) { return SerializeIF::STREAM_TOO_SHORT; } - cfdp::TlvTypes type = static_cast(**buffer); + auto type = static_cast(**buffer); if (type != getType()) { return cfdp::INVALID_TLV_TYPE; } @@ -117,7 +118,7 @@ class FilestoreTlvBase : public TlvIF { return returnvalue::OK; } - bool requiresSecondFileName() const { + [[nodiscard]] bool requiresSecondFileName() const { using namespace cfdp; if (actionCode == FilestoreActionCode::RENAME_FILE or actionCode == FilestoreActionCode::APPEND_FILE or @@ -141,9 +142,9 @@ class FilestoreTlvBase : public TlvIF { #endif } - FilestoreActionCode getActionCode() const { return actionCode; } + [[nodiscard]] FilestoreActionCode getActionCode() const { return actionCode; } - void setActionCode(FilestoreActionCode actionCode) { this->actionCode = actionCode; } + void setActionCode(FilestoreActionCode actionCode_) { this->actionCode = actionCode_; } cfdp::Lv& getFirstFileName() { return firstFileName; } @@ -160,11 +161,11 @@ class FilestoreTlvBase : public TlvIF { return result; } - size_t getSerializedSize() const override { return getLengthField() + 2; } + [[nodiscard]] size_t getSerializedSize() const override { return getLengthField() + 2; } protected: FilestoreActionCode actionCode = FilestoreActionCode::INVALID; - cfdp::Lv& firstFileName; + cfdp::StringLv& firstFileName; }; } // namespace cfdp diff --git a/src/fsfw/cfdp/tlv/FlowLabelTlv.cpp b/src/fsfw/cfdp/tlv/FlowLabelTlv.cpp index 938af9f4..5f225669 100644 --- a/src/fsfw/cfdp/tlv/FlowLabelTlv.cpp +++ b/src/fsfw/cfdp/tlv/FlowLabelTlv.cpp @@ -1,4 +1,4 @@ #include "FlowLabelTlv.h" FlowLabelTlv::FlowLabelTlv(uint8_t* value, size_t size) - : Tlv(cfdp::TlvTypes::FLOW_LABEL, value, size) {} + : Tlv(cfdp::TlvType::FLOW_LABEL, value, size) {} diff --git a/src/fsfw/cfdp/tlv/Lv.cpp b/src/fsfw/cfdp/tlv/Lv.cpp index 33c0e381..e7fa414a 100644 --- a/src/fsfw/cfdp/tlv/Lv.cpp +++ b/src/fsfw/cfdp/tlv/Lv.cpp @@ -6,6 +6,12 @@ cfdp::Lv::Lv(const uint8_t* value, size_t size) : value(value, size, true) { } } +cfdp::Lv::Lv(const std::vector& data) : value(data.data(), data.size(), true) { + if (!data.empty()) { + zeroLen = false; + } +} + cfdp::Lv::Lv() : value(static_cast(nullptr), 0, true) {} cfdp::Lv::Lv(const Lv& other) @@ -17,11 +23,11 @@ cfdp::Lv::Lv(const Lv& other) cfdp::Lv& cfdp::Lv::operator=(const Lv& other) { size_t otherSize = 0; - uint8_t* value = const_cast(other.getValue(&otherSize)); - if (value == nullptr or otherSize == 0) { + auto* otherVal = const_cast(other.getValue(&otherSize)); + if (otherVal == nullptr or otherSize == 0) { this->zeroLen = true; } - this->value.setConstBuffer(value, otherSize); + this->value.setConstBuffer(otherVal, otherSize); return *this; } diff --git a/src/fsfw/cfdp/tlv/Lv.h b/src/fsfw/cfdp/tlv/Lv.h index 29764433..efabfdef 100644 --- a/src/fsfw/cfdp/tlv/Lv.h +++ b/src/fsfw/cfdp/tlv/Lv.h @@ -1,5 +1,7 @@ -#ifndef FSFW_SRC_FSFW_CFDP_LV_H_ -#define FSFW_SRC_FSFW_CFDP_LV_H_ +#ifndef FSFW_CFDP_LV_H_ +#define FSFW_CFDP_LV_H_ + +#include #include "fsfw/serialize/SerialBufferAdapter.h" @@ -12,18 +14,17 @@ namespace cfdp { */ class Lv : public SerializeIF { public: + explicit Lv(const std::vector& data); Lv(const uint8_t* value, size_t size); Lv(); - // Delete copy ctor and assingment ctor for now because this class contains a reference to - // data Lv(const Lv&); Lv& operator=(const Lv&); ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, Endianness streamEndianness) const override; - size_t getSerializedSize() const override; + [[nodiscard]] size_t getSerializedSize() const override; /** * @brief Deserialize a LV field from a raw buffer @@ -50,4 +51,4 @@ class Lv : public SerializeIF { } // namespace cfdp -#endif /* FSFW_SRC_FSFW_CFDP_LV_H_ */ +#endif /* FSFW_CFDP_LV_H_ */ diff --git a/src/fsfw/cfdp/tlv/MessageToUserTlv.cpp b/src/fsfw/cfdp/tlv/MessageToUserTlv.cpp index 9034552b..9a3e55ff 100644 --- a/src/fsfw/cfdp/tlv/MessageToUserTlv.cpp +++ b/src/fsfw/cfdp/tlv/MessageToUserTlv.cpp @@ -1,6 +1,9 @@ #include "MessageToUserTlv.h" -MessageToUserTlv::MessageToUserTlv(uint8_t *value, size_t size) - : Tlv(cfdp::TlvTypes::MSG_TO_USER, value, size) {} +MessageToUserTlv::MessageToUserTlv(uint8_t* value, size_t size) + : Tlv(cfdp::TlvType::MSG_TO_USER, value, size) {} MessageToUserTlv::MessageToUserTlv() : Tlv() {} + +MessageToUserTlv::MessageToUserTlv(const std::vector& data) + : Tlv(cfdp::TlvType::MSG_TO_USER, data.data(), data.size()) {} diff --git a/src/fsfw/cfdp/tlv/MessageToUserTlv.h b/src/fsfw/cfdp/tlv/MessageToUserTlv.h index 1d00bf31..e7f63ed2 100644 --- a/src/fsfw/cfdp/tlv/MessageToUserTlv.h +++ b/src/fsfw/cfdp/tlv/MessageToUserTlv.h @@ -1,12 +1,15 @@ #ifndef FSFW_SRC_FSFW_CFDP_TLV_MESSAGETOUSERTLV_H_ #define FSFW_SRC_FSFW_CFDP_TLV_MESSAGETOUSERTLV_H_ +#include + #include "Tlv.h" class MessageToUserTlv : public cfdp::Tlv { public: MessageToUserTlv(); MessageToUserTlv(uint8_t* value, size_t size); + explicit MessageToUserTlv(const std::vector& data); private: }; diff --git a/src/fsfw/cfdp/tlv/StringLv.cpp b/src/fsfw/cfdp/tlv/StringLv.cpp new file mode 100644 index 00000000..60c278a7 --- /dev/null +++ b/src/fsfw/cfdp/tlv/StringLv.cpp @@ -0,0 +1,9 @@ +#include "StringLv.h" + +cfdp::StringLv::StringLv(const std::string& fileName) + : Lv(reinterpret_cast(fileName.data()), fileName.size()) {} + +cfdp::StringLv::StringLv(const char* filename, size_t len) + : Lv(reinterpret_cast(filename), len) {} + +cfdp::StringLv::StringLv() : Lv() {} diff --git a/src/fsfw/cfdp/tlv/StringLv.h b/src/fsfw/cfdp/tlv/StringLv.h new file mode 100644 index 00000000..6c200b8b --- /dev/null +++ b/src/fsfw/cfdp/tlv/StringLv.h @@ -0,0 +1,22 @@ +#ifndef FSFW_CFDP_STRINGLV_H +#define FSFW_CFDP_STRINGLV_H + +#include + +#include "Lv.h" + +namespace cfdp { + +class StringLv : public Lv { + public: + StringLv(); + explicit StringLv(const std::string& fileName); + explicit StringLv(const char* filename, size_t len); + + // Delete the move constructor to avoid passing in a temporary + StringLv(const std::string&&) = delete; +}; + +} // namespace cfdp + +#endif // FSFW_CFDP_STRINGLV_H diff --git a/src/fsfw/cfdp/tlv/Tlv.cpp b/src/fsfw/cfdp/tlv/Tlv.cpp index 9d5f7f15..c3fce612 100644 --- a/src/fsfw/cfdp/tlv/Tlv.cpp +++ b/src/fsfw/cfdp/tlv/Tlv.cpp @@ -1,6 +1,6 @@ #include "Tlv.h" -cfdp::Tlv::Tlv(TlvTypes type, const uint8_t *value, size_t size) +cfdp::Tlv::Tlv(TlvType type, const uint8_t *value, size_t size) : type(type), value(value, size, true) { if (size > 0) { zeroLen = false; @@ -17,7 +17,7 @@ ReturnValue_t cfdp::Tlv::serialize(uint8_t **buffer, size_t *size, size_t maxSiz if (*size + 2 > maxSize) { return BUFFER_TOO_SHORT; } - if (type == TlvTypes::INVALID_TLV) { + if (type == TlvType::INVALID_TLV) { return INVALID_TLV_TYPE; } **buffer = type; @@ -59,7 +59,7 @@ ReturnValue_t cfdp::Tlv::deSerialize(const uint8_t **buffer, size_t *size, return INVALID_TLV_TYPE; } - type = static_cast(rawType); + type = static_cast(rawType); *buffer += 1; *size -= 1; @@ -83,7 +83,7 @@ ReturnValue_t cfdp::Tlv::deSerialize(const uint8_t **buffer, size_t *size, const uint8_t *cfdp::Tlv::getValue() const { return value.getConstBuffer(); } -cfdp::TlvTypes cfdp::Tlv::getType() const { return type; } +cfdp::TlvType cfdp::Tlv::getType() const { return type; } bool cfdp::Tlv::checkType(uint8_t rawType) { if (rawType != 0x03 and rawType <= 6) { @@ -101,4 +101,4 @@ void cfdp::Tlv::setValue(uint8_t *value, size_t len) { uint8_t cfdp::Tlv::getLengthField() const { return this->value.getSerializedSize() - 1; } -void cfdp::Tlv::setType(TlvTypes type) { this->type = type; } +void cfdp::Tlv::setType(TlvType type) { this->type = type; } diff --git a/src/fsfw/cfdp/tlv/Tlv.h b/src/fsfw/cfdp/tlv/Tlv.h index dded5652..786a3b79 100644 --- a/src/fsfw/cfdp/tlv/Tlv.h +++ b/src/fsfw/cfdp/tlv/Tlv.h @@ -13,7 +13,7 @@ namespace cfdp { */ class Tlv : public TlvIF { public: - Tlv(TlvTypes type, const uint8_t *value, size_t size); + Tlv(TlvType type, const uint8_t *value, size_t size); Tlv(); /** @@ -27,10 +27,10 @@ class Tlv : public TlvIF { * - INVALID_TLV_TYPE * - SerializeIF returncode on wrong serialization parameters */ - virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, - Endianness streamEndianness) const override; + ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const override; - virtual size_t getSerializedSize() const override; + [[nodiscard]] size_t getSerializedSize() const override; /** * @brief Deserialize a LV field from a raw buffer. Zero-copy implementation @@ -41,21 +41,21 @@ class Tlv : public TlvIF { * - INVALID_TLV_TYPE * - SerializeIF returncode on wrong deserialization parameters */ - virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, - Endianness streamEndianness) override; + ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override; void setValue(uint8_t *value, size_t len); - const uint8_t *getValue() const; - void setType(TlvTypes type); - TlvTypes getType() const override; - uint8_t getLengthField() const override; + [[nodiscard]] const uint8_t *getValue() const; + void setType(TlvType type); + [[nodiscard]] TlvType getType() const override; + [[nodiscard]] uint8_t getLengthField() const override; private: bool checkType(uint8_t rawType); bool zeroLen = true; - TlvTypes type = TlvTypes::INVALID_TLV; + TlvType type = TlvType::INVALID_TLV; SerialBufferAdapter value; }; diff --git a/src/fsfw/cfdp/tlv/TlvIF.h b/src/fsfw/cfdp/tlv/TlvIF.h index 9a02b241..317d970a 100644 --- a/src/fsfw/cfdp/tlv/TlvIF.h +++ b/src/fsfw/cfdp/tlv/TlvIF.h @@ -8,7 +8,7 @@ class TlvIF : public SerializeIF { virtual ~TlvIF(){}; virtual uint8_t getLengthField() const = 0; - virtual cfdp::TlvTypes getType() const = 0; + virtual cfdp::TlvType getType() const = 0; }; #endif /* FSFW_SRC_FSFW_CFDP_TLVIF_H_ */ diff --git a/src/fsfw/container/DynamicFIFO.h b/src/fsfw/container/DynamicFIFO.h index 96f55938..5d1d46e7 100644 --- a/src/fsfw/container/DynamicFIFO.h +++ b/src/fsfw/container/DynamicFIFO.h @@ -18,7 +18,8 @@ template class DynamicFIFO : public FIFOBase { public: - DynamicFIFO(size_t maxCapacity) : FIFOBase(nullptr, maxCapacity), fifoVector(maxCapacity) { + explicit DynamicFIFO(size_t maxCapacity) + : FIFOBase(nullptr, maxCapacity), fifoVector(maxCapacity) { // trying to pass the pointer of the uninitialized vector // to the FIFOBase constructor directly lead to a super evil bug. // So we do it like this now. diff --git a/src/fsfw/container/FIFOBase.h b/src/fsfw/container/FIFOBase.h index bb92790c..b215dae4 100644 --- a/src/fsfw/container/FIFOBase.h +++ b/src/fsfw/container/FIFOBase.h @@ -15,7 +15,7 @@ class FIFOBase { /** Default ctor, takes pointer to first entry of underlying container * and maximum capacity */ - FIFOBase(T* values, const size_t maxCapacity); + FIFOBase(T* values, size_t maxCapacity); /** * Insert value into FIFO @@ -60,7 +60,7 @@ class FIFOBase { * Get maximal capacity of fifo * @return size_t with max capacity of this fifo */ - size_t getMaxCapacity() const; + [[nodiscard]] size_t getMaxCapacity() const; protected: void setContainer(T* data); diff --git a/src/fsfw/datapoollocal/HasLocalDataPoolIF.h b/src/fsfw/datapoollocal/HasLocalDataPoolIF.h index 8530fd77..488e0cd4 100644 --- a/src/fsfw/datapoollocal/HasLocalDataPoolIF.h +++ b/src/fsfw/datapoollocal/HasLocalDataPoolIF.h @@ -3,11 +3,11 @@ #include -#include "../datapool/PoolEntryIF.h" -#include "../housekeeping/HousekeepingMessage.h" -#include "../ipc/MessageQueueSenderIF.h" -#include "../serviceinterface/ServiceInterface.h" #include "LocalDataPoolManager.h" +#include "fsfw/datapool/PoolEntryIF.h" +#include "fsfw/housekeeping/HousekeepingMessage.h" +#include "fsfw/ipc/MessageQueueSenderIF.h" +#include "fsfw/serviceinterface.h" #include "localPoolDefinitions.h" class AccessPoolManagerIF; diff --git a/src/fsfw/events/EventReportingProxyIF.h b/src/fsfw/events/EventReportingProxyIF.h index c6034c9f..51f8ed1d 100644 --- a/src/fsfw/events/EventReportingProxyIF.h +++ b/src/fsfw/events/EventReportingProxyIF.h @@ -5,7 +5,7 @@ class EventReportingProxyIF { public: - virtual ~EventReportingProxyIF() {} + virtual ~EventReportingProxyIF() = default; virtual void forwardEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0) const = 0; diff --git a/src/fsfw/events/fwSubsystemIdRanges.h b/src/fsfw/events/fwSubsystemIdRanges.h index fa4351e9..d8e4ade6 100644 --- a/src/fsfw/events/fwSubsystemIdRanges.h +++ b/src/fsfw/events/fwSubsystemIdRanges.h @@ -19,6 +19,7 @@ enum : uint8_t { HK = 73, SYSTEM_MANAGER = 74, SYSTEM_MANAGER_1 = 75, + TMTC_DISTRIBUTION = 76, SYSTEM_1 = 79, PUS_SERVICE_1 = 80, PUS_SERVICE_2 = 82, diff --git a/src/fsfw/filesystem.h b/src/fsfw/filesystem.h new file mode 100644 index 00000000..c4a6ebc6 --- /dev/null +++ b/src/fsfw/filesystem.h @@ -0,0 +1,7 @@ +#ifndef FSFW_FILESYSTEM_H +#define FSFW_FILESYSTEM_H + +#include "filesystem/FileSystemArgsIF.h" +#include "filesystem/HasFileSystemIF.h" + +#endif // FSFW_FILESYSTEM_H diff --git a/src/fsfw/filesystem/CMakeLists.txt b/src/fsfw/filesystem/CMakeLists.txt new file mode 100644 index 00000000..a0618d97 --- /dev/null +++ b/src/fsfw/filesystem/CMakeLists.txt @@ -0,0 +1 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE GenericFileSystemMessage.cpp) diff --git a/src/fsfw/memory/FileSystemArgsIF.h b/src/fsfw/filesystem/FileSystemArgsIF.h similarity index 89% rename from src/fsfw/memory/FileSystemArgsIF.h rename to src/fsfw/filesystem/FileSystemArgsIF.h index f1617f62..656764fa 100644 --- a/src/fsfw/memory/FileSystemArgsIF.h +++ b/src/fsfw/filesystem/FileSystemArgsIF.h @@ -7,7 +7,7 @@ */ class FileSystemArgsIF { public: - virtual ~FileSystemArgsIF(){}; + virtual ~FileSystemArgsIF() = default; }; #endif /* FSFW_SRC_FSFW_MEMORY_FILESYSTEMARGS_H_ */ diff --git a/src/fsfw/memory/GenericFileSystemMessage.cpp b/src/fsfw/filesystem/GenericFileSystemMessage.cpp similarity index 99% rename from src/fsfw/memory/GenericFileSystemMessage.cpp rename to src/fsfw/filesystem/GenericFileSystemMessage.cpp index cdbfeb62..496a973f 100644 --- a/src/fsfw/memory/GenericFileSystemMessage.cpp +++ b/src/fsfw/filesystem/GenericFileSystemMessage.cpp @@ -1,4 +1,4 @@ -#include "fsfw/memory/GenericFileSystemMessage.h" +#include "GenericFileSystemMessage.h" #include "fsfw/objectmanager/ObjectManager.h" #include "fsfw/storagemanager/StorageManagerIF.h" diff --git a/src/fsfw/memory/GenericFileSystemMessage.h b/src/fsfw/filesystem/GenericFileSystemMessage.h similarity index 100% rename from src/fsfw/memory/GenericFileSystemMessage.h rename to src/fsfw/filesystem/GenericFileSystemMessage.h diff --git a/src/fsfw/filesystem/HasFileSystemIF.h b/src/fsfw/filesystem/HasFileSystemIF.h new file mode 100644 index 00000000..6f7112ad --- /dev/null +++ b/src/fsfw/filesystem/HasFileSystemIF.h @@ -0,0 +1,175 @@ +#ifndef FSFW_MEMORY_HASFILESYSTEMIF_H_ +#define FSFW_MEMORY_HASFILESYSTEMIF_H_ + +#include + +#include "FileSystemArgsIF.h" +#include "fsfw/ipc/MessageQueueIF.h" +#include "fsfw/ipc/messageQueueDefinitions.h" +#include "fsfw/returnvalues/FwClassIds.h" +#include "fsfw/returnvalues/returnvalue.h" + +struct FilesystemParams { + explicit FilesystemParams(const char* path) : path(path) {} + + const char* path; + FileSystemArgsIF* args = nullptr; +}; + +struct FileOpParams { + FileOpParams(const char* path, size_t size) : fsParams(path), size(size) {} + + [[nodiscard]] const char* path() const { return fsParams.path; } + + [[nodiscard]] FileSystemArgsIF* args() const { return fsParams.args; } + + FilesystemParams fsParams; + size_t size; + size_t offset = 0; +}; + +/** + * @brief Generic interface for objects which expose a file system to enable + * message based file handling. + * @author J. Meier, R. Mueller + */ +class HasFileSystemIF { + public: + static constexpr uint8_t INTERFACE_ID = CLASS_ID::FILE_SYSTEM; + + //! [EXPORT] : P1: Can be file system specific error code + static constexpr ReturnValue_t GENERIC_FILE_ERROR = MAKE_RETURN_CODE(0); + static constexpr ReturnValue_t GENERIC_DIR_ERROR = MAKE_RETURN_CODE(1); + static constexpr ReturnValue_t GENERIC_RENAME_ERROR = MAKE_RETURN_CODE(3); + + //! [EXPORT] : File system is currently busy + static constexpr ReturnValue_t IS_BUSY = MAKE_RETURN_CODE(4); + //! [EXPORT] : Invalid parameters like file name or repository path + static constexpr ReturnValue_t INVALID_PARAMETERS = MAKE_RETURN_CODE(5); + + static constexpr ReturnValue_t FILE_DOES_NOT_EXIST = MAKE_RETURN_CODE(10); + static constexpr ReturnValue_t FILE_ALREADY_EXISTS = MAKE_RETURN_CODE(11); + static constexpr ReturnValue_t NOT_A_FILE = MAKE_RETURN_CODE(12); + static constexpr ReturnValue_t FILE_LOCKED = MAKE_RETURN_CODE(13); + static constexpr ReturnValue_t PERMISSION_DENIED = MAKE_RETURN_CODE(14); + + static constexpr ReturnValue_t DIRECTORY_DOES_NOT_EXIST = MAKE_RETURN_CODE(21); + static constexpr ReturnValue_t DIRECTORY_ALREADY_EXISTS = MAKE_RETURN_CODE(22); + static constexpr ReturnValue_t NOT_A_DIRECTORY = MAKE_RETURN_CODE(23); + static constexpr ReturnValue_t DIRECTORY_NOT_EMPTY = MAKE_RETURN_CODE(24); + + //! [EXPORT] : P1: Sequence number missing + static constexpr ReturnValue_t SEQUENCE_PACKET_MISSING_WRITE = MAKE_RETURN_CODE(30); + //! [EXPORT] : P1: Sequence number missing + static constexpr ReturnValue_t SEQUENCE_PACKET_MISSING_READ = MAKE_RETURN_CODE(31); + + virtual ~HasFileSystemIF() = default; + + /** + * Function to get the MessageQueueId_t of the implementing object + * @return MessageQueueId_t of the object + */ + [[nodiscard]] virtual MessageQueueId_t getCommandQueue() const { + return MessageQueueIF::NO_QUEUE; + } + + virtual bool fileExists(FilesystemParams params) = 0; + + /** + * Truncate a file, deleting its contents and setting its size to 0 accordingly. + * @param params + * @return + */ + virtual ReturnValue_t truncateFile(FilesystemParams params) = 0; + + /** + * @brief Generic function to write to a file. + * + * @details + * Implementations should not truncate the file. This is equivalent to opening a file with "r+" + * on Unix systems or using ios::out | ios::in with the C++ API. + * @param fileOpInfo General information: File name, size to write, offset, additional arguments + * @param data The data to write to the file + */ + virtual ReturnValue_t writeToFile(FileOpParams params, const uint8_t* data) = 0; + + /** + * @brief Generic function to read from a file. This variant takes a pointer to a buffer and + * performs pointer arithmetic by incrementing the pointer by the read size + * @param fileOpInfo General information: File name, size to write, offset, additional arguments + * @param buffer [in/out] Data will be read into the provided buffer, and the pointer will be + * incremented by the read length + * @param readSize [out] Will be incremented by the read length + * @param maxSize Maximum size of the provided buffer + * @param args + * @return + */ + virtual ReturnValue_t readFromFile(FileOpParams fileOpInfo, uint8_t** buffer, size_t& readSize, + size_t maxSize) = 0; + /** + * Variant of the @readFromFile which does not perform pointer arithmetic. + * @param fileOpInfo General information: File name, size to write, offset, additional arguments + * @param buf + * @param maxSize + * @return + */ + virtual ReturnValue_t readFromFile(FileOpParams fileOpInfo, uint8_t* buf, size_t maxSize) { + size_t dummy = 0; + return readFromFile(fileOpInfo, &buf, dummy, maxSize); + } + + /** + * @brief Generic function to create a new file. + * @param repositoryPath + * @param filename + * @param data + * @param size + * @param args Any other arguments which an implementation might require + * @return + */ + virtual ReturnValue_t createFile(FilesystemParams params) { + return createFile(params, nullptr, 0); + } + virtual ReturnValue_t createFile(FilesystemParams params, const uint8_t* data, size_t size) = 0; + + /** + * @brief Generic function to delete a file. + * @param repositoryPath + * @param filename + * @param args Any other arguments which an implementation might require + * @return + */ + virtual ReturnValue_t removeFile(const char* path, FileSystemArgsIF* args) = 0; + virtual ReturnValue_t removeFile(const char* path) { return removeFile(path, nullptr); } + + /** + * @brief Generic function to create a directory + * @param repositoryPath + * @param Equivalent to the -p flag in Unix systems. If some required parent directories + * do not exist, create them as well + * @param args Any other arguments which an implementation might require + * @return + */ + virtual ReturnValue_t createDirectory(FilesystemParams params, bool createParentDirs) = 0; + virtual ReturnValue_t createDirectory(FilesystemParams params) { + return createDirectory(params, false); + } + + /** + * @brief Generic function to remove a directory + * @param repositoryPath + * @param args Any other arguments which an implementation might require + */ + virtual ReturnValue_t removeDirectory(FilesystemParams params, bool deleteRecurively) = 0; + virtual ReturnValue_t removeDirectory(FilesystemParams params) { + return removeDirectory(params, false); + } + + virtual ReturnValue_t rename(const char* oldPath, const char* newPath) { + return rename(oldPath, newPath, nullptr); + } + virtual ReturnValue_t rename(const char* oldPath, const char* newPath, + FileSystemArgsIF* args) = 0; +}; + +#endif /* FSFW_MEMORY_HASFILESYSTEMIF_H_ */ diff --git a/src/fsfw/ipc/CommandMessageCleaner.cpp b/src/fsfw/ipc/CommandMessageCleaner.cpp index 328441e6..0a43774b 100644 --- a/src/fsfw/ipc/CommandMessageCleaner.cpp +++ b/src/fsfw/ipc/CommandMessageCleaner.cpp @@ -1,10 +1,9 @@ #include "fsfw/ipc/CommandMessageCleaner.h" -#include "fsfw/FSFW.h" #include "fsfw/devicehandlers/DeviceHandlerMessage.h" +#include "fsfw/filesystem/GenericFileSystemMessage.h" #include "fsfw/health/HealthMessage.h" #include "fsfw/housekeeping/HousekeepingMessage.h" -#include "fsfw/memory/GenericFileSystemMessage.h" #include "fsfw/memory/MemoryMessage.h" #include "fsfw/modes/ModeMessage.h" #include "fsfw/monitoring/MonitoringMessage.h" diff --git a/src/fsfw/memory/CMakeLists.txt b/src/fsfw/memory/CMakeLists.txt index 9e591bae..9d9c90c4 100644 --- a/src/fsfw/memory/CMakeLists.txt +++ b/src/fsfw/memory/CMakeLists.txt @@ -1,2 +1 @@ -target_sources(${LIB_FSFW_NAME} PRIVATE MemoryHelper.cpp MemoryMessage.cpp - GenericFileSystemMessage.cpp) +target_sources(${LIB_FSFW_NAME} PRIVATE MemoryHelper.cpp MemoryMessage.cpp) diff --git a/src/fsfw/memory/HasFileSystemIF.h b/src/fsfw/memory/HasFileSystemIF.h deleted file mode 100644 index 4c081e26..00000000 --- a/src/fsfw/memory/HasFileSystemIF.h +++ /dev/null @@ -1,113 +0,0 @@ -#ifndef FSFW_MEMORY_HASFILESYSTEMIF_H_ -#define FSFW_MEMORY_HASFILESYSTEMIF_H_ - -#include - -#include "FileSystemArgsIF.h" -#include "fsfw/ipc/messageQueueDefinitions.h" -#include "fsfw/returnvalues/FwClassIds.h" -#include "fsfw/returnvalues/returnvalue.h" - -/** - * @brief Generic interface for objects which expose a file system to enable - * message based file handling. - * @author J. Meier, R. Mueller - */ -class HasFileSystemIF { - public: - static constexpr uint8_t INTERFACE_ID = CLASS_ID::FILE_SYSTEM; - - //! [EXPORT] : P1: Can be file system specific error code - static constexpr ReturnValue_t GENERIC_FILE_ERROR = MAKE_RETURN_CODE(0); - //! [EXPORT] : File system is currently busy - static constexpr ReturnValue_t IS_BUSY = MAKE_RETURN_CODE(1); - //! [EXPORT] : Invalid parameters like file name or repository path - static constexpr ReturnValue_t INVALID_PARAMETERS = MAKE_RETURN_CODE(2); - - static constexpr ReturnValue_t FILE_DOES_NOT_EXIST = MAKE_RETURN_CODE(5); - static constexpr ReturnValue_t FILE_ALREADY_EXISTS = MAKE_RETURN_CODE(6); - static constexpr ReturnValue_t FILE_LOCKED = MAKE_RETURN_CODE(7); - - static constexpr ReturnValue_t DIRECTORY_DOES_NOT_EXIST = MAKE_RETURN_CODE(10); - static constexpr ReturnValue_t DIRECTORY_ALREADY_EXISTS = MAKE_RETURN_CODE(11); - static constexpr ReturnValue_t DIRECTORY_NOT_EMPTY = MAKE_RETURN_CODE(12); - - //! [EXPORT] : P1: Sequence number missing - static constexpr ReturnValue_t SEQUENCE_PACKET_MISSING_WRITE = MAKE_RETURN_CODE(15); - //! [EXPORT] : P1: Sequence number missing - static constexpr ReturnValue_t SEQUENCE_PACKET_MISSING_READ = MAKE_RETURN_CODE(16); - - virtual ~HasFileSystemIF() {} - - /** - * Function to get the MessageQueueId_t of the implementing object - * @return MessageQueueId_t of the object - */ - virtual MessageQueueId_t getCommandQueue() const = 0; - - /** - * @brief Generic function to append to file. - * @param dirname Directory of the file - * @param filename The filename of the file - * @param data The data to write to the file - * @param size The size of the data to write - * @param packetNumber Current packet number. Can be used to verify that - * there are no missing packets. - * @param args Any other arguments which an implementation might require. - * @param bytesWritten Actual bytes written to file - * For large files the write procedure must be split in multiple calls - * to writeToFile - */ - virtual ReturnValue_t appendToFile(const char* repositoryPath, const char* filename, - const uint8_t* data, size_t size, uint16_t packetNumber, - FileSystemArgsIF* args = nullptr) = 0; - - /** - * @brief Generic function to create a new file. - * @param repositoryPath - * @param filename - * @param data - * @param size - * @param args Any other arguments which an implementation might require - * @return - */ - virtual ReturnValue_t createFile(const char* repositoryPath, const char* filename, - const uint8_t* data = nullptr, size_t size = 0, - FileSystemArgsIF* args = nullptr) = 0; - - /** - * @brief Generic function to delete a file. - * @param repositoryPath - * @param filename - * @param args Any other arguments which an implementation might require - * @return - */ - virtual ReturnValue_t removeFile(const char* repositoryPath, const char* filename, - FileSystemArgsIF* args = nullptr) = 0; - - /** - * @brief Generic function to create a directory - * @param repositoryPath - * @param Equivalent to the -p flag in Unix systems. If some required parent directories - * do not exist, create them as well - * @param args Any other arguments which an implementation might require - * @return - */ - virtual ReturnValue_t createDirectory(const char* repositoryPath, const char* dirname, - bool createParentDirs, - FileSystemArgsIF* args = nullptr) = 0; - - /** - * @brief Generic function to remove a directory - * @param repositoryPath - * @param args Any other arguments which an implementation might require - */ - virtual ReturnValue_t removeDirectory(const char* repositoryPath, const char* dirname, - bool deleteRecurively = false, - FileSystemArgsIF* args = nullptr) = 0; - - virtual ReturnValue_t renameFile(const char* repositoryPath, const char* oldFilename, - const char* newFilename, FileSystemArgsIF* args = nullptr) = 0; -}; - -#endif /* FSFW_MEMORY_HASFILESYSTEMIF_H_ */ diff --git a/src/fsfw/osal/common/TcpTmTcBridge.cpp b/src/fsfw/osal/common/TcpTmTcBridge.cpp index 6b3561ba..f99a8bc1 100644 --- a/src/fsfw/osal/common/TcpTmTcBridge.cpp +++ b/src/fsfw/osal/common/TcpTmTcBridge.cpp @@ -18,7 +18,7 @@ TcpTmTcBridge::TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination, object_id_t tmStoreId, object_id_t tcStoreId) - : TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) { + : TmTcBridge("TCP TMTC Bridge", objectId, tcDestination, tmStoreId, tcStoreId) { mutex = MutexFactory::instance()->createMutex(); // Connection is always up, TM is requested by connecting to server and receiving packets registerCommConnect(); diff --git a/src/fsfw/osal/common/UdpTmTcBridge.cpp b/src/fsfw/osal/common/UdpTmTcBridge.cpp index 0a847271..c0848ceb 100644 --- a/src/fsfw/osal/common/UdpTmTcBridge.cpp +++ b/src/fsfw/osal/common/UdpTmTcBridge.cpp @@ -22,7 +22,7 @@ const std::string UdpTmTcBridge::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_POR UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, const std::string &udpServerPort_, object_id_t tmStoreId, object_id_t tcStoreId) - : TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) { + : TmTcBridge("UDP TMTC Bridge", objectId, tcDestination, tmStoreId, tcStoreId) { if (udpServerPort_.empty()) { udpServerPort = DEFAULT_SERVER_PORT; } else { diff --git a/src/fsfw/pus/CService200ModeCommanding.cpp b/src/fsfw/pus/CService200ModeCommanding.cpp index 69c057ea..d28df59b 100644 --- a/src/fsfw/pus/CService200ModeCommanding.cpp +++ b/src/fsfw/pus/CService200ModeCommanding.cpp @@ -10,8 +10,8 @@ CService200ModeCommanding::CService200ModeCommanding(object_id_t objectId, uint16_t apid, uint8_t serviceId, uint8_t numParallelCommands, uint16_t commandTimeoutSeconds) - : CommandingServiceBase(objectId, apid, serviceId, numParallelCommands, commandTimeoutSeconds) { -} + : CommandingServiceBase(objectId, apid, "PUS 200 Mode MGMT", serviceId, numParallelCommands, + commandTimeoutSeconds) {} CService200ModeCommanding::~CService200ModeCommanding() {} diff --git a/src/fsfw/pus/CService201HealthCommanding.cpp b/src/fsfw/pus/CService201HealthCommanding.cpp index c8458edb..bf21c5bd 100644 --- a/src/fsfw/pus/CService201HealthCommanding.cpp +++ b/src/fsfw/pus/CService201HealthCommanding.cpp @@ -10,8 +10,8 @@ CService201HealthCommanding::CService201HealthCommanding(object_id_t objectId, u uint8_t serviceId, uint8_t numParallelCommands, uint16_t commandTimeoutSeconds) - : CommandingServiceBase(objectId, apid, serviceId, numParallelCommands, commandTimeoutSeconds) { -} + : CommandingServiceBase(objectId, apid, "PUS 201 Health MGMT", serviceId, numParallelCommands, + commandTimeoutSeconds) {} ReturnValue_t CService201HealthCommanding::isValidSubservice(uint8_t subservice) { switch (subservice) { diff --git a/src/fsfw/pus/Service11TelecommandScheduling.tpp b/src/fsfw/pus/Service11TelecommandScheduling.tpp index a0308cc0..47b0e5c8 100644 --- a/src/fsfw/pus/Service11TelecommandScheduling.tpp +++ b/src/fsfw/pus/Service11TelecommandScheduling.tpp @@ -16,7 +16,9 @@ inline Service11TelecommandScheduling::Service11TelecommandScheduli : PusServiceBase(params), RELEASE_TIME_MARGIN_SECONDS(releaseTimeMarginSeconds), debugMode(debugMode), - tcRecipient(tcRecipient) {} + tcRecipient(tcRecipient) { + params.name = "PUS 11 TC Scheduling"; +} template inline Service11TelecommandScheduling::~Service11TelecommandScheduling() = default; diff --git a/src/fsfw/pus/Service17Test.cpp b/src/fsfw/pus/Service17Test.cpp index 0a9db32f..bea2eeb8 100644 --- a/src/fsfw/pus/Service17Test.cpp +++ b/src/fsfw/pus/Service17Test.cpp @@ -8,7 +8,9 @@ Service17Test::Service17Test(PsbParams params) : PusServiceBase(params), storeHelper(params.apid), - tmHelper(params.serviceId, storeHelper, sendHelper) {} + tmHelper(params.serviceId, storeHelper, sendHelper) { + params.name = "PUS 17 Test"; +} Service17Test::~Service17Test() = default; diff --git a/src/fsfw/pus/Service20ParameterManagement.cpp b/src/fsfw/pus/Service20ParameterManagement.cpp index f58a0d6c..e12d47bc 100644 --- a/src/fsfw/pus/Service20ParameterManagement.cpp +++ b/src/fsfw/pus/Service20ParameterManagement.cpp @@ -11,8 +11,8 @@ Service20ParameterManagement::Service20ParameterManagement(object_id_t objectId, uint8_t serviceId, uint8_t numberOfParallelCommands, uint16_t commandTimeoutSeconds) - : CommandingServiceBase(objectId, apid, serviceId, numberOfParallelCommands, - commandTimeoutSeconds) {} + : CommandingServiceBase(objectId, apid, "PUS 20 Parameter MGMT", serviceId, + numberOfParallelCommands, commandTimeoutSeconds) {} Service20ParameterManagement::~Service20ParameterManagement() = default; diff --git a/src/fsfw/pus/Service2DeviceAccess.cpp b/src/fsfw/pus/Service2DeviceAccess.cpp index 6eea1807..517c35e6 100644 --- a/src/fsfw/pus/Service2DeviceAccess.cpp +++ b/src/fsfw/pus/Service2DeviceAccess.cpp @@ -14,8 +14,8 @@ Service2DeviceAccess::Service2DeviceAccess(object_id_t objectId, uint16_t apid, uint8_t serviceId, uint8_t numberOfParallelCommands, uint16_t commandTimeoutSeconds) - : CommandingServiceBase(objectId, apid, serviceId, numberOfParallelCommands, - commandTimeoutSeconds) {} + : CommandingServiceBase(objectId, apid, "PUS 2 Raw Commanding", serviceId, + numberOfParallelCommands, commandTimeoutSeconds) {} Service2DeviceAccess::~Service2DeviceAccess() {} diff --git a/src/fsfw/pus/Service3Housekeeping.cpp b/src/fsfw/pus/Service3Housekeeping.cpp index 5c887572..0a51aa4b 100644 --- a/src/fsfw/pus/Service3Housekeeping.cpp +++ b/src/fsfw/pus/Service3Housekeeping.cpp @@ -5,7 +5,7 @@ #include "fsfw/pus/servicepackets/Service3Packets.h" Service3Housekeeping::Service3Housekeeping(object_id_t objectId, uint16_t apid, uint8_t serviceId) - : CommandingServiceBase(objectId, apid, serviceId, NUM_OF_PARALLEL_COMMANDS, + : CommandingServiceBase(objectId, apid, "PUS 3 HK", serviceId, NUM_OF_PARALLEL_COMMANDS, COMMAND_TIMEOUT_SECONDS) {} Service3Housekeeping::~Service3Housekeeping() {} diff --git a/src/fsfw/pus/Service5EventReporting.cpp b/src/fsfw/pus/Service5EventReporting.cpp index d927bc3e..c1affa6f 100644 --- a/src/fsfw/pus/Service5EventReporting.cpp +++ b/src/fsfw/pus/Service5EventReporting.cpp @@ -14,8 +14,9 @@ Service5EventReporting::Service5EventReporting(PsbParams params, size_t maxNumbe tmHelper(params.serviceId, storeHelper, sendHelper), maxNumberReportsPerCycle(maxNumberReportsPerCycle) { auto mqArgs = MqArgs(getObjectId(), static_cast(this)); - eventQueue = QueueFactory::instance()->createMessageQueue( - messageQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs); + psbParams.name = "PUS 5 Event Reporting"; + eventQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth, + MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs); } Service5EventReporting::~Service5EventReporting() { diff --git a/src/fsfw/pus/Service8FunctionManagement.cpp b/src/fsfw/pus/Service8FunctionManagement.cpp index b9ef6c4d..8b7c6972 100644 --- a/src/fsfw/pus/Service8FunctionManagement.cpp +++ b/src/fsfw/pus/Service8FunctionManagement.cpp @@ -12,8 +12,8 @@ Service8FunctionManagement::Service8FunctionManagement(object_id_t objectId, uin uint8_t serviceId, uint8_t numParallelCommands, uint16_t commandTimeoutSeconds) - : CommandingServiceBase(objectId, apid, serviceId, numParallelCommands, commandTimeoutSeconds) { -} + : CommandingServiceBase(objectId, apid, "PUS 8 Functional Commanding", serviceId, + numParallelCommands, commandTimeoutSeconds) {} Service8FunctionManagement::~Service8FunctionManagement() {} diff --git a/src/fsfw/pus/Service9TimeManagement.cpp b/src/fsfw/pus/Service9TimeManagement.cpp index 698290c9..d19cb518 100644 --- a/src/fsfw/pus/Service9TimeManagement.cpp +++ b/src/fsfw/pus/Service9TimeManagement.cpp @@ -5,7 +5,9 @@ #include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/timemanager/CCSDSTime.h" -Service9TimeManagement::Service9TimeManagement(PsbParams params) : PusServiceBase(params) {} +Service9TimeManagement::Service9TimeManagement(PsbParams params) : PusServiceBase(params) { + params.name = "PUS 9 Time MGMT"; +} Service9TimeManagement::~Service9TimeManagement() = default; diff --git a/src/fsfw/returnvalues/FwClassIds.h b/src/fsfw/returnvalues/FwClassIds.h index 1dfe1cc8..9a5cc812 100644 --- a/src/fsfw/returnvalues/FwClassIds.h +++ b/src/fsfw/returnvalues/FwClassIds.h @@ -34,7 +34,7 @@ enum : uint8_t { FIFO_CLASS, // FF MESSAGE_PROXY, // MQP TRIPLE_REDUNDACY_CHECK, // TRC - PACKET_CHECK, // TCC + TMTC_DISTRIBUTION, // TCC PACKET_DISTRIBUTION, // TCD ACCEPTS_TELECOMMANDS_IF, // ATC PUS_IF, // PUS diff --git a/src/fsfw/serialize/SerialBufferAdapter.cpp b/src/fsfw/serialize/SerialBufferAdapter.cpp index cf28d2ba..01eb76f9 100644 --- a/src/fsfw/serialize/SerialBufferAdapter.cpp +++ b/src/fsfw/serialize/SerialBufferAdapter.cpp @@ -24,12 +24,12 @@ template SerialBufferAdapter::~SerialBufferAdapter() = default; template -ReturnValue_t SerialBufferAdapter::serialize(uint8_t** buffer, size_t* size, +ReturnValue_t SerialBufferAdapter::serialize(uint8_t** buffer_, size_t* size, size_t maxSize, Endianness streamEndianness) const { if (serializeLength) { ReturnValue_t result = - SerializeAdapter::serialize(&bufferLength, buffer, size, maxSize, streamEndianness); + SerializeAdapter::serialize(&bufferLength, buffer_, size, maxSize, streamEndianness); if (result != returnvalue::OK) { return result; } @@ -40,16 +40,16 @@ ReturnValue_t SerialBufferAdapter::serialize(uint8_t** buffer, size_t* } if (this->constBuffer != nullptr) { - std::memcpy(*buffer, this->constBuffer, bufferLength); + std::memcpy(*buffer_, this->constBuffer, bufferLength); } else if (this->buffer != nullptr) { // This will propably be never reached, constBuffer should always be // set if non-const buffer is set. - std::memcpy(*buffer, this->buffer, bufferLength); + std::memcpy(*buffer_, this->buffer, bufferLength); } else { return returnvalue::FAILED; } *size += bufferLength; - (*buffer) += bufferLength; + (*buffer_) += bufferLength; return returnvalue::OK; } @@ -63,7 +63,7 @@ size_t SerialBufferAdapter::getSerializedSize() const { } template -ReturnValue_t SerialBufferAdapter::deSerialize(const uint8_t** buffer, size_t* size, +ReturnValue_t SerialBufferAdapter::deSerialize(const uint8_t** buffer_, size_t* size, Endianness streamEndianness) { if (this->buffer == nullptr) { return returnvalue::FAILED; @@ -72,7 +72,7 @@ ReturnValue_t SerialBufferAdapter::deSerialize(const uint8_t** buffer, if (serializeLength) { count_t lengthField = 0; ReturnValue_t result = - SerializeAdapter::deSerialize(&lengthField, buffer, size, streamEndianness); + SerializeAdapter::deSerialize(&lengthField, buffer_, size, streamEndianness); if (result != returnvalue::OK) { return result; } @@ -84,8 +84,8 @@ ReturnValue_t SerialBufferAdapter::deSerialize(const uint8_t** buffer, if (bufferLength <= *size) { *size -= bufferLength; - std::memcpy(this->buffer, *buffer, bufferLength); - (*buffer) += bufferLength; + std::memcpy(this->buffer, *buffer_, bufferLength); + (*buffer_) += bufferLength; return returnvalue::OK; } else { return STREAM_TOO_SHORT; diff --git a/src/fsfw/serialize/SerialBufferAdapter.h b/src/fsfw/serialize/SerialBufferAdapter.h index b156bb02..9030d7cc 100644 --- a/src/fsfw/serialize/SerialBufferAdapter.h +++ b/src/fsfw/serialize/SerialBufferAdapter.h @@ -54,7 +54,7 @@ class SerialBufferAdapter : public SerializeIF { * If a length field is present, it is ignored, as the size should have * been set in the constructor. If the size is not known beforehand, * consider using SerialFixedArrayListAdapter instead. - * @param buffer [out] Resulting buffer + * @param buffer_ [out] Resulting buffer * @param size remaining size to deserialize, should be larger than buffer * + size field size * @param bigEndian diff --git a/src/fsfw/serviceinterface/ServiceInterfaceBuffer.cpp b/src/fsfw/serviceinterface/ServiceInterfaceBuffer.cpp index 23892dcc..0e73be83 100644 --- a/src/fsfw/serviceinterface/ServiceInterfaceBuffer.cpp +++ b/src/fsfw/serviceinterface/ServiceInterfaceBuffer.cpp @@ -3,7 +3,6 @@ #if FSFW_CPP_OSTREAM_ENABLED == 1 #include - #include #include "fsfw/serviceinterface/serviceInterfaceDefintions.h" diff --git a/src/fsfw/serviceinterface/ServiceInterfaceStream.h b/src/fsfw/serviceinterface/ServiceInterfaceStream.h index 0b3d6745..ca746e7d 100644 --- a/src/fsfw/serviceinterface/ServiceInterfaceStream.h +++ b/src/fsfw/serviceinterface/ServiceInterfaceStream.h @@ -1,9 +1,8 @@ #ifndef FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACESTREAM_H_ #define FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACESTREAM_H_ -#include - #include "ServiceInterfaceBuffer.h" +#include "fsfw/FSFW.h" #if FSFW_CPP_OSTREAM_ENABLED == 1 diff --git a/src/fsfw/storagemanager/ConstStorageAccessor.cpp b/src/fsfw/storagemanager/ConstStorageAccessor.cpp index f64334f7..e39fa36b 100644 --- a/src/fsfw/storagemanager/ConstStorageAccessor.cpp +++ b/src/fsfw/storagemanager/ConstStorageAccessor.cpp @@ -19,7 +19,7 @@ ConstStorageAccessor::~ConstStorageAccessor() { } } -ConstStorageAccessor::ConstStorageAccessor(ConstStorageAccessor&& other) +ConstStorageAccessor::ConstStorageAccessor(ConstStorageAccessor&& other) noexcept : constDataPointer(other.constDataPointer), storeId(other.storeId), size_(other.size_), @@ -30,7 +30,7 @@ ConstStorageAccessor::ConstStorageAccessor(ConstStorageAccessor&& other) other.store = nullptr; } -ConstStorageAccessor& ConstStorageAccessor::operator=(ConstStorageAccessor&& other) { +ConstStorageAccessor& ConstStorageAccessor::operator=(ConstStorageAccessor&& other) noexcept { constDataPointer = other.constDataPointer; storeId = other.storeId; store = other.store; @@ -84,7 +84,7 @@ void ConstStorageAccessor::print() const { arrayprinter::print(constDataPointer, size_); } -void ConstStorageAccessor::assignStore(StorageManagerIF* store) { +void ConstStorageAccessor::assignStore(StorageManagerIF* store_) { internalState = AccessState::ASSIGNED; - this->store = store; + store = store_; } diff --git a/src/fsfw/storagemanager/ConstStorageAccessor.h b/src/fsfw/storagemanager/ConstStorageAccessor.h index 9cad346c..0911c6d9 100644 --- a/src/fsfw/storagemanager/ConstStorageAccessor.h +++ b/src/fsfw/storagemanager/ConstStorageAccessor.h @@ -23,6 +23,7 @@ class ConstStorageAccessor { //! StorageManager classes have exclusive access to private variables. friend class PoolManager; friend class LocalPool; + friend class StorageManagerIF; public: /** @@ -30,7 +31,7 @@ class ConstStorageAccessor { * entry to access. * @param storeId */ - ConstStorageAccessor(store_address_t storeId); + explicit ConstStorageAccessor(store_address_t storeId); ConstStorageAccessor(store_address_t storeId, StorageManagerIF* store); /** @@ -43,7 +44,7 @@ class ConstStorageAccessor { * @brief Returns a pointer to the read-only data * @return */ - const uint8_t* data() const; + [[nodiscard]] const uint8_t* data() const; /** * @brief Copies the read-only data to the supplied pointer @@ -61,13 +62,13 @@ class ConstStorageAccessor { * Get the size of the data * @return */ - size_t size() const; + [[nodiscard]] size_t size() const; /** * Get the storage ID. * @return */ - store_address_t getId() const; + [[nodiscard]] store_address_t getId() const; void print() const; @@ -79,8 +80,8 @@ class ConstStorageAccessor { * @param * @return */ - ConstStorageAccessor& operator=(ConstStorageAccessor&&); - ConstStorageAccessor(ConstStorageAccessor&&); + ConstStorageAccessor& operator=(ConstStorageAccessor&&) noexcept; + ConstStorageAccessor(ConstStorageAccessor&&) noexcept; //! The copy ctor and copy assignemnt should be deleted implicitely //! according to https://foonathan.net/2019/02/special-member-functions/ diff --git a/src/fsfw/storagemanager/LocalPool.cpp b/src/fsfw/storagemanager/LocalPool.cpp index d907a9b3..970b05f5 100644 --- a/src/fsfw/storagemanager/LocalPool.cpp +++ b/src/fsfw/storagemanager/LocalPool.cpp @@ -29,7 +29,7 @@ LocalPool::LocalPool(object_id_t setObjectId, const LocalPoolConfig& poolConfig, } } -LocalPool::~LocalPool(void) {} +LocalPool::~LocalPool() = default; ReturnValue_t LocalPool::addData(store_address_t* storageId, const uint8_t* data, size_t size, bool ignoreFault) { @@ -48,22 +48,6 @@ ReturnValue_t LocalPool::getData(store_address_t packetId, const uint8_t** packe return status; } -ReturnValue_t LocalPool::getData(store_address_t storeId, ConstStorageAccessor& storeAccessor) { - uint8_t* tempData = nullptr; - ReturnValue_t status = modifyData(storeId, &tempData, &storeAccessor.size_); - storeAccessor.assignStore(this); - storeAccessor.constDataPointer = tempData; - return status; -} - -ConstAccessorPair LocalPool::getData(store_address_t storeId) { - uint8_t* tempData = nullptr; - ConstStorageAccessor constAccessor(storeId, this); - ReturnValue_t status = modifyData(storeId, &tempData, &constAccessor.size_); - constAccessor.constDataPointer = tempData; - return ConstAccessorPair(status, std::move(constAccessor)); -} - ReturnValue_t LocalPool::getFreeElement(store_address_t* storageId, const size_t size, uint8_t** pData, bool ignoreFault) { ReturnValue_t status = reserveSpace(size, storageId, ignoreFault); @@ -75,20 +59,6 @@ ReturnValue_t LocalPool::getFreeElement(store_address_t* storageId, const size_t return status; } -AccessorPair LocalPool::modifyData(store_address_t storeId) { - StorageAccessor accessor(storeId, this); - ReturnValue_t status = modifyData(storeId, &accessor.dataPointer, &accessor.size_); - accessor.assignConstPointer(); - return AccessorPair(status, std::move(accessor)); -} - -ReturnValue_t LocalPool::modifyData(store_address_t storeId, StorageAccessor& storeAccessor) { - storeAccessor.assignStore(this); - ReturnValue_t status = modifyData(storeId, &storeAccessor.dataPointer, &storeAccessor.size_); - storeAccessor.assignConstPointer(); - return status; -} - ReturnValue_t LocalPool::modifyData(store_address_t storeId, uint8_t** packetPtr, size_t* size) { ReturnValue_t status = returnvalue::FAILED; if (storeId.poolIndex >= NUMBER_OF_SUBPOOLS) { @@ -197,8 +167,7 @@ void LocalPool::clearStore() { } } -ReturnValue_t LocalPool::reserveSpace(const size_t size, store_address_t* storeId, - bool ignoreFault) { +ReturnValue_t LocalPool::reserveSpace(size_t size, store_address_t* storeId, bool ignoreFault) { ReturnValue_t status = getSubPoolIndex(size, &storeId->poolIndex); if (status != returnvalue::OK) { #if FSFW_CPP_OSTREAM_ENABLED == 1 @@ -349,3 +318,27 @@ bool LocalPool::hasDataAtId(store_address_t storeId) const { } return false; } + +ReturnValue_t LocalPool::getFreeElement(store_address_t* storeId, size_t size, uint8_t** pData) { + return StorageManagerIF::getFreeElement(storeId, size, pData); +} + +ConstAccessorPair LocalPool::getData(store_address_t storeId) { + return StorageManagerIF::getData(storeId); +} + +ReturnValue_t LocalPool::addData(store_address_t* storeId, const uint8_t* data, size_t size) { + return StorageManagerIF::addData(storeId, data, size); +} + +ReturnValue_t LocalPool::getData(store_address_t storeId, ConstStorageAccessor& accessor) { + return StorageManagerIF::getData(storeId, accessor); +} + +ReturnValue_t LocalPool::modifyData(store_address_t storeId, StorageAccessor& accessor) { + return StorageManagerIF::modifyData(storeId, accessor); +} + +AccessorPair LocalPool::modifyData(store_address_t storeId) { + return StorageManagerIF::modifyData(storeId); +} diff --git a/src/fsfw/storagemanager/LocalPool.h b/src/fsfw/storagemanager/LocalPool.h index a82da971..54d704e6 100644 --- a/src/fsfw/storagemanager/LocalPool.h +++ b/src/fsfw/storagemanager/LocalPool.h @@ -87,21 +87,23 @@ class LocalPool : public SystemObject, public StorageManagerIF { * Documentation: See StorageManagerIF.h */ ReturnValue_t addData(store_address_t* storeId, const uint8_t* data, size_t size, - bool ignoreFault = false) override; - ReturnValue_t getFreeElement(store_address_t* storeId, const size_t size, uint8_t** pData, - bool ignoreFault = false) override; + bool ignoreFault) override; + ReturnValue_t addData(store_address_t* storeId, const uint8_t* data, size_t size) override; + + ReturnValue_t getFreeElement(store_address_t* storeId, size_t size, uint8_t** pData) override; + ReturnValue_t getFreeElement(store_address_t* storeId, size_t size, uint8_t** pData, + bool ignoreFault) override; ConstAccessorPair getData(store_address_t storeId) override; - ReturnValue_t getData(store_address_t storeId, ConstStorageAccessor& constAccessor) override; + ReturnValue_t getData(store_address_t storeId, ConstStorageAccessor& accessor) override; ReturnValue_t getData(store_address_t storeId, const uint8_t** packet_ptr, size_t* size) override; AccessorPair modifyData(store_address_t storeId) override; - ReturnValue_t modifyData(store_address_t storeId, StorageAccessor& storeAccessor) override; ReturnValue_t modifyData(store_address_t storeId, uint8_t** packet_ptr, size_t* size) override; + ReturnValue_t modifyData(store_address_t storeId, StorageAccessor& accessor) override; - virtual ReturnValue_t deleteData(store_address_t storeId) override; - virtual ReturnValue_t deleteData(uint8_t* ptr, size_t size, - store_address_t* storeId = nullptr) override; + ReturnValue_t deleteData(store_address_t storeId) override; + ReturnValue_t deleteData(uint8_t* ptr, size_t size, store_address_t* storeId) override; /** * Get the total size of allocated memory for pool data. @@ -131,8 +133,8 @@ class LocalPool : public SystemObject, public StorageManagerIF { * Get number sub pools. Each pool has pages with a specific bucket size. * @return */ - max_subpools_t getNumberOfSubPools() const override; - bool hasDataAtId(store_address_t storeId) const override; + [[nodiscard]] max_subpools_t getNumberOfSubPools() const override; + [[nodiscard]] bool hasDataAtId(store_address_t storeId) const override; protected: /** @@ -142,7 +144,7 @@ class LocalPool : public SystemObject, public StorageManagerIF { * @return - returnvalue::OK on success, * - the return codes of #getPoolIndex or #findEmpty otherwise. */ - virtual ReturnValue_t reserveSpace(const size_t size, store_address_t* address, bool ignoreFault); + virtual ReturnValue_t reserveSpace(size_t size, store_address_t* address, bool ignoreFault); private: /** diff --git a/src/fsfw/storagemanager/PoolManager.h b/src/fsfw/storagemanager/PoolManager.h index 0951a518..eaa978ef 100644 --- a/src/fsfw/storagemanager/PoolManager.h +++ b/src/fsfw/storagemanager/PoolManager.h @@ -27,7 +27,7 @@ class PoolManager : public LocalPool { * @brief In the PoolManager's destructor all allocated memory * is freed. */ - virtual ~PoolManager(); + ~PoolManager() override; /** * Set the default mutex timeout for internal calls. @@ -40,8 +40,7 @@ class PoolManager : public LocalPool { * which wraps LocalPool calls with a mutex protection. */ ReturnValue_t deleteData(store_address_t) override; - ReturnValue_t deleteData(uint8_t* buffer, size_t size, - store_address_t* storeId = nullptr) override; + ReturnValue_t deleteData(uint8_t* buffer, size_t size, store_address_t* storeId) override; /** * The developer is allowed to lock the mutex in case the lock needs @@ -58,8 +57,7 @@ class PoolManager : public LocalPool { //! Default mutex timeout value to prevent permanent blocking. uint32_t mutexTimeoutMs = 20; - ReturnValue_t reserveSpace(const size_t size, store_address_t* address, - bool ignoreFault) override; + ReturnValue_t reserveSpace(size_t size, store_address_t* address, bool ignoreFault) override; /** * @brief The mutex is created in the constructor and makes diff --git a/src/fsfw/storagemanager/StorageAccessor.cpp b/src/fsfw/storagemanager/StorageAccessor.cpp index 8a96dcec..b576a113 100644 --- a/src/fsfw/storagemanager/StorageAccessor.cpp +++ b/src/fsfw/storagemanager/StorageAccessor.cpp @@ -10,7 +10,7 @@ StorageAccessor::StorageAccessor(store_address_t storeId) : ConstStorageAccessor StorageAccessor::StorageAccessor(store_address_t storeId, StorageManagerIF* store) : ConstStorageAccessor(storeId, store) {} -StorageAccessor& StorageAccessor::operator=(StorageAccessor&& other) { +StorageAccessor& StorageAccessor::operator=(StorageAccessor&& other) noexcept { // Call the parent move assignment and also assign own member. dataPointer = other.dataPointer; ConstStorageAccessor::operator=(std::move(other)); @@ -18,7 +18,7 @@ StorageAccessor& StorageAccessor::operator=(StorageAccessor&& other) { } // Call the parent move ctor and also transfer own member. -StorageAccessor::StorageAccessor(StorageAccessor&& other) +StorageAccessor::StorageAccessor(StorageAccessor&& other) noexcept : ConstStorageAccessor(std::move(other)), dataPointer(other.dataPointer) {} ReturnValue_t StorageAccessor::getDataCopy(uint8_t* pointer, size_t maxSize) { diff --git a/src/fsfw/storagemanager/StorageAccessor.h b/src/fsfw/storagemanager/StorageAccessor.h index 5e8b25e4..b6c5dc14 100644 --- a/src/fsfw/storagemanager/StorageAccessor.h +++ b/src/fsfw/storagemanager/StorageAccessor.h @@ -12,9 +12,10 @@ class StorageAccessor : public ConstStorageAccessor { //! StorageManager classes have exclusive access to private variables. friend class PoolManager; friend class LocalPool; + friend class StorageManagerIF; public: - StorageAccessor(store_address_t storeId); + explicit StorageAccessor(store_address_t storeId); StorageAccessor(store_address_t storeId, StorageManagerIF* store); /** @@ -25,8 +26,8 @@ class StorageAccessor : public ConstStorageAccessor { * @param * @return */ - StorageAccessor& operator=(StorageAccessor&&); - StorageAccessor(StorageAccessor&&); + StorageAccessor& operator=(StorageAccessor&&) noexcept; + StorageAccessor(StorageAccessor&&) noexcept; ReturnValue_t write(uint8_t* data, size_t size, uint16_t offset = 0); uint8_t* data(); diff --git a/src/fsfw/storagemanager/StorageManagerIF.h b/src/fsfw/storagemanager/StorageManagerIF.h index 228d380b..2845e581 100644 --- a/src/fsfw/storagemanager/StorageManagerIF.h +++ b/src/fsfw/storagemanager/StorageManagerIF.h @@ -67,7 +67,12 @@ class StorageManagerIF { * @returnvalue::FAILED if data could not be added, storageId is unchanged then. */ virtual ReturnValue_t addData(store_address_t* storageId, const uint8_t* data, size_t size, - bool ignoreFault = false) = 0; + bool ignoreFault) = 0; + + virtual ReturnValue_t addData(store_address_t* storageId, const uint8_t* data, size_t size) { + return addData(storageId, data, size, false); + } + /** * @brief With deleteData, the storageManager frees the memory region * identified by packet_id. @@ -86,9 +91,10 @@ class StorageManagerIF { * @return @li returnvalue::OK on success. * @li failure code if deletion did not work */ - virtual ReturnValue_t deleteData(uint8_t* buffer, size_t size, - store_address_t* storeId = nullptr) = 0; - + virtual ReturnValue_t deleteData(uint8_t* buffer, size_t size, store_address_t* storeId) = 0; + virtual ReturnValue_t deleteData(uint8_t* buffer, size_t size) { + return deleteData(buffer, size, nullptr); + } /** * @brief Access the data by supplying a store ID. * @details @@ -97,7 +103,13 @@ class StorageManagerIF { * @param storeId * @return Pair of return value and a ConstStorageAccessor instance */ - virtual ConstAccessorPair getData(store_address_t storeId) = 0; + virtual ConstAccessorPair getData(store_address_t storeId) { + uint8_t* tempData = nullptr; + ConstStorageAccessor constAccessor(storeId, this); + ReturnValue_t status = modifyData(storeId, &tempData, &constAccessor.size_); + constAccessor.constDataPointer = tempData; + return {status, std::move(constAccessor)}; + } /** * @brief Access the data by supplying a store ID and a helper @@ -106,7 +118,13 @@ class StorageManagerIF { * @param constAccessor Wrapper function to access store data. * @return */ - virtual ReturnValue_t getData(store_address_t storeId, ConstStorageAccessor& constAccessor) = 0; + virtual ReturnValue_t getData(store_address_t storeId, ConstStorageAccessor& accessor) { + uint8_t* tempData = nullptr; + ReturnValue_t status = modifyData(storeId, &tempData, &accessor.size_); + accessor.assignStore(this); + accessor.constDataPointer = tempData; + return status; + } /** * @brief getData returns an address to data and the size of the data @@ -127,7 +145,12 @@ class StorageManagerIF { * @param storeId * @return Pair of return value and StorageAccessor helper */ - virtual AccessorPair modifyData(store_address_t storeId) = 0; + virtual AccessorPair modifyData(store_address_t storeId) { + StorageAccessor accessor(storeId, this); + ReturnValue_t status = modifyData(storeId, &accessor.dataPointer, &accessor.size_); + accessor.assignConstPointer(); + return {status, std::move(accessor)}; + } /** * Modify data by supplying a store ID and a StorageAccessor helper instance. @@ -135,7 +158,12 @@ class StorageManagerIF { * @param accessor Helper class to access the modifiable data. * @return */ - virtual ReturnValue_t modifyData(store_address_t storeId, StorageAccessor& accessor) = 0; + virtual ReturnValue_t modifyData(store_address_t storeId, StorageAccessor& accessor) { + accessor.assignStore(this); + ReturnValue_t status = modifyData(storeId, &accessor.dataPointer, &accessor.size_); + accessor.assignConstPointer(); + return status; + } /** * Get pointer and size of modifiable data by supplying the storeId @@ -154,12 +182,16 @@ class StorageManagerIF { * written to p_data! * @param storageId A pointer to the storageId to retrieve. * @param size The size of the space to be reserved. - * @param p_data A pointer to the element data is returned here. - * @return Returns @li returnvalue::OK if data was added. + * @param dataPtr A pointer to the element data is returned here. + * @return Returns @returnvalue::OK if data was added. * @returnvalue::FAILED if data could not be added, storageId is unchanged then. */ - virtual ReturnValue_t getFreeElement(store_address_t* storageId, size_t size, uint8_t** p_data, - bool ignoreFault = false) = 0; + virtual ReturnValue_t getFreeElement(store_address_t* storageId, size_t size, uint8_t** dataPtr, + bool ignoreFault) = 0; + + virtual ReturnValue_t getFreeElement(store_address_t* storageId, size_t size, uint8_t** dataPtr) { + return getFreeElement(storageId, size, dataPtr, false); + } [[nodiscard]] virtual bool hasDataAtId(store_address_t storeId) const = 0; diff --git a/src/fsfw/tcdistribution/CCSDSDistributor.cpp b/src/fsfw/tcdistribution/CCSDSDistributor.cpp deleted file mode 100644 index db408e6d..00000000 --- a/src/fsfw/tcdistribution/CCSDSDistributor.cpp +++ /dev/null @@ -1,113 +0,0 @@ -#include "fsfw/tcdistribution/CCSDSDistributor.h" - -#include "fsfw/objectmanager/ObjectManager.h" -#include "fsfw/serviceinterface/ServiceInterface.h" -#include "fsfw/tmtcpacket/ccsds/SpacePacketReader.h" - -#define CCSDS_DISTRIBUTOR_DEBUGGING 0 - -CCSDSDistributor::CCSDSDistributor(uint16_t setDefaultApid, object_id_t setObjectId, - CcsdsPacketCheckIF* packetChecker) - : TcDistributor(setObjectId), defaultApid(setDefaultApid), packetChecker(packetChecker) {} - -CCSDSDistributor::~CCSDSDistributor() = default; - -TcDistributor::TcMqMapIter CCSDSDistributor::selectDestination() { -#if CCSDS_DISTRIBUTOR_DEBUGGING == 1 -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "CCSDSDistributor::selectDestination received: " - << this->currentMessage.getStorageId().poolIndex << ", " - << this->currentMessage.getStorageId().packetIndex << std::endl; -#else - sif::printDebug("CCSDSDistributor::selectDestination received: %d, %d\n", - currentMessage.getStorageId().poolIndex, - currentMessage.getStorageId().packetIndex); -#endif -#endif - const uint8_t* packet = nullptr; - size_t size = 0; - ReturnValue_t result = tcStore->getData(currentMessage.getStorageId(), &packet, &size); - if (result != returnvalue::OK) { -#if FSFW_VERBOSE_LEVEL >= 1 -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "CCSDSDistributor::selectDestination: Getting data from" - " store failed!" - << std::endl; -#else - sif::printError( - "CCSDSDistributor::selectDestination: Getting data from" - " store failed!\n"); -#endif -#endif - return queueMap.end(); - } - SpacePacketReader currentPacket(packet, size); - result = packetChecker->checkPacket(currentPacket, size); - if (result != returnvalue::OK) { - } -#if FSFW_CPP_OSTREAM_ENABLED == 1 && CCSDS_DISTRIBUTOR_DEBUGGING == 1 - sif::info << "CCSDSDistributor::selectDestination has packet with APID 0x" << std::hex - << currentPacket.getApid() << std::dec << std::endl; -#endif - auto position = this->queueMap.find(currentPacket.getApid()); - if (position != this->queueMap.end()) { - return position; - } else { - // The APID was not found. Forward packet to main SW-APID anyway to - // create acceptance failure report. - return queueMap.find(this->defaultApid); - } -} - -MessageQueueId_t CCSDSDistributor::getRequestQueue() { return tcQueue->getId(); } - -ReturnValue_t CCSDSDistributor::registerApplication(AcceptsTelecommandsIF* application) { - ReturnValue_t returnValue = returnvalue::OK; - auto insertPair = - this->queueMap.emplace(application->getIdentifier(), application->getRequestQueue()); - if (not insertPair.second) { - returnValue = returnvalue::FAILED; - } - return returnValue; -} - -ReturnValue_t CCSDSDistributor::registerApplication(uint16_t apid, MessageQueueId_t id) { - ReturnValue_t returnValue = returnvalue::OK; - auto insertPair = this->queueMap.emplace(apid, id); - if (not insertPair.second) { - returnValue = returnvalue::FAILED; - } - return returnValue; -} - -uint16_t CCSDSDistributor::getIdentifier() { return 0; } - -ReturnValue_t CCSDSDistributor::initialize() { - if (packetChecker == nullptr) { - packetChecker = new CcsdsPacketChecker(ccsds::PacketType::TC); - } - ReturnValue_t status = this->TcDistributor::initialize(); - this->tcStore = ObjectManager::instance()->get(objects::TC_STORE); - if (this->tcStore == nullptr) { -#if FSFW_VERBOSE_LEVEL >= 1 -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "CCSDSDistributor::initialize: Could not initialize" - " TC store!" - << std::endl; -#else - sif::printError( - "CCSDSDistributor::initialize: Could not initialize" - " TC store!\n"); -#endif -#endif - status = returnvalue::FAILED; - } - return status; -} - -ReturnValue_t CCSDSDistributor::callbackAfterSending(ReturnValue_t queueStatus) { - if (queueStatus != returnvalue::OK) { - tcStore->deleteData(currentMessage.getStorageId()); - } - return returnvalue::OK; -} diff --git a/src/fsfw/tcdistribution/CCSDSDistributorIF.h b/src/fsfw/tcdistribution/CCSDSDistributorIF.h deleted file mode 100644 index 2ad012a0..00000000 --- a/src/fsfw/tcdistribution/CCSDSDistributorIF.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef FSFW_TCDISTRIBUTION_CCSDSDISTRIBUTORIF_H_ -#define FSFW_TCDISTRIBUTION_CCSDSDISTRIBUTORIF_H_ - -#include "../ipc/MessageQueueSenderIF.h" -#include "../tmtcservices/AcceptsTelecommandsIF.h" -/** - * This is the Interface to a CCSDS Distributor. - * On a CCSDS Distributor, Applications (in terms of CCSDS) may register - * themselves, either by passing a pointer to themselves (and implementing the - * CCSDSApplicationIF), or by explicitly passing an APID and a MessageQueueId - * to route the TC's to. - * @ingroup tc_distribution - */ -class CCSDSDistributorIF { - public: - /** - * With this call, a class implementing the CCSDSApplicationIF can register - * at the distributor. - * @param application A pointer to the Application to register. - * @return - @c returnvalue::OK on success, - * - @c returnvalue::FAILED on failure. - */ - virtual ReturnValue_t registerApplication(AcceptsTelecommandsIF* application) = 0; - /** - * With this call, other Applications can register to the CCSDS distributor. - * This is done by passing an APID and a MessageQueueId to the method. - * @param apid The APID to register. - * @param id The MessageQueueId of the message queue to send the - * TC Packets to. - * @return - @c returnvalue::OK on success, - * - @c returnvalue::FAILED on failure. - */ - virtual ReturnValue_t registerApplication(uint16_t apid, MessageQueueId_t id) = 0; - /** - * The empty virtual destructor. - */ - virtual ~CCSDSDistributorIF() = default; -}; - -#endif /* FSFW_TCDISTRIBUTION_CCSDSDISTRIBUTORIF_H_ */ diff --git a/src/fsfw/tcdistribution/CFDPDistributor.cpp b/src/fsfw/tcdistribution/CFDPDistributor.cpp deleted file mode 100644 index 1aa4adf9..00000000 --- a/src/fsfw/tcdistribution/CFDPDistributor.cpp +++ /dev/null @@ -1,142 +0,0 @@ -#include "fsfw/tcdistribution/CFDPDistributor.h" - -#include "fsfw/objectmanager/ObjectManager.h" -#include "fsfw/tcdistribution/CCSDSDistributorIF.h" -#include "fsfw/tmtcpacket/cfdp/CfdpPacketStored.h" - -#ifndef FSFW_CFDP_DISTRIBUTOR_DEBUGGING -#define FSFW_CFDP_DISTRIBUTOR_DEBUGGING 1 -#endif - -CFDPDistributor::CFDPDistributor(uint16_t setApid, object_id_t setObjectId, - object_id_t setPacketSource) - : TcDistributor(setObjectId), - apid(setApid), - checker(setApid), - tcStatus(returnvalue::FAILED), - packetSource(setPacketSource) {} - -CFDPDistributor::~CFDPDistributor() = default; - -CFDPDistributor::TcMqMapIter CFDPDistributor::selectDestination() { -#if FSFW_CFDP_DISTRIBUTOR_DEBUGGING == 1 - store_address_t storeId = this->currentMessage.getStorageId(); -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "CFDPDistributor::handlePacket received: " << storeId.poolIndex << ", " - << storeId.packetIndex << std::endl; -#else - sif::printDebug("CFDPDistributor::handlePacket received: %d, %d\n", storeId.poolIndex, - storeId.packetIndex); -#endif -#endif - auto queueMapIt = this->queueMap.end(); - if (this->currentPacket == nullptr) { - return queueMapIt; - } - this->currentPacket->setStoreAddress(this->currentMessage.getStorageId()); - if (currentPacket->getFullData() != nullptr) { - tcStatus = checker.checkPacket(*currentPacket, currentPacket->getFullPacketLen()); - if (tcStatus != returnvalue::OK) { -#if FSFW_VERBOSE_LEVEL >= 1 -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "CFDPDistributor::handlePacket: Packet format invalid, code " - << static_cast(tcStatus) << std::endl; -#else - sif::printDebug("CFDPDistributor::handlePacket: Packet format invalid, code %d\n", - static_cast(tcStatus)); -#endif -#endif - } - queueMapIt = this->queueMap.find(0); - } else { - tcStatus = PACKET_LOST; - } - - if (queueMapIt == this->queueMap.end()) { - tcStatus = DESTINATION_NOT_FOUND; -#if FSFW_VERBOSE_LEVEL >= 1 -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "CFDPDistributor::handlePacket: Destination not found" << std::endl; -#else - sif::printDebug("CFDPDistributor::handlePacket: Destination not found\n"); -#endif /* !FSFW_CPP_OSTREAM_ENABLED == 1 */ -#endif - } - - if (tcStatus != returnvalue::OK) { - return this->queueMap.end(); - } else { - return queueMapIt; - } -} - -ReturnValue_t CFDPDistributor::registerHandler(AcceptsTelecommandsIF* handler) { - uint16_t handlerId = - handler->getIdentifier(); // should be 0, because CfdpHandler does not set a set a service-ID -#if FSFW_CFDP_DISTRIBUTOR_DEBUGGING == 1 -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::info << "CFDPDistributor::registerHandler: Handler ID: " << static_cast(handlerId) - << std::endl; -#else - sif::printInfo("CFDPDistributor::registerHandler: Handler ID: %d\n", static_cast(handlerId)); -#endif -#endif - MessageQueueId_t queue = handler->getRequestQueue(); - auto returnPair = queueMap.emplace(handlerId, queue); - if (not returnPair.second) { -#if FSFW_VERBOSE_LEVEL >= 1 -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "CFDPDistributor::registerHandler: Service ID already" - " exists in map" - << std::endl; -#else - sif::printError("CFDPDistributor::registerHandler: Service ID already exists in map\n"); -#endif -#endif - return SERVICE_ID_ALREADY_EXISTS; - } - return returnvalue::OK; -} - -MessageQueueId_t CFDPDistributor::getRequestQueue() { return tcQueue->getId(); } - -// ReturnValue_t CFDPDistributor::callbackAfterSending(ReturnValue_t queueStatus) { -// if (queueStatus != returnvalue::OK) { -// tcStatus = queueStatus; -// } -// if (tcStatus != returnvalue::OK) { -// this->verifyChannel.sendFailureReport(tc_verification::ACCEPTANCE_FAILURE, -// currentPacket, tcStatus); -// // A failed packet is deleted immediately after reporting, -// // otherwise it will block memory. -// currentPacket->deletePacket(); -// return returnvalue::FAILED; -// } else { -// this->verifyChannel.sendSuccessReport(tc_verification::ACCEPTANCE_SUCCESS, -// currentPacket); -// return returnvalue::OK; -// } -// } - -uint16_t CFDPDistributor::getIdentifier() { return this->apid; } - -ReturnValue_t CFDPDistributor::initialize() { - currentPacket = new CfdpPacketStored(); - if (currentPacket == nullptr) { - // Should not happen, memory allocation failed! - return ObjectManagerIF::CHILD_INIT_FAILED; - } - - auto* ccsdsDistributor = ObjectManager::instance()->get(packetSource); - if (ccsdsDistributor == nullptr) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "CFDPDistributor::initialize: Packet source invalid" << std::endl; - sif::error << " Make sure it exists and implements CCSDSDistributorIF!" << std::endl; -#else - sif::printError("CFDPDistributor::initialize: Packet source invalid\n"); - sif::printError("Make sure it exists and implements CCSDSDistributorIF\n"); -#endif - return returnvalue::FAILED; - } - return ccsdsDistributor->registerApplication(this); -} diff --git a/src/fsfw/tcdistribution/CFDPDistributor.h b/src/fsfw/tcdistribution/CFDPDistributor.h deleted file mode 100644 index 17e79ff3..00000000 --- a/src/fsfw/tcdistribution/CFDPDistributor.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef FSFW_TCDISTRIBUTION_CFDPDISTRIBUTOR_H_ -#define FSFW_TCDISTRIBUTION_CFDPDISTRIBUTOR_H_ - -#include - -#include "../returnvalues/returnvalue.h" -#include "../tmtcpacket/cfdp/CfdpPacketStored.h" -#include "../tmtcservices/AcceptsTelecommandsIF.h" -#include "../tmtcservices/VerificationReporter.h" -#include "CFDPDistributorIF.h" -#include "TcDistributor.h" - -/** - * This class accepts CFDP Telecommands and forwards them to Application - * services. - * @ingroup tc_distribution - */ -class CFDPDistributor : public TcDistributor, - public CFDPDistributorIF, - public AcceptsTelecommandsIF { - public: - /** - * The ctor passes @c set_apid to the checker class and calls the - * TcDistribution ctor with a certain object id. - * @param setApid The APID of this receiving Application. - * @param setObjectId Object ID of the distributor itself - * @param setPacketSource Object ID of the source of TC packets. - * Must implement CCSDSDistributorIF. - */ - CFDPDistributor(uint16_t setApid, object_id_t setObjectId, object_id_t setPacketSource); - /** - * The destructor is empty. - */ - ~CFDPDistributor() override; - ReturnValue_t registerHandler(AcceptsTelecommandsIF* handler) override; - MessageQueueId_t getRequestQueue() override; - ReturnValue_t initialize() override; - uint16_t getIdentifier() override; - - protected: - uint16_t apid; - /** - * The currently handled packet is stored here. - */ - CfdpPacketStored* currentPacket = nullptr; - CfdpPacketChecker checker; - /** - * With this variable, the current check status is stored to generate - * acceptance messages later. - */ - ReturnValue_t tcStatus; - - const object_id_t packetSource; - - /** - * This method reads the packet service, checks if such a service is - * registered and forwards the packet to the destination. - * It also initiates the formal packet check and sending of verification - * messages. - * @return Iterator to map entry of found service id - * or iterator to @c map.end(). - */ - TcMqMapIter selectDestination() override; - /** - * The callback here handles the generation of acceptance - * success/failure messages. - */ - // ReturnValue_t callbackAfterSending(ReturnValue_t queueStatus) override; -}; - -#endif /* FSFW_TCDISTRIBUTION_CFDPDISTRIBUTOR_H_ */ diff --git a/src/fsfw/tcdistribution/CFDPDistributorIF.h b/src/fsfw/tcdistribution/CFDPDistributorIF.h deleted file mode 100644 index 101ffa15..00000000 --- a/src/fsfw/tcdistribution/CFDPDistributorIF.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef FSFW_TCDISTRIBUTION_CFDPDISTRIBUTORIF_H_ -#define FSFW_TCDISTRIBUTION_CFDPDISTRIBUTORIF_H_ - -#include "../ipc/MessageQueueSenderIF.h" -#include "../tmtcservices/AcceptsTelecommandsIF.h" - -/** - * This interface allows CFDP Services to register themselves at a CFDP Distributor. - * @ingroup tc_distribution - */ -class CFDPDistributorIF { - public: - /** - * The empty virtual destructor. - */ - virtual ~CFDPDistributorIF() = default; - /** - * With this method, Handlers can register themselves at the CFDP Distributor. - * @param handler A pointer to the registering Handler. - * @return - @c returnvalue::OK on success, - * - @c returnvalue::FAILED on failure. - */ - virtual ReturnValue_t registerHandler(AcceptsTelecommandsIF* handler) = 0; -}; - -#endif /* FSFW_TCDISTRIBUTION_CFDPDISTRIBUTORIF_H_ */ diff --git a/src/fsfw/tcdistribution/CMakeLists.txt b/src/fsfw/tcdistribution/CMakeLists.txt index 532ba2ca..bcad563a 100644 --- a/src/fsfw/tcdistribution/CMakeLists.txt +++ b/src/fsfw/tcdistribution/CMakeLists.txt @@ -1,9 +1,4 @@ target_sources( ${LIB_FSFW_NAME} - PRIVATE CCSDSDistributor.cpp - PusDistributor.cpp - TcDistributor.cpp - PusPacketChecker.cpp - TcPacketCheckCFDP.cpp - CFDPDistributor.cpp - CcsdsPacketChecker.cpp) + PRIVATE CcsdsDistributor.cpp PusDistributor.cpp TcDistributorBase.cpp + PusPacketChecker.cpp TcPacketCheckCFDP.cpp CcsdsPacketChecker.cpp) diff --git a/src/fsfw/tcdistribution/CcsdsDistributor.cpp b/src/fsfw/tcdistribution/CcsdsDistributor.cpp new file mode 100644 index 00000000..4668a3bc --- /dev/null +++ b/src/fsfw/tcdistribution/CcsdsDistributor.cpp @@ -0,0 +1,194 @@ +#include "fsfw/tcdistribution/CcsdsDistributor.h" + +#include "definitions.h" +#include "fsfw/FSFW.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/tmtcpacket/ccsds/SpacePacketReader.h" + +#define CCSDS_DISTRIBUTOR_DEBUGGING 0 + +CcsdsDistributor::CcsdsDistributor(uint16_t setDefaultApid, object_id_t setObjectId, + StorageManagerIF* tcStore, MessageQueueIF* queue, + CcsdsPacketCheckIF* packetChecker) + : TcDistributorBase(setObjectId, queue), + defaultApid(setDefaultApid), + tcStore(tcStore), + packetChecker(packetChecker) {} + +CcsdsDistributor::~CcsdsDistributor() { + if (ownedPacketChecker) { + delete packetChecker; + } +} + +ReturnValue_t CcsdsDistributor::selectDestination(MessageQueueId_t& destId) { +#if CCSDS_DISTRIBUTOR_DEBUGGING == 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::debug << "CCSDSDistributor::selectDestination received: " + << this->currentMessage.getStorageId().poolIndex << ", " + << this->currentMessage.getStorageId().packetIndex << std::endl; +#else + sif::printDebug("CCSDSDistributor::selectDestination received: %d, %d\n", + currentMessage.getStorageId().poolIndex, + currentMessage.getStorageId().packetIndex); +#endif +#endif + auto accessorPair = tcStore->getData(currentMessage.getStorageId()); + ReturnValue_t result = accessorPair.first; + if (result != returnvalue::OK) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "CCSDSDistributor::selectDestination: Getting data from" + " store failed!" + << std::endl; +#else + sif::printError( + "CCSDSDistributor::selectDestination: Getting data from" + " store failed!\n"); +#endif +#endif + return result; + } + // Minimum length of a space packet + if (accessorPair.second.size() < ccsds::HEADER_LEN + 1) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << __func__ << ": SP with length" << accessorPair.second.size() << " too short" + << std::endl; +#else + sif::printError("%s: SP with length %d too short\n", __func__, accessorPair.second.size()); +#endif +#endif + return SerializeIF::STREAM_TOO_SHORT; + } + SpacePacketReader currentPacket(accessorPair.second.data(), accessorPair.second.size()); + result = packetChecker->checkPacket(currentPacket, accessorPair.second.size()); + if (result != returnvalue::OK) { + handlePacketCheckFailure(result); + return result; + } +#if FSFW_CPP_OSTREAM_ENABLED == 1 && CCSDS_DISTRIBUTOR_DEBUGGING == 1 + sif::info << "CCSDSDistributor::selectDestination has packet with APID 0x" << std::hex + << currentPacket.getApid() << std::dec << std::endl; +#endif + auto iter = receiverMap.find(currentPacket.getApid()); + if (iter != receiverMap.end()) { + destId = iter->second.destId; + } else if (iter == receiverMap.end()) { + // The APID was not found. Forward packet to main SW-APID anyway to + // create acceptance failure report. + iter = receiverMap.find(defaultApid); + if (iter != receiverMap.end()) { + destId = iter->second.destId; + } else { + return DESTINATION_NOT_FOUND; + } + } + if (iter->second.removeHeader) { + // Do not call accessor release method here to ensure the old packet gets deleted. + return handleCcsdsHeaderRemoval(accessorPair.second); + } + accessorPair.second.release(); + return returnvalue::OK; +} + +void CcsdsDistributor::handlePacketCheckFailure(ReturnValue_t result) { +#if FSFW_VERBOSE_LEVEL >= 1 + const char* reason = "Unknown reason"; + if (result == tmtcdistrib::INVALID_CCSDS_VERSION) { + reason = "Invalid CCSDS version"; + } else if (result == tmtcdistrib::INCOMPLETE_PACKET) { + reason = "Size missmatch between CCSDS data length and packet length"; + } else if (result == tmtcdistrib::INVALID_APID) { + reason = "No valid handler APID found"; + } else if (result == tmtcdistrib::INVALID_PACKET_TYPE) { + reason = "Invalid Packet Type TM detected"; + } +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "CCSDS packet check failed: " << reason << std::endl; +#else + sif::printWarning("CCSDS packet check failed: %s\n", reason); +#endif +#endif +} + +MessageQueueId_t CcsdsDistributor::getRequestQueue() const { return tcQueue->getId(); } + +ReturnValue_t CcsdsDistributor::registerApplication(DestInfo info) { + ReturnValue_t returnValue = returnvalue::OK; + auto insertPair = receiverMap.emplace(info.apid, info); + if (not insertPair.second) { + returnValue = returnvalue::FAILED; + } + return returnValue; +} + +uint32_t CcsdsDistributor::getIdentifier() const { return 0; } + +ReturnValue_t CcsdsDistributor::initialize() { + ReturnValue_t result = TcDistributorBase::initialize(); + if (result != returnvalue::OK) { + return result; + } + if (packetChecker == nullptr) { + ownedPacketChecker = true; + packetChecker = new CcsdsPacketChecker(ccsds::PacketType::TC); + } + if (tcStore == nullptr) { + tcStore = ObjectManager::instance()->get(objects::TC_STORE); + if (tcStore == nullptr) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "CCSDSDistributor::initialize: Could not initialize" + " TC store!" + << std::endl; +#else + sif::printError( + "CCSDSDistributor::initialize: Could not initialize" + " TC store!\n"); +#endif +#endif + return ObjectManagerIF::CHILD_INIT_FAILED; + } + } + return result; +} + +ReturnValue_t CcsdsDistributor::callbackAfterSending(ReturnValue_t queueStatus) { + if (queueStatus != returnvalue::OK) { + tcStore->deleteData(currentMessage.getStorageId()); + } + return returnvalue::OK; +} + +void CcsdsDistributor::print() { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::debug << "Distributor content is: " << std::endl << "ID\t| Message Queue ID" << std::endl; + sif::debug << std::setfill('0') << std::setw(8) << std::hex; + for (const auto& iter : receiverMap) { + sif::debug << iter.first << "\t| 0x" << iter.second.destId + << ", Header Removed: " << std::boolalpha << iter.second.removeHeader << std::endl; + } + sif::debug << std::setfill(' ') << std::dec; +#endif +} + +const char* CcsdsDistributor::getName() const { return "CCSDS Distributor"; } + +ReturnValue_t CcsdsDistributor::handleCcsdsHeaderRemoval(ConstStorageAccessor& accessor) { + store_address_t newStoreId; + ReturnValue_t result = tcStore->addData(&newStoreId, accessor.data() + ccsds::HEADER_LEN, + accessor.size() - ccsds::HEADER_LEN); + if (result != returnvalue::OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << __func__ << ": TC store full" << std::endl; +#else + sif::printError("%s: TC store full\n", __func__); +#endif + return result; + } + currentMessage.setStorageId(newStoreId); + // The const accessor will delete the old data automatically + return returnvalue::OK; +} diff --git a/src/fsfw/tcdistribution/CCSDSDistributor.h b/src/fsfw/tcdistribution/CcsdsDistributor.h similarity index 61% rename from src/fsfw/tcdistribution/CCSDSDistributor.h rename to src/fsfw/tcdistribution/CcsdsDistributor.h index d6e4f0e7..83199646 100644 --- a/src/fsfw/tcdistribution/CCSDSDistributor.h +++ b/src/fsfw/tcdistribution/CcsdsDistributor.h @@ -1,23 +1,25 @@ #ifndef FRAMEWORK_TCDISTRIBUTION_CCSDSDISTRIBUTOR_H_ #define FRAMEWORK_TCDISTRIBUTION_CCSDSDISTRIBUTOR_H_ +#include + #include "fsfw/objectmanager/ObjectManagerIF.h" #include "fsfw/storagemanager/StorageManagerIF.h" -#include "fsfw/tcdistribution/CCSDSDistributorIF.h" +#include "fsfw/tcdistribution/CcsdsDistributorIF.h" #include "fsfw/tcdistribution/CcsdsPacketChecker.h" -#include "fsfw/tcdistribution/TcDistributor.h" +#include "fsfw/tcdistribution/TcDistributorBase.h" #include "fsfw/tmtcservices/AcceptsTelecommandsIF.h" /** - * @brief An instantiation of the CCSDSDistributorIF. + * @brief An instantiation of the CcsdsDistributorIF. * @details * It receives Space Packets, and selects a destination depending on the * APID of the telecommands. * The Secondary Header (with Service/Subservice) is ignored. * @ingroup tc_distribution */ -class CCSDSDistributor : public TcDistributor, - public CCSDSDistributorIF, +class CcsdsDistributor : public TcDistributorBase, + public CcsdsDistributorIF, public AcceptsTelecommandsIF { public: /** @@ -28,34 +30,44 @@ class CCSDSDistributor : public TcDistributor, * @param unknownApid The default APID, where packets with unknown * destination are sent to. */ - CCSDSDistributor(uint16_t unknownApid, object_id_t setObjectId, + CcsdsDistributor(uint16_t unknownApid, object_id_t setObjectId, + StorageManagerIF* tcStore = nullptr, MessageQueueIF* msgQueue = nullptr, CcsdsPacketCheckIF* packetChecker = nullptr); /** * The destructor is empty. */ - ~CCSDSDistributor() override; + ~CcsdsDistributor() override; - MessageQueueId_t getRequestQueue() override; - ReturnValue_t registerApplication(uint16_t apid, MessageQueueId_t id) override; - ReturnValue_t registerApplication(AcceptsTelecommandsIF* application) override; - uint16_t getIdentifier() override; + [[nodiscard]] MessageQueueId_t getRequestQueue() const override; + ReturnValue_t registerApplication(DestInfo info) override; + [[nodiscard]] uint32_t getIdentifier() const override; ReturnValue_t initialize() override; + [[nodiscard]] const char* getName() const override; protected: + using CcsdsReceiverMap = std::map; + CcsdsReceiverMap receiverMap; + /** * This implementation checks if an application with fitting APID has * registered and forwards the packet to the according message queue. * If the packet is not found, it returns the queue to @c defaultApid, * where a Acceptance Failure message should be generated. - * @return Iterator to map entry of found APID or iterator to default APID. + * @return + * - @c RETURN_OK if a valid desintation was found, error code otherwise + * - @c SerializeIF::STREAM_TOO_SHORT: Packet too short to be a space packet */ - TcMqMapIter selectDestination() override; + ReturnValue_t selectDestination(MessageQueueId_t& destId) override; /** * The callback here handles the generation of acceptance * success/failure messages. */ ReturnValue_t callbackAfterSending(ReturnValue_t queueStatus) override; + static void handlePacketCheckFailure(ReturnValue_t result); + + ReturnValue_t handleCcsdsHeaderRemoval(ConstStorageAccessor& accessor); + void print(); /** * The default APID, where packets with unknown APID are sent to. */ @@ -66,6 +78,7 @@ class CCSDSDistributor : public TcDistributor, */ StorageManagerIF* tcStore = nullptr; + bool ownedPacketChecker = false; CcsdsPacketCheckIF* packetChecker = nullptr; }; diff --git a/src/fsfw/tcdistribution/CcsdsDistributorIF.h b/src/fsfw/tcdistribution/CcsdsDistributorIF.h new file mode 100644 index 00000000..f70a2ef9 --- /dev/null +++ b/src/fsfw/tcdistribution/CcsdsDistributorIF.h @@ -0,0 +1,54 @@ +#ifndef FSFW_TCDISTRIBUTION_CCSDSDISTRIBUTORIF_H_ +#define FSFW_TCDISTRIBUTION_CCSDSDISTRIBUTORIF_H_ + +#include "fsfw/ipc/MessageQueueSenderIF.h" +#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h" + +/** + * This is the Interface to a CCSDS Distributor. + * On a CCSDS Distributor, Applications (in terms of CCSDS) may register + * themselves, either by passing a pointer to themselves (and implementing the + * CCSDSApplicationIF), or by explicitly passing an APID and a MessageQueueId + * to route the TC's to. + * @ingroup tc_distribution + */ +class CcsdsDistributorIF { + public: + struct DestInfo { + DestInfo(const char* name, uint16_t apid, MessageQueueId_t destId, bool removeHeader) + : name(name), apid(apid), destId(destId), removeHeader(removeHeader) {} + DestInfo(const AcceptsTelecommandsIF& ccsdsReceiver, bool removeHeader_) + : name(ccsdsReceiver.getName()) { + apid = ccsdsReceiver.getIdentifier(); + destId = ccsdsReceiver.getRequestQueue(); + removeHeader = removeHeader_; + } + const char* name; + uint16_t apid; + MessageQueueId_t destId; + bool removeHeader; + }; + + /** + * With this call, other Applications can register to the CCSDS distributor. + * This is done by passing an APID and a MessageQueueId to the method. + * @param info Contains all necessary info to register an application. + * @return + * - @c RETURN_OK on success, + * - @c RETURN_FAILED or tmtcdistrib error code on failure. + * - @c tmtcdistrib::INVALID_CCSDS_VERSION + * - @c tmtcdistrib::INVALID_APID No APID available to handle this packet + * - @c tmtcdistrib::INVALID_PACKET_TYPE Packet type TM detected + * - @c tmtcdistrib::INCORRECT_PRIMARY_HEADER Something other wrong with primary header + * - @c tmtcdistrib::INCOMPLETE_PACKET Size missmatch between data length field and actual + * length + */ + virtual ReturnValue_t registerApplication(DestInfo info) = 0; + + /** + * The empty virtual destructor. + */ + virtual ~CcsdsDistributorIF() = default; +}; + +#endif /* FSFW_TCDISTRIBUTION_CCSDSDISTRIBUTORIF_H_ */ diff --git a/src/fsfw/tcdistribution/CcsdsPacketChecker.cpp b/src/fsfw/tcdistribution/CcsdsPacketChecker.cpp index 08ec1811..977a90a2 100644 --- a/src/fsfw/tcdistribution/CcsdsPacketChecker.cpp +++ b/src/fsfw/tcdistribution/CcsdsPacketChecker.cpp @@ -10,19 +10,19 @@ ReturnValue_t CcsdsPacketChecker::checkPacket(const SpacePacketReader& currentPa size_t packetLen) { if (checkApid) { if (currentPacket.getApid() != apid) { - return tcdistrib::INVALID_APID; + return tmtcdistrib::INVALID_APID; } } if (currentPacket.getVersion() != ccsdsVersion) { - return tcdistrib::INVALID_CCSDS_VERSION; + return tmtcdistrib::INVALID_CCSDS_VERSION; } if (currentPacket.getPacketType() != packetType) { - return tcdistrib::INVALID_PACKET_TYPE; + return tmtcdistrib::INVALID_PACKET_TYPE; } // This assumes that the getFullPacketLen version uses the space packet data length field if (currentPacket.getFullPacketLen() != packetLen) { - return tcdistrib::INCOMPLETE_PACKET; + return tmtcdistrib::INCOMPLETE_PACKET; } return returnvalue::OK; } diff --git a/src/fsfw/tcdistribution/PusDistributor.cpp b/src/fsfw/tcdistribution/PusDistributor.cpp index 37e09d56..7599114b 100644 --- a/src/fsfw/tcdistribution/PusDistributor.cpp +++ b/src/fsfw/tcdistribution/PusDistributor.cpp @@ -3,14 +3,14 @@ #include "definitions.h" #include "fsfw/objectmanager/ObjectManager.h" #include "fsfw/serviceinterface/ServiceInterface.h" -#include "fsfw/tcdistribution/CCSDSDistributorIF.h" +#include "fsfw/tcdistribution/CcsdsDistributorIF.h" #include "fsfw/tmtcservices/PusVerificationReport.h" #define PUS_DISTRIBUTOR_DEBUGGING 0 PusDistributor::PusDistributor(uint16_t setApid, object_id_t setObjectId, - CCSDSDistributorIF* distributor, StorageManagerIF* store_) - : TcDistributor(setObjectId), + CcsdsDistributorIF* distributor, StorageManagerIF* store_) + : TcDistributorBase(setObjectId), store(store_), checker(setApid, ccsds::PacketType::TC), ccsdsDistributor(distributor), @@ -18,61 +18,59 @@ PusDistributor::PusDistributor(uint16_t setApid, object_id_t setObjectId, PusDistributor::~PusDistributor() = default; -PusDistributor::TcMqMapIter PusDistributor::selectDestination() { +ReturnValue_t PusDistributor::selectDestination(MessageQueueId_t& destId) { #if FSFW_CPP_OSTREAM_ENABLED == 1 && PUS_DISTRIBUTOR_DEBUGGING == 1 store_address_t storeId = currentMessage.getStorageId(); sif::debug << "PUSDistributor::handlePacket received: " << storeId.poolIndex << ", " << storeId.packetIndex << std::endl; #endif - auto queueMapIt = queueMap.end(); // TODO: Need to set the data const uint8_t* packetPtr = nullptr; size_t packetLen = 0; - if (store->getData(currentMessage.getStorageId(), &packetPtr, &packetLen) != returnvalue::OK) { - return queueMapIt; - } - ReturnValue_t result = reader.setReadOnlyData(packetPtr, packetLen); + ReturnValue_t result = + store->getData(currentMessage.getStorageId(), &packetPtr, &packetLen) != returnvalue::OK; if (result != returnvalue::OK) { tcStatus = PACKET_LOST; - return queueMapIt; + return result; + } + result = reader.setReadOnlyData(packetPtr, packetLen); + if (result != returnvalue::OK) { + tcStatus = PACKET_LOST; + return result; } // CRC check done by checker result = reader.parseDataWithoutCrcCheck(); if (result != returnvalue::OK) { tcStatus = PACKET_LOST; - return queueMapIt; + return result; } + if (reader.getFullData() != nullptr) { tcStatus = checker.checkPacket(reader, reader.getFullPacketLen()); if (tcStatus != returnvalue::OK) { checkerFailurePrinter(); } - uint32_t queue_id = reader.getService(); - queueMapIt = queueMap.find(queue_id); + uint8_t pusId = reader.getService(); + auto iter = receiverMap.find(pusId); + if (iter == receiverMap.end()) { + tcStatus = DESTINATION_NOT_FOUND; +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::debug << "PUSDistributor::handlePacket: Destination not found" << std::endl; +#else + sif::printDebug("PUSDistributor::handlePacket: Destination not found\n"); +#endif /* !FSFW_CPP_OSTREAM_ENABLED == 1 */ +#endif + } + destId = iter->second.destId; } else { tcStatus = PACKET_LOST; } - - if (queueMapIt == this->queueMap.end()) { - tcStatus = DESTINATION_NOT_FOUND; -#if FSFW_VERBOSE_LEVEL >= 1 -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "PUSDistributor::handlePacket: Destination not found" << std::endl; -#else - sif::printDebug("PUSDistributor::handlePacket: Destination not found\n"); -#endif /* !FSFW_CPP_OSTREAM_ENABLED == 1 */ -#endif - } - - if (tcStatus != returnvalue::OK) { - return this->queueMap.end(); - } else { - return queueMapIt; - } + return tcStatus; } -ReturnValue_t PusDistributor::registerService(AcceptsTelecommandsIF* service) { - uint16_t serviceId = service->getIdentifier(); +ReturnValue_t PusDistributor::registerService(const AcceptsTelecommandsIF& service) { + uint16_t serviceId = service.getIdentifier(); #if PUS_DISTRIBUTOR_DEBUGGING == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "Service ID: " << static_cast(serviceId) << std::endl; @@ -80,8 +78,8 @@ ReturnValue_t PusDistributor::registerService(AcceptsTelecommandsIF* service) { sif::printInfo("Service ID: %d\n", static_cast(serviceId)); #endif #endif - MessageQueueId_t queue = service->getRequestQueue(); - auto returnPair = queueMap.emplace(serviceId, queue); + MessageQueueId_t queue = service.getRequestQueue(); + auto returnPair = receiverMap.emplace(serviceId, ServiceInfo(service.getName(), queue)); if (not returnPair.second) { #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 @@ -97,7 +95,7 @@ ReturnValue_t PusDistributor::registerService(AcceptsTelecommandsIF* service) { return returnvalue::OK; } -MessageQueueId_t PusDistributor::getRequestQueue() { return tcQueue->getId(); } +MessageQueueId_t PusDistributor::getRequestQueue() const { return tcQueue->getId(); } ReturnValue_t PusDistributor::callbackAfterSending(ReturnValue_t queueStatus) { if (queueStatus != returnvalue::OK) { @@ -115,7 +113,7 @@ ReturnValue_t PusDistributor::callbackAfterSending(ReturnValue_t queueStatus) { } } -uint16_t PusDistributor::getIdentifier() { return checker.getApid(); } +uint32_t PusDistributor::getIdentifier() const { return checker.getApid(); } ReturnValue_t PusDistributor::initialize() { if (store == nullptr) { @@ -130,7 +128,7 @@ ReturnValue_t PusDistributor::initialize() { sif::error << " Make sure it exists and implements CCSDSDistributorIF!" << std::endl; #else sif::printError("PusDistributor::initialize: Packet source invalid\n"); - sif::printError("Make sure it exists and implements CCSDSDistributorIF\n"); + sif::printError("Make sure it exists and implements CcsdsDistributorIF\n"); #endif return ObjectManagerIF::CHILD_INIT_FAILED; } @@ -141,30 +139,29 @@ ReturnValue_t PusDistributor::initialize() { return ObjectManagerIF::CHILD_INIT_FAILED; } } - return ccsdsDistributor->registerApplication(this); + return ccsdsDistributor->registerApplication(CcsdsDistributorIF::DestInfo(*this, false)); } void PusDistributor::checkerFailurePrinter() const { #if FSFW_VERBOSE_LEVEL >= 1 - const char* keyword = "unnamed"; - if (tcStatus == tcdistrib::INCORRECT_CHECKSUM) { - keyword = "checksum"; - } else if (tcStatus == tcdistrib::INCORRECT_PRIMARY_HEADER) { - keyword = "incorrect primary header"; - } else if (tcStatus == tcdistrib::INVALID_APID) { - keyword = "illegal APID"; - } else if (tcStatus == tcdistrib::INCORRECT_SECONDARY_HEADER) { - keyword = "incorrect secondary header"; - } else if (tcStatus == tcdistrib::INCOMPLETE_PACKET) { - keyword = "incomplete packet"; - } else if (tcStatus == tcdistrib::INVALID_SEC_HEADER_FIELD) { - keyword = "invalid secondary header field"; + const char* reason = "Unknown reason"; + if (tcStatus == tmtcdistrib::INCORRECT_CHECKSUM) { + reason = "Checksum Error"; + } else if (tcStatus == tmtcdistrib::INCORRECT_PRIMARY_HEADER) { + reason = "Incorrect Primary Header"; + } else if (tcStatus == tmtcdistrib::INVALID_APID) { + reason = "Illegal APID"; + } else if (tcStatus == tmtcdistrib::INCORRECT_SECONDARY_HEADER) { + reason = "Incorrect Secondary Header"; + } else if (tcStatus == tmtcdistrib::INCOMPLETE_PACKET) { + reason = "Incomplete packet"; } #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "PUSDistributor::handlePacket: Packet format invalid, " << keyword << " error" - << std::endl; + sif::warning << "PUSDistributor::handlePacket: Check failed: " << reason << std::endl; #else - sif::printWarning("PUSDistributor::handlePacket: Packet format invalid, %s error\n", keyword); + sif::printWarning("PUSDistributor::handlePacket: Check failed: %s\n", reason); #endif #endif } + +const char* PusDistributor::getName() const { return "PUS Distributor"; } diff --git a/src/fsfw/tcdistribution/PusDistributor.h b/src/fsfw/tcdistribution/PusDistributor.h index d2265f95..206f112a 100644 --- a/src/fsfw/tcdistribution/PusDistributor.h +++ b/src/fsfw/tcdistribution/PusDistributor.h @@ -1,15 +1,17 @@ #ifndef FSFW_TCDISTRIBUTION_PUSDISTRIBUTOR_H_ #define FSFW_TCDISTRIBUTION_PUSDISTRIBUTOR_H_ -#include "PUSDistributorIF.h" +#include + +#include "PusDistributorIF.h" #include "PusPacketChecker.h" -#include "TcDistributor.h" +#include "TcDistributorBase.h" #include "fsfw/returnvalues/returnvalue.h" #include "fsfw/tmtcpacket/pus/tc.h" #include "fsfw/tmtcservices/AcceptsTelecommandsIF.h" #include "fsfw/tmtcservices/VerificationReporter.h" -class CCSDSDistributorIF; +class CcsdsDistributorIF; /** * This class accepts PUS Telecommands and forwards them to Application @@ -17,7 +19,9 @@ class CCSDSDistributorIF; * sends acceptance success or failure messages. * @ingroup tc_distribution */ -class PusDistributor : public TcDistributor, public PUSDistributorIF, public AcceptsTelecommandsIF { +class PusDistributor : public TcDistributorBase, + public PusDistributorIF, + public AcceptsTelecommandsIF { public: /** * The ctor passes @c set_apid to the checker class and calls the @@ -25,20 +29,31 @@ class PusDistributor : public TcDistributor, public PUSDistributorIF, public Acc * @param setApid The APID of this receiving Application. * @param setObjectId Object ID of the distributor itself * @param setPacketSource Object ID of the source of TC packets. - * Must implement CCSDSDistributorIF. + * Must implement CcsdsDistributorIF. */ - PusDistributor(uint16_t setApid, object_id_t setObjectId, CCSDSDistributorIF* packetSource, + PusDistributor(uint16_t setApid, object_id_t setObjectId, CcsdsDistributorIF* packetSource, StorageManagerIF* store = nullptr); + [[nodiscard]] const char* getName() const override; /** * The destructor is empty. */ ~PusDistributor() override; - ReturnValue_t registerService(AcceptsTelecommandsIF* service) override; - MessageQueueId_t getRequestQueue() override; + ReturnValue_t registerService(const AcceptsTelecommandsIF& service) override; + [[nodiscard]] MessageQueueId_t getRequestQueue() const override; ReturnValue_t initialize() override; - uint16_t getIdentifier() override; + [[nodiscard]] uint32_t getIdentifier() const override; protected: + struct ServiceInfo { + ServiceInfo(const char* name, MessageQueueId_t destId) : name(name), destId(destId) {} + + const char* name; + MessageQueueId_t destId; + }; + /// PUS recipient map. The key value will generally be the PUS Service + using PusReceiverMap = std::map; + + PusReceiverMap receiverMap; StorageManagerIF* store; /** * This attribute contains the class, that performs a formal packet check. @@ -50,7 +65,7 @@ class PusDistributor : public TcDistributor, public PUSDistributorIF, public Acc */ VerificationReporterIF* verifyChannel = nullptr; //! Cached for initialization - CCSDSDistributorIF* ccsdsDistributor = nullptr; + CcsdsDistributorIF* ccsdsDistributor = nullptr; PusTcReader reader; /** @@ -67,7 +82,7 @@ class PusDistributor : public TcDistributor, public PUSDistributorIF, public Acc * @return Iterator to map entry of found service id * or iterator to @c map.end(). */ - TcMqMapIter selectDestination() override; + ReturnValue_t selectDestination(MessageQueueId_t& destId) override; /** * The callback here handles the generation of acceptance * success/failure messages. diff --git a/src/fsfw/tcdistribution/PUSDistributorIF.h b/src/fsfw/tcdistribution/PusDistributorIF.h similarity index 81% rename from src/fsfw/tcdistribution/PUSDistributorIF.h rename to src/fsfw/tcdistribution/PusDistributorIF.h index 85a80b46..99981939 100644 --- a/src/fsfw/tcdistribution/PUSDistributorIF.h +++ b/src/fsfw/tcdistribution/PusDistributorIF.h @@ -8,19 +8,19 @@ * This interface allows PUS Services to register themselves at a PUS Distributor. * @ingroup tc_distribution */ -class PUSDistributorIF { +class PusDistributorIF { public: /** * The empty virtual destructor. */ - virtual ~PUSDistributorIF() {} + virtual ~PusDistributorIF() = default; /** * With this method, Services can register themselves at the PUS Distributor. * @param service A pointer to the registering Service. * @return - @c returnvalue::OK on success, * - @c returnvalue::FAILED on failure. */ - virtual ReturnValue_t registerService(AcceptsTelecommandsIF* service) = 0; + virtual ReturnValue_t registerService(const AcceptsTelecommandsIF& service) = 0; }; #endif /* FSFW_TCDISTRIBUTION_PUSDISTRIBUTORIF_H_ */ diff --git a/src/fsfw/tcdistribution/PusPacketChecker.cpp b/src/fsfw/tcdistribution/PusPacketChecker.cpp index dc5b9ab9..55a7934c 100644 --- a/src/fsfw/tcdistribution/PusPacketChecker.cpp +++ b/src/fsfw/tcdistribution/PusPacketChecker.cpp @@ -12,17 +12,17 @@ PusPacketChecker::PusPacketChecker(uint16_t apid, ccsds::PacketType packetType_, ReturnValue_t PusPacketChecker::checkPacket(const PusTcReader& pusPacket, size_t packetLen) { // Other primary header fields are checked by base class if (not pusPacket.hasSecHeader()) { - return tcdistrib::INVALID_SEC_HEADER_FIELD; + return tmtcdistrib::INVALID_SEC_HEADER_FIELD; } uint16_t calculated_crc = CRC::crc16ccitt(pusPacket.getFullData(), pusPacket.getFullPacketLen()); if (calculated_crc != 0) { - return tcdistrib::INCORRECT_CHECKSUM; + return tmtcdistrib::INCORRECT_CHECKSUM; } if (pusPacket.getApid() != apid) { - return tcdistrib::INVALID_APID; + return tmtcdistrib::INVALID_APID; } if (pusPacket.getPusVersion() != pusVersion) { - return tcdistrib::INVALID_PUS_VERSION; + return tmtcdistrib::INVALID_PUS_VERSION; } return returnvalue::OK; } diff --git a/src/fsfw/tcdistribution/TcDistributor.cpp b/src/fsfw/tcdistribution/TcDistributor.cpp deleted file mode 100644 index f76df208..00000000 --- a/src/fsfw/tcdistribution/TcDistributor.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "fsfw/tcdistribution/TcDistributor.h" - -#include "fsfw/ipc/QueueFactory.h" -#include "fsfw/serviceinterface/ServiceInterface.h" -#include "fsfw/tmtcservices/TmTcMessage.h" - -TcDistributor::TcDistributor(object_id_t objectId) : SystemObject(objectId) { - auto mqArgs = MqArgs(objectId); - tcQueue = QueueFactory::instance()->createMessageQueue( - DISTRIBUTER_MAX_PACKETS, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs); -} - -TcDistributor::~TcDistributor() { QueueFactory::instance()->deleteMessageQueue(tcQueue); } - -ReturnValue_t TcDistributor::performOperation(uint8_t opCode) { - ReturnValue_t status; - for (status = tcQueue->receiveMessage(¤tMessage); status == returnvalue::OK; - status = tcQueue->receiveMessage(¤tMessage)) { - status = handlePacket(); - } - if (status == MessageQueueIF::EMPTY) { - return returnvalue::OK; - } - return status; -} - -ReturnValue_t TcDistributor::handlePacket() { - auto queueMapIt = selectDestination(); - ReturnValue_t result = returnvalue::FAILED; - if (queueMapIt != queueMap.end()) { - result = tcQueue->sendMessage(queueMapIt->second, ¤tMessage); - } - return callbackAfterSending(result); -} - -void TcDistributor::print() { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "Distributor content is: " << std::endl << "ID\t| Message Queue ID" << std::endl; - sif::debug << std::setfill('0') << std::setw(8) << std::hex; - for (const auto& queueMapIter : queueMap) { - sif::debug << queueMapIter.first << "\t| 0x" << queueMapIter.second << std::endl; - } - sif::debug << std::setfill(' ') << std::dec; -#endif -} - -ReturnValue_t TcDistributor::callbackAfterSending(ReturnValue_t queueStatus) { - return returnvalue::OK; -} diff --git a/src/fsfw/tcdistribution/TcDistributorBase.cpp b/src/fsfw/tcdistribution/TcDistributorBase.cpp new file mode 100644 index 00000000..a561b465 --- /dev/null +++ b/src/fsfw/tcdistribution/TcDistributorBase.cpp @@ -0,0 +1,49 @@ +#include "TcDistributorBase.h" + +#include "definitions.h" +#include "fsfw/ipc/QueueFactory.h" +#include "fsfw/tmtcservices/TmTcMessage.h" + +TcDistributorBase::TcDistributorBase(object_id_t objectId, MessageQueueIF* tcQueue_) + : SystemObject(objectId), tcQueue(tcQueue_) { + if (tcQueue == nullptr) { + ownedQueue = true; + tcQueue = QueueFactory::instance()->createMessageQueue(DISTRIBUTER_MAX_PACKETS); + } +} + +TcDistributorBase::~TcDistributorBase() { + if (ownedQueue) { + QueueFactory::instance()->deleteMessageQueue(tcQueue); + } +} + +ReturnValue_t TcDistributorBase::performOperation(uint8_t opCode) { + ReturnValue_t status; + ReturnValue_t result = returnvalue::OK; + for (status = tcQueue->receiveMessage(¤tMessage); status == returnvalue::OK; + status = tcQueue->receiveMessage(¤tMessage)) { + ReturnValue_t packetResult = handlePacket(); + if (packetResult != returnvalue::OK) { + result = packetResult; + triggerEvent(tmtcdistrib::HANDLE_PACKET_FAILED, packetResult, 1); + } + } + if (status == MessageQueueIF::EMPTY) { + return result; + } + return result; +} + +ReturnValue_t TcDistributorBase::handlePacket() { + MessageQueueId_t destId; + ReturnValue_t result = selectDestination(destId); + if (result != returnvalue::OK) { + return result; + } + return callbackAfterSending(tcQueue->sendMessage(destId, ¤tMessage)); +} + +ReturnValue_t TcDistributorBase::callbackAfterSending(ReturnValue_t queueStatus) { + return returnvalue::OK; +} diff --git a/src/fsfw/tcdistribution/TcDistributor.h b/src/fsfw/tcdistribution/TcDistributorBase.h similarity index 74% rename from src/fsfw/tcdistribution/TcDistributor.h rename to src/fsfw/tcdistribution/TcDistributorBase.h index bc1534a6..be4c15ab 100644 --- a/src/fsfw/tcdistribution/TcDistributor.h +++ b/src/fsfw/tcdistribution/TcDistributorBase.h @@ -3,6 +3,7 @@ #include +#include "fsfw/events/Event.h" #include "fsfw/ipc/MessageQueueIF.h" #include "fsfw/objectmanager/ObjectManagerIF.h" #include "fsfw/objectmanager/SystemObject.h" @@ -18,20 +19,17 @@ */ /** - * This is the base class to implement distributors for Space Packets. - * Typically, the distribution is required to forward Telecommand packets + * This is the base class to implement distributors for telecommands. + * Typically, the distribution is required to forward telecommand packets * over the satellite applications and services. The class receives - * Space Packets over a message queue and holds a map that links other - * message queue ids to some identifier. The process of unpacking the + * TC packets over a message queue and holds a map that links other + * message queue IDs to some identifier. The process of unpacking the * destination information from the packet is handled by the child class * implementations. * @ingroup tc_distribution */ -class TcDistributor : public SystemObject, public ExecutableObjectIF { +class TcDistributorBase : public SystemObject, public ExecutableObjectIF { public: - using TcMessageQueueMap = std::map; - using TcMqMapIter = std::map::iterator; - static constexpr uint8_t INTERFACE_ID = CLASS_ID::PACKET_DISTRIBUTION; static constexpr ReturnValue_t PACKET_LOST = MAKE_RETURN_CODE(1); static constexpr ReturnValue_t DESTINATION_NOT_FOUND = MAKE_RETURN_CODE(2); @@ -43,12 +41,12 @@ class TcDistributor : public SystemObject, public ExecutableObjectIF { * @param set_object_id This id is assigned to the distributor * implementation. */ - TcDistributor(object_id_t objectId); + explicit TcDistributorBase(object_id_t objectId, MessageQueueIF* tcQueue = nullptr); /** * The destructor is empty, the message queues are not in the vicinity of * this class. */ - virtual ~TcDistributor(); + ~TcDistributorBase() override; /** * The method is called cyclically and fetches new incoming packets from * the message queue. @@ -56,14 +54,10 @@ class TcDistributor : public SystemObject, public ExecutableObjectIF { * with distribution. * @return The error code of the message queue call. */ - ReturnValue_t performOperation(uint8_t opCode); - /** - * A simple debug print, that prints all distribution information stored in - * queueMap. - */ - void print(); + ReturnValue_t performOperation(uint8_t opCode) override; protected: + bool ownedQueue = false; /** * This is the receiving queue for incoming Telecommands. * The child classes must make its queue id public. @@ -73,23 +67,18 @@ class TcDistributor : public SystemObject, public ExecutableObjectIF { * The last received incoming packet information is stored in this * member. * As different child classes unpack the incoming packet differently - * (i.e. as a CCSDS Space Packet or as a PUS Telecommand Packet), it - * is not tried to unpack the packet information within this class. + * (i.e. as a CCSDS Space Packet or as a PUS Telecommand Packet), no unpacking will be + * done in this class. */ TmTcMessage currentMessage; - /** - * The map that links certain packet information to a destination. - * The packet information may be the APID of the packet or the service - * identifier. Filling of the map is under control of the different child - * classes. - */ - TcMessageQueueMap queueMap; + /** * This method shall unpack the routing information from the incoming * packet and select the map entry which represents the packet's target. - * @return An iterator to the map element to forward to or queuMap.end(). + * @return + * - @c RETURN_OK if a desitnation was selected successfully */ - virtual TcMqMapIter selectDestination() = 0; + virtual ReturnValue_t selectDestination(MessageQueueId_t& destId) = 0; /** * The handlePacket method calls the child class's selectDestination method * and forwards the packet to its destination, if found. diff --git a/src/fsfw/tcdistribution/definitions.h b/src/fsfw/tcdistribution/definitions.h index 3d455077..01fc3085 100644 --- a/src/fsfw/tcdistribution/definitions.h +++ b/src/fsfw/tcdistribution/definitions.h @@ -3,16 +3,19 @@ #include +#include "fsfw/events/Event.h" +#include "fsfw/events/fwSubsystemIdRanges.h" #include "fsfw/returnvalues/FwClassIds.h" #include "fsfw/returnvalues/returnvalue.h" -namespace tcdistrib { -static const uint8_t INTERFACE_ID = CLASS_ID::PACKET_CHECK; -static constexpr ReturnValue_t INVALID_CCSDS_VERSION = MAKE_RETURN_CODE(0); -static constexpr ReturnValue_t INVALID_APID = MAKE_RETURN_CODE(1); -static constexpr ReturnValue_t INVALID_PACKET_TYPE = MAKE_RETURN_CODE(2); -static constexpr ReturnValue_t INVALID_SEC_HEADER_FIELD = MAKE_RETURN_CODE(3); -static constexpr ReturnValue_t INCORRECT_PRIMARY_HEADER = MAKE_RETURN_CODE(4); +namespace tmtcdistrib { +static const uint8_t INTERFACE_ID = CLASS_ID::TMTC_DISTRIBUTION; +static constexpr ReturnValue_t NO_DESTINATION_FOUND = returnvalue::makeCode(INTERFACE_ID, 0); +static constexpr ReturnValue_t INVALID_CCSDS_VERSION = MAKE_RETURN_CODE(1); +static constexpr ReturnValue_t INVALID_APID = MAKE_RETURN_CODE(2); +static constexpr ReturnValue_t INVALID_PACKET_TYPE = MAKE_RETURN_CODE(3); +static constexpr ReturnValue_t INVALID_SEC_HEADER_FIELD = MAKE_RETURN_CODE(4); +static constexpr ReturnValue_t INCORRECT_PRIMARY_HEADER = MAKE_RETURN_CODE(5); static constexpr ReturnValue_t INCOMPLETE_PACKET = MAKE_RETURN_CODE(5); static constexpr ReturnValue_t INVALID_PUS_VERSION = MAKE_RETURN_CODE(6); @@ -20,5 +23,9 @@ static constexpr ReturnValue_t INCORRECT_CHECKSUM = MAKE_RETURN_CODE(7); static constexpr ReturnValue_t ILLEGAL_PACKET_SUBTYPE = MAKE_RETURN_CODE(8); static constexpr ReturnValue_t INCORRECT_SECONDARY_HEADER = MAKE_RETURN_CODE(9); -}; // namespace tcdistrib +static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::TMTC_DISTRIBUTION; +//! P1: Returnvalue, P2: 0 for TM issues, 1 for TC issues +static constexpr Event HANDLE_PACKET_FAILED = event::makeEvent(SUBSYSTEM_ID, 0, severity::LOW); + +}; // namespace tmtcdistrib #endif // FSFW_TMTCPACKET_DEFINITIONS_H diff --git a/src/fsfw/tmtcpacket/ccsds/SpacePacketCreator.cpp b/src/fsfw/tmtcpacket/ccsds/SpacePacketCreator.cpp index 8c4822cd..b8607079 100644 --- a/src/fsfw/tmtcpacket/ccsds/SpacePacketCreator.cpp +++ b/src/fsfw/tmtcpacket/ccsds/SpacePacketCreator.cpp @@ -40,7 +40,13 @@ ReturnValue_t SpacePacketCreator::serialize(uint8_t **buffer, size_t *size, size return SerializeAdapter::serialize(¶ms.dataLen, buffer, size, maxSize, streamEndianness); } -size_t SpacePacketCreator::getSerializedSize() const { return 6; } +void SpacePacketCreator::setCcsdsLenFromTotalDataFieldLen(size_t actualLength) { + if (actualLength == 0) { + return; + } + setDataLenField(actualLength - 1); +} +size_t SpacePacketCreator::getSerializedSize() const { return ccsds::HEADER_LEN; } ReturnValue_t SpacePacketCreator::deSerialize(const uint8_t **buffer, size_t *size, SerializeIF::Endianness streamEndianness) { @@ -64,7 +70,7 @@ void SpacePacketCreator::setSeqCount(uint16_t seqCount) { void SpacePacketCreator::setSeqFlags(ccsds::SequenceFlags flags) { params.packetSeqCtrl.seqFlags = flags; } -void SpacePacketCreator::setDataLen(uint16_t dataLen_) { params.dataLen = dataLen_; } +void SpacePacketCreator::setDataLenField(uint16_t dataLen_) { params.dataLen = dataLen_; } void SpacePacketCreator::checkFieldValidity() { valid = true; if (params.packetId.apid > ccsds::LIMIT_APID or diff --git a/src/fsfw/tmtcpacket/ccsds/SpacePacketCreator.h b/src/fsfw/tmtcpacket/ccsds/SpacePacketCreator.h index 5869560d..59234a1b 100644 --- a/src/fsfw/tmtcpacket/ccsds/SpacePacketCreator.h +++ b/src/fsfw/tmtcpacket/ccsds/SpacePacketCreator.h @@ -38,24 +38,51 @@ class SpacePacketCreator : public SpacePacketIF, public SerializeIF { [[nodiscard]] uint16_t getPacketDataLen() const override; SpacePacketParams &getParams(); + /** + * Sets the CCSDS data length field from the actual data field length. The field will contain + * the actual length minus one. This means that the minimum allowed size is one, as is also + * specified in 4.1.4.1.2 of the standard. Values of 0 will be ignored. + * @param dataFieldLen + */ + void setCcsdsLenFromTotalDataFieldLen(size_t dataFieldLen); void setParams(SpacePacketParams params); void setSecHeaderFlag(); void setPacketType(ccsds::PacketType type); void setApid(uint16_t apid); void setSeqCount(uint16_t seqCount); void setSeqFlags(ccsds::SequenceFlags flags); - void setDataLen(uint16_t dataLen); + void setDataLenField(uint16_t dataLen); + /** + * Please note that this method will only serialize the header part of the space packet. + * @param buffer + * @param size + * @param maxSize + * @param streamEndianness + * @return + */ ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, Endianness streamEndianness) const override; + /** + * This will always return 6 or ccsds::HEADER_LEN + * @return + */ [[nodiscard]] size_t getSerializedSize() const override; - ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, - Endianness streamEndianness) override; private: void checkFieldValidity(); bool valid{}; SpacePacketParams params{}; + + /** + * Forbidden to call and always return HasReturnvaluesIF::RETURN_FAILED + * @param buffer + * @param size + * @param streamEndianness + * @return + */ + ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override; }; #endif // FSFW_TMTCPACKET_SPACEPACKETCREATOR_H diff --git a/src/fsfw/tmtcpacket/ccsds/SpacePacketReader.cpp b/src/fsfw/tmtcpacket/ccsds/SpacePacketReader.cpp index 091a641a..605bbd21 100644 --- a/src/fsfw/tmtcpacket/ccsds/SpacePacketReader.cpp +++ b/src/fsfw/tmtcpacket/ccsds/SpacePacketReader.cpp @@ -35,8 +35,11 @@ uint16_t SpacePacketReader::getPacketDataLen() const { return ccsds::getPacketLe ReturnValue_t SpacePacketReader::setInternalFields(const uint8_t* data, size_t maxSize_) { bufSize = maxSize_; + if (maxSize_ < ccsds::HEADER_LEN) { + return SerializeIF::STREAM_TOO_SHORT; + } spHeader = reinterpret_cast(data); - if (maxSize_ > 6) { + if (maxSize_ > ccsds::HEADER_LEN) { packetDataField = data + ccsds::HEADER_LEN; } return checkSize(); diff --git a/src/fsfw/tmtcpacket/pus/tc/PusTcCreator.cpp b/src/fsfw/tmtcpacket/pus/tc/PusTcCreator.cpp index 34d8396d..2c818c7b 100644 --- a/src/fsfw/tmtcpacket/pus/tc/PusTcCreator.cpp +++ b/src/fsfw/tmtcpacket/pus/tc/PusTcCreator.cpp @@ -48,11 +48,11 @@ ReturnValue_t PusTcCreator::serialize(uint8_t **buffer, size_t *size, size_t max } void PusTcCreator::updateSpLengthField() { - size_t len = ecss::PusTcDataFieldHeader::MIN_SIZE + 1; + size_t len = ecss::PusTcDataFieldHeader::MIN_SIZE + sizeof(ecss::PusChecksumT); if (pusParams.appData != nullptr) { len += pusParams.appData->getSerializedSize(); } - spCreator.setDataLen(len); + spCreator.setCcsdsLenFromTotalDataFieldLen(len); } size_t PusTcCreator::getSerializedSize() const { return spCreator.getFullPacketLen(); } diff --git a/src/fsfw/tmtcpacket/pus/tm/PusTmCreator.cpp b/src/fsfw/tmtcpacket/pus/tm/PusTmCreator.cpp index 41512c07..d95a18ea 100644 --- a/src/fsfw/tmtcpacket/pus/tm/PusTmCreator.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/PusTmCreator.cpp @@ -103,14 +103,14 @@ TimeWriterIF* PusTmCreator::getTimestamper() const { return pusParams.secHeader. SpacePacketParams& PusTmCreator::getSpParams() { return spCreator.getParams(); } void PusTmCreator::updateSpLengthField() { - size_t headerLen = PusTmIF::MIN_SEC_HEADER_LEN + sizeof(ecss::PusChecksumT) - 1; + size_t headerLen = PusTmIF::MIN_SEC_HEADER_LEN + sizeof(ecss::PusChecksumT); if (pusParams.sourceData != nullptr) { headerLen += pusParams.sourceData->getSerializedSize(); } if (pusParams.secHeader.timeStamper != nullptr) { headerLen += pusParams.secHeader.timeStamper->getSerializedSize(); } - spCreator.setDataLen(headerLen); + spCreator.setCcsdsLenFromTotalDataFieldLen(headerLen); } void PusTmCreator::setApid(uint16_t apid) { spCreator.setApid(apid); } diff --git a/src/fsfw/tmtcservices/AcceptsTelecommandsIF.h b/src/fsfw/tmtcservices/AcceptsTelecommandsIF.h index e18a4f3a..6c214b0f 100644 --- a/src/fsfw/tmtcservices/AcceptsTelecommandsIF.h +++ b/src/fsfw/tmtcservices/AcceptsTelecommandsIF.h @@ -21,20 +21,22 @@ class AcceptsTelecommandsIF { * @brief The virtual destructor as it is mandatory for C++ interfaces. */ virtual ~AcceptsTelecommandsIF() = default; + [[nodiscard]] virtual const char* getName() const = 0; + /** - * @brief Getter for the service id. - * @details Any receiving service (at least any PUS service) shall have a - * service ID. If the receiver can handle Telecommands, but for - * some reason has no service id, it shall return 0. - * @return The service ID or 0. + * @brief Getter for a generic identifier ID. + * @details Any receiving service (at least any PUS service) shall have an identifier. For + * example, this could be the APID for a receiver expecting generic PUS packets, or a PUS + * service for a component expecting specific PUS service packets. + * @return The identifier. */ - virtual uint16_t getIdentifier() = 0; + [[nodiscard]] virtual uint32_t getIdentifier() const = 0; /** * @brief This method returns the message queue id of the telecommand * receiving message queue. * @return The telecommand reception message queue id. */ - virtual MessageQueueId_t getRequestQueue() = 0; + [[nodiscard]] virtual MessageQueueId_t getRequestQueue() const = 0; }; #endif /* FRAMEWORK_TMTCSERVICES_ACCEPTSTELECOMMANDSIF_H_ */ diff --git a/src/fsfw/tmtcservices/AcceptsTelemetryIF.h b/src/fsfw/tmtcservices/AcceptsTelemetryIF.h index 6f8a6226..c3e3eff3 100644 --- a/src/fsfw/tmtcservices/AcceptsTelemetryIF.h +++ b/src/fsfw/tmtcservices/AcceptsTelemetryIF.h @@ -14,6 +14,8 @@ class AcceptsTelemetryIF { * @brief The virtual destructor as it is mandatory for C++ interfaces. */ virtual ~AcceptsTelemetryIF() = default; + + [[nodiscard]] virtual const char* getName() const = 0; /** * @brief This method returns the message queue id of the telemetry * receiving message queue. diff --git a/src/fsfw/tmtcservices/CommandingServiceBase.cpp b/src/fsfw/tmtcservices/CommandingServiceBase.cpp index 41d6ad07..0cdcc653 100644 --- a/src/fsfw/tmtcservices/CommandingServiceBase.cpp +++ b/src/fsfw/tmtcservices/CommandingServiceBase.cpp @@ -3,7 +3,7 @@ #include "fsfw/ipc/QueueFactory.h" #include "fsfw/objectmanager/ObjectManager.h" #include "fsfw/serviceinterface/ServiceInterface.h" -#include "fsfw/tcdistribution/PUSDistributorIF.h" +#include "fsfw/tcdistribution/PusDistributorIF.h" #include "fsfw/tmtcpacket/pus/tc.h" #include "fsfw/tmtcservices/AcceptsTelemetryIF.h" #include "fsfw/tmtcservices/TmTcMessage.h" @@ -14,7 +14,8 @@ object_id_t CommandingServiceBase::defaultPacketSource = objects::NO_OBJECT; object_id_t CommandingServiceBase::defaultPacketDestination = objects::NO_OBJECT; CommandingServiceBase::CommandingServiceBase(object_id_t setObjectId, uint16_t apid, - uint8_t service, uint8_t numberOfParallelCommands, + const char* name, uint8_t service, + uint8_t numberOfParallelCommands, uint16_t commandTimeoutSeconds, size_t queueDepth, VerificationReporterIF* verificationReporter) : SystemObject(setObjectId), @@ -24,7 +25,8 @@ CommandingServiceBase::CommandingServiceBase(object_id_t setObjectId, uint16_t a tmStoreHelper(apid), tmHelper(service, tmStoreHelper, tmSendHelper), verificationReporter(verificationReporter), - commandMap(numberOfParallelCommands) { + commandMap(numberOfParallelCommands), + name(name) { auto mqArgs = MqArgs(setObjectId, static_cast(this)); size_t mqSz = MessageQueueMessage::MAX_MESSAGE_SIZE; commandQueue = QueueFactory::instance()->createMessageQueue(queueDepth, mqSz, &mqArgs); @@ -52,9 +54,9 @@ ReturnValue_t CommandingServiceBase::performOperation(uint8_t opCode) { return returnvalue::OK; } -uint16_t CommandingServiceBase::getIdentifier() { return service; } +uint32_t CommandingServiceBase::getIdentifier() const { return service; } -MessageQueueId_t CommandingServiceBase::getRequestQueue() { return requestQueue->getId(); } +MessageQueueId_t CommandingServiceBase::getRequestQueue() const { return requestQueue->getId(); } ReturnValue_t CommandingServiceBase::initialize() { ReturnValue_t result = SystemObject::initialize(); @@ -70,7 +72,7 @@ ReturnValue_t CommandingServiceBase::initialize() { if (packetSource == objects::NO_OBJECT) { packetSource = defaultPacketSource; } - auto* distributor = ObjectManager::instance()->get(packetSource); + auto* distributor = ObjectManager::instance()->get(packetSource); if (packetForwarding == nullptr or distributor == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 @@ -81,7 +83,7 @@ ReturnValue_t CommandingServiceBase::initialize() { return ObjectManagerIF::CHILD_INIT_FAILED; } - distributor->registerService(this); + distributor->registerService(*this); requestQueue->setDefaultDestination(packetForwarding->getReportReceptionQueue()); ipcStore = ObjectManager::instance()->get(objects::IPC_STORE); @@ -491,3 +493,5 @@ void CommandingServiceBase::prepareVerificationSuccessWithFullInfo( successParams.tcPsc = tcInfo.tcSequenceControl; successParams.ackFlags = tcInfo.ackFlags; } + +const char* CommandingServiceBase::getName() const { return name; } diff --git a/src/fsfw/tmtcservices/CommandingServiceBase.h b/src/fsfw/tmtcservices/CommandingServiceBase.h index 303d6d2e..92369b58 100644 --- a/src/fsfw/tmtcservices/CommandingServiceBase.h +++ b/src/fsfw/tmtcservices/CommandingServiceBase.h @@ -75,7 +75,7 @@ class CommandingServiceBase : public SystemObject, * @param setPacketDestination * @param queueDepth */ - CommandingServiceBase(object_id_t setObjectId, uint16_t apid, uint8_t service, + CommandingServiceBase(object_id_t setObjectId, uint16_t apid, const char* name, uint8_t service, uint8_t numberOfParallelCommands, uint16_t commandTimeoutSeconds, size_t queueDepth = 20, VerificationReporterIF* reporter = nullptr); ~CommandingServiceBase() override; @@ -105,7 +105,7 @@ class CommandingServiceBase : public SystemObject, */ ReturnValue_t performOperation(uint8_t opCode) override; - uint16_t getIdentifier() override; + uint32_t getIdentifier() const override; /** * Returns the requestQueue MessageQueueId_t @@ -114,7 +114,7 @@ class CommandingServiceBase : public SystemObject, * * @return requestQueue messageQueueId_t */ - MessageQueueId_t getRequestQueue() override; + MessageQueueId_t getRequestQueue() const override; /** * Returns the commandQueue MessageQueueId_t @@ -133,6 +133,7 @@ class CommandingServiceBase : public SystemObject, * @param task Pointer to the taskIF of this task */ void setTaskIF(PeriodicTaskIF* task) override; + const char* getName() const override; protected: /** @@ -283,6 +284,8 @@ class CommandingServiceBase : public SystemObject, uint32_t failureParameter1 = 0; uint32_t failureParameter2 = 0; + const char* name = ""; + static object_id_t defaultPacketSource; object_id_t packetSource = objects::NO_OBJECT; static object_id_t defaultPacketDestination; diff --git a/src/fsfw/tmtcservices/PusServiceBase.cpp b/src/fsfw/tmtcservices/PusServiceBase.cpp index 091ab2f8..9598e536 100644 --- a/src/fsfw/tmtcservices/PusServiceBase.cpp +++ b/src/fsfw/tmtcservices/PusServiceBase.cpp @@ -3,7 +3,7 @@ #include "fsfw/ipc/QueueFactory.h" #include "fsfw/objectmanager/ObjectManager.h" #include "fsfw/serviceinterface/ServiceInterface.h" -#include "fsfw/tcdistribution/PUSDistributorIF.h" +#include "fsfw/tcdistribution/PusDistributorIF.h" #include "fsfw/timemanager/CdsShortTimeStamper.h" #include "fsfw/tmtcservices/AcceptsTelemetryIF.h" #include "fsfw/tmtcservices/PusVerificationReport.h" @@ -82,9 +82,9 @@ void PusServiceBase::handleRequestQueue() { } } -uint16_t PusServiceBase::getIdentifier() { return psbParams.serviceId; } +uint32_t PusServiceBase::getIdentifier() const { return psbParams.serviceId; } -MessageQueueId_t PusServiceBase::getRequestQueue() { +MessageQueueId_t PusServiceBase::getRequestQueue() const { if (psbParams.reqQueue == nullptr) { return MessageQueueIF::NO_QUEUE; } @@ -111,7 +111,7 @@ ReturnValue_t PusServiceBase::initialize() { } if (psbParams.pusDistributor == nullptr) { - psbParams.pusDistributor = ObjectManager::instance()->get(PUS_DISTRIBUTOR); + psbParams.pusDistributor = ObjectManager::instance()->get(PUS_DISTRIBUTOR); if (psbParams.pusDistributor != nullptr) { registerService(*psbParams.pusDistributor); } @@ -193,8 +193,8 @@ void PusServiceBase::setVerificationReporter(VerificationReporterIF& reporter) { psbParams.verifReporter = &reporter; } -ReturnValue_t PusServiceBase::registerService(PUSDistributorIF& distributor) { - return distributor.registerService(this); +ReturnValue_t PusServiceBase::registerService(PusDistributorIF& distributor) { + return distributor.registerService(*this); } void PusServiceBase::setTmReceiver(AcceptsTelemetryIF& tmReceiver_) { @@ -202,3 +202,5 @@ void PusServiceBase::setTmReceiver(AcceptsTelemetryIF& tmReceiver_) { } void PusServiceBase::setRequestQueue(MessageQueueIF& reqQueue) { psbParams.reqQueue = &reqQueue; } + +const char* PusServiceBase::getName() const { return psbParams.name; } diff --git a/src/fsfw/tmtcservices/PusServiceBase.h b/src/fsfw/tmtcservices/PusServiceBase.h index 8a4f3cd0..92ce0d99 100644 --- a/src/fsfw/tmtcservices/PusServiceBase.h +++ b/src/fsfw/tmtcservices/PusServiceBase.h @@ -12,7 +12,7 @@ #include "fsfw/objectmanager/SystemObject.h" #include "fsfw/returnvalues/returnvalue.h" #include "fsfw/tasks/ExecutableObjectIF.h" -#include "fsfw/tcdistribution/PUSDistributorIF.h" +#include "fsfw/tcdistribution/PusDistributorIF.h" class StorageManagerIF; @@ -22,9 +22,13 @@ class StorageManagerIF; struct PsbParams { PsbParams() = default; PsbParams(uint16_t apid, AcceptsTelemetryIF* tmReceiver) : apid(apid), tmReceiver(tmReceiver) {} + PsbParams(const char* name, uint16_t apid, AcceptsTelemetryIF* tmReceiver) + : name(name), apid(apid), tmReceiver(tmReceiver) {} PsbParams(object_id_t objectId, uint16_t apid, uint8_t serviceId) : objectId(objectId), apid(apid), serviceId(serviceId) {} - + PsbParams(const char* name, object_id_t objectId, uint16_t apid, uint8_t serviceId) + : name(name), objectId(objectId), apid(apid), serviceId(serviceId) {} + const char* name = ""; object_id_t objectId = objects::NO_OBJECT; uint16_t apid = 0; uint8_t serviceId = 0; @@ -64,7 +68,7 @@ struct PsbParams { * a suitable global distributor with the static ID @PusServiceBase::pusDistributor and * register itself at that object. */ - PUSDistributorIF* pusDistributor = nullptr; + PusDistributorIF* pusDistributor = nullptr; TimeWriterIF* timeStamper = nullptr; }; @@ -115,7 +119,7 @@ class PusServiceBase : public ExecutableObjectIF, */ ~PusServiceBase() override; - ReturnValue_t registerService(PUSDistributorIF& distributor); + ReturnValue_t registerService(PusDistributorIF& distributor); /** * Set the request queue which is used to receive requests. If none is set, the initialize * function will create one @@ -187,11 +191,12 @@ class PusServiceBase : public ExecutableObjectIF, * @c returnvalue::FAILED else. */ ReturnValue_t performOperation(uint8_t opCode) override; - uint16_t getIdentifier() override; - MessageQueueId_t getRequestQueue() override; + uint32_t getIdentifier() const override; + MessageQueueId_t getRequestQueue() const override; ReturnValue_t initialize() override; void setTaskIF(PeriodicTaskIF* taskHandle) override; + [[nodiscard]] const char* getName() const override; protected: /** @@ -200,6 +205,7 @@ class PusServiceBase : public ExecutableObjectIF, * Will be set by setTaskIF(), which is called on task creation. */ PeriodicTaskIF* taskHandle = nullptr; + /** * One of two error parameters for additional error information. */ diff --git a/src/fsfw/tmtcservices/TmTcBridge.cpp b/src/fsfw/tmtcservices/TmTcBridge.cpp index a5a64b1d..bd381d7a 100644 --- a/src/fsfw/tmtcservices/TmTcBridge.cpp +++ b/src/fsfw/tmtcservices/TmTcBridge.cpp @@ -7,9 +7,10 @@ #define TMTCBRIDGE_WIRETAPPING 0 -TmTcBridge::TmTcBridge(object_id_t objectId, object_id_t tcDestination, object_id_t tmStoreId, - object_id_t tcStoreId) +TmTcBridge::TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDestination, + object_id_t tmStoreId, object_id_t tcStoreId) : SystemObject(objectId), + name(name), tmStoreId(tmStoreId), tcStoreId(tcStoreId), tcDestination(tcDestination) @@ -69,8 +70,7 @@ ReturnValue_t TmTcBridge::initialize() { #endif return ObjectManagerIF::CHILD_INIT_FAILED; } - AcceptsTelecommandsIF* tcDistributor = - ObjectManager::instance()->get(tcDestination); + auto* tcDistributor = ObjectManager::instance()->get(tcDestination); if (tcDistributor == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TmTcBridge::initialize: TC Distributor invalid" << std::endl; @@ -251,14 +251,16 @@ MessageQueueId_t TmTcBridge::getReportReceptionQueue(uint8_t virtualChannel) { void TmTcBridge::printData(uint8_t* data, size_t dataLen) { arrayprinter::print(data, dataLen); } -uint16_t TmTcBridge::getIdentifier() { +uint32_t TmTcBridge::getIdentifier() const { // This is no PUS service, so we just return 0 return 0; } -MessageQueueId_t TmTcBridge::getRequestQueue() { +MessageQueueId_t TmTcBridge::getRequestQueue() const { // Default implementation: Relay TC messages to TC distributor directly. return tmTcReceptionQueue->getDefaultDestination(); } void TmTcBridge::setFifoToOverwriteOldData(bool overwriteOld) { this->overwriteOld = overwriteOld; } + +const char* TmTcBridge::getName() const { return name; } diff --git a/src/fsfw/tmtcservices/TmTcBridge.h b/src/fsfw/tmtcservices/TmTcBridge.h index 887cbd13..c64818d4 100644 --- a/src/fsfw/tmtcservices/TmTcBridge.h +++ b/src/fsfw/tmtcservices/TmTcBridge.h @@ -22,9 +22,9 @@ class TmTcBridge : public AcceptsTelemetryIF, static constexpr uint8_t DEFAULT_STORED_DATA_SENT_PER_CYCLE = 5; static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10; - TmTcBridge(object_id_t objectId, object_id_t tcDestination, object_id_t tmStoreId, - object_id_t tcStoreId); - virtual ~TmTcBridge(); + TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDestination, + object_id_t tmStoreId, object_id_t tcStoreId); + ~TmTcBridge() override; /** * Set number of packets sent per performOperation().Please note that this @@ -57,23 +57,26 @@ class TmTcBridge : public AcceptsTelemetryIF, * Initializes necessary FSFW components for the TMTC Bridge * @return */ - virtual ReturnValue_t initialize() override; + ReturnValue_t initialize() override; /** * @brief Handles TMTC reception */ - virtual ReturnValue_t performOperation(uint8_t operationCode = 0) override; + ReturnValue_t performOperation(uint8_t operationCode = 0) override; /** AcceptsTelemetryIF override */ - virtual MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel = 0) override; + MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel = 0) override; /** AcceptsTelecommandsIF override */ - virtual uint16_t getIdentifier() override; - virtual MessageQueueId_t getRequestQueue() override; + uint32_t getIdentifier() const override; + MessageQueueId_t getRequestQueue() const override; + const char* getName() const override; bool warningSwitch = true; protected: + const char* name = ""; + //! Cached for initialize function. object_id_t tmStoreId = objects::NO_OBJECT; object_id_t tcStoreId = objects::NO_OBJECT; diff --git a/src/fsfw_hal/CMakeLists.txt b/src/fsfw_hal/CMakeLists.txt index 057ab3a6..24d712aa 100644 --- a/src/fsfw_hal/CMakeLists.txt +++ b/src/fsfw_hal/CMakeLists.txt @@ -1,5 +1,6 @@ add_subdirectory(devicehandlers) add_subdirectory(common) +add_subdirectory(host) if(UNIX) add_subdirectory(linux) diff --git a/src/fsfw_hal/common/CMakeLists.txt b/src/fsfw_hal/common/CMakeLists.txt index 1cd9c678..2f4608f8 100644 --- a/src/fsfw_hal/common/CMakeLists.txt +++ b/src/fsfw_hal/common/CMakeLists.txt @@ -1,3 +1,3 @@ add_subdirectory(gpio) -target_sources(${LIB_FSFW_NAME} PRIVATE printChar.c) \ No newline at end of file +target_sources(${LIB_FSFW_NAME} PRIVATE printChar.c) diff --git a/src/fsfw_hal/common/printChar.c b/src/fsfw_hal/common/printChar.c index 6e02c1df..24fba5c8 100644 --- a/src/fsfw_hal/common/printChar.c +++ b/src/fsfw_hal/common/printChar.c @@ -1,5 +1,5 @@ -#include #include +#include void __attribute__((weak)) printChar(const char* character, bool errStream) { if (errStream) { diff --git a/src/fsfw_hal/host/CMakeLists.txt b/src/fsfw_hal/host/CMakeLists.txt index 8b137891..95b79675 100644 --- a/src/fsfw_hal/host/CMakeLists.txt +++ b/src/fsfw_hal/host/CMakeLists.txt @@ -1 +1 @@ - +target_sources(${LIB_FSFW_NAME} PUBLIC HostFilesystem.cpp) diff --git a/src/fsfw_hal/host/HostFilesystem.cpp b/src/fsfw_hal/host/HostFilesystem.cpp new file mode 100644 index 00000000..fe593f27 --- /dev/null +++ b/src/fsfw_hal/host/HostFilesystem.cpp @@ -0,0 +1,162 @@ +#include "HostFilesystem.h" + +#include +#include + +#include "fsfw/serialize.h" + +using namespace std::filesystem; +using namespace std; + +HostFilesystem::HostFilesystem() = default; + +ReturnValue_t HostFilesystem::writeToFile(FileOpParams params, const uint8_t *data) { + if (params.path() == nullptr) { + return returnvalue::FAILED; + } + path path(params.path()); + if (not exists(path)) { + return HasFileSystemIF::FILE_DOES_NOT_EXIST; + } + // This is equivalent to "r+" mode, which is what we need here. Only using ::out would truncate + // the file + ofstream file(path, ios::binary | ios::out | ios::in); + if (file.fail()) { + return HasFileSystemIF::GENERIC_FILE_ERROR; + } + file.seekp(static_cast(params.offset)); + file.write(reinterpret_cast(data), static_cast(params.size)); + return returnvalue::OK; +} + +ReturnValue_t HostFilesystem::readFromFile(FileOpParams params, uint8_t **buffer, size_t &readSize, + size_t maxSize) { + if (params.path() == nullptr) { + return returnvalue::FAILED; + } + path path(params.path()); + if (not exists(path)) { + return HasFileSystemIF::FILE_DOES_NOT_EXIST; + } + ifstream file(path); + if (file.fail()) { + return HasFileSystemIF::GENERIC_FILE_ERROR; + } + auto sizeToRead = static_cast(params.size); + file.seekg(static_cast(params.offset)); + if (readSize + sizeToRead > maxSize) { + return SerializeIF::BUFFER_TOO_SHORT; + } + file.read(reinterpret_cast(*buffer), sizeToRead); + readSize += sizeToRead; + *buffer += sizeToRead; + return returnvalue::OK; +} + +ReturnValue_t HostFilesystem::createFile(FilesystemParams params, const uint8_t *data, + size_t size) { + if (params.path == nullptr) { + return returnvalue::FAILED; + } + path path(params.path); + if (exists(path)) { + return HasFileSystemIF::FILE_ALREADY_EXISTS; + } + ofstream file(path); + if (file.fail()) { + return HasFileSystemIF::GENERIC_FILE_ERROR; + } + return returnvalue::OK; +} + +ReturnValue_t HostFilesystem::removeFile(const char *path_, FileSystemArgsIF *args) { + if (path_ == nullptr) { + return returnvalue::FAILED; + } + path path(path_); + if (not exists(path)) { + return HasFileSystemIF::FILE_DOES_NOT_EXIST; + } + if (remove(path, errorCode)) { + return returnvalue::OK; + } + return HasFileSystemIF::GENERIC_FILE_ERROR; +} + +ReturnValue_t HostFilesystem::createDirectory(FilesystemParams params, bool createParentDirs) { + if (params.path == nullptr) { + return returnvalue::FAILED; + } + path dirPath(params.path); + + if (exists(dirPath)) { + return HasFileSystemIF::DIRECTORY_ALREADY_EXISTS; + } + + if (createParentDirs) { + if (create_directories(dirPath, errorCode)) { + return returnvalue::OK; + } + return HasFileSystemIF::GENERIC_DIR_ERROR; + } + if (create_directory(dirPath, errorCode)) { + return returnvalue::OK; + } + return HasFileSystemIF::GENERIC_DIR_ERROR; +} + +ReturnValue_t HostFilesystem::removeDirectory(FilesystemParams params, bool deleteRecurively) { + if (params.path == nullptr) { + return returnvalue::FAILED; + } + path dirPath(params.path); + if (not exists(dirPath)) { + return HasFileSystemIF::DIRECTORY_DOES_NOT_EXIST; + } + if (is_regular_file(dirPath)) { + return HasFileSystemIF::NOT_A_DIRECTORY; + } + if (deleteRecurively) { + if (remove_all(dirPath, errorCode)) { + return returnvalue::OK; + } + } else { + if (remove(dirPath, errorCode)) { + return returnvalue::OK; + } + } + // Error handling + if (errorCode == std::errc::directory_not_empty) { + return HasFileSystemIF::DIRECTORY_NOT_EMPTY; + } + return HasFileSystemIF::GENERIC_DIR_ERROR; +} + +ReturnValue_t HostFilesystem::rename(const char *oldPath_, const char *newPath_, + FileSystemArgsIF *args) { + if (oldPath_ == nullptr or newPath_ == nullptr) { + return returnvalue::FAILED; + } + path oldPath(oldPath_); + path newPath(newPath_); + errorCode.clear(); + std::filesystem::rename(oldPath, newPath, errorCode); + if (errorCode) { + return HasFileSystemIF::GENERIC_RENAME_ERROR; + } + return returnvalue::OK; +} + +bool HostFilesystem::fileExists(FilesystemParams params) { + path path(params.path); + return filesystem::exists(path); +} + +ReturnValue_t HostFilesystem::truncateFile(FilesystemParams params) { + path path(params.path); + if (not filesystem::exists(path)) { + return FILE_DOES_NOT_EXIST; + } + ofstream of(path); + return returnvalue::OK; +} diff --git a/src/fsfw_hal/host/HostFilesystem.h b/src/fsfw_hal/host/HostFilesystem.h new file mode 100644 index 00000000..7b865e2d --- /dev/null +++ b/src/fsfw_hal/host/HostFilesystem.h @@ -0,0 +1,32 @@ +#ifndef FSFW_HAL_HOSTFILESYSTEM_H +#define FSFW_HAL_HOSTFILESYSTEM_H + +#include + +#include "fsfw/filesystem/HasFileSystemIF.h" + +class HostFilesystem : public HasFileSystemIF { + public: + HostFilesystem(); + + bool fileExists(FilesystemParams params) override; + ReturnValue_t truncateFile(FilesystemParams params) override; + ReturnValue_t writeToFile(FileOpParams params, const uint8_t *data) override; + ReturnValue_t readFromFile(FileOpParams fileOpInfo, uint8_t **buffer, size_t &readSize, + size_t maxSize) override; + ReturnValue_t createFile(FilesystemParams params, const uint8_t *data, size_t size) override; + ReturnValue_t removeFile(const char *path, FileSystemArgsIF *args) override; + ReturnValue_t createDirectory(FilesystemParams params, bool createParentDirs) override; + ReturnValue_t removeDirectory(FilesystemParams params, bool deleteRecurively) override; + ReturnValue_t rename(const char *oldPath, const char *newPath, FileSystemArgsIF *args) override; + + std::error_code errorCode; + using HasFileSystemIF::createDirectory; + using HasFileSystemIF::createFile; + using HasFileSystemIF::removeDirectory; + using HasFileSystemIF::removeFile; + using HasFileSystemIF::rename; + + private: +}; +#endif // FSFW_HAL_HOSTFILESYSTEM_H diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index 7bdbcce2..ad26e392 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -1,18 +1,12 @@ -target_sources(${FSFW_TEST_TGT} PRIVATE - CatchDefinitions.cpp - CatchFactory.cpp - printChar.cpp - testVersion.cpp -) +target_sources(${FSFW_TEST_TGT} PRIVATE CatchDefinitions.cpp CatchFactory.cpp + printChar.cpp testVersion.cpp) -target_sources(${FSFW_TEST_TGT} PRIVATE - CatchRunner.cpp - CatchSetup.cpp -) +target_sources(${FSFW_TEST_TGT} PRIVATE CatchRunner.cpp CatchSetup.cpp) add_subdirectory(testcfg) add_subdirectory(mocks) +add_subdirectory(tcdistributor) add_subdirectory(action) add_subdirectory(power) add_subdirectory(util) diff --git a/unittests/CatchDefinitions.cpp b/unittests/CatchDefinitions.cpp index 85e3aad0..3c76fd88 100644 --- a/unittests/CatchDefinitions.cpp +++ b/unittests/CatchDefinitions.cpp @@ -3,6 +3,8 @@ #include #include +#include "fsfw/FSFW.h" + StorageManagerIF* tglob::getIpcStoreHandle() { if (ObjectManager::instance() != nullptr) { return ObjectManager::instance()->get(objects::IPC_STORE); diff --git a/unittests/CatchDefinitions.h b/unittests/CatchDefinitions.h index 64a72f57..a5949fed 100644 --- a/unittests/CatchDefinitions.h +++ b/unittests/CatchDefinitions.h @@ -5,6 +5,8 @@ #include #include +#include "fsfw/FSFW.h" + namespace tconst { static constexpr MessageQueueId_t testQueueId = 42; } diff --git a/unittests/CatchSetup.cpp b/unittests/CatchSetup.cpp index 9206c2e1..4f2a4a54 100644 --- a/unittests/CatchSetup.cpp +++ b/unittests/CatchSetup.cpp @@ -1,5 +1,6 @@ #include "CatchDefinitions.h" #include "CatchFactory.h" +#include "fsfw/FSFW.h" #ifdef GCOV #include diff --git a/unittests/action/CMakeLists.txt b/unittests/action/CMakeLists.txt index 659f251a..99941357 100644 --- a/unittests/action/CMakeLists.txt +++ b/unittests/action/CMakeLists.txt @@ -1,3 +1 @@ -target_sources(${FSFW_TEST_TGT} PRIVATE - TestActionHelper.cpp -) +target_sources(${FSFW_TEST_TGT} PRIVATE TestActionHelper.cpp) diff --git a/unittests/action/TestActionHelper.cpp b/unittests/action/TestActionHelper.cpp index 77c055aa..d99700d7 100644 --- a/unittests/action/TestActionHelper.cpp +++ b/unittests/action/TestActionHelper.cpp @@ -8,7 +8,7 @@ #include "mocks/MessageQueueMock.h" -TEST_CASE("Action Helper", "[ActionHelper]") { +TEST_CASE("Action Helper", "[action]") { ActionHelperOwnerMockBase testDhMock; // TODO: Setting another number here breaks the test. Find out why MessageQueueMock testMqMock(MessageQueueIF::NO_QUEUE); diff --git a/unittests/cfdp/CMakeLists.txt b/unittests/cfdp/CMakeLists.txt index 8e18cd3b..1867a534 100644 --- a/unittests/cfdp/CMakeLists.txt +++ b/unittests/cfdp/CMakeLists.txt @@ -1,12 +1,5 @@ -target_sources(${FSFW_TEST_TGT} PRIVATE - testCfdp.cpp - testTlvsLvs.cpp - testAckPdu.cpp - testEofPdu.cpp - testNakPdu.cpp - testFinishedPdu.cpp - testPromptPdu.cpp - testKeepAlivePdu.cpp - testMetadataPdu.cpp - testFileData.cpp -) +target_sources(${FSFW_TEST_TGT} PRIVATE testCfdp.cpp testOtherTlvs.cpp + testTlv.cpp testLvs.cpp) + +add_subdirectory(handler) +add_subdirectory(pdu) diff --git a/unittests/cfdp/handler/CMakeLists.txt b/unittests/cfdp/handler/CMakeLists.txt new file mode 100644 index 00000000..f70e5dfb --- /dev/null +++ b/unittests/cfdp/handler/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources( + ${FSFW_TEST_TGT} PRIVATE testDistributor.cpp testDestHandler.cpp + testSourceHandler.cpp testFaultHandler.cpp) diff --git a/unittests/cfdp/handler/testDestHandler.cpp b/unittests/cfdp/handler/testDestHandler.cpp new file mode 100644 index 00000000..0224a20b --- /dev/null +++ b/unittests/cfdp/handler/testDestHandler.cpp @@ -0,0 +1,244 @@ +#include + +#include +#include +#include + +#include "fsfw/cfdp.h" +#include "fsfw/cfdp/pdu/EofPduCreator.h" +#include "fsfw/cfdp/pdu/FileDataCreator.h" +#include "fsfw/cfdp/pdu/MetadataPduCreator.h" +#include "mocks/AcceptsTmMock.h" +#include "mocks/EventReportingProxyMock.h" +#include "mocks/FilesystemMock.h" +#include "mocks/MessageQueueMock.h" +#include "mocks/StorageManagerMock.h" +#include "mocks/cfdp/FaultHandlerMock.h" +#include "mocks/cfdp/RemoteConfigTableMock.h" +#include "mocks/cfdp/UserMock.h" + +TEST_CASE("CFDP Dest Handler", "[cfdp]") { + using namespace cfdp; + using namespace returnvalue; + MessageQueueId_t destQueueId = 2; + AcceptsTmMock tmReceiver(destQueueId); + MessageQueueMock mqMock(destQueueId); + EntityId localId = EntityId(UnsignedByteField(2)); + EntityId remoteId = EntityId(UnsignedByteField(3)); + FaultHandlerMock fhMock; + LocalEntityCfg localEntityCfg(localId, IndicationCfg(), fhMock); + FilesystemMock fsMock; + UserMock userMock(fsMock); + RemoteConfigTableMock remoteCfgTableMock; + PacketInfoList<64> packetInfoList; + LostSegmentsList<128> lostSegmentsList; + DestHandlerParams dp(localEntityCfg, userMock, remoteCfgTableMock, packetInfoList, + lostSegmentsList); + EventReportingProxyMock eventReporterMock; + LocalPool::LocalPoolConfig storeCfg = {{10, 32}, {10, 64}, {10, 128}, {10, 1024}}; + StorageManagerMock tcStore(2, storeCfg); + StorageManagerMock tmStore(3, storeCfg); + FsfwParams fp(tmReceiver, &mqMock, &eventReporterMock); + RemoteEntityCfg cfg(remoteId); + remoteCfgTableMock.addRemoteConfig(cfg); + fp.tcStore = &tcStore; + fp.tmStore = &tmStore; + uint8_t* buf = nullptr; + size_t serLen = 0; + store_address_t storeId; + PduConfig conf; + auto destHandler = DestHandler(dp, fp); + CHECK(destHandler.initialize() == OK); + + auto metadataPreparation = [&](FileSize cfdpFileSize, ChecksumType checksumType) { + std::string srcNameString = "hello.txt"; + std::string destNameString = "hello-cpy.txt"; + StringLv srcName(srcNameString); + StringLv destName(destNameString); + MetadataInfo info(false, checksumType, cfdpFileSize, srcName, destName); + TransactionSeqNum seqNum(UnsignedByteField(1)); + conf.sourceId = remoteId; + conf.destId = localId; + conf.mode = TransmissionMode::UNACKNOWLEDGED; + conf.seqNum = seqNum; + MetadataPduCreator metadataCreator(conf, info); + REQUIRE(tcStore.getFreeElement(&storeId, metadataCreator.getSerializedSize(), &buf) == OK); + REQUIRE(metadataCreator.serialize(buf, serLen, metadataCreator.getSerializedSize()) == OK); + PacketInfo packetInfo(metadataCreator.getPduType(), storeId, + metadataCreator.getDirectiveCode()); + packetInfoList.push_back(packetInfo); + }; + + auto metadataCheck = [&](const cfdp::DestHandler::FsmResult& res, const char* sourceName, + const char* destName, size_t fileLen) { + REQUIRE(res.result == OK); + REQUIRE(res.callStatus == CallStatus::CALL_AGAIN); + REQUIRE(res.errors == 0); + // Assert that the packet was deleted after handling + REQUIRE(not tcStore.hasDataAtId(storeId)); + REQUIRE(packetInfoList.empty()); + REQUIRE(userMock.metadataRecvd.size() == 1); + auto& idMetadataPair = userMock.metadataRecvd.back(); + REQUIRE(idMetadataPair.first == destHandler.getTransactionId()); + REQUIRE(idMetadataPair.second.sourceId.getValue() == 3); + REQUIRE(idMetadataPair.second.fileSize == fileLen); + REQUIRE(strcmp(idMetadataPair.second.destFileName, destName) == 0); + REQUIRE(strcmp(idMetadataPair.second.sourceFileName, sourceName) == 0); + userMock.metadataRecvd.pop(); + REQUIRE(fsMock.fileMap.find(destName) != fsMock.fileMap.end()); + REQUIRE(res.result == OK); + REQUIRE(res.state == CfdpStates::BUSY_CLASS_1_NACKED); + REQUIRE(res.step == DestHandler::TransactionStep::RECEIVING_FILE_DATA_PDUS); + }; + + auto eofPreparation = [&](FileSize cfdpFileSize, uint32_t crc) { + EofInfo eofInfo(cfdp::ConditionCode::NO_ERROR, crc, std::move(cfdpFileSize)); + EofPduCreator eofCreator(conf, eofInfo); + REQUIRE(tcStore.getFreeElement(&storeId, eofCreator.getSerializedSize(), &buf) == OK); + REQUIRE(eofCreator.serialize(buf, serLen, eofCreator.getSerializedSize()) == OK); + PacketInfo packetInfo(eofCreator.getPduType(), storeId, eofCreator.getDirectiveCode()); + packetInfoList.push_back(packetInfo); + }; + + auto eofCheck = [&](const cfdp::DestHandler::FsmResult& res, const TransactionId& id) { + REQUIRE(res.result == OK); + REQUIRE(res.state == CfdpStates::IDLE); + REQUIRE(res.errors == 0); + REQUIRE(res.step == DestHandler::TransactionStep::IDLE); + // Assert that the packet was deleted after handling + REQUIRE(not tcStore.hasDataAtId(storeId)); + REQUIRE(packetInfoList.empty()); + REQUIRE(userMock.eofsRevd.size() == 1); + auto& eofId = userMock.eofsRevd.back(); + CHECK(eofId == id); + REQUIRE(userMock.finishedRecvd.size() == 1); + auto& idParamPair = userMock.finishedRecvd.back(); + CHECK(idParamPair.first == id); + CHECK(idParamPair.second.condCode == ConditionCode::NO_ERROR); + }; + + auto fileDataPduCheck = [&](const cfdp::DestHandler::FsmResult& res, + const std::vector& idsToCheck) { + REQUIRE(res.result == OK); + REQUIRE(res.state == CfdpStates::BUSY_CLASS_1_NACKED); + REQUIRE(res.step == DestHandler::TransactionStep::RECEIVING_FILE_DATA_PDUS); + for (const auto id : idsToCheck) { + REQUIRE(not tcStore.hasDataAtId(id)); + } + REQUIRE(packetInfoList.empty()); + }; + + SECTION("State") { + CHECK(destHandler.getCfdpState() == CfdpStates::IDLE); + CHECK(destHandler.getTransactionStep() == DestHandler::TransactionStep::IDLE); + } + + SECTION("Idle State Machine Iteration") { + auto res = destHandler.performStateMachine(); + CHECK(res.result == OK); + CHECK(res.callStatus == CallStatus::CALL_AFTER_DELAY); + CHECK(res.errors == 0); + CHECK(destHandler.getCfdpState() == CfdpStates::IDLE); + CHECK(destHandler.getTransactionStep() == DestHandler::TransactionStep::IDLE); + } + + SECTION("Empty File Transfer") { + const DestHandler::FsmResult& res = destHandler.performStateMachine(); + CHECK(res.result == OK); + FileSize cfdpFileSize(0); + metadataPreparation(cfdpFileSize, ChecksumType::NULL_CHECKSUM); + destHandler.performStateMachine(); + metadataCheck(res, "hello.txt", "hello-cpy.txt", 0); + destHandler.performStateMachine(); + REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY); + auto transactionId = destHandler.getTransactionId(); + eofPreparation(cfdpFileSize, 0); + // After EOF, operation is done because no closure was requested + destHandler.performStateMachine(); + eofCheck(res, transactionId); + } + + SECTION("Small File Transfer") { + const DestHandler::FsmResult& res = destHandler.performStateMachine(); + CHECK(res.result == OK); + std::string fileData = "hello test data"; + etl::crc32 crcCalc; + crcCalc.add(fileData.begin(), fileData.end()); + uint32_t crc32 = crcCalc.value(); + FileSize cfdpFileSize(fileData.size()); + metadataPreparation(cfdpFileSize, ChecksumType::CRC_32); + destHandler.performStateMachine(); + metadataCheck(res, "hello.txt", "hello-cpy.txt", fileData.size()); + destHandler.performStateMachine(); + REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY); + auto transactionId = destHandler.getTransactionId(); + FileSize offset(0); + FileDataInfo fdPduInfo(offset, reinterpret_cast(fileData.data()), + fileData.size()); + FileDataCreator fdPduCreator(conf, fdPduInfo); + REQUIRE(tcStore.getFreeElement(&storeId, fdPduCreator.getSerializedSize(), &buf) == OK); + REQUIRE(fdPduCreator.serialize(buf, serLen, fdPduCreator.getSerializedSize()) == OK); + PacketInfo packetInfo(fdPduCreator.getPduType(), storeId, std::nullopt); + packetInfoList.push_back(packetInfo); + destHandler.performStateMachine(); + fileDataPduCheck(res, {storeId}); + eofPreparation(cfdpFileSize, crc32); + // After EOF, operation is done because no closure was requested + destHandler.performStateMachine(); + eofCheck(res, transactionId); + } + + SECTION("Segmented File Transfer") { + const DestHandler::FsmResult& res = destHandler.performStateMachine(); + CHECK(res.result == OK); + std::random_device dev; + std::mt19937 rng(dev()); + std::uniform_int_distribution distU8(0, 255); + std::array largerFileData{}; + for (auto& val : largerFileData) { + val = distU8(rng); + } + etl::crc32 crcCalc; + crcCalc.add(largerFileData.begin(), largerFileData.end()); + uint32_t crc32 = crcCalc.value(); + FileSize cfdpFileSize(largerFileData.size()); + metadataPreparation(cfdpFileSize, ChecksumType::CRC_32); + destHandler.performStateMachine(); + metadataCheck(res, "hello.txt", "hello-cpy.txt", largerFileData.size()); + destHandler.performStateMachine(); + REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY); + auto transactionId = destHandler.getTransactionId(); + + std::vector idsToCheck; + { + FileSize offset(0); + FileDataInfo fdPduInfo(offset, reinterpret_cast(largerFileData.data()), + largerFileData.size() / 2); + FileDataCreator fdPduCreator(conf, fdPduInfo); + REQUIRE(tcStore.getFreeElement(&storeId, fdPduCreator.getSerializedSize(), &buf) == OK); + REQUIRE(fdPduCreator.serialize(buf, serLen, fdPduCreator.getSerializedSize()) == OK); + PacketInfo packetInfo(fdPduCreator.getPduType(), storeId, std::nullopt); + idsToCheck.push_back(storeId); + packetInfoList.push_back(packetInfo); + } + + { + FileSize offset(512); + FileDataInfo fdPduInfo(offset, reinterpret_cast(largerFileData.data() + 512), + largerFileData.size() / 2); + FileDataCreator fdPduCreator(conf, fdPduInfo); + REQUIRE(tcStore.getFreeElement(&storeId, fdPduCreator.getSerializedSize(), &buf) == OK); + REQUIRE(fdPduCreator.serialize(buf, serLen, fdPduCreator.getSerializedSize()) == OK); + PacketInfo packetInfo(fdPduCreator.getPduType(), storeId, std::nullopt); + idsToCheck.push_back(storeId); + packetInfoList.push_back(packetInfo); + } + + destHandler.performStateMachine(); + fileDataPduCheck(res, idsToCheck); + eofPreparation(cfdpFileSize, crc32); + // After EOF, operation is done because no closure was requested + destHandler.performStateMachine(); + eofCheck(res, transactionId); + } +} \ No newline at end of file diff --git a/unittests/cfdp/handler/testDistributor.cpp b/unittests/cfdp/handler/testDistributor.cpp new file mode 100644 index 00000000..8b6c46af --- /dev/null +++ b/unittests/cfdp/handler/testDistributor.cpp @@ -0,0 +1,99 @@ +#include + +#include "fsfw/cfdp/CfdpDistributor.h" +#include "fsfw/cfdp/pdu/MetadataPduCreator.h" +#include "fsfw/cfdp/tlv/StringLv.h" +#include "fsfw/storagemanager/LocalPool.h" +#include "fsfw/tcdistribution/definitions.h" +#include "mocks/AcceptsTcMock.h" +#include "mocks/MessageQueueMock.h" +#include "mocks/StorageManagerMock.h" + +TEST_CASE("CFDP Distributor", "[cfdp][distributor]") { + LocalPool::LocalPoolConfig cfg = {{5, 32}, {2, 64}}; + StorageManagerMock pool(objects::NO_OBJECT, cfg); + auto queue = MessageQueueMock(1); + CfdpDistribCfg distribCfg(1, pool, &queue); + auto distributor = CfdpDistributor(distribCfg); + auto obswEntityId = cfdp::EntityId(UnsignedByteField(2)); + auto groundEntityId = cfdp::EntityId(UnsignedByteField(1)); + MessageQueueId_t receiverQueueId = 3; + auto tcAcceptor = AcceptsTcMock("CFDP Receiver", 0, receiverQueueId); + + // Set up Metadata PDU for generate test data. + cfdp::FileSize fileSize(12); + const cfdp::EntityId& sourceId(groundEntityId); + const cfdp::EntityId& destId(obswEntityId); + cfdp::TransactionSeqNum seqNum(UnsignedByteField(12)); + auto pduConf = PduConfig(sourceId, destId, cfdp::TransmissionMode::UNACKNOWLEDGED, seqNum); + std::string sourceFileString = "hello.txt"; + cfdp::StringLv sourceFileName(sourceFileString); + std::string destFileString = "hello2.txt"; + cfdp::StringLv destFileName(destFileString); + MetadataInfo metadataInfo(false, cfdp::ChecksumType::CRC_32, fileSize, sourceFileName, + destFileName); + MetadataPduCreator creator(pduConf, metadataInfo); + uint8_t* dataPtr = nullptr; + + SECTION("State") { + CHECK(distributor.initialize() == returnvalue::OK); + CHECK(std::strcmp(distributor.getName(), "CFDP Distributor") == 0); + CHECK(distributor.getIdentifier() == 0); + CHECK(distributor.getRequestQueue() == queue.getId()); + } + + SECTION("Packet Forwarding") { + CHECK(distributor.initialize() == returnvalue::OK); + CHECK(distributor.registerTcDestination(obswEntityId, tcAcceptor) == returnvalue::OK); + size_t serLen = 0; + store_address_t storeId; + CHECK(pool.LocalPool::getFreeElement(&storeId, creator.getSerializedSize(), &dataPtr) == + returnvalue::OK); + REQUIRE(creator.SerializeIF::serializeBe(dataPtr, serLen, creator.getSerializedSize()) == + returnvalue::OK); + TmTcMessage msg(storeId); + queue.addReceivedMessage(msg); + CHECK(distributor.performOperation(0) == returnvalue::OK); + CHECK(queue.wasMessageSent()); + CHECK(queue.numberOfSentMessages() == 1); + // The packet is forwarded, with no need to delete the data + CHECK(pool.hasDataAtId(storeId)); + TmTcMessage sentMsg; + CHECK(queue.getNextSentMessage(receiverQueueId, sentMsg) == returnvalue::OK); + CHECK(sentMsg.getStorageId() == storeId); + } + + SECTION("No Destination found") { + CHECK(distributor.initialize() == returnvalue::OK); + size_t serLen = 0; + store_address_t storeId; + CHECK(pool.LocalPool::getFreeElement(&storeId, creator.getSerializedSize(), &dataPtr) == + returnvalue::OK); + REQUIRE(creator.SerializeIF::serializeBe(dataPtr, serLen, creator.getSerializedSize()) == + returnvalue::OK); + TmTcMessage msg(storeId); + queue.addReceivedMessage(msg); + CHECK(distributor.performOperation(0) == tmtcdistrib::NO_DESTINATION_FOUND); + } + + SECTION("Getting data fails") { + pool.nextModifyDataCallFails.first = true; + pool.nextModifyDataCallFails.second = StorageManagerIF::DATA_DOES_NOT_EXIST; + size_t serLen = 0; + store_address_t storeId; + CHECK(distributor.registerTcDestination(obswEntityId, tcAcceptor) == returnvalue::OK); + CHECK(pool.LocalPool::getFreeElement(&storeId, creator.getSerializedSize(), &dataPtr) == + returnvalue::OK); + REQUIRE(creator.SerializeIF::serializeBe(dataPtr, serLen, creator.getSerializedSize()) == + returnvalue::OK); + TmTcMessage msg(storeId); + queue.addReceivedMessage(msg); + CHECK(distributor.performOperation(0) == StorageManagerIF::DATA_DOES_NOT_EXIST); + } + + SECTION("Duplicate registration") { + CHECK(distributor.initialize() == returnvalue::OK); + CHECK(distributor.registerTcDestination(obswEntityId, tcAcceptor) == returnvalue::OK); + CHECK(distributor.registerTcDestination(obswEntityId, tcAcceptor) == returnvalue::FAILED); + } +} \ No newline at end of file diff --git a/unittests/cfdp/handler/testFaultHandler.cpp b/unittests/cfdp/handler/testFaultHandler.cpp new file mode 100644 index 00000000..5da9a70d --- /dev/null +++ b/unittests/cfdp/handler/testFaultHandler.cpp @@ -0,0 +1,89 @@ +#include + +#include "mocks/cfdp/FaultHandlerMock.h" + +TEST_CASE("CFDP Fault Handler", "[cfdp]") { + using namespace cfdp; + auto fhMock = FaultHandlerMock(); + cfdp::FaultHandlerCode fhCode; + cfdp::TransactionId id; + + SECTION("State") { + // Verify initial condition + CHECK(fhMock.getFaultHandler(ConditionCode::UNSUPPORTED_CHECKSUM_TYPE, fhCode)); + CHECK(fhCode == FaultHandlerCode::IGNORE_ERROR); + CHECK(fhMock.getFaultHandler(ConditionCode::POSITIVE_ACK_LIMIT_REACHED, fhCode)); + CHECK(fhCode == FaultHandlerCode::IGNORE_ERROR); + CHECK(fhMock.getFaultHandler(ConditionCode::KEEP_ALIVE_LIMIT_REACHED, fhCode)); + CHECK(fhCode == FaultHandlerCode::IGNORE_ERROR); + CHECK(fhMock.getFaultHandler(ConditionCode::INVALID_TRANSMISSION_MODE, fhCode)); + CHECK(fhCode == FaultHandlerCode::IGNORE_ERROR); + CHECK(fhMock.getFaultHandler(ConditionCode::FILESTORE_REJECTION, fhCode)); + CHECK(fhCode == FaultHandlerCode::IGNORE_ERROR); + CHECK(fhMock.getFaultHandler(ConditionCode::FILE_CHECKSUM_FAILURE, fhCode)); + CHECK(fhCode == FaultHandlerCode::IGNORE_ERROR); + CHECK(fhMock.getFaultHandler(ConditionCode::FILE_SIZE_ERROR, fhCode)); + CHECK(fhCode == FaultHandlerCode::IGNORE_ERROR); + CHECK(fhMock.getFaultHandler(ConditionCode::NAK_LIMIT_REACHED, fhCode)); + CHECK(fhCode == FaultHandlerCode::IGNORE_ERROR); + CHECK(fhMock.getFaultHandler(ConditionCode::INACTIVITY_DETECTED, fhCode)); + CHECK(fhCode == FaultHandlerCode::IGNORE_ERROR); + CHECK(fhMock.getFaultHandler(ConditionCode::CHECK_LIMIT_REACHED, fhCode)); + CHECK(fhCode == FaultHandlerCode::IGNORE_ERROR); + } + + SECTION("Call Handler, Ignore Fault") { + auto& info = fhMock.getFhInfo(FaultHandlerCode::IGNORE_ERROR); + CHECK(fhMock.reportFault(id, ConditionCode::CHECK_LIMIT_REACHED)); + CHECK(info.callCount == 1); + CHECK(info.condCodes.back() == ConditionCode::CHECK_LIMIT_REACHED); + fhMock.reportFault(id, ConditionCode::FILE_CHECKSUM_FAILURE); + CHECK(info.callCount == 2); + CHECK(info.condCodes.back() == ConditionCode::FILE_CHECKSUM_FAILURE); + } + + SECTION("Invalid Reported Code") { CHECK(not fhMock.reportFault(id, ConditionCode::NO_ERROR)); } + + SECTION("Invalid FH code") { + CHECK(not fhMock.setFaultHandler(ConditionCode::KEEP_ALIVE_LIMIT_REACHED, + FaultHandlerCode::RESERVED)); + CHECK(fhMock.getFaultHandler(ConditionCode::KEEP_ALIVE_LIMIT_REACHED, fhCode)); + CHECK(fhCode == FaultHandlerCode::IGNORE_ERROR); + CHECK(not fhMock.setFaultHandler(ConditionCode::NO_ERROR, FaultHandlerCode::IGNORE_ERROR)); + CHECK(not fhMock.getFaultHandler(ConditionCode::NO_ERROR, fhCode)); + } + + SECTION("Set Other Fault Handler") { + CHECK(fhMock.setFaultHandler(ConditionCode::FILE_CHECKSUM_FAILURE, + FaultHandlerCode::NOTICE_OF_CANCELLATION)); + CHECK(fhMock.setFaultHandler(ConditionCode::INACTIVITY_DETECTED, + FaultHandlerCode::ABANDON_TRANSACTION)); + CHECK(fhMock.setFaultHandler(ConditionCode::KEEP_ALIVE_LIMIT_REACHED, + FaultHandlerCode::NOTICE_OF_SUSPENSION)); + auto& ignoreInfo = fhMock.getFhInfo(FaultHandlerCode::IGNORE_ERROR); + auto& cancellationInfo = fhMock.getFhInfo(FaultHandlerCode::NOTICE_OF_CANCELLATION); + auto& suspensionInfo = fhMock.getFhInfo(FaultHandlerCode::NOTICE_OF_SUSPENSION); + auto& abandonInfo = fhMock.getFhInfo(FaultHandlerCode::ABANDON_TRANSACTION); + + CHECK(fhMock.reportFault(id, ConditionCode::FILE_CHECKSUM_FAILURE)); + CHECK(cancellationInfo.callCount == 1); + CHECK(cancellationInfo.condCodes.back() == ConditionCode::FILE_CHECKSUM_FAILURE); + CHECK(ignoreInfo.callCount == 0); + CHECK(suspensionInfo.callCount == 0); + CHECK(abandonInfo.callCount == 0); + + CHECK(fhMock.reportFault(id, ConditionCode::INACTIVITY_DETECTED)); + CHECK(cancellationInfo.callCount == 1); + CHECK(ignoreInfo.callCount == 0); + CHECK(suspensionInfo.callCount == 0); + CHECK(abandonInfo.callCount == 1); + CHECK(abandonInfo.condCodes.back() == ConditionCode::INACTIVITY_DETECTED); + + CHECK(fhMock.reportFault(id, ConditionCode::KEEP_ALIVE_LIMIT_REACHED)); + CHECK(cancellationInfo.callCount == 1); + CHECK(ignoreInfo.callCount == 0); + CHECK(suspensionInfo.callCount == 1); + CHECK(suspensionInfo.condCodes.back() == ConditionCode::KEEP_ALIVE_LIMIT_REACHED); + CHECK(abandonInfo.callCount == 1); + } +} \ No newline at end of file diff --git a/unittests/cfdp/handler/testSourceHandler.cpp b/unittests/cfdp/handler/testSourceHandler.cpp new file mode 100644 index 00000000..570ecb08 --- /dev/null +++ b/unittests/cfdp/handler/testSourceHandler.cpp @@ -0,0 +1,3 @@ +#include + +TEST_CASE("CFDP Source Handler", "[cfdp]") {} \ No newline at end of file diff --git a/unittests/cfdp/pdu/CMakeLists.txt b/unittests/cfdp/pdu/CMakeLists.txt new file mode 100644 index 00000000..02981217 --- /dev/null +++ b/unittests/cfdp/pdu/CMakeLists.txt @@ -0,0 +1,13 @@ +target_sources( + ${FSFW_TEST_TGT} + PRIVATE testAckPdu.cpp + testAckPdu.cpp + testEofPdu.cpp + testNakPdu.cpp + testFinishedPdu.cpp + testPromptPdu.cpp + testKeepAlivePdu.cpp + testMetadataPdu.cpp + testFileData.cpp + testCfdpHeader.cpp + testFileDirective.cpp) diff --git a/unittests/cfdp/pdu/testAckPdu.cpp b/unittests/cfdp/pdu/testAckPdu.cpp new file mode 100644 index 00000000..10b264ec --- /dev/null +++ b/unittests/cfdp/pdu/testAckPdu.cpp @@ -0,0 +1,100 @@ +#include +#include + +#include "fsfw/cfdp/pdu/AckPduCreator.h" +#include "fsfw/cfdp/pdu/AckPduReader.h" +#include "fsfw/globalfunctions/arrayprinter.h" + +TEST_CASE("ACK PDU", "[cfdp][pdu]") { + using namespace cfdp; + ReturnValue_t result; + std::array buf = {}; + uint8_t* bufptr = buf.data(); + size_t maxsz = buf.size(); + size_t sz = 0; + auto seqNum = TransactionSeqNum(WidthInBytes::TWO_BYTES, 15); + auto sourceId = EntityId(WidthInBytes::TWO_BYTES, 1); + auto destId = EntityId(WidthInBytes::TWO_BYTES, 2); + auto pduConf = PduConfig(sourceId, destId, TransmissionMode::ACKNOWLEDGED, seqNum); + AckInfo ackInfo(FileDirective::EOF_DIRECTIVE, ConditionCode::NO_ERROR, + AckTransactionStatus::ACTIVE); + auto ackSerializer = AckPduCreator(ackInfo, pduConf); + result = ackSerializer.serialize(&bufptr, &sz, maxsz, SerializeIF::Endianness::NETWORK); + REQUIRE(result == returnvalue::OK); + + SECTION("Serialize") { + REQUIRE(buf[sz - 3] == cfdp::FileDirective::ACK); + REQUIRE((buf[sz - 2] >> 4) == FileDirective::EOF_DIRECTIVE); + REQUIRE((buf[sz - 2] & 0x0f) == 0); + REQUIRE(buf[sz - 1] == AckTransactionStatus::ACTIVE); + ackInfo.setAckedDirective(FileDirective::FINISH); + ackInfo.setAckedConditionCode(ConditionCode::FILESTORE_REJECTION); + ackInfo.setTransactionStatus(AckTransactionStatus::TERMINATED); + auto ackSerializer2 = AckPduCreator(ackInfo, pduConf); + bufptr = buf.data(); + sz = 0; + result = ackSerializer2.serialize(&bufptr, &sz, maxsz, SerializeIF::Endianness::NETWORK); + REQUIRE(result == returnvalue::OK); + REQUIRE(buf[sz - 3] == cfdp::FileDirective::ACK); + REQUIRE((buf[sz - 2] >> 4) == FileDirective::FINISH); + REQUIRE((buf[sz - 2] & 0x0f) == 0b0001); + REQUIRE((buf[sz - 1] >> 4) == ConditionCode::FILESTORE_REJECTION); + REQUIRE((buf[sz - 1] & 0b11) == AckTransactionStatus::TERMINATED); + + bufptr = buf.data(); + sz = 0; + ackInfo.setAckedDirective(FileDirective::KEEP_ALIVE); + auto ackSerializer3 = AckPduCreator(ackInfo, pduConf); + result = ackSerializer3.serialize(&bufptr, &sz, maxsz, SerializeIF::Endianness::NETWORK); + // Invalid file directive + REQUIRE(result != returnvalue::OK); + + ackInfo.setAckedDirective(FileDirective::FINISH); + // buffer too small + result = ackSerializer.serialize(&bufptr, &sz, 8, SerializeIF::Endianness::NETWORK); + REQUIRE(result == SerializeIF::BUFFER_TOO_SHORT); + } + + SECTION("Deserialize") { + AckInfo ackInfo2; + auto reader = AckPduReader(buf.data(), sz, ackInfo2); + result = reader.parseData(); + REQUIRE(result == returnvalue::OK); + REQUIRE(ackInfo2.getAckedDirective() == FileDirective::EOF_DIRECTIVE); + REQUIRE(ackInfo2.getAckedConditionCode() == ConditionCode::NO_ERROR); + REQUIRE(ackInfo2.getDirectiveSubtypeCode() == 0); + REQUIRE(ackInfo2.getTransactionStatus() == AckTransactionStatus::ACTIVE); + + AckInfo newInfo = AckInfo(FileDirective::FINISH, ConditionCode::FILESTORE_REJECTION, + AckTransactionStatus::TERMINATED); + auto ackSerializer2 = AckPduCreator(newInfo, pduConf); + bufptr = buf.data(); + sz = 0; + result = ackSerializer2.serialize(&bufptr, &sz, maxsz, SerializeIF::Endianness::NETWORK); + REQUIRE(result == returnvalue::OK); + + auto reader2 = AckPduReader(buf.data(), sz, ackInfo2); + result = reader2.parseData(); + REQUIRE(result == returnvalue::OK); + REQUIRE(ackInfo2.getAckedDirective() == FileDirective::FINISH); + REQUIRE(ackInfo2.getAckedConditionCode() == ConditionCode::FILESTORE_REJECTION); + REQUIRE(ackInfo2.getDirectiveSubtypeCode() == 0b0001); + REQUIRE(ackInfo2.getTransactionStatus() == AckTransactionStatus::TERMINATED); + + uint8_t prevVal = buf[sz - 2]; + buf[sz - 2] = FileDirective::INVALID_DIRECTIVE << 4; + result = reader2.parseData(); + REQUIRE(result == cfdp::INVALID_ACK_DIRECTIVE_FIELDS); + buf[sz - 2] = FileDirective::FINISH << 4 | 0b1111; + result = reader2.parseData(); + REQUIRE(result == cfdp::INVALID_ACK_DIRECTIVE_FIELDS); + buf[sz - 2] = prevVal; + buf[sz - 3] = cfdp::FileDirective::INVALID_DIRECTIVE; + result = reader2.parseData(); + REQUIRE(result == cfdp::INVALID_DIRECTIVE_FIELD); + buf[sz - 3] = cfdp::FileDirective::ACK; + auto maxSizeTooSmall = AckPduReader(buf.data(), sz - 2, ackInfo2); + result = maxSizeTooSmall.parseData(); + REQUIRE(result == SerializeIF::STREAM_TOO_SHORT); + } +} diff --git a/unittests/cfdp/pdu/testCfdpHeader.cpp b/unittests/cfdp/pdu/testCfdpHeader.cpp new file mode 100644 index 00000000..5f81bec9 --- /dev/null +++ b/unittests/cfdp/pdu/testCfdpHeader.cpp @@ -0,0 +1,327 @@ +#include +#include + +#include "fsfw/cfdp/pdu/FinishedInfo.h" +#include "fsfw/cfdp/pdu/FinishedPduCreator.h" +#include "fsfw/cfdp/pdu/HeaderCreator.h" +#include "fsfw/cfdp/pdu/PduHeaderReader.h" +#include "fsfw/returnvalues/returnvalue.h" + +using namespace returnvalue; + +TEST_CASE("CFDP Header", "[cfdp]") { + using namespace cfdp; + std::array serBuf{}; + ReturnValue_t result; + cfdp::TransactionSeqNum seqNum = TransactionSeqNum(cfdp::WidthInBytes::ONE_BYTE, 2); + cfdp::EntityId sourceId = EntityId(cfdp::WidthInBytes::ONE_BYTE, 0); + cfdp::EntityId destId = EntityId(cfdp::WidthInBytes::ONE_BYTE, 1); + PduConfig pduConf = + PduConfig(sourceId, destId, cfdp::TransmissionMode::ACKNOWLEDGED, seqNum, false); + uint8_t* serTarget = serBuf.data(); + const uint8_t* deserTarget = serTarget; + size_t serSize = 0; + auto creator = HeaderCreator(pduConf, cfdp::PduType::FILE_DIRECTIVE, 0); + + SECTION("Header State") { + REQUIRE(seqNum.getSerializedSize() == 1); + REQUIRE(creator.getPduDataFieldLen() == 0); + REQUIRE(creator.getSerializedSize() == 7); + REQUIRE(creator.getWholePduSize() == 7); + REQUIRE(creator.getCrcFlag() == false); + REQUIRE(creator.getDirection() == cfdp::Direction::TOWARDS_RECEIVER); + REQUIRE(creator.getLargeFileFlag() == false); + REQUIRE(creator.getLenEntityIds() == 1); + REQUIRE(creator.getLenSeqNum() == 1); + REQUIRE(creator.getPduType() == cfdp::PduType::FILE_DIRECTIVE); + REQUIRE(creator.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::NOT_PRESENT); + REQUIRE(creator.getSegmentationControl() == false); + REQUIRE(creator.getTransmissionMode() == cfdp::TransmissionMode::ACKNOWLEDGED); + cfdp::TransactionSeqNum seqNumLocal; + creator.getTransactionSeqNum(seqNumLocal); + REQUIRE(seqNumLocal.getWidth() == cfdp::WidthInBytes::ONE_BYTE); + REQUIRE(seqNumLocal.getValue() == 2); + cfdp::EntityId sourceDestId; + creator.getSourceId(sourceDestId); + REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::ONE_BYTE); + REQUIRE(sourceDestId.getValue() == 0); + creator.getDestId(sourceDestId); + REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::ONE_BYTE); + REQUIRE(sourceDestId.getValue() == 1); + } + + SECTION("Deserialization fails") { + const uint8_t** dummyPtr = nullptr; + REQUIRE(creator.deSerialize(dummyPtr, &serSize, SerializeIF::Endianness::NETWORK) == + returnvalue::FAILED); + } + + SECTION("Serialization fails") { + REQUIRE(creator.serialize(nullptr, &serSize, serBuf.size(), SerializeIF::Endianness::NETWORK) == + returnvalue::FAILED); + } + + SECTION("Buffer Too Short") { + for (uint8_t idx = 0; idx < 7; idx++) { + result = creator.serialize(&serTarget, &serSize, idx, SerializeIF::Endianness::BIG); + REQUIRE(result == static_cast(SerializeIF::BUFFER_TOO_SHORT)); + } + } + + SECTION("Set Data Field Len") { + // Set PDU data field len + creator.setPduDataFieldLen(0x0ff0); + REQUIRE(creator.getPduDataFieldLen() == 0x0ff0); + REQUIRE(creator.getSerializedSize() == 7); + REQUIRE(creator.getWholePduSize() == 7 + 0x0ff0); + serTarget = serBuf.data(); + serSize = 0; + result = creator.serialize(&serTarget, &serSize, serBuf.size(), SerializeIF::Endianness::BIG); + REQUIRE(serBuf[1] == 0x0f); + REQUIRE(serBuf[2] == 0xf0); + } + + SECTION("Serialize with Fields Flipped") { + pduConf.crcFlag = true; + pduConf.largeFile = true; + pduConf.direction = cfdp::Direction::TOWARDS_SENDER; + pduConf.mode = cfdp::TransmissionMode::UNACKNOWLEDGED; + creator.setSegmentationControl(cfdp::SegmentationControl::RECORD_BOUNDARIES_PRESERVATION); + creator.setPduType(cfdp::PduType::FILE_DATA); + creator.setSegmentMetadataFlag(cfdp::SegmentMetadataFlag::PRESENT); + serTarget = serBuf.data(); + serSize = 0; + + SECTION("Regular") { + // Everything except version bit flipped to one now + REQUIRE(creator.serialize(&serTarget, &serSize, serBuf.size(), + SerializeIF::Endianness::BIG) == returnvalue::OK); + CHECK(serBuf[0] == 0x3f); + CHECK(serBuf[3] == 0x99); + REQUIRE(creator.getCrcFlag() == true); + REQUIRE(creator.getDirection() == cfdp::Direction::TOWARDS_SENDER); + REQUIRE(creator.getLargeFileFlag() == true); + REQUIRE(creator.getLenEntityIds() == 1); + REQUIRE(creator.getLenSeqNum() == 1); + REQUIRE(creator.getPduType() == cfdp::PduType::FILE_DATA); + REQUIRE(creator.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::PRESENT); + REQUIRE(creator.getTransmissionMode() == cfdp::TransmissionMode::UNACKNOWLEDGED); + REQUIRE(creator.getSegmentationControl() == true); + } + + SECTION("Other variable sized fields") { + pduConf.seqNum.setValue(cfdp::WidthInBytes::TWO_BYTES, 0x0fff); + pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00); + pduConf.destId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff); + REQUIRE(pduConf.sourceId.getSerializedSize() == 4); + REQUIRE(creator.getSerializedSize() == 14); + REQUIRE(creator.serialize(&serTarget, &serSize, serBuf.size(), + SerializeIF::Endianness::BIG) == returnvalue::OK); + REQUIRE(creator.getCrcFlag() == true); + REQUIRE(creator.getDirection() == cfdp::Direction::TOWARDS_SENDER); + REQUIRE(creator.getLargeFileFlag() == true); + REQUIRE(creator.getLenEntityIds() == 4); + REQUIRE(creator.getLenSeqNum() == 2); + REQUIRE(creator.getPduType() == cfdp::PduType::FILE_DATA); + REQUIRE(creator.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::PRESENT); + REQUIRE(creator.getTransmissionMode() == cfdp::TransmissionMode::UNACKNOWLEDGED); + REQUIRE(creator.getSegmentationControl() == true); + // Last three bits are 2 now (length of seq number) and bit 1 to bit 3 is 4 (len entity IDs) + REQUIRE(serBuf[3] == 0b11001010); + uint32_t entityId = 0; + size_t deSerSize = 0; + SerializeAdapter::deSerialize(&entityId, serBuf.data() + 4, &deSerSize, + SerializeIF::Endianness::NETWORK); + CHECK(deSerSize == 4); + CHECK(entityId == 0xff00ff00); + uint16_t seqNumRaw = 0; + SerializeAdapter::deSerialize(&seqNumRaw, serBuf.data() + 8, &deSerSize, + SerializeIF::Endianness::NETWORK); + CHECK(deSerSize == 2); + CHECK(seqNumRaw == 0x0fff); + SerializeAdapter::deSerialize(&entityId, serBuf.data() + 10, &deSerSize, + SerializeIF::Endianness::NETWORK); + CHECK(deSerSize == 4); + CHECK(entityId == 0x00ff00ff); + } + + SECTION("Buffer Too Short") { + pduConf.seqNum.setValue(cfdp::WidthInBytes::TWO_BYTES, 0x0fff); + pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00); + pduConf.destId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff); + for (uint8_t idx = 0; idx < 14; idx++) { + REQUIRE(creator.serialize(&serTarget, &serSize, idx, SerializeIF::Endianness::BIG) == + SerializeIF::BUFFER_TOO_SHORT); + } + } + } + + SECTION("Invalid Variable Sized Fields") { + result = pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 0xfff); + REQUIRE(result == returnvalue::FAILED); + result = pduConf.sourceId.setValue(cfdp::WidthInBytes::TWO_BYTES, 0xfffff); + REQUIRE(result == returnvalue::FAILED); + result = pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xfffffffff); + REQUIRE(result == returnvalue::FAILED); + } + + SECTION("Header Serialization") { + result = creator.serialize(&serTarget, &serSize, serBuf.size(), SerializeIF::Endianness::BIG); + REQUIRE(result == returnvalue::OK); + REQUIRE(serSize == 7); + // Only version bits are set + REQUIRE(serBuf[0] == 0b00100000); + // PDU data field length is 0 + REQUIRE(serBuf[1] == 0); + REQUIRE(serBuf[2] == 0); + // Entity and Transaction Sequence number are 1 byte large + REQUIRE(serBuf[3] == 0b00010001); + // Source ID + REQUIRE(serBuf[4] == 0); + // Transaction Seq Number + REQUIRE(serBuf[5] == 2); + // Dest ID + REQUIRE(serBuf[6] == 1); + + uint8_t oneByteSourceId = 32; + serTarget = &oneByteSourceId; + size_t deserLen = 1; + pduConf.sourceId.deSerialize(cfdp::WidthInBytes::ONE_BYTE, + const_cast(&serTarget), &deserLen, + SerializeIF::Endianness::MACHINE); + REQUIRE(pduConf.sourceId.getValue() == 32); + + uint16_t twoByteSourceId = 0xf0f0; + serTarget = reinterpret_cast(&twoByteSourceId); + deserLen = 2; + pduConf.sourceId.deSerialize(cfdp::WidthInBytes::TWO_BYTES, + const_cast(&serTarget), &deserLen, + SerializeIF::Endianness::MACHINE); + REQUIRE(pduConf.sourceId.getValue() == 0xf0f0); + + uint32_t fourByteSourceId = 0xf0f0f0f0; + serTarget = reinterpret_cast(&fourByteSourceId); + deserLen = 4; + pduConf.sourceId.deSerialize(cfdp::WidthInBytes::FOUR_BYTES, + const_cast(&serTarget), &deserLen, + SerializeIF::Endianness::MACHINE); + REQUIRE(pduConf.sourceId.getValue() == 0xf0f0f0f0); + + pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 1); + serTarget = serBuf.data(); + serSize = 1; + result = pduConf.sourceId.serialize(&serTarget, &serSize, 1, SerializeIF::Endianness::MACHINE); + REQUIRE(result == static_cast(SerializeIF::BUFFER_TOO_SHORT)); + } + + SECTION("Header Deserialization 0") { + REQUIRE(creator.serialize(&serTarget, &serSize, serBuf.size(), SerializeIF::Endianness::BIG) == + returnvalue::OK); + REQUIRE(serBuf[1] == 0); + REQUIRE(serBuf[2] == 0); + // Entity and Transaction Sequence number are 1 byte large + REQUIRE(serBuf[3] == 0b00010001); + REQUIRE(serSize == 7); + // Deser call not strictly necessary + auto reader = PduHeaderReader(serBuf.data(), serBuf.size()); + + ReturnValue_t serResult = reader.parseData(); + REQUIRE(serResult == returnvalue::OK); + REQUIRE(reader.getPduDataFieldLen() == 0); + REQUIRE(reader.getHeaderSize() == 7); + REQUIRE(reader.getWholePduSize() == 7); + REQUIRE(reader.getCrcFlag() == false); + REQUIRE(reader.getDirection() == cfdp::Direction::TOWARDS_RECEIVER); + REQUIRE(reader.getLargeFileFlag() == false); + REQUIRE(reader.getLenEntityIds() == 1); + REQUIRE(reader.getLenSeqNum() == 1); + REQUIRE(reader.getPduType() == cfdp::PduType::FILE_DIRECTIVE); + REQUIRE(reader.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::NOT_PRESENT); + REQUIRE(reader.getSegmentationControl() == false); + REQUIRE(reader.getTransmissionMode() == cfdp::TransmissionMode::ACKNOWLEDGED); + // No PDU data contained, so the PDU data field is empty + REQUIRE(reader.getPduDataField() == nullptr); + + size_t deSerSize = reader.getWholePduSize(); + serTarget = serBuf.data(); + const auto** serTargetConst = const_cast(&serTarget); + result = reader.parseData(); + REQUIRE(result == returnvalue::OK); + } + + SECTION("Header Deserialization 1") { + pduConf.crcFlag = true; + pduConf.largeFile = true; + pduConf.direction = cfdp::Direction::TOWARDS_SENDER; + pduConf.mode = cfdp::TransmissionMode::UNACKNOWLEDGED; + creator.setSegmentationControl(cfdp::SegmentationControl::RECORD_BOUNDARIES_PRESERVATION); + creator.setPduType(cfdp::PduType::FILE_DATA); + creator.setSegmentMetadataFlag(cfdp::SegmentMetadataFlag::PRESENT); + result = pduConf.seqNum.setValue(cfdp::WidthInBytes::TWO_BYTES, 0x0fff); + REQUIRE(result == returnvalue::OK); + result = pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00); + REQUIRE(result == returnvalue::OK); + result = pduConf.destId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff); + REQUIRE(result == returnvalue::OK); + serTarget = serBuf.data(); + serSize = 0; + result = creator.serialize(&serTarget, &serSize, serBuf.size(), SerializeIF::Endianness::BIG); + PduHeaderReader reader(serBuf.data(), serBuf.size()); + REQUIRE(reader.parseData() == returnvalue::OK); + // Everything except version bit flipped to one now + REQUIRE(serBuf[0] == 0x3f); + REQUIRE(serBuf[3] == 0b11001010); + REQUIRE(reader.getWholePduSize() == 14); + + REQUIRE(reader.getCrcFlag() == true); + REQUIRE(reader.getDirection() == cfdp::Direction::TOWARDS_SENDER); + REQUIRE(reader.getLargeFileFlag() == true); + REQUIRE(reader.getLenEntityIds() == 4); + REQUIRE(reader.getLenSeqNum() == 2); + REQUIRE(reader.getPduType() == cfdp::PduType::FILE_DATA); + REQUIRE(reader.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::PRESENT); + REQUIRE(reader.getSegmentationControl() == true); + REQUIRE(reader.getTransmissionMode() == cfdp::TransmissionMode::UNACKNOWLEDGED); + // Again, no data field set because this is a header only + REQUIRE(reader.getPduDataField() == nullptr); + + cfdp::TransactionSeqNum seqNumLocal; + reader.getTransactionSeqNum(seqNumLocal); + REQUIRE(seqNumLocal.getWidth() == cfdp::WidthInBytes::TWO_BYTES); + REQUIRE(seqNumLocal.getValue() == 0x0fff); + cfdp::EntityId sourceDestId; + reader.getSourceId(sourceDestId); + REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::FOUR_BYTES); + REQUIRE(sourceDestId.getValue() == 0xff00ff00); + reader.getDestId(sourceDestId); + REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::FOUR_BYTES); + REQUIRE(sourceDestId.getValue() == 0x00ff00ff); + CHECK(reader.setReadOnlyData(nullptr, -1) != returnvalue::OK); + REQUIRE(reader.getHeaderSize() == 14); + + SECTION("Manipulate Source Dest ID") { + serTarget = serBuf.data(); + serSize = 0; + pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 22); + pduConf.destId.setValue(cfdp::WidthInBytes::ONE_BYTE, 48); + result = creator.serialize(&serTarget, &serSize, serBuf.size(), SerializeIF::Endianness::BIG); + reader.getSourceId(sourceDestId); + REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::ONE_BYTE); + REQUIRE(sourceDestId.getValue() == 22); + } + } + + SECTION("Verify data field pointer") { + FinishedInfo info(cfdp::ConditionCode::INACTIVITY_DETECTED, + cfdp::FileDeliveryCode::DATA_INCOMPLETE, + cfdp::FileDeliveryStatus::DISCARDED_DELIBERATELY); + FinishPduCreator finishCreator(pduConf, info); + REQUIRE(finishCreator.serialize(serBuf.data(), serSize, serBuf.size()) == OK); + // This PDU contains the directive code and some finishes PDU properties packed into one byte + // in addition to the header + REQUIRE(finishCreator.getSerializedSize() == 9); + PduHeaderReader reader(serBuf.data(), serBuf.size()); + REQUIRE(reader.parseData() == returnvalue::OK); + REQUIRE(reader.getPduDataField() == serBuf.data() + 7); + } +} diff --git a/unittests/cfdp/testEofPdu.cpp b/unittests/cfdp/pdu/testEofPdu.cpp similarity index 82% rename from unittests/cfdp/testEofPdu.cpp rename to unittests/cfdp/pdu/testEofPdu.cpp index b5cd801c..83e61780 100644 --- a/unittests/cfdp/testEofPdu.cpp +++ b/unittests/cfdp/pdu/testEofPdu.cpp @@ -1,11 +1,11 @@ #include #include -#include "fsfw/cfdp/pdu/EofPduDeserializer.h" -#include "fsfw/cfdp/pdu/EofPduSerializer.h" +#include "fsfw/cfdp/pdu/EofPduCreator.h" +#include "fsfw/cfdp/pdu/EofPduReader.h" #include "fsfw/globalfunctions/arrayprinter.h" -TEST_CASE("EOF PDU", "[EofPdu]") { +TEST_CASE("EOF PDU", "[cfdp][pdu]") { using namespace cfdp; ReturnValue_t result = returnvalue::OK; @@ -20,9 +20,9 @@ TEST_CASE("EOF PDU", "[EofPdu]") { TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15); EntityId sourceId(WidthInBytes::TWO_BYTES, 1); - PduConfig pduConf(TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId); + PduConfig pduConf(sourceId, destId, TransmissionMode::ACKNOWLEDGED, seqNum); - auto eofSerializer = EofPduSerializer(pduConf, eofInfo); + auto eofSerializer = EofPduCreator(pduConf, eofInfo); SECTION("Serialize") { result = eofSerializer.serialize(&bufPtr, &sz, buf.size(), SerializeIF::Endianness::NETWORK); REQUIRE(result == returnvalue::OK); @@ -37,7 +37,7 @@ TEST_CASE("EOF PDU", "[EofPdu]") { SerializeIF::Endianness::NETWORK); REQUIRE(result == returnvalue::OK); REQUIRE(fileSizeVal == 12); - REQUIRE(buf[sz - 10] == cfdp::FileDirectives::EOF_DIRECTIVE); + REQUIRE(buf[sz - 10] == cfdp::FileDirective::EOF_DIRECTIVE); REQUIRE(buf[sz - 9] == 0x00); REQUIRE(sz == 20); @@ -45,20 +45,20 @@ TEST_CASE("EOF PDU", "[EofPdu]") { eofInfo.setFileSize(0x10ffffff10, true); pduConf.largeFile = true; // Should serialize with fault location now - auto serializeWithFaultLocation = EofPduSerializer(pduConf, eofInfo); + auto serializeWithFaultLocation = EofPduCreator(pduConf, eofInfo); bufPtr = buf.data(); sz = 0; result = serializeWithFaultLocation.serialize(&bufPtr, &sz, buf.size(), SerializeIF::Endianness::NETWORK); REQUIRE(result == returnvalue::OK); REQUIRE(sz == 28); - REQUIRE(buf[10] == cfdp::FileDirectives::EOF_DIRECTIVE); + REQUIRE(buf[10] == cfdp::FileDirective::EOF_DIRECTIVE); REQUIRE(buf[11] >> 4 == cfdp::ConditionCode::FILESTORE_REJECTION); uint64_t fileSizeLarge = 0; result = SerializeAdapter::deSerialize(&fileSizeLarge, buf.data() + 16, nullptr, SerializeIF::Endianness::NETWORK); REQUIRE(fileSizeLarge == 0x10ffffff10); - REQUIRE(buf[sz - 4] == cfdp::TlvTypes::ENTITY_ID); + REQUIRE(buf[sz - 4] == cfdp::TlvType::ENTITY_ID); // width of entity ID is 2 REQUIRE(buf[sz - 3] == 2); uint16_t entityIdRaw = 0; @@ -83,7 +83,7 @@ TEST_CASE("EOF PDU", "[EofPdu]") { REQUIRE(result == returnvalue::OK); EntityIdTlv tlv(destId); EofInfo emptyInfo(&tlv); - auto deserializer = EofPduDeserializer(buf.data(), buf.size(), emptyInfo); + auto deserializer = EofPduReader(buf.data(), buf.size(), emptyInfo); result = deserializer.parseData(); REQUIRE(result == returnvalue::OK); REQUIRE(emptyInfo.getConditionCode() == cfdp::ConditionCode::NO_ERROR); @@ -94,23 +94,23 @@ TEST_CASE("EOF PDU", "[EofPdu]") { eofInfo.setFileSize(0x10ffffff10, true); pduConf.largeFile = true; // Should serialize with fault location now - auto serializeWithFaultLocation = EofPduSerializer(pduConf, eofInfo); + auto serializeWithFaultLocation = EofPduCreator(pduConf, eofInfo); bufPtr = buf.data(); sz = 0; result = serializeWithFaultLocation.serialize(&bufPtr, &sz, buf.size(), SerializeIF::Endianness::NETWORK); - auto deserializer2 = EofPduDeserializer(buf.data(), buf.size(), emptyInfo); + auto deserializer2 = EofPduReader(buf.data(), buf.size(), emptyInfo); result = deserializer2.parseData(); REQUIRE(result == returnvalue::OK); REQUIRE(emptyInfo.getConditionCode() == cfdp::ConditionCode::FILESTORE_REJECTION); REQUIRE(emptyInfo.getChecksum() == 5); REQUIRE(emptyInfo.getFileSize().getSize() == 0x10ffffff10); - REQUIRE(emptyInfo.getFaultLoc()->getType() == cfdp::TlvTypes::ENTITY_ID); + REQUIRE(emptyInfo.getFaultLoc()->getType() == cfdp::TlvType::ENTITY_ID); REQUIRE(emptyInfo.getFaultLoc()->getSerializedSize() == 4); uint16_t destId = emptyInfo.getFaultLoc()->getEntityId().getValue(); REQUIRE(destId == 2); for (size_t maxSz = 0; maxSz < deserializer2.getWholePduSize() - 1; maxSz++) { - auto invalidDeser = EofPduDeserializer(buf.data(), maxSz, emptyInfo); + auto invalidDeser = EofPduReader(buf.data(), maxSz, emptyInfo); result = invalidDeser.parseData(); REQUIRE(result != returnvalue::OK); } diff --git a/unittests/cfdp/testFileData.cpp b/unittests/cfdp/pdu/testFileData.cpp similarity index 94% rename from unittests/cfdp/testFileData.cpp rename to unittests/cfdp/pdu/testFileData.cpp index dd8654d6..258ef9c1 100644 --- a/unittests/cfdp/testFileData.cpp +++ b/unittests/cfdp/pdu/testFileData.cpp @@ -1,12 +1,12 @@ #include #include -#include "fsfw/cfdp/pdu/FileDataDeserializer.h" -#include "fsfw/cfdp/pdu/FileDataSerializer.h" +#include "fsfw/cfdp/pdu/FileDataCreator.h" +#include "fsfw/cfdp/pdu/FileDataReader.h" #include "fsfw/globalfunctions/arrayprinter.h" #include "fsfw/serviceinterface.h" -TEST_CASE("File Data PDU", "[FileDataPdu]") { +TEST_CASE("File Data PDU", "[cfdp][pdu]") { using namespace cfdp; ReturnValue_t result = returnvalue::OK; @@ -17,7 +17,7 @@ TEST_CASE("File Data PDU", "[FileDataPdu]") { EntityId destId(WidthInBytes::TWO_BYTES, 2); TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15); EntityId sourceId(WidthInBytes::TWO_BYTES, 1); - PduConfig pduConf(TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId); + PduConfig pduConf(sourceId, destId, TransmissionMode::ACKNOWLEDGED, seqNum); for (uint8_t idx = 0; idx < 10; idx++) { fileBuffer[idx] = idx; @@ -26,7 +26,7 @@ TEST_CASE("File Data PDU", "[FileDataPdu]") { FileDataInfo info(offset, fileBuffer.data(), 10); SECTION("Serialization") { - FileDataSerializer serializer(pduConf, info); + FileDataCreator serializer(pduConf, info); result = serializer.serialize(&buffer, &sz, fileDataBuffer.size(), SerializeIF::Endianness::NETWORK); REQUIRE(result == returnvalue::OK); @@ -102,14 +102,14 @@ TEST_CASE("File Data PDU", "[FileDataPdu]") { } SECTION("Deserialization") { - FileDataSerializer serializer(pduConf, info); + FileDataCreator serializer(pduConf, info); result = serializer.serialize(&buffer, &sz, fileDataBuffer.size(), SerializeIF::Endianness::NETWORK); REQUIRE(result == returnvalue::OK); FileSize emptyOffset; FileDataInfo emptyInfo(emptyOffset); - FileDataDeserializer deserializer(fileDataBuffer.data(), fileDataBuffer.size(), emptyInfo); + FileDataReader deserializer(fileDataBuffer.data(), fileDataBuffer.size(), emptyInfo); result = deserializer.parseData(); REQUIRE(result == returnvalue::OK); REQUIRE(deserializer.getWholePduSize() == 24); diff --git a/unittests/cfdp/pdu/testFileDirective.cpp b/unittests/cfdp/pdu/testFileDirective.cpp new file mode 100644 index 00000000..e1158a1a --- /dev/null +++ b/unittests/cfdp/pdu/testFileDirective.cpp @@ -0,0 +1,85 @@ +#include +#include + +#include "fsfw/cfdp/pdu/FileDirectiveCreator.h" +#include "fsfw/cfdp/pdu/FileDirectiveReader.h" + +TEST_CASE("CFDP File Directive", "[cfdp][pdu]") { + using namespace cfdp; + std::array serBuf{}; + ReturnValue_t result; + cfdp::TransactionSeqNum seqNum = TransactionSeqNum(cfdp::WidthInBytes::ONE_BYTE, 2); + cfdp::EntityId sourceId = EntityId(cfdp::WidthInBytes::ONE_BYTE, 0); + cfdp::EntityId destId = EntityId(cfdp::WidthInBytes::ONE_BYTE, 1); + PduConfig pduConf = + PduConfig(sourceId, destId, cfdp::TransmissionMode::ACKNOWLEDGED, seqNum, false); + uint8_t* serTarget = serBuf.data(); + const uint8_t* deserTarget = serTarget; + size_t serSize = 0; + auto fdSer = FileDirectiveCreator(pduConf, FileDirective::ACK, 4); + + SECTION("Serialization") { + REQUIRE(fdSer.getSerializedSize() == 8); + serTarget = serBuf.data(); + serSize = 0; + result = fdSer.serialize(&serTarget, &serSize, serBuf.size(), SerializeIF::Endianness::NETWORK); + REQUIRE(result == returnvalue::OK); + // Only version bits are set + REQUIRE(serBuf[0] == 0b00100000); + // PDU data field length is 5 (4 + Directive code octet) + REQUIRE(serBuf[1] == 0); + REQUIRE(serBuf[2] == 5); + // Entity and Transaction Sequence number are 1 byte large + REQUIRE(serBuf[3] == 0b00010001); + // Source ID + REQUIRE(serBuf[4] == 0); + // Transaction Seq Number + REQUIRE(serBuf[5] == 2); + // Dest ID + REQUIRE(serBuf[6] == 1); + REQUIRE(serBuf[7] == FileDirective::ACK); + } + + SECTION("Serialization fails") { + REQUIRE(fdSer.serialize(nullptr, nullptr, 85, SerializeIF::Endianness::NETWORK) == + returnvalue::FAILED); + } + + SECTION("Buffer Too Short") { + for (uint8_t idx = 0; idx < 8; idx++) { + serTarget = serBuf.data(); + serSize = 0; + REQUIRE(fdSer.serialize(&serTarget, &serSize, idx, SerializeIF::Endianness::NETWORK) == + SerializeIF::BUFFER_TOO_SHORT); + } + } + + SECTION("Deserialize") { + CHECK(fdSer.serialize(&serTarget, &serSize, serBuf.size(), SerializeIF::Endianness::NETWORK) == + returnvalue::OK); + serTarget = serBuf.data(); + + REQUIRE(fdSer.deSerialize(&deserTarget, &serSize, SerializeIF::Endianness::NETWORK) == + returnvalue::FAILED); + deserTarget = serBuf.data(); + CHECK(serSize == 8); + auto fdDeser = FileDirectiveReader(deserTarget, serBuf.size()); + REQUIRE(fdDeser.isNull()); + REQUIRE(not fdDeser); + REQUIRE(fdDeser.getEndianness() == SerializeIF::Endianness::NETWORK); + fdDeser.setEndianness(SerializeIF::Endianness::MACHINE); + REQUIRE(fdDeser.getEndianness() == SerializeIF::Endianness::MACHINE); + fdDeser.setEndianness(SerializeIF::Endianness::NETWORK); + REQUIRE(fdDeser.parseData() == returnvalue::OK); + REQUIRE(not fdDeser.isNull()); + REQUIRE(fdDeser); + REQUIRE(fdDeser.getFileDirective() == FileDirective::ACK); + REQUIRE(fdDeser.getPduDataFieldLen() == 5); + REQUIRE(fdDeser.getHeaderSize() == 8); + REQUIRE(fdDeser.getPduType() == cfdp::PduType::FILE_DIRECTIVE); + + serBuf[7] = 0xff; + // Invalid file directive + REQUIRE(fdDeser.parseData() == cfdp::INVALID_DIRECTIVE_FIELD); + } +} \ No newline at end of file diff --git a/unittests/cfdp/testFinishedPdu.cpp b/unittests/cfdp/pdu/testFinishedPdu.cpp similarity index 79% rename from unittests/cfdp/testFinishedPdu.cpp rename to unittests/cfdp/pdu/testFinishedPdu.cpp index dd04144c..b8b395cb 100644 --- a/unittests/cfdp/testFinishedPdu.cpp +++ b/unittests/cfdp/pdu/testFinishedPdu.cpp @@ -1,11 +1,11 @@ #include #include -#include "fsfw/cfdp/pdu/FinishedPduDeserializer.h" -#include "fsfw/cfdp/pdu/FinishedPduSerializer.h" +#include "fsfw/cfdp/pdu/FinishedPduCreator.h" +#include "fsfw/cfdp/pdu/FinishedPduReader.h" #include "fsfw/globalfunctions/arrayprinter.h" -TEST_CASE("Finished PDU", "[FinishedPdu]") { +TEST_CASE("Finished PDU", "[cfdp][pdu]") { using namespace cfdp; ReturnValue_t result = returnvalue::OK; std::array fnBuffer = {}; @@ -14,28 +14,28 @@ TEST_CASE("Finished PDU", "[FinishedPdu]") { EntityId destId(WidthInBytes::TWO_BYTES, 2); TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15); EntityId sourceId(WidthInBytes::TWO_BYTES, 1); - PduConfig pduConf(TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId); + PduConfig pduConf(sourceId, destId, TransmissionMode::ACKNOWLEDGED, seqNum); cfdp::Lv emptyFsMsg; FinishedInfo info(cfdp::ConditionCode::INACTIVITY_DETECTED, - cfdp::FinishedDeliveryCode::DATA_INCOMPLETE, - cfdp::FinishedFileStatus::DISCARDED_DELIBERATELY); + cfdp::FileDeliveryCode::DATA_INCOMPLETE, + cfdp::FileDeliveryStatus::DISCARDED_DELIBERATELY); SECTION("Serialize") { - FinishPduSerializer serializer(pduConf, info); + FinishPduCreator serializer(pduConf, info); result = serializer.serialize(&buffer, &sz, fnBuffer.size(), SerializeIF::Endianness::NETWORK); REQUIRE(result == returnvalue::OK); REQUIRE(serializer.getSerializedSize() == 12); REQUIRE(((fnBuffer[1] << 8) | fnBuffer[2]) == 2); - REQUIRE(fnBuffer[10] == cfdp::FileDirectives::FINISH); + REQUIRE(fnBuffer[10] == cfdp::FileDirective::FINISH); REQUIRE(((fnBuffer[sz - 1] >> 4) & 0x0f) == cfdp::ConditionCode::INACTIVITY_DETECTED); - REQUIRE(((fnBuffer[sz - 1] >> 2) & 0x01) == cfdp::FinishedDeliveryCode::DATA_INCOMPLETE); - REQUIRE((fnBuffer[sz - 1] & 0b11) == cfdp::FinishedFileStatus::DISCARDED_DELIBERATELY); + REQUIRE(((fnBuffer[sz - 1] >> 2) & 0x01) == cfdp::FileDeliveryCode::DATA_INCOMPLETE); + REQUIRE((fnBuffer[sz - 1] & 0b11) == cfdp::FileDeliveryStatus::DISCARDED_DELIBERATELY); REQUIRE(sz == 12); // Add a filestore response std::string firstName = "hello.txt"; - cfdp::Lv firstNameLv(reinterpret_cast(firstName.data()), firstName.size()); + cfdp::StringLv firstNameLv(firstName); FilestoreResponseTlv response(cfdp::FilestoreActionCode::DELETE_FILE, cfdp::FSR_APPEND_FILE_1_NOT_EXISTS, firstNameLv, nullptr); FilestoreResponseTlv* responsePtr = &response; @@ -53,7 +53,7 @@ TEST_CASE("Finished PDU", "[FinishedPdu]") { // Add two filestore responses and a fault location parameter std::string secondName = "hello2.txt"; - cfdp::Lv secondNameLv(reinterpret_cast(secondName.data()), secondName.size()); + cfdp::StringLv secondNameLv(secondName); FilestoreResponseTlv response2(cfdp::FilestoreActionCode::DENY_FILE, cfdp::FSR_SUCCESS, secondNameLv, nullptr); REQUIRE(response2.getSerializedSize() == 15); @@ -73,10 +73,10 @@ TEST_CASE("Finished PDU", "[FinishedPdu]") { info.setConditionCode(cfdp::ConditionCode::FILESTORE_REJECTION); REQUIRE(serializer.getSerializedSize() == 12 + 14 + 15 + 4); REQUIRE(sz == 12 + 14 + 15 + 4); - info.setFileStatus(cfdp::FinishedFileStatus::DISCARDED_FILESTORE_REJECTION); - REQUIRE(info.getFileStatus() == cfdp::FinishedFileStatus::DISCARDED_FILESTORE_REJECTION); - info.setDeliveryCode(cfdp::FinishedDeliveryCode::DATA_INCOMPLETE); - REQUIRE(info.getDeliveryCode() == cfdp::FinishedDeliveryCode::DATA_INCOMPLETE); + info.setFileStatus(cfdp::FileDeliveryStatus::DISCARDED_FILESTORE_REJECTION); + REQUIRE(info.getFileStatus() == cfdp::FileDeliveryStatus::DISCARDED_FILESTORE_REJECTION); + info.setDeliveryCode(cfdp::FileDeliveryCode::DATA_INCOMPLETE); + REQUIRE(info.getDeliveryCode() == cfdp::FileDeliveryCode::DATA_INCOMPLETE); for (size_t maxSz = 0; maxSz < 45; maxSz++) { sz = 0; buffer = fnBuffer.data(); @@ -87,21 +87,21 @@ TEST_CASE("Finished PDU", "[FinishedPdu]") { SECTION("Deserialize") { FinishedInfo emptyInfo; - FinishPduSerializer serializer(pduConf, info); + FinishPduCreator serializer(pduConf, info); result = serializer.serialize(&buffer, &sz, fnBuffer.size(), SerializeIF::Endianness::NETWORK); REQUIRE(result == returnvalue::OK); - FinishPduDeserializer deserializer(fnBuffer.data(), fnBuffer.size(), emptyInfo); + FinishPduReader deserializer(fnBuffer.data(), fnBuffer.size(), emptyInfo); result = deserializer.parseData(); REQUIRE(result == returnvalue::OK); - REQUIRE(emptyInfo.getFileStatus() == cfdp::FinishedFileStatus::DISCARDED_DELIBERATELY); + REQUIRE(emptyInfo.getFileStatus() == cfdp::FileDeliveryStatus::DISCARDED_DELIBERATELY); REQUIRE(emptyInfo.getConditionCode() == cfdp::ConditionCode::INACTIVITY_DETECTED); - REQUIRE(emptyInfo.getDeliveryCode() == cfdp::FinishedDeliveryCode::DATA_INCOMPLETE); + REQUIRE(emptyInfo.getDeliveryCode() == cfdp::FileDeliveryCode::DATA_INCOMPLETE); // Add a filestore response sz = 0; buffer = fnBuffer.data(); std::string firstName = "hello.txt"; - cfdp::Lv firstNameLv(reinterpret_cast(firstName.data()), firstName.size()); + cfdp::StringLv firstNameLv(firstName); FilestoreResponseTlv response(cfdp::FilestoreActionCode::DELETE_FILE, cfdp::FSR_NOT_PERFORMED, firstNameLv, nullptr); FilestoreResponseTlv* responsePtr = &response; @@ -114,7 +114,7 @@ TEST_CASE("Finished PDU", "[FinishedPdu]") { FilestoreResponseTlv emptyResponse(firstNameLv, nullptr); responsePtr = &emptyResponse; emptyInfo.setFilestoreResponsesArray(&responsePtr, nullptr, &len); - FinishPduDeserializer deserializer2(fnBuffer.data(), fnBuffer.size(), emptyInfo); + FinishPduReader deserializer2(fnBuffer.data(), fnBuffer.size(), emptyInfo); result = deserializer2.parseData(); REQUIRE(result == returnvalue::OK); REQUIRE(emptyInfo.getFsResponsesLen() == 1); @@ -130,7 +130,7 @@ TEST_CASE("Finished PDU", "[FinishedPdu]") { // Add two filestore responses and a fault location parameter std::string secondName = "hello2.txt"; - cfdp::Lv secondNameLv(reinterpret_cast(secondName.data()), secondName.size()); + cfdp::StringLv secondNameLv(secondName); FilestoreResponseTlv response2(cfdp::FilestoreActionCode::DENY_FILE, cfdp::FSR_SUCCESS, secondNameLv, nullptr); REQUIRE(response2.getSerializedSize() == 15); @@ -152,7 +152,7 @@ TEST_CASE("Finished PDU", "[FinishedPdu]") { response.setFilestoreMessage(&emptyFsMsg); emptyInfo.setFilestoreResponsesArray(responses.data(), &len, &len); response2.setFilestoreMessage(&emptyFsMsg); - FinishPduDeserializer deserializer3(fnBuffer.data(), fnBuffer.size(), emptyInfo); + FinishPduReader deserializer3(fnBuffer.data(), fnBuffer.size(), emptyInfo); result = deserializer3.parseData(); REQUIRE(result == returnvalue::OK); auto& infoRef = deserializer3.getInfo(); @@ -176,12 +176,12 @@ TEST_CASE("Finished PDU", "[FinishedPdu]") { fnBuffer[11] = tmp; // Invalid TLV type, should be entity ID - fnBuffer[sz - 4] = cfdp::TlvTypes::FILESTORE_REQUEST; + fnBuffer[sz - 4] = cfdp::TlvType::FILESTORE_REQUEST; result = deserializer3.parseData(); REQUIRE(result == cfdp::INVALID_TLV_TYPE); for (size_t maxSz = 0; maxSz < 45; maxSz++) { - FinishPduDeserializer faultyDeser(fnBuffer.data(), maxSz, emptyInfo); + FinishPduReader faultyDeser(fnBuffer.data(), maxSz, emptyInfo); result = faultyDeser.parseData(); REQUIRE(result != returnvalue::OK); } diff --git a/unittests/cfdp/testKeepAlivePdu.cpp b/unittests/cfdp/pdu/testKeepAlivePdu.cpp similarity index 74% rename from unittests/cfdp/testKeepAlivePdu.cpp rename to unittests/cfdp/pdu/testKeepAlivePdu.cpp index 4b52a084..d07bccae 100644 --- a/unittests/cfdp/testKeepAlivePdu.cpp +++ b/unittests/cfdp/pdu/testKeepAlivePdu.cpp @@ -1,11 +1,11 @@ #include #include -#include "fsfw/cfdp/pdu/KeepAlivePduDeserializer.h" -#include "fsfw/cfdp/pdu/KeepAlivePduSerializer.h" +#include "fsfw/cfdp/pdu/KeepAlivePduCreator.h" +#include "fsfw/cfdp/pdu/KeepAlivePduReader.h" #include "fsfw/globalfunctions/arrayprinter.h" -TEST_CASE("Keep Alive PDU", "[KeepAlivePdu]") { +TEST_CASE("Keep Alive PDU", "[cfdp][pdu]") { using namespace cfdp; ReturnValue_t result = returnvalue::OK; std::array kaBuffer = {}; @@ -14,15 +14,15 @@ TEST_CASE("Keep Alive PDU", "[KeepAlivePdu]") { EntityId destId(WidthInBytes::TWO_BYTES, 2); TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15); EntityId sourceId(WidthInBytes::TWO_BYTES, 1); - PduConfig pduConf(TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId); + PduConfig pduConf(sourceId, destId, TransmissionMode::ACKNOWLEDGED, seqNum); FileSize progress(0x50); SECTION("Serialize") { - KeepAlivePduSerializer serializer(pduConf, progress); + KeepAlivePduCreator serializer(pduConf, progress); result = serializer.serialize(&buffer, &sz, kaBuffer.size(), SerializeIF::Endianness::NETWORK); REQUIRE(result == returnvalue::OK); - REQUIRE(kaBuffer[10] == cfdp::FileDirectives::KEEP_ALIVE); + REQUIRE(kaBuffer[10] == cfdp::FileDirective::KEEP_ALIVE); uint32_t fsRaw = 0; result = SerializeAdapter::deSerialize(&fsRaw, kaBuffer.data() + 11, nullptr, SerializeIF::Endianness::NETWORK); @@ -55,25 +55,27 @@ TEST_CASE("Keep Alive PDU", "[KeepAlivePdu]") { } SECTION("Deserialize") { - KeepAlivePduSerializer serializer(pduConf, progress); + KeepAlivePduCreator serializer(pduConf, progress); result = serializer.serialize(&buffer, &sz, kaBuffer.size(), SerializeIF::Endianness::NETWORK); REQUIRE(result == returnvalue::OK); // Set another file size progress.setFileSize(200, false); - KeepAlivePduDeserializer deserializer(kaBuffer.data(), kaBuffer.size(), progress); - result = deserializer.parseData(); + KeepAlivePduReader reader(kaBuffer.data(), kaBuffer.size(), progress); + result = reader.parseData(); REQUIRE(result == returnvalue::OK); - auto& progRef = deserializer.getProgress(); + auto& progRef = reader.getProgress(); // Should have been overwritten REQUIRE(progRef.getSize() == 0x50); - sz = deserializer.getWholePduSize(); + sz = reader.getWholePduSize(); // invalid max size for (size_t invalidMaxSz = 0; invalidMaxSz < sz; invalidMaxSz++) { - deserializer.setData(kaBuffer.data(), invalidMaxSz); - result = deserializer.parseData(); - REQUIRE(result != returnvalue::OK); + ReturnValue_t setResult = reader.setReadOnlyData(kaBuffer.data(), invalidMaxSz); + if (setResult == returnvalue::OK) { + result = reader.parseData(); + REQUIRE(result != returnvalue::OK); + } } } } diff --git a/unittests/cfdp/testMetadataPdu.cpp b/unittests/cfdp/pdu/testMetadataPdu.cpp similarity index 79% rename from unittests/cfdp/testMetadataPdu.cpp rename to unittests/cfdp/pdu/testMetadataPdu.cpp index 7e90e8d3..a9f8bf86 100644 --- a/unittests/cfdp/testMetadataPdu.cpp +++ b/unittests/cfdp/pdu/testMetadataPdu.cpp @@ -1,14 +1,14 @@ -#include - #include #include +#include -#include "fsfw/cfdp/pdu/MetadataPduDeserializer.h" -#include "fsfw/cfdp/pdu/MetadataPduSerializer.h" +#include "fsfw/cfdp/pdu/MetadataPduCreator.h" +#include "fsfw/cfdp/pdu/MetadataPduReader.h" #include "fsfw/cfdp/tlv/FilestoreResponseTlv.h" +#include "fsfw/cfdp/tlv/MessageToUserTlv.h" #include "fsfw/globalfunctions/arrayprinter.h" -TEST_CASE("Metadata PDU", "[MetadataPdu]") { +TEST_CASE("Metadata PDU", "[cfdp][pdu]") { using namespace cfdp; ReturnValue_t result = returnvalue::OK; std::array mdBuffer = {}; @@ -17,12 +17,11 @@ TEST_CASE("Metadata PDU", "[MetadataPdu]") { EntityId destId(WidthInBytes::TWO_BYTES, 2); TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15); EntityId sourceId(WidthInBytes::TWO_BYTES, 1); - PduConfig pduConf(TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId); + PduConfig pduConf(sourceId, destId, TransmissionMode::ACKNOWLEDGED, seqNum); std::string firstFileName = "hello.txt"; - cfdp::Lv sourceFileName(reinterpret_cast(firstFileName.data()), - firstFileName.size()); - cfdp::Lv destFileName(nullptr, 0); + cfdp::StringLv sourceFileName(firstFileName); + cfdp::StringLv destFileName; FileSize fileSize(35); MetadataInfo info(false, ChecksumType::MODULAR, fileSize, sourceFileName, destFileName); @@ -39,7 +38,7 @@ TEST_CASE("Metadata PDU", "[MetadataPdu]") { REQUIRE(options[1]->getSerializedSize() == 5); SECTION("Serialize") { - MetadataPduSerializer serializer(pduConf, info); + MetadataPduCreator serializer(pduConf, info); result = serializer.serialize(&buffer, &sz, mdBuffer.size(), SerializeIF::Endianness::NETWORK); REQUIRE(result == returnvalue::OK); REQUIRE(serializer.getWholePduSize() == 27); @@ -47,7 +46,7 @@ TEST_CASE("Metadata PDU", "[MetadataPdu]") { REQUIRE(info.getDestFileName().getSerializedSize() == 1); REQUIRE(info.getSerializedSize() == 16); REQUIRE((mdBuffer[1] << 8 | mdBuffer[2]) == 17); - REQUIRE(mdBuffer[10] == FileDirectives::METADATA); + REQUIRE(mdBuffer[10] == FileDirective::METADATA); // no closure requested and checksum type is modular => 0x00 REQUIRE(mdBuffer[11] == 0x00); uint32_t fileSizeRaw = 0; @@ -68,11 +67,10 @@ TEST_CASE("Metadata PDU", "[MetadataPdu]") { REQUIRE(mdBuffer[26] == 0); std::string otherFileName = "hello2.txt"; - cfdp::Lv otherFileNameLv(reinterpret_cast(otherFileName.data()), - otherFileName.size()); + cfdp::StringLv otherFileNameLv(otherFileName.data(), otherFileName.size()); info.setSourceFileName(otherFileNameLv); size_t sizeOfOptions = options.size(); - info.setOptionsArray(options.data(), &sizeOfOptions, &sizeOfOptions); + info.setOptionsArray(options.data(), sizeOfOptions, sizeOfOptions); REQUIRE(info.getMaxOptionsLen() == 2); info.setMaxOptionsLen(3); REQUIRE(info.getMaxOptionsLen() == 3); @@ -115,22 +113,22 @@ TEST_CASE("Metadata PDU", "[MetadataPdu]") { } SECTION("Deserialize") { - MetadataPduSerializer serializer(pduConf, info); + MetadataPduCreator serializer(pduConf, info); result = serializer.serialize(&buffer, &sz, mdBuffer.size(), SerializeIF::Endianness::NETWORK); REQUIRE(result == returnvalue::OK); - MetadataPduDeserializer deserializer(mdBuffer.data(), mdBuffer.size(), info); + MetadataPduReader deserializer(mdBuffer.data(), mdBuffer.size(), info); result = deserializer.parseData(); REQUIRE(result == returnvalue::OK); size_t fullSize = deserializer.getWholePduSize(); for (size_t maxSz = 0; maxSz < fullSize; maxSz++) { - MetadataPduDeserializer invalidSzDeser(mdBuffer.data(), maxSz, info); + MetadataPduReader invalidSzDeser(mdBuffer.data(), maxSz, info); result = invalidSzDeser.parseData(); REQUIRE(result != returnvalue::OK); } size_t sizeOfOptions = options.size(); size_t maxSize = 4; - info.setOptionsArray(options.data(), &sizeOfOptions, &maxSize); + info.setOptionsArray(options.data(), sizeOfOptions, maxSize); REQUIRE(info.getOptionsLen() == 2); info.setChecksumType(cfdp::ChecksumType::CRC_32C); info.setClosureRequested(true); @@ -142,12 +140,12 @@ TEST_CASE("Metadata PDU", "[MetadataPdu]") { result = serializer.serialize(&buffer, &sz, mdBuffer.size(), SerializeIF::Endianness::NETWORK); REQUIRE(result == returnvalue::OK); - MetadataPduDeserializer deserializer2(mdBuffer.data(), mdBuffer.size(), info); + MetadataPduReader deserializer2(mdBuffer.data(), mdBuffer.size(), info); result = deserializer2.parseData(); REQUIRE(result == returnvalue::OK); - REQUIRE(options[0]->getType() == cfdp::TlvTypes::FILESTORE_RESPONSE); + REQUIRE(options[0]->getType() == cfdp::TlvType::FILESTORE_RESPONSE); REQUIRE(options[0]->getSerializedSize() == 14); - REQUIRE(options[1]->getType() == cfdp::TlvTypes::MSG_TO_USER); + REQUIRE(options[1]->getType() == cfdp::TlvType::MSG_TO_USER); REQUIRE(options[1]->getSerializedSize() == 5); for (size_t invalidFieldLen = 0; invalidFieldLen < 36; invalidFieldLen++) { @@ -167,13 +165,15 @@ TEST_CASE("Metadata PDU", "[MetadataPdu]") { } mdBuffer[1] = (36 >> 8) & 0xff; mdBuffer[2] = 36 & 0xff; - info.setOptionsArray(nullptr, nullptr, nullptr); + info.setOptionsArray(nullptr, std::nullopt, std::nullopt); REQUIRE(deserializer2.parseData() == cfdp::METADATA_CANT_PARSE_OPTIONS); - info.setOptionsArray(options.data(), &sizeOfOptions, nullptr); + info.setOptionsArray(options.data(), sizeOfOptions, std::nullopt); for (size_t maxSz = 0; maxSz < 46; maxSz++) { - MetadataPduDeserializer invalidSzDeser(mdBuffer.data(), maxSz, info); - result = invalidSzDeser.parseData(); - REQUIRE(result == SerializeIF::STREAM_TOO_SHORT); + MetadataPduReader invalidSzDeser(mdBuffer.data(), maxSz, info); + if (not invalidSzDeser.isNull()) { + result = invalidSzDeser.parseData(); + REQUIRE(result == SerializeIF::STREAM_TOO_SHORT); + } } } } diff --git a/unittests/cfdp/testNakPdu.cpp b/unittests/cfdp/pdu/testNakPdu.cpp similarity index 89% rename from unittests/cfdp/testNakPdu.cpp rename to unittests/cfdp/pdu/testNakPdu.cpp index 0fc74c89..7974dab1 100644 --- a/unittests/cfdp/testNakPdu.cpp +++ b/unittests/cfdp/pdu/testNakPdu.cpp @@ -1,12 +1,12 @@ #include #include -#include "fsfw/cfdp/pdu/NakPduDeserializer.h" -#include "fsfw/cfdp/pdu/NakPduSerializer.h" +#include "fsfw/cfdp/pdu/NakPduCreator.h" +#include "fsfw/cfdp/pdu/NakPduReader.h" #include "fsfw/cfdp/pdu/PduConfig.h" #include "fsfw/globalfunctions/arrayprinter.h" -TEST_CASE("NAK PDU", "[NakPdu]") { +TEST_CASE("NAK PDU", "[cfdp][pdu]") { using namespace cfdp; ReturnValue_t result = returnvalue::OK; std::array nakBuffer = {}; @@ -15,21 +15,21 @@ TEST_CASE("NAK PDU", "[NakPdu]") { EntityId destId(WidthInBytes::TWO_BYTES, 2); TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15); EntityId sourceId(WidthInBytes::TWO_BYTES, 1); - PduConfig pduConf(TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId); + PduConfig pduConf(sourceId, destId, TransmissionMode::ACKNOWLEDGED, seqNum); FileSize startOfScope(50); FileSize endOfScope(1050); NakInfo info(startOfScope, endOfScope); SECTION("Serializer") { - NakPduSerializer serializer(pduConf, info); + NakPduCreator serializer(pduConf, info); result = serializer.serialize(&buffer, &sz, nakBuffer.size(), SerializeIF::Endianness::NETWORK); REQUIRE(result == returnvalue::OK); REQUIRE(serializer.getSerializedSize() == 19); - REQUIRE(serializer.FileDirectiveSerializer::getSerializedSize() == 11); + REQUIRE(serializer.FileDirectiveCreator::getSerializedSize() == 11); REQUIRE(sz == 19); REQUIRE(serializer.getPduDataFieldLen() == 9); REQUIRE(((nakBuffer[1] << 8) | nakBuffer[2]) == 0x09); - REQUIRE(nakBuffer[10] == cfdp::FileDirectives::NAK); + REQUIRE(nakBuffer[10] == cfdp::FileDirective::NAK); uint32_t scope = 0; result = SerializeAdapter::deSerialize(&scope, nakBuffer.data() + 11, nullptr, SerializeIF::Endianness::NETWORK); @@ -87,13 +87,13 @@ TEST_CASE("NAK PDU", "[NakPdu]") { } SECTION("Deserializer") { - NakPduSerializer serializer(pduConf, info); + NakPduCreator serializer(pduConf, info); result = serializer.serialize(&buffer, &sz, nakBuffer.size(), SerializeIF::Endianness::NETWORK); REQUIRE(result == returnvalue::OK); info.getStartOfScope().setFileSize(0, false); info.getEndOfScope().setFileSize(0, false); - NakPduDeserializer deserializer(nakBuffer.data(), nakBuffer.size(), info); + NakPduReader deserializer(nakBuffer.data(), nakBuffer.size(), info); result = deserializer.parseData(); REQUIRE(result == returnvalue::OK); REQUIRE(deserializer.getWholePduSize() == 19); @@ -112,7 +112,7 @@ TEST_CASE("NAK PDU", "[NakPdu]") { result = serializer.serialize(&buffer, &sz, nakBuffer.size(), SerializeIF::Endianness::NETWORK); REQUIRE(result == returnvalue::OK); - NakPduDeserializer deserializeWithSegReqs(nakBuffer.data(), nakBuffer.size(), info); + NakPduReader deserializeWithSegReqs(nakBuffer.data(), nakBuffer.size(), info); result = deserializeWithSegReqs.parseData(); REQUIRE(result == returnvalue::OK); NakInfo::SegmentRequest* segReqsPtr = nullptr; @@ -126,14 +126,14 @@ TEST_CASE("NAK PDU", "[NakPdu]") { REQUIRE(deserializeWithSegReqs.getPduDataFieldLen() == 25); REQUIRE(info.getSegmentRequestsLen() == 2); for (size_t idx = 0; idx < 34; idx++) { - NakPduDeserializer faultyDeserializer(nakBuffer.data(), idx, info); + NakPduReader faultyDeserializer(nakBuffer.data(), idx, info); result = faultyDeserializer.parseData(); REQUIRE(result != returnvalue::OK); } for (size_t pduFieldLen = 0; pduFieldLen < 25; pduFieldLen++) { nakBuffer[1] = (pduFieldLen >> 8) & 0xff; nakBuffer[2] = pduFieldLen & 0xff; - NakPduDeserializer faultyDeserializer(nakBuffer.data(), nakBuffer.size(), info); + NakPduReader faultyDeserializer(nakBuffer.data(), nakBuffer.size(), info); result = faultyDeserializer.parseData(); if (pduFieldLen == 9) { REQUIRE(info.getSegmentRequestsLen() == 0); diff --git a/unittests/cfdp/testPromptPdu.cpp b/unittests/cfdp/pdu/testPromptPdu.cpp similarity index 67% rename from unittests/cfdp/testPromptPdu.cpp rename to unittests/cfdp/pdu/testPromptPdu.cpp index 80363983..6032f44e 100644 --- a/unittests/cfdp/testPromptPdu.cpp +++ b/unittests/cfdp/pdu/testPromptPdu.cpp @@ -1,11 +1,11 @@ #include #include -#include "fsfw/cfdp/pdu/PromptPduDeserializer.h" -#include "fsfw/cfdp/pdu/PromptPduSerializer.h" +#include "fsfw/cfdp/pdu/PromptPduCreator.h" +#include "fsfw/cfdp/pdu/PromptPduReader.h" #include "fsfw/globalfunctions/arrayprinter.h" -TEST_CASE("Prompt PDU", "[PromptPdu]") { +TEST_CASE("Prompt PDU", "[cfdp][pdu]") { using namespace cfdp; ReturnValue_t result = returnvalue::OK; std::array rawBuf = {}; @@ -14,17 +14,17 @@ TEST_CASE("Prompt PDU", "[PromptPdu]") { EntityId destId(WidthInBytes::TWO_BYTES, 2); TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15); EntityId sourceId(WidthInBytes::TWO_BYTES, 1); - PduConfig pduConf(TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId); + PduConfig pduConf(sourceId, destId, TransmissionMode::ACKNOWLEDGED, seqNum); SECTION("Serialize") { - PromptPduSerializer serializer(pduConf, cfdp::PromptResponseRequired::PROMPT_KEEP_ALIVE); + PromptPduCreator serializer(pduConf, cfdp::PromptResponseRequired::PROMPT_KEEP_ALIVE); result = serializer.serialize(&buffer, &sz, rawBuf.size(), SerializeIF::Endianness::NETWORK); REQUIRE(result == returnvalue::OK); REQUIRE(serializer.getWholePduSize() == 12); REQUIRE(sz == 12); REQUIRE(serializer.getPduDataFieldLen() == 2); - REQUIRE(rawBuf[10] == FileDirectives::PROMPT); - REQUIRE((rawBuf[sz - 1] >> 7) & 0x01 == cfdp::PromptResponseRequired::PROMPT_KEEP_ALIVE); + REQUIRE(rawBuf[10] == FileDirective::PROMPT); + REQUIRE(((rawBuf[sz - 1] >> 7) & 0x01) == cfdp::PromptResponseRequired::PROMPT_KEEP_ALIVE); for (size_t invalidMaxSz = 0; invalidMaxSz < sz; invalidMaxSz++) { uint8_t* buffer = rawBuf.data(); @@ -41,25 +41,29 @@ TEST_CASE("Prompt PDU", "[PromptPdu]") { } SECTION("Deserialize") { - PromptPduSerializer serializer(pduConf, cfdp::PromptResponseRequired::PROMPT_KEEP_ALIVE); + PromptPduCreator serializer(pduConf, cfdp::PromptResponseRequired::PROMPT_KEEP_ALIVE); result = serializer.serialize(&buffer, &sz, rawBuf.size(), SerializeIF::Endianness::NETWORK); REQUIRE(result == returnvalue::OK); - PromptPduDeserializer deserializer(rawBuf.data(), rawBuf.size()); + PromptPduReader deserializer(rawBuf.data(), rawBuf.size()); result = deserializer.parseData(); REQUIRE(result == returnvalue::OK); REQUIRE(deserializer.getPromptResponseRequired() == cfdp::PromptResponseRequired::PROMPT_KEEP_ALIVE); sz = deserializer.getWholePduSize(); + // Set invalid size rawBuf[2] = 1; result = deserializer.parseData(); + size_t sz2 = deserializer.getWholePduSize(); REQUIRE(result == SerializeIF::STREAM_TOO_SHORT); rawBuf[2] = 2; for (size_t invalidMaxSz = 0; invalidMaxSz < sz; invalidMaxSz++) { - deserializer.setData(rawBuf.data(), invalidMaxSz); - result = deserializer.parseData(); - REQUIRE(result != returnvalue::OK); + ReturnValue_t setResult = deserializer.setReadOnlyData(rawBuf.data(), invalidMaxSz); + if (setResult == returnvalue::OK) { + result = deserializer.parseData(); + REQUIRE(result != returnvalue::OK); + } } } } diff --git a/unittests/cfdp/testAckPdu.cpp b/unittests/cfdp/testAckPdu.cpp deleted file mode 100644 index 93d484db..00000000 --- a/unittests/cfdp/testAckPdu.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include -#include - -#include "fsfw/cfdp/pdu/AckPduDeserializer.h" -#include "fsfw/cfdp/pdu/AckPduSerializer.h" -#include "fsfw/globalfunctions/arrayprinter.h" - -TEST_CASE("ACK PDU", "[AckPdu]") { - using namespace cfdp; - ReturnValue_t result = returnvalue::OK; - std::array buf = {}; - uint8_t* bufptr = buf.data(); - size_t maxsz = buf.size(); - size_t sz = 0; - auto seqNum = TransactionSeqNum(WidthInBytes::TWO_BYTES, 15); - auto sourceId = EntityId(WidthInBytes::TWO_BYTES, 1); - auto destId = EntityId(WidthInBytes::TWO_BYTES, 2); - auto pduConf = PduConfig(TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId); - AckInfo ackInfo(FileDirectives::EOF_DIRECTIVE, ConditionCode::NO_ERROR, - AckTransactionStatus::ACTIVE); - auto ackSerializer = AckPduSerializer(ackInfo, pduConf); - result = ackSerializer.serialize(&bufptr, &sz, maxsz, SerializeIF::Endianness::NETWORK); - REQUIRE(result == returnvalue::OK); - - SECTION("Serialize") { - REQUIRE(buf.data()[sz - 3] == cfdp::FileDirectives::ACK); - REQUIRE((buf.data()[sz - 2] >> 4) == FileDirectives::EOF_DIRECTIVE); - REQUIRE((buf.data()[sz - 2] & 0x0f) == 0); - REQUIRE(buf.data()[sz - 1] == AckTransactionStatus::ACTIVE); - ackInfo.setAckedDirective(FileDirectives::FINISH); - ackInfo.setAckedConditionCode(ConditionCode::FILESTORE_REJECTION); - ackInfo.setTransactionStatus(AckTransactionStatus::TERMINATED); - auto ackSerializer2 = AckPduSerializer(ackInfo, pduConf); - bufptr = buf.data(); - sz = 0; - result = ackSerializer2.serialize(&bufptr, &sz, maxsz, SerializeIF::Endianness::NETWORK); - REQUIRE(result == returnvalue::OK); - REQUIRE(buf.data()[sz - 3] == cfdp::FileDirectives::ACK); - REQUIRE((buf.data()[sz - 2] >> 4) == FileDirectives::FINISH); - REQUIRE((buf.data()[sz - 2] & 0x0f) == 0b0001); - REQUIRE((buf.data()[sz - 1] >> 4) == ConditionCode::FILESTORE_REJECTION); - REQUIRE((buf.data()[sz - 1] & 0b11) == AckTransactionStatus::TERMINATED); - - bufptr = buf.data(); - sz = 0; - ackInfo.setAckedDirective(FileDirectives::KEEP_ALIVE); - auto ackSerializer3 = AckPduSerializer(ackInfo, pduConf); - result = ackSerializer3.serialize(&bufptr, &sz, maxsz, SerializeIF::Endianness::NETWORK); - // Invalid file directive - REQUIRE(result != returnvalue::OK); - - ackInfo.setAckedDirective(FileDirectives::FINISH); - // buffer too small - result = ackSerializer.serialize(&bufptr, &sz, 8, SerializeIF::Endianness::NETWORK); - REQUIRE(result == SerializeIF::BUFFER_TOO_SHORT); - } - - SECTION("Deserialize") { - AckInfo ackInfo; - auto reader = AckPduDeserializer(buf.data(), sz, ackInfo); - result = reader.parseData(); - REQUIRE(result == returnvalue::OK); - REQUIRE(ackInfo.getAckedDirective() == FileDirectives::EOF_DIRECTIVE); - REQUIRE(ackInfo.getAckedConditionCode() == ConditionCode::NO_ERROR); - REQUIRE(ackInfo.getDirectiveSubtypeCode() == 0); - REQUIRE(ackInfo.getTransactionStatus() == AckTransactionStatus::ACTIVE); - - AckInfo newInfo = AckInfo(FileDirectives::FINISH, ConditionCode::FILESTORE_REJECTION, - AckTransactionStatus::TERMINATED); - auto ackSerializer2 = AckPduSerializer(newInfo, pduConf); - bufptr = buf.data(); - sz = 0; - result = ackSerializer2.serialize(&bufptr, &sz, maxsz, SerializeIF::Endianness::NETWORK); - REQUIRE(result == returnvalue::OK); - - auto reader2 = AckPduDeserializer(buf.data(), sz, ackInfo); - result = reader2.parseData(); - REQUIRE(result == returnvalue::OK); - REQUIRE(ackInfo.getAckedDirective() == FileDirectives::FINISH); - REQUIRE(ackInfo.getAckedConditionCode() == ConditionCode::FILESTORE_REJECTION); - REQUIRE(ackInfo.getDirectiveSubtypeCode() == 0b0001); - REQUIRE(ackInfo.getTransactionStatus() == AckTransactionStatus::TERMINATED); - - uint8_t prevVal = buf[sz - 2]; - buf[sz - 2] = FileDirectives::INVALID_DIRECTIVE << 4; - result = reader2.parseData(); - REQUIRE(result == cfdp::INVALID_ACK_DIRECTIVE_FIELDS); - buf[sz - 2] = FileDirectives::FINISH << 4 | 0b1111; - result = reader2.parseData(); - REQUIRE(result == cfdp::INVALID_ACK_DIRECTIVE_FIELDS); - buf[sz - 2] = prevVal; - buf[sz - 3] = cfdp::FileDirectives::INVALID_DIRECTIVE; - result = reader2.parseData(); - REQUIRE(result == cfdp::INVALID_DIRECTIVE_FIELDS); - buf[sz - 3] = cfdp::FileDirectives::ACK; - auto maxSizeTooSmall = AckPduDeserializer(buf.data(), sz - 2, ackInfo); - result = maxSizeTooSmall.parseData(); - REQUIRE(result == SerializeIF::STREAM_TOO_SHORT); - } -} diff --git a/unittests/cfdp/testCfdp.cpp b/unittests/cfdp/testCfdp.cpp index b18ef9a3..eacc83de 100644 --- a/unittests/cfdp/testCfdp.cpp +++ b/unittests/cfdp/testCfdp.cpp @@ -2,301 +2,27 @@ #include #include -#include "CatchDefinitions.h" #include "fsfw/cfdp/FileSize.h" -#include "fsfw/cfdp/pdu/FileDirectiveDeserializer.h" -#include "fsfw/cfdp/pdu/FileDirectiveSerializer.h" -#include "fsfw/cfdp/pdu/HeaderDeserializer.h" -#include "fsfw/cfdp/pdu/HeaderSerializer.h" +#include "fsfw/cfdp/pdu/FileDirectiveCreator.h" +#include "fsfw/cfdp/pdu/FileDirectiveReader.h" #include "fsfw/globalfunctions/arrayprinter.h" #include "fsfw/serialize/SerializeAdapter.h" -TEST_CASE("CFDP Base", "[CfdpBase]") { +TEST_CASE("CFDP Base", "[cfdp]") { using namespace cfdp; - std::array serBuf; - ReturnValue_t result = returnvalue::OK; + std::array serBuf{}; + ReturnValue_t result; cfdp::TransactionSeqNum seqNum = TransactionSeqNum(cfdp::WidthInBytes::ONE_BYTE, 2); cfdp::EntityId sourceId = EntityId(cfdp::WidthInBytes::ONE_BYTE, 0); cfdp::EntityId destId = EntityId(cfdp::WidthInBytes::ONE_BYTE, 1); PduConfig pduConf = - PduConfig(cfdp::TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId, false); + PduConfig(sourceId, destId, cfdp::TransmissionMode::ACKNOWLEDGED, seqNum, false); uint8_t* serTarget = serBuf.data(); const uint8_t* deserTarget = serTarget; size_t serSize = 0; - SECTION("Header Serialization") { - auto headerSerializer = HeaderSerializer(pduConf, cfdp::PduType::FILE_DIRECTIVE, 0); - const uint8_t** dummyPtr = nullptr; - ReturnValue_t deserResult = - headerSerializer.deSerialize(dummyPtr, &serSize, SerializeIF::Endianness::NETWORK); - REQUIRE(deserResult == returnvalue::FAILED); - deserResult = headerSerializer.serialize(nullptr, &serSize, serBuf.size(), - SerializeIF::Endianness::NETWORK); - REQUIRE(deserResult == returnvalue::FAILED); - REQUIRE(seqNum.getSerializedSize() == 1); - - REQUIRE(headerSerializer.getPduDataFieldLen() == 0); - REQUIRE(headerSerializer.getSerializedSize() == 7); - REQUIRE(headerSerializer.getWholePduSize() == 7); - REQUIRE(headerSerializer.getCrcFlag() == false); - REQUIRE(headerSerializer.getDirection() == cfdp::Direction::TOWARDS_RECEIVER); - REQUIRE(headerSerializer.getLargeFileFlag() == false); - REQUIRE(headerSerializer.getLenEntityIds() == 1); - REQUIRE(headerSerializer.getLenSeqNum() == 1); - REQUIRE(headerSerializer.getPduType() == cfdp::PduType::FILE_DIRECTIVE); - REQUIRE(headerSerializer.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::NOT_PRESENT); - REQUIRE(headerSerializer.getSegmentationControl() == false); - REQUIRE(headerSerializer.getTransmissionMode() == cfdp::TransmissionModes::ACKNOWLEDGED); - - cfdp::TransactionSeqNum seqNumLocal; - headerSerializer.getTransactionSeqNum(seqNumLocal); - REQUIRE(seqNumLocal.getWidth() == cfdp::WidthInBytes::ONE_BYTE); - REQUIRE(seqNumLocal.getValue() == 2); - cfdp::EntityId sourceDestId; - headerSerializer.getSourceId(sourceDestId); - REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::ONE_BYTE); - REQUIRE(sourceDestId.getValue() == 0); - headerSerializer.getDestId(sourceDestId); - REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::ONE_BYTE); - REQUIRE(sourceDestId.getValue() == 1); - - result = headerSerializer.serialize(&serTarget, &serSize, serBuf.size(), - SerializeIF::Endianness::BIG); - REQUIRE(result == returnvalue::OK); - REQUIRE(serSize == 7); - // Only version bits are set - REQUIRE(serBuf[0] == 0b00100000); - // PDU data field length is 0 - REQUIRE(serBuf[1] == 0); - REQUIRE(serBuf[2] == 0); - // Entity and Transaction Sequence number are 1 byte large - REQUIRE(serBuf[3] == 0b00010001); - // Source ID - REQUIRE(serBuf[4] == 0); - // Transaction Seq Number - REQUIRE(serBuf[5] == 2); - // Dest ID - REQUIRE(serBuf[6] == 1); - - for (uint8_t idx = 0; idx < 7; idx++) { - ReturnValue_t result = - headerSerializer.serialize(&serTarget, &serSize, idx, SerializeIF::Endianness::BIG); - REQUIRE(result == static_cast(SerializeIF::BUFFER_TOO_SHORT)); - } - - // Set PDU data field len - headerSerializer.setPduDataFieldLen(0x0ff0); - REQUIRE(headerSerializer.getPduDataFieldLen() == 0x0ff0); - REQUIRE(headerSerializer.getSerializedSize() == 7); - REQUIRE(headerSerializer.getWholePduSize() == 7 + 0x0ff0); - serTarget = serBuf.data(); - serSize = 0; - result = headerSerializer.serialize(&serTarget, &serSize, serBuf.size(), - SerializeIF::Endianness::BIG); - REQUIRE(serBuf[1] == 0x0f); - REQUIRE(serBuf[2] == 0xf0); - - pduConf.crcFlag = true; - pduConf.largeFile = true; - pduConf.direction = cfdp::Direction::TOWARDS_SENDER; - pduConf.mode = cfdp::TransmissionModes::UNACKNOWLEDGED; - headerSerializer.setSegmentationControl( - cfdp::SegmentationControl::RECORD_BOUNDARIES_PRESERVATION); - headerSerializer.setPduType(cfdp::PduType::FILE_DATA); - headerSerializer.setSegmentMetadataFlag(cfdp::SegmentMetadataFlag::PRESENT); - serTarget = serBuf.data(); - serSize = 0; - result = headerSerializer.serialize(&serTarget, &serSize, serBuf.size(), - SerializeIF::Endianness::BIG); - - // Everything except version bit flipped to one now - REQUIRE(serBuf[0] == 0x3f); - REQUIRE(serBuf[3] == 0x99); - pduConf.seqNum.setValue(cfdp::WidthInBytes::TWO_BYTES, 0x0fff); - pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00); - pduConf.destId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff); - REQUIRE(pduConf.sourceId.getSerializedSize() == 4); - REQUIRE(headerSerializer.getSerializedSize() == 14); - serTarget = serBuf.data(); - serSize = 0; - result = headerSerializer.serialize(&serTarget, &serSize, serBuf.size(), - SerializeIF::Endianness::BIG); - - for (uint8_t idx = 0; idx < 14; idx++) { - ReturnValue_t result = - headerSerializer.serialize(&serTarget, &serSize, idx, SerializeIF::Endianness::BIG); - REQUIRE(result == static_cast(SerializeIF::BUFFER_TOO_SHORT)); - } - REQUIRE(headerSerializer.getCrcFlag() == true); - REQUIRE(headerSerializer.getDirection() == cfdp::Direction::TOWARDS_SENDER); - REQUIRE(headerSerializer.getLargeFileFlag() == true); - REQUIRE(headerSerializer.getLenEntityIds() == 4); - REQUIRE(headerSerializer.getLenSeqNum() == 2); - REQUIRE(headerSerializer.getPduType() == cfdp::PduType::FILE_DATA); - REQUIRE(headerSerializer.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::PRESENT); - REQUIRE(headerSerializer.getTransmissionMode() == cfdp::TransmissionModes::UNACKNOWLEDGED); - REQUIRE(headerSerializer.getSegmentationControl() == true); - // Last three bits are 2 now (length of seq number) and bit 1 to bit 3 is 4 (len entity IDs) - REQUIRE(serBuf[3] == 0b11001010); - uint32_t entityId = 0; - size_t deSerSize = 0; - SerializeAdapter::deSerialize(&entityId, serBuf.data() + 4, &deSerSize, - SerializeIF::Endianness::NETWORK); - REQUIRE(deSerSize == 4); - REQUIRE(entityId == 0xff00ff00); - uint16_t seqNum = 0; - SerializeAdapter::deSerialize(&seqNum, serBuf.data() + 8, &deSerSize, - SerializeIF::Endianness::NETWORK); - REQUIRE(deSerSize == 2); - REQUIRE(seqNum == 0x0fff); - SerializeAdapter::deSerialize(&entityId, serBuf.data() + 10, &deSerSize, - SerializeIF::Endianness::NETWORK); - REQUIRE(deSerSize == 4); - REQUIRE(entityId == 0x00ff00ff); - - result = pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 0xfff); - REQUIRE(result == returnvalue::FAILED); - result = pduConf.sourceId.setValue(cfdp::WidthInBytes::TWO_BYTES, 0xfffff); - REQUIRE(result == returnvalue::FAILED); - result = pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xfffffffff); - REQUIRE(result == returnvalue::FAILED); - uint8_t oneByteSourceId = 32; - serTarget = &oneByteSourceId; - size_t deserLen = 1; - pduConf.sourceId.deSerialize(cfdp::WidthInBytes::ONE_BYTE, - const_cast(&serTarget), &deserLen, - SerializeIF::Endianness::MACHINE); - REQUIRE(pduConf.sourceId.getValue() == 32); - - uint16_t twoByteSourceId = 0xf0f0; - serTarget = reinterpret_cast(&twoByteSourceId); - deserLen = 2; - pduConf.sourceId.deSerialize(cfdp::WidthInBytes::TWO_BYTES, - const_cast(&serTarget), &deserLen, - SerializeIF::Endianness::MACHINE); - REQUIRE(pduConf.sourceId.getValue() == 0xf0f0); - - uint32_t fourByteSourceId = 0xf0f0f0f0; - serTarget = reinterpret_cast(&fourByteSourceId); - deserLen = 4; - pduConf.sourceId.deSerialize(cfdp::WidthInBytes::FOUR_BYTES, - const_cast(&serTarget), &deserLen, - SerializeIF::Endianness::MACHINE); - REQUIRE(pduConf.sourceId.getValue() == 0xf0f0f0f0); - - pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 1); - serTarget = serBuf.data(); - serSize = 1; - result = pduConf.sourceId.serialize(&serTarget, &serSize, 1, SerializeIF::Endianness::MACHINE); - REQUIRE(result == static_cast(SerializeIF::BUFFER_TOO_SHORT)); - } - - SECTION("Header Deserialization") { - // We unittested the serializer before, so we can use it now to generate valid raw CFDP - // data - auto headerSerializer = HeaderSerializer(pduConf, cfdp::PduType::FILE_DIRECTIVE, 0); - ReturnValue_t result = headerSerializer.serialize(&serTarget, &serSize, serBuf.size(), - SerializeIF::Endianness::BIG); - REQUIRE(result == returnvalue::OK); - REQUIRE(serBuf[1] == 0); - REQUIRE(serBuf[2] == 0); - // Entity and Transaction Sequence number are 1 byte large - REQUIRE(serBuf[3] == 0b00010001); - REQUIRE(serSize == 7); - // Deser call not strictly necessary - auto headerDeser = HeaderDeserializer(serBuf.data(), serBuf.size()); - - ReturnValue_t serResult = headerDeser.parseData(); - REQUIRE(serResult == returnvalue::OK); - REQUIRE(headerDeser.getPduDataFieldLen() == 0); - REQUIRE(headerDeser.getHeaderSize() == 7); - REQUIRE(headerDeser.getWholePduSize() == 7); - REQUIRE(headerDeser.getCrcFlag() == false); - REQUIRE(headerDeser.getDirection() == cfdp::Direction::TOWARDS_RECEIVER); - REQUIRE(headerDeser.getLargeFileFlag() == false); - REQUIRE(headerDeser.getLenEntityIds() == 1); - REQUIRE(headerDeser.getLenSeqNum() == 1); - REQUIRE(headerDeser.getPduType() == cfdp::PduType::FILE_DIRECTIVE); - REQUIRE(headerDeser.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::NOT_PRESENT); - REQUIRE(headerDeser.getSegmentationControl() == false); - REQUIRE(headerDeser.getTransmissionMode() == cfdp::TransmissionModes::ACKNOWLEDGED); - - pduConf.crcFlag = true; - pduConf.largeFile = true; - pduConf.direction = cfdp::Direction::TOWARDS_SENDER; - pduConf.mode = cfdp::TransmissionModes::UNACKNOWLEDGED; - headerSerializer.setSegmentationControl( - cfdp::SegmentationControl::RECORD_BOUNDARIES_PRESERVATION); - headerSerializer.setPduType(cfdp::PduType::FILE_DATA); - headerSerializer.setSegmentMetadataFlag(cfdp::SegmentMetadataFlag::PRESENT); - result = pduConf.seqNum.setValue(cfdp::WidthInBytes::TWO_BYTES, 0x0fff); - REQUIRE(result == returnvalue::OK); - result = pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00); - REQUIRE(result == returnvalue::OK); - result = pduConf.destId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff); - REQUIRE(result == returnvalue::OK); - serTarget = serBuf.data(); - serSize = 0; - result = headerSerializer.serialize(&serTarget, &serSize, serBuf.size(), - SerializeIF::Endianness::BIG); - headerDeser = HeaderDeserializer(serBuf.data(), serBuf.size()); - - result = headerDeser.parseData(); - REQUIRE(result == returnvalue::OK); - // Everything except version bit flipped to one now - REQUIRE(serBuf[0] == 0x3f); - REQUIRE(serBuf[3] == 0b11001010); - REQUIRE(headerDeser.getWholePduSize() == 14); - - REQUIRE(headerDeser.getCrcFlag() == true); - REQUIRE(headerDeser.getDirection() == cfdp::Direction::TOWARDS_SENDER); - REQUIRE(headerDeser.getLargeFileFlag() == true); - REQUIRE(headerDeser.getLenEntityIds() == 4); - REQUIRE(headerDeser.getLenSeqNum() == 2); - REQUIRE(headerDeser.getPduType() == cfdp::PduType::FILE_DATA); - REQUIRE(headerDeser.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::PRESENT); - REQUIRE(headerDeser.getSegmentationControl() == true); - REQUIRE(headerDeser.getTransmissionMode() == cfdp::TransmissionModes::UNACKNOWLEDGED); - - cfdp::TransactionSeqNum seqNumLocal; - headerDeser.getTransactionSeqNum(seqNumLocal); - REQUIRE(seqNumLocal.getWidth() == cfdp::WidthInBytes::TWO_BYTES); - REQUIRE(seqNumLocal.getValue() == 0x0fff); - cfdp::EntityId sourceDestId; - headerDeser.getSourceId(sourceDestId); - REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::FOUR_BYTES); - REQUIRE(sourceDestId.getValue() == 0xff00ff00); - headerDeser.getDestId(sourceDestId); - REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::FOUR_BYTES); - REQUIRE(sourceDestId.getValue() == 0x00ff00ff); - - size_t deSerSize = headerDeser.getWholePduSize(); - serTarget = serBuf.data(); - const uint8_t** serTargetConst = const_cast(&serTarget); - result = headerDeser.parseData(); - REQUIRE(result == returnvalue::OK); - - headerDeser.setData(nullptr, -1); - REQUIRE(headerDeser.getHeaderSize() == 0); - headerDeser.setData(serBuf.data(), serBuf.size()); - - serTarget = serBuf.data(); - serSize = 0; - pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 22); - pduConf.destId.setValue(cfdp::WidthInBytes::ONE_BYTE, 48); - result = headerSerializer.serialize(&serTarget, &serSize, serBuf.size(), - SerializeIF::Endianness::BIG); - REQUIRE(result == returnvalue::OK); - REQUIRE(headerDeser.getWholePduSize() == 8); - headerDeser.setData(serBuf.data(), serBuf.size()); - - headerDeser.getSourceId(sourceDestId); - REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::ONE_BYTE); - REQUIRE(sourceDestId.getValue() == 22); - } - SECTION("File Directive") { - auto fdSer = FileDirectiveSerializer(pduConf, FileDirectives::ACK, 4); + auto fdSer = FileDirectiveCreator(pduConf, FileDirective::ACK, 4); REQUIRE(fdSer.getSerializedSize() == 8); serTarget = serBuf.data(); serSize = 0; @@ -315,7 +41,7 @@ TEST_CASE("CFDP Base", "[CfdpBase]") { REQUIRE(serBuf[5] == 2); // Dest ID REQUIRE(serBuf[6] == 1); - REQUIRE(serBuf[7] == FileDirectives::ACK); + REQUIRE(serBuf[7] == FileDirective::ACK); serTarget = serBuf.data(); size_t deserSize = 20; @@ -333,31 +59,30 @@ TEST_CASE("CFDP Base", "[CfdpBase]") { deserTarget = serBuf.data(); deserSize = 0; - auto fdDeser = FileDirectiveDeserializer(deserTarget, serBuf.size()); + auto fdDeser = FileDirectiveReader(deserTarget, serBuf.size()); REQUIRE(fdDeser.getEndianness() == SerializeIF::Endianness::NETWORK); fdDeser.setEndianness(SerializeIF::Endianness::MACHINE); REQUIRE(fdDeser.getEndianness() == SerializeIF::Endianness::MACHINE); fdDeser.setEndianness(SerializeIF::Endianness::NETWORK); REQUIRE(fdDeser.parseData() == returnvalue::OK); - REQUIRE(fdDeser.getFileDirective() == FileDirectives::ACK); + REQUIRE(fdDeser.getFileDirective() == FileDirective::ACK); REQUIRE(fdDeser.getPduDataFieldLen() == 5); REQUIRE(fdDeser.getHeaderSize() == 8); REQUIRE(fdDeser.getPduType() == cfdp::PduType::FILE_DIRECTIVE); serBuf[7] = 0xff; // Invalid file directive - REQUIRE(fdDeser.parseData() == cfdp::INVALID_DIRECTIVE_FIELDS); + REQUIRE(fdDeser.parseData() == cfdp::INVALID_DIRECTIVE_FIELD); } - SECTION("FileSize") { + SECTION("File Size") { std::array fssBuf = {}; uint8_t* buffer = fssBuf.data(); size_t size = 0; cfdp::FileSize fss; REQUIRE(fss.getSize() == 0); fss.setFileSize(0x20, false); - ReturnValue_t result = - fss.serialize(&buffer, &size, fssBuf.size(), SerializeIF::Endianness::MACHINE); + result = fss.serialize(&buffer, &size, fssBuf.size(), SerializeIF::Endianness::MACHINE); REQUIRE(result == returnvalue::OK); uint32_t fileSize = 0; result = SerializeAdapter::deSerialize(&fileSize, fssBuf.data(), nullptr, @@ -365,4 +90,16 @@ TEST_CASE("CFDP Base", "[CfdpBase]") { REQUIRE(result == returnvalue::OK); REQUIRE(fileSize == 0x20); } + + SECTION("Var Length Field") { + VarLenField defaultField; + CHECK(defaultField.getValue() == 0); + CHECK(defaultField.getWidth() == WidthInBytes::ONE_BYTE); + VarLenField explicitField(WidthInBytes::FOUR_BYTES, 12); + CHECK(explicitField.getWidth() == WidthInBytes::FOUR_BYTES); + CHECK(explicitField.getValue() == 12); + VarLenField fromUnsignedByteField(UnsignedByteField(12)); + CHECK(fromUnsignedByteField.getWidth() == WidthInBytes::TWO_BYTES); + CHECK(fromUnsignedByteField.getValue() == 12); + } } diff --git a/unittests/cfdp/testLvs.cpp b/unittests/cfdp/testLvs.cpp new file mode 100644 index 00000000..22094568 --- /dev/null +++ b/unittests/cfdp/testLvs.cpp @@ -0,0 +1,116 @@ +#include +#include + +#include "fsfw/cfdp.h" +#include "fsfw/cfdp/VarLenFields.h" + +TEST_CASE("CFDP LV", "[cfdp][lv]") { + using namespace cfdp; + ReturnValue_t result = returnvalue::OK; + std::array rawBuf{}; + uint8_t* serPtr = rawBuf.data(); + const uint8_t* deserPtr = rawBuf.data(); + size_t deserSize = 0; + cfdp::EntityId sourceId = EntityId(cfdp::WidthInBytes::TWO_BYTES, 0x0ff0); + + SECTION("LV Serialization") { + std::array lvRawBuf{}; + serPtr = lvRawBuf.data(); + REQUIRE(sourceId.serialize(&serPtr, &deserSize, lvRawBuf.size(), + SerializeIF::Endianness::NETWORK) == returnvalue::OK); + REQUIRE(deserSize == 2); + + auto lv = cfdp::Lv(lvRawBuf.data(), 2); + REQUIRE(lv.getSerializedSize() == 3); + + SECTION("Copy") { + auto lvCopy = cfdp::Lv(lv); + REQUIRE(lvCopy.getSerializedSize() == 3); + REQUIRE(lv.getValue(nullptr) == lvCopy.getValue(nullptr)); + } + + serPtr = rawBuf.data(); + deserSize = 0; + REQUIRE(lv.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK) == + returnvalue::OK); + REQUIRE(deserSize == 3); + REQUIRE(rawBuf[0] == 2); + uint16_t sourceIdRaw = 0; + REQUIRE(SerializeAdapter::deSerialize(&sourceIdRaw, rawBuf.data() + 1, &deserSize, + SerializeIF::Endianness::BIG) == returnvalue::OK); + REQUIRE(sourceIdRaw == 0x0ff0); + } + + SECTION("Empty Serialization") { + auto lvEmpty = Lv(); + REQUIRE(lvEmpty.getSerializedSize() == 1); + serPtr = rawBuf.data(); + deserSize = 0; + result = + lvEmpty.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK); + REQUIRE(result == returnvalue::OK); + REQUIRE(deserSize == 1); + deserPtr = rawBuf.data(); + result = lvEmpty.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::BIG); + REQUIRE(result == returnvalue::OK); + REQUIRE(lvEmpty.getSerializedSize() == 1); + } + + SECTION("Uninit LV") { + std::array lvRawBuf{}; + serPtr = lvRawBuf.data(); + REQUIRE(sourceId.serialize(&serPtr, &deserSize, lvRawBuf.size(), + SerializeIF::Endianness::NETWORK) == returnvalue::OK); + auto lv = cfdp::Lv(lvRawBuf.data(), 2); + serPtr = rawBuf.data(); + deserSize = 0; + result = lv.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK); + REQUIRE(result == returnvalue::OK); + Lv uninitLv; + deserPtr = rawBuf.data(); + deserSize = 3; + result = uninitLv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::BIG); + REQUIRE(result == returnvalue::OK); + REQUIRE(uninitLv.getSerializedSize() == 3); + const uint8_t* storedValue = uninitLv.getValue(nullptr); + uint16_t sourceIdRaw = 0; + REQUIRE(SerializeAdapter::deSerialize(&sourceIdRaw, storedValue, &deserSize, + SerializeIF::Endianness::BIG) == returnvalue::OK); + REQUIRE(sourceIdRaw == 0x0ff0); + } + + SECTION("Invalid Input") { + Lv uninitLv; + REQUIRE(uninitLv.deSerialize(nullptr, nullptr, SerializeIF::Endianness::BIG) == + returnvalue::FAILED); + serPtr = rawBuf.data(); + deserSize = 0; + REQUIRE(uninitLv.serialize(&serPtr, &deserSize, 0, SerializeIF::Endianness::BIG) == + SerializeIF::BUFFER_TOO_SHORT); + REQUIRE(uninitLv.serialize(nullptr, nullptr, 12, SerializeIF::Endianness::BIG)); + deserSize = 0; + REQUIRE(uninitLv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::BIG) == + SerializeIF::STREAM_TOO_SHORT); + } + + SECTION("String LV String") { + std::string filename = "hello.txt"; + StringLv sourceFileName(filename); + REQUIRE(sourceFileName.getSerializedSize() == 1 + filename.size()); + REQUIRE(sourceFileName.serializeBe(rawBuf.data(), deserSize, rawBuf.size()) == returnvalue::OK); + REQUIRE(rawBuf[0] == filename.size()); + std::string filenameFromRaw(reinterpret_cast(rawBuf.data() + 1), filename.size()); + REQUIRE(filenameFromRaw == filename); + } + + SECTION("String LV Const Char") { + const char filename[] = "hello.txt"; + StringLv sourceFileName(filename, sizeof(filename) - 1); + REQUIRE(sourceFileName.getSerializedSize() == 1 + sizeof(filename) - 1); + REQUIRE(sourceFileName.serializeBe(rawBuf.data(), deserSize, rawBuf.size()) == returnvalue::OK); + REQUIRE(rawBuf[0] == sizeof(filename) - 1); + rawBuf[deserSize] = '\0'; + const char* filenameFromRaw = reinterpret_cast(rawBuf.data() + 1); + REQUIRE(std::strcmp(filename, filenameFromRaw) == 0); + } +} diff --git a/unittests/cfdp/testOtherTlvs.cpp b/unittests/cfdp/testOtherTlvs.cpp new file mode 100644 index 00000000..88413195 --- /dev/null +++ b/unittests/cfdp/testOtherTlvs.cpp @@ -0,0 +1,137 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "fsfw/cfdp/pdu/PduConfig.h" +#include "fsfw/cfdp/tlv/Lv.h" +#include "fsfw/cfdp/tlv/Tlv.h" +#include "fsfw/globalfunctions/arrayprinter.h" + +TEST_CASE("CFDP Other TLVs", "[cfdp][tlv]") { + using namespace cfdp; + ReturnValue_t result; + std::array rawBuf{}; + uint8_t* serPtr = rawBuf.data(); + const uint8_t* deserPtr = rawBuf.data(); + size_t deserSize = 0; + cfdp::EntityId sourceId = EntityId(cfdp::WidthInBytes::TWO_BYTES, 0x0ff0); + + SECTION("Filestore Response TLV") { + std::string name = "hello.txt"; + cfdp::StringLv firstName(name); + std::string name2 = "hello2.txt"; + cfdp::StringLv secondName(name2); + std::string msg = "12345"; + cfdp::Lv fsMsg(reinterpret_cast(msg.data()), msg.size()); + FilestoreResponseTlv response(cfdp::FilestoreActionCode::APPEND_FILE, cfdp::FSR_SUCCESS, + firstName, &fsMsg); + response.setSecondFileName(&secondName); + REQUIRE(response.getLengthField() == 10 + 11 + 6 + 1); + REQUIRE(response.getSerializedSize() == response.getLengthField() + 2); + + cfdp::Tlv rawResponse; + std::array serBuf = {}; + result = response.convertToTlv(rawResponse, serBuf.data(), serBuf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == returnvalue::OK); + REQUIRE(rawResponse.getType() == cfdp::TlvType::FILESTORE_RESPONSE); + cfdp::StringLv emptyMsg; + cfdp::StringLv emptySecondName; + FilestoreResponseTlv emptyTlv(firstName, &emptyMsg); + emptyTlv.setSecondFileName(&emptySecondName); + result = emptyTlv.deSerialize(rawResponse, SerializeIF::Endianness::NETWORK); + REQUIRE(result == returnvalue::OK); + REQUIRE(emptyTlv.getActionCode() == cfdp::FilestoreActionCode::APPEND_FILE); + REQUIRE(emptyTlv.getStatusCode() == cfdp::FSR_SUCCESS); + size_t firstNameLen = 0; + const char* firstNamePtr = + reinterpret_cast(emptyTlv.getFirstFileName().getValue(&firstNameLen)); + auto helloString = std::string(firstNamePtr, firstNameLen); + REQUIRE(helloString == "hello.txt"); + } + + SECTION("Filestore Request TLV") { + std::string name = "hello.txt"; + cfdp::StringLv firstName(name); + std::string name2 = "hello2.txt"; + cfdp::StringLv secondName(name2); + FilestoreRequestTlv request(cfdp::FilestoreActionCode::APPEND_FILE, firstName); + + // second name not set yet + REQUIRE(request.getLengthField() == 10 + 1); + REQUIRE(request.getSerializedSize() == request.getLengthField() + 2); + + std::array serBuf = {}; + uint8_t* ptr = serBuf.data(); + size_t sz = 0; + result = request.serialize(&ptr, &sz, serBuf.size(), SerializeIF::Endianness::NETWORK); + REQUIRE(result == cfdp::FILESTORE_REQUIRES_SECOND_FILE); + + ptr = serBuf.data(); + sz = 0; + request.setSecondFileName(&secondName); + size_t expectedSz = request.getLengthField(); + REQUIRE(expectedSz == 10 + 11 + 1); + REQUIRE(request.getSerializedSize() == expectedSz + 2); + result = request.serialize(&ptr, &sz, serBuf.size(), SerializeIF::Endianness::NETWORK); + REQUIRE(result == returnvalue::OK); + REQUIRE(sz == expectedSz + 2); + + FilestoreRequestTlv emptyRequest(firstName); + emptyRequest.setSecondFileName(&secondName); + const uint8_t* constptr = serBuf.data(); + result = emptyRequest.deSerialize(&constptr, &sz, SerializeIF::Endianness::NETWORK); + REQUIRE(result == returnvalue::OK); + + cfdp::Tlv rawRequest; + ptr = serBuf.data(); + sz = 0; + result = request.convertToTlv(rawRequest, serBuf.data(), serBuf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == returnvalue::OK); + REQUIRE(rawRequest.getType() == cfdp::TlvType::FILESTORE_REQUEST); + + emptyRequest.setActionCode(cfdp::FilestoreActionCode::DELETE_FILE); + result = emptyRequest.deSerialize(rawRequest, SerializeIF::Endianness::NETWORK); + REQUIRE(result == returnvalue::OK); + REQUIRE(emptyRequest.getType() == cfdp::TlvType::FILESTORE_REQUEST); + REQUIRE(emptyRequest.getActionCode() == cfdp::FilestoreActionCode::APPEND_FILE); + } + + SECTION("Other") { + MessageToUserTlv emptyTlv; + uint8_t flowLabel = 1; + FlowLabelTlv flowLabelTlv(&flowLabel, 1); + + FaultHandlerOverrideTlv faultOverrideTlv(cfdp::ConditionCode::FILESTORE_REJECTION, + cfdp::FaultHandlerCode::NOTICE_OF_CANCELLATION); + size_t sz = 0; + result = + faultOverrideTlv.serialize(&serPtr, &sz, rawBuf.size(), SerializeIF::Endianness::NETWORK); + REQUIRE(faultOverrideTlv.getSerializedSize() == 3); + REQUIRE(sz == 3); + REQUIRE(result == returnvalue::OK); + + FaultHandlerOverrideTlv emptyOverrideTlv; + result = emptyOverrideTlv.deSerialize(&deserPtr, &sz, SerializeIF::Endianness::NETWORK); + REQUIRE(result == returnvalue::OK); + + EntityId entId(cfdp::WidthInBytes::TWO_BYTES, 0x42); + EntityId emptyId; + EntityIdTlv idTlv(emptyId); + serPtr = rawBuf.data(); + result = idTlv.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK); + cfdp::Tlv rawTlv(cfdp::TlvType::ENTITY_ID, rawBuf.data() + 2, 2); + REQUIRE(result == returnvalue::OK); + deserPtr = rawBuf.data(); + result = idTlv.deSerialize(rawTlv, SerializeIF::Endianness::NETWORK); + REQUIRE(result == returnvalue::OK); + } +} diff --git a/unittests/cfdp/testTlv.cpp b/unittests/cfdp/testTlv.cpp new file mode 100644 index 00000000..979bfac5 --- /dev/null +++ b/unittests/cfdp/testTlv.cpp @@ -0,0 +1,128 @@ +#include +#include + +#include "fsfw/cfdp.h" +#include "fsfw/cfdp/VarLenFields.h" + +TEST_CASE("CFDP TLV", "[cfdp][tlv]") { + using namespace cfdp; + ReturnValue_t result; + std::array rawBuf{}; + uint8_t* serPtr = rawBuf.data(); + const uint8_t* deserPtr = rawBuf.data(); + size_t deserSize = 0; + cfdp::EntityId sourceId = EntityId(cfdp::WidthInBytes::TWO_BYTES, 0x0ff0); + + SECTION("Entity ID Serialization") { + REQUIRE(sourceId.serialize(&serPtr, &deserSize, rawBuf.size(), + SerializeIF::Endianness::NETWORK) == returnvalue::OK); + REQUIRE(deserSize == 2); + } + + SECTION("TLV Serialization") { + std::array tlvBuf{}; + REQUIRE(sourceId.serializeBe(tlvBuf.data(), deserSize, tlvBuf.size()) == returnvalue::OK); + auto tlv = Tlv(TlvType::ENTITY_ID, tlvBuf.data(), deserSize); + REQUIRE(tlv.getSerializedSize() == 4); + REQUIRE(tlv.getLengthField() == 2); + deserSize = 0; + REQUIRE(tlv.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK) == + returnvalue::OK); + REQUIRE(deserSize == 4); + REQUIRE(rawBuf[0] == TlvType::ENTITY_ID); + REQUIRE(rawBuf[1] == 2); + uint16_t entityId = 0; + REQUIRE(SerializeAdapter::deSerialize(&entityId, rawBuf.data() + 2, &deserSize, + SerializeIF::Endianness::NETWORK) == returnvalue::OK); + REQUIRE(entityId == 0x0ff0); + } + + SECTION("TLV Other Value") { + auto tlv = Tlv(TlvType::ENTITY_ID, rawBuf.data(), deserSize); + // Set new value + sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 12); + REQUIRE(sourceId.serialize(&serPtr, &deserSize, rawBuf.size(), + SerializeIF::Endianness::NETWORK) == returnvalue::OK); + tlv.setValue(rawBuf.data(), cfdp::WidthInBytes::FOUR_BYTES); + serPtr = rawBuf.data(); + deserSize = 0; + result = tlv.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK); + REQUIRE(result == returnvalue::OK); + REQUIRE(rawBuf[0] == TlvType::ENTITY_ID); + REQUIRE(rawBuf[1] == 4); + + REQUIRE(result == returnvalue::OK); + } + + SECTION("TLV Invalid") { + auto tlvInvalid = Tlv(cfdp::TlvType::INVALID_TLV, rawBuf.data(), 0); + REQUIRE(tlvInvalid.serialize(&serPtr, &deserSize, rawBuf.size(), + SerializeIF::Endianness::NETWORK) != returnvalue::OK); + tlvInvalid = Tlv(cfdp::TlvType::ENTITY_ID, nullptr, 3); + REQUIRE(tlvInvalid.serialize(&serPtr, &deserSize, rawBuf.size(), + SerializeIF::Endianness::NETWORK) != returnvalue::OK); + REQUIRE(tlvInvalid.serialize(&serPtr, &deserSize, 0, SerializeIF::Endianness::NETWORK) != + returnvalue::OK); + REQUIRE(tlvInvalid.getSerializedSize() == 0); + REQUIRE(tlvInvalid.serialize(nullptr, nullptr, 0, SerializeIF::Endianness::NETWORK) != + returnvalue::OK); + } + + SECTION("TLV Zero Length Field") { + Tlv zeroLenField(TlvType::FAULT_HANDLER, nullptr, 0); + REQUIRE(zeroLenField.getSerializedSize() == 2); + serPtr = rawBuf.data(); + deserSize = 0; + REQUIRE(zeroLenField.serialize(&serPtr, &deserSize, rawBuf.size(), + SerializeIF::Endianness::NETWORK) == returnvalue::OK); + REQUIRE(rawBuf[0] == TlvType::FAULT_HANDLER); + REQUIRE(rawBuf[1] == 0); + } + + SECTION("TLV Deserialization") { + // Serialization was tested before, generate raw data now + std::array tlvRawBuf{}; + serPtr = tlvRawBuf.data(); + result = + sourceId.serialize(&serPtr, &deserSize, tlvRawBuf.size(), SerializeIF::Endianness::NETWORK); + auto tlvSerialization = Tlv(TlvType::ENTITY_ID, tlvRawBuf.data(), deserSize); + serPtr = rawBuf.data(); + deserSize = 0; + result = tlvSerialization.serialize(&serPtr, &deserSize, rawBuf.size(), + SerializeIF::Endianness::NETWORK); + Tlv tlv; + deserPtr = rawBuf.data(); + result = tlv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::NETWORK); + REQUIRE(result == returnvalue::OK); + REQUIRE(tlv.getSerializedSize() == 4); + REQUIRE(tlv.getType() == TlvType::ENTITY_ID); + deserPtr = tlv.getValue(); + uint16_t entityId = 0; + deserSize = 0; + SerializeAdapter::deSerialize(&entityId, deserPtr, &deserSize, + SerializeIF::Endianness::NETWORK); + REQUIRE(entityId == 0x0ff0); + + REQUIRE(tlv.deSerialize(nullptr, nullptr, SerializeIF::Endianness::NETWORK) != returnvalue::OK); + deserPtr = rawBuf.data(); + deserSize = 0; + REQUIRE(tlv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::NETWORK) == + SerializeIF::STREAM_TOO_SHORT); + // Set invalid TLV + rawBuf[0] = TlvType::INVALID_TLV; + deserSize = 4; + REQUIRE(tlv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::NETWORK) != + returnvalue::OK); + + Tlv zeroLenField(TlvType::FAULT_HANDLER, nullptr, 0); + serPtr = rawBuf.data(); + deserSize = 0; + REQUIRE(zeroLenField.serialize(&serPtr, &deserSize, rawBuf.size(), + SerializeIF::Endianness::NETWORK) == returnvalue::OK); + deserPtr = rawBuf.data(); + result = zeroLenField.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::NETWORK); + REQUIRE(result == returnvalue::OK); + REQUIRE(zeroLenField.getSerializedSize() == 2); + REQUIRE(deserSize == 0); + } +} diff --git a/unittests/cfdp/testTlvsLvs.cpp b/unittests/cfdp/testTlvsLvs.cpp deleted file mode 100644 index bd5ec849..00000000 --- a/unittests/cfdp/testTlvsLvs.cpp +++ /dev/null @@ -1,327 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "fsfw/cfdp/pdu/PduConfig.h" -#include "fsfw/cfdp/tlv/Lv.h" -#include "fsfw/cfdp/tlv/Tlv.h" -#include "fsfw/globalfunctions/arrayprinter.h" - -TEST_CASE("CFDP TLV LV", "[CfdpTlvLv]") { - using namespace cfdp; - int result = returnvalue::OK; - std::array rawBuf; - uint8_t* serPtr = rawBuf.data(); - const uint8_t* deserPtr = rawBuf.data(); - size_t deserSize = 0; - cfdp::EntityId sourceId = EntityId(cfdp::WidthInBytes::TWO_BYTES, 0x0ff0); - - SECTION("TLV Serialization") { - std::array tlvRawBuf; - serPtr = tlvRawBuf.data(); - result = - sourceId.serialize(&serPtr, &deserSize, tlvRawBuf.size(), SerializeIF::Endianness::NETWORK); - REQUIRE(result == returnvalue::OK); - REQUIRE(deserSize == 2); - auto tlv = Tlv(TlvTypes::ENTITY_ID, tlvRawBuf.data(), deserSize); - REQUIRE(tlv.getSerializedSize() == 4); - REQUIRE(tlv.getLengthField() == 2); - serPtr = rawBuf.data(); - deserSize = 0; - result = tlv.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK); - REQUIRE(result == returnvalue::OK); - REQUIRE(deserSize == 4); - REQUIRE(rawBuf[0] == TlvTypes::ENTITY_ID); - REQUIRE(rawBuf[1] == 2); - uint16_t entityId = 0; - SerializeAdapter::deSerialize(&entityId, rawBuf.data() + 2, &deserSize, - SerializeIF::Endianness::NETWORK); - REQUIRE(entityId == 0x0ff0); - - // Set new value - sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 12); - serPtr = tlvRawBuf.data(); - deserSize = 0; - result = - sourceId.serialize(&serPtr, &deserSize, tlvRawBuf.size(), SerializeIF::Endianness::NETWORK); - tlv.setValue(tlvRawBuf.data(), cfdp::WidthInBytes::FOUR_BYTES); - serPtr = rawBuf.data(); - deserSize = 0; - result = tlv.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK); - REQUIRE(result == returnvalue::OK); - REQUIRE(rawBuf[0] == TlvTypes::ENTITY_ID); - REQUIRE(rawBuf[1] == 4); - - REQUIRE(result == returnvalue::OK); - - serPtr = rawBuf.data(); - deserSize = 0; - auto tlvInvalid = Tlv(cfdp::TlvTypes::INVALID_TLV, tlvRawBuf.data(), 0); - REQUIRE(tlvInvalid.serialize(&serPtr, &deserSize, rawBuf.size(), - SerializeIF::Endianness::NETWORK) != returnvalue::OK); - tlvInvalid = Tlv(cfdp::TlvTypes::ENTITY_ID, nullptr, 3); - REQUIRE(tlvInvalid.serialize(&serPtr, &deserSize, rawBuf.size(), - SerializeIF::Endianness::NETWORK) != returnvalue::OK); - REQUIRE(tlvInvalid.serialize(&serPtr, &deserSize, 0, SerializeIF::Endianness::NETWORK) != - returnvalue::OK); - REQUIRE(tlvInvalid.getSerializedSize() == 0); - REQUIRE(tlvInvalid.serialize(nullptr, nullptr, 0, SerializeIF::Endianness::NETWORK) != - returnvalue::OK); - - Tlv zeroLenField(TlvTypes::FAULT_HANDLER, nullptr, 0); - REQUIRE(zeroLenField.getSerializedSize() == 2); - serPtr = rawBuf.data(); - deserSize = 0; - REQUIRE(zeroLenField.serialize(&serPtr, &deserSize, rawBuf.size(), - SerializeIF::Endianness::NETWORK) == returnvalue::OK); - REQUIRE(rawBuf[0] == TlvTypes::FAULT_HANDLER); - REQUIRE(rawBuf[1] == 0); - } - - SECTION("TLV Deserialization") { - // Serialization was tested before, generate raw data now - std::array tlvRawBuf; - serPtr = tlvRawBuf.data(); - result = - sourceId.serialize(&serPtr, &deserSize, tlvRawBuf.size(), SerializeIF::Endianness::NETWORK); - auto tlvSerialization = Tlv(TlvTypes::ENTITY_ID, tlvRawBuf.data(), deserSize); - serPtr = rawBuf.data(); - deserSize = 0; - result = tlvSerialization.serialize(&serPtr, &deserSize, rawBuf.size(), - SerializeIF::Endianness::NETWORK); - Tlv tlv; - deserPtr = rawBuf.data(); - result = tlv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::NETWORK); - REQUIRE(result == returnvalue::OK); - REQUIRE(tlv.getSerializedSize() == 4); - REQUIRE(tlv.getType() == TlvTypes::ENTITY_ID); - deserPtr = tlv.getValue(); - uint16_t entityId = 0; - deserSize = 0; - SerializeAdapter::deSerialize(&entityId, deserPtr, &deserSize, - SerializeIF::Endianness::NETWORK); - REQUIRE(entityId == 0x0ff0); - - REQUIRE(tlv.deSerialize(nullptr, nullptr, SerializeIF::Endianness::NETWORK) != returnvalue::OK); - deserPtr = rawBuf.data(); - deserSize = 0; - REQUIRE(tlv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::NETWORK) == - SerializeIF::STREAM_TOO_SHORT); - // Set invalid TLV - rawBuf[0] = TlvTypes::INVALID_TLV; - deserSize = 4; - REQUIRE(tlv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::NETWORK) != - returnvalue::OK); - - Tlv zeroLenField(TlvTypes::FAULT_HANDLER, nullptr, 0); - serPtr = rawBuf.data(); - deserSize = 0; - REQUIRE(zeroLenField.serialize(&serPtr, &deserSize, rawBuf.size(), - SerializeIF::Endianness::NETWORK) == returnvalue::OK); - deserPtr = rawBuf.data(); - result = zeroLenField.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::NETWORK); - REQUIRE(result == returnvalue::OK); - REQUIRE(zeroLenField.getSerializedSize() == 2); - REQUIRE(deserSize == 0); - } - - SECTION("LV Serialization") { - std::array lvRawBuf; - serPtr = lvRawBuf.data(); - result = - sourceId.serialize(&serPtr, &deserSize, lvRawBuf.size(), SerializeIF::Endianness::NETWORK); - REQUIRE(result == returnvalue::OK); - REQUIRE(deserSize == 2); - auto lv = cfdp::Lv(lvRawBuf.data(), 2); - auto lvCopy = cfdp::Lv(lv); - REQUIRE(lv.getSerializedSize() == 3); - REQUIRE(lvCopy.getSerializedSize() == 3); - REQUIRE(lv.getValue(nullptr) == lvCopy.getValue(nullptr)); - serPtr = rawBuf.data(); - deserSize = 0; - result = lv.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK); - REQUIRE(result == returnvalue::OK); - REQUIRE(deserSize == 3); - REQUIRE(rawBuf[0] == 2); - uint16_t sourceId = 0; - result = SerializeAdapter::deSerialize(&sourceId, rawBuf.data() + 1, &deserSize, - SerializeIF::Endianness::BIG); - REQUIRE(sourceId == 0x0ff0); - - auto lvEmpty = Lv(nullptr, 0); - REQUIRE(lvEmpty.getSerializedSize() == 1); - serPtr = rawBuf.data(); - deserSize = 0; - result = - lvEmpty.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK); - REQUIRE(result == returnvalue::OK); - REQUIRE(deserSize == 1); - } - - SECTION("LV Deserialization") { - std::array lvRawBuf; - serPtr = lvRawBuf.data(); - result = - sourceId.serialize(&serPtr, &deserSize, lvRawBuf.size(), SerializeIF::Endianness::NETWORK); - auto lv = cfdp::Lv(lvRawBuf.data(), 2); - serPtr = rawBuf.data(); - deserSize = 0; - result = lv.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK); - REQUIRE(result == returnvalue::OK); - - Lv uninitLv; - deserPtr = rawBuf.data(); - deserSize = 3; - result = uninitLv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::BIG); - REQUIRE(result == returnvalue::OK); - REQUIRE(uninitLv.getSerializedSize() == 3); - const uint8_t* storedValue = uninitLv.getValue(nullptr); - uint16_t sourceId = 0; - result = SerializeAdapter::deSerialize(&sourceId, storedValue, &deserSize, - SerializeIF::Endianness::BIG); - REQUIRE(sourceId == 0x0ff0); - - auto lvEmpty = Lv(nullptr, 0); - REQUIRE(lvEmpty.getSerializedSize() == 1); - serPtr = rawBuf.data(); - deserSize = 0; - result = - lvEmpty.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK); - REQUIRE(result == returnvalue::OK); - REQUIRE(deserSize == 1); - deserPtr = rawBuf.data(); - result = uninitLv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::BIG); - REQUIRE(result == returnvalue::OK); - REQUIRE(uninitLv.getSerializedSize() == 1); - - REQUIRE(uninitLv.deSerialize(nullptr, nullptr, SerializeIF::Endianness::BIG) == - returnvalue::FAILED); - serPtr = rawBuf.data(); - deserSize = 0; - REQUIRE(uninitLv.serialize(&serPtr, &deserSize, 0, SerializeIF::Endianness::BIG) == - SerializeIF::BUFFER_TOO_SHORT); - REQUIRE(uninitLv.serialize(nullptr, nullptr, 12, SerializeIF::Endianness::BIG)); - deserSize = 0; - REQUIRE(uninitLv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::BIG) == - SerializeIF::STREAM_TOO_SHORT); - } - - SECTION("Filestore Response TLV") { - std::string name = "hello.txt"; - cfdp::Lv firstName(reinterpret_cast(name.data()), name.size()); - std::string name2 = "hello2.txt"; - cfdp::Lv secondName(reinterpret_cast(name2.data()), name2.size()); - std::string msg = "12345"; - cfdp::Lv fsMsg(reinterpret_cast(msg.data()), msg.size()); - FilestoreResponseTlv response(cfdp::FilestoreActionCode::APPEND_FILE, cfdp::FSR_SUCCESS, - firstName, &fsMsg); - response.setSecondFileName(&secondName); - REQUIRE(response.getLengthField() == 10 + 11 + 6 + 1); - REQUIRE(response.getSerializedSize() == response.getLengthField() + 2); - - cfdp::Tlv rawResponse; - std::array serBuf = {}; - result = response.convertToTlv(rawResponse, serBuf.data(), serBuf.size(), - SerializeIF::Endianness::NETWORK); - REQUIRE(result == returnvalue::OK); - REQUIRE(rawResponse.getType() == cfdp::TlvTypes::FILESTORE_RESPONSE); - cfdp::Lv emptyMsg; - cfdp::Lv emptySecondName; - FilestoreResponseTlv emptyTlv(firstName, &emptyMsg); - emptyTlv.setSecondFileName(&emptySecondName); - result = emptyTlv.deSerialize(rawResponse, SerializeIF::Endianness::NETWORK); - REQUIRE(result == returnvalue::OK); - REQUIRE(emptyTlv.getActionCode() == cfdp::FilestoreActionCode::APPEND_FILE); - REQUIRE(emptyTlv.getStatusCode() == cfdp::FSR_SUCCESS); - size_t firstNameLen = 0; - const char* firstNamePtr = - reinterpret_cast(emptyTlv.getFirstFileName().getValue(&firstNameLen)); - auto helloString = std::string(firstNamePtr, firstNameLen); - REQUIRE(helloString == "hello.txt"); - } - - SECTION("Filestore Request TLV") { - std::string name = "hello.txt"; - cfdp::Lv firstName(reinterpret_cast(name.data()), name.size()); - std::string name2 = "hello2.txt"; - cfdp::Lv secondName(reinterpret_cast(name2.data()), name2.size()); - FilestoreRequestTlv request(cfdp::FilestoreActionCode::APPEND_FILE, firstName); - - // second name not set yet - REQUIRE(request.getLengthField() == 10 + 1); - REQUIRE(request.getSerializedSize() == request.getLengthField() + 2); - - std::array serBuf = {}; - uint8_t* ptr = serBuf.data(); - size_t sz = 0; - result = request.serialize(&ptr, &sz, serBuf.size(), SerializeIF::Endianness::NETWORK); - REQUIRE(result == cfdp::FILESTORE_REQUIRES_SECOND_FILE); - - ptr = serBuf.data(); - sz = 0; - request.setSecondFileName(&secondName); - size_t expectedSz = request.getLengthField(); - REQUIRE(expectedSz == 10 + 11 + 1); - REQUIRE(request.getSerializedSize() == expectedSz + 2); - result = request.serialize(&ptr, &sz, serBuf.size(), SerializeIF::Endianness::NETWORK); - REQUIRE(result == returnvalue::OK); - REQUIRE(sz == expectedSz + 2); - - FilestoreRequestTlv emptyRequest(firstName); - emptyRequest.setSecondFileName(&secondName); - const uint8_t* constptr = serBuf.data(); - result = emptyRequest.deSerialize(&constptr, &sz, SerializeIF::Endianness::NETWORK); - REQUIRE(result == returnvalue::OK); - - cfdp::Tlv rawRequest; - ptr = serBuf.data(); - sz = 0; - result = request.convertToTlv(rawRequest, serBuf.data(), serBuf.size(), - SerializeIF::Endianness::NETWORK); - REQUIRE(result == returnvalue::OK); - REQUIRE(rawRequest.getType() == cfdp::TlvTypes::FILESTORE_REQUEST); - - emptyRequest.setActionCode(cfdp::FilestoreActionCode::DELETE_FILE); - result = emptyRequest.deSerialize(rawRequest, SerializeIF::Endianness::NETWORK); - REQUIRE(result == returnvalue::OK); - REQUIRE(emptyRequest.getType() == cfdp::TlvTypes::FILESTORE_REQUEST); - REQUIRE(emptyRequest.getActionCode() == cfdp::FilestoreActionCode::APPEND_FILE); - } - - SECTION("Other") { - MessageToUserTlv emptyTlv; - uint8_t flowLabel = 1; - FlowLabelTlv flowLabelTlv(&flowLabel, 1); - - FaultHandlerOverrideTlv faultOverrideTlv(cfdp::ConditionCode::FILESTORE_REJECTION, - cfdp::FaultHandlerCode::NOTICE_OF_CANCELLATION); - size_t sz = 0; - ReturnValue_t result = - faultOverrideTlv.serialize(&serPtr, &sz, rawBuf.size(), SerializeIF::Endianness::NETWORK); - REQUIRE(faultOverrideTlv.getSerializedSize() == 3); - REQUIRE(sz == 3); - REQUIRE(result == returnvalue::OK); - - FaultHandlerOverrideTlv emptyOverrideTlv; - result = emptyOverrideTlv.deSerialize(&deserPtr, &sz, SerializeIF::Endianness::NETWORK); - REQUIRE(result == returnvalue::OK); - - EntityId entId(cfdp::WidthInBytes::TWO_BYTES, 0x42); - EntityId emptyId; - EntityIdTlv idTlv(emptyId); - serPtr = rawBuf.data(); - result = idTlv.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK); - cfdp::Tlv rawTlv(cfdp::TlvTypes::ENTITY_ID, rawBuf.data() + 2, 2); - REQUIRE(result == returnvalue::OK); - deserPtr = rawBuf.data(); - result = idTlv.deSerialize(rawTlv, SerializeIF::Endianness::NETWORK); - REQUIRE(result == returnvalue::OK); - } -} diff --git a/unittests/container/CMakeLists.txt b/unittests/container/CMakeLists.txt index 5dae974c..d65e5993 100644 --- a/unittests/container/CMakeLists.txt +++ b/unittests/container/CMakeLists.txt @@ -1,10 +1,10 @@ -target_sources(${FSFW_TEST_TGT} PRIVATE - RingBufferTest.cpp - TestArrayList.cpp - TestDynamicFifo.cpp - TestFifo.cpp - TestFixedArrayList.cpp - TestFixedMap.cpp - TestFixedOrderedMultimap.cpp - TestPlacementFactory.cpp -) +target_sources( + ${FSFW_TEST_TGT} + PRIVATE RingBufferTest.cpp + TestArrayList.cpp + TestDynamicFifo.cpp + TestFifo.cpp + TestFixedArrayList.cpp + TestFixedMap.cpp + TestFixedOrderedMultimap.cpp + TestPlacementFactory.cpp) diff --git a/unittests/container/RingBufferTest.cpp b/unittests/container/RingBufferTest.cpp index efc571b4..49fa1ab0 100644 --- a/unittests/container/RingBufferTest.cpp +++ b/unittests/container/RingBufferTest.cpp @@ -5,7 +5,7 @@ #include "CatchDefinitions.h" -TEST_CASE("Ring Buffer Test", "[RingBufferTest]") { +TEST_CASE("Ring Buffer Test", "[containers]") { uint8_t testData[13] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; uint8_t readBuffer[10] = {13, 13, 13, 13, 13, 13, 13, 13, 13, 13}; SimpleRingBuffer ringBuffer(10, false, 5); diff --git a/unittests/container/TestArrayList.cpp b/unittests/container/TestArrayList.cpp index 04560cef..69b08faa 100644 --- a/unittests/container/TestArrayList.cpp +++ b/unittests/container/TestArrayList.cpp @@ -8,7 +8,7 @@ /** * @brief Array List test */ -TEST_CASE("Array List", "[ArrayListTest]") { +TEST_CASE("Array List", "[containers]") { // perform set-up here ArrayList list(20); struct TestClass { diff --git a/unittests/container/TestDynamicFifo.cpp b/unittests/container/TestDynamicFifo.cpp index 1e3d4a62..d32f7e5e 100644 --- a/unittests/container/TestDynamicFifo.cpp +++ b/unittests/container/TestDynamicFifo.cpp @@ -6,7 +6,7 @@ #include "CatchDefinitions.h" -TEST_CASE("Dynamic Fifo Tests", "[TestDynamicFifo]") { +TEST_CASE("Dynamic Fifo Tests", "[containers]") { INFO("Dynamic Fifo Tests"); struct Test { uint64_t number1; diff --git a/unittests/container/TestFifo.cpp b/unittests/container/TestFifo.cpp index 9fc9ee93..bfd9391f 100644 --- a/unittests/container/TestFifo.cpp +++ b/unittests/container/TestFifo.cpp @@ -6,7 +6,7 @@ #include "CatchDefinitions.h" -TEST_CASE("Static Fifo Tests", "[TestFifo]") { +TEST_CASE("Static Fifo Tests", "[containers]") { INFO("Fifo Tests"); struct Test { uint64_t number1; diff --git a/unittests/container/TestFixedArrayList.cpp b/unittests/container/TestFixedArrayList.cpp index 0a8de39f..876d6792 100644 --- a/unittests/container/TestFixedArrayList.cpp +++ b/unittests/container/TestFixedArrayList.cpp @@ -5,7 +5,7 @@ #include "CatchDefinitions.h" -TEST_CASE("FixedArrayList Tests", "[TestFixedArrayList]") { +TEST_CASE("FixedArrayList Tests", "[containers]") { INFO("FixedArrayList Tests"); using testList = FixedArrayList; testList list; diff --git a/unittests/container/TestFixedMap.cpp b/unittests/container/TestFixedMap.cpp index f8479899..8bfe9fed 100644 --- a/unittests/container/TestFixedMap.cpp +++ b/unittests/container/TestFixedMap.cpp @@ -7,7 +7,7 @@ template class FixedMap; -TEST_CASE("FixedMap Tests", "[TestFixedMap]") { +TEST_CASE("FixedMap Tests", "[containers]") { INFO("FixedMap Tests"); FixedMap map(30); diff --git a/unittests/container/TestFixedOrderedMultimap.cpp b/unittests/container/TestFixedOrderedMultimap.cpp index 4d90a0cf..cadb03e6 100644 --- a/unittests/container/TestFixedOrderedMultimap.cpp +++ b/unittests/container/TestFixedOrderedMultimap.cpp @@ -5,7 +5,7 @@ #include "CatchDefinitions.h" -TEST_CASE("FixedOrderedMultimap Tests", "[TestFixedOrderedMultimap]") { +TEST_CASE("FixedOrderedMultimap Tests", "[containers]") { INFO("FixedOrderedMultimap Tests"); FixedOrderedMultimap map(30); diff --git a/unittests/container/TestPlacementFactory.cpp b/unittests/container/TestPlacementFactory.cpp index a898f4c1..fa8e1e07 100644 --- a/unittests/container/TestPlacementFactory.cpp +++ b/unittests/container/TestPlacementFactory.cpp @@ -7,7 +7,7 @@ #include "CatchDefinitions.h" -TEST_CASE("PlacementFactory Tests", "[TestPlacementFactory]") { +TEST_CASE("PlacementFactory Tests", "[containers]") { INFO("PlacementFactory Tests"); LocalPool::LocalPoolConfig poolCfg = { diff --git a/unittests/datapoollocal/CMakeLists.txt b/unittests/datapoollocal/CMakeLists.txt index 016645fd..2c7a573f 100644 --- a/unittests/datapoollocal/CMakeLists.txt +++ b/unittests/datapoollocal/CMakeLists.txt @@ -1,6 +1,3 @@ -target_sources(${FSFW_TEST_TGT} PRIVATE - testLocalPoolVariable.cpp - testLocalPoolVector.cpp - testDataSet.cpp - testLocalPoolManager.cpp -) +target_sources( + ${FSFW_TEST_TGT} PRIVATE testLocalPoolVariable.cpp testLocalPoolVector.cpp + testDataSet.cpp testLocalPoolManager.cpp) diff --git a/unittests/devicehandler/CMakeLists.txt b/unittests/devicehandler/CMakeLists.txt index 5d4d9b06..068e0dd4 100644 --- a/unittests/devicehandler/CMakeLists.txt +++ b/unittests/devicehandler/CMakeLists.txt @@ -1,4 +1,2 @@ -target_sources(${FSFW_TEST_TGT} PRIVATE - DeviceHandlerCommander.cpp - TestDeviceHandlerBase.cpp -) +target_sources(${FSFW_TEST_TGT} PRIVATE DeviceHandlerCommander.cpp + TestDeviceHandlerBase.cpp) diff --git a/unittests/globalfunctions/CMakeLists.txt b/unittests/globalfunctions/CMakeLists.txt index 348b99fc..ee94ca77 100644 --- a/unittests/globalfunctions/CMakeLists.txt +++ b/unittests/globalfunctions/CMakeLists.txt @@ -1,7 +1,3 @@ -target_sources(${FSFW_TEST_TGT} PRIVATE - testDleEncoder.cpp - testOpDivider.cpp - testBitutil.cpp - testCRC.cpp - testTimevalOperations.cpp -) +target_sources( + ${FSFW_TEST_TGT} PRIVATE testDleEncoder.cpp testOpDivider.cpp testBitutil.cpp + testCRC.cpp testTimevalOperations.cpp) diff --git a/unittests/hal/CMakeLists.txt b/unittests/hal/CMakeLists.txt index ee14a3aa..5d1c7846 100644 --- a/unittests/hal/CMakeLists.txt +++ b/unittests/hal/CMakeLists.txt @@ -1,3 +1,2 @@ -target_sources(${FSFW_TEST_TGT} PRIVATE - testCommandExecutor.cpp -) +target_sources(${FSFW_TEST_TGT} PRIVATE testCommandExecutor.cpp + testHostFilesystem.cpp testFsMock.cpp) diff --git a/unittests/hal/testCommandExecutor.cpp b/unittests/hal/testCommandExecutor.cpp index aecadd1b..f66da7a9 100644 --- a/unittests/hal/testCommandExecutor.cpp +++ b/unittests/hal/testCommandExecutor.cpp @@ -15,7 +15,7 @@ static const char TEST_FILE_NAME[] = "/tmp/fsfw-unittest-test.txt"; -TEST_CASE("Command Executor", "[cmd-exec]") { +TEST_CASE("Command Executor", "[hal][linux]") { // Check blocking mode first CommandExecutor cmdExecutor(1024); std::string cmd = "echo \"test\" >> " + std::string(TEST_FILE_NAME); diff --git a/unittests/hal/testFsMock.cpp b/unittests/hal/testFsMock.cpp new file mode 100644 index 00000000..2ebcd231 --- /dev/null +++ b/unittests/hal/testFsMock.cpp @@ -0,0 +1,49 @@ +#include + +#include "fsfw/serialize/SerializeIF.h" +#include "mocks/FilesystemMock.h" + +using namespace std; + +TEST_CASE("Filesystem Mock", "[mocks]") { + auto fsMock = FilesystemMock(); + + SECTION("Create File") { + FilesystemParams params("hello.txt"); + CHECK(fsMock.createFile(params) == returnvalue::OK); + auto iter = fsMock.fileMap.find("hello.txt"); + REQUIRE(iter != fsMock.fileMap.end()); + FilesystemMock::FileInfo &stats = iter->second; + CHECK(stats.fileSegQueue.empty()); + CHECK(stats.fileRaw.empty()); + } + + SECTION("Write to File") { + std::string testData = "test data"; + FileOpParams params("hello.txt", testData.size()); + CHECK(fsMock.writeToFile(params, reinterpret_cast(testData.data())) == + returnvalue::OK); + auto iter = fsMock.fileMap.find("hello.txt"); + REQUIRE(iter != fsMock.fileMap.end()); + FilesystemMock::FileInfo &stats = iter->second; + CHECK(not stats.fileSegQueue.empty()); + CHECK(not stats.fileRaw.empty()); + auto &segment = stats.fileSegQueue.back(); + CHECK(segment.offset == 0); + CHECK(std::string(reinterpret_cast(segment.data.data()), segment.data.size()) == + testData); + CHECK(std::string(reinterpret_cast(stats.fileRaw.data()), segment.data.size()) == + testData); + } + + SECTION("Create Directory") { + FilesystemParams params("hello"); + CHECK(fsMock.createDirectory(params) == returnvalue::OK); + REQUIRE(not fsMock.dirMap.empty()); + auto iter = fsMock.dirMap.find("hello"); + REQUIRE(iter != fsMock.dirMap.end()); + auto &dirInfo = iter->second; + CHECK(dirInfo.createCallCount == 1); + CHECK(dirInfo.delCallCount == 0); + } +} \ No newline at end of file diff --git a/unittests/hal/testHostFilesystem.cpp b/unittests/hal/testHostFilesystem.cpp new file mode 100644 index 00000000..e33b30cc --- /dev/null +++ b/unittests/hal/testHostFilesystem.cpp @@ -0,0 +1,228 @@ +#include + +#include +#include +#include +#include + +#include "fsfw/serialize/SerializeIF.h" +#include "fsfw_hal/host/HostFilesystem.h" + +using namespace std; + +TEST_CASE("Host Filesystem", "[hal][host]") { + namespace fs = filesystem; + auto hostFs = HostFilesystem(); + auto tmpDir = fs::temp_directory_path(); + fs::path file0 = tmpDir / "hello.txt"; + fs::path file1 = tmpDir / "hello2.txt"; + fs::path dir0 = tmpDir / "test_dir"; + fs::path fileInDir0 = dir0 / "hello.txt"; + fs::path dirWithParent = dir0 / "test_dir"; + + REQUIRE_NOTHROW(fs::remove(file0)); + REQUIRE_NOTHROW(fs::remove(file1)); + REQUIRE_NOTHROW(fs::remove_all(dir0)); + + SECTION("Create file") { + FilesystemParams params(file0.c_str()); + REQUIRE(hostFs.createFile(params) == returnvalue::OK); + CHECK(fs::is_regular_file(file0)); + REQUIRE(fs::exists(file0)); + } + + SECTION("Remove File") { + FilesystemParams params(file0.c_str()); + REQUIRE(hostFs.createFile(params) == returnvalue::OK); + CHECK(fs::is_regular_file(file0)); + REQUIRE(fs::exists(file0)); + REQUIRE(hostFs.removeFile(file0.c_str()) == returnvalue::OK); + REQUIRE(not fs::exists(file0)); + } + + SECTION("Create Directory") { + FilesystemParams params(dir0.c_str()); + REQUIRE(hostFs.createDirectory(params) == returnvalue::OK); + CHECK(fs::is_directory(dir0)); + REQUIRE(fs::exists(dir0)); + } + + SECTION("Remove Directory") { + FilesystemParams params(dir0.c_str()); + REQUIRE(hostFs.createDirectory(params) == returnvalue::OK); + REQUIRE(fs::exists(dir0)); + REQUIRE(hostFs.removeDirectory(params) == returnvalue::OK); + REQUIRE(not fs::exists(dir0)); + } + + SECTION("Rename File") { + FilesystemParams params(file0.c_str()); + REQUIRE(hostFs.createFile(params) == returnvalue::OK); + CHECK(fs::is_regular_file(file0)); + REQUIRE(fs::exists(file0)); + REQUIRE(hostFs.rename(file0.c_str(), file1.c_str()) == returnvalue::OK); + } + + SECTION("Write To File") { + std::string data = "hello world!"; + FileOpParams params(file0.c_str(), data.size()); + REQUIRE(hostFs.createFile(params.fsParams) == returnvalue::OK); + CHECK(fs::is_regular_file(file0)); + REQUIRE(fs::exists(file0)); + CHECK(hostFs.writeToFile(params, reinterpret_cast(data.c_str())) == + returnvalue::OK); + CHECK(fs::file_size(file0) == data.size()); + ifstream ifile(file0); + std::array readBuf{}; + ifile.read(readBuf.data(), sizeof(readBuf)); + std::string readBackString(readBuf.data()); + CHECK(data == readBackString); + } + + SECTION("Write To File, Check Not Truncated") { + std::random_device dev; + std::mt19937 rng(dev()); + std::uniform_int_distribution distU8(1, 255); + std::array randData{}; + for (uint8_t& byte : randData) { + byte = distU8(rng); + } + FileOpParams params(file0.c_str(), randData.size() - 256); + REQUIRE(hostFs.createFile(params.fsParams) == returnvalue::OK); + CHECK(fs::is_regular_file(file0)); + REQUIRE(fs::exists(file0)); + // Write first file chunk + CHECK(hostFs.writeToFile(params, randData.cbegin()) == returnvalue::OK); + params.offset = 256; + CHECK(hostFs.writeToFile(params, randData.cbegin() + 256) == returnvalue::OK); + std::ifstream rf(file0, ios::binary); + std::array readBack{}; + REQUIRE(std::filesystem::file_size(file0) == 512); + rf.read(reinterpret_cast(readBack.data()), readBack.size()); + for (size_t i = 0; i < 512; i++) { + CHECK(randData[i] == readBack[i]); + } + } + + SECTION("Read From File") { + std::string data = "hello world!"; + FileOpParams params(file0.c_str(), data.size()); + REQUIRE(hostFs.createFile(params.fsParams) == returnvalue::OK); + CHECK(fs::is_regular_file(file0)); + ofstream of(file0); + of.write(data.c_str(), static_cast(data.size())); + of.close(); + CHECK(fs::file_size(file0) == data.size()); + REQUIRE(fs::exists(file0)); + std::array readBuf{}; + uint8_t* readPtr = readBuf.data(); + size_t readSize = 0; + CHECK(hostFs.readFromFile(params, &readPtr, readSize, readBuf.size()) == returnvalue::OK); + std::string readBackString(reinterpret_cast(readBuf.data())); + CHECK(readSize == data.size()); + CHECK(data == readBackString); + } + + SECTION("Invalid Input does not crash") { + FileOpParams params(nullptr, 10); + REQUIRE(hostFs.createFile(params.fsParams) != returnvalue::OK); + REQUIRE(hostFs.createDirectory(params.fsParams) != returnvalue::OK); + REQUIRE(hostFs.createFile(params.fsParams) != returnvalue::OK); + REQUIRE(hostFs.removeDirectory(params.fsParams) != returnvalue::OK); + REQUIRE(hostFs.removeFile(nullptr) != returnvalue::OK); + REQUIRE(hostFs.rename(nullptr, nullptr) != returnvalue::OK); + REQUIRE(hostFs.writeToFile(params, nullptr) != returnvalue::OK); + size_t readLen = 0; + REQUIRE(hostFs.readFromFile(params, nullptr, readLen, 20) != returnvalue::OK); + } + + SECTION("Create File but already exists") { + FilesystemParams params(file0.c_str()); + REQUIRE(hostFs.createFile(params) == returnvalue::OK); + REQUIRE(hostFs.createFile(params) == HasFileSystemIF::FILE_ALREADY_EXISTS); + } + + SECTION("Remove File but does not exist") { + REQUIRE(hostFs.removeFile(file0.c_str()) == HasFileSystemIF::FILE_DOES_NOT_EXIST); + } + + SECTION("Create Directory but already exists") { + FileOpParams params(file0.c_str(), 12); + REQUIRE(hostFs.createDirectory(params.fsParams) == returnvalue::OK); + REQUIRE(hostFs.createDirectory(params.fsParams) == HasFileSystemIF::DIRECTORY_ALREADY_EXISTS); + } + + SECTION("Remove Directory but does not exist") { + FilesystemParams params(dir0.c_str()); + REQUIRE(hostFs.removeDirectory(params) == HasFileSystemIF::DIRECTORY_DOES_NOT_EXIST); + } + + SECTION("Remove Directory but is file") { + ofstream of(file0); + FilesystemParams params(file0.c_str()); + REQUIRE(hostFs.removeDirectory(params) == HasFileSystemIF::NOT_A_DIRECTORY); + } + + SECTION("Read from file but does not exist") { + std::string data = "hello world!"; + FileOpParams params(file0.c_str(), data.size()); + std::array readBuf{}; + uint8_t* readPtr = readBuf.data(); + size_t readSize = 0; + CHECK(hostFs.readFromFile(params, &readPtr, readSize, readBuf.size()) == + HasFileSystemIF::FILE_DOES_NOT_EXIST); + } + + SECTION("Write to file but does not exist") { + std::string data = "hello world!"; + FileOpParams params(file0.c_str(), data.size()); + CHECK(hostFs.writeToFile(params, reinterpret_cast(data.c_str())) == + HasFileSystemIF::FILE_DOES_NOT_EXIST); + } + + SECTION("Remove recursively") { + fs::create_directory(dir0.c_str()); + ofstream of(fileInDir0); + CHECK(fs::is_directory(dir0)); + CHECK(fs::is_regular_file(fileInDir0)); + REQUIRE(hostFs.removeDirectory(FilesystemParams(dir0.c_str()), true) == returnvalue::OK); + CHECK(not fs::is_directory(dir0)); + CHECK(not fs::is_regular_file(fileInDir0)); + } + + SECTION("Non-Recursive Removal Fails") { + fs::create_directory(dir0.c_str()); + ofstream of(fileInDir0); + CHECK(fs::is_directory(dir0)); + CHECK(fs::is_regular_file(fileInDir0)); + REQUIRE(hostFs.removeDirectory(FilesystemParams(dir0.c_str())) == + HasFileSystemIF::DIRECTORY_NOT_EMPTY); + } + + SECTION("Create directory with parent directory") { + CHECK(hostFs.createDirectory(FilesystemParams(dirWithParent.c_str()), true) == returnvalue::OK); + CHECK(fs::is_directory(dir0)); + CHECK(fs::is_directory(dirWithParent)); + } + + SECTION("Read but provided buffer too small") { + std::string data = "hello world!"; + FileOpParams params(file0.c_str(), data.size()); + ofstream of(file0); + of.write(data.c_str(), static_cast(data.size())); + of.close(); + CHECK(fs::file_size(file0) == data.size()); + REQUIRE(fs::exists(file0)); + std::array readBuf{}; + uint8_t* readPtr = readBuf.data(); + size_t readSize = 0; + CHECK(hostFs.readFromFile(params, &readPtr, readSize, 5) == SerializeIF::BUFFER_TOO_SHORT); + readSize = 10; + CHECK(hostFs.readFromFile(params, &readPtr, readSize, readBuf.size()) == + SerializeIF::BUFFER_TOO_SHORT); + } + + REQUIRE_NOTHROW(fs::remove(file0)); + REQUIRE_NOTHROW(fs::remove(file1)); + REQUIRE_NOTHROW(fs::remove_all(dir0)); +} \ No newline at end of file diff --git a/unittests/internalerror/CMakeLists.txt b/unittests/internalerror/CMakeLists.txt index d49ce006..c02cbafc 100644 --- a/unittests/internalerror/CMakeLists.txt +++ b/unittests/internalerror/CMakeLists.txt @@ -1,3 +1 @@ -target_sources(${FSFW_TEST_TGT} PRIVATE - TestInternalErrorReporter.cpp -) +target_sources(${FSFW_TEST_TGT} PRIVATE TestInternalErrorReporter.cpp) diff --git a/unittests/mocks/AcceptsTcMock.cpp b/unittests/mocks/AcceptsTcMock.cpp new file mode 100644 index 00000000..a9afafd9 --- /dev/null +++ b/unittests/mocks/AcceptsTcMock.cpp @@ -0,0 +1,8 @@ +#include "AcceptsTcMock.h" + +AcceptsTcMock::AcceptsTcMock(const char* name, uint32_t id, MessageQueueId_t queueId) + : name(name), id(id), queueId(queueId) {} + +const char* AcceptsTcMock::getName() const { return name; } +uint32_t AcceptsTcMock::getIdentifier() const { return id; } +MessageQueueId_t AcceptsTcMock::getRequestQueue() const { return queueId; } diff --git a/unittests/mocks/AcceptsTcMock.h b/unittests/mocks/AcceptsTcMock.h new file mode 100644 index 00000000..028b68cd --- /dev/null +++ b/unittests/mocks/AcceptsTcMock.h @@ -0,0 +1,20 @@ +#ifndef FSFW_TESTS_ACCEPTSTCMOCK_H +#define FSFW_TESTS_ACCEPTSTCMOCK_H + +#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h" + +class AcceptsTcMock : public AcceptsTelecommandsIF { + public: + AcceptsTcMock(const char* name, uint32_t id, MessageQueueId_t queueId); + [[nodiscard]] const char* getName() const override; + [[nodiscard]] uint32_t getIdentifier() const override; + [[nodiscard]] MessageQueueId_t getRequestQueue() const override; + + const char* name; + uint32_t id; + MessageQueueId_t queueId; + + private: +}; + +#endif // FSFW_TESTS_ACCEPTSTCMOCK_H diff --git a/unittests/mocks/AcceptsTmMock.cpp b/unittests/mocks/AcceptsTmMock.cpp index 5b1e0d05..7b997047 100644 --- a/unittests/mocks/AcceptsTmMock.cpp +++ b/unittests/mocks/AcceptsTmMock.cpp @@ -9,3 +9,5 @@ AcceptsTmMock::AcceptsTmMock(MessageQueueId_t queueToReturn) MessageQueueId_t AcceptsTmMock::getReportReceptionQueue(uint8_t virtualChannel) { return returnedQueue; } + +const char* AcceptsTmMock::getName() const { return "TM Acceptor Mock"; } diff --git a/unittests/mocks/AcceptsTmMock.h b/unittests/mocks/AcceptsTmMock.h index a9422eb4..d6cc7f85 100644 --- a/unittests/mocks/AcceptsTmMock.h +++ b/unittests/mocks/AcceptsTmMock.h @@ -10,6 +10,7 @@ class AcceptsTmMock : public SystemObject, public AcceptsTelemetryIF { explicit AcceptsTmMock(MessageQueueId_t queueToReturn); MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel) override; + const char* getName() const override; MessageQueueId_t returnedQueue; }; diff --git a/unittests/mocks/CMakeLists.txt b/unittests/mocks/CMakeLists.txt index f3b50f62..bd093da8 100644 --- a/unittests/mocks/CMakeLists.txt +++ b/unittests/mocks/CMakeLists.txt @@ -1,14 +1,21 @@ -target_sources(${FSFW_TEST_TGT} PRIVATE - PowerSwitcherMock.cpp - DeviceHandlerMock.cpp - DeviceFdirMock.cpp - CookieIFMock.cpp - ComIFMock.cpp - MessageQueueMock.cpp - InternalErrorReporterMock.cpp - LocalPoolOwnerBase.cpp - PusVerificationReporterMock.cpp - PusServiceBaseMock.cpp - AcceptsTmMock.cpp - PusDistributorMock.cpp -) +target_sources( + ${FSFW_TEST_TGT} + PRIVATE PowerSwitcherMock.cpp + DeviceHandlerMock.cpp + DeviceFdirMock.cpp + CookieIFMock.cpp + ComIFMock.cpp + MessageQueueMock.cpp + InternalErrorReporterMock.cpp + LocalPoolOwnerBase.cpp + PusVerificationReporterMock.cpp + PusServiceBaseMock.cpp + AcceptsTmMock.cpp + PusDistributorMock.cpp + CcsdsCheckerMock.cpp + AcceptsTcMock.cpp + StorageManagerMock.cpp + FilesystemMock.cpp + EventReportingProxyMock.cpp) + +add_subdirectory(cfdp) diff --git a/unittests/mocks/CcsdsCheckerMock.cpp b/unittests/mocks/CcsdsCheckerMock.cpp new file mode 100644 index 00000000..18c5fb4e --- /dev/null +++ b/unittests/mocks/CcsdsCheckerMock.cpp @@ -0,0 +1,10 @@ +#include "CcsdsCheckerMock.h" + +CcsdsCheckerMock::CcsdsCheckerMock() = default; + +ReturnValue_t CcsdsCheckerMock::checkPacket(const SpacePacketReader& currentPacket, + size_t packetLen) { + checkCallCount++; + checkedPacketLen = packetLen; + return nextResult; +} diff --git a/unittests/mocks/CcsdsCheckerMock.h b/unittests/mocks/CcsdsCheckerMock.h new file mode 100644 index 00000000..bdcd491a --- /dev/null +++ b/unittests/mocks/CcsdsCheckerMock.h @@ -0,0 +1,16 @@ +#ifndef FSFW_TESTS_CCSDSCHECKERMOCK_H +#define FSFW_TESTS_CCSDSCHECKERMOCK_H + +#include "fsfw/tcdistribution/CcsdsPacketCheckIF.h" +class CcsdsCheckerMock : public CcsdsPacketCheckIF { + public: + CcsdsCheckerMock(); + unsigned int checkCallCount = 0; + size_t checkedPacketLen = 0; + ReturnValue_t nextResult = returnvalue::OK; + ReturnValue_t checkPacket(const SpacePacketReader& currentPacket, size_t packetLen) override; + + private: +}; + +#endif // FSFW_TESTS_CCSDSCHECKERMOCK_H diff --git a/unittests/mocks/EventReportingProxyMock.cpp b/unittests/mocks/EventReportingProxyMock.cpp new file mode 100644 index 00000000..cb4f6d93 --- /dev/null +++ b/unittests/mocks/EventReportingProxyMock.cpp @@ -0,0 +1,6 @@ +#include "EventReportingProxyMock.h" + +void EventReportingProxyMock::forwardEvent(Event event, uint32_t parameter1, + uint32_t parameter2) const { + eventQueue.emplace(event, parameter1, parameter2); +} diff --git a/unittests/mocks/EventReportingProxyMock.h b/unittests/mocks/EventReportingProxyMock.h new file mode 100644 index 00000000..c04942c3 --- /dev/null +++ b/unittests/mocks/EventReportingProxyMock.h @@ -0,0 +1,21 @@ +#ifndef FSFW_TESTS_EVENTREPORTPROXYMOCK_H +#define FSFW_TESTS_EVENTREPORTPROXYMOCK_H + +#include + +#include "fsfw/events/EventReportingProxyIF.h" + +class EventReportingProxyMock : public EventReportingProxyIF { + public: + void forwardEvent(Event event, uint32_t parameter1, uint32_t parameter2) const override; + + struct EventInfo { + EventInfo(Event event, uint32_t p1, uint32_t p2) : event(event), p1(p1), p2(p2) {} + + Event event; + uint32_t p1; + uint32_t p2; + }; + mutable std::queue eventQueue; +}; +#endif // FSFW_TESTS_EVENTREPORTPROXYMOCK_H diff --git a/unittests/mocks/FilesystemMock.cpp b/unittests/mocks/FilesystemMock.cpp new file mode 100644 index 00000000..bf0c3bf6 --- /dev/null +++ b/unittests/mocks/FilesystemMock.cpp @@ -0,0 +1,140 @@ +#include "FilesystemMock.h" + +#include + +#include "fsfw/serialize/SerializeIF.h" + +ReturnValue_t FilesystemMock::feedFile(const std::string &filename, std::ifstream &file) { + if (not std::filesystem::exists(filename)) { + return returnvalue::FAILED; + } + size_t fileSize = std::filesystem::file_size(filename); + FileOpParams params(filename.c_str(), fileSize); + std::vector rawData(fileSize); + file.read(reinterpret_cast(rawData.data()), static_cast(rawData.size())); + createOrAddToFile(params, rawData.data()); + return returnvalue::OK; +} + +ReturnValue_t FilesystemMock::writeToFile(FileOpParams params, const uint8_t *data) { + createOrAddToFile(params, data); + return returnvalue::OK; +} + +ReturnValue_t FilesystemMock::readFromFile(FileOpParams params, uint8_t **buffer, size_t &readSize, + size_t maxSize) { + std::string filename(params.path()); + auto iter = fileMap.find(filename); + if (iter == fileMap.end()) { + return HasFileSystemIF::FILE_DOES_NOT_EXIST; + } else { + FileInfo &info = iter->second; + size_t readLen = params.size; + if (params.offset + params.size > info.fileRaw.size()) { + if (params.offset > info.fileRaw.size()) { + return returnvalue::OK; + } + readLen = info.fileRaw.size() - params.offset; + } + if (readSize + readLen > maxSize) { + return SerializeIF::STREAM_TOO_SHORT; + } + std::copy(info.fileRaw.data() + params.offset, info.fileRaw.data() + readLen, *buffer); + *buffer += readLen; + readSize += readLen; + } + return returnvalue::OK; +} + +ReturnValue_t FilesystemMock::createFile(FilesystemParams params, const uint8_t *data, + size_t size) { + FileOpParams params2(params.path, size); + createOrAddToFile(params2, data); + return returnvalue::OK; +} + +ReturnValue_t FilesystemMock::removeFile(const char *path, FileSystemArgsIF *args) { + std::string filename(path); + auto iter = fileMap.find(filename); + if (iter == fileMap.end()) { + return HasFileSystemIF::FILE_DOES_NOT_EXIST; + } else { + fileMap.erase(iter); + return returnvalue::OK; + } +} + +ReturnValue_t FilesystemMock::createDirectory(FilesystemParams params, bool createParentDirs) { + std::string dirPath = params.path; + dirMap[dirPath].createCallCount++; + dirMap[dirPath].wihParentDir.push(createParentDirs); + return returnvalue::OK; +} + +ReturnValue_t FilesystemMock::removeDirectory(FilesystemParams params, bool deleteRecurively) { + std::string dirPath = params.path; + dirMap[dirPath].delCallCount++; + dirMap[dirPath].recursiveDeletion.push(deleteRecurively); + return returnvalue::OK; +} + +ReturnValue_t FilesystemMock::rename(const char *oldPath, const char *newPath, + FileSystemArgsIF *args) { + renameQueue.push(RenameInfo(oldPath, newPath)); + return returnvalue::OK; +} + +void FilesystemMock::createOrAddToFile(FileOpParams params, const uint8_t *data) { + std::string filename(params.path()); + auto iter = fileMap.find(filename); + if (iter == fileMap.end()) { + FileSegmentQueue queue; + if (params.size > 0) { + queue.push(FileWriteInfo(filename, params.offset, data, params.size)); + } + FileInfo info; + info.fileSegQueue = queue; + if (data != nullptr) { + info.fileRaw.insert(info.fileRaw.end(), data, data + params.size); + } + fileMap.emplace(filename, info); + } else { + FileInfo &info = iter->second; + info.fileSegQueue.push(FileWriteInfo(filename, params.offset, data, params.size)); + if (data == nullptr) { + return; + } + // Easiest case: append data to the end + if (params.offset == info.fileRaw.size()) { + info.fileRaw.insert(info.fileRaw.end(), data, data + params.size); + } else { + size_t totalNewLen = params.offset + params.size; + if (totalNewLen > info.fileRaw.size()) { + info.fileRaw.resize(params.offset + params.size); + } + std::copy(data, data + params.size, + info.fileRaw.begin() + static_cast(params.offset)); + } + } +} + +void FilesystemMock::reset() { + fileMap.clear(); + dirMap.clear(); + std::queue empty; + std::swap(renameQueue, empty); +} + +bool FilesystemMock::fileExists(FilesystemParams params) { + std::string filename(params.path); + auto iter = fileMap.find(filename); + if (iter == fileMap.end()) { + return false; + } + return true; +} + +ReturnValue_t FilesystemMock::truncateFile(FilesystemParams params) { + truncateCalledOnFile = params.path; + return returnvalue::OK; +} diff --git a/unittests/mocks/FilesystemMock.h b/unittests/mocks/FilesystemMock.h new file mode 100644 index 00000000..74221d70 --- /dev/null +++ b/unittests/mocks/FilesystemMock.h @@ -0,0 +1,81 @@ +#ifndef FSFW_MOCKS_FILESYSTEMMOCK_H +#define FSFW_MOCKS_FILESYSTEMMOCK_H + +#include +#include +#include +#include +#include + +#include "fsfw/filesystem.h" + +/** + * This mock models a filesystem in the RAM. It can be used to verify correct behaviour of + * a component using a filesystem without relying on an actual OS filesystem implementation. + * + * Please note that this object does not actually check paths for validity. The file API was + * built in a way to allow reading a file back after it was written while also remembering + * the specific file segments which were inserted in write calls. + */ +class FilesystemMock : public HasFileSystemIF { + public: + struct FileWriteInfo { + FileWriteInfo(std::string filename, size_t offset, const uint8_t *data, size_t len) + : filename(std::move(filename)), offset(offset) { + this->data.insert(this->data.end(), data, data + len); + } + std::string filename; + size_t offset; + std::vector data; + }; + using FileSegmentQueue = std::queue; + + struct FileInfo { + FileSegmentQueue fileSegQueue; + std::vector fileRaw; + }; + + std::map fileMap; + + struct DirInfo { + size_t createCallCount = 0; + size_t delCallCount = 0; + std::queue wihParentDir; + std::queue recursiveDeletion; + }; + std::map dirMap; + + struct RenameInfo { + RenameInfo(std::string oldName, std::string newName) + : oldName(std::move(oldName)), newName(std::move(newName)) {} + + std::string oldName; + std::string newName; + }; + std::queue renameQueue; + std::string truncateCalledOnFile; + ReturnValue_t feedFile(const std::string &filename, std::ifstream &file); + + bool fileExists(FilesystemParams params) override; + ReturnValue_t truncateFile(FilesystemParams params) override; + + ReturnValue_t writeToFile(FileOpParams params, const uint8_t *data) override; + ReturnValue_t readFromFile(FileOpParams params, uint8_t **buffer, size_t &readSize, + size_t maxSize) override; + ReturnValue_t createFile(FilesystemParams params, const uint8_t *data, size_t size) override; + ReturnValue_t removeFile(const char *path, FileSystemArgsIF *args) override; + ReturnValue_t createDirectory(FilesystemParams params, bool createParentDirs) override; + ReturnValue_t removeDirectory(FilesystemParams params, bool deleteRecurively) override; + ReturnValue_t rename(const char *oldPath, const char *newPath, FileSystemArgsIF *args) override; + + void reset(); + + using HasFileSystemIF::createDirectory; + using HasFileSystemIF::createFile; + using HasFileSystemIF::readFromFile; + + private: + void createOrAddToFile(FileOpParams params, const uint8_t *data); +}; + +#endif // FSFW_MOCKS_FILESYSTEMMOCK_H diff --git a/unittests/mocks/PusDistributorMock.cpp b/unittests/mocks/PusDistributorMock.cpp index 625dffc5..aed45ce4 100644 --- a/unittests/mocks/PusDistributorMock.cpp +++ b/unittests/mocks/PusDistributorMock.cpp @@ -5,8 +5,8 @@ PusDistributorMock::PusDistributorMock() : SystemObject(objects::NO_OBJECT, fals PusDistributorMock::PusDistributorMock(object_id_t registeredId) : SystemObject(registeredId, true) {} -ReturnValue_t PusDistributorMock::registerService(AcceptsTelecommandsIF *service) { +ReturnValue_t PusDistributorMock::registerService(const AcceptsTelecommandsIF& service) { registerCallCount++; - lastServiceArg = service; + registeredServies.push_back(&service); return returnvalue::OK; } diff --git a/unittests/mocks/PusDistributorMock.h b/unittests/mocks/PusDistributorMock.h index d5c7d96f..417ae448 100644 --- a/unittests/mocks/PusDistributorMock.h +++ b/unittests/mocks/PusDistributorMock.h @@ -1,16 +1,18 @@ #ifndef FSFW_TESTS_PUSDISTRIBUTORMOCK_H #define FSFW_TESTS_PUSDISTRIBUTORMOCK_H -#include "fsfw/objectmanager/SystemObject.h" -#include "fsfw/tcdistribution/PUSDistributorIF.h" +#include -class PusDistributorMock : public SystemObject, public PUSDistributorIF { +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/tcdistribution/PusDistributorIF.h" + +class PusDistributorMock : public SystemObject, public PusDistributorIF { public: PusDistributorMock(); explicit PusDistributorMock(object_id_t registeredId); unsigned int registerCallCount = 0; - AcceptsTelecommandsIF* lastServiceArg = nullptr; - ReturnValue_t registerService(AcceptsTelecommandsIF* service) override; + std::vector registeredServies; + ReturnValue_t registerService(const AcceptsTelecommandsIF& service) override; }; #endif // FSFW_TESTS_PUSDISTRIBUTORMOCK_H diff --git a/unittests/mocks/StorageManagerMock.cpp b/unittests/mocks/StorageManagerMock.cpp new file mode 100644 index 00000000..5cd3a575 --- /dev/null +++ b/unittests/mocks/StorageManagerMock.cpp @@ -0,0 +1,81 @@ +#include "StorageManagerMock.h" + +ReturnValue_t StorageManagerMock::addData(store_address_t *storageId, const uint8_t *data, + size_t size, bool ignoreFault) { + if (nextAddDataCallFails.first) { + return nextAddDataCallFails.second; + } + return LocalPool::addData(storageId, data, size, ignoreFault); +} +ReturnValue_t StorageManagerMock::deleteData(store_address_t packet_id) { + if (nextDeleteDataCallFails.first) { + return nextDeleteDataCallFails.second; + } + return LocalPool::deleteData(packet_id); +} + +ReturnValue_t StorageManagerMock::deleteData(uint8_t *buffer, size_t size, + store_address_t *storeId) { + if (nextDeleteDataCallFails.first) { + return nextDeleteDataCallFails.second; + } + return LocalPool::deleteData(buffer, size, storeId); +} + +ReturnValue_t StorageManagerMock::getData(store_address_t packet_id, const uint8_t **packet_ptr, + size_t *size) { + return LocalPool::getData(packet_id, packet_ptr, size); +} + +ReturnValue_t StorageManagerMock::modifyData(store_address_t packet_id, uint8_t **packet_ptr, + size_t *size) { + if (nextModifyDataCallFails.first) { + return nextModifyDataCallFails.second; + } + return LocalPool::modifyData(packet_id, packet_ptr, size); +} + +ReturnValue_t StorageManagerMock::getFreeElement(store_address_t *storageId, size_t size, + uint8_t **p_data, bool ignoreFault) { + if (nextFreeElementCallFails.first) { + return nextFreeElementCallFails.second; + } + return LocalPool::getFreeElement(storageId, size, p_data, ignoreFault); +} + +bool StorageManagerMock::hasDataAtId(store_address_t storeId) const { + return LocalPool::hasDataAtId(storeId); +} +void StorageManagerMock::clearStore() { return LocalPool::clearStore(); } + +void StorageManagerMock::clearSubPool(uint8_t poolIndex) { + return LocalPool::clearSubPool(poolIndex); +} + +void StorageManagerMock::getFillCount(uint8_t *buffer, uint8_t *bytesWritten) { + return LocalPool::getFillCount(buffer, bytesWritten); +} + +size_t StorageManagerMock::getTotalSize(size_t *additionalSize) { + return LocalPool::getTotalSize(additionalSize); +} + +StorageManagerIF::max_subpools_t StorageManagerMock::getNumberOfSubPools() const { + return LocalPool::getNumberOfSubPools(); +} + +void StorageManagerMock::reset() { + clearStore(); + nextAddDataCallFails.first = false; + nextAddDataCallFails.second = returnvalue::OK; + nextModifyDataCallFails.first = false; + nextModifyDataCallFails.second = returnvalue::OK; + nextDeleteDataCallFails.first = false; + nextDeleteDataCallFails.second = returnvalue::OK; + nextFreeElementCallFails.first = false; + nextFreeElementCallFails.second = returnvalue::OK; +} + +StorageManagerMock::StorageManagerMock(object_id_t setObjectId, + const LocalPool::LocalPoolConfig &poolConfig) + : LocalPool(setObjectId, poolConfig) {} diff --git a/unittests/mocks/StorageManagerMock.h b/unittests/mocks/StorageManagerMock.h new file mode 100644 index 00000000..a52e46db --- /dev/null +++ b/unittests/mocks/StorageManagerMock.h @@ -0,0 +1,40 @@ +#ifndef FSFW_TESTS_STORAGEMANAGERMOCK_H +#define FSFW_TESTS_STORAGEMANAGERMOCK_H + +#include "fsfw/storagemanager/LocalPool.h" +#include "fsfw/storagemanager/StorageManagerIF.h" + +class StorageManagerMock : public LocalPool { + public: + StorageManagerMock(object_id_t setObjectId, const LocalPoolConfig &poolConfig); + + ReturnValue_t addData(store_address_t *storageId, const uint8_t *data, size_t size, + bool ignoreFault) override; + ReturnValue_t deleteData(store_address_t packet_id) override; + ReturnValue_t deleteData(uint8_t *buffer, size_t size, store_address_t *storeId) override; + ReturnValue_t getData(store_address_t packet_id, const uint8_t **packet_ptr, + size_t *size) override; + ReturnValue_t modifyData(store_address_t packet_id, uint8_t **packet_ptr, size_t *size) override; + ReturnValue_t getFreeElement(store_address_t *storageId, size_t size, uint8_t **p_data, + bool ignoreFault) override; + [[nodiscard]] bool hasDataAtId(store_address_t storeId) const override; + void clearStore() override; + void clearSubPool(uint8_t poolIndex) override; + void getFillCount(uint8_t *buffer, uint8_t *bytesWritten) override; + size_t getTotalSize(size_t *additionalSize) override; + [[nodiscard]] max_subpools_t getNumberOfSubPools() const override; + + std::pair nextAddDataCallFails; + /** + * This can be used to make both the modify and get API call fail. This is because generally, + * the pool implementation get functions will use the modify API internally. + */ + std::pair nextModifyDataCallFails; + std::pair nextDeleteDataCallFails; + std::pair nextFreeElementCallFails; + + using LocalPool::getFreeElement; + + void reset(); +}; +#endif // FSFW_TESTS_STORAGEMANAGERMOCK_H diff --git a/unittests/mocks/cfdp/CMakeLists.txt b/unittests/mocks/cfdp/CMakeLists.txt new file mode 100644 index 00000000..769e06ae --- /dev/null +++ b/unittests/mocks/cfdp/CMakeLists.txt @@ -0,0 +1,2 @@ +target_sources(${FSFW_TEST_TGT} PRIVATE FaultHandlerMock.cpp UserMock.cpp + RemoteConfigTableMock.cpp) diff --git a/unittests/mocks/cfdp/FaultHandlerMock.cpp b/unittests/mocks/cfdp/FaultHandlerMock.cpp new file mode 100644 index 00000000..03736f71 --- /dev/null +++ b/unittests/mocks/cfdp/FaultHandlerMock.cpp @@ -0,0 +1,42 @@ +#include "FaultHandlerMock.h" + +namespace cfdp { + +void FaultHandlerMock::noticeOfSuspensionCb(TransactionId& id, cfdp::ConditionCode code) { + auto& info = fhInfoMap.at(cfdp::FaultHandlerCode::NOTICE_OF_SUSPENSION); + info.callCount++; + info.condCodes.push(code); +} + +void FaultHandlerMock::noticeOfCancellationCb(TransactionId& id, cfdp::ConditionCode code) { + auto& info = fhInfoMap.at(cfdp::FaultHandlerCode::NOTICE_OF_CANCELLATION); + info.callCount++; + info.condCodes.push(code); +} + +void FaultHandlerMock::abandonCb(TransactionId& id, cfdp::ConditionCode code) { + auto& info = fhInfoMap.at(cfdp::FaultHandlerCode::ABANDON_TRANSACTION); + info.callCount++; + info.condCodes.push(code); +} + +void FaultHandlerMock::ignoreCb(TransactionId& id, cfdp::ConditionCode code) { + auto& info = fhInfoMap.at(cfdp::FaultHandlerCode::IGNORE_ERROR); + info.callCount++; + info.condCodes.push(code); +} + +FaultHandlerMock::FaultInfo& FaultHandlerMock::getFhInfo(cfdp::FaultHandlerCode fhCode) { + return fhInfoMap.at(fhCode); +} + +void FaultHandlerMock::reset() { fhInfoMap.clear(); } + +bool FaultHandlerMock::faultCbWasCalled() const { + return std::any_of(fhInfoMap.begin(), fhInfoMap.end(), + [](const std::pair& pair) { + return pair.second.callCount > 0; + }); +} + +} // namespace cfdp diff --git a/unittests/mocks/cfdp/FaultHandlerMock.h b/unittests/mocks/cfdp/FaultHandlerMock.h new file mode 100644 index 00000000..1c59485c --- /dev/null +++ b/unittests/mocks/cfdp/FaultHandlerMock.h @@ -0,0 +1,37 @@ +#ifndef FSFW_TESTS_FAULTHANDLERMOCK_H +#define FSFW_TESTS_FAULTHANDLERMOCK_H + +#include +#include + +#include "fsfw/cfdp/handler/FaultHandlerBase.h" + +namespace cfdp { + +class FaultHandlerMock : public FaultHandlerBase { + public: + struct FaultInfo { + size_t callCount = 0; + std::queue condCodes; + }; + + void noticeOfSuspensionCb(TransactionId& id, ConditionCode code) override; + void noticeOfCancellationCb(TransactionId& id, ConditionCode code) override; + void abandonCb(TransactionId& id,ConditionCode code) override; + void ignoreCb(TransactionId& id, ConditionCode code) override; + + FaultInfo& getFhInfo(FaultHandlerCode fhCode); + [[nodiscard]] bool faultCbWasCalled() const; + void reset(); + + private: + std::map fhInfoMap = { + std::pair{cfdp::FaultHandlerCode::IGNORE_ERROR, FaultInfo()}, + std::pair{cfdp::FaultHandlerCode::NOTICE_OF_CANCELLATION, FaultInfo()}, + std::pair{cfdp::FaultHandlerCode::NOTICE_OF_SUSPENSION, FaultInfo()}, + std::pair{cfdp::FaultHandlerCode::ABANDON_TRANSACTION, FaultInfo()}}; +}; + +} // namespace cfdp + +#endif // FSFW_TESTS_FAULTHANDLERMOCK_H diff --git a/unittests/mocks/cfdp/RemoteConfigTableMock.cpp b/unittests/mocks/cfdp/RemoteConfigTableMock.cpp new file mode 100644 index 00000000..9cb0b77c --- /dev/null +++ b/unittests/mocks/cfdp/RemoteConfigTableMock.cpp @@ -0,0 +1,15 @@ +#include "RemoteConfigTableMock.h" + +void cfdp::RemoteConfigTableMock::addRemoteConfig(const cfdp::RemoteEntityCfg& cfg) { + remoteCfgTable.emplace(cfg.remoteId, cfg); +} + +bool cfdp::RemoteConfigTableMock::getRemoteCfg(const cfdp::EntityId& remoteId, + cfdp::RemoteEntityCfg** cfg) { + auto iter = remoteCfgTable.find(remoteId); + if (iter == remoteCfgTable.end()) { + return false; + } + *cfg = &iter->second; + return true; +} diff --git a/unittests/mocks/cfdp/RemoteConfigTableMock.h b/unittests/mocks/cfdp/RemoteConfigTableMock.h new file mode 100644 index 00000000..70891836 --- /dev/null +++ b/unittests/mocks/cfdp/RemoteConfigTableMock.h @@ -0,0 +1,20 @@ +#ifndef FSFW_TESTS_CFDP_REMOTCONFIGTABLEMOCK_H +#define FSFW_TESTS_CFDP_REMOTCONFIGTABLEMOCK_H + +#include + +#include "fsfw/cfdp/handler/RemoteConfigTableIF.h" + +namespace cfdp { + +class RemoteConfigTableMock : public RemoteConfigTableIF { + public: + void addRemoteConfig(const RemoteEntityCfg& cfg); + bool getRemoteCfg(const cfdp::EntityId& remoteId, cfdp::RemoteEntityCfg** cfg) override; + + std::map remoteCfgTable; +}; + +} // namespace cfdp + +#endif // FSFW_TESTS_CFDP_REMOTCONFIGTABLEMOCK_H diff --git a/unittests/mocks/cfdp/UserMock.cpp b/unittests/mocks/cfdp/UserMock.cpp new file mode 100644 index 00000000..ca15a5e6 --- /dev/null +++ b/unittests/mocks/cfdp/UserMock.cpp @@ -0,0 +1,35 @@ +#include "UserMock.h" + +namespace cfdp { + +cfdp::UserMock::UserMock(HasFileSystemIF& vfs) : UserBase(vfs) {} + +void UserMock::transactionIndication(const TransactionId& id) {} +void UserMock::eofSentIndication(const TransactionId& id) {} +void UserMock::abandonedIndication(const TransactionId& id, cfdp::ConditionCode code, + uint64_t progress) {} + +void UserMock::eofRecvIndication(const TransactionId& id) { eofsRevd.push(id); } + +void UserMock::transactionFinishedIndication(const TransactionFinishedParams& finishedParams) { + finishedRecvd.push({finishedParams.id, finishedParams}); +} + +void UserMock::metadataRecvdIndication(const MetadataRecvdParams& params) { + metadataRecvd.push({params.id, params}); +} + +void UserMock::fileSegmentRecvdIndication(const FileSegmentRecvdParams& params) {} +void UserMock::reportIndication(const TransactionId& id, StatusReportIF& report) {} +void UserMock::suspendedIndication(const TransactionId& id, ConditionCode code) {} +void UserMock::resumedIndication(const TransactionId& id, size_t progress) {} +void UserMock::faultIndication(const TransactionId& id, cfdp::ConditionCode code, size_t progress) { +} + +void UserMock::reset() { + std::queue().swap(eofsRevd); + std::queue>().swap(metadataRecvd); + std::queue>().swap(finishedRecvd); +} + +} // namespace cfdp diff --git a/unittests/mocks/cfdp/UserMock.h b/unittests/mocks/cfdp/UserMock.h new file mode 100644 index 00000000..e2a4a483 --- /dev/null +++ b/unittests/mocks/cfdp/UserMock.h @@ -0,0 +1,34 @@ +#ifndef FSFW_TESTS_CFDP_USERMOCK_H +#define FSFW_TESTS_CFDP_USERMOCK_H + +#include + +#include "fsfw/cfdp/handler/UserBase.h" + +namespace cfdp { + +class UserMock : public UserBase { + public: + explicit UserMock(HasFileSystemIF& vfs); + + void transactionIndication(const TransactionId& id) override; + void eofSentIndication(const TransactionId& id) override; + void abandonedIndication(const TransactionId& id, ConditionCode code, size_t progress) override; + void eofRecvIndication(const TransactionId& id) override; + void transactionFinishedIndication(const TransactionFinishedParams& params) override; + void metadataRecvdIndication(const MetadataRecvdParams& params) override; + void fileSegmentRecvdIndication(const FileSegmentRecvdParams& params) override; + void reportIndication(const TransactionId& id, StatusReportIF& report) override; + void suspendedIndication(const TransactionId& id, ConditionCode code) override; + void resumedIndication(const TransactionId& id, size_t progress) override; + void faultIndication(const TransactionId& id, ConditionCode code, size_t progress) override; + + std::queue> metadataRecvd; + std::queue eofsRevd; + std::queue> finishedRecvd; + void reset(); +}; + +} // namespace cfdp + +#endif // FSFW_TESTS_CFDP_USERMOCK_H diff --git a/unittests/osal/CMakeLists.txt b/unittests/osal/CMakeLists.txt index 0c93eba1..90eea2c7 100644 --- a/unittests/osal/CMakeLists.txt +++ b/unittests/osal/CMakeLists.txt @@ -1,5 +1,2 @@ -target_sources(${FSFW_TEST_TGT} PRIVATE - testMq.cpp - TestSemaphore.cpp - TestClock.cpp -) +target_sources(${FSFW_TEST_TGT} PRIVATE testMq.cpp TestSemaphore.cpp + TestClock.cpp) diff --git a/unittests/power/CMakeLists.txt b/unittests/power/CMakeLists.txt index 667e6f51..78c33b42 100644 --- a/unittests/power/CMakeLists.txt +++ b/unittests/power/CMakeLists.txt @@ -1,3 +1 @@ -target_sources(${FSFW_TEST_TGT} PRIVATE - testPowerSwitcher.cpp -) +target_sources(${FSFW_TEST_TGT} PRIVATE testPowerSwitcher.cpp) diff --git a/unittests/pus/CMakeLists.txt b/unittests/pus/CMakeLists.txt index ecd7fb49..7f615a50 100644 --- a/unittests/pus/CMakeLists.txt +++ b/unittests/pus/CMakeLists.txt @@ -1,3 +1 @@ -target_sources(${FSFW_TEST_TGT} PRIVATE - testService11.cpp -) +target_sources(${FSFW_TEST_TGT} PRIVATE testService11.cpp) diff --git a/unittests/serialize/CMakeLists.txt b/unittests/serialize/CMakeLists.txt index be4301db..b42be1d5 100644 --- a/unittests/serialize/CMakeLists.txt +++ b/unittests/serialize/CMakeLists.txt @@ -1,6 +1,3 @@ -target_sources(${FSFW_TEST_TGT} PRIVATE - testSerialBufferAdapter.cpp - testSerializeAdapter.cpp - testSerialLinkedPacket.cpp - testSerializeIF.cpp -) +target_sources( + ${FSFW_TEST_TGT} PRIVATE testSerialBufferAdapter.cpp testSerializeAdapter.cpp + testSerialLinkedPacket.cpp testSerializeIF.cpp) diff --git a/unittests/storagemanager/CMakeLists.txt b/unittests/storagemanager/CMakeLists.txt index d2bb4dbc..19e84233 100644 --- a/unittests/storagemanager/CMakeLists.txt +++ b/unittests/storagemanager/CMakeLists.txt @@ -1,4 +1 @@ -target_sources(${FSFW_TEST_TGT} PRIVATE - testAccessor.cpp - testPool.cpp -) +target_sources(${FSFW_TEST_TGT} PRIVATE testAccessor.cpp testPool.cpp) diff --git a/unittests/storagemanager/testAccessor.cpp b/unittests/storagemanager/testAccessor.cpp index d1c38f5d..56b858db 100644 --- a/unittests/storagemanager/testAccessor.cpp +++ b/unittests/storagemanager/testAccessor.cpp @@ -8,7 +8,7 @@ TEST_CASE("Pool Accessor", "[pool-accessor]") { LocalPool::LocalPoolConfig poolCfg = {{1, 10}}; - LocalPool SimplePool = LocalPool(0, poolCfg); + LocalPool simplePool = LocalPool(0, poolCfg); std::array testDataArray{}; std::array receptionArray{}; store_address_t testStoreId; @@ -20,9 +20,9 @@ TEST_CASE("Pool Accessor", "[pool-accessor]") { size_t size = 10; SECTION("Simple tests getter functions") { - result = SimplePool.addData(&testStoreId, testDataArray.data(), size); + result = simplePool.addData(&testStoreId, testDataArray.data(), size); REQUIRE(result == returnvalue::OK); - auto resultPair = SimplePool.getData(testStoreId); + auto resultPair = simplePool.getData(testStoreId); REQUIRE(resultPair.first == returnvalue::OK); resultPair.second.getDataCopy(receptionArray.data(), 20); CHECK(resultPair.second.getId() == testStoreId); @@ -38,18 +38,18 @@ TEST_CASE("Pool Accessor", "[pool-accessor]") { } { - auto resultPairLoc = SimplePool.getData(testStoreId); + auto resultPairLoc = simplePool.getData(testStoreId); REQUIRE(resultPairLoc.first == returnvalue::OK); // data should be deleted when accessor goes out of scope. } - resultPair = SimplePool.getData(testStoreId); + resultPair = simplePool.getData(testStoreId); REQUIRE(resultPair.first == (int)StorageManagerIF::DATA_DOES_NOT_EXIST); - result = SimplePool.addData(&testStoreId, testDataArray.data(), size); + result = simplePool.addData(&testStoreId, testDataArray.data(), size); REQUIRE(result == returnvalue::OK); { ConstStorageAccessor constAccessor(testStoreId); - result = SimplePool.getData(testStoreId, constAccessor); + result = simplePool.getData(testStoreId, constAccessor); REQUIRE(result == returnvalue::OK); constAccessor.getDataCopy(receptionArray.data(), 20); for (size_t i = 0; i < size; i++) { @@ -57,17 +57,17 @@ TEST_CASE("Pool Accessor", "[pool-accessor]") { } // likewise, data should be deleted when accessor gets out of scope. } - resultPair = SimplePool.getData(testStoreId); + resultPair = simplePool.getData(testStoreId); REQUIRE(resultPair.first == (int)StorageManagerIF::DATA_DOES_NOT_EXIST); - result = SimplePool.addData(&testStoreId, testDataArray.data(), size); + result = simplePool.addData(&testStoreId, testDataArray.data(), size); { - resultPair = SimplePool.getData(testStoreId); + resultPair = simplePool.getData(testStoreId); REQUIRE(resultPair.first == returnvalue::OK); resultPair.second.release(); // now data should not be deleted anymore } - resultPair = SimplePool.getData(testStoreId); + resultPair = simplePool.getData(testStoreId); REQUIRE(resultPair.first == returnvalue::OK); resultPair.second.getDataCopy(receptionArray.data(), 20); for (size_t i = 0; i < size; i++) { @@ -76,11 +76,11 @@ TEST_CASE("Pool Accessor", "[pool-accessor]") { } SECTION("Simple tests modify functions") { - result = SimplePool.addData(&testStoreId, testDataArray.data(), size); + result = simplePool.addData(&testStoreId, testDataArray.data(), size); REQUIRE(result == returnvalue::OK); { StorageAccessor accessor(testStoreId); - result = SimplePool.modifyData(testStoreId, accessor); + result = simplePool.modifyData(testStoreId, accessor); REQUIRE(result == returnvalue::OK); CHECK(accessor.getId() == testStoreId); CHECK(accessor.size() == 10); @@ -94,13 +94,13 @@ TEST_CASE("Pool Accessor", "[pool-accessor]") { } // data should be deleted when accessor goes out of scope } - auto resultPair = SimplePool.getData(testStoreId); + auto resultPair = simplePool.getData(testStoreId); REQUIRE(resultPair.first == (int)StorageManagerIF::DATA_DOES_NOT_EXIST); - result = SimplePool.addData(&testStoreId, testDataArray.data(), size); + result = simplePool.addData(&testStoreId, testDataArray.data(), size); REQUIRE(result == returnvalue::OK); { - auto resultPairLoc = SimplePool.modifyData(testStoreId); + auto resultPairLoc = simplePool.modifyData(testStoreId); REQUIRE(resultPairLoc.first == returnvalue::OK); CHECK(resultPairLoc.second.getId() == testStoreId); CHECK(resultPairLoc.second.size() == 10); @@ -116,22 +116,22 @@ TEST_CASE("Pool Accessor", "[pool-accessor]") { resultPairLoc.second.release(); // data should not be deleted when accessor goes out of scope } - resultPair = SimplePool.getData(testStoreId); + resultPair = simplePool.getData(testStoreId); REQUIRE(resultPair.first == returnvalue::OK); } SECTION("Write tests") { - result = SimplePool.addData(&testStoreId, testDataArray.data(), size); + result = simplePool.addData(&testStoreId, testDataArray.data(), size); REQUIRE(result == returnvalue::OK); { - auto resultPair = SimplePool.modifyData(testStoreId); + auto resultPair = simplePool.modifyData(testStoreId); REQUIRE(resultPair.first == returnvalue::OK); testDataArray[9] = 42; resultPair.second.write(testDataArray.data(), 10, 0); // now data should not be deleted resultPair.second.release(); } - auto resultConstPair = SimplePool.getData(testStoreId); + auto resultConstPair = simplePool.getData(testStoreId); REQUIRE(resultConstPair.first == returnvalue::OK); resultConstPair.second.getDataCopy(receptionArray.data(), 10); @@ -140,7 +140,7 @@ TEST_CASE("Pool Accessor", "[pool-accessor]") { } CHECK(receptionArray[9] == 42); - auto resultPair = SimplePool.modifyData(testStoreId); + auto resultPair = simplePool.modifyData(testStoreId); REQUIRE(resultPair.first == returnvalue::OK); result = resultPair.second.write(testDataArray.data(), 20, 0); REQUIRE(result == returnvalue::FAILED); @@ -150,7 +150,7 @@ TEST_CASE("Pool Accessor", "[pool-accessor]") { std::memset(testDataArray.data(), 42, 5); result = resultPair.second.write(testDataArray.data(), 5, 5); REQUIRE(result == returnvalue::OK); - resultConstPair = SimplePool.getData(testStoreId); + resultConstPair = simplePool.getData(testStoreId); resultPair.second.getDataCopy(receptionArray.data(), 20); for (size_t i = 5; i < 10; i++) { CHECK(receptionArray[i] == 42); @@ -158,7 +158,7 @@ TEST_CASE("Pool Accessor", "[pool-accessor]") { } SECTION("Operators") { - result = SimplePool.addData(&testStoreId, testDataArray.data(), size); + result = simplePool.addData(&testStoreId, testDataArray.data(), size); REQUIRE(result == returnvalue::OK); { StorageAccessor accessor(testStoreId); @@ -169,7 +169,7 @@ TEST_CASE("Pool Accessor", "[pool-accessor]") { size_t size = 6; result = accessor.write(data.data(), data.size()); REQUIRE(result == returnvalue::FAILED); - result = SimplePool.modifyData(testStoreId, accessor2); + result = simplePool.modifyData(testStoreId, accessor2); REQUIRE(result == returnvalue::OK); CHECK(accessor2.getId() == testStoreId); CHECK(accessor2.size() == 10); diff --git a/unittests/tcdistributor/CMakeLists.txt b/unittests/tcdistributor/CMakeLists.txt new file mode 100644 index 00000000..1743440a --- /dev/null +++ b/unittests/tcdistributor/CMakeLists.txt @@ -0,0 +1 @@ +target_sources(${FSFW_TEST_TGT} PRIVATE testCcsdsDistributor.cpp) diff --git a/unittests/tcdistributor/testCcsdsDistributor.cpp b/unittests/tcdistributor/testCcsdsDistributor.cpp new file mode 100644 index 00000000..c8aa81f7 --- /dev/null +++ b/unittests/tcdistributor/testCcsdsDistributor.cpp @@ -0,0 +1,169 @@ +#include +#include + +#include "fsfw/storagemanager/LocalPool.h" +#include "fsfw/tcdistribution/CcsdsDistributor.h" +#include "fsfw/tmtcpacket/ccsds/SpacePacketCreator.h" +#include "mocks/AcceptsTcMock.h" +#include "mocks/CcsdsCheckerMock.h" +#include "mocks/MessageQueueMock.h" + +TEST_CASE("CCSDS Distributor", "[ccsds][tmtcdistrib]") { + LocalPool::LocalPoolConfig cfg = {{5, 32}, {2, 64}}; + LocalPool pool(objects::NO_OBJECT, cfg); + auto queue = MessageQueueMock(1); + auto checkerMock = CcsdsCheckerMock(); + uint16_t unregisteredApid = 0; + uint16_t defaultApid = 4; + MessageQueueId_t defaultQueueId = 5; + auto ccsdsDistrib = CcsdsDistributor(defaultApid, 1, &pool, &queue, &checkerMock); + uint32_t tcAcceptorApid = 1; + MessageQueueId_t tcAcceptorQueueId = 3; + + auto tcAcceptorMock = AcceptsTcMock("TC Receiver Dummy", tcAcceptorApid, tcAcceptorQueueId); + auto defReceiverMock = AcceptsTcMock("Default Receiver Dummy", defaultApid, defaultQueueId); + auto packetId = PacketId(ccsds::PacketType::TC, true, 0); + auto psc = PacketSeqCtrl(ccsds::SequenceFlags::FIRST_SEGMENT, 0x34); + auto spParams = SpacePacketParams(packetId, psc, 0x16); + SpacePacketCreator spCreator(spParams); + std::array buf{}; + + auto createSpacePacket = [&](uint16_t apid, TmTcMessage& msg, uint8_t* dataField = nullptr, + size_t dataFieldLen = 1) { + store_address_t storeId{}; + spCreator.setApid(tcAcceptorApid); + spCreator.setCcsdsLenFromTotalDataFieldLen(dataFieldLen); + uint8_t* dataPtr; + REQUIRE(pool.getFreeElement(&storeId, spCreator.getSerializedSize() + dataFieldLen, &dataPtr) == + returnvalue::OK); + size_t serLen = 0; + REQUIRE(spCreator.SerializeIF::serializeBe(dataPtr, serLen, ccsds::HEADER_LEN) == + returnvalue::OK); + REQUIRE(spCreator.SerializeIF::serializeBe(buf.data(), serLen, ccsds::HEADER_LEN) == + returnvalue::OK); + if (dataField == nullptr) { + dataPtr[ccsds::HEADER_LEN] = 0; + buf[ccsds::HEADER_LEN] = 0; + } else { + std::memcpy(dataPtr + ccsds::HEADER_LEN, dataField, dataFieldLen); + std::memcpy(buf.data() + ccsds::HEADER_LEN, dataField, dataFieldLen); + } + msg.setStorageId(storeId); + }; + + SECTION("State") { + CHECK(ccsdsDistrib.initialize() == returnvalue::OK); + CHECK(ccsdsDistrib.getRequestQueue() == 1); + CHECK(ccsdsDistrib.getIdentifier() == 0); + CHECK(ccsdsDistrib.getObjectId() == 1); + REQUIRE(ccsdsDistrib.getName() != nullptr); + CHECK(std::strcmp(ccsdsDistrib.getName(), "CCSDS Distributor") == 0); + } + + SECTION("Basic Forwarding") { + CcsdsDistributor::DestInfo info(tcAcceptorMock, false); + REQUIRE(ccsdsDistrib.registerApplication(info) == returnvalue::OK); + TmTcMessage message; + createSpacePacket(tcAcceptorApid, message); + store_address_t storeId = message.getStorageId(); + queue.addReceivedMessage(message); + REQUIRE(ccsdsDistrib.performOperation(0) == returnvalue::OK); + CHECK(checkerMock.checkedPacketLen == 7); + CHECK(checkerMock.checkCallCount == 1); + CHECK(queue.wasMessageSent()); + CHECK(queue.numberOfSentMessages() == 1); + // The packet is forwarded, with no need to delete the data + CHECK(pool.hasDataAtId(storeId)); + TmTcMessage sentMsg; + CHECK(queue.getNextSentMessage(tcAcceptorQueueId, sentMsg) == returnvalue::OK); + CHECK(sentMsg.getStorageId() == storeId); + auto accessor = pool.getData(storeId); + CHECK(accessor.first == returnvalue::OK); + CHECK(accessor.second.size() == ccsds::HEADER_LEN + 1); + for (size_t i = 0; i < ccsds::HEADER_LEN; i++) { + CHECK(accessor.second.data()[i] == buf[i]); + } + } + + SECTION("Forwarding to Default Destination, but not registered") { + TmTcMessage message; + createSpacePacket(unregisteredApid, message); + store_address_t storeId = message.getStorageId(); + message.setStorageId(storeId); + queue.addReceivedMessage(message); + REQUIRE(ccsdsDistrib.performOperation(0) == TcDistributorBase::DESTINATION_NOT_FOUND); + } + + SECTION("Forward to Default Handler") { + CcsdsDistributor::DestInfo info(defReceiverMock, false); + ccsdsDistrib.registerApplication(info); + TmTcMessage message; + createSpacePacket(defaultApid, message); + store_address_t storeId = message.getStorageId(); + message.setStorageId(storeId); + queue.addReceivedMessage(message); + REQUIRE(ccsdsDistrib.performOperation(0) == returnvalue::OK); + CHECK(checkerMock.checkedPacketLen == 7); + CHECK(checkerMock.checkCallCount == 1); + CHECK(queue.wasMessageSent()); + CHECK(queue.numberOfSentMessages() == 1); + // The packet is forwarded, with no need to delete the data + CHECK(pool.hasDataAtId(storeId)); + TmTcMessage sentMsg; + CHECK(queue.getNextSentMessage(defaultQueueId, sentMsg) == returnvalue::OK); + CHECK(sentMsg.getStorageId() == storeId); + auto accessor = pool.getData(storeId); + CHECK(accessor.first == returnvalue::OK); + CHECK(accessor.second.size() == ccsds::HEADER_LEN + 1); + for (size_t i = 0; i < ccsds::HEADER_LEN; i++) { + CHECK(accessor.second.data()[i] == buf[i]); + } + } + + SECTION("Remove CCSDS header") { + uint16_t tgtApid = 0; + MessageQueueId_t tgtQueueId = MessageQueueIF::NO_QUEUE; + SECTION("Default destination") { + CcsdsDistributor::DestInfo info(defReceiverMock, true); + tgtApid = defaultApid; + tgtQueueId = defaultQueueId; + REQUIRE(ccsdsDistrib.registerApplication(info) == returnvalue::OK); + } + SECTION("Specific destination") { + CcsdsDistributor::DestInfo info(tcAcceptorMock, true); + tgtApid = tcAcceptorApid; + tgtQueueId = tcAcceptorQueueId; + REQUIRE(ccsdsDistrib.registerApplication(info) == returnvalue::OK); + } + TmTcMessage message; + std::array dataField = {0, 1, 2, 3, 4}; + createSpacePacket(tgtApid, message, dataField.data(), 5); + store_address_t storeId = message.getStorageId(); + message.setStorageId(storeId); + queue.addReceivedMessage(message); + REQUIRE(ccsdsDistrib.performOperation(0) == returnvalue::OK); + CHECK(checkerMock.checkedPacketLen == 11); + CHECK(checkerMock.checkCallCount == 1); + // Data was deleted from old slot to re-store without the header + CHECK(not pool.hasDataAtId(storeId)); + TmTcMessage sentMsg; + CHECK(queue.getNextSentMessage(tgtQueueId, sentMsg) == returnvalue::OK); + CHECK(sentMsg.getStorageId() != storeId); + auto accessor = pool.getData(sentMsg.getStorageId()); + CHECK(accessor.first == returnvalue::OK); + CHECK(accessor.second.size() == 5); + // Verify correctness of data field + for (size_t i = 0; i < 5; i++) { + CHECK(accessor.second.data()[i] == i); + } + } + + SECTION("Invalid Space Packet, Too Short") { + store_address_t storeId{}; + std::array data = {1, 2, 3, 4}; + pool.addData(&storeId, data.data(), data.size()); + TmTcMessage message(storeId); + queue.addReceivedMessage(message); + REQUIRE(ccsdsDistrib.performOperation(0) == SerializeIF::STREAM_TOO_SHORT); + } +} \ No newline at end of file diff --git a/unittests/testcfg/CMakeLists.txt b/unittests/testcfg/CMakeLists.txt index f840e38b..3edb59f6 100644 --- a/unittests/testcfg/CMakeLists.txt +++ b/unittests/testcfg/CMakeLists.txt @@ -1,23 +1,16 @@ -target_sources(${FSFW_TEST_TGT} PRIVATE - ipc/MissionMessageTypes.cpp - pollingsequence/PollingSequenceFactory.cpp -) +target_sources( + ${FSFW_TEST_TGT} PRIVATE ipc/MissionMessageTypes.cpp + pollingsequence/PollingSequenceFactory.cpp) # Add include paths for the executable -target_include_directories(${FSFW_TEST_TGT} PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR} -) +target_include_directories(${FSFW_TEST_TGT} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) # If a special translation file for object IDs exists, compile it. if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/objects/translateObjects.cpp") - target_sources(${FSFW_TEST_TGT} PRIVATE - objects/translateObjects.cpp - ) + target_sources(${FSFW_TEST_TGT} PRIVATE objects/translateObjects.cpp) endif() # If a special translation file for events exists, compile it. if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/objects/translateObjects.cpp") - target_sources(${FSFW_TEST_TGT} PRIVATE - events/translateEvents.cpp - ) -endif() \ No newline at end of file + target_sources(${FSFW_TEST_TGT} PRIVATE events/translateEvents.cpp) +endif() diff --git a/unittests/testcfg/pollingsequence/PollingSequenceFactory.cpp b/unittests/testcfg/pollingsequence/PollingSequenceFactory.cpp index 9559cca9..2ee88f96 100644 --- a/unittests/testcfg/pollingsequence/PollingSequenceFactory.cpp +++ b/unittests/testcfg/pollingsequence/PollingSequenceFactory.cpp @@ -4,6 +4,7 @@ #include #include +#include "fsfw/FSFW.h" #include "tests/TestsConfig.h" ReturnValue_t pst::pollingSequenceInitDefault(FixedTimeslotTaskIF *thisSequence) { @@ -20,7 +21,7 @@ ReturnValue_t pst::pollingSequenceInitDefault(FixedTimeslotTaskIF *thisSequence) if (thisSequence->checkSequence() == returnvalue::OK) { return returnvalue::OK; } else { -#if FSFW_CPP_OSTREAM_ENABLED +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "pst::pollingSequenceInitDefault: Sequence invalid!" << std::endl; #else sif::printError("pst::pollingSequenceInitDefault: Sequence invalid!"); diff --git a/unittests/timemanager/CMakeLists.txt b/unittests/timemanager/CMakeLists.txt index 4b1693a9..ad9cae23 100644 --- a/unittests/timemanager/CMakeLists.txt +++ b/unittests/timemanager/CMakeLists.txt @@ -1,4 +1 @@ -target_sources(${FSFW_TEST_TGT} PRIVATE - TestCountdown.cpp - TestCCSDSTime.cpp -) +target_sources(${FSFW_TEST_TGT} PRIVATE TestCountdown.cpp TestCCSDSTime.cpp) diff --git a/unittests/tmtcpacket/CMakeLists.txt b/unittests/tmtcpacket/CMakeLists.txt index 5b53328f..4415685e 100644 --- a/unittests/tmtcpacket/CMakeLists.txt +++ b/unittests/tmtcpacket/CMakeLists.txt @@ -1,10 +1,10 @@ -target_sources(${FSFW_TEST_TGT} PRIVATE - testCcsdsCreator.cpp - testCcsdsReader.cpp - testPusTcCreator.cpp - testPusTcReader.cpp - testPusTmCreator.cpp - testPusTmReader.cpp - testCcsds.cpp - testZcTmWriter.cpp -) +target_sources( + ${FSFW_TEST_TGT} + PRIVATE testCcsdsCreator.cpp + testCcsdsReader.cpp + testPusTcCreator.cpp + testPusTcReader.cpp + testPusTmCreator.cpp + testPusTmReader.cpp + testCcsds.cpp + testZcTmWriter.cpp) diff --git a/unittests/tmtcpacket/testCcsdsCreator.cpp b/unittests/tmtcpacket/testCcsdsCreator.cpp index 2b043717..9c113bb6 100644 --- a/unittests/tmtcpacket/testCcsdsCreator.cpp +++ b/unittests/tmtcpacket/testCcsdsCreator.cpp @@ -39,7 +39,8 @@ TEST_CASE("CCSDS Creator", "[ccsds-creator]") { SECTION("Deserialization Fails") { serLen = 6; const uint8_t* readOnlyPtr = buf.data(); - REQUIRE(base.deSerialize(&readOnlyPtr, &serLen, SerializeIF::Endianness::BIG) == + auto& ser = dynamic_cast(base); + REQUIRE(ser.deSerialize(&readOnlyPtr, &serLen, SerializeIF::Endianness::BIG) == returnvalue::FAILED); } @@ -64,7 +65,7 @@ TEST_CASE("CCSDS Creator", "[ccsds-creator]") { base.setApid(static_cast(std::pow(2, 11)) - 1); base.setSeqCount(static_cast(std::pow(2, 14)) - 1); base.setSeqFlags(ccsds::SequenceFlags::UNSEGMENTED); - base.setDataLen(static_cast(std::pow(2, 16)) - 1); + base.setDataLenField(static_cast(std::pow(2, 16)) - 1); REQUIRE(base.isValid()); REQUIRE(base.serializeBe(&bufPtr, &serLen, buf.size()) == returnvalue::OK); CHECK(buf[0] == 0x1F); @@ -75,6 +76,15 @@ TEST_CASE("CCSDS Creator", "[ccsds-creator]") { CHECK(buf[5] == 0xFF); } + SECTION("Setting data length 0 is ignored") { + SpacePacketCreator creator = SpacePacketCreator( + ccsds::PacketType::TC, true, 0xFFFF, ccsds::SequenceFlags::FIRST_SEGMENT, 0x34, 0x22); + creator.setCcsdsLenFromTotalDataFieldLen(0); + REQUIRE(creator.getPacketDataLen() == 0x22); + creator.setCcsdsLenFromTotalDataFieldLen(1); + REQUIRE(creator.getPacketDataLen() == 0x00); + } + SECTION("Invalid APID") { SpacePacketCreator creator = SpacePacketCreator( ccsds::PacketType::TC, true, 0xFFFF, ccsds::SequenceFlags::FIRST_SEGMENT, 0x34, 0x16); diff --git a/unittests/tmtcpacket/testCcsdsReader.cpp b/unittests/tmtcpacket/testCcsdsReader.cpp index 519ef08b..5a36d70d 100644 --- a/unittests/tmtcpacket/testCcsdsReader.cpp +++ b/unittests/tmtcpacket/testCcsdsReader.cpp @@ -64,7 +64,7 @@ TEST_CASE("CCSDS Reader", "[ccsds-reader]") { SECTION("Invalid Size") { for (size_t i = 0; i < 5; i++) { REQUIRE(reader.setReadOnlyData(buf.data(), i) == SerializeIF::STREAM_TOO_SHORT); - REQUIRE(not reader.isNull()); + REQUIRE(reader.isNull()); REQUIRE(reader.getPacketData() == nullptr); } } diff --git a/unittests/tmtcservices/CMakeLists.txt b/unittests/tmtcservices/CMakeLists.txt index 9e60ced1..1004a5f9 100644 --- a/unittests/tmtcservices/CMakeLists.txt +++ b/unittests/tmtcservices/CMakeLists.txt @@ -1,6 +1,2 @@ -target_sources(${FSFW_TEST_TGT} PRIVATE - testStoreHelper.cpp - testSendHelper.cpp - testStoreAndSendHelper.cpp - testPsb.cpp -) +target_sources(${FSFW_TEST_TGT} PRIVATE testStoreHelper.cpp testSendHelper.cpp + testStoreAndSendHelper.cpp testPsb.cpp) diff --git a/unittests/tmtcservices/testPsb.cpp b/unittests/tmtcservices/testPsb.cpp index ec252da6..93d8aec5 100644 --- a/unittests/tmtcservices/testPsb.cpp +++ b/unittests/tmtcservices/testPsb.cpp @@ -194,7 +194,7 @@ TEST_CASE("Pus Service Base", "[pus-service-base]") { REQUIRE(PsbMock::getStaticPusDistributor() == distributorId); REQUIRE(psb2.initialize() == returnvalue::OK); REQUIRE(pusDistrib.registerCallCount == 1); - REQUIRE(pusDistrib.lastServiceArg == &psb2); + REQUIRE(pusDistrib.registeredServies.front() == &psb2); } SECTION("Auto Initialize Packet Destination") { diff --git a/unittests/util/CMakeLists.txt b/unittests/util/CMakeLists.txt index dd9f6dc1..fb660d54 100644 --- a/unittests/util/CMakeLists.txt +++ b/unittests/util/CMakeLists.txt @@ -1,4 +1 @@ -target_sources(${FSFW_TEST_TGT} PRIVATE - testUnsignedByteField.cpp - testDataWrapper.cpp -) +target_sources(${FSFW_TEST_TGT} PRIVATE testUnsignedByteField.cpp)