CFDP SOURCE handler #157

Merged
muellerr merged 107 commits from cfdp-source-handler into develop 2023-10-19 10:59:55 +02:00
8 changed files with 92 additions and 42 deletions
Showing only changes of commit a856f91c67 - Show all commits

View File

@ -185,3 +185,17 @@ const uint8_t *cfdp::PutRequest::getMessagesToUser(size_t &totalSize) {
totalSize = this->msgsToUsersTotalSize; totalSize = this->msgsToUsersTotalSize;
return msgsToUserStartPtr; 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<cfdp::TransmissionMode>(this->transmissionMode);
}
return hasTransmissionMode;
}

View File

@ -22,7 +22,9 @@ class PutRequest : public SerializeIF {
PutRequest(EntityId destId, const uint8_t* msgsToUser, size_t msgsToUserTotalSize, PutRequest(EntityId destId, const uint8_t* msgsToUser, size_t msgsToUserTotalSize,
const uint8_t* fsRequests, size_t fsRequestsSize); 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 destId
* @param sourceName * @param sourceName
* @param destName * @param destName
@ -53,6 +55,9 @@ class PutRequest : public SerializeIF {
[[nodiscard]] bool isMetadataOnly() const; [[nodiscard]] bool isMetadataOnly() const;
bool getTransmissionMode(TransmissionMode& mode) const;
bool getClosureRequested(bool& closureRequested) const;
[[nodiscard]] const EntityId& getDestId() const; [[nodiscard]] const EntityId& getDestId() const;
void setDestId(EntityId id); void setDestId(EntityId id);

View File

@ -138,21 +138,23 @@ ReturnValue_t cfdp::SourceHandler::checksumGeneration() {
return OK; return OK;
} }
ReturnValue_t cfdp::SourceHandler::putRequest(PutRequestFull& putRequest, RemoteEntityCfg& cfg) { ReturnValue_t cfdp::SourceHandler::transactionStart(PutRequest& putRequest, RemoteEntityCfg& cfg) {
if (state != CfdpState::IDLE) { if (state != CfdpState::IDLE) {
Review

boop

boop
Review

Will be added when fault declaration works properly

Will be added when fault declaration works properly
return SOURCE_TRANSACTION_PENDING; return SOURCE_TRANSACTION_PENDING;
} }
if (putRequest.sourceNameSize > transactionParams.sourceName.size()) { if (cfg.remoteId != putRequest.getDestId()) {
return FAILED; return WRONG_REMOTE_CFG_ENTITY_ID;
} }
if (putRequest.destNameSize > transactionParams.destName.size()) { if (putRequest.getSourceName().getValueLen() == 0) {
return FAILED; return SOURCE_NAME_EMPTY;
} }
std::memcpy(transactionParams.destName.data(), putRequest.destName, putRequest.destNameSize); if (putRequest.getDestName().getValueLen() == 0) {
std::memcpy(transactionParams.sourceName.data(), putRequest.sourceName, return DEST_NAME_EMPTY;
putRequest.sourceNameSize); }
transactionParams.sourceNameSize = putRequest.sourceNameSize; const char* srcNamePtr = putRequest.getSourceName().getString(transactionParams.sourceNameSize);
transactionParams.destNameSize = putRequest.destNameSize; 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()); FilesystemParams params(transactionParams.sourceName.data());
if (!sourceParams.user.vfs.fileExists(params)) { if (!sourceParams.user.vfs.fileExists(params)) {
return FILE_DOES_NOT_EXIST; 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) { if (cfg.maxFileSegmentLen > fileBuf.size() or cfg.maxFileSegmentLen == 0) {
return FILE_SEGMENT_LEN_INVALID; return FILE_SEGMENT_LEN_INVALID;
} }
transactionParams.closureRequested = putRequest.closureRequested; // If transmission mode is not set, use default transmission mode for the remote entity.
transactionParams.pduConf.mode = putRequest.transmissionMode; if (not putRequest.getTransmissionMode(transactionParams.pduConf.mode)) {
transactionParams.pduConf.destId = putRequest.destId; 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. // Only used for PDU forwarding, file is sent to file receiver regularly here.
transactionParams.pduConf.direction = Direction::TOWARDS_RECEIVER; transactionParams.pduConf.direction = Direction::TOWARDS_RECEIVER;
transactionParams.pduConf.sourceId = sourceParams.cfg.localId; transactionParams.pduConf.sourceId = sourceParams.cfg.localId;
@ -304,3 +312,6 @@ ReturnValue_t cfdp::SourceHandler::reset() {
transactionParams.reset(); transactionParams.reset();
return OK; return OK;
} }
cfdp::CfdpState cfdp::SourceHandler::getState() const { return state; }
cfdp::SourceHandler::TransactionStep cfdp::SourceHandler::getStep() const { return step; }

View File

@ -7,6 +7,7 @@
#include "UserBase.h" #include "UserBase.h"
#include "defs.h" #include "defs.h"
#include "fsfw/cfdp/Fss.h" #include "fsfw/cfdp/Fss.h"
#include "fsfw/cfdp/handler/PutRequest.h"
#include "fsfw/cfdp/handler/mib.h" #include "fsfw/cfdp/handler/mib.h"
#include "fsfw/events/EventReportingProxyIF.h" #include "fsfw/events/EventReportingProxyIF.h"
#include "fsfw/storagemanager/StorageManagerIF.h" #include "fsfw/storagemanager/StorageManagerIF.h"
@ -26,6 +27,17 @@ struct SourceHandlerParams {
class SourceHandler { class SourceHandler {
public: 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 { struct FsmResult {
public: public:
ReturnValue_t result = returnvalue::OK; ReturnValue_t result = returnvalue::OK;
@ -38,33 +50,25 @@ class SourceHandler {
SourceHandler(SourceHandlerParams params, FsfwParams fsfwParams); 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 * Pass a put request to the source handler, which might initiate a CFDP transaction and start
* the state machine * the state machine
* @return * @return
*/ */
ReturnValue_t putRequest(PutRequestFull& putRequest, RemoteEntityCfg& cfg); ReturnValue_t transactionStart(PutRequest& putRequest, RemoteEntityCfg& cfg);
FsmResult& stateMachine(); FsmResult& stateMachine();
ReturnValue_t initialize(); ReturnValue_t initialize();
private: 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 { struct TransactionParams {
uint32_t crc{}; uint32_t crc{};
std::array<char, 524> sourceName{}; std::array<char, UINT8_MAX + 1> sourceName{};
size_t sourceNameSize = 0; size_t sourceNameSize = 0;
std::array<char, 524> destName{}; std::array<char, UINT8_MAX + 1> destName{};
size_t destNameSize = 0; size_t destNameSize = 0;
cfdp::Fss fileSize; cfdp::Fss fileSize;
size_t progress = 0; size_t progress = 0;
@ -72,7 +76,7 @@ class SourceHandler {
RemoteEntityCfg remoteCfg; RemoteEntityCfg remoteCfg;
PduConfig pduConf; PduConfig pduConf;
cfdp::TransactionId id{}; cfdp::TransactionId id{};
cfdp::WidthInBytes seqCountWidth; cfdp::WidthInBytes seqCountWidth{};
void reset() { void reset() {
sourceNameSize = 0; sourceNameSize = 0;

View File

@ -48,18 +48,6 @@ template <size_t SIZE>
using PacketInfoList = etl::list<PacketInfo, SIZE>; using PacketInfoList = etl::list<PacketInfo, SIZE>;
using PacketInfoListBase = etl::ilist<PacketInfo>; using PacketInfoListBase = etl::ilist<PacketInfo>;
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 }; enum class CallStatus { DONE, CALL_AFTER_DELAY, CALL_AGAIN };
namespace events { 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 SOURCE_TRANSACTION_PENDING = returnvalue::makeCode(CID, 0);
static constexpr ReturnValue_t FILE_DOES_NOT_EXIST = returnvalue::makeCode(CID, 1); 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 } // namespace cfdp
#endif // FSFW_CFDP_HANDLER_DEFS_H #endif // FSFW_CFDP_HANDLER_DEFS_H

View File

@ -93,3 +93,5 @@ cfdp::Lv& cfdp::Lv::operator=(cfdp::Lv&& other) noexcept {
other.value = SerialBufferAdapter<uint8_t>(); other.value = SerialBufferAdapter<uint8_t>();
return *this; return *this;
} }
size_t cfdp::Lv::getValueLen() const { return getSerializedSize() - 1; }

View File

@ -40,6 +40,8 @@ class Lv : public SerializeIF {
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) override; Endianness streamEndianness) override;
size_t getValueLen() const;
/** /**
* Get value field and its size. * Get value field and its size.
* @param size Optionally retrieve size. Size will be the size of the actual value field * @param size Optionally retrieve size. Size will be the size of the actual value field

View File

@ -1,6 +1,8 @@
#include <catch2/catch_test_macros.hpp> #include <catch2/catch_test_macros.hpp>
#include <filesystem>
#include "fsfw/cfdp.h" #include "fsfw/cfdp.h"
#include "fsfw/cfdp/handler/PutRequest.h"
#include "fsfw/cfdp/handler/SourceHandler.h" #include "fsfw/cfdp/handler/SourceHandler.h"
#include "fsfw/cfdp/pdu/EofPduCreator.h" #include "fsfw/cfdp/pdu/EofPduCreator.h"
#include "fsfw/cfdp/pdu/FileDataCreator.h" #include "fsfw/cfdp/pdu/FileDataCreator.h"
@ -18,6 +20,7 @@
TEST_CASE("CFDP Source Handler", "[cfdp]") { TEST_CASE("CFDP Source Handler", "[cfdp]") {
using namespace cfdp; using namespace cfdp;
using namespace returnvalue; using namespace returnvalue;
using namespace std::filesystem;
MessageQueueId_t destQueueId = 2; MessageQueueId_t destQueueId = 2;
AcceptsTmMock tmReceiver(destQueueId); AcceptsTmMock tmReceiver(destQueueId);
MessageQueueMock mqMock(destQueueId); MessageQueueMock mqMock(destQueueId);
@ -36,4 +39,22 @@ TEST_CASE("CFDP Source Handler", "[cfdp]") {
StorageManagerMock tmStore(3, storeCfg); StorageManagerMock tmStore(3, storeCfg);
FsfwParams fp(tmReceiver, &mqMock, &eventReporterMock); FsfwParams fp(tmReceiver, &mqMock, &eventReporterMock);
auto sourceHandler = SourceHandler(dp, fp); 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);
}
} }