diff --git a/.gitignore b/.gitignore index eb461072..a5a8d2ba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ # PyCharm and CLion -/.idea/* +.idea/* !/.idea/runConfigurations !/.idea/cmake.xml !/.idea/codeStyles diff --git a/.idea/cmake.xml b/.idea/cmake.xml index b0a4921a..8986ec94 100644 --- a/.idea/cmake.xml +++ b/.idea/cmake.xml @@ -2,7 +2,7 @@ - + \ No newline at end of file diff --git a/src/fsfw/CMakeLists.txt b/src/fsfw/CMakeLists.txt index e645d34f..c8d4dc37 100644 --- a/src/fsfw/CMakeLists.txt +++ b/src/fsfw/CMakeLists.txt @@ -32,6 +32,7 @@ add_subdirectory(timemanager) add_subdirectory(tmtcpacket) add_subdirectory(tmtcservices) add_subdirectory(filesystem) +add_subdirectory(util) # Optional diff --git a/src/fsfw/cfdp/CfdpMessage.cpp b/src/fsfw/cfdp/CfdpMessage.cpp index ea4e2c98..f5bff8fd 100644 --- a/src/fsfw/cfdp/CfdpMessage.cpp +++ b/src/fsfw/cfdp/CfdpMessage.cpp @@ -4,8 +4,9 @@ CfdpMessage::CfdpMessage() = default; CfdpMessage::~CfdpMessage() = default; -void CfdpMessage::setCommand(CommandMessage *message, store_address_t cfdpPacket) { - message->setParameter(cfdpPacket.raw); +void CfdpMessage::setPutRequest(CommandMessage *message, store_address_t putRequest) { + message->setCommand(PUT_REQUEST); + message->setParameter(putRequest.raw); } store_address_t CfdpMessage::getStoreId(const CommandMessage *message) { diff --git a/src/fsfw/cfdp/CfdpMessage.h b/src/fsfw/cfdp/CfdpMessage.h index a3ee9421..b75902eb 100644 --- a/src/fsfw/cfdp/CfdpMessage.h +++ b/src/fsfw/cfdp/CfdpMessage.h @@ -11,9 +11,11 @@ class CfdpMessage { public: static const uint8_t MESSAGE_ID = messagetypes::CFDP; + static const Command_t PUT_REQUEST = MAKE_COMMAND_ID(1); + static const Command_t CANCEL_REQUEST = MAKE_COMMAND_ID(1); virtual ~CfdpMessage(); - static void setCommand(CommandMessage* message, store_address_t cfdpPacket); + static void setPutRequest(CommandMessage* message, store_address_t putRequest); static store_address_t getStoreId(const CommandMessage* message); diff --git a/src/fsfw/cfdp/FileSize.h b/src/fsfw/cfdp/Fss.h similarity index 91% rename from src/fsfw/cfdp/FileSize.h rename to src/fsfw/cfdp/Fss.h index b0b48452..f7110122 100644 --- a/src/fsfw/cfdp/FileSize.h +++ b/src/fsfw/cfdp/Fss.h @@ -8,11 +8,14 @@ namespace cfdp { -struct FileSize : public SerializeIF { +/** + * Helper type for the CFDP File Size Sensitive (FSS) fields. + */ +struct Fss : public SerializeIF { public: - FileSize() = default; + Fss() = default; - explicit FileSize(uint64_t fileSize, bool isLarge = false) { setFileSize(fileSize, isLarge); }; + explicit Fss(uint64_t fileSize, bool isLarge = false) { setFileSize(fileSize, isLarge); }; [[nodiscard]] uint64_t value() const { return fileSize; } diff --git a/src/fsfw/cfdp/VarLenFields.cpp b/src/fsfw/cfdp/VarLenFields.cpp index b9e0b3a8..d0582467 100644 --- a/src/fsfw/cfdp/VarLenFields.cpp +++ b/src/fsfw/cfdp/VarLenFields.cpp @@ -3,8 +3,8 @@ #include "fsfw/serialize/SerializeAdapter.h" #include "fsfw/serviceinterface.h" -cfdp::VarLenField::VarLenField(cfdp::WidthInBytes width, size_t value) : VarLenField() { - ReturnValue_t result = this->setValue(width, value); +cfdp::VarLenField::VarLenField(cfdp::WidthInBytes width, uint64_t value) : VarLenField() { + ReturnValue_t result = this->setValueAndWidth(width, value); if (result != returnvalue::OK) { #if FSFW_DISABLE_PRINTOUT == 0 #if FSFW_CPP_OSTREAM_ENABLED == 1 @@ -20,8 +20,8 @@ cfdp::VarLenField::VarLenField() : width(cfdp::WidthInBytes::ONE_BYTE) { value.o cfdp::WidthInBytes cfdp::VarLenField::getWidth() const { return width; } -ReturnValue_t cfdp::VarLenField::setValue(cfdp::WidthInBytes widthInBytes, size_t value_) { - switch (widthInBytes) { +ReturnValue_t cfdp::VarLenField::setValueAndWidth(cfdp::WidthInBytes width_, uint64_t value_) { + switch (width_) { case (cfdp::WidthInBytes::ONE_BYTE): { if (value_ > UINT8_MAX) { return returnvalue::FAILED; @@ -43,15 +43,18 @@ ReturnValue_t cfdp::VarLenField::setValue(cfdp::WidthInBytes widthInBytes, size_ this->value.fourBytes = value_; break; } + case (cfdp::WidthInBytes::EIGHT_BYTES): { + this->value.eightBytes = value_; + } default: { break; } } - this->width = widthInBytes; + this->width = width_; return returnvalue::OK; } -size_t cfdp::VarLenField::getValue() const { +uint64_t cfdp::VarLenField::getValue() const { switch (width) { case (cfdp::WidthInBytes::ONE_BYTE): { return value.oneByte; @@ -62,6 +65,9 @@ size_t cfdp::VarLenField::getValue() const { case (cfdp::WidthInBytes::FOUR_BYTES): { return value.fourBytes; } + case (cfdp::WidthInBytes::EIGHT_BYTES): { + return value.eightBytes; + } } return 0; } @@ -84,6 +90,10 @@ ReturnValue_t cfdp::VarLenField::serialize(uint8_t **buffer, size_t *size, size_ case (cfdp::WidthInBytes::FOUR_BYTES): { return SerializeAdapter::serialize(&value.fourBytes, buffer, size, maxSize, streamEndianness); } + case (cfdp::WidthInBytes::EIGHT_BYTES): { + return SerializeAdapter::serialize(&value.eightBytes, buffer, size, maxSize, + streamEndianness); + } default: { return returnvalue::FAILED; } @@ -98,11 +108,16 @@ ReturnValue_t cfdp::VarLenField::deSerialize(cfdp::WidthInBytes width_, const ui return deSerialize(buffer, size, streamEndianness); } +ReturnValue_t cfdp::VarLenField::setValue(uint64_t value_) { + return setValueAndWidth(getWidth(), value_); +} + ReturnValue_t cfdp::VarLenField::deSerialize(const uint8_t **buffer, size_t *size, Endianness streamEndianness) { switch (width) { case (cfdp::WidthInBytes::ONE_BYTE): { value.oneByte = **buffer; + *buffer += 1; *size += 1; return returnvalue::OK; } @@ -112,6 +127,9 @@ ReturnValue_t cfdp::VarLenField::deSerialize(const uint8_t **buffer, size_t *siz case (cfdp::WidthInBytes::FOUR_BYTES): { return SerializeAdapter::deSerialize(&value.fourBytes, buffer, size, streamEndianness); } + case (cfdp::WidthInBytes::EIGHT_BYTES): { + return SerializeAdapter::deSerialize(&value.eightBytes, buffer, size, streamEndianness); + } default: { return returnvalue::FAILED; } @@ -135,3 +153,5 @@ bool cfdp::VarLenField::operator==(const cfdp::VarLenField &other) const { bool cfdp::VarLenField::operator!=(const cfdp::VarLenField &other) const { return not(*this == other); } + +void cfdp::VarLenField::setWidth(cfdp::WidthInBytes width_) { this->width = width_; } diff --git a/src/fsfw/cfdp/VarLenFields.h b/src/fsfw/cfdp/VarLenFields.h index 37602c75..69835c37 100644 --- a/src/fsfw/cfdp/VarLenFields.h +++ b/src/fsfw/cfdp/VarLenFields.h @@ -25,13 +25,15 @@ class VarLenField : public SerializeIF { template explicit VarLenField(UnsignedByteField byteField); - VarLenField(cfdp::WidthInBytes width, size_t value); + VarLenField(cfdp::WidthInBytes width, uint64_t value); bool operator==(const VarLenField &other) const; bool operator!=(const VarLenField &other) const; bool operator<(const VarLenField &other) const; - ReturnValue_t setValue(cfdp::WidthInBytes, size_t value); + ReturnValue_t setValueAndWidth(cfdp::WidthInBytes width, uint64_t value); + void setWidth(cfdp::WidthInBytes width); + ReturnValue_t setValue(uint64_t value); ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, Endianness streamEndianness) const override; @@ -42,7 +44,7 @@ class VarLenField : public SerializeIF { Endianness streamEndianness); [[nodiscard]] cfdp::WidthInBytes getWidth() const; - [[nodiscard]] size_t getValue() const; + [[nodiscard]] uint64_t getValue() const; #if FSFW_CPP_OSTREAM_ENABLED == 1 friend std::ostream &operator<<(std::ostream &os, const VarLenField &id) { @@ -64,7 +66,7 @@ template cfdp::VarLenField::VarLenField(UnsignedByteField byteField) : width(static_cast(sizeof(T))) { static_assert((sizeof(T) % 2) == 0); - setValue(width, byteField.getValue()); + setValueAndWidth(width, byteField.getValue()); } struct EntityId : public VarLenField { @@ -73,6 +75,32 @@ struct EntityId : public VarLenField { template explicit EntityId(UnsignedByteField byteField) : VarLenField(byteField) {} EntityId(cfdp::WidthInBytes width, size_t entityId) : VarLenField(width, entityId) {} + + ReturnValue_t serializeAsLv(uint8_t **buffer, size_t *size, size_t maxSize) const { + if (buffer == nullptr or size == nullptr) { + return returnvalue::FAILED; + } + if (*size + 1 + getWidth() > maxSize) { + return SerializeIF::BUFFER_TOO_SHORT; + } + **buffer = getWidth(); + *buffer += 1; + *size += 1; + return serialize(buffer, size, maxSize, SerializeIF::Endianness::NETWORK); + } + + ReturnValue_t deSerializeFromLv(const uint8_t **buffer, size_t *deserLen) { + if (buffer == nullptr or deserLen == nullptr) { + return returnvalue::FAILED; + } + if (*deserLen < 2) { + return SerializeIF::STREAM_TOO_SHORT; + } + auto width = static_cast(**buffer); + *buffer += 1; + *deserLen -= 1; + return VarLenField::deSerialize(width, buffer, deserLen, SerializeIF::Endianness::NETWORK); + } }; struct TransactionSeqNum : public VarLenField { diff --git a/src/fsfw/cfdp/definitions.h b/src/fsfw/cfdp/definitions.h index 2d7a37fc..d19d8532 100644 --- a/src/fsfw/cfdp/definitions.h +++ b/src/fsfw/cfdp/definitions.h @@ -17,7 +17,7 @@ static constexpr char CFDP_VERSION_2_NAME[] = "CCSDS 727.0-B-5"; static constexpr uint8_t CFDP_VERSION_2 = 0b001; static constexpr uint8_t VERSION_BITS = CFDP_VERSION_2 << 5; -static constexpr uint8_t CFDP_CLASS_ID = CLASS_ID::CFDP; +static constexpr uint8_t CFDP_CLASS_ID = CLASS_ID::CFDP_BASE; static constexpr ReturnValue_t INVALID_TLV_TYPE = returnvalue::makeCode(CFDP_CLASS_ID, 1); static constexpr ReturnValue_t INVALID_DIRECTIVE_FIELD = returnvalue::makeCode(CFDP_CLASS_ID, 2); @@ -68,6 +68,7 @@ enum WidthInBytes : uint8_t { ONE_BYTE = 1, TWO_BYTES = 2, FOUR_BYTES = 4, + EIGHT_BYTES = 8 }; enum FileDirective : uint8_t { @@ -142,6 +143,20 @@ enum RecordContinuationState { CONTAINS_START_AND_END = 0b11 }; +enum class ProxyOpMessageType : uint8_t { + PUT_REQUEST = 0x00, + MSG_TO_USR = 0x01, + FS_REQUEST = 0x02, + FAULT_HANDLER_OVERRIDE = 0x03, + TRANSMISSION_MODE = 0x04, + FLOW_LABEL = 0x05, + SEG_CTRL = 0x06, + PUT_RESPONSE = 0x07, + FS_RESPONSE = 0x08, + PUT_CANCEL = 0x09, + CLOSURE = 0x0b +}; + } // namespace cfdp #endif /* FSFW_SRC_FSFW_CFDP_PDU_DEFINITIONS_H_ */ diff --git a/src/fsfw/cfdp/handler/CMakeLists.txt b/src/fsfw/cfdp/handler/CMakeLists.txt index 7ad995c0..8ba2fec8 100644 --- a/src/fsfw/cfdp/handler/CMakeLists.txt +++ b/src/fsfw/cfdp/handler/CMakeLists.txt @@ -1,2 +1,4 @@ -target_sources(${LIB_FSFW_NAME} PRIVATE SourceHandler.cpp DestHandler.cpp - FaultHandlerBase.cpp UserBase.cpp) +target_sources( + ${LIB_FSFW_NAME} + PRIVATE SourceHandler.cpp DestHandler.cpp PutRequest.cpp + ReservedMessageParser.cpp FaultHandlerBase.cpp UserBase.cpp) diff --git a/src/fsfw/cfdp/handler/DestHandler.cpp b/src/fsfw/cfdp/handler/DestHandler.cpp index 4ffa797f..d9c8793d 100644 --- a/src/fsfw/cfdp/handler/DestHandler.cpp +++ b/src/fsfw/cfdp/handler/DestHandler.cpp @@ -16,25 +16,26 @@ using namespace returnvalue; cfdp::DestHandler::DestHandler(DestHandlerParams params, FsfwParams fsfwParams) : tlvVec(params.maxTlvsInOnePdu), - userTlvVec(params.maxTlvsInOnePdu), - dp(std::move(params)), - fp(fsfwParams), - tp(params.maxFilenameLen) { - tp.pduConf.direction = cfdp::Direction::TOWARDS_SENDER; + msgToUserVec(params.maxTlvsInOnePdu), + transactionParams(params.maxFilenameLen), + destParams(std::move(params)), + fsfwParams(fsfwParams) { + transactionParams.pduConf.direction = cfdp::Direction::TOWARDS_SENDER; } -const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() { +const cfdp::DestHandler::FsmResult& cfdp::DestHandler::stateMachine() { ReturnValue_t result; uint8_t errorIdx = 0; fsmRes.resetOfIteration(); if (fsmRes.step == TransactionStep::IDLE) { - for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) { + for (auto infoIter = destParams.packetListRef.begin(); + infoIter != destParams.packetListRef.end();) { if (infoIter->pduType == PduType::FILE_DIRECTIVE and infoIter->directiveType == FileDirective::METADATA) { result = handleMetadataPdu(*infoIter); checkAndHandleError(result, errorIdx); // Store data was deleted in PDU handler because a store guard is used - dp.packetListRef.erase(infoIter++); + destParams.packetListRef.erase(infoIter++); } else { infoIter++; } @@ -42,11 +43,12 @@ const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() { if (fsmRes.step == TransactionStep::IDLE) { // To decrease the already high complexity of the software, all packets arriving before // a metadata PDU are deleted. - for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) { - fp.tcStore->deleteData(infoIter->storeId); + for (auto infoIter = destParams.packetListRef.begin(); + infoIter != destParams.packetListRef.end();) { + fsfwParams.tcStore->deleteData(infoIter->storeId); infoIter++; } - dp.packetListRef.clear(); + destParams.packetListRef.clear(); } if (fsmRes.step != TransactionStep::IDLE) { @@ -54,21 +56,22 @@ const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() { } return updateFsmRes(errorIdx); } - if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) { + if (fsmRes.state == CfdpState::BUSY_CLASS_1_NACKED) { if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) { - for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) { + for (auto infoIter = destParams.packetListRef.begin(); + infoIter != destParams.packetListRef.end();) { if (infoIter->pduType == PduType::FILE_DATA) { result = handleFileDataPdu(*infoIter); checkAndHandleError(result, errorIdx); // Store data was deleted in PDU handler because a store guard is used - dp.packetListRef.erase(infoIter++); + destParams.packetListRef.erase(infoIter++); } else if (infoIter->pduType == PduType::FILE_DIRECTIVE and infoIter->directiveType == FileDirective::EOF_DIRECTIVE) { // TODO: Support for check timer missing result = handleEofPdu(*infoIter); checkAndHandleError(result, errorIdx); // Store data was deleted in PDU handler because a store guard is used - dp.packetListRef.erase(infoIter++); + destParams.packetListRef.erase(infoIter++); } else { infoIter++; } @@ -85,7 +88,7 @@ const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() { } return updateFsmRes(errorIdx); } - if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) { + if (fsmRes.state == CfdpState::BUSY_CLASS_2_ACKED) { // TODO: Will be implemented at a later stage #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "CFDP state machine for acknowledged mode not implemented yet" << std::endl; @@ -95,29 +98,29 @@ const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() { } ReturnValue_t cfdp::DestHandler::passPacket(PacketInfo packet) { - if (dp.packetListRef.full()) { + if (destParams.packetListRef.full()) { return FAILED; } - dp.packetListRef.push_back(packet); + destParams.packetListRef.push_back(packet); return OK; } ReturnValue_t cfdp::DestHandler::initialize() { - if (fp.tmStore == nullptr) { - fp.tmStore = ObjectManager::instance()->get(objects::TM_STORE); - if (fp.tmStore == nullptr) { + if (fsfwParams.tmStore == nullptr) { + fsfwParams.tmStore = ObjectManager::instance()->get(objects::TM_STORE); + if (fsfwParams.tmStore == nullptr) { return FAILED; } } - if (fp.tcStore == nullptr) { - fp.tcStore = ObjectManager::instance()->get(objects::TC_STORE); - if (fp.tcStore == nullptr) { + if (fsfwParams.tcStore == nullptr) { + fsfwParams.tcStore = ObjectManager::instance()->get(objects::TC_STORE); + if (fsfwParams.tcStore == nullptr) { return FAILED; } } - if (fp.msgQueue == nullptr) { + if (fsfwParams.msgQueue == nullptr) { return FAILED; } return OK; @@ -125,18 +128,16 @@ ReturnValue_t cfdp::DestHandler::initialize() { ReturnValue_t cfdp::DestHandler::handleMetadataPdu(const PacketInfo& info) { // Process metadata PDU - auto constAccessorPair = fp.tcStore->getData(info.storeId); + auto constAccessorPair = fsfwParams.tcStore->getData(info.storeId); if (constAccessorPair.first != OK) { // TODO: This is not a CFDP error. Event and/or warning? return constAccessorPair.first; } cfdp::StringLv sourceFileName; cfdp::StringLv destFileName; - MetadataInfo metadataInfo(tp.fileSize, sourceFileName, destFileName); - cfdp::Tlv* tlvArrayAsPtr = tlvVec.data(); - metadataInfo.setOptionsArray(&tlvArrayAsPtr, std::nullopt, tlvVec.size()); + MetadataGenericInfo metadataInfo(transactionParams.fileSize); MetadataPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), - metadataInfo); + metadataInfo, tlvVec.data(), tlvVec.size()); ReturnValue_t result = reader.parseData(); // TODO: The standard does not really specify what happens if this kind of error happens // I think it might be a good idea to cache some sort of error code, which @@ -145,18 +146,17 @@ ReturnValue_t cfdp::DestHandler::handleMetadataPdu(const PacketInfo& info) { return handleMetadataParseError(result, constAccessorPair.second.data(), constAccessorPair.second.size()); } - return startTransaction(reader, metadataInfo); + return startTransaction(reader); } ReturnValue_t cfdp::DestHandler::handleFileDataPdu(const cfdp::PacketInfo& info) { // Process file data PDU - auto constAccessorPair = fp.tcStore->getData(info.storeId); + auto constAccessorPair = fsfwParams.tcStore->getData(info.storeId); if (constAccessorPair.first != OK) { // TODO: This is not a CFDP error. Event and/or warning? return constAccessorPair.first; } - cfdp::FileSize offset; - FileDataInfo fdInfo(offset); + FileDataInfo fdInfo; FileDataReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), fdInfo); ReturnValue_t result = reader.parseData(); if (result != OK) { @@ -164,46 +164,46 @@ ReturnValue_t cfdp::DestHandler::handleFileDataPdu(const cfdp::PacketInfo& info) } size_t fileSegmentLen = 0; const uint8_t* fileData = fdInfo.getFileData(&fileSegmentLen); - FileOpParams fileOpParams(tp.destName.data(), fileSegmentLen); - fileOpParams.offset = offset.value(); - if (dp.cfg.indicCfg.fileSegmentRecvIndicRequired) { + FileOpParams fileOpParams(transactionParams.destName.data(), fileSegmentLen); + fileOpParams.offset = fdInfo.getOffset().value(); + if (destParams.cfg.indicCfg.fileSegmentRecvIndicRequired) { FileSegmentRecvdParams segParams; - segParams.offset = offset.value(); - segParams.id = tp.transactionId; + segParams.offset = fdInfo.getOffset().value(); + segParams.id = transactionParams.transactionId; segParams.length = fileSegmentLen; segParams.recContState = fdInfo.getRecordContinuationState(); size_t segmentMetadatLen = 0; auto* segMetadata = fdInfo.getSegmentMetadata(&segmentMetadatLen); segParams.segmentMetadata = {segMetadata, segmentMetadatLen}; - dp.user.fileSegmentRecvdIndication(segParams); + destParams.user.fileSegmentRecvdIndication(segParams); } - result = dp.user.vfs.writeToFile(fileOpParams, fileData); + result = destParams.user.vfs.writeToFile(fileOpParams, fileData); if (result != returnvalue::OK) { // TODO: Proper Error handling #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "cfdp::DestHandler: VFS file write error with code 0x" << std::hex << std::setw(2) << result << std::endl; #endif - tp.vfsErrorCount++; - if (tp.vfsErrorCount < 3) { + transactionParams.vfsErrorCount++; + if (transactionParams.vfsErrorCount < 3) { // TODO: Provide execution step as parameter - fp.eventReporter->forwardEvent(events::FILESTORE_ERROR, static_cast(fsmRes.step), - result); + fsfwParams.eventReporter->forwardEvent(events::FILESTORE_ERROR, + static_cast(fsmRes.step), result); } return result; } else { - tp.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE; - tp.vfsErrorCount = 0; + transactionParams.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE; + transactionParams.vfsErrorCount = 0; } - if (offset.value() + fileSegmentLen > tp.progress) { - tp.progress = offset.value() + fileSegmentLen; + if (fdInfo.getOffset().value() + fileSegmentLen > transactionParams.progress) { + transactionParams.progress = fdInfo.getOffset().value() + fileSegmentLen; } return result; } ReturnValue_t cfdp::DestHandler::handleEofPdu(const cfdp::PacketInfo& info) { // Process EOF PDU - auto constAccessorPair = fp.tcStore->getData(info.storeId); + auto constAccessorPair = fsfwParams.tcStore->getData(info.storeId); if (constAccessorPair.first != OK) { // TODO: This is not a CFDP error. Event and/or warning? return constAccessorPair.first; @@ -216,21 +216,21 @@ ReturnValue_t cfdp::DestHandler::handleEofPdu(const cfdp::PacketInfo& info) { } // TODO: Error handling if (eofInfo.getConditionCode() == ConditionCode::NO_ERROR) { - tp.crc = eofInfo.getChecksum(); + transactionParams.crc = eofInfo.getChecksum(); uint64_t fileSizeFromEof = eofInfo.getFileSize().value(); // CFDP 4.6.1.2.9: Declare file size error if progress exceeds file size - if (fileSizeFromEof > tp.progress) { + if (fileSizeFromEof > transactionParams.progress) { // TODO: File size error } - tp.fileSize.setFileSize(fileSizeFromEof, std::nullopt); + transactionParams.fileSize.setFileSize(fileSizeFromEof, std::nullopt); } - if (dp.cfg.indicCfg.eofRecvIndicRequired) { - dp.user.eofRecvIndication(getTransactionId()); + if (destParams.cfg.indicCfg.eofRecvIndicRequired) { + destParams.user.eofRecvIndication(getTransactionId()); } if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) { - if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) { + if (fsmRes.state == CfdpState::BUSY_CLASS_1_NACKED) { fsmRes.step = TransactionStep::TRANSFER_COMPLETION; - } else if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) { + } else if (fsmRes.state == CfdpState::BUSY_CLASS_2_ACKED) { fsmRes.step = TransactionStep::SENDING_ACK_PDU; } } @@ -260,7 +260,7 @@ ReturnValue_t cfdp::DestHandler::handleMetadataParseError(ReturnValue_t result, cfdp::EntityId destId; headerReader.getDestId(destId); RemoteEntityCfg* remoteCfg; - if (not dp.remoteCfgTable.getRemoteCfg(destId, &remoteCfg)) { + if (not destParams.remoteCfgTable.getRemoteCfg(destId, &remoteCfg)) { // TODO: No remote config for dest ID. I consider this a configuration error, which is not // covered by the standard. // Warning or error, yield or cache appropriate returnvalue @@ -274,51 +274,57 @@ ReturnValue_t cfdp::DestHandler::handleMetadataParseError(ReturnValue_t result, return returnvalue::FAILED; } -ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader, MetadataInfo& info) { - if (fsmRes.state != CfdpStates::IDLE) { +ReturnValue_t cfdp::DestHandler::startTransaction(const MetadataPduReader& reader) { + if (fsmRes.state != CfdpState::IDLE) { // According to standard, discard metadata PDU if we are busy return OK; } ReturnValue_t result = OK; size_t sourceNameSize = 0; - const uint8_t* sourceNamePtr = info.getSourceFileName().getValue(&sourceNameSize); - if (sourceNameSize + 1 > tp.sourceName.size()) { - fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "source filename too large"); - return FAILED; + if (not reader.getSourceFileName().isEmpty()) { + const uint8_t* sourceNamePtr = reader.getSourceFileName().getValue(&sourceNameSize); + if (sourceNameSize + 1 > transactionParams.sourceName.size()) { + fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "source filename too large"); + return FAILED; + } + std::memcpy(transactionParams.sourceName.data(), sourceNamePtr, sourceNameSize); + transactionParams.sourceName[sourceNameSize] = '\0'; } - std::memcpy(tp.sourceName.data(), sourceNamePtr, sourceNameSize); - tp.sourceName[sourceNameSize] = '\0'; size_t destNameSize = 0; - const uint8_t* destNamePtr = info.getDestFileName().getValue(&destNameSize); - if (destNameSize + 1 > tp.destName.size()) { - fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "dest filename too large"); - return FAILED; + if (not reader.getDestFileName().isEmpty()) { + const uint8_t* destNamePtr = reader.getDestFileName().getValue(&destNameSize); + if (destNameSize + 1 > transactionParams.destName.size()) { + fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "dest filename too large"); + return FAILED; + } + std::memcpy(transactionParams.destName.data(), destNamePtr, destNameSize); + transactionParams.destName[destNameSize] = '\0'; } - std::memcpy(tp.destName.data(), destNamePtr, destNameSize); - tp.destName[destNameSize] = '\0'; + transactionParams.metadataOnly = true; // If both dest name size and source name size are 0, we are dealing with a metadata only PDU, // so there is no need to create a file or truncate an existing file if (destNameSize > 0 and sourceNameSize > 0) { - FilesystemParams fparams(tp.destName.data()); + transactionParams.metadataOnly = false; + FilesystemParams fparams(transactionParams.destName.data()); // handling to allow only specifying target directory. Example: // Source path /test/hello.txt, dest path /tmp -> dest path /tmp/hello.txt - if (dp.user.vfs.isDirectory(tp.destName.data())) { + if (destParams.user.vfs.isDirectory(transactionParams.destName.data())) { result = tryBuildingAbsoluteDestName(destNameSize); if (result != OK) { return result; } } - if (dp.user.vfs.fileExists(fparams)) { - result = dp.user.vfs.truncateFile(fparams); + if (destParams.user.vfs.fileExists(fparams)) { + result = destParams.user.vfs.truncateFile(fparams); if (result != returnvalue::OK) { fileErrorHandler(events::FILESTORE_ERROR, result, "file truncation error"); return FAILED; // TODO: Relevant for filestore rejection error? } } else { - result = dp.user.vfs.createFile(fparams); + result = destParams.user.vfs.createFile(fparams); if (result != OK) { fileErrorHandler(events::FILESTORE_ERROR, result, "file creation error"); return FAILED; @@ -328,120 +334,135 @@ ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader, Met } EntityId sourceId; reader.getSourceId(sourceId); - if (not dp.remoteCfgTable.getRemoteCfg(sourceId, &tp.remoteCfg)) { + if (not destParams.remoteCfgTable.getRemoteCfg(sourceId, &transactionParams.remoteCfg)) { // TODO: Warning, event etc. #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "cfdp::DestHandler" << __func__ << ": No remote configuration found for destination ID " - << tp.pduConf.sourceId.getValue() << std::endl; + << transactionParams.pduConf.sourceId.getValue() << std::endl; #endif return FAILED; } - fsmRes.step = TransactionStep::TRANSACTION_START; if (reader.getTransmissionMode() == TransmissionMode::UNACKNOWLEDGED) { - fsmRes.state = CfdpStates::BUSY_CLASS_1_NACKED; + fsmRes.state = CfdpState::BUSY_CLASS_1_NACKED; } else if (reader.getTransmissionMode() == TransmissionMode::ACKNOWLEDGED) { - fsmRes.state = CfdpStates::BUSY_CLASS_2_ACKED; + fsmRes.state = CfdpState::BUSY_CLASS_2_ACKED; } - tp.checksumType = info.getChecksumType(); - tp.closureRequested = info.isClosureRequested(); - reader.fillConfig(tp.pduConf); - tp.pduConf.direction = Direction::TOWARDS_SENDER; - tp.transactionId.entityId = tp.pduConf.sourceId; - tp.transactionId.seqNum = tp.pduConf.seqNum; - fsmRes.step = TransactionStep::RECEIVING_FILE_DATA_PDUS; - MetadataRecvdParams params(tp.transactionId, tp.pduConf.sourceId); - params.fileSize = tp.fileSize.getSize(); - params.destFileName = tp.destName.data(); - params.sourceFileName = tp.sourceName.data(); - params.msgsToUserArray = dynamic_cast(userTlvVec.data()); - params.msgsToUserLen = info.getOptionsLen(); - dp.user.metadataRecvdIndication(params); + if (transactionParams.metadataOnly) { + fsmRes.step = TransactionStep::TRANSFER_COMPLETION; + } else { + // Kind of ugly, make FSM working on packet per packet basis.. + fsmRes.step = TransactionStep::TRANSACTION_START; + fsmRes.step = TransactionStep::RECEIVING_FILE_DATA_PDUS; + } + auto& info = reader.getGenericInfo(); + transactionParams.checksumType = info.getChecksumType(); + transactionParams.closureRequested = info.isClosureRequested(); + reader.fillConfig(transactionParams.pduConf); + transactionParams.pduConf.direction = Direction::TOWARDS_SENDER; + transactionParams.transactionId.entityId = transactionParams.pduConf.sourceId; + transactionParams.transactionId.seqNum = transactionParams.pduConf.seqNum; + transactionParams.fileSize = info.getFileSize(); + MetadataRecvdParams params(transactionParams.transactionId, transactionParams.pduConf.sourceId, + transactionParams.fileSize); + params.destFileName = transactionParams.destName.data(); + params.sourceFileName = transactionParams.sourceName.data(); + params.numberOfMsgsToUser = 0; + for (const auto& opt : tlvVec) { + if (opt.getType() == TlvType::MSG_TO_USER) { + msgToUserVec[params.numberOfMsgsToUser] = + MessageToUserTlv(opt.getValue(), opt.getLengthField()); + params.numberOfMsgsToUser++; + } + } + params.msgsToUserArray = msgToUserVec.data(); + destParams.user.metadataRecvdIndication(params); return result; } -cfdp::CfdpStates cfdp::DestHandler::getCfdpState() const { return fsmRes.state; } +cfdp::CfdpState cfdp::DestHandler::getCfdpState() const { return fsmRes.state; } ReturnValue_t cfdp::DestHandler::handleTransferCompletion() { ReturnValue_t result; - if (tp.checksumType != ChecksumType::NULL_CHECKSUM) { + if (transactionParams.checksumType != ChecksumType::NULL_CHECKSUM) { result = checksumVerification(); if (result != OK) { // TODO: Warning / error handling? } } else { - tp.conditionCode = ConditionCode::NO_ERROR; + transactionParams.conditionCode = ConditionCode::NO_ERROR; } result = noticeOfCompletion(); if (result != OK) { } - if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) { - if (tp.closureRequested) { + if (fsmRes.state == CfdpState::BUSY_CLASS_1_NACKED) { + if (transactionParams.closureRequested) { fsmRes.step = TransactionStep::SENDING_FINISHED_PDU; } else { finish(); } - } else if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) { + } else if (fsmRes.state == CfdpState::BUSY_CLASS_2_ACKED) { fsmRes.step = TransactionStep::SENDING_FINISHED_PDU; } return OK; } ReturnValue_t cfdp::DestHandler::tryBuildingAbsoluteDestName(size_t destNameSize) { - char baseNameBuf[tp.destName.size()]{}; - FilesystemParams fparamsSrc(tp.sourceName.data()); + // A path may only have a maximum of 256 characters in CFDP, so this buffer should be sufficient + // for all use-cases. + char baseNameBuf[512]{}; + FilesystemParams fparamsSrc(transactionParams.sourceName.data()); size_t baseNameLen = 0; - ReturnValue_t result = - dp.user.vfs.getBaseFilename(fparamsSrc, baseNameBuf, sizeof(baseNameBuf), baseNameLen); + ReturnValue_t result = destParams.user.vfs.getBaseFilename(fparamsSrc, baseNameBuf, + sizeof(baseNameBuf), baseNameLen); if (result != returnvalue::OK or baseNameLen == 0) { fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "error retrieving source base name"); return FAILED; } // Destination name + slash + base name + null termination - if (destNameSize + 1 + baseNameLen + 1 > tp.destName.size()) { + if (destNameSize + 1 + baseNameLen + 1 > transactionParams.destName.size()) { fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "dest filename too large after adding source base name"); return FAILED; } - tp.destName[destNameSize++] = '/'; - std::memcpy(tp.destName.data() + destNameSize, baseNameBuf, baseNameLen); + transactionParams.destName[destNameSize++] = '/'; + std::memcpy(transactionParams.destName.data() + destNameSize, baseNameBuf, baseNameLen); destNameSize += baseNameLen; - tp.destName[destNameSize++] = '\0'; + transactionParams.destName[destNameSize++] = '\0'; return OK; } -void cfdp::DestHandler::fileErrorHandler(Event event, ReturnValue_t result, const char* info) { - fp.eventReporter->forwardEvent(events::FILENAME_TOO_LARGE_ERROR, - static_cast(fsmRes.step), result); +void cfdp::DestHandler::fileErrorHandler(Event event, ReturnValue_t result, + const char* info) const { + fsfwParams.eventReporter->forwardEvent(event, static_cast(fsmRes.step), result); #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "cfdp::DestHandler: " << info << std::endl; #endif } void cfdp::DestHandler::finish() { - tp.reset(); - dp.packetListRef.clear(); - fsmRes.state = CfdpStates::IDLE; + transactionParams.reset(); + destParams.packetListRef.clear(); + fsmRes.state = CfdpState::IDLE; fsmRes.step = TransactionStep::IDLE; } ReturnValue_t cfdp::DestHandler::checksumVerification() { std::array buf{}; - // TODO: Checksum verification and notice of completion etl::crc32 crcCalc; uint64_t currentOffset = 0; - FileOpParams params(tp.destName.data(), tp.fileSize.value()); - while (currentOffset < tp.fileSize.value()) { + FileOpParams params(transactionParams.destName.data(), transactionParams.fileSize.value()); + while (currentOffset < transactionParams.fileSize.value()) { uint64_t readLen; - if (currentOffset + buf.size() > tp.fileSize.value()) { - readLen = tp.fileSize.value() - currentOffset; + if (currentOffset + buf.size() > transactionParams.fileSize.value()) { + readLen = transactionParams.fileSize.value() - currentOffset; } else { readLen = buf.size(); } if (readLen > 0) { params.offset = currentOffset; params.size = readLen; - auto result = dp.user.vfs.readFromFile(params, buf.data(), buf.size()); + auto result = destParams.user.vfs.readFromFile(params, buf.data(), buf.size()); if (result != OK) { // TODO: I think this is a case for a filestore rejection, but it might sense to print // a warning or trigger an event because this should generally not happen @@ -453,40 +474,43 @@ ReturnValue_t cfdp::DestHandler::checksumVerification() { } uint32_t value = crcCalc.value(); - if (value == tp.crc) { - tp.conditionCode = ConditionCode::NO_ERROR; - tp.deliveryCode = FileDeliveryCode::DATA_COMPLETE; + if (value == transactionParams.crc) { + transactionParams.conditionCode = ConditionCode::NO_ERROR; + transactionParams.deliveryCode = FileDeliveryCode::DATA_COMPLETE; } else { // TODO: Proper error handling #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "CRC check for file " << tp.destName.data() << " failed" << std::endl; + sif::warning << "CRC check for file " << transactionParams.destName.data() << " failed" + << std::endl; #endif - tp.conditionCode = ConditionCode::FILE_CHECKSUM_FAILURE; + transactionParams.conditionCode = ConditionCode::FILE_CHECKSUM_FAILURE; } return OK; } ReturnValue_t cfdp::DestHandler::noticeOfCompletion() { - if (dp.cfg.indicCfg.transactionFinishedIndicRequired) { - TransactionFinishedParams params(tp.transactionId, tp.conditionCode, tp.deliveryCode, - tp.deliveryStatus); - dp.user.transactionFinishedIndication(params); + if (destParams.cfg.indicCfg.transactionFinishedIndicRequired) { + TransactionFinishedParams params( + transactionParams.transactionId, transactionParams.conditionCode, + transactionParams.deliveryCode, transactionParams.deliveryStatus); + destParams.user.transactionFinishedIndication(params); } return OK; } ReturnValue_t cfdp::DestHandler::sendFinishedPdu() { - FinishedInfo info(tp.conditionCode, tp.deliveryCode, tp.deliveryStatus); - FinishPduCreator finishedPdu(tp.pduConf, info); + FinishedInfo info(transactionParams.conditionCode, transactionParams.deliveryCode, + transactionParams.deliveryStatus); + FinishPduCreator finishedPdu(transactionParams.pduConf, info); store_address_t storeId; uint8_t* dataPtr = nullptr; ReturnValue_t result = - fp.tmStore->getFreeElement(&storeId, finishedPdu.getSerializedSize(), &dataPtr); + fsfwParams.tmStore->getFreeElement(&storeId, finishedPdu.getSerializedSize(), &dataPtr); if (result != OK) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "cfdp::DestHandler:sendFinishedPdu: Getting store slot failed" << std::endl; #endif - fp.eventReporter->forwardEvent(events::STORE_ERROR, result, 0); + fsfwParams.eventReporter->forwardEvent(events::STORE_ERROR, result, 0); return result; } size_t serLen = 0; @@ -496,16 +520,16 @@ ReturnValue_t cfdp::DestHandler::sendFinishedPdu() { sif::warning << "cfdp::DestHandler::sendFinishedPdu: Serializing Finished PDU failed" << std::endl; #endif - fp.eventReporter->forwardEvent(events::SERIALIZATION_ERROR, result, 0); + fsfwParams.eventReporter->forwardEvent(events::SERIALIZATION_ERROR, result, 0); return result; } TmTcMessage msg(storeId); - result = fp.msgQueue->sendMessage(fp.packetDest.getReportReceptionQueue(), &msg); + result = fsfwParams.msgQueue->sendMessage(fsfwParams.packetDest.getReportReceptionQueue(), &msg); if (result != OK) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "cfdp::DestHandler::sendFinishedPdu: Sending PDU failed" << std::endl; #endif - fp.eventReporter->forwardEvent(events::MSG_QUEUE_ERROR, result, 0); + fsfwParams.eventReporter->forwardEvent(events::MSG_QUEUE_ERROR, result, 0); return result; } fsmRes.packetsSent++; @@ -525,7 +549,9 @@ const cfdp::DestHandler::FsmResult& cfdp::DestHandler::updateFsmRes(uint8_t erro return fsmRes; } -const cfdp::TransactionId& cfdp::DestHandler::getTransactionId() const { return tp.transactionId; } +const cfdp::TransactionId& cfdp::DestHandler::getTransactionId() const { + return transactionParams.transactionId; +} void cfdp::DestHandler::checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx) { if (result != OK and errorIdx < 3) { @@ -534,13 +560,15 @@ void cfdp::DestHandler::checkAndHandleError(ReturnValue_t result, uint8_t& error } } -void cfdp::DestHandler::setMsgQueue(MessageQueueIF& queue) { fp.msgQueue = &queue; } +void cfdp::DestHandler::setMsgQueue(MessageQueueIF& queue) { fsfwParams.msgQueue = &queue; } void cfdp::DestHandler::setEventReporter(EventReportingProxyIF& reporter) { - fp.eventReporter = &reporter; + fsfwParams.eventReporter = &reporter; } -const cfdp::DestHandlerParams& cfdp::DestHandler::getDestHandlerParams() const { return dp; } +const cfdp::DestHandlerParams& cfdp::DestHandler::getDestHandlerParams() const { + return destParams; +} -StorageManagerIF* cfdp::DestHandler::getTmStore() const { return fp.tmStore; } -StorageManagerIF* cfdp::DestHandler::getTcStore() const { return fp.tcStore; } +StorageManagerIF* cfdp::DestHandler::getTmStore() const { return fsfwParams.tmStore; } +StorageManagerIF* cfdp::DestHandler::getTcStore() const { return fsfwParams.tcStore; } diff --git a/src/fsfw/cfdp/handler/DestHandler.h b/src/fsfw/cfdp/handler/DestHandler.h index 9057b3f5..370cb274 100644 --- a/src/fsfw/cfdp/handler/DestHandler.h +++ b/src/fsfw/cfdp/handler/DestHandler.h @@ -13,6 +13,7 @@ #include "fsfw/cfdp/handler/mib.h" #include "fsfw/cfdp/pdu/MetadataPduReader.h" #include "fsfw/cfdp/pdu/PduConfig.h" +#include "fsfw/cfdp/tlv/MessageToUserTlv.h" #include "fsfw/container/DynamicFIFO.h" #include "fsfw/storagemanager/StorageManagerIF.h" #include "fsfw/storagemanager/storeAddress.h" @@ -20,23 +21,9 @@ namespace cfdp { -struct PacketInfo { - PacketInfo(PduType type, store_address_t storeId, - std::optional directive = std::nullopt) - : pduType(type), directiveType(directive), storeId(storeId) {} - - PduType pduType = PduType::FILE_DATA; - std::optional directiveType = FileDirective::INVALID_DIRECTIVE; - store_address_t storeId = store_address_t::invalid(); - PacketInfo() = default; -}; - template using LostSegmentsList = etl::set, SIZE>; -template -using PacketInfoList = etl::list; using LostSegmentsListBase = etl::iset>; -using PacketInfoListBase = etl::ilist; struct DestHandlerParams { DestHandlerParams(LocalEntityCfg cfg, UserBase& user, RemoteConfigTableIF& remoteCfgTable, @@ -44,6 +31,9 @@ struct DestHandlerParams { // TODO: This container can potentially take tons of space. For a better // memory efficient implementation, an additional abstraction could be // be used so users can use uint32_t as the pair type + // TODO: Actually, we can provide a better abstraction via interface, which + // allows using something like a bounded map. This simplifies + // the implementation significantly. LostSegmentsListBase& lostSegmentsContainer) : cfg(std::move(cfg)), user(user), @@ -57,31 +47,10 @@ struct DestHandlerParams { PacketInfoListBase& packetListRef; LostSegmentsListBase& lostSegmentsContainer; - uint8_t maxTlvsInOnePdu = 10; + uint8_t maxTlvsInOnePdu = 20; size_t maxFilenameLen = 255; }; -struct FsfwParams { - FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue, - EventReportingProxyIF* eventReporter, StorageManagerIF& tcStore, - StorageManagerIF& tmStore) - : FsfwParams(packetDest, msgQueue, eventReporter) { - this->tcStore = &tcStore; - this->tmStore = &tmStore; - } - - FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue, - EventReportingProxyIF* eventReporter) - : packetDest(packetDest), msgQueue(msgQueue), eventReporter(eventReporter) {} - AcceptsTelemetryIF& packetDest; - MessageQueueIF* msgQueue; - EventReportingProxyIF* eventReporter = nullptr; - StorageManagerIF* tcStore = nullptr; - StorageManagerIF* tmStore = nullptr; -}; - -enum class CallStatus { DONE, CALL_AFTER_DELAY, CALL_AGAIN }; - class DestHandler { public: enum class TransactionStep : uint8_t { @@ -98,7 +67,7 @@ class DestHandler { ReturnValue_t result = returnvalue::OK; CallStatus callStatus = CallStatus::CALL_AFTER_DELAY; TransactionStep step = TransactionStep::IDLE; - CfdpStates state = CfdpStates::IDLE; + CfdpState state = CfdpState::IDLE; uint32_t packetsSent = 0; uint8_t errors = 0; std::array errorCodes = {}; @@ -123,7 +92,7 @@ class DestHandler { * - @c returnvalue::OK State machine OK for this execution cycle * - @c CALL_FSM_AGAIN State machine should be called again. */ - const FsmResult& performStateMachine(); + const FsmResult& stateMachine(); void setMsgQueue(MessageQueueIF& queue); void setEventReporter(EventReportingProxyIF& reporter); @@ -131,7 +100,7 @@ class DestHandler { ReturnValue_t initialize(); - [[nodiscard]] CfdpStates getCfdpState() const; + [[nodiscard]] CfdpState getCfdpState() const; [[nodiscard]] TransactionStep getTransactionStep() const; [[nodiscard]] const TransactionId& getTransactionId() const; [[nodiscard]] const DestHandlerParams& getDestHandlerParams() const; @@ -156,17 +125,19 @@ class DestHandler { crc = 0; progress = 0; remoteCfg = nullptr; + metadataOnly = false; closureRequested = false; vfsErrorCount = 0; checksumType = ChecksumType::NULL_CHECKSUM; } + bool metadataOnly = false; ChecksumType checksumType = ChecksumType::NULL_CHECKSUM; bool closureRequested = false; uint16_t vfsErrorCount = 0; std::vector sourceName; std::vector destName; - cfdp::FileSize fileSize; + cfdp::Fss fileSize; TransactionId transactionId; PduConfig pduConf; ConditionCode conditionCode = ConditionCode::NO_ERROR; @@ -178,13 +149,13 @@ class DestHandler { }; std::vector tlvVec; - std::vector userTlvVec; - DestHandlerParams dp; - FsfwParams fp; - TransactionParams tp; + std::vector msgToUserVec; + TransactionParams transactionParams; + DestHandlerParams destParams; + cfdp::FsfwParams fsfwParams; FsmResult fsmRes; - ReturnValue_t startTransaction(MetadataPduReader& reader, MetadataInfo& info); + ReturnValue_t startTransaction(const MetadataPduReader& reader); ReturnValue_t handleMetadataPdu(const PacketInfo& info); ReturnValue_t handleFileDataPdu(const PacketInfo& info); ReturnValue_t handleEofPdu(const PacketInfo& info); @@ -195,7 +166,7 @@ class DestHandler { ReturnValue_t sendFinishedPdu(); ReturnValue_t noticeOfCompletion(); ReturnValue_t checksumVerification(); - void fileErrorHandler(Event event, ReturnValue_t result, const char* info); + void fileErrorHandler(Event event, ReturnValue_t result, const char* info) const; const FsmResult& updateFsmRes(uint8_t errors); void checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx); void finish(); diff --git a/src/fsfw/cfdp/handler/PutRequest.cpp b/src/fsfw/cfdp/handler/PutRequest.cpp new file mode 100644 index 00000000..a1abcc14 --- /dev/null +++ b/src/fsfw/cfdp/handler/PutRequest.cpp @@ -0,0 +1,201 @@ +#include "PutRequest.h" + +using namespace returnvalue; + +cfdp::PutRequest::PutRequest(cfdp::EntityId destId, const uint8_t *msgsToUser, + size_t msgsToUserTotalSize, const uint8_t *fsRequests, + size_t fsRequestsSize) + : destId(std::move(destId)), + metadataOnly(true), + msgsToUsersTotalSize(msgsToUserTotalSize), + msgsToUserStartPtr(msgsToUser), + fsRequestsTotalSize(fsRequestsSize), + fsRequestStartPtr(fsRequests) {} + +cfdp::PutRequest::PutRequest(cfdp::EntityId destId, cfdp::StringLv &sourceName, + cfdp::StringLv &destName) + : destId(std::move(destId)), sourceName(std::move(sourceName)), destName(std::move(destName)) {} + +[[nodiscard]] bool cfdp::PutRequest::isMetadataOnly() const { return metadataOnly; } + +ReturnValue_t cfdp::PutRequest::serialize(uint8_t **buffer, size_t *size, size_t maxSize, + SerializeIF::Endianness streamEndianness) const { + if (buffer == nullptr or size == nullptr) { + return FAILED; + } + if (*size + getSerializedSize() > maxSize) { + return SerializeIF::BUFFER_TOO_SHORT; + } + ReturnValue_t result = destId.serializeAsLv(buffer, size, maxSize); + if (result != OK) { + return result; + } + result = SerializeAdapter::serialize(&metadataOnly, buffer, size, maxSize, streamEndianness); + if (result != OK) { + return result; + } + if (!metadataOnly) { + result = sourceName.serialize(buffer, size, maxSize, streamEndianness); + if (result != OK) { + return result; + } + result = destName.serialize(buffer, size, maxSize, streamEndianness); + if (result != OK) { + return result; + } + result = + SerializeAdapter::serialize(&hasTransmissionMode, buffer, size, maxSize, streamEndianness); + if (result != OK) { + return result; + } + result = + SerializeAdapter::serialize(&transmissionMode, buffer, size, maxSize, streamEndianness); + if (result != OK) { + return result; + } + result = + SerializeAdapter::serialize(&hasClosureRequested, buffer, size, maxSize, streamEndianness); + if (result != OK) { + return result; + } + result = + SerializeAdapter::serialize(&closureRequested, buffer, size, maxSize, streamEndianness); + if (result != OK) { + return result; + } + } + result = + SerializeAdapter::serialize(&msgsToUsersTotalSize, buffer, size, maxSize, streamEndianness); + if (result != OK) { + return result; + } + std::memcpy(*buffer, msgsToUserStartPtr, msgsToUsersTotalSize); + *buffer += msgsToUsersTotalSize; + *size += msgsToUsersTotalSize; + + result = + SerializeAdapter::serialize(&fsRequestsTotalSize, buffer, size, maxSize, streamEndianness); + if (result != OK) { + return result; + } + std::memcpy(*buffer, fsRequestStartPtr, fsRequestsTotalSize); + *buffer += fsRequestsTotalSize; + *size += fsRequestsTotalSize; + return OK; +} + +ReturnValue_t cfdp::PutRequest::deSerialize(const uint8_t **buffer, size_t *size, + SerializeIF::Endianness streamEndianness) { + if (buffer == nullptr or size == nullptr) { + return FAILED; + } + ReturnValue_t result = destId.deSerializeFromLv(buffer, size); + if (result != OK) { + return result; + } + result = SerializeAdapter::deSerialize(&metadataOnly, buffer, size, streamEndianness); + if (result != OK) { + return result; + } + if (!metadataOnly) { + result = sourceName.deSerialize(buffer, size, streamEndianness); + if (result != OK) { + return result; + } + result = destName.deSerialize(buffer, size, streamEndianness); + if (result != OK) { + return result; + } + result = SerializeAdapter::deSerialize(&hasTransmissionMode, buffer, size, streamEndianness); + if (result != OK) { + return result; + } + result = SerializeAdapter::deSerialize(&transmissionMode, buffer, size, streamEndianness); + if (result != OK) { + return result; + } + result = SerializeAdapter::deSerialize(&hasClosureRequested, buffer, size, streamEndianness); + if (result != OK) { + return result; + } + result = SerializeAdapter::deSerialize(&closureRequested, buffer, size, streamEndianness); + if (result != OK) { + return result; + } + } + result = SerializeAdapter::deSerialize(&msgsToUsersTotalSize, buffer, size, streamEndianness); + if (result != OK) { + return result; + } + msgsToUserStartPtr = *buffer; + *buffer += msgsToUsersTotalSize; + *size += msgsToUsersTotalSize; + + result = SerializeAdapter::deSerialize(&fsRequestsTotalSize, buffer, size, streamEndianness); + if (result != OK) { + return result; + } + fsRequestStartPtr = *buffer; + *buffer += fsRequestsTotalSize; + *size += fsRequestsTotalSize; + return OK; +} + +size_t cfdp::PutRequest::getSerializedSize() const { + // Entity ID LV (1 leading size byte) and the metadata only flag. + size_t baseSize = 1 + destId.getSerializedSize() + 1; + if (!metadataOnly) { + baseSize += sourceName.getSerializedSize() + destName.getSerializedSize() + 4; + } + baseSize += sizeof(msgsToUsersTotalSize) + msgsToUsersTotalSize + sizeof(fsRequestsTotalSize) + + fsRequestsTotalSize; + return baseSize; +} + +void cfdp::PutRequest::setSourceAndDestName(cfdp::StringLv &sourceName_, + cfdp::StringLv &destName_) { + metadataOnly = false; + this->sourceName = std::move(sourceName_); + this->destName = std::move(destName_); +} + +const cfdp::StringLv &cfdp::PutRequest::getSourceName() const { return sourceName; } + +const cfdp::StringLv &cfdp::PutRequest::getDestName() const { return destName; } + +const cfdp::EntityId &cfdp::PutRequest::getDestId() const { return destId; } + +void cfdp::PutRequest::setDestId(cfdp::EntityId id) { destId = std::move(id); } + +void cfdp::PutRequest::setTransmissionMode(cfdp::TransmissionMode transmissionMode_) { + this->transmissionMode = transmissionMode_; + hasTransmissionMode = true; +} + +void cfdp::PutRequest::clearTransmissionMode() { hasTransmissionMode = false; } + +void cfdp::PutRequest::clearClosureRequest() { hasClosureRequested = false; } + +void cfdp::PutRequest::setClosureRequest(bool closureRequested_) { + this->closureRequested = closureRequested_; + hasClosureRequested = true; +} + +const uint8_t *cfdp::PutRequest::getMessagesToUser(size_t &totalSize) { + totalSize = this->msgsToUsersTotalSize; + return msgsToUserStartPtr; +} + +bool cfdp::PutRequest::getClosureRequested(bool &closureRequested_) const { + if (hasClosureRequested) { + closureRequested_ = this->closureRequested; + } + return hasClosureRequested; +} + +bool cfdp::PutRequest::getTransmissionMode(cfdp::TransmissionMode &mode) const { + if (hasTransmissionMode) { + mode = static_cast(this->transmissionMode); + } + return hasTransmissionMode; +} diff --git a/src/fsfw/cfdp/handler/PutRequest.h b/src/fsfw/cfdp/handler/PutRequest.h new file mode 100644 index 00000000..6bf46c60 --- /dev/null +++ b/src/fsfw/cfdp/handler/PutRequest.h @@ -0,0 +1,82 @@ +#pragma once + +#include +#include + +#include "fsfw/cfdp/VarLenFields.h" +#include "fsfw/cfdp/tlv/FilestoreRequestTlv.h" +#include "fsfw/cfdp/tlv/MessageToUserTlv.h" + +namespace cfdp { + +class PutRequest : public SerializeIF { + public: + /** + * Metadata only constructor. + * @param destId + * @param msgsToUser + * @param msgsToUserTotalSize + * @param fsRequests + * @param fsRequestsSize + */ + PutRequest(EntityId destId, const uint8_t* msgsToUser, size_t msgsToUserTotalSize, + const uint8_t* fsRequests, size_t fsRequestsSize); + /** + * Put request to initiate file transfers. By default, the transmission mode and closure requested + * parameter are not present, thereby being derived from the remote configuration for a + * particular destination ID. + * @param destId + * @param sourceName + * @param destName + */ + PutRequest(EntityId destId, cfdp::StringLv& sourceName, cfdp::StringLv& destName); + + /** + * Default constructor for deserialization. + */ + PutRequest() = default; + + [[nodiscard]] ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + Endianness streamEndianness) const override; + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) override; + [[nodiscard]] size_t getSerializedSize() const override; + void setSourceAndDestName(cfdp::StringLv& sourceName, cfdp::StringLv& destName); + + [[nodiscard]] const cfdp::StringLv& getSourceName() const; + [[nodiscard]] const cfdp::StringLv& getDestName() const; + + void setTransmissionMode(cfdp::TransmissionMode transmissionMode); + void clearTransmissionMode(); + void setClosureRequest(bool closureRequested); + void clearClosureRequest(); + + const uint8_t* getMessagesToUser(size_t& msgSize); + + [[nodiscard]] bool isMetadataOnly() const; + + bool getTransmissionMode(TransmissionMode& mode) const; + bool getClosureRequested(bool& closureRequested) const; + + [[nodiscard]] const EntityId& getDestId() const; + void setDestId(EntityId id); + + private: + EntityId destId; + uint8_t metadataOnly = true; + // Transaction parameters. Omitted if the put request is metadata only. + cfdp::StringLv sourceName; + + cfdp::StringLv destName; + bool hasTransmissionMode = false; + uint8_t transmissionMode = TransmissionMode::UNACKNOWLEDGED; + bool hasClosureRequested = false; + uint8_t closureRequested = false; + // Metadata + size_t msgsToUsersTotalSize = 0; + const uint8_t* msgsToUserStartPtr = nullptr; + size_t fsRequestsTotalSize = 0; + const uint8_t* fsRequestStartPtr = nullptr; +}; + +} // namespace cfdp diff --git a/src/fsfw/cfdp/handler/RemoteConfigTableIF.h b/src/fsfw/cfdp/handler/RemoteConfigTableIF.h index d0e6121d..1c1603c9 100644 --- a/src/fsfw/cfdp/handler/RemoteConfigTableIF.h +++ b/src/fsfw/cfdp/handler/RemoteConfigTableIF.h @@ -16,7 +16,7 @@ class RemoteConfigTableIF { */ class OneRemoteConfigProvider : public RemoteConfigTableIF { public: - explicit OneRemoteConfigProvider(RemoteEntityCfg cfg) : cfg(std::move(cfg)) {} + explicit OneRemoteConfigProvider(RemoteEntityCfg& cfg) : cfg(cfg) {} bool getRemoteCfg(const EntityId& remoteId, cfdp::RemoteEntityCfg** cfg_) override { if (remoteId != cfg.remoteId) { @@ -27,7 +27,7 @@ class OneRemoteConfigProvider : public RemoteConfigTableIF { } private: - RemoteEntityCfg cfg; + RemoteEntityCfg& cfg; }; } // namespace cfdp diff --git a/src/fsfw/cfdp/handler/ReservedMessageParser.cpp b/src/fsfw/cfdp/handler/ReservedMessageParser.cpp new file mode 100644 index 00000000..ffd2fdc6 --- /dev/null +++ b/src/fsfw/cfdp/handler/ReservedMessageParser.cpp @@ -0,0 +1,74 @@ +#include "ReservedMessageParser.h" + +#include "fsfw/cfdp/CfdpMessage.h" +#include "fsfw/cfdp/handler/PutRequest.h" +#include "fsfw/cfdp/tlv/MessageToUserTlv.h" +#include "fsfw/ipc/CommandMessage.h" +#include "fsfw/ipc/QueueFactory.h" + +using namespace returnvalue; + +cfdp::ReservedMessageParser::ReservedMessageParser(StorageManagerIF& ipcStore, + MessageQueueIF& msgQueue, + MessageQueueId_t userDestination) + : msgQueue(msgQueue), ipcStore(ipcStore), userDestination(userDestination) {} + +ReturnValue_t cfdp::ReservedMessageParser::parse(const MessageToUserTlv* msgsToUserArray, + size_t numMsgToUser) { + ReturnValue_t result = returnvalue::OK; + cfdp::StringLv sourceFileName; + cfdp::StringLv destFileName; + PutRequest putRequest; + const uint8_t* currentPtr = nullptr; + size_t deserSize = 0; + bool needToSendPutRequest = false; + for (size_t idx = 0; idx < numMsgToUser; idx++) { + if (&msgsToUserArray[idx] == nullptr) { + continue; + } + uint8_t messageType = 0; + if (msgsToUserArray[idx].isReservedCfdpMessage(messageType, ¤tPtr, deserSize)) { + if (messageType == static_cast(ProxyOpMessageType::PUT_REQUEST)) { + EntityId entityIdLv; + result = entityIdLv.deSerializeFromLv(¤tPtr, &deserSize); + if (result != returnvalue::OK) { + return result; + } + putRequest.setDestId(entityIdLv); + result = + sourceFileName.deSerialize(¤tPtr, &deserSize, SerializeIF::Endianness::NETWORK); + if (result != OK) { + return result; + } + result = + destFileName.deSerialize(¤tPtr, &deserSize, SerializeIF::Endianness::NETWORK); + if (result != OK) { + return result; + } + putRequest.setSourceAndDestName(sourceFileName, destFileName); + needToSendPutRequest = true; + } + } + } + if (needToSendPutRequest) { + store_address_t storeId; + uint8_t* dataPtr; + result = ipcStore.getFreeElement(&storeId, putRequest.getSerializedSize(), &dataPtr); + if (result != OK) { + return result; + } + size_t serLen = 0; + result = putRequest.serialize(&dataPtr, &serLen, putRequest.getSerializedSize(), + SerializeIF::Endianness::MACHINE); + if (result != OK) { + return result; + } + CommandMessage msg; + CfdpMessage::setPutRequest(&msg, storeId); + result = msgQueue.sendMessage(userDestination, &msg); + if (result != OK) { + return result; + } + } + return OK; +} diff --git a/src/fsfw/cfdp/handler/ReservedMessageParser.h b/src/fsfw/cfdp/handler/ReservedMessageParser.h new file mode 100644 index 00000000..2b5c89b2 --- /dev/null +++ b/src/fsfw/cfdp/handler/ReservedMessageParser.h @@ -0,0 +1,27 @@ +#pragma once + +#include "fsfw/cfdp/tlv/MessageToUserTlv.h" +#include "fsfw/ipc/MessageQueueIF.h" +#include "fsfw/storagemanager/StorageManagerIF.h" + +namespace cfdp { + +/** + * This class parses messages to user for special CFDP messages and converts them to appropriate + * CFDP requests sent via the IPC store where applicable. It also provides an API to retrieve + * custom messages which are not special CFDP messages from a provided bytestream. + */ +class ReservedMessageParser { + public: + ReservedMessageParser(StorageManagerIF& ipcStore, MessageQueueIF& msgQueue, + MessageQueueId_t userDestination); + + ReturnValue_t parse(const MessageToUserTlv* msgsToUserArray, size_t numMsgsToUser); + + private: + MessageQueueIF& msgQueue; + StorageManagerIF& ipcStore; + MessageQueueId_t userDestination; +}; + +} // namespace cfdp diff --git a/src/fsfw/cfdp/handler/SourceHandler.cpp b/src/fsfw/cfdp/handler/SourceHandler.cpp index 513b25f3..f0f89607 100644 --- a/src/fsfw/cfdp/handler/SourceHandler.cpp +++ b/src/fsfw/cfdp/handler/SourceHandler.cpp @@ -1 +1,376 @@ #include "SourceHandler.h" + +#include + +#include + +#include "fsfw/cfdp/pdu/EofPduCreator.h" +#include "fsfw/cfdp/pdu/FileDataCreator.h" +#include "fsfw/cfdp/pdu/MetadataPduCreator.h" +#include "fsfw/filesystem/HasFileSystemIF.h" +#include "fsfw/globalfunctions/arrayprinter.h" +#include "fsfw/objectmanager.h" +#include "fsfw/serviceinterface.h" +#include "fsfw/tasks/TaskFactory.h" +#include "fsfw/tmtcservices/TmTcMessage.h" + +using namespace returnvalue; + +cfdp::SourceHandler::SourceHandler(SourceHandlerParams params, FsfwParams fsfwParams) + : sourceParams(std::move(params)), fsfwParams(fsfwParams) { + // The entity ID portion of the transaction ID will always remain fixed. + transactionParams.id.entityId = sourceParams.cfg.localId; + transactionParams.pduConf.sourceId = sourceParams.cfg.localId; + if (sourceParams.seqCountProvider.bitWidth() == 8) { + transactionParams.pduConf.seqNum.setWidth(cfdp::WidthInBytes::ONE_BYTE); + } else if (sourceParams.seqCountProvider.bitWidth() == 16) { + transactionParams.pduConf.seqNum.setWidth(cfdp::WidthInBytes::TWO_BYTES); + } else if (sourceParams.seqCountProvider.bitWidth() == 32) { + transactionParams.pduConf.seqNum.setWidth(cfdp::WidthInBytes::FOUR_BYTES); + } else if (sourceParams.seqCountProvider.bitWidth() == 64) { + transactionParams.pduConf.seqNum.setWidth(cfdp::WidthInBytes::EIGHT_BYTES); + } else { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "cfdp::SourceHandler: Seq count provider bit width " + << sourceParams.seqCountProvider.bitWidth() << " not allowed" << std::endl; +#else + sif::printError("cfdp::SourceHandler: Seq count provider bit width %d not allowed\n", + sourceParams.seqCountProvider.bitWidth()); +#endif + // Yeah, what am I supposed to do here? Can't throw an exception in the FSFW.. + transactionParams.pduConf.seqNum.setWidth(cfdp::WidthInBytes::ONE_BYTE); + } + transactionParams.pduConf.seqNum.setValue(0); +} + +cfdp::SourceHandler::FsmResult& cfdp::SourceHandler::fsmNacked() { + ReturnValue_t result; + if (step == TransactionStep::IDLE) { + step = TransactionStep::TRANSACTION_START; + } + if (step == TransactionStep::TRANSACTION_START) { + sourceParams.user.transactionIndication(transactionParams.id); + result = checksumGeneration(); + if (result != OK) { + addError(result); + } + step = TransactionStep::SENDING_METADATA; + } + if (step == TransactionStep::SENDING_METADATA) { + result = prepareAndSendMetadataPdu(); + if (result != OK) { + addError(result); + } + fsmResult.callStatus = CallStatus::CALL_AGAIN; + return fsmResult; + } + if (step == TransactionStep::SENDING_FILE_DATA) { + bool noFdPdu = false; + result = prepareAndSendNextFileDataPdu(noFdPdu); + if (result == OK and !noFdPdu) { + fsmResult.callStatus = CallStatus::CALL_AGAIN; + return fsmResult; + } + } + if (step == TransactionStep::SENDING_EOF) { + result = prepareAndSendEofPdu(); + if (result != OK) { + addError(result); + } + if (sourceParams.cfg.indicCfg.eofSentIndicRequired) { + sourceParams.user.eofSentIndication(transactionParams.id); + } + if (transactionParams.closureRequested) { + step = TransactionStep::WAIT_FOR_FINISH; + fsmResult.callStatus = CallStatus::CALL_AFTER_DELAY; + } else { + step = TransactionStep::NOTICE_OF_COMPLETION; + fsmResult.callStatus = CallStatus::CALL_AGAIN; + } + return fsmResult; + } + if (step == TransactionStep::WAIT_FOR_FINISH) { + // TODO: In case this is a request with closure, wait for finish. + // Done, issue notice of completion + step = TransactionStep::NOTICE_OF_COMPLETION; + } + if (step == TransactionStep::NOTICE_OF_COMPLETION) { + noticeOfCompletion(); + reset(); + } + return fsmResult; +} + +const cfdp::SourceHandler::FsmResult& cfdp::SourceHandler::stateMachine() { + fsmResult.packetsSent = 0; + fsmResult.errors = 0; + fsmResult.callStatus = CallStatus::DONE; + if (state == cfdp::CfdpState::IDLE) { + return fsmResult; + } + if (state == cfdp::CfdpState::BUSY_CLASS_1_NACKED) { + return fsmNacked(); + } + return fsmResult; +} + +ReturnValue_t cfdp::SourceHandler::checksumGeneration() { + if (transactionParams.fileSize.value() == 0) { + // NULL checksum for empty file. + transactionParams.crc = 0; + return OK; + } + std::array buf{}; + etl::crc32 crcCalc; + uint64_t currentOffset = 0; + FileOpParams params(transactionParams.sourceName.data(), transactionParams.fileSize.value()); + while (currentOffset < transactionParams.fileSize.value()) { + uint64_t readLen; + if (currentOffset + buf.size() > transactionParams.fileSize.value()) { + readLen = transactionParams.fileSize.value() - currentOffset; + } else { + readLen = buf.size(); + } + if (readLen > 0) { + params.offset = currentOffset; + params.size = readLen; + auto result = sourceParams.user.vfs.readFromFile(params, buf.data(), buf.size()); + if (result != OK) { + addError(result); + return FAILED; + } + crcCalc.add(buf.begin(), buf.begin() + readLen); + } + currentOffset += readLen; + } + + transactionParams.crc = crcCalc.value(); + return OK; +} + +ReturnValue_t cfdp::SourceHandler::transactionStart(PutRequest& putRequest, RemoteEntityCfg& cfg) { + if (state != CfdpState::IDLE) { + return SOURCE_TRANSACTION_PENDING; + } + if (cfg.remoteId != putRequest.getDestId()) { + return WRONG_REMOTE_CFG_ENTITY_ID; + } + if (putRequest.getSourceName().getValueLen() == 0) { + return SOURCE_NAME_EMPTY; + } + if (putRequest.getDestName().getValueLen() == 0) { + return DEST_NAME_EMPTY; + } + const char* srcNamePtr = putRequest.getSourceName().getCString(transactionParams.sourceNameSize); + const char* destNamePtr = putRequest.getDestName().getCString(transactionParams.destNameSize); + std::strncpy(transactionParams.sourceName.data(), srcNamePtr, transactionParams.sourceNameSize); + std::strncpy(transactionParams.destName.data(), destNamePtr, transactionParams.destNameSize); + // Add 0 termination. The source and dest name size can not be larger than UINT8_MAX, so this + // operation is safe. + transactionParams.sourceName[transactionParams.sourceNameSize] = '\0'; + transactionParams.destName[transactionParams.destNameSize] = '\0'; + FilesystemParams params(transactionParams.sourceName.data()); + if (!sourceParams.user.vfs.fileExists(params)) { + return FILE_DOES_NOT_EXIST; + } + if (cfg.maxFileSegmentLen > fileBuf.size() or cfg.maxFileSegmentLen == 0) { + return FILE_SEGMENT_LEN_INVALID; + } + // If transmission mode is not set, use default transmission mode for the remote entity. + if (not putRequest.getTransmissionMode(transactionParams.pduConf.mode)) { + transactionParams.pduConf.mode = cfg.defaultTransmissionMode; + } + // If closure request field is not set, use default option for the remote entity. + if (not putRequest.getClosureRequested(transactionParams.closureRequested)) { + transactionParams.closureRequested = cfg.closureRequested; + } + const EntityId& destId = putRequest.getDestId(); + // The width of the source and destination ID must be the same. Use the larger ID value to + // ensure the width is large enough for both IDs + if (destId.getWidth() > transactionParams.pduConf.sourceId.getWidth()) { + transactionParams.pduConf.destId = destId; + transactionParams.pduConf.sourceId.setWidth(destId.getWidth()); + } else { + transactionParams.pduConf.destId.setValueAndWidth(transactionParams.pduConf.sourceId.getWidth(), + destId.getValue()); + } + // Only used for PDU forwarding, file is sent to file receiver regularly here. + transactionParams.pduConf.direction = Direction::TOWARDS_RECEIVER; + transactionParams.pduConf.seqNum.setValue(sourceParams.seqCountProvider.getAndIncrement()); + transactionParams.id.seqNum = transactionParams.pduConf.seqNum; + + if (transactionParams.pduConf.mode == TransmissionMode::ACKNOWLEDGED) { + state = cfdp::CfdpState::BUSY_CLASS_2_ACKED; + } else if (transactionParams.pduConf.mode == TransmissionMode::UNACKNOWLEDGED) { + state = cfdp::CfdpState::BUSY_CLASS_1_NACKED; + } + step = TransactionStep::IDLE; + uint64_t fileSize = 0; + sourceParams.user.vfs.getFileSize(params, fileSize); + transactionParams.pduConf.largeFile = false; + if (fileSize > UINT32_MAX) { + transactionParams.pduConf.largeFile = true; + } + if (fileSize == 0) { + transactionParams.checksumType = ChecksumType::NULL_CHECKSUM; + } else { + transactionParams.checksumType = ChecksumType::CRC_32; + } + transactionParams.fileSize.setFileSize(fileSize, transactionParams.pduConf.largeFile); + transactionParams.progress = 0; + transactionParams.remoteCfg = cfg; + return OK; +} + +ReturnValue_t cfdp::SourceHandler::prepareAndSendMetadataPdu() { + cfdp::StringLv sourceName(transactionParams.sourceName.data(), transactionParams.sourceNameSize); + cfdp::StringLv destName(transactionParams.destName.data(), transactionParams.destNameSize); + auto metadataInfo = + MetadataGenericInfo(transactionParams.closureRequested, transactionParams.checksumType, + transactionParams.fileSize); + auto metadataPdu = + MetadataPduCreator(transactionParams.pduConf, metadataInfo, sourceName, destName, nullptr, 0); + ReturnValue_t result = sendGenericPdu(metadataPdu); + if (result != OK) { + return result; + } + // Advance FSM if everything works + step = TransactionStep::SENDING_FILE_DATA; + return OK; +} + +ReturnValue_t cfdp::SourceHandler::prepareAndSendNextFileDataPdu(bool& noFileDataPdu) { + cfdp::Fss offset(transactionParams.progress); + uint64_t readLen; + uint64_t fileSize = transactionParams.fileSize.value(); + noFileDataPdu = false; + if (fileSize == 0) { + // We are done, no need to send file data PDUs for an empty file. + step = TransactionStep::SENDING_EOF; + noFileDataPdu = true; + return OK; + } + if (fileSize < transactionParams.remoteCfg.maxFileSegmentLen) { + readLen = transactionParams.fileSize.value(); + } else { + if (transactionParams.progress + transactionParams.remoteCfg.maxFileSegmentLen > fileSize) { + readLen = fileSize - transactionParams.progress; + } else { + readLen = transactionParams.remoteCfg.maxFileSegmentLen; + } + } + FileOpParams fileParams(transactionParams.sourceName.data(), readLen); + fileParams.offset = transactionParams.progress; + ReturnValue_t result = + sourceParams.user.vfs.readFromFile(fileParams, fileBuf.data(), fileBuf.size()); + if (result != returnvalue::OK) { + addError(result); + return result; + } + auto fileDataInfo = FileDataInfo(offset, fileBuf.data(), readLen); + auto fileDataPdu = FileDataCreator(transactionParams.pduConf, fileDataInfo); + result = sendGenericPdu(fileDataPdu); + if (result != OK) { + return result; + } + transactionParams.progress += readLen; + if (transactionParams.progress >= fileSize) { + // Advance FSM after all file data PDUs were sent. + step = TransactionStep::SENDING_EOF; + } + return OK; +} + +ReturnValue_t cfdp::SourceHandler::prepareAndSendEofPdu() { + auto eofInfo = + EofInfo(ConditionCode::NO_ERROR, transactionParams.crc, transactionParams.fileSize); + auto eofPdu = EofPduCreator(transactionParams.pduConf, eofInfo); + ReturnValue_t result = sendGenericPdu(eofPdu); + if (result != OK) { + return result; + } + return OK; +} + +ReturnValue_t cfdp::SourceHandler::initialize() { + if (fsfwParams.tmStore == nullptr) { + fsfwParams.tmStore = ObjectManager::instance()->get(objects::TM_STORE); + if (fsfwParams.tmStore == nullptr) { + return FAILED; + } + } + + if (fsfwParams.tcStore == nullptr) { + fsfwParams.tcStore = ObjectManager::instance()->get(objects::TC_STORE); + if (fsfwParams.tcStore == nullptr) { + return FAILED; + } + } + + if (fsfwParams.msgQueue == nullptr) { + return FAILED; + } + return OK; +} + +ReturnValue_t cfdp::SourceHandler::sendGenericPdu(const SerializeIF& pdu) { + uint8_t* dataPtr; + store_address_t storeId; + ReturnValue_t result = + fsfwParams.tmStore->getFreeElement(&storeId, pdu.getSerializedSize(), &dataPtr); + if (result != OK) { + addError(result); + fsmResult.callStatus = CallStatus::CALL_AFTER_DELAY; + if (result == StorageManagerIF::DATA_STORAGE_FULL) { + return TM_STORE_FULL; + } + return result; + } + size_t serializedLen = 0; + result = pdu.serializeBe(dataPtr, serializedLen, pdu.getSerializedSize()); + if (result != OK) { + addError(result); + return result; + } + TmTcMessage tmMsg(storeId); + result = + fsfwParams.msgQueue->sendMessage(fsfwParams.packetDest.getReportReceptionQueue(), &tmMsg); + if (result != OK) { + fsmResult.callStatus = CallStatus::CALL_AFTER_DELAY; + } + if (result == MessageQueueIF::FULL) { + return TARGET_MSG_QUEUE_FULL; + } else if (result == OK) { + fsmResult.packetsSent += 1; + } + return result; +} + +ReturnValue_t cfdp::SourceHandler::noticeOfCompletion() { + if (sourceParams.cfg.indicCfg.transactionFinishedIndicRequired) { + cfdp::TransactionFinishedParams params(transactionParams.id, ConditionCode::NO_ERROR, + FileDeliveryCode::DATA_COMPLETE, + FileDeliveryStatus::RETAINED_IN_FILESTORE); + sourceParams.user.transactionFinishedIndication(params); + } + return OK; +} + +ReturnValue_t cfdp::SourceHandler::reset() { + step = TransactionStep::IDLE; + state = cfdp::CfdpState::IDLE; + fsmResult.callStatus = CallStatus::DONE; + transactionParams.reset(); + return OK; +} +cfdp::CfdpState cfdp::SourceHandler::getState() const { return state; } + +cfdp::SourceHandler::TransactionStep cfdp::SourceHandler::getStep() const { return step; } + +void cfdp::SourceHandler::addError(ReturnValue_t error) { + if (fsmResult.errors < fsmResult.errorCodes.size()) { + fsmResult.errorCodes[fsmResult.errors] = error; + fsmResult.errors++; + fsmResult.result = error; + } +} diff --git a/src/fsfw/cfdp/handler/SourceHandler.h b/src/fsfw/cfdp/handler/SourceHandler.h index 319cf258..d1d3fab2 100644 --- a/src/fsfw/cfdp/handler/SourceHandler.h +++ b/src/fsfw/cfdp/handler/SourceHandler.h @@ -1,6 +1,110 @@ #ifndef FSFW_CFDP_CFDPSOURCEHANDLER_H #define FSFW_CFDP_CFDPSOURCEHANDLER_H -class SourceHandler {}; +#include +#include + +#include "UserBase.h" +#include "defs.h" +#include "fsfw/cfdp/Fss.h" +#include "fsfw/cfdp/handler/PutRequest.h" +#include "fsfw/cfdp/handler/mib.h" +#include "fsfw/events/EventReportingProxyIF.h" +#include "fsfw/storagemanager/StorageManagerIF.h" +#include "fsfw/tmtcservices/AcceptsTelemetryIF.h" +#include "fsfw/util/ProvidesSeqCountIF.h" + +namespace cfdp { + +struct SourceHandlerParams { + SourceHandlerParams(LocalEntityCfg cfg, UserBase& user, ProvidesSeqCountIF& seqCountProvider) + : cfg(std::move(cfg)), user(user), seqCountProvider(seqCountProvider) {} + + LocalEntityCfg cfg; + UserBase& user; + ProvidesSeqCountIF& seqCountProvider; +}; + +class SourceHandler { + public: + enum class TransactionStep : uint8_t { + IDLE = 0, + TRANSACTION_START = 1, + SENDING_METADATA = 3, + SENDING_FILE_DATA = 4, + SENDING_EOF = 5, + WAIT_FOR_ACK = 6, + WAIT_FOR_FINISH = 7, + NOTICE_OF_COMPLETION = 8 + }; + struct FsmResult { + public: + ReturnValue_t result = returnvalue::OK; + CallStatus callStatus = CallStatus::CALL_AFTER_DELAY; + CfdpState state = CfdpState::IDLE; + uint32_t packetsSent = 0; + uint8_t errors = 0; + std::array errorCodes = {}; + }; + + SourceHandler(SourceHandlerParams params, FsfwParams fsfwParams); + + [[nodiscard]] CfdpState getState() const; + [[nodiscard]] TransactionStep getStep() const; + + /** + * Pass a put request to the source handler, which might initiate a CFDP transaction and start + * the state machine + * @return + */ + ReturnValue_t transactionStart(PutRequest& putRequest, RemoteEntityCfg& cfg); + const FsmResult& stateMachine(); + + ReturnValue_t initialize(); + + private: + struct TransactionParams { + uint32_t crc{}; + std::array sourceName{}; + size_t sourceNameSize = 0; + std::array destName{}; + size_t destNameSize = 0; + cfdp::Fss fileSize; + size_t progress = 0; + bool closureRequested = false; + ChecksumType checksumType = ChecksumType::NULL_CHECKSUM; + RemoteEntityCfg remoteCfg; + PduConfig pduConf; + cfdp::TransactionId id{}; + + void reset() { + sourceNameSize = 0; + destNameSize = 0; + fileSize.setFileSize(0, false); + progress = 0; + closureRequested = false; + } + } transactionParams; + + cfdp::CfdpState state = cfdp::CfdpState::IDLE; + TransactionStep step = TransactionStep::IDLE; + std::array fileBuf{}; + SourceHandlerParams sourceParams; + cfdp::FsfwParams fsfwParams; + FsmResult fsmResult; + + FsmResult& fsmNacked(); + ReturnValue_t checksumGeneration(); + ReturnValue_t prepareAndSendMetadataPdu(); + ReturnValue_t prepareAndSendNextFileDataPdu(bool& noFileDataPdu); + ReturnValue_t prepareAndSendEofPdu(); + ReturnValue_t noticeOfCompletion(); + ReturnValue_t reset(); + + [[nodiscard]] ReturnValue_t sendGenericPdu(const SerializeIF& pdu); + void addError(ReturnValue_t error); +}; + +} // namespace cfdp #endif // FSFW_CFDP_CFDPSOURCEHANDLER_H diff --git a/src/fsfw/cfdp/handler/UserBase.h b/src/fsfw/cfdp/handler/UserBase.h index e367b4a8..6141eea9 100644 --- a/src/fsfw/cfdp/handler/UserBase.h +++ b/src/fsfw/cfdp/handler/UserBase.h @@ -6,6 +6,7 @@ #include #include "StatusReportIF.h" +#include "fsfw/cfdp/Fss.h" #include "fsfw/cfdp/VarLenFields.h" #include "fsfw/cfdp/tlv/FilestoreResponseTlv.h" #include "fsfw/cfdp/tlv/MessageToUserTlv.h" @@ -27,14 +28,14 @@ struct TransactionFinishedParams { }; struct MetadataRecvdParams { - MetadataRecvdParams(const TransactionId& id, const EntityId& sourceId) - : id(id), sourceId(sourceId) {} + MetadataRecvdParams(const TransactionId& id, const EntityId& sourceId, Fss fileSize) + : id(id), sourceId(sourceId), fileSize(std::move(fileSize)) {} const TransactionId& id; const EntityId& sourceId; - uint64_t fileSize = 0; + Fss fileSize{}; const char* sourceFileName = ""; const char* destFileName = ""; - size_t msgsToUserLen = 0; + size_t numberOfMsgsToUser = 0; const MessageToUserTlv* msgsToUserArray = nullptr; }; @@ -65,6 +66,7 @@ struct FileSegmentRecvdParams { */ class UserBase { friend class DestHandler; + friend class SourceHandler; public: explicit UserBase(HasFileSystemIF& vfs); diff --git a/src/fsfw/cfdp/handler/defs.h b/src/fsfw/cfdp/handler/defs.h index 5f17ca2d..4356835d 100644 --- a/src/fsfw/cfdp/handler/defs.h +++ b/src/fsfw/cfdp/handler/defs.h @@ -1,11 +1,54 @@ #ifndef FSFW_CFDP_HANDLER_DEFS_H #define FSFW_CFDP_HANDLER_DEFS_H +#include + +#include "fsfw/storagemanager/StorageManagerIF.h" +#include "fsfw/storagemanager/storeAddress.h" +#include "fsfw/tmtcservices/AcceptsTelemetryIF.h" + namespace cfdp { -enum class CfdpStates { IDLE, BUSY_CLASS_1_NACKED, BUSY_CLASS_2_ACKED, SUSPENDED }; +enum class CfdpState { IDLE, BUSY_CLASS_1_NACKED, BUSY_CLASS_2_ACKED, SUSPENDED }; static constexpr uint8_t SSID = SUBSYSTEM_ID::CFDP; +static constexpr uint8_t CID = CLASS_ID::CFDP_HANDLER; + +struct PacketInfo { + PacketInfo(PduType type, store_address_t storeId, + std::optional directive = std::nullopt) + : pduType(type), directiveType(directive), storeId(storeId) {} + + PduType pduType = PduType::FILE_DATA; + std::optional directiveType = FileDirective::INVALID_DIRECTIVE; + store_address_t storeId = store_address_t::invalid(); + PacketInfo() = default; +}; + +struct FsfwParams { + FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue, + EventReportingProxyIF* eventReporter, StorageManagerIF& tcStore, + StorageManagerIF& tmStore) + : FsfwParams(packetDest, msgQueue, eventReporter) { + this->tcStore = &tcStore; + this->tmStore = &tmStore; + } + + FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue, + EventReportingProxyIF* eventReporter) + : packetDest(packetDest), msgQueue(msgQueue), eventReporter(eventReporter) {} + AcceptsTelemetryIF& packetDest; + MessageQueueIF* msgQueue; + EventReportingProxyIF* eventReporter = nullptr; + StorageManagerIF* tcStore = nullptr; + StorageManagerIF* tmStore = nullptr; +}; + +template +using PacketInfoList = etl::list; +using PacketInfoListBase = etl::ilist; + +enum class CallStatus { DONE, CALL_AFTER_DELAY, CALL_AGAIN }; namespace events { @@ -15,8 +58,19 @@ static constexpr Event SERIALIZATION_ERROR = event::makeEvent(SSID, 2, severity: static constexpr Event FILESTORE_ERROR = event::makeEvent(SSID, 3, severity::LOW); //! [EXPORT] : [COMMENT] P1: Transaction step ID, P2: 0 for source file name, 1 for dest file name static constexpr Event FILENAME_TOO_LARGE_ERROR = event::makeEvent(SSID, 4, severity::LOW); +//! [EXPORT] : [COMMENT] CFDP request handling failed. P2: Returncode. +static constexpr Event HANDLING_CFDP_REQUEST_FAILED = event::makeEvent(SSID, 5, severity::LOW); } // namespace events +static constexpr ReturnValue_t SOURCE_TRANSACTION_PENDING = returnvalue::makeCode(CID, 0); +static constexpr ReturnValue_t FILE_DOES_NOT_EXIST = returnvalue::makeCode(CID, 1); +static constexpr ReturnValue_t FILE_SEGMENT_LEN_INVALID = returnvalue::makeCode(CID, 2); +static constexpr ReturnValue_t SOURCE_NAME_EMPTY = returnvalue::makeCode(CID, 3); +static constexpr ReturnValue_t DEST_NAME_EMPTY = returnvalue::makeCode(CID, 4); +static constexpr ReturnValue_t WRONG_REMOTE_CFG_ENTITY_ID = returnvalue::makeCode(CID, 5); +static constexpr ReturnValue_t TARGET_MSG_QUEUE_FULL = returnvalue::makeCode(CID, 6); +static constexpr ReturnValue_t TM_STORE_FULL = returnvalue::makeCode(CID, 7); + } // namespace cfdp #endif // FSFW_CFDP_HANDLER_DEFS_H diff --git a/src/fsfw/cfdp/handler/mib.h b/src/fsfw/cfdp/handler/mib.h index 553596a6..7e4454ef 100644 --- a/src/fsfw/cfdp/handler/mib.h +++ b/src/fsfw/cfdp/handler/mib.h @@ -27,14 +27,15 @@ struct LocalEntityCfg { }; struct RemoteEntityCfg { + RemoteEntityCfg() = default; explicit RemoteEntityCfg(EntityId id) : remoteId(std::move(id)) {} EntityId remoteId; - size_t maxFileSegmentLen = 2048; + size_t maxFileSegmentLen = 1024; bool closureRequested = false; bool crcOnTransmission = false; TransmissionMode defaultTransmissionMode = TransmissionMode::UNACKNOWLEDGED; ChecksumType defaultChecksum = ChecksumType::NULL_CHECKSUM; - const uint8_t version = CFDP_VERSION_2; + uint8_t version = CFDP_VERSION_2; }; } // namespace cfdp diff --git a/src/fsfw/cfdp/pdu/CMakeLists.txt b/src/fsfw/cfdp/pdu/CMakeLists.txt index c08a4b29..89de7b86 100644 --- a/src/fsfw/cfdp/pdu/CMakeLists.txt +++ b/src/fsfw/cfdp/pdu/CMakeLists.txt @@ -17,7 +17,7 @@ target_sources( FinishedInfo.cpp FinishedPduCreator.cpp FinishedPduReader.cpp - MetadataInfo.cpp + MetadataGenericInfo.cpp MetadataPduCreator.cpp MetadataPduReader.cpp KeepAlivePduCreator.cpp diff --git a/src/fsfw/cfdp/pdu/EofInfo.cpp b/src/fsfw/cfdp/pdu/EofInfo.cpp index 98e79df7..b226fe7f 100644 --- a/src/fsfw/cfdp/pdu/EofInfo.cpp +++ b/src/fsfw/cfdp/pdu/EofInfo.cpp @@ -1,8 +1,13 @@ #include "EofInfo.h" -EofInfo::EofInfo(cfdp::ConditionCode conditionCode, uint32_t checksum, cfdp::FileSize fileSize, +#include + +EofInfo::EofInfo(cfdp::ConditionCode conditionCode, uint32_t checksum, cfdp::Fss fileSize, EntityIdTlv* faultLoc) - : conditionCode(conditionCode), checksum(checksum), fileSize(fileSize), faultLoc(faultLoc) {} + : conditionCode(conditionCode), + checksum(checksum), + fileSize(std::move(fileSize)), + faultLoc(faultLoc) {} EofInfo::EofInfo(EntityIdTlv* faultLoc) : conditionCode(cfdp::ConditionCode::NO_CONDITION_FIELD), @@ -16,15 +21,15 @@ cfdp::ConditionCode EofInfo::getConditionCode() const { return conditionCode; } EntityIdTlv* EofInfo::getFaultLoc() const { return faultLoc; } -cfdp::FileSize& EofInfo::getFileSize() { return fileSize; } +cfdp::Fss& EofInfo::getFileSize() { return fileSize; } -void EofInfo::setChecksum(uint32_t checksum) { this->checksum = checksum; } +void EofInfo::setChecksum(uint32_t checksum_) { this->checksum = checksum_; } -void EofInfo::setConditionCode(cfdp::ConditionCode conditionCode) { - this->conditionCode = conditionCode; +void EofInfo::setConditionCode(cfdp::ConditionCode conditionCode_) { + this->conditionCode = conditionCode_; } -void EofInfo::setFaultLoc(EntityIdTlv* faultLoc) { this->faultLoc = faultLoc; } +void EofInfo::setFaultLoc(EntityIdTlv* faultLoc_) { this->faultLoc = faultLoc_; } size_t EofInfo::getSerializedSize(bool fssLarge) { // Condition code + spare + 4 byte checksum @@ -42,6 +47,6 @@ size_t EofInfo::getSerializedSize(bool fssLarge) { return size; } -ReturnValue_t EofInfo::setFileSize(size_t fileSize, bool isLarge) { - return this->fileSize.setFileSize(fileSize, isLarge); +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 index 4b4fb057..59bfed31 100644 --- a/src/fsfw/cfdp/pdu/EofInfo.h +++ b/src/fsfw/cfdp/pdu/EofInfo.h @@ -1,14 +1,14 @@ #ifndef FSFW_SRC_FSFW_CFDP_PDU_EOFINFO_H_ #define FSFW_SRC_FSFW_CFDP_PDU_EOFINFO_H_ -#include "../FileSize.h" +#include "../Fss.h" #include "../definitions.h" #include "fsfw/cfdp/tlv/EntityIdTlv.h" struct EofInfo { public: explicit EofInfo(EntityIdTlv* faultLoc = nullptr); - EofInfo(cfdp::ConditionCode conditionCode, uint32_t checksum, cfdp::FileSize fileSize, + EofInfo(cfdp::ConditionCode conditionCode, uint32_t checksum, cfdp::Fss fileSize, EntityIdTlv* faultLoc = nullptr); size_t getSerializedSize(bool fssLarge = false); @@ -17,7 +17,7 @@ struct EofInfo { [[nodiscard]] cfdp::ConditionCode getConditionCode() const; [[nodiscard]] EntityIdTlv* getFaultLoc() const; - cfdp::FileSize& getFileSize(); + cfdp::Fss& getFileSize(); void setChecksum(uint32_t checksum); void setConditionCode(cfdp::ConditionCode conditionCode); void setFaultLoc(EntityIdTlv* faultLoc); @@ -26,7 +26,7 @@ struct EofInfo { private: cfdp::ConditionCode conditionCode; uint32_t checksum; - cfdp::FileSize fileSize; + cfdp::Fss fileSize; EntityIdTlv* faultLoc = nullptr; }; diff --git a/src/fsfw/cfdp/pdu/FileDataCreator.cpp b/src/fsfw/cfdp/pdu/FileDataCreator.cpp index 956752fb..70779a51 100644 --- a/src/fsfw/cfdp/pdu/FileDataCreator.cpp +++ b/src/fsfw/cfdp/pdu/FileDataCreator.cpp @@ -37,7 +37,7 @@ ReturnValue_t FileDataCreator::serialize(uint8_t** buffer, size_t* size, size_t *buffer += segmentMetadataLen; *size += segmentMetadataLen; } - cfdp::FileSize& offset = info.getOffset(); + cfdp::Fss& offset = info.getOffset(); result = offset.serialize(this->getLargeFileFlag(), buffer, size, maxSize, streamEndianness); if (result != returnvalue::OK) { return result; diff --git a/src/fsfw/cfdp/pdu/FileDataInfo.cpp b/src/fsfw/cfdp/pdu/FileDataInfo.cpp index 19fc00cd..8248a727 100644 --- a/src/fsfw/cfdp/pdu/FileDataInfo.cpp +++ b/src/fsfw/cfdp/pdu/FileDataInfo.cpp @@ -1,9 +1,9 @@ #include "FileDataInfo.h" -FileDataInfo::FileDataInfo(cfdp::FileSize &offset, const uint8_t *fileData, size_t fileSize) - : offset(offset), fileData(fileData), fileSize(fileSize) {} +#include -FileDataInfo::FileDataInfo(cfdp::FileSize &offset) : offset(offset) {} +FileDataInfo::FileDataInfo(cfdp::Fss offset, const uint8_t *fileData, size_t fileSize) + : offset(std::move(offset)), fileData(fileData), fileSize(fileSize) {} void FileDataInfo::setSegmentMetadataFlag(bool enable) { if (enable) { @@ -71,7 +71,7 @@ const uint8_t *FileDataInfo::getSegmentMetadata(size_t *segmentMetadataLen_) { return segmentMetadata; } -cfdp::FileSize &FileDataInfo::getOffset() { return offset; } +cfdp::Fss &FileDataInfo::getOffset() { return offset; } void FileDataInfo::setRecordContinuationState(cfdp::RecordContinuationState recContState) { this->recContState = recContState; diff --git a/src/fsfw/cfdp/pdu/FileDataInfo.h b/src/fsfw/cfdp/pdu/FileDataInfo.h index 36908d8b..b2b975ad 100644 --- a/src/fsfw/cfdp/pdu/FileDataInfo.h +++ b/src/fsfw/cfdp/pdu/FileDataInfo.h @@ -1,17 +1,17 @@ #ifndef FSFW_SRC_FSFW_CFDP_PDU_FILEDATAINFO_H_ #define FSFW_SRC_FSFW_CFDP_PDU_FILEDATAINFO_H_ -#include +#include #include class FileDataInfo { public: - explicit FileDataInfo(cfdp::FileSize& offset); - FileDataInfo(cfdp::FileSize& offset, const uint8_t* fileData, size_t fileSize); + FileDataInfo() = default; + FileDataInfo(cfdp::Fss offset, const uint8_t* fileData, size_t fileSize); [[nodiscard]] size_t getSerializedSize(bool largeFile = false) const; - cfdp::FileSize& getOffset(); + cfdp::Fss& getOffset(); const uint8_t* getFileData(size_t* fileSize = nullptr) const; void setFileData(const uint8_t* fileData, size_t fileSize); @@ -33,7 +33,7 @@ class FileDataInfo { private: cfdp::SegmentMetadataFlag segmentMetadataFlag = cfdp::SegmentMetadataFlag::NOT_PRESENT; cfdp::SegmentationControl segCtrl = cfdp::SegmentationControl::NO_RECORD_BOUNDARIES_PRESERVATION; - cfdp::FileSize& offset; + cfdp::Fss offset; const uint8_t* fileData = nullptr; size_t fileSize = 0; cfdp::RecordContinuationState recContState = cfdp::RecordContinuationState::NO_START_NO_END; diff --git a/src/fsfw/cfdp/pdu/HeaderReader.cpp b/src/fsfw/cfdp/pdu/HeaderReader.cpp index de3d2906..4d853920 100644 --- a/src/fsfw/cfdp/pdu/HeaderReader.cpp +++ b/src/fsfw/cfdp/pdu/HeaderReader.cpp @@ -103,11 +103,11 @@ void PduHeaderReader::getTransactionSeqNum(cfdp::TransactionSeqNum &seqNum) cons } void PduHeaderReader::assignVarLenField(cfdp::VarLenField *field, cfdp::WidthInBytes width, - void *sourcePtr) const { + void *sourcePtr) { switch (width) { case (cfdp::WidthInBytes::ONE_BYTE): { auto *fieldTyped = static_cast(sourcePtr); - field->setValue(width, *fieldTyped); + field->setValueAndWidth(width, *fieldTyped); break; } case (cfdp::WidthInBytes::TWO_BYTES): { @@ -115,7 +115,7 @@ void PduHeaderReader::assignVarLenField(cfdp::VarLenField *field, cfdp::WidthInB size_t deserSize = 0; SerializeAdapter::deSerialize(&fieldTyped, static_cast(sourcePtr), &deserSize, SerializeIF::Endianness::NETWORK); - field->setValue(width, fieldTyped); + field->setValueAndWidth(width, fieldTyped); break; } case (cfdp::WidthInBytes::FOUR_BYTES): { @@ -123,7 +123,15 @@ void PduHeaderReader::assignVarLenField(cfdp::VarLenField *field, cfdp::WidthInB size_t deserSize = 0; SerializeAdapter::deSerialize(&fieldTyped, static_cast(sourcePtr), &deserSize, SerializeIF::Endianness::NETWORK); - field->setValue(width, fieldTyped); + field->setValueAndWidth(width, fieldTyped); + break; + } + case (cfdp::WidthInBytes::EIGHT_BYTES): { + uint64_t fieldTyped = 0; + size_t deserSize = 0; + SerializeAdapter::deSerialize(&fieldTyped, static_cast(sourcePtr), &deserSize, + SerializeIF::Endianness::NETWORK); + field->setValueAndWidth(width, fieldTyped); break; } } diff --git a/src/fsfw/cfdp/pdu/KeepAlivePduCreator.cpp b/src/fsfw/cfdp/pdu/KeepAlivePduCreator.cpp index 40747751..2afcd427 100644 --- a/src/fsfw/cfdp/pdu/KeepAlivePduCreator.cpp +++ b/src/fsfw/cfdp/pdu/KeepAlivePduCreator.cpp @@ -1,6 +1,6 @@ #include "KeepAlivePduCreator.h" -KeepAlivePduCreator::KeepAlivePduCreator(PduConfig &conf, cfdp::FileSize &progress) +KeepAlivePduCreator::KeepAlivePduCreator(PduConfig &conf, cfdp::Fss &progress) : FileDirectiveCreator(conf, cfdp::FileDirective::KEEP_ALIVE, 4), progress(progress) { updateDirectiveFieldLen(); } diff --git a/src/fsfw/cfdp/pdu/KeepAlivePduCreator.h b/src/fsfw/cfdp/pdu/KeepAlivePduCreator.h index aa4bf0fd..97ce6095 100644 --- a/src/fsfw/cfdp/pdu/KeepAlivePduCreator.h +++ b/src/fsfw/cfdp/pdu/KeepAlivePduCreator.h @@ -1,12 +1,12 @@ #ifndef FSFW_CFDP_PDU_KEEPALIVEPDUSERIALIZER_H_ #define FSFW_CFDP_PDU_KEEPALIVEPDUSERIALIZER_H_ -#include "fsfw/cfdp/FileSize.h" +#include "fsfw/cfdp/Fss.h" #include "fsfw/cfdp/pdu/FileDirectiveCreator.h" class KeepAlivePduCreator : public FileDirectiveCreator { public: - KeepAlivePduCreator(PduConfig& conf, cfdp::FileSize& progress); + KeepAlivePduCreator(PduConfig& conf, cfdp::Fss& progress); void updateDirectiveFieldLen(); @@ -16,7 +16,7 @@ class KeepAlivePduCreator : public FileDirectiveCreator { Endianness streamEndianness) const override; private: - cfdp::FileSize& progress; + cfdp::Fss& progress; }; #endif /* FSFW_CFDP_PDU_KEEPALIVEPDUSERIALIZER_H_ */ diff --git a/src/fsfw/cfdp/pdu/KeepAlivePduReader.cpp b/src/fsfw/cfdp/pdu/KeepAlivePduReader.cpp index d3362cf9..73ddc678 100644 --- a/src/fsfw/cfdp/pdu/KeepAlivePduReader.cpp +++ b/src/fsfw/cfdp/pdu/KeepAlivePduReader.cpp @@ -1,7 +1,6 @@ #include "KeepAlivePduReader.h" -KeepAlivePduReader::KeepAlivePduReader(const uint8_t* pduBuf, size_t maxSize, - cfdp::FileSize& progress) +KeepAlivePduReader::KeepAlivePduReader(const uint8_t* pduBuf, size_t maxSize, cfdp::Fss& progress) : FileDirectiveReader(pduBuf, maxSize), progress(progress) {} ReturnValue_t KeepAlivePduReader::parseData() { @@ -15,4 +14,4 @@ ReturnValue_t KeepAlivePduReader::parseData() { return progress.deSerialize(&buffer, &remLen, getEndianness()); } -cfdp::FileSize& KeepAlivePduReader::getProgress() { return progress; } +cfdp::Fss& KeepAlivePduReader::getProgress() { return progress; } diff --git a/src/fsfw/cfdp/pdu/KeepAlivePduReader.h b/src/fsfw/cfdp/pdu/KeepAlivePduReader.h index 38e061f1..553101c9 100644 --- a/src/fsfw/cfdp/pdu/KeepAlivePduReader.h +++ b/src/fsfw/cfdp/pdu/KeepAlivePduReader.h @@ -1,19 +1,19 @@ #ifndef FSFW_CFDP_PDU_KEEPALIVEREADER_H_ #define FSFW_CFDP_PDU_KEEPALIVEREADER_H_ -#include "fsfw/cfdp/FileSize.h" +#include "fsfw/cfdp/Fss.h" #include "fsfw/cfdp/pdu/FileDirectiveReader.h" class KeepAlivePduReader : public FileDirectiveReader { public: - KeepAlivePduReader(const uint8_t* pduBuf, size_t maxSize, cfdp::FileSize& progress); + KeepAlivePduReader(const uint8_t* pduBuf, size_t maxSize, cfdp::Fss& progress); ReturnValue_t parseData() override; - cfdp::FileSize& getProgress(); + cfdp::Fss& getProgress(); private: - cfdp::FileSize& progress; + cfdp::Fss& progress; }; #endif /* FSFW_CFDP_PDU_KEEPALIVEPDUREADER_H_ */ diff --git a/src/fsfw/cfdp/pdu/MetadataGenericInfo.cpp b/src/fsfw/cfdp/pdu/MetadataGenericInfo.cpp new file mode 100644 index 00000000..f3b1c751 --- /dev/null +++ b/src/fsfw/cfdp/pdu/MetadataGenericInfo.cpp @@ -0,0 +1,35 @@ +#include "MetadataGenericInfo.h" + +MetadataGenericInfo::MetadataGenericInfo(bool closureRequested, cfdp::ChecksumType checksumType, + cfdp::Fss fileSize) + : MetadataGenericInfo(std::move(fileSize)) { + this->closureRequested = closureRequested; + this->checksumType = checksumType; +} + +MetadataGenericInfo::MetadataGenericInfo(cfdp::Fss fileSize) : fileSize(std::move(fileSize)) {} + +cfdp::ChecksumType MetadataGenericInfo::getChecksumType() const { return checksumType; } + +void MetadataGenericInfo::setChecksumType(cfdp::ChecksumType checksumType_) { + checksumType = checksumType_; +} + +bool MetadataGenericInfo::isClosureRequested() const { return closureRequested; } + +void MetadataGenericInfo::setClosureRequested(bool closureRequested_) { + closureRequested = closureRequested_; +} + +const cfdp::Fss& MetadataGenericInfo::getFileSize() const { return fileSize; } + +size_t MetadataGenericInfo::getSerializedSize(bool fssLarge) { + // 1 byte + minimal FSS 4 bytes + size_t size = 5; + if (fssLarge) { + size += 4; + } + return size; +} + +cfdp::Fss& MetadataGenericInfo::getMutFileSize() { return fileSize; } diff --git a/src/fsfw/cfdp/pdu/MetadataGenericInfo.h b/src/fsfw/cfdp/pdu/MetadataGenericInfo.h new file mode 100644 index 00000000..73a54972 --- /dev/null +++ b/src/fsfw/cfdp/pdu/MetadataGenericInfo.h @@ -0,0 +1,35 @@ +#ifndef FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_ +#define FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_ + +#include + +#include "fsfw/cfdp/Fss.h" +#include "fsfw/cfdp/definitions.h" +#include "fsfw/cfdp/tlv/Lv.h" +#include "fsfw/cfdp/tlv/StringLv.h" +#include "fsfw/cfdp/tlv/Tlv.h" + +class MetadataGenericInfo { + public: + MetadataGenericInfo() = default; + explicit MetadataGenericInfo(cfdp::Fss fileSize); + MetadataGenericInfo(bool closureRequested, cfdp::ChecksumType checksumType, cfdp::Fss fileSize); + + static size_t getSerializedSize(bool fssLarge = false); + + [[nodiscard]] cfdp::ChecksumType getChecksumType() const; + void setChecksumType(cfdp::ChecksumType checksumType); + [[nodiscard]] bool isClosureRequested() const; + void setClosureRequested(bool closureRequested = false); + + [[nodiscard]] const cfdp::Fss& getFileSize() const; + + cfdp::Fss& getMutFileSize(); + + private: + bool closureRequested = false; + cfdp::ChecksumType checksumType = cfdp::ChecksumType::NULL_CHECKSUM; + cfdp::Fss fileSize; +}; + +#endif /* FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_ */ diff --git a/src/fsfw/cfdp/pdu/MetadataInfo.cpp b/src/fsfw/cfdp/pdu/MetadataInfo.cpp deleted file mode 100644 index d88bdd87..00000000 --- a/src/fsfw/cfdp/pdu/MetadataInfo.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include "MetadataInfo.h" - -MetadataInfo::MetadataInfo(bool closureRequested, cfdp::ChecksumType checksumType, - cfdp::FileSize& fileSize, cfdp::StringLv& sourceFileName, - cfdp::StringLv& destFileName) - : MetadataInfo(fileSize, sourceFileName, destFileName) { - this->closureRequested = closureRequested; - this->checksumType = checksumType; -} - -MetadataInfo::MetadataInfo(cfdp::FileSize& fileSize, cfdp::StringLv& sourceFileName, - cfdp::StringLv& destFileName) - : fileSize(fileSize), sourceFileName(sourceFileName), destFileName(destFileName) {} - -void MetadataInfo::setOptionsArray(cfdp::Tlv** optionsArray_, std::optional optionsLen_, - std::optional maxOptionsLen_) { - this->optionsArray = optionsArray_; - if (maxOptionsLen_) { - this->maxOptionsLen = maxOptionsLen_.value(); - } - if (optionsLen_) { - this->optionsLen = optionsLen_.value(); - } -} - -cfdp::ChecksumType MetadataInfo::getChecksumType() const { return checksumType; } - -void MetadataInfo::setChecksumType(cfdp::ChecksumType checksumType_) { - checksumType = checksumType_; -} - -bool MetadataInfo::isClosureRequested() const { return closureRequested; } - -void MetadataInfo::setClosureRequested(bool closureRequested_) { - closureRequested = closureRequested_; -} - -cfdp::StringLv& 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 optionsArray == nullptr) { - return returnvalue::FAILED; - } - *optionsArray_ = optionsArray; - if (optionsLen_ != nullptr) { - *optionsLen_ = this->optionsLen; - } - if (maxOptsLen != nullptr) { - *maxOptsLen = this->maxOptionsLen; - } - return returnvalue::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::StringLv& destFileName_) { - this->destFileName = destFileName_; -} - -void MetadataInfo::setSourceFileName(cfdp::StringLv& sourceFileName_) { - this->sourceFileName = sourceFileName_; -} - -size_t MetadataInfo::getMaxOptionsLen() const { return maxOptionsLen; } - -void MetadataInfo::setMaxOptionsLen(size_t maxOptionsLen_) { this->maxOptionsLen = maxOptionsLen_; } - -size_t MetadataInfo::getOptionsLen() const { return optionsLen; } - -void MetadataInfo::setOptionsLen(size_t optionsLen_) { this->optionsLen = optionsLen_; } - -cfdp::StringLv& MetadataInfo::getSourceFileName() { return sourceFileName; } diff --git a/src/fsfw/cfdp/pdu/MetadataInfo.h b/src/fsfw/cfdp/pdu/MetadataInfo.h deleted file mode 100644 index 95f4544a..00000000 --- a/src/fsfw/cfdp/pdu/MetadataInfo.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_ -#define FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_ - -#include - -#include "fsfw/cfdp/FileSize.h" -#include "fsfw/cfdp/definitions.h" -#include "fsfw/cfdp/tlv/Lv.h" -#include "fsfw/cfdp/tlv/StringLv.h" -#include "fsfw/cfdp/tlv/Tlv.h" - -class MetadataInfo { - public: - MetadataInfo(cfdp::FileSize& fileSize, cfdp::StringLv& sourceFileName, - cfdp::StringLv& destFileName); - MetadataInfo(bool closureRequested, cfdp::ChecksumType checksumType, cfdp::FileSize& fileSize, - cfdp::StringLv& sourceFileName, cfdp::StringLv& destFileName); - - size_t getSerializedSize(bool fssLarge = false); - - void setOptionsArray(cfdp::Tlv** optionsArray, std::optional optionsLen, - std::optional maxOptionsLen); - [[nodiscard]] cfdp::ChecksumType getChecksumType() const; - void setChecksumType(cfdp::ChecksumType checksumType); - [[nodiscard]] bool isClosureRequested() const; - void setClosureRequested(bool closureRequested = false); - - void setDestFileName(cfdp::StringLv& destFileName); - void setSourceFileName(cfdp::StringLv& sourceFileName); - - cfdp::StringLv& getDestFileName(); - cfdp::StringLv& getSourceFileName(); - cfdp::FileSize& getFileSize(); - - [[nodiscard]] bool hasOptions() const; - [[nodiscard]] bool canHoldOptions() const; - ReturnValue_t getOptions(cfdp::Tlv*** optionsArray, size_t* optionsLen, size_t* maxOptsLen); - void setOptionsLen(size_t optionsLen); - [[nodiscard]] size_t getOptionsLen() const; - void setMaxOptionsLen(size_t maxOptionsLen); - [[nodiscard]] size_t getMaxOptionsLen() const; - - private: - bool closureRequested = false; - cfdp::ChecksumType checksumType = cfdp::ChecksumType::NULL_CHECKSUM; - cfdp::FileSize& fileSize; - cfdp::StringLv& sourceFileName; - cfdp::StringLv& 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/MetadataPduCreator.cpp b/src/fsfw/cfdp/pdu/MetadataPduCreator.cpp index 536a48f4..9f8633cb 100644 --- a/src/fsfw/cfdp/pdu/MetadataPduCreator.cpp +++ b/src/fsfw/cfdp/pdu/MetadataPduCreator.cpp @@ -1,12 +1,26 @@ #include "MetadataPduCreator.h" -MetadataPduCreator::MetadataPduCreator(PduConfig &conf, MetadataInfo &info) - : FileDirectiveCreator(conf, cfdp::FileDirective::METADATA, 5), info(info) { +MetadataPduCreator::MetadataPduCreator(PduConfig &conf, MetadataGenericInfo &info, + cfdp::StringLv &srcFileName, cfdp::StringLv &destFileName, + cfdp::Tlv **optionsArray, size_t optionsLen) + : FileDirectiveCreator(conf, cfdp::FileDirective::METADATA, 5), + info(info), + srcFileName(srcFileName), + destFileName(destFileName), + optionsArray(optionsArray), + optionsLen(optionsLen) { updateDirectiveFieldLen(); } void MetadataPduCreator::updateDirectiveFieldLen() { - setDirectiveDataFieldLen(info.getSerializedSize(getLargeFileFlag())); + size_t dirFieldLen = MetadataGenericInfo::getSerializedSize(HeaderCreator::getLargeFileFlag()) + + srcFileName.getSerializedSize() + destFileName.getSerializedSize(); + if (optionsLen > 0 and optionsArray != nullptr) { + for (size_t idx = 0; idx < optionsLen; idx++) { + dirFieldLen += optionsArray[idx]->getSerializedSize(); + } + } + setDirectiveDataFieldLen(dirFieldLen); } size_t MetadataPduCreator::getSerializedSize() const { @@ -29,21 +43,18 @@ ReturnValue_t MetadataPduCreator::serialize(uint8_t **buffer, size_t *size, size if (result != returnvalue::OK) { return result; } - result = info.getSourceFileName().serialize(buffer, size, maxSize, streamEndianness); + result = srcFileName.serialize(buffer, size, maxSize, streamEndianness); if (result != returnvalue::OK) { return result; } - result = info.getDestFileName().serialize(buffer, size, maxSize, streamEndianness); + result = destFileName.serialize(buffer, size, maxSize, streamEndianness); if (result != returnvalue::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 (optionsLen > 0 and optionsArray != nullptr) { + for (size_t idx = 0; idx < optionsLen; idx++) { + result = optionsArray[idx]->serialize(buffer, size, maxSize, streamEndianness); if (result != returnvalue::OK) { return result; } @@ -51,3 +62,5 @@ ReturnValue_t MetadataPduCreator::serialize(uint8_t **buffer, size_t *size, size } return result; } +const cfdp::StringLv &MetadataPduCreator::getSourceFileName() const { return srcFileName; } +const cfdp::StringLv &MetadataPduCreator::getDestFileName() const { return destFileName; } diff --git a/src/fsfw/cfdp/pdu/MetadataPduCreator.h b/src/fsfw/cfdp/pdu/MetadataPduCreator.h index 4486a79c..e1c931e5 100644 --- a/src/fsfw/cfdp/pdu/MetadataPduCreator.h +++ b/src/fsfw/cfdp/pdu/MetadataPduCreator.h @@ -2,22 +2,30 @@ #define FSFW_CFDP_PDU_METADATAPDUCREATOR_H_ #include "fsfw/cfdp/pdu/FileDirectiveCreator.h" -#include "fsfw/cfdp/pdu/MetadataInfo.h" +#include "fsfw/cfdp/pdu/MetadataGenericInfo.h" class MetadataPduCreator : public FileDirectiveCreator { public: - MetadataPduCreator(PduConfig& conf, MetadataInfo& info); + MetadataPduCreator(PduConfig& conf, MetadataGenericInfo& info, cfdp::StringLv& srcFileName, + cfdp::StringLv& destFileName, cfdp::Tlv** optionsArray, size_t optionsLen); void updateDirectiveFieldLen(); [[nodiscard]] size_t getSerializedSize() const override; + const cfdp::StringLv& getSourceFileName() const; + const cfdp::StringLv& getDestFileName() const; + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, Endianness streamEndianness) const override; using FileDirectiveCreator::serialize; private: - MetadataInfo& info; + MetadataGenericInfo& info; + cfdp::StringLv& srcFileName; + cfdp::StringLv& destFileName; + cfdp::Tlv** optionsArray; + size_t optionsLen; }; #endif /* FSFW_CFDP_PDU_METADATAPDUCREATOR_H_ */ diff --git a/src/fsfw/cfdp/pdu/MetadataPduReader.cpp b/src/fsfw/cfdp/pdu/MetadataPduReader.cpp index 66025140..e6160ce8 100644 --- a/src/fsfw/cfdp/pdu/MetadataPduReader.cpp +++ b/src/fsfw/cfdp/pdu/MetadataPduReader.cpp @@ -1,9 +1,15 @@ #include "MetadataPduReader.h" -MetadataPduReader::MetadataPduReader(const uint8_t* pduBuf, size_t maxSize, MetadataInfo& info) - : FileDirectiveReader(pduBuf, maxSize), info(info) {} +MetadataPduReader::MetadataPduReader(const uint8_t* pduBuf, size_t maxSize, + MetadataGenericInfo& info, cfdp::Tlv* optionsArray, + size_t optArrayMaxSize) + : FileDirectiveReader(pduBuf, maxSize), + info(info), + optionArray(optionsArray), + optionArrayMaxSize(optArrayMaxSize) {} ReturnValue_t MetadataPduReader::parseData() { + parsedOptions = 0; ReturnValue_t result = FileDirectiveReader::parseData(); if (result != returnvalue::OK) { return result; @@ -19,39 +25,43 @@ ReturnValue_t MetadataPduReader::parseData() { remSize -= 1; buf += 1; auto endianness = getEndianness(); - result = info.getFileSize().deSerialize(&buf, &remSize, endianness); + result = info.getMutFileSize().deSerialize(&buf, &remSize, endianness); if (result != returnvalue::OK) { return result; } - result = info.getSourceFileName().deSerialize(&buf, &remSize, endianness); + result = srcFileName.deSerialize(&buf, &remSize, endianness); if (result != returnvalue::OK) { return result; } - result = info.getDestFileName().deSerialize(&buf, &remSize, endianness); + result = destFileName.deSerialize(&buf, &remSize, endianness); if (result != returnvalue::OK) { return result; } - info.setOptionsLen(0); if (remSize > 0) { - if (not info.canHoldOptions()) { + if (optionArrayMaxSize == 0 or optionArray == nullptr) { 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) { + if (optsIdx > optionArrayMaxSize) { return cfdp::METADATA_CANT_PARSE_OPTIONS; } - result = optionsArray[optsIdx]->deSerialize(&buf, &remSize, endianness); + result = optionArray[optsIdx].deSerialize(&buf, &remSize, endianness); if (result != returnvalue::OK) { return result; } optsIdx++; } - info.setOptionsLen(optsIdx); + parsedOptions = optsIdx; } return result; } + +size_t MetadataPduReader::getNumberOfParsedOptions() const { return parsedOptions; } + +const cfdp::StringLv& MetadataPduReader::getSourceFileName() const { return srcFileName; } + +const cfdp::StringLv& MetadataPduReader::getDestFileName() const { return destFileName; } + +const MetadataGenericInfo& MetadataPduReader::getGenericInfo() const { return info; } diff --git a/src/fsfw/cfdp/pdu/MetadataPduReader.h b/src/fsfw/cfdp/pdu/MetadataPduReader.h index 3e8c0f30..a409928e 100644 --- a/src/fsfw/cfdp/pdu/MetadataPduReader.h +++ b/src/fsfw/cfdp/pdu/MetadataPduReader.h @@ -2,16 +2,28 @@ #define FSFW_CFDP_PDU_METADATAPDUREADER_H_ #include "fsfw/cfdp/pdu/FileDirectiveReader.h" -#include "fsfw/cfdp/pdu/MetadataInfo.h" +#include "fsfw/cfdp/pdu/MetadataGenericInfo.h" class MetadataPduReader : public FileDirectiveReader { public: - MetadataPduReader(const uint8_t* pduBuf, size_t maxSize, MetadataInfo& info); + MetadataPduReader(const uint8_t* pduBuf, size_t maxSize, MetadataGenericInfo& info, + cfdp::Tlv* optionsArray, size_t optArrayMaxSize); ReturnValue_t parseData() override; + [[nodiscard]] const MetadataGenericInfo& getGenericInfo() const; + [[nodiscard]] const cfdp::StringLv& getSourceFileName() const; + [[nodiscard]] const cfdp::StringLv& getDestFileName() const; + + [[nodiscard]] size_t getNumberOfParsedOptions() const; + private: - MetadataInfo& info; + cfdp::StringLv srcFileName; + cfdp::StringLv destFileName; + MetadataGenericInfo& info; + cfdp::Tlv* optionArray; + size_t optionArrayMaxSize; + size_t parsedOptions = 0; }; #endif /* FSFW_CFDP_PDU_METADATAPDUREADER_H_ */ diff --git a/src/fsfw/cfdp/pdu/NakInfo.cpp b/src/fsfw/cfdp/pdu/NakInfo.cpp index 14d06cb0..8ae317f4 100644 --- a/src/fsfw/cfdp/pdu/NakInfo.cpp +++ b/src/fsfw/cfdp/pdu/NakInfo.cpp @@ -1,6 +1,6 @@ #include "NakInfo.h" -NakInfo::NakInfo(cfdp::FileSize startOfScope, cfdp::FileSize endOfScope) +NakInfo::NakInfo(cfdp::Fss startOfScope, cfdp::Fss endOfScope) : startOfScope(startOfScope), endOfScope(endOfScope) {} size_t NakInfo::getSerializedSize(bool fssLarge) { @@ -57,9 +57,9 @@ void NakInfo::setSegmentRequests(SegmentRequest* segmentRequests, size_t* segmen } } -cfdp::FileSize& NakInfo::getStartOfScope() { return startOfScope; } +cfdp::Fss& NakInfo::getStartOfScope() { return startOfScope; } -cfdp::FileSize& NakInfo::getEndOfScope() { return endOfScope; } +cfdp::Fss& NakInfo::getEndOfScope() { return endOfScope; } size_t NakInfo::getSegmentRequestsLen() const { return segmentRequestsLen; } diff --git a/src/fsfw/cfdp/pdu/NakInfo.h b/src/fsfw/cfdp/pdu/NakInfo.h index 02d6b6f4..f8f6b147 100644 --- a/src/fsfw/cfdp/pdu/NakInfo.h +++ b/src/fsfw/cfdp/pdu/NakInfo.h @@ -3,21 +3,21 @@ #include -#include "fsfw/cfdp/FileSize.h" +#include "fsfw/cfdp/Fss.h" class NakInfo { public: - using SegmentRequest = std::pair; + using SegmentRequest = std::pair; - NakInfo(cfdp::FileSize startOfScope, cfdp::FileSize endOfScope); + NakInfo(cfdp::Fss startOfScope, cfdp::Fss endOfScope); void setSegmentRequests(SegmentRequest* segmentRequests, size_t* segmentRequestLen, size_t* maxSegmentRequestLen); size_t getSerializedSize(bool fssLarge = false); - cfdp::FileSize& getStartOfScope(); - cfdp::FileSize& getEndOfScope(); + cfdp::Fss& getStartOfScope(); + cfdp::Fss& getEndOfScope(); bool hasSegmentRequests() const; bool canHoldSegmentRequests() const; @@ -31,8 +31,8 @@ class NakInfo { void setSegmentRequestLen(size_t readLen); private: - cfdp::FileSize startOfScope; - cfdp::FileSize endOfScope; + cfdp::Fss startOfScope; + cfdp::Fss endOfScope; SegmentRequest* segmentRequests = nullptr; size_t segmentRequestsLen = 0; size_t maxSegmentRequestsLen = 0; diff --git a/src/fsfw/cfdp/pdu/NakPduCreator.h b/src/fsfw/cfdp/pdu/NakPduCreator.h index bfcff78d..601078fc 100644 --- a/src/fsfw/cfdp/pdu/NakPduCreator.h +++ b/src/fsfw/cfdp/pdu/NakPduCreator.h @@ -4,7 +4,7 @@ #include #include "NakInfo.h" -#include "fsfw/cfdp/FileSize.h" +#include "fsfw/cfdp/Fss.h" #include "fsfw/cfdp/definitions.h" #include "fsfw/cfdp/pdu/FileDirectiveCreator.h" diff --git a/src/fsfw/cfdp/pdu/PduHeaderReader.h b/src/fsfw/cfdp/pdu/PduHeaderReader.h index a2e122cd..d910e0e3 100644 --- a/src/fsfw/cfdp/pdu/PduHeaderReader.h +++ b/src/fsfw/cfdp/pdu/PduHeaderReader.h @@ -105,7 +105,8 @@ class PduHeaderReader : public RedirectableDataPointerIF, public PduHeaderIF { * @return */ ReturnValue_t setData(uint8_t* dataPtr, size_t maxSize, void* args) override; - void assignVarLenField(cfdp::VarLenField* field, cfdp::WidthInBytes width, void* sourcePtr) const; + static void assignVarLenField(cfdp::VarLenField* field, cfdp::WidthInBytes width, + void* sourcePtr); void* sourceIdRaw = nullptr; void* seqNumRaw = nullptr; void* destIdRaw = nullptr; diff --git a/src/fsfw/cfdp/tlv/CMakeLists.txt b/src/fsfw/cfdp/tlv/CMakeLists.txt index 617b1b0f..09adf941 100644 --- a/src/fsfw/cfdp/tlv/CMakeLists.txt +++ b/src/fsfw/cfdp/tlv/CMakeLists.txt @@ -8,4 +8,5 @@ target_sources( StringLv.cpp FlowLabelTlv.cpp MessageToUserTlv.cpp - FaultHandlerOverrideTlv.cpp) + FaultHandlerOverrideTlv.cpp + ReservedMessageCreator.cpp) diff --git a/src/fsfw/cfdp/tlv/Lv.cpp b/src/fsfw/cfdp/tlv/Lv.cpp index e7fa414a..0972d973 100644 --- a/src/fsfw/cfdp/tlv/Lv.cpp +++ b/src/fsfw/cfdp/tlv/Lv.cpp @@ -14,23 +14,6 @@ cfdp::Lv::Lv(const std::vector& data) : value(data.data(), data.size(), 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; - auto* otherVal = const_cast(other.getValue(&otherSize)); - if (otherVal == nullptr or otherSize == 0) { - this->zeroLen = true; - } - this->value.setConstBuffer(otherVal, otherSize); - return *this; -} - ReturnValue_t cfdp::Lv::serialize(uint8_t** buffer, size_t* size, size_t maxSize, Endianness streamEndianness) const { if (maxSize < 1) { @@ -49,10 +32,8 @@ ReturnValue_t cfdp::Lv::serialize(uint8_t** buffer, size_t* size, size_t maxSize } size_t cfdp::Lv::getSerializedSize() const { - if (zeroLen) { + if (zeroLen or value.getConstBuffer() == nullptr) { return 1; - } else if (value.getConstBuffer() == nullptr) { - return 0; } return value.getSerializedSize(); } @@ -85,7 +66,34 @@ ReturnValue_t cfdp::Lv::deSerialize(const uint8_t** buffer, size_t* size, const uint8_t* cfdp::Lv::getValue(size_t* size) const { if (size != nullptr) { // Length without length field - *size = value.getSerializedSize() - 1; + *size = getSerializedSize() - 1; } return value.getConstBuffer(); } +cfdp::Lv::Lv(cfdp::Lv&& other) noexcept + : value(other.value.getConstBuffer(), other.value.getSerializedSize() - 1, true) { + if (other.value.getSerializedSize() - 1 > 0) { + zeroLen = false; + } + // Leave other class in intact state. + other.zeroLen = false; + other.value = SerialBufferAdapter(); +} + +cfdp::Lv& cfdp::Lv::operator=(cfdp::Lv&& other) noexcept { + size_t otherSize = 0; + this->zeroLen = false; + auto* otherVal = const_cast(other.getValue(&otherSize)); + if (otherVal == nullptr or otherSize == 0) { + this->zeroLen = true; + } + this->value.setConstBuffer(otherVal, otherSize); + // Leave other class in intact state. + other.zeroLen = false; + other.value = SerialBufferAdapter(); + return *this; +} + +size_t cfdp::Lv::getValueLen() const { return getSerializedSize() - 1; } + +bool cfdp::Lv::isEmpty() const { return zeroLen; } diff --git a/src/fsfw/cfdp/tlv/Lv.h b/src/fsfw/cfdp/tlv/Lv.h index efabfdef..ee8e18c6 100644 --- a/src/fsfw/cfdp/tlv/Lv.h +++ b/src/fsfw/cfdp/tlv/Lv.h @@ -18,8 +18,12 @@ class Lv : public SerializeIF { Lv(const uint8_t* value, size_t size); Lv(); - Lv(const Lv&); - Lv& operator=(const Lv&); + // Semantically, this class is a zero-copy helper, so the copy ctor and copy assigment do not + // really make sense here. + Lv(const Lv&) = delete; + Lv& operator=(const Lv&) = delete; + Lv(Lv&&) noexcept; + Lv& operator=(Lv&&) noexcept; ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, Endianness streamEndianness) const override; @@ -36,6 +40,8 @@ class Lv : public SerializeIF { ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, Endianness streamEndianness) override; + size_t getValueLen() const; + /** * Get value field and its size. * @param size Optionally retrieve size. Size will be the size of the actual value field @@ -44,6 +50,8 @@ class Lv : public SerializeIF { */ const uint8_t* getValue(size_t* size) const; + bool isEmpty() const; + private: bool zeroLen = true; SerialBufferAdapter value; diff --git a/src/fsfw/cfdp/tlv/MessageToUserTlv.cpp b/src/fsfw/cfdp/tlv/MessageToUserTlv.cpp index 9a3e55ff..714379b6 100644 --- a/src/fsfw/cfdp/tlv/MessageToUserTlv.cpp +++ b/src/fsfw/cfdp/tlv/MessageToUserTlv.cpp @@ -7,3 +7,22 @@ MessageToUserTlv::MessageToUserTlv() : Tlv() {} MessageToUserTlv::MessageToUserTlv(const std::vector& data) : Tlv(cfdp::TlvType::MSG_TO_USER, data.data(), data.size()) {} + +MessageToUserTlv::MessageToUserTlv(const uint8_t* value, size_t size) + : Tlv(cfdp::TlvType::MSG_TO_USER, value, size) {} + +bool MessageToUserTlv::isReservedCfdpMessage(uint8_t& messageType, const uint8_t** msgDataStart, + size_t& msgLen) const { + if (cfdp::Tlv::getLengthField() < 5) { + return false; + } + if (std::strncmp(reinterpret_cast(getValue()), "cfdp", 4) == 0) { + messageType = getValue()[4]; + if (msgDataStart != nullptr) { + *msgDataStart = getValue() + 5; + } + msgLen = cfdp::Tlv::getSerializedSize() - 5; + return true; + } + return false; +} diff --git a/src/fsfw/cfdp/tlv/MessageToUserTlv.h b/src/fsfw/cfdp/tlv/MessageToUserTlv.h index e7f63ed2..7018a386 100644 --- a/src/fsfw/cfdp/tlv/MessageToUserTlv.h +++ b/src/fsfw/cfdp/tlv/MessageToUserTlv.h @@ -9,8 +9,12 @@ class MessageToUserTlv : public cfdp::Tlv { public: MessageToUserTlv(); MessageToUserTlv(uint8_t* value, size_t size); + MessageToUserTlv(const uint8_t* value, size_t size); explicit MessageToUserTlv(const std::vector& data); + bool isReservedCfdpMessage(uint8_t& messageType, const uint8_t** msgDataStart, + size_t& msgLen) const; + private: }; diff --git a/src/fsfw/cfdp/tlv/ReservedMessageCreator.cpp b/src/fsfw/cfdp/tlv/ReservedMessageCreator.cpp new file mode 100644 index 00000000..d37338ed --- /dev/null +++ b/src/fsfw/cfdp/tlv/ReservedMessageCreator.cpp @@ -0,0 +1,39 @@ +#include "ReservedMessageCreator.h" + +cfdp::ReservedMessageCreator::ReservedMessageCreator(uint8_t messageType, uint8_t *msgData, + size_t msgLen) + : messageType(messageType), msgData(msgData), msgSize(msgLen) {} + +ReturnValue_t cfdp::ReservedMessageCreator::serialize( + uint8_t **buffer, size_t *size, size_t maxSize, + SerializeIF::Endianness streamEndianness) const { + if (*size + getSerializedSize() > maxSize) { + return SerializeIF::BUFFER_TOO_SHORT; + } + **buffer = TlvType::MSG_TO_USER; + *buffer += 1; + *size += 1; + **buffer = getSerializedSize() - 2; + *size += 1; + *buffer += 1; + std::memcpy(*buffer, MSG_HEADER, 4); + *buffer += 4; + *size += 4; + **buffer = messageType; + *buffer += 1; + *size += 1; + std::memcpy(*buffer, msgData, msgSize); + *buffer += msgSize; + *size += msgSize; + return returnvalue::OK; +} + +size_t cfdp::ReservedMessageCreator::getSerializedSize() const { + // 2 bytes type and length, 4 bytes CFDP, 1 byte reserved message type, message data. + return 2 + 5 + msgSize; +} + +ReturnValue_t cfdp::ReservedMessageCreator::deSerialize(const uint8_t **buffer, size_t *size, + SerializeIF::Endianness streamEndianness) { + return returnvalue::FAILED; +} diff --git a/src/fsfw/cfdp/tlv/ReservedMessageCreator.h b/src/fsfw/cfdp/tlv/ReservedMessageCreator.h new file mode 100644 index 00000000..363791c8 --- /dev/null +++ b/src/fsfw/cfdp/tlv/ReservedMessageCreator.h @@ -0,0 +1,24 @@ +#pragma once + +#include "Tlv.h" + +namespace cfdp { + +class ReservedMessageCreator : public SerializeIF { + public: + static constexpr char MSG_HEADER[] = "cfdp"; + + ReservedMessageCreator(uint8_t messageType, uint8_t *msgData, size_t msgLen); + [[nodiscard]] ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const override; + [[nodiscard]] size_t getSerializedSize() const override; + ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override; + + private: + uint8_t messageType; + uint8_t *msgData; + size_t msgSize; +}; + +} // namespace cfdp diff --git a/src/fsfw/cfdp/tlv/StringLv.cpp b/src/fsfw/cfdp/tlv/StringLv.cpp index 60c278a7..ce290460 100644 --- a/src/fsfw/cfdp/tlv/StringLv.cpp +++ b/src/fsfw/cfdp/tlv/StringLv.cpp @@ -7,3 +7,12 @@ cfdp::StringLv::StringLv(const char* filename, size_t len) : Lv(reinterpret_cast(filename), len) {} cfdp::StringLv::StringLv() : Lv() {} + +const char* cfdp::StringLv::getCString(size_t& fileSize) const { + return reinterpret_cast(getValue(&fileSize)); +} + +std::string cfdp::StringLv::getString() const { + size_t fileSize; + return {getCString(fileSize), fileSize}; +} diff --git a/src/fsfw/cfdp/tlv/StringLv.h b/src/fsfw/cfdp/tlv/StringLv.h index 6c200b8b..3a1dba36 100644 --- a/src/fsfw/cfdp/tlv/StringLv.h +++ b/src/fsfw/cfdp/tlv/StringLv.h @@ -13,6 +13,8 @@ class StringLv : public Lv { explicit StringLv(const std::string& fileName); explicit StringLv(const char* filename, size_t len); + const char* getCString(size_t& fileSize) const; + std::string getString() const; // Delete the move constructor to avoid passing in a temporary StringLv(const std::string&&) = delete; }; diff --git a/src/fsfw/cfdp/tlv/Tlv.cpp b/src/fsfw/cfdp/tlv/Tlv.cpp index c3fce612..39635e53 100644 --- a/src/fsfw/cfdp/tlv/Tlv.cpp +++ b/src/fsfw/cfdp/tlv/Tlv.cpp @@ -54,6 +54,7 @@ ReturnValue_t cfdp::Tlv::deSerialize(const uint8_t **buffer, size_t *size, return STREAM_TOO_SHORT; } + rawData = *buffer; uint8_t rawType = **buffer; if (not checkType(rawType)) { return INVALID_TLV_TYPE; @@ -102,3 +103,5 @@ void cfdp::Tlv::setValue(uint8_t *value, size_t len) { uint8_t cfdp::Tlv::getLengthField() const { return this->value.getSerializedSize() - 1; } void cfdp::Tlv::setType(TlvType type) { this->type = type; } + +const uint8_t *cfdp::Tlv::getRawData() const { return rawData; } diff --git a/src/fsfw/cfdp/tlv/Tlv.h b/src/fsfw/cfdp/tlv/Tlv.h index 786a3b79..deea12c3 100644 --- a/src/fsfw/cfdp/tlv/Tlv.h +++ b/src/fsfw/cfdp/tlv/Tlv.h @@ -47,6 +47,7 @@ class Tlv : public TlvIF { void setValue(uint8_t *value, size_t len); [[nodiscard]] const uint8_t *getValue() const; + [[nodiscard]] const uint8_t *getRawData() const; void setType(TlvType type); [[nodiscard]] TlvType getType() const override; [[nodiscard]] uint8_t getLengthField() const override; @@ -55,6 +56,7 @@ class Tlv : public TlvIF { bool checkType(uint8_t rawType); bool zeroLen = true; + const uint8_t *rawData = nullptr; TlvType type = TlvType::INVALID_TLV; SerialBufferAdapter value; }; diff --git a/src/fsfw/filesystem/HasFileSystemIF.h b/src/fsfw/filesystem/HasFileSystemIF.h index a507938e..4f041135 100644 --- a/src/fsfw/filesystem/HasFileSystemIF.h +++ b/src/fsfw/filesystem/HasFileSystemIF.h @@ -17,7 +17,7 @@ struct FilesystemParams { }; struct FileOpParams { - FileOpParams(const char* path, size_t size) : fsParams(path), size(size) {} + FileOpParams(const char* path, size_t opSize) : fsParams(path), size(opSize) {} [[nodiscard]] const char* path() const { return fsParams.path; } @@ -80,6 +80,8 @@ class HasFileSystemIF { virtual bool isDirectory(const char* path) = 0; + virtual bool getFileSize(FilesystemParams params, uint64_t& fileSize) = 0; + virtual bool fileExists(FilesystemParams params) = 0; /** diff --git a/src/fsfw/objectmanager/ObjectManager.cpp b/src/fsfw/objectmanager/ObjectManager.cpp index 2193d3a5..f2b45d59 100644 --- a/src/fsfw/objectmanager/ObjectManager.cpp +++ b/src/fsfw/objectmanager/ObjectManager.cpp @@ -116,8 +116,8 @@ void ObjectManager::initialize() { << std::dec << std::setfill(' ') << std::endl; #else sif::printError( - "ObjectManager::initialize: Object 0x%08x failed to initialize with code 0x%04x\n", var, - it.first); + "ObjectManager::initialize: Object 0x%08x failed to initialize with code 0x%04x\n", + it.first, result); #endif #endif errorCount++; diff --git a/src/fsfw/osal/common/TcpTmTcBridge.cpp b/src/fsfw/osal/common/TcpTmTcBridge.cpp index 0bf3ab28..80c2ddd1 100644 --- a/src/fsfw/osal/common/TcpTmTcBridge.cpp +++ b/src/fsfw/osal/common/TcpTmTcBridge.cpp @@ -21,7 +21,7 @@ TcpTmTcBridge::TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination, : TmTcBridge("TCP TMTC Bridge", objectId, tcDestination, msgQueueDepth, tmStoreId, tcStoreId) { mutex = MutexFactory::instance()->createMutex(); // Connection is always up, TM is requested by connecting to server and receiving packets - registerCommConnect(); + TmTcBridge::registerCommConnect(); } ReturnValue_t TcpTmTcBridge::initialize() { diff --git a/src/fsfw/osal/common/TcpTmTcServer.h b/src/fsfw/osal/common/TcpTmTcServer.h index b8c6ea2c..2b549d87 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.h +++ b/src/fsfw/osal/common/TcpTmTcServer.h @@ -123,6 +123,7 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb StorageManagerIF* tmStore = nullptr; private: + //! [EXPORT] : [SKIP] static constexpr ReturnValue_t CONN_BROKEN = returnvalue::makeCode(1, 0); //! TMTC bridge is cached. object_id_t tmtcBridgeId = objects::NO_OBJECT; diff --git a/src/fsfw/returnvalues/FwClassIds.h b/src/fsfw/returnvalues/FwClassIds.h index 9a5cc812..9a4fa992 100644 --- a/src/fsfw/returnvalues/FwClassIds.h +++ b/src/fsfw/returnvalues/FwClassIds.h @@ -61,7 +61,8 @@ enum : uint8_t { HAS_ACTIONS_IF, // HF DEVICE_COMMUNICATION_IF, // DC BSP, // BSP - CFDP, // CFDP + CFDP_BASE, // CFDP + CFDP_HANDLER, // 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 01eb76f9..3d0de695 100644 --- a/src/fsfw/serialize/SerialBufferAdapter.cpp +++ b/src/fsfw/serialize/SerialBufferAdapter.cpp @@ -107,14 +107,6 @@ uint8_t* SerialBufferAdapter::getBuffer() { template const uint8_t* SerialBufferAdapter::getConstBuffer() const { - if (constBuffer == nullptr) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "SerialBufferAdapter::getConstBuffer:" - " Buffers are unitialized!" - << std::endl; -#endif - return nullptr; - } return constBuffer; } diff --git a/src/fsfw/serialize/SerialBufferAdapter.h b/src/fsfw/serialize/SerialBufferAdapter.h index 9030d7cc..37bc69b3 100644 --- a/src/fsfw/serialize/SerialBufferAdapter.h +++ b/src/fsfw/serialize/SerialBufferAdapter.h @@ -63,7 +63,17 @@ class SerialBufferAdapter : public SerializeIF { ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, Endianness streamEndianness) override; + /** + * Please note that this function can also return a nullpointer in case the length field contains + * 0. + * @return + */ uint8_t* getBuffer(); + /** + * Please note that this function can also return a nullpointer in case the length field contains + * 0. + * @return + */ [[nodiscard]] const uint8_t* getConstBuffer() const; void setConstBuffer(const uint8_t* buf, count_t bufLen); diff --git a/src/fsfw/storagemanager/LocalPool.cpp b/src/fsfw/storagemanager/LocalPool.cpp index b62c19b6..9a4b53a6 100644 --- a/src/fsfw/storagemanager/LocalPool.cpp +++ b/src/fsfw/storagemanager/LocalPool.cpp @@ -89,7 +89,7 @@ ReturnValue_t LocalPool::deleteData(store_address_t storeId) { ReturnValue_t status = returnvalue::OK; size_type pageSize = getSubpoolElementSize(storeId.poolIndex); if ((pageSize != 0) and (storeId.packetIndex < numberOfElements[storeId.poolIndex])) { - uint16_t packetPosition = getRawPosition(storeId); + size_type packetPosition = getRawPosition(storeId); uint8_t* ptr = &store[storeId.poolIndex][packetPosition]; std::memset(ptr, 0, pageSize); // Set free list diff --git a/src/fsfw/tmtcservices/TmTcBridge.cpp b/src/fsfw/tmtcservices/TmTcBridge.cpp index f098103e..9801b21e 100644 --- a/src/fsfw/tmtcservices/TmTcBridge.cpp +++ b/src/fsfw/tmtcservices/TmTcBridge.cpp @@ -23,18 +23,8 @@ TmTcBridge::TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDes TmTcBridge::~TmTcBridge() { QueueFactory::instance()->deleteMessageQueue(tmTcReceptionQueue); } -ReturnValue_t TmTcBridge::setNumberOfSentPacketsPerCycle(uint8_t sentPacketsPerCycle) { - if (sentPacketsPerCycle <= LIMIT_STORED_DATA_SENT_PER_CYCLE) { - this->sentPacketsPerCycle = sentPacketsPerCycle; - return returnvalue::OK; - } else { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "TmTcBridge::setNumberOfSentPacketsPerCycle: Number of " - << "packets sent per cycle exceeds limits. " - << "Keeping default value." << std::endl; -#endif - return returnvalue::FAILED; - } +void TmTcBridge::setNumberOfSentPacketsPerCycle(uint32_t sentPacketsPerCycle_) { + this->sentPacketsPerCycle = sentPacketsPerCycle_; } ReturnValue_t TmTcBridge::setMaxNumberOfPacketsStored(unsigned int maxNumberOfPacketsStored) { @@ -144,8 +134,8 @@ ReturnValue_t TmTcBridge::handleTmQueue() { #endif #endif /* FSFW_VERBOSE_LEVEL >= 3 */ - if (communicationLinkUp == false or packetSentCounter >= sentPacketsPerCycle) { - ReturnValue_t result = storeDownlinkData(&message); + if (!communicationLinkUp or packetSentCounter >= sentPacketsPerCycle) { + result = storeDownlinkData(&message); if (result != returnvalue::OK) { tmStore->deleteData(message.getStorageId()); } diff --git a/src/fsfw/tmtcservices/TmTcBridge.h b/src/fsfw/tmtcservices/TmTcBridge.h index 858793cc..c87be45c 100644 --- a/src/fsfw/tmtcservices/TmTcBridge.h +++ b/src/fsfw/tmtcservices/TmTcBridge.h @@ -15,10 +15,9 @@ class TmTcBridge : public AcceptsTelemetryIF, public ExecutableObjectIF, public SystemObject { public: - static constexpr uint8_t LIMIT_STORED_DATA_SENT_PER_CYCLE = 15; static constexpr unsigned int LIMIT_DOWNLINK_PACKETS_STORED = 500; - static constexpr uint8_t DEFAULT_STORED_DATA_SENT_PER_CYCLE = 5; + static constexpr uint8_t DEFAULT_STORED_DATA_SENT_PER_CYCLE = 20; static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10; TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDestination, @@ -32,7 +31,7 @@ class TmTcBridge : public AcceptsTelemetryIF, * @return -@c returnvalue::OK if value was set successfully * -@c returnvalue::FAILED otherwise, stored value stays the same */ - ReturnValue_t setNumberOfSentPacketsPerCycle(uint8_t sentPacketsPerCycle); + void setNumberOfSentPacketsPerCycle(uint32_t sentPacketsPerCycle); /** * Set number of packets sent per performOperation().Please note that this @@ -151,7 +150,7 @@ class TmTcBridge : public AcceptsTelemetryIF, * This FIFO can be used to store downlink data which can not be sent at the moment. */ DynamicFIFO* tmFifo = nullptr; - uint8_t sentPacketsPerCycle = DEFAULT_STORED_DATA_SENT_PER_CYCLE; + uint32_t sentPacketsPerCycle = DEFAULT_STORED_DATA_SENT_PER_CYCLE; unsigned int maxNumberOfPacketsStored = DEFAULT_DOWNLINK_PACKETS_STORED; }; diff --git a/src/fsfw/util/CMakeLists.txt b/src/fsfw/util/CMakeLists.txt new file mode 100644 index 00000000..a0d48465 --- /dev/null +++ b/src/fsfw/util/CMakeLists.txt @@ -0,0 +1 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE) diff --git a/src/fsfw/util/ProvidesSeqCountIF.h b/src/fsfw/util/ProvidesSeqCountIF.h new file mode 100644 index 00000000..d88f9024 --- /dev/null +++ b/src/fsfw/util/ProvidesSeqCountIF.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +class ProvidesSeqCountIF { + public: + virtual ~ProvidesSeqCountIF() = default; + + [[nodiscard]] virtual unsigned int bitWidth() const = 0; + + virtual uint64_t get() = 0; + virtual void increment() = 0; + + virtual uint64_t getAndIncrement() { + uint64_t val = get(); + increment(); + return val; + } +}; diff --git a/src/fsfw/util/SeqCountProvider.h b/src/fsfw/util/SeqCountProvider.h new file mode 100644 index 00000000..fe16431f --- /dev/null +++ b/src/fsfw/util/SeqCountProvider.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +#include "ProvidesSeqCountIF.h" + +template +class SeqCountProvider : public ProvidesSeqCountIF { + static_assert(std::is_same::value || std::is_same::value || + std::is_same::value, + "Only uint8_t, uint16_t, and uint32_t are allowed."); + + public: + [[nodiscard]] unsigned int bitWidth() const override { return sizeof(T) * 8; } + uint64_t get() override { return counter; } + // I'm also abusing the primitive C variable overflow wrap around here. + void increment() override { counter++; } + + private: + T counter{}; +}; + +using SeqCountProviderU8 = SeqCountProvider; +using SeqCountProviderU16 = SeqCountProvider; +using SeqCountProviderU32 = SeqCountProvider; diff --git a/src/fsfw_hal/host/HostFilesystem.cpp b/src/fsfw_hal/host/HostFilesystem.cpp index 20984f77..b574c6c0 100644 --- a/src/fsfw_hal/host/HostFilesystem.cpp +++ b/src/fsfw_hal/host/HostFilesystem.cpp @@ -184,3 +184,11 @@ ReturnValue_t HostFilesystem::getBaseFilename(FilesystemParams params, char *nam baseNameLen = baseName.size(); return returnvalue::OK; } + +bool HostFilesystem::getFileSize(FilesystemParams params, uint64_t &fileSize) { + if (!fileExists(params)) { + return false; + } + fileSize = std::filesystem::file_size(params.path); + return true; +} diff --git a/src/fsfw_hal/host/HostFilesystem.h b/src/fsfw_hal/host/HostFilesystem.h index da217aec..fd745e09 100644 --- a/src/fsfw_hal/host/HostFilesystem.h +++ b/src/fsfw_hal/host/HostFilesystem.h @@ -11,6 +11,7 @@ class HostFilesystem : public HasFileSystemIF { ReturnValue_t getBaseFilename(FilesystemParams params, char *nameBuf, size_t maxLen, size_t &baseNameLen) override; + virtual bool getFileSize(FilesystemParams params, uint64_t &fileSize) override; bool isDirectory(const char *path) override; bool fileExists(FilesystemParams params) override; ReturnValue_t truncateFile(FilesystemParams params) override; diff --git a/src/fsfw_hal/stm32h7/spi/SpiComIF.cpp b/src/fsfw_hal/stm32h7/spi/SpiComIF.cpp index 4d688bd5..611b34dc 100644 --- a/src/fsfw_hal/stm32h7/spi/SpiComIF.cpp +++ b/src/fsfw_hal/stm32h7/spi/SpiComIF.cpp @@ -282,7 +282,7 @@ ReturnValue_t SpiComIF::handlePollingSendOperation(uint8_t *recvPtr, SPI_HandleT #endif #endif spiCookie.setTransferState(spi::TransferStates::FAILURE); - return spi::HAL_TIMEOUT_RETVAL; + return spi::TIMEOUT; } case (HAL_ERROR): default: { @@ -296,7 +296,7 @@ ReturnValue_t SpiComIF::handlePollingSendOperation(uint8_t *recvPtr, SPI_HandleT #endif #endif spiCookie.setTransferState(spi::TransferStates::FAILURE); - return spi::HAL_ERROR_RETVAL; + return spi::GENERIC_ERROR; } } return returnvalue::OK; diff --git a/src/fsfw_hal/stm32h7/spi/spiDefinitions.h b/src/fsfw_hal/stm32h7/spi/spiDefinitions.h index cf05d986..60c662b1 100644 --- a/src/fsfw_hal/stm32h7/spi/spiDefinitions.h +++ b/src/fsfw_hal/stm32h7/spi/spiDefinitions.h @@ -9,11 +9,6 @@ namespace spi { -static constexpr uint8_t HAL_SPI_ID = CLASS_ID::HAL_SPI; -static constexpr ReturnValue_t HAL_TIMEOUT_RETVAL = returnvalue::makeCode(HAL_SPI_ID, 0); -static constexpr ReturnValue_t HAL_BUSY_RETVAL = returnvalue::makeCode(HAL_SPI_ID, 1); -static constexpr ReturnValue_t HAL_ERROR_RETVAL = returnvalue::makeCode(HAL_SPI_ID, 2); - enum class TransferStates { IDLE, WAIT, SUCCESS, FAILURE }; enum SpiBus { SPI_1, SPI_2 }; diff --git a/unittests/CatchFactory.cpp b/unittests/CatchFactory.cpp index 589e6887..62c2bc13 100644 --- a/unittests/CatchFactory.cpp +++ b/unittests/CatchFactory.cpp @@ -32,7 +32,7 @@ void Factory::produceFrameworkObjects(void* args) { setStaticFrameworkObjectIds(); new EventManager(objects::EVENT_MANAGER, 120); new HealthTable(objects::HEALTH_TABLE); - new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER, 20, false, 1.0); + new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER, 20, false, 5.0); { PoolManager::LocalPoolConfig poolCfg = {{100, 16}, {50, 32}, {25, 64}, {15, 128}, {5, 1024}}; diff --git a/unittests/action/TestActionHelper.cpp b/unittests/action/TestActionHelper.cpp index de021bb8..3b22dcee 100644 --- a/unittests/action/TestActionHelper.cpp +++ b/unittests/action/TestActionHelper.cpp @@ -57,7 +57,7 @@ TEST_CASE("Action Helper", "[action]") { step += 1; CHECK(testMqMock.wasMessageSent()); CommandMessage testMessage; - REQUIRE(testMqMock.getNextSentMessage(testMessage) == returnvalue::OK); + REQUIRE(testMqMock.getNextSentMessageToDefaultDest(testMessage) == returnvalue::OK); REQUIRE(testMessage.getCommand() == static_cast(ActionMessage::STEP_FAILED)); REQUIRE(testMessage.getParameter() == static_cast(testActionId)); uint32_t parameter2 = ((uint32_t)step << 16) | (uint32_t)status; @@ -71,7 +71,7 @@ TEST_CASE("Action Helper", "[action]") { actionHelper.finish(false, testMqMock.getId(), testActionId, status); CHECK(testMqMock.wasMessageSent()); CommandMessage testMessage; - REQUIRE(testMqMock.getNextSentMessage(testMessage) == returnvalue::OK); + REQUIRE(testMqMock.getNextSentMessageToDefaultDest(testMessage) == returnvalue::OK); REQUIRE(testMessage.getCommand() == static_cast(ActionMessage::COMPLETION_FAILED)); REQUIRE(ActionMessage::getActionId(&testMessage) == testActionId); REQUIRE(ActionMessage::getReturnCode(&testMessage) == static_cast(status)); @@ -87,7 +87,7 @@ TEST_CASE("Action Helper", "[action]") { REQUIRE(ipcStore->getData(toLongParamAddress).first == static_cast(StorageManagerIF::DATA_DOES_NOT_EXIST)); CommandMessage testMessage; - REQUIRE(testMqMock.getNextSentMessage(testMessage) == returnvalue::OK); + REQUIRE(testMqMock.getNextSentMessageToDefaultDest(testMessage) == returnvalue::OK); REQUIRE(testMessage.getCommand() == static_cast(ActionMessage::STEP_FAILED)); REQUIRE(ActionMessage::getReturnCode(&testMessage) == 0xAFFE); REQUIRE(ActionMessage::getStep(&testMessage) == 0); diff --git a/unittests/cfdp/CMakeLists.txt b/unittests/cfdp/CMakeLists.txt index 1867a534..aba30ede 100644 --- a/unittests/cfdp/CMakeLists.txt +++ b/unittests/cfdp/CMakeLists.txt @@ -1,5 +1,6 @@ -target_sources(${FSFW_TEST_TGT} PRIVATE testCfdp.cpp testOtherTlvs.cpp - testTlv.cpp testLvs.cpp) +target_sources( + ${FSFW_TEST_TGT} PRIVATE testCfdp.cpp testOtherTlvs.cpp + testReservedMsgCreator.cpp testTlv.cpp testLvs.cpp) add_subdirectory(handler) add_subdirectory(pdu) diff --git a/unittests/cfdp/handler/CMakeLists.txt b/unittests/cfdp/handler/CMakeLists.txt index f70e5dfb..6a8b25ec 100644 --- a/unittests/cfdp/handler/CMakeLists.txt +++ b/unittests/cfdp/handler/CMakeLists.txt @@ -1,3 +1,4 @@ target_sources( - ${FSFW_TEST_TGT} PRIVATE testDistributor.cpp testDestHandler.cpp - testSourceHandler.cpp testFaultHandler.cpp) + ${FSFW_TEST_TGT} + PRIVATE testDistributor.cpp testDestHandler.cpp testReservedMsgParser.cpp + testPutRequest.cpp testSourceHandler.cpp testFaultHandler.cpp) diff --git a/unittests/cfdp/handler/testDestHandler.cpp b/unittests/cfdp/handler/testDestHandler.cpp index 0224a20b..4aa2dc32 100644 --- a/unittests/cfdp/handler/testDestHandler.cpp +++ b/unittests/cfdp/handler/testDestHandler.cpp @@ -50,18 +50,18 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") { auto destHandler = DestHandler(dp, fp); CHECK(destHandler.initialize() == OK); - auto metadataPreparation = [&](FileSize cfdpFileSize, ChecksumType checksumType) { + auto metadataPreparation = [&](Fss cfdpFileSize, ChecksumType checksumType) { std::string srcNameString = "hello.txt"; std::string destNameString = "hello-cpy.txt"; StringLv srcName(srcNameString); StringLv destName(destNameString); - MetadataInfo info(false, checksumType, cfdpFileSize, srcName, destName); + MetadataGenericInfo info(false, checksumType, std::move(cfdpFileSize)); TransactionSeqNum seqNum(UnsignedByteField(1)); conf.sourceId = remoteId; conf.destId = localId; conf.mode = TransmissionMode::UNACKNOWLEDGED; conf.seqNum = seqNum; - MetadataPduCreator metadataCreator(conf, info); + MetadataPduCreator metadataCreator(conf, info, srcName, destName, nullptr, 0); REQUIRE(tcStore.getFreeElement(&storeId, metadataCreator.getSerializedSize(), &buf) == OK); REQUIRE(metadataCreator.serialize(buf, serLen, metadataCreator.getSerializedSize()) == OK); PacketInfo packetInfo(metadataCreator.getPduType(), storeId, @@ -81,17 +81,17 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") { auto& idMetadataPair = userMock.metadataRecvd.back(); REQUIRE(idMetadataPair.first == destHandler.getTransactionId()); REQUIRE(idMetadataPair.second.sourceId.getValue() == 3); - REQUIRE(idMetadataPair.second.fileSize == fileLen); + REQUIRE(idMetadataPair.second.fileSize.getSize(nullptr) == fileLen); REQUIRE(strcmp(idMetadataPair.second.destFileName, destName) == 0); REQUIRE(strcmp(idMetadataPair.second.sourceFileName, sourceName) == 0); userMock.metadataRecvd.pop(); REQUIRE(fsMock.fileMap.find(destName) != fsMock.fileMap.end()); REQUIRE(res.result == OK); - REQUIRE(res.state == CfdpStates::BUSY_CLASS_1_NACKED); + REQUIRE(res.state == CfdpState::BUSY_CLASS_1_NACKED); REQUIRE(res.step == DestHandler::TransactionStep::RECEIVING_FILE_DATA_PDUS); }; - auto eofPreparation = [&](FileSize cfdpFileSize, uint32_t crc) { + auto eofPreparation = [&](Fss cfdpFileSize, uint32_t crc) { EofInfo eofInfo(cfdp::ConditionCode::NO_ERROR, crc, std::move(cfdpFileSize)); EofPduCreator eofCreator(conf, eofInfo); REQUIRE(tcStore.getFreeElement(&storeId, eofCreator.getSerializedSize(), &buf) == OK); @@ -102,14 +102,14 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") { auto eofCheck = [&](const cfdp::DestHandler::FsmResult& res, const TransactionId& id) { REQUIRE(res.result == OK); - REQUIRE(res.state == CfdpStates::IDLE); + REQUIRE(res.state == CfdpState::IDLE); REQUIRE(res.errors == 0); REQUIRE(res.step == DestHandler::TransactionStep::IDLE); // Assert that the packet was deleted after handling REQUIRE(not tcStore.hasDataAtId(storeId)); REQUIRE(packetInfoList.empty()); - REQUIRE(userMock.eofsRevd.size() == 1); - auto& eofId = userMock.eofsRevd.back(); + REQUIRE(userMock.eofRecvdRecvd.size() == 1); + auto& eofId = userMock.eofRecvdRecvd.back(); CHECK(eofId == id); REQUIRE(userMock.finishedRecvd.size() == 1); auto& idParamPair = userMock.finishedRecvd.back(); @@ -120,7 +120,7 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") { auto fileDataPduCheck = [&](const cfdp::DestHandler::FsmResult& res, const std::vector& idsToCheck) { REQUIRE(res.result == OK); - REQUIRE(res.state == CfdpStates::BUSY_CLASS_1_NACKED); + REQUIRE(res.state == CfdpState::BUSY_CLASS_1_NACKED); REQUIRE(res.step == DestHandler::TransactionStep::RECEIVING_FILE_DATA_PDUS); for (const auto id : idsToCheck) { REQUIRE(not tcStore.hasDataAtId(id)); @@ -129,50 +129,50 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") { }; SECTION("State") { - CHECK(destHandler.getCfdpState() == CfdpStates::IDLE); + CHECK(destHandler.getCfdpState() == CfdpState::IDLE); CHECK(destHandler.getTransactionStep() == DestHandler::TransactionStep::IDLE); } SECTION("Idle State Machine Iteration") { - auto res = destHandler.performStateMachine(); + auto res = destHandler.stateMachine(); CHECK(res.result == OK); CHECK(res.callStatus == CallStatus::CALL_AFTER_DELAY); CHECK(res.errors == 0); - CHECK(destHandler.getCfdpState() == CfdpStates::IDLE); + CHECK(destHandler.getCfdpState() == CfdpState::IDLE); CHECK(destHandler.getTransactionStep() == DestHandler::TransactionStep::IDLE); } SECTION("Empty File Transfer") { - const DestHandler::FsmResult& res = destHandler.performStateMachine(); + const DestHandler::FsmResult& res = destHandler.stateMachine(); CHECK(res.result == OK); - FileSize cfdpFileSize(0); + Fss cfdpFileSize(0); metadataPreparation(cfdpFileSize, ChecksumType::NULL_CHECKSUM); - destHandler.performStateMachine(); + destHandler.stateMachine(); metadataCheck(res, "hello.txt", "hello-cpy.txt", 0); - destHandler.performStateMachine(); + destHandler.stateMachine(); REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY); auto transactionId = destHandler.getTransactionId(); eofPreparation(cfdpFileSize, 0); // After EOF, operation is done because no closure was requested - destHandler.performStateMachine(); + destHandler.stateMachine(); eofCheck(res, transactionId); } SECTION("Small File Transfer") { - const DestHandler::FsmResult& res = destHandler.performStateMachine(); + const DestHandler::FsmResult& res = destHandler.stateMachine(); CHECK(res.result == OK); std::string fileData = "hello test data"; etl::crc32 crcCalc; crcCalc.add(fileData.begin(), fileData.end()); uint32_t crc32 = crcCalc.value(); - FileSize cfdpFileSize(fileData.size()); + Fss cfdpFileSize(fileData.size()); metadataPreparation(cfdpFileSize, ChecksumType::CRC_32); - destHandler.performStateMachine(); + destHandler.stateMachine(); metadataCheck(res, "hello.txt", "hello-cpy.txt", fileData.size()); - destHandler.performStateMachine(); + destHandler.stateMachine(); REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY); auto transactionId = destHandler.getTransactionId(); - FileSize offset(0); + Fss offset(0); FileDataInfo fdPduInfo(offset, reinterpret_cast(fileData.data()), fileData.size()); FileDataCreator fdPduCreator(conf, fdPduInfo); @@ -180,16 +180,16 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") { REQUIRE(fdPduCreator.serialize(buf, serLen, fdPduCreator.getSerializedSize()) == OK); PacketInfo packetInfo(fdPduCreator.getPduType(), storeId, std::nullopt); packetInfoList.push_back(packetInfo); - destHandler.performStateMachine(); + destHandler.stateMachine(); fileDataPduCheck(res, {storeId}); eofPreparation(cfdpFileSize, crc32); // After EOF, operation is done because no closure was requested - destHandler.performStateMachine(); + destHandler.stateMachine(); eofCheck(res, transactionId); } SECTION("Segmented File Transfer") { - const DestHandler::FsmResult& res = destHandler.performStateMachine(); + const DestHandler::FsmResult& res = destHandler.stateMachine(); CHECK(res.result == OK); std::random_device dev; std::mt19937 rng(dev()); @@ -201,17 +201,17 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") { etl::crc32 crcCalc; crcCalc.add(largerFileData.begin(), largerFileData.end()); uint32_t crc32 = crcCalc.value(); - FileSize cfdpFileSize(largerFileData.size()); + Fss cfdpFileSize(largerFileData.size()); metadataPreparation(cfdpFileSize, ChecksumType::CRC_32); - destHandler.performStateMachine(); + destHandler.stateMachine(); metadataCheck(res, "hello.txt", "hello-cpy.txt", largerFileData.size()); - destHandler.performStateMachine(); + destHandler.stateMachine(); REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY); auto transactionId = destHandler.getTransactionId(); std::vector idsToCheck; { - FileSize offset(0); + Fss offset(0); FileDataInfo fdPduInfo(offset, reinterpret_cast(largerFileData.data()), largerFileData.size() / 2); FileDataCreator fdPduCreator(conf, fdPduInfo); @@ -223,7 +223,7 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") { } { - FileSize offset(512); + Fss offset(512); FileDataInfo fdPduInfo(offset, reinterpret_cast(largerFileData.data() + 512), largerFileData.size() / 2); FileDataCreator fdPduCreator(conf, fdPduInfo); @@ -234,11 +234,11 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") { packetInfoList.push_back(packetInfo); } - destHandler.performStateMachine(); + destHandler.stateMachine(); fileDataPduCheck(res, idsToCheck); eofPreparation(cfdpFileSize, crc32); // After EOF, operation is done because no closure was requested - destHandler.performStateMachine(); + destHandler.stateMachine(); eofCheck(res, transactionId); } } \ No newline at end of file diff --git a/unittests/cfdp/handler/testDistributor.cpp b/unittests/cfdp/handler/testDistributor.cpp index 8b6c46af..f6685c89 100644 --- a/unittests/cfdp/handler/testDistributor.cpp +++ b/unittests/cfdp/handler/testDistributor.cpp @@ -21,7 +21,7 @@ TEST_CASE("CFDP Distributor", "[cfdp][distributor]") { auto tcAcceptor = AcceptsTcMock("CFDP Receiver", 0, receiverQueueId); // Set up Metadata PDU for generate test data. - cfdp::FileSize fileSize(12); + cfdp::Fss fileSize(12); const cfdp::EntityId& sourceId(groundEntityId); const cfdp::EntityId& destId(obswEntityId); cfdp::TransactionSeqNum seqNum(UnsignedByteField(12)); @@ -30,9 +30,8 @@ TEST_CASE("CFDP Distributor", "[cfdp][distributor]") { cfdp::StringLv sourceFileName(sourceFileString); std::string destFileString = "hello2.txt"; cfdp::StringLv destFileName(destFileString); - MetadataInfo metadataInfo(false, cfdp::ChecksumType::CRC_32, fileSize, sourceFileName, - destFileName); - MetadataPduCreator creator(pduConf, metadataInfo); + MetadataGenericInfo metadataInfo(false, cfdp::ChecksumType::CRC_32, fileSize); + MetadataPduCreator creator(pduConf, metadataInfo, sourceFileName, destFileName, nullptr, 0); uint8_t* dataPtr = nullptr; SECTION("State") { diff --git a/unittests/cfdp/handler/testPutRequest.cpp b/unittests/cfdp/handler/testPutRequest.cpp new file mode 100644 index 00000000..6dcf5ca8 --- /dev/null +++ b/unittests/cfdp/handler/testPutRequest.cpp @@ -0,0 +1,59 @@ +#include +#include + +#include "fsfw/cfdp/handler/PutRequest.h" +#include "fsfw/cfdp/tlv/ReservedMessageCreator.h" + +TEST_CASE("Put Request", "[cfdp]") { + using namespace cfdp; + using namespace returnvalue; + + std::array reservedMsgCustomData{}; + std::array reservedMsgBuf{}; + std::array buffer{}; + EntityId destId(WidthInBytes::ONE_BYTE, 5); + std::string srcFileName = "hello.txt"; + std::string destFileName = "hello2.txt"; + uint8_t* msgBufPtr = reservedMsgCustomData.data(); + size_t msgSize = 0; + cfdp::StringLv srcName(srcFileName); + cfdp::StringLv destName(destFileName); + CHECK(destId.serializeAsLv(&msgBufPtr, &msgSize, reservedMsgCustomData.size()) == OK); + CHECK(srcName.serialize(&msgBufPtr, &msgSize, reservedMsgCustomData.size(), + SerializeIF::Endianness::NETWORK) == OK); + CHECK(destName.serialize(&msgBufPtr, &msgSize, reservedMsgCustomData.size(), + SerializeIF::Endianness::NETWORK) == OK); + ReservedMessageCreator creator(static_cast(ProxyOpMessageType::PUT_REQUEST), + reservedMsgCustomData.data(), msgSize); + msgSize = 0; + ReturnValue_t result = creator.serializeBe(reservedMsgBuf.data(), msgSize, buffer.size()); + CHECK(result == returnvalue::OK); + + SECTION("Put Request with reserved message") { + PutRequest putRequest(destId, reservedMsgBuf.data(), msgSize, nullptr, 0); + uint8_t* bufPtr = buffer.data(); + size_t serLen = 0; + REQUIRE(putRequest.serialize(&bufPtr, &serLen, buffer.size(), + SerializeIF::Endianness::NETWORK) == OK); + + CHECK(putRequest.getSerializedSize() == serLen); + PutRequest requestDeserialized; + size_t deserLen = putRequest.getSerializedSize(); + const uint8_t* deserPtr = buffer.data(); + REQUIRE(requestDeserialized.deSerialize(&deserPtr, &deserLen, + SerializeIF::Endianness::NETWORK) == OK); + CHECK(requestDeserialized.getDestId().getWidth() == destId.getWidth()); + CHECK(requestDeserialized.getDestId().getValue() == destId.getValue()); + size_t totalMsgsSize = 0; + const uint8_t* msgsToUserStart = requestDeserialized.getMessagesToUser(totalMsgsSize); + CHECK(totalMsgsSize == msgSize); + cfdp::Tlv genericTlv; + genericTlv.deSerialize(&msgsToUserStart, &totalMsgsSize, SerializeIF::Endianness::NETWORK); + CHECK(genericTlv.getType() == TlvType::MSG_TO_USER); + CHECK(genericTlv.getLengthField() == genericTlv.getSerializedSize() - 2); + CHECK(genericTlv.getValue()[0] == 'c'); + CHECK(genericTlv.getValue()[1] == 'f'); + CHECK(genericTlv.getValue()[2] == 'd'); + CHECK(genericTlv.getValue()[3] == 'p'); + } +} diff --git a/unittests/cfdp/handler/testReservedMsgParser.cpp b/unittests/cfdp/handler/testReservedMsgParser.cpp new file mode 100644 index 00000000..e87dc06d --- /dev/null +++ b/unittests/cfdp/handler/testReservedMsgParser.cpp @@ -0,0 +1,67 @@ +#include + +#include "fsfw/cfdp/CfdpMessage.h" +#include "fsfw/cfdp/VarLenFields.h" +#include "fsfw/cfdp/handler/PutRequest.h" +#include "fsfw/cfdp/handler/ReservedMessageParser.h" +#include "fsfw/cfdp/tlv/Lv.h" +#include "fsfw/cfdp/tlv/ReservedMessageCreator.h" +#include "fsfw/cfdp/tlv/StringLv.h" +#include "fsfw/globalfunctions/arrayprinter.h" +#include "fsfw/serialize.h" +#include "mocks/MessageQueueMock.h" +#include "mocks/StorageManagerMock.h" + +TEST_CASE("Reserved Message Parser", "[cfdp]") { + using namespace cfdp; + using namespace returnvalue; + + std::string srcFileName = "hello.txt"; + std::string destFileName = "hello2.txt"; + MessageQueueId_t destQueueId = 2; + MessageQueueMock msgQueue(1); + LocalPool::LocalPoolConfig storeCfg = {{10, 32}, {10, 64}, {10, 128}, {10, 1024}}; + StorageManagerMock ipcStore(0, storeCfg); + std::array buffer{}; + uint8_t msgBuf[32]{}; + + EntityId entityId(cfdp::WidthInBytes::ONE_BYTE, 5); + uint8_t* msgBufPtr = msgBuf; + size_t serLen = 0; + cfdp::StringLv srcName(srcFileName); + cfdp::StringLv destName(destFileName); + CHECK(entityId.serializeAsLv(&msgBufPtr, &serLen, sizeof(msgBuf)) == OK); + CHECK(srcName.serialize(&msgBufPtr, &serLen, sizeof(msgBuf), SerializeIF::Endianness::NETWORK) == + OK); + CHECK(destName.serialize(&msgBufPtr, &serLen, sizeof(msgBuf), SerializeIF::Endianness::NETWORK) == + OK); + ReservedMessageCreator creator(static_cast(ProxyOpMessageType::PUT_REQUEST), msgBuf, + serLen); + serLen = 0; + ReturnValue_t result = creator.serializeBe(buffer.data(), serLen, buffer.size()); + CHECK(result == returnvalue::OK); + MessageToUserTlv msgToUser; + CHECK(msgToUser.deSerializeBe(buffer.data(), serLen, buffer.size()) == OK); + ReservedMessageParser parser(ipcStore, msgQueue, destQueueId); + REQUIRE(parser.parse(&msgToUser, 1) == OK); + CommandMessage msg; + CHECK(msgQueue.wasMessageSent()); + CHECK(msgQueue.numberOfSentMessages() == 1); + CHECK(msgQueue.getNextSentMessage(destQueueId, msg) == OK); + store_address_t storeId = CfdpMessage::getStoreId(&msg); + const uint8_t* data; + size_t packetLen; + CHECK(ipcStore.getData(storeId, &data, &packetLen) == OK); + CHECK(packetLen > 0); + PutRequest putRequest; + size_t dummy = packetLen; + REQUIRE(putRequest.deSerialize(&data, &dummy, SerializeIF::Endianness::MACHINE) == OK); + CHECK(putRequest.getDestId().getValue() == entityId.getValue()); + CHECK(putRequest.getDestId().getWidth() == entityId.getWidth()); + auto& sourceNameLv = putRequest.getSourceName(); + std::string srcNameRead = sourceNameLv.getString(); + CHECK(srcNameRead == srcFileName); + auto& destNameLv = putRequest.getDestName(); + std::string destNameRead = destNameLv.getString(); + CHECK(destNameRead == destFileName); +} diff --git a/unittests/cfdp/handler/testSourceHandler.cpp b/unittests/cfdp/handler/testSourceHandler.cpp index 570ecb08..7fbec9a1 100644 --- a/unittests/cfdp/handler/testSourceHandler.cpp +++ b/unittests/cfdp/handler/testSourceHandler.cpp @@ -1,3 +1,286 @@ -#include +#include -TEST_CASE("CFDP Source Handler", "[cfdp]") {} \ No newline at end of file +#include +#include +#include + +#include "fsfw/cfdp.h" +#include "fsfw/cfdp/handler/PutRequest.h" +#include "fsfw/cfdp/handler/SourceHandler.h" +#include "fsfw/cfdp/pdu/EofPduCreator.h" +#include "fsfw/cfdp/pdu/EofPduReader.h" +#include "fsfw/cfdp/pdu/FileDataReader.h" +#include "fsfw/cfdp/pdu/MetadataPduCreator.h" +#include "fsfw/cfdp/pdu/MetadataPduReader.h" +#include "fsfw/tmtcservices/TmTcMessage.h" +#include "fsfw/util/SeqCountProvider.h" +#include "mocks/AcceptsTmMock.h" +#include "mocks/EventReportingProxyMock.h" +#include "mocks/FilesystemMock.h" +#include "mocks/MessageQueueMock.h" +#include "mocks/StorageManagerMock.h" +#include "mocks/cfdp/FaultHandlerMock.h" +#include "mocks/cfdp/RemoteConfigTableMock.h" +#include "mocks/cfdp/UserMock.h" + +TEST_CASE("CFDP Source Handler", "[cfdp]") { + using namespace cfdp; + using namespace returnvalue; + using namespace std::filesystem; + const size_t MAX_FILE_SEGMENT_SIZE = 255; + + MessageQueueId_t destQueueId = 2; + AcceptsTmMock tmReceiver(destQueueId); + MessageQueueMock mqMock(destQueueId); + EntityId localId = EntityId(UnsignedByteField(2)); + EntityId remoteId = EntityId(UnsignedByteField(5)); + FaultHandlerMock fhMock; + LocalEntityCfg localEntityCfg(localId, IndicationCfg(), fhMock); + FilesystemMock fsMock; + UserMock userMock(fsMock); + SeqCountProviderU16 seqCountProvider; + SourceHandlerParams dp(localEntityCfg, userMock, seqCountProvider); + + EventReportingProxyMock eventReporterMock; + LocalPool::LocalPoolConfig storeCfg = {{10, 32}, {10, 64}, {10, 128}, {10, 1024}}; + StorageManagerMock tcStore(2, storeCfg); + StorageManagerMock tmStore(3, storeCfg); + FsfwParams fp(tmReceiver, &mqMock, &eventReporterMock); + fp.tcStore = &tcStore; + fp.tmStore = &tmStore; + auto sourceHandler = SourceHandler(dp, fp); + + RemoteEntityCfg cfg; + cfg.maxFileSegmentLen = MAX_FILE_SEGMENT_SIZE; + cfg.remoteId = remoteId; + std::string srcFileName = "/tmp/cfdp-test.txt"; + std::string destFileName = "/tmp/cfdp-test2.txt"; + FilesystemParams srcFileNameFs(srcFileName.c_str()); + fsMock.createFile(srcFileNameFs); + cfdp::StringLv srcNameLv(srcFileNameFs.path, std::strlen(srcFileNameFs.path)); + FilesystemParams destFileNameFs(destFileName.c_str()); + cfdp::StringLv destNameLv(destFileNameFs.path, std::strlen(destFileNameFs.path)); + PutRequest putRequest(remoteId, srcNameLv, destNameLv); + CHECK(sourceHandler.initialize() == OK); + + auto onePduSentCheck = [&](const SourceHandler::FsmResult& fsmResult, TmTcMessage& tmtcMessage, + const uint8_t** pduPtr) { + CHECK(fsmResult.errors == 0); + CHECK(fsmResult.packetsSent == 1); + CHECK(mqMock.numberOfSentMessages() == 1); + REQUIRE(mqMock.getNextSentMessage(destQueueId, tmtcMessage) == OK); + auto accessor = tmStore.getData(tmtcMessage.getStorageId()); + REQUIRE(accessor.first == OK); + *pduPtr = accessor.second.data(); + return std::move(accessor); + }; + auto genericMetadataCheck = [&](const SourceHandler::FsmResult& fsmResult, + size_t expectedFileSize, uint16_t expectedSeqNum) { + CHECK(fsmResult.errors == 0); + CHECK(fsmResult.callStatus == CallStatus::CALL_AGAIN); + TmTcMessage tmtcMessage; + const uint8_t* pduPtr; + auto accessor = onePduSentCheck(fsmResult, tmtcMessage, &pduPtr); + CHECK(accessor.second.size() == 55); + MetadataGenericInfo metadataInfo; + MetadataPduReader metadataReader(pduPtr, accessor.second.size(), metadataInfo, nullptr, 0); + REQUIRE(metadataReader.parseData() == OK); + std::string srcNameRead = metadataReader.getSourceFileName().getString(); + CHECK(srcNameRead == srcFileName); + TransactionSeqNum seqNum; + metadataReader.getTransactionSeqNum(seqNum); + CHECK(seqNum.getValue() == expectedSeqNum); + CHECK(userMock.transactionIndicRecvd.size() == 1); + CHECK(userMock.transactionIndicRecvd.back() == TransactionId(localId, seqNum)); + EntityId srcId; + metadataReader.getSourceId(srcId); + EntityId destId; + metadataReader.getDestId(destId); + CHECK(srcId.getValue() == localId.getValue()); + CHECK(destId.getValue() == remoteId.getValue()); + std::string destNameRead = metadataReader.getDestFileName().getString(); + CHECK(destNameRead == destFileName); + if (expectedFileSize == 0) { + CHECK(metadataInfo.getChecksumType() == ChecksumType::NULL_CHECKSUM); + } else { + CHECK(metadataInfo.getChecksumType() == ChecksumType::CRC_32); + } + CHECK(metadataInfo.getFileSize().value() == expectedFileSize); + CHECK(!metadataInfo.isClosureRequested()); + mqMock.clearMessages(); + }; + auto genericEofCheck = [&](const SourceHandler::FsmResult& fsmResult, size_t expectedFileSize, + uint32_t expectedChecksum, uint16_t expectedSeqNum) { + CHECK(fsmResult.errors == 0); + CHECK(fsmResult.callStatus == CallStatus::CALL_AGAIN); + TmTcMessage tmtcMessage; + const uint8_t* pduPtr; + auto accessor = onePduSentCheck(fsmResult, tmtcMessage, &pduPtr); + // 10 byte PDU header, 1 byte directive field, 1 byte condition code, 4 byte checksum, + // 4 byte FSS + CHECK(accessor.second.size() == 20); + EofInfo eofInfo; + EofPduReader eofReader(pduPtr, accessor.second.size(), eofInfo); + REQUIRE(eofReader.parseData() == OK); + TransactionSeqNum seqNum; + eofReader.getTransactionSeqNum(seqNum); + CHECK(seqNum.getValue() == expectedSeqNum); + auto transactionId = TransactionId(localId, seqNum); + CHECK(userMock.eofSentRecvd.size() == 1); + CHECK(userMock.eofSentRecvd.back() == transactionId); + CHECK(eofInfo.getChecksum() == expectedChecksum); + CHECK(eofInfo.getConditionCode() == ConditionCode::NO_ERROR); + CHECK(eofInfo.getFileSize().value() == expectedFileSize); + }; + auto genericNoticeOfCompletionCheck = [&](const SourceHandler::FsmResult& fsmResult, + uint16_t expectedSeqNum) { + CHECK(fsmResult.callStatus == CallStatus::DONE); + CHECK(userMock.finishedRecvd.size() == 1); + CHECK(userMock.finishedRecvd.back().first == + TransactionId(localId, TransactionSeqNum(cfdp::WidthInBytes::TWO_BYTES, expectedSeqNum))); + CHECK(sourceHandler.getStep() == SourceHandler::TransactionStep::IDLE); + CHECK(sourceHandler.getState() == CfdpState::IDLE); + }; + + SECTION("Test Basic") { + CHECK(sourceHandler.getState() == CfdpState::IDLE); + CHECK(sourceHandler.getStep() == SourceHandler::TransactionStep::IDLE); + } + + SECTION("Transfer empty file") { + CHECK(sourceHandler.transactionStart(putRequest, cfg) == OK); + + size_t expectedFileSize = 0; + const SourceHandler::FsmResult& fsmResult = sourceHandler.stateMachine(); + // Verify metadata PDU was sent. + genericMetadataCheck(fsmResult, expectedFileSize, 0); + + sourceHandler.stateMachine(); + // Verify EOF PDU was sent. No file data PDU is sent for an empty file and the checksum is 0. + genericEofCheck(fsmResult, expectedFileSize, 0, 0); + + // Verify notice of completion. + sourceHandler.stateMachine(); + genericNoticeOfCompletionCheck(fsmResult, 0); + } + + SECTION("Transfer small file") { + uint16_t expectedSeqNum = 0; + fsMock.createFile(srcFileNameFs); + std::string fileContent = "hello world\n"; + size_t expectedFileSize = fileContent.size(); + FileOpParams params(srcFileName.c_str(), expectedFileSize); + fsMock.writeToFile(params, reinterpret_cast(fileContent.data())); + CHECK(sourceHandler.transactionStart(putRequest, cfg) == OK); + const SourceHandler::FsmResult& fsmResult = sourceHandler.stateMachine(); + + // Verify metadata PDU was sent. + genericMetadataCheck(fsmResult, expectedFileSize, expectedSeqNum); + + // Verify that a small file data PDU was sent. + sourceHandler.stateMachine(); + TmTcMessage tmtcMessage; + const uint8_t* pduPtr; + auto accessor = onePduSentCheck(fsmResult, tmtcMessage, &pduPtr); + FileDataInfo fdInfo; + FileDataReader fdReader(pduPtr, accessor.second.size(), fdInfo); + // 10 byte PDU header, 4 byte offset, 12 bytes file data. + CHECK(accessor.second.size() == 26); + CHECK(fdReader.parseData() == OK); + CHECK(fdInfo.getOffset().value() == 0); + size_t fileSize = 0; + const uint8_t* fileData = fdInfo.getFileData(&fileSize); + REQUIRE(fileSize == fileContent.size()); + CHECK(fileData != nullptr); + std::string dataReadBack(reinterpret_cast(fileData), fileSize); + CHECK(dataReadBack == fileContent); + mqMock.clearMessages(); + + sourceHandler.stateMachine(); + + etl::crc32 crcCalc; + crcCalc.add(fileContent.data(), fileContent.data() + fileContent.size()); + // Verify EOF PDU was sent. + genericEofCheck(fsmResult, expectedFileSize, crcCalc.value(), expectedSeqNum); + + // Verify notice of completion. + sourceHandler.stateMachine(); + genericNoticeOfCompletionCheck(fsmResult, expectedSeqNum); + } + + SECTION("Transfer two segment file") { + uint16_t expectedSeqNum = 0; + // Create 400 bytes of random data. This should result in two file segments, with one + // having the maximum size. + std::random_device dev; + std::mt19937 rng(dev()); + std::uniform_int_distribution distU8(0, 255); + std::array largerFileData{}; + for (auto& val : largerFileData) { + val = distU8(rng); + } + size_t expectedFileSize = largerFileData.size(); + fsMock.createFile(srcFileNameFs); + FileOpParams params(srcFileName.c_str(), expectedFileSize); + fsMock.writeToFile(params, reinterpret_cast(largerFileData.data())); + CHECK(sourceHandler.transactionStart(putRequest, cfg) == OK); + const SourceHandler::FsmResult& fsmResult = sourceHandler.stateMachine(); + // Verify metadata PDU was sent. + genericMetadataCheck(fsmResult, expectedFileSize, expectedSeqNum); + + // Check first file data PDU. It should have the maximum file segment size. + sourceHandler.stateMachine(); + TmTcMessage tmtcMessage; + const uint8_t* pduPtr; + FileDataInfo fdInfo; + { + CHECK(fsmResult.callStatus == CallStatus::CALL_AGAIN); + auto accessor = onePduSentCheck(fsmResult, tmtcMessage, &pduPtr); + FileDataReader fdReader(pduPtr, accessor.second.size(), fdInfo); + // 10 byte PDU header, 4 byte offset, 255 byte file data + CHECK(accessor.second.size() == 269); + CHECK(fdReader.parseData() == OK); + CHECK(fdInfo.getOffset().value() == 0); + size_t fileSize = 0; + const uint8_t* fileData = fdInfo.getFileData(&fileSize); + // Maximum file segment size. + REQUIRE(fileSize == MAX_FILE_SEGMENT_SIZE); + for (unsigned i = 0; i < fileSize; i++) { + CHECK(fileData[i] == largerFileData[i]); + } + } + mqMock.clearMessages(); + + // Check second file data PDU. + sourceHandler.stateMachine(); + { + CHECK(fsmResult.callStatus == CallStatus::CALL_AGAIN); + auto accessor = onePduSentCheck(fsmResult, tmtcMessage, &pduPtr); + FileDataReader fdReader(pduPtr, accessor.second.size(), fdInfo); + // 10 byte PDU header, 4 byte offset, remaining file data (400 - 255 == 145). + CHECK(accessor.second.size() == 10 + 4 + largerFileData.size() - MAX_FILE_SEGMENT_SIZE); + CHECK(fdReader.parseData() == OK); + CHECK(fdInfo.getOffset().value() == MAX_FILE_SEGMENT_SIZE); + size_t fileDataSize = 0; + const uint8_t* fileData = fdInfo.getFileData(&fileDataSize); + // Maximum file segment size. + REQUIRE(fileDataSize == largerFileData.size() - MAX_FILE_SEGMENT_SIZE); + for (unsigned i = 0; i < fileDataSize; i++) { + CHECK(fileData[i] == largerFileData[MAX_FILE_SEGMENT_SIZE + i]); + } + } + mqMock.clearMessages(); + + // Check EOF and verify checksum. + sourceHandler.stateMachine(); + + etl::crc32 crcCalc; + crcCalc.add(largerFileData.data(), largerFileData.data() + largerFileData.size()); + // Verify EOF PDU was sent. + genericEofCheck(fsmResult, expectedFileSize, crcCalc.value(), expectedSeqNum); + + // Verify notice of completion. + sourceHandler.stateMachine(); + genericNoticeOfCompletionCheck(fsmResult, expectedSeqNum); + } +} \ No newline at end of file diff --git a/unittests/cfdp/pdu/testCfdpHeader.cpp b/unittests/cfdp/pdu/testCfdpHeader.cpp index 1fc7dfd4..447e3722 100644 --- a/unittests/cfdp/pdu/testCfdpHeader.cpp +++ b/unittests/cfdp/pdu/testCfdpHeader.cpp @@ -110,9 +110,9 @@ TEST_CASE("CFDP Header", "[cfdp]") { } SECTION("Other variable sized fields") { - pduConf.seqNum.setValue(cfdp::WidthInBytes::TWO_BYTES, 0x0fff); - pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00); - pduConf.destId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff); + pduConf.seqNum.setValueAndWidth(cfdp::WidthInBytes::TWO_BYTES, 0x0fff); + pduConf.sourceId.setValueAndWidth(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00); + pduConf.destId.setValueAndWidth(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff); REQUIRE(pduConf.sourceId.getSerializedSize() == 4); REQUIRE(creator.getSerializedSize() == 14); REQUIRE(creator.serialize(&serTarget, &serSize, serBuf.size(), @@ -146,9 +146,9 @@ TEST_CASE("CFDP Header", "[cfdp]") { } SECTION("Buffer Too Short") { - pduConf.seqNum.setValue(cfdp::WidthInBytes::TWO_BYTES, 0x0fff); - pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00); - pduConf.destId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff); + pduConf.seqNum.setValueAndWidth(cfdp::WidthInBytes::TWO_BYTES, 0x0fff); + pduConf.sourceId.setValueAndWidth(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00); + pduConf.destId.setValueAndWidth(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff); for (uint8_t idx = 0; idx < 14; idx++) { REQUIRE(creator.serialize(&serTarget, &serSize, idx, SerializeIF::Endianness::BIG) == SerializeIF::BUFFER_TOO_SHORT); @@ -157,11 +157,11 @@ TEST_CASE("CFDP Header", "[cfdp]") { } SECTION("Invalid Variable Sized Fields") { - result = pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 0xfff); + result = pduConf.sourceId.setValueAndWidth(cfdp::WidthInBytes::ONE_BYTE, 0xfff); REQUIRE(result == returnvalue::FAILED); - result = pduConf.sourceId.setValue(cfdp::WidthInBytes::TWO_BYTES, 0xfffff); + result = pduConf.sourceId.setValueAndWidth(cfdp::WidthInBytes::TWO_BYTES, 0xfffff); REQUIRE(result == returnvalue::FAILED); - result = pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xfffffffff); + result = pduConf.sourceId.setValueAndWidth(cfdp::WidthInBytes::FOUR_BYTES, 0xfffffffff); REQUIRE(result == returnvalue::FAILED); } @@ -207,7 +207,7 @@ TEST_CASE("CFDP Header", "[cfdp]") { SerializeIF::Endianness::MACHINE); REQUIRE(pduConf.sourceId.getValue() == 0xf0f0f0f0); - pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 1); + pduConf.sourceId.setValueAndWidth(cfdp::WidthInBytes::ONE_BYTE, 1); serTarget = serBuf.data(); serSize = 1; result = pduConf.sourceId.serialize(&serTarget, &serSize, 1, SerializeIF::Endianness::MACHINE); @@ -257,11 +257,11 @@ TEST_CASE("CFDP Header", "[cfdp]") { creator.setSegmentationControl(cfdp::SegmentationControl::RECORD_BOUNDARIES_PRESERVATION); creator.setPduType(cfdp::PduType::FILE_DATA); creator.setSegmentMetadataFlag(cfdp::SegmentMetadataFlag::PRESENT); - result = pduConf.seqNum.setValue(cfdp::WidthInBytes::TWO_BYTES, 0x0fff); + result = pduConf.seqNum.setValueAndWidth(cfdp::WidthInBytes::TWO_BYTES, 0x0fff); REQUIRE(result == returnvalue::OK); - result = pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00); + result = pduConf.sourceId.setValueAndWidth(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00); REQUIRE(result == returnvalue::OK); - result = pduConf.destId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff); + result = pduConf.destId.setValueAndWidth(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff); REQUIRE(result == returnvalue::OK); serTarget = serBuf.data(); serSize = 0; @@ -302,8 +302,8 @@ TEST_CASE("CFDP Header", "[cfdp]") { SECTION("Manipulate Source Dest ID") { serTarget = serBuf.data(); serSize = 0; - pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 22); - pduConf.destId.setValue(cfdp::WidthInBytes::ONE_BYTE, 48); + pduConf.sourceId.setValueAndWidth(cfdp::WidthInBytes::ONE_BYTE, 22); + pduConf.destId.setValueAndWidth(cfdp::WidthInBytes::ONE_BYTE, 48); result = creator.serialize(&serTarget, &serSize, serBuf.size(), SerializeIF::Endianness::BIG); reader.getSourceId(sourceDestId); REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::ONE_BYTE); diff --git a/unittests/cfdp/pdu/testEofPdu.cpp b/unittests/cfdp/pdu/testEofPdu.cpp index 83e61780..0eb0342b 100644 --- a/unittests/cfdp/pdu/testEofPdu.cpp +++ b/unittests/cfdp/pdu/testEofPdu.cpp @@ -14,7 +14,7 @@ TEST_CASE("EOF PDU", "[cfdp][pdu]") { size_t sz = 0; EntityId destId(WidthInBytes::TWO_BYTES, 2); EntityIdTlv faultLoc(destId); - FileSize fileSize(12); + Fss 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); diff --git a/unittests/cfdp/pdu/testFileData.cpp b/unittests/cfdp/pdu/testFileData.cpp index 39139378..80b02603 100644 --- a/unittests/cfdp/pdu/testFileData.cpp +++ b/unittests/cfdp/pdu/testFileData.cpp @@ -22,7 +22,7 @@ TEST_CASE("File Data PDU", "[cfdp][pdu]") { for (uint8_t idx = 0; idx < 10; idx++) { fileBuffer[idx] = idx; } - FileSize offset(50); + Fss offset(50); FileDataInfo info(offset, fileBuffer.data(), 10); SECTION("Serialization") { @@ -107,8 +107,7 @@ TEST_CASE("File Data PDU", "[cfdp][pdu]") { serializer.serialize(&buffer, &sz, fileDataBuffer.size(), SerializeIF::Endianness::NETWORK); REQUIRE(result == returnvalue::OK); - FileSize emptyOffset; - FileDataInfo emptyInfo(emptyOffset); + FileDataInfo emptyInfo; FileDataReader deserializer(fileDataBuffer.data(), fileDataBuffer.size(), emptyInfo); result = deserializer.parseData(); REQUIRE(result == returnvalue::OK); diff --git a/unittests/cfdp/pdu/testKeepAlivePdu.cpp b/unittests/cfdp/pdu/testKeepAlivePdu.cpp index d07bccae..f8eeda42 100644 --- a/unittests/cfdp/pdu/testKeepAlivePdu.cpp +++ b/unittests/cfdp/pdu/testKeepAlivePdu.cpp @@ -16,7 +16,7 @@ TEST_CASE("Keep Alive PDU", "[cfdp][pdu]") { EntityId sourceId(WidthInBytes::TWO_BYTES, 1); PduConfig pduConf(sourceId, destId, TransmissionMode::ACKNOWLEDGED, seqNum); - FileSize progress(0x50); + Fss progress(0x50); SECTION("Serialize") { KeepAlivePduCreator serializer(pduConf, progress); diff --git a/unittests/cfdp/pdu/testMetadataPdu.cpp b/unittests/cfdp/pdu/testMetadataPdu.cpp index a9f8bf86..e13b4717 100644 --- a/unittests/cfdp/pdu/testMetadataPdu.cpp +++ b/unittests/cfdp/pdu/testMetadataPdu.cpp @@ -6,11 +6,10 @@ #include "fsfw/cfdp/pdu/MetadataPduReader.h" #include "fsfw/cfdp/tlv/FilestoreResponseTlv.h" #include "fsfw/cfdp/tlv/MessageToUserTlv.h" -#include "fsfw/globalfunctions/arrayprinter.h" TEST_CASE("Metadata PDU", "[cfdp][pdu]") { using namespace cfdp; - ReturnValue_t result = returnvalue::OK; + ReturnValue_t result; std::array mdBuffer = {}; uint8_t* buffer = mdBuffer.data(); size_t sz = 0; @@ -22,30 +21,22 @@ TEST_CASE("Metadata PDU", "[cfdp][pdu]") { std::string firstFileName = "hello.txt"; cfdp::StringLv sourceFileName(firstFileName); cfdp::StringLv destFileName; - FileSize fileSize(35); - MetadataInfo info(false, ChecksumType::MODULAR, fileSize, sourceFileName, destFileName); + Fss fileSize(35); + MetadataGenericInfo info(false, ChecksumType::MODULAR, fileSize); 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}; + std::array tlvDeser{}; REQUIRE(options[0]->getSerializedSize() == 2 + 1 + 10 + 1); REQUIRE(options[1]->getSerializedSize() == 5); - SECTION("Serialize") { - MetadataPduCreator serializer(pduConf, info); - result = serializer.serialize(&buffer, &sz, mdBuffer.size(), SerializeIF::Endianness::NETWORK); - REQUIRE(result == returnvalue::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); + auto metadataCheckPartOne = [&]() { REQUIRE(mdBuffer[10] == FileDirective::METADATA); // no closure requested and checksum type is modular => 0x00 REQUIRE(mdBuffer[11] == 0x00); @@ -64,20 +55,59 @@ TEST_CASE("Metadata PDU", "[cfdp][pdu]") { REQUIRE(mdBuffer[23] == 't'); REQUIRE(mdBuffer[24] == 'x'); REQUIRE(mdBuffer[25] == 't'); - REQUIRE(mdBuffer[26] == 0); + }; + SECTION("Serialize with empty dest name") { + MetadataPduCreator serializer(pduConf, info, sourceFileName, destFileName, nullptr, 0); + result = serializer.serialize(&buffer, &sz, mdBuffer.size(), SerializeIF::Endianness::NETWORK); + REQUIRE(result == returnvalue::OK); + CHECK(sz == serializer.getSerializedSize()); + // 10 byte heater + 1 byte PDU directive field + 1 byte PDU content + FSS field (4) + source + // name field (10) + dest name field (1). + REQUIRE(serializer.getWholePduSize() == 27); + REQUIRE(serializer.getSourceFileName().getSerializedSize() == 10); + REQUIRE(serializer.getDestFileName().getSerializedSize() == 1); + REQUIRE(info.getSerializedSize() == 5); + REQUIRE((mdBuffer[1] << 8 | mdBuffer[2]) == 17); + REQUIRE(serializer.getSerializedSize() == serializer.getWholePduSize()); + metadataCheckPartOne(); + REQUIRE(mdBuffer[26] == 0); + } + + SECTION("Serialize with dest name") { + std::string secondFileName = "hello2.txt"; + cfdp::StringLv destFileName2(secondFileName); + MetadataPduCreator serializer(pduConf, info, sourceFileName, destFileName2, nullptr, 0); + result = serializer.serialize(&buffer, &sz, mdBuffer.size(), SerializeIF::Endianness::NETWORK); + REQUIRE(result == returnvalue::OK); + // 10 byte heater + 1 byte PDU directive field + 1 byte PDU content + FSS field (4) + source + // name field (10) + dest name field (11). + REQUIRE(serializer.getWholePduSize() == 37); + CHECK(sz == serializer.getSerializedSize()); + REQUIRE((mdBuffer[1] << 8 | mdBuffer[2]) == 27); + REQUIRE(serializer.getSerializedSize() == serializer.getWholePduSize()); + metadataCheckPartOne(); + // Size of destination name field + REQUIRE(mdBuffer[26] == 10); + REQUIRE(mdBuffer[27] == 'h'); + REQUIRE(mdBuffer[28] == 'e'); + REQUIRE(mdBuffer[29] == 'l'); + REQUIRE(mdBuffer[30] == 'l'); + REQUIRE(mdBuffer[31] == 'o'); + REQUIRE(mdBuffer[32] == '2'); + REQUIRE(mdBuffer[33] == '.'); + REQUIRE(mdBuffer[34] == 't'); + REQUIRE(mdBuffer[35] == 'x'); + REQUIRE(mdBuffer[36] == 't'); + } + + SECTION("Serialize with 2 options") { std::string otherFileName = "hello2.txt"; cfdp::StringLv otherFileNameLv(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); + MetadataPduCreator serializer(pduConf, info, otherFileNameLv, destFileName, options.data(), + options.size()); 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); @@ -98,49 +128,47 @@ TEST_CASE("Metadata PDU", "[cfdp][pdu]") { // TLV unittests REQUIRE(sz == 10 + 37); for (size_t maxSz = 0; maxSz < sz; maxSz++) { - uint8_t* buffer = mdBuffer.data(); - size_t sz = 0; + buffer = mdBuffer.data(); + 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; + buffer = mdBuffer.data(); + sz = initSz; result = serializer.serialize(&buffer, &sz, 46, SerializeIF::Endianness::NETWORK); REQUIRE(result == SerializeIF::BUFFER_TOO_SHORT); } - info.setDestFileName(destFileName); } SECTION("Deserialize") { - MetadataPduCreator serializer(pduConf, info); + MetadataPduCreator serializer(pduConf, info, sourceFileName, destFileName, nullptr, 0); result = serializer.serialize(&buffer, &sz, mdBuffer.size(), SerializeIF::Endianness::NETWORK); REQUIRE(result == returnvalue::OK); - MetadataPduReader deserializer(mdBuffer.data(), mdBuffer.size(), info); + MetadataPduReader deserializer(mdBuffer.data(), mdBuffer.size(), info, nullptr, 0); result = deserializer.parseData(); REQUIRE(result == returnvalue::OK); size_t fullSize = deserializer.getWholePduSize(); for (size_t maxSz = 0; maxSz < fullSize; maxSz++) { - MetadataPduReader invalidSzDeser(mdBuffer.data(), maxSz, info); + MetadataPduReader invalidSzDeser(mdBuffer.data(), maxSz, info, nullptr, 0); result = invalidSzDeser.parseData(); REQUIRE(result != returnvalue::OK); } - size_t sizeOfOptions = options.size(); - size_t maxSize = 4; - info.setOptionsArray(options.data(), sizeOfOptions, maxSize); - REQUIRE(info.getOptionsLen() == 2); + } + + SECTION("Deserialize with 2 options") { + MetadataPduCreator serializer(pduConf, info, sourceFileName, destFileName, options.data(), + options.size()); 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 == returnvalue::OK); - MetadataPduReader deserializer2(mdBuffer.data(), mdBuffer.size(), info); + MetadataPduReader deserializer2(mdBuffer.data(), mdBuffer.size(), info, tlvDeser.data(), + tlvDeser.max_size()); result = deserializer2.parseData(); REQUIRE(result == returnvalue::OK); REQUIRE(options[0]->getType() == cfdp::TlvType::FILESTORE_RESPONSE); @@ -151,12 +179,15 @@ TEST_CASE("Metadata PDU", "[cfdp][pdu]") { for (size_t invalidFieldLen = 0; invalidFieldLen < 36; invalidFieldLen++) { mdBuffer[1] = (invalidFieldLen >> 8) & 0xff; mdBuffer[2] = invalidFieldLen & 0xff; + if (invalidFieldLen == 17) { + volatile uint32_t dummy = 0; + } result = deserializer2.parseData(); if (invalidFieldLen == 17) { - REQUIRE(info.getOptionsLen() == 0); + REQUIRE(deserializer2.getNumberOfParsedOptions() == 0); } if (invalidFieldLen == 31) { - REQUIRE(info.getOptionsLen() == 1); + REQUIRE(deserializer2.getNumberOfParsedOptions() == 1); } // This is the precise length where there are no options or one option if (invalidFieldLen != 17 and invalidFieldLen != 31) { @@ -165,11 +196,25 @@ TEST_CASE("Metadata PDU", "[cfdp][pdu]") { } mdBuffer[1] = (36 >> 8) & 0xff; mdBuffer[2] = 36 & 0xff; - info.setOptionsArray(nullptr, std::nullopt, std::nullopt); + } + + SECTION("Can not parse options") { + MetadataPduCreator serializer(pduConf, info, sourceFileName, destFileName, options.data(), + options.size()); + info.setChecksumType(cfdp::ChecksumType::CRC_32C); + info.setClosureRequested(true); + buffer = mdBuffer.data(); + sz = 0; + serializer.updateDirectiveFieldLen(); + + // info.setSourceFileName(sourceFileName); + result = serializer.serialize(&buffer, &sz, mdBuffer.size(), SerializeIF::Endianness::NETWORK); + REQUIRE(result == returnvalue::OK); + + MetadataPduReader deserializer2(mdBuffer.data(), mdBuffer.size(), info, nullptr, 0); REQUIRE(deserializer2.parseData() == cfdp::METADATA_CANT_PARSE_OPTIONS); - info.setOptionsArray(options.data(), sizeOfOptions, std::nullopt); for (size_t maxSz = 0; maxSz < 46; maxSz++) { - MetadataPduReader invalidSzDeser(mdBuffer.data(), maxSz, info); + MetadataPduReader invalidSzDeser(mdBuffer.data(), maxSz, info, nullptr, 0); if (not invalidSzDeser.isNull()) { result = invalidSzDeser.parseData(); REQUIRE(result == SerializeIF::STREAM_TOO_SHORT); diff --git a/unittests/cfdp/pdu/testNakPdu.cpp b/unittests/cfdp/pdu/testNakPdu.cpp index 7974dab1..c3650c63 100644 --- a/unittests/cfdp/pdu/testNakPdu.cpp +++ b/unittests/cfdp/pdu/testNakPdu.cpp @@ -17,8 +17,8 @@ TEST_CASE("NAK PDU", "[cfdp][pdu]") { EntityId sourceId(WidthInBytes::TWO_BYTES, 1); PduConfig pduConf(sourceId, destId, TransmissionMode::ACKNOWLEDGED, seqNum); - FileSize startOfScope(50); - FileSize endOfScope(1050); + Fss startOfScope(50); + Fss endOfScope(1050); NakInfo info(startOfScope, endOfScope); SECTION("Serializer") { NakPduCreator serializer(pduConf, info); @@ -40,8 +40,8 @@ TEST_CASE("NAK PDU", "[cfdp][pdu]") { REQUIRE(result == returnvalue::OK); REQUIRE(scope == 1050); - NakInfo::SegmentRequest segReq0(cfdp::FileSize(2020), cfdp::FileSize(2520)); - NakInfo::SegmentRequest segReq1(cfdp::FileSize(2932), cfdp::FileSize(3021)); + NakInfo::SegmentRequest segReq0(cfdp::Fss(2020), cfdp::Fss(2520)); + NakInfo::SegmentRequest segReq1(cfdp::Fss(2932), cfdp::Fss(3021)); // Now add 2 segment requests to NAK info and serialize them as well std::array segReqs = {segReq0, segReq1}; size_t segReqsLen = segReqs.size(); @@ -100,8 +100,8 @@ TEST_CASE("NAK PDU", "[cfdp][pdu]") { 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)); + NakInfo::SegmentRequest segReq0(cfdp::Fss(2020), cfdp::Fss(2520)); + NakInfo::SegmentRequest segReq1(cfdp::Fss(2932), cfdp::Fss(3021)); // Now add 2 segment requests to NAK info and serialize them as well std::array segReqs = {segReq0, segReq1}; size_t segReqsLen = segReqs.size(); diff --git a/unittests/cfdp/testCfdp.cpp b/unittests/cfdp/testCfdp.cpp index 467b5b2d..60b14b77 100644 --- a/unittests/cfdp/testCfdp.cpp +++ b/unittests/cfdp/testCfdp.cpp @@ -2,7 +2,7 @@ #include #include -#include "fsfw/cfdp/FileSize.h" +#include "fsfw/cfdp/Fss.h" #include "fsfw/cfdp/pdu/FileDirectiveCreator.h" #include "fsfw/cfdp/pdu/FileDirectiveReader.h" #include "fsfw/globalfunctions/arrayprinter.h" @@ -79,7 +79,7 @@ TEST_CASE("CFDP Base", "[cfdp]") { std::array fssBuf = {}; uint8_t* buffer = fssBuf.data(); size_t size = 0; - cfdp::FileSize fss; + cfdp::Fss fss; REQUIRE(fss.getSize() == 0); fss.setFileSize(0x20, false); result = fss.serialize(&buffer, &size, fssBuf.size(), SerializeIF::Endianness::MACHINE); diff --git a/unittests/cfdp/testLvs.cpp b/unittests/cfdp/testLvs.cpp index 22094568..8415f0d8 100644 --- a/unittests/cfdp/testLvs.cpp +++ b/unittests/cfdp/testLvs.cpp @@ -23,12 +23,6 @@ TEST_CASE("CFDP LV", "[cfdp][lv]") { auto lv = cfdp::Lv(lvRawBuf.data(), 2); REQUIRE(lv.getSerializedSize() == 3); - SECTION("Copy") { - auto lvCopy = cfdp::Lv(lv); - REQUIRE(lvCopy.getSerializedSize() == 3); - REQUIRE(lv.getValue(nullptr) == lvCopy.getValue(nullptr)); - } - serPtr = rawBuf.data(); deserSize = 0; REQUIRE(lv.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK) == @@ -41,6 +35,16 @@ TEST_CASE("CFDP LV", "[cfdp][lv]") { REQUIRE(sourceIdRaw == 0x0ff0); } + SECTION("Move LV") { + std::array lvRawBuf{}; + serPtr = lvRawBuf.data(); + REQUIRE(sourceId.serialize(&serPtr, &deserSize, lvRawBuf.size(), + SerializeIF::Endianness::NETWORK) == returnvalue::OK); + auto lv = cfdp::Lv(lvRawBuf.data(), 2); + auto lvMovedCopy = cfdp::Lv(std::move(lv)); + REQUIRE(lvMovedCopy.getSerializedSize() == 3); + } + SECTION("Empty Serialization") { auto lvEmpty = Lv(); REQUIRE(lvEmpty.getSerializedSize() == 1); diff --git a/unittests/cfdp/testReservedMsgCreator.cpp b/unittests/cfdp/testReservedMsgCreator.cpp new file mode 100644 index 00000000..1873becf --- /dev/null +++ b/unittests/cfdp/testReservedMsgCreator.cpp @@ -0,0 +1,49 @@ +#include +#include + +#include "fsfw/cfdp/VarLenFields.h" +#include "fsfw/cfdp/tlv/ReservedMessageCreator.h" +#include "fsfw/cfdp/tlv/StringLv.h" + +TEST_CASE("Reserved Message Creator", "[cfdp][tlv]") { + using namespace cfdp; + using namespace returnvalue; + + std::string srcFileName = "hello.txt"; + std::string destFileName = "hello2.txt"; + std::array buffer{}; + uint8_t msgBuf[32]{}; + EntityId entityId(cfdp::WidthInBytes::ONE_BYTE, 5); + uint8_t* msgBufPtr = msgBuf; + size_t serLen = 0; + cfdp::StringLv srcName(srcFileName); + cfdp::StringLv destName(destFileName); + CHECK(entityId.serializeAsLv(&msgBufPtr, &serLen, sizeof(msgBuf)) == OK); + CHECK(srcName.serialize(&msgBufPtr, &serLen, sizeof(msgBuf), SerializeIF::Endianness::NETWORK) == + OK); + CHECK(destName.serialize(&msgBufPtr, &serLen, sizeof(msgBuf), SerializeIF::Endianness::NETWORK) == + OK); + ReservedMessageCreator creator(static_cast(ProxyOpMessageType::PUT_REQUEST), msgBuf, + serLen); + serLen = 0; + ReturnValue_t result = creator.serializeBe(buffer.data(), serLen, buffer.size()); + CHECK(result == returnvalue::OK); + CHECK(buffer[0] == TlvType::MSG_TO_USER); + // 4 bytes "cfdp" header, 1 byte message type, entity ID LV, source name LV and dest name LV + CHECK(buffer[1] == + 5 + 1 + entityId.getSerializedSize() + 1 + srcFileName.size() + 1 + destFileName.size()); + CHECK(buffer[2] == 'c'); + CHECK(buffer[3] == 'f'); + CHECK(buffer[4] == 'd'); + CHECK(buffer[5] == 'p'); + CHECK(buffer[6] == static_cast(ProxyOpMessageType::PUT_REQUEST)); + CHECK(buffer[7] == 1); + CHECK(buffer[8] == entityId.getValue()); + CHECK(buffer[9] == srcFileName.size()); + size_t currentIdx = 10; + CHECK(std::string(reinterpret_cast(buffer.data()) + currentIdx, + srcFileName.size()) == srcFileName); + currentIdx += srcFileName.size() + 1; + CHECK(std::string(reinterpret_cast(buffer.data()) + currentIdx, + destFileName.size()) == destFileName); +} diff --git a/unittests/cfdp/testTlv.cpp b/unittests/cfdp/testTlv.cpp index 979bfac5..020365f8 100644 --- a/unittests/cfdp/testTlv.cpp +++ b/unittests/cfdp/testTlv.cpp @@ -40,7 +40,7 @@ TEST_CASE("CFDP TLV", "[cfdp][tlv]") { SECTION("TLV Other Value") { auto tlv = Tlv(TlvType::ENTITY_ID, rawBuf.data(), deserSize); // Set new value - sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 12); + sourceId.setValueAndWidth(cfdp::WidthInBytes::FOUR_BYTES, 12); REQUIRE(sourceId.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK) == returnvalue::OK); tlv.setValue(rawBuf.data(), cfdp::WidthInBytes::FOUR_BYTES); diff --git a/unittests/datapoollocal/testLocalPoolManager.cpp b/unittests/datapoollocal/testLocalPoolManager.cpp index e463a123..1913474e 100644 --- a/unittests/datapoollocal/testLocalPoolManager.cpp +++ b/unittests/datapoollocal/testLocalPoolManager.cpp @@ -82,7 +82,7 @@ TEST_CASE("Local Pool Manager Tests", "[LocManTest]") { REQUIRE(poolOwnerMock.getNextSentMessage(subscriberId, messageSent) == returnvalue::OK); CHECK(messageSent.getCommand() == static_cast(HousekeepingMessage::UPDATE_NOTIFICATION_SET)); - REQUIRE(poolOwnerMock.getNextSentMessage(messageSent) == returnvalue::OK); + REQUIRE(poolOwnerMock.getNextSentMessageToDefaultDest(messageSent) == returnvalue::OK); CHECK(messageSent.getCommand() == static_cast(HousekeepingMessage::HK_REPORT)); /* Clear message to avoid memory leak, our mock won't do it for us (yet) */ CommandMessageCleaner::clearCommandMessage(&messageSent); @@ -259,11 +259,11 @@ TEST_CASE("Local Pool Manager Tests", "[LocManTest]") { CHECK(messageSent.getCommand() == static_cast(HousekeepingMessage::UPDATE_NOTIFICATION_SET)); REQUIRE(poolOwnerMock.clearLastSentMessage(subscriberId) == returnvalue::OK); - REQUIRE(poolOwnerMock.getNextSentMessage(messageSent) == returnvalue::OK); + REQUIRE(poolOwnerMock.getNextSentMessageToDefaultDest(messageSent) == returnvalue::OK); CHECK(messageSent.getCommand() == static_cast(HousekeepingMessage::HK_REPORT)); REQUIRE(poolOwnerMock.clearLastSentMessage() == returnvalue::OK); REQUIRE(poolOwnerMock.getNextSentMessage(subscriberId, messageSent) == MessageQueueIF::EMPTY); - REQUIRE(poolOwnerMock.getNextSentMessage(messageSent) == MessageQueueIF::EMPTY); + REQUIRE(poolOwnerMock.getNextSentMessageToDefaultDest(messageSent) == MessageQueueIF::EMPTY); } SECTION("PeriodicHKAndMessaging") { diff --git a/unittests/mocks/AcceptsTmMock.h b/unittests/mocks/AcceptsTmMock.h index b12e1094..c736c952 100644 --- a/unittests/mocks/AcceptsTmMock.h +++ b/unittests/mocks/AcceptsTmMock.h @@ -9,8 +9,8 @@ class AcceptsTmMock : public SystemObject, public AcceptsTelemetryIF { AcceptsTmMock(object_id_t registeredId, MessageQueueId_t queueToReturn); explicit AcceptsTmMock(MessageQueueId_t queueToReturn); - MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel) const override; - const char* getName() const override; + [[nodiscard]] MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel) const override; + [[nodiscard]] const char* getName() const override; MessageQueueId_t returnedQueue; }; diff --git a/unittests/mocks/FilesystemMock.cpp b/unittests/mocks/FilesystemMock.cpp index 24850227..51c0c686 100644 --- a/unittests/mocks/FilesystemMock.cpp +++ b/unittests/mocks/FilesystemMock.cpp @@ -39,7 +39,8 @@ ReturnValue_t FilesystemMock::readFromFile(FileOpParams params, uint8_t **buffer if (readSize + readLen > maxSize) { return SerializeIF::STREAM_TOO_SHORT; } - std::copy(info.fileRaw.data() + params.offset, info.fileRaw.data() + readLen, *buffer); + std::copy(info.fileRaw.data() + params.offset, info.fileRaw.data() + params.offset + readLen, + *buffer); *buffer += readLen; readSize += readLen; } @@ -80,7 +81,7 @@ ReturnValue_t FilesystemMock::removeDirectory(FilesystemParams params, bool dele ReturnValue_t FilesystemMock::rename(const char *oldPath, const char *newPath, FileSystemArgsIF *args) { - renameQueue.push(RenameInfo(oldPath, newPath)); + renameQueue.emplace(oldPath, newPath); return returnvalue::OK; } @@ -90,7 +91,7 @@ void FilesystemMock::createOrAddToFile(FileOpParams params, const uint8_t *data) if (iter == fileMap.end()) { FileSegmentQueue queue; if (params.size > 0) { - queue.push(FileWriteInfo(filename, params.offset, data, params.size)); + queue.emplace(filename, params.offset, data, params.size); } FileInfo info; info.fileSegQueue = queue; @@ -100,7 +101,7 @@ void FilesystemMock::createOrAddToFile(FileOpParams params, const uint8_t *data) fileMap.emplace(filename, info); } else { FileInfo &info = iter->second; - info.fileSegQueue.push(FileWriteInfo(filename, params.offset, data, params.size)); + info.fileSegQueue.emplace(filename, params.offset, data, params.size); if (data == nullptr) { return; } @@ -145,3 +146,13 @@ ReturnValue_t FilesystemMock::getBaseFilename(FilesystemParams params, char *nam } bool FilesystemMock::isDirectory(const char *path) { return false; } + +bool FilesystemMock::getFileSize(FilesystemParams params, size_t &fileSize) { + std::string filename(params.path); + auto iter = fileMap.find(filename); + if (iter != fileMap.end()) { + fileSize = iter->second.fileRaw.size(); + return true; + } + return false; +} diff --git a/unittests/mocks/FilesystemMock.h b/unittests/mocks/FilesystemMock.h index 2ddbefc3..b24d5c4c 100644 --- a/unittests/mocks/FilesystemMock.h +++ b/unittests/mocks/FilesystemMock.h @@ -62,6 +62,7 @@ class FilesystemMock : public HasFileSystemIF { bool isDirectory(const char *path) override; bool fileExists(FilesystemParams params) override; ReturnValue_t truncateFile(FilesystemParams params) override; + bool getFileSize(FilesystemParams params, size_t &fileSize) override; ReturnValue_t writeToFile(FileOpParams params, const uint8_t *data) override; ReturnValue_t readFromFile(FileOpParams params, uint8_t **buffer, size_t &readSize, diff --git a/unittests/mocks/MessageQueueMock.cpp b/unittests/mocks/MessageQueueMock.cpp index cac5a0d9..96a6ee86 100644 --- a/unittests/mocks/MessageQueueMock.cpp +++ b/unittests/mocks/MessageQueueMock.cpp @@ -124,7 +124,7 @@ ReturnValue_t MessageQueueMock::getNextSentMessage(MessageQueueId_t id, return returnvalue::OK; } -ReturnValue_t MessageQueueMock::getNextSentMessage(MessageQueueMessageIF& message) { +ReturnValue_t MessageQueueMock::getNextSentMessageToDefaultDest(MessageQueueMessageIF& message) { return getNextSentMessage(MessageQueueBase::getDefaultDestination(), message); } diff --git a/unittests/mocks/MessageQueueMock.h b/unittests/mocks/MessageQueueMock.h index 52ba5dfe..cacb72e4 100644 --- a/unittests/mocks/MessageQueueMock.h +++ b/unittests/mocks/MessageQueueMock.h @@ -26,7 +26,7 @@ class MessageQueueMock : public MessageQueueBase { explicit MessageQueueMock(MessageQueueId_t queueId); //! Get next message which was sent to the default destination - ReturnValue_t getNextSentMessage(MessageQueueMessageIF& message); + ReturnValue_t getNextSentMessageToDefaultDest(MessageQueueMessageIF& message); //! Get message which was sent to a specific ID ReturnValue_t getNextSentMessage(MessageQueueId_t id, MessageQueueMessageIF& message); [[nodiscard]] bool wasMessageSent() const; diff --git a/unittests/mocks/StorageManagerMock.h b/unittests/mocks/StorageManagerMock.h index a0a59a47..ce5f3811 100644 --- a/unittests/mocks/StorageManagerMock.h +++ b/unittests/mocks/StorageManagerMock.h @@ -32,6 +32,7 @@ class StorageManagerMock : public LocalPool { std::pair nextFreeElementCallFails; using LocalPool::getFreeElement; + using StorageManagerIF::getData; void reset(); }; diff --git a/unittests/mocks/cfdp/UserMock.cpp b/unittests/mocks/cfdp/UserMock.cpp index ca15a5e6..78223506 100644 --- a/unittests/mocks/cfdp/UserMock.cpp +++ b/unittests/mocks/cfdp/UserMock.cpp @@ -4,19 +4,20 @@ namespace cfdp { cfdp::UserMock::UserMock(HasFileSystemIF& vfs) : UserBase(vfs) {} -void UserMock::transactionIndication(const TransactionId& id) {} -void UserMock::eofSentIndication(const TransactionId& id) {} +void UserMock::transactionIndication(const TransactionId& id) { transactionIndicRecvd.emplace(id); } + +void UserMock::eofSentIndication(const TransactionId& id) { eofSentRecvd.emplace(id); } void UserMock::abandonedIndication(const TransactionId& id, cfdp::ConditionCode code, uint64_t progress) {} -void UserMock::eofRecvIndication(const TransactionId& id) { eofsRevd.push(id); } +void UserMock::eofRecvIndication(const TransactionId& id) { eofRecvdRecvd.push(id); } void UserMock::transactionFinishedIndication(const TransactionFinishedParams& finishedParams) { - finishedRecvd.push({finishedParams.id, finishedParams}); + finishedRecvd.emplace(finishedParams.id, finishedParams); } void UserMock::metadataRecvdIndication(const MetadataRecvdParams& params) { - metadataRecvd.push({params.id, params}); + metadataRecvd.emplace(params.id, params); } void UserMock::fileSegmentRecvdIndication(const FileSegmentRecvdParams& params) {} @@ -27,7 +28,7 @@ void UserMock::faultIndication(const TransactionId& id, cfdp::ConditionCode code } void UserMock::reset() { - std::queue().swap(eofsRevd); + std::queue().swap(eofRecvdRecvd); std::queue>().swap(metadataRecvd); std::queue>().swap(finishedRecvd); } diff --git a/unittests/mocks/cfdp/UserMock.h b/unittests/mocks/cfdp/UserMock.h index e2a4a483..ad9e152d 100644 --- a/unittests/mocks/cfdp/UserMock.h +++ b/unittests/mocks/cfdp/UserMock.h @@ -23,8 +23,10 @@ class UserMock : public UserBase { void resumedIndication(const TransactionId& id, size_t progress) override; void faultIndication(const TransactionId& id, ConditionCode code, size_t progress) override; + std::queue transactionIndicRecvd; std::queue> metadataRecvd; - std::queue eofsRevd; + std::queue eofRecvdRecvd; + std::queue eofSentRecvd; std::queue> finishedRecvd; void reset(); }; diff --git a/unittests/tmtcservices/testSendHelper.cpp b/unittests/tmtcservices/testSendHelper.cpp index 43816835..07315e44 100644 --- a/unittests/tmtcservices/testSendHelper.cpp +++ b/unittests/tmtcservices/testSendHelper.cpp @@ -71,7 +71,7 @@ TEST_CASE("TM Send Helper", "[tm-send-helper]") { REQUIRE(msgQueue.wasMessageSent()); REQUIRE(msgQueue.numberOfSentMessagesToDefault() == 1); TmTcMessage msg; - REQUIRE(msgQueue.getNextSentMessage(msg) == returnvalue::OK); + REQUIRE(msgQueue.getNextSentMessageToDefaultDest(msg) == returnvalue::OK); REQUIRE(msg.getStorageId() == storeId); REQUIRE(pool.hasDataAtId(msg.getStorageId())); } diff --git a/unittests/tmtcservices/testStoreAndSendHelper.cpp b/unittests/tmtcservices/testStoreAndSendHelper.cpp index 46418dfe..6fe9f8e2 100644 --- a/unittests/tmtcservices/testStoreAndSendHelper.cpp +++ b/unittests/tmtcservices/testStoreAndSendHelper.cpp @@ -52,7 +52,7 @@ TEST_CASE("TM Store And Send Helper", "[tm-store-send-helper]") { REQUIRE(msgQueue.wasMessageSent()); REQUIRE(msgQueue.numberOfSentMessagesToDefault() == 1); TmTcMessage msg; - REQUIRE(msgQueue.getNextSentMessage(msg) == returnvalue::OK); + REQUIRE(msgQueue.getNextSentMessageToDefaultDest(msg) == returnvalue::OK); REQUIRE(msg.getStorageId() == storeId); REQUIRE(pool.hasDataAtId(msg.getStorageId())); storeHelper.deletePacket(); diff --git a/unittests/util/CMakeLists.txt b/unittests/util/CMakeLists.txt index fb660d54..47c10569 100644 --- a/unittests/util/CMakeLists.txt +++ b/unittests/util/CMakeLists.txt @@ -1 +1,2 @@ -target_sources(${FSFW_TEST_TGT} PRIVATE testUnsignedByteField.cpp) +target_sources(${FSFW_TEST_TGT} PRIVATE testUnsignedByteField.cpp + testSeqCountProvider.cpp) diff --git a/unittests/util/testSeqCountProvider.cpp b/unittests/util/testSeqCountProvider.cpp new file mode 100644 index 00000000..fce8bf43 --- /dev/null +++ b/unittests/util/testSeqCountProvider.cpp @@ -0,0 +1,35 @@ +#include + +#include "fsfw/util/SeqCountProvider.h" + +TEST_CASE("Seq Count Providers", "[util]") { + auto genericProviderTest = [](ProvidesSeqCountIF& provider, unsigned expectedWidth) { + CHECK(provider.get() == 0); + CHECK(provider.bitWidth() == expectedWidth); + CHECK(provider.getAndIncrement() == 0); + CHECK(provider.getAndIncrement() == 1); + CHECK(provider.get() == 2); + provider.increment(); + provider.increment(); + CHECK(provider.get() == 4); + }; + { + SeqCountProviderU16 provider; + genericProviderTest(provider, 16); + } + + { + SeqCountProviderU32 provider; + genericProviderTest(provider, 32); + } + + { + SeqCountProviderU8 provider; + genericProviderTest(provider, 8); + for (unsigned i = 4; i < UINT8_MAX + 1; i++) { + provider.increment(); + } + // Verify wrap-around. + CHECK(provider.get() == 0); + } +}