Merge pull request 'Filesystem and CFDP updates' (#34) from filesystem-api-update into main

Reviewed-on: #34
This commit is contained in:
Robin Müller 2024-10-29 10:26:43 +01:00
commit 3915e0d641
98 changed files with 919 additions and 863 deletions

View File

@ -4,4 +4,5 @@ IndentWidth: 2
--- ---
Language: Cpp Language: Cpp
ColumnLimit: 100 ColumnLimit: 100
ReflowComments: true
--- ---

2
.gitignore vendored
View File

@ -2,7 +2,7 @@
.idea/* .idea/*
!/.idea/runConfigurations !/.idea/runConfigurations
!/.idea/cmake.xml !/.idea/cmake.xml
!/.idea/codeStyles # !/.idea/codeStyles
# Eclipse # Eclipse
.cproject .cproject

View File

@ -1,14 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<clangFormatSettings>
<option name="ENABLED" value="true" />
</clangFormatSettings>
<codeStyleSettings language="CMake">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="0" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>

View File

@ -1,5 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

View File

@ -30,9 +30,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/742 https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/742
- `PusTmZcWriter` now exposes API to set message counter field. - `PusTmZcWriter` now exposes API to set message counter field.
- Relative timeshift in the PUS time service. - Relative timeshift in the PUS time service.
- CFDP support for PDU checksums
## Changed ## Changed
- Improved File System Abstraction to be more in line with normal filesystems.
- CFDP implementation was improved, has now even less dependencies on other FSFW components
and allows one inserted packet per state machine call.
- The PUS time service now dumps the time before setting a new time and after having set the - The PUS time service now dumps the time before setting a new time and after having set the
time. time.
- HK generation is now countdown based. - HK generation is now countdown based.

View File

@ -140,7 +140,7 @@ option(FSFW_ADD_SGP4_PROPAGATOR "Add SGP4 propagator code" OFF)
set(FSFW_TEST_TGT fsfw-tests) set(FSFW_TEST_TGT fsfw-tests)
set(FSFW_DUMMY_TGT fsfw-dummy) set(FSFW_DUMMY_TGT fsfw-dummy)
add_library(${LIB_FSFW_NAME}) add_library(${LIB_FSFW_NAME} src/fsfw/cfdp/handler/PduPacketIF.h)
if(IPO_SUPPORTED AND FSFW_ENABLE_IPO) if(IPO_SUPPORTED AND FSFW_ENABLE_IPO)
set_property(TARGET ${LIB_FSFW_NAME} PROPERTY INTERPROCEDURAL_OPTIMIZATION set_property(TARGET ${LIB_FSFW_NAME} PROPERTY INTERPROCEDURAL_OPTIMIZATION
@ -175,7 +175,10 @@ if(FSFW_BUILD_TESTS)
configure_file(unittests/testcfg/TestsConfig.h.in tests/TestsConfig.h) configure_file(unittests/testcfg/TestsConfig.h.in tests/TestsConfig.h)
project(${FSFW_TEST_TGT} CXX C) project(${FSFW_TEST_TGT} CXX C)
add_executable(${FSFW_TEST_TGT}) add_executable(
${FSFW_TEST_TGT}
unittests/cfdp/PduSenderMock.cpp unittests/cfdp/PduSenderMock.h
unittests/cfdp/handler/OwnedPduPacket.h)
if(IPO_SUPPORTED AND FSFW_ENABLE_IPO) if(IPO_SUPPORTED AND FSFW_ENABLE_IPO)
set_property(TARGET ${FSFW_TEST_TGT} PROPERTY INTERPROCEDURAL_OPTIMIZATION set_property(TARGET ${FSFW_TEST_TGT} PROPERTY INTERPROCEDURAL_OPTIMIZATION
TRUE) TRUE)

View File

@ -4,7 +4,7 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "fsfw/cfdp/pdu/PduHeaderReader.h" #include "fsfw/cfdp/pdu/HeaderReader.h"
#include "fsfw/returnvalues/returnvalue.h" #include "fsfw/returnvalues/returnvalue.h"
#include "fsfw/tcdistribution/CfdpPacketChecker.h" #include "fsfw/tcdistribution/CfdpPacketChecker.h"
#include "fsfw/tcdistribution/TcDistributorBase.h" #include "fsfw/tcdistribution/TcDistributorBase.h"

View File

@ -38,6 +38,7 @@ static constexpr ReturnValue_t FILESTORE_REQUIRES_SECOND_FILE =
static constexpr ReturnValue_t FILESTORE_RESPONSE_CANT_PARSE_FS_MESSAGE = static constexpr ReturnValue_t FILESTORE_RESPONSE_CANT_PARSE_FS_MESSAGE =
returnvalue::makeCode(CFDP_CLASS_ID, 9); returnvalue::makeCode(CFDP_CLASS_ID, 9);
static constexpr ReturnValue_t INVALID_PDU_FORMAT = returnvalue::makeCode(CFDP_CLASS_ID, 10); static constexpr ReturnValue_t INVALID_PDU_FORMAT = returnvalue::makeCode(CFDP_CLASS_ID, 10);
static constexpr ReturnValue_t PDU_CHECKSUM_FAILURE = returnvalue::makeCode(CFDP_CLASS_ID, 11);
//! Checksum types according to the SANA Checksum Types registry //! Checksum types according to the SANA Checksum Types registry
//! https://sanaregistry.org/r/checksum_identifiers/ //! https://sanaregistry.org/r/checksum_identifiers/

View File

@ -8,14 +8,18 @@
#include "fsfw/cfdp/pdu/EofPduReader.h" #include "fsfw/cfdp/pdu/EofPduReader.h"
#include "fsfw/cfdp/pdu/FileDataReader.h" #include "fsfw/cfdp/pdu/FileDataReader.h"
#include "fsfw/cfdp/pdu/FinishedPduCreator.h" #include "fsfw/cfdp/pdu/FinishedPduCreator.h"
#include "fsfw/cfdp/pdu/PduHeaderReader.h" #include "fsfw/cfdp/pdu/HeaderReader.h"
#include "fsfw/objectmanager.h" #include "fsfw/objectmanager.h"
#include "fsfw/tmtcservices/TmTcMessage.h" #include "fsfw/tmtcservices/TmTcMessage.h"
using namespace returnvalue; using namespace returnvalue;
cfdp::DestHandler::DestHandler(DestHandlerParams params, FsfwParams fsfwParams) cfdp::DestHandler::DestHandler(PduSenderIF& pduSender, size_t pduBufSize, DestHandlerParams params,
: tlvVec(params.maxTlvsInOnePdu), FsfwParams fsfwParams)
: pduBuf(pduBufSize),
pduSender(pduSender),
tlvVec(params.maxTlvsInOnePdu),
msgToUserVec(params.maxTlvsInOnePdu), msgToUserVec(params.maxTlvsInOnePdu),
transactionParams(params.maxFilenameLen), transactionParams(params.maxFilenameLen),
destParams(std::move(params)), destParams(std::move(params)),
@ -23,57 +27,44 @@ cfdp::DestHandler::DestHandler(DestHandlerParams params, FsfwParams fsfwParams)
transactionParams.pduConf.direction = cfdp::Direction::TOWARDS_SENDER; transactionParams.pduConf.direction = cfdp::Direction::TOWARDS_SENDER;
} }
const cfdp::DestHandler::FsmResult& cfdp::DestHandler::stateMachine() { const cfdp::DestHandler::FsmResult& cfdp::DestHandler::stateMachineNoPacket() {
return stateMachine(std::nullopt);
}
const cfdp::DestHandler::FsmResult& cfdp::DestHandler::stateMachine(
const std::optional<std::reference_wrapper<PduPacketIF>> optPduPacket) {
ReturnValue_t result; ReturnValue_t result;
uint8_t errorIdx = 0; uint8_t errorIdx = 0;
fsmRes.resetOfIteration(); fsmRes.resetOfIteration();
if (fsmRes.step == TransactionStep::IDLE) { if (fsmRes.step == TransactionStep::IDLE) {
for (auto infoIter = destParams.packetListRef.begin(); if (!optPduPacket.has_value()) {
infoIter != destParams.packetListRef.end();) { return fsmRes;
if (infoIter->pduType == PduType::FILE_DIRECTIVE and }
infoIter->directiveType == FileDirective::METADATA) { PduPacketIF& pduPacket = *optPduPacket;
result = handleMetadataPdu(*infoIter); if (pduPacket.getPduType() == FILE_DATA or
(pduPacket.getPduType() == FILE_DIRECTIVE and *pduPacket.getFileDirective() != METADATA)) {
fsmRes.result = DEST_NON_METADATA_PDU_AS_FIRST_PDU;
return fsmRes;
}
result = handleMetadataPdu(pduPacket);
checkAndHandleError(result, errorIdx); checkAndHandleError(result, errorIdx);
// Store data was deleted in PDU handler because a store guard is used
destParams.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 = destParams.packetListRef.begin();
infoIter != destParams.packetListRef.end();) {
fsfwParams.tcStore->deleteData(infoIter->storeId);
infoIter++;
}
destParams.packetListRef.clear();
}
if (fsmRes.step != TransactionStep::IDLE) {
fsmRes.callStatus = CallStatus::CALL_AGAIN;
}
return updateFsmRes(errorIdx); return updateFsmRes(errorIdx);
} }
if (fsmRes.state == CfdpState::BUSY_CLASS_1_NACKED) { if (fsmRes.state == CfdpState::BUSY_CLASS_1_NACKED) {
if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) { if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) {
for (auto infoIter = destParams.packetListRef.begin(); if (!optPduPacket.has_value()) {
infoIter != destParams.packetListRef.end();) { return fsmRes;
if (infoIter->pduType == PduType::FILE_DATA) { }
result = handleFileDataPdu(*infoIter); PduPacketIF& pduPacket = *optPduPacket;
if (pduPacket.getPduType() == FILE_DATA) {
result = handleFileDataPdu(pduPacket);
checkAndHandleError(result, errorIdx); checkAndHandleError(result, errorIdx);
// Store data was deleted in PDU handler because a store guard is used
destParams.packetListRef.erase(infoIter++); } else if (pduPacket.getPduType() == FILE_DIRECTIVE and
} else if (infoIter->pduType == PduType::FILE_DIRECTIVE and *pduPacket.getFileDirective() == EOF_DIRECTIVE) {
infoIter->directiveType == FileDirective::EOF_DIRECTIVE) {
// TODO: Support for check timer missing // TODO: Support for check timer missing
result = handleEofPdu(*infoIter); result = handleEofPdu(pduPacket);
checkAndHandleError(result, errorIdx); checkAndHandleError(result, errorIdx);
// Store data was deleted in PDU handler because a store guard is used
destParams.packetListRef.erase(infoIter++);
} else {
infoIter++;
} }
} }
} }
@ -85,7 +76,6 @@ const cfdp::DestHandler::FsmResult& cfdp::DestHandler::stateMachine() {
result = sendFinishedPdu(); result = sendFinishedPdu();
checkAndHandleError(result, errorIdx); checkAndHandleError(result, errorIdx);
finish(); finish();
}
return updateFsmRes(errorIdx); return updateFsmRes(errorIdx);
} }
if (fsmRes.state == CfdpState::BUSY_CLASS_2_ACKED) { if (fsmRes.state == CfdpState::BUSY_CLASS_2_ACKED) {
@ -97,75 +87,37 @@ const cfdp::DestHandler::FsmResult& cfdp::DestHandler::stateMachine() {
return updateFsmRes(errorIdx); return updateFsmRes(errorIdx);
} }
ReturnValue_t cfdp::DestHandler::passPacket(PacketInfo packet) { ReturnValue_t cfdp::DestHandler::handleMetadataPdu(const PduPacketIF& pduPacket) {
if (destParams.packetListRef.full()) {
return FAILED;
}
destParams.packetListRef.push_back(packet);
return OK;
}
ReturnValue_t cfdp::DestHandler::initialize() {
if (fsfwParams.tmStore == nullptr) {
fsfwParams.tmStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TM_STORE);
if (fsfwParams.tmStore == nullptr) {
return FAILED;
}
}
if (fsfwParams.tcStore == nullptr) {
fsfwParams.tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
if (fsfwParams.tcStore == nullptr) {
return FAILED;
}
}
if (fsfwParams.msgQueue == nullptr) {
return FAILED;
}
return OK;
}
ReturnValue_t cfdp::DestHandler::handleMetadataPdu(const PacketInfo& info) {
// Process metadata PDU // Process metadata PDU
auto constAccessorPair = fsfwParams.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 sourceFileName;
cfdp::StringLv destFileName; cfdp::StringLv destFileName;
MetadataGenericInfo metadataInfo(transactionParams.fileSize); MetadataGenericInfo metadataInfo(transactionParams.fileSize);
MetadataPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), size_t pduSize = 0;
metadataInfo, tlvVec.data(), tlvVec.size()); auto rawPdu = pduPacket.getRawPduData(pduSize);
MetadataPduReader reader(rawPdu, pduSize, metadataInfo, tlvVec.data(), tlvVec.size());
ReturnValue_t result = reader.parseData(); ReturnValue_t result = reader.parseData();
// TODO: The standard does not really specify what happens if this kind of error happens // 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 // 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 // is translated into a warning and/or event by an upper layer
if (result != OK) { if (result != OK) {
return handleMetadataParseError(result, constAccessorPair.second.data(), return handleMetadataParseError(result, rawPdu, pduSize);
constAccessorPair.second.size());
} }
return startTransaction(reader); return startTransaction(reader);
} }
ReturnValue_t cfdp::DestHandler::handleFileDataPdu(const cfdp::PacketInfo& info) { ReturnValue_t cfdp::DestHandler::handleFileDataPdu(const PduPacketIF& info) {
size_t pduSize = 0;
const auto rawPdu = info.getRawPduData(pduSize);
// Process file data PDU // Process file data PDU
auto constAccessorPair = fsfwParams.tcStore->getData(info.storeId);
if (constAccessorPair.first != OK) {
// TODO: This is not a CFDP error. Event and/or warning?
return constAccessorPair.first;
}
FileDataInfo fdInfo; FileDataInfo fdInfo;
FileDataReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), fdInfo); FileDataReader reader(rawPdu, pduSize, fdInfo);
ReturnValue_t result = reader.parseData(); ReturnValue_t result = reader.parseData();
if (result != OK) { if (result != OK) {
return result; return result;
} }
size_t fileSegmentLen = 0; size_t fileSegmentLen = 0;
const uint8_t* fileData = fdInfo.getFileData(&fileSegmentLen); const uint8_t* fileData = fdInfo.getFileData(&fileSegmentLen);
FileOpParams fileOpParams(transactionParams.destName.data(), fileSegmentLen);
fileOpParams.offset = fdInfo.getOffset().value();
if (destParams.cfg.indicCfg.fileSegmentRecvIndicRequired) { if (destParams.cfg.indicCfg.fileSegmentRecvIndicRequired) {
FileSegmentRecvdParams segParams; FileSegmentRecvdParams segParams;
segParams.offset = fdInfo.getOffset().value(); segParams.offset = fdInfo.getOffset().value();
@ -177,7 +129,9 @@ ReturnValue_t cfdp::DestHandler::handleFileDataPdu(const cfdp::PacketInfo& info)
segParams.segmentMetadata = {segMetadata, segmentMetadatLen}; segParams.segmentMetadata = {segMetadata, segmentMetadatLen};
destParams.user.fileSegmentRecvdIndication(segParams); destParams.user.fileSegmentRecvdIndication(segParams);
} }
result = destParams.user.vfs.writeToFile(fileOpParams, fileData); // sif::printDebug("Writing %d bytes at offset %d\n", fileSegmentLen, fdInfo.getOffset().value());
result = destParams.user.vfs.writeToFile(transactionParams.destName.data(),
fdInfo.getOffset().value(), fileData, fileSegmentLen);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
// TODO: Proper Error handling // TODO: Proper Error handling
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
@ -191,25 +145,21 @@ ReturnValue_t cfdp::DestHandler::handleFileDataPdu(const cfdp::PacketInfo& info)
static_cast<uint8_t>(fsmRes.step), result); static_cast<uint8_t>(fsmRes.step), result);
} }
return result; return result;
} else { }
transactionParams.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE; transactionParams.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE;
transactionParams.vfsErrorCount = 0; transactionParams.vfsErrorCount = 0;
}
if (fdInfo.getOffset().value() + fileSegmentLen > transactionParams.progress) { if (fdInfo.getOffset().value() + fileSegmentLen > transactionParams.progress) {
transactionParams.progress = fdInfo.getOffset().value() + fileSegmentLen; transactionParams.progress = fdInfo.getOffset().value() + fileSegmentLen;
} }
return result; return result;
} }
ReturnValue_t cfdp::DestHandler::handleEofPdu(const cfdp::PacketInfo& info) { ReturnValue_t cfdp::DestHandler::handleEofPdu(const cfdp::PduPacketIF& info) {
size_t pduSize = 0;
const auto rawPdu = info.getRawPduData(pduSize);
// Process EOF PDU // Process EOF PDU
auto constAccessorPair = fsfwParams.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); EofInfo eofInfo(nullptr);
EofPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), eofInfo); EofPduReader reader(rawPdu, pduSize, eofInfo);
ReturnValue_t result = reader.parseData(); ReturnValue_t result = reader.parseData();
if (result != OK) { if (result != OK) {
return result; return result;
@ -244,6 +194,7 @@ ReturnValue_t cfdp::DestHandler::handleMetadataParseError(ReturnValue_t result,
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Parsing Metadata PDU failed with code " << result << std::endl; sif::warning << "Parsing Metadata PDU failed with code " << result << std::endl;
#else #else
sif::printWarning("cfdp::DestHandler: parsing metadata PDU failed with code %04x\n", result);
#endif #endif
PduHeaderReader headerReader(rawData, maxSize); PduHeaderReader headerReader(rawData, maxSize);
result = headerReader.parseData(); result = headerReader.parseData();
@ -307,24 +258,26 @@ ReturnValue_t cfdp::DestHandler::startTransaction(const MetadataPduReader& reade
// so there is no need to create a file or truncate an existing file // so there is no need to create a file or truncate an existing file
if (destNameSize > 0 and sourceNameSize > 0) { if (destNameSize > 0 and sourceNameSize > 0) {
transactionParams.metadataOnly = false; transactionParams.metadataOnly = false;
FilesystemParams fparams(transactionParams.destName.data());
// handling to allow only specifying target directory. Example: // handling to allow only specifying target directory. Example:
// Source path /test/hello.txt, dest path /tmp -> dest path /tmp/hello.txt // Source path /test/hello.txt, dest path /tmp -> dest path /tmp/hello.txt
if (destParams.user.vfs.isDirectory(transactionParams.destName.data())) { bool isDirectory = false;
result = destParams.user.vfs.isDirectory(transactionParams.destName.data(), isDirectory);
if (result == returnvalue::OK && isDirectory) {
result = tryBuildingAbsoluteDestName(destNameSize); result = tryBuildingAbsoluteDestName(destNameSize);
if (result != OK) { if (result != OK) {
return result; return result;
} }
} }
if (destParams.user.vfs.fileExists(fparams)) { if (destParams.user.vfs.fileExists(transactionParams.destName.data())) {
result = destParams.user.vfs.truncateFile(fparams); result = destParams.user.vfs.truncateFile(transactionParams.destName.data());
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
fileErrorHandler(events::FILESTORE_ERROR, result, "file truncation error"); fileErrorHandler(events::FILESTORE_ERROR, result, "file truncation error");
return FAILED; return FAILED;
// TODO: Relevant for filestore rejection error? // TODO: Relevant for filestore rejection error?
} }
} else { } else {
result = destParams.user.vfs.createFile(fparams); result = destParams.user.vfs.createFile(transactionParams.destName.data());
if (result != OK) { if (result != OK) {
fileErrorHandler(events::FILESTORE_ERROR, result, "file creation error"); fileErrorHandler(events::FILESTORE_ERROR, result, "file creation error");
return FAILED; return FAILED;
@ -359,6 +312,7 @@ ReturnValue_t cfdp::DestHandler::startTransaction(const MetadataPduReader& reade
transactionParams.checksumType = info.getChecksumType(); transactionParams.checksumType = info.getChecksumType();
transactionParams.closureRequested = info.isClosureRequested(); transactionParams.closureRequested = info.isClosureRequested();
reader.fillConfig(transactionParams.pduConf); reader.fillConfig(transactionParams.pduConf);
transactionParams.pduConf.crcFlag = transactionParams.remoteCfg->crcOnTransmission;
transactionParams.pduConf.direction = Direction::TOWARDS_SENDER; transactionParams.pduConf.direction = Direction::TOWARDS_SENDER;
transactionParams.transactionId.entityId = transactionParams.pduConf.sourceId; transactionParams.transactionId.entityId = transactionParams.pduConf.sourceId;
transactionParams.transactionId.seqNum = transactionParams.pduConf.seqNum; transactionParams.transactionId.seqNum = transactionParams.pduConf.seqNum;
@ -368,10 +322,10 @@ ReturnValue_t cfdp::DestHandler::startTransaction(const MetadataPduReader& reade
params.destFileName = transactionParams.destName.data(); params.destFileName = transactionParams.destName.data();
params.sourceFileName = transactionParams.sourceName.data(); params.sourceFileName = transactionParams.sourceName.data();
params.numberOfMsgsToUser = 0; params.numberOfMsgsToUser = 0;
for (const auto& opt : tlvVec) { for (uint32_t tlvIdx = 0; tlvIdx < reader.getNumberOfParsedOptions(); tlvIdx++) {
if (opt.getType() == TlvType::MSG_TO_USER) { if (tlvVec[tlvIdx].getType() == TlvType::MSG_TO_USER) {
msgToUserVec[params.numberOfMsgsToUser] = msgToUserVec[params.numberOfMsgsToUser] =
MessageToUserTlv(opt.getValue(), opt.getLengthField()); MessageToUserTlv(tlvVec[tlvIdx].getValue(), tlvVec[tlvIdx].getLengthField());
params.numberOfMsgsToUser++; params.numberOfMsgsToUser++;
} }
} }
@ -411,10 +365,9 @@ ReturnValue_t cfdp::DestHandler::tryBuildingAbsoluteDestName(size_t destNameSize
// A path may only have a maximum of 256 characters in CFDP, so this buffer should be sufficient // A path may only have a maximum of 256 characters in CFDP, so this buffer should be sufficient
// for all use-cases. // for all use-cases.
char baseNameBuf[512]{}; char baseNameBuf[512]{};
FilesystemParams fparamsSrc(transactionParams.sourceName.data());
size_t baseNameLen = 0; size_t baseNameLen = 0;
ReturnValue_t result = destParams.user.vfs.getBaseFilename(fparamsSrc, baseNameBuf, const ReturnValue_t result = destParams.user.vfs.getBaseFilename(
sizeof(baseNameBuf), baseNameLen); transactionParams.sourceName.data(), baseNameBuf, sizeof(baseNameBuf), baseNameLen);
if (result != returnvalue::OK or baseNameLen == 0) { if (result != returnvalue::OK or baseNameLen == 0) {
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "error retrieving source base name"); fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "error retrieving source base name");
return FAILED; return FAILED;
@ -442,7 +395,6 @@ void cfdp::DestHandler::fileErrorHandler(Event event, ReturnValue_t result,
void cfdp::DestHandler::finish() { void cfdp::DestHandler::finish() {
transactionParams.reset(); transactionParams.reset();
destParams.packetListRef.clear();
fsmRes.state = CfdpState::IDLE; fsmRes.state = CfdpState::IDLE;
fsmRes.step = TransactionStep::IDLE; fsmRes.step = TransactionStep::IDLE;
} }
@ -451,26 +403,26 @@ ReturnValue_t cfdp::DestHandler::checksumVerification() {
std::array<uint8_t, 1024> buf{}; std::array<uint8_t, 1024> buf{};
etl::crc32 crcCalc; etl::crc32 crcCalc;
uint64_t currentOffset = 0; uint64_t currentOffset = 0;
FileOpParams params(transactionParams.destName.data(), transactionParams.fileSize.value());
while (currentOffset < transactionParams.fileSize.value()) { while (currentOffset < transactionParams.fileSize.value()) {
uint64_t readLen; uint64_t lenToRead;
if (currentOffset + buf.size() > transactionParams.fileSize.value()) { if (currentOffset + buf.size() > transactionParams.fileSize.value()) {
readLen = transactionParams.fileSize.value() - currentOffset; lenToRead = transactionParams.fileSize.value() - currentOffset;
} else { } else {
readLen = buf.size(); lenToRead = buf.size();
} }
if (readLen > 0) { if (lenToRead > 0) {
params.offset = currentOffset; size_t readLen = 0;
params.size = readLen; const auto result =
auto result = destParams.user.vfs.readFromFile(params, buf.data(), buf.size()); destParams.user.vfs.readFromFile(transactionParams.destName.data(), currentOffset,
lenToRead, buf.data(), readLen, buf.size());
if (result != OK) { if (result != OK) {
// TODO: I think this is a case for a filestore rejection, but it might sense to print // 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 // a warning or trigger an event because this should generally not happen
return FAILED; return FAILED;
} }
crcCalc.add(buf.begin(), buf.begin() + readLen); crcCalc.add(buf.begin(), buf.begin() + lenToRead);
} }
currentOffset += readLen; currentOffset += lenToRead;
} }
uint32_t value = crcCalc.value(); uint32_t value = crcCalc.value();
@ -502,19 +454,11 @@ ReturnValue_t cfdp::DestHandler::sendFinishedPdu() {
FinishedInfo info(transactionParams.conditionCode, transactionParams.deliveryCode, FinishedInfo info(transactionParams.conditionCode, transactionParams.deliveryCode,
transactionParams.deliveryStatus); transactionParams.deliveryStatus);
FinishPduCreator finishedPdu(transactionParams.pduConf, info); FinishPduCreator finishedPdu(transactionParams.pduConf, info);
store_address_t storeId;
uint8_t* dataPtr = nullptr;
ReturnValue_t result =
fsfwParams.tmStore->getFreeElement(&storeId, finishedPdu.getSerializedSize(), &dataPtr);
if (result != OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "cfdp::DestHandler:sendFinishedPdu: Getting store slot failed" << std::endl;
#endif
fsfwParams.eventReporter->forwardEvent(events::STORE_ERROR, result, 0);
return result;
}
size_t serLen = 0; size_t serLen = 0;
result = finishedPdu.serialize(dataPtr, serLen, finishedPdu.getSerializedSize()); ReturnValue_t result =
finishedPdu.serialize(pduBuf.data(), serLen, finishedPdu.getSerializedSize());
checkAndHandleError(result, fsmRes.errors);
if (result != OK) { if (result != OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "cfdp::DestHandler::sendFinishedPdu: Serializing Finished PDU failed" sif::warning << "cfdp::DestHandler::sendFinishedPdu: Serializing Finished PDU failed"
@ -523,13 +467,12 @@ ReturnValue_t cfdp::DestHandler::sendFinishedPdu() {
fsfwParams.eventReporter->forwardEvent(events::SERIALIZATION_ERROR, result, 0); fsfwParams.eventReporter->forwardEvent(events::SERIALIZATION_ERROR, result, 0);
return result; return result;
} }
TmTcMessage msg(storeId); pduSender.sendPdu(PduType::FILE_DIRECTIVE, FileDirective::FINISH, pduBuf.data(), serLen);
result = fsfwParams.msgQueue->sendMessage(fsfwParams.packetDest.getReportReceptionQueue(), &msg);
if (result != OK) { if (result != OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "cfdp::DestHandler::sendFinishedPdu: Sending PDU failed" << std::endl; sif::warning << "cfdp::DestHandler::sendFinishedPdu: Sending PDU failed" << std::endl;
#endif #endif
fsfwParams.eventReporter->forwardEvent(events::MSG_QUEUE_ERROR, result, 0); fsfwParams.eventReporter->forwardEvent(events::PDU_SEND_ERROR, result, 0);
return result; return result;
} }
fsmRes.packetsSent++; fsmRes.packetsSent++;
@ -560,8 +503,6 @@ void cfdp::DestHandler::checkAndHandleError(ReturnValue_t result, uint8_t& error
} }
} }
void cfdp::DestHandler::setMsgQueue(MessageQueueIF& queue) { fsfwParams.msgQueue = &queue; }
void cfdp::DestHandler::setEventReporter(EventReportingProxyIF& reporter) { void cfdp::DestHandler::setEventReporter(EventReportingProxyIF& reporter) {
fsfwParams.eventReporter = &reporter; fsfwParams.eventReporter = &reporter;
} }
@ -569,6 +510,3 @@ void cfdp::DestHandler::setEventReporter(EventReportingProxyIF& reporter) {
const cfdp::DestHandlerParams& cfdp::DestHandler::getDestHandlerParams() const { const cfdp::DestHandlerParams& cfdp::DestHandler::getDestHandlerParams() const {
return destParams; return destParams;
} }
StorageManagerIF* cfdp::DestHandler::getTmStore() const { return fsfwParams.tmStore; }
StorageManagerIF* cfdp::DestHandler::getTcStore() const { return fsfwParams.tcStore; }

View File

@ -11,13 +11,13 @@
#include "RemoteConfigTableIF.h" #include "RemoteConfigTableIF.h"
#include "UserBase.h" #include "UserBase.h"
#include "defs.h" #include "defs.h"
#include "fsfw/cfdp/handler/PduPacketIF.h"
#include "fsfw/cfdp/handler/PduSenderIF.h"
#include "fsfw/cfdp/handler/mib.h" #include "fsfw/cfdp/handler/mib.h"
#include "fsfw/cfdp/pdu/MetadataPduReader.h" #include "fsfw/cfdp/pdu/MetadataPduReader.h"
#include "fsfw/cfdp/pdu/PduConfig.h" #include "fsfw/cfdp/pdu/PduConfig.h"
#include "fsfw/cfdp/tlv/MessageToUserTlv.h" #include "fsfw/cfdp/tlv/MessageToUserTlv.h"
#include "fsfw/container/DynamicFIFO.h"
#include "fsfw/storagemanager/StorageManagerIF.h" #include "fsfw/storagemanager/StorageManagerIF.h"
#include "fsfw/storagemanager/storeAddress.h"
#include "fsfw/tmtcservices/AcceptsTelemetryIF.h" #include "fsfw/tmtcservices/AcceptsTelemetryIF.h"
namespace cfdp { namespace cfdp {
@ -28,7 +28,6 @@ using LostSegmentsListBase = etl::iset<etl::pair<uint64_t, uint64_t>>;
struct DestHandlerParams { struct DestHandlerParams {
DestHandlerParams(LocalEntityCfg cfg, UserBase& user, RemoteConfigTableIF& remoteCfgTable, DestHandlerParams(LocalEntityCfg cfg, UserBase& user, RemoteConfigTableIF& remoteCfgTable,
PacketInfoListBase& packetList,
// TODO: This container can potentially take tons of space. For a better // TODO: This container can potentially take tons of space. For a better
// memory efficient implementation, an additional abstraction could be // memory efficient implementation, an additional abstraction could be
// be used so users can use uint32_t as the pair type // be used so users can use uint32_t as the pair type
@ -39,14 +38,12 @@ struct DestHandlerParams {
: cfg(std::move(cfg)), : cfg(std::move(cfg)),
user(user), user(user),
remoteCfgTable(remoteCfgTable), remoteCfgTable(remoteCfgTable),
packetListRef(packetList),
lostSegmentsContainer(lostSegmentsContainer) {} lostSegmentsContainer(lostSegmentsContainer) {}
LocalEntityCfg cfg; LocalEntityCfg cfg;
UserBase& user; UserBase& user;
RemoteConfigTableIF& remoteCfgTable; RemoteConfigTableIF& remoteCfgTable;
PacketInfoListBase& packetListRef;
LostSegmentsListBase& lostSegmentsContainer; LostSegmentsListBase& lostSegmentsContainer;
uint8_t maxTlvsInOnePdu = 20; uint8_t maxTlvsInOnePdu = 20;
size_t maxFilenameLen = 255; size_t maxFilenameLen = 255;
@ -64,17 +61,14 @@ class DestHandler {
}; };
struct FsmResult { struct FsmResult {
public: uint32_t packetsSent = 0;
ReturnValue_t result = returnvalue::OK; ReturnValue_t result = returnvalue::OK;
CallStatus callStatus = CallStatus::CALL_AFTER_DELAY;
TransactionStep step = TransactionStep::IDLE; TransactionStep step = TransactionStep::IDLE;
CfdpState state = CfdpState::IDLE; CfdpState state = CfdpState::IDLE;
uint32_t packetsSent = 0;
uint8_t errors = 0; uint8_t errors = 0;
std::array<ReturnValue_t, 3> errorCodes = {}; std::array<ReturnValue_t, 3> errorCodes = {};
void resetOfIteration() { void resetOfIteration() {
result = returnvalue::OK; result = returnvalue::OK;
callStatus = CallStatus::CALL_AFTER_DELAY;
packetsSent = 0; packetsSent = 0;
errors = 0; errors = 0;
errorCodes.fill(returnvalue::OK); errorCodes.fill(returnvalue::OK);
@ -85,28 +79,30 @@ class DestHandler {
*/ */
ReturnValue_t PARTIAL_SUCCESS = returnvalue::makeCode(0, 2); ReturnValue_t PARTIAL_SUCCESS = returnvalue::makeCode(0, 2);
ReturnValue_t FAILURE = returnvalue::makeCode(0, 3); ReturnValue_t FAILURE = returnvalue::makeCode(0, 3);
explicit DestHandler(DestHandlerParams handlerParams, FsfwParams fsfwParams);
explicit DestHandler(PduSenderIF& pduSender, size_t pduBufSize, DestHandlerParams handlerParams,
FsfwParams fsfwParams);
/** /**
* This is the core function to drive the destination handler. It is also used to insert
* packets into the destination handler.
* *
* @return * The state machine should either be called if packets with the appropriate destination ID
* - @c returnvalue::OK State machine OK for this execution cycle * are received and periodically to perform all CFDP related tasks, for example
* - @c CALL_FSM_AGAIN State machine should be called again. * checking for timeouts or missed file segments.
*
* The function returns the number of sent PDU packets on success.
*/ */
const FsmResult& stateMachine(); const FsmResult& stateMachine(std::optional<std::reference_wrapper<PduPacketIF>> optPduPacket);
void setMsgQueue(MessageQueueIF& queue);
const FsmResult& stateMachineNoPacket();
void setEventReporter(EventReportingProxyIF& reporter); void setEventReporter(EventReportingProxyIF& reporter);
ReturnValue_t passPacket(PacketInfo packet);
ReturnValue_t initialize();
[[nodiscard]] CfdpState getCfdpState() const; [[nodiscard]] CfdpState getCfdpState() const;
[[nodiscard]] TransactionStep getTransactionStep() const; [[nodiscard]] TransactionStep getTransactionStep() const;
[[nodiscard]] const TransactionId& getTransactionId() const; [[nodiscard]] const TransactionId& getTransactionId() const;
[[nodiscard]] const DestHandlerParams& getDestHandlerParams() const; [[nodiscard]] const DestHandlerParams& getDestHandlerParams() const;
[[nodiscard]] StorageManagerIF* getTcStore() const;
[[nodiscard]] StorageManagerIF* getTmStore() const;
private: private:
struct TransactionParams { struct TransactionParams {
@ -149,6 +145,8 @@ class DestHandler {
RemoteEntityCfg* remoteCfg = nullptr; RemoteEntityCfg* remoteCfg = nullptr;
}; };
std::vector<uint8_t> pduBuf;
PduSenderIF& pduSender;
std::vector<cfdp::Tlv> tlvVec; std::vector<cfdp::Tlv> tlvVec;
std::vector<MessageToUserTlv> msgToUserVec; std::vector<MessageToUserTlv> msgToUserVec;
TransactionParams transactionParams; TransactionParams transactionParams;
@ -157,9 +155,9 @@ class DestHandler {
FsmResult fsmRes; FsmResult fsmRes;
ReturnValue_t startTransaction(const MetadataPduReader& reader); ReturnValue_t startTransaction(const MetadataPduReader& reader);
ReturnValue_t handleMetadataPdu(const PacketInfo& info); ReturnValue_t handleMetadataPdu(const PduPacketIF& pduPacket);
ReturnValue_t handleFileDataPdu(const PacketInfo& info); ReturnValue_t handleFileDataPdu(const PduPacketIF& info);
ReturnValue_t handleEofPdu(const PacketInfo& info); ReturnValue_t handleEofPdu(const PduPacketIF& info);
ReturnValue_t handleMetadataParseError(ReturnValue_t result, const uint8_t* rawData, ReturnValue_t handleMetadataParseError(ReturnValue_t result, const uint8_t* rawData,
size_t maxSize); size_t maxSize);
ReturnValue_t handleTransferCompletion(); ReturnValue_t handleTransferCompletion();

View File

@ -0,0 +1,18 @@
#pragma once
#include <optional>
#include "fsfw/cfdp/definitions.h"
namespace cfdp {
class PduPacketIF {
public:
virtual ~PduPacketIF() = default;
[[nodiscard]] virtual cfdp::PduType getPduType() const = 0;
[[nodiscard]] virtual std::optional<cfdp::FileDirective> getFileDirective() const = 0;
[[nodiscard]] virtual const uint8_t* getRawPduData(size_t& pduLen) const = 0;
};
} // namespace cfdp

View File

@ -0,0 +1,17 @@
#pragma once
#include <optional>
#include "fsfw/cfdp/definitions.h"
namespace cfdp {
class PduSenderIF {
public:
virtual ~PduSenderIF() = default;
virtual ReturnValue_t sendPdu(cfdp::PduType pduType,
std::optional<cfdp::FileDirective> fileDirective,
const uint8_t* pdu, size_t pduSize) = 0;
};
} // namespace cfdp

View File

@ -14,7 +14,7 @@ cfdp::ReservedMessageParser::ReservedMessageParser(StorageManagerIF& ipcStore,
: msgQueue(msgQueue), ipcStore(ipcStore), userDestination(userDestination) {} : msgQueue(msgQueue), ipcStore(ipcStore), userDestination(userDestination) {}
ReturnValue_t cfdp::ReservedMessageParser::parse(const MessageToUserTlv* msgsToUserArray, ReturnValue_t cfdp::ReservedMessageParser::parse(const MessageToUserTlv* msgsToUserArray,
size_t numMsgToUser) { size_t numMsgToUser) const {
ReturnValue_t result = returnvalue::OK; ReturnValue_t result = returnvalue::OK;
cfdp::StringLv sourceFileName; cfdp::StringLv sourceFileName;
cfdp::StringLv destFileName; cfdp::StringLv destFileName;
@ -23,11 +23,10 @@ ReturnValue_t cfdp::ReservedMessageParser::parse(const MessageToUserTlv* msgsToU
size_t deserSize = 0; size_t deserSize = 0;
bool needToSendPutRequest = false; bool needToSendPutRequest = false;
for (size_t idx = 0; idx < numMsgToUser; idx++) { for (size_t idx = 0; idx < numMsgToUser; idx++) {
if (&msgsToUserArray[idx] == nullptr) { uint8_t messageType = 0;
if (not msgsToUserArray[idx].isReservedCfdpMessage(messageType, &currentPtr, deserSize)) {
continue; continue;
} }
uint8_t messageType = 0;
if (msgsToUserArray[idx].isReservedCfdpMessage(messageType, &currentPtr, deserSize)) {
if (messageType == static_cast<uint8_t>(ProxyOpMessageType::PUT_REQUEST)) { if (messageType == static_cast<uint8_t>(ProxyOpMessageType::PUT_REQUEST)) {
EntityId entityIdLv; EntityId entityIdLv;
result = entityIdLv.deSerializeFromLv(&currentPtr, &deserSize); result = entityIdLv.deSerializeFromLv(&currentPtr, &deserSize);
@ -40,8 +39,7 @@ ReturnValue_t cfdp::ReservedMessageParser::parse(const MessageToUserTlv* msgsToU
if (result != OK) { if (result != OK) {
return result; return result;
} }
result = result = destFileName.deSerialize(&currentPtr, &deserSize, SerializeIF::Endianness::NETWORK);
destFileName.deSerialize(&currentPtr, &deserSize, SerializeIF::Endianness::NETWORK);
if (result != OK) { if (result != OK) {
return result; return result;
} }
@ -49,7 +47,6 @@ ReturnValue_t cfdp::ReservedMessageParser::parse(const MessageToUserTlv* msgsToU
needToSendPutRequest = true; needToSendPutRequest = true;
} }
} }
}
if (needToSendPutRequest) { if (needToSendPutRequest) {
store_address_t storeId; store_address_t storeId;
uint8_t* dataPtr; uint8_t* dataPtr;

View File

@ -16,7 +16,7 @@ class ReservedMessageParser {
ReservedMessageParser(StorageManagerIF& ipcStore, MessageQueueIF& msgQueue, ReservedMessageParser(StorageManagerIF& ipcStore, MessageQueueIF& msgQueue,
MessageQueueId_t userDestination); MessageQueueId_t userDestination);
ReturnValue_t parse(const MessageToUserTlv* msgsToUserArray, size_t numMsgsToUser); ReturnValue_t parse(const MessageToUserTlv* msgsToUserArray, size_t numMsgsToUser) const;
private: private:
MessageQueueIF& msgQueue; MessageQueueIF& msgQueue;

View File

@ -16,8 +16,12 @@
using namespace returnvalue; using namespace returnvalue;
cfdp::SourceHandler::SourceHandler(SourceHandlerParams params, FsfwParams fsfwParams) cfdp::SourceHandler::SourceHandler(PduSenderIF& pduSender, size_t pduBufferSize,
: sourceParams(std::move(params)), fsfwParams(fsfwParams) { SourceHandlerParams params, FsfwParams fsfwParams)
: pduSender(pduSender),
pduBuf(pduBufferSize),
sourceParams(std::move(params)),
fsfwParams(fsfwParams) {
// The entity ID portion of the transaction ID will always remain fixed. // The entity ID portion of the transaction ID will always remain fixed.
transactionParams.id.entityId = sourceParams.cfg.localId; transactionParams.id.entityId = sourceParams.cfg.localId;
transactionParams.pduConf.sourceId = sourceParams.cfg.localId; transactionParams.pduConf.sourceId = sourceParams.cfg.localId;
@ -61,14 +65,14 @@ cfdp::SourceHandler::FsmResult& cfdp::SourceHandler::fsmNacked() {
if (result != OK) { if (result != OK) {
addError(result); addError(result);
} }
fsmResult.callStatus = CallStatus::CALL_AGAIN; // fsmResult.callStatus = CallStatus::CALL_AGAIN;
return fsmResult; return fsmResult;
} }
if (step == TransactionStep::SENDING_FILE_DATA) { if (step == TransactionStep::SENDING_FILE_DATA) {
bool noFdPdu = false; bool noFdPdu = false;
result = prepareAndSendNextFileDataPdu(noFdPdu); result = prepareAndSendNextFileDataPdu(noFdPdu);
if (result == OK and !noFdPdu) { if (result == OK and !noFdPdu) {
fsmResult.callStatus = CallStatus::CALL_AGAIN; // fsmResult.callStatus = CallStatus::CALL_AGAIN;
return fsmResult; return fsmResult;
} }
} }
@ -82,10 +86,10 @@ cfdp::SourceHandler::FsmResult& cfdp::SourceHandler::fsmNacked() {
} }
if (transactionParams.closureRequested) { if (transactionParams.closureRequested) {
step = TransactionStep::WAIT_FOR_FINISH; step = TransactionStep::WAIT_FOR_FINISH;
fsmResult.callStatus = CallStatus::CALL_AFTER_DELAY; // fsmResult.callStatus = CallStatus::CALL_AFTER_DELAY;
} else { } else {
step = TransactionStep::NOTICE_OF_COMPLETION; step = TransactionStep::NOTICE_OF_COMPLETION;
fsmResult.callStatus = CallStatus::CALL_AGAIN; // fsmResult.callStatus = CallStatus::CALL_AGAIN;
} }
return fsmResult; return fsmResult;
} }
@ -101,10 +105,14 @@ cfdp::SourceHandler::FsmResult& cfdp::SourceHandler::fsmNacked() {
return fsmResult; return fsmResult;
} }
const cfdp::SourceHandler::FsmResult& cfdp::SourceHandler::stateMachine() { const cfdp::SourceHandler::FsmResult& cfdp::SourceHandler::stateMachineNoPacket() {
return stateMachine(std::nullopt);
}
const cfdp::SourceHandler::FsmResult& cfdp::SourceHandler::stateMachine(
std::optional<std::reference_wrapper<PduPacketIF>> optPduPacket) {
fsmResult.packetsSent = 0; fsmResult.packetsSent = 0;
fsmResult.errors = 0; fsmResult.errors = 0;
fsmResult.callStatus = CallStatus::DONE;
if (state == cfdp::CfdpState::IDLE) { if (state == cfdp::CfdpState::IDLE) {
return fsmResult; return fsmResult;
} }
@ -123,25 +131,25 @@ ReturnValue_t cfdp::SourceHandler::checksumGeneration() {
std::array<uint8_t, 1024> buf{}; std::array<uint8_t, 1024> buf{};
etl::crc32 crcCalc; etl::crc32 crcCalc;
uint64_t currentOffset = 0; uint64_t currentOffset = 0;
FileOpParams params(transactionParams.sourceName.data(), transactionParams.fileSize.value());
while (currentOffset < transactionParams.fileSize.value()) { while (currentOffset < transactionParams.fileSize.value()) {
uint64_t readLen; uint64_t lenToRead;
if (currentOffset + buf.size() > transactionParams.fileSize.value()) { if (currentOffset + buf.size() > transactionParams.fileSize.value()) {
readLen = transactionParams.fileSize.value() - currentOffset; lenToRead = transactionParams.fileSize.value() - currentOffset;
} else { } else {
readLen = buf.size(); lenToRead = buf.size();
} }
if (readLen > 0) { if (lenToRead > 0) {
params.offset = currentOffset; size_t readLen = 0;
params.size = readLen; auto result =
auto result = sourceParams.user.vfs.readFromFile(params, buf.data(), buf.size()); sourceParams.user.vfs.readFromFile(transactionParams.sourceName.data(), currentOffset,
lenToRead, buf.data(), readLen, buf.size());
if (result != OK) { if (result != OK) {
addError(result); addError(result);
return FAILED; return FAILED;
} }
crcCalc.add(buf.begin(), buf.begin() + readLen); crcCalc.add(buf.begin(), buf.begin() + lenToRead);
} }
currentOffset += readLen; currentOffset += lenToRead;
} }
transactionParams.crc = crcCalc.value(); transactionParams.crc = crcCalc.value();
@ -169,8 +177,7 @@ ReturnValue_t cfdp::SourceHandler::transactionStart(PutRequest& putRequest, Remo
// operation is safe. // operation is safe.
transactionParams.sourceName[transactionParams.sourceNameSize] = '\0'; transactionParams.sourceName[transactionParams.sourceNameSize] = '\0';
transactionParams.destName[transactionParams.destNameSize] = '\0'; transactionParams.destName[transactionParams.destNameSize] = '\0';
FilesystemParams params(transactionParams.sourceName.data()); if (!sourceParams.user.vfs.fileExists(transactionParams.sourceName.data())) {
if (!sourceParams.user.vfs.fileExists(params)) {
return FILE_DOES_NOT_EXIST; return FILE_DOES_NOT_EXIST;
} }
if (cfg.maxFileSegmentLen > fileBuf.size() or cfg.maxFileSegmentLen == 0) { if (cfg.maxFileSegmentLen > fileBuf.size() or cfg.maxFileSegmentLen == 0) {
@ -206,7 +213,7 @@ ReturnValue_t cfdp::SourceHandler::transactionStart(PutRequest& putRequest, Remo
} }
step = TransactionStep::IDLE; step = TransactionStep::IDLE;
uint64_t fileSize = 0; uint64_t fileSize = 0;
sourceParams.user.vfs.getFileSize(params, fileSize); sourceParams.user.vfs.getFileSize(transactionParams.sourceName.data(), fileSize);
transactionParams.pduConf.largeFile = false; transactionParams.pduConf.largeFile = false;
if (fileSize > UINT32_MAX) { if (fileSize > UINT32_MAX) {
transactionParams.pduConf.largeFile = true; transactionParams.pduConf.largeFile = true;
@ -230,7 +237,8 @@ ReturnValue_t cfdp::SourceHandler::prepareAndSendMetadataPdu() {
transactionParams.fileSize); transactionParams.fileSize);
auto metadataPdu = auto metadataPdu =
MetadataPduCreator(transactionParams.pduConf, metadataInfo, sourceName, destName, nullptr, 0); MetadataPduCreator(transactionParams.pduConf, metadataInfo, sourceName, destName, nullptr, 0);
ReturnValue_t result = sendGenericPdu(metadataPdu); ReturnValue_t result =
sendGenericPdu(PduType::FILE_DIRECTIVE, FileDirective::METADATA, metadataPdu);
if (result != OK) { if (result != OK) {
return result; return result;
} }
@ -241,7 +249,7 @@ ReturnValue_t cfdp::SourceHandler::prepareAndSendMetadataPdu() {
ReturnValue_t cfdp::SourceHandler::prepareAndSendNextFileDataPdu(bool& noFileDataPdu) { ReturnValue_t cfdp::SourceHandler::prepareAndSendNextFileDataPdu(bool& noFileDataPdu) {
cfdp::Fss offset(transactionParams.progress); cfdp::Fss offset(transactionParams.progress);
uint64_t readLen; uint64_t lenToRead;
uint64_t fileSize = transactionParams.fileSize.value(); uint64_t fileSize = transactionParams.fileSize.value();
noFileDataPdu = false; noFileDataPdu = false;
if (fileSize == 0) { if (fileSize == 0) {
@ -251,29 +259,31 @@ ReturnValue_t cfdp::SourceHandler::prepareAndSendNextFileDataPdu(bool& noFileDat
return OK; return OK;
} }
if (fileSize < transactionParams.remoteCfg.maxFileSegmentLen) { if (fileSize < transactionParams.remoteCfg.maxFileSegmentLen) {
readLen = transactionParams.fileSize.value(); lenToRead = transactionParams.fileSize.value();
} else { } else {
if (transactionParams.progress + transactionParams.remoteCfg.maxFileSegmentLen > fileSize) { if (transactionParams.progress + transactionParams.remoteCfg.maxFileSegmentLen > fileSize) {
readLen = fileSize - transactionParams.progress; lenToRead = fileSize - transactionParams.progress;
} else { } else {
readLen = transactionParams.remoteCfg.maxFileSegmentLen; lenToRead = transactionParams.remoteCfg.maxFileSegmentLen;
} }
} }
FileOpParams fileParams(transactionParams.sourceName.data(), readLen); FileOpParams fileParams(transactionParams.sourceName.data(), lenToRead);
fileParams.offset = transactionParams.progress; fileParams.offset = transactionParams.progress;
ReturnValue_t result = size_t readLen = 0;
sourceParams.user.vfs.readFromFile(fileParams, fileBuf.data(), fileBuf.size()); ReturnValue_t result = sourceParams.user.vfs.readFromFile(
transactionParams.sourceName.data(), transactionParams.progress, lenToRead, fileBuf.data(),
readLen, fileBuf.size());
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
addError(result); addError(result);
return result; return result;
} }
auto fileDataInfo = FileDataInfo(offset, fileBuf.data(), readLen); auto fileDataInfo = FileDataInfo(offset, fileBuf.data(), lenToRead);
auto fileDataPdu = FileDataCreator(transactionParams.pduConf, fileDataInfo); auto fileDataPdu = FileDataCreator(transactionParams.pduConf, fileDataInfo);
result = sendGenericPdu(fileDataPdu); result = sendGenericPdu(PduType::FILE_DATA, std::nullopt, fileDataPdu);
if (result != OK) { if (result != OK) {
return result; return result;
} }
transactionParams.progress += readLen; transactionParams.progress += lenToRead;
if (transactionParams.progress >= fileSize) { if (transactionParams.progress >= fileSize) {
// Advance FSM after all file data PDUs were sent. // Advance FSM after all file data PDUs were sent.
step = TransactionStep::SENDING_EOF; step = TransactionStep::SENDING_EOF;
@ -285,72 +295,44 @@ ReturnValue_t cfdp::SourceHandler::prepareAndSendEofPdu() {
auto eofInfo = auto eofInfo =
EofInfo(ConditionCode::NO_ERROR, transactionParams.crc, transactionParams.fileSize); EofInfo(ConditionCode::NO_ERROR, transactionParams.crc, transactionParams.fileSize);
auto eofPdu = EofPduCreator(transactionParams.pduConf, eofInfo); auto eofPdu = EofPduCreator(transactionParams.pduConf, eofInfo);
ReturnValue_t result = sendGenericPdu(eofPdu);
if (result != OK) {
return result;
}
return OK;
}
ReturnValue_t cfdp::SourceHandler::initialize() {
if (fsfwParams.tmStore == nullptr) {
fsfwParams.tmStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TM_STORE);
if (fsfwParams.tmStore == nullptr) {
return FAILED;
}
}
if (fsfwParams.tcStore == nullptr) {
fsfwParams.tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
if (fsfwParams.tcStore == nullptr) {
return FAILED;
}
}
if (fsfwParams.msgQueue == nullptr) {
return FAILED;
}
return OK;
}
ReturnValue_t cfdp::SourceHandler::sendGenericPdu(const SerializeIF& pdu) {
uint8_t* dataPtr;
store_address_t storeId;
ReturnValue_t result = ReturnValue_t result =
fsfwParams.tmStore->getFreeElement(&storeId, pdu.getSerializedSize(), &dataPtr); sendGenericPdu(PduType::FILE_DIRECTIVE, FileDirective::EOF_DIRECTIVE, eofPdu);
if (result != OK) { if (result != OK) {
addError(result);
fsmResult.callStatus = CallStatus::CALL_AFTER_DELAY;
if (result == StorageManagerIF::DATA_STORAGE_FULL) {
return TM_STORE_FULL;
}
return result; return result;
} }
return OK;
}
ReturnValue_t cfdp::SourceHandler::initialize() { return OK; }
ReturnValue_t cfdp::SourceHandler::sendGenericPdu(PduType pduType,
std::optional<FileDirective> fileDirective,
const SerializeIF& pdu) {
store_address_t storeId;
if (pdu.getSerializedSize() > pduBuf.size()) {
addError(PDU_BUFFER_TOO_SMALL);
return PDU_BUFFER_TOO_SMALL;
}
size_t serializedLen = 0; size_t serializedLen = 0;
result = pdu.serializeBe(dataPtr, serializedLen, pdu.getSerializedSize()); ReturnValue_t result = pdu.serializeBe(pduBuf.data(), serializedLen, pdu.getSerializedSize());
if (result != OK) { if (result != OK) {
addError(result); addError(result);
return result; return result;
} }
TmTcMessage tmMsg(storeId); pduSender.sendPdu(pduType, fileDirective, pduBuf.data(), serializedLen);
result =
fsfwParams.msgQueue->sendMessage(fsfwParams.packetDest.getReportReceptionQueue(), &tmMsg);
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; fsmResult.packetsSent += 1;
}
return result; return result;
} }
ReturnValue_t cfdp::SourceHandler::noticeOfCompletion() { ReturnValue_t cfdp::SourceHandler::noticeOfCompletion() {
if (sourceParams.cfg.indicCfg.transactionFinishedIndicRequired) { if (sourceParams.cfg.indicCfg.transactionFinishedIndicRequired) {
// TODO: This could still be improved by caching the Finished PDU parameters.
FileDeliveryStatus deliveryStatus = FileDeliveryStatus::FILE_STATUS_UNREPORTED;
if (transactionParams.closureRequested) {
deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE;
}
cfdp::TransactionFinishedParams params(transactionParams.id, ConditionCode::NO_ERROR, cfdp::TransactionFinishedParams params(transactionParams.id, ConditionCode::NO_ERROR,
FileDeliveryCode::DATA_COMPLETE, FileDeliveryCode::DATA_COMPLETE, deliveryStatus);
FileDeliveryStatus::RETAINED_IN_FILESTORE);
sourceParams.user.transactionFinishedIndication(params); sourceParams.user.transactionFinishedIndication(params);
} }
return OK; return OK;
@ -359,7 +341,7 @@ ReturnValue_t cfdp::SourceHandler::noticeOfCompletion() {
ReturnValue_t cfdp::SourceHandler::reset() { ReturnValue_t cfdp::SourceHandler::reset() {
step = TransactionStep::IDLE; step = TransactionStep::IDLE;
state = cfdp::CfdpState::IDLE; state = cfdp::CfdpState::IDLE;
fsmResult.callStatus = CallStatus::DONE; // fsmResult.callStatus = CallStatus::DONE;
transactionParams.reset(); transactionParams.reset();
return OK; return OK;
} }

View File

@ -4,6 +4,8 @@
#include <cstdint> #include <cstdint>
#include <vector> #include <vector>
#include "PduPacketIF.h"
#include "PduSenderIF.h"
#include "UserBase.h" #include "UserBase.h"
#include "defs.h" #include "defs.h"
#include "fsfw/cfdp/Fss.h" #include "fsfw/cfdp/Fss.h"
@ -40,14 +42,15 @@ class SourceHandler {
struct FsmResult { struct FsmResult {
public: public:
ReturnValue_t result = returnvalue::OK; ReturnValue_t result = returnvalue::OK;
CallStatus callStatus = CallStatus::CALL_AFTER_DELAY;
CfdpState state = CfdpState::IDLE;
uint32_t packetsSent = 0; uint32_t packetsSent = 0;
// CallStatus callStatus = CallStatus::CALL_AFTER_DELAY;
CfdpState state = CfdpState::IDLE;
uint8_t errors = 0; uint8_t errors = 0;
std::array<ReturnValue_t, 3> errorCodes = {}; std::array<ReturnValue_t, 3> errorCodes = {};
}; };
SourceHandler(SourceHandlerParams params, FsfwParams fsfwParams); SourceHandler(PduSenderIF& pduSender, size_t pduBufferSize, SourceHandlerParams params,
FsfwParams fsfwParams);
[[nodiscard]] CfdpState getState() const; [[nodiscard]] CfdpState getState() const;
[[nodiscard]] TransactionStep getStep() const; [[nodiscard]] TransactionStep getStep() const;
@ -58,7 +61,8 @@ class SourceHandler {
* @return * @return
*/ */
ReturnValue_t transactionStart(PutRequest& putRequest, RemoteEntityCfg& cfg); ReturnValue_t transactionStart(PutRequest& putRequest, RemoteEntityCfg& cfg);
const FsmResult& stateMachine(); const FsmResult& stateMachine(std::optional<std::reference_wrapper<PduPacketIF>> optPduPacket);
const FsmResult& stateMachineNoPacket();
ReturnValue_t initialize(); ReturnValue_t initialize();
@ -86,6 +90,8 @@ class SourceHandler {
} }
} transactionParams; } transactionParams;
PduSenderIF& pduSender;
std::vector<uint8_t> pduBuf;
cfdp::CfdpState state = cfdp::CfdpState::IDLE; cfdp::CfdpState state = cfdp::CfdpState::IDLE;
TransactionStep step = TransactionStep::IDLE; TransactionStep step = TransactionStep::IDLE;
std::array<uint8_t, 4096> fileBuf{}; std::array<uint8_t, 4096> fileBuf{};
@ -101,7 +107,9 @@ class SourceHandler {
ReturnValue_t noticeOfCompletion(); ReturnValue_t noticeOfCompletion();
ReturnValue_t reset(); ReturnValue_t reset();
[[nodiscard]] ReturnValue_t sendGenericPdu(const SerializeIF& pdu); [[nodiscard]] ReturnValue_t sendGenericPdu(PduType pduType,
std::optional<FileDirective> fileDirective,
const SerializeIF& pdu);
void addError(ReturnValue_t error); void addError(ReturnValue_t error);
}; };

View File

@ -1,5 +1,4 @@
#ifndef FSFW_CFDP_HANDLER_DEFS_H #pragma once
#define FSFW_CFDP_HANDLER_DEFS_H
#include <etl/list.h> #include <etl/list.h>
@ -8,59 +7,25 @@
#include "fsfw/tmtcservices/AcceptsTelemetryIF.h" #include "fsfw/tmtcservices/AcceptsTelemetryIF.h"
namespace cfdp { namespace cfdp {
enum class CfdpState { IDLE, BUSY_CLASS_1_NACKED, BUSY_CLASS_2_ACKED, SUSPENDED }; 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 SSID = SUBSYSTEM_ID::CFDP;
static constexpr uint8_t CID = CLASS_ID::CFDP_HANDLER; static constexpr uint8_t CID = CLASS_ID::CFDP_HANDLER;
struct PacketInfo {
PacketInfo(PduType type, store_address_t storeId,
std::optional<FileDirective> directive = std::nullopt)
: pduType(type), directiveType(directive), storeId(storeId) {}
PduType pduType = PduType::FILE_DATA;
std::optional<FileDirective> directiveType = FileDirective::INVALID_DIRECTIVE;
store_address_t storeId = store_address_t::invalid();
PacketInfo() = default;
};
struct FsfwParams { struct FsfwParams {
FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue, FsfwParams(EventReportingProxyIF* eventReporter) : eventReporter(eventReporter) {}
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; EventReportingProxyIF* eventReporter = nullptr;
StorageManagerIF* tcStore = nullptr;
StorageManagerIF* tmStore = nullptr;
}; };
template <size_t SIZE>
using PacketInfoList = etl::list<PacketInfo, SIZE>;
using PacketInfoListBase = etl::ilist<PacketInfo>;
enum class CallStatus { DONE, CALL_AFTER_DELAY, CALL_AGAIN };
namespace events { namespace events {
static constexpr Event PDU_SEND_ERROR = event::makeEvent(SSID, 1, severity::LOW);
static constexpr Event STORE_ERROR = event::makeEvent(SSID, 0, severity::LOW);
static constexpr Event MSG_QUEUE_ERROR = event::makeEvent(SSID, 1, severity::LOW);
static constexpr Event SERIALIZATION_ERROR = event::makeEvent(SSID, 2, severity::LOW); static constexpr Event SERIALIZATION_ERROR = event::makeEvent(SSID, 2, severity::LOW);
static constexpr Event FILESTORE_ERROR = event::makeEvent(SSID, 3, severity::LOW); 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 //! [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); static constexpr Event FILENAME_TOO_LARGE_ERROR = event::makeEvent(SSID, 4, severity::LOW);
//! [EXPORT] : [COMMENT] CFDP request handling failed. P2: Returncode. //! [EXPORT] : [COMMENT] CFDP request handling failed. P2: Returncode.
static constexpr Event HANDLING_CFDP_REQUEST_FAILED = event::makeEvent(SSID, 5, severity::LOW); static constexpr Event HANDLING_CFDP_REQUEST_FAILED = event::makeEvent(SSID, 5, severity::LOW);
} // namespace events } // namespace events
static constexpr ReturnValue_t SOURCE_TRANSACTION_PENDING = returnvalue::makeCode(CID, 0); static constexpr ReturnValue_t SOURCE_TRANSACTION_PENDING = returnvalue::makeCode(CID, 0);
@ -71,6 +36,6 @@ 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 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 TARGET_MSG_QUEUE_FULL = returnvalue::makeCode(CID, 6);
static constexpr ReturnValue_t TM_STORE_FULL = returnvalue::makeCode(CID, 7); static constexpr ReturnValue_t TM_STORE_FULL = returnvalue::makeCode(CID, 7);
static constexpr ReturnValue_t DEST_NON_METADATA_PDU_AS_FIRST_PDU = returnvalue::makeCode(CID, 8);
static constexpr ReturnValue_t PDU_BUFFER_TOO_SMALL = returnvalue::makeCode(CID, 9);
} // namespace cfdp } // namespace cfdp
#endif // FSFW_CFDP_HANDLER_DEFS_H

View File

@ -1,5 +1,7 @@
#include "AckPduCreator.h" #include "AckPduCreator.h"
#include "fsfw/globalfunctions/CRC.h"
AckPduCreator::AckPduCreator(AckInfo &ackInfo, PduConfig &pduConf) AckPduCreator::AckPduCreator(AckInfo &ackInfo, PduConfig &pduConf)
: FileDirectiveCreator(pduConf, cfdp::FileDirective::ACK, 2), ackInfo(ackInfo) {} : FileDirectiveCreator(pduConf, cfdp::FileDirective::ACK, 2), ackInfo(ackInfo) {}
@ -7,6 +9,7 @@ size_t AckPduCreator::getSerializedSize() const { return FileDirectiveCreator::g
ReturnValue_t AckPduCreator::serialize(uint8_t **buffer, size_t *size, size_t maxSize, ReturnValue_t AckPduCreator::serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const { Endianness streamEndianness) const {
const uint8_t *start = *buffer;
ReturnValue_t result = FileDirectiveCreator::serialize(buffer, size, maxSize, streamEndianness); ReturnValue_t result = FileDirectiveCreator::serialize(buffer, size, maxSize, streamEndianness);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
return result; return result;
@ -29,5 +32,10 @@ ReturnValue_t AckPduCreator::serialize(uint8_t **buffer, size_t *size, size_t ma
**buffer = ackedConditionCode << 4 | transactionStatus; **buffer = ackedConditionCode << 4 | transactionStatus;
*buffer += 1; *buffer += 1;
*size += 1; *size += 1;
if (getCrcFlag()) {
uint16_t crc = CRC::crc16ccitt(start, getWholePduSize() - 2);
result = SerializeAdapter::serialize(&crc, buffer, size, maxSize, streamEndianness);
}
return returnvalue::OK; return returnvalue::OK;
} }

View File

@ -1,6 +1,7 @@
#include "EofPduCreator.h" #include "EofPduCreator.h"
#include "fsfw/FSFW.h" #include "fsfw/FSFW.h"
#include "fsfw/globalfunctions/CRC.h"
EofPduCreator::EofPduCreator(PduConfig &conf, EofInfo &info) EofPduCreator::EofPduCreator(PduConfig &conf, EofInfo &info)
: FileDirectiveCreator(conf, cfdp::FileDirective::EOF_DIRECTIVE, 9), info(info) { : FileDirectiveCreator(conf, cfdp::FileDirective::EOF_DIRECTIVE, 9), info(info) {
@ -11,6 +12,7 @@ size_t EofPduCreator::getSerializedSize() const { return FileDirectiveCreator::g
ReturnValue_t EofPduCreator::serialize(uint8_t **buffer, size_t *size, size_t maxSize, ReturnValue_t EofPduCreator::serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const { Endianness streamEndianness) const {
const uint8_t *start = *buffer;
ReturnValue_t result = FileDirectiveCreator::serialize(buffer, size, maxSize, streamEndianness); ReturnValue_t result = FileDirectiveCreator::serialize(buffer, size, maxSize, streamEndianness);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
return result; return result;
@ -36,5 +38,9 @@ ReturnValue_t EofPduCreator::serialize(uint8_t **buffer, size_t *size, size_t ma
if (info.getFaultLoc() != nullptr and info.getConditionCode() != cfdp::ConditionCode::NO_ERROR) { if (info.getFaultLoc() != nullptr and info.getConditionCode() != cfdp::ConditionCode::NO_ERROR) {
result = info.getFaultLoc()->serialize(buffer, size, maxSize, streamEndianness); result = info.getFaultLoc()->serialize(buffer, size, maxSize, streamEndianness);
} }
if (getCrcFlag()) {
uint16_t crc = CRC::crc16ccitt(start, getWholePduSize() - 2);
result = SerializeAdapter::serialize(&crc, buffer, size, maxSize, streamEndianness);
}
return result; return result;
} }

View File

@ -2,6 +2,8 @@
#include <cstring> #include <cstring>
#include "fsfw/globalfunctions/CRC.h"
FileDataCreator::FileDataCreator(PduConfig& conf, FileDataInfo& info) FileDataCreator::FileDataCreator(PduConfig& conf, FileDataInfo& info)
: HeaderCreator(conf, cfdp::PduType::FILE_DATA, 0, info.getSegmentMetadataFlag()), info(info) { : HeaderCreator(conf, cfdp::PduType::FILE_DATA, 0, info.getSegmentMetadataFlag()), info(info) {
update(); update();
@ -18,6 +20,7 @@ ReturnValue_t FileDataCreator::serialize(uint8_t** buffer, size_t* size, size_t
if (buffer == nullptr or size == nullptr) { if (buffer == nullptr or size == nullptr) {
return returnvalue::FAILED; return returnvalue::FAILED;
} }
const uint8_t* start = *buffer;
if (*size + getSerializedSize() > maxSize) { if (*size + getSerializedSize() > maxSize) {
return SerializeIF::BUFFER_TOO_SHORT; return SerializeIF::BUFFER_TOO_SHORT;
} }
@ -50,6 +53,11 @@ ReturnValue_t FileDataCreator::serialize(uint8_t** buffer, size_t* size, size_t
std::memcpy(*buffer, readOnlyPtr, fileSize); std::memcpy(*buffer, readOnlyPtr, fileSize);
*buffer += fileSize; *buffer += fileSize;
*size += fileSize; *size += fileSize;
if (getCrcFlag()) {
uint16_t crc = CRC::crc16ccitt(start, getWholePduSize() - 2);
result = SerializeAdapter::serialize(&crc, buffer, size, maxSize, streamEndianness);
}
return returnvalue::OK; return returnvalue::OK;
} }

View File

@ -8,6 +8,9 @@ ReturnValue_t FileDataReader::parseData() {
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
return result; return result;
} }
if (not performCrcCheckIfApplicable()) {
return cfdp::PDU_CHECKSUM_FAILURE;
}
size_t currentIdx = PduHeaderReader::getHeaderSize(); size_t currentIdx = PduHeaderReader::getHeaderSize();
const uint8_t* buf = pointers.rawPtr + currentIdx; const uint8_t* buf = pointers.rawPtr + currentIdx;
size_t remSize = PduHeaderReader::getWholePduSize() - currentIdx; size_t remSize = PduHeaderReader::getWholePduSize() - currentIdx;
@ -34,6 +37,9 @@ ReturnValue_t FileDataReader::parseData() {
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
return result; return result;
} }
if (getCrcFlag()) {
remSize -= 2;
}
if (remSize > 0) { if (remSize > 0) {
info.setFileData(buf, remSize); info.setFileData(buf, remSize);
} }

View File

@ -3,7 +3,7 @@
#include "../definitions.h" #include "../definitions.h"
#include "FileDataInfo.h" #include "FileDataInfo.h"
#include "PduHeaderReader.h" #include "HeaderReader.h"
class FileDataReader : public PduHeaderReader { class FileDataReader : public PduHeaderReader {
public: public:

View File

@ -1,5 +1,7 @@
#include "FileDirectiveReader.h" #include "FileDirectiveReader.h"
#include "fsfw/globalfunctions/CRC.h"
FileDirectiveReader::FileDirectiveReader(const uint8_t *pduBuf, size_t maxSize) FileDirectiveReader::FileDirectiveReader(const uint8_t *pduBuf, size_t maxSize)
: PduHeaderReader(pduBuf, maxSize) {} : PduHeaderReader(pduBuf, maxSize) {}
@ -10,6 +12,10 @@ ReturnValue_t FileDirectiveReader::parseData() {
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
return result; return result;
} }
if (not performCrcCheckIfApplicable()) {
return cfdp::PDU_CHECKSUM_FAILURE;
}
if (this->getPduDataFieldLen() < 1) { if (this->getPduDataFieldLen() < 1) {
return cfdp::INVALID_PDU_DATAFIELD_LEN; return cfdp::INVALID_PDU_DATAFIELD_LEN;
} }

View File

@ -2,7 +2,7 @@
#define FSFW_SRC_FSFW_CFDP_PDU_FILEDIRECTIVEDESERIALIZER_H_ #define FSFW_SRC_FSFW_CFDP_PDU_FILEDIRECTIVEDESERIALIZER_H_
#include "../definitions.h" #include "../definitions.h"
#include "fsfw/cfdp/pdu/PduHeaderReader.h" #include "fsfw/cfdp/pdu/HeaderReader.h"
/** /**
* @brief This class is used to deserialize a PDU file directive header from raw memory. * @brief This class is used to deserialize a PDU file directive header from raw memory.

View File

@ -1,5 +1,7 @@
#include "FinishedPduCreator.h" #include "FinishedPduCreator.h"
#include "fsfw/globalfunctions/CRC.h"
FinishPduCreator::FinishPduCreator(PduConfig &conf, FinishedInfo &finishInfo) FinishPduCreator::FinishPduCreator(PduConfig &conf, FinishedInfo &finishInfo)
: FileDirectiveCreator(conf, cfdp::FileDirective::FINISH, 0), finishInfo(finishInfo) { : FileDirectiveCreator(conf, cfdp::FileDirective::FINISH, 0), finishInfo(finishInfo) {
updateDirectiveFieldLen(); updateDirectiveFieldLen();
@ -13,6 +15,7 @@ void FinishPduCreator::updateDirectiveFieldLen() {
ReturnValue_t FinishPduCreator::serialize(uint8_t **buffer, size_t *size, size_t maxSize, ReturnValue_t FinishPduCreator::serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const { Endianness streamEndianness) const {
const uint8_t *start = *buffer;
ReturnValue_t result = FileDirectiveCreator::serialize(buffer, size, maxSize, streamEndianness); ReturnValue_t result = FileDirectiveCreator::serialize(buffer, size, maxSize, streamEndianness);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
return result; return result;
@ -40,5 +43,9 @@ ReturnValue_t FinishPduCreator::serialize(uint8_t **buffer, size_t *size, size_t
if (finishInfo.getFaultLocation(&entityId) == returnvalue::OK) { if (finishInfo.getFaultLocation(&entityId) == returnvalue::OK) {
result = entityId->serialize(buffer, size, maxSize, streamEndianness); result = entityId->serialize(buffer, size, maxSize, streamEndianness);
} }
if (getCrcFlag()) {
uint16_t crc = CRC::crc16ccitt(start, getWholePduSize() - 2);
result = SerializeAdapter::serialize(&crc, buffer, size, maxSize, streamEndianness);
}
return result; return result;
} }

View File

@ -1,8 +1,10 @@
#include "HeaderReader.h"
#include <fsfw/serialize/SerializeAdapter.h> #include <fsfw/serialize/SerializeAdapter.h>
#include <cstring> #include <cstring>
#include "PduHeaderReader.h" #include "fsfw/globalfunctions/CRC.h"
PduHeaderReader::PduHeaderReader(const uint8_t *pduBuf, size_t maxSize) { PduHeaderReader::PduHeaderReader(const uint8_t *pduBuf, size_t maxSize) {
setReadOnlyData(pduBuf, maxSize); setReadOnlyData(pduBuf, maxSize);
@ -17,28 +19,29 @@ ReturnValue_t PduHeaderReader::parseData() {
} }
pointers.fixedHeader = pointers.fixedHeader =
reinterpret_cast<PduHeaderFixedStruct *>(const_cast<uint8_t *>(pointers.rawPtr)); reinterpret_cast<PduHeaderFixedStruct *>(const_cast<uint8_t *>(pointers.rawPtr));
sourceIdRaw = static_cast<uint8_t *>(&pointers.fixedHeader->variableFieldsStart); sourceIdRaw = &pointers.fixedHeader->variableFieldsStart;
cfdp::WidthInBytes widthEntityIds = getLenEntityIds(); cfdp::WidthInBytes widthEntityIds = getLenEntityIds();
cfdp::WidthInBytes widthSeqNum = getLenSeqNum(); cfdp::WidthInBytes widthSeqNum = getLenSeqNum();
seqNumRaw = static_cast<uint8_t *>(sourceIdRaw) + static_cast<uint8_t>(widthEntityIds); seqNumRaw = static_cast<uint8_t *>(sourceIdRaw) + static_cast<uint8_t>(widthEntityIds);
destIdRaw = static_cast<uint8_t *>(seqNumRaw) + static_cast<uint8_t>(widthSeqNum); destIdRaw = static_cast<uint8_t *>(seqNumRaw) + static_cast<uint8_t>(widthSeqNum);
if (getWholePduSize() > PduHeaderReader::getHeaderSize()) { if (getWholePduSize() > PduHeaderReader::getHeaderSize()) {
pointers.dataFieldStart = reinterpret_cast<const uint8_t *>(destIdRaw) + widthEntityIds; pointers.dataFieldStart = static_cast<const uint8_t *>(destIdRaw) + widthEntityIds;
} else { } else {
pointers.dataFieldStart = nullptr; pointers.dataFieldStart = nullptr;
} }
return returnvalue::OK; return returnvalue::OK;
} }
ReturnValue_t PduHeaderReader::setData(uint8_t *dataPtr, size_t maxSize_, void *args) { ReturnValue_t PduHeaderReader::setData(uint8_t *dataPtr, size_t maxSize, void *args) {
if (dataPtr == nullptr) { if (dataPtr == nullptr) {
return returnvalue::FAILED; return returnvalue::FAILED;
} }
if (maxSize_ < 7) { if (maxSize < 7) {
return SerializeIF::STREAM_TOO_SHORT; return SerializeIF::STREAM_TOO_SHORT;
} }
pointers.rawPtr = dataPtr; pointers.rawPtr = dataPtr;
maxSize = maxSize_; this->maxSize = maxSize;
return returnvalue::OK; return returnvalue::OK;
} }
@ -166,3 +169,12 @@ void PduHeaderReader::fillConfig(PduConfig &cfg) const {
} }
const uint8_t *PduHeaderReader::getPduDataField() const { return pointers.dataFieldStart; } const uint8_t *PduHeaderReader::getPduDataField() const { return pointers.dataFieldStart; }
bool PduHeaderReader::performCrcCheckIfApplicable() const {
if (getCrcFlag()) {
if (CRC::crc16ccitt(pointers.rawPtr, getWholePduSize()) != 0) {
return false;
}
}
return true;
}

View File

@ -71,6 +71,11 @@ class PduHeaderReader : public RedirectableDataPointerIF, public PduHeaderIF {
void getDestId(cfdp::EntityId& destId) const override; void getDestId(cfdp::EntityId& destId) const override;
void getTransactionSeqNum(cfdp::TransactionSeqNum& seqNum) const override; void getTransactionSeqNum(cfdp::TransactionSeqNum& seqNum) const override;
/**
* Performs the CRC check on the whole PDU if the CRC flag is set.
*/
[[nodiscard]] bool performCrcCheckIfApplicable() const;
ReturnValue_t deserResult = returnvalue::OK; ReturnValue_t deserResult = returnvalue::OK;
[[nodiscard]] size_t getMaxSize() const; [[nodiscard]] size_t getMaxSize() const;

View File

@ -1,5 +1,7 @@
#include "KeepAlivePduCreator.h" #include "KeepAlivePduCreator.h"
#include "fsfw/globalfunctions/CRC.h"
KeepAlivePduCreator::KeepAlivePduCreator(PduConfig &conf, cfdp::Fss &progress) KeepAlivePduCreator::KeepAlivePduCreator(PduConfig &conf, cfdp::Fss &progress)
: FileDirectiveCreator(conf, cfdp::FileDirective::KEEP_ALIVE, 4), progress(progress) { : FileDirectiveCreator(conf, cfdp::FileDirective::KEEP_ALIVE, 4), progress(progress) {
updateDirectiveFieldLen(); updateDirectiveFieldLen();
@ -17,9 +19,18 @@ void KeepAlivePduCreator::updateDirectiveFieldLen() {
ReturnValue_t KeepAlivePduCreator::serialize(uint8_t **buffer, size_t *size, size_t maxSize, ReturnValue_t KeepAlivePduCreator::serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const { Endianness streamEndianness) const {
const uint8_t *start = *buffer;
ReturnValue_t result = FileDirectiveCreator::serialize(buffer, size, maxSize, streamEndianness); ReturnValue_t result = FileDirectiveCreator::serialize(buffer, size, maxSize, streamEndianness);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
return result; return result;
} }
return progress.serialize(this->getLargeFileFlag(), buffer, size, maxSize, streamEndianness); result = progress.serialize(this->getLargeFileFlag(), buffer, size, maxSize, streamEndianness);
if (result != returnvalue::OK) {
return result;
}
if (getCrcFlag()) {
uint16_t crc = CRC::crc16ccitt(start, getWholePduSize() - 2);
result = SerializeAdapter::serialize(&crc, buffer, size, maxSize, streamEndianness);
}
return result;
} }

View File

@ -1,5 +1,7 @@
#include "MetadataPduCreator.h" #include "MetadataPduCreator.h"
#include "fsfw/globalfunctions/CRC.h"
MetadataPduCreator::MetadataPduCreator(PduConfig &conf, MetadataGenericInfo &info, MetadataPduCreator::MetadataPduCreator(PduConfig &conf, MetadataGenericInfo &info,
cfdp::StringLv &srcFileName, cfdp::StringLv &destFileName, cfdp::StringLv &srcFileName, cfdp::StringLv &destFileName,
cfdp::Tlv **optionsArray, size_t optionsLen) cfdp::Tlv **optionsArray, size_t optionsLen)
@ -29,6 +31,7 @@ size_t MetadataPduCreator::getSerializedSize() const {
ReturnValue_t MetadataPduCreator::serialize(uint8_t **buffer, size_t *size, size_t maxSize, ReturnValue_t MetadataPduCreator::serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const { Endianness streamEndianness) const {
const uint8_t *start = *buffer;
ReturnValue_t result = FileDirectiveCreator::serialize(buffer, size, maxSize, streamEndianness); ReturnValue_t result = FileDirectiveCreator::serialize(buffer, size, maxSize, streamEndianness);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
return result; return result;
@ -60,6 +63,11 @@ ReturnValue_t MetadataPduCreator::serialize(uint8_t **buffer, size_t *size, size
} }
} }
} }
if (getCrcFlag()) {
uint16_t crc = CRC::crc16ccitt(start, getWholePduSize() - 2);
result = SerializeAdapter::serialize(&crc, buffer, size, maxSize, streamEndianness);
}
return result; return result;
} }
const cfdp::StringLv &MetadataPduCreator::getSourceFileName() const { return srcFileName; } const cfdp::StringLv &MetadataPduCreator::getSourceFileName() const { return srcFileName; }

View File

@ -38,6 +38,10 @@ ReturnValue_t MetadataPduReader::parseData() {
return result; return result;
} }
if (getCrcFlag() && remSize == 2) {
return returnvalue::OK;
}
if (remSize > 0) { if (remSize > 0) {
if (optionArrayMaxSize == 0 or optionArray == nullptr) { if (optionArrayMaxSize == 0 or optionArray == nullptr) {
return cfdp::METADATA_CANT_PARSE_OPTIONS; return cfdp::METADATA_CANT_PARSE_OPTIONS;

View File

@ -1,5 +1,7 @@
#include "NakPduCreator.h" #include "NakPduCreator.h"
#include "fsfw/globalfunctions/CRC.h"
NakPduCreator::NakPduCreator(PduConfig &pduConf, NakInfo &nakInfo) NakPduCreator::NakPduCreator(PduConfig &pduConf, NakInfo &nakInfo)
: FileDirectiveCreator(pduConf, cfdp::FileDirective::NAK, 0), nakInfo(nakInfo) { : FileDirectiveCreator(pduConf, cfdp::FileDirective::NAK, 0), nakInfo(nakInfo) {
updateDirectiveFieldLen(); updateDirectiveFieldLen();
@ -13,6 +15,7 @@ size_t NakPduCreator::getSerializedSize() const { return FileDirectiveCreator::g
ReturnValue_t NakPduCreator::serialize(uint8_t **buffer, size_t *size, size_t maxSize, ReturnValue_t NakPduCreator::serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const { Endianness streamEndianness) const {
const uint8_t *start = *buffer;
ReturnValue_t result = FileDirectiveCreator::serialize(buffer, size, maxSize, streamEndianness); ReturnValue_t result = FileDirectiveCreator::serialize(buffer, size, maxSize, streamEndianness);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
return result; return result;
@ -40,5 +43,9 @@ ReturnValue_t NakPduCreator::serialize(uint8_t **buffer, size_t *size, size_t ma
} }
} }
} }
if (getCrcFlag()) {
uint16_t crc = CRC::crc16ccitt(start, getWholePduSize() - 2);
result = SerializeAdapter::serialize(&crc, buffer, size, maxSize, streamEndianness);
}
return result; return result;
} }

View File

@ -1,5 +1,7 @@
#include "PromptPduCreator.h" #include "PromptPduCreator.h"
#include "fsfw/globalfunctions/CRC.h"
PromptPduCreator::PromptPduCreator(PduConfig &conf, cfdp::PromptResponseRequired responseRequired) PromptPduCreator::PromptPduCreator(PduConfig &conf, cfdp::PromptResponseRequired responseRequired)
: FileDirectiveCreator(conf, cfdp::FileDirective::PROMPT, 1), : FileDirectiveCreator(conf, cfdp::FileDirective::PROMPT, 1),
responseRequired(responseRequired) {} responseRequired(responseRequired) {}
@ -10,6 +12,7 @@ size_t PromptPduCreator::getSerializedSize() const {
ReturnValue_t PromptPduCreator::serialize(uint8_t **buffer, size_t *size, size_t maxSize, ReturnValue_t PromptPduCreator::serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const { Endianness streamEndianness) const {
const uint8_t *start = *buffer;
ReturnValue_t result = FileDirectiveCreator::serialize(buffer, size, maxSize, streamEndianness); ReturnValue_t result = FileDirectiveCreator::serialize(buffer, size, maxSize, streamEndianness);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
return result; return result;
@ -20,5 +23,10 @@ ReturnValue_t PromptPduCreator::serialize(uint8_t **buffer, size_t *size, size_t
**buffer = responseRequired << 7; **buffer = responseRequired << 7;
*buffer += 1; *buffer += 1;
*size += 1; *size += 1;
if (getCrcFlag()) {
uint16_t crc = CRC::crc16ccitt(start, getWholePduSize() - 2);
result = SerializeAdapter::serialize(&crc, buffer, size, maxSize, streamEndianness);
}
return result; return result;
} }

View File

@ -17,8 +17,7 @@ LocalPoolDataSetBase::LocalPoolDataSetBase(HasLocalDataPoolIF *hkOwner, uint32_t
if (hkOwner == nullptr) { if (hkOwner == nullptr) {
// Configuration error. // Configuration error.
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "LocalPoolDataSetBase::LocalPoolDataSetBase: Owner " sif::error << "LocalPoolDataSetBase::LocalPoolDataSetBase: Owner " << "invalid!" << std::endl;
<< "invalid!" << std::endl;
#else #else
sif::printError( sif::printError(
"LocalPoolDataSetBase::LocalPoolDataSetBase: Owner " "LocalPoolDataSetBase::LocalPoolDataSetBase: Owner "
@ -187,8 +186,8 @@ ReturnValue_t LocalPoolDataSetBase::serializeLocalPoolIds(uint8_t **buffer, size
SerializeAdapter::serialize(&currentPoolId, buffer, size, maxSize, streamEndianness); SerializeAdapter::serialize(&currentPoolId, buffer, size, maxSize, streamEndianness);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LocalPoolDataSetBase::serializeLocalPoolIds: " sif::warning << "LocalPoolDataSetBase::serializeLocalPoolIds: " << "Serialization error!"
<< "Serialization error!" << std::endl; << std::endl;
#else #else
sif::printWarning( sif::printWarning(
"LocalPoolDataSetBase::serializeLocalPoolIds: " "LocalPoolDataSetBase::serializeLocalPoolIds: "

View File

@ -17,8 +17,8 @@ LocalPoolObjectBase::LocalPoolObjectBase(lp_id_t poolId, HasLocalDataPoolIF* hkO
} }
if (hkOwner == nullptr) { if (hkOwner == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "LocalPoolVar<T>::LocalPoolVar: The supplied pool " sif::error << "LocalPoolVar<T>::LocalPoolVar: The supplied pool " << "owner is a invalid!"
<< "owner is a invalid!" << std::endl; << std::endl;
#endif #endif
return; return;
} }

View File

@ -243,8 +243,8 @@ bool DeviceHandlerFailureIsolation::isFdirInActionOrAreWeFaulty(EventMessage* ev
if (owner == nullptr) { if (owner == nullptr) {
// Configuration error. // Configuration error.
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DeviceHandlerFailureIsolation::" sif::error << "DeviceHandlerFailureIsolation::" << "isFdirInActionOrAreWeFaulty: Owner not set!"
<< "isFdirInActionOrAreWeFaulty: Owner not set!" << std::endl; << std::endl;
#endif #endif
return false; return false;
} }

View File

@ -62,8 +62,7 @@ ReturnValue_t FailureIsolationBase::initialize() {
ObjectManager::instance()->get<ConfirmsFailuresIF>(faultTreeParent); ObjectManager::instance()->get<ConfirmsFailuresIF>(faultTreeParent);
if (parentIF == nullptr) { if (parentIF == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "FailureIsolationBase::intialize: Parent object " sif::error << "FailureIsolationBase::intialize: Parent object " << "invalid" << std::endl;
<< "invalid" << std::endl;
sif::error << "Make sure it implements ConfirmsFailuresIF" << std::endl; sif::error << "Make sure it implements ConfirmsFailuresIF" << std::endl;
#else #else
sif::printError("FailureIsolationBase::intialize: Parent object invalid\n"); sif::printError("FailureIsolationBase::intialize: Parent object invalid\n");

View File

@ -58,11 +58,7 @@ class HasFileSystemIF {
static constexpr ReturnValue_t DIRECTORY_ALREADY_EXISTS = MAKE_RETURN_CODE(22); static constexpr ReturnValue_t DIRECTORY_ALREADY_EXISTS = MAKE_RETURN_CODE(22);
static constexpr ReturnValue_t NOT_A_DIRECTORY = MAKE_RETURN_CODE(23); static constexpr ReturnValue_t NOT_A_DIRECTORY = MAKE_RETURN_CODE(23);
static constexpr ReturnValue_t DIRECTORY_NOT_EMPTY = MAKE_RETURN_CODE(24); static constexpr ReturnValue_t DIRECTORY_NOT_EMPTY = MAKE_RETURN_CODE(24);
static constexpr ReturnValue_t ELEMENT_DOES_NOT_EXIST = MAKE_RETURN_CODE(25);
//! [EXPORT] : P1: Sequence number missing
static constexpr ReturnValue_t SEQUENCE_PACKET_MISSING_WRITE = MAKE_RETURN_CODE(30);
//! [EXPORT] : P1: Sequence number missing
static constexpr ReturnValue_t SEQUENCE_PACKET_MISSING_READ = MAKE_RETURN_CODE(31);
virtual ~HasFileSystemIF() = default; virtual ~HasFileSystemIF() = default;
@ -75,21 +71,27 @@ class HasFileSystemIF {
} }
// Get the base filename without the full directory path // Get the base filename without the full directory path
virtual ReturnValue_t getBaseFilename(FilesystemParams params, char* nameBuf, size_t maxLen, virtual ReturnValue_t getBaseFilename(const char* path, char* nameBuf, size_t maxLen,
size_t& baseNameLen) = 0; size_t& baseNameLen) = 0;
virtual bool isDirectory(const char* path) = 0; virtual ReturnValue_t isDirectory(const char* path, bool& isDirectory) = 0;
virtual ReturnValue_t getFileSize(FilesystemParams params, uint64_t& fileSize) = 0; virtual ReturnValue_t getFileSize(const char* path, uint64_t& fileSize,
FileSystemArgsIF* args) = 0;
virtual ReturnValue_t getFileSize(const char* path, uint64_t& fileSize) {
return getFileSize(path, fileSize, nullptr);
}
virtual bool fileExists(FilesystemParams params) = 0; virtual bool fileExists(const char* path, FileSystemArgsIF* args) = 0;
virtual bool fileExists(const char* path) { return fileExists(path, nullptr); }
/** /**
* Truncate a file, deleting its contents and setting its size to 0 accordingly. * Truncate a file, deleting its contents and setting its size to 0 accordingly.
* @param params * @param params
* @return * @return
*/ */
virtual ReturnValue_t truncateFile(FilesystemParams params) = 0; virtual ReturnValue_t truncateFile(const char* path, FileSystemArgsIF* args) = 0;
virtual ReturnValue_t truncateFile(const char* path) { return truncateFile(path, nullptr); }
/** /**
* @brief Generic function to write to a file. * @brief Generic function to write to a file.
@ -100,32 +102,23 @@ class HasFileSystemIF {
* @param fileOpInfo General information: File name, size to write, offset, additional arguments * @param fileOpInfo General information: File name, size to write, offset, additional arguments
* @param data The data to write to the file * @param data The data to write to the file
*/ */
virtual ReturnValue_t writeToFile(FileOpParams params, const uint8_t* data) = 0; virtual ReturnValue_t writeToFile(const char* path, size_t offset, const uint8_t* data,
size_t size) = 0;
/** /**
* @brief Generic function to read from a file. This variant takes a pointer to a buffer and * @brief Generic function to read from a file. This variant takes a pointer to a buffer and
* performs pointer arithmetic by incrementing the pointer by the read size * performs pointer arithmetic by incrementing the pointer by the read size
* @param fileOpInfo General information: File name, size to write, offset, additional arguments * @param path [in] file path
* @param buffer [in/out] Data will be read into the provided buffer, and the pointer will be * @param offset [in] offset of data to read
* incremented by the read length * @param sizeToRead [in] size of data to read
* @param readSize [out] Will be incremented by the read length * @param buffer [in/out] Data will be read into the provided buffer.
* @param maxSize Maximum size of the provided buffer * @param actuallyRead [out] Will be set to the length actually read.
* @param maxSize [in] Maximum size of the provided buffer
* @param args * @param args
* @return * @return
*/ */
virtual ReturnValue_t readFromFile(FileOpParams fileOpInfo, uint8_t** buffer, size_t& readSize, virtual ReturnValue_t readFromFile(const char* path, size_t offset, size_t sizeToRead,
size_t maxSize) = 0; uint8_t* buffer, size_t& actuallyRead, size_t maxSize) = 0;
/**
* Variant of the @readFromFile which does not perform pointer arithmetic.
* @param fileOpInfo General information: File name, size to write, offset, additional arguments
* @param buf
* @param maxSize
* @return
*/
virtual ReturnValue_t readFromFile(FileOpParams fileOpInfo, uint8_t* buf, size_t maxSize) {
size_t dummy = 0;
return readFromFile(fileOpInfo, &buf, dummy, maxSize);
}
/** /**
* @brief Generic function to create a new file. * @brief Generic function to create a new file.
@ -136,10 +129,8 @@ class HasFileSystemIF {
* @param args Any other arguments which an implementation might require * @param args Any other arguments which an implementation might require
* @return * @return
*/ */
virtual ReturnValue_t createFile(FilesystemParams params) { virtual ReturnValue_t createFile(const char* path) { return createFile(path, nullptr, 0); }
return createFile(params, nullptr, 0); virtual ReturnValue_t createFile(const char* path, const uint8_t* data, size_t size) = 0;
}
virtual ReturnValue_t createFile(FilesystemParams params, const uint8_t* data, size_t size) = 0;
/** /**
* @brief Generic function to delete a file. * @brief Generic function to delete a file.
@ -159,9 +150,13 @@ class HasFileSystemIF {
* @param args Any other arguments which an implementation might require * @param args Any other arguments which an implementation might require
* @return * @return
*/ */
virtual ReturnValue_t createDirectory(FilesystemParams params, bool createParentDirs) = 0; virtual ReturnValue_t createDirectory(const char* path, bool createParentDirs,
virtual ReturnValue_t createDirectory(FilesystemParams params) { FileSystemArgsIF* args) = 0;
return createDirectory(params, false); virtual ReturnValue_t createDirectory(const char* path, FileSystemArgsIF* args) {
return createDirectory(path, false, args);
}
virtual ReturnValue_t createDirectory(const char* path) {
return createDirectory(path, false, nullptr);
} }
/** /**
@ -169,9 +164,10 @@ class HasFileSystemIF {
* @param repositoryPath * @param repositoryPath
* @param args Any other arguments which an implementation might require * @param args Any other arguments which an implementation might require
*/ */
virtual ReturnValue_t removeDirectory(FilesystemParams params, bool deleteRecurively) = 0; virtual ReturnValue_t removeDirectory(const char* path, bool deleteRecurively,
virtual ReturnValue_t removeDirectory(FilesystemParams params) { FileSystemArgsIF* args) = 0;
return removeDirectory(params, false); virtual ReturnValue_t removeDirectory(const char* path, FileSystemArgsIF* args) {
return removeDirectory(path, false, nullptr);
} }
virtual ReturnValue_t rename(const char* oldPath, const char* newPath) { virtual ReturnValue_t rename(const char* oldPath, const char* newPath) {

View File

@ -49,8 +49,8 @@ ReturnValue_t TcpTmTcBridge::handleTm() {
MutexGuard guard(mutex, timeoutType, mutexTimeoutMs); MutexGuard guard(mutex, timeoutType, mutexTimeoutMs);
TmTcMessage message; TmTcMessage message;
ReturnValue_t status = returnvalue::OK; ReturnValue_t status = returnvalue::OK;
for (ReturnValue_t result = tmTcReceptionQueue->receiveMessage(&message); for (ReturnValue_t result = tmtcReceptionQueue->receiveMessage(&message);
result == returnvalue::OK; result = tmTcReceptionQueue->receiveMessage(&message)) { result == returnvalue::OK; result = tmtcReceptionQueue->receiveMessage(&message)) {
status = storeDownlinkData(&message); status = storeDownlinkData(&message);
if (status != returnvalue::OK) { if (status != returnvalue::OK) {
break; break;

View File

@ -321,8 +321,8 @@ ReturnValue_t TcpTmTcServer::handleTcRingBufferData(size_t availableReadData) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
// Possible configuration error, too much data or/and data coming in too fast, // Possible configuration error, too much data or/and data coming in too fast,
// requiring larger buffers // requiring larger buffers
sif::warning << "TcpTmTcServer::handleServerOperation: Ring buffer reached " sif::warning << "TcpTmTcServer::handleServerOperation: Ring buffer reached " << "fill count"
<< "fill count" << std::endl; << std::endl;
#else #else
sif::printWarning( sif::printWarning(
"TcpTmTcServer::handleServerOperation: Ring buffer reached " "TcpTmTcServer::handleServerOperation: Ring buffer reached "

View File

@ -49,8 +49,8 @@ ReturnValue_t Service20ParameterManagement::checkAndAcquireTargetID(object_id_t*
if (SerializeAdapter::deSerialize(objectIdToSet, &tcData, &tcDataLen, if (SerializeAdapter::deSerialize(objectIdToSet, &tcData, &tcDataLen,
SerializeIF::Endianness::BIG) != returnvalue::OK) { SerializeIF::Endianness::BIG) != returnvalue::OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Service20ParameterManagement::checkAndAcquireTargetID: " sif::error << "Service20ParameterManagement::checkAndAcquireTargetID: " << "Invalid data."
<< "Invalid data." << std::endl; << std::endl;
#else #else
sif::printError( sif::printError(
"Service20ParameterManagement::" "Service20ParameterManagement::"

View File

@ -196,8 +196,8 @@ ReturnValue_t Service3Housekeeping::handleReply(const CommandMessage* reply,
default: default:
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Service3Housekeeping::handleReply: Invalid reply with " sif::warning << "Service3Housekeeping::handleReply: Invalid reply with " << "reply command "
<< "reply command " << command << std::endl; << command << std::endl;
#else #else
sif::printWarning( sif::printWarning(
"Service3Housekeeping::handleReply: Invalid reply with " "Service3Housekeeping::handleReply: Invalid reply with "

View File

@ -12,8 +12,7 @@ LocalPool::LocalPool(object_id_t setObjectId, const LocalPoolConfig& poolConfig,
spillsToHigherPools(spillsToHigherPools) { spillsToHigherPools(spillsToHigherPools) {
if (NUMBER_OF_SUBPOOLS == 0) { if (NUMBER_OF_SUBPOOLS == 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "LocalPool::LocalPool: Passed pool configuration is " sif::error << "LocalPool::LocalPool: Passed pool configuration is " << " invalid!" << std::endl;
<< " invalid!" << std::endl;
#endif #endif
} }
max_subpools_t index = 0; max_subpools_t index = 0;

View File

@ -38,10 +38,9 @@ ReturnValue_t Subsystem::checkSequence(HybridIterator<ModeListEntry> iter,
if (!existsModeTable(iter->getTableId())) { if (!existsModeTable(iter->getTableId())) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
using namespace std; using namespace std;
sif::warning << "Subsystem::checkSequence: " sif::warning << "Subsystem::checkSequence: " << "Object " << setfill('0') << hex << "0x"
<< "Object " << setfill('0') << hex << "0x" << setw(8) << getObjectId() << setw(8) << getObjectId() << setw(0) << ": Mode table for mode ID " << "0x"
<< setw(0) << ": Mode table for mode ID " << setw(8) << iter->getTableId() << " does not exist" << dec << endl;
<< "0x" << setw(8) << iter->getTableId() << " does not exist" << dec << endl;
#endif #endif
return TABLE_DOES_NOT_EXIST; return TABLE_DOES_NOT_EXIST;
} else { } else {

View File

@ -101,8 +101,7 @@ ReturnValue_t FixedSlotSequence::checkSequence() const {
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
// Continue for now but print error output. // Continue for now but print error output.
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "FixedSlotSequence::checkSequence:" sif::error << "FixedSlotSequence::checkSequence:" << " Custom check failed!" << std::endl;
<< " Custom check failed!" << std::endl;
#endif #endif
} }
} }

View File

@ -8,8 +8,8 @@
#define PUS_DISTRIBUTOR_DEBUGGING 0 #define PUS_DISTRIBUTOR_DEBUGGING 0
PusDistributor::PusDistributor(uint16_t setApid, object_id_t setObjectId, PusDistributor::PusDistributor(uint16_t setApid, object_id_t setObjectId, StorageManagerIF* store_,
CcsdsDistributorIF* distributor, StorageManagerIF* store_) CcsdsDistributorIF* distributor)
: TcDistributorBase(setObjectId), : TcDistributorBase(setObjectId),
store(store_), store(store_),
checker(setApid, ccsds::PacketType::TC), checker(setApid, ccsds::PacketType::TC),
@ -122,14 +122,12 @@ ReturnValue_t PusDistributor::initialize() {
return ObjectManagerIF::CHILD_INIT_FAILED; return ObjectManagerIF::CHILD_INIT_FAILED;
} }
} }
if (ccsdsDistributor == nullptr) { if (ccsdsDistributor != nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 ReturnValue_t result =
sif::error << "PUSDistributor::initialize: Packet source invalid" << std::endl; ccsdsDistributor->registerApplication(CcsdsDistributorIF::DestInfo(*this, false));
sif::error << " Make sure it exists and implements CCSDSDistributorIF!" << std::endl; if (result != returnvalue::OK) {
#else return result;
sif::printError("PusDistributor::initialize: Packet source invalid\n"); }
sif::printError("Make sure it exists and implements CcsdsDistributorIF\n");
#endif
return ObjectManagerIF::CHILD_INIT_FAILED; return ObjectManagerIF::CHILD_INIT_FAILED;
} }
if (verifyChannel == nullptr) { if (verifyChannel == nullptr) {
@ -139,7 +137,7 @@ ReturnValue_t PusDistributor::initialize() {
return ObjectManagerIF::CHILD_INIT_FAILED; return ObjectManagerIF::CHILD_INIT_FAILED;
} }
} }
return ccsdsDistributor->registerApplication(CcsdsDistributorIF::DestInfo(*this, false)); return SystemObject::initialize();
} }
void PusDistributor::checkerFailurePrinter() const { void PusDistributor::checkerFailurePrinter() const {

View File

@ -31,8 +31,9 @@ class PusDistributor : public TcDistributorBase,
* @param setPacketSource Object ID of the source of TC packets. * @param setPacketSource Object ID of the source of TC packets.
* Must implement CcsdsDistributorIF. * Must implement CcsdsDistributorIF.
*/ */
PusDistributor(uint16_t setApid, object_id_t setObjectId, CcsdsDistributorIF* packetSource, PusDistributor(uint16_t setApid, object_id_t setObjectId, StorageManagerIF* store = nullptr,
StorageManagerIF* store = nullptr); CcsdsDistributorIF* packetSource = nullptr);
[[nodiscard]] const char* getName() const override; [[nodiscard]] const char* getName() const override;
/** /**
* The destructor is empty. * The destructor is empty.

View File

@ -43,10 +43,11 @@ ReturnValue_t SpacePacketCreator::serialize(uint8_t **buffer, size_t *size, size
void SpacePacketCreator::setCcsdsLenFromTotalDataFieldLen(size_t actualLength) { void SpacePacketCreator::setCcsdsLenFromTotalDataFieldLen(size_t actualLength) {
if (actualLength == 0) { if (actualLength == 0) {
return; setDataLenField(actualLength);
} } else {
setDataLenField(actualLength - 1); setDataLenField(actualLength - 1);
} }
}
size_t SpacePacketCreator::getSerializedSize() const { return ccsds::HEADER_LEN; } size_t SpacePacketCreator::getSerializedSize() const { return ccsds::HEADER_LEN; }
ReturnValue_t SpacePacketCreator::deSerialize(const uint8_t **buffer, size_t *size, ReturnValue_t SpacePacketCreator::deSerialize(const uint8_t **buffer, size_t *size,

View File

@ -17,11 +17,11 @@ TmTcBridge::TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDes
{ {
auto mqArgs = MqArgs(objectId, static_cast<void*>(this)); auto mqArgs = MqArgs(objectId, static_cast<void*>(this));
tmTcReceptionQueue = QueueFactory::instance()->createMessageQueue( tmtcReceptionQueue = QueueFactory::instance()->createMessageQueue(
msgQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs); msgQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
} }
TmTcBridge::~TmTcBridge() { QueueFactory::instance()->deleteMessageQueue(tmTcReceptionQueue); } TmTcBridge::~TmTcBridge() { QueueFactory::instance()->deleteMessageQueue(tmtcReceptionQueue); }
void TmTcBridge::setNumberOfSentPacketsPerCycle(uint32_t sentPacketsPerCycle_) { void TmTcBridge::setNumberOfSentPacketsPerCycle(uint32_t sentPacketsPerCycle_) {
this->sentPacketsPerCycle = sentPacketsPerCycle_; this->sentPacketsPerCycle = sentPacketsPerCycle_;
@ -34,8 +34,7 @@ ReturnValue_t TmTcBridge::setMaxNumberOfPacketsStored(unsigned int maxNumberOfPa
} else { } else {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TmTcBridge::setMaxNumberOfPacketsStored: Number of " sif::warning << "TmTcBridge::setMaxNumberOfPacketsStored: Number of "
<< "packets stored exceeds limits. " << "packets stored exceeds limits. " << "Keeping default value." << std::endl;
<< "Keeping default value." << std::endl;
#endif #endif
return returnvalue::FAILED; return returnvalue::FAILED;
} }
@ -70,7 +69,7 @@ ReturnValue_t TmTcBridge::initialize() {
tmFifo = new DynamicFIFO<store_address_t>(maxNumberOfPacketsStored); tmFifo = new DynamicFIFO<store_address_t>(maxNumberOfPacketsStored);
tmTcReceptionQueue->setDefaultDestination(tcDistributor->getRequestQueue()); tmtcReceptionQueue->setDefaultDestination(tcDistributor->getRequestQueue());
return returnvalue::OK; return returnvalue::OK;
} }
@ -79,15 +78,13 @@ ReturnValue_t TmTcBridge::performOperation(uint8_t operationCode) {
result = handleTc(); result = handleTc();
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "TmTcBridge::performOperation: " sif::debug << "TmTcBridge::performOperation: " << "Error handling TCs" << std::endl;
<< "Error handling TCs" << std::endl;
#endif #endif
} }
result = handleTm(); result = handleTm();
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "TmTcBridge::performOperation: " sif::debug << "TmTcBridge::performOperation: " << "Error handling TMs" << std::endl;
<< "Error handling TMs" << std::endl;
#endif #endif
} }
return result; return result;
@ -124,8 +121,8 @@ ReturnValue_t TmTcBridge::handleTmQueue() {
const uint8_t* data = nullptr; const uint8_t* data = nullptr;
size_t size = 0; size_t size = 0;
ReturnValue_t status = returnvalue::OK; ReturnValue_t status = returnvalue::OK;
for (ReturnValue_t result = tmTcReceptionQueue->receiveMessage(&message); for (ReturnValue_t result = tmtcReceptionQueue->receiveMessage(&message);
result == returnvalue::OK; result = tmTcReceptionQueue->receiveMessage(&message)) { result == returnvalue::OK; result = tmtcReceptionQueue->receiveMessage(&message)) {
#if FSFW_VERBOSE_LEVEL >= 3 #if FSFW_VERBOSE_LEVEL >= 3
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "Sent packet counter: " << static_cast<int>(packetSentCounter) << std::endl; sif::info << "Sent packet counter: " << static_cast<int>(packetSentCounter) << std::endl;
@ -241,7 +238,7 @@ void TmTcBridge::registerCommDisconnect() {
} }
MessageQueueId_t TmTcBridge::getReportReceptionQueue(uint8_t virtualChannel) const { MessageQueueId_t TmTcBridge::getReportReceptionQueue(uint8_t virtualChannel) const {
return tmTcReceptionQueue->getId(); return tmtcReceptionQueue->getId();
} }
void TmTcBridge::printData(uint8_t* data, size_t dataLen) { arrayprinter::print(data, dataLen); } void TmTcBridge::printData(uint8_t* data, size_t dataLen) { arrayprinter::print(data, dataLen); }
@ -253,7 +250,7 @@ uint32_t TmTcBridge::getIdentifier() const {
MessageQueueId_t TmTcBridge::getRequestQueue() const { MessageQueueId_t TmTcBridge::getRequestQueue() const {
// Default implementation: Relay TC messages to TC distributor directly. // Default implementation: Relay TC messages to TC distributor directly.
return tmTcReceptionQueue->getDefaultDestination(); return tmtcReceptionQueue->getDefaultDestination();
} }
void TmTcBridge::setFifoToOverwriteOldData(bool overwriteOld) { this->overwriteOld = overwriteOld; } void TmTcBridge::setFifoToOverwriteOldData(bool overwriteOld) { this->overwriteOld = overwriteOld; }

View File

@ -80,7 +80,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
//! Used to send and receive TMTC messages. //! Used to send and receive TMTC messages.
//! The TmTcMessage class is used to transport messages between tasks. //! The TmTcMessage class is used to transport messages between tasks.
MessageQueueIF* tmTcReceptionQueue = nullptr; MessageQueueIF* tmtcReceptionQueue = nullptr;
StorageManagerIF* tmStore = nullptr; StorageManagerIF* tmStore = nullptr;
StorageManagerIF* tcStore = nullptr; StorageManagerIF* tcStore = nullptr;

View File

@ -10,11 +10,12 @@ using namespace std;
HostFilesystem::HostFilesystem() = default; HostFilesystem::HostFilesystem() = default;
ReturnValue_t HostFilesystem::writeToFile(FileOpParams params, const uint8_t *data) { ReturnValue_t HostFilesystem::writeToFile(const char *path_, size_t offset, const uint8_t *data,
if (params.path() == nullptr) { size_t size) {
if (path_ == nullptr) {
return returnvalue::FAILED; return returnvalue::FAILED;
} }
path path(params.path()); path path(path_);
std::error_code e; std::error_code e;
if (not exists(path, e)) { if (not exists(path, e)) {
return HasFileSystemIF::FILE_DOES_NOT_EXIST; return HasFileSystemIF::FILE_DOES_NOT_EXIST;
@ -25,17 +26,20 @@ ReturnValue_t HostFilesystem::writeToFile(FileOpParams params, const uint8_t *da
if (file.fail()) { if (file.fail()) {
return HasFileSystemIF::GENERIC_FILE_ERROR; return HasFileSystemIF::GENERIC_FILE_ERROR;
} }
file.seekp(static_cast<unsigned int>(params.offset)); file.seekp(static_cast<unsigned int>(offset));
file.write(reinterpret_cast<const char *>(data), static_cast<unsigned int>(params.size)); file.write(reinterpret_cast<const char *>(data), static_cast<unsigned int>(size));
return returnvalue::OK; return returnvalue::OK;
} }
ReturnValue_t HostFilesystem::readFromFile(FileOpParams params, uint8_t **buffer, size_t &readSize, ReturnValue_t HostFilesystem::readFromFile(const char *path_, size_t offset, size_t sizeToRead,
size_t maxSize) { uint8_t *buffer, size_t &actuallyRead, size_t maxSize) {
if (params.path() == nullptr) { if (path_ == nullptr) {
return returnvalue::FAILED; return returnvalue::FAILED;
} }
path path(params.path()); if (sizeToRead > maxSize) {
return SerializeIF::BUFFER_TOO_SHORT;
}
path path(path_);
std::error_code e; std::error_code e;
if (not exists(path, e)) { if (not exists(path, e)) {
return HasFileSystemIF::FILE_DOES_NOT_EXIST; return HasFileSystemIF::FILE_DOES_NOT_EXIST;
@ -44,23 +48,17 @@ ReturnValue_t HostFilesystem::readFromFile(FileOpParams params, uint8_t **buffer
if (file.fail()) { if (file.fail()) {
return HasFileSystemIF::GENERIC_FILE_ERROR; return HasFileSystemIF::GENERIC_FILE_ERROR;
} }
auto sizeToRead = static_cast<unsigned int>(params.size); file.seekg(static_cast<unsigned int>(offset));
file.seekg(static_cast<unsigned int>(params.offset)); file.read(reinterpret_cast<char *>(buffer), static_cast<long>(sizeToRead));
if (readSize + sizeToRead > maxSize) { actuallyRead = sizeToRead;
return SerializeIF::BUFFER_TOO_SHORT;
}
file.read(reinterpret_cast<char *>(*buffer), sizeToRead);
readSize += sizeToRead;
*buffer += sizeToRead;
return returnvalue::OK; return returnvalue::OK;
} }
ReturnValue_t HostFilesystem::createFile(FilesystemParams params, const uint8_t *data, ReturnValue_t HostFilesystem::createFile(const char *path_, const uint8_t *data, size_t size) {
size_t size) { if (path_ == nullptr) {
if (params.path == nullptr) {
return returnvalue::FAILED; return returnvalue::FAILED;
} }
path path(params.path); std::filesystem::path path(path_);
std::error_code e; std::error_code e;
if (exists(path, e)) { if (exists(path, e)) {
return HasFileSystemIF::FILE_ALREADY_EXISTS; return HasFileSystemIF::FILE_ALREADY_EXISTS;
@ -87,11 +85,12 @@ ReturnValue_t HostFilesystem::removeFile(const char *path_, FileSystemArgsIF *ar
return HasFileSystemIF::GENERIC_FILE_ERROR; return HasFileSystemIF::GENERIC_FILE_ERROR;
} }
ReturnValue_t HostFilesystem::createDirectory(FilesystemParams params, bool createParentDirs) { ReturnValue_t HostFilesystem::createDirectory(const char *path, bool createParentDirs,
if (params.path == nullptr) { FileSystemArgsIF *args) {
if (path == nullptr) {
return returnvalue::FAILED; return returnvalue::FAILED;
} }
path dirPath(params.path); std::filesystem::path dirPath(path);
std::error_code e; std::error_code e;
if (exists(dirPath, e)) { if (exists(dirPath, e)) {
@ -110,11 +109,12 @@ ReturnValue_t HostFilesystem::createDirectory(FilesystemParams params, bool crea
return HasFileSystemIF::GENERIC_DIR_ERROR; return HasFileSystemIF::GENERIC_DIR_ERROR;
} }
ReturnValue_t HostFilesystem::removeDirectory(FilesystemParams params, bool deleteRecurively) { ReturnValue_t HostFilesystem::removeDirectory(const char *path, bool deleteRecurively,
if (params.path == nullptr) { FileSystemArgsIF *args) {
if (path == nullptr) {
return returnvalue::FAILED; return returnvalue::FAILED;
} }
path dirPath(params.path); std::filesystem::path dirPath(path);
std::error_code e; std::error_code e;
if (not exists(dirPath, e)) { if (not exists(dirPath, e)) {
return HasFileSystemIF::DIRECTORY_DOES_NOT_EXIST; return HasFileSystemIF::DIRECTORY_DOES_NOT_EXIST;
@ -153,14 +153,14 @@ ReturnValue_t HostFilesystem::rename(const char *oldPath_, const char *newPath_,
return returnvalue::OK; return returnvalue::OK;
} }
bool HostFilesystem::fileExists(FilesystemParams params) { bool HostFilesystem::fileExists(const char *path_, FileSystemArgsIF *args) {
path path(params.path); std::filesystem::path path(path_);
std::error_code e; std::error_code e;
return filesystem::exists(path, e); return filesystem::exists(path, e);
} }
ReturnValue_t HostFilesystem::truncateFile(FilesystemParams params) { ReturnValue_t HostFilesystem::truncateFile(const char *path_, FileSystemArgsIF *args) {
path path(params.path); std::filesystem::path path(path_);
std::error_code e; std::error_code e;
if (not filesystem::exists(path, e)) { if (not filesystem::exists(path, e)) {
return FILE_DOES_NOT_EXIST; return FILE_DOES_NOT_EXIST;
@ -170,12 +170,19 @@ ReturnValue_t HostFilesystem::truncateFile(FilesystemParams params) {
return returnvalue::OK; return returnvalue::OK;
} }
bool HostFilesystem::isDirectory(const char *path) { return filesystem::is_directory(path); } ReturnValue_t HostFilesystem::isDirectory(const char *path, bool &isDirectory) {
isDirectory = filesystem::is_directory(path);
return returnvalue::OK;
}
ReturnValue_t HostFilesystem::getBaseFilename(FilesystemParams params, char *nameBuf, size_t maxLen, ReturnValue_t HostFilesystem::getBaseFilename(const char *path, char *nameBuf, size_t maxLen,
size_t &baseNameLen) { size_t &baseNameLen) {
std::string path(params.path); std::string pathAsStr(path);
std::string baseName = path.substr(path.find_last_of("/\\") + 1); size_t lastPos = pathAsStr.find_last_of("/\\");
if (lastPos == std::string::npos) {
return returnvalue::FAILED;
}
std::string baseName = pathAsStr.substr(pathAsStr.find_last_of("/\\") + 1);
if (baseName.size() + 1 > maxLen) { if (baseName.size() + 1 > maxLen) {
return returnvalue::FAILED; return returnvalue::FAILED;
} }
@ -185,10 +192,11 @@ ReturnValue_t HostFilesystem::getBaseFilename(FilesystemParams params, char *nam
return returnvalue::OK; return returnvalue::OK;
} }
ReturnValue_t HostFilesystem::getFileSize(FilesystemParams params, uint64_t &fileSize) { ReturnValue_t HostFilesystem::getFileSize(const char *path, uint64_t &fileSize,
if (!fileExists(params)) { FileSystemArgsIF *args) {
if (!fileExists(path, args)) {
return HasFileSystemIF::FILE_DOES_NOT_EXIST; return HasFileSystemIF::FILE_DOES_NOT_EXIST;
} }
fileSize = std::filesystem::file_size(params.path); fileSize = std::filesystem::file_size(path);
return returnvalue::OK; return returnvalue::OK;
} }

View File

@ -9,19 +9,23 @@ class HostFilesystem : public HasFileSystemIF {
public: public:
HostFilesystem(); HostFilesystem();
ReturnValue_t getBaseFilename(FilesystemParams params, char *nameBuf, size_t maxLen, ReturnValue_t getBaseFilename(const char *path, char *nameBuf, size_t maxLen,
size_t &baseNameLen) override; size_t &baseNameLen) override;
virtual ReturnValue_t getFileSize(FilesystemParams params, uint64_t &fileSize) override; virtual ReturnValue_t getFileSize(const char *path, uint64_t &fileSize,
bool isDirectory(const char *path) override; FileSystemArgsIF *args) override;
bool fileExists(FilesystemParams params) override; ReturnValue_t isDirectory(const char *path, bool &isDirectory) override;
ReturnValue_t truncateFile(FilesystemParams params) override; bool fileExists(const char *path, FileSystemArgsIF *args) override;
ReturnValue_t writeToFile(FileOpParams params, const uint8_t *data) override; ReturnValue_t truncateFile(const char *path, FileSystemArgsIF *args) override;
ReturnValue_t readFromFile(FileOpParams fileOpInfo, uint8_t **buffer, size_t &readSize, ReturnValue_t writeToFile(const char *path, size_t offset, const uint8_t *data,
size_t maxSize) override; size_t size) override;
ReturnValue_t createFile(FilesystemParams params, const uint8_t *data, size_t size) override; ReturnValue_t readFromFile(const char *path, size_t offset, size_t sizeToRead, uint8_t *buffer,
size_t &actuallyRead, size_t maxSize) override;
ReturnValue_t createFile(const char *path, const uint8_t *data, size_t size) override;
ReturnValue_t removeFile(const char *path, FileSystemArgsIF *args) override; ReturnValue_t removeFile(const char *path, FileSystemArgsIF *args) override;
ReturnValue_t createDirectory(FilesystemParams params, bool createParentDirs) override; ReturnValue_t createDirectory(const char *path, bool createParentDirs,
ReturnValue_t removeDirectory(FilesystemParams params, bool deleteRecurively) override; FileSystemArgsIF *args) override;
ReturnValue_t removeDirectory(const char *path, bool deleteRecurively,
FileSystemArgsIF *args) override;
ReturnValue_t rename(const char *oldPath, const char *newPath, FileSystemArgsIF *args) override; ReturnValue_t rename(const char *oldPath, const char *newPath, FileSystemArgsIF *args) override;
std::error_code errorCode; std::error_code errorCode;

View File

@ -418,8 +418,8 @@ ReturnValue_t LinuxLibgpioIF::checkForConflictsById(gpioId_t gpioIdToCheck,
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LinuxLibgpioIF::checkForConflictsRegularGpio: Duplicate GPIO " sif::warning << "LinuxLibgpioIF::checkForConflictsRegularGpio: Duplicate GPIO "
"definition with ID " "definition with ID "
<< gpioIdToCheck << " detected. " << gpioIdToCheck << " detected. " << "Duplicate will be removed from map to add"
<< "Duplicate will be removed from map to add" << std::endl; << std::endl;
#else #else
sif::printWarning( sif::printWarning(
"LinuxLibgpioIF::checkForConflictsRegularGpio: Duplicate GPIO definition " "LinuxLibgpioIF::checkForConflictsRegularGpio: Duplicate GPIO definition "

View File

@ -49,8 +49,7 @@ ReturnValue_t I2cComIF::initializeInterface(CookieIF* cookie) {
if (not statusPair.second) { if (not statusPair.second) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "I2cComIF::initializeInterface: Failed to insert device with address " sif::error << "I2cComIF::initializeInterface: Failed to insert device with address "
<< i2cAddress << "to I2C device " << i2cAddress << "to I2C device " << "map" << std::endl;
<< "map" << std::endl;
#endif #endif
return returnvalue::FAILED; return returnvalue::FAILED;
} }
@ -91,8 +90,8 @@ ReturnValue_t I2cComIF::sendMessage(CookieIF* cookie, const uint8_t* sendData, s
auto i2cDeviceMapIter = i2cDeviceMap.find(i2cAddress); auto i2cDeviceMapIter = i2cDeviceMap.find(i2cAddress);
if (i2cDeviceMapIter == i2cDeviceMap.end()) { if (i2cDeviceMapIter == i2cDeviceMap.end()) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "I2cComIF::sendMessage: i2cAddress of Cookie not " sif::error << "I2cComIF::sendMessage: i2cAddress of Cookie not " << "registered in i2cDeviceMap"
<< "registered in i2cDeviceMap" << std::endl; << std::endl;
#endif #endif
return returnvalue::FAILED; return returnvalue::FAILED;
} }

View File

@ -197,9 +197,8 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
if (result == MutexIF::MUTEX_TIMEOUT) { if (result == MutexIF::MUTEX_TIMEOUT) {
sif::error << "SpiComIF::sendMessage: Lock timeout" << std::endl; sif::error << "SpiComIF::sendMessage: Lock timeout" << std::endl;
} else { } else {
sif::error << "SpiComIF::sendMessage: Failed to lock mutex with code " sif::error << "SpiComIF::sendMessage: Failed to lock mutex with code " << "0x" << std::hex
<< "0x" << std::hex << std::setfill('0') << std::setw(4) << result << std::dec << std::setfill('0') << std::setw(4) << result << std::dec << std::endl;
<< std::endl;
} }
#else #else
sif::printError("SpiComIF::sendMessage: Failed to lock mutex with code %d\n", result); sif::printError("SpiComIF::sendMessage: Failed to lock mutex with code %d\n", result);
@ -307,9 +306,8 @@ ReturnValue_t SpiComIF::performHalfDuplexReception(SpiCookie* spiCookie) {
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "SpiComIF::sendMessage: Failed to lock mutex with code " sif::error << "SpiComIF::sendMessage: Failed to lock mutex with code " << "0x" << std::hex
<< "0x" << std::hex << std::setfill('0') << std::setw(4) << result << std::dec << std::setfill('0') << std::setw(4) << result << std::dec << std::endl;
<< std::endl;
#else #else
sif::printError("SpiComIF::sendMessage: Failed to lock mutex with code %d\n", result); sif::printError("SpiComIF::sendMessage: Failed to lock mutex with code %d\n", result);
#endif #endif

View File

@ -1,6 +1,7 @@
target_sources( target_sources(
${FSFW_TEST_TGT} PRIVATE testCfdp.cpp testOtherTlvs.cpp ${FSFW_TEST_TGT}
testReservedMsgCreator.cpp testTlv.cpp testLvs.cpp) PRIVATE testCfdp.cpp testOtherTlvs.cpp testReservedMsgCreator.cpp testTlv.cpp
testLvs.cpp PduSenderMock.cpp)
add_subdirectory(handler) add_subdirectory(handler)
add_subdirectory(pdu) add_subdirectory(pdu)

View File

@ -0,0 +1 @@
#include "PduSenderMock.h"

View File

@ -0,0 +1,36 @@
#pragma once
#include <deque>
#include <vector>
#include "fsfw/cfdp/handler/PduSenderIF.h"
struct SentPdu {
cfdp::PduType pduType;
std::optional<cfdp::FileDirective> fileDirective;
std::vector<uint8_t> rawPdu;
};
class PduSenderMock : public cfdp::PduSenderIF {
public:
ReturnValue_t sendPdu(cfdp::PduType pduType, std::optional<cfdp::FileDirective> fileDirective,
const uint8_t* pdu, size_t pduSize) override {
SentPdu sentPdu;
sentPdu.pduType = pduType;
sentPdu.fileDirective = fileDirective;
sentPdu.rawPdu = std::vector(pdu, pdu + pduSize);
sentPdus.push_back(sentPdu);
return returnvalue::OK;
}
std::optional<SentPdu> getNextSentPacket() {
if (sentPdus.empty()) {
return std::nullopt;
}
SentPdu nextPdu = sentPdus.front();
sentPdus.pop_front();
return nextPdu;
}
std::deque<SentPdu> sentPdus;
};

View File

@ -0,0 +1,31 @@
#pragma once
#include <optional>
#include <vector>
#include "fsfw/cfdp/definitions.h"
#include "fsfw/cfdp/handler/PduPacketIF.h"
namespace cfdp {
class OwnedPduPacket : public PduPacketIF {
public:
OwnedPduPacket(PduType pduType, std::optional<FileDirective> fileDirective, const uint8_t* rawPdu,
size_t pduLen)
: pduType(pduType), fileDirective(fileDirective), rawPdu(rawPdu, rawPdu + pduLen) {}
[[nodiscard]] cfdp::PduType getPduType() const override { return pduType; };
[[nodiscard]] std::optional<cfdp::FileDirective> getFileDirective() const override {
return fileDirective;
};
[[nodiscard]] const uint8_t* getRawPduData(size_t& pduLen) const override {
pduLen = rawPdu.size();
return rawPdu.data();
}
PduType pduType;
std::optional<FileDirective> fileDirective;
std::vector<uint8_t> rawPdu;
};
} // namespace cfdp

View File

@ -4,6 +4,8 @@
#include <random> #include <random>
#include <utility> #include <utility>
#include "OwnedPduPacket.h"
#include "cfdp/PduSenderMock.h"
#include "fsfw/cfdp.h" #include "fsfw/cfdp.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"
@ -23,60 +25,49 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
MessageQueueId_t destQueueId = 2; MessageQueueId_t destQueueId = 2;
AcceptsTmMock tmReceiver(destQueueId); AcceptsTmMock tmReceiver(destQueueId);
MessageQueueMock mqMock(destQueueId); MessageQueueMock mqMock(destQueueId);
EntityId localId = EntityId(UnsignedByteField<uint16_t>(2)); auto localId = EntityId(UnsignedByteField<uint16_t>(2));
EntityId remoteId = EntityId(UnsignedByteField<uint16_t>(3)); auto remoteId = EntityId(UnsignedByteField<uint16_t>(3));
FaultHandlerMock fhMock; FaultHandlerMock fhMock;
LocalEntityCfg localEntityCfg(localId, IndicationCfg(), fhMock); LocalEntityCfg localEntityCfg(localId, IndicationCfg(), fhMock);
FilesystemMock fsMock; FilesystemMock fsMock;
UserMock userMock(fsMock); UserMock userMock(fsMock);
RemoteConfigTableMock remoteCfgTableMock; RemoteConfigTableMock remoteCfgTableMock;
PacketInfoList<64> packetInfoList;
LostSegmentsList<128> lostSegmentsList; LostSegmentsList<128> lostSegmentsList;
DestHandlerParams dp(localEntityCfg, userMock, remoteCfgTableMock, packetInfoList, DestHandlerParams dp(localEntityCfg, userMock, remoteCfgTableMock, lostSegmentsList);
lostSegmentsList);
EventReportingProxyMock eventReporterMock; EventReportingProxyMock eventReporterMock;
LocalPool::LocalPoolConfig storeCfg = {{10, 32}, {10, 64}, {10, 128}, {10, 1024}}; LocalPool::LocalPoolConfig storeCfg = {{10, 32}, {10, 64}, {10, 128}, {10, 1024}};
StorageManagerMock tcStore(2, storeCfg); PduSenderMock senderMock;
StorageManagerMock tmStore(3, storeCfg); FsfwParams fp(&eventReporterMock);
FsfwParams fp(tmReceiver, &mqMock, &eventReporterMock);
RemoteEntityCfg cfg(remoteId); RemoteEntityCfg cfg(remoteId);
remoteCfgTableMock.addRemoteConfig(cfg); remoteCfgTableMock.addRemoteConfig(cfg);
fp.tcStore = &tcStore; std::array<uint8_t, 4096> pduBuf{};
fp.tmStore = &tmStore;
uint8_t* buf = nullptr;
size_t serLen = 0; size_t serLen = 0;
store_address_t storeId; store_address_t storeId;
PduConfig conf; PduConfig conf;
auto destHandler = DestHandler(dp, fp); auto destHandler = DestHandler(senderMock, 4096, dp, fp);
CHECK(destHandler.initialize() == OK);
auto metadataPreparation = [&](Fss cfdpFileSize, ChecksumType checksumType) { auto metadataPreparation = [&](Fss cfdpFileSize, ChecksumType checksumType) {
std::string srcNameString = "hello.txt"; const std::string srcNameString = "hello.txt";
std::string destNameString = "hello-cpy.txt"; const std::string destNameString = "hello-cpy.txt";
StringLv srcName(srcNameString); StringLv srcName(srcNameString);
StringLv destName(destNameString); StringLv destName(destNameString);
MetadataGenericInfo info(false, checksumType, std::move(cfdpFileSize)); MetadataGenericInfo info(false, checksumType, std::move(cfdpFileSize));
TransactionSeqNum seqNum(UnsignedByteField<uint16_t>(1)); const TransactionSeqNum seqNum(UnsignedByteField<uint16_t>(1));
conf.sourceId = remoteId; conf.sourceId = remoteId;
conf.destId = localId; conf.destId = localId;
conf.mode = TransmissionMode::UNACKNOWLEDGED; conf.mode = TransmissionMode::UNACKNOWLEDGED;
conf.seqNum = seqNum; conf.seqNum = seqNum;
MetadataPduCreator metadataCreator(conf, info, srcName, destName, nullptr, 0); const MetadataPduCreator metadataCreator(conf, info, srcName, destName, nullptr, 0);
REQUIRE(tcStore.getFreeElement(&storeId, metadataCreator.getSerializedSize(), &buf) == OK); REQUIRE(metadataCreator.serialize(pduBuf.data(), serLen, metadataCreator.getSerializedSize()) ==
REQUIRE(metadataCreator.serialize(buf, serLen, metadataCreator.getSerializedSize()) == OK); OK);
PacketInfo packetInfo(metadataCreator.getPduType(), storeId, return OwnedPduPacket(metadataCreator.getPduType(), metadataCreator.getDirectiveCode(),
metadataCreator.getDirectiveCode()); pduBuf.data(), serLen);
packetInfoList.push_back(packetInfo);
}; };
auto metadataCheck = [&](const cfdp::DestHandler::FsmResult& res, const char* sourceName, auto metadataCheck = [&](const cfdp::DestHandler::FsmResult& res, const char* sourceName,
const char* destName, size_t fileLen) { const char* destName, size_t fileLen) {
REQUIRE(res.result == OK); REQUIRE(res.result == OK);
REQUIRE(res.callStatus == CallStatus::CALL_AGAIN);
REQUIRE(res.errors == 0); 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); REQUIRE(userMock.metadataRecvd.size() == 1);
auto& idMetadataPair = userMock.metadataRecvd.back(); auto& idMetadataPair = userMock.metadataRecvd.back();
REQUIRE(idMetadataPair.first == destHandler.getTransactionId()); REQUIRE(idMetadataPair.first == destHandler.getTransactionId());
@ -94,10 +85,10 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
auto eofPreparation = [&](Fss cfdpFileSize, uint32_t crc) { auto eofPreparation = [&](Fss cfdpFileSize, uint32_t crc) {
EofInfo eofInfo(cfdp::ConditionCode::NO_ERROR, crc, std::move(cfdpFileSize)); EofInfo eofInfo(cfdp::ConditionCode::NO_ERROR, crc, std::move(cfdpFileSize));
EofPduCreator eofCreator(conf, eofInfo); EofPduCreator eofCreator(conf, eofInfo);
REQUIRE(tcStore.getFreeElement(&storeId, eofCreator.getSerializedSize(), &buf) == OK); REQUIRE(eofCreator.serialize(pduBuf.data(), serLen, eofCreator.getSerializedSize()) == OK);
REQUIRE(eofCreator.serialize(buf, serLen, eofCreator.getSerializedSize()) == OK); OwnedPduPacket packet(eofCreator.getPduType(), eofCreator.getDirectiveCode(), pduBuf.data(),
PacketInfo packetInfo(eofCreator.getPduType(), storeId, eofCreator.getDirectiveCode()); serLen);
packetInfoList.push_back(packetInfo); return packet;
}; };
auto eofCheck = [&](const cfdp::DestHandler::FsmResult& res, const TransactionId& id) { auto eofCheck = [&](const cfdp::DestHandler::FsmResult& res, const TransactionId& id) {
@ -105,9 +96,6 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
REQUIRE(res.state == CfdpState::IDLE); REQUIRE(res.state == CfdpState::IDLE);
REQUIRE(res.errors == 0); REQUIRE(res.errors == 0);
REQUIRE(res.step == DestHandler::TransactionStep::IDLE); REQUIRE(res.step == DestHandler::TransactionStep::IDLE);
// Assert that the packet was deleted after handling
REQUIRE(not tcStore.hasDataAtId(storeId));
REQUIRE(packetInfoList.empty());
REQUIRE(userMock.eofRecvdRecvd.size() == 1); REQUIRE(userMock.eofRecvdRecvd.size() == 1);
auto& eofId = userMock.eofRecvdRecvd.back(); auto& eofId = userMock.eofRecvdRecvd.back();
CHECK(eofId == id); CHECK(eofId == id);
@ -122,10 +110,6 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
REQUIRE(res.result == OK); REQUIRE(res.result == OK);
REQUIRE(res.state == CfdpState::BUSY_CLASS_1_NACKED); REQUIRE(res.state == CfdpState::BUSY_CLASS_1_NACKED);
REQUIRE(res.step == DestHandler::TransactionStep::RECEIVING_FILE_DATA_PDUS); REQUIRE(res.step == DestHandler::TransactionStep::RECEIVING_FILE_DATA_PDUS);
for (const auto id : idsToCheck) {
REQUIRE(not tcStore.hasDataAtId(id));
}
REQUIRE(packetInfoList.empty());
}; };
SECTION("State") { SECTION("State") {
@ -134,62 +118,59 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
} }
SECTION("Idle State Machine Iteration") { SECTION("Idle State Machine Iteration") {
auto res = destHandler.stateMachine(); auto [packetsSent, result, step, state, errors, errorCodes] =
CHECK(res.result == OK); destHandler.stateMachineNoPacket();
CHECK(res.callStatus == CallStatus::CALL_AFTER_DELAY); CHECK(result == OK);
CHECK(res.errors == 0); CHECK(errors == 0);
CHECK(destHandler.getCfdpState() == CfdpState::IDLE); CHECK(destHandler.getCfdpState() == CfdpState::IDLE);
CHECK(destHandler.getTransactionStep() == DestHandler::TransactionStep::IDLE); CHECK(destHandler.getTransactionStep() == DestHandler::TransactionStep::IDLE);
} }
SECTION("Empty File Transfer") { SECTION("Empty File Transfer") {
const DestHandler::FsmResult& res = destHandler.stateMachine(); const DestHandler::FsmResult& res = destHandler.stateMachineNoPacket();
CHECK(res.result == OK); CHECK(res.result == OK);
Fss cfdpFileSize(0); Fss cfdpFileSize(0);
metadataPreparation(cfdpFileSize, ChecksumType::NULL_CHECKSUM); auto packet = metadataPreparation(cfdpFileSize, ChecksumType::NULL_CHECKSUM);
destHandler.stateMachine(); destHandler.stateMachine(packet);
metadataCheck(res, "hello.txt", "hello-cpy.txt", 0); metadataCheck(res, "hello.txt", "hello-cpy.txt", 0);
destHandler.stateMachine(); destHandler.stateMachine(packet);
REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY); // REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY);
auto transactionId = destHandler.getTransactionId(); auto transactionId = destHandler.getTransactionId();
eofPreparation(cfdpFileSize, 0); auto ownedEofPacket = eofPreparation(cfdpFileSize, 0);
// After EOF, operation is done because no closure was requested // After EOF, operation is done because no closure was requested
destHandler.stateMachine(); destHandler.stateMachine(ownedEofPacket);
eofCheck(res, transactionId); eofCheck(res, transactionId);
} }
SECTION("Small File Transfer") { SECTION("Small File Transfer") {
const DestHandler::FsmResult& res = destHandler.stateMachine(); const DestHandler::FsmResult& res = destHandler.stateMachineNoPacket();
CHECK(res.result == OK); CHECK(res.result == OK);
std::string fileData = "hello test data"; std::string fileData = "hello test data";
etl::crc32 crcCalc; etl::crc32 crcCalc;
crcCalc.add(fileData.begin(), fileData.end()); crcCalc.add(fileData.begin(), fileData.end());
uint32_t crc32 = crcCalc.value(); uint32_t crc32 = crcCalc.value();
Fss cfdpFileSize(fileData.size()); Fss cfdpFileSize(fileData.size());
metadataPreparation(cfdpFileSize, ChecksumType::CRC_32); auto metadataPacket = metadataPreparation(cfdpFileSize, ChecksumType::CRC_32);
destHandler.stateMachine(); destHandler.stateMachine(metadataPacket);
metadataCheck(res, "hello.txt", "hello-cpy.txt", fileData.size()); metadataCheck(res, "hello.txt", "hello-cpy.txt", fileData.size());
destHandler.stateMachine(); destHandler.stateMachineNoPacket();
REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY);
auto transactionId = destHandler.getTransactionId(); auto transactionId = destHandler.getTransactionId();
Fss offset(0); Fss offset(0);
FileDataInfo fdPduInfo(offset, reinterpret_cast<const uint8_t*>(fileData.data()), FileDataInfo fdPduInfo(offset, reinterpret_cast<const uint8_t*>(fileData.data()),
fileData.size()); fileData.size());
FileDataCreator fdPduCreator(conf, fdPduInfo); FileDataCreator fdPduCreator(conf, fdPduInfo);
REQUIRE(tcStore.getFreeElement(&storeId, fdPduCreator.getSerializedSize(), &buf) == OK); REQUIRE(fdPduCreator.serialize(pduBuf.data(), serLen, fdPduCreator.getSerializedSize()) == OK);
REQUIRE(fdPduCreator.serialize(buf, serLen, fdPduCreator.getSerializedSize()) == OK); OwnedPduPacket fdPdu(fdPduCreator.getPduType(), std::nullopt, pduBuf.data(), serLen);
PacketInfo packetInfo(fdPduCreator.getPduType(), storeId, std::nullopt); destHandler.stateMachine(fdPdu);
packetInfoList.push_back(packetInfo);
destHandler.stateMachine();
fileDataPduCheck(res, {storeId}); fileDataPduCheck(res, {storeId});
eofPreparation(cfdpFileSize, crc32); auto eofPacket = eofPreparation(cfdpFileSize, crc32);
// After EOF, operation is done because no closure was requested // After EOF, operation is done because no closure was requested
destHandler.stateMachine(); destHandler.stateMachine(eofPacket);
eofCheck(res, transactionId); eofCheck(res, transactionId);
} }
SECTION("Segmented File Transfer") { SECTION("Segmented File Transfer") {
const DestHandler::FsmResult& res = destHandler.stateMachine(); const DestHandler::FsmResult& res = destHandler.stateMachineNoPacket();
CHECK(res.result == OK); CHECK(res.result == OK);
std::random_device dev; std::random_device dev;
std::mt19937 rng(dev()); std::mt19937 rng(dev());
@ -202,43 +183,40 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
crcCalc.add(largerFileData.begin(), largerFileData.end()); crcCalc.add(largerFileData.begin(), largerFileData.end());
uint32_t crc32 = crcCalc.value(); uint32_t crc32 = crcCalc.value();
Fss cfdpFileSize(largerFileData.size()); Fss cfdpFileSize(largerFileData.size());
metadataPreparation(cfdpFileSize, ChecksumType::CRC_32); auto metaPacket = metadataPreparation(cfdpFileSize, ChecksumType::CRC_32);
destHandler.stateMachine(); destHandler.stateMachine(metaPacket);
metadataCheck(res, "hello.txt", "hello-cpy.txt", largerFileData.size()); metadataCheck(res, "hello.txt", "hello-cpy.txt", largerFileData.size());
destHandler.stateMachine(); destHandler.stateMachineNoPacket();
REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY);
auto transactionId = destHandler.getTransactionId(); auto transactionId = destHandler.getTransactionId();
std::vector<store_address_t> idsToCheck; std::vector<store_address_t> idsToCheck;
{ {
Fss offset(0); Fss offset(0);
FileDataInfo fdPduInfo(offset, reinterpret_cast<const uint8_t*>(largerFileData.data()), FileDataInfo fdPduInfo(offset, (largerFileData.data()), largerFileData.size() / 2);
largerFileData.size() / 2);
FileDataCreator fdPduCreator(conf, fdPduInfo); FileDataCreator fdPduCreator(conf, fdPduInfo);
REQUIRE(tcStore.getFreeElement(&storeId, fdPduCreator.getSerializedSize(), &buf) == OK); REQUIRE(fdPduCreator.serialize(pduBuf.data(), serLen, fdPduCreator.getSerializedSize()) ==
REQUIRE(fdPduCreator.serialize(buf, serLen, fdPduCreator.getSerializedSize()) == OK); OK);
PacketInfo packetInfo(fdPduCreator.getPduType(), storeId, std::nullopt);
idsToCheck.push_back(storeId); idsToCheck.push_back(storeId);
packetInfoList.push_back(packetInfo); OwnedPduPacket fdPdu(fdPduCreator.getPduType(), std::nullopt, pduBuf.data(), serLen);
destHandler.stateMachine(fdPdu);
} }
{ {
Fss offset(512); Fss offset(512);
FileDataInfo fdPduInfo(offset, reinterpret_cast<const uint8_t*>(largerFileData.data() + 512), FileDataInfo fdPduInfo(offset, largerFileData.data() + 512, largerFileData.size() / 2);
largerFileData.size() / 2);
FileDataCreator fdPduCreator(conf, fdPduInfo); FileDataCreator fdPduCreator(conf, fdPduInfo);
REQUIRE(tcStore.getFreeElement(&storeId, fdPduCreator.getSerializedSize(), &buf) == OK); REQUIRE(fdPduCreator.serialize(pduBuf.data(), serLen, fdPduCreator.getSerializedSize()) ==
REQUIRE(fdPduCreator.serialize(buf, serLen, fdPduCreator.getSerializedSize()) == OK); OK);
PacketInfo packetInfo(fdPduCreator.getPduType(), storeId, std::nullopt);
idsToCheck.push_back(storeId); idsToCheck.push_back(storeId);
packetInfoList.push_back(packetInfo); OwnedPduPacket fdPdu(fdPduCreator.getPduType(), std::nullopt, pduBuf.data(), serLen);
destHandler.stateMachine(fdPdu);
} }
destHandler.stateMachine(); destHandler.stateMachineNoPacket();
fileDataPduCheck(res, idsToCheck); fileDataPduCheck(res, idsToCheck);
eofPreparation(cfdpFileSize, crc32); auto eofPacket = eofPreparation(cfdpFileSize, crc32);
// After EOF, operation is done because no closure was requested // After EOF, operation is done because no closure was requested
destHandler.stateMachine(); destHandler.stateMachine(eofPacket);
eofCheck(res, transactionId); eofCheck(res, transactionId);
} }
} }

View File

@ -1,3 +1,4 @@
#include <array>
#include <catch2/catch_test_macros.hpp> #include <catch2/catch_test_macros.hpp>
#include "fsfw/cfdp/CfdpMessage.h" #include "fsfw/cfdp/CfdpMessage.h"

View File

@ -4,6 +4,7 @@
#include <filesystem> #include <filesystem>
#include <random> #include <random>
#include "cfdp/PduSenderMock.h"
#include "fsfw/cfdp.h" #include "fsfw/cfdp.h"
#include "fsfw/cfdp/handler/PutRequest.h" #include "fsfw/cfdp/handler/PutRequest.h"
#include "fsfw/cfdp/handler/SourceHandler.h" #include "fsfw/cfdp/handler/SourceHandler.h"
@ -27,13 +28,13 @@ TEST_CASE("CFDP Source Handler", "[cfdp]") {
using namespace cfdp; using namespace cfdp;
using namespace returnvalue; using namespace returnvalue;
using namespace std::filesystem; using namespace std::filesystem;
const size_t MAX_FILE_SEGMENT_SIZE = 255; constexpr size_t MAX_FILE_SEGMENT_SIZE = 255;
MessageQueueId_t destQueueId = 2; MessageQueueId_t destQueueId = 2;
AcceptsTmMock tmReceiver(destQueueId); AcceptsTmMock tmReceiver(destQueueId);
MessageQueueMock mqMock(destQueueId); // MessageQueueMock mqMock(destQueueId);
EntityId localId = EntityId(UnsignedByteField<uint16_t>(2)); auto localId = EntityId(UnsignedByteField<uint16_t>(2));
EntityId remoteId = EntityId(UnsignedByteField<uint16_t>(5)); auto remoteId = EntityId(UnsignedByteField<uint16_t>(5));
FaultHandlerMock fhMock; FaultHandlerMock fhMock;
LocalEntityCfg localEntityCfg(localId, IndicationCfg(), fhMock); LocalEntityCfg localEntityCfg(localId, IndicationCfg(), fhMock);
FilesystemMock fsMock; FilesystemMock fsMock;
@ -41,49 +42,37 @@ TEST_CASE("CFDP Source Handler", "[cfdp]") {
SeqCountProviderU16 seqCountProvider; SeqCountProviderU16 seqCountProvider;
SourceHandlerParams dp(localEntityCfg, userMock, seqCountProvider); SourceHandlerParams dp(localEntityCfg, userMock, seqCountProvider);
PduSenderMock pduSender;
EventReportingProxyMock eventReporterMock; EventReportingProxyMock eventReporterMock;
LocalPool::LocalPoolConfig storeCfg = {{10, 32}, {10, 64}, {10, 128}, {10, 1024}}; LocalPool::LocalPoolConfig storeCfg = {{10, 32}, {10, 64}, {10, 128}, {10, 1024}};
StorageManagerMock tcStore(2, storeCfg); FsfwParams fp(&eventReporterMock);
StorageManagerMock tmStore(3, storeCfg); auto sourceHandler = SourceHandler(pduSender, 4096, dp, fp);
FsfwParams fp(tmReceiver, &mqMock, &eventReporterMock);
fp.tcStore = &tcStore;
fp.tmStore = &tmStore;
auto sourceHandler = SourceHandler(dp, fp);
RemoteEntityCfg cfg; RemoteEntityCfg cfg;
cfg.maxFileSegmentLen = MAX_FILE_SEGMENT_SIZE; cfg.maxFileSegmentLen = MAX_FILE_SEGMENT_SIZE;
cfg.remoteId = remoteId; cfg.remoteId = remoteId;
std::string srcFileName = "/tmp/cfdp-test.txt"; std::string srcFileName = "/tmp/cfdp-test.txt";
std::string destFileName = "/tmp/cfdp-test2.txt"; std::string destFileName = "/tmp/cfdp-test2.txt";
FilesystemParams srcFileNameFs(srcFileName.c_str()); fsMock.createFile(srcFileName.c_str());
fsMock.createFile(srcFileNameFs); cfdp::StringLv srcNameLv(srcFileName.c_str(), srcFileName.length());
cfdp::StringLv srcNameLv(srcFileNameFs.path, std::strlen(srcFileNameFs.path));
FilesystemParams destFileNameFs(destFileName.c_str()); FilesystemParams destFileNameFs(destFileName.c_str());
cfdp::StringLv destNameLv(destFileNameFs.path, std::strlen(destFileNameFs.path)); cfdp::StringLv destNameLv(destFileNameFs.path, std::strlen(destFileNameFs.path));
PutRequest putRequest(remoteId, srcNameLv, destNameLv); PutRequest putRequest(remoteId, srcNameLv, destNameLv);
CHECK(sourceHandler.initialize() == OK); CHECK(sourceHandler.initialize() == OK);
auto onePduSentCheck = [&](const SourceHandler::FsmResult& fsmResult, TmTcMessage& tmtcMessage, auto onePduSentCheck = [&](const SourceHandler::FsmResult& fsmResult) {
const uint8_t** pduPtr) {
CHECK(fsmResult.errors == 0); CHECK(fsmResult.errors == 0);
CHECK(fsmResult.packetsSent == 1); CHECK(fsmResult.packetsSent == 1);
CHECK(mqMock.numberOfSentMessages() == 1);
REQUIRE(mqMock.getNextSentMessage(destQueueId, tmtcMessage) == OK);
auto accessor = tmStore.getData(tmtcMessage.getStorageId());
REQUIRE(accessor.first == OK);
*pduPtr = accessor.second.data();
return std::move(accessor);
}; };
auto genericMetadataCheck = [&](const SourceHandler::FsmResult& fsmResult, auto genericMetadataCheck = [&](const SourceHandler::FsmResult& fsmResult,
size_t expectedFileSize, uint16_t expectedSeqNum) { size_t expectedFileSize, uint16_t expectedSeqNum) {
CHECK(fsmResult.errors == 0); CHECK(fsmResult.errors == 0);
CHECK(fsmResult.callStatus == CallStatus::CALL_AGAIN); auto optNextPacket = pduSender.getNextSentPacket();
TmTcMessage tmtcMessage; CHECK(optNextPacket.has_value());
const uint8_t* pduPtr; const auto& [pduType, fileDirective, rawPdu] = *optNextPacket;
auto accessor = onePduSentCheck(fsmResult, tmtcMessage, &pduPtr); CHECK(rawPdu.size() == 55);
CHECK(accessor.second.size() == 55);
MetadataGenericInfo metadataInfo; MetadataGenericInfo metadataInfo;
MetadataPduReader metadataReader(pduPtr, accessor.second.size(), metadataInfo, nullptr, 0); MetadataPduReader metadataReader(rawPdu.data(), rawPdu.size(), metadataInfo, nullptr, 0);
REQUIRE(metadataReader.parseData() == OK); REQUIRE(metadataReader.parseData() == OK);
std::string srcNameRead = metadataReader.getSourceFileName().getString(); std::string srcNameRead = metadataReader.getSourceFileName().getString();
CHECK(srcNameRead == srcFileName); CHECK(srcNameRead == srcFileName);
@ -107,20 +96,19 @@ TEST_CASE("CFDP Source Handler", "[cfdp]") {
} }
CHECK(metadataInfo.getFileSize().value() == expectedFileSize); CHECK(metadataInfo.getFileSize().value() == expectedFileSize);
CHECK(!metadataInfo.isClosureRequested()); CHECK(!metadataInfo.isClosureRequested());
mqMock.clearMessages();
}; };
auto genericEofCheck = [&](const SourceHandler::FsmResult& fsmResult, size_t expectedFileSize, auto genericEofCheck = [&](const SourceHandler::FsmResult& fsmResult, size_t expectedFileSize,
uint32_t expectedChecksum, uint16_t expectedSeqNum) { uint32_t expectedChecksum, uint16_t expectedSeqNum) {
CHECK(fsmResult.errors == 0); onePduSentCheck(fsmResult);
CHECK(fsmResult.callStatus == CallStatus::CALL_AGAIN);
TmTcMessage tmtcMessage; TmTcMessage tmtcMessage;
const uint8_t* pduPtr; auto optNextPacket = pduSender.getNextSentPacket();
auto accessor = onePduSentCheck(fsmResult, tmtcMessage, &pduPtr); CHECK(optNextPacket.has_value());
const auto& [pduType, fileDirective, rawPdu] = *optNextPacket;
// 10 byte PDU header, 1 byte directive field, 1 byte condition code, 4 byte checksum, // 10 byte PDU header, 1 byte directive field, 1 byte condition code, 4 byte checksum,
// 4 byte FSS // 4 byte FSS
CHECK(accessor.second.size() == 20); CHECK(rawPdu.size() == 20);
EofInfo eofInfo; EofInfo eofInfo;
EofPduReader eofReader(pduPtr, accessor.second.size(), eofInfo); EofPduReader eofReader(rawPdu.data(), rawPdu.size(), eofInfo);
REQUIRE(eofReader.parseData() == OK); REQUIRE(eofReader.parseData() == OK);
TransactionSeqNum seqNum; TransactionSeqNum seqNum;
eofReader.getTransactionSeqNum(seqNum); eofReader.getTransactionSeqNum(seqNum);
@ -133,8 +121,7 @@ TEST_CASE("CFDP Source Handler", "[cfdp]") {
CHECK(eofInfo.getFileSize().value() == expectedFileSize); CHECK(eofInfo.getFileSize().value() == expectedFileSize);
}; };
auto genericNoticeOfCompletionCheck = [&](const SourceHandler::FsmResult& fsmResult, auto genericNoticeOfCompletionCheck = [&](const SourceHandler::FsmResult& fsmResult,
uint16_t expectedSeqNum) { const uint16_t expectedSeqNum) {
CHECK(fsmResult.callStatus == CallStatus::DONE);
CHECK(userMock.finishedRecvd.size() == 1); CHECK(userMock.finishedRecvd.size() == 1);
CHECK(userMock.finishedRecvd.back().first == CHECK(userMock.finishedRecvd.back().first ==
TransactionId(localId, TransactionSeqNum(cfdp::WidthInBytes::TWO_BYTES, expectedSeqNum))); TransactionId(localId, TransactionSeqNum(cfdp::WidthInBytes::TWO_BYTES, expectedSeqNum)));
@ -151,41 +138,43 @@ TEST_CASE("CFDP Source Handler", "[cfdp]") {
CHECK(sourceHandler.transactionStart(putRequest, cfg) == OK); CHECK(sourceHandler.transactionStart(putRequest, cfg) == OK);
size_t expectedFileSize = 0; size_t expectedFileSize = 0;
const SourceHandler::FsmResult& fsmResult = sourceHandler.stateMachine(); const SourceHandler::FsmResult& fsmResult = sourceHandler.stateMachineNoPacket();
// Verify metadata PDU was sent. // Verify metadata PDU was sent.
genericMetadataCheck(fsmResult, expectedFileSize, 0); genericMetadataCheck(fsmResult, expectedFileSize, 0);
sourceHandler.stateMachine(); sourceHandler.stateMachineNoPacket();
// Verify EOF PDU was sent. No file data PDU is sent for an empty file and the checksum is 0. // 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); genericEofCheck(fsmResult, expectedFileSize, 0, 0);
// Verify notice of completion. // Verify notice of completion.
sourceHandler.stateMachine(); sourceHandler.stateMachineNoPacket();
genericNoticeOfCompletionCheck(fsmResult, 0); genericNoticeOfCompletionCheck(fsmResult, 0);
} }
SECTION("Transfer small file") { SECTION("Transfer small file") {
uint16_t expectedSeqNum = 0; uint16_t expectedSeqNum = 0;
fsMock.createFile(srcFileNameFs); fsMock.createFile(srcFileName.c_str());
std::string fileContent = "hello world\n"; std::string fileContent = "hello world\n";
size_t expectedFileSize = fileContent.size(); size_t expectedFileSize = fileContent.size();
FileOpParams params(srcFileName.c_str(), expectedFileSize); fsMock.writeToFile(srcFileName.c_str(), 0, reinterpret_cast<const uint8_t*>(fileContent.data()),
fsMock.writeToFile(params, reinterpret_cast<const uint8_t*>(fileContent.data())); expectedFileSize);
CHECK(sourceHandler.transactionStart(putRequest, cfg) == OK); CHECK(sourceHandler.transactionStart(putRequest, cfg) == OK);
const SourceHandler::FsmResult& fsmResult = sourceHandler.stateMachine(); const SourceHandler::FsmResult& fsmResult = sourceHandler.stateMachineNoPacket();
// Verify metadata PDU was sent. // Verify metadata PDU was sent.
genericMetadataCheck(fsmResult, expectedFileSize, expectedSeqNum); genericMetadataCheck(fsmResult, expectedFileSize, expectedSeqNum);
// Verify that a small file data PDU was sent. // Verify that a small file data PDU was sent.
sourceHandler.stateMachine(); sourceHandler.stateMachineNoPacket();
TmTcMessage tmtcMessage;
const uint8_t* pduPtr; onePduSentCheck(fsmResult);
auto accessor = onePduSentCheck(fsmResult, tmtcMessage, &pduPtr); auto optNextPacket = pduSender.getNextSentPacket();
CHECK(optNextPacket.has_value());
const auto& [pduType, fileDirective, rawPdu] = *optNextPacket;
FileDataInfo fdInfo; FileDataInfo fdInfo;
FileDataReader fdReader(pduPtr, accessor.second.size(), fdInfo); FileDataReader fdReader(rawPdu.data(), rawPdu.size(), fdInfo);
// 10 byte PDU header, 4 byte offset, 12 bytes file data. // 10 byte PDU header, 4 byte offset, 12 bytes file data.
CHECK(accessor.second.size() == 26); CHECK(rawPdu.size() == 26);
CHECK(fdReader.parseData() == OK); CHECK(fdReader.parseData() == OK);
CHECK(fdInfo.getOffset().value() == 0); CHECK(fdInfo.getOffset().value() == 0);
size_t fileSize = 0; size_t fileSize = 0;
@ -194,9 +183,8 @@ TEST_CASE("CFDP Source Handler", "[cfdp]") {
CHECK(fileData != nullptr); CHECK(fileData != nullptr);
std::string dataReadBack(reinterpret_cast<const char*>(fileData), fileSize); std::string dataReadBack(reinterpret_cast<const char*>(fileData), fileSize);
CHECK(dataReadBack == fileContent); CHECK(dataReadBack == fileContent);
mqMock.clearMessages();
sourceHandler.stateMachine(); sourceHandler.stateMachineNoPacket();
etl::crc32 crcCalc; etl::crc32 crcCalc;
crcCalc.add(fileContent.data(), fileContent.data() + fileContent.size()); crcCalc.add(fileContent.data(), fileContent.data() + fileContent.size());
@ -204,7 +192,7 @@ TEST_CASE("CFDP Source Handler", "[cfdp]") {
genericEofCheck(fsmResult, expectedFileSize, crcCalc.value(), expectedSeqNum); genericEofCheck(fsmResult, expectedFileSize, crcCalc.value(), expectedSeqNum);
// Verify notice of completion. // Verify notice of completion.
sourceHandler.stateMachine(); sourceHandler.stateMachineNoPacket();
genericNoticeOfCompletionCheck(fsmResult, expectedSeqNum); genericNoticeOfCompletionCheck(fsmResult, expectedSeqNum);
} }
@ -220,25 +208,26 @@ TEST_CASE("CFDP Source Handler", "[cfdp]") {
val = distU8(rng); val = distU8(rng);
} }
size_t expectedFileSize = largerFileData.size(); size_t expectedFileSize = largerFileData.size();
fsMock.createFile(srcFileNameFs); fsMock.createFile(srcFileName.c_str());
FileOpParams params(srcFileName.c_str(), expectedFileSize); fsMock.writeToFile(srcFileName.c_str(), 0, largerFileData.data(), largerFileData.size());
fsMock.writeToFile(params, reinterpret_cast<const uint8_t*>(largerFileData.data()));
CHECK(sourceHandler.transactionStart(putRequest, cfg) == OK); CHECK(sourceHandler.transactionStart(putRequest, cfg) == OK);
const SourceHandler::FsmResult& fsmResult = sourceHandler.stateMachine(); const SourceHandler::FsmResult& fsmResult = sourceHandler.stateMachineNoPacket();
// Verify metadata PDU was sent. // Verify metadata PDU was sent.
genericMetadataCheck(fsmResult, expectedFileSize, expectedSeqNum); genericMetadataCheck(fsmResult, expectedFileSize, expectedSeqNum);
// Check first file data PDU. It should have the maximum file segment size. // Check first file data PDU. It should have the maximum file segment size.
sourceHandler.stateMachine(); sourceHandler.stateMachineNoPacket();
TmTcMessage tmtcMessage;
const uint8_t* pduPtr; onePduSentCheck(fsmResult);
auto optNextPacket = pduSender.getNextSentPacket();
CHECK(optNextPacket.has_value());
const auto& [pduType, fileDirective, rawPdu] = *optNextPacket;
FileDataInfo fdInfo; FileDataInfo fdInfo;
{ {
CHECK(fsmResult.callStatus == CallStatus::CALL_AGAIN); // auto accessor = onePduSentCheck(fsmResult, tmtcMessage, &pduPtr);
auto accessor = onePduSentCheck(fsmResult, tmtcMessage, &pduPtr); FileDataReader fdReader(rawPdu.data(), rawPdu.size(), fdInfo);
FileDataReader fdReader(pduPtr, accessor.second.size(), fdInfo);
// 10 byte PDU header, 4 byte offset, 255 byte file data // 10 byte PDU header, 4 byte offset, 255 byte file data
CHECK(accessor.second.size() == 269); CHECK(rawPdu.size() == 269);
CHECK(fdReader.parseData() == OK); CHECK(fdReader.parseData() == OK);
CHECK(fdInfo.getOffset().value() == 0); CHECK(fdInfo.getOffset().value() == 0);
size_t fileSize = 0; size_t fileSize = 0;
@ -249,16 +238,16 @@ TEST_CASE("CFDP Source Handler", "[cfdp]") {
CHECK(fileData[i] == largerFileData[i]); CHECK(fileData[i] == largerFileData[i]);
} }
} }
mqMock.clearMessages();
// Check second file data PDU. // Check second file data PDU.
sourceHandler.stateMachine(); sourceHandler.stateMachineNoPacket();
{ {
CHECK(fsmResult.callStatus == CallStatus::CALL_AGAIN); optNextPacket = pduSender.getNextSentPacket();
auto accessor = onePduSentCheck(fsmResult, tmtcMessage, &pduPtr); CHECK(optNextPacket.has_value());
FileDataReader fdReader(pduPtr, accessor.second.size(), fdInfo); const auto& [pduType, fileDirective, rawPdu] = *optNextPacket;
FileDataReader fdReader(rawPdu.data(), rawPdu.size(), fdInfo);
// 10 byte PDU header, 4 byte offset, remaining file data (400 - 255 == 145). // 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(rawPdu.size() == 10 + 4 + largerFileData.size() - MAX_FILE_SEGMENT_SIZE);
CHECK(fdReader.parseData() == OK); CHECK(fdReader.parseData() == OK);
CHECK(fdInfo.getOffset().value() == MAX_FILE_SEGMENT_SIZE); CHECK(fdInfo.getOffset().value() == MAX_FILE_SEGMENT_SIZE);
size_t fileDataSize = 0; size_t fileDataSize = 0;
@ -269,10 +258,9 @@ TEST_CASE("CFDP Source Handler", "[cfdp]") {
CHECK(fileData[i] == largerFileData[MAX_FILE_SEGMENT_SIZE + i]); CHECK(fileData[i] == largerFileData[MAX_FILE_SEGMENT_SIZE + i]);
} }
} }
mqMock.clearMessages();
// Check EOF and verify checksum. // Check EOF and verify checksum.
sourceHandler.stateMachine(); sourceHandler.stateMachineNoPacket();
etl::crc32 crcCalc; etl::crc32 crcCalc;
crcCalc.add(largerFileData.data(), largerFileData.data() + largerFileData.size()); crcCalc.add(largerFileData.data(), largerFileData.data() + largerFileData.size());
@ -280,7 +268,7 @@ TEST_CASE("CFDP Source Handler", "[cfdp]") {
genericEofCheck(fsmResult, expectedFileSize, crcCalc.value(), expectedSeqNum); genericEofCheck(fsmResult, expectedFileSize, crcCalc.value(), expectedSeqNum);
// Verify notice of completion. // Verify notice of completion.
sourceHandler.stateMachine(); sourceHandler.stateMachineNoPacket();
genericNoticeOfCompletionCheck(fsmResult, expectedSeqNum); genericNoticeOfCompletionCheck(fsmResult, expectedSeqNum);
} }
} }

View File

@ -4,7 +4,7 @@
#include "fsfw/cfdp/pdu/FinishedInfo.h" #include "fsfw/cfdp/pdu/FinishedInfo.h"
#include "fsfw/cfdp/pdu/FinishedPduCreator.h" #include "fsfw/cfdp/pdu/FinishedPduCreator.h"
#include "fsfw/cfdp/pdu/HeaderCreator.h" #include "fsfw/cfdp/pdu/HeaderCreator.h"
#include "fsfw/cfdp/pdu/PduHeaderReader.h" #include "fsfw/cfdp/pdu/HeaderReader.h"
#include "fsfw/returnvalues/returnvalue.h" #include "fsfw/returnvalues/returnvalue.h"
using namespace returnvalue; using namespace returnvalue;

View File

@ -10,7 +10,7 @@ TEST_CASE("Filesystem Mock", "[mocks]") {
SECTION("Create File") { SECTION("Create File") {
FilesystemParams params("hello.txt"); FilesystemParams params("hello.txt");
CHECK(fsMock.createFile(params) == returnvalue::OK); CHECK(fsMock.createFile("hello.txt") == returnvalue::OK);
auto iter = fsMock.fileMap.find("hello.txt"); auto iter = fsMock.fileMap.find("hello.txt");
REQUIRE(iter != fsMock.fileMap.end()); REQUIRE(iter != fsMock.fileMap.end());
FilesystemMock::FileInfo &stats = iter->second; FilesystemMock::FileInfo &stats = iter->second;
@ -21,8 +21,8 @@ TEST_CASE("Filesystem Mock", "[mocks]") {
SECTION("Write to File") { SECTION("Write to File") {
std::string testData = "test data"; std::string testData = "test data";
FileOpParams params("hello.txt", testData.size()); FileOpParams params("hello.txt", testData.size());
CHECK(fsMock.writeToFile(params, reinterpret_cast<const uint8_t *>(testData.data())) == CHECK(fsMock.writeToFile("hello.txt", 0, reinterpret_cast<const uint8_t *>(testData.data()),
returnvalue::OK); testData.size()) == returnvalue::OK);
auto iter = fsMock.fileMap.find("hello.txt"); auto iter = fsMock.fileMap.find("hello.txt");
REQUIRE(iter != fsMock.fileMap.end()); REQUIRE(iter != fsMock.fileMap.end());
FilesystemMock::FileInfo &stats = iter->second; FilesystemMock::FileInfo &stats = iter->second;
@ -38,7 +38,7 @@ TEST_CASE("Filesystem Mock", "[mocks]") {
SECTION("Create Directory") { SECTION("Create Directory") {
FilesystemParams params("hello"); FilesystemParams params("hello");
CHECK(fsMock.createDirectory(params) == returnvalue::OK); CHECK(fsMock.createDirectory("hello") == returnvalue::OK);
REQUIRE(not fsMock.dirMap.empty()); REQUIRE(not fsMock.dirMap.empty());
auto iter = fsMock.dirMap.find("hello"); auto iter = fsMock.dirMap.find("hello");
REQUIRE(iter != fsMock.dirMap.end()); REQUIRE(iter != fsMock.dirMap.end());

View File

@ -25,15 +25,13 @@ TEST_CASE("Host Filesystem", "[hal][host]") {
REQUIRE_NOTHROW(fs::remove_all(dir0)); REQUIRE_NOTHROW(fs::remove_all(dir0));
SECTION("Create file") { SECTION("Create file") {
FilesystemParams params(file0.c_str()); REQUIRE(hostFs.createFile(file0.c_str()) == returnvalue::OK);
REQUIRE(hostFs.createFile(params) == returnvalue::OK);
CHECK(fs::is_regular_file(file0)); CHECK(fs::is_regular_file(file0));
REQUIRE(fs::exists(file0)); REQUIRE(fs::exists(file0));
} }
SECTION("Remove File") { SECTION("Remove File") {
FilesystemParams params(file0.c_str()); REQUIRE(hostFs.createFile(file0.c_str()) == returnvalue::OK);
REQUIRE(hostFs.createFile(params) == returnvalue::OK);
CHECK(fs::is_regular_file(file0)); CHECK(fs::is_regular_file(file0));
REQUIRE(fs::exists(file0)); REQUIRE(fs::exists(file0));
REQUIRE(hostFs.removeFile(file0.c_str()) == returnvalue::OK); REQUIRE(hostFs.removeFile(file0.c_str()) == returnvalue::OK);
@ -41,23 +39,20 @@ TEST_CASE("Host Filesystem", "[hal][host]") {
} }
SECTION("Create Directory") { SECTION("Create Directory") {
FilesystemParams params(dir0.c_str()); REQUIRE(hostFs.createDirectory(dir0.c_str()) == returnvalue::OK);
REQUIRE(hostFs.createDirectory(params) == returnvalue::OK);
CHECK(fs::is_directory(dir0)); CHECK(fs::is_directory(dir0));
REQUIRE(fs::exists(dir0)); REQUIRE(fs::exists(dir0));
} }
SECTION("Remove Directory") { SECTION("Remove Directory") {
FilesystemParams params(dir0.c_str()); REQUIRE(hostFs.createDirectory(dir0.c_str()) == returnvalue::OK);
REQUIRE(hostFs.createDirectory(params) == returnvalue::OK);
REQUIRE(fs::exists(dir0)); REQUIRE(fs::exists(dir0));
REQUIRE(hostFs.removeDirectory(params) == returnvalue::OK); REQUIRE(hostFs.removeDirectory(dir0.c_str(), false, nullptr) == returnvalue::OK);
REQUIRE(not fs::exists(dir0)); REQUIRE(not fs::exists(dir0));
} }
SECTION("Rename File") { SECTION("Rename File") {
FilesystemParams params(file0.c_str()); REQUIRE(hostFs.createFile(file0.c_str()) == returnvalue::OK);
REQUIRE(hostFs.createFile(params) == returnvalue::OK);
CHECK(fs::is_regular_file(file0)); CHECK(fs::is_regular_file(file0));
REQUIRE(fs::exists(file0)); REQUIRE(fs::exists(file0));
REQUIRE(hostFs.rename(file0.c_str(), file1.c_str()) == returnvalue::OK); REQUIRE(hostFs.rename(file0.c_str(), file1.c_str()) == returnvalue::OK);
@ -65,12 +60,11 @@ TEST_CASE("Host Filesystem", "[hal][host]") {
SECTION("Write To File") { SECTION("Write To File") {
std::string data = "hello world!"; std::string data = "hello world!";
FileOpParams params(file0.c_str(), data.size()); REQUIRE(hostFs.createFile(file0.c_str()) == returnvalue::OK);
REQUIRE(hostFs.createFile(params.fsParams) == returnvalue::OK);
CHECK(fs::is_regular_file(file0)); CHECK(fs::is_regular_file(file0));
REQUIRE(fs::exists(file0)); REQUIRE(fs::exists(file0));
CHECK(hostFs.writeToFile(params, reinterpret_cast<const uint8_t*>(data.c_str())) == CHECK(hostFs.writeToFile(file0.c_str(), 0, reinterpret_cast<const uint8_t*>(data.c_str()),
returnvalue::OK); data.size()) == returnvalue::OK);
CHECK(fs::file_size(file0) == data.size()); CHECK(fs::file_size(file0) == data.size());
ifstream ifile(file0); ifstream ifile(file0);
std::array<char, 524> readBuf{}; std::array<char, 524> readBuf{};
@ -87,14 +81,13 @@ TEST_CASE("Host Filesystem", "[hal][host]") {
for (uint8_t& byte : randData) { for (uint8_t& byte : randData) {
byte = distU8(rng); byte = distU8(rng);
} }
FileOpParams params(file0.c_str(), randData.size() - 256); REQUIRE(hostFs.createFile(file0.c_str()) == returnvalue::OK);
REQUIRE(hostFs.createFile(params.fsParams) == returnvalue::OK);
CHECK(fs::is_regular_file(file0)); CHECK(fs::is_regular_file(file0));
REQUIRE(fs::exists(file0)); REQUIRE(fs::exists(file0));
// Write first file chunk // Write first file chunk
CHECK(hostFs.writeToFile(params, randData.cbegin()) == returnvalue::OK); CHECK(hostFs.writeToFile(file0.c_str(), 0, randData.cbegin(), randData.size() - 256) ==
params.offset = 256; returnvalue::OK);
CHECK(hostFs.writeToFile(params, randData.cbegin() + 256) == returnvalue::OK); CHECK(hostFs.writeToFile(file0.c_str(), 256, randData.cbegin() + 256, 256) == returnvalue::OK);
std::ifstream rf(file0, ios::binary); std::ifstream rf(file0, ios::binary);
std::array<uint8_t, 512> readBack{}; std::array<uint8_t, 512> readBack{};
REQUIRE(std::filesystem::file_size(file0) == 512); REQUIRE(std::filesystem::file_size(file0) == 512);
@ -106,8 +99,7 @@ TEST_CASE("Host Filesystem", "[hal][host]") {
SECTION("Read From File") { SECTION("Read From File") {
std::string data = "hello world!"; std::string data = "hello world!";
FileOpParams params(file0.c_str(), data.size()); REQUIRE(hostFs.createFile(file0.c_str()) == returnvalue::OK);
REQUIRE(hostFs.createFile(params.fsParams) == returnvalue::OK);
CHECK(fs::is_regular_file(file0)); CHECK(fs::is_regular_file(file0));
ofstream of(file0); ofstream of(file0);
of.write(data.c_str(), static_cast<unsigned int>(data.size())); of.write(data.c_str(), static_cast<unsigned int>(data.size()));
@ -116,8 +108,10 @@ TEST_CASE("Host Filesystem", "[hal][host]") {
REQUIRE(fs::exists(file0)); REQUIRE(fs::exists(file0));
std::array<uint8_t, 256> readBuf{}; std::array<uint8_t, 256> readBuf{};
uint8_t* readPtr = readBuf.data(); uint8_t* readPtr = readBuf.data();
size_t readSize = 0; size_t readSize = data.size();
CHECK(hostFs.readFromFile(params, &readPtr, readSize, readBuf.size()) == returnvalue::OK); size_t actuallyRead = 0;
CHECK(hostFs.readFromFile(file0.c_str(), 0, readSize, readPtr, actuallyRead, readBuf.size()) ==
returnvalue::OK);
std::string readBackString(reinterpret_cast<const char*>(readBuf.data())); std::string readBackString(reinterpret_cast<const char*>(readBuf.data()));
CHECK(readSize == data.size()); CHECK(readSize == data.size());
CHECK(data == readBackString); CHECK(data == readBackString);
@ -125,21 +119,21 @@ TEST_CASE("Host Filesystem", "[hal][host]") {
SECTION("Invalid Input does not crash") { SECTION("Invalid Input does not crash") {
FileOpParams params(nullptr, 10); FileOpParams params(nullptr, 10);
REQUIRE(hostFs.createFile(params.fsParams) != returnvalue::OK); REQUIRE(hostFs.createFile(nullptr) != returnvalue::OK);
REQUIRE(hostFs.createDirectory(params.fsParams) != returnvalue::OK); REQUIRE(hostFs.createDirectory(nullptr) != returnvalue::OK);
REQUIRE(hostFs.createFile(params.fsParams) != returnvalue::OK); REQUIRE(hostFs.createFile(nullptr) != returnvalue::OK);
REQUIRE(hostFs.removeDirectory(params.fsParams) != returnvalue::OK); REQUIRE(hostFs.removeDirectory(nullptr, false, nullptr) != returnvalue::OK);
REQUIRE(hostFs.removeFile(nullptr) != returnvalue::OK); REQUIRE(hostFs.removeFile(nullptr) != returnvalue::OK);
REQUIRE(hostFs.rename(nullptr, nullptr) != returnvalue::OK); REQUIRE(hostFs.rename(nullptr, nullptr) != returnvalue::OK);
REQUIRE(hostFs.writeToFile(params, nullptr) != returnvalue::OK); REQUIRE(hostFs.writeToFile(nullptr, 0, nullptr, 0) != returnvalue::OK);
size_t readLen = 0; size_t readLen = 0;
REQUIRE(hostFs.readFromFile(params, nullptr, readLen, 20) != returnvalue::OK); REQUIRE(hostFs.readFromFile(nullptr, 0, 0, nullptr, readLen, 20) != returnvalue::OK);
} }
SECTION("Create File but already exists") { SECTION("Create File but already exists") {
FilesystemParams params(file0.c_str()); FilesystemParams params(file0.c_str());
REQUIRE(hostFs.createFile(params) == returnvalue::OK); REQUIRE(hostFs.createFile(file0.c_str()) == returnvalue::OK);
REQUIRE(hostFs.createFile(params) == HasFileSystemIF::FILE_ALREADY_EXISTS); REQUIRE(hostFs.createFile(file0.c_str()) == HasFileSystemIF::FILE_ALREADY_EXISTS);
} }
SECTION("Remove File but does not exist") { SECTION("Remove File but does not exist") {
@ -148,36 +142,35 @@ TEST_CASE("Host Filesystem", "[hal][host]") {
SECTION("Create Directory but already exists") { SECTION("Create Directory but already exists") {
FileOpParams params(file0.c_str(), 12); FileOpParams params(file0.c_str(), 12);
REQUIRE(hostFs.createDirectory(params.fsParams) == returnvalue::OK); REQUIRE(hostFs.createDirectory(file0.c_str()) == returnvalue::OK);
REQUIRE(hostFs.createDirectory(params.fsParams) == HasFileSystemIF::DIRECTORY_ALREADY_EXISTS); REQUIRE(hostFs.createDirectory(file0.c_str()) == HasFileSystemIF::DIRECTORY_ALREADY_EXISTS);
} }
SECTION("Remove Directory but does not exist") { SECTION("Remove Directory but does not exist") {
FilesystemParams params(dir0.c_str()); FilesystemParams params(dir0.c_str());
REQUIRE(hostFs.removeDirectory(params) == HasFileSystemIF::DIRECTORY_DOES_NOT_EXIST); REQUIRE(hostFs.removeDirectory(dir0.c_str(), false, nullptr) ==
HasFileSystemIF::DIRECTORY_DOES_NOT_EXIST);
} }
SECTION("Remove Directory but is file") { SECTION("Remove Directory but is file") {
ofstream of(file0); ofstream of(file0);
FilesystemParams params(file0.c_str()); REQUIRE(hostFs.removeDirectory(file0.c_str(), false, nullptr) ==
REQUIRE(hostFs.removeDirectory(params) == HasFileSystemIF::NOT_A_DIRECTORY); HasFileSystemIF::NOT_A_DIRECTORY);
} }
SECTION("Read from file but does not exist") { SECTION("Read from file but does not exist") {
std::string data = "hello world!"; std::string data = "hello world!";
FileOpParams params(file0.c_str(), data.size()); std::array<uint8_t, 16> readBuf{};
std::array<uint8_t, 10> readBuf{};
uint8_t* readPtr = readBuf.data(); uint8_t* readPtr = readBuf.data();
size_t readSize = 0; size_t readSize = 0;
CHECK(hostFs.readFromFile(params, &readPtr, readSize, readBuf.size()) == CHECK(hostFs.readFromFile(file0.c_str(), 0, data.size(), readPtr, readSize, readBuf.size()) ==
HasFileSystemIF::FILE_DOES_NOT_EXIST); HasFileSystemIF::FILE_DOES_NOT_EXIST);
} }
SECTION("Write to file but does not exist") { SECTION("Write to file but does not exist") {
std::string data = "hello world!"; std::string data = "hello world!";
FileOpParams params(file0.c_str(), data.size()); CHECK(hostFs.writeToFile(file0.c_str(), 0, reinterpret_cast<const uint8_t*>(data.c_str()),
CHECK(hostFs.writeToFile(params, reinterpret_cast<const uint8_t*>(data.c_str())) == data.size()) == HasFileSystemIF::FILE_DOES_NOT_EXIST);
HasFileSystemIF::FILE_DOES_NOT_EXIST);
} }
SECTION("Remove recursively") { SECTION("Remove recursively") {
@ -185,7 +178,7 @@ TEST_CASE("Host Filesystem", "[hal][host]") {
ofstream of(fileInDir0); ofstream of(fileInDir0);
CHECK(fs::is_directory(dir0)); CHECK(fs::is_directory(dir0));
CHECK(fs::is_regular_file(fileInDir0)); CHECK(fs::is_regular_file(fileInDir0));
REQUIRE(hostFs.removeDirectory(FilesystemParams(dir0.c_str()), true) == returnvalue::OK); REQUIRE(hostFs.removeDirectory(dir0.c_str(), true, nullptr) == returnvalue::OK);
CHECK(not fs::is_directory(dir0)); CHECK(not fs::is_directory(dir0));
CHECK(not fs::is_regular_file(fileInDir0)); CHECK(not fs::is_regular_file(fileInDir0));
} }
@ -195,12 +188,12 @@ TEST_CASE("Host Filesystem", "[hal][host]") {
ofstream of(fileInDir0); ofstream of(fileInDir0);
CHECK(fs::is_directory(dir0)); CHECK(fs::is_directory(dir0));
CHECK(fs::is_regular_file(fileInDir0)); CHECK(fs::is_regular_file(fileInDir0));
REQUIRE(hostFs.removeDirectory(FilesystemParams(dir0.c_str())) == REQUIRE(hostFs.removeDirectory(dir0.c_str(), false, nullptr) ==
HasFileSystemIF::DIRECTORY_NOT_EMPTY); HasFileSystemIF::DIRECTORY_NOT_EMPTY);
} }
SECTION("Create directory with parent directory") { SECTION("Create directory with parent directory") {
CHECK(hostFs.createDirectory(FilesystemParams(dirWithParent.c_str()), true) == returnvalue::OK); CHECK(hostFs.createDirectory(dirWithParent.c_str(), true, nullptr) == returnvalue::OK);
CHECK(fs::is_directory(dir0)); CHECK(fs::is_directory(dir0));
CHECK(fs::is_directory(dirWithParent)); CHECK(fs::is_directory(dirWithParent));
} }
@ -216,10 +209,9 @@ TEST_CASE("Host Filesystem", "[hal][host]") {
std::array<uint8_t, 15> readBuf{}; std::array<uint8_t, 15> readBuf{};
uint8_t* readPtr = readBuf.data(); uint8_t* readPtr = readBuf.data();
size_t readSize = 0; size_t readSize = 0;
CHECK(hostFs.readFromFile(params, &readPtr, readSize, 5) == SerializeIF::BUFFER_TOO_SHORT); CHECK(hostFs.readFromFile(file0.c_str(), 0, data.size(), readPtr, readSize, 5) ==
readSize = 10;
CHECK(hostFs.readFromFile(params, &readPtr, readSize, readBuf.size()) ==
SerializeIF::BUFFER_TOO_SHORT); SerializeIF::BUFFER_TOO_SHORT);
;
} }
REQUIRE_NOTHROW(fs::remove(file0)); REQUIRE_NOTHROW(fs::remove(file0));

View File

@ -4,9 +4,7 @@
DeviceHandlerMock::DeviceHandlerMock(object_id_t objectId, object_id_t deviceCommunication, DeviceHandlerMock::DeviceHandlerMock(object_id_t objectId, object_id_t deviceCommunication,
CookieIF *comCookie, FailureIsolationBase *fdirInstance) CookieIF *comCookie, FailureIsolationBase *fdirInstance)
: DeviceHandlerBase(objectId, deviceCommunication, comCookie, fdirInstance) { : DeviceHandlerBase(objectId, deviceCommunication, comCookie, fdirInstance) {}
setMode(MODE_ON);
}
DeviceHandlerMock::~DeviceHandlerMock() = default; DeviceHandlerMock::~DeviceHandlerMock() = default;
@ -101,3 +99,12 @@ ReturnValue_t DeviceHandlerMock::enablePeriodicReply(DeviceCommandId_t replyId)
ReturnValue_t DeviceHandlerMock::disablePeriodicReply(DeviceCommandId_t replyId) { ReturnValue_t DeviceHandlerMock::disablePeriodicReply(DeviceCommandId_t replyId) {
return updatePeriodicReply(false, replyId); return updatePeriodicReply(false, replyId);
} }
ReturnValue_t DeviceHandlerMock::initialize() {
ReturnValue_t result = DeviceHandlerBase::initialize();
if (result != returnvalue::OK) {
return result;
}
setMode(MODE_ON);
return result;
}

View File

@ -21,6 +21,8 @@ class DeviceHandlerMock : public DeviceHandlerBase {
ReturnValue_t enablePeriodicReply(DeviceCommandId_t replyId); ReturnValue_t enablePeriodicReply(DeviceCommandId_t replyId);
ReturnValue_t disablePeriodicReply(DeviceCommandId_t replyId); ReturnValue_t disablePeriodicReply(DeviceCommandId_t replyId);
ReturnValue_t initialize() override;
protected: protected:
void doStartUp() override; void doStartUp() override;
void doShutDown() override; void doShutDown() override;

View File

@ -1,5 +1,6 @@
#include "FilesystemMock.h" #include "FilesystemMock.h"
#include <cstring>
#include <filesystem> #include <filesystem>
#include "fsfw/serialize/SerializeIF.h" #include "fsfw/serialize/SerializeIF.h"
@ -12,45 +13,42 @@ ReturnValue_t FilesystemMock::feedFile(const std::string &filename, std::ifstrea
FileOpParams params(filename.c_str(), fileSize); FileOpParams params(filename.c_str(), fileSize);
std::vector<uint8_t> rawData(fileSize); std::vector<uint8_t> rawData(fileSize);
file.read(reinterpret_cast<char*>(rawData.data()), static_cast<unsigned int>(rawData.size())); file.read(reinterpret_cast<char*>(rawData.data()), static_cast<unsigned int>(rawData.size()));
createOrAddToFile(params, rawData.data()); createOrAddToFile(filename.data(), 0, rawData.data(), rawData.size());
return returnvalue::OK; return returnvalue::OK;
} }
ReturnValue_t FilesystemMock::writeToFile(FileOpParams params, const uint8_t *data) { ReturnValue_t FilesystemMock::writeToFile(const char* path, size_t offset, const uint8_t* data,
createOrAddToFile(params, data); size_t size) {
createOrAddToFile(path, offset, data, size);
return returnvalue::OK; return returnvalue::OK;
} }
ReturnValue_t FilesystemMock::readFromFile(FileOpParams params, uint8_t **buffer, size_t &readSize, ReturnValue_t FilesystemMock::readFromFile(const char* path, size_t offset, size_t size,
size_t maxSize) { uint8_t* buffer, size_t& readSize, size_t maxSize) {
std::string filename(params.path()); const std::string filename(path);
auto iter = fileMap.find(filename); const auto iter = fileMap.find(filename);
if (iter == fileMap.end()) { if (iter == fileMap.end()) {
return HasFileSystemIF::FILE_DOES_NOT_EXIST; return HasFileSystemIF::FILE_DOES_NOT_EXIST;
} else { }
FileInfo &info = iter->second; auto& [fileSegQueue, fileRaw] = iter->second;
size_t readLen = params.size; size_t readLen = size;
if (params.offset + params.size > info.fileRaw.size()) { if (offset + size > fileRaw.size()) {
if (params.offset > info.fileRaw.size()) { if (offset > fileRaw.size()) {
return returnvalue::OK; return returnvalue::OK;
} }
readLen = info.fileRaw.size() - params.offset; readLen = fileRaw.size() - offset;
} }
if (readSize + readLen > maxSize) { if (readSize + readLen > maxSize) {
return SerializeIF::STREAM_TOO_SHORT; return SerializeIF::STREAM_TOO_SHORT;
} }
std::copy(info.fileRaw.data() + params.offset, info.fileRaw.data() + params.offset + readLen, // std::copy(info.fileRaw.data() + offset, info.fileRaw.data() + offset + readLen, *buffer);
*buffer); std::memcpy(buffer, fileRaw.data() + offset, readLen);
*buffer += readLen; readSize = readLen;
readSize += readLen;
}
return returnvalue::OK; return returnvalue::OK;
} }
ReturnValue_t FilesystemMock::createFile(FilesystemParams params, const uint8_t *data, ReturnValue_t FilesystemMock::createFile(const char* path, const uint8_t* data, size_t size) {
size_t size) { createOrAddToFile(path, 0, data, size);
FileOpParams params2(params.path, size);
createOrAddToFile(params2, data);
return returnvalue::OK; return returnvalue::OK;
} }
@ -65,15 +63,17 @@ ReturnValue_t FilesystemMock::removeFile(const char *path, FileSystemArgsIF *arg
} }
} }
ReturnValue_t FilesystemMock::createDirectory(FilesystemParams params, bool createParentDirs) { ReturnValue_t FilesystemMock::createDirectory(const char* path, bool createParentDirs,
std::string dirPath = params.path; FileSystemArgsIF* args) {
std::string dirPath = path;
dirMap[dirPath].createCallCount++; dirMap[dirPath].createCallCount++;
dirMap[dirPath].wihParentDir.push(createParentDirs); dirMap[dirPath].wihParentDir.push(createParentDirs);
return returnvalue::OK; return returnvalue::OK;
} }
ReturnValue_t FilesystemMock::removeDirectory(FilesystemParams params, bool deleteRecurively) { ReturnValue_t FilesystemMock::removeDirectory(const char* path, bool deleteRecurively,
std::string dirPath = params.path; FileSystemArgsIF* args) {
std::string dirPath = path;
dirMap[dirPath].delCallCount++; dirMap[dirPath].delCallCount++;
dirMap[dirPath].recursiveDeletion.push(deleteRecurively); dirMap[dirPath].recursiveDeletion.push(deleteRecurively);
return returnvalue::OK; return returnvalue::OK;
@ -85,36 +85,36 @@ ReturnValue_t FilesystemMock::rename(const char *oldPath, const char *newPath,
return returnvalue::OK; return returnvalue::OK;
} }
void FilesystemMock::createOrAddToFile(FileOpParams params, const uint8_t *data) { void FilesystemMock::createOrAddToFile(const char* path, size_t offset, const uint8_t* data,
std::string filename(params.path()); size_t dataSize) {
std::string filename(path);
auto iter = fileMap.find(filename); auto iter = fileMap.find(filename);
if (iter == fileMap.end()) { if (iter == fileMap.end()) {
FileSegmentQueue queue; FileSegmentQueue queue;
if (params.size > 0) { if (dataSize > 0) {
queue.emplace(filename, params.offset, data, params.size); queue.emplace(filename, offset, data, dataSize);
} }
FileInfo info; FileInfo info;
info.fileSegQueue = queue; info.fileSegQueue = queue;
if (data != nullptr) { if (data != nullptr) {
info.fileRaw.insert(info.fileRaw.end(), data, data + params.size); info.fileRaw.insert(info.fileRaw.end(), data, data + dataSize);
} }
fileMap.emplace(filename, info); fileMap.emplace(filename, info);
} else { } else {
FileInfo& info = iter->second; FileInfo& info = iter->second;
info.fileSegQueue.emplace(filename, params.offset, data, params.size); info.fileSegQueue.emplace(filename, offset, data, dataSize);
if (data == nullptr) { if (data == nullptr) {
return; return;
} }
// Easiest case: append data to the end // Easiest case: append data to the end
if (params.offset == info.fileRaw.size()) { if (offset == info.fileRaw.size()) {
info.fileRaw.insert(info.fileRaw.end(), data, data + params.size); info.fileRaw.insert(info.fileRaw.end(), data, data + dataSize);
} else { } else {
size_t totalNewLen = params.offset + params.size; size_t totalNewLen = offset + dataSize;
if (totalNewLen > info.fileRaw.size()) { if (totalNewLen > info.fileRaw.size()) {
info.fileRaw.resize(params.offset + params.size); info.fileRaw.resize(offset + dataSize);
} }
std::copy(data, data + params.size, std::copy(data, data + dataSize, info.fileRaw.begin() + static_cast<unsigned int>(offset));
info.fileRaw.begin() + static_cast<unsigned int>(params.offset));
} }
} }
} }
@ -126,8 +126,8 @@ void FilesystemMock::reset() {
std::swap(renameQueue, empty); std::swap(renameQueue, empty);
} }
bool FilesystemMock::fileExists(FilesystemParams params) { bool FilesystemMock::fileExists(const char* path, FileSystemArgsIF* args) {
std::string filename(params.path); std::string filename(path);
auto iter = fileMap.find(filename); auto iter = fileMap.find(filename);
if (iter == fileMap.end()) { if (iter == fileMap.end()) {
return false; return false;
@ -135,20 +135,21 @@ bool FilesystemMock::fileExists(FilesystemParams params) {
return true; return true;
} }
ReturnValue_t FilesystemMock::truncateFile(FilesystemParams params) { ReturnValue_t FilesystemMock::truncateFile(const char* path, FileSystemArgsIF* args) {
truncateCalledOnFile = params.path; truncateCalledOnFile = path;
return returnvalue::OK; return returnvalue::OK;
} }
ReturnValue_t FilesystemMock::getBaseFilename(FilesystemParams params, char *nameBuf, size_t maxLen, ReturnValue_t FilesystemMock::getBaseFilename(const char* path, char* nameBuf, size_t maxLen,
size_t& baseNameLen) { size_t& baseNameLen) {
return returnvalue::OK; return returnvalue::OK;
} }
bool FilesystemMock::isDirectory(const char *path) { return false; } ReturnValue_t FilesystemMock::isDirectory(const char* path, bool& isDirectory) { return false; }
bool FilesystemMock::getFileSize(FilesystemParams params, size_t &fileSize) { ReturnValue_t FilesystemMock::getFileSize(const char* path, uint64_t& fileSize,
std::string filename(params.path); FileSystemArgsIF* args) {
std::string filename(path);
auto iter = fileMap.find(filename); auto iter = fileMap.find(filename);
if (iter != fileMap.end()) { if (iter != fileMap.end()) {
fileSize = iter->second.fileRaw.size(); fileSize = iter->second.fileRaw.size();

View File

@ -56,21 +56,31 @@ class FilesystemMock : public HasFileSystemIF {
std::string truncateCalledOnFile; std::string truncateCalledOnFile;
ReturnValue_t feedFile(const std::string& filename, std::ifstream& file); ReturnValue_t feedFile(const std::string& filename, std::ifstream& file);
ReturnValue_t getBaseFilename(FilesystemParams params, char *nameBuf, size_t maxLen, ReturnValue_t getBaseFilename(const char* path, char* nameBuf, size_t maxLen,
size_t& baseNameLen) override; size_t& baseNameLen) override;
bool isDirectory(const char *path) override; ReturnValue_t isDirectory(const char* path, bool& isDirectory) override;
bool fileExists(FilesystemParams params) override;
ReturnValue_t truncateFile(FilesystemParams params) override;
bool getFileSize(FilesystemParams params, size_t &fileSize) override;
ReturnValue_t writeToFile(FileOpParams params, const uint8_t *data) override; bool fileExists(const char* path, FileSystemArgsIF* args) override;
ReturnValue_t readFromFile(FileOpParams params, uint8_t **buffer, size_t &readSize,
size_t maxSize) override; ReturnValue_t truncateFile(const char* path, FileSystemArgsIF* args) override;
ReturnValue_t createFile(FilesystemParams params, const uint8_t *data, size_t size) override;
ReturnValue_t getFileSize(const char* path, uint64_t& fileSize, FileSystemArgsIF* args) override;
ReturnValue_t writeToFile(const char* path, size_t offset, const uint8_t* data,
size_t size) override;
ReturnValue_t readFromFile(const char* path, size_t offset, size_t size, uint8_t* buffer,
size_t& readSize, size_t maxSize) override;
ReturnValue_t createFile(const char* path, const uint8_t* data, size_t size) override;
ReturnValue_t removeFile(const char* path, FileSystemArgsIF* args) override; ReturnValue_t removeFile(const char* path, FileSystemArgsIF* args) override;
ReturnValue_t createDirectory(FilesystemParams params, bool createParentDirs) override;
ReturnValue_t removeDirectory(FilesystemParams params, bool deleteRecurively) override; ReturnValue_t createDirectory(const char* path, bool createParentDirs,
FileSystemArgsIF* args) override;
ReturnValue_t removeDirectory(const char* path, bool deleteRecurively,
FileSystemArgsIF* args) override;
ReturnValue_t rename(const char* oldPath, const char* newPath, FileSystemArgsIF* args) override; ReturnValue_t rename(const char* oldPath, const char* newPath, FileSystemArgsIF* args) override;
void reset(); void reset();
@ -80,7 +90,7 @@ class FilesystemMock : public HasFileSystemIF {
using HasFileSystemIF::readFromFile; using HasFileSystemIF::readFromFile;
private: private:
void createOrAddToFile(FileOpParams params, const uint8_t *data); void createOrAddToFile(const char* path, size_t offset, const uint8_t* data, size_t dataSize);
}; };
#endif // FSFW_MOCKS_FILESYSTEMMOCK_H #endif // FSFW_MOCKS_FILESYSTEMMOCK_H

View File

@ -82,13 +82,15 @@ TEST_CASE("CCSDS Creator", "[ccsds-creator]") {
CHECK(buf[5] == 0xFF); CHECK(buf[5] == 0xFF);
} }
SECTION("Setting data length 0 is ignored") { SECTION("Setting data length 0") {
SpacePacketCreator creator = SpacePacketCreator( SpacePacketCreator creator = SpacePacketCreator(
ccsds::PacketType::TC, true, 0xFFFF, ccsds::SequenceFlags::FIRST_SEGMENT, 0x34, 0x22); ccsds::PacketType::TC, true, 0xFFFF, ccsds::SequenceFlags::FIRST_SEGMENT, 0x34, 0x22);
creator.setCcsdsLenFromTotalDataFieldLen(0); creator.setCcsdsLenFromTotalDataFieldLen(0);
REQUIRE(creator.getPacketDataLen() == 0x22); // Will result in field length 0.
REQUIRE(creator.getPacketDataLen() == 0);
// Will also result in field length 0.
creator.setCcsdsLenFromTotalDataFieldLen(1); creator.setCcsdsLenFromTotalDataFieldLen(1);
REQUIRE(creator.getPacketDataLen() == 0x00); REQUIRE(creator.getPacketDataLen() == 0);
} }
SECTION("Invalid APID") { SECTION("Invalid APID") {