diff --git a/CMakeLists.txt b/CMakeLists.txt index e78e8929..bd65cfe1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -189,13 +189,13 @@ if(FSFW_BUILD_UNITTESTS) "--exclude-unreachable-branches" ) set(COVERAGE_EXCLUDES - "/c/msys64/mingw64/*" + "/c/msys64/mingw64/*" "*/fsfw_hal/*" ) elseif(UNIX) set(COVERAGE_EXCLUDES "/usr/include/*" "/usr/bin/*" "Catch2/*" "/usr/local/include/*" "*/fsfw_tests/*" - "*/catch2-src/*" + "*/catch2-src/*" "*/fsfw_hal/*" ) endif() diff --git a/README.md b/README.md index 312bc077..a6f52ca0 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ You can use the following commands inside the `fsfw` folder to set up the build ```sh mkdir build-Unittest && cd build-Unittest -cmake -DFSFW_BUILD_UNITTESTS=ON -DFSFW_OSAL=host .. +cmake -DFSFW_BUILD_UNITTESTS=ON -DFSFW_OSAL=host -DCMAKE_BUILD_TYPE=Debug .. ``` You can also use `-DFSFW_OSAL=linux` on Linux systems. diff --git a/misc/defaultcfg/fsfwconfig/devices/logicalAddresses.h b/misc/defaultcfg/fsfwconfig/devices/logicalAddresses.h index 53edcd54..8f263e9a 100644 --- a/misc/defaultcfg/fsfwconfig/devices/logicalAddresses.h +++ b/misc/defaultcfg/fsfwconfig/devices/logicalAddresses.h @@ -10,7 +10,7 @@ */ namespace addresses { /* Logical addresses have uint32_t datatype */ - enum logicalAddresses: address_t { + enum LogAddr: address_t { }; } diff --git a/src/fsfw/CMakeLists.txt b/src/fsfw/CMakeLists.txt index 7c665e28..12c673ed 100644 --- a/src/fsfw/CMakeLists.txt +++ b/src/fsfw/CMakeLists.txt @@ -1,6 +1,7 @@ # Core add_subdirectory(action) +add_subdirectory(cfdp) add_subdirectory(container) add_subdirectory(controller) add_subdirectory(datapool) diff --git a/src/fsfw/FSFW.h.in b/src/fsfw/FSFW.h.in index 7e52b646..d4a8f3ba 100644 --- a/src/fsfw/FSFW.h.in +++ b/src/fsfw/FSFW.h.in @@ -42,6 +42,10 @@ #define FSFW_USE_PUS_C_TELECOMMANDS 1 #endif +#ifndef FSFW_TCP_RECV_WIRETAPPING_ENABLED +#define FSFW_TCP_RECV_WIRETAPPING_ENABLED 0 +#endif + // FSFW HAL defines // Can be used for low-level debugging of the SPI bus diff --git a/src/fsfw/cfdp/CFDPHandler.cpp b/src/fsfw/cfdp/CFDPHandler.cpp new file mode 100644 index 00000000..79712bf2 --- /dev/null +++ b/src/fsfw/cfdp/CFDPHandler.cpp @@ -0,0 +1,60 @@ +#include "fsfw/ipc/CommandMessage.h" +#include "fsfw/storagemanager/storeAddress.h" +#include "fsfw/cfdp/CFDPHandler.h" +#include "fsfw/cfdp/CFDPMessage.h" + +#include "fsfw/tmtcservices/AcceptsTelemetryIF.h" +#include "fsfw/ipc/QueueFactory.h" +#include "fsfw/objectmanager/ObjectManager.h" + +object_id_t CFDPHandler::packetSource = 0; +object_id_t CFDPHandler::packetDestination = 0; + +CFDPHandler::CFDPHandler(object_id_t setObjectId, CFDPDistributor* dist) : SystemObject(setObjectId) { + requestQueue = QueueFactory::instance()->createMessageQueue(CFDP_HANDLER_MAX_RECEPTION); + distributor = dist; +} + +CFDPHandler::~CFDPHandler() {} + +ReturnValue_t CFDPHandler::initialize() { + ReturnValue_t result = SystemObject::initialize(); + if (result != RETURN_OK) { + return result; + } + this->distributor->registerHandler(this); + return HasReturnvaluesIF::RETURN_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 RETURN_OK; +} + +ReturnValue_t CFDPHandler::performOperation(uint8_t opCode) { + ReturnValue_t status = RETURN_OK; + CommandMessage currentMessage; + for (status = this->requestQueue->receiveMessage(¤tMessage); status == RETURN_OK; + status = this->requestQueue->receiveMessage(¤tMessage)) { + store_address_t storeId = CFDPMessage::getStoreId(¤tMessage); + this->handleRequest(storeId); + } + return RETURN_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 new file mode 100644 index 00000000..2f11eee3 --- /dev/null +++ b/src/fsfw/cfdp/CFDPHandler.h @@ -0,0 +1,62 @@ +#ifndef FSFW_CFDP_CFDPHANDLER_H_ +#define FSFW_CFDP_CFDPHANDLER_H_ + +#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h" +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/tasks/ExecutableObjectIF.h" +#include "fsfw/tcdistribution/CFDPDistributor.h" + +#include "fsfw/ipc/MessageQueueIF.h" + +namespace Factory{ +void setStaticFrameworkObjectIds(); +} + +class CFDPHandler : + public ExecutableObjectIF, + public AcceptsTelecommandsIF, + public SystemObject, + public HasReturnvaluesIF { + 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/CFDPMessage.cpp b/src/fsfw/cfdp/CFDPMessage.cpp new file mode 100644 index 00000000..c75b6b2c --- /dev/null +++ b/src/fsfw/cfdp/CFDPMessage.cpp @@ -0,0 +1,21 @@ +#include "CFDPMessage.h" + +CFDPMessage::CFDPMessage() { +} + +CFDPMessage::~CFDPMessage() { +} + +void CFDPMessage::setCommand(CommandMessage *message, + store_address_t cfdpPacket) { + message->setParameter(cfdpPacket.raw); +} + +store_address_t CFDPMessage::getStoreId(const CommandMessage *message) { + store_address_t storeAddressCFDPPacket; + storeAddressCFDPPacket = message->getParameter(); + return storeAddressCFDPPacket; +} + +void CFDPMessage::clear(CommandMessage *message) { +} diff --git a/src/fsfw/cfdp/CFDPMessage.h b/src/fsfw/cfdp/CFDPMessage.h new file mode 100644 index 00000000..5b321975 --- /dev/null +++ b/src/fsfw/cfdp/CFDPMessage.h @@ -0,0 +1,23 @@ +#ifndef FSFW_CFDP_CFDPMESSAGE_H_ +#define FSFW_CFDP_CFDPMESSAGE_H_ + +#include "fsfw/ipc/CommandMessage.h" +#include "fsfw/objectmanager/ObjectManagerIF.h" +#include "fsfw/storagemanager/StorageManagerIF.h" + +class CFDPMessage { +private: + CFDPMessage(); +public: + static const uint8_t MESSAGE_ID = messagetypes::CFDP; + + virtual ~CFDPMessage(); + static void setCommand(CommandMessage* message, + store_address_t cfdpPacket); + + static store_address_t getStoreId(const CommandMessage* message); + + static void clear(CommandMessage* message); +}; + +#endif /* FSFW_CFDP_CFDPMESSAGE_H_ */ diff --git a/src/fsfw/cfdp/CMakeLists.txt b/src/fsfw/cfdp/CMakeLists.txt new file mode 100644 index 00000000..908dc32a --- /dev/null +++ b/src/fsfw/cfdp/CMakeLists.txt @@ -0,0 +1,7 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + CFDPHandler.cpp + CFDPMessage.cpp +) + +add_subdirectory(pdu) +add_subdirectory(tlv) diff --git a/src/fsfw/cfdp/FileSize.h b/src/fsfw/cfdp/FileSize.h new file mode 100644 index 00000000..3997d5a4 --- /dev/null +++ b/src/fsfw/cfdp/FileSize.h @@ -0,0 +1,83 @@ +#ifndef FSFW_SRC_FSFW_CFDP_FILESIZE_H_ +#define FSFW_SRC_FSFW_CFDP_FILESIZE_H_ + +#include "fsfw/serialize/SerializeAdapter.h" +#include "fsfw/serialize/SerializeIF.h" + +namespace cfdp { + +struct FileSize: public SerializeIF { +public: + FileSize(): largeFile(false) {}; + + FileSize(uint64_t fileSize, bool isLarge = false) { + setFileSize(fileSize, isLarge); + }; + + ReturnValue_t serialize(bool isLarge, uint8_t **buffer, size_t *size,size_t maxSize, + Endianness streamEndianness) { + this->largeFile = isLarge; + return serialize(buffer, size, maxSize, streamEndianness); + } + + ReturnValue_t serialize(uint8_t **buffer, size_t *size,size_t maxSize, + Endianness streamEndianness) const override { + if(not largeFile) { + uint32_t fileSizeTyped = fileSize; + return SerializeAdapter::serialize(&fileSizeTyped, buffer, size, maxSize, + streamEndianness); + + } + return SerializeAdapter::serialize(&fileSize, buffer, size, maxSize, streamEndianness); + } + + size_t getSerializedSize() const override { + if (largeFile) { + return 8; + } else { + return 4; + } + } + + ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override { + if(largeFile) { + return SerializeAdapter::deSerialize(&size, buffer, size, streamEndianness); + } else { + uint32_t sizeTmp = 0; + ReturnValue_t result = SerializeAdapter::deSerialize(&sizeTmp, buffer, size, + streamEndianness); + if(result == HasReturnvaluesIF::RETURN_OK) { + fileSize = sizeTmp; + } + return result; + } + } + + ReturnValue_t setFileSize(uint64_t fileSize, bool largeFile) { + if (not largeFile and fileSize > UINT32_MAX) { + // TODO: emit warning here + return HasReturnvaluesIF::RETURN_FAILED; + } + this->fileSize = fileSize; + this->largeFile = largeFile; + return HasReturnvaluesIF::RETURN_OK; + } + + bool isLargeFile() const { + return largeFile; + } + uint64_t getSize(bool* largeFile = nullptr) const { + if(largeFile != nullptr) { + *largeFile = this->largeFile; + } + return fileSize; + } +private: + uint64_t fileSize = 0; + bool largeFile = false; +}; + +} + +#endif /* FSFW_SRC_FSFW_CFDP_FILESIZE_H_ */ diff --git a/src/fsfw/cfdp/definitions.h b/src/fsfw/cfdp/definitions.h new file mode 100644 index 00000000..ffcbca97 --- /dev/null +++ b/src/fsfw/cfdp/definitions.h @@ -0,0 +1,153 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_DEFINITIONS_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_DEFINITIONS_H_ + +#include +#include +#include +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/returnvalues/FwClassIds.h" + +namespace cfdp { + +static constexpr uint8_t VERSION_BITS = 0b00100000; + +static constexpr uint8_t CFDP_CLASS_ID = CLASS_ID::CFDP; + +static constexpr ReturnValue_t INVALID_TLV_TYPE = + HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 1); +static constexpr ReturnValue_t INVALID_DIRECTIVE_FIELDS = + HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 2); +static constexpr ReturnValue_t INVALID_PDU_DATAFIELD_LEN = + HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 3); +static constexpr ReturnValue_t INVALID_ACK_DIRECTIVE_FIELDS = + HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 4); +//! Can not parse options. This can also occur because there are options +//! available but the user did not pass a valid options array +static constexpr ReturnValue_t METADATA_CANT_PARSE_OPTIONS = + HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 5); +static constexpr ReturnValue_t NAK_CANT_PARSE_OPTIONS = + HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 6); +static constexpr ReturnValue_t FINISHED_CANT_PARSE_FS_RESPONSES = + HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 6); +static constexpr ReturnValue_t FILESTORE_REQUIRES_SECOND_FILE = + HasReturnvaluesIF::makeReturnCode(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 = + HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 9); + +//! Checksum types according to the SANA Checksum Types registry +//! https://sanaregistry.org/r/checksum_identifiers/ +enum ChecksumType { + // Modular legacy checksum + MODULAR = 0, + CRC_32_PROXIMITY_1 = 1, + CRC_32C = 2, + CRC_32 = 3, + NULL_CHECKSUM = 15 +}; + +enum PduType: bool { + FILE_DIRECTIVE = 0, + FILE_DATA = 1 +}; + +enum TransmissionModes: bool { + ACKNOWLEDGED = 0, + UNACKNOWLEDGED = 1 +}; + +enum SegmentMetadataFlag: bool { + NOT_PRESENT = 0, + PRESENT = 1 +}; + +enum Direction: bool { + TOWARDS_RECEIVER = 0, + TOWARDS_SENDER = 1 +}; + +enum SegmentationControl: bool { + NO_RECORD_BOUNDARIES_PRESERVATION = 0, + RECORD_BOUNDARIES_PRESERVATION = 1 +}; + +enum WidthInBytes: uint8_t { + // Only those are supported for now + ONE_BYTE = 1, + TWO_BYTES = 2, + FOUR_BYTES = 4, +}; + +enum FileDirectives: uint8_t { + INVALID_DIRECTIVE = 0x0f, + EOF_DIRECTIVE = 0x04, + FINISH = 0x05, + ACK = 0x06, + METADATA = 0x07, + NAK = 0x08, + PROMPT = 0x09, + KEEP_ALIVE = 0x0c +}; + +enum ConditionCode: uint8_t { + NO_CONDITION_FIELD = 0xff, + NO_ERROR = 0b0000, + POSITIVE_ACK_LIMIT_REACHED = 0b0001, + KEEP_ALIVE_LIMIT_REACHED = 0b0010, + INVALID_TRANSMISSION_MODE = 0b0011, + FILESTORE_REJECTION = 0b0100, + FILE_CHECKSUM_FAILURE = 0b0101, + FILE_SIZE_ERROR = 0b0110, + NAK_LIMIT_REACHED = 0b0111, + INACTIVITY_DETECTED = 0b1000, + CHECK_LIMIT_REACHED = 0b1010, + UNSUPPORTED_CHECKSUM_TYPE = 0b1011, + SUSPEND_REQUEST_RECEIVED = 0b1110, + CANCEL_REQUEST_RECEIVED = 0b1111 +}; + +enum AckTransactionStatus { + UNDEFINED = 0b00, + ACTIVE = 0b01, + TERMINATED = 0b10, + UNRECOGNIZED = 0b11 +}; + +enum FinishedDeliveryCode { + DATA_COMPLETE = 0, + DATA_INCOMPLETE = 1 +}; + +enum FinishedFileStatus { + 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 TlvTypes: uint8_t { + FILESTORE_REQUEST = 0x00, + FILESTORE_RESPONSE = 0x01, + MSG_TO_USER = 0x02, + FAULT_HANDLER = 0x04, + FLOW_LABEL = 0x05, + ENTITY_ID = 0x06, + INVALID_TLV = 0xff, +}; + +enum RecordContinuationState { + NO_START_NO_END = 0b00, + CONTAINS_START_NO_END = 0b01, + CONTAINS_END_NO_START = 0b10, + CONTAINS_START_AND_END = 0b11 +}; + +} + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_DEFINITIONS_H_ */ diff --git a/src/fsfw/cfdp/pdu/AckInfo.cpp b/src/fsfw/cfdp/pdu/AckInfo.cpp new file mode 100644 index 00000000..4095e8bf --- /dev/null +++ b/src/fsfw/cfdp/pdu/AckInfo.cpp @@ -0,0 +1,52 @@ +#include "AckInfo.h" + +AckInfo::AckInfo(cfdp::FileDirectives ackedDirective, cfdp::ConditionCode ackedConditionCode, + cfdp::AckTransactionStatus transactionStatus, uint8_t directiveSubtypeCode): + ackedDirective(ackedDirective), ackedConditionCode(ackedConditionCode), + transactionStatus(transactionStatus), directiveSubtypeCode(directiveSubtypeCode) { + if (ackedDirective == cfdp::FileDirectives::FINISH) { + this->directiveSubtypeCode = 0b0001; + } else { + this->directiveSubtypeCode = 0b0000; + } +} + +cfdp::ConditionCode AckInfo::getAckedConditionCode() const { + return ackedConditionCode; +} + +void AckInfo::setAckedConditionCode(cfdp::ConditionCode ackedConditionCode) { + this->ackedConditionCode = ackedConditionCode; + if (ackedDirective == cfdp::FileDirectives::FINISH) { + this->directiveSubtypeCode = 0b0001; + } else { + this->directiveSubtypeCode = 0b0000; + } +} + +cfdp::FileDirectives AckInfo::getAckedDirective() const { + return ackedDirective; +} + +void AckInfo::setAckedDirective(cfdp::FileDirectives ackedDirective) { + this->ackedDirective = ackedDirective; +} + +uint8_t AckInfo::getDirectiveSubtypeCode() const { + return directiveSubtypeCode; +} + +void AckInfo::setDirectiveSubtypeCode(uint8_t directiveSubtypeCode) { + this->directiveSubtypeCode = directiveSubtypeCode; +} + +cfdp::AckTransactionStatus AckInfo::getTransactionStatus() const { + return transactionStatus; +} + +AckInfo::AckInfo() { +} + +void AckInfo::setTransactionStatus(cfdp::AckTransactionStatus transactionStatus) { + this->transactionStatus = transactionStatus; +} diff --git a/src/fsfw/cfdp/pdu/AckInfo.h b/src/fsfw/cfdp/pdu/AckInfo.h new file mode 100644 index 00000000..2d54c535 --- /dev/null +++ b/src/fsfw/cfdp/pdu/AckInfo.h @@ -0,0 +1,33 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_ACKINFO_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_ACKINFO_H_ + +#include "../definitions.h" + +class AckInfo { +public: + AckInfo(); + AckInfo(cfdp::FileDirectives 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); + + uint8_t getDirectiveSubtypeCode() const; + void setDirectiveSubtypeCode(uint8_t directiveSubtypeCode); + + cfdp::AckTransactionStatus getTransactionStatus() const; + void setTransactionStatus(cfdp::AckTransactionStatus transactionStatus); + +private: + cfdp::FileDirectives ackedDirective = cfdp::FileDirectives::INVALID_DIRECTIVE; + cfdp::ConditionCode ackedConditionCode = cfdp::ConditionCode::NO_CONDITION_FIELD; + cfdp::AckTransactionStatus transactionStatus = cfdp::AckTransactionStatus::UNDEFINED; + uint8_t directiveSubtypeCode = 0; +}; + + + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_ACKINFO_H_ */ diff --git a/src/fsfw/cfdp/pdu/AckPduDeserializer.cpp b/src/fsfw/cfdp/pdu/AckPduDeserializer.cpp new file mode 100644 index 00000000..b4f59a7a --- /dev/null +++ b/src/fsfw/cfdp/pdu/AckPduDeserializer.cpp @@ -0,0 +1,38 @@ +#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 != HasReturnvaluesIF::RETURN_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 HasReturnvaluesIF::RETURN_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/AckPduDeserializer.h b/src/fsfw/cfdp/pdu/AckPduDeserializer.h new file mode 100644 index 00000000..31f09c92 --- /dev/null +++ b/src/fsfw/cfdp/pdu/AckPduDeserializer.h @@ -0,0 +1,26 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_ACKPDUDESERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_ACKPDUDESERIALIZER_H_ + +#include "fsfw/cfdp/pdu/FileDirectiveDeserializer.h" +#include "AckInfo.h" + +class AckPduDeserializer: public FileDirectiveDeserializer { +public: + AckPduDeserializer(const uint8_t* pduBuf, size_t maxSize, AckInfo& info); + + /** + * + * @return + * - cfdp::INVALID_DIRECTIVE_FIELDS: Invalid fields + */ + ReturnValue_t parseData(); + +private: + bool checkAndSetCodes(uint8_t rawAckedByte, uint8_t rawAckedConditionCode); + AckInfo& info; + +}; + + + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_ACKPDUDESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/AckPduSerializer.cpp b/src/fsfw/cfdp/pdu/AckPduSerializer.cpp new file mode 100644 index 00000000..56fe8b33 --- /dev/null +++ b/src/fsfw/cfdp/pdu/AckPduSerializer.cpp @@ -0,0 +1,38 @@ +#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 != HasReturnvaluesIF::RETURN_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 HasReturnvaluesIF::RETURN_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 HasReturnvaluesIF::RETURN_OK; +} diff --git a/src/fsfw/cfdp/pdu/AckPduSerializer.h b/src/fsfw/cfdp/pdu/AckPduSerializer.h new file mode 100644 index 00000000..de478c69 --- /dev/null +++ b/src/fsfw/cfdp/pdu/AckPduSerializer.h @@ -0,0 +1,30 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_ACKPDUSERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_ACKPDUSERIALIZER_H_ + +#include "AckInfo.h" +#include "FileDirectiveDeserializer.h" +#include "FileDirectiveSerializer.h" + +class AckPduSerializer: public FileDirectiveSerializer { +public: + /** + * @brief Serializer to pack ACK PDUs + * @details + * Please note that only Finished PDUs and EOF are acknowledged. + * @param ackedDirective + * @param ackedConditionCode + * @param transactionStatus + * @param pduConf + */ + AckPduSerializer(AckInfo& ackInfo, PduConfig& pduConf); + + size_t getSerializedSize() const override; + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + Endianness streamEndianness) const override; + +private: + AckInfo& ackInfo; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_ACKPDUSERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/CMakeLists.txt b/src/fsfw/cfdp/pdu/CMakeLists.txt new file mode 100644 index 00000000..931db306 --- /dev/null +++ b/src/fsfw/cfdp/pdu/CMakeLists.txt @@ -0,0 +1,32 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + PduConfig.cpp + VarLenField.cpp + HeaderSerializer.cpp + HeaderDeserializer.cpp + FileDirectiveDeserializer.cpp + FileDirectiveSerializer.cpp + + AckInfo.cpp + AckPduSerializer.cpp + AckPduDeserializer.cpp + EofInfo.cpp + EofPduSerializer.cpp + EofPduDeserializer.cpp + NakInfo.cpp + NakPduSerializer.cpp + NakPduDeserializer.cpp + FinishedInfo.cpp + FinishedPduSerializer.cpp + FinishedPduDeserializer.cpp + MetadataInfo.cpp + MetadataPduSerializer.cpp + MetadataPduDeserializer.cpp + KeepAlivePduSerializer.cpp + KeepAlivePduDeserializer.cpp + PromptPduSerializer.cpp + PromptPduDeserializer.cpp + + FileDataSerializer.cpp + FileDataDeserializer.cpp + FileDataInfo.cpp +) \ No newline at end of file diff --git a/src/fsfw/cfdp/pdu/EofInfo.cpp b/src/fsfw/cfdp/pdu/EofInfo.cpp new file mode 100644 index 00000000..f7c41dbe --- /dev/null +++ b/src/fsfw/cfdp/pdu/EofInfo.cpp @@ -0,0 +1,58 @@ +#include "EofInfo.h" + +EofInfo::EofInfo(cfdp::ConditionCode conditionCode, uint32_t checksum, cfdp::FileSize fileSize, + EntityIdTlv* faultLoc): conditionCode(conditionCode), checksum(checksum), + fileSize(fileSize), faultLoc(faultLoc) { +} + +EofInfo::EofInfo(EntityIdTlv *faultLoc): conditionCode(cfdp::ConditionCode::NO_CONDITION_FIELD), + checksum(0), fileSize(0), faultLoc(faultLoc) { +} + +uint32_t EofInfo::getChecksum() const { + return checksum; +} + +cfdp::ConditionCode EofInfo::getConditionCode() const { + return conditionCode; +} + +EntityIdTlv* EofInfo::getFaultLoc() const { + return faultLoc; +} + +cfdp::FileSize& EofInfo::getFileSize() { + return fileSize; +} + +void EofInfo::setChecksum(uint32_t checksum) { + this->checksum = checksum; +} + +void EofInfo::setConditionCode(cfdp::ConditionCode conditionCode) { + this->conditionCode = conditionCode; +} + +void EofInfo::setFaultLoc(EntityIdTlv *faultLoc) { + this->faultLoc = faultLoc; +} + +size_t EofInfo::getSerializedSize(bool fssLarge) { + // Condition code + spare + 4 byte checksum + size_t size = 5; + if(fssLarge) { + size += 8; + } else { + size += 4; + } + // Do not account for fault location if the condition code is NO_ERROR. We assume that + // a serializer will not serialize the fault location here. + if(getFaultLoc() != nullptr and getConditionCode() != cfdp::ConditionCode::NO_ERROR) { + size+= faultLoc->getSerializedSize(); + } + return size; +} + +ReturnValue_t EofInfo::setFileSize(size_t fileSize, bool isLarge) { + return this->fileSize.setFileSize(fileSize, isLarge); +} diff --git a/src/fsfw/cfdp/pdu/EofInfo.h b/src/fsfw/cfdp/pdu/EofInfo.h new file mode 100644 index 00000000..33feb4fd --- /dev/null +++ b/src/fsfw/cfdp/pdu/EofInfo.h @@ -0,0 +1,33 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_EOFINFO_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_EOFINFO_H_ + +#include "fsfw/cfdp/tlv/EntityIdTlv.h" +#include "../definitions.h" +#include "../FileSize.h" + +struct EofInfo { +public: + 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; + + EntityIdTlv* getFaultLoc() const; + cfdp::FileSize& getFileSize(); + void setChecksum(uint32_t checksum); + void setConditionCode(cfdp::ConditionCode conditionCode); + void setFaultLoc(EntityIdTlv *faultLoc); + ReturnValue_t setFileSize(size_t size, bool isLarge); +private: + + cfdp::ConditionCode conditionCode; + uint32_t checksum; + cfdp::FileSize fileSize; + EntityIdTlv* faultLoc = nullptr; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_EOFINFO_H_ */ diff --git a/src/fsfw/cfdp/pdu/EofPduDeserializer.cpp b/src/fsfw/cfdp/pdu/EofPduDeserializer.cpp new file mode 100644 index 00000000..e5f607bf --- /dev/null +++ b/src/fsfw/cfdp/pdu/EofPduDeserializer.cpp @@ -0,0 +1,68 @@ +#include "EofPduDeserializer.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) { +} + +ReturnValue_t EofPduDeserializer::parseData() { + ReturnValue_t result = FileDirectiveDeserializer::parseData(); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + const uint8_t* bufPtr = rawPtr; + size_t expectedFileFieldLen = 4; + if(this->getLargeFileFlag()) { + expectedFileFieldLen = 8; + } + size_t currentIdx = FileDirectiveDeserializer::getHeaderSize(); + size_t deserLen = maxSize; + if(maxSize < currentIdx + 5 + expectedFileFieldLen) { + return SerializeIF::STREAM_TOO_SHORT; + } + + bufPtr += currentIdx; + deserLen -= currentIdx; + info.setConditionCode(static_cast(*bufPtr >> 4)); + bufPtr += 1; + deserLen -= 1; + uint32_t checksum = 0; + auto endianness = getEndianness(); + result = SerializeAdapter::deSerialize(&checksum, &bufPtr, &deserLen, endianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + info.setChecksum(checksum); + if(this->getLargeFileFlag()) { + uint64_t fileSizeValue = 0; + result = SerializeAdapter::deSerialize(&fileSizeValue, &bufPtr, &deserLen, endianness); + info.setFileSize(fileSizeValue, true); + } + else { + uint32_t fileSizeValue = 0; + result = SerializeAdapter::deSerialize(&fileSizeValue, &bufPtr, &deserLen, endianness); + info.setFileSize(fileSizeValue, false); + } + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(info.getConditionCode() != cfdp::ConditionCode::NO_ERROR) { + EntityIdTlv* tlvPtr = info.getFaultLoc(); + if(tlvPtr == nullptr) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "EofPduDeserializer::parseData: Ca not deserialize fault location," + " given TLV pointer invalid" << std::endl; +#else + sif::printWarning("EofPduDeserializer::parseData: Ca not deserialize fault location," + " given TLV pointer invalid"); +#endif +#endif /* FSFW_VERBOSE_LEVEL >= 1 */ + return HasReturnvaluesIF::RETURN_FAILED; + } + result = tlvPtr->deSerialize(&bufPtr, &deserLen, endianness); + } + return result; +} diff --git a/src/fsfw/cfdp/pdu/EofPduDeserializer.h b/src/fsfw/cfdp/pdu/EofPduDeserializer.h new file mode 100644 index 00000000..fea5f03f --- /dev/null +++ b/src/fsfw/cfdp/pdu/EofPduDeserializer.h @@ -0,0 +1,18 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_EOFPDUDESERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_EOFPDUDESERIALIZER_H_ + +#include "fsfw/cfdp/pdu/FileDirectiveDeserializer.h" +#include "EofInfo.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/EofPduSerializer.cpp b/src/fsfw/cfdp/pdu/EofPduSerializer.cpp new file mode 100644 index 00000000..81bd98f1 --- /dev/null +++ b/src/fsfw/cfdp/pdu/EofPduSerializer.cpp @@ -0,0 +1,46 @@ +#include "fsfw/FSFW.h" +#include "fsfw/serviceinterface.h" +#include "EofPduSerializer.h" + +EofPduSerializer::EofPduSerializer(PduConfig &conf, EofInfo& info): + FileDirectiveSerializer(conf, cfdp::FileDirectives::EOF_DIRECTIVE, 9), info(info) { + setDirectiveDataFieldLen(info.getSerializedSize(getLargeFileFlag())); +} + +size_t EofPduSerializer::getSerializedSize() const { + return FileDirectiveSerializer::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); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(*size + 1 > maxSize) { + return SerializeIF::BUFFER_TOO_SHORT; + } + **buffer = info.getConditionCode() << 4; + *buffer += 1; + *size += 1; + uint32_t checksum = info.getChecksum(); + result = SerializeAdapter::serialize(&checksum, buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(info.getFileSize().isLargeFile()) { + uint64_t fileSizeValue = info.getFileSize().getSize(); + result = SerializeAdapter::serialize(&fileSizeValue, buffer, size, + maxSize, streamEndianness); + } + else { + uint32_t fileSizeValue = info.getFileSize().getSize(); + result = SerializeAdapter::serialize(&fileSizeValue, buffer, size, + maxSize, streamEndianness); + } + if(info.getFaultLoc() != nullptr and info.getConditionCode() != cfdp::ConditionCode::NO_ERROR) { + result = info.getFaultLoc()->serialize(buffer, size, maxSize, streamEndianness); + } + return result; +} diff --git a/src/fsfw/cfdp/pdu/EofPduSerializer.h b/src/fsfw/cfdp/pdu/EofPduSerializer.h new file mode 100644 index 00000000..cdc9b0f1 --- /dev/null +++ b/src/fsfw/cfdp/pdu/EofPduSerializer.h @@ -0,0 +1,22 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_EOFPDUSERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_EOFPDUSERIALIZER_H_ + +#include "fsfw/cfdp/pdu/FileDirectiveSerializer.h" +#include "fsfw/cfdp/tlv/EntityIdTlv.h" +#include "EofInfo.h" + +class EofPduSerializer: public FileDirectiveSerializer { +public: + EofPduSerializer(PduConfig &conf, EofInfo& info); + + size_t getSerializedSize() const override; + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + Endianness streamEndianness) const override; +private: + EofInfo& info; +}; + + + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_EOFPDUSERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/FileDataDeserializer.cpp b/src/fsfw/cfdp/pdu/FileDataDeserializer.cpp new file mode 100644 index 00000000..80106edf --- /dev/null +++ b/src/fsfw/cfdp/pdu/FileDataDeserializer.cpp @@ -0,0 +1,52 @@ +#include "FileDataDeserializer.h" + +FileDataDeserializer::FileDataDeserializer(const uint8_t *pduBuf, size_t maxSize, + FileDataInfo& info): + HeaderDeserializer(pduBuf, maxSize), info(info) { +} + +ReturnValue_t FileDataDeserializer::parseData() { + ReturnValue_t result = HeaderDeserializer::parseData(); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + size_t currentIdx = HeaderDeserializer::getHeaderSize(); + const uint8_t* buf = rawPtr + currentIdx; + size_t remSize = HeaderDeserializer::getWholePduSize() - currentIdx; + if (remSize < 1) { + return SerializeIF::STREAM_TOO_SHORT; + } + if(hasSegmentMetadataFlag()) { + info.setSegmentMetadataFlag(true); + info.setRecordContinuationState(static_cast( + (*buf >> 6) & 0b11)); + size_t segmentMetadataLen = *buf & 0b00111111; + info.setSegmentMetadataLen(segmentMetadataLen); + if(remSize < segmentMetadataLen + 1) { + return SerializeIF::STREAM_TOO_SHORT; + } + if(segmentMetadataLen > 0) { + buf += 1; + remSize -= 1; + info.setSegmentMetadata(buf); + buf += segmentMetadataLen; + remSize -= segmentMetadataLen; + } + } + result = info.getOffset().deSerialize(&buf, &remSize, this->getEndianness()); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(remSize > 0) { + info.setFileData(buf, remSize); + } + return HasReturnvaluesIF::RETURN_OK; +} + +SerializeIF::Endianness FileDataDeserializer::getEndianness() const { + return endianness; +} + +void FileDataDeserializer::setEndianness(SerializeIF::Endianness endianness) { + this->endianness = endianness; +} diff --git a/src/fsfw/cfdp/pdu/FileDataDeserializer.h b/src/fsfw/cfdp/pdu/FileDataDeserializer.h new file mode 100644 index 00000000..13532d95 --- /dev/null +++ b/src/fsfw/cfdp/pdu/FileDataDeserializer.h @@ -0,0 +1,22 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_FILEDATADESERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_FILEDATADESERIALIZER_H_ + +#include "FileDataInfo.h" +#include "HeaderDeserializer.h" +#include "../definitions.h" + +class FileDataDeserializer: public HeaderDeserializer { +public: + FileDataDeserializer(const uint8_t* pduBuf, size_t maxSize, FileDataInfo& info); + + ReturnValue_t parseData(); + SerializeIF::Endianness getEndianness() const; + void setEndianness(SerializeIF::Endianness endianness = SerializeIF::Endianness::NETWORK); + +private: + + SerializeIF::Endianness endianness = SerializeIF::Endianness::NETWORK; + FileDataInfo& info; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_FILEDATADESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/FileDataInfo.cpp b/src/fsfw/cfdp/pdu/FileDataInfo.cpp new file mode 100644 index 00000000..1698f5e0 --- /dev/null +++ b/src/fsfw/cfdp/pdu/FileDataInfo.cpp @@ -0,0 +1,104 @@ +#include "FileDataInfo.h" + +FileDataInfo::FileDataInfo(cfdp::FileSize &offset, const uint8_t *fileData, size_t fileSize): + offset(offset), fileData(fileData), fileSize(fileSize) { +} + +FileDataInfo::FileDataInfo(cfdp::FileSize &offset): offset(offset) { +} + +void FileDataInfo::setSegmentMetadataFlag(bool enable) { + if(enable) { + segmentMetadataFlag = cfdp::SegmentMetadataFlag::PRESENT; + } else { + segmentMetadataFlag = cfdp::SegmentMetadataFlag::NOT_PRESENT; + } +} + +size_t FileDataInfo::getSerializedSize(bool largeFile) const { + size_t sz = 0; + if(segmentMetadataFlag == cfdp::SegmentMetadataFlag::PRESENT) { + sz += 1 + segmentMetadataLen; + } + if(largeFile) { + sz += 8; + } else { + sz += 4; + } + sz += fileSize; + return sz; +} + +cfdp::SegmentMetadataFlag FileDataInfo::getSegmentMetadataFlag() const { + return this->segmentMetadataFlag; +} + +bool FileDataInfo::hasSegmentMetadata() const { + if(segmentMetadataFlag == cfdp::SegmentMetadataFlag::PRESENT) { + return true; + } + return false; +} + +cfdp::RecordContinuationState FileDataInfo::getRecordContinuationState() const { + return this->recContState; +} + +size_t FileDataInfo::getSegmentMetadataLen() const { + return segmentMetadataLen; +} + +ReturnValue_t FileDataInfo::addSegmentMetadataInfo(cfdp::RecordContinuationState recContState, + const uint8_t* segmentMetadata, size_t segmentMetadataLen) { + this->segmentMetadataFlag = cfdp::SegmentMetadataFlag::PRESENT; + this->recContState = recContState; + if(segmentMetadataLen > 63) { + return HasReturnvaluesIF::RETURN_FAILED; + } + this->segmentMetadata = segmentMetadata; + this->segmentMetadataLen = segmentMetadataLen; + return HasReturnvaluesIF::RETURN_OK; +} + +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; + } + return segmentMetadata; +} + +cfdp::FileSize& FileDataInfo::getOffset() { + return offset; +} + +void FileDataInfo::setRecordContinuationState(cfdp::RecordContinuationState recContState) { + this->recContState = recContState; +} + +void FileDataInfo::setSegmentMetadataLen(size_t len) { + this->segmentMetadataLen = len; +} + +void FileDataInfo::setSegmentMetadata(const uint8_t *ptr) { + this->segmentMetadata = ptr; +} + +void FileDataInfo::setFileData(const uint8_t *fileData, size_t fileSize) { + this->fileData = fileData; + this->fileSize = fileSize; +} + +cfdp::SegmentationControl FileDataInfo::getSegmentationControl() const { + return segCtrl; +} + +void FileDataInfo::setSegmentationControl(cfdp::SegmentationControl segCtrl) { + this->segCtrl = segCtrl; +} diff --git a/src/fsfw/cfdp/pdu/FileDataInfo.h b/src/fsfw/cfdp/pdu/FileDataInfo.h new file mode 100644 index 00000000..1fcc6ff0 --- /dev/null +++ b/src/fsfw/cfdp/pdu/FileDataInfo.h @@ -0,0 +1,45 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_FILEDATAINFO_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_FILEDATAINFO_H_ + +#include +#include + +class FileDataInfo { +public: + FileDataInfo(cfdp::FileSize& offset); + FileDataInfo(cfdp::FileSize& offset, const uint8_t* fileData, size_t fileSize); + + 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; + void setRecordContinuationState(cfdp::RecordContinuationState recContState); + void setSegmentationControl(cfdp::SegmentationControl segCtrl); + + size_t getSegmentMetadataLen() const; + void setSegmentMetadataLen(size_t len); + void setSegmentMetadata(const uint8_t* ptr); + bool hasSegmentMetadata() const; + void setSegmentMetadataFlag(bool enable); + ReturnValue_t addSegmentMetadataInfo(cfdp::RecordContinuationState recContState, + const uint8_t* segmentMetadata, size_t segmentMetadataLen); + const uint8_t* getSegmentMetadata(size_t* segmentMetadataLen = nullptr); + +private: + cfdp::SegmentMetadataFlag segmentMetadataFlag = cfdp::SegmentMetadataFlag::NOT_PRESENT; + cfdp::SegmentationControl segCtrl = + cfdp::SegmentationControl::NO_RECORD_BOUNDARIES_PRESERVATION; + cfdp::FileSize& offset; + const uint8_t* fileData = nullptr; + size_t fileSize = 0; + cfdp::RecordContinuationState recContState = cfdp::RecordContinuationState::NO_START_NO_END; + size_t segmentMetadataLen = 0; + const uint8_t* segmentMetadata = nullptr; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_FILEDATAINFO_H_ */ diff --git a/src/fsfw/cfdp/pdu/FileDataSerializer.cpp b/src/fsfw/cfdp/pdu/FileDataSerializer.cpp new file mode 100644 index 00000000..4488e368 --- /dev/null +++ b/src/fsfw/cfdp/pdu/FileDataSerializer.cpp @@ -0,0 +1,54 @@ +#include "FileDataSerializer.h" +#include + +FileDataSerializer::FileDataSerializer(PduConfig& conf, FileDataInfo& info): + HeaderSerializer(conf, cfdp::PduType::FILE_DATA, 0, info.getSegmentMetadataFlag()), + info(info) { + update(); +} + +void FileDataSerializer::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); + if(result != HasReturnvaluesIF::RETURN_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(); + **buffer = info.getRecordContinuationState() << 6 | segmentMetadataLen; + *buffer += 1; + *size += 1; + readOnlyPtr = info.getSegmentMetadata(); + std::memcpy(*buffer, readOnlyPtr, segmentMetadataLen); + *buffer += segmentMetadataLen; + *size += segmentMetadataLen; + } + cfdp::FileSize& offset = info.getOffset(); + result = offset.serialize(this->getLargeFileFlag(), buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + size_t fileSize = 0; + readOnlyPtr = info.getFileData(&fileSize); + if(*size + fileSize > maxSize) { + return SerializeIF::BUFFER_TOO_SHORT; + } + std::memcpy(*buffer, readOnlyPtr, fileSize); + *buffer += fileSize; + *size += fileSize; + return HasReturnvaluesIF::RETURN_OK; +} + +size_t FileDataSerializer::getSerializedSize() const { + return HeaderSerializer::getSerializedSize() + info.getSerializedSize(this->getLargeFileFlag()); +} diff --git a/src/fsfw/cfdp/pdu/FileDataSerializer.h b/src/fsfw/cfdp/pdu/FileDataSerializer.h new file mode 100644 index 00000000..b0153528 --- /dev/null +++ b/src/fsfw/cfdp/pdu/FileDataSerializer.h @@ -0,0 +1,23 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_FILEDATASERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_FILEDATASERIALIZER_H_ + +#include "FileDataInfo.h" +#include "../definitions.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/FileDirectiveDeserializer.cpp b/src/fsfw/cfdp/pdu/FileDirectiveDeserializer.cpp new file mode 100644 index 00000000..b348c5bd --- /dev/null +++ b/src/fsfw/cfdp/pdu/FileDirectiveDeserializer.cpp @@ -0,0 +1,55 @@ +#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 != HasReturnvaluesIF::RETURN_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 HasReturnvaluesIF::RETURN_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/FileDirectiveDeserializer.h b/src/fsfw/cfdp/pdu/FileDirectiveDeserializer.h new file mode 100644 index 00000000..257fb5c0 --- /dev/null +++ b/src/fsfw/cfdp/pdu/FileDirectiveDeserializer.h @@ -0,0 +1,41 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_FILEDIRECTIVEDESERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_FILEDIRECTIVEDESERIALIZER_H_ + +#include "../definitions.h" +#include "fsfw/cfdp/pdu/HeaderDeserializer.h" + +/** + * @brief This class is used to deserialize a PDU file directive header from raw memory. + * @details + * Base class for other file directives. + * This is a zero-copy implementation and #parseData needs to be called to ensure the data is + * valid. + */ +class FileDirectiveDeserializer: public HeaderDeserializer { +public: + FileDirectiveDeserializer(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; + + cfdp::FileDirectives getFileDirective() const; + + void setEndianness(SerializeIF::Endianness endianness); + SerializeIF::Endianness getEndianness() const; + +protected: + bool checkFileDirective(uint8_t rawByte); + +private: + void setFileDirective(cfdp::FileDirectives fileDirective); + cfdp::FileDirectives fileDirective = cfdp::FileDirectives::INVALID_DIRECTIVE; + SerializeIF::Endianness endianness = SerializeIF::Endianness::NETWORK; +}; + + + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_FILEDIRECTIVEDESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/FileDirectiveSerializer.cpp b/src/fsfw/cfdp/pdu/FileDirectiveSerializer.cpp new file mode 100644 index 00000000..89600d1d --- /dev/null +++ b/src/fsfw/cfdp/pdu/FileDirectiveSerializer.cpp @@ -0,0 +1,39 @@ +#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 HasReturnvaluesIF::RETURN_FAILED; + } + if(FileDirectiveSerializer::getWholePduSize() > maxSize) { + return BUFFER_TOO_SHORT; + } + ReturnValue_t result = HeaderSerializer::serialize(buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + if(*size >= maxSize) { + return BUFFER_TOO_SHORT; + } + **buffer = directiveCode; + *buffer += 1; + *size += 1; + return HasReturnvaluesIF::RETURN_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 new file mode 100644 index 00000000..75a3582d --- /dev/null +++ b/src/fsfw/cfdp/pdu/FileDirectiveSerializer.h @@ -0,0 +1,28 @@ +#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 new file mode 100644 index 00000000..e6b7e9b4 --- /dev/null +++ b/src/fsfw/cfdp/pdu/FinishedInfo.cpp @@ -0,0 +1,111 @@ +#include "FinishedInfo.h" + +FinishedInfo::FinishedInfo() { +} + + +FinishedInfo::FinishedInfo(cfdp::ConditionCode conditionCode, + cfdp::FinishedDeliveryCode deliveryCode, cfdp::FinishedFileStatus fileStatus): + conditionCode(conditionCode), deliveryCode(deliveryCode), fileStatus(fileStatus) { +} + +size_t FinishedInfo::getSerializedSize() const { + size_t size = 1; + if(hasFsResponses()) { + for(size_t idx = 0; idx < fsResponsesLen; idx++) { + size += fsResponses[idx]->getSerializedSize(); + } + } + if(this->faultLocation != nullptr) { + size += faultLocation->getSerializedSize(); + } + return size; +} + +bool FinishedInfo::hasFsResponses() const { + if(fsResponses != nullptr and fsResponsesLen > 0) { + return true; + } + return false; +} +bool FinishedInfo::canHoldFsResponses() const { + if(fsResponses != nullptr and fsResponsesMaxLen > 0) { + return true; + } + return false; +} + + +ReturnValue_t FinishedInfo::setFilestoreResponsesArray(FilestoreResponseTlv** fsResponses, + size_t* fsResponsesLen, const size_t* maxFsResponsesLen) { + this->fsResponses = fsResponses; + if(fsResponsesLen != nullptr) { + this->fsResponsesLen = *fsResponsesLen; + if(this->fsResponsesMaxLen < *fsResponsesLen) { + this->fsResponsesMaxLen = this->fsResponsesLen; + } + } + if(maxFsResponsesLen != nullptr) { + this->fsResponsesMaxLen = *maxFsResponsesLen; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t FinishedInfo::getFilestoreResonses(FilestoreResponseTlv ***fsResponses, + size_t *fsResponsesLen, size_t* fsResponsesMaxLen) { + if(fsResponses == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + *fsResponses = this->fsResponses; + if(fsResponsesLen != nullptr) { + *fsResponsesLen = this->fsResponsesLen; + } + if(fsResponsesMaxLen != nullptr) { + *fsResponsesMaxLen = this->fsResponsesMaxLen; + } + return HasReturnvaluesIF::RETURN_OK; +} + +void FinishedInfo::setFaultLocation(EntityIdTlv *faultLocation) { + this->faultLocation = faultLocation; +} + +ReturnValue_t FinishedInfo::getFaultLocation(EntityIdTlv** faultLocation) { + if(this->faultLocation == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + *faultLocation = this->faultLocation; + return HasReturnvaluesIF::RETURN_OK; +} + +cfdp::ConditionCode FinishedInfo::getConditionCode() const { + return conditionCode; +} + +void FinishedInfo::setConditionCode(cfdp::ConditionCode conditionCode) { + this->conditionCode = conditionCode; +} + +cfdp::FinishedDeliveryCode FinishedInfo::getDeliveryCode() const { + return deliveryCode; +} + +void FinishedInfo::setDeliveryCode(cfdp::FinishedDeliveryCode deliveryCode) { + this->deliveryCode = deliveryCode; +} + +cfdp::FinishedFileStatus FinishedInfo::getFileStatus() const { + return fileStatus; +} + +void FinishedInfo::setFilestoreResponsesArrayLen(size_t fsResponsesLen) { + this->fsResponsesLen = fsResponsesLen; +} + +size_t FinishedInfo::getFsResponsesLen() const { + return fsResponsesLen; +} + +void FinishedInfo::setFileStatus(cfdp::FinishedFileStatus fileStatus) { + this->fileStatus = fileStatus; +} diff --git a/src/fsfw/cfdp/pdu/FinishedInfo.h b/src/fsfw/cfdp/pdu/FinishedInfo.h new file mode 100644 index 00000000..18552df5 --- /dev/null +++ b/src/fsfw/cfdp/pdu/FinishedInfo.h @@ -0,0 +1,45 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_FINISHINFO_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_FINISHINFO_H_ + +#include "fsfw/cfdp/tlv/EntityIdTlv.h" +#include "fsfw/cfdp/tlv/FilestoreResponseTlv.h" +#include "../definitions.h" + +class FinishedInfo { +public: + FinishedInfo(); + FinishedInfo(cfdp::ConditionCode conditionCode, cfdp::FinishedDeliveryCode deliveryCode, + cfdp::FinishedFileStatus fileStatus); + + size_t getSerializedSize() const; + + bool hasFsResponses() const; + bool canHoldFsResponses() const; + + ReturnValue_t setFilestoreResponsesArray(FilestoreResponseTlv** fsResponses, + size_t* fsResponsesLen, const size_t* maxFsResponseLen); + void setFaultLocation(EntityIdTlv* entityId); + + ReturnValue_t getFilestoreResonses(FilestoreResponseTlv ***fsResponses, + size_t *fsResponsesLen, size_t* fsResponsesMaxLen); + size_t getFsResponsesLen() const; + void setFilestoreResponsesArrayLen(size_t fsResponsesLen); + ReturnValue_t getFaultLocation(EntityIdTlv** entityId); + 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); + +private: + cfdp::ConditionCode conditionCode = cfdp::ConditionCode::NO_CONDITION_FIELD; + cfdp::FinishedDeliveryCode deliveryCode = cfdp::FinishedDeliveryCode::DATA_COMPLETE; + cfdp::FinishedFileStatus fileStatus = cfdp::FinishedFileStatus::DISCARDED_DELIBERATELY; + FilestoreResponseTlv** fsResponses = nullptr; + size_t fsResponsesLen = 0; + size_t fsResponsesMaxLen = 0; + EntityIdTlv* faultLocation = nullptr; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_FINISHINFO_H_ */ diff --git a/src/fsfw/cfdp/pdu/FinishedPduDeserializer.cpp b/src/fsfw/cfdp/pdu/FinishedPduDeserializer.cpp new file mode 100644 index 00000000..55528650 --- /dev/null +++ b/src/fsfw/cfdp/pdu/FinishedPduDeserializer.cpp @@ -0,0 +1,90 @@ +#include "FinishedPduDeserializer.h" + +FinishPduDeserializer::FinishPduDeserializer(const uint8_t *pduBuf, size_t maxSize, + FinishedInfo &info): FileDirectiveDeserializer(pduBuf, maxSize), finishedInfo(info) { +} + +ReturnValue_t FinishPduDeserializer::parseData() { + ReturnValue_t result = FileDirectiveDeserializer::parseData(); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + size_t currentIdx = FileDirectiveDeserializer::getHeaderSize(); + const uint8_t* buf = rawPtr + currentIdx; + size_t remSize = FileDirectiveDeserializer::getWholePduSize() - currentIdx; + if (remSize < 1) { + return SerializeIF::STREAM_TOO_SHORT; + } + uint8_t firstByte = *buf; + cfdp::ConditionCode condCode = static_cast((firstByte >> 4) & 0x0f); + finishedInfo.setConditionCode(condCode); + finishedInfo.setDeliveryCode(static_cast(firstByte >> 2 & 0b1)); + finishedInfo.setFileStatus(static_cast(firstByte & 0b11)); + buf += 1; + remSize -= 1; + currentIdx += 1; + if(remSize > 0) { + result = parseTlvs(remSize, currentIdx, buf, condCode); + } + return result; +} + +FinishedInfo& FinishPduDeserializer::getInfo() { + return finishedInfo; +} + +ReturnValue_t FinishPduDeserializer::parseTlvs(size_t remLen, size_t currentIdx, + const uint8_t* buf, cfdp::ConditionCode conditionCode) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_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; + 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 + // location is omitted + if (currentIdx + 2 > maxSize) { + return SerializeIF::STREAM_TOO_SHORT; + } + nextTlv = static_cast(*buf); + if (nextTlv == cfdp::TlvTypes::FILESTORE_RESPONSE) { + if(fsResponseArray == nullptr) { + if(not finishedInfo.canHoldFsResponses()) { + return cfdp::FINISHED_CANT_PARSE_FS_RESPONSES; + } + result = finishedInfo.getFilestoreResonses(&fsResponseArray, nullptr, + &fsResponseMaxArrayLen); + } + if(fsResponsesIdx == fsResponseMaxArrayLen) { + return cfdp::FINISHED_CANT_PARSE_FS_RESPONSES; + } + result = fsResponseArray[fsResponsesIdx]->deSerialize(&buf, &remLen, endianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + fsResponsesIdx += 1; + } else if(nextTlv == cfdp::TlvTypes::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 + conditionCode == cfdp::ConditionCode::UNSUPPORTED_CHECKSUM_TYPE) { + return cfdp::INVALID_TLV_TYPE; + } + result = finishedInfo.getFaultLocation(&faultLocation); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = faultLocation->deSerialize(&buf, &remLen, endianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } else { + return cfdp::INVALID_TLV_TYPE; + } + } + finishedInfo.setFilestoreResponsesArrayLen(fsResponsesIdx); + return result; +} diff --git a/src/fsfw/cfdp/pdu/FinishedPduDeserializer.h b/src/fsfw/cfdp/pdu/FinishedPduDeserializer.h new file mode 100644 index 00000000..dcbc23bd --- /dev/null +++ b/src/fsfw/cfdp/pdu/FinishedPduDeserializer.h @@ -0,0 +1,21 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_FINISHEDPDUDESERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_FINISHEDPDUDESERIALIZER_H_ + +#include "fsfw/cfdp/pdu/FinishedInfo.h" +#include "fsfw/cfdp/pdu/FileDirectiveDeserializer.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/FinishedPduSerializer.cpp b/src/fsfw/cfdp/pdu/FinishedPduSerializer.cpp new file mode 100644 index 00000000..98112ce2 --- /dev/null +++ b/src/fsfw/cfdp/pdu/FinishedPduSerializer.cpp @@ -0,0 +1,47 @@ +#include "FinishedPduSerializer.h" + +FinishPduSerializer::FinishPduSerializer(PduConfig &conf, FinishedInfo &finishInfo): + FileDirectiveSerializer(conf, cfdp::FileDirectives::FINISH, 0), finishInfo(finishInfo) { + updateDirectiveFieldLen(); +} + +size_t FinishPduSerializer::getSerializedSize() const { + return FinishPduSerializer::getWholePduSize(); +} + +void FinishPduSerializer::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); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(*size + 1 >= maxSize) { + return SerializeIF::BUFFER_TOO_SHORT; + } + **buffer = finishInfo.getConditionCode() << 4 | finishInfo.getDeliveryCode() << 2 | + finishInfo.getFileStatus(); + *size += 1; + *buffer += 1; + + if(finishInfo.hasFsResponses()) { + FilestoreResponseTlv** fsResponsesArray = nullptr; + size_t fsResponsesArrayLen = 0; + finishInfo.getFilestoreResonses(&fsResponsesArray, &fsResponsesArrayLen, nullptr); + for(size_t idx = 0; idx < fsResponsesArrayLen; idx++) { + result = fsResponsesArray[idx]->serialize(buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + } + EntityIdTlv* entityId = nullptr; + if(finishInfo.getFaultLocation(&entityId) == HasReturnvaluesIF::RETURN_OK) { + result = entityId->serialize(buffer, size, maxSize, streamEndianness); + } + return result; +} diff --git a/src/fsfw/cfdp/pdu/FinishedPduSerializer.h b/src/fsfw/cfdp/pdu/FinishedPduSerializer.h new file mode 100644 index 00000000..cfb067a5 --- /dev/null +++ b/src/fsfw/cfdp/pdu/FinishedPduSerializer.h @@ -0,0 +1,22 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_FINISHEDPDUSERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_FINISHEDPDUSERIALIZER_H_ + +#include "fsfw/cfdp/pdu/FileDirectiveSerializer.h" +#include "fsfw/cfdp/pdu/FileDataSerializer.h" +#include "FinishedInfo.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/HeaderDeserializer.cpp b/src/fsfw/cfdp/pdu/HeaderDeserializer.cpp new file mode 100644 index 00000000..39994eb5 --- /dev/null +++ b/src/fsfw/cfdp/pdu/HeaderDeserializer.cpp @@ -0,0 +1,136 @@ +#include +#include "HeaderDeserializer.h" +#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 HasReturnvaluesIF::RETURN_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 HasReturnvaluesIF::RETURN_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/HeaderDeserializer.h b/src/fsfw/cfdp/pdu/HeaderDeserializer.h new file mode 100644 index 00000000..d44d538f --- /dev/null +++ b/src/fsfw/cfdp/pdu/HeaderDeserializer.h @@ -0,0 +1,93 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_HEADERDESERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_HEADERDESERIALIZER_H_ + +#include "PduConfig.h" +#include "PduHeaderIF.h" +#include "fsfw/serialize/SerializeIF.h" +#include "fsfw/tmtcpacket/RedirectableDataPointerIF.h" +#include +#include + +struct PduHeaderFixedStruct { + uint8_t firstByte; + uint8_t pduDataFieldLenH; + uint8_t pduDataFieldLenL; + uint8_t fourthByte; + uint8_t variableFieldsStart; +}; + +/** + * @brief This class is used to deserialize a PDU header from raw memory. + * @details + * This is a zero-copy implementation and #parseData needs to be called to ensure the data is + * valid. + */ +class HeaderDeserializer: + public RedirectableDataPointerIF, + public PduHeaderIF { +public: + /** + * 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); + + /** + * This needs to be called before accessing the PDU fields to avoid segmentation faults. + * @return + * - RETURN_OK on parse success + * - RETURN_FAILED Invalid raw data + * - SerializeIF::BUFFER_TOO_SHORT if buffer is shorter than expected + */ + virtual ReturnValue_t parseData(); + size_t getHeaderSize() const; + + size_t getPduDataFieldLen() const override; + 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; + + void getSourceId(cfdp::EntityId& sourceId) const override; + void getDestId(cfdp::EntityId& destId) const override; + void getTransactionSeqNum(cfdp::TransactionSeqNum& seqNum) const override; + + ReturnValue_t deserResult = HasReturnvaluesIF::RETURN_OK; + + /** + * Can also be used to reset the pointer to a nullptr, but the getter functions will not + * perform nullptr checks! + * @param dataPtr + * @param maxSize + * @param args + * @return + */ + ReturnValue_t setData(uint8_t* dataPtr, size_t maxSize, + void* args = nullptr) override; + + size_t getMaxSize() const; +protected: + PduHeaderFixedStruct* fixedHeader = nullptr; + const uint8_t* rawPtr = nullptr; + size_t maxSize = 0; + +private: + + void assignVarLenField(cfdp::VarLenField* field, cfdp::WidthInBytes width, + void* sourcePtr) const; + void* sourceIdRaw = nullptr; + void* seqNumRaw = nullptr; + void* destIdRaw = nullptr; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_HEADERDESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/HeaderSerializer.cpp b/src/fsfw/cfdp/pdu/HeaderSerializer.cpp new file mode 100644 index 00000000..a5163b29 --- /dev/null +++ b/src/fsfw/cfdp/pdu/HeaderSerializer.cpp @@ -0,0 +1,135 @@ +#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 HasReturnvaluesIF::RETURN_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 != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = pduConf.seqNum.serialize(buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = pduConf.destId.serialize(buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + return HasReturnvaluesIF::RETURN_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 HasReturnvaluesIF::RETURN_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/HeaderSerializer.h b/src/fsfw/cfdp/pdu/HeaderSerializer.h new file mode 100644 index 00000000..61e9d74a --- /dev/null +++ b/src/fsfw/cfdp/pdu/HeaderSerializer.h @@ -0,0 +1,64 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_HEADERSERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_HEADERSERIALIZER_H_ + +#include "PduHeaderIF.h" +#include "fsfw/serialize/SerializeIF.h" +#include "../definitions.h" +#include "PduConfig.h" + +class HeaderSerializer: public SerializeIF, public PduHeaderIF { +public: + + HeaderSerializer(PduConfig& pduConf, cfdp::PduType pduType, + size_t initPduDataFieldLen, + cfdp::SegmentMetadataFlag segmentMetadataFlag = cfdp::SegmentMetadataFlag::NOT_PRESENT, + cfdp::SegmentationControl segCtrl = + cfdp::SegmentationControl::NO_RECORD_BOUNDARIES_PRESERVATION); + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + Endianness streamEndianness) const override; + + /** + * This only returns the length of the serialized hader. + * Use #getWholePduSize to get the length of the full packet, assuming that the PDU + * data field length was not properly. + * @return + */ + size_t getSerializedSize() const override; + + ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override; + + void setPduDataFieldLen(size_t pduDataFieldLen); + void setPduType(cfdp::PduType pduType); + void setSegmentMetadataFlag(cfdp::SegmentMetadataFlag); + + size_t getPduDataFieldLen() const override; + 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; + void setSegmentationControl(cfdp::SegmentationControl); + + void getSourceId(cfdp::EntityId& sourceId) const override; + void getDestId(cfdp::EntityId& destId) const override; + void getTransactionSeqNum(cfdp::TransactionSeqNum& seqNum) const override; +private: + cfdp::PduType pduType; + cfdp::SegmentMetadataFlag segmentMetadataFlag; + cfdp::SegmentationControl segmentationCtrl; + size_t pduDataFieldLen; + + PduConfig& pduConf; +}; + + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_HEADERSERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/KeepAlivePduDeserializer.cpp b/src/fsfw/cfdp/pdu/KeepAlivePduDeserializer.cpp new file mode 100644 index 00000000..f8778224 --- /dev/null +++ b/src/fsfw/cfdp/pdu/KeepAlivePduDeserializer.cpp @@ -0,0 +1,20 @@ +#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 != HasReturnvaluesIF::RETURN_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 new file mode 100644 index 00000000..a7016166 --- /dev/null +++ b/src/fsfw/cfdp/pdu/KeepAlivePduDeserializer.h @@ -0,0 +1,18 @@ +#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/KeepAlivePduSerializer.cpp b/src/fsfw/cfdp/pdu/KeepAlivePduSerializer.cpp new file mode 100644 index 00000000..7882562b --- /dev/null +++ b/src/fsfw/cfdp/pdu/KeepAlivePduSerializer.cpp @@ -0,0 +1,26 @@ +#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 != HasReturnvaluesIF::RETURN_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 new file mode 100644 index 00000000..57882d3f --- /dev/null +++ b/src/fsfw/cfdp/pdu/KeepAlivePduSerializer.h @@ -0,0 +1,21 @@ +#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 new file mode 100644 index 00000000..04e0d6d1 --- /dev/null +++ b/src/fsfw/cfdp/pdu/MetadataInfo.cpp @@ -0,0 +1,115 @@ +#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) { +} + +void MetadataInfo::setOptionsArray(cfdp::Tlv** optionsArray, size_t* optionsLen, + size_t* maxOptionsLen) { + this->optionsArray = optionsArray; + if(maxOptionsLen != nullptr) { + this->maxOptionsLen = *maxOptionsLen; + } + if(optionsLen != nullptr) { + this->optionsLen = *optionsLen; + } +} + +cfdp::ChecksumType MetadataInfo::getChecksumType() const { + return checksumType; +} + +void MetadataInfo::setChecksumType(cfdp::ChecksumType checksumType) { + this->checksumType = checksumType; +} + +bool MetadataInfo::isClosureRequested() const { + return closureRequested; +} + +void MetadataInfo::setClosureRequested(bool closureRequested) { + this->closureRequested = closureRequested; +} + +cfdp::Lv& MetadataInfo::getDestFileName() { + return destFileName; +} + +cfdp::FileSize& MetadataInfo::getFileSize() { + return fileSize; +} + +ReturnValue_t MetadataInfo::getOptions(cfdp::Tlv*** optionsArray, size_t *optionsLen, + size_t* maxOptsLen) { + if(optionsArray == nullptr or this->optionsArray == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + *optionsArray = this->optionsArray; + if(optionsLen != nullptr) { + *optionsLen = this->optionsLen; + } + if(maxOptsLen != nullptr) { + *maxOptsLen = this->maxOptionsLen; + } + return HasReturnvaluesIF::RETURN_OK; +} + +bool MetadataInfo::hasOptions() const { + if (optionsArray != nullptr and optionsLen > 0) { + return true; + } + return false; +} + +bool MetadataInfo::canHoldOptions() const { + if (optionsArray != nullptr and maxOptionsLen > 0) { + return true; + } + return false; +} + +size_t MetadataInfo::getSerializedSize(bool fssLarge) { + // 1 byte + minimal FSS 4 bytes + size_t size = 5; + if(fssLarge) { + size += 4; + } + size += sourceFileName.getSerializedSize(); + size += destFileName.getSerializedSize(); + if(hasOptions()) { + for(size_t idx = 0; idx < optionsLen; idx++) { + size += optionsArray[idx]->getSerializedSize(); + } + } + return size; +} + +void MetadataInfo::setDestFileName(cfdp::Lv &destFileName) { + this->destFileName = destFileName; +} + +void MetadataInfo::setSourceFileName(cfdp::Lv &sourceFileName) { + this->sourceFileName = sourceFileName; +} + +size_t MetadataInfo::getMaxOptionsLen() const { + return 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; +} + +cfdp::Lv& MetadataInfo::getSourceFileName() { + return sourceFileName; +} diff --git a/src/fsfw/cfdp/pdu/MetadataInfo.h b/src/fsfw/cfdp/pdu/MetadataInfo.h new file mode 100644 index 00000000..c5a9a0ef --- /dev/null +++ b/src/fsfw/cfdp/pdu/MetadataInfo.h @@ -0,0 +1,49 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_ + +#include "fsfw/cfdp/tlv/Tlv.h" +#include "fsfw/cfdp/tlv/Lv.h" +#include "fsfw/cfdp/FileSize.h" +#include "fsfw/cfdp/definitions.h" + +class MetadataInfo { +public: + MetadataInfo(bool closureRequested, cfdp::ChecksumType checksumType, cfdp::FileSize& fileSize, + cfdp::Lv& sourceFileName, cfdp::Lv& destFileName); + + size_t getSerializedSize(bool fssLarge = false); + + void setOptionsArray(cfdp::Tlv** optionsArray, size_t* optionsLen, size_t* maxOptionsLen); + cfdp::ChecksumType getChecksumType() const; + void setChecksumType(cfdp::ChecksumType checksumType); + bool isClosureRequested() const; + void setClosureRequested(bool closureRequested = false); + + void setDestFileName(cfdp::Lv& destFileName); + void setSourceFileName(cfdp::Lv& sourceFileName); + + cfdp::Lv& getDestFileName(); + cfdp::Lv& getSourceFileName(); + cfdp::FileSize& getFileSize(); + + bool hasOptions() const; + bool canHoldOptions() const; + ReturnValue_t getOptions(cfdp::Tlv*** optionsArray, size_t* optionsLen, size_t* maxOptsLen); + void setOptionsLen(size_t optionsLen); + size_t getOptionsLen() const; + void setMaxOptionsLen(size_t maxOptionsLen); + size_t getMaxOptionsLen() const; + +private: + bool closureRequested = false; + cfdp::ChecksumType checksumType; + cfdp::FileSize& fileSize; + cfdp::Lv& sourceFileName; + cfdp::Lv& destFileName; + + cfdp::Tlv** optionsArray = nullptr; + size_t optionsLen = 0; + size_t maxOptionsLen = 0; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_ */ diff --git a/src/fsfw/cfdp/pdu/MetadataPduDeserializer.cpp b/src/fsfw/cfdp/pdu/MetadataPduDeserializer.cpp new file mode 100644 index 00000000..ccfaf2c9 --- /dev/null +++ b/src/fsfw/cfdp/pdu/MetadataPduDeserializer.cpp @@ -0,0 +1,58 @@ +#include "MetadataPduDeserializer.h" + +MetadataPduDeserializer::MetadataPduDeserializer(const uint8_t *pduBuf, size_t maxSize, + MetadataInfo &info): FileDirectiveDeserializer(pduBuf, maxSize), info(info) { +} + +ReturnValue_t MetadataPduDeserializer::parseData() { + ReturnValue_t result = FileDirectiveDeserializer::parseData(); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + size_t currentIdx = FileDirectiveDeserializer::getHeaderSize(); + const uint8_t* buf = rawPtr + currentIdx; + size_t remSize = FileDirectiveDeserializer::getWholePduSize() - currentIdx; + if (remSize < 1) { + return SerializeIF::STREAM_TOO_SHORT; + } + info.setClosureRequested((*buf >> 6) & 0x01); + info.setChecksumType(static_cast(*buf & 0x0f)); + remSize -= 1; + buf += 1; + auto endianness = getEndianness(); + result = info.getFileSize().deSerialize(&buf, &remSize, endianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = info.getSourceFileName().deSerialize(&buf, &remSize, endianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = info.getDestFileName().deSerialize(&buf, &remSize, endianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + info.setOptionsLen(0); + if (remSize > 0) { + if(not info.canHoldOptions()) { + return cfdp::METADATA_CANT_PARSE_OPTIONS; + } + cfdp::Tlv** optionsArray = nullptr; + size_t optsMaxLen = 0; + size_t optsIdx = 0; + info.getOptions(&optionsArray, nullptr, &optsMaxLen); + while(remSize > 0) { + if(optsIdx > optsMaxLen) { + return cfdp::METADATA_CANT_PARSE_OPTIONS; + } + result = optionsArray[optsIdx]->deSerialize(&buf, &remSize, endianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + optsIdx++; + } + info.setOptionsLen(optsIdx); + } + return result; +} diff --git a/src/fsfw/cfdp/pdu/MetadataPduDeserializer.h b/src/fsfw/cfdp/pdu/MetadataPduDeserializer.h new file mode 100644 index 00000000..a3b343b4 --- /dev/null +++ b/src/fsfw/cfdp/pdu/MetadataPduDeserializer.h @@ -0,0 +1,18 @@ +#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/MetadataPduSerializer.cpp b/src/fsfw/cfdp/pdu/MetadataPduSerializer.cpp new file mode 100644 index 00000000..1d2d67c2 --- /dev/null +++ b/src/fsfw/cfdp/pdu/MetadataPduSerializer.cpp @@ -0,0 +1,54 @@ +#include "MetadataPduSerializer.h" + +MetadataPduSerializer::MetadataPduSerializer(PduConfig &conf, MetadataInfo &info): + FileDirectiveSerializer(conf, cfdp::FileDirectives::METADATA, 5), info(info) { + updateDirectiveFieldLen(); +} + +void MetadataPduSerializer::updateDirectiveFieldLen() { + setDirectiveDataFieldLen(info.getSerializedSize(getLargeFileFlag())); +} + +size_t MetadataPduSerializer::getSerializedSize() const { + return FileDirectiveSerializer::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); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(*size + 1 >= maxSize) { + return SerializeIF::BUFFER_TOO_SHORT; + } + **buffer = info.isClosureRequested() << 6 | info.getChecksumType(); + *buffer += 1; + *size += 1; + result = info.getFileSize().serialize(buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = info.getSourceFileName().serialize(buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = info.getDestFileName().serialize(buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + if(info.hasOptions()) { + cfdp::Tlv** optsArray = nullptr; + size_t optsLen = 0; + info.getOptions(&optsArray, &optsLen, nullptr); + for(size_t idx = 0; idx < optsLen; idx++) { + result = optsArray[idx]->serialize(buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + } + return result; +} diff --git a/src/fsfw/cfdp/pdu/MetadataPduSerializer.h b/src/fsfw/cfdp/pdu/MetadataPduSerializer.h new file mode 100644 index 00000000..6cbead49 --- /dev/null +++ b/src/fsfw/cfdp/pdu/MetadataPduSerializer.h @@ -0,0 +1,23 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_METADATAPDUSERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_METADATAPDUSERIALIZER_H_ + +#include "fsfw/cfdp/pdu/MetadataInfo.h" +#include "fsfw/cfdp/pdu/FileDirectiveSerializer.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 new file mode 100644 index 00000000..d11aabc1 --- /dev/null +++ b/src/fsfw/cfdp/pdu/NakInfo.cpp @@ -0,0 +1,83 @@ +#include "NakInfo.h" + +NakInfo::NakInfo(cfdp::FileSize startOfScope, cfdp::FileSize endOfScope): + startOfScope(startOfScope), endOfScope(endOfScope) { +} + +size_t NakInfo::getSerializedSize(bool fssLarge) { + size_t size = 8; + if(fssLarge) { + size += 8; + } + if(hasSegmentRequests()) { + if(fssLarge) { + size += segmentRequestsLen * 16; + } else { + size += segmentRequestsLen * 8; + } + } + return size; +} + +bool NakInfo::hasSegmentRequests() const { + if(this->segmentRequests != nullptr and segmentRequestsLen > 0) { + return true; + } + return false; +} + +bool NakInfo::canHoldSegmentRequests() const { + if(this->segmentRequests != nullptr and maxSegmentRequestsLen > 0) { + return true; + } + return false; +} + +bool NakInfo::getSegmentRequests(SegmentRequest **segmentRequestPtr, + size_t *segmentRequestLen, size_t* maxSegmentRequestsLen) { + if(this->segmentRequests != nullptr) { + *segmentRequestPtr = this->segmentRequests; + } + if(segmentRequestLen != nullptr) { + *segmentRequestLen = this->segmentRequestsLen; + } + if(maxSegmentRequestsLen != nullptr) { + *maxSegmentRequestsLen = this->maxSegmentRequestsLen; + } + return true; +} + +void NakInfo::setSegmentRequests(SegmentRequest *segmentRequests, size_t* segmentRequestLen, + size_t* maxSegmentRequestLen) { + this->segmentRequests = segmentRequests; + if(segmentRequestLen != nullptr) { + this->segmentRequestsLen = *segmentRequestLen; + } + if(maxSegmentRequestLen != nullptr) { + this->maxSegmentRequestsLen = *maxSegmentRequestLen; + } +} + +cfdp::FileSize& NakInfo::getStartOfScope() { + return startOfScope; +} + +cfdp::FileSize& NakInfo::getEndOfScope() { + return endOfScope; +} + +size_t NakInfo::getSegmentRequestsLen() const { + return segmentRequestsLen; +} + +size_t NakInfo::getSegmentRequestsMaxLen() const { + return maxSegmentRequestsLen; +} + +void NakInfo::setSegmentRequestLen(size_t readLen) { + this->segmentRequestsLen = readLen; +} + +void NakInfo::setMaxSegmentRequestLen(size_t maxSize) { + this->maxSegmentRequestsLen = maxSize; +} diff --git a/src/fsfw/cfdp/pdu/NakInfo.h b/src/fsfw/cfdp/pdu/NakInfo.h new file mode 100644 index 00000000..839484be --- /dev/null +++ b/src/fsfw/cfdp/pdu/NakInfo.h @@ -0,0 +1,40 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_NAKINFO_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_NAKINFO_H_ + +#include "fsfw/cfdp/FileSize.h" +#include + +class NakInfo { +public: + using SegmentRequest = std::pair; + + NakInfo(cfdp::FileSize startOfScope, cfdp::FileSize endOfScope); + + void setSegmentRequests(SegmentRequest* segmentRequests, size_t* segmentRequestLen, + size_t* maxSegmentRequestLen); + + size_t getSerializedSize(bool fssLarge = false); + + cfdp::FileSize& getStartOfScope(); + cfdp::FileSize& getEndOfScope(); + + bool hasSegmentRequests() const; + bool canHoldSegmentRequests() const; + void setMaxSegmentRequestLen(size_t maxSize); + bool getSegmentRequests(SegmentRequest** segmentRequestPtr, size_t* segmentRequestLen, + size_t* maxSegmentRequestsLen); + size_t getSegmentRequestsLen() const; + size_t getSegmentRequestsMaxLen() const; + + //! This functions is more relevant for deserializers + void setSegmentRequestLen(size_t readLen); + +private: + cfdp::FileSize startOfScope; + cfdp::FileSize endOfScope; + SegmentRequest* segmentRequests = nullptr; + size_t segmentRequestsLen = 0; + size_t maxSegmentRequestsLen = 0; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_NAKINFO_H_ */ diff --git a/src/fsfw/cfdp/pdu/NakPduDeserializer.cpp b/src/fsfw/cfdp/pdu/NakPduDeserializer.cpp new file mode 100644 index 00000000..b2d02322 --- /dev/null +++ b/src/fsfw/cfdp/pdu/NakPduDeserializer.cpp @@ -0,0 +1,58 @@ +#include "NakPduDeserializer.h" + +NakPduDeserializer::NakPduDeserializer(const uint8_t *pduBuf, size_t maxSize, NakInfo &info): + FileDirectiveDeserializer(pduBuf, maxSize), nakInfo(info) { +} + +ReturnValue_t NakPduDeserializer::parseData() { + ReturnValue_t result = FileDirectiveDeserializer::parseData(); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + size_t currentIdx = FileDirectiveDeserializer::getHeaderSize(); + const uint8_t* buffer = rawPtr + currentIdx; + size_t remSize = FileDirectiveDeserializer::getWholePduSize() - currentIdx; + if (remSize < 1) { + return SerializeIF::STREAM_TOO_SHORT; + } + result = nakInfo.getStartOfScope().deSerialize(&buffer, &remSize, + SerializeIF::Endianness::NETWORK); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = nakInfo.getEndOfScope().deSerialize(&buffer, &remSize, + SerializeIF::Endianness::NETWORK); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + nakInfo.setSegmentRequestLen(0); + if(remSize > 0) { + if(not nakInfo.canHoldSegmentRequests()) { + return cfdp::NAK_CANT_PARSE_OPTIONS; + } + NakInfo::SegmentRequest* segReqs = nullptr; + size_t maxSegReqs = 0; + nakInfo.getSegmentRequests(&segReqs, nullptr, &maxSegReqs); + if(segReqs != nullptr) { + size_t idx = 0; + while(remSize > 0) { + if(idx == maxSegReqs) { + return cfdp::NAK_CANT_PARSE_OPTIONS; + } + result = segReqs[idx].first.deSerialize(&buffer, &remSize, + SerializeIF::Endianness::NETWORK); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = segReqs[idx].second.deSerialize(&buffer, &remSize, + SerializeIF::Endianness::NETWORK); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + idx++; + } + nakInfo.setSegmentRequestLen(idx); + } + } + return result; +} diff --git a/src/fsfw/cfdp/pdu/NakPduDeserializer.h b/src/fsfw/cfdp/pdu/NakPduDeserializer.h new file mode 100644 index 00000000..81726610 --- /dev/null +++ b/src/fsfw/cfdp/pdu/NakPduDeserializer.h @@ -0,0 +1,22 @@ +#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/NakPduSerializer.cpp b/src/fsfw/cfdp/pdu/NakPduSerializer.cpp new file mode 100644 index 00000000..9afb80cb --- /dev/null +++ b/src/fsfw/cfdp/pdu/NakPduSerializer.cpp @@ -0,0 +1,49 @@ +#include "NakPduSerializer.h" + +NakPduSerializer::NakPduSerializer(PduConfig& pduConf, NakInfo& nakInfo): + FileDirectiveSerializer(pduConf, cfdp::FileDirectives::NAK, 0), nakInfo(nakInfo) { + updateDirectiveFieldLen(); +} + +void NakPduSerializer::updateDirectiveFieldLen() { + this->setDirectiveDataFieldLen(nakInfo.getSerializedSize(getLargeFileFlag())); +} + +size_t NakPduSerializer::getSerializedSize() const { + return FileDirectiveSerializer::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); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = nakInfo.getStartOfScope().serialize(buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = nakInfo.getEndOfScope().serialize(buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(nakInfo.hasSegmentRequests()) { + NakInfo::SegmentRequest *segmentRequests = nullptr; + size_t segmentRequestLen = 0; + nakInfo.getSegmentRequests(&segmentRequests, &segmentRequestLen, nullptr); + for(size_t idx = 0; idx < segmentRequestLen; idx++) { + result = segmentRequests[idx].first.serialize(buffer, size, maxSize, + streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = segmentRequests[idx].second.serialize(buffer, size, maxSize, + streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + } + return result; +} diff --git a/src/fsfw/cfdp/pdu/NakPduSerializer.h b/src/fsfw/cfdp/pdu/NakPduSerializer.h new file mode 100644 index 00000000..556f0037 --- /dev/null +++ b/src/fsfw/cfdp/pdu/NakPduSerializer.h @@ -0,0 +1,41 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_NAKPDUSERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_NAKPDUSERIALIZER_H_ + +#include "fsfw/cfdp/pdu/FileDirectiveSerializer.h" +#include "fsfw/cfdp/definitions.h" +#include "fsfw/cfdp/FileSize.h" +#include "NakInfo.h" + +#include + +class NakPduSerializer: public FileDirectiveSerializer { +public: + + /** + * + * @param PduConf + * @param startOfScope + * @param endOfScope + * @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); + + size_t getSerializedSize() const override; + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + Endianness streamEndianness) const override; + + /** + * If you change the info struct, you might need to update the directive field length + * manually + */ + void updateDirectiveFieldLen(); +private: + NakInfo& nakInfo; + +}; + + + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_NAKPDUSERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/PduConfig.cpp b/src/fsfw/cfdp/pdu/PduConfig.cpp new file mode 100644 index 00000000..acf02f5b --- /dev/null +++ b/src/fsfw/cfdp/pdu/PduConfig.cpp @@ -0,0 +1,8 @@ +#include "PduConfig.h" + +PduConfig::PduConfig(cfdp::TransmissionModes mode, cfdp::TransactionSeqNum seqNum, + cfdp::EntityId sourceId, cfdp::EntityId destId, bool crcFlag, + bool largeFile, cfdp::Direction direction): + mode(mode), seqNum(seqNum), sourceId(sourceId), destId(destId), + crcFlag(crcFlag), largeFile(largeFile), direction(direction) { +} diff --git a/src/fsfw/cfdp/pdu/PduConfig.h b/src/fsfw/cfdp/pdu/PduConfig.h new file mode 100644 index 00000000..79d14a2e --- /dev/null +++ b/src/fsfw/cfdp/pdu/PduConfig.h @@ -0,0 +1,36 @@ +#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) {} +}; + +} + +class PduConfig { +public: + PduConfig(cfdp::TransmissionModes mode, cfdp::TransactionSeqNum seqNum, + cfdp::EntityId sourceId, cfdp::EntityId destId, bool crcFlag = false, + bool largeFile = false, cfdp::Direction direction = cfdp::Direction::TOWARDS_RECEIVER); + cfdp::TransmissionModes mode; + cfdp::TransactionSeqNum seqNum; + cfdp::EntityId sourceId; + cfdp::EntityId destId; + bool crcFlag; + bool largeFile; + cfdp::Direction direction; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_PDUCONFIG_H_ */ diff --git a/src/fsfw/cfdp/pdu/PduHeaderIF.h b/src/fsfw/cfdp/pdu/PduHeaderIF.h new file mode 100644 index 00000000..0ea8b4fe --- /dev/null +++ b/src/fsfw/cfdp/pdu/PduHeaderIF.h @@ -0,0 +1,37 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_PDUHEADERIF_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_PDUHEADERIF_H_ + +#include "PduConfig.h" +#include "../definitions.h" +#include + +/** + * @brief Generic interface to access all fields of a PDU header + * @details + * See CCSDS 727.0-B-5 pp.75 for more information about these fields + */ +class PduHeaderIF { +public: + virtual~ PduHeaderIF() {}; + + 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; + virtual void getSourceId(cfdp::EntityId& sourceId) const = 0; + virtual void getDestId(cfdp::EntityId& destId) const = 0; + virtual void getTransactionSeqNum(cfdp::TransactionSeqNum& seqNum) const = 0; +private: +}; + + + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_PDUHEADERIF_H_ */ diff --git a/src/fsfw/cfdp/pdu/PromptPduDeserializer.cpp b/src/fsfw/cfdp/pdu/PromptPduDeserializer.cpp new file mode 100644 index 00000000..abff805e --- /dev/null +++ b/src/fsfw/cfdp/pdu/PromptPduDeserializer.cpp @@ -0,0 +1,22 @@ +#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 != HasReturnvaluesIF::RETURN_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 HasReturnvaluesIF::RETURN_OK; +} diff --git a/src/fsfw/cfdp/pdu/PromptPduDeserializer.h b/src/fsfw/cfdp/pdu/PromptPduDeserializer.h new file mode 100644 index 00000000..97762243 --- /dev/null +++ b/src/fsfw/cfdp/pdu/PromptPduDeserializer.h @@ -0,0 +1,18 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_PROMPTPDUDESERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_PROMPTPDUDESERIALIZER_H_ + +#include "fsfw/cfdp/pdu/FileDirectiveDeserializer.h" + +class PromptPduDeserializer: public FileDirectiveDeserializer { +public: + PromptPduDeserializer(const uint8_t *pduBuf, size_t maxSize); + + cfdp::PromptResponseRequired getPromptResponseRequired() const; + ReturnValue_t parseData() override; +private: + cfdp::PromptResponseRequired responseRequired = cfdp::PromptResponseRequired::PROMPT_NAK; +}; + + + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_PROMPTPDUDESERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/PromptPduSerializer.cpp b/src/fsfw/cfdp/pdu/PromptPduSerializer.cpp new file mode 100644 index 00000000..599f8072 --- /dev/null +++ b/src/fsfw/cfdp/pdu/PromptPduSerializer.cpp @@ -0,0 +1,27 @@ +#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 != HasReturnvaluesIF::RETURN_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/PromptPduSerializer.h b/src/fsfw/cfdp/pdu/PromptPduSerializer.h new file mode 100644 index 00000000..79945fd7 --- /dev/null +++ b/src/fsfw/cfdp/pdu/PromptPduSerializer.h @@ -0,0 +1,18 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_PROMPTPDUSERIALIZER_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_PROMPTPDUSERIALIZER_H_ + +#include "fsfw/cfdp/pdu/FileDirectiveSerializer.h" + +class PromptPduSerializer: public FileDirectiveSerializer { +public: + PromptPduSerializer(PduConfig& conf, cfdp::PromptResponseRequired responseRequired); + + size_t getSerializedSize() const override; + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + Endianness streamEndianness) const override; +private: + cfdp::PromptResponseRequired responseRequired; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_PROMPTPDUSERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/VarLenField.cpp b/src/fsfw/cfdp/pdu/VarLenField.cpp new file mode 100644 index 00000000..ac2410c8 --- /dev/null +++ b/src/fsfw/cfdp/pdu/VarLenField.cpp @@ -0,0 +1,127 @@ +#include "VarLenField.h" +#include "fsfw/FSFW.h" +#include "fsfw/serviceinterface.h" +#include "fsfw/serialize/SerializeAdapter.h" + +cfdp::VarLenField::VarLenField(cfdp::WidthInBytes width, size_t value): VarLenField() { + ReturnValue_t result = this->setValue(width, value); + if(result != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_DISABLE_PRINTOUT == 0 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "cfdp::VarLenField: Setting value failed" << std::endl; +#else + sif::printWarning("cfdp::VarLenField: Setting value failed\n"); +#endif +#endif + } +} + +cfdp::VarLenField::VarLenField(): width(cfdp::WidthInBytes::ONE_BYTE) { + value.oneByte = 0; +} + +cfdp::WidthInBytes cfdp::VarLenField::getWidth() const { + return width; +} + +ReturnValue_t cfdp::VarLenField::setValue(cfdp::WidthInBytes widthInBytes, size_t value) { + switch(widthInBytes) { + case(cfdp::WidthInBytes::ONE_BYTE): { + if(value > UINT8_MAX) { + return HasReturnvaluesIF::RETURN_FAILED; + } + this->value.oneByte = value; + break; + } + case(cfdp::WidthInBytes::TWO_BYTES): { + if(value > UINT16_MAX) { + return HasReturnvaluesIF::RETURN_FAILED; + } + this->value.twoBytes = value; + break; + } + case(cfdp::WidthInBytes::FOUR_BYTES): { + if(value > UINT32_MAX) { + return HasReturnvaluesIF::RETURN_FAILED; + } + this->value.fourBytes = value; + break; + } + default: { + break; + } + } + this->width = widthInBytes; + return HasReturnvaluesIF::RETURN_OK; +} + +size_t cfdp::VarLenField::getValue() const { + switch(width) { + case(cfdp::WidthInBytes::ONE_BYTE): { + return value.oneByte; + } + case(cfdp::WidthInBytes::TWO_BYTES): { + return value.twoBytes; + } + case(cfdp::WidthInBytes::FOUR_BYTES): { + return value.fourBytes; + } + } + return 0; +} + +ReturnValue_t cfdp::VarLenField::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + switch(width) { + case(cfdp::WidthInBytes::ONE_BYTE): { + if (*size + 1 > maxSize) { + return BUFFER_TOO_SHORT; + } + **buffer = value.oneByte; + *size += 1; + *buffer += 1; + return HasReturnvaluesIF::RETURN_OK; + } + case(cfdp::WidthInBytes::TWO_BYTES): { + return SerializeAdapter::serialize(&value.twoBytes, buffer, size, maxSize, + streamEndianness); + } + case(cfdp::WidthInBytes::FOUR_BYTES): { + return SerializeAdapter::serialize(&value.fourBytes, buffer, size, maxSize, + streamEndianness); + } + default: { + return HasReturnvaluesIF::RETURN_FAILED; + } + } +} + +size_t cfdp::VarLenField::getSerializedSize() const { + return width; +} + +ReturnValue_t cfdp::VarLenField::deSerialize(cfdp::WidthInBytes width, const uint8_t **buffer, + size_t *size, Endianness streamEndianness) { + this->width = width; + return deSerialize(buffer, size, streamEndianness); +} + +ReturnValue_t cfdp::VarLenField::deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) { + switch(width) { + case(cfdp::WidthInBytes::ONE_BYTE): { + value.oneByte = **buffer; + *size += 1; + return HasReturnvaluesIF::RETURN_OK; + } + case(cfdp::WidthInBytes::TWO_BYTES): { + return SerializeAdapter::deSerialize(&value.twoBytes, buffer, size, streamEndianness); + } + case(cfdp::WidthInBytes::FOUR_BYTES): { + return SerializeAdapter::deSerialize(&value.fourBytes, buffer, size, streamEndianness); + } + default: { + return HasReturnvaluesIF::RETURN_FAILED; + } + } +} diff --git a/src/fsfw/cfdp/pdu/VarLenField.h b/src/fsfw/cfdp/pdu/VarLenField.h new file mode 100644 index 00000000..01bcfaed --- /dev/null +++ b/src/fsfw/cfdp/pdu/VarLenField.h @@ -0,0 +1,45 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_VARLENFIELD_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_VARLENFIELD_H_ + +#include "../definitions.h" +#include "fsfw/serialize/SerializeIF.h" +#include +#include + +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; +}; + +} + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_VARLENFIELD_H_ */ diff --git a/src/fsfw/cfdp/tlv/CMakeLists.txt b/src/fsfw/cfdp/tlv/CMakeLists.txt new file mode 100644 index 00000000..24459cf8 --- /dev/null +++ b/src/fsfw/cfdp/tlv/CMakeLists.txt @@ -0,0 +1,10 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + EntityIdTlv.cpp + FilestoreRequestTlv.cpp + FilestoreResponseTlv.cpp + Lv.cpp + Tlv.cpp + FlowLabelTlv.cpp + MessageToUserTlv.cpp + FaultHandlerOverrideTlv.cpp +) \ No newline at end of file diff --git a/src/fsfw/cfdp/tlv/EntityIdTlv.cpp b/src/fsfw/cfdp/tlv/EntityIdTlv.cpp new file mode 100644 index 00000000..98b1094e --- /dev/null +++ b/src/fsfw/cfdp/tlv/EntityIdTlv.cpp @@ -0,0 +1,68 @@ +#include "EntityIdTlv.h" +#include + +EntityIdTlv::EntityIdTlv(cfdp::EntityId& entityId): entityId(entityId) { +} + +EntityIdTlv::~EntityIdTlv() { +} + +ReturnValue_t EntityIdTlv::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + if(maxSize < this->getSerializedSize()) { + return BUFFER_TOO_SHORT; + } + **buffer = cfdp::TlvTypes::ENTITY_ID; + *size += 1; + *buffer += 1; + size_t serLen = entityId.getSerializedSize(); + **buffer = serLen; + *size += 1; + *buffer += 1; + return entityId.serialize(buffer, size, maxSize, streamEndianness); +} + +size_t EntityIdTlv::getSerializedSize() const { + return getLengthField() + 1; +} + +ReturnValue_t EntityIdTlv::deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) { + if(*size < 3) { + return STREAM_TOO_SHORT; + } + cfdp::TlvTypes type = static_cast(**buffer); + if(type != cfdp::TlvTypes::ENTITY_ID) { + return cfdp::INVALID_TLV_TYPE; + } + *buffer += 1; + *size -= 1; + + cfdp::WidthInBytes width = static_cast(**buffer); + if (*size < static_cast(1 + width)) { + return STREAM_TOO_SHORT; + } + *buffer += 1; + *size -= 1; + + return entityId.deSerialize(width, buffer, size, streamEndianness); +} + +ReturnValue_t EntityIdTlv::deSerialize(cfdp::Tlv &tlv, Endianness endianness) { + const uint8_t* ptr = tlv.getValue() + 2; + size_t remSz = tlv.getSerializedSize() - 2; + cfdp::WidthInBytes width = static_cast(remSz); + return entityId.deSerialize(width, &ptr, &remSz, endianness); +} + +uint8_t EntityIdTlv::getLengthField() const { + return 1 + entityId.getSerializedSize(); +} + +cfdp::TlvTypes EntityIdTlv::getType() const { + return cfdp::TlvTypes::ENTITY_ID; +} + +cfdp::EntityId& EntityIdTlv::getEntityId() { + return entityId; +} diff --git a/src/fsfw/cfdp/tlv/EntityIdTlv.h b/src/fsfw/cfdp/tlv/EntityIdTlv.h new file mode 100644 index 00000000..5860ce05 --- /dev/null +++ b/src/fsfw/cfdp/tlv/EntityIdTlv.h @@ -0,0 +1,39 @@ +#ifndef FSFW_SRC_FSFW_CFDP_ENTITYIDTLV_H_ +#define FSFW_SRC_FSFW_CFDP_ENTITYIDTLV_H_ + +#include "fsfw/cfdp/tlv/Tlv.h" +#include "fsfw/cfdp/pdu/PduConfig.h" +#include "TlvIF.h" + +class EntityIdTlv: public TlvIF { +public: + EntityIdTlv(cfdp::EntityId& entityId); + virtual~ EntityIdTlv(); + + ReturnValue_t serialize(uint8_t **buffer, size_t *size, + size_t maxSize, Endianness streamEndianness) const override; + + size_t getSerializedSize() const override; + + /** + * Deserialize an entity ID from a raw TLV object + * @param tlv + * @param endianness + * @return + */ + ReturnValue_t deSerialize(cfdp::Tlv& tlv, Endianness endianness); + + ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override; + + uint8_t getLengthField() const override; + cfdp::TlvTypes getType() const override; + + cfdp::EntityId& getEntityId(); +private: + cfdp::EntityId& entityId; +}; + + + +#endif /* FSFW_SRC_FSFW_CFDP_ENTITYIDTLV_H_ */ diff --git a/src/fsfw/cfdp/tlv/FaultHandlerOverrideTlv.cpp b/src/fsfw/cfdp/tlv/FaultHandlerOverrideTlv.cpp new file mode 100644 index 00000000..f5ef9311 --- /dev/null +++ b/src/fsfw/cfdp/tlv/FaultHandlerOverrideTlv.cpp @@ -0,0 +1,64 @@ +#include "FaultHandlerOverrideTlv.h" + +FaultHandlerOverrideTlv::FaultHandlerOverrideTlv(cfdp::ConditionCode conditionCode, + cfdp::FaultHandlerCode handlerCode): + conditionCode(conditionCode), handlerCode(handlerCode) { +} + +FaultHandlerOverrideTlv::FaultHandlerOverrideTlv() { +} + +uint8_t FaultHandlerOverrideTlv::getLengthField() const { + return 1; +} + + +ReturnValue_t FaultHandlerOverrideTlv::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + if((maxSize < 3) or ((*size + 3) > maxSize)) { + return SerializeIF::BUFFER_TOO_SHORT; + } + **buffer = getType(); + *size += 1; + *buffer += 1; + **buffer = getLengthField(); + *size += 1; + *buffer += 1; + **buffer = this->conditionCode << 4 | this->handlerCode; + *buffer += 1; + *size += 1; + return HasReturnvaluesIF::RETURN_OK; +} + +size_t FaultHandlerOverrideTlv::getSerializedSize() const { + return getLengthField() + 2; +} + +ReturnValue_t FaultHandlerOverrideTlv::deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) { + if(*size < 3) { + return SerializeIF::STREAM_TOO_SHORT; + } + auto detectedType = static_cast(**buffer); + if(detectedType != cfdp::TlvTypes::FAULT_HANDLER) { + return cfdp::INVALID_TLV_TYPE; + } + *buffer += 1; + *size -= 1; + size_t detectedSize = **buffer; + if(detectedSize != getLengthField()) { + return HasReturnvaluesIF::RETURN_FAILED; + } + *buffer += 1; + *size += 1; + this->conditionCode = static_cast((**buffer >> 4) & 0x0f); + this->handlerCode = static_cast(**buffer & 0x0f); + *buffer += 1; + *size += 1; + return HasReturnvaluesIF::RETURN_OK; +} + + +cfdp::TlvTypes FaultHandlerOverrideTlv::getType() const { + return cfdp::TlvTypes::FAULT_HANDLER; +} diff --git a/src/fsfw/cfdp/tlv/FaultHandlerOverrideTlv.h b/src/fsfw/cfdp/tlv/FaultHandlerOverrideTlv.h new file mode 100644 index 00000000..7014ae0e --- /dev/null +++ b/src/fsfw/cfdp/tlv/FaultHandlerOverrideTlv.h @@ -0,0 +1,39 @@ +#ifndef FSFW_SRC_FSFW_CFDP_TLV_FAULTHANDLEROVERRIDETLV_H_ +#define FSFW_SRC_FSFW_CFDP_TLV_FAULTHANDLEROVERRIDETLV_H_ + +#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(); + FaultHandlerOverrideTlv(cfdp::ConditionCode conditionCode, cfdp::FaultHandlerCode handlerCode); + + ReturnValue_t serialize(uint8_t **buffer, size_t *size, + size_t maxSize, Endianness streamEndianness) const override; + + 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; + +private: + cfdp::ConditionCode conditionCode = cfdp::ConditionCode::NO_CONDITION_FIELD; + cfdp::FaultHandlerCode handlerCode = cfdp::FaultHandlerCode::RESERVED; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_TLV_FAULTHANDLEROVERRIDETLV_H_ */ diff --git a/src/fsfw/cfdp/tlv/FilestoreRequestTlv.cpp b/src/fsfw/cfdp/tlv/FilestoreRequestTlv.cpp new file mode 100644 index 00000000..044c4e9a --- /dev/null +++ b/src/fsfw/cfdp/tlv/FilestoreRequestTlv.cpp @@ -0,0 +1,83 @@ +#include "fsfw/cfdp/tlv/FilestoreRequestTlv.h" +#include "fsfw/FSFW.h" + +FilestoreRequestTlv::FilestoreRequestTlv(cfdp::FilestoreActionCode actionCode, + cfdp::Lv& firstFileName): FilestoreTlvBase(actionCode, firstFileName) { +} + +FilestoreRequestTlv::FilestoreRequestTlv(cfdp::Lv &firstFileName): + FilestoreTlvBase(cfdp::FilestoreActionCode::INVALID, firstFileName) { +} + +void FilestoreRequestTlv::setSecondFileName(cfdp::Lv *secondFileName) { + this->secondFileName = secondFileName; +} + +ReturnValue_t FilestoreRequestTlv::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + ReturnValue_t result = commonSerialize(buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = firstFileName.serialize(buffer, size, maxSize, + streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(requiresSecondFileName()) { + if(secondFileName == nullptr) { + secondFileNameMissing(); + return cfdp::FILESTORE_REQUIRES_SECOND_FILE; + } + secondFileName->serialize(buffer, size, maxSize, streamEndianness); + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t FilestoreRequestTlv::deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) { + ReturnValue_t result = commonDeserialize(buffer, size, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return deSerializeFromValue(buffer, size, streamEndianness); +} + +ReturnValue_t FilestoreRequestTlv::deSerialize(cfdp::Tlv &tlv, + SerializeIF::Endianness endianness) { + const uint8_t* ptr = tlv.getValue(); + size_t remSz = tlv.getSerializedSize(); + + return deSerializeFromValue(&ptr, &remSz, endianness); +} + +uint8_t FilestoreRequestTlv::getLengthField() const { + size_t secondFileNameLen = 0; + if(secondFileName != nullptr and requiresSecondFileName()) { + secondFileNameLen = secondFileName->getSerializedSize(); + } + return 1 + firstFileName.getSerializedSize() + secondFileNameLen; +} + +ReturnValue_t FilestoreRequestTlv::deSerializeFromValue(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) { + this->actionCode = static_cast((**buffer >> 4) & 0x0f); + *buffer += 1; + *size -= 1; + ReturnValue_t result = firstFileName.deSerialize(buffer, size, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(requiresSecondFileName()) { + if(secondFileName == nullptr) { + secondFileNameMissing(); + return HasReturnvaluesIF::RETURN_FAILED; + } + result = secondFileName->deSerialize(buffer, size, streamEndianness); + } + return result; +} + +cfdp::TlvTypes FilestoreRequestTlv::getType() const { + return cfdp::TlvTypes::FILESTORE_REQUEST; +} diff --git a/src/fsfw/cfdp/tlv/FilestoreRequestTlv.h b/src/fsfw/cfdp/tlv/FilestoreRequestTlv.h new file mode 100644 index 00000000..d4cedbb2 --- /dev/null +++ b/src/fsfw/cfdp/tlv/FilestoreRequestTlv.h @@ -0,0 +1,45 @@ +#ifndef FSFW_SRC_FSFW_CFDP_FILESTOREREQUESTTLV_H_ +#define FSFW_SRC_FSFW_CFDP_FILESTOREREQUESTTLV_H_ + +#include "fsfw/cfdp/tlv/FilestoreTlvBase.h" +#include "fsfw/cfdp/tlv/Tlv.h" +#include "TlvIF.h" +#include "Lv.h" +#include "../definitions.h" + +class FilestoreRequestTlv: + public cfdp::FilestoreTlvBase { +public: + FilestoreRequestTlv(cfdp::FilestoreActionCode actionCode, cfdp::Lv& firstFileName); + + FilestoreRequestTlv(cfdp::Lv& firstFileName); + + void setSecondFileName(cfdp::Lv* secondFileName); + + ReturnValue_t serialize(uint8_t **buffer, size_t *size, + size_t maxSize, Endianness streamEndianness) const override; + + /** + * Deserialize a FS request from a raw TLV object + * @param tlv + * @param endianness + * @return + */ + ReturnValue_t deSerialize(cfdp::Tlv& tlv, Endianness endianness); + + ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override; + + uint8_t getLengthField() const override; + cfdp::TlvTypes getType() const override; + +private: + cfdp::Lv* secondFileName = nullptr; + + ReturnValue_t deSerializeFromValue(const uint8_t **buffer, size_t *size, + Endianness streamEndianness); +}; + + + +#endif /* FSFW_SRC_FSFW_CFDP_FILESTOREREQUESTTLV_H_ */ diff --git a/src/fsfw/cfdp/tlv/FilestoreResponseTlv.cpp b/src/fsfw/cfdp/tlv/FilestoreResponseTlv.cpp new file mode 100644 index 00000000..ec57579a --- /dev/null +++ b/src/fsfw/cfdp/tlv/FilestoreResponseTlv.cpp @@ -0,0 +1,124 @@ +#include "FilestoreResponseTlv.h" + +FilestoreResponseTlv::FilestoreResponseTlv(cfdp::FilestoreActionCode actionCode, uint8_t statusCode, + cfdp::Lv& firstFileName, cfdp::Lv* fsMsg): FilestoreTlvBase(actionCode, firstFileName), + statusCode(statusCode), filestoreMsg(fsMsg) { +} + +FilestoreResponseTlv::FilestoreResponseTlv(cfdp::Lv &firstFileName, cfdp::Lv* fsMsg): + FilestoreTlvBase(firstFileName), statusCode(0), filestoreMsg(fsMsg) { +} + +uint8_t FilestoreResponseTlv::getLengthField() const { + size_t optFieldsLen = 0; + if(secondFileName != nullptr) { + optFieldsLen += secondFileName->getSerializedSize(); + } + if(filestoreMsg != nullptr) { + optFieldsLen += filestoreMsg->getSerializedSize(); + } else { + optFieldsLen += 1; + } + return 1 + firstFileName.getSerializedSize() + optFieldsLen; +} + +void FilestoreResponseTlv::setSecondFileName(cfdp::Lv *secondFileName) { + this->secondFileName = secondFileName; +} + +void FilestoreResponseTlv::setFilestoreMessage(cfdp::Lv *filestoreMsg) { + this->filestoreMsg = filestoreMsg; +} + +ReturnValue_t FilestoreResponseTlv::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + ReturnValue_t result = commonSerialize(buffer, size, maxSize, streamEndianness, + true, this->statusCode); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = firstFileName.serialize(buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(requiresSecondFileName()) { + if(secondFileName == nullptr) { + secondFileNameMissing(); + return cfdp::FILESTORE_REQUIRES_SECOND_FILE; + } + } + if(filestoreMsg != nullptr) { + result = filestoreMsg->serialize(buffer, size, maxSize, streamEndianness); + } + else { + if(*size == maxSize) { + return SerializeIF::BUFFER_TOO_SHORT; + } + **buffer = 0; + *buffer += 1; + *size +=1; + } + return result; +} + +ReturnValue_t FilestoreResponseTlv::deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) { + ReturnValue_t result = commonDeserialize(buffer, size, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return deSerializeFromValue(buffer, size, streamEndianness); +} + +ReturnValue_t FilestoreResponseTlv::deSerializeFromValue(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) { + + // The common function above checks whether at least one byte is remaining + this->actionCode = static_cast((**buffer >> 4) & 0x0f); + this->statusCode = **buffer & 0x0f; + *buffer += 1; + *size -= 1; + ReturnValue_t result = firstFileName.deSerialize(buffer, size, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(requiresSecondFileName()) { + if(secondFileName == nullptr) { + return cfdp::FILESTORE_REQUIRES_SECOND_FILE; + } + result = secondFileName->deSerialize(buffer, size, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + // If the filestore message is not empty, the deserialization is only considered successfully + // if the filestore message can be parsed. Also, if data follows after the FS response, + // the FS msg needs to be set as well. + if(*size == 0 or (*size > 1 and filestoreMsg == nullptr)) { + // Filestore message missing or can't parse it + return cfdp::FILESTORE_RESPONSE_CANT_PARSE_FS_MESSAGE; + } + if(filestoreMsg == nullptr) { + *size -= 1; + *buffer += 1; + // Ignore empty filestore message + return HasReturnvaluesIF::RETURN_OK; + } + return filestoreMsg->deSerialize(buffer, size, streamEndianness); +} + +ReturnValue_t FilestoreResponseTlv::deSerialize(const cfdp::Tlv &tlv, Endianness endianness) { + const uint8_t* ptr = tlv.getValue(); + size_t remSz = tlv.getSerializedSize(); + + return deSerializeFromValue(&ptr, &remSz, endianness); +} + +uint8_t FilestoreResponseTlv::getStatusCode() const { + return statusCode; +} + + +cfdp::TlvTypes FilestoreResponseTlv::getType() const { + return cfdp::TlvTypes::FILESTORE_RESPONSE; +} diff --git a/src/fsfw/cfdp/tlv/FilestoreResponseTlv.h b/src/fsfw/cfdp/tlv/FilestoreResponseTlv.h new file mode 100644 index 00000000..1159fdca --- /dev/null +++ b/src/fsfw/cfdp/tlv/FilestoreResponseTlv.h @@ -0,0 +1,50 @@ +#ifndef FSFW_SRC_FSFW_CFDP_FILESTORERESPONSETLV_H_ +#define FSFW_SRC_FSFW_CFDP_FILESTORERESPONSETLV_H_ + +#include "fsfw/cfdp/tlv/FilestoreTlvBase.h" +#include "fsfw/cfdp/tlv/Tlv.h" +#include "TlvIF.h" +#include "Lv.h" + +class FilestoreResponseTlv: + public cfdp::FilestoreTlvBase { +public: + + FilestoreResponseTlv(cfdp::Lv& firstFileName, cfdp::Lv* fsMsg); + + FilestoreResponseTlv(cfdp::FilestoreActionCode actionCode, uint8_t statusCode, + cfdp::Lv& firstFileName, cfdp::Lv* fsMsg); + + uint8_t getStatusCode() const; + void setSecondFileName(cfdp::Lv* secondFileName); + void setFilestoreMessage(cfdp::Lv* filestoreMsg); + + ReturnValue_t serialize(uint8_t **buffer, size_t *size, + size_t maxSize, Endianness streamEndianness) const override; + + /** + * Deserialize a filestore response from a raw TLV object + * @param tlv + * @param endianness + * @return + */ + ReturnValue_t deSerialize(const cfdp::Tlv& tlv, Endianness endianness); + + ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override; + + uint8_t getLengthField() const override; + cfdp::TlvTypes getType() const override; + +private: + uint8_t statusCode; + cfdp::Lv* secondFileName = nullptr; + cfdp::Lv* filestoreMsg = nullptr; + + ReturnValue_t deSerializeFromValue(const uint8_t **buffer, size_t *size, + Endianness streamEndianness); +}; + + + +#endif /* FSFW_SRC_FSFW_CFDP_FILESTORERESPONSETLV_H_ */ diff --git a/src/fsfw/cfdp/tlv/FilestoreTlvBase.h b/src/fsfw/cfdp/tlv/FilestoreTlvBase.h new file mode 100644 index 00000000..f81b8807 --- /dev/null +++ b/src/fsfw/cfdp/tlv/FilestoreTlvBase.h @@ -0,0 +1,176 @@ +#ifndef FSFW_SRC_FSFW_CFDP_FILESTOREREQUESTBASE_H_ +#define FSFW_SRC_FSFW_CFDP_FILESTOREREQUESTBASE_H_ + +#include +#include +#include +#include +#include +#include +#include + +namespace cfdp { + +enum FilestoreActionCode { + CREATE_FILE = 0b0000, + DELETE_FILE = 0b0001, + // Second file name present + RENAME_FILE = 0b0010, + // Second file name present + APPEND_FILE = 0b0011, + // Second file name present + REPLACE_FILE = 0b0100, + CREATE_DIRECTORY = 0b0101, + REMOVE_DIRECTORY = 0b0110, + // Delete file if present + DENY_FILE = 0b0111, + // Remove directory if present + DNEY_DIRECTORY = 0b1000, + INVALID = 0b1111 +}; + +// FSR = Filestore Response +static constexpr uint8_t FSR_SUCCESS = 0b0000; +static constexpr uint8_t FSR_NOT_PERFORMED = 0b1111; + +static constexpr uint8_t FSR_CREATE_NOT_ALLOWED = 0b0001; + +static constexpr uint8_t FSR_DEL_FILE_NOT_EXISTS = 0b0001; +static constexpr uint8_t FSR_DEL_NOT_ALLOWED = 0b0010; + +static constexpr uint8_t FSR_RENAME_OLD_FILE_NOT_EXISTS = 0b0001; +static constexpr uint8_t FSR_RENAME_NEW_FILE_ALREADY_EXISTS = 0b0010; +static constexpr uint8_t FSR_RENAME_NOT_ALLOWED = 0b0011; + +static constexpr uint8_t FSR_APPEND_FILE_1_NOT_EXISTS = 0b0001; +static constexpr uint8_t FSR_APPEND_FILE_2_NOT_EXISTS = 0b0010; +static constexpr uint8_t FSR_APPEND_NOT_ALLOWED = 0b0011; + +static constexpr uint8_t FSR_REPLACE_FILE_1_NOT_EXISTS = 0b0001; +static constexpr uint8_t FSR_REPLACE_FILE_2_NOT_EXISTS = 0b0010; +static constexpr uint8_t FSR_REPLACE_REPLACE_NOT_ALLOWED = 0b0011; + +static constexpr uint8_t FSR_CREATE_DIR_NOT_POSSIBLE = 0b0001; + +static constexpr uint8_t FSR_DELDIR_NOT_EXISTS = 0b0001; +static constexpr uint8_t FSR_DELDIR_NOT_ALLOWED = 0b0010; + +static constexpr uint8_t FSR_DENY_FILE_NOT_ALLOWED = 0b0010; + +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): + actionCode(actionCode), firstFileName(firstFileName) {}; + + ReturnValue_t commonSerialize(uint8_t **buffer, size_t *size, + size_t maxSize, Endianness streamEndianness, + bool isResponse = false, uint8_t responseStatusCode = 0) const { + if(buffer == nullptr or size == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + if(maxSize < 3) { + return SerializeIF::BUFFER_TOO_SHORT; + } + **buffer = getType(); + *buffer += 1; + *size += 1; + **buffer = getLengthField(); + *buffer += 1; + *size += 1; + **buffer = this->actionCode << 4; + if(isResponse) { + **buffer |= responseStatusCode; + } + *buffer += 1; + *size += 1; + return HasReturnvaluesIF::RETURN_OK; + } + + ReturnValue_t commonDeserialize(const uint8_t **buffer, size_t *size, + SerializeIF::Endianness streamEndianness) { + if(buffer == nullptr or size == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + if(*size < 3) { + return SerializeIF::STREAM_TOO_SHORT; + } + cfdp::TlvTypes type = static_cast(**buffer); + if(type != getType()) { + return cfdp::INVALID_TLV_TYPE; + } + *size -= 1; + *buffer += 1; + + size_t remainingLength = **buffer; + *size -= 1; + *buffer += 1; + if(remainingLength == 0) { + return SerializeIF::STREAM_TOO_SHORT; + } + return HasReturnvaluesIF::RETURN_OK; + } + + bool requiresSecondFileName() const { + using namespace cfdp; + if(actionCode == FilestoreActionCode::RENAME_FILE or + actionCode == FilestoreActionCode::APPEND_FILE or + actionCode == FilestoreActionCode::REPLACE_FILE) { + return true; + } + return false; + } + + void secondFileNameMissing() const { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "FilestoreRequestTlv::deSerialize: Second file name required" + " but TLV pointer not set" << std::endl; +#else + sif::printWarning("FilestoreRequestTlv::deSerialize: Second file name required" + " but TLV pointer not set\n"); +#endif +#endif + } + + FilestoreActionCode getActionCode() const { + return actionCode; + } + + void setActionCode(FilestoreActionCode actionCode) { + this->actionCode = actionCode; + } + + cfdp::Lv& getFirstFileName() { + return firstFileName; + } + + ReturnValue_t convertToTlv(cfdp::Tlv& tlv, uint8_t *buffer, size_t maxSize, + Endianness streamEndianness) { + size_t serSize = 0; + uint8_t* valueStart = buffer + 2; + ReturnValue_t result = this->serialize(&buffer, &serSize, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + tlv.setValue(valueStart, serSize - 2); + tlv.setType(getType()); + return result; + } + + size_t getSerializedSize() const override { + return getLengthField() + 2; + } +protected: + FilestoreActionCode actionCode = FilestoreActionCode::INVALID; + cfdp::Lv& firstFileName; +}; + +} + + + +#endif /* FSFW_SRC_FSFW_CFDP_FILESTOREREQUESTBASE_H_ */ diff --git a/src/fsfw/cfdp/tlv/FlowLabelTlv.cpp b/src/fsfw/cfdp/tlv/FlowLabelTlv.cpp new file mode 100644 index 00000000..c5835414 --- /dev/null +++ b/src/fsfw/cfdp/tlv/FlowLabelTlv.cpp @@ -0,0 +1,5 @@ +#include "FlowLabelTlv.h" + +FlowLabelTlv::FlowLabelTlv(uint8_t* value, size_t size): + Tlv(cfdp::TlvTypes::FLOW_LABEL, value, size) { +} diff --git a/src/fsfw/cfdp/tlv/FlowLabelTlv.h b/src/fsfw/cfdp/tlv/FlowLabelTlv.h new file mode 100644 index 00000000..3375c361 --- /dev/null +++ b/src/fsfw/cfdp/tlv/FlowLabelTlv.h @@ -0,0 +1,13 @@ +#ifndef FSFW_SRC_FSFW_CFDP_TLV_FLOWLABELTLV_H_ +#define FSFW_SRC_FSFW_CFDP_TLV_FLOWLABELTLV_H_ + +#include "Tlv.h" + +class FlowLabelTlv: public cfdp::Tlv { +public: + FlowLabelTlv(uint8_t* value, size_t size); +private: + +}; + +#endif /* FSFW_SRC_FSFW_CFDP_TLV_FLOWLABELTLV_H_ */ diff --git a/src/fsfw/cfdp/tlv/Lv.cpp b/src/fsfw/cfdp/tlv/Lv.cpp new file mode 100644 index 00000000..fa3b99e7 --- /dev/null +++ b/src/fsfw/cfdp/tlv/Lv.cpp @@ -0,0 +1,88 @@ +#include "Lv.h" + +cfdp::Lv::Lv(const uint8_t *value, size_t size): value(value, size, true) { + if(size > 0) { + zeroLen = false; + } +} + +cfdp::Lv::Lv(): value(static_cast(nullptr), 0, true) { +} + +cfdp::Lv::Lv(const Lv& other): + value(other.value.getConstBuffer(), other.value.getSerializedSize() - 1, true) { + if(other.value.getSerializedSize() - 1 > 0) { + zeroLen = false; + } +} + +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) { + this->zeroLen = true; + } + this->value.setBuffer(value, otherSize); + return *this; +} + + +ReturnValue_t cfdp::Lv::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + if(maxSize < 1) { + return BUFFER_TOO_SHORT; + } + if(buffer == nullptr or size == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + if(zeroLen) { + **buffer = 0; + *size += 1; + *buffer += 1; + return HasReturnvaluesIF::RETURN_OK; + } + return value.serialize(buffer, size, maxSize, streamEndianness); +} + +size_t cfdp::Lv::getSerializedSize() const { + if(zeroLen) { + return 1; + } + else if(value.getConstBuffer() == nullptr) { + return 0; + } + return value.getSerializedSize(); +} + +ReturnValue_t cfdp::Lv::deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) { + if(buffer == nullptr or size == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + if(*size < 1) { + return SerializeIF::STREAM_TOO_SHORT; + } + size_t lengthField = **buffer; + if(lengthField == 0) { + zeroLen = true; + *buffer += 1; + *size -= 1; + return HasReturnvaluesIF::RETURN_OK; + } else if(*size < lengthField + 1) { + return SerializeIF::STREAM_TOO_SHORT; + } + zeroLen = false; + // Zero-copy implementation + value.setBuffer(const_cast(*buffer + 1), lengthField); + *buffer += 1 + lengthField; + *size -= 1 + lengthField; + return HasReturnvaluesIF::RETURN_OK; +} + +const uint8_t* cfdp::Lv::getValue(size_t* size) const { + if(size != nullptr) { + // Length without length field + *size = value.getSerializedSize() - 1; + } + return value.getConstBuffer(); +} diff --git a/src/fsfw/cfdp/tlv/Lv.h b/src/fsfw/cfdp/tlv/Lv.h new file mode 100644 index 00000000..46d47819 --- /dev/null +++ b/src/fsfw/cfdp/tlv/Lv.h @@ -0,0 +1,53 @@ +#ifndef FSFW_SRC_FSFW_CFDP_LV_H_ +#define FSFW_SRC_FSFW_CFDP_LV_H_ + +#include "fsfw/serialize/SerialBufferAdapter.h" + +namespace cfdp { + +/** + * @brief Length-Value field implementation + * @details + * Thin abstraction layer around a serial buffer adapter + */ +class Lv: public SerializeIF { +public: + 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; + + /** + * @brief Deserialize a LV field from a raw buffer + * @param buffer Raw buffer including the size field + * @param size + * @param streamEndianness + * @return + */ + ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override; + + /** + * Get value field and its size. + * @param size Optionally retrieve size. Size will be the size of the actual value field + * without the length field of the LV + * @return + */ + const uint8_t* getValue(size_t* size) const; +private: + + bool zeroLen = true; + SerialBufferAdapter value; +}; + +} + +#endif /* FSFW_SRC_FSFW_CFDP_LV_H_ */ diff --git a/src/fsfw/cfdp/tlv/MessageToUserTlv.cpp b/src/fsfw/cfdp/tlv/MessageToUserTlv.cpp new file mode 100644 index 00000000..f776f5ef --- /dev/null +++ b/src/fsfw/cfdp/tlv/MessageToUserTlv.cpp @@ -0,0 +1,8 @@ +#include "MessageToUserTlv.h" + +MessageToUserTlv::MessageToUserTlv(uint8_t *value, size_t size): + Tlv(cfdp::TlvTypes::MSG_TO_USER, value, size) { +} + +MessageToUserTlv::MessageToUserTlv(): Tlv() { +} diff --git a/src/fsfw/cfdp/tlv/MessageToUserTlv.h b/src/fsfw/cfdp/tlv/MessageToUserTlv.h new file mode 100644 index 00000000..7bbe3a40 --- /dev/null +++ b/src/fsfw/cfdp/tlv/MessageToUserTlv.h @@ -0,0 +1,13 @@ +#ifndef FSFW_SRC_FSFW_CFDP_TLV_MESSAGETOUSERTLV_H_ +#define FSFW_SRC_FSFW_CFDP_TLV_MESSAGETOUSERTLV_H_ + +#include "Tlv.h" + +class MessageToUserTlv: public cfdp::Tlv { +public: + MessageToUserTlv(); + MessageToUserTlv(uint8_t* value, size_t size); +private: +}; + +#endif /* FSFW_SRC_FSFW_CFDP_TLV_MESSAGETOUSERTLV_H_ */ diff --git a/src/fsfw/cfdp/tlv/Tlv.cpp b/src/fsfw/cfdp/tlv/Tlv.cpp new file mode 100644 index 00000000..71aa512d --- /dev/null +++ b/src/fsfw/cfdp/tlv/Tlv.cpp @@ -0,0 +1,114 @@ +#include "Tlv.h" + +cfdp::Tlv::Tlv(TlvTypes type, const uint8_t *value, size_t size): type(type), + value(value, size, true) { + if(size > 0) { + zeroLen = false; + } +} + +cfdp::Tlv::Tlv(): value(static_cast(nullptr), 0, true) { +} + +ReturnValue_t cfdp::Tlv::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { + if(buffer == nullptr or size == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + if(*size + 2 > maxSize) { + return BUFFER_TOO_SHORT; + } + if(type == TlvTypes::INVALID_TLV) { + return INVALID_TLV_TYPE; + } + **buffer = type; + *size += 1; + *buffer += 1; + + if(zeroLen) { + **buffer = 0; + *size += 1; + *buffer += 1; + return HasReturnvaluesIF::RETURN_OK; + } + if(value.getConstBuffer() == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + return value.serialize(buffer, size, maxSize, streamEndianness); +} + +size_t cfdp::Tlv::getSerializedSize() const { + if(zeroLen) { + return 2; + } + else if (value.getConstBuffer() == nullptr) { + return 0; + } + return value.getSerializedSize() + 1; +} + +ReturnValue_t cfdp::Tlv::deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) { + if(buffer == nullptr or size == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + if(*size < 2) { + return STREAM_TOO_SHORT; + } + + uint8_t rawType = **buffer; + if(not checkType(rawType)) { + return INVALID_TLV_TYPE; + } + + type = static_cast(rawType); + *buffer += 1; + *size -= 1; + + size_t lengthField = **buffer; + if(lengthField == 0) { + zeroLen = true; + *buffer += 1; + *size -= 1; + return HasReturnvaluesIF::RETURN_OK; + } + if(lengthField + 1 > *size) { + return SerializeIF::STREAM_TOO_SHORT; + } + zeroLen = false; + // Zero-copy implementation + value.setBuffer(const_cast(*buffer + 1), lengthField); + *buffer += 1 + lengthField; + *size -= 1 + lengthField; + return HasReturnvaluesIF::RETURN_OK; +} + +const uint8_t* cfdp::Tlv::getValue() const { + return value.getConstBuffer(); +} + +cfdp::TlvTypes cfdp::Tlv::getType() const { + return type; +} + +bool cfdp::Tlv::checkType(uint8_t rawType) { + if (rawType != 0x03 and rawType <= 6) { + return true; + } + return false; +} + +void cfdp::Tlv::setValue(uint8_t *value, size_t len) { + if(len > 0) { + zeroLen = false; + } + this->value.setBuffer(value, len); +} + +uint8_t cfdp::Tlv::getLengthField() const { + return this->value.getSerializedSize() - 1; +} + +void cfdp::Tlv::setType(TlvTypes type) { + this->type = type; +} diff --git a/src/fsfw/cfdp/tlv/Tlv.h b/src/fsfw/cfdp/tlv/Tlv.h new file mode 100644 index 00000000..65c6ca09 --- /dev/null +++ b/src/fsfw/cfdp/tlv/Tlv.h @@ -0,0 +1,64 @@ +#ifndef FSFW_SRC_FSFW_CFDP_TLV_H_ +#define FSFW_SRC_FSFW_CFDP_TLV_H_ + +#include "TlvIF.h" +#include "fsfw/serialize/SerialBufferAdapter.h" + +namespace cfdp { + +/** + * @brief Type-Length-Value field implementation + * @details + * Thin abstraction layer around a serial buffer adapter + */ +class Tlv: public TlvIF { +public: + Tlv(TlvTypes type, const uint8_t *value, size_t size); + Tlv(); + + /** + * Serialize a TLV into a given buffer + * @param buffer + * @param size + * @param maxSize + * @param streamEndianness + * @return + * - RETURN_OK on success + * - 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; + + virtual size_t getSerializedSize() const override; + + /** + * @brief Deserialize a LV field from a raw buffer. Zero-copy implementation + * @param buffer Raw buffer including the size field + * @param size + * @param streamEndianness + * - RETURN_OK on success + * - INVALID_TLV_TYPE + * - SerializeIF returncode on wrong deserialization parameters + */ + virtual 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; +private: + bool checkType(uint8_t rawType); + + bool zeroLen = true; + TlvTypes type = TlvTypes::INVALID_TLV; + SerialBufferAdapter value; +}; + +} + +#endif /* FSFW_SRC_FSFW_CFDP_TLV_H_ */ diff --git a/src/fsfw/cfdp/tlv/TlvIF.h b/src/fsfw/cfdp/tlv/TlvIF.h new file mode 100644 index 00000000..885e7814 --- /dev/null +++ b/src/fsfw/cfdp/tlv/TlvIF.h @@ -0,0 +1,16 @@ +#ifndef FSFW_SRC_FSFW_CFDP_TLVIF_H_ +#define FSFW_SRC_FSFW_CFDP_TLVIF_H_ + +#include "../definitions.h" + +class TlvIF: public SerializeIF { +public: + virtual~ TlvIF() {}; + + virtual uint8_t getLengthField() const = 0; + virtual cfdp::TlvTypes getType() const = 0; +}; + + + +#endif /* FSFW_SRC_FSFW_CFDP_TLVIF_H_ */ diff --git a/src/fsfw/controller/ExtendedControllerBase.h b/src/fsfw/controller/ExtendedControllerBase.h index 4172e03e..abd48637 100644 --- a/src/fsfw/controller/ExtendedControllerBase.h +++ b/src/fsfw/controller/ExtendedControllerBase.h @@ -8,11 +8,10 @@ #include "fsfw/datapoollocal/LocalDataPoolManager.h" /** - * @brief Extendes the basic ControllerBase with the common components - * HasActionsIF for commandability and HasLocalDataPoolIF to keep - * a pool of local data pool variables. + * @brief Extends the basic ControllerBase with commonly used components * @details - * Default implementations required for the interfaces will be empty and have + * HasActionsIF for commandability and HasLocalDataPoolIF to keep a pool of local data pool + * variables. Default implementations required for the interfaces will be empty and have * to be implemented by child class. */ class ExtendedControllerBase: public ControllerBase, diff --git a/src/fsfw/devicehandlers/AssemblyBase.h b/src/fsfw/devicehandlers/AssemblyBase.h index 6cac81b4..7d54f14d 100644 --- a/src/fsfw/devicehandlers/AssemblyBase.h +++ b/src/fsfw/devicehandlers/AssemblyBase.h @@ -7,7 +7,7 @@ /** * @brief Base class to implement reconfiguration and failure handling for - * redundant devices by monitoring their modes health states. + * redundant devices by monitoring their modes and health states. * @details * Documentation: Dissertation Baetz p.156, 157. * diff --git a/src/fsfw/devicehandlers/DeviceCommunicationIF.h b/src/fsfw/devicehandlers/DeviceCommunicationIF.h index e0b473d3..527e4700 100644 --- a/src/fsfw/devicehandlers/DeviceCommunicationIF.h +++ b/src/fsfw/devicehandlers/DeviceCommunicationIF.h @@ -85,9 +85,10 @@ public: * Called by DHB in the GET_WRITE doGetWrite(). * Get send confirmation that the data in sendMessage() was sent successfully. * @param cookie - * @return - @c RETURN_OK if data was sent successfull - * - Everything else triggers falure event with - * returnvalue as parameter 1 + * @return + * - @c RETURN_OK if data was sent successfully but a reply is expected + * - NO_REPLY_EXPECTED if data was sent successfully and no reply is expected + * - Everything else to indicate failure */ virtual ReturnValue_t getSendSuccess(CookieIF *cookie) = 0; diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.h b/src/fsfw/devicehandlers/DeviceHandlerBase.h index b182b611..da609eed 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.h +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.h @@ -78,15 +78,16 @@ class StorageManagerIF; * * @ingroup devices */ -class DeviceHandlerBase: public DeviceHandlerIF, -public HasReturnvaluesIF, -public ExecutableObjectIF, -public SystemObject, -public HasModesIF, -public HasHealthIF, -public HasActionsIF, -public ReceivesParameterMessagesIF, -public HasLocalDataPoolIF { +class DeviceHandlerBase: + public DeviceHandlerIF, + public HasReturnvaluesIF, + public ExecutableObjectIF, + public SystemObject, + public HasModesIF, + public HasHealthIF, + public HasActionsIF, + public ReceivesParameterMessagesIF, + public HasLocalDataPoolIF { friend void (Factory::setStaticFrameworkObjectIds)(); public: /** @@ -334,8 +335,7 @@ protected: * - @c RETURN_OK to send command after #rawPacket and #rawPacketLen * have been set. * - @c HasActionsIF::EXECUTION_COMPLETE to generate a finish reply immediately. This can - * be used if no reply is expected. Otherwise, the developer can call #actionHelper.finish - * to finish the command handling. + * be used if no reply is expected * - Anything else triggers an event with the return code as a parameter as well as a * step reply failed with the return code */ diff --git a/src/fsfw/devicehandlers/DeviceHandlerIF.h b/src/fsfw/devicehandlers/DeviceHandlerIF.h index 1933c571..1fc57c42 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerIF.h +++ b/src/fsfw/devicehandlers/DeviceHandlerIF.h @@ -120,7 +120,8 @@ public: static const ReturnValue_t WRONG_MODE_FOR_COMMAND = MAKE_RETURN_CODE(0xA5); static const ReturnValue_t TIMEOUT = MAKE_RETURN_CODE(0xA6); static const ReturnValue_t BUSY = MAKE_RETURN_CODE(0xA7); - static const ReturnValue_t NO_REPLY_EXPECTED = MAKE_RETURN_CODE(0xA8); //!< Used to indicate that this is a command-only command. + //!< Used to indicate that this is a command-only command. + static const ReturnValue_t NO_REPLY_EXPECTED = MAKE_RETURN_CODE(0xA8); static const ReturnValue_t NON_OP_TEMPERATURE = MAKE_RETURN_CODE(0xA9); static const ReturnValue_t COMMAND_NOT_IMPLEMENTED = MAKE_RETURN_CODE(0xAA); diff --git a/src/fsfw/ipc/FwMessageTypes.h b/src/fsfw/ipc/FwMessageTypes.h index 8b49c122..22fe9d0d 100644 --- a/src/fsfw/ipc/FwMessageTypes.h +++ b/src/fsfw/ipc/FwMessageTypes.h @@ -9,6 +9,7 @@ enum FsfwMessageTypes { HEALTH_COMMAND, MODE_SEQUENCE, ACTION, + CFDP, TM_STORE, DEVICE_HANDLER_COMMAND, MONITORING, diff --git a/src/fsfw/objectmanager/frameworkObjects.h b/src/fsfw/objectmanager/frameworkObjects.h index 36010807..ff7d9341 100644 --- a/src/fsfw/objectmanager/frameworkObjects.h +++ b/src/fsfw/objectmanager/frameworkObjects.h @@ -19,6 +19,9 @@ enum framework_objects: object_id_t { PUS_SERVICE_200_MODE_MGMT = 0x53000200, PUS_SERVICE_201_HEALTH = 0x53000201, + /* CFDP Distributer */ + CFDP_PACKET_DISTRIBUTOR = 0x53001000, + //Generic IDs for IPC, modes, health, events HEALTH_TABLE = 0x53010000, // MODE_STORE = 0x53010100, diff --git a/src/fsfw/osal/linux/CMakeLists.txt b/src/fsfw/osal/linux/CMakeLists.txt index 41800764..63206cb2 100644 --- a/src/fsfw/osal/linux/CMakeLists.txt +++ b/src/fsfw/osal/linux/CMakeLists.txt @@ -15,6 +15,7 @@ target_sources(${LIB_FSFW_NAME} TaskFactory.cpp tcpipHelpers.cpp unixUtility.cpp + CommandExecutor.cpp ) find_package(Threads REQUIRED) diff --git a/src/fsfw/osal/linux/MessageQueue.cpp b/src/fsfw/osal/linux/MessageQueue.cpp index b068c04f..d028f9f7 100644 --- a/src/fsfw/osal/linux/MessageQueue.cpp +++ b/src/fsfw/osal/linux/MessageQueue.cpp @@ -285,10 +285,10 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, utility::printUnixErrorGeneric(CLASS_NAME, "sendMessageFromMessageQueue", "EBADF"); #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "mq_send to: " << sendTo << " sent from " - << sentFrom << "failed" << std::endl; + sif::warning << "mq_send to " << sendTo << " sent from " + << sentFrom << " failed" << std::endl; #else - sif::printWarning("mq_send to: %d sent from %d failed\n", sendTo, sentFrom); + sif::printWarning("mq_send to %d sent from %d failed\n", sendTo, sentFrom); #endif return DESTINATION_INVALID; } diff --git a/src/fsfw/returnvalues/FwClassIds.h b/src/fsfw/returnvalues/FwClassIds.h index 9fa0c9ae..96f96660 100644 --- a/src/fsfw/returnvalues/FwClassIds.h +++ b/src/fsfw/returnvalues/FwClassIds.h @@ -60,6 +60,7 @@ enum: uint8_t { HAS_ACTIONS_IF, //HF DEVICE_COMMUNICATION_IF, //DC BSP, //BSP + CFDP, //CFDP TIME_STAMPER_IF, //TSI SGP4PROPAGATOR_CLASS, //SGP4 MUTEX_IF, //MUX diff --git a/src/fsfw/serialize/SerialBufferAdapter.cpp b/src/fsfw/serialize/SerialBufferAdapter.cpp index 4f03658a..6db17d5e 100644 --- a/src/fsfw/serialize/SerialBufferAdapter.cpp +++ b/src/fsfw/serialize/SerialBufferAdapter.cpp @@ -105,7 +105,7 @@ uint8_t * SerialBufferAdapter::getBuffer() { } template -const uint8_t * SerialBufferAdapter::getConstBuffer() { +const uint8_t * SerialBufferAdapter::getConstBuffer() const { if(constBuffer == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "SerialBufferAdapter::getConstBuffer:" diff --git a/src/fsfw/serialize/SerialBufferAdapter.h b/src/fsfw/serialize/SerialBufferAdapter.h index 6c79cd03..48f5ce53 100644 --- a/src/fsfw/serialize/SerialBufferAdapter.h +++ b/src/fsfw/serialize/SerialBufferAdapter.h @@ -66,7 +66,7 @@ public: Endianness streamEndianness) override; uint8_t * getBuffer(); - const uint8_t * getConstBuffer(); + const uint8_t * getConstBuffer() const; void setBuffer(uint8_t* buffer, count_t bufferLength); private: bool serializeLength = false; diff --git a/src/fsfw/subsystem/SubsystemBase.h b/src/fsfw/subsystem/SubsystemBase.h index 6b2e9b5f..a1de077d 100644 --- a/src/fsfw/subsystem/SubsystemBase.h +++ b/src/fsfw/subsystem/SubsystemBase.h @@ -62,7 +62,8 @@ protected: struct ChildInfo { MessageQueueId_t commandQueue; Mode_t mode; - Submode_t submode;bool healthChanged; + Submode_t submode; + bool healthChanged; }; Mode_t mode; diff --git a/src/fsfw/tcdistribution/CCSDSDistributor.cpp b/src/fsfw/tcdistribution/CCSDSDistributor.cpp index ffceaecc..a040a5df 100644 --- a/src/fsfw/tcdistribution/CCSDSDistributor.cpp +++ b/src/fsfw/tcdistribution/CCSDSDistributor.cpp @@ -7,8 +7,8 @@ #define CCSDS_DISTRIBUTOR_DEBUGGING 0 CCSDSDistributor::CCSDSDistributor(uint16_t setDefaultApid, - object_id_t setObjectId): - TcDistributor(setObjectId), defaultApid( setDefaultApid ) { + object_id_t setObjectId): + TcDistributor(setObjectId), defaultApid( setDefaultApid ) { } CCSDSDistributor::~CCSDSDistributor() {} @@ -16,97 +16,97 @@ CCSDSDistributor::~CCSDSDistributor() {} 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; + 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); + 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 = this->tcStore->getData(currentMessage.getStorageId(), - &packet, &size ); - if(result != HasReturnvaluesIF::RETURN_OK) { + const uint8_t* packet = nullptr; + size_t size = 0; + ReturnValue_t result = this->tcStore->getData(currentMessage.getStorageId(), + &packet, &size ); + if(result != HasReturnvaluesIF::RETURN_OK) { #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "CCSDSDistributor::selectDestination: Getting data from" - " store failed!" << std::endl; + sif::error << "CCSDSDistributor::selectDestination: Getting data from" + " store failed!" << std::endl; #else - sif::printError("CCSDSDistributor::selectDestination: Getting data from" + sif::printError("CCSDSDistributor::selectDestination: Getting data from" " store failed!\n"); #endif #endif - } - SpacePacketBase currentPacket(packet); + } + SpacePacketBase currentPacket(packet); #if FSFW_CPP_OSTREAM_ENABLED == 1 && CCSDS_DISTRIBUTOR_DEBUGGING == 1 - sif::info << "CCSDSDistributor::selectDestination has packet with APID " << std::hex << - currentPacket.getAPID() << std::dec << std::endl; + sif::info << "CCSDSDistributor::selectDestination has packet with APID " << std::hex << + currentPacket.getAPID() << std::dec << std::endl; #endif - TcMqMapIter 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 this->queueMap.find( this->defaultApid ); - } + TcMqMapIter 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 this->queueMap.find( this->defaultApid ); + } } MessageQueueId_t CCSDSDistributor::getRequestQueue() { - return tcQueue->getId(); + return tcQueue->getId(); } ReturnValue_t CCSDSDistributor::registerApplication( - AcceptsTelecommandsIF* application) { - ReturnValue_t returnValue = RETURN_OK; - auto insertPair = this->queueMap.emplace(application->getIdentifier(), - application->getRequestQueue()); - if(not insertPair.second) { - returnValue = RETURN_FAILED; - } - return returnValue; + AcceptsTelecommandsIF* application) { + ReturnValue_t returnValue = RETURN_OK; + auto insertPair = this->queueMap.emplace(application->getIdentifier(), + application->getRequestQueue()); + if(not insertPair.second) { + returnValue = RETURN_FAILED; + } + return returnValue; } ReturnValue_t CCSDSDistributor::registerApplication(uint16_t apid, - MessageQueueId_t id) { - ReturnValue_t returnValue = RETURN_OK; - auto insertPair = this->queueMap.emplace(apid, id); - if(not insertPair.second) { - returnValue = RETURN_FAILED; - } - return returnValue; + MessageQueueId_t id) { + ReturnValue_t returnValue = RETURN_OK; + auto insertPair = this->queueMap.emplace(apid, id); + if(not insertPair.second) { + returnValue = RETURN_FAILED; + } + return returnValue; } uint16_t CCSDSDistributor::getIdentifier() { - return 0; + return 0; } ReturnValue_t CCSDSDistributor::initialize() { - ReturnValue_t status = this->TcDistributor::initialize(); - this->tcStore = ObjectManager::instance()->get( objects::TC_STORE ); - if (this->tcStore == nullptr) { + 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; + sif::error << "CCSDSDistributor::initialize: Could not initialize" + " TC store!" << std::endl; #else - sif::printError("CCSDSDistributor::initialize: Could not initialize" + sif::printError("CCSDSDistributor::initialize: Could not initialize" " TC store!\n"); #endif #endif - status = RETURN_FAILED; - } - return status; + status = RETURN_FAILED; + } + return status; } ReturnValue_t CCSDSDistributor::callbackAfterSending( - ReturnValue_t queueStatus) { - if (queueStatus != RETURN_OK) { - tcStore->deleteData(currentMessage.getStorageId()); - } - return RETURN_OK; + ReturnValue_t queueStatus) { + if (queueStatus != RETURN_OK) { + tcStore->deleteData(currentMessage.getStorageId()); + } + return RETURN_OK; } diff --git a/src/fsfw/tcdistribution/CCSDSDistributor.h b/src/fsfw/tcdistribution/CCSDSDistributor.h index e8d54c9c..f8995bc5 100644 --- a/src/fsfw/tcdistribution/CCSDSDistributor.h +++ b/src/fsfw/tcdistribution/CCSDSDistributor.h @@ -15,56 +15,57 @@ * The Secondary Header (with Service/Subservice) is ignored. * @ingroup tc_distribution */ -class CCSDSDistributor : public TcDistributor, - public CCSDSDistributorIF, - public AcceptsTelecommandsIF { +class CCSDSDistributor: + public TcDistributor, + public CCSDSDistributorIF, + public AcceptsTelecommandsIF { public: - /** - * @brief The constructor sets the default APID and calls the - * TcDistributor ctor with a certain object id. - * @details - * @c tcStore is set in the @c initialize method. - * @param setDefaultApid The default APID, where packets with unknown - * destination are sent to. - */ - CCSDSDistributor(uint16_t setDefaultApid, object_id_t setObjectId); - /** - * The destructor is empty. - */ - virtual ~CCSDSDistributor(); + /** + * @brief The constructor sets the default APID and calls the + * TcDistributor ctor with a certain object id. + * @details + * @c tcStore is set in the @c initialize method. + * @param setDefaultApid The default APID, where packets with unknown + * destination are sent to. + */ + CCSDSDistributor(uint16_t setDefaultApid, object_id_t setObjectId); + /** + * The destructor is empty. + */ + virtual ~CCSDSDistributor(); - MessageQueueId_t getRequestQueue() override; - ReturnValue_t registerApplication( uint16_t apid, - MessageQueueId_t id) override; - ReturnValue_t registerApplication( - AcceptsTelecommandsIF* application) override; - uint16_t getIdentifier() override; - ReturnValue_t initialize() 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; + ReturnValue_t initialize() override; protected: - /** - * 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. - */ - TcMqMapIter selectDestination() override; + /** + * 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. + */ + TcMqMapIter selectDestination() override; /** * The callback here handles the generation of acceptance * success/failure messages. */ ReturnValue_t callbackAfterSending( ReturnValue_t queueStatus ) override; - /** - * The default APID, where packets with unknown APID are sent to. - */ - uint16_t defaultApid; - /** - * A reference to the TC storage must be maintained, as this class handles - * pure Space Packets and there exists no SpacePacketStored class. - */ - StorageManagerIF* tcStore = nullptr; + /** + * The default APID, where packets with unknown APID are sent to. + */ + uint16_t defaultApid; + /** + * A reference to the TC storage must be maintained, as this class handles + * pure Space Packets and there exists no SpacePacketStored class. + */ + StorageManagerIF* tcStore = nullptr; }; diff --git a/src/fsfw/tcdistribution/CCSDSDistributorIF.h b/src/fsfw/tcdistribution/CCSDSDistributorIF.h index 6334a35a..4e4c2a5b 100644 --- a/src/fsfw/tcdistribution/CCSDSDistributorIF.h +++ b/src/fsfw/tcdistribution/CCSDSDistributorIF.h @@ -13,31 +13,30 @@ */ 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 RETURN_OK on success, - * - @c RETURN_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 RETURN_OK on success, - * - @c RETURN_FAILED on failure. - */ - virtual ReturnValue_t registerApplication( uint16_t apid, - MessageQueueId_t id) = 0; - /** - * The empty virtual destructor. - */ - virtual ~CCSDSDistributorIF() { - } + /** + * With this call, a class implementing the CCSDSApplicationIF can register + * at the distributor. + * @param application A pointer to the Application to register. + * @return - @c RETURN_OK on success, + * - @c RETURN_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 RETURN_OK on success, + * - @c RETURN_FAILED on failure. + */ + virtual ReturnValue_t registerApplication( uint16_t apid, + MessageQueueId_t id) = 0; + /** + * The empty virtual destructor. + */ + virtual ~CCSDSDistributorIF() {} }; diff --git a/src/fsfw/tcdistribution/CFDPDistributor.cpp b/src/fsfw/tcdistribution/CFDPDistributor.cpp new file mode 100644 index 00000000..f28a2998 --- /dev/null +++ b/src/fsfw/tcdistribution/CFDPDistributor.cpp @@ -0,0 +1,147 @@ +#include "fsfw/tcdistribution/CCSDSDistributorIF.h" +#include "fsfw/tcdistribution/CFDPDistributor.h" + +#include "fsfw/tmtcpacket/cfdp/CFDPPacketStored.h" + +#include "fsfw/objectmanager/ObjectManager.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(RETURN_FAILED), packetSource(setPacketSource) { +} + +CFDPDistributor::~CFDPDistributor() {} + +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 + TcMqMapIter queueMapIt = this->queueMap.end(); + if(this->currentPacket == nullptr) { + return queueMapIt; + } + this->currentPacket->setStoreAddress(this->currentMessage.getStorageId()); + if (currentPacket->getWholeData() != nullptr) { + tcStatus = checker.checkPacket(currentPacket); + if(tcStatus != HasReturnvaluesIF::RETURN_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 != RETURN_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 HasReturnvaluesIF::RETURN_OK; +} + +MessageQueueId_t CFDPDistributor::getRequestQueue() { + return tcQueue->getId(); +} + +//ReturnValue_t CFDPDistributor::callbackAfterSending(ReturnValue_t queueStatus) { +// if (queueStatus != RETURN_OK) { +// tcStatus = queueStatus; +// } +// if (tcStatus != RETURN_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 RETURN_FAILED; +// } else { +// this->verifyChannel.sendSuccessReport(tc_verification::ACCEPTANCE_SUCCESS, +// currentPacket); +// return RETURN_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; + } + + CCSDSDistributorIF* 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 RETURN_FAILED; + } + return ccsdsDistributor->registerApplication(this); +} diff --git a/src/fsfw/tcdistribution/CFDPDistributor.h b/src/fsfw/tcdistribution/CFDPDistributor.h new file mode 100644 index 00000000..5c7513b3 --- /dev/null +++ b/src/fsfw/tcdistribution/CFDPDistributor.h @@ -0,0 +1,72 @@ +#ifndef FSFW_TCDISTRIBUTION_CFDPDISTRIBUTOR_H_ +#define FSFW_TCDISTRIBUTION_CFDPDISTRIBUTOR_H_ + +#include +#include "CFDPDistributorIF.h" +#include "TcDistributor.h" +#include "../tmtcpacket/cfdp/CFDPPacketStored.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../tmtcservices/AcceptsTelecommandsIF.h" +#include "../tmtcservices/VerificationReporter.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. + */ + virtual ~CFDPDistributor(); + 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; + TcPacketCheckCFDP 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 new file mode 100644 index 00000000..f1c85772 --- /dev/null +++ b/src/fsfw/tcdistribution/CFDPDistributorIF.h @@ -0,0 +1,27 @@ +#ifndef FSFW_TCDISTRIBUTION_CFDPDISTRIBUTORIF_H_ +#define FSFW_TCDISTRIBUTION_CFDPDISTRIBUTORIF_H_ + +#include "../tmtcservices/AcceptsTelecommandsIF.h" +#include "../ipc/MessageQueueSenderIF.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() { + } + /** + * With this method, Handlers can register themselves at the CFDP Distributor. + * @param handler A pointer to the registering Handler. + * @return - @c RETURN_OK on success, + * - @c RETURN_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 6f237076..7118c38c 100644 --- a/src/fsfw/tcdistribution/CMakeLists.txt +++ b/src/fsfw/tcdistribution/CMakeLists.txt @@ -2,5 +2,8 @@ target_sources(${LIB_FSFW_NAME} PRIVATE CCSDSDistributor.cpp PUSDistributor.cpp TcDistributor.cpp - TcPacketCheck.cpp + TcPacketCheckPUS.cpp + TcPacketCheckCFDP.cpp + CFDPDistributor.cpp ) + diff --git a/src/fsfw/tcdistribution/PUSDistributor.cpp b/src/fsfw/tcdistribution/PUSDistributor.cpp index adab58c8..aafd1244 100644 --- a/src/fsfw/tcdistribution/PUSDistributor.cpp +++ b/src/fsfw/tcdistribution/PUSDistributor.cpp @@ -24,25 +24,25 @@ PUSDistributor::TcMqMapIter PUSDistributor::selectDestination() { if(this->currentPacket == nullptr) { return queueMapIt; } - this->currentPacket->setStoreAddress(this->currentMessage.getStorageId()); + this->currentPacket->setStoreAddress(this->currentMessage.getStorageId(), currentPacket); if (currentPacket->getWholeData() != nullptr) { tcStatus = checker.checkPacket(currentPacket); if(tcStatus != HasReturnvaluesIF::RETURN_OK) { #if FSFW_VERBOSE_LEVEL >= 1 const char* keyword = "unnamed error"; - if(tcStatus == TcPacketCheck::INCORRECT_CHECKSUM) { + if(tcStatus == TcPacketCheckPUS::INCORRECT_CHECKSUM) { keyword = "checksum"; } - else if(tcStatus == TcPacketCheck::INCORRECT_PRIMARY_HEADER) { + else if(tcStatus == TcPacketCheckPUS::INCORRECT_PRIMARY_HEADER) { keyword = "incorrect primary header"; } - else if(tcStatus == TcPacketCheck::ILLEGAL_APID) { + else if(tcStatus == TcPacketCheckPUS::ILLEGAL_APID) { keyword = "illegal APID"; } - else if(tcStatus == TcPacketCheck::INCORRECT_SECONDARY_HEADER) { + else if(tcStatus == TcPacketCheckPUS::INCORRECT_SECONDARY_HEADER) { keyword = "incorrect secondary header"; } - else if(tcStatus == TcPacketCheck::INCOMPLETE_PACKET) { + else if(tcStatus == TcPacketCheckPUS::INCOMPLETE_PACKET) { keyword = "incomplete packet"; } #if FSFW_CPP_OSTREAM_ENABLED == 1 diff --git a/src/fsfw/tcdistribution/PUSDistributor.h b/src/fsfw/tcdistribution/PUSDistributor.h index 53a996ca..b010125c 100644 --- a/src/fsfw/tcdistribution/PUSDistributor.h +++ b/src/fsfw/tcdistribution/PUSDistributor.h @@ -3,7 +3,7 @@ #include "PUSDistributorIF.h" #include "TcDistributor.h" -#include "TcPacketCheck.h" +#include "TcPacketCheckPUS.h" #include "fsfw/tmtcpacket/pus/tc.h" #include "fsfw/returnvalues/HasReturnvaluesIF.h" @@ -17,65 +17,65 @@ * @ingroup tc_distribution */ class PUSDistributor: public TcDistributor, - public PUSDistributorIF, - public AcceptsTelecommandsIF { +public PUSDistributorIF, +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. - */ - PUSDistributor(uint16_t setApid, object_id_t setObjectId, - object_id_t setPacketSource); - /** - * The destructor is empty. - */ - virtual ~PUSDistributor(); - ReturnValue_t registerService(AcceptsTelecommandsIF* service) override; - MessageQueueId_t getRequestQueue() override; - ReturnValue_t initialize() override; - uint16_t getIdentifier() override; + /** + * 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. + */ + PUSDistributor(uint16_t setApid, object_id_t setObjectId, + object_id_t setPacketSource); + /** + * The destructor is empty. + */ + virtual ~PUSDistributor(); + ReturnValue_t registerService(AcceptsTelecommandsIF* service) override; + MessageQueueId_t getRequestQueue() override; + ReturnValue_t initialize() override; + uint16_t getIdentifier() override; protected: - /** - * This attribute contains the class, that performs a formal packet check. - */ - TcPacketCheck checker; - /** - * With this class, verification messages are sent to the - * TC Verification service. - */ - VerificationReporter verifyChannel; - /** - * The currently handled packet is stored here. - */ - TcPacketStoredPus* currentPacket = nullptr; + /** + * This attribute contains the class, that performs a formal packet check. + */ + TcPacketCheckPUS checker; + /** + * With this class, verification messages are sent to the + * TC Verification service. + */ + VerificationReporter verifyChannel; + /** + * The currently handled packet is stored here. + */ + TcPacketStoredPus* currentPacket = nullptr; - /** - * With this variable, the current check status is stored to generate - * acceptance messages later. - */ - ReturnValue_t tcStatus; + /** + * With this variable, the current check status is stored to generate + * acceptance messages later. + */ + ReturnValue_t tcStatus; - const object_id_t packetSource; + 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; + /** + * 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_PUSDISTRIBUTOR_H_ */ diff --git a/src/fsfw/tcdistribution/PUSDistributorIF.h b/src/fsfw/tcdistribution/PUSDistributorIF.h index 0125c08f..e4a66758 100644 --- a/src/fsfw/tcdistribution/PUSDistributorIF.h +++ b/src/fsfw/tcdistribution/PUSDistributorIF.h @@ -10,18 +10,18 @@ */ class PUSDistributorIF { public: - /** - * The empty virtual destructor. - */ - virtual ~PUSDistributorIF() { - } -/** - * With this method, Services can register themselves at the PUS Distributor. - * @param service A pointer to the registering Service. - * @return - @c RETURN_OK on success, - * - @c RETURN_FAILED on failure. - */ - virtual ReturnValue_t registerService( AcceptsTelecommandsIF* service ) = 0; + /** + * The empty virtual destructor. + */ + virtual ~PUSDistributorIF() { + } + /** + * With this method, Services can register themselves at the PUS Distributor. + * @param service A pointer to the registering Service. + * @return - @c RETURN_OK on success, + * - @c RETURN_FAILED on failure. + */ + virtual ReturnValue_t registerService( AcceptsTelecommandsIF* service ) = 0; }; #endif /* FSFW_TCDISTRIBUTION_PUSDISTRIBUTORIF_H_ */ diff --git a/src/fsfw/tcdistribution/TcPacketCheckCFDP.cpp b/src/fsfw/tcdistribution/TcPacketCheckCFDP.cpp new file mode 100644 index 00000000..43e5511b --- /dev/null +++ b/src/fsfw/tcdistribution/TcPacketCheckCFDP.cpp @@ -0,0 +1,13 @@ +#include "fsfw/tcdistribution/TcPacketCheckCFDP.h" +#include "fsfw/tmtcpacket/cfdp/CFDPPacketStored.h" + +TcPacketCheckCFDP::TcPacketCheckCFDP(uint16_t setApid): apid(setApid) { +} + +ReturnValue_t TcPacketCheckCFDP::checkPacket(SpacePacketBase* currentPacket) { + return RETURN_OK; +} + +uint16_t TcPacketCheckCFDP::getApid() const { + return apid; +} diff --git a/src/fsfw/tcdistribution/TcPacketCheckCFDP.h b/src/fsfw/tcdistribution/TcPacketCheckCFDP.h new file mode 100644 index 00000000..8205fe4b --- /dev/null +++ b/src/fsfw/tcdistribution/TcPacketCheckCFDP.h @@ -0,0 +1,35 @@ +#ifndef FSFW_TCDISTRIBUTION_TCPACKETCHECKCFDP_H_ +#define FSFW_TCDISTRIBUTION_TCPACKETCHECKCFDP_H_ + +#include "TcPacketCheckIF.h" + +#include "fsfw/FSFW.h" + +class CFDPPacketStored; + +/** + * This class performs a formal packet check for incoming CFDP Packets. + * @ingroup tc_distribution + */ +class TcPacketCheckCFDP : + public TcPacketCheckIF, + public HasReturnvaluesIF { +protected: + /** + * The packet id each correct packet should have. + * It is composed of the APID and some static fields. + */ + uint16_t apid; +public: + /** + * The constructor only sets the APID attribute. + * @param set_apid The APID to set. + */ + TcPacketCheckCFDP(uint16_t setApid); + + ReturnValue_t checkPacket(SpacePacketBase* currentPacket) override; + + uint16_t getApid() const; +}; + +#endif /* FSFW_TCDISTRIBUTION_TCPACKETCHECKCFDP_H_ */ diff --git a/src/fsfw/tcdistribution/TcPacketCheckIF.h b/src/fsfw/tcdistribution/TcPacketCheckIF.h new file mode 100644 index 00000000..ac1dfef9 --- /dev/null +++ b/src/fsfw/tcdistribution/TcPacketCheckIF.h @@ -0,0 +1,31 @@ +#ifndef FSFW_TCDISTRIBUTION_TCPACKETCHECKIF_H_ +#define FSFW_TCDISTRIBUTION_TCPACKETCHECKIF_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" + +class SpacePacketBase; + +/** + * This interface is used by PacketCheckers for PUS packets and CFDP packets . + * @ingroup tc_distribution + */ +class TcPacketCheckIF { +public: + /** + * The empty virtual destructor. + */ + virtual ~TcPacketCheckIF() { + } + + /** + * This is the actual method to formally check a certain Packet. + * The packet's Application Data can not be checked here. + * @param current_packet The packet to check + * @return - @c RETURN_OK on success. + * - @c INCORRECT_CHECKSUM if checksum is invalid. + * - @c ILLEGAL_APID if APID does not match. + */ + virtual ReturnValue_t checkPacket(SpacePacketBase* currentPacket) = 0; +}; + +#endif /* FSFW_TCDISTRIBUTION_TCPACKETCHECKIF_H_ */ diff --git a/src/fsfw/tcdistribution/TcPacketCheck.cpp b/src/fsfw/tcdistribution/TcPacketCheckPUS.cpp similarity index 65% rename from src/fsfw/tcdistribution/TcPacketCheck.cpp rename to src/fsfw/tcdistribution/TcPacketCheckPUS.cpp index 44501c58..d106a455 100644 --- a/src/fsfw/tcdistribution/TcPacketCheck.cpp +++ b/src/fsfw/tcdistribution/TcPacketCheckPUS.cpp @@ -1,18 +1,20 @@ -#include "fsfw/tcdistribution/TcPacketCheck.h" +#include "fsfw/tcdistribution/TcPacketCheckPUS.h" #include "fsfw/globalfunctions/CRC.h" -#include "fsfw/tmtcpacket/pus/tc/TcPacketBase.h" +#include "fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.h" +#include "fsfw/tmtcpacket/pus/tc/TcPacketPusBase.h" #include "fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.h" #include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/storagemanager/StorageManagerIF.h" #include "fsfw/tmtcservices/VerificationCodes.h" -TcPacketCheck::TcPacketCheck(uint16_t setApid): apid(setApid) { +TcPacketCheckPUS::TcPacketCheckPUS(uint16_t setApid): apid(setApid) { } -ReturnValue_t TcPacketCheck::checkPacket(TcPacketStoredBase* currentPacket) { - TcPacketBase* tcPacketBase = currentPacket->getPacketBase(); - if(tcPacketBase == nullptr) { +ReturnValue_t TcPacketCheckPUS::checkPacket(SpacePacketBase* currentPacket) { + TcPacketStoredBase* storedPacket = dynamic_cast(currentPacket); + TcPacketPusBase* tcPacketBase = dynamic_cast(currentPacket); + if(tcPacketBase == nullptr or storedPacket == nullptr) { return RETURN_FAILED; } uint16_t calculated_crc = CRC::crc16ccitt(tcPacketBase->getWholeData(), @@ -29,7 +31,7 @@ ReturnValue_t TcPacketCheck::checkPacket(TcPacketStoredBase* currentPacket) { if (tcPacketBase->getAPID() != this->apid) return ILLEGAL_APID; - if (not currentPacket->isSizeCorrect()) { + if (not storedPacket->isSizeCorrect()) { return INCOMPLETE_PACKET; } @@ -41,6 +43,6 @@ ReturnValue_t TcPacketCheck::checkPacket(TcPacketStoredBase* currentPacket) { return RETURN_OK; } -uint16_t TcPacketCheck::getApid() const { +uint16_t TcPacketCheckPUS::getApid() const { return apid; } diff --git a/src/fsfw/tcdistribution/TcPacketCheck.h b/src/fsfw/tcdistribution/TcPacketCheckPUS.h similarity index 73% rename from src/fsfw/tcdistribution/TcPacketCheck.h rename to src/fsfw/tcdistribution/TcPacketCheckPUS.h index 519943c7..ae4c7789 100644 --- a/src/fsfw/tcdistribution/TcPacketCheck.h +++ b/src/fsfw/tcdistribution/TcPacketCheckPUS.h @@ -1,5 +1,7 @@ -#ifndef FSFW_TCDISTRIBUTION_TCPACKETCHECK_H_ -#define FSFW_TCDISTRIBUTION_TCPACKETCHECK_H_ +#ifndef FSFW_TCDISTRIBUTION_TCPACKETCHECKPUS_H_ +#define FSFW_TCDISTRIBUTION_TCPACKETCHECKPUS_H_ + +#include "TcPacketCheckIF.h" #include "fsfw/FSFW.h" #include "fsfw/returnvalues/HasReturnvaluesIF.h" @@ -12,7 +14,9 @@ class TcPacketStoredBase; * Currently, it only checks if the APID and CRC are correct. * @ingroup tc_distribution */ -class TcPacketCheck : public HasReturnvaluesIF { +class TcPacketCheckPUS : + public TcPacketCheckIF, + public HasReturnvaluesIF { protected: /** * Describes the version number a packet must have to pass. @@ -49,18 +53,11 @@ public: * The constructor only sets the APID attribute. * @param set_apid The APID to set. */ - TcPacketCheck(uint16_t setApid); - /** - * This is the actual method to formally check a certain Telecommand Packet. - * The packet's Application Data can not be checked here. - * @param current_packet The packt to check - * @return - @c RETURN_OK on success. - * - @c INCORRECT_CHECKSUM if checksum is invalid. - * - @c ILLEGAL_APID if APID does not match. - */ - ReturnValue_t checkPacket(TcPacketStoredBase* currentPacket); + TcPacketCheckPUS(uint16_t setApid); + + ReturnValue_t checkPacket(SpacePacketBase* currentPacket) override; uint16_t getApid() const; }; -#endif /* FSFW_TCDISTRIBUTION_TCPACKETCHECK_H_ */ +#endif /* FSFW_TCDISTRIBUTION_TCPACKETCHECKPUS_H_ */ diff --git a/src/fsfw/tmtcpacket/CMakeLists.txt b/src/fsfw/tmtcpacket/CMakeLists.txt index fdc884ec..e1deaba9 100644 --- a/src/fsfw/tmtcpacket/CMakeLists.txt +++ b/src/fsfw/tmtcpacket/CMakeLists.txt @@ -3,5 +3,6 @@ target_sources(${LIB_FSFW_NAME} PRIVATE SpacePacketBase.cpp ) +add_subdirectory(cfdp) add_subdirectory(packetmatcher) add_subdirectory(pus) \ No newline at end of file diff --git a/src/fsfw/tmtcpacket/RedirectableDataPointerIF.h b/src/fsfw/tmtcpacket/RedirectableDataPointerIF.h new file mode 100644 index 00000000..63a760ec --- /dev/null +++ b/src/fsfw/tmtcpacket/RedirectableDataPointerIF.h @@ -0,0 +1,34 @@ +#ifndef TMTCPACKET_PUS_TC_SETTABLEDATAPOINTERIF_H_ +#define TMTCPACKET_PUS_TC_SETTABLEDATAPOINTERIF_H_ + +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include + +/** + * @brief This interface can be used for classes which store a reference to data. It allows + * the implementing class to redirect the data it refers too. + */ +class RedirectableDataPointerIF { +public: + virtual ~RedirectableDataPointerIF() {}; + + /** + * Redirect the data pointer, but allow an implementation to change the data. + * The default implementation also sets a read-only pointer where applicable. + * @param dataPtr + * @param maxSize Maximum allowed size in buffer which holds the data. Can be used for size + * checks if a struct is cast directly onto the data pointer to ensure that the buffer is + * large enough + * @param args Any additional user arguments required to set the data pointer + * @return + * - RETURN_OK if the pointer was set successfully + * - RETURN_FAILED on general error of if the maximum size is too small + */ + virtual ReturnValue_t setData(uint8_t* dataPtr, size_t maxSize, void* args = nullptr) = 0; + +private: +}; + + + +#endif /* FSFW_SRC_FSFW_TMTCPACKET_PUS_TC_SETTABLEDATAPOINTERIF_H_ */ diff --git a/src/fsfw/tmtcpacket/SpacePacket.cpp b/src/fsfw/tmtcpacket/SpacePacket.cpp index cbf82e0d..5284eb5c 100644 --- a/src/fsfw/tmtcpacket/SpacePacket.cpp +++ b/src/fsfw/tmtcpacket/SpacePacket.cpp @@ -5,23 +5,23 @@ SpacePacket::SpacePacket(uint16_t packetDataLength, bool isTelecommand, uint16_t apid, uint16_t sequenceCount): SpacePacketBase( (uint8_t*)&this->localData ) { - initSpacePacketHeader(isTelecommand, false, apid, sequenceCount); - this->setPacketSequenceCount(sequenceCount); - if ( packetDataLength <= sizeof(this->localData.fields.buffer) ) { - this->setPacketDataLength(packetDataLength); - } else { - this->setPacketDataLength( sizeof(this->localData.fields.buffer) ); - } + initSpacePacketHeader(isTelecommand, false, apid, sequenceCount); + this->setPacketSequenceCount(sequenceCount); + if ( packetDataLength <= sizeof(this->localData.fields.buffer) ) { + this->setPacketDataLength(packetDataLength); + } else { + this->setPacketDataLength( sizeof(this->localData.fields.buffer) ); + } } SpacePacket::~SpacePacket( void ) { } bool SpacePacket::addWholeData( const uint8_t* p_Data, uint32_t packet_size ) { - if ( packet_size <= sizeof(this->data) ) { - memcpy( &this->localData.byteStream, p_Data, packet_size ); - return true; - } else { - return false; - } + if ( packet_size <= sizeof(this->data) ) { + memcpy( &this->localData.byteStream, p_Data, packet_size ); + return true; + } else { + return false; + } } diff --git a/src/fsfw/tmtcpacket/SpacePacket.h b/src/fsfw/tmtcpacket/SpacePacket.h index a092712c..d9e51f35 100644 --- a/src/fsfw/tmtcpacket/SpacePacket.h +++ b/src/fsfw/tmtcpacket/SpacePacket.h @@ -26,7 +26,7 @@ public: * @param sequenceCount ets the packet's Source Sequence Count field. */ SpacePacket(uint16_t packetDataLength, bool isTelecommand = false, - uint16_t apid = APID_IDLE_PACKET, uint16_t sequenceCount = 0); + uint16_t apid = APID_IDLE_PACKET, uint16_t sequenceCount = 0); /** * The class's default destructor. */ diff --git a/src/fsfw/tmtcpacket/SpacePacketBase.cpp b/src/fsfw/tmtcpacket/SpacePacketBase.cpp index 16883d7f..58f4feea 100644 --- a/src/fsfw/tmtcpacket/SpacePacketBase.cpp +++ b/src/fsfw/tmtcpacket/SpacePacketBase.cpp @@ -110,10 +110,6 @@ uint8_t* SpacePacketBase::getWholeData() { return (uint8_t*)this->data; } -void SpacePacketBase::setData( const uint8_t* p_Data ) { - this->data = (SpacePacketPointer*)p_Data; -} - uint32_t SpacePacketBase::getApidAndSequenceCount() const { return (getAPID() << 16) + getPacketSequenceCount(); } @@ -121,3 +117,11 @@ uint32_t SpacePacketBase::getApidAndSequenceCount() const { uint8_t* SpacePacketBase::getPacketData() { return &(data->packet_data); } + +ReturnValue_t SpacePacketBase::setData(uint8_t *pData, size_t maxSize, void *args) { + if(maxSize < 6) { + return HasReturnvaluesIF::RETURN_FAILED; + } + this->data = reinterpret_cast(const_cast(pData)); + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/src/fsfw/tmtcpacket/SpacePacketBase.h b/src/fsfw/tmtcpacket/SpacePacketBase.h index 1ebc484f..dfc808e3 100644 --- a/src/fsfw/tmtcpacket/SpacePacketBase.h +++ b/src/fsfw/tmtcpacket/SpacePacketBase.h @@ -1,6 +1,7 @@ #ifndef FSFW_TMTCPACKET_SPACEPACKETBASE_H_ #define FSFW_TMTCPACKET_SPACEPACKETBASE_H_ +#include #include "ccsds_header.h" #include "fsfw/returnvalues/HasReturnvaluesIF.h" @@ -37,7 +38,7 @@ struct SpacePacketPointer { * the most significant bit (from left). * @ingroup tmtcpackets */ -class SpacePacketBase { +class SpacePacketBase: virtual public RedirectableDataPointerIF { protected: /** * A pointer to a structure which defines the data structure of @@ -70,8 +71,7 @@ public: */ virtual ~SpacePacketBase(); - //CCSDS Methods - + //CCSDS Methods: /** * Getter for the packet version number field. * @return Returns the highest three bit of the packet in one byte. @@ -163,7 +163,7 @@ public: */ void setPacketDataLength( uint16_t setLength ); - // Helper methods + //Helper methods: /** * This method returns a raw uint8_t pointer to the packet. * @return A \c uint8_t pointer to the first byte of the CCSDS primary header. @@ -171,12 +171,14 @@ public: virtual uint8_t* getWholeData( void ); uint8_t* getPacketData(); + /** * With this method, the packet data pointer can be redirected to another * location. * @param p_Data A pointer to another raw Space Packet. */ - virtual void setData( const uint8_t* p_Data ); + virtual ReturnValue_t setData(uint8_t* p_Data , size_t maxSize, + void* args = nullptr) override; /** * This method returns the full raw packet size. * @return The full size of the packet in bytes. diff --git a/src/fsfw/tmtcpacket/cfdp/CFDPPacket.cpp b/src/fsfw/tmtcpacket/cfdp/CFDPPacket.cpp new file mode 100644 index 00000000..6172201e --- /dev/null +++ b/src/fsfw/tmtcpacket/cfdp/CFDPPacket.cpp @@ -0,0 +1,20 @@ +#include "fsfw/tmtcpacket/cfdp/CFDPPacket.h" + +#include "fsfw/globalfunctions/CRC.h" +#include "fsfw/globalfunctions/arrayprinter.h" +#include "fsfw/serviceinterface/ServiceInterface.h" + +#include + +CFDPPacket::CFDPPacket(const uint8_t* setData): SpacePacketBase(setData) {} + +CFDPPacket::~CFDPPacket() {} + +void CFDPPacket::print() { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "CFDPPacket::print:" << std::endl; +#else + sif::printInfo("CFDPPacket::print:\n"); +#endif + arrayprinter::print(getWholeData(), getFullSize()); +} diff --git a/src/fsfw/tmtcpacket/cfdp/CFDPPacket.h b/src/fsfw/tmtcpacket/cfdp/CFDPPacket.h new file mode 100644 index 00000000..f288a8ae --- /dev/null +++ b/src/fsfw/tmtcpacket/cfdp/CFDPPacket.h @@ -0,0 +1,27 @@ +#ifndef FSFW_INC_FSFW_TMTCPACKET_CFDP_CFDPPACKET_H_ +#define FSFW_INC_FSFW_TMTCPACKET_CFDP_CFDPPACKET_H_ + +#include "fsfw/tmtcpacket/SpacePacketBase.h" + +class CFDPPacket : public SpacePacketBase { +public: + /** + * This is the default constructor. + * It sets its internal data pointer to the address passed and also + * forwards the data pointer to the parent SpacePacketBase class. + * @param setData The position where the packet data lies. + */ + CFDPPacket( const uint8_t* setData ); + /** + * This is the empty default destructor. + */ + virtual ~CFDPPacket(); + + /** + * This is a debugging helper method that prints the whole packet content + * to the screen. + */ + void print(); +}; + +#endif /* FSFW_INC_FSFW_TMTCPACKET_CFDP_CFDPPACKET_H_ */ diff --git a/src/fsfw/tmtcpacket/cfdp/CFDPPacketStored.cpp b/src/fsfw/tmtcpacket/cfdp/CFDPPacketStored.cpp new file mode 100644 index 00000000..568d8981 --- /dev/null +++ b/src/fsfw/tmtcpacket/cfdp/CFDPPacketStored.cpp @@ -0,0 +1,97 @@ +#include "fsfw/tmtcpacket/cfdp/CFDPPacketStored.h" +#include "fsfw/objectmanager/ObjectManager.h" + +StorageManagerIF* CFDPPacketStored::store = nullptr; + +CFDPPacketStored::CFDPPacketStored(): CFDPPacket(nullptr) { +} + +CFDPPacketStored::CFDPPacketStored(store_address_t setAddress): CFDPPacket(nullptr) { + this->setStoreAddress(setAddress); +} + +CFDPPacketStored::CFDPPacketStored(const uint8_t* data, size_t size): CFDPPacket(data) { + if (this->getFullSize() != size) { + return; + } + if (this->checkAndSetStore()) { + ReturnValue_t status = store->addData(&storeAddress, data, size); + if (status != HasReturnvaluesIF::RETURN_OK) { + this->setData(nullptr, -1); + } + const uint8_t* storePtr = nullptr; + // Repoint base data pointer to the data in the store. + store->getData(storeAddress, &storePtr, &size); + this->setData(const_cast(storePtr), size); + } +} + +ReturnValue_t CFDPPacketStored::deletePacket() { + ReturnValue_t result = this->store->deleteData(this->storeAddress); + this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; + // To circumvent size checks + this->setData(nullptr, -1); + return result; +} + +//CFDPPacket* CFDPPacketStored::getPacketBase() { +// return this; +//} +void CFDPPacketStored::setStoreAddress(store_address_t setAddress) { + this->storeAddress = setAddress; + const uint8_t* tempData = nullptr; + size_t tempSize; + ReturnValue_t status = StorageManagerIF::RETURN_FAILED; + if (this->checkAndSetStore()) { + status = this->store->getData(this->storeAddress, &tempData, &tempSize); + } + if (status == StorageManagerIF::RETURN_OK) { + this->setData(const_cast(tempData), tempSize); + } else { + // To circumvent size checks + this->setData(nullptr, -1); + this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; + } +} + +store_address_t CFDPPacketStored::getStoreAddress() { + return this->storeAddress; +} + +CFDPPacketStored::~CFDPPacketStored() { +} + +ReturnValue_t CFDPPacketStored::getData(const uint8_t **dataPtr, size_t *dataSize) { + return HasReturnvaluesIF::RETURN_OK; +} + +//ReturnValue_t CFDPPacketStored::setData(const uint8_t *data) { +// return HasReturnvaluesIF::RETURN_OK; +//} + +bool CFDPPacketStored::checkAndSetStore() { + if (this->store == nullptr) { + this->store = ObjectManager::instance()->get(objects::TC_STORE); + if (this->store == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "CFDPPacketStored::CFDPPacketStored: TC Store not found!" + << std::endl; +#endif + return false; + } + } + return true; +} + +bool CFDPPacketStored::isSizeCorrect() { + const uint8_t* temp_data = nullptr; + size_t temp_size; + ReturnValue_t status = this->store->getData(this->storeAddress, &temp_data, + &temp_size); + if (status == StorageManagerIF::RETURN_OK) { + if (this->getFullSize() == temp_size) { + return true; + } + } + return false; +} diff --git a/src/fsfw/tmtcpacket/cfdp/CFDPPacketStored.h b/src/fsfw/tmtcpacket/cfdp/CFDPPacketStored.h new file mode 100644 index 00000000..2c03439b --- /dev/null +++ b/src/fsfw/tmtcpacket/cfdp/CFDPPacketStored.h @@ -0,0 +1,67 @@ +#ifndef FSFW_INC_FSFW_TMTCPACKET_CFDP_CFDPPACKETSTORED_H_ +#define FSFW_INC_FSFW_TMTCPACKET_CFDP_CFDPPACKETSTORED_H_ + +#include "../pus/tc/TcPacketStoredBase.h" +#include "CFDPPacket.h" + +class CFDPPacketStored: + public CFDPPacket, + public TcPacketStoredBase { +public: + /** + * Create stored packet with existing data. + * @param data + * @param size + */ + CFDPPacketStored(const uint8_t* data, size_t size); + /** + * Create stored packet from existing packet in store + * @param setAddress + */ + CFDPPacketStored(store_address_t setAddress); + CFDPPacketStored(); + + virtual ~CFDPPacketStored(); + + /** + * Getter function for the raw data. + * @param dataPtr [out] Pointer to the data pointer to set + * @param dataSize [out] Address of size to set. + * @return -@c RETURN_OK if data was retrieved successfully. + */ + ReturnValue_t getData(const uint8_t ** dataPtr, size_t* dataSize); + + void setStoreAddress(store_address_t setAddress); + + store_address_t getStoreAddress(); + + ReturnValue_t deletePacket(); + +private: + + bool isSizeCorrect(); +protected: + /** + * This is a pointer to the store all instances of the class use. + * If the store is not yet set (i.e. @c store is NULL), every constructor + * call tries to set it and throws an error message in case of failures. + * The default store is objects::TC_STORE. + */ + static StorageManagerIF* store; + /** + * The address where the packet data of the object instance is stored. + */ + store_address_t storeAddress; + /** + * A helper method to check if a store is assigned to the class. + * If not, the method tries to retrieve the store from the global + * ObjectManager. + * @return @li @c true if the store is linked or could be created. + * @li @c false otherwise. + */ + bool checkAndSetStore(); +}; + + + +#endif /* FSFW_INC_FSFW_TMTCPACKET_CFDP_CFDPPACKETSTORED_H_ */ diff --git a/src/fsfw/tmtcpacket/cfdp/CMakeLists.txt b/src/fsfw/tmtcpacket/cfdp/CMakeLists.txt new file mode 100644 index 00000000..0b7ab18a --- /dev/null +++ b/src/fsfw/tmtcpacket/cfdp/CMakeLists.txt @@ -0,0 +1,4 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + CFDPPacket.cpp + CFDPPacketStored.cpp +) diff --git a/src/fsfw/tmtcpacket/pus/tc/CMakeLists.txt b/src/fsfw/tmtcpacket/pus/tc/CMakeLists.txt index 723b7943..dc611263 100644 --- a/src/fsfw/tmtcpacket/pus/tc/CMakeLists.txt +++ b/src/fsfw/tmtcpacket/pus/tc/CMakeLists.txt @@ -1,5 +1,5 @@ target_sources(${LIB_FSFW_NAME} PRIVATE - TcPacketBase.cpp + TcPacketPusBase.cpp TcPacketPus.cpp TcPacketStoredBase.cpp TcPacketStoredPus.cpp diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.cpp b/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.cpp index 2b97b0d2..dc1eb4bf 100644 --- a/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.cpp +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.cpp @@ -3,7 +3,7 @@ #include -TcPacketPus::TcPacketPus(const uint8_t *setData): TcPacketBase(setData) { +TcPacketPus::TcPacketPus(const uint8_t *setData): TcPacketPusBase(setData) { tcData = reinterpret_cast(const_cast(setData)); } @@ -59,13 +59,6 @@ void TcPacketPus::setErrorControl() { (&tcData->appData)[size + 1] = (crc) & 0X00FF; // CRCL } -void TcPacketPus::setData(const uint8_t* pData) { - SpacePacketBase::setData(pData); - // This function is const-correct, but it was decided to keep the pointer non-const - // for convenience. Therefore, cast aways constness here and then cast to packet type. - tcData = reinterpret_cast(const_cast(pData)); -} - uint8_t TcPacketPus::getSecondaryHeaderFlag() const { #if FSFW_USE_PUS_C_TELECOMMANDS == 1 // Does not exist for PUS C @@ -93,5 +86,20 @@ uint16_t TcPacketPus::getSourceId() const { size_t TcPacketPus::calculateFullPacketLength(size_t appDataLen) const { return sizeof(CCSDSPrimaryHeader) + sizeof(PUSTcDataFieldHeader) + - appDataLen + TcPacketBase::CRC_SIZE; + appDataLen + TcPacketPusBase::CRC_SIZE; } + +ReturnValue_t TcPacketPus::setData(uint8_t *dataPtr, size_t maxSize, void *args) { + ReturnValue_t result = SpacePacketBase::setData(dataPtr, maxSize); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(maxSize < sizeof(TcPacketPointer)) { + return HasReturnvaluesIF::RETURN_FAILED; + } + // This function is const-correct, but it was decided to keep the pointer non-const + // for convenience. Therefore, cast away constness here and then cast to packet type. + tcData = reinterpret_cast(const_cast(dataPtr)); + return HasReturnvaluesIF::RETURN_OK; +} + diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.h b/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.h index 1bacc3a7..1b0facaf 100644 --- a/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.h +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.h @@ -4,7 +4,7 @@ #include "fsfw/FSFW.h" #include "../definitions.h" #include "fsfw/tmtcpacket/ccsds_header.h" -#include "TcPacketBase.h" +#include "TcPacketPusBase.h" #include @@ -38,7 +38,7 @@ struct TcPacketPointer { }; -class TcPacketPus: public TcPacketBase { +class TcPacketPus: public TcPacketPusBase { public: static const uint16_t TC_PACKET_MIN_SIZE = (sizeof(CCSDSPrimaryHeader) + sizeof(PUSTcDataFieldHeader) + 2); @@ -65,7 +65,8 @@ public: protected: - void setData(const uint8_t* pData) override; + ReturnValue_t setData(uint8_t* dataPtr, size_t maxSize, + void* args = nullptr) override; /** * Initializes the Tc Packet header. diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketBase.cpp b/src/fsfw/tmtcpacket/pus/tc/TcPacketPusBase.cpp similarity index 65% rename from src/fsfw/tmtcpacket/pus/tc/TcPacketBase.cpp rename to src/fsfw/tmtcpacket/pus/tc/TcPacketPusBase.cpp index 0c7a4183..1a8850b1 100644 --- a/src/fsfw/tmtcpacket/pus/tc/TcPacketBase.cpp +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketPusBase.cpp @@ -1,4 +1,4 @@ -#include "fsfw/tmtcpacket/pus/tc/TcPacketBase.h" +#include "TcPacketPusBase.h" #include "fsfw/globalfunctions/CRC.h" #include "fsfw/globalfunctions/arrayprinter.h" @@ -6,11 +6,11 @@ #include -TcPacketBase::TcPacketBase(const uint8_t* setData): SpacePacketBase(setData) {} +TcPacketPusBase::TcPacketPusBase(const uint8_t* setData): SpacePacketBase(setData) {} -TcPacketBase::~TcPacketBase() {} +TcPacketPusBase::~TcPacketPusBase() {} -void TcPacketBase::print() { +void TcPacketPusBase::print() { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "TcPacketBase::print:" << std::endl; #else diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketBase.h b/src/fsfw/tmtcpacket/pus/tc/TcPacketPusBase.h similarity index 93% rename from src/fsfw/tmtcpacket/pus/tc/TcPacketBase.h rename to src/fsfw/tmtcpacket/pus/tc/TcPacketPusBase.h index 14356c8c..b65ca0fb 100644 --- a/src/fsfw/tmtcpacket/pus/tc/TcPacketBase.h +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketPusBase.h @@ -1,6 +1,7 @@ #ifndef TMTCPACKET_PUS_TCPACKETBASE_H_ #define TMTCPACKET_PUS_TCPACKETBASE_H_ +#include #include "fsfw/tmtcpacket/SpacePacketBase.h" #include @@ -15,7 +16,8 @@ * check can be performed by making use of the getWholeData method. * @ingroup tmtcpackets */ -class TcPacketBase : public SpacePacketBase { +class TcPacketPusBase : public SpacePacketBase, + virtual public RedirectableDataPointerIF { friend class TcPacketStoredBase; public: @@ -41,11 +43,11 @@ public: * forwards the data pointer to the parent SpacePacketBase class. * @param setData The position where the packet data lies. */ - TcPacketBase( const uint8_t* setData ); + TcPacketPusBase( const uint8_t* setData ); /** * This is the empty default destructor. */ - virtual ~TcPacketBase(); + virtual ~TcPacketPusBase(); /** * This command returns the CCSDS Secondary Header Flag. @@ -133,6 +135,7 @@ public: * to the screen. */ void print(); + protected: /** @@ -143,7 +146,8 @@ protected: * * @param p_data A pointer to another PUS Telecommand Packet. */ - void setData( const uint8_t* pData ) = 0; + virtual ReturnValue_t setData(uint8_t* pData, size_t maxSize, + void* args = nullptr) override = 0; }; diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.cpp b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.cpp index 98ce1725..35bfdfeb 100644 --- a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.cpp +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.cpp @@ -46,7 +46,8 @@ bool TcPacketStoredBase::checkAndSetStore() { return true; } -void TcPacketStoredBase::setStoreAddress(store_address_t setAddress) { +void TcPacketStoredBase::setStoreAddress(store_address_t setAddress, + RedirectableDataPointerIF* packet) { this->storeAddress = setAddress; const uint8_t* tempData = nullptr; size_t tempSize; @@ -54,15 +55,12 @@ void TcPacketStoredBase::setStoreAddress(store_address_t setAddress) { if (this->checkAndSetStore()) { status = this->store->getData(this->storeAddress, &tempData, &tempSize); } - TcPacketBase* tcPacketBase = this->getPacketBase(); - if(tcPacketBase == nullptr) { - return; - } + if (status == StorageManagerIF::RETURN_OK) { - tcPacketBase->setData(tempData); + packet->setData(const_cast(tempData), tempSize); } else { - tcPacketBase->setData(nullptr); + packet->setData(nullptr, -1); this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; } } diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.h b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.h index 1e1681f6..045d40d8 100644 --- a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.h +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.h @@ -2,16 +2,10 @@ #define TMTCPACKET_PUS_TCPACKETSTORED_H_ #include "TcPacketStoredIF.h" -#include "../../../storagemanager/StorageManagerIF.h" +#include "fsfw/storagemanager/StorageManagerIF.h" /** - * This class generates a ECSS PUS Telecommand packet within a given - * intermediate storage. - * As most packets are passed between tasks with the help of a storage - * anyway, it seems logical to create a Packet-In-Storage access class - * which saves the user almost all storage handling operation. - * Packets can both be newly created with the class and be "linked" to - * packets in a store with the help of a storeAddress. + * Base class for telecommand packets like CFDP or PUS packets. * @ingroup tmtcpackets */ class TcPacketStoredBase: public TcPacketStoredIF { @@ -44,7 +38,7 @@ public: */ ReturnValue_t getData(const uint8_t ** dataPtr, size_t* dataSize) override; - void setStoreAddress(store_address_t setAddress) override; + void setStoreAddress(store_address_t setAddress, RedirectableDataPointerIF* packet) override; store_address_t getStoreAddress() override; /** diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredIF.h b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredIF.h index 3d356725..4beafedc 100644 --- a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredIF.h +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredIF.h @@ -1,9 +1,10 @@ #ifndef FSFW_TMTCPACKET_PUS_TCPACKETSTOREDIF_H_ #define FSFW_TMTCPACKET_PUS_TCPACKETSTOREDIF_H_ -#include "TcPacketBase.h" -#include "../../../storagemanager/storeAddress.h" -#include "../../../returnvalues/HasReturnvaluesIF.h" +#include +#include "TcPacketPusBase.h" +#include "fsfw/storagemanager/storeAddress.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" class TcPacketStoredIF { public: @@ -14,7 +15,7 @@ public: * if the packet is a class member and used for more than one packet. * @param setAddress The new packet id to link to. */ - virtual void setStoreAddress(store_address_t setAddress) = 0; + virtual void setStoreAddress(store_address_t setAddress, RedirectableDataPointerIF* packet) = 0; virtual store_address_t getStoreAddress() = 0; @@ -25,12 +26,6 @@ public: * @return -@c RETURN_OK if data was retrieved successfully. */ virtual ReturnValue_t getData(const uint8_t ** dataPtr, size_t* dataSize) = 0; - - /** - * Get packet base pointer which can be used to get access to PUS packet fields - * @return - */ - virtual TcPacketBase* getPacketBase() = 0; }; diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.cpp b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.cpp index 7f8f4ac8..f1ad13e1 100644 --- a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.cpp +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.cpp @@ -22,7 +22,7 @@ TcPacketStoredPus::TcPacketStoredPus(uint16_t apid, uint8_t service, #endif return; } - this->setData(pData); + this->setData(pData, TC_PACKET_MIN_SIZE + size); #if FSFW_USE_PUS_C_TELECOMMANDS == 1 pus::PusVersion pusVersion = pus::PusVersion::PUS_C_VERSION; #else @@ -39,7 +39,7 @@ TcPacketStoredPus::TcPacketStoredPus(): TcPacketStoredBase(), TcPacketPus(nullpt } TcPacketStoredPus::TcPacketStoredPus(store_address_t setAddress): TcPacketPus(nullptr) { - TcPacketStoredBase::setStoreAddress(setAddress); + TcPacketStoredBase::setStoreAddress(setAddress, this); } TcPacketStoredPus::TcPacketStoredPus(const uint8_t* data, size_t size): TcPacketPus(data) { @@ -49,23 +49,24 @@ TcPacketStoredPus::TcPacketStoredPus(const uint8_t* data, size_t size): TcPacket if (this->checkAndSetStore()) { ReturnValue_t status = store->addData(&storeAddress, data, size); if (status != HasReturnvaluesIF::RETURN_OK) { - this->setData(nullptr); + this->setData(nullptr, size); } const uint8_t* storePtr = nullptr; // Repoint base data pointer to the data in the store. store->getData(storeAddress, &storePtr, &size); - this->setData(storePtr); + this->setData(const_cast(storePtr), size); } } ReturnValue_t TcPacketStoredPus::deletePacket() { ReturnValue_t result = this->store->deleteData(this->storeAddress); this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - this->setData(nullptr); + // To circumvent size checks + this->setData(nullptr, -1); return result; } -TcPacketBase* TcPacketStoredPus::getPacketBase() { +TcPacketPusBase* TcPacketStoredPus::getPacketBase() { return this; } diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.h b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.h index 8b318733..f0434b33 100644 --- a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.h +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.h @@ -26,7 +26,7 @@ public: */ TcPacketStoredPus(uint16_t apid, uint8_t service, uint8_t subservice, uint8_t sequence_count = 0, const uint8_t* data = nullptr, - size_t size = 0, uint8_t ack = TcPacketBase::ACK_ALL); + size_t size = 0, uint8_t ack = TcPacketPusBase::ACK_ALL); /** * Create stored packet with existing data. * @param data @@ -41,7 +41,7 @@ public: TcPacketStoredPus(); ReturnValue_t deletePacket() override; - TcPacketBase* getPacketBase() override; + TcPacketPusBase* getPacketBase(); private: diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.cpp index ccf5a8ac..933a6b4c 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.cpp @@ -36,9 +36,13 @@ uint16_t TmPacketPusA::getSourceDataSize() { - CRC_SIZE + 1; } -void TmPacketPusA::setData(const uint8_t* p_Data) { - SpacePacketBase::setData(p_Data); - tmData = (TmPacketPointerPusA*) p_Data; +ReturnValue_t TmPacketPusA::setData(uint8_t* p_Data, size_t maxSize, void* args) { + ReturnValue_t result = SpacePacketBase::setData(p_Data, maxSize); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + tmData = reinterpret_cast(const_cast(p_Data)); + return HasReturnvaluesIF::RETURN_OK; } diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.h index 3856c779..9bb01890 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.h +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.h @@ -110,7 +110,8 @@ protected: * * @param p_data A pointer to another PUS Telemetry Packet. */ - void setData( const uint8_t* pData ); + ReturnValue_t setData(uint8_t* pData, size_t maxSize, + void* args = nullptr) override; /** * In case data was filled manually (almost never the case). diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp index 003d565e..f33a896a 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp @@ -35,9 +35,16 @@ uint16_t TmPacketPusC::getSourceDataSize() { return getPacketDataLength() - sizeof(tmData->dataField) - CRC_SIZE + 1; } -void TmPacketPusC::setData(const uint8_t* p_Data) { - SpacePacketBase::setData(p_Data); - tmData = (TmPacketPointerPusC*) p_Data; +ReturnValue_t TmPacketPusC::setData(uint8_t* p_Data, size_t maxSize, void* args) { + ReturnValue_t result = SpacePacketBase::setData(p_Data, maxSize); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(maxSize < sizeof(TmPacketPointerPusC)) { + return HasReturnvaluesIF::RETURN_OK; + } + tmData = reinterpret_cast(const_cast(p_Data)); + return HasReturnvaluesIF::RETURN_OK; } diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h index 3a9be132..b3780183 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h @@ -110,9 +110,9 @@ protected: * This call overwrites the parent's setData method to set both its * @c tc_data pointer and the parent's @c data pointer. * - * @param p_data A pointer to another PUS Telemetry Packet. + * @param pData A pointer to another PUS Telemetry Packet. */ - void setData( const uint8_t* pData ); + ReturnValue_t setData(uint8_t* pData, size_t maxSize, void* args = nullptr) override; /** * In case data was filled manually (almost never the case). diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.cpp index 523fb619..f2cc5a67 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.cpp @@ -27,7 +27,7 @@ store_address_t TmPacketStoredBase::getStoreAddress() { void TmPacketStoredBase::deletePacket() { store->deleteData(storeAddress); storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - setDataPointer(nullptr); + setData(nullptr, -1); } void TmPacketStoredBase::setStoreAddress(store_address_t setAddress) { @@ -39,9 +39,9 @@ void TmPacketStoredBase::setStoreAddress(store_address_t setAddress) { } ReturnValue_t status = store->getData(storeAddress, &tempData, &tempSize); if (status == StorageManagerIF::RETURN_OK) { - setDataPointer(tempData); + setData(const_cast(tempData), tempSize); } else { - setDataPointer(nullptr); + setData(nullptr, -1); storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; } } diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.h index 91ca2f93..372b1e63 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.h +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.h @@ -21,7 +21,7 @@ * packets in a store with the help of a storeAddress. * @ingroup tmtcpackets */ -class TmPacketStoredBase { +class TmPacketStoredBase: virtual public RedirectableDataPointerIF { public: /** * This is a default constructor which does not set the data pointer. @@ -33,7 +33,6 @@ public: virtual ~TmPacketStoredBase(); virtual uint8_t* getAllTmData() = 0; - virtual void setDataPointer(const uint8_t* newPointer) = 0; /** * This is a getter for the current store address of the packet. diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp index 4ffacce4..b4b396b5 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp @@ -26,7 +26,7 @@ TmPacketStoredPusA::TmPacketStoredPusA(uint16_t apid, uint8_t service, handleStoreFailure("A", returnValue, sizeToReserve); return; } - setData(pData); + setData(pData, sizeToReserve); initializeTmPacket(apid, service, subservice, packetSubcounter); memcpy(getSourceData(), headerData, headerSize); memcpy(getSourceData() + headerSize, data, size); @@ -56,7 +56,7 @@ TmPacketStoredPusA::TmPacketStoredPusA(uint16_t apid, uint8_t service, handleStoreFailure("A", returnValue, sizeToReserve); return; } - setData(pData); + setData(pData, sizeToReserve); initializeTmPacket(apid, service, subservice, packetSubcounter); uint8_t *putDataHere = getSourceData(); size_t size = 0; @@ -75,6 +75,6 @@ uint8_t* TmPacketStoredPusA::getAllTmData() { return getWholeData(); } -void TmPacketStoredPusA::setDataPointer(const uint8_t *newPointer) { - setData(newPointer); +ReturnValue_t TmPacketStoredPusA::setData(uint8_t *newPointer, size_t maxSize, void* args) { + return TmPacketPusA::setData(newPointer, maxSize); } diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.h index 6a338cd5..6fa80949 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.h +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.h @@ -57,7 +57,17 @@ public: SerializeIF* header = nullptr); uint8_t* getAllTmData() override; - void setDataPointer(const uint8_t* newPointer) override; + +private: + + /** + * Implementation required by base class + * @param newPointer + * @param maxSize + * @param args + * @return + */ + ReturnValue_t setData(uint8_t* newPointer, size_t maxSize, void* args = nullptr) override; }; diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp index ee574299..8d7dd9eb 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp @@ -27,7 +27,7 @@ TmPacketStoredPusC::TmPacketStoredPusC(uint16_t apid, uint8_t service, handleStoreFailure("C", returnValue, sizeToReserve); return; } - setData(pData); + setData(pData, sizeToReserve); initializeTmPacket(apid, service, subservice, packetSubcounter, destinationId, timeRefField); memcpy(getSourceData(), headerData, headerSize); memcpy(getSourceData() + headerSize, data, size); @@ -56,7 +56,7 @@ TmPacketStoredPusC::TmPacketStoredPusC(uint16_t apid, uint8_t service, handleStoreFailure("C", returnValue, sizeToReserve); return; } - setData(pData); + TmPacketPusC::setData(pData, sizeToReserve); initializeTmPacket(apid, service, subservice, packetSubcounter, destinationId, timeRefField); uint8_t *putDataHere = getSourceData(); size_t size = 0; @@ -76,6 +76,7 @@ uint8_t* TmPacketStoredPusC::getAllTmData() { return getWholeData(); } -void TmPacketStoredPusC::setDataPointer(const uint8_t *newPointer) { - setData(newPointer); +ReturnValue_t TmPacketStoredPusC::setData(uint8_t *newPointer, size_t maxSize, + void* args) { + return TmPacketPusC::setData(newPointer, maxSize); } diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.h index 35c66083..cbf62b1b 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.h +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.h @@ -59,7 +59,17 @@ public: SerializeIF* header = nullptr, uint16_t destinationId = 0, uint8_t timeRefField = 0); uint8_t* getAllTmData() override; - void setDataPointer(const uint8_t* newPointer) override; + +private: + + /** + * Implementation required by base class + * @param newPointer + * @param maxSize + * @param args + * @return + */ + ReturnValue_t setData(uint8_t* newPointer, size_t maxSize, void* args = nullptr) override; }; diff --git a/src/fsfw/tmtcservices/CommandingServiceBase.cpp b/src/fsfw/tmtcservices/CommandingServiceBase.cpp index 10805b47..00fed415 100644 --- a/src/fsfw/tmtcservices/CommandingServiceBase.cpp +++ b/src/fsfw/tmtcservices/CommandingServiceBase.cpp @@ -13,300 +13,300 @@ 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, - uint16_t commandTimeoutSeconds, size_t queueDepth) : - SystemObject(setObjectId), apid(apid), service(service), - timeoutSeconds(commandTimeoutSeconds), - commandMap(numberOfParallelCommands) { - commandQueue = QueueFactory::instance()->createMessageQueue(queueDepth); - requestQueue = QueueFactory::instance()->createMessageQueue(queueDepth); + uint16_t apid, uint8_t service, uint8_t numberOfParallelCommands, + uint16_t commandTimeoutSeconds, size_t queueDepth) : + SystemObject(setObjectId), apid(apid), service(service), + timeoutSeconds(commandTimeoutSeconds), + commandMap(numberOfParallelCommands) { + commandQueue = QueueFactory::instance()->createMessageQueue(queueDepth); + requestQueue = QueueFactory::instance()->createMessageQueue(queueDepth); } void CommandingServiceBase::setPacketSource(object_id_t packetSource) { - this->packetSource = packetSource; + this->packetSource = packetSource; } void CommandingServiceBase::setPacketDestination( - object_id_t packetDestination) { - this->packetDestination = packetDestination; + object_id_t packetDestination) { + this->packetDestination = packetDestination; } CommandingServiceBase::~CommandingServiceBase() { - QueueFactory::instance()->deleteMessageQueue(commandQueue); - QueueFactory::instance()->deleteMessageQueue(requestQueue); + QueueFactory::instance()->deleteMessageQueue(commandQueue); + QueueFactory::instance()->deleteMessageQueue(requestQueue); } ReturnValue_t CommandingServiceBase::performOperation(uint8_t opCode) { - handleCommandQueue(); - handleRequestQueue(); - checkTimeout(); - doPeriodicOperation(); - return RETURN_OK; + handleCommandQueue(); + handleRequestQueue(); + checkTimeout(); + doPeriodicOperation(); + return RETURN_OK; } uint16_t CommandingServiceBase::getIdentifier() { - return service; + return service; } MessageQueueId_t CommandingServiceBase::getRequestQueue() { - return requestQueue->getId(); + return requestQueue->getId(); } ReturnValue_t CommandingServiceBase::initialize() { - ReturnValue_t result = SystemObject::initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } + ReturnValue_t result = SystemObject::initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } - if(packetDestination == objects::NO_OBJECT) { - packetDestination = defaultPacketDestination; - } - AcceptsTelemetryIF* packetForwarding = - ObjectManager::instance()->get(packetDestination); + if(packetDestination == objects::NO_OBJECT) { + packetDestination = defaultPacketDestination; + } + AcceptsTelemetryIF* packetForwarding = + ObjectManager::instance()->get(packetDestination); - if(packetSource == objects::NO_OBJECT) { - packetSource = defaultPacketSource; - } - PUSDistributorIF* distributor = ObjectManager::instance()->get( - packetSource); + if(packetSource == objects::NO_OBJECT) { + packetSource = defaultPacketSource; + } + PUSDistributorIF* distributor = ObjectManager::instance()->get( + packetSource); - if (packetForwarding == nullptr or distributor == nullptr) { + if (packetForwarding == nullptr or distributor == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "CommandingServiceBase::intialize: Packet source or " - "packet destination invalid!" << std::endl; + sif::error << "CommandingServiceBase::intialize: Packet source or " + "packet destination invalid!" << std::endl; #endif - return ObjectManagerIF::CHILD_INIT_FAILED; - } + return ObjectManagerIF::CHILD_INIT_FAILED; + } - distributor->registerService(this); - requestQueue->setDefaultDestination( - packetForwarding->getReportReceptionQueue()); + distributor->registerService(this); + requestQueue->setDefaultDestination( + packetForwarding->getReportReceptionQueue()); - IPCStore = ObjectManager::instance()->get(objects::IPC_STORE); - TCStore = ObjectManager::instance()->get(objects::TC_STORE); + IPCStore = ObjectManager::instance()->get(objects::IPC_STORE); + TCStore = ObjectManager::instance()->get(objects::TC_STORE); - if (IPCStore == nullptr or TCStore == nullptr) { + if (IPCStore == nullptr or TCStore == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "CommandingServiceBase::intialize: IPC store or TC store " - "not initialized yet!" << std::endl; + sif::error << "CommandingServiceBase::intialize: IPC store or TC store " + "not initialized yet!" << std::endl; #endif - return ObjectManagerIF::CHILD_INIT_FAILED; - } + return ObjectManagerIF::CHILD_INIT_FAILED; + } - return RETURN_OK; + return RETURN_OK; } void CommandingServiceBase::handleCommandQueue() { - CommandMessage reply; - ReturnValue_t result = RETURN_FAILED; - while(true) { - result = commandQueue->receiveMessage(&reply); - if (result == HasReturnvaluesIF::RETURN_OK) { - handleCommandMessage(&reply); - continue; - } - else if(result == MessageQueueIF::EMPTY) { - break; - } - else { + CommandMessage reply; + ReturnValue_t result = RETURN_FAILED; + while(true) { + result = commandQueue->receiveMessage(&reply); + if (result == HasReturnvaluesIF::RETURN_OK) { + handleCommandMessage(&reply); + continue; + } + else if(result == MessageQueueIF::EMPTY) { + break; + } + else { #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "CommandingServiceBase::handleCommandQueue: Receiving message failed" - "with code" << result << std::endl; + sif::warning << "CommandingServiceBase::handleCommandQueue: Receiving message failed" + "with code" << result << std::endl; #else - sif::printWarning("CommandingServiceBase::handleCommandQueue: Receiving message " - "failed with code %d\n", result); + sif::printWarning("CommandingServiceBase::handleCommandQueue: Receiving message " + "failed with code %d\n", result); #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ #endif /* FSFW_VERBOSE_LEVEL >= 1 */ - break; - } - } + break; + } + } } void CommandingServiceBase::handleCommandMessage(CommandMessage* reply) { - bool isStep = false; - CommandMessage nextCommand; - CommandMapIter iter = commandMap.find(reply->getSender()); + bool isStep = false; + CommandMessage nextCommand; + CommandMapIter iter = commandMap.find(reply->getSender()); - // handle unrequested reply first - if (reply->getSender() == MessageQueueIF::NO_QUEUE or - iter == commandMap.end()) { - handleUnrequestedReply(reply); - return; - } - nextCommand.setCommand(CommandMessage::CMD_NONE); + // handle unrequested reply first + if (reply->getSender() == MessageQueueIF::NO_QUEUE or + iter == commandMap.end()) { + handleUnrequestedReply(reply); + return; + } + nextCommand.setCommand(CommandMessage::CMD_NONE); - // Implemented by child class, specifies what to do with reply. - ReturnValue_t result = handleReply(reply, iter->second.command, &iter->second.state, - &nextCommand, iter->second.objectId, &isStep); + // Implemented by child class, specifies what to do with reply. + ReturnValue_t result = handleReply(reply, iter->second.command, &iter->second.state, + &nextCommand, iter->second.objectId, &isStep); - /* If the child implementation does not implement special handling for - * rejected replies (RETURN_FAILED or INVALID_REPLY is returned), a - * failure verification will be generated with the reason as the - * return code and the initial command as failure parameter 1 */ - if((reply->getCommand() == CommandMessage::REPLY_REJECTED) and - (result == RETURN_FAILED or result == INVALID_REPLY)) { - result = reply->getReplyRejectedReason(); - failureParameter1 = iter->second.command; - } + /* If the child implementation does not implement special handling for + * rejected replies (RETURN_FAILED or INVALID_REPLY is returned), a + * failure verification will be generated with the reason as the + * return code and the initial command as failure parameter 1 */ + if((reply->getCommand() == CommandMessage::REPLY_REJECTED) and + (result == RETURN_FAILED or result == INVALID_REPLY)) { + result = reply->getReplyRejectedReason(); + failureParameter1 = iter->second.command; + } - switch (result) { - case EXECUTION_COMPLETE: - case RETURN_OK: - case NO_STEP_MESSAGE: - // handle result of reply handler implemented by developer. - handleReplyHandlerResult(result, iter, &nextCommand, reply, isStep); - break; - case INVALID_REPLY: - //might be just an unrequested reply at a bad moment - handleUnrequestedReply(reply); - break; - default: - if (isStep) { - verificationReporter.sendFailureReport( - tc_verification::PROGRESS_FAILURE, iter->second.tcInfo.ackFlags, - iter->second.tcInfo.tcPacketId, iter->second.tcInfo.tcSequenceControl, - result, ++iter->second.step, failureParameter1, - failureParameter2); - } else { - verificationReporter.sendFailureReport( - tc_verification::COMPLETION_FAILURE, iter->second.tcInfo.ackFlags, - iter->second.tcInfo.tcPacketId, iter->second.tcInfo.tcSequenceControl, - result, 0, failureParameter1, failureParameter2); - } - failureParameter1 = 0; - failureParameter2 = 0; - checkAndExecuteFifo(iter); - break; - } + switch (result) { + case EXECUTION_COMPLETE: + case RETURN_OK: + case NO_STEP_MESSAGE: + // handle result of reply handler implemented by developer. + handleReplyHandlerResult(result, iter, &nextCommand, reply, isStep); + break; + case INVALID_REPLY: + //might be just an unrequested reply at a bad moment + handleUnrequestedReply(reply); + break; + default: + if (isStep) { + verificationReporter.sendFailureReport( + tc_verification::PROGRESS_FAILURE, iter->second.tcInfo.ackFlags, + iter->second.tcInfo.tcPacketId, iter->second.tcInfo.tcSequenceControl, + result, ++iter->second.step, failureParameter1, + failureParameter2); + } else { + verificationReporter.sendFailureReport( + tc_verification::COMPLETION_FAILURE, iter->second.tcInfo.ackFlags, + iter->second.tcInfo.tcPacketId, iter->second.tcInfo.tcSequenceControl, + result, 0, failureParameter1, failureParameter2); + } + failureParameter1 = 0; + failureParameter2 = 0; + checkAndExecuteFifo(iter); + break; + } } void CommandingServiceBase::handleReplyHandlerResult(ReturnValue_t result, - CommandMapIter iter, CommandMessage* nextCommand, - CommandMessage* reply, bool& isStep) { - iter->second.command = nextCommand->getCommand(); + CommandMapIter iter, CommandMessage* nextCommand, + CommandMessage* reply, bool& isStep) { + iter->second.command = nextCommand->getCommand(); - // In case a new command is to be sent immediately, this is performed here. - // If no new command is sent, only analyse reply result by initializing - // sendResult as RETURN_OK - ReturnValue_t sendResult = RETURN_OK; - if (nextCommand->getCommand() != CommandMessage::CMD_NONE) { - sendResult = commandQueue->sendMessage(reply->getSender(), - nextCommand); - } + // In case a new command is to be sent immediately, this is performed here. + // If no new command is sent, only analyse reply result by initializing + // sendResult as RETURN_OK + ReturnValue_t sendResult = RETURN_OK; + if (nextCommand->getCommand() != CommandMessage::CMD_NONE) { + sendResult = commandQueue->sendMessage(reply->getSender(), + nextCommand); + } - if (sendResult == RETURN_OK) { - if (isStep and result != NO_STEP_MESSAGE) { - verificationReporter.sendSuccessReport( - tc_verification::PROGRESS_SUCCESS, - iter->second.tcInfo.ackFlags, iter->second.tcInfo.tcPacketId, - iter->second.tcInfo.tcSequenceControl, ++iter->second.step); - } - else { - verificationReporter.sendSuccessReport( - tc_verification::COMPLETION_SUCCESS, - iter->second.tcInfo.ackFlags, iter->second.tcInfo.tcPacketId, - iter->second.tcInfo.tcSequenceControl, 0); - checkAndExecuteFifo(iter); - } - } - else { - if (isStep) { - nextCommand->clearCommandMessage(); - verificationReporter.sendFailureReport( - tc_verification::PROGRESS_FAILURE, iter->second.tcInfo.ackFlags, - iter->second.tcInfo.tcPacketId, - iter->second.tcInfo.tcSequenceControl, sendResult, - ++iter->second.step, failureParameter1, failureParameter2); - } else { - nextCommand->clearCommandMessage(); - verificationReporter.sendFailureReport( - tc_verification::COMPLETION_FAILURE, - iter->second.tcInfo.ackFlags, iter->second.tcInfo.tcPacketId, - iter->second.tcInfo.tcSequenceControl, sendResult, 0, - failureParameter1, failureParameter2); - } - failureParameter1 = 0; - failureParameter2 = 0; - checkAndExecuteFifo(iter); - } + if (sendResult == RETURN_OK) { + if (isStep and result != NO_STEP_MESSAGE) { + verificationReporter.sendSuccessReport( + tc_verification::PROGRESS_SUCCESS, + iter->second.tcInfo.ackFlags, iter->second.tcInfo.tcPacketId, + iter->second.tcInfo.tcSequenceControl, ++iter->second.step); + } + else { + verificationReporter.sendSuccessReport( + tc_verification::COMPLETION_SUCCESS, + iter->second.tcInfo.ackFlags, iter->second.tcInfo.tcPacketId, + iter->second.tcInfo.tcSequenceControl, 0); + checkAndExecuteFifo(iter); + } + } + else { + if (isStep) { + nextCommand->clearCommandMessage(); + verificationReporter.sendFailureReport( + tc_verification::PROGRESS_FAILURE, iter->second.tcInfo.ackFlags, + iter->second.tcInfo.tcPacketId, + iter->second.tcInfo.tcSequenceControl, sendResult, + ++iter->second.step, failureParameter1, failureParameter2); + } else { + nextCommand->clearCommandMessage(); + verificationReporter.sendFailureReport( + tc_verification::COMPLETION_FAILURE, + iter->second.tcInfo.ackFlags, iter->second.tcInfo.tcPacketId, + iter->second.tcInfo.tcSequenceControl, sendResult, 0, + failureParameter1, failureParameter2); + } + failureParameter1 = 0; + failureParameter2 = 0; + checkAndExecuteFifo(iter); + } } void CommandingServiceBase::handleRequestQueue() { - TmTcMessage message; - ReturnValue_t result; - store_address_t address; - TcPacketStoredPus packet; - MessageQueueId_t queue; - object_id_t objectId; - for (result = requestQueue->receiveMessage(&message); result == RETURN_OK; - result = requestQueue->receiveMessage(&message)) { - address = message.getStorageId(); - packet.setStoreAddress(address); + TmTcMessage message; + ReturnValue_t result; + store_address_t address; + TcPacketStoredPus packet; + MessageQueueId_t queue; + object_id_t objectId; + for (result = requestQueue->receiveMessage(&message); result == RETURN_OK; + result = requestQueue->receiveMessage(&message)) { + address = message.getStorageId(); + packet.setStoreAddress(address, &packet); - if ((packet.getSubService() == 0) - or (isValidSubservice(packet.getSubService()) != RETURN_OK)) { - rejectPacket(tc_verification::START_FAILURE, &packet, INVALID_SUBSERVICE); - continue; - } + if ((packet.getSubService() == 0) + or (isValidSubservice(packet.getSubService()) != RETURN_OK)) { + rejectPacket(tc_verification::START_FAILURE, &packet, INVALID_SUBSERVICE); + continue; + } - result = getMessageQueueAndObject(packet.getSubService(), - packet.getApplicationData(), packet.getApplicationDataSize(), - &queue, &objectId); - if (result != HasReturnvaluesIF::RETURN_OK) { - rejectPacket(tc_verification::START_FAILURE, &packet, result); - continue; - } + result = getMessageQueueAndObject(packet.getSubService(), + packet.getApplicationData(), packet.getApplicationDataSize(), + &queue, &objectId); + if (result != HasReturnvaluesIF::RETURN_OK) { + rejectPacket(tc_verification::START_FAILURE, &packet, result); + continue; + } - //Is a command already active for the target object? - CommandMapIter iter; - iter = commandMap.find(queue); + //Is a command already active for the target object? + CommandMapIter iter; + iter = commandMap.find(queue); - if (iter != commandMap.end()) { - result = iter->second.fifo.insert(address); - if (result != RETURN_OK) { - rejectPacket(tc_verification::START_FAILURE, &packet, OBJECT_BUSY); - } - } else { - CommandInfo newInfo; //Info will be set by startExecution if neccessary - newInfo.objectId = objectId; - result = commandMap.insert(queue, newInfo, &iter); - if (result != RETURN_OK) { - rejectPacket(tc_verification::START_FAILURE, &packet, BUSY); - } else { - startExecution(&packet, iter); - } - } + if (iter != commandMap.end()) { + result = iter->second.fifo.insert(address); + if (result != RETURN_OK) { + rejectPacket(tc_verification::START_FAILURE, &packet, OBJECT_BUSY); + } + } else { + CommandInfo newInfo; //Info will be set by startExecution if neccessary + newInfo.objectId = objectId; + result = commandMap.insert(queue, newInfo, &iter); + if (result != RETURN_OK) { + rejectPacket(tc_verification::START_FAILURE, &packet, BUSY); + } else { + startExecution(&packet, iter); + } + } - } + } } ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice, - const uint8_t* data, size_t dataLen, const uint8_t* headerData, - size_t headerSize) { + const uint8_t* data, size_t dataLen, const uint8_t* headerData, + size_t headerSize) { #if FSFW_USE_PUS_C_TELEMETRY == 0 - TmPacketStoredPusA tmPacketStored(this->apid, this->service, subservice, - this->tmPacketCounter, data, dataLen, headerData, headerSize); + TmPacketStoredPusA tmPacketStored(this->apid, this->service, subservice, + this->tmPacketCounter, data, dataLen, headerData, headerSize); #else - TmPacketStoredPusC tmPacketStored(this->apid, this->service, subservice, + TmPacketStoredPusC tmPacketStored(this->apid, this->service, subservice, this->tmPacketCounter, data, dataLen, headerData, headerSize); #endif - ReturnValue_t result = tmPacketStored.sendPacket( - requestQueue->getDefaultDestination(), requestQueue->getId()); - if (result == HasReturnvaluesIF::RETURN_OK) { - this->tmPacketCounter++; - } - return result; + ReturnValue_t result = tmPacketStored.sendPacket( + requestQueue->getDefaultDestination(), requestQueue->getId()); + if (result == HasReturnvaluesIF::RETURN_OK) { + this->tmPacketCounter++; + } + return result; } @@ -316,7 +316,7 @@ ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice, uint8_t* pBuffer = buffer; size_t size = 0; SerializeAdapter::serialize(&objectId, &pBuffer, &size, - sizeof(object_id_t), SerializeIF::Endianness::BIG); + sizeof(object_id_t), SerializeIF::Endianness::BIG); #if FSFW_USE_PUS_C_TELEMETRY == 0 TmPacketStoredPusA tmPacketStored(this->apid, this->service, subservice, this->tmPacketCounter, data, dataLen, buffer, size); @@ -351,95 +351,96 @@ ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice, } -void CommandingServiceBase::startExecution(TcPacketStoredBase *storedPacket, +void CommandingServiceBase::startExecution(TcPacketStoredPus* storedPacket, CommandMapIter iter) { ReturnValue_t result = RETURN_OK; CommandMessage command; - TcPacketBase* tcPacketBase = storedPacket->getPacketBase(); - if(tcPacketBase == nullptr) { + //TcPacketPusBase* tcPacketBase = storedPacket->getPacketBase(); + if(storedPacket == nullptr) { return; } - iter->second.subservice = tcPacketBase->getSubService(); + iter->second.subservice = storedPacket->getSubService(); result = prepareCommand(&command, iter->second.subservice, - tcPacketBase->getApplicationData(), - tcPacketBase->getApplicationDataSize(), &iter->second.state, + storedPacket->getApplicationData(), + storedPacket->getApplicationDataSize(), &iter->second.state, iter->second.objectId); ReturnValue_t sendResult = RETURN_OK; - switch (result) { - case RETURN_OK: - if (command.getCommand() != CommandMessage::CMD_NONE) { - sendResult = commandQueue->sendMessage(iter.value->first, - &command); - } - if (sendResult == RETURN_OK) { - Clock::getUptime(&iter->second.uptimeOfStart); - iter->second.step = 0; - iter->second.subservice = tcPacketBase->getSubService(); - iter->second.command = command.getCommand(); - iter->second.tcInfo.ackFlags = tcPacketBase->getAcknowledgeFlags(); - iter->second.tcInfo.tcPacketId = tcPacketBase->getPacketId(); - iter->second.tcInfo.tcSequenceControl = - tcPacketBase->getPacketSequenceControl(); - acceptPacket(tc_verification::START_SUCCESS, storedPacket); - } else { - command.clearCommandMessage(); - rejectPacket(tc_verification::START_FAILURE, storedPacket, sendResult); - checkAndExecuteFifo(iter); - } - break; - case EXECUTION_COMPLETE: - if (command.getCommand() != CommandMessage::CMD_NONE) { - //Fire-and-forget command. - sendResult = commandQueue->sendMessage(iter.value->first, - &command); - } - if (sendResult == RETURN_OK) { - verificationReporter.sendSuccessReport(tc_verification::START_SUCCESS, - storedPacket->getPacketBase()); - acceptPacket(tc_verification::COMPLETION_SUCCESS, storedPacket); - checkAndExecuteFifo(iter); - } else { - command.clearCommandMessage(); - rejectPacket(tc_verification::START_FAILURE, storedPacket, sendResult); - checkAndExecuteFifo(iter); - } - break; - default: - rejectPacket(tc_verification::START_FAILURE, storedPacket, result); - checkAndExecuteFifo(iter); - break; - } + switch (result) { + case RETURN_OK: + if (command.getCommand() != CommandMessage::CMD_NONE) { + sendResult = commandQueue->sendMessage(iter.value->first, + &command); + } + if (sendResult == RETURN_OK) { + Clock::getUptime(&iter->second.uptimeOfStart); + iter->second.step = 0; + iter->second.subservice = storedPacket->getSubService(); + iter->second.command = command.getCommand(); + iter->second.tcInfo.ackFlags = storedPacket->getAcknowledgeFlags(); + iter->second.tcInfo.tcPacketId = storedPacket->getPacketId(); + iter->second.tcInfo.tcSequenceControl = + storedPacket->getPacketSequenceControl(); + acceptPacket(tc_verification::START_SUCCESS, storedPacket); + } else { + command.clearCommandMessage(); + rejectPacket(tc_verification::START_FAILURE, storedPacket, sendResult); + checkAndExecuteFifo(iter); + } + break; + case EXECUTION_COMPLETE: + if (command.getCommand() != CommandMessage::CMD_NONE) { + //Fire-and-forget command. + sendResult = commandQueue->sendMessage(iter.value->first, + &command); + } + if (sendResult == RETURN_OK) { + verificationReporter.sendSuccessReport(tc_verification::START_SUCCESS, + storedPacket->getPacketBase()); + acceptPacket(tc_verification::COMPLETION_SUCCESS, storedPacket); + checkAndExecuteFifo(iter); + } else { + command.clearCommandMessage(); + rejectPacket(tc_verification::START_FAILURE, storedPacket, sendResult); + checkAndExecuteFifo(iter); + } + break; + default: + rejectPacket(tc_verification::START_FAILURE, storedPacket, result); + checkAndExecuteFifo(iter); + break; + } } void CommandingServiceBase::rejectPacket(uint8_t reportId, - TcPacketStoredBase* packet, ReturnValue_t errorCode) { - verificationReporter.sendFailureReport(reportId, packet->getPacketBase(), errorCode); - packet->deletePacket(); + TcPacketStoredPus* packet, ReturnValue_t errorCode) { + verificationReporter.sendFailureReport(reportId, dynamic_cast(packet), + errorCode); + packet->deletePacket(); } void CommandingServiceBase::acceptPacket(uint8_t reportId, - TcPacketStoredBase* packet) { - verificationReporter.sendSuccessReport(reportId, packet->getPacketBase()); - packet->deletePacket(); + TcPacketStoredPus* packet) { + verificationReporter.sendSuccessReport(reportId, dynamic_cast(packet)); + packet->deletePacket(); } void CommandingServiceBase::checkAndExecuteFifo(CommandMapIter& iter) { - store_address_t address; - if (iter->second.fifo.retrieve(&address) != RETURN_OK) { - commandMap.erase(&iter); - } else { - TcPacketStoredPus newPacket(address); - startExecution(&newPacket, iter); - } + store_address_t address; + if (iter->second.fifo.retrieve(&address) != RETURN_OK) { + commandMap.erase(&iter); + } else { + TcPacketStoredPus newPacket(address); + startExecution(&newPacket, iter); + } } void CommandingServiceBase::handleUnrequestedReply(CommandMessage* reply) { - reply->clearCommandMessage(); + reply->clearCommandMessage(); } @@ -447,22 +448,22 @@ inline void CommandingServiceBase::doPeriodicOperation() { } MessageQueueId_t CommandingServiceBase::getCommandQueue() { - return commandQueue->getId(); + return commandQueue->getId(); } void CommandingServiceBase::checkTimeout() { - uint32_t uptime; - Clock::getUptime(&uptime); - CommandMapIter iter; - for (iter = commandMap.begin(); iter != commandMap.end(); ++iter) { - if ((iter->second.uptimeOfStart + (timeoutSeconds * 1000)) < uptime) { - verificationReporter.sendFailureReport( - tc_verification::COMPLETION_FAILURE, iter->second.tcInfo.ackFlags, - iter->second.tcInfo.tcPacketId, iter->second.tcInfo.tcSequenceControl, - TIMEOUT); - checkAndExecuteFifo(iter); - } - } + uint32_t uptime; + Clock::getUptime(&uptime); + CommandMapIter iter; + for (iter = commandMap.begin(); iter != commandMap.end(); ++iter) { + if ((iter->second.uptimeOfStart + (timeoutSeconds * 1000)) < uptime) { + verificationReporter.sendFailureReport( + tc_verification::COMPLETION_FAILURE, iter->second.tcInfo.ackFlags, + iter->second.tcInfo.tcPacketId, iter->second.tcInfo.tcSequenceControl, + TIMEOUT); + checkAndExecuteFifo(iter); + } + } } void CommandingServiceBase::setTaskIF(PeriodicTaskIF* task_) { diff --git a/src/fsfw/tmtcservices/CommandingServiceBase.h b/src/fsfw/tmtcservices/CommandingServiceBase.h index b6709693..d9b1b5ef 100644 --- a/src/fsfw/tmtcservices/CommandingServiceBase.h +++ b/src/fsfw/tmtcservices/CommandingServiceBase.h @@ -14,8 +14,8 @@ #include "fsfw/container/FIFO.h" #include "fsfw/serialize/SerializeIF.h" -class TcPacketStored; class TcPacketStoredBase; +class TcPacketStoredPus; namespace Factory{ void setStaticFrameworkObjectIds(); @@ -36,333 +36,333 @@ void setStaticFrameworkObjectIds(); * @ingroup pus_services */ class CommandingServiceBase: public SystemObject, - public AcceptsTelecommandsIF, - public ExecutableObjectIF, - public HasReturnvaluesIF { - friend void (Factory::setStaticFrameworkObjectIds)(); +public AcceptsTelecommandsIF, +public ExecutableObjectIF, +public HasReturnvaluesIF { + friend void (Factory::setStaticFrameworkObjectIds)(); public: - // We could make this configurable via preprocessor and the FSFWConfig file. - static constexpr uint8_t COMMAND_INFO_FIFO_DEPTH = - fsfwconfig::FSFW_CSB_FIFO_DEPTH; + // We could make this configurable via preprocessor and the FSFWConfig file. + static constexpr uint8_t COMMAND_INFO_FIFO_DEPTH = + fsfwconfig::FSFW_CSB_FIFO_DEPTH; - static const uint8_t INTERFACE_ID = CLASS_ID::COMMAND_SERVICE_BASE; + static const uint8_t INTERFACE_ID = CLASS_ID::COMMAND_SERVICE_BASE; - static const ReturnValue_t EXECUTION_COMPLETE = MAKE_RETURN_CODE(1); - static const ReturnValue_t NO_STEP_MESSAGE = MAKE_RETURN_CODE(2); - static const ReturnValue_t OBJECT_BUSY = MAKE_RETURN_CODE(3); - static const ReturnValue_t BUSY = MAKE_RETURN_CODE(4); - static const ReturnValue_t INVALID_TC = MAKE_RETURN_CODE(5); - static const ReturnValue_t INVALID_OBJECT = MAKE_RETURN_CODE(6); - static const ReturnValue_t INVALID_REPLY = MAKE_RETURN_CODE(7); + static const ReturnValue_t EXECUTION_COMPLETE = MAKE_RETURN_CODE(1); + static const ReturnValue_t NO_STEP_MESSAGE = MAKE_RETURN_CODE(2); + static const ReturnValue_t OBJECT_BUSY = MAKE_RETURN_CODE(3); + static const ReturnValue_t BUSY = MAKE_RETURN_CODE(4); + static const ReturnValue_t INVALID_TC = MAKE_RETURN_CODE(5); + static const ReturnValue_t INVALID_OBJECT = MAKE_RETURN_CODE(6); + static const ReturnValue_t INVALID_REPLY = MAKE_RETURN_CODE(7); - /** - * Class constructor. Initializes two important MessageQueues: - * commandQueue for command reception and requestQueue for device reception - * @param setObjectId - * @param apid - * @param service - * @param numberOfParallelCommands - * @param commandTimeout_seconds - * @param setPacketSource - * @param setPacketDestination - * @param queueDepth - */ - CommandingServiceBase(object_id_t setObjectId, uint16_t apid, - uint8_t service, uint8_t numberOfParallelCommands, - uint16_t commandTimeoutSeconds, size_t queueDepth = 20); - virtual ~CommandingServiceBase(); + /** + * Class constructor. Initializes two important MessageQueues: + * commandQueue for command reception and requestQueue for device reception + * @param setObjectId + * @param apid + * @param service + * @param numberOfParallelCommands + * @param commandTimeout_seconds + * @param setPacketSource + * @param setPacketDestination + * @param queueDepth + */ + CommandingServiceBase(object_id_t setObjectId, uint16_t apid, + uint8_t service, uint8_t numberOfParallelCommands, + uint16_t commandTimeoutSeconds, size_t queueDepth = 20); + virtual ~CommandingServiceBase(); - /** - * This setter can be used to set the packet source individually instead - * of using the default static framework ID set in the factory. - * This should be called at object initialization and not during run-time! - * @param packetSource - */ - void setPacketSource(object_id_t packetSource); - /** - * This setter can be used to set the packet destination individually - * instead of using the default static framework ID set in the factory. - * This should be called at object initialization and not during run-time! - * @param packetDestination - */ - void setPacketDestination(object_id_t packetDestination); + /** + * This setter can be used to set the packet source individually instead + * of using the default static framework ID set in the factory. + * This should be called at object initialization and not during run-time! + * @param packetSource + */ + void setPacketSource(object_id_t packetSource); + /** + * This setter can be used to set the packet destination individually + * instead of using the default static framework ID set in the factory. + * This should be called at object initialization and not during run-time! + * @param packetDestination + */ + void setPacketDestination(object_id_t packetDestination); - /*** - * This is the periodically called function. - * Handle request queue for external commands. - * Handle command Queue for internal commands. - * @param opCode is unused here at the moment - * @return RETURN_OK - */ - virtual ReturnValue_t performOperation(uint8_t opCode) override; + /*** + * This is the periodically called function. + * Handle request queue for external commands. + * Handle command Queue for internal commands. + * @param opCode is unused here at the moment + * @return RETURN_OK + */ + virtual ReturnValue_t performOperation(uint8_t opCode) override; - virtual uint16_t getIdentifier(); + virtual uint16_t getIdentifier(); - /** - * Returns the requestQueue MessageQueueId_t - * - * The requestQueue is the queue for external commands (TC) - * - * @return requestQueue messageQueueId_t - */ - virtual MessageQueueId_t getRequestQueue(); + /** + * Returns the requestQueue MessageQueueId_t + * + * The requestQueue is the queue for external commands (TC) + * + * @return requestQueue messageQueueId_t + */ + virtual MessageQueueId_t getRequestQueue(); - /** - * Returns the commandQueue MessageQueueId_t - * - * Remember the CommandQueue is the queue for internal communication - * @return commandQueue messageQueueId_t - */ - virtual MessageQueueId_t getCommandQueue(); + /** + * Returns the commandQueue MessageQueueId_t + * + * Remember the CommandQueue is the queue for internal communication + * @return commandQueue messageQueueId_t + */ + virtual MessageQueueId_t getCommandQueue(); - virtual ReturnValue_t initialize() override; + virtual ReturnValue_t initialize() override; - /** - * Implementation of ExecutableObjectIF function - * - * Used to setup the reference of the task, that executes this component - * @param task Pointer to the taskIF of this task - */ - virtual void setTaskIF(PeriodicTaskIF* task) override; + /** + * Implementation of ExecutableObjectIF function + * + * Used to setup the reference of the task, that executes this component + * @param task Pointer to the taskIF of this task + */ + virtual void setTaskIF(PeriodicTaskIF* task) override; protected: - /** - * Check the target subservice - * @param subservice[in] - * @return - * -@c RETURN_OK Subservice valid, continue message handling + /** + * Check the target subservice + * @param subservice[in] + * @return + * -@c RETURN_OK Subservice valid, continue message handling * -@c INVALID_SUBSERVICE if service is not known, rejects packet. - */ - virtual ReturnValue_t isValidSubservice(uint8_t subservice) = 0; + */ + virtual ReturnValue_t isValidSubservice(uint8_t subservice) = 0; - /** - * Once a TC Request is valid, the existence of the destination and its - * target interface is checked and retrieved. The target message queue ID - * can then be acquired by using the target interface. - * @param subservice - * @param tcData Application Data of TC Packet - * @param tcDataLen - * @param id MessageQueue ID is stored here - * @param objectId Object ID is extracted and stored here - * @return - * - @c RETURN_OK Cotinue message handling - * - @c RETURN_FAILED Reject the packet and generates a start failure - * verification - */ - virtual ReturnValue_t getMessageQueueAndObject(uint8_t subservice, - const uint8_t *tcData, size_t tcDataLen, MessageQueueId_t *id, - object_id_t *objectId) = 0; + /** + * Once a TC Request is valid, the existence of the destination and its + * target interface is checked and retrieved. The target message queue ID + * can then be acquired by using the target interface. + * @param subservice + * @param tcData Application Data of TC Packet + * @param tcDataLen + * @param id MessageQueue ID is stored here + * @param objectId Object ID is extracted and stored here + * @return + * - @c RETURN_OK Cotinue message handling + * - @c RETURN_FAILED Reject the packet and generates a start failure + * verification + */ + virtual ReturnValue_t getMessageQueueAndObject(uint8_t subservice, + const uint8_t *tcData, size_t tcDataLen, MessageQueueId_t *id, + object_id_t *objectId) = 0; - /** - * After the Message Queue and Object ID are determined, the command is - * prepared by using an implementation specific CommandMessage type - * which is sent to the target object. It contains all necessary information - * for the device to execute telecommands. - * @param message [out] message which can be set and is sent to the object - * @param subservice Subservice of the current communication - * @param tcData Application data of command - * @param tcDataLen Application data length - * @param state [out/in] Setable state of the communication. - * communication - * @param objectId Target object ID - * @return - * - @c RETURN_OK to generate a verification start message - * - @c EXECUTION_COMPELTE Fire-and-forget command. Generate a completion - * verification message. - * - @c Anything else rejects the packets and generates a start failure - * verification. - */ - virtual ReturnValue_t prepareCommand(CommandMessage* message, - uint8_t subservice, const uint8_t *tcData, size_t tcDataLen, - uint32_t *state, object_id_t objectId) = 0; + /** + * After the Message Queue and Object ID are determined, the command is + * prepared by using an implementation specific CommandMessage type + * which is sent to the target object. It contains all necessary information + * for the device to execute telecommands. + * @param message [out] message which can be set and is sent to the object + * @param subservice Subservice of the current communication + * @param tcData Application data of command + * @param tcDataLen Application data length + * @param state [out/in] Setable state of the communication. + * communication + * @param objectId Target object ID + * @return + * - @c RETURN_OK to generate a verification start message + * - @c EXECUTION_COMPELTE Fire-and-forget command. Generate a completion + * verification message. + * - @c Anything else rejects the packets and generates a start failure + * verification. + */ + virtual ReturnValue_t prepareCommand(CommandMessage* message, + uint8_t subservice, const uint8_t *tcData, size_t tcDataLen, + uint32_t *state, object_id_t objectId) = 0; - /** - * This function is implemented by child services to specify how replies - * to a command from another software component are handled. - * @param reply - * This is the reply in form of a generic read-only command message. - * @param previousCommand - * Command_t of related command - * @param state [out/in] - * Additional parameter which can be used to pass state information. - * State of the communication - * @param optionalNextCommand [out] - * An optional next command which can be set in this function - * @param objectId Source object ID - * @param isStep Flag value to mark steps of command execution - * @return - * - @c RETURN_OK, @c EXECUTION_COMPLETE or @c NO_STEP_MESSAGE to - * generate TC verification success - * - @c INVALID_REPLY Calls handleUnrequestedReply - * - Anything else triggers a TC verification failure. If RETURN_FAILED or - * INVALID_REPLY is returned and the command ID is - * CommandMessage::REPLY_REJECTED, a failure verification message with - * the reason as the error parameter and the initial command as - * failure parameter 1 is generated. - */ - virtual ReturnValue_t handleReply(const CommandMessage* reply, - Command_t previousCommand, uint32_t *state, - CommandMessage* optionalNextCommand, object_id_t objectId, - bool *isStep) = 0; + /** + * This function is implemented by child services to specify how replies + * to a command from another software component are handled. + * @param reply + * This is the reply in form of a generic read-only command message. + * @param previousCommand + * Command_t of related command + * @param state [out/in] + * Additional parameter which can be used to pass state information. + * State of the communication + * @param optionalNextCommand [out] + * An optional next command which can be set in this function + * @param objectId Source object ID + * @param isStep Flag value to mark steps of command execution + * @return + * - @c RETURN_OK, @c EXECUTION_COMPLETE or @c NO_STEP_MESSAGE to + * generate TC verification success + * - @c INVALID_REPLY Calls handleUnrequestedReply + * - Anything else triggers a TC verification failure. If RETURN_FAILED or + * INVALID_REPLY is returned and the command ID is + * CommandMessage::REPLY_REJECTED, a failure verification message with + * the reason as the error parameter and the initial command as + * failure parameter 1 is generated. + */ + virtual ReturnValue_t handleReply(const CommandMessage* reply, + Command_t previousCommand, uint32_t *state, + CommandMessage* optionalNextCommand, object_id_t objectId, + bool *isStep) = 0; - /** - * This function can be overidden to handle unrequested reply, - * when the reply sender ID is unknown or is not found is the command map. - * The default implementation will clear the command message and all - * its contents. - * @param reply - * Reply which is non-const so the default implementation can clear the - * message. - */ - virtual void handleUnrequestedReply(CommandMessage* reply); + /** + * This function can be overidden to handle unrequested reply, + * when the reply sender ID is unknown or is not found is the command map. + * The default implementation will clear the command message and all + * its contents. + * @param reply + * Reply which is non-const so the default implementation can clear the + * message. + */ + virtual void handleUnrequestedReply(CommandMessage* reply); - virtual void doPeriodicOperation(); + virtual void doPeriodicOperation(); - struct CommandInfo: public SerializeIF{ - struct tcInfo { - uint8_t ackFlags; - uint16_t tcPacketId; - uint16_t tcSequenceControl; - } tcInfo; - uint32_t uptimeOfStart; - uint8_t step; - uint8_t subservice; - uint32_t state; - Command_t command; - object_id_t objectId; - FIFO fifo; + struct CommandInfo: public SerializeIF{ + struct tcInfo { + uint8_t ackFlags; + uint16_t tcPacketId; + uint16_t tcSequenceControl; + } tcInfo; + uint32_t uptimeOfStart; + uint8_t step; + uint8_t subservice; + uint32_t state; + Command_t command; + object_id_t objectId; + FIFO fifo; - virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, - size_t maxSize, Endianness streamEndianness) const override{ - return HasReturnvaluesIF::RETURN_FAILED; - }; + virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, + size_t maxSize, Endianness streamEndianness) const override{ + return HasReturnvaluesIF::RETURN_FAILED; + }; - virtual size_t getSerializedSize() const override { - return 0; - }; + virtual size_t getSerializedSize() const override { + return 0; + }; - virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, - Endianness streamEndianness) override { - return HasReturnvaluesIF::RETURN_FAILED; - }; - }; + virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override { + return HasReturnvaluesIF::RETURN_FAILED; + }; + }; - using CommandMapIter = FixedMap::Iterator; + using CommandMapIter = FixedMap::Iterator; - const uint16_t apid; + const uint16_t apid; - const uint8_t service; + const uint8_t service; - const uint16_t timeoutSeconds; + const uint16_t timeoutSeconds; - uint8_t tmPacketCounter = 0; + uint8_t tmPacketCounter = 0; - StorageManagerIF *IPCStore = nullptr; + StorageManagerIF *IPCStore = nullptr; - StorageManagerIF *TCStore = nullptr; + StorageManagerIF *TCStore = nullptr; - MessageQueueIF* commandQueue = nullptr; + MessageQueueIF* commandQueue = nullptr; - MessageQueueIF* requestQueue = nullptr; + MessageQueueIF* requestQueue = nullptr; - VerificationReporter verificationReporter; + VerificationReporter verificationReporter; - FixedMap commandMap; + FixedMap commandMap; - /* May be set be children to return a more precise failure condition. */ - uint32_t failureParameter1 = 0; - uint32_t failureParameter2 = 0; + /* May be set be children to return a more precise failure condition. */ + uint32_t failureParameter1 = 0; + uint32_t failureParameter2 = 0; - static object_id_t defaultPacketSource; - object_id_t packetSource = objects::NO_OBJECT; - static object_id_t defaultPacketDestination; - object_id_t packetDestination = objects::NO_OBJECT; + static object_id_t defaultPacketSource; + object_id_t packetSource = objects::NO_OBJECT; + static object_id_t defaultPacketDestination; + object_id_t packetDestination = objects::NO_OBJECT; - /** - * Pointer to the task which executes this component, - * is invalid before setTaskIF was called. - */ - PeriodicTaskIF* executingTask = nullptr; + /** + * Pointer to the task which executes this component, + * is invalid before setTaskIF was called. + */ + PeriodicTaskIF* executingTask = nullptr; - /** - * @brief Send TM data from pointer to data. - * If a header is supplied it is added before data - * @param subservice Number of subservice - * @param data Pointer to the data in the Packet - * @param dataLen Lenght of data in the Packet - * @param headerData HeaderData will be placed before data - * @param headerSize Size of HeaderData - */ - ReturnValue_t sendTmPacket(uint8_t subservice, const uint8_t *data, - size_t dataLen, const uint8_t* headerData = nullptr, - size_t headerSize = 0); + /** + * @brief Send TM data from pointer to data. + * If a header is supplied it is added before data + * @param subservice Number of subservice + * @param data Pointer to the data in the Packet + * @param dataLen Lenght of data in the Packet + * @param headerData HeaderData will be placed before data + * @param headerSize Size of HeaderData + */ + ReturnValue_t sendTmPacket(uint8_t subservice, const uint8_t *data, + size_t dataLen, const uint8_t* headerData = nullptr, + size_t headerSize = 0); - /** - * @brief To send TM packets of objects that still need to be serialized - * and consist of an object ID with appended data. - * @param subservice Number of subservice - * @param objectId ObjectId is placed before data - * @param data Data to append to the packet - * @param dataLen Length of Data - */ - ReturnValue_t sendTmPacket(uint8_t subservice, object_id_t objectId, - const uint8_t *data, size_t dataLen); + /** + * @brief To send TM packets of objects that still need to be serialized + * and consist of an object ID with appended data. + * @param subservice Number of subservice + * @param objectId ObjectId is placed before data + * @param data Data to append to the packet + * @param dataLen Length of Data + */ + ReturnValue_t sendTmPacket(uint8_t subservice, object_id_t objectId, + const uint8_t *data, size_t dataLen); - /** - * @brief To send packets which are contained inside a class implementing - * SerializeIF. - * @param subservice Number of subservice - * @param content This is a pointer to the serialized packet - * @param header Serialize IF header which will be placed before content - */ - ReturnValue_t sendTmPacket(uint8_t subservice, SerializeIF* content, - SerializeIF* header = nullptr); + /** + * @brief To send packets which are contained inside a class implementing + * SerializeIF. + * @param subservice Number of subservice + * @param content This is a pointer to the serialized packet + * @param header Serialize IF header which will be placed before content + */ + ReturnValue_t sendTmPacket(uint8_t subservice, SerializeIF* content, + SerializeIF* header = nullptr); - void checkAndExecuteFifo(CommandMapIter& iter); + void checkAndExecuteFifo(CommandMapIter& iter); -private: - /** - * This method handles internal execution of a command, - * once it has been started by @sa{startExecution()} in the request - * queue handler. - * It handles replies generated by the devices and relayed by the specific - * service implementation. This means that it determines further course of - * action depending on the return values specified in the service - * implementation. - * This includes the generation of TC verification messages. Note that - * the static framework object ID @c VerificationReporter::messageReceiver - * needs to be set. - * - TM[1,5] Step Successs - * - TM[1,6] Step Failure - * - TM[1,7] Completion Success - * - TM[1,8] Completion Failure - */ - void handleCommandQueue(); + private: + /** + * This method handles internal execution of a command, + * once it has been started by @sa{startExecution()} in the request + * queue handler. + * It handles replies generated by the devices and relayed by the specific + * service implementation. This means that it determines further course of + * action depending on the return values specified in the service + * implementation. + * This includes the generation of TC verification messages. Note that + * the static framework object ID @c VerificationReporter::messageReceiver + * needs to be set. + * - TM[1,5] Step Successs + * - TM[1,6] Step Failure + * - TM[1,7] Completion Success + * - TM[1,8] Completion Failure + */ + void handleCommandQueue(); - /** - * @brief Handler function for request queue - * @details - * Sequence of request queue handling: - * isValidSubservice -> getMessageQueueAndObject -> startExecution - * Generates a Start Success Reports TM[1,3] in subfunction - * @sa{startExecution()} or a Start Failure Report TM[1,4] by using the - * TC Verification Service. - */ - void handleRequestQueue(); + /** + * @brief Handler function for request queue + * @details + * Sequence of request queue handling: + * isValidSubservice -> getMessageQueueAndObject -> startExecution + * Generates a Start Success Reports TM[1,3] in subfunction + * @sa{startExecution()} or a Start Failure Report TM[1,4] by using the + * TC Verification Service. + */ + void handleRequestQueue(); - void rejectPacket(uint8_t reportId, TcPacketStoredBase* packet, - ReturnValue_t errorCode); + void rejectPacket(uint8_t reportId, TcPacketStoredPus* packet, + ReturnValue_t errorCode); - void acceptPacket(uint8_t reportId, TcPacketStoredBase* packet); + void acceptPacket(uint8_t reportId, TcPacketStoredPus* packet); - void startExecution(TcPacketStoredBase *storedPacket, CommandMapIter iter); + void startExecution(TcPacketStoredPus* storedPacket, CommandMapIter iter); - void handleCommandMessage(CommandMessage* reply); - void handleReplyHandlerResult(ReturnValue_t result, CommandMapIter iter, - CommandMessage* nextCommand, CommandMessage* reply, bool& isStep); + void handleCommandMessage(CommandMessage* reply); + void handleReplyHandlerResult(ReturnValue_t result, CommandMapIter iter, + CommandMessage* nextCommand, CommandMessage* reply, bool& isStep); - void checkTimeout(); + void checkTimeout(); }; #endif /* FSFW_TMTCSERVICES_COMMANDINGSERVICEBASE_H_ */ diff --git a/src/fsfw/tmtcservices/PusServiceBase.cpp b/src/fsfw/tmtcservices/PusServiceBase.cpp index 866e0844..191acd9c 100644 --- a/src/fsfw/tmtcservices/PusServiceBase.cpp +++ b/src/fsfw/tmtcservices/PusServiceBase.cpp @@ -12,28 +12,28 @@ object_id_t PusServiceBase::packetSource = 0; object_id_t PusServiceBase::packetDestination = 0; PusServiceBase::PusServiceBase(object_id_t setObjectId, uint16_t setApid, - uint8_t setServiceId) : - SystemObject(setObjectId), apid(setApid), serviceId(setServiceId) { - requestQueue = QueueFactory::instance()-> - createMessageQueue(PUS_SERVICE_MAX_RECEPTION); + uint8_t setServiceId): + SystemObject(setObjectId), apid(setApid), serviceId(setServiceId) { + requestQueue = QueueFactory::instance()-> + createMessageQueue(PUS_SERVICE_MAX_RECEPTION); } PusServiceBase::~PusServiceBase() { - QueueFactory::instance()->deleteMessageQueue(requestQueue); + QueueFactory::instance()->deleteMessageQueue(requestQueue); } ReturnValue_t PusServiceBase::performOperation(uint8_t opCode) { - handleRequestQueue(); - ReturnValue_t result = this->performService(); - if (result != RETURN_OK) { + handleRequestQueue(); + ReturnValue_t result = this->performService(); + if (result != RETURN_OK) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "PusService " << (uint16_t) this->serviceId - << ": performService returned with " << (int16_t) result - << std::endl; + sif::error << "PusService " << (uint16_t) this->serviceId + << ": performService returned with " << (int16_t) result + << std::endl; #endif - return RETURN_FAILED; - } - return RETURN_OK; + return RETURN_FAILED; + } + return RETURN_OK; } void PusServiceBase::setTaskIF(PeriodicTaskIF* taskHandle) { @@ -41,88 +41,88 @@ void PusServiceBase::setTaskIF(PeriodicTaskIF* taskHandle) { } void PusServiceBase::handleRequestQueue() { - TmTcMessage message; - ReturnValue_t result = RETURN_FAILED; - for (uint8_t count = 0; count < PUS_SERVICE_MAX_RECEPTION; count++) { - ReturnValue_t status = this->requestQueue->receiveMessage(&message); -// if(status != MessageQueueIF::EMPTY) { + TmTcMessage message; + ReturnValue_t result = RETURN_FAILED; + for (uint8_t count = 0; count < PUS_SERVICE_MAX_RECEPTION; count++) { + ReturnValue_t status = this->requestQueue->receiveMessage(&message); + // if(status != MessageQueueIF::EMPTY) { #if FSFW_CPP_OSTREAM_ENABLED == 1 -// sif::debug << "PusServiceBase::performOperation: Receiving from " -// << "MQ ID: " << std::hex << "0x" << std::setw(8) -// << std::setfill('0') << this->requestQueue->getId() -// << std::dec << " returned: " << status << std::setfill(' ') -// << std::endl; + // sif::debug << "PusServiceBase::performOperation: Receiving from " + // << "MQ ID: " << std::hex << "0x" << std::setw(8) + // << std::setfill('0') << this->requestQueue->getId() + // << std::dec << " returned: " << status << std::setfill(' ') + // << std::endl; #endif -// } + // } - if (status == RETURN_OK) { - this->currentPacket.setStoreAddress(message.getStorageId()); - //info << "Service " << (uint16_t) this->serviceId << - // ": new packet!" << std::endl; + if (status == RETURN_OK) { + this->currentPacket.setStoreAddress(message.getStorageId(), ¤tPacket); + //info << "Service " << (uint16_t) this->serviceId << + // ": new packet!" << std::endl; - result = this->handleRequest(currentPacket.getSubService()); + result = this->handleRequest(currentPacket.getSubService()); - // debug << "Service " << (uint16_t)this->serviceId << - // ": handleRequest returned: " << (int)return_code << std::endl; - if (result == RETURN_OK) { - this->verifyReporter.sendSuccessReport( - tc_verification::COMPLETION_SUCCESS, &this->currentPacket); - } - else { - this->verifyReporter.sendFailureReport( - tc_verification::COMPLETION_FAILURE, &this->currentPacket, - result, 0, errorParameter1, errorParameter2); - } - this->currentPacket.deletePacket(); - errorParameter1 = 0; - errorParameter2 = 0; - } - else if (status == MessageQueueIF::EMPTY) { - status = RETURN_OK; - // debug << "PusService " << (uint16_t)this->serviceId << - // ": no new packet." << std::endl; - break; - } - else { + // debug << "Service " << (uint16_t)this->serviceId << + // ": handleRequest returned: " << (int)return_code << std::endl; + if (result == RETURN_OK) { + this->verifyReporter.sendSuccessReport( + tc_verification::COMPLETION_SUCCESS, &this->currentPacket); + } + else { + this->verifyReporter.sendFailureReport( + tc_verification::COMPLETION_FAILURE, &this->currentPacket, + result, 0, errorParameter1, errorParameter2); + } + this->currentPacket.deletePacket(); + errorParameter1 = 0; + errorParameter2 = 0; + } + else if (status == MessageQueueIF::EMPTY) { + status = RETURN_OK; + // debug << "PusService " << (uint16_t)this->serviceId << + // ": no new packet." << std::endl; + break; + } + else { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "PusServiceBase::performOperation: Service " - << this->serviceId << ": Error receiving packet. Code: " - << std::hex << status << std::dec << std::endl; + sif::error << "PusServiceBase::performOperation: Service " + << this->serviceId << ": Error receiving packet. Code: " + << std::hex << status << std::dec << std::endl; #endif - } - } + } + } } uint16_t PusServiceBase::getIdentifier() { - return this->serviceId; + return this->serviceId; } MessageQueueId_t PusServiceBase::getRequestQueue() { - return this->requestQueue->getId(); + return this->requestQueue->getId(); } ReturnValue_t PusServiceBase::initialize() { - ReturnValue_t result = SystemObject::initialize(); - if (result != RETURN_OK) { - return result; - } - AcceptsTelemetryIF* destService = ObjectManager::instance()->get( - packetDestination); - PUSDistributorIF* distributor = ObjectManager::instance()->get( - packetSource); - if (destService == nullptr or distributor == nullptr) { + ReturnValue_t result = SystemObject::initialize(); + if (result != RETURN_OK) { + return result; + } + AcceptsTelemetryIF* destService = ObjectManager::instance()->get( + packetDestination); + PUSDistributorIF* distributor = ObjectManager::instance()->get( + packetSource); + if (destService == nullptr or distributor == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "PusServiceBase::PusServiceBase: Service " - << this->serviceId << ": Configuration error. Make sure " - << "packetSource and packetDestination are defined correctly" - << std::endl; + sif::error << "PusServiceBase::PusServiceBase: Service " + << this->serviceId << ": Configuration error. Make sure " + << "packetSource and packetDestination are defined correctly" + << std::endl; #endif - return ObjectManagerIF::CHILD_INIT_FAILED; - } - this->requestQueue->setDefaultDestination( - destService->getReportReceptionQueue()); - distributor->registerService(this); - return HasReturnvaluesIF::RETURN_OK; + return ObjectManagerIF::CHILD_INIT_FAILED; + } + this->requestQueue->setDefaultDestination( + destService->getReportReceptionQueue()); + distributor->registerService(this); + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t PusServiceBase::initializeAfterTaskCreation() { diff --git a/src/fsfw/tmtcservices/PusServiceBase.h b/src/fsfw/tmtcservices/PusServiceBase.h index ea4147fe..ec338331 100644 --- a/src/fsfw/tmtcservices/PusServiceBase.h +++ b/src/fsfw/tmtcservices/PusServiceBase.h @@ -35,126 +35,126 @@ void setStaticFrameworkObjectIds(); * @ingroup pus_services */ class PusServiceBase : public ExecutableObjectIF, - public AcceptsTelecommandsIF, - public SystemObject, - public HasReturnvaluesIF { - friend void (Factory::setStaticFrameworkObjectIds)(); +public AcceptsTelecommandsIF, +public SystemObject, +public HasReturnvaluesIF { + friend void (Factory::setStaticFrameworkObjectIds)(); public: - /** - * @brief The passed values are set, but inter-object initialization is - * done in the initialize method. - * @param setObjectId - * The system object identifier of this Service instance. - * @param setApid - * The APID the Service is instantiated for. - * @param setServiceId - * The Service Identifier as specified in ECSS PUS. - */ - PusServiceBase( object_id_t setObjectId, uint16_t setApid, - uint8_t setServiceId); - /** - * The destructor is empty. - */ - virtual ~PusServiceBase(); - /** - * @brief The handleRequest method shall handle any kind of Telecommand - * Request immediately. - * @details - * Implemetations can take the Telecommand in currentPacket and perform - * any kind of operation. - * They may send additional "Start Success (1,3)" messages with the - * verifyReporter, but Completion Success or Failure Reports are generated - * automatically after execution of this method. - * - * If a Telecommand can not be executed within one call cycle, - * this Base class is not the right parent. - * - * The child class may add additional error information by setting - * #errorParameters which aren attached to the generated verification - * message. - * - * Subservice checking should be implemented in this method. - * - * @return The returned status_code is directly taken as main error code - * in the Verification Report. - * On success, RETURN_OK shall be returned. - */ - virtual ReturnValue_t handleRequest(uint8_t subservice) = 0; - /** - * In performService, implementations can handle periodic, - * non-TC-triggered activities. - * The performService method is always called. - * @return Currently, everything other that RETURN_OK only triggers - * diagnostic output. - */ - virtual ReturnValue_t performService() = 0; - /** - * This method implements the typical activity of a simple PUS Service. - * It checks for new requests, and, if found, calls handleRequest, sends - * completion verification messages and deletes - * the TC requests afterwards. - * performService is always executed afterwards. - * @return @c RETURN_OK if the periodic performService was successful. - * @c RETURN_FAILED else. - */ - ReturnValue_t performOperation(uint8_t opCode) override; - virtual uint16_t getIdentifier() override; - MessageQueueId_t getRequestQueue() override; - virtual ReturnValue_t initialize() override; + /** + * @brief The passed values are set, but inter-object initialization is + * done in the initialize method. + * @param setObjectId + * The system object identifier of this Service instance. + * @param setApid + * The APID the Service is instantiated for. + * @param setServiceId + * The Service Identifier as specified in ECSS PUS. + */ + PusServiceBase( object_id_t setObjectId, uint16_t setApid, + uint8_t setServiceId); + /** + * The destructor is empty. + */ + virtual ~PusServiceBase(); + /** + * @brief The handleRequest method shall handle any kind of Telecommand + * Request immediately. + * @details + * Implemetations can take the Telecommand in currentPacket and perform + * any kind of operation. + * They may send additional "Start Success (1,3)" messages with the + * verifyReporter, but Completion Success or Failure Reports are generated + * automatically after execution of this method. + * + * If a Telecommand can not be executed within one call cycle, + * this Base class is not the right parent. + * + * The child class may add additional error information by setting + * #errorParameters which aren attached to the generated verification + * message. + * + * Subservice checking should be implemented in this method. + * + * @return The returned status_code is directly taken as main error code + * in the Verification Report. + * On success, RETURN_OK shall be returned. + */ + virtual ReturnValue_t handleRequest(uint8_t subservice) = 0; + /** + * In performService, implementations can handle periodic, + * non-TC-triggered activities. + * The performService method is always called. + * @return Currently, everything other that RETURN_OK only triggers + * diagnostic output. + */ + virtual ReturnValue_t performService() = 0; + /** + * This method implements the typical activity of a simple PUS Service. + * It checks for new requests, and, if found, calls handleRequest, sends + * completion verification messages and deletes + * the TC requests afterwards. + * performService is always executed afterwards. + * @return @c RETURN_OK if the periodic performService was successful. + * @c RETURN_FAILED else. + */ + ReturnValue_t performOperation(uint8_t opCode) override; + virtual uint16_t getIdentifier() override; + MessageQueueId_t getRequestQueue() override; + virtual ReturnValue_t initialize() override; - virtual void setTaskIF(PeriodicTaskIF* taskHandle) override; - virtual ReturnValue_t initializeAfterTaskCreation() override; + virtual void setTaskIF(PeriodicTaskIF* taskHandle) override; + virtual ReturnValue_t initializeAfterTaskCreation() override; protected: - /** - * @brief Handle to the underlying task - * @details - * Will be set by setTaskIF(), which is called on task creation. - */ - PeriodicTaskIF* taskHandle = nullptr; - /** - * The APID of this instance of the Service. - */ - uint16_t apid; - /** - * The Service Identifier. - */ - uint8_t serviceId; - /** - * One of two error parameters for additional error information. - */ - uint32_t errorParameter1 = 0; - /** - * One of two error parameters for additional error information. - */ - uint32_t errorParameter2 = 0; - /** - * This is a complete instance of the telecommand reception queue - * of the class. It is initialized on construction of the class. - */ - MessageQueueIF* requestQueue = nullptr; - /** - * An instance of the VerificationReporter class, that simplifies - * sending any kind of verification message to the TC Verification Service. - */ - VerificationReporter verifyReporter; - /** - * The current Telecommand to be processed. - * It is deleted after handleRequest was executed. - */ - TcPacketStoredPus currentPacket; + /** + * @brief Handle to the underlying task + * @details + * Will be set by setTaskIF(), which is called on task creation. + */ + PeriodicTaskIF* taskHandle = nullptr; + /** + * The APID of this instance of the Service. + */ + uint16_t apid; + /** + * The Service Identifier. + */ + uint8_t serviceId; + /** + * One of two error parameters for additional error information. + */ + uint32_t errorParameter1 = 0; + /** + * One of two error parameters for additional error information. + */ + uint32_t errorParameter2 = 0; + /** + * This is a complete instance of the telecommand reception queue + * of the class. It is initialized on construction of the class. + */ + MessageQueueIF* requestQueue = nullptr; + /** + * An instance of the VerificationReporter class, that simplifies + * sending any kind of verification message to the TC Verification Service. + */ + VerificationReporter verifyReporter; + /** + * The current Telecommand to be processed. + * It is deleted after handleRequest was executed. + */ + TcPacketStoredPus currentPacket; - static object_id_t packetSource; + static object_id_t packetSource; - static object_id_t packetDestination; + 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 PUS_SERVICE_MAX_RECEPTION = 10; + /** + * 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 PUS_SERVICE_MAX_RECEPTION = 10; - void handleRequestQueue(); + void handleRequestQueue(); }; #endif /* FSFW_TMTCSERVICES_PUSSERVICEBASE_H_ */ diff --git a/src/fsfw/tmtcservices/PusVerificationReport.h b/src/fsfw/tmtcservices/PusVerificationReport.h index c22ba535..bc9793d9 100644 --- a/src/fsfw/tmtcservices/PusVerificationReport.h +++ b/src/fsfw/tmtcservices/PusVerificationReport.h @@ -4,7 +4,7 @@ #include "VerificationCodes.h" #include "fsfw/ipc/MessageQueueMessage.h" -#include "fsfw/tmtcpacket/pus/tc/TcPacketBase.h" +#include "fsfw/tmtcpacket/pus/tc/TcPacketPusBase.h" #include "fsfw/returnvalues/HasReturnvaluesIF.h" class PusVerificationMessage: public MessageQueueMessage { diff --git a/src/fsfw/tmtcservices/VerificationReporter.cpp b/src/fsfw/tmtcservices/VerificationReporter.cpp index 2b371d1e..b885cccf 100644 --- a/src/fsfw/tmtcservices/VerificationReporter.cpp +++ b/src/fsfw/tmtcservices/VerificationReporter.cpp @@ -17,7 +17,7 @@ VerificationReporter::VerificationReporter() : VerificationReporter::~VerificationReporter() {} void VerificationReporter::sendSuccessReport(uint8_t set_report_id, - TcPacketBase* currentPacket, uint8_t set_step) { + TcPacketPusBase* currentPacket, uint8_t set_step) { if (acknowledgeQueue == MessageQueueIF::NO_QUEUE) { this->initialize(); } @@ -59,7 +59,7 @@ void VerificationReporter::sendSuccessReport(uint8_t set_report_id, } void VerificationReporter::sendFailureReport(uint8_t report_id, - TcPacketBase* currentPacket, ReturnValue_t error_code, uint8_t step, + TcPacketPusBase* currentPacket, ReturnValue_t error_code, uint8_t step, uint32_t parameter1, uint32_t parameter2) { if (acknowledgeQueue == MessageQueueIF::NO_QUEUE) { this->initialize(); diff --git a/src/fsfw/tmtcservices/VerificationReporter.h b/src/fsfw/tmtcservices/VerificationReporter.h index 4a64d3df..d57cc791 100644 --- a/src/fsfw/tmtcservices/VerificationReporter.h +++ b/src/fsfw/tmtcservices/VerificationReporter.h @@ -25,13 +25,13 @@ public: VerificationReporter(); virtual ~VerificationReporter(); - void sendSuccessReport( uint8_t set_report_id, TcPacketBase* current_packet, + void sendSuccessReport( uint8_t set_report_id, TcPacketPusBase* current_packet, uint8_t set_step = 0 ); void sendSuccessReport(uint8_t set_report_id, uint8_t ackFlags, uint16_t tcPacketId, uint16_t tcSequenceControl, uint8_t set_step = 0); - void sendFailureReport( uint8_t report_id, TcPacketBase* current_packet, + void sendFailureReport( uint8_t report_id, TcPacketPusBase* current_packet, ReturnValue_t error_code = 0, uint8_t step = 0, uint32_t parameter1 = 0, uint32_t parameter2 = 0 ); diff --git a/tests/src/fsfw_tests/unit/CMakeLists.txt b/tests/src/fsfw_tests/unit/CMakeLists.txt index 164e3bde..ce0d313c 100644 --- a/tests/src/fsfw_tests/unit/CMakeLists.txt +++ b/tests/src/fsfw_tests/unit/CMakeLists.txt @@ -21,3 +21,4 @@ add_subdirectory(storagemanager) add_subdirectory(globalfunctions) add_subdirectory(timemanager) add_subdirectory(tmtcpacket) +add_subdirectory(cfdp) diff --git a/tests/src/fsfw_tests/unit/cfdp/CMakeLists.txt b/tests/src/fsfw_tests/unit/cfdp/CMakeLists.txt new file mode 100644 index 00000000..8e18cd3b --- /dev/null +++ b/tests/src/fsfw_tests/unit/cfdp/CMakeLists.txt @@ -0,0 +1,12 @@ +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 +) diff --git a/tests/src/fsfw_tests/unit/cfdp/testAckPdu.cpp b/tests/src/fsfw_tests/unit/cfdp/testAckPdu.cpp new file mode 100644 index 00000000..70576543 --- /dev/null +++ b/tests/src/fsfw_tests/unit/cfdp/testAckPdu.cpp @@ -0,0 +1,101 @@ +#include + +#include "fsfw/cfdp/pdu/AckPduDeserializer.h" +#include "fsfw/cfdp/pdu/AckPduSerializer.h" +#include "fsfw/globalfunctions/arrayprinter.h" + +#include + +TEST_CASE( "ACK PDU" , "[AckPdu]") { + + using namespace cfdp; + ReturnValue_t result = HasReturnvaluesIF::RETURN_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 == HasReturnvaluesIF::RETURN_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 == HasReturnvaluesIF::RETURN_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 != HasReturnvaluesIF::RETURN_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 == HasReturnvaluesIF::RETURN_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 == HasReturnvaluesIF::RETURN_OK); + + auto reader2 = AckPduDeserializer(buf.data(), sz, ackInfo); + result = reader2.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_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/tests/src/fsfw_tests/unit/cfdp/testCfdp.cpp b/tests/src/fsfw_tests/unit/cfdp/testCfdp.cpp new file mode 100644 index 00000000..7db3800d --- /dev/null +++ b/tests/src/fsfw_tests/unit/cfdp/testCfdp.cpp @@ -0,0 +1,372 @@ +#include +#include "fsfw/cfdp/pdu/FileDirectiveDeserializer.h" +#include "fsfw/cfdp/pdu/FileDirectiveSerializer.h" +#include "fsfw/cfdp/pdu/HeaderDeserializer.h" +#include "fsfw_tests/unit/CatchDefinitions.h" +#include "fsfw/cfdp/FileSize.h" +#include "fsfw/globalfunctions/arrayprinter.h" +#include "fsfw/cfdp/pdu/HeaderSerializer.h" +#include "fsfw/serialize/SerializeAdapter.h" + +#include +#include + +TEST_CASE( "CFDP Base" , "[CfdpBase]") { + using namespace cfdp; + std::array serBuf; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + 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); + 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 == retval::CATCH_FAILED); + deserResult = headerSerializer.serialize(nullptr, &serSize, serBuf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(deserResult == retval::CATCH_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 == retval::CATCH_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 == retval::CATCH_FAILED); + result = pduConf.sourceId.setValue(cfdp::WidthInBytes::TWO_BYTES, 0xfffff); + REQUIRE(result == retval::CATCH_FAILED); + result = pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xfffffffff); + REQUIRE(result == retval::CATCH_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 == retval::CATCH_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 == retval::CATCH_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 == retval::CATCH_OK); + result = pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00); + REQUIRE(result == retval::CATCH_OK); + result = pduConf.destId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff); + REQUIRE(result == retval::CATCH_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 == retval::CATCH_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 == retval::CATCH_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 == retval::CATCH_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); + REQUIRE(fdSer.getSerializedSize() == 8); + serTarget = serBuf.data(); + serSize = 0; + result = fdSer.serialize(&serTarget, &serSize, serBuf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_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] == FileDirectives::ACK); + + serTarget = serBuf.data(); + size_t deserSize = 20; + serSize = 0; + REQUIRE(fdSer.deSerialize(&deserTarget, &deserSize, SerializeIF::Endianness::NETWORK) == + HasReturnvaluesIF::RETURN_FAILED); + REQUIRE(fdSer.serialize(nullptr, nullptr, 85, SerializeIF::Endianness::NETWORK) == + HasReturnvaluesIF::RETURN_FAILED); + 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); + } + + deserTarget = serBuf.data(); + deserSize = 0; + auto fdDeser = FileDirectiveDeserializer(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() == HasReturnvaluesIF::RETURN_OK); + REQUIRE(fdDeser.getFileDirective() == FileDirectives::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); + } + + SECTION("FileSize") { + 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); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + uint32_t fileSize = 0; + result = SerializeAdapter::deSerialize(&fileSize, fssBuf.data(), nullptr, + SerializeIF::Endianness::MACHINE); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(fileSize == 0x20); + + } +} + diff --git a/tests/src/fsfw_tests/unit/cfdp/testEofPdu.cpp b/tests/src/fsfw_tests/unit/cfdp/testEofPdu.cpp new file mode 100644 index 00000000..9edaf572 --- /dev/null +++ b/tests/src/fsfw_tests/unit/cfdp/testEofPdu.cpp @@ -0,0 +1,124 @@ +#include + +#include "fsfw/cfdp/pdu/EofPduDeserializer.h" +#include "fsfw/cfdp/pdu/EofPduSerializer.h" +#include "fsfw/globalfunctions/arrayprinter.h" + +#include + +TEST_CASE( "EOF PDU" , "[EofPdu]") { + using namespace cfdp; + + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + std::array buf = {}; + uint8_t* bufPtr = buf.data(); + size_t sz = 0; + EntityId destId(WidthInBytes::TWO_BYTES, 2); + EntityIdTlv faultLoc(destId); + FileSize fileSize(12); + // We can already set the fault location, it will be ignored + EofInfo eofInfo(cfdp::ConditionCode::NO_ERROR, 5, fileSize, &faultLoc); + TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15); + EntityId sourceId(WidthInBytes::TWO_BYTES, 1); + + PduConfig pduConf(TransmissionModes::ACKNOWLEDGED, seqNum, sourceId, destId); + + auto eofSerializer = EofPduSerializer(pduConf, eofInfo); + SECTION("Serialize") { + result = eofSerializer.serialize(&bufPtr, &sz, buf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(((buf[1] << 8) | buf[2]) == 10); + uint32_t checksum = 0; + result = SerializeAdapter::deSerialize(&checksum, buf.data() + sz - 8, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(checksum == 5); + uint32_t fileSizeVal = 0; + result = SerializeAdapter::deSerialize(&fileSizeVal, buf.data() + sz - 4, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(fileSizeVal == 12); + REQUIRE(buf[sz - 10] == cfdp::FileDirectives::EOF_DIRECTIVE); + REQUIRE(buf[sz - 9] == 0x00); + REQUIRE(sz == 20); + + eofInfo.setConditionCode(cfdp::ConditionCode::FILESTORE_REJECTION); + eofInfo.setFileSize(0x10ffffff10, true); + pduConf.largeFile = true; + // Should serialize with fault location now + auto serializeWithFaultLocation = EofPduSerializer(pduConf, eofInfo); + bufPtr = buf.data(); + sz = 0; + result = serializeWithFaultLocation.serialize(&bufPtr, &sz, buf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(sz == 28); + REQUIRE(buf[10] == cfdp::FileDirectives::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); + // width of entity ID is 2 + REQUIRE(buf[sz - 3] == 2); + uint16_t entityIdRaw = 0; + result = SerializeAdapter::deSerialize(&entityIdRaw, buf.data() + sz - 2, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(entityIdRaw == 2); + bufPtr = buf.data(); + sz = 0; + for(size_t idx = 0; idx < 27; idx++) { + result = serializeWithFaultLocation.serialize(&bufPtr, &sz, idx, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == SerializeIF::BUFFER_TOO_SHORT); + bufPtr = buf.data(); + sz = 0; + } + eofInfo.setChecksum(16); + eofInfo.setFaultLoc(nullptr); + } + + SECTION("Deserialize") { + result = eofSerializer.serialize(&bufPtr, &sz, buf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + EntityIdTlv tlv(destId); + EofInfo emptyInfo(&tlv); + auto deserializer = EofPduDeserializer(buf.data(), buf.size(), emptyInfo); + result = deserializer.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(emptyInfo.getConditionCode() == cfdp::ConditionCode::NO_ERROR); + REQUIRE(emptyInfo.getChecksum() == 5); + REQUIRE(emptyInfo.getFileSize().getSize() == 12); + + eofInfo.setConditionCode(cfdp::ConditionCode::FILESTORE_REJECTION); + eofInfo.setFileSize(0x10ffffff10, true); + pduConf.largeFile = true; + // Should serialize with fault location now + auto serializeWithFaultLocation = EofPduSerializer(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); + result = deserializer2.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_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()->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); + result = invalidDeser.parseData(); + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + } + } + +} + + diff --git a/tests/src/fsfw_tests/unit/cfdp/testFileData.cpp b/tests/src/fsfw_tests/unit/cfdp/testFileData.cpp new file mode 100644 index 00000000..8a84a2a3 --- /dev/null +++ b/tests/src/fsfw_tests/unit/cfdp/testFileData.cpp @@ -0,0 +1,175 @@ +#include + +#include "fsfw/cfdp/pdu/FileDataDeserializer.h" +#include "fsfw/cfdp/pdu/FileDataSerializer.h" +#include "fsfw/globalfunctions/arrayprinter.h" +#include "fsfw/serviceinterface.h" + +#include + +TEST_CASE( "File Data PDU" , "[FileDataPdu]") { + using namespace cfdp; + + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + std::array fileBuffer = {}; + std::array fileDataBuffer = {}; + uint8_t* buffer = fileDataBuffer.data(); + size_t sz = 0; + 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); + + for(uint8_t idx = 0; idx < 10; idx++) { + fileBuffer[idx] = idx; + } + FileSize offset(50); + FileDataInfo info(offset, fileBuffer.data(), 10); + + SECTION("Serialization") { + FileDataSerializer serializer(pduConf, info); + result = serializer.serialize(&buffer, &sz, fileDataBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(sz == 24); + // 10 file bytes plus 4 byte offset + REQUIRE(((fileDataBuffer[1] << 8) | fileDataBuffer[2]) == 14); + // File Data -> Fourth bit is one + REQUIRE(fileDataBuffer[0] == 0b00110000); + uint32_t offsetRaw = 0; + buffer = fileDataBuffer.data(); + result = SerializeAdapter::deSerialize(&offsetRaw, buffer + 10, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(offsetRaw == 50); + buffer = fileDataBuffer.data() + 14; + for(size_t idx = 0; idx < 10; idx++) { + REQUIRE(buffer[idx] == idx); + } + + REQUIRE(info.hasSegmentMetadata() == false); + info.addSegmentMetadataInfo(cfdp::RecordContinuationState::CONTAINS_START_AND_END, + fileBuffer.data(), 10); + REQUIRE(info.hasSegmentMetadata() == true); + REQUIRE(info.getSegmentationControl() == + cfdp::SegmentationControl::NO_RECORD_BOUNDARIES_PRESERVATION); + info.setSegmentationControl(cfdp::SegmentationControl::RECORD_BOUNDARIES_PRESERVATION); + serializer.update(); + REQUIRE(serializer.getSegmentationControl() == + cfdp::SegmentationControl::RECORD_BOUNDARIES_PRESERVATION); + buffer = fileDataBuffer.data(); + sz = 0; + serializer.setSegmentationControl(cfdp::SegmentationControl::RECORD_BOUNDARIES_PRESERVATION); + + result = serializer.serialize(&buffer, &sz, fileDataBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(((fileDataBuffer[1] << 8) | fileDataBuffer[2]) == 25); + // First bit: Seg Ctrl is set + // Bits 1 to 3 length of enitity IDs is 2 + // Bit 4: Segment metadata flag is set + // Bit 5 to seven: length of transaction seq num is 2 + REQUIRE(fileDataBuffer[3] == 0b10101010); + REQUIRE((fileDataBuffer[10] >> 6) & 0b11 == + cfdp::RecordContinuationState::CONTAINS_START_AND_END); + // Segment metadata length + REQUIRE((fileDataBuffer[10] & 0x3f) == 10); + buffer = fileDataBuffer.data() + 11; + // Check segment metadata + for(size_t idx = 0; idx < 10; idx++) { + REQUIRE(buffer[idx] == idx); + } + // Check filedata + buffer = fileDataBuffer.data() + 25; + for(size_t idx = 0; idx < 10; idx++) { + REQUIRE(buffer[idx] == idx); + } + + for(size_t invalidStartSz = 1; invalidStartSz < sz; invalidStartSz ++) { + buffer = fileDataBuffer.data(); + sz = 0; + result = serializer.serialize(&buffer, &invalidStartSz, sz, + SerializeIF::Endianness::NETWORK); + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + } + + info.setSegmentMetadataFlag(true); + REQUIRE(info.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::PRESENT); + info.setSegmentMetadataFlag(false); + REQUIRE(info.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::NOT_PRESENT); + info.setRecordContinuationState(cfdp::RecordContinuationState::CONTAINS_END_NO_START); + info.setSegmentMetadataLen(10); + info.setSegmentMetadata(nullptr); + info.setFileData(nullptr, 0); + } + + SECTION("Deserialization") { + FileDataSerializer serializer(pduConf, info); + result = serializer.serialize(&buffer, &sz, fileDataBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + + FileSize emptyOffset; + FileDataInfo emptyInfo(emptyOffset); + FileDataDeserializer deserializer(fileDataBuffer.data(), fileDataBuffer.size(), emptyInfo); + result = deserializer.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(deserializer.getWholePduSize() == 24); + REQUIRE(deserializer.getPduDataFieldLen() == 14); + REQUIRE(deserializer.getSegmentationControl() == + cfdp::SegmentationControl::NO_RECORD_BOUNDARIES_PRESERVATION); + REQUIRE(deserializer.getSegmentMetadataFlag() == + cfdp::SegmentMetadataFlag::NOT_PRESENT); + + REQUIRE(emptyInfo.getOffset().getSize() == 50); + REQUIRE(emptyInfo.hasSegmentMetadata() == false); + size_t emptyFileSize = 0; + const uint8_t* fileData = emptyInfo.getFileData(&emptyFileSize); + REQUIRE(emptyFileSize == 10); + for(size_t idx = 0; idx < 10; idx++) { + REQUIRE(fileData[idx] == idx); + } + + deserializer.setEndianness(SerializeIF::Endianness::NETWORK); + + info.addSegmentMetadataInfo(cfdp::RecordContinuationState::CONTAINS_START_AND_END, + fileBuffer.data(), 10); + serializer.update(); + buffer = fileDataBuffer.data(); + sz = 0; + result = serializer.serialize(&buffer, &sz, fileDataBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + + result = deserializer.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + + REQUIRE(emptyInfo.getOffset().getSize() == 50); + REQUIRE(emptyInfo.hasSegmentMetadata() == true); + REQUIRE(emptyInfo.getRecordContinuationState() == + cfdp::RecordContinuationState::CONTAINS_START_AND_END); + emptyFileSize = 0; + fileData = emptyInfo.getFileData(&emptyFileSize); + REQUIRE(emptyFileSize == 10); + for(size_t idx = 0; idx < 10; idx++) { + REQUIRE(fileData[idx] == idx); + } + size_t segmentMetadataLen = 0; + fileData = emptyInfo.getSegmentMetadata(&segmentMetadataLen); + REQUIRE(segmentMetadataLen == 10); + for(size_t idx = 0; idx < 10; idx++) { + REQUIRE(fileData[idx] == idx); + } + for(size_t invalidPduField = 0; invalidPduField < 24; invalidPduField++) { + fileDataBuffer[1] = (invalidPduField >> 8) & 0xff; + fileDataBuffer[2] = invalidPduField & 0xff; + result = deserializer.parseData(); + // Starting at 15, the file data is parsed. There is not leading file data length + // field to the parser can't check whether the remaining length is valid + if(invalidPduField < 15) { + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + } + } + + } +} diff --git a/tests/src/fsfw_tests/unit/cfdp/testFinishedPdu.cpp b/tests/src/fsfw_tests/unit/cfdp/testFinishedPdu.cpp new file mode 100644 index 00000000..718750de --- /dev/null +++ b/tests/src/fsfw_tests/unit/cfdp/testFinishedPdu.cpp @@ -0,0 +1,196 @@ +#include + +#include "fsfw/globalfunctions/arrayprinter.h" +#include "fsfw/cfdp/pdu/FinishedPduDeserializer.h" +#include "fsfw/cfdp/pdu/FinishedPduSerializer.h" + +#include + +TEST_CASE( "Finished PDU" , "[FinishedPdu]") { + using namespace cfdp; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + std::array fnBuffer = {}; + uint8_t* buffer = fnBuffer.data(); + size_t sz = 0; + 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); + + cfdp::Lv emptyFsMsg; + FinishedInfo info(cfdp::ConditionCode::INACTIVITY_DETECTED, + cfdp::FinishedDeliveryCode::DATA_INCOMPLETE, + cfdp::FinishedFileStatus::DISCARDED_DELIBERATELY); + + SECTION("Serialize") { + FinishPduSerializer serializer(pduConf, info); + result = serializer.serialize(&buffer, &sz, fnBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(serializer.getSerializedSize() == 12); + REQUIRE(((fnBuffer[1] << 8) | fnBuffer[2]) == 2); + REQUIRE(fnBuffer[10] == cfdp::FileDirectives::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(sz == 12); + + // Add a filestore response + std::string firstName = "hello.txt"; + cfdp::Lv firstNameLv(reinterpret_cast(firstName.data()), firstName.size()); + FilestoreResponseTlv response(cfdp::FilestoreActionCode::DELETE_FILE, + cfdp::FSR_APPEND_FILE_1_NOT_EXISTS, firstNameLv, nullptr); + FilestoreResponseTlv* responsePtr = &response; + REQUIRE(response.getSerializedSize() == 14); + size_t len = 1; + info.setFilestoreResponsesArray(&responsePtr, &len, &len); + serializer.updateDirectiveFieldLen(); + REQUIRE(serializer.getSerializedSize() == 12 + 14); + sz = 0; + buffer = fnBuffer.data(); + result = serializer.serialize(&buffer, &sz, fnBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(serializer.getSerializedSize() == 12 + 14); + REQUIRE(serializer.getPduDataFieldLen() == 16); + + // Add two filestore responses and a fault location parameter + std::string secondName = "hello2.txt"; + cfdp::Lv secondNameLv(reinterpret_cast(secondName.data()), secondName.size()); + FilestoreResponseTlv response2(cfdp::FilestoreActionCode::DENY_FILE , + cfdp::FSR_SUCCESS, secondNameLv, nullptr); + REQUIRE(response2.getSerializedSize() == 15); + len = 2; + std::array responses {&response, &response2}; + info.setFilestoreResponsesArray(responses.data(), &len, &len); + serializer.updateDirectiveFieldLen(); + + EntityIdTlv faultLoc(destId); + REQUIRE(faultLoc.getSerializedSize() == 4); + info.setFaultLocation(&faultLoc); + serializer.updateDirectiveFieldLen(); + sz = 0; + buffer = fnBuffer.data(); + result = serializer.serialize(&buffer, &sz, fnBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + 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); + for(size_t maxSz = 0; maxSz < 45; maxSz++) { + sz = 0; + buffer = fnBuffer.data(); + result = serializer.serialize(&buffer, &sz, maxSz, SerializeIF::Endianness::NETWORK); + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + } + } + + SECTION("Deserialize") { + FinishedInfo emptyInfo; + FinishPduSerializer serializer(pduConf, info); + result = serializer.serialize(&buffer, &sz, fnBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + FinishPduDeserializer deserializer(fnBuffer.data(), fnBuffer.size(), emptyInfo); + result = deserializer.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(emptyInfo.getFileStatus() == cfdp::FinishedFileStatus::DISCARDED_DELIBERATELY); + REQUIRE(emptyInfo.getConditionCode() == cfdp::ConditionCode::INACTIVITY_DETECTED); + REQUIRE(emptyInfo.getDeliveryCode() == cfdp::FinishedDeliveryCode::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()); + FilestoreResponseTlv response(cfdp::FilestoreActionCode::DELETE_FILE, + cfdp::FSR_NOT_PERFORMED, firstNameLv, nullptr); + FilestoreResponseTlv* responsePtr = &response; + size_t len = 1; + info.setFilestoreResponsesArray(&responsePtr, &len, &len); + serializer.updateDirectiveFieldLen(); + REQUIRE(serializer.getPduDataFieldLen() == 16); + result = serializer.serialize(&buffer, &sz, fnBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + FilestoreResponseTlv emptyResponse(firstNameLv, nullptr); + responsePtr = &emptyResponse; + emptyInfo.setFilestoreResponsesArray(&responsePtr, nullptr, &len); + FinishPduDeserializer deserializer2(fnBuffer.data(), fnBuffer.size(), emptyInfo); + result = deserializer2.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(emptyInfo.getFsResponsesLen() == 1); + FilestoreResponseTlv** responseArray = nullptr; + emptyInfo.getFilestoreResonses(&responseArray, nullptr, nullptr); + REQUIRE(responseArray[0]->getActionCode() == cfdp::FilestoreActionCode::DELETE_FILE); + REQUIRE(responseArray[0]->getStatusCode() == cfdp::FSR_NOT_PERFORMED); + auto& fileNameRef = responseArray[0]->getFirstFileName(); + size_t stringSize = 0; + const char* string = reinterpret_cast(fileNameRef.getValue(&stringSize)); + std::string firstFileName(string, stringSize); + REQUIRE(firstFileName == "hello.txt"); + + // Add two filestore responses and a fault location parameter + std::string secondName = "hello2.txt"; + cfdp::Lv secondNameLv(reinterpret_cast(secondName.data()), secondName.size()); + FilestoreResponseTlv response2(cfdp::FilestoreActionCode::DENY_FILE , + cfdp::FSR_SUCCESS, secondNameLv, nullptr); + REQUIRE(response2.getSerializedSize() == 15); + len = 2; + std::array responses {&response, &response2}; + info.setFilestoreResponsesArray(responses.data(), &len, &len); + serializer.updateDirectiveFieldLen(); + + EntityIdTlv faultLoc(destId); + info.setFaultLocation(&faultLoc); + serializer.updateDirectiveFieldLen(); + sz = 0; + buffer = fnBuffer.data(); + result = serializer.serialize(&buffer, &sz, fnBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + EntityId emptyId; + EntityIdTlv emptyFaultLoc(emptyId); + emptyInfo.setFaultLocation(&emptyFaultLoc); + response.setFilestoreMessage(&emptyFsMsg); + emptyInfo.setFilestoreResponsesArray(responses.data(), &len, &len); + response2.setFilestoreMessage(&emptyFsMsg); + FinishPduDeserializer deserializer3(fnBuffer.data(), fnBuffer.size(), emptyInfo); + result = deserializer3.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + auto& infoRef = deserializer3.getInfo(); + REQUIRE(deserializer3.getWholePduSize() == 45); + + size_t invalidMaxLen = 1; + emptyInfo.setFilestoreResponsesArray(responses.data(), &len, &invalidMaxLen); + result = deserializer3.parseData(); + REQUIRE(result == cfdp::FINISHED_CANT_PARSE_FS_RESPONSES); + emptyInfo.setFilestoreResponsesArray(nullptr, nullptr, nullptr); + result = deserializer3.parseData(); + REQUIRE(result == cfdp::FINISHED_CANT_PARSE_FS_RESPONSES); + + // Clear condition code + auto tmp = fnBuffer[11]; + fnBuffer[11] = fnBuffer[11] & ~0xf0; + fnBuffer[11] = fnBuffer[11] | (cfdp::ConditionCode::NO_ERROR << 4); + emptyInfo.setFilestoreResponsesArray(responses.data(), &len, &len); + result = deserializer3.parseData(); + REQUIRE(result == cfdp::INVALID_TLV_TYPE); + + fnBuffer[11] = tmp; + // Invalid TLV type, should be entity ID + fnBuffer[sz - 4] = cfdp::TlvTypes::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); + result = faultyDeser.parseData(); + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + } + } +} diff --git a/tests/src/fsfw_tests/unit/cfdp/testKeepAlivePdu.cpp b/tests/src/fsfw_tests/unit/cfdp/testKeepAlivePdu.cpp new file mode 100644 index 00000000..09008650 --- /dev/null +++ b/tests/src/fsfw_tests/unit/cfdp/testKeepAlivePdu.cpp @@ -0,0 +1,84 @@ +#include + +#include "fsfw/cfdp/pdu/KeepAlivePduDeserializer.h" +#include "fsfw/cfdp/pdu/KeepAlivePduSerializer.h" +#include "fsfw/globalfunctions/arrayprinter.h" + +#include + +TEST_CASE( "Keep Alive PDU" , "[KeepAlivePdu]") { + using namespace cfdp; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + std::array kaBuffer = {}; + uint8_t* buffer = kaBuffer.data(); + size_t sz = 0; + 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); + + FileSize progress(0x50); + + SECTION("Serialize") { + KeepAlivePduSerializer serializer(pduConf, progress); + result = serializer.serialize(&buffer, &sz, kaBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(kaBuffer[10] == cfdp::FileDirectives::KEEP_ALIVE); + uint32_t fsRaw = 0; + result = SerializeAdapter::deSerialize(&fsRaw, kaBuffer.data() + 11, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(fsRaw == 0x50); + REQUIRE(sz == 15); + REQUIRE(serializer.getWholePduSize() == 15); + REQUIRE(serializer.getPduDataFieldLen() == 5); + + pduConf.largeFile = true; + serializer.updateDirectiveFieldLen(); + buffer = kaBuffer.data(); + sz = 0; + result = serializer.serialize(&buffer, &sz, kaBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(serializer.getWholePduSize() == 19); + REQUIRE(serializer.getPduDataFieldLen() == 9); + uint64_t fsRawLarge = 0; + result = SerializeAdapter::deSerialize(&fsRawLarge, kaBuffer.data() + 11, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(fsRawLarge == 0x50); + + for(size_t invalidMaxSz = 0; invalidMaxSz < sz; invalidMaxSz++) { + buffer = kaBuffer.data(); + sz = 0; + result = serializer.serialize(&buffer, &sz, invalidMaxSz, + SerializeIF::Endianness::NETWORK); + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + } + } + + SECTION("Deserialize") { + KeepAlivePduSerializer serializer(pduConf, progress); + result = serializer.serialize(&buffer, &sz, kaBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + + // Set another file size + progress.setFileSize(200, false); + KeepAlivePduDeserializer deserializer(kaBuffer.data(), kaBuffer.size(), progress); + result = deserializer.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + auto& progRef = deserializer.getProgress(); + // Should have been overwritten + REQUIRE(progRef.getSize() == 0x50); + sz = deserializer.getWholePduSize(); + + // invalid max size + for(size_t invalidMaxSz = 0; invalidMaxSz < sz; invalidMaxSz++) { + deserializer.setData(kaBuffer.data(), invalidMaxSz); + result = deserializer.parseData(); + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + } + } +} diff --git a/tests/src/fsfw_tests/unit/cfdp/testMetadataPdu.cpp b/tests/src/fsfw_tests/unit/cfdp/testMetadataPdu.cpp new file mode 100644 index 00000000..50dae9e9 --- /dev/null +++ b/tests/src/fsfw_tests/unit/cfdp/testMetadataPdu.cpp @@ -0,0 +1,185 @@ +#include +#include + +#include "fsfw/cfdp/tlv/FilestoreResponseTlv.h" +#include "fsfw/cfdp/pdu/MetadataPduDeserializer.h" +#include "fsfw/cfdp/pdu/MetadataPduSerializer.h" +#include "fsfw/globalfunctions/arrayprinter.h" + +#include + +TEST_CASE( "Metadata PDU" , "[MetadataPdu]") { + using namespace cfdp; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + std::array mdBuffer = {}; + uint8_t* buffer = mdBuffer.data(); + size_t sz = 0; + 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); + + std::string firstFileName = "hello.txt"; + cfdp::Lv sourceFileName(reinterpret_cast(firstFileName.data()), + firstFileName.size()); + cfdp::Lv destFileName(nullptr, 0); + FileSize fileSize(35); + MetadataInfo info(false, ChecksumType::MODULAR, fileSize, sourceFileName, destFileName); + + FilestoreResponseTlv response(FilestoreActionCode::CREATE_DIRECTORY, FSR_CREATE_NOT_ALLOWED, + sourceFileName, nullptr); + std::array msg = {0x41, 0x42, 0x43}; + cfdp::Tlv responseTlv; + std::array responseBuf = {}; + uint8_t* responseBufPtr = responseBuf.data(); + response.convertToTlv(responseTlv, buffer, responseBuf.size(), + SerializeIF::Endianness::MACHINE); + MessageToUserTlv msgToUser(msg.data(), msg.size()); + std::array options {&responseTlv, &msgToUser}; + REQUIRE(options[0]->getSerializedSize() == 2 + 1 + 10 + 1); + REQUIRE(options[1]->getSerializedSize() == 5); + + SECTION("Serialize") { + MetadataPduSerializer serializer(pduConf, info); + result = serializer.serialize(&buffer, &sz, mdBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(serializer.getWholePduSize() == 27); + REQUIRE(info.getSourceFileName().getSerializedSize() == 10); + REQUIRE(info.getDestFileName().getSerializedSize() == 1); + REQUIRE(info.getSerializedSize() == 16); + REQUIRE((mdBuffer[1] << 8 | mdBuffer[2]) == 17); + REQUIRE(mdBuffer[10] == FileDirectives::METADATA); + // no closure requested and checksum type is modular => 0x00 + REQUIRE(mdBuffer[11] == 0x00); + uint32_t fileSizeRaw = 0; + result = SerializeAdapter::deSerialize(&fileSizeRaw, mdBuffer.data() + 12, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(fileSizeRaw == 35); + REQUIRE(mdBuffer[16] == 9); + REQUIRE(mdBuffer[17] == 'h'); + REQUIRE(mdBuffer[18] == 'e'); + REQUIRE(mdBuffer[19] == 'l'); + REQUIRE(mdBuffer[20] == 'l'); + REQUIRE(mdBuffer[21] == 'o'); + REQUIRE(mdBuffer[22] == '.'); + REQUIRE(mdBuffer[23] == 't'); + REQUIRE(mdBuffer[24] == 'x'); + REQUIRE(mdBuffer[25] == 't'); + REQUIRE(mdBuffer[26] == 0); + + std::string otherFileName = "hello2.txt"; + cfdp::Lv otherFileNameLv(reinterpret_cast(otherFileName.data()), + otherFileName.size()); + info.setSourceFileName(otherFileNameLv); + size_t sizeOfOptions = options.size(); + info.setOptionsArray(options.data(), &sizeOfOptions, &sizeOfOptions); + REQUIRE(info.getMaxOptionsLen() == 2); + info.setMaxOptionsLen(3); + REQUIRE(info.getMaxOptionsLen() == 3); + info.setChecksumType(cfdp::ChecksumType::CRC_32C); + info.setClosureRequested(true); + uint8_t* buffer = mdBuffer.data(); + size_t sz = 0; + serializer.updateDirectiveFieldLen(); + + result = serializer.serialize(&buffer, &sz, mdBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE((mdBuffer[1] << 8 | mdBuffer[2]) == 37); + auto checksumType = static_cast(mdBuffer[11] & 0x0f); + REQUIRE(checksumType == cfdp::ChecksumType::CRC_32C); + bool closureRequested = mdBuffer[11] >> 6 & 0x01; + REQUIRE(closureRequested == true); + // The size of the two options is 19. Summing up: + // - 11 bytes of source file name + // - 1 byte for dest file name + // - 4 for FSS + // - 1 leading byte. + // - 1 byte for PDU type + // PDU header has 10 bytes. + // I am not going to check the options raw content, those are part of the dedicated + // TLV unittests + REQUIRE(sz == 10 + 37); + for(size_t maxSz = 0; maxSz < sz; maxSz++) { + uint8_t* buffer = mdBuffer.data(); + size_t sz = 0; + result = serializer.serialize(&buffer, &sz, maxSz, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == SerializeIF::BUFFER_TOO_SHORT); + } + for(size_t initSz = 1; initSz < 47; initSz++) { + uint8_t* buffer = mdBuffer.data(); + size_t sz = initSz; + result = serializer.serialize(&buffer, &sz, 46, SerializeIF::Endianness::NETWORK); + REQUIRE(result == SerializeIF::BUFFER_TOO_SHORT); + } + info.setDestFileName(destFileName); + } + + SECTION("Deserialize") { + MetadataPduSerializer serializer(pduConf, info); + result = serializer.serialize(&buffer, &sz, mdBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + + MetadataPduDeserializer deserializer(mdBuffer.data(), mdBuffer.size(), info); + result = deserializer.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + size_t fullSize = deserializer.getWholePduSize(); + for(size_t maxSz = 0; maxSz < fullSize; maxSz++) { + MetadataPduDeserializer invalidSzDeser(mdBuffer.data(), maxSz, info); + result = invalidSzDeser.parseData(); + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + } + size_t sizeOfOptions = options.size(); + size_t maxSize = 4; + info.setOptionsArray(options.data(), &sizeOfOptions, &maxSize); + REQUIRE(info.getOptionsLen() == 2); + info.setChecksumType(cfdp::ChecksumType::CRC_32C); + info.setClosureRequested(true); + uint8_t* buffer = mdBuffer.data(); + size_t sz = 0; + serializer.updateDirectiveFieldLen(); + + info.setSourceFileName(sourceFileName); + result = serializer.serialize(&buffer, &sz, mdBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + + MetadataPduDeserializer deserializer2(mdBuffer.data(), mdBuffer.size(), info); + result = deserializer2.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(options[0]->getType() == cfdp::TlvTypes::FILESTORE_RESPONSE); + REQUIRE(options[0]->getSerializedSize() == 14); + REQUIRE(options[1]->getType() == cfdp::TlvTypes::MSG_TO_USER); + REQUIRE(options[1]->getSerializedSize() == 5); + + for(size_t invalidFieldLen = 0; invalidFieldLen < 36; invalidFieldLen++) { + mdBuffer[1] = (invalidFieldLen >> 8) & 0xff; + mdBuffer[2] = invalidFieldLen & 0xff; + result = deserializer2.parseData(); + if(invalidFieldLen == 17) { + REQUIRE(info.getOptionsLen() == 0); + } + if(invalidFieldLen == 31) { + REQUIRE(info.getOptionsLen() == 1); + } + // This is the precise length where there are no options or one option + if(invalidFieldLen != 17 and invalidFieldLen != 31) { + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + } + } + mdBuffer[1] = (36 >> 8) & 0xff; + mdBuffer[2] = 36 & 0xff; + info.setOptionsArray(nullptr, nullptr, nullptr); + REQUIRE(deserializer2.parseData() == cfdp::METADATA_CANT_PARSE_OPTIONS); + info.setOptionsArray(options.data(), &sizeOfOptions, nullptr); + for(size_t maxSz = 0; maxSz < 46; maxSz++) { + MetadataPduDeserializer invalidSzDeser(mdBuffer.data(), maxSz, info); + result = invalidSzDeser.parseData(); + REQUIRE(result == SerializeIF::STREAM_TOO_SHORT); + } + } +} diff --git a/tests/src/fsfw_tests/unit/cfdp/testNakPdu.cpp b/tests/src/fsfw_tests/unit/cfdp/testNakPdu.cpp new file mode 100644 index 00000000..57ec5140 --- /dev/null +++ b/tests/src/fsfw_tests/unit/cfdp/testNakPdu.cpp @@ -0,0 +1,160 @@ +#include + +#include "fsfw/cfdp/pdu/PduConfig.h" +#include "fsfw/cfdp/pdu/NakPduDeserializer.h" +#include "fsfw/cfdp/pdu/NakPduSerializer.h" +#include "fsfw/globalfunctions/arrayprinter.h" + +#include + +TEST_CASE( "NAK PDU" , "[NakPdu]") { + using namespace cfdp; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + std::array nakBuffer = {}; + uint8_t* buffer = nakBuffer.data(); + size_t sz = 0; + 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); + + FileSize startOfScope(50); + FileSize endOfScope(1050); + NakInfo info(startOfScope, endOfScope); + SECTION("Serializer") { + NakPduSerializer serializer(pduConf, info); + result = serializer.serialize(&buffer, &sz, nakBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(serializer.getSerializedSize() == 19); + REQUIRE(serializer.FileDirectiveSerializer::getSerializedSize() == 11); + REQUIRE(sz == 19); + REQUIRE(serializer.getPduDataFieldLen() == 9); + REQUIRE(((nakBuffer[1] << 8) | nakBuffer[2]) == 0x09); + REQUIRE(nakBuffer[10] == cfdp::FileDirectives::NAK); + uint32_t scope = 0; + result = SerializeAdapter::deSerialize(&scope, nakBuffer.data() + 11, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(scope == 50); + result = SerializeAdapter::deSerialize(&scope, nakBuffer.data() + 15, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(scope == 1050); + + NakInfo::SegmentRequest segReq0(cfdp::FileSize(2020), cfdp::FileSize(2520)); + NakInfo::SegmentRequest segReq1(cfdp::FileSize(2932), cfdp::FileSize(3021)); + // Now add 2 segment requests to NAK info and serialize them as well + std::array segReqs = { segReq0, segReq1 }; + size_t segReqsLen = segReqs.size(); + info.setSegmentRequests(segReqs.data(), &segReqsLen , &segReqsLen); + uint8_t* buffer = nakBuffer.data(); + size_t sz = 0; + serializer.updateDirectiveFieldLen(); + result = serializer.serialize(&buffer, &sz, nakBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(serializer.getSerializedSize() == 35); + REQUIRE(serializer.getPduDataFieldLen() == 25); + REQUIRE(((nakBuffer[1] << 8) | nakBuffer[2]) == 25); + uint32_t segReqScopes = 0; + result = SerializeAdapter::deSerialize(&segReqScopes, nakBuffer.data() + 19, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(segReqScopes == 2020); + result = SerializeAdapter::deSerialize(&segReqScopes, nakBuffer.data() + 23, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(segReqScopes == 2520); + result = SerializeAdapter::deSerialize(&segReqScopes, nakBuffer.data() + 27, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(segReqScopes == 2932); + result = SerializeAdapter::deSerialize(&segReqScopes, nakBuffer.data() + 31, nullptr, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(segReqScopes == 3021); + + for(size_t maxSz = 0; maxSz < 35; maxSz++) { + uint8_t* buffer = nakBuffer.data(); + size_t sz = 0; + result = serializer.serialize(&buffer, &sz, maxSz, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == SerializeIF::BUFFER_TOO_SHORT); + } + for(size_t sz = 35; sz > 0; sz--) { + uint8_t* buffer = nakBuffer.data(); + size_t locSize = sz; + result = serializer.serialize(&buffer, &locSize, 35, + SerializeIF::Endianness::NETWORK); + REQUIRE(result == SerializeIF::BUFFER_TOO_SHORT); + } + } + + SECTION("Deserializer") { + NakPduSerializer serializer(pduConf, info); + result = serializer.serialize(&buffer, &sz, nakBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + + info.getStartOfScope().setFileSize(0, false); + info.getEndOfScope().setFileSize(0, false); + NakPduDeserializer deserializer(nakBuffer.data(), nakBuffer.size(), info); + result = deserializer.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(deserializer.getWholePduSize() == 19); + REQUIRE(info.getStartOfScope().getSize() == 50); + REQUIRE(info.getEndOfScope().getSize() == 1050); + + NakInfo::SegmentRequest segReq0(cfdp::FileSize(2020), cfdp::FileSize(2520)); + NakInfo::SegmentRequest segReq1(cfdp::FileSize(2932), cfdp::FileSize(3021)); + // Now add 2 segment requests to NAK info and serialize them as well + std::array segReqs = { segReq0, segReq1 }; + size_t segReqsLen = segReqs.size(); + info.setSegmentRequests(segReqs.data(), &segReqsLen, &segReqsLen); + uint8_t* buffer = nakBuffer.data(); + size_t sz = 0; + serializer.updateDirectiveFieldLen(); + result = serializer.serialize(&buffer, &sz, nakBuffer.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + + NakPduDeserializer deserializeWithSegReqs(nakBuffer.data(), nakBuffer.size(), info); + result = deserializeWithSegReqs.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + NakInfo::SegmentRequest* segReqsPtr = nullptr; + size_t readSegReqs = 0; + info.getSegmentRequests(&segReqsPtr, &readSegReqs, nullptr); + REQUIRE(readSegReqs == 2); + REQUIRE(segReqsPtr[0].first.getSize() == 2020); + REQUIRE(segReqsPtr[0].second.getSize() == 2520); + REQUIRE(segReqsPtr[1].first.getSize() == 2932); + REQUIRE(segReqsPtr[1].second.getSize() == 3021); + REQUIRE(deserializeWithSegReqs.getPduDataFieldLen() == 25); + REQUIRE(info.getSegmentRequestsLen() == 2); + for(size_t idx = 0; idx < 34; idx ++) { + NakPduDeserializer faultyDeserializer(nakBuffer.data(), idx, info); + result = faultyDeserializer.parseData(); + REQUIRE(result != HasReturnvaluesIF::RETURN_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); + result = faultyDeserializer.parseData(); + if(pduFieldLen == 9) { + REQUIRE(info.getSegmentRequestsLen() == 0); + } else if(pduFieldLen == 17) { + REQUIRE(info.getSegmentRequestsLen() == 1); + } else if(pduFieldLen == 25) { + REQUIRE(info.getSegmentRequestsLen() == 2); + } + if(pduFieldLen != 9 and pduFieldLen != 17 and pduFieldLen != 25) { + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + } + } + info.setMaxSegmentRequestLen(5); + REQUIRE(info.getSegmentRequestsMaxLen() == 5); + } +} + diff --git a/tests/src/fsfw_tests/unit/cfdp/testPromptPdu.cpp b/tests/src/fsfw_tests/unit/cfdp/testPromptPdu.cpp new file mode 100644 index 00000000..64589e46 --- /dev/null +++ b/tests/src/fsfw_tests/unit/cfdp/testPromptPdu.cpp @@ -0,0 +1,71 @@ +#include + +#include "fsfw/cfdp/pdu/PromptPduDeserializer.h" +#include "fsfw/cfdp/pdu/PromptPduSerializer.h" +#include "fsfw/globalfunctions/arrayprinter.h" + +#include + +TEST_CASE( "Prompt PDU" , "[PromptPdu]") { + using namespace cfdp; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + std::array rawBuf = {}; + uint8_t* buffer = rawBuf.data(); + size_t sz = 0; + 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); + + SECTION("Serialize") { + PromptPduSerializer serializer(pduConf, cfdp::PromptResponseRequired::PROMPT_KEEP_ALIVE); + result = serializer.serialize(&buffer, &sz, rawBuf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_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); + + for(size_t invalidMaxSz = 0; invalidMaxSz < sz; invalidMaxSz++) { + uint8_t* buffer = rawBuf.data(); + size_t sz = 0; + result = serializer.serialize(&buffer, &sz, invalidMaxSz, + SerializeIF::Endianness::NETWORK); + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + } + for(size_t invalidSz = 1; invalidSz < sz; invalidSz++) { + size_t locSz = invalidSz; + uint8_t* buffer = rawBuf.data(); + result = serializer.serialize(&buffer, &locSz, sz, + SerializeIF::Endianness::NETWORK); + REQUIRE(result != HasReturnvaluesIF::RETURN_OK); + } + } + + SECTION("Deserialize") { + PromptPduSerializer serializer(pduConf, cfdp::PromptResponseRequired::PROMPT_KEEP_ALIVE); + result = serializer.serialize(&buffer, &sz, rawBuf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + + PromptPduDeserializer deserializer(rawBuf.data(), rawBuf.size()); + result = deserializer.parseData(); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(deserializer.getPromptResponseRequired() == + cfdp::PromptResponseRequired::PROMPT_KEEP_ALIVE); + sz = deserializer.getWholePduSize(); + rawBuf[2] = 1; + result = deserializer.parseData(); + 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 != HasReturnvaluesIF::RETURN_OK); + } + } +} + diff --git a/tests/src/fsfw_tests/unit/cfdp/testTlvsLvs.cpp b/tests/src/fsfw_tests/unit/cfdp/testTlvsLvs.cpp new file mode 100644 index 00000000..15e94ebb --- /dev/null +++ b/tests/src/fsfw_tests/unit/cfdp/testTlvsLvs.cpp @@ -0,0 +1,334 @@ +#include "fsfw/cfdp/pdu/PduConfig.h" +#include "fsfw/cfdp/tlv/Tlv.h" +#include "fsfw/cfdp/tlv/Lv.h" + +#include +#include +#include +#include + +#include "fsfw/globalfunctions/arrayprinter.h" +#include +#include +#include + +#include +#include + +TEST_CASE( "CFDP TLV LV" , "[CfdpTlvLv]") { + using namespace cfdp; + int result = HasReturnvaluesIF::RETURN_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 == HasReturnvaluesIF::RETURN_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 == HasReturnvaluesIF::RETURN_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 == HasReturnvaluesIF::RETURN_OK); + REQUIRE(rawBuf[0] == TlvTypes::ENTITY_ID); + REQUIRE(rawBuf[1] == 4); + + REQUIRE(result == HasReturnvaluesIF::RETURN_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) != HasReturnvaluesIF::RETURN_OK); + tlvInvalid = Tlv(cfdp::TlvTypes::ENTITY_ID, nullptr, 3); + REQUIRE(tlvInvalid.serialize(&serPtr, &deserSize, rawBuf.size(), + SerializeIF::Endianness::NETWORK) != HasReturnvaluesIF::RETURN_OK); + REQUIRE(tlvInvalid.serialize(&serPtr, &deserSize, 0, + SerializeIF::Endianness::NETWORK) != HasReturnvaluesIF::RETURN_OK); + REQUIRE(tlvInvalid.getSerializedSize() == 0); + REQUIRE(tlvInvalid.serialize(nullptr, nullptr, 0, + SerializeIF::Endianness::NETWORK) != HasReturnvaluesIF::RETURN_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) == HasReturnvaluesIF::RETURN_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 == HasReturnvaluesIF::RETURN_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) != + HasReturnvaluesIF::RETURN_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) != + HasReturnvaluesIF::RETURN_OK); + + Tlv zeroLenField(TlvTypes::FAULT_HANDLER, nullptr, 0); + serPtr = rawBuf.data(); + deserSize = 0; + REQUIRE(zeroLenField.serialize(&serPtr, &deserSize, rawBuf.size(), + SerializeIF::Endianness::NETWORK) == HasReturnvaluesIF::RETURN_OK); + deserPtr = rawBuf.data(); + result = zeroLenField.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_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 == HasReturnvaluesIF::RETURN_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 == HasReturnvaluesIF::RETURN_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 == HasReturnvaluesIF::RETURN_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 == HasReturnvaluesIF::RETURN_OK); + + Lv uninitLv; + deserPtr = rawBuf.data(); + deserSize = 3; + result = uninitLv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::BIG); + REQUIRE(result == HasReturnvaluesIF::RETURN_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 == HasReturnvaluesIF::RETURN_OK); + REQUIRE(deserSize == 1); + deserPtr = rawBuf.data(); + result = uninitLv.deSerialize(&deserPtr, &deserSize, SerializeIF::Endianness::BIG); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(uninitLv.getSerializedSize() == 1); + + REQUIRE(uninitLv.deSerialize(nullptr, nullptr, SerializeIF::Endianness::BIG) == + HasReturnvaluesIF::RETURN_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 == HasReturnvaluesIF::RETURN_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 == HasReturnvaluesIF::RETURN_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 == HasReturnvaluesIF::RETURN_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 == HasReturnvaluesIF::RETURN_OK); + + cfdp::Tlv rawRequest; + ptr = serBuf.data(); + sz = 0; + result = request.convertToTlv(rawRequest, serBuf.data(), serBuf.size(), + SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(rawRequest.getType() == cfdp::TlvTypes::FILESTORE_REQUEST); + + emptyRequest.setActionCode(cfdp::FilestoreActionCode::DELETE_FILE); + result = emptyRequest.deSerialize(rawRequest, SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_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 == HasReturnvaluesIF::RETURN_OK); + + FaultHandlerOverrideTlv emptyOverrideTlv; + result = emptyOverrideTlv.deSerialize(&deserPtr, &sz, SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_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 == HasReturnvaluesIF::RETURN_OK); + deserPtr = rawBuf.data(); + result = idTlv.deSerialize(rawTlv, SerializeIF::Endianness::NETWORK); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + } +}