#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/cfdp/tlv/MessageToUserTlv.h" #include "fsfw/container/DynamicFIFO.h" #include "fsfw/storagemanager/StorageManagerIF.h" #include "fsfw/storagemanager/storeAddress.h" #include "fsfw/tmtcservices/AcceptsTelemetryIF.h" namespace cfdp { template using LostSegmentsList = etl::set, SIZE>; using LostSegmentsListBase = etl::iset>; 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 // 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), remoteCfgTable(remoteCfgTable), packetListRef(packetList), lostSegmentsContainer(lostSegmentsContainer) {} LocalEntityCfg cfg; UserBase& user; RemoteConfigTableIF& remoteCfgTable; PacketInfoListBase& packetListRef; LostSegmentsListBase& lostSegmentsContainer; uint8_t maxTlvsInOnePdu = 20; size_t maxFilenameLen = 255; }; class DestHandler { public: enum class TransactionStep : uint8_t { 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; CfdpState state = CfdpState::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& stateMachine(); void setMsgQueue(MessageQueueIF& queue); void setEventReporter(EventReportingProxyIF& reporter); ReturnValue_t passPacket(PacketInfo packet); ReturnValue_t initialize(); [[nodiscard]] CfdpState 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; 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::Fss 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 msgToUserVec; TransactionParams transactionParams; DestHandlerParams destParams; cfdp::FsfwParams fsfwParams; FsmResult fsmRes; ReturnValue_t startTransaction(const MetadataPduReader& reader); 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 tryBuildingAbsoluteDestName(size_t destNameSize); ReturnValue_t sendFinishedPdu(); ReturnValue_t noticeOfCompletion(); ReturnValue_t checksumVerification(); 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(); }; } // namespace cfdp #endif // FSFW_CFDP_CFDPDESTHANDLER_H