Compare commits

...

25 Commits

Author SHA1 Message Date
dfe7c378da move CRC check 2023-11-10 11:27:54 +01:00
cc3e64e70d Merge pull request 'CFDP SOURCE handler' (#157) from cfdp-source-handler into develop
Reviewed-on: #157
Reviewed-by: Marius Eggert <eggertm@irs.uni-stuttgart.de>
2023-10-19 10:59:53 +02:00
6021257a87 unittest fix 2023-10-19 10:21:18 +02:00
63c238005e Merge remote-tracking branch 'origin/develop' into cfdp-source-handler 2023-10-11 12:57:14 +02:00
0f604b35c6 improved readability 2023-10-09 09:26:56 +02:00
e3a815444e checkModeCommand to protected 2023-09-29 15:26:43 +02:00
19093866ee rtval for non op soc 2023-09-29 14:27:54 +02:00
497f947237 add missing 0 termination 2023-09-14 15:04:54 +02:00
5bd020193b initialize result 2023-09-11 15:38:46 +02:00
420c0625a5 result was not stored properly 2023-09-11 15:38:06 +02:00
42a0b15303 hardcore bug 2023-09-06 20:49:53 +02:00
c199cbedaa some improvements, remove debugging stuff 2023-09-06 13:40:18 +02:00
c4e18cc2f3 what was i thinking here? 2023-09-06 11:45:02 +02:00
c143198494 debugging 2023-09-06 10:11:09 +02:00
448fbd0d38 this should be less confusing, saner defaults 2023-09-05 16:04:48 +02:00
470f589bde need to rework this fsm.. but works now 2023-09-04 11:01:55 +02:00
dfcfb035be fix some retval duplications 2023-08-31 15:09:22 +02:00
6e53582dc9 split up CFDP retval domains 2023-08-31 14:59:09 +02:00
fb1500e041 continue 2023-08-30 11:34:38 +02:00
ea2e58249d API improvements 2023-08-30 11:18:49 +02:00
9ef63825f3 optimization 2023-08-16 13:15:34 +02:00
073cb4b3d5 adaptions for reserved message handling 2023-08-16 13:10:21 +02:00
8c11685240 introduce handling for full target queue 2023-08-14 21:19:35 +02:00
cb1aaea6cd add more checks 2023-08-14 21:04:22 +02:00
22df8f6147 fix the tests 2023-08-14 21:01:29 +02:00
36 changed files with 200 additions and 157 deletions

View File

@@ -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);

View File

@@ -146,7 +146,7 @@ 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) {
@@ -274,8 +274,7 @@ ReturnValue_t cfdp::DestHandler::handleMetadataParseError(ReturnValue_t result,
return returnvalue::FAILED;
}
ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader,
MetadataGenericInfo& info) {
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;
@@ -283,25 +282,31 @@ ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader,
ReturnValue_t result = OK;
size_t sourceNameSize = 0;
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;
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(transactionParams.sourceName.data(), sourceNamePtr, sourceNameSize);
transactionParams.sourceName[sourceNameSize] = '\0';
size_t destNameSize = 0;
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;
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(transactionParams.destName.data(), destNamePtr, destNameSize);
transactionParams.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) {
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
@@ -338,12 +343,19 @@ ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader,
#endif
return FAILED;
}
fsmRes.step = TransactionStep::TRANSACTION_START;
if (reader.getTransmissionMode() == TransmissionMode::UNACKNOWLEDGED) {
fsmRes.state = CfdpState::BUSY_CLASS_1_NACKED;
} else if (reader.getTransmissionMode() == TransmissionMode::ACKNOWLEDGED) {
fsmRes.state = CfdpState::BUSY_CLASS_2_ACKED;
}
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);
@@ -351,20 +363,19 @@ ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader,
transactionParams.transactionId.entityId = transactionParams.pduConf.sourceId;
transactionParams.transactionId.seqNum = transactionParams.pduConf.seqNum;
transactionParams.fileSize = info.getFileSize();
fsmRes.step = TransactionStep::RECEIVING_FILE_DATA_PDUS;
MetadataRecvdParams params(transactionParams.transactionId, transactionParams.pduConf.sourceId,
transactionParams.fileSize);
params.destFileName = transactionParams.destName.data();
params.sourceFileName = transactionParams.sourceName.data();
unsigned tlvIdx = 0;
params.numberOfMsgsToUser = 0;
for (const auto& opt : tlvVec) {
if (opt.getType() == TlvType::MSG_TO_USER) {
msgToUserVec[tlvIdx] = MessageToUserTlv(opt.getValue(), opt.getLengthField());
tlvIdx++;
msgToUserVec[params.numberOfMsgsToUser] =
MessageToUserTlv(opt.getValue(), opt.getLengthField());
params.numberOfMsgsToUser++;
}
}
params.msgsToUserArray = msgToUserVec.data();
params.msgsToUserLen = tlvIdx;
destParams.user.metadataRecvdIndication(params);
return result;
}

View File

@@ -125,11 +125,13 @@ 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;
@@ -153,7 +155,7 @@ class DestHandler {
cfdp::FsfwParams fsfwParams;
FsmResult fsmRes;
ReturnValue_t startTransaction(MetadataPduReader& reader, MetadataGenericInfo& 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);

View File

@@ -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

View File

@@ -13,27 +13,24 @@ cfdp::ReservedMessageParser::ReservedMessageParser(StorageManagerIF& ipcStore,
MessageQueueId_t userDestination)
: msgQueue(msgQueue), ipcStore(ipcStore), userDestination(userDestination) {}
ReturnValue_t cfdp::ReservedMessageParser::parse(const uint8_t* msgsToUserPtr,
size_t sizeOfMessages) {
ReturnValue_t result;
size_t currentIdx = 0;
const uint8_t* currentPtr = msgsToUserPtr;
MessageToUserTlv tlv;
size_t deserSize = sizeOfMessages;
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;
while (currentIdx < sizeOfMessages) {
result = tlv.deSerialize(&currentPtr, &deserSize, SerializeIF::Endianness::NETWORK);
if (result != returnvalue::OK) {
return result;
for (size_t idx = 0; idx < numMsgToUser; idx++) {
if (&msgsToUserArray[idx] == nullptr) {
continue;
}
uint8_t messageType = 0;
if (tlv.isReservedCfdpMessage(messageType, &currentPtr, deserSize)) {
if (msgsToUserArray[idx].isReservedCfdpMessage(messageType, &currentPtr, deserSize)) {
if (messageType == static_cast<uint8_t>(ProxyOpMessageType::PUT_REQUEST)) {
EntityId entityIdLv;
entityIdLv.deSerializeFromLv(&currentPtr, &deserSize);
result = entityIdLv.deSerializeFromLv(&currentPtr, &deserSize);
if (result != returnvalue::OK) {
return result;
}
@@ -52,7 +49,6 @@ ReturnValue_t cfdp::ReservedMessageParser::parse(const uint8_t* msgsToUserPtr,
needToSendPutRequest = true;
}
}
currentIdx += tlv.getSerializedSize();
}
if (needToSendPutRequest) {
store_address_t storeId;

View File

@@ -1,5 +1,6 @@
#pragma once
#include "fsfw/cfdp/tlv/MessageToUserTlv.h"
#include "fsfw/ipc/MessageQueueIF.h"
#include "fsfw/storagemanager/StorageManagerIF.h"
@@ -15,7 +16,7 @@ class ReservedMessageParser {
ReservedMessageParser(StorageManagerIF& ipcStore, MessageQueueIF& msgQueue,
MessageQueueId_t userDestination);
ReturnValue_t parse(const uint8_t* msgsToUserPtr, size_t sizeOfMessages);
ReturnValue_t parse(const MessageToUserTlv* msgsToUserArray, size_t numMsgsToUser);
private:
MessageQueueIF& msgQueue;

View File

@@ -11,6 +11,7 @@
#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;
@@ -49,19 +50,16 @@ cfdp::SourceHandler::FsmResult& cfdp::SourceHandler::fsmNacked() {
}
if (step == TransactionStep::TRANSACTION_START) {
sourceParams.user.transactionIndication(transactionParams.id);
step = TransactionStep::CRC_PROCEDURE;
}
if (step == TransactionStep::CRC_PROCEDURE) {
result = checksumGeneration();
if (result != OK) {
// TODO: Some error handling
addError(result);
}
step = TransactionStep::SENDING_METADATA;
}
if (step == TransactionStep::SENDING_METADATA) {
result = prepareAndSendMetadataPdu();
if (result != OK) {
// TODO: Error handling
addError(result);
}
fsmResult.callStatus = CallStatus::CALL_AGAIN;
return fsmResult;
@@ -69,10 +67,7 @@ cfdp::SourceHandler::FsmResult& cfdp::SourceHandler::fsmNacked() {
if (step == TransactionStep::SENDING_FILE_DATA) {
bool noFdPdu = false;
result = prepareAndSendNextFileDataPdu(noFdPdu);
if (result != OK) {
// TODO: Error handling
}
if (!noFdPdu) {
if (result == OK and !noFdPdu) {
fsmResult.callStatus = CallStatus::CALL_AGAIN;
return fsmResult;
}
@@ -80,7 +75,7 @@ cfdp::SourceHandler::FsmResult& cfdp::SourceHandler::fsmNacked() {
if (step == TransactionStep::SENDING_EOF) {
result = prepareAndSendEofPdu();
if (result != OK) {
// TODO: Error handling
addError(result);
}
if (sourceParams.cfg.indicCfg.eofSentIndicRequired) {
sourceParams.user.eofSentIndication(transactionParams.id);
@@ -141,8 +136,7 @@ ReturnValue_t cfdp::SourceHandler::checksumGeneration() {
params.size = readLen;
auto result = sourceParams.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
addError(result);
return FAILED;
}
crcCalc.add(buf.begin(), buf.begin() + readLen);
@@ -171,6 +165,10 @@ ReturnValue_t cfdp::SourceHandler::transactionStart(PutRequest& putRequest, Remo
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;
@@ -322,6 +320,10 @@ ReturnValue_t cfdp::SourceHandler::sendGenericPdu(const SerializeIF& pdu) {
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;
@@ -333,7 +335,12 @@ ReturnValue_t cfdp::SourceHandler::sendGenericPdu(const SerializeIF& pdu) {
TmTcMessage tmMsg(storeId);
result =
fsfwParams.msgQueue->sendMessage(fsfwParams.packetDest.getReportReceptionQueue(), &tmMsg);
if (result == OK) {
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;
@@ -364,5 +371,6 @@ void cfdp::SourceHandler::addError(ReturnValue_t error) {
if (fsmResult.errors < fsmResult.errorCodes.size()) {
fsmResult.errorCodes[fsmResult.errors] = error;
fsmResult.errors++;
fsmResult.result = error;
}
}

View File

@@ -30,7 +30,6 @@ class SourceHandler {
enum class TransactionStep : uint8_t {
IDLE = 0,
TRANSACTION_START = 1,
CRC_PROCEDURE = 2,
SENDING_METADATA = 3,
SENDING_FILE_DATA = 4,
SENDING_EOF = 5,

View File

@@ -35,7 +35,7 @@ struct MetadataRecvdParams {
Fss fileSize{};
const char* sourceFileName = "";
const char* destFileName = "";
size_t msgsToUserLen = 0;
size_t numberOfMsgsToUser = 0;
const MessageToUserTlv* msgsToUserArray = nullptr;
};

View File

@@ -12,7 +12,7 @@ namespace cfdp {
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;
static constexpr uint8_t CID = CLASS_ID::CFDP_HANDLER;
struct PacketInfo {
PacketInfo(PduType type, store_address_t storeId,
@@ -58,6 +58,8 @@ 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
@@ -67,6 +69,8 @@ static constexpr ReturnValue_t FILE_SEGMENT_LEN_INVALID = returnvalue::makeCode(
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

View File

@@ -30,7 +30,7 @@ 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;

View File

@@ -21,7 +21,7 @@ void MetadataGenericInfo::setClosureRequested(bool closureRequested_) {
closureRequested = closureRequested_;
}
cfdp::Fss& MetadataGenericInfo::getFileSize() { return fileSize; }
const cfdp::Fss& MetadataGenericInfo::getFileSize() const { return fileSize; }
size_t MetadataGenericInfo::getSerializedSize(bool fssLarge) {
// 1 byte + minimal FSS 4 bytes
@@ -31,3 +31,5 @@ size_t MetadataGenericInfo::getSerializedSize(bool fssLarge) {
}
return size;
}
cfdp::Fss& MetadataGenericInfo::getMutFileSize() { return fileSize; }

View File

@@ -22,7 +22,9 @@ class MetadataGenericInfo {
[[nodiscard]] bool isClosureRequested() const;
void setClosureRequested(bool closureRequested = false);
cfdp::Fss& getFileSize();
[[nodiscard]] const cfdp::Fss& getFileSize() const;
cfdp::Fss& getMutFileSize();
private:
bool closureRequested = false;

View File

@@ -25,7 +25,7 @@ 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;
}
@@ -63,3 +63,5 @@ size_t MetadataPduReader::getNumberOfParsedOptions() const { return parsedOption
const cfdp::StringLv& MetadataPduReader::getSourceFileName() const { return srcFileName; }
const cfdp::StringLv& MetadataPduReader::getDestFileName() const { return destFileName; }
const MetadataGenericInfo& MetadataPduReader::getGenericInfo() const { return info; }

View File

@@ -11,6 +11,7 @@ class MetadataPduReader : public FileDirectiveReader {
ReturnValue_t parseData() override;
[[nodiscard]] const MetadataGenericInfo& getGenericInfo() const;
[[nodiscard]] const cfdp::StringLv& getSourceFileName() const;
[[nodiscard]] const cfdp::StringLv& getDestFileName() const;

View File

@@ -95,3 +95,5 @@ cfdp::Lv& cfdp::Lv::operator=(cfdp::Lv&& other) noexcept {
}
size_t cfdp::Lv::getValueLen() const { return getSerializedSize() - 1; }
bool cfdp::Lv::isEmpty() const { return zeroLen; }

View File

@@ -50,6 +50,8 @@ class Lv : public SerializeIF {
*/
const uint8_t* getValue(size_t* size) const;
bool isEmpty() const;
private:
bool zeroLen = true;
SerialBufferAdapter<uint8_t> value;

View File

@@ -16,7 +16,7 @@ bool MessageToUserTlv::isReservedCfdpMessage(uint8_t& messageType, const uint8_t
if (cfdp::Tlv::getLengthField() < 5) {
return false;
}
if (std::strcmp(reinterpret_cast<const char*>(getValue()), "cfdp") == 0) {
if (std::strncmp(reinterpret_cast<const char*>(getValue()), "cfdp", 4) == 0) {
messageType = getValue()[4];
if (msgDataStart != nullptr) {
*msgDataStart = getValue() + 5;

View File

@@ -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; }

View File

@@ -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<uint8_t> value;
};

View File

@@ -85,6 +85,7 @@ class DeviceHandlerIF {
static const ReturnValue_t NO_REPLY_EXPECTED = MAKE_RETURN_CODE(0xA8);
static const ReturnValue_t NON_OP_TEMPERATURE = MAKE_RETURN_CODE(0xA9);
static const ReturnValue_t COMMAND_NOT_IMPLEMENTED = MAKE_RETURN_CODE(0xAA);
static const ReturnValue_t NON_OP_STATE_OF_CHARGE = MAKE_RETURN_CODE(0xAB);
// Standard codes used in scanForReply
static const ReturnValue_t CHECKSUM_ERROR = MAKE_RETURN_CODE(0xB0);

View File

@@ -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() {

View File

@@ -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;

View File

@@ -38,6 +38,8 @@ class PowerSwitcherComponent : public SystemObject,
protected:
PowerSwitcher switcher;
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode) override;
private:
MessageQueueIF *queue = nullptr;
@@ -56,8 +58,6 @@ class PowerSwitcherComponent : public SystemObject,
[[nodiscard]] MessageQueueId_t getCommandQueue() const override;
void getMode(Mode_t *mode, Submode_t *submode) override;
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode) override;
void startTransition(Mode_t mode, Submode_t submode) override;
virtual void performFaultyOperation();
void setToExternalControl() override;

View File

@@ -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

View File

@@ -107,14 +107,6 @@ uint8_t* SerialBufferAdapter<count_t>::getBuffer() {
template <typename count_t>
const uint8_t* SerialBufferAdapter<count_t>::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;
}

View File

@@ -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);

View File

@@ -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

View File

@@ -57,6 +57,13 @@ ReturnValue_t PusTmReader::parseData(bool crcCheck) {
if (result != returnvalue::OK) {
return result;
}
if (crcCheck) {
uint16_t crc16 = CRC::crc16ccitt(spReader.getFullData(), getFullPacketLen());
if (crc16 != 0) {
// Checksum failure
return PusIF::INVALID_CRC_16;
}
}
size_t currentOffset = SpacePacketReader::getHeaderLen();
pointers.secHeaderStart = pointers.spHeaderStart + currentOffset;
currentOffset += PusTmIF::MIN_SEC_HEADER_LEN;
@@ -77,13 +84,6 @@ ReturnValue_t PusTmReader::parseData(bool crcCheck) {
}
currentOffset += sourceDataLen;
pointers.crcStart = pointers.spHeaderStart + currentOffset;
if (crcCheck) {
uint16_t crc16 = CRC::crc16ccitt(spReader.getFullData(), getFullPacketLen());
if (crc16 != 0) {
// Checksum failure
return PusIF::INVALID_CRC_16;
}
}
return returnvalue::OK;
}
bool PusTmReader::isNull() const { return spReader.isNull() or pointers.secHeaderStart == nullptr; }

View File

@@ -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());
}

View File

@@ -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<store_address_t>* 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;
};

View File

@@ -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;

View File

@@ -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 };

View File

@@ -134,7 +134,7 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
}
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);
@@ -143,23 +143,23 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
}
SECTION("Empty File Transfer") {
const DestHandler::FsmResult& res = destHandler.performStateMachine();
const DestHandler::FsmResult& res = destHandler.stateMachine();
CHECK(res.result == OK);
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;
@@ -167,9 +167,9 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
uint32_t crc32 = crcCalc.value();
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();
Fss offset(0);
@@ -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());
@@ -203,9 +203,9 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
uint32_t crc32 = crcCalc.value();
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();
@@ -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);
}
}

View File

@@ -40,10 +40,10 @@ TEST_CASE("Reserved Message Parser", "[cfdp]") {
serLen = 0;
ReturnValue_t result = creator.serializeBe(buffer.data(), serLen, buffer.size());
CHECK(result == returnvalue::OK);
arrayprinter::print(buffer.data(), serLen);
MessageToUserTlv msgToUser;
CHECK(msgToUser.deSerializeBe(buffer.data(), serLen, buffer.size()) == OK);
ReservedMessageParser parser(ipcStore, msgQueue, destQueueId);
REQUIRE(parser.parse(buffer.data(), serLen) == OK);
REQUIRE(parser.parse(&msgToUser, 1) == OK);
CommandMessage msg;
CHECK(msgQueue.wasMessageSent());
CHECK(msgQueue.numberOfSentMessages() == 1);

View File

@@ -63,7 +63,7 @@ TEST_CASE("CFDP Source Handler", "[cfdp]") {
PutRequest putRequest(remoteId, srcNameLv, destNameLv);
CHECK(sourceHandler.initialize() == OK);
auto onePduSentCheck = [&](SourceHandler::FsmResult& fsmResult, TmTcMessage& tmtcMessage,
auto onePduSentCheck = [&](const SourceHandler::FsmResult& fsmResult, TmTcMessage& tmtcMessage,
const uint8_t** pduPtr) {
CHECK(fsmResult.errors == 0);
CHECK(fsmResult.packetsSent == 1);
@@ -74,9 +74,10 @@ TEST_CASE("CFDP Source Handler", "[cfdp]") {
*pduPtr = accessor.second.data();
return std::move(accessor);
};
auto genericMetadataCheck = [&](SourceHandler::FsmResult& fsmResult, size_t expectedFileSize,
uint16_t expectedSeqNum) {
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);
@@ -108,9 +109,10 @@ TEST_CASE("CFDP Source Handler", "[cfdp]") {
CHECK(!metadataInfo.isClosureRequested());
mqMock.clearMessages();
};
auto genericEofCheck = [&](SourceHandler::FsmResult& fsmResult, size_t expectedFileSize,
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);
@@ -126,12 +128,20 @@ TEST_CASE("CFDP Source Handler", "[cfdp]") {
auto transactionId = TransactionId(localId, seqNum);
CHECK(userMock.eofSentRecvd.size() == 1);
CHECK(userMock.eofSentRecvd.back() == transactionId);
CHECK(userMock.finishedRecvd.size() == 1);
CHECK(userMock.finishedRecvd.back().first == 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);
@@ -141,16 +151,17 @@ TEST_CASE("CFDP Source Handler", "[cfdp]") {
CHECK(sourceHandler.transactionStart(putRequest, cfg) == OK);
size_t expectedFileSize = 0;
SourceHandler::FsmResult& fsmResult = sourceHandler.stateMachine();
const SourceHandler::FsmResult& fsmResult = sourceHandler.stateMachine();
// Verify metadata PDU was sent.
genericMetadataCheck(fsmResult, expectedFileSize, 0);
fsmResult = sourceHandler.stateMachine();
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);
CHECK(sourceHandler.getStep() == SourceHandler::TransactionStep::IDLE);
CHECK(sourceHandler.getState() == CfdpState::IDLE);
// Verify notice of completion.
sourceHandler.stateMachine();
genericNoticeOfCompletionCheck(fsmResult, 0);
}
SECTION("Transfer small file") {
@@ -161,13 +172,13 @@ TEST_CASE("CFDP Source Handler", "[cfdp]") {
FileOpParams params(srcFileName.c_str(), expectedFileSize);
fsMock.writeToFile(params, reinterpret_cast<const uint8_t*>(fileContent.data()));
CHECK(sourceHandler.transactionStart(putRequest, cfg) == OK);
SourceHandler::FsmResult& fsmResult = sourceHandler.stateMachine();
const SourceHandler::FsmResult& fsmResult = sourceHandler.stateMachine();
// Verify metadata PDU was sent.
genericMetadataCheck(fsmResult, expectedFileSize, expectedSeqNum);
// Verify that a small file data PDU was sent.
fsmResult = sourceHandler.stateMachine();
sourceHandler.stateMachine();
TmTcMessage tmtcMessage;
const uint8_t* pduPtr;
auto accessor = onePduSentCheck(fsmResult, tmtcMessage, &pduPtr);
@@ -185,15 +196,16 @@ TEST_CASE("CFDP Source Handler", "[cfdp]") {
CHECK(dataReadBack == fileContent);
mqMock.clearMessages();
fsmResult = sourceHandler.stateMachine();
sourceHandler.stateMachine();
etl::crc32 crcCalc;
crcCalc.add(fileContent.data(), fileContent.data() + fileContent.size());
// Verify EOF PDU was sent.
genericEofCheck(fsmResult, expectedFileSize, crcCalc.value(), expectedSeqNum);
CHECK(sourceHandler.getStep() == SourceHandler::TransactionStep::IDLE);
CHECK(sourceHandler.getState() == CfdpState::IDLE);
// Verify notice of completion.
sourceHandler.stateMachine();
genericNoticeOfCompletionCheck(fsmResult, expectedSeqNum);
}
SECTION("Transfer two segment file") {
@@ -212,16 +224,17 @@ TEST_CASE("CFDP Source Handler", "[cfdp]") {
FileOpParams params(srcFileName.c_str(), expectedFileSize);
fsMock.writeToFile(params, reinterpret_cast<const uint8_t*>(largerFileData.data()));
CHECK(sourceHandler.transactionStart(putRequest, cfg) == OK);
SourceHandler::FsmResult& fsmResult = sourceHandler.stateMachine();
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.
fsmResult = sourceHandler.stateMachine();
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
@@ -239,31 +252,35 @@ TEST_CASE("CFDP Source Handler", "[cfdp]") {
mqMock.clearMessages();
// Check second file data PDU.
fsmResult = sourceHandler.stateMachine();
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]);
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.
fsmResult = sourceHandler.stateMachine();
sourceHandler.stateMachine();
etl::crc32 crcCalc;
crcCalc.add(largerFileData.data(), largerFileData.data() + largerFileData.size());
// Verify EOF PDU was sent.
genericEofCheck(fsmResult, expectedFileSize, crcCalc.value(), expectedSeqNum);
CHECK(sourceHandler.getStep() == SourceHandler::TransactionStep::IDLE);
CHECK(sourceHandler.getState() == CfdpState::IDLE);
// Verify notice of completion.
sourceHandler.stateMachine();
genericNoticeOfCompletionCheck(fsmResult, expectedSeqNum);
}
}