diff --git a/src/fsfw/cfdp.h b/src/fsfw/cfdp.h index 28ddfec2..86086432 100644 --- a/src/fsfw/cfdp.h +++ b/src/fsfw/cfdp.h @@ -2,7 +2,6 @@ #define FSFW_CFDP_H #include "cfdp/definitions.h" -#include "cfdp/handler/DestHandler.h" #include "cfdp/handler/FaultHandlerBase.h" #include "cfdp/tlv/Lv.h" #include "cfdp/tlv/StringLv.h" diff --git a/src/fsfw/cfdp/handler/CMakeLists.txt b/src/fsfw/cfdp/handler/CMakeLists.txt index 7ad995c0..90130806 100644 --- a/src/fsfw/cfdp/handler/CMakeLists.txt +++ b/src/fsfw/cfdp/handler/CMakeLists.txt @@ -1,2 +1 @@ -target_sources(${LIB_FSFW_NAME} PRIVATE SourceHandler.cpp DestHandler.cpp - FaultHandlerBase.cpp UserBase.cpp) +target_sources(${LIB_FSFW_NAME} PRIVATE FaultHandlerBase.cpp UserBase.cpp) diff --git a/src/fsfw/cfdp/handler/DestHandler.cpp b/src/fsfw/cfdp/handler/DestHandler.cpp deleted file mode 100644 index d43d1482..00000000 --- a/src/fsfw/cfdp/handler/DestHandler.cpp +++ /dev/null @@ -1,480 +0,0 @@ -#include "DestHandler.h" - -#include - -#include - -#include "fsfw/FSFW.h" -#include "fsfw/cfdp/pdu/EofPduReader.h" -#include "fsfw/cfdp/pdu/FileDataReader.h" -#include "fsfw/cfdp/pdu/FinishedPduCreator.h" -#include "fsfw/cfdp/pdu/PduHeaderReader.h" -#include "fsfw/objectmanager.h" -#include "fsfw/tmtcservices/TmTcMessage.h" - -using namespace returnvalue; - -cfdp::DestHandler::DestHandler(DestHandlerParams params, FsfwParams fsfwParams) - : tlvVec(params.maxTlvsInOnePdu), - userTlvVec(params.maxTlvsInOnePdu), - dp(std::move(params)), - fp(fsfwParams), - tp(params.maxFilenameLen) { - tp.pduConf.direction = cfdp::Direction::TOWARDS_SENDER; -} - -const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() { - ReturnValue_t result; - uint8_t errorIdx = 0; - fsmRes.resetOfIteration(); - if (fsmRes.step == TransactionStep::IDLE) { - for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) { - if (infoIter->pduType == PduTypes::FILE_DIRECTIVE and - infoIter->directiveType == FileDirectives::METADATA) { - result = handleMetadataPdu(*infoIter); - checkAndHandleError(result, errorIdx); - // Store data was deleted in PDU handler because a store guard is used - dp.packetListRef.erase(infoIter++); - } else { - infoIter++; - } - } - if (fsmRes.step == TransactionStep::IDLE) { - // To decrease the already high complexity of the software, all packets arriving before - // a metadata PDU are deleted. - for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) { - fp.tcStore->deleteData(infoIter->storeId); - infoIter++; - } - dp.packetListRef.clear(); - } - - if (fsmRes.step != TransactionStep::IDLE) { - fsmRes.callStatus = CallStatus::CALL_AGAIN; - } - return updateFsmRes(errorIdx); - } - if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) { - if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) { - for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) { - if (infoIter->pduType == PduTypes::FILE_DATA) { - result = handleFileDataPdu(*infoIter); - checkAndHandleError(result, errorIdx); - // Store data was deleted in PDU handler because a store guard is used - dp.packetListRef.erase(infoIter++); - } else if (infoIter->pduType == PduTypes::FILE_DIRECTIVE and - infoIter->directiveType == FileDirectives::EOF_DIRECTIVE) { - // TODO: Support for check timer missing - result = handleEofPdu(*infoIter); - checkAndHandleError(result, errorIdx); - // Store data was deleted in PDU handler because a store guard is used - dp.packetListRef.erase(infoIter++); - } else { - infoIter++; - } - } - } - if (fsmRes.step == TransactionStep::TRANSFER_COMPLETION) { - result = handleTransferCompletion(); - checkAndHandleError(result, errorIdx); - } - if (fsmRes.step == TransactionStep::SENDING_FINISHED_PDU) { - result = sendFinishedPdu(); - checkAndHandleError(result, errorIdx); - finish(); - } - return updateFsmRes(errorIdx); - } - if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) { - // TODO: Will be implemented at a later stage -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "CFDP state machine for acknowledged mode not implemented yet" << std::endl; -#endif - } - return updateFsmRes(errorIdx); -} - -ReturnValue_t cfdp::DestHandler::passPacket(PacketInfo packet) { - if (dp.packetListRef.full()) { - return FAILED; - } - dp.packetListRef.push_back(packet); - return OK; -} - -ReturnValue_t cfdp::DestHandler::initialize() { - if (fp.tmStore == nullptr) { - fp.tmStore = ObjectManager::instance()->get(objects::TM_STORE); - if (fp.tmStore == nullptr) { - return FAILED; - } - } - - if (fp.tcStore == nullptr) { - fp.tcStore = ObjectManager::instance()->get(objects::TC_STORE); - if (fp.tcStore == nullptr) { - return FAILED; - } - } - - if (fp.msgQueue == nullptr) { - return FAILED; - } - return OK; -} - -ReturnValue_t cfdp::DestHandler::handleMetadataPdu(const PacketInfo& info) { - // Process metadata PDU - auto constAccessorPair = fp.tcStore->getData(info.storeId); - if (constAccessorPair.first != OK) { - // TODO: This is not a CFDP error. Event and/or warning? - return constAccessorPair.first; - } - cfdp::StringLv sourceFileName; - cfdp::StringLv destFileName; - MetadataInfo metadataInfo(tp.fileSize, sourceFileName, destFileName); - cfdp::Tlv* tlvArrayAsPtr = tlvVec.data(); - metadataInfo.setOptionsArray(&tlvArrayAsPtr, std::nullopt, tlvVec.size()); - MetadataPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), - metadataInfo); - ReturnValue_t result = reader.parseData(); - // TODO: The standard does not really specify what happens if this kind of error happens - // I think it might be a good idea to cache some sort of error code, which - // is translated into a warning and/or event by an upper layer - if (result != OK) { - return handleMetadataParseError(result, constAccessorPair.second.data(), - constAccessorPair.second.size()); - } - return startTransaction(reader, metadataInfo); -} - -ReturnValue_t cfdp::DestHandler::handleFileDataPdu(const cfdp::PacketInfo& info) { - // Process file data PDU - auto constAccessorPair = fp.tcStore->getData(info.storeId); - if (constAccessorPair.first != OK) { - // TODO: This is not a CFDP error. Event and/or warning? - return constAccessorPair.first; - } - cfdp::FileSize offset; - FileDataInfo fdInfo(offset); - FileDataReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), fdInfo); - ReturnValue_t result = reader.parseData(); - if (result != OK) { - return result; - } - size_t fileSegmentLen = 0; - const uint8_t* fileData = fdInfo.getFileData(&fileSegmentLen); - FileOpParams fileOpParams(tp.destName.data(), fileSegmentLen); - fileOpParams.offset = offset.value(); - if (dp.cfg.indicCfg.fileSegmentRecvIndicRequired) { - FileSegmentRecvdParams segParams; - segParams.offset = offset.value(); - segParams.id = tp.transactionId; - segParams.length = fileSegmentLen; - segParams.recContState = fdInfo.getRecordContinuationState(); - size_t segmentMetadatLen = 0; - auto* segMetadata = fdInfo.getSegmentMetadata(&segmentMetadatLen); - segParams.segmentMetadata = {segMetadata, segmentMetadatLen}; - dp.user.fileSegmentRecvdIndication(segParams); - } - result = dp.user.vfs.writeToFile(fileOpParams, fileData); - if (offset.value() + fileSegmentLen > tp.progress) { - tp.progress = offset.value() + fileSegmentLen; - } - if (result != returnvalue::OK) { - // TODO: Proper Error handling -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "File write error" << std::endl; -#endif - } else { - tp.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE; - } - return result; -} - -ReturnValue_t cfdp::DestHandler::handleEofPdu(const cfdp::PacketInfo& info) { - // Process EOF PDU - auto constAccessorPair = fp.tcStore->getData(info.storeId); - if (constAccessorPair.first != OK) { - // TODO: This is not a CFDP error. Event and/or warning? - return constAccessorPair.first; - } - EofInfo eofInfo(nullptr); - EofPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), eofInfo); - ReturnValue_t result = reader.parseData(); - if (result != OK) { - return result; - } - // TODO: Error handling - if (eofInfo.getConditionCode() == ConditionCode::NO_ERROR) { - tp.crc = eofInfo.getChecksum(); - uint64_t fileSizeFromEof = eofInfo.getFileSize().value(); - // CFDP 4.6.1.2.9: Declare file size error if progress exceeds file size - if (fileSizeFromEof > tp.progress) { - // TODO: File size error - } - tp.fileSize.setFileSize(fileSizeFromEof, std::nullopt); - } - if (dp.cfg.indicCfg.eofRecvIndicRequired) { - dp.user.eofRecvIndication(getTransactionId()); - } - if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) { - if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) { - fsmRes.step = TransactionStep::TRANSFER_COMPLETION; - } else if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) { - fsmRes.step = TransactionStep::SENDING_ACK_PDU; - } - } - return returnvalue::OK; -} - -ReturnValue_t cfdp::DestHandler::handleMetadataParseError(ReturnValue_t result, - const uint8_t* rawData, size_t maxSize) { - // TODO: try to extract destination ID for error - // TODO: Invalid metadata PDU. -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "Parsing Metadata PDU failed with code " << result << std::endl; -#else -#endif - PduHeaderReader headerReader(rawData, maxSize); - result = headerReader.parseData(); - if (result != OK) { - // TODO: Now this really should not happen. Warning or error, - // yield or cache appropriate returnvalue -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "Parsing Header failed" << std::endl; -#else -#endif - // TODO: Trigger appropriate event - return result; - } - cfdp::EntityId destId; - headerReader.getDestId(destId); - RemoteEntityCfg* remoteCfg; - if (not dp.remoteCfgTable.getRemoteCfg(destId, &remoteCfg)) { -// TODO: No remote config for dest ID. I consider this a configuration error, which is not -// covered by the standard. -// Warning or error, yield or cache appropriate returnvalue -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "No remote config exists for destination ID" << std::endl; -#else -#endif - // TODO: Trigger appropriate event - } - // TODO: Appropriate returnvalue? - return returnvalue::FAILED; -} - -ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader, MetadataInfo& info) { - if (fsmRes.state != CfdpStates::IDLE) { - // According to standard, discard metadata PDU if we are busy - return OK; - } - ReturnValue_t result = OK; - fsmRes.step = TransactionStep::TRANSACTION_START; - if (reader.getTransmissionMode() == TransmissionModes::UNACKNOWLEDGED) { - fsmRes.state = CfdpStates::BUSY_CLASS_1_NACKED; - } else if (reader.getTransmissionMode() == TransmissionModes::ACKNOWLEDGED) { - fsmRes.state = CfdpStates::BUSY_CLASS_2_ACKED; - } - tp.checksumType = info.getChecksumType(); - tp.closureRequested = info.isClosureRequested(); - size_t sourceNameSize = 0; - const uint8_t* sourceNamePtr = info.getSourceFileName().getValue(&sourceNameSize); - if (sourceNameSize > tp.sourceName.size()) { - // TODO: Warning, event etc. - return FAILED; - } - std::memcpy(tp.sourceName.data(), sourceNamePtr, sourceNameSize); - tp.sourceName[sourceNameSize] = '\0'; - size_t destNameSize = 0; - const uint8_t* destNamePtr = info.getDestFileName().getValue(&destNameSize); - if (destNameSize > tp.destName.size()) { - // TODO: Warning, event etc. - return FAILED; - } - std::memcpy(tp.destName.data(), destNamePtr, destNameSize); - tp.destName[destNameSize] = '\0'; - reader.fillConfig(tp.pduConf); - tp.pduConf.direction = Direction::TOWARDS_SENDER; - tp.transactionId.entityId = tp.pduConf.sourceId; - tp.transactionId.seqNum = tp.pduConf.seqNum; - if (not dp.remoteCfgTable.getRemoteCfg(tp.pduConf.sourceId, &tp.remoteCfg)) { - // TODO: Warning, event etc. -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "cfdp::DestHandler" << __func__ - << ": No remote configuration found for destination ID " - << tp.pduConf.sourceId.getValue() << std::endl; -#endif - return FAILED; - } - // If both dest name size and source name size are 0, we are dealing with a metadata only PDU, - // so there is no need to create a file or truncate an existing file - if (destNameSize > 0 and sourceNameSize > 0) { - FilesystemParams fparams(tp.destName.data()); - // TODO: Filesystem errors? - if (dp.user.vfs.fileExists(fparams)) { - dp.user.vfs.truncateFile(fparams); - } else { - result = dp.user.vfs.createFile(fparams); - if (result != OK) { - // TODO: Handle FS error. This is probably a case for the filestore rejection mechanism of - // CFDP. - // In any case, it does not really make sense to continue here - } - } - } - fsmRes.step = TransactionStep::RECEIVING_FILE_DATA_PDUS; - MetadataRecvdParams params(tp.transactionId, tp.pduConf.sourceId); - params.fileSize = tp.fileSize.getSize(); - params.destFileName = tp.destName.data(); - params.sourceFileName = tp.sourceName.data(); - params.msgsToUserArray = dynamic_cast(userTlvVec.data()); - params.msgsToUserLen = info.getOptionsLen(); - dp.user.metadataRecvdIndication(params); - return result; -} - -cfdp::CfdpStates cfdp::DestHandler::getCfdpState() const { return fsmRes.state; } - -ReturnValue_t cfdp::DestHandler::handleTransferCompletion() { - ReturnValue_t result; - if (tp.checksumType != ChecksumTypes::NULL_CHECKSUM) { - result = checksumVerification(); - if (result != OK) { - // TODO: Warning / error handling? - } - } else { - tp.conditionCode = ConditionCode::NO_ERROR; - } - result = noticeOfCompletion(); - if (result != OK) { - } - if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) { - if (tp.closureRequested) { - fsmRes.step = TransactionStep::SENDING_FINISHED_PDU; - } else { - finish(); - } - } else if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) { - fsmRes.step = TransactionStep::SENDING_FINISHED_PDU; - } - return OK; -} - -void cfdp::DestHandler::finish() { - tp.reset(); - dp.packetListRef.clear(); - fsmRes.state = CfdpStates::IDLE; - fsmRes.step = TransactionStep::IDLE; -} - -ReturnValue_t cfdp::DestHandler::checksumVerification() { - std::array buf{}; - // TODO: Checksum verification and notice of completion - etl::crc32 crcCalc; - uint64_t currentOffset = 0; - FileOpParams params(tp.destName.data(), tp.fileSize.value()); - while (currentOffset < tp.fileSize.value()) { - uint64_t readLen; - if (currentOffset + buf.size() > tp.fileSize.value()) { - readLen = tp.fileSize.value() - currentOffset; - } else { - readLen = buf.size(); - } - if (readLen > 0) { - params.offset = currentOffset; - params.size = readLen; - auto result = dp.user.vfs.readFromFile(params, buf.data(), buf.size()); - if (result != OK) { - // TODO: I think this is a case for a filestore rejection, but it might sense to print - // a warning or trigger an event because this should generally not happen - return FAILED; - } - crcCalc.add(buf.begin(), buf.begin() + readLen); - } - currentOffset += readLen; - } - - uint32_t value = crcCalc.value(); - if (value == tp.crc) { - tp.conditionCode = ConditionCode::NO_ERROR; - tp.deliveryCode = FileDeliveryCode::DATA_COMPLETE; - } else { - // TODO: Proper error handling -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "CRC check for file " << tp.destName.data() << " failed" << std::endl; -#endif - tp.conditionCode = ConditionCode::FILE_CHECKSUM_FAILURE; - } - return OK; -} - -ReturnValue_t cfdp::DestHandler::noticeOfCompletion() { - if (dp.cfg.indicCfg.transactionFinishedIndicRequired) { - TransactionFinishedParams params(tp.transactionId, tp.conditionCode, tp.deliveryCode, - tp.deliveryStatus); - dp.user.transactionFinishedIndication(params); - } - return OK; -} - -ReturnValue_t cfdp::DestHandler::sendFinishedPdu() { - FinishedInfo info(tp.conditionCode, tp.deliveryCode, tp.deliveryStatus); - FinishPduCreator finishedPdu(tp.pduConf, info); - store_address_t storeId; - uint8_t* dataPtr = nullptr; - ReturnValue_t result = - fp.tcStore->getFreeElement(&storeId, finishedPdu.getSerializedSize(), &dataPtr); - if (result != OK) { - // TODO: Error handling and event, this is a non CFDP specific error (most likely store is full) - return result; - } - size_t serLen = 0; - result = finishedPdu.serialize(dataPtr, serLen, finishedPdu.getSerializedSize()); - if (result != OK) { - // TODO: Error printout, this really should not happen - return result; - } - TmTcMessage msg(storeId); - result = fp.msgQueue->sendMessage(fp.packetDest.getReportReceptionQueue(), &msg); - if (result != OK) { - // TODO: Error handling and event, this is a non CFDP specific error (most likely store is full) - return result; - } - fsmRes.packetsSent++; - return OK; -} - -cfdp::DestHandler::TransactionStep cfdp::DestHandler::getTransactionStep() const { - return fsmRes.step; -} - -const cfdp::DestHandler::FsmResult& cfdp::DestHandler::updateFsmRes(uint8_t errors) { - fsmRes.errors = errors; - fsmRes.result = OK; - if (fsmRes.errors > 0) { - fsmRes.result = FAILED; - } - return fsmRes; -} - -const cfdp::TransactionId& cfdp::DestHandler::getTransactionId() const { return tp.transactionId; } - -void cfdp::DestHandler::checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx) { - if (result != OK and errorIdx < 3) { - fsmRes.errorCodes[errorIdx] = result; - errorIdx++; - } -} - -void cfdp::DestHandler::setMsgQueue(MessageQueueIF& queue) { fp.msgQueue = &queue; } - -void cfdp::DestHandler::setEventReporter(EventReportingProxyIF& reporter) { - fp.eventReporter = &reporter; -} - -const cfdp::DestHandlerParams& cfdp::DestHandler::getDestHandlerParams() const { return dp; } - -StorageManagerIF* cfdp::DestHandler::getTmStore() const { return fp.tmStore; } -StorageManagerIF* cfdp::DestHandler::getTcStore() const { return fp.tcStore; } diff --git a/src/fsfw/cfdp/handler/DestHandler.h b/src/fsfw/cfdp/handler/DestHandler.h deleted file mode 100644 index 000fc2c0..00000000 --- a/src/fsfw/cfdp/handler/DestHandler.h +++ /dev/null @@ -1,202 +0,0 @@ -#ifndef FSFW_CFDP_CFDPDESTHANDLER_H -#define FSFW_CFDP_CFDPDESTHANDLER_H - -#include -#include - -#include -#include - -#include "RemoteConfigTableIF.h" -#include "UserBase.h" -#include "defs.h" -#include "fsfw/cfdp/handler/mib.h" -#include "fsfw/cfdp/pdu/MetadataPduReader.h" -#include "fsfw/cfdp/pdu/PduConfig.h" -#include "fsfw/container/DynamicFIFO.h" -#include "fsfw/storagemanager/StorageManagerIF.h" -#include "fsfw/storagemanager/storeAddress.h" -#include "fsfw/tmtcservices/AcceptsTelemetryIF.h" - -namespace cfdp { - -struct PacketInfo { - PacketInfo(PduTypes type, store_address_t storeId, - std::optional directive = std::nullopt) - : pduType(type), directiveType(directive), storeId(storeId) {} - - PduTypes pduType = PduTypes::FILE_DATA; - std::optional directiveType = FileDirectives::INVALID_DIRECTIVE; - store_address_t storeId = store_address_t::invalid(); - PacketInfo() = default; -}; - -template -using LostSegmentsList = etl::set, SIZE>; -template -using PacketInfoList = etl::list; -using LostSegmentsListBase = etl::iset>; -using PacketInfoListBase = etl::ilist; - -struct DestHandlerParams { - DestHandlerParams(LocalEntityCfg cfg, UserBase& user, RemoteConfigTableIF& remoteCfgTable, - PacketInfoListBase& packetList, - // TODO: This container can potentially take tons of space. For a better - // memory efficient implementation, an additional abstraction could be - // be used so users can use uint32_t as the pair type - LostSegmentsListBase& lostSegmentsContainer) - : cfg(std::move(cfg)), - user(user), - remoteCfgTable(remoteCfgTable), - packetListRef(packetList), - lostSegmentsContainer(lostSegmentsContainer) {} - - LocalEntityCfg cfg; - UserBase& user; - RemoteConfigTableIF& remoteCfgTable; - - PacketInfoListBase& packetListRef; - LostSegmentsListBase& lostSegmentsContainer; - uint8_t maxTlvsInOnePdu = 10; - size_t maxFilenameLen = 255; -}; - -struct FsfwParams { - FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue, - EventReportingProxyIF* eventReporter, StorageManagerIF& tcStore, - StorageManagerIF& tmStore) - : FsfwParams(packetDest, msgQueue, eventReporter) { - this->tcStore = &tcStore; - this->tmStore = &tmStore; - } - - FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue, - EventReportingProxyIF* eventReporter) - : packetDest(packetDest), msgQueue(msgQueue), eventReporter(eventReporter) {} - AcceptsTelemetryIF& packetDest; - MessageQueueIF* msgQueue; - EventReportingProxyIF* eventReporter = nullptr; - StorageManagerIF* tcStore = nullptr; - StorageManagerIF* tmStore = nullptr; -}; - -enum class CallStatus { DONE, CALL_AFTER_DELAY, CALL_AGAIN }; - -class DestHandler { - public: - enum class TransactionStep { - IDLE = 0, - TRANSACTION_START = 1, - RECEIVING_FILE_DATA_PDUS = 2, - SENDING_ACK_PDU = 3, - TRANSFER_COMPLETION = 4, - SENDING_FINISHED_PDU = 5 - }; - - struct FsmResult { - public: - ReturnValue_t result = returnvalue::OK; - CallStatus callStatus = CallStatus::CALL_AFTER_DELAY; - TransactionStep step = TransactionStep::IDLE; - CfdpStates state = CfdpStates::IDLE; - uint32_t packetsSent = 0; - uint8_t errors = 0; - std::array errorCodes = {}; - void resetOfIteration() { - result = returnvalue::OK; - callStatus = CallStatus::CALL_AFTER_DELAY; - packetsSent = 0; - errors = 0; - errorCodes.fill(returnvalue::OK); - } - }; - /** - * Will be returned if it is advisable to call the state machine operation call again - */ - ReturnValue_t PARTIAL_SUCCESS = returnvalue::makeCode(0, 2); - ReturnValue_t FAILURE = returnvalue::makeCode(0, 3); - explicit DestHandler(DestHandlerParams handlerParams, FsfwParams fsfwParams); - - /** - * - * @return - * - @c returnvalue::OK State machine OK for this execution cycle - * - @c CALL_FSM_AGAIN State machine should be called again. - */ - const FsmResult& performStateMachine(); - void setMsgQueue(MessageQueueIF& queue); - void setEventReporter(EventReportingProxyIF& reporter); - - ReturnValue_t passPacket(PacketInfo packet); - - ReturnValue_t initialize(); - - [[nodiscard]] CfdpStates getCfdpState() const; - [[nodiscard]] TransactionStep getTransactionStep() const; - [[nodiscard]] const TransactionId& getTransactionId() const; - [[nodiscard]] const DestHandlerParams& getDestHandlerParams() const; - [[nodiscard]] StorageManagerIF* getTcStore() const; - [[nodiscard]] StorageManagerIF* getTmStore() const; - - private: - struct TransactionParams { - // Initialize char vectors with length + 1 for 0 termination - explicit TransactionParams(size_t maxFileNameLen) - : sourceName(maxFileNameLen + 1), destName(maxFileNameLen + 1) {} - - void reset() { - pduConf = PduConfig(); - transactionId = TransactionId(); - std::fill(sourceName.begin(), sourceName.end(), '\0'); - std::fill(destName.begin(), destName.end(), '\0'); - fileSize.setFileSize(0, false); - conditionCode = ConditionCode::NO_ERROR; - deliveryCode = FileDeliveryCode::DATA_INCOMPLETE; - deliveryStatus = FileDeliveryStatus::DISCARDED_DELIBERATELY; - crc = 0; - progress = 0; - remoteCfg = nullptr; - closureRequested = false; - checksumType = ChecksumTypes::NULL_CHECKSUM; - } - - ChecksumTypes checksumType = ChecksumTypes::NULL_CHECKSUM; - bool closureRequested = false; - std::vector sourceName; - std::vector destName; - cfdp::FileSize fileSize; - TransactionId transactionId; - PduConfig pduConf; - ConditionCode conditionCode = ConditionCode::NO_ERROR; - FileDeliveryCode deliveryCode = FileDeliveryCode::DATA_INCOMPLETE; - FileDeliveryStatus deliveryStatus = FileDeliveryStatus::DISCARDED_DELIBERATELY; - uint32_t crc = 0; - uint64_t progress = 0; - RemoteEntityCfg* remoteCfg = nullptr; - }; - - std::vector tlvVec; - std::vector userTlvVec; - DestHandlerParams dp; - FsfwParams fp; - TransactionParams tp; - FsmResult fsmRes; - - ReturnValue_t startTransaction(MetadataPduReader& reader, MetadataInfo& info); - ReturnValue_t handleMetadataPdu(const PacketInfo& info); - ReturnValue_t handleFileDataPdu(const PacketInfo& info); - ReturnValue_t handleEofPdu(const PacketInfo& info); - ReturnValue_t handleMetadataParseError(ReturnValue_t result, const uint8_t* rawData, - size_t maxSize); - ReturnValue_t handleTransferCompletion(); - ReturnValue_t sendFinishedPdu(); - ReturnValue_t noticeOfCompletion(); - ReturnValue_t checksumVerification(); - const FsmResult& updateFsmRes(uint8_t errors); - void checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx); - void finish(); -}; - -} // namespace cfdp - -#endif // FSFW_CFDP_CFDPDESTHANDLER_H diff --git a/src/fsfw/cfdp/handler/SourceHandler.cpp b/src/fsfw/cfdp/handler/SourceHandler.cpp deleted file mode 100644 index 513b25f3..00000000 --- a/src/fsfw/cfdp/handler/SourceHandler.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "SourceHandler.h" diff --git a/src/fsfw/cfdp/handler/SourceHandler.h b/src/fsfw/cfdp/handler/SourceHandler.h deleted file mode 100644 index 319cf258..00000000 --- a/src/fsfw/cfdp/handler/SourceHandler.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef FSFW_CFDP_CFDPSOURCEHANDLER_H -#define FSFW_CFDP_CFDPSOURCEHANDLER_H - -class SourceHandler {}; - -#endif // FSFW_CFDP_CFDPSOURCEHANDLER_H diff --git a/unittests/cfdp/handler/CMakeLists.txt b/unittests/cfdp/handler/CMakeLists.txt index f70e5dfb..0993a398 100644 --- a/unittests/cfdp/handler/CMakeLists.txt +++ b/unittests/cfdp/handler/CMakeLists.txt @@ -1,3 +1,2 @@ -target_sources( - ${FSFW_TEST_TGT} PRIVATE testDistributor.cpp testDestHandler.cpp - testSourceHandler.cpp testFaultHandler.cpp) +target_sources(${FSFW_TEST_TGT} PRIVATE testDistributor.cpp + testFaultHandler.cpp) diff --git a/unittests/cfdp/handler/testDestHandler.cpp b/unittests/cfdp/handler/testDestHandler.cpp deleted file mode 100644 index 30bb9fc5..00000000 --- a/unittests/cfdp/handler/testDestHandler.cpp +++ /dev/null @@ -1,244 +0,0 @@ -#include - -#include -#include -#include - -#include "fsfw/cfdp.h" -#include "fsfw/cfdp/pdu/EofPduCreator.h" -#include "fsfw/cfdp/pdu/FileDataCreator.h" -#include "fsfw/cfdp/pdu/MetadataPduCreator.h" -#include "mocks/AcceptsTmMock.h" -#include "mocks/EventReportingProxyMock.h" -#include "mocks/FilesystemMock.h" -#include "mocks/MessageQueueMock.h" -#include "mocks/StorageManagerMock.h" -#include "mocks/cfdp/FaultHandlerMock.h" -#include "mocks/cfdp/RemoteConfigTableMock.h" -#include "mocks/cfdp/UserMock.h" - -TEST_CASE("CFDP Dest Handler", "[cfdp]") { - using namespace cfdp; - using namespace returnvalue; - MessageQueueId_t destQueueId = 2; - AcceptsTmMock tmReceiver(destQueueId); - MessageQueueMock mqMock(destQueueId); - EntityId localId = EntityId(UnsignedByteField(2)); - EntityId remoteId = EntityId(UnsignedByteField(3)); - FaultHandlerMock fhMock; - LocalEntityCfg localEntityCfg(localId, IndicationCfg(), fhMock); - FilesystemMock fsMock; - UserMock userMock(fsMock); - RemoteConfigTableMock remoteCfgTableMock; - PacketInfoList<64> packetInfoList; - LostSegmentsList<128> lostSegmentsList; - DestHandlerParams dp(localEntityCfg, userMock, remoteCfgTableMock, packetInfoList, - lostSegmentsList); - EventReportingProxyMock eventReporterMock; - LocalPool::LocalPoolConfig storeCfg = {{10, 32}, {10, 64}, {10, 128}, {10, 1024}}; - StorageManagerMock tcStore(2, storeCfg); - StorageManagerMock tmStore(3, storeCfg); - FsfwParams fp(tmReceiver, &mqMock, &eventReporterMock); - RemoteEntityCfg cfg(remoteId); - remoteCfgTableMock.addRemoteConfig(cfg); - fp.tcStore = &tcStore; - fp.tmStore = &tmStore; - uint8_t* buf = nullptr; - size_t serLen = 0; - store_address_t storeId; - PduConfig conf; - auto destHandler = DestHandler(dp, fp); - CHECK(destHandler.initialize() == OK); - - auto metadataPreparation = [&](FileSize cfdpFileSize, ChecksumTypes checksumType) { - std::string srcNameString = "hello.txt"; - std::string destNameString = "hello-cpy.txt"; - StringLv srcName(srcNameString); - StringLv destName(destNameString); - MetadataInfo info(false, checksumType, cfdpFileSize, srcName, destName); - TransactionSeqNum seqNum(UnsignedByteField(1)); - conf.sourceId = remoteId; - conf.destId = localId; - conf.mode = TransmissionModes::UNACKNOWLEDGED; - conf.seqNum = seqNum; - MetadataPduCreator metadataCreator(conf, info); - REQUIRE(tcStore.getFreeElement(&storeId, metadataCreator.getSerializedSize(), &buf) == OK); - REQUIRE(metadataCreator.serialize(buf, serLen, metadataCreator.getSerializedSize()) == OK); - PacketInfo packetInfo(metadataCreator.getPduType(), storeId, - metadataCreator.getDirectiveCode()); - packetInfoList.push_back(packetInfo); - }; - - auto metadataCheck = [&](const cfdp::DestHandler::FsmResult& res, const char* sourceName, - const char* destName, size_t fileLen) { - REQUIRE(res.result == OK); - REQUIRE(res.callStatus == CallStatus::CALL_AGAIN); - REQUIRE(res.errors == 0); - // Assert that the packet was deleted after handling - REQUIRE(not tcStore.hasDataAtId(storeId)); - REQUIRE(packetInfoList.empty()); - REQUIRE(userMock.metadataRecvd.size() == 1); - auto& idMetadataPair = userMock.metadataRecvd.back(); - REQUIRE(idMetadataPair.first == destHandler.getTransactionId()); - REQUIRE(idMetadataPair.second.sourceId.getValue() == 3); - REQUIRE(idMetadataPair.second.fileSize == fileLen); - REQUIRE(strcmp(idMetadataPair.second.destFileName, destName) == 0); - REQUIRE(strcmp(idMetadataPair.second.sourceFileName, sourceName) == 0); - userMock.metadataRecvd.pop(); - REQUIRE(fsMock.fileMap.find(destName) != fsMock.fileMap.end()); - REQUIRE(res.result == OK); - REQUIRE(res.state == CfdpStates::BUSY_CLASS_1_NACKED); - REQUIRE(res.step == DestHandler::TransactionStep::RECEIVING_FILE_DATA_PDUS); - }; - - auto eofPreparation = [&](FileSize cfdpFileSize, uint32_t crc) { - EofInfo eofInfo(cfdp::ConditionCode::NO_ERROR, crc, std::move(cfdpFileSize)); - EofPduCreator eofCreator(conf, eofInfo); - REQUIRE(tcStore.getFreeElement(&storeId, eofCreator.getSerializedSize(), &buf) == OK); - REQUIRE(eofCreator.serialize(buf, serLen, eofCreator.getSerializedSize()) == OK); - PacketInfo packetInfo(eofCreator.getPduType(), storeId, eofCreator.getDirectiveCode()); - packetInfoList.push_back(packetInfo); - }; - - auto eofCheck = [&](const cfdp::DestHandler::FsmResult& res, const TransactionId& id) { - REQUIRE(res.result == OK); - REQUIRE(res.state == CfdpStates::IDLE); - REQUIRE(res.errors == 0); - REQUIRE(res.step == DestHandler::TransactionStep::IDLE); - // Assert that the packet was deleted after handling - REQUIRE(not tcStore.hasDataAtId(storeId)); - REQUIRE(packetInfoList.empty()); - REQUIRE(userMock.eofsRevd.size() == 1); - auto& eofId = userMock.eofsRevd.back(); - CHECK(eofId == id); - REQUIRE(userMock.finishedRecvd.size() == 1); - auto& idParamPair = userMock.finishedRecvd.back(); - CHECK(idParamPair.first == id); - CHECK(idParamPair.second.condCode == ConditionCode::NO_ERROR); - }; - - auto fileDataPduCheck = [&](const cfdp::DestHandler::FsmResult& res, - const std::vector& idsToCheck) { - REQUIRE(res.result == OK); - REQUIRE(res.state == CfdpStates::BUSY_CLASS_1_NACKED); - REQUIRE(res.step == DestHandler::TransactionStep::RECEIVING_FILE_DATA_PDUS); - for (const auto id : idsToCheck) { - REQUIRE(not tcStore.hasDataAtId(id)); - } - REQUIRE(packetInfoList.empty()); - }; - - SECTION("State") { - CHECK(destHandler.getCfdpState() == CfdpStates::IDLE); - CHECK(destHandler.getTransactionStep() == DestHandler::TransactionStep::IDLE); - } - - SECTION("Idle State Machine Iteration") { - auto res = destHandler.performStateMachine(); - CHECK(res.result == OK); - CHECK(res.callStatus == CallStatus::CALL_AFTER_DELAY); - CHECK(res.errors == 0); - CHECK(destHandler.getCfdpState() == CfdpStates::IDLE); - CHECK(destHandler.getTransactionStep() == DestHandler::TransactionStep::IDLE); - } - - SECTION("Empty File Transfer") { - const DestHandler::FsmResult& res = destHandler.performStateMachine(); - CHECK(res.result == OK); - FileSize cfdpFileSize(0); - metadataPreparation(cfdpFileSize, ChecksumTypes::NULL_CHECKSUM); - destHandler.performStateMachine(); - metadataCheck(res, "hello.txt", "hello-cpy.txt", 0); - destHandler.performStateMachine(); - REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY); - auto transactionId = destHandler.getTransactionId(); - eofPreparation(cfdpFileSize, 0); - // After EOF, operation is done because no closure was requested - destHandler.performStateMachine(); - eofCheck(res, transactionId); - } - - SECTION("Small File Transfer") { - const DestHandler::FsmResult& res = destHandler.performStateMachine(); - CHECK(res.result == OK); - std::string fileData = "hello test data"; - etl::crc32 crcCalc; - crcCalc.add(fileData.begin(), fileData.end()); - uint32_t crc32 = crcCalc.value(); - FileSize cfdpFileSize(fileData.size()); - metadataPreparation(cfdpFileSize, ChecksumTypes::CRC_32); - destHandler.performStateMachine(); - metadataCheck(res, "hello.txt", "hello-cpy.txt", fileData.size()); - destHandler.performStateMachine(); - REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY); - auto transactionId = destHandler.getTransactionId(); - FileSize offset(0); - FileDataInfo fdPduInfo(offset, reinterpret_cast(fileData.data()), - fileData.size()); - FileDataCreator fdPduCreator(conf, fdPduInfo); - REQUIRE(tcStore.getFreeElement(&storeId, fdPduCreator.getSerializedSize(), &buf) == OK); - REQUIRE(fdPduCreator.serialize(buf, serLen, fdPduCreator.getSerializedSize()) == OK); - PacketInfo packetInfo(fdPduCreator.getPduType(), storeId, std::nullopt); - packetInfoList.push_back(packetInfo); - destHandler.performStateMachine(); - fileDataPduCheck(res, {storeId}); - eofPreparation(cfdpFileSize, crc32); - // After EOF, operation is done because no closure was requested - destHandler.performStateMachine(); - eofCheck(res, transactionId); - } - - SECTION("Segmented File Transfer") { - const DestHandler::FsmResult& res = destHandler.performStateMachine(); - CHECK(res.result == OK); - std::random_device dev; - std::mt19937 rng(dev()); - std::uniform_int_distribution distU8(0, 255); - std::array largerFileData{}; - for (auto& val : largerFileData) { - val = distU8(rng); - } - etl::crc32 crcCalc; - crcCalc.add(largerFileData.begin(), largerFileData.end()); - uint32_t crc32 = crcCalc.value(); - FileSize cfdpFileSize(largerFileData.size()); - metadataPreparation(cfdpFileSize, ChecksumTypes::CRC_32); - destHandler.performStateMachine(); - metadataCheck(res, "hello.txt", "hello-cpy.txt", largerFileData.size()); - destHandler.performStateMachine(); - REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY); - auto transactionId = destHandler.getTransactionId(); - - std::vector idsToCheck; - { - FileSize offset(0); - FileDataInfo fdPduInfo(offset, reinterpret_cast(largerFileData.data()), - largerFileData.size() / 2); - FileDataCreator fdPduCreator(conf, fdPduInfo); - REQUIRE(tcStore.getFreeElement(&storeId, fdPduCreator.getSerializedSize(), &buf) == OK); - REQUIRE(fdPduCreator.serialize(buf, serLen, fdPduCreator.getSerializedSize()) == OK); - PacketInfo packetInfo(fdPduCreator.getPduType(), storeId, std::nullopt); - idsToCheck.push_back(storeId); - packetInfoList.push_back(packetInfo); - } - - { - FileSize offset(512); - FileDataInfo fdPduInfo(offset, reinterpret_cast(largerFileData.data() + 512), - largerFileData.size() / 2); - FileDataCreator fdPduCreator(conf, fdPduInfo); - REQUIRE(tcStore.getFreeElement(&storeId, fdPduCreator.getSerializedSize(), &buf) == OK); - REQUIRE(fdPduCreator.serialize(buf, serLen, fdPduCreator.getSerializedSize()) == OK); - PacketInfo packetInfo(fdPduCreator.getPduType(), storeId, std::nullopt); - idsToCheck.push_back(storeId); - packetInfoList.push_back(packetInfo); - } - - destHandler.performStateMachine(); - fileDataPduCheck(res, idsToCheck); - eofPreparation(cfdpFileSize, crc32); - // After EOF, operation is done because no closure was requested - destHandler.performStateMachine(); - eofCheck(res, transactionId); - } -} \ No newline at end of file diff --git a/unittests/cfdp/handler/testSourceHandler.cpp b/unittests/cfdp/handler/testSourceHandler.cpp deleted file mode 100644 index 570ecb08..00000000 --- a/unittests/cfdp/handler/testSourceHandler.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include - -TEST_CASE("CFDP Source Handler", "[cfdp]") {} \ No newline at end of file diff --git a/unittests/cfdp/testLvs.cpp b/unittests/cfdp/testLvs.cpp index 062281e5..22094568 100644 --- a/unittests/cfdp/testLvs.cpp +++ b/unittests/cfdp/testLvs.cpp @@ -2,6 +2,7 @@ #include #include "fsfw/cfdp.h" +#include "fsfw/cfdp/VarLenFields.h" TEST_CASE("CFDP LV", "[cfdp][lv]") { using namespace cfdp; diff --git a/unittests/cfdp/testTlv.cpp b/unittests/cfdp/testTlv.cpp index 3e7435cd..b78d8a80 100644 --- a/unittests/cfdp/testTlv.cpp +++ b/unittests/cfdp/testTlv.cpp @@ -2,6 +2,7 @@ #include #include "fsfw/cfdp.h" +#include "fsfw/cfdp/VarLenFields.h" TEST_CASE("CFDP TLV", "[cfdp][tlv]") { using namespace cfdp;