diff --git a/src/fsfw/cfdp/handler/PutRequest.cpp b/src/fsfw/cfdp/handler/PutRequest.cpp index 899cf11b..a1abcc14 100644 --- a/src/fsfw/cfdp/handler/PutRequest.cpp +++ b/src/fsfw/cfdp/handler/PutRequest.cpp @@ -185,3 +185,17 @@ 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 index 9b7edc0a..6bf46c60 100644 --- a/src/fsfw/cfdp/handler/PutRequest.h +++ b/src/fsfw/cfdp/handler/PutRequest.h @@ -22,7 +22,9 @@ class PutRequest : public SerializeIF { PutRequest(EntityId destId, const uint8_t* msgsToUser, size_t msgsToUserTotalSize, const uint8_t* fsRequests, size_t fsRequestsSize); /** - * Put request to initiate file transfers. + * 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 @@ -53,6 +55,9 @@ class PutRequest : public SerializeIF { [[nodiscard]] bool isMetadataOnly() const; + bool getTransmissionMode(TransmissionMode& mode) const; + bool getClosureRequested(bool& closureRequested) const; + [[nodiscard]] const EntityId& getDestId() const; void setDestId(EntityId id); diff --git a/src/fsfw/cfdp/handler/SourceHandler.cpp b/src/fsfw/cfdp/handler/SourceHandler.cpp index cfe4cc23..e46edf6c 100644 --- a/src/fsfw/cfdp/handler/SourceHandler.cpp +++ b/src/fsfw/cfdp/handler/SourceHandler.cpp @@ -138,21 +138,23 @@ ReturnValue_t cfdp::SourceHandler::checksumGeneration() { return OK; } -ReturnValue_t cfdp::SourceHandler::putRequest(PutRequestFull& putRequest, RemoteEntityCfg& cfg) { +ReturnValue_t cfdp::SourceHandler::transactionStart(PutRequest& putRequest, RemoteEntityCfg& cfg) { if (state != CfdpState::IDLE) { return SOURCE_TRANSACTION_PENDING; } - if (putRequest.sourceNameSize > transactionParams.sourceName.size()) { - return FAILED; + if (cfg.remoteId != putRequest.getDestId()) { + return WRONG_REMOTE_CFG_ENTITY_ID; } - if (putRequest.destNameSize > transactionParams.destName.size()) { - return FAILED; + if (putRequest.getSourceName().getValueLen() == 0) { + return SOURCE_NAME_EMPTY; } - std::memcpy(transactionParams.destName.data(), putRequest.destName, putRequest.destNameSize); - std::memcpy(transactionParams.sourceName.data(), putRequest.sourceName, - putRequest.sourceNameSize); - transactionParams.sourceNameSize = putRequest.sourceNameSize; - transactionParams.destNameSize = putRequest.destNameSize; + if (putRequest.getDestName().getValueLen() == 0) { + return DEST_NAME_EMPTY; + } + const char* srcNamePtr = putRequest.getSourceName().getString(transactionParams.sourceNameSize); + const char* destNamePtr = putRequest.getDestName().getString(transactionParams.destNameSize); + std::strncpy(transactionParams.sourceName.data(), srcNamePtr, transactionParams.sourceNameSize); + std::strncpy(transactionParams.destName.data(), destNamePtr, transactionParams.destNameSize); FilesystemParams params(transactionParams.sourceName.data()); if (!sourceParams.user.vfs.fileExists(params)) { return FILE_DOES_NOT_EXIST; @@ -160,9 +162,15 @@ ReturnValue_t cfdp::SourceHandler::putRequest(PutRequestFull& putRequest, Remote if (cfg.maxFileSegmentLen > fileBuf.size() or cfg.maxFileSegmentLen == 0) { return FILE_SEGMENT_LEN_INVALID; } - transactionParams.closureRequested = putRequest.closureRequested; - transactionParams.pduConf.mode = putRequest.transmissionMode; - transactionParams.pduConf.destId = putRequest.destId; + // 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; + } + transactionParams.pduConf.destId = putRequest.getDestId(); // Only used for PDU forwarding, file is sent to file receiver regularly here. transactionParams.pduConf.direction = Direction::TOWARDS_RECEIVER; transactionParams.pduConf.sourceId = sourceParams.cfg.localId; @@ -304,3 +312,6 @@ ReturnValue_t cfdp::SourceHandler::reset() { transactionParams.reset(); return OK; } +cfdp::CfdpState cfdp::SourceHandler::getState() const { return state; } + +cfdp::SourceHandler::TransactionStep cfdp::SourceHandler::getStep() const { return step; } diff --git a/src/fsfw/cfdp/handler/SourceHandler.h b/src/fsfw/cfdp/handler/SourceHandler.h index 31fafcb2..acac6dfd 100644 --- a/src/fsfw/cfdp/handler/SourceHandler.h +++ b/src/fsfw/cfdp/handler/SourceHandler.h @@ -7,6 +7,7 @@ #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" @@ -26,6 +27,17 @@ struct SourceHandlerParams { class SourceHandler { public: + enum class TransactionStep : uint8_t { + IDLE = 0, + TRANSACTION_START = 1, + CRC_PROCEDURE = 2, + 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; @@ -38,33 +50,25 @@ class SourceHandler { 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 putRequest(PutRequestFull& putRequest, RemoteEntityCfg& cfg); + ReturnValue_t transactionStart(PutRequest& putRequest, RemoteEntityCfg& cfg); FsmResult& stateMachine(); ReturnValue_t initialize(); private: - enum class TransactionStep : uint8_t { - IDLE = 0, - TRANSACTION_START = 1, - CRC_PROCEDURE = 2, - SENDING_METADATA = 3, - SENDING_FILE_DATA = 4, - SENDING_EOF = 5, - WAIT_FOR_ACK = 6, - WAIT_FOR_FINISH = 7, - NOTICE_OF_COMPLETION = 8 - }; struct TransactionParams { uint32_t crc{}; - std::array sourceName{}; + std::array sourceName{}; size_t sourceNameSize = 0; - std::array destName{}; + std::array destName{}; size_t destNameSize = 0; cfdp::Fss fileSize; size_t progress = 0; @@ -72,7 +76,7 @@ class SourceHandler { RemoteEntityCfg remoteCfg; PduConfig pduConf; cfdp::TransactionId id{}; - cfdp::WidthInBytes seqCountWidth; + cfdp::WidthInBytes seqCountWidth{}; void reset() { sourceNameSize = 0; diff --git a/src/fsfw/cfdp/handler/defs.h b/src/fsfw/cfdp/handler/defs.h index 97ef009c..c1a3fbfd 100644 --- a/src/fsfw/cfdp/handler/defs.h +++ b/src/fsfw/cfdp/handler/defs.h @@ -48,18 +48,6 @@ template using PacketInfoList = etl::list; using PacketInfoListBase = etl::ilist; -struct PutRequestFull { - public: - EntityId destId; - TransmissionMode transmissionMode = TransmissionMode::UNACKNOWLEDGED; - char destName[524]{}; - size_t destNameSize = 0; - char sourceName[524]{}; - size_t sourceNameSize = 0; - bool closureRequested = true; - // MessageToUserTlv -}; - enum class CallStatus { DONE, CALL_AFTER_DELAY, CALL_AGAIN }; namespace events { @@ -75,7 +63,10 @@ static constexpr Event FILENAME_TOO_LARGE_ERROR = event::makeEvent(SSID, 4, seve 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, 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); } // namespace cfdp #endif // FSFW_CFDP_HANDLER_DEFS_H diff --git a/src/fsfw/cfdp/tlv/Lv.cpp b/src/fsfw/cfdp/tlv/Lv.cpp index 3bbfb5b9..0daec472 100644 --- a/src/fsfw/cfdp/tlv/Lv.cpp +++ b/src/fsfw/cfdp/tlv/Lv.cpp @@ -93,3 +93,5 @@ cfdp::Lv& cfdp::Lv::operator=(cfdp::Lv&& other) noexcept { other.value = SerialBufferAdapter(); return *this; } + +size_t cfdp::Lv::getValueLen() const { return getSerializedSize() - 1; } diff --git a/src/fsfw/cfdp/tlv/Lv.h b/src/fsfw/cfdp/tlv/Lv.h index a17d4617..c1ab78de 100644 --- a/src/fsfw/cfdp/tlv/Lv.h +++ b/src/fsfw/cfdp/tlv/Lv.h @@ -40,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 diff --git a/unittests/cfdp/handler/testSourceHandler.cpp b/unittests/cfdp/handler/testSourceHandler.cpp index 29b12f99..879e5ca2 100644 --- a/unittests/cfdp/handler/testSourceHandler.cpp +++ b/unittests/cfdp/handler/testSourceHandler.cpp @@ -1,6 +1,8 @@ #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/FileDataCreator.h" @@ -18,6 +20,7 @@ TEST_CASE("CFDP Source Handler", "[cfdp]") { using namespace cfdp; using namespace returnvalue; + using namespace std::filesystem; MessageQueueId_t destQueueId = 2; AcceptsTmMock tmReceiver(destQueueId); MessageQueueMock mqMock(destQueueId); @@ -36,4 +39,22 @@ TEST_CASE("CFDP Source Handler", "[cfdp]") { StorageManagerMock tmStore(3, storeCfg); FsfwParams fp(tmReceiver, &mqMock, &eventReporterMock); auto sourceHandler = SourceHandler(dp, fp); + + SECTION("Test Basic") { + CHECK(sourceHandler.getState() == CfdpState::IDLE); + CHECK(sourceHandler.getStep() == SourceHandler::TransactionStep::IDLE); + } + + SECTION("Transfer empty file") { + RemoteEntityCfg cfg; + EntityId id(cfdp::WidthInBytes::ONE_BYTE, 5); + cfg.remoteId = id; + FilesystemParams srcFileName("/tmp/cfdp-test.txt"); + fsMock.createFile(srcFileName); + cfdp::StringLv srcNameLv(srcFileName.path, std::strlen(srcFileName.path)); + FilesystemParams destFileName("/tmp/cfdp-test.txt"); + cfdp::StringLv destNameLv(destFileName.path, std::strlen(destFileName.path)); + PutRequest putRequest(id, srcNameLv, destNameLv); + CHECK(sourceHandler.transactionStart(putRequest, cfg) == OK); + } } \ No newline at end of file