removed handlers
This commit is contained in:
parent
ac7dc55fc1
commit
3a52454949
@ -2,7 +2,6 @@
|
|||||||
#define FSFW_CFDP_H
|
#define FSFW_CFDP_H
|
||||||
|
|
||||||
#include "cfdp/definitions.h"
|
#include "cfdp/definitions.h"
|
||||||
#include "cfdp/handler/DestHandler.h"
|
|
||||||
#include "cfdp/handler/FaultHandlerBase.h"
|
#include "cfdp/handler/FaultHandlerBase.h"
|
||||||
#include "cfdp/tlv/Lv.h"
|
#include "cfdp/tlv/Lv.h"
|
||||||
#include "cfdp/tlv/StringLv.h"
|
#include "cfdp/tlv/StringLv.h"
|
||||||
|
@ -1,2 +1 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE SourceHandler.cpp DestHandler.cpp
|
target_sources(${LIB_FSFW_NAME} PRIVATE FaultHandlerBase.cpp UserBase.cpp)
|
||||||
FaultHandlerBase.cpp UserBase.cpp)
|
|
||||||
|
@ -1,480 +0,0 @@
|
|||||||
#include "DestHandler.h"
|
|
||||||
|
|
||||||
#include <etl/crc32.h>
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "fsfw/FSFW.h"
|
|
||||||
#include "fsfw/cfdp/pdu/EofPduReader.h"
|
|
||||||
#include "fsfw/cfdp/pdu/FileDataReader.h"
|
|
||||||
#include "fsfw/cfdp/pdu/FinishedPduCreator.h"
|
|
||||||
#include "fsfw/cfdp/pdu/PduHeaderReader.h"
|
|
||||||
#include "fsfw/objectmanager.h"
|
|
||||||
#include "fsfw/tmtcservices/TmTcMessage.h"
|
|
||||||
|
|
||||||
using namespace returnvalue;
|
|
||||||
|
|
||||||
cfdp::DestHandler::DestHandler(DestHandlerParams params, FsfwParams fsfwParams)
|
|
||||||
: tlvVec(params.maxTlvsInOnePdu),
|
|
||||||
userTlvVec(params.maxTlvsInOnePdu),
|
|
||||||
dp(std::move(params)),
|
|
||||||
fp(fsfwParams),
|
|
||||||
tp(params.maxFilenameLen) {
|
|
||||||
tp.pduConf.direction = cfdp::Direction::TOWARDS_SENDER;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() {
|
|
||||||
ReturnValue_t result;
|
|
||||||
uint8_t errorIdx = 0;
|
|
||||||
fsmRes.resetOfIteration();
|
|
||||||
if (fsmRes.step == TransactionStep::IDLE) {
|
|
||||||
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
|
|
||||||
if (infoIter->pduType == PduTypes::FILE_DIRECTIVE and
|
|
||||||
infoIter->directiveType == FileDirectives::METADATA) {
|
|
||||||
result = handleMetadataPdu(*infoIter);
|
|
||||||
checkAndHandleError(result, errorIdx);
|
|
||||||
// Store data was deleted in PDU handler because a store guard is used
|
|
||||||
dp.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 = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
|
|
||||||
fp.tcStore->deleteData(infoIter->storeId);
|
|
||||||
infoIter++;
|
|
||||||
}
|
|
||||||
dp.packetListRef.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fsmRes.step != TransactionStep::IDLE) {
|
|
||||||
fsmRes.callStatus = CallStatus::CALL_AGAIN;
|
|
||||||
}
|
|
||||||
return updateFsmRes(errorIdx);
|
|
||||||
}
|
|
||||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
|
|
||||||
if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) {
|
|
||||||
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
|
|
||||||
if (infoIter->pduType == PduTypes::FILE_DATA) {
|
|
||||||
result = handleFileDataPdu(*infoIter);
|
|
||||||
checkAndHandleError(result, errorIdx);
|
|
||||||
// Store data was deleted in PDU handler because a store guard is used
|
|
||||||
dp.packetListRef.erase(infoIter++);
|
|
||||||
} else if (infoIter->pduType == PduTypes::FILE_DIRECTIVE and
|
|
||||||
infoIter->directiveType == FileDirectives::EOF_DIRECTIVE) {
|
|
||||||
// TODO: Support for check timer missing
|
|
||||||
result = handleEofPdu(*infoIter);
|
|
||||||
checkAndHandleError(result, errorIdx);
|
|
||||||
// Store data was deleted in PDU handler because a store guard is used
|
|
||||||
dp.packetListRef.erase(infoIter++);
|
|
||||||
} else {
|
|
||||||
infoIter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (fsmRes.step == TransactionStep::TRANSFER_COMPLETION) {
|
|
||||||
result = handleTransferCompletion();
|
|
||||||
checkAndHandleError(result, errorIdx);
|
|
||||||
}
|
|
||||||
if (fsmRes.step == TransactionStep::SENDING_FINISHED_PDU) {
|
|
||||||
result = sendFinishedPdu();
|
|
||||||
checkAndHandleError(result, errorIdx);
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
return updateFsmRes(errorIdx);
|
|
||||||
}
|
|
||||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
|
|
||||||
// TODO: Will be implemented at a later stage
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "CFDP state machine for acknowledged mode not implemented yet" << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return updateFsmRes(errorIdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t cfdp::DestHandler::passPacket(PacketInfo packet) {
|
|
||||||
if (dp.packetListRef.full()) {
|
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
dp.packetListRef.push_back(packet);
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t cfdp::DestHandler::initialize() {
|
|
||||||
if (fp.tmStore == nullptr) {
|
|
||||||
fp.tmStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TM_STORE);
|
|
||||||
if (fp.tmStore == nullptr) {
|
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fp.tcStore == nullptr) {
|
|
||||||
fp.tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
|
|
||||||
if (fp.tcStore == nullptr) {
|
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fp.msgQueue == nullptr) {
|
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t cfdp::DestHandler::handleMetadataPdu(const PacketInfo& info) {
|
|
||||||
// Process metadata PDU
|
|
||||||
auto constAccessorPair = fp.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 destFileName;
|
|
||||||
MetadataInfo metadataInfo(tp.fileSize, sourceFileName, destFileName);
|
|
||||||
cfdp::Tlv* tlvArrayAsPtr = tlvVec.data();
|
|
||||||
metadataInfo.setOptionsArray(&tlvArrayAsPtr, std::nullopt, tlvVec.size());
|
|
||||||
MetadataPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(),
|
|
||||||
metadataInfo);
|
|
||||||
ReturnValue_t result = reader.parseData();
|
|
||||||
// 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
|
|
||||||
// is translated into a warning and/or event by an upper layer
|
|
||||||
if (result != OK) {
|
|
||||||
return handleMetadataParseError(result, constAccessorPair.second.data(),
|
|
||||||
constAccessorPair.second.size());
|
|
||||||
}
|
|
||||||
return startTransaction(reader, metadataInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t cfdp::DestHandler::handleFileDataPdu(const cfdp::PacketInfo& info) {
|
|
||||||
// Process file data PDU
|
|
||||||
auto constAccessorPair = fp.tcStore->getData(info.storeId);
|
|
||||||
if (constAccessorPair.first != OK) {
|
|
||||||
// TODO: This is not a CFDP error. Event and/or warning?
|
|
||||||
return constAccessorPair.first;
|
|
||||||
}
|
|
||||||
cfdp::FileSize offset;
|
|
||||||
FileDataInfo fdInfo(offset);
|
|
||||||
FileDataReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), fdInfo);
|
|
||||||
ReturnValue_t result = reader.parseData();
|
|
||||||
if (result != OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
size_t fileSegmentLen = 0;
|
|
||||||
const uint8_t* fileData = fdInfo.getFileData(&fileSegmentLen);
|
|
||||||
FileOpParams fileOpParams(tp.destName.data(), fileSegmentLen);
|
|
||||||
fileOpParams.offset = offset.value();
|
|
||||||
if (dp.cfg.indicCfg.fileSegmentRecvIndicRequired) {
|
|
||||||
FileSegmentRecvdParams segParams;
|
|
||||||
segParams.offset = offset.value();
|
|
||||||
segParams.id = tp.transactionId;
|
|
||||||
segParams.length = fileSegmentLen;
|
|
||||||
segParams.recContState = fdInfo.getRecordContinuationState();
|
|
||||||
size_t segmentMetadatLen = 0;
|
|
||||||
auto* segMetadata = fdInfo.getSegmentMetadata(&segmentMetadatLen);
|
|
||||||
segParams.segmentMetadata = {segMetadata, segmentMetadatLen};
|
|
||||||
dp.user.fileSegmentRecvdIndication(segParams);
|
|
||||||
}
|
|
||||||
result = dp.user.vfs.writeToFile(fileOpParams, fileData);
|
|
||||||
if (offset.value() + fileSegmentLen > tp.progress) {
|
|
||||||
tp.progress = offset.value() + fileSegmentLen;
|
|
||||||
}
|
|
||||||
if (result != returnvalue::OK) {
|
|
||||||
// TODO: Proper Error handling
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "File write error" << std::endl;
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
tp.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t cfdp::DestHandler::handleEofPdu(const cfdp::PacketInfo& info) {
|
|
||||||
// Process EOF PDU
|
|
||||||
auto constAccessorPair = fp.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);
|
|
||||||
EofPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), eofInfo);
|
|
||||||
ReturnValue_t result = reader.parseData();
|
|
||||||
if (result != OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
// TODO: Error handling
|
|
||||||
if (eofInfo.getConditionCode() == ConditionCode::NO_ERROR) {
|
|
||||||
tp.crc = eofInfo.getChecksum();
|
|
||||||
uint64_t fileSizeFromEof = eofInfo.getFileSize().value();
|
|
||||||
// CFDP 4.6.1.2.9: Declare file size error if progress exceeds file size
|
|
||||||
if (fileSizeFromEof > tp.progress) {
|
|
||||||
// TODO: File size error
|
|
||||||
}
|
|
||||||
tp.fileSize.setFileSize(fileSizeFromEof, std::nullopt);
|
|
||||||
}
|
|
||||||
if (dp.cfg.indicCfg.eofRecvIndicRequired) {
|
|
||||||
dp.user.eofRecvIndication(getTransactionId());
|
|
||||||
}
|
|
||||||
if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) {
|
|
||||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
|
|
||||||
fsmRes.step = TransactionStep::TRANSFER_COMPLETION;
|
|
||||||
} else if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
|
|
||||||
fsmRes.step = TransactionStep::SENDING_ACK_PDU;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t cfdp::DestHandler::handleMetadataParseError(ReturnValue_t result,
|
|
||||||
const uint8_t* rawData, size_t maxSize) {
|
|
||||||
// TODO: try to extract destination ID for error
|
|
||||||
// TODO: Invalid metadata PDU.
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "Parsing Metadata PDU failed with code " << result << std::endl;
|
|
||||||
#else
|
|
||||||
#endif
|
|
||||||
PduHeaderReader headerReader(rawData, maxSize);
|
|
||||||
result = headerReader.parseData();
|
|
||||||
if (result != OK) {
|
|
||||||
// TODO: Now this really should not happen. Warning or error,
|
|
||||||
// yield or cache appropriate returnvalue
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "Parsing Header failed" << std::endl;
|
|
||||||
#else
|
|
||||||
#endif
|
|
||||||
// TODO: Trigger appropriate event
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
cfdp::EntityId destId;
|
|
||||||
headerReader.getDestId(destId);
|
|
||||||
RemoteEntityCfg* remoteCfg;
|
|
||||||
if (not dp.remoteCfgTable.getRemoteCfg(destId, &remoteCfg)) {
|
|
||||||
// TODO: No remote config for dest ID. I consider this a configuration error, which is not
|
|
||||||
// covered by the standard.
|
|
||||||
// Warning or error, yield or cache appropriate returnvalue
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "No remote config exists for destination ID" << std::endl;
|
|
||||||
#else
|
|
||||||
#endif
|
|
||||||
// TODO: Trigger appropriate event
|
|
||||||
}
|
|
||||||
// TODO: Appropriate returnvalue?
|
|
||||||
return returnvalue::FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader, MetadataInfo& info) {
|
|
||||||
if (fsmRes.state != CfdpStates::IDLE) {
|
|
||||||
// According to standard, discard metadata PDU if we are busy
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
ReturnValue_t result = OK;
|
|
||||||
fsmRes.step = TransactionStep::TRANSACTION_START;
|
|
||||||
if (reader.getTransmissionMode() == TransmissionModes::UNACKNOWLEDGED) {
|
|
||||||
fsmRes.state = CfdpStates::BUSY_CLASS_1_NACKED;
|
|
||||||
} else if (reader.getTransmissionMode() == TransmissionModes::ACKNOWLEDGED) {
|
|
||||||
fsmRes.state = CfdpStates::BUSY_CLASS_2_ACKED;
|
|
||||||
}
|
|
||||||
tp.checksumType = info.getChecksumType();
|
|
||||||
tp.closureRequested = info.isClosureRequested();
|
|
||||||
size_t sourceNameSize = 0;
|
|
||||||
const uint8_t* sourceNamePtr = info.getSourceFileName().getValue(&sourceNameSize);
|
|
||||||
if (sourceNameSize > tp.sourceName.size()) {
|
|
||||||
// TODO: Warning, event etc.
|
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
std::memcpy(tp.sourceName.data(), sourceNamePtr, sourceNameSize);
|
|
||||||
tp.sourceName[sourceNameSize] = '\0';
|
|
||||||
size_t destNameSize = 0;
|
|
||||||
const uint8_t* destNamePtr = info.getDestFileName().getValue(&destNameSize);
|
|
||||||
if (destNameSize > tp.destName.size()) {
|
|
||||||
// TODO: Warning, event etc.
|
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
std::memcpy(tp.destName.data(), destNamePtr, destNameSize);
|
|
||||||
tp.destName[destNameSize] = '\0';
|
|
||||||
reader.fillConfig(tp.pduConf);
|
|
||||||
tp.pduConf.direction = Direction::TOWARDS_SENDER;
|
|
||||||
tp.transactionId.entityId = tp.pduConf.sourceId;
|
|
||||||
tp.transactionId.seqNum = tp.pduConf.seqNum;
|
|
||||||
if (not dp.remoteCfgTable.getRemoteCfg(tp.pduConf.sourceId, &tp.remoteCfg)) {
|
|
||||||
// TODO: Warning, event etc.
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "cfdp::DestHandler" << __func__
|
|
||||||
<< ": No remote configuration found for destination ID "
|
|
||||||
<< tp.pduConf.sourceId.getValue() << std::endl;
|
|
||||||
#endif
|
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
// If both dest name size and source name size are 0, we are dealing with a metadata only PDU,
|
|
||||||
// so there is no need to create a file or truncate an existing file
|
|
||||||
if (destNameSize > 0 and sourceNameSize > 0) {
|
|
||||||
FilesystemParams fparams(tp.destName.data());
|
|
||||||
// TODO: Filesystem errors?
|
|
||||||
if (dp.user.vfs.fileExists(fparams)) {
|
|
||||||
dp.user.vfs.truncateFile(fparams);
|
|
||||||
} else {
|
|
||||||
result = dp.user.vfs.createFile(fparams);
|
|
||||||
if (result != OK) {
|
|
||||||
// TODO: Handle FS error. This is probably a case for the filestore rejection mechanism of
|
|
||||||
// CFDP.
|
|
||||||
// In any case, it does not really make sense to continue here
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fsmRes.step = TransactionStep::RECEIVING_FILE_DATA_PDUS;
|
|
||||||
MetadataRecvdParams params(tp.transactionId, tp.pduConf.sourceId);
|
|
||||||
params.fileSize = tp.fileSize.getSize();
|
|
||||||
params.destFileName = tp.destName.data();
|
|
||||||
params.sourceFileName = tp.sourceName.data();
|
|
||||||
params.msgsToUserArray = dynamic_cast<MessageToUserTlv*>(userTlvVec.data());
|
|
||||||
params.msgsToUserLen = info.getOptionsLen();
|
|
||||||
dp.user.metadataRecvdIndication(params);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
cfdp::CfdpStates cfdp::DestHandler::getCfdpState() const { return fsmRes.state; }
|
|
||||||
|
|
||||||
ReturnValue_t cfdp::DestHandler::handleTransferCompletion() {
|
|
||||||
ReturnValue_t result;
|
|
||||||
if (tp.checksumType != ChecksumTypes::NULL_CHECKSUM) {
|
|
||||||
result = checksumVerification();
|
|
||||||
if (result != OK) {
|
|
||||||
// TODO: Warning / error handling?
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tp.conditionCode = ConditionCode::NO_ERROR;
|
|
||||||
}
|
|
||||||
result = noticeOfCompletion();
|
|
||||||
if (result != OK) {
|
|
||||||
}
|
|
||||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
|
|
||||||
if (tp.closureRequested) {
|
|
||||||
fsmRes.step = TransactionStep::SENDING_FINISHED_PDU;
|
|
||||||
} else {
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
} else if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
|
|
||||||
fsmRes.step = TransactionStep::SENDING_FINISHED_PDU;
|
|
||||||
}
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cfdp::DestHandler::finish() {
|
|
||||||
tp.reset();
|
|
||||||
dp.packetListRef.clear();
|
|
||||||
fsmRes.state = CfdpStates::IDLE;
|
|
||||||
fsmRes.step = TransactionStep::IDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t cfdp::DestHandler::checksumVerification() {
|
|
||||||
std::array<uint8_t, 1024> buf{};
|
|
||||||
// TODO: Checksum verification and notice of completion
|
|
||||||
etl::crc32 crcCalc;
|
|
||||||
uint64_t currentOffset = 0;
|
|
||||||
FileOpParams params(tp.destName.data(), tp.fileSize.value());
|
|
||||||
while (currentOffset < tp.fileSize.value()) {
|
|
||||||
uint64_t readLen;
|
|
||||||
if (currentOffset + buf.size() > tp.fileSize.value()) {
|
|
||||||
readLen = tp.fileSize.value() - currentOffset;
|
|
||||||
} else {
|
|
||||||
readLen = buf.size();
|
|
||||||
}
|
|
||||||
if (readLen > 0) {
|
|
||||||
params.offset = currentOffset;
|
|
||||||
params.size = readLen;
|
|
||||||
auto result = dp.user.vfs.readFromFile(params, buf.data(), buf.size());
|
|
||||||
if (result != OK) {
|
|
||||||
// TODO: I think this is a case for a filestore rejection, but it might sense to print
|
|
||||||
// a warning or trigger an event because this should generally not happen
|
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
crcCalc.add(buf.begin(), buf.begin() + readLen);
|
|
||||||
}
|
|
||||||
currentOffset += readLen;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t value = crcCalc.value();
|
|
||||||
if (value == tp.crc) {
|
|
||||||
tp.conditionCode = ConditionCode::NO_ERROR;
|
|
||||||
tp.deliveryCode = FileDeliveryCode::DATA_COMPLETE;
|
|
||||||
} else {
|
|
||||||
// TODO: Proper error handling
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "CRC check for file " << tp.destName.data() << " failed" << std::endl;
|
|
||||||
#endif
|
|
||||||
tp.conditionCode = ConditionCode::FILE_CHECKSUM_FAILURE;
|
|
||||||
}
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t cfdp::DestHandler::noticeOfCompletion() {
|
|
||||||
if (dp.cfg.indicCfg.transactionFinishedIndicRequired) {
|
|
||||||
TransactionFinishedParams params(tp.transactionId, tp.conditionCode, tp.deliveryCode,
|
|
||||||
tp.deliveryStatus);
|
|
||||||
dp.user.transactionFinishedIndication(params);
|
|
||||||
}
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t cfdp::DestHandler::sendFinishedPdu() {
|
|
||||||
FinishedInfo info(tp.conditionCode, tp.deliveryCode, tp.deliveryStatus);
|
|
||||||
FinishPduCreator finishedPdu(tp.pduConf, info);
|
|
||||||
store_address_t storeId;
|
|
||||||
uint8_t* dataPtr = nullptr;
|
|
||||||
ReturnValue_t result =
|
|
||||||
fp.tcStore->getFreeElement(&storeId, finishedPdu.getSerializedSize(), &dataPtr);
|
|
||||||
if (result != OK) {
|
|
||||||
// TODO: Error handling and event, this is a non CFDP specific error (most likely store is full)
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
size_t serLen = 0;
|
|
||||||
result = finishedPdu.serialize(dataPtr, serLen, finishedPdu.getSerializedSize());
|
|
||||||
if (result != OK) {
|
|
||||||
// TODO: Error printout, this really should not happen
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
TmTcMessage msg(storeId);
|
|
||||||
result = fp.msgQueue->sendMessage(fp.packetDest.getReportReceptionQueue(), &msg);
|
|
||||||
if (result != OK) {
|
|
||||||
// TODO: Error handling and event, this is a non CFDP specific error (most likely store is full)
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
fsmRes.packetsSent++;
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
cfdp::DestHandler::TransactionStep cfdp::DestHandler::getTransactionStep() const {
|
|
||||||
return fsmRes.step;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cfdp::DestHandler::FsmResult& cfdp::DestHandler::updateFsmRes(uint8_t errors) {
|
|
||||||
fsmRes.errors = errors;
|
|
||||||
fsmRes.result = OK;
|
|
||||||
if (fsmRes.errors > 0) {
|
|
||||||
fsmRes.result = FAILED;
|
|
||||||
}
|
|
||||||
return fsmRes;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cfdp::TransactionId& cfdp::DestHandler::getTransactionId() const { return tp.transactionId; }
|
|
||||||
|
|
||||||
void cfdp::DestHandler::checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx) {
|
|
||||||
if (result != OK and errorIdx < 3) {
|
|
||||||
fsmRes.errorCodes[errorIdx] = result;
|
|
||||||
errorIdx++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void cfdp::DestHandler::setMsgQueue(MessageQueueIF& queue) { fp.msgQueue = &queue; }
|
|
||||||
|
|
||||||
void cfdp::DestHandler::setEventReporter(EventReportingProxyIF& reporter) {
|
|
||||||
fp.eventReporter = &reporter;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cfdp::DestHandlerParams& cfdp::DestHandler::getDestHandlerParams() const { return dp; }
|
|
||||||
|
|
||||||
StorageManagerIF* cfdp::DestHandler::getTmStore() const { return fp.tmStore; }
|
|
||||||
StorageManagerIF* cfdp::DestHandler::getTcStore() const { return fp.tcStore; }
|
|
@ -1,202 +0,0 @@
|
|||||||
#ifndef FSFW_CFDP_CFDPDESTHANDLER_H
|
|
||||||
#define FSFW_CFDP_CFDPDESTHANDLER_H
|
|
||||||
|
|
||||||
#include <etl/list.h>
|
|
||||||
#include <etl/set.h>
|
|
||||||
|
|
||||||
#include <optional>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "RemoteConfigTableIF.h"
|
|
||||||
#include "UserBase.h"
|
|
||||||
#include "defs.h"
|
|
||||||
#include "fsfw/cfdp/handler/mib.h"
|
|
||||||
#include "fsfw/cfdp/pdu/MetadataPduReader.h"
|
|
||||||
#include "fsfw/cfdp/pdu/PduConfig.h"
|
|
||||||
#include "fsfw/container/DynamicFIFO.h"
|
|
||||||
#include "fsfw/storagemanager/StorageManagerIF.h"
|
|
||||||
#include "fsfw/storagemanager/storeAddress.h"
|
|
||||||
#include "fsfw/tmtcservices/AcceptsTelemetryIF.h"
|
|
||||||
|
|
||||||
namespace cfdp {
|
|
||||||
|
|
||||||
struct PacketInfo {
|
|
||||||
PacketInfo(PduTypes type, store_address_t storeId,
|
|
||||||
std::optional<FileDirectives> directive = std::nullopt)
|
|
||||||
: pduType(type), directiveType(directive), storeId(storeId) {}
|
|
||||||
|
|
||||||
PduTypes pduType = PduTypes::FILE_DATA;
|
|
||||||
std::optional<FileDirectives> directiveType = FileDirectives::INVALID_DIRECTIVE;
|
|
||||||
store_address_t storeId = store_address_t::invalid();
|
|
||||||
PacketInfo() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <size_t SIZE>
|
|
||||||
using LostSegmentsList = etl::set<etl::pair<uint64_t, uint64_t>, SIZE>;
|
|
||||||
template <size_t SIZE>
|
|
||||||
using PacketInfoList = etl::list<PacketInfo, SIZE>;
|
|
||||||
using LostSegmentsListBase = etl::iset<etl::pair<uint64_t, uint64_t>>;
|
|
||||||
using PacketInfoListBase = etl::ilist<PacketInfo>;
|
|
||||||
|
|
||||||
struct DestHandlerParams {
|
|
||||||
DestHandlerParams(LocalEntityCfg cfg, UserBase& user, RemoteConfigTableIF& remoteCfgTable,
|
|
||||||
PacketInfoListBase& packetList,
|
|
||||||
// TODO: This container can potentially take tons of space. For a better
|
|
||||||
// memory efficient implementation, an additional abstraction could be
|
|
||||||
// be used so users can use uint32_t as the pair type
|
|
||||||
LostSegmentsListBase& lostSegmentsContainer)
|
|
||||||
: cfg(std::move(cfg)),
|
|
||||||
user(user),
|
|
||||||
remoteCfgTable(remoteCfgTable),
|
|
||||||
packetListRef(packetList),
|
|
||||||
lostSegmentsContainer(lostSegmentsContainer) {}
|
|
||||||
|
|
||||||
LocalEntityCfg cfg;
|
|
||||||
UserBase& user;
|
|
||||||
RemoteConfigTableIF& remoteCfgTable;
|
|
||||||
|
|
||||||
PacketInfoListBase& packetListRef;
|
|
||||||
LostSegmentsListBase& lostSegmentsContainer;
|
|
||||||
uint8_t maxTlvsInOnePdu = 10;
|
|
||||||
size_t maxFilenameLen = 255;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FsfwParams {
|
|
||||||
FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue,
|
|
||||||
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;
|
|
||||||
StorageManagerIF* tcStore = nullptr;
|
|
||||||
StorageManagerIF* tmStore = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class CallStatus { DONE, CALL_AFTER_DELAY, CALL_AGAIN };
|
|
||||||
|
|
||||||
class DestHandler {
|
|
||||||
public:
|
|
||||||
enum class TransactionStep {
|
|
||||||
IDLE = 0,
|
|
||||||
TRANSACTION_START = 1,
|
|
||||||
RECEIVING_FILE_DATA_PDUS = 2,
|
|
||||||
SENDING_ACK_PDU = 3,
|
|
||||||
TRANSFER_COMPLETION = 4,
|
|
||||||
SENDING_FINISHED_PDU = 5
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FsmResult {
|
|
||||||
public:
|
|
||||||
ReturnValue_t result = returnvalue::OK;
|
|
||||||
CallStatus callStatus = CallStatus::CALL_AFTER_DELAY;
|
|
||||||
TransactionStep step = TransactionStep::IDLE;
|
|
||||||
CfdpStates state = CfdpStates::IDLE;
|
|
||||||
uint32_t packetsSent = 0;
|
|
||||||
uint8_t errors = 0;
|
|
||||||
std::array<ReturnValue_t, 3> errorCodes = {};
|
|
||||||
void resetOfIteration() {
|
|
||||||
result = returnvalue::OK;
|
|
||||||
callStatus = CallStatus::CALL_AFTER_DELAY;
|
|
||||||
packetsSent = 0;
|
|
||||||
errors = 0;
|
|
||||||
errorCodes.fill(returnvalue::OK);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Will be returned if it is advisable to call the state machine operation call again
|
|
||||||
*/
|
|
||||||
ReturnValue_t PARTIAL_SUCCESS = returnvalue::makeCode(0, 2);
|
|
||||||
ReturnValue_t FAILURE = returnvalue::makeCode(0, 3);
|
|
||||||
explicit DestHandler(DestHandlerParams handlerParams, FsfwParams fsfwParams);
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* - @c returnvalue::OK State machine OK for this execution cycle
|
|
||||||
* - @c CALL_FSM_AGAIN State machine should be called again.
|
|
||||||
*/
|
|
||||||
const FsmResult& performStateMachine();
|
|
||||||
void setMsgQueue(MessageQueueIF& queue);
|
|
||||||
void setEventReporter(EventReportingProxyIF& reporter);
|
|
||||||
|
|
||||||
ReturnValue_t passPacket(PacketInfo packet);
|
|
||||||
|
|
||||||
ReturnValue_t initialize();
|
|
||||||
|
|
||||||
[[nodiscard]] CfdpStates getCfdpState() const;
|
|
||||||
[[nodiscard]] TransactionStep getTransactionStep() const;
|
|
||||||
[[nodiscard]] const TransactionId& getTransactionId() const;
|
|
||||||
[[nodiscard]] const DestHandlerParams& getDestHandlerParams() const;
|
|
||||||
[[nodiscard]] StorageManagerIF* getTcStore() const;
|
|
||||||
[[nodiscard]] StorageManagerIF* getTmStore() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct TransactionParams {
|
|
||||||
// Initialize char vectors with length + 1 for 0 termination
|
|
||||||
explicit TransactionParams(size_t maxFileNameLen)
|
|
||||||
: sourceName(maxFileNameLen + 1), destName(maxFileNameLen + 1) {}
|
|
||||||
|
|
||||||
void reset() {
|
|
||||||
pduConf = PduConfig();
|
|
||||||
transactionId = TransactionId();
|
|
||||||
std::fill(sourceName.begin(), sourceName.end(), '\0');
|
|
||||||
std::fill(destName.begin(), destName.end(), '\0');
|
|
||||||
fileSize.setFileSize(0, false);
|
|
||||||
conditionCode = ConditionCode::NO_ERROR;
|
|
||||||
deliveryCode = FileDeliveryCode::DATA_INCOMPLETE;
|
|
||||||
deliveryStatus = FileDeliveryStatus::DISCARDED_DELIBERATELY;
|
|
||||||
crc = 0;
|
|
||||||
progress = 0;
|
|
||||||
remoteCfg = nullptr;
|
|
||||||
closureRequested = false;
|
|
||||||
checksumType = ChecksumTypes::NULL_CHECKSUM;
|
|
||||||
}
|
|
||||||
|
|
||||||
ChecksumTypes checksumType = ChecksumTypes::NULL_CHECKSUM;
|
|
||||||
bool closureRequested = false;
|
|
||||||
std::vector<char> sourceName;
|
|
||||||
std::vector<char> destName;
|
|
||||||
cfdp::FileSize fileSize;
|
|
||||||
TransactionId transactionId;
|
|
||||||
PduConfig pduConf;
|
|
||||||
ConditionCode conditionCode = ConditionCode::NO_ERROR;
|
|
||||||
FileDeliveryCode deliveryCode = FileDeliveryCode::DATA_INCOMPLETE;
|
|
||||||
FileDeliveryStatus deliveryStatus = FileDeliveryStatus::DISCARDED_DELIBERATELY;
|
|
||||||
uint32_t crc = 0;
|
|
||||||
uint64_t progress = 0;
|
|
||||||
RemoteEntityCfg* remoteCfg = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<cfdp::Tlv> tlvVec;
|
|
||||||
std::vector<cfdp::Tlv> userTlvVec;
|
|
||||||
DestHandlerParams dp;
|
|
||||||
FsfwParams fp;
|
|
||||||
TransactionParams tp;
|
|
||||||
FsmResult fsmRes;
|
|
||||||
|
|
||||||
ReturnValue_t startTransaction(MetadataPduReader& reader, MetadataInfo& info);
|
|
||||||
ReturnValue_t handleMetadataPdu(const PacketInfo& info);
|
|
||||||
ReturnValue_t handleFileDataPdu(const PacketInfo& info);
|
|
||||||
ReturnValue_t handleEofPdu(const PacketInfo& info);
|
|
||||||
ReturnValue_t handleMetadataParseError(ReturnValue_t result, const uint8_t* rawData,
|
|
||||||
size_t maxSize);
|
|
||||||
ReturnValue_t handleTransferCompletion();
|
|
||||||
ReturnValue_t sendFinishedPdu();
|
|
||||||
ReturnValue_t noticeOfCompletion();
|
|
||||||
ReturnValue_t checksumVerification();
|
|
||||||
const FsmResult& updateFsmRes(uint8_t errors);
|
|
||||||
void checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx);
|
|
||||||
void finish();
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace cfdp
|
|
||||||
|
|
||||||
#endif // FSFW_CFDP_CFDPDESTHANDLER_H
|
|
@ -1 +0,0 @@
|
|||||||
#include "SourceHandler.h"
|
|
@ -1,6 +0,0 @@
|
|||||||
#ifndef FSFW_CFDP_CFDPSOURCEHANDLER_H
|
|
||||||
#define FSFW_CFDP_CFDPSOURCEHANDLER_H
|
|
||||||
|
|
||||||
class SourceHandler {};
|
|
||||||
|
|
||||||
#endif // FSFW_CFDP_CFDPSOURCEHANDLER_H
|
|
@ -1,3 +1,2 @@
|
|||||||
target_sources(
|
target_sources(${FSFW_TEST_TGT} PRIVATE testDistributor.cpp
|
||||||
${FSFW_TEST_TGT} PRIVATE testDistributor.cpp testDestHandler.cpp
|
testFaultHandler.cpp)
|
||||||
testSourceHandler.cpp testFaultHandler.cpp)
|
|
||||||
|
@ -1,244 +0,0 @@
|
|||||||
#include <etl/crc32.h>
|
|
||||||
|
|
||||||
#include <catch2/catch_test_macros.hpp>
|
|
||||||
#include <random>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "fsfw/cfdp.h"
|
|
||||||
#include "fsfw/cfdp/pdu/EofPduCreator.h"
|
|
||||||
#include "fsfw/cfdp/pdu/FileDataCreator.h"
|
|
||||||
#include "fsfw/cfdp/pdu/MetadataPduCreator.h"
|
|
||||||
#include "mocks/AcceptsTmMock.h"
|
|
||||||
#include "mocks/EventReportingProxyMock.h"
|
|
||||||
#include "mocks/FilesystemMock.h"
|
|
||||||
#include "mocks/MessageQueueMock.h"
|
|
||||||
#include "mocks/StorageManagerMock.h"
|
|
||||||
#include "mocks/cfdp/FaultHandlerMock.h"
|
|
||||||
#include "mocks/cfdp/RemoteConfigTableMock.h"
|
|
||||||
#include "mocks/cfdp/UserMock.h"
|
|
||||||
|
|
||||||
TEST_CASE("CFDP Dest Handler", "[cfdp]") {
|
|
||||||
using namespace cfdp;
|
|
||||||
using namespace returnvalue;
|
|
||||||
MessageQueueId_t destQueueId = 2;
|
|
||||||
AcceptsTmMock tmReceiver(destQueueId);
|
|
||||||
MessageQueueMock mqMock(destQueueId);
|
|
||||||
EntityId localId = EntityId(UnsignedByteField<uint16_t>(2));
|
|
||||||
EntityId remoteId = EntityId(UnsignedByteField<uint16_t>(3));
|
|
||||||
FaultHandlerMock fhMock;
|
|
||||||
LocalEntityCfg localEntityCfg(localId, IndicationCfg(), fhMock);
|
|
||||||
FilesystemMock fsMock;
|
|
||||||
UserMock userMock(fsMock);
|
|
||||||
RemoteConfigTableMock remoteCfgTableMock;
|
|
||||||
PacketInfoList<64> packetInfoList;
|
|
||||||
LostSegmentsList<128> lostSegmentsList;
|
|
||||||
DestHandlerParams dp(localEntityCfg, userMock, remoteCfgTableMock, packetInfoList,
|
|
||||||
lostSegmentsList);
|
|
||||||
EventReportingProxyMock eventReporterMock;
|
|
||||||
LocalPool::LocalPoolConfig storeCfg = {{10, 32}, {10, 64}, {10, 128}, {10, 1024}};
|
|
||||||
StorageManagerMock tcStore(2, storeCfg);
|
|
||||||
StorageManagerMock tmStore(3, storeCfg);
|
|
||||||
FsfwParams fp(tmReceiver, &mqMock, &eventReporterMock);
|
|
||||||
RemoteEntityCfg cfg(remoteId);
|
|
||||||
remoteCfgTableMock.addRemoteConfig(cfg);
|
|
||||||
fp.tcStore = &tcStore;
|
|
||||||
fp.tmStore = &tmStore;
|
|
||||||
uint8_t* buf = nullptr;
|
|
||||||
size_t serLen = 0;
|
|
||||||
store_address_t storeId;
|
|
||||||
PduConfig conf;
|
|
||||||
auto destHandler = DestHandler(dp, fp);
|
|
||||||
CHECK(destHandler.initialize() == OK);
|
|
||||||
|
|
||||||
auto metadataPreparation = [&](FileSize cfdpFileSize, ChecksumTypes checksumType) {
|
|
||||||
std::string srcNameString = "hello.txt";
|
|
||||||
std::string destNameString = "hello-cpy.txt";
|
|
||||||
StringLv srcName(srcNameString);
|
|
||||||
StringLv destName(destNameString);
|
|
||||||
MetadataInfo info(false, checksumType, cfdpFileSize, srcName, destName);
|
|
||||||
TransactionSeqNum seqNum(UnsignedByteField<uint16_t>(1));
|
|
||||||
conf.sourceId = remoteId;
|
|
||||||
conf.destId = localId;
|
|
||||||
conf.mode = TransmissionModes::UNACKNOWLEDGED;
|
|
||||||
conf.seqNum = seqNum;
|
|
||||||
MetadataPduCreator metadataCreator(conf, info);
|
|
||||||
REQUIRE(tcStore.getFreeElement(&storeId, metadataCreator.getSerializedSize(), &buf) == OK);
|
|
||||||
REQUIRE(metadataCreator.serialize(buf, serLen, metadataCreator.getSerializedSize()) == OK);
|
|
||||||
PacketInfo packetInfo(metadataCreator.getPduType(), storeId,
|
|
||||||
metadataCreator.getDirectiveCode());
|
|
||||||
packetInfoList.push_back(packetInfo);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto metadataCheck = [&](const cfdp::DestHandler::FsmResult& res, const char* sourceName,
|
|
||||||
const char* destName, size_t fileLen) {
|
|
||||||
REQUIRE(res.result == OK);
|
|
||||||
REQUIRE(res.callStatus == CallStatus::CALL_AGAIN);
|
|
||||||
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);
|
|
||||||
auto& idMetadataPair = userMock.metadataRecvd.back();
|
|
||||||
REQUIRE(idMetadataPair.first == destHandler.getTransactionId());
|
|
||||||
REQUIRE(idMetadataPair.second.sourceId.getValue() == 3);
|
|
||||||
REQUIRE(idMetadataPair.second.fileSize == fileLen);
|
|
||||||
REQUIRE(strcmp(idMetadataPair.second.destFileName, destName) == 0);
|
|
||||||
REQUIRE(strcmp(idMetadataPair.second.sourceFileName, sourceName) == 0);
|
|
||||||
userMock.metadataRecvd.pop();
|
|
||||||
REQUIRE(fsMock.fileMap.find(destName) != fsMock.fileMap.end());
|
|
||||||
REQUIRE(res.result == OK);
|
|
||||||
REQUIRE(res.state == CfdpStates::BUSY_CLASS_1_NACKED);
|
|
||||||
REQUIRE(res.step == DestHandler::TransactionStep::RECEIVING_FILE_DATA_PDUS);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto eofPreparation = [&](FileSize cfdpFileSize, uint32_t crc) {
|
|
||||||
EofInfo eofInfo(cfdp::ConditionCode::NO_ERROR, crc, std::move(cfdpFileSize));
|
|
||||||
EofPduCreator eofCreator(conf, eofInfo);
|
|
||||||
REQUIRE(tcStore.getFreeElement(&storeId, eofCreator.getSerializedSize(), &buf) == OK);
|
|
||||||
REQUIRE(eofCreator.serialize(buf, serLen, eofCreator.getSerializedSize()) == OK);
|
|
||||||
PacketInfo packetInfo(eofCreator.getPduType(), storeId, eofCreator.getDirectiveCode());
|
|
||||||
packetInfoList.push_back(packetInfo);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto eofCheck = [&](const cfdp::DestHandler::FsmResult& res, const TransactionId& id) {
|
|
||||||
REQUIRE(res.result == OK);
|
|
||||||
REQUIRE(res.state == CfdpStates::IDLE);
|
|
||||||
REQUIRE(res.errors == 0);
|
|
||||||
REQUIRE(res.step == DestHandler::TransactionStep::IDLE);
|
|
||||||
// Assert that the packet was deleted after handling
|
|
||||||
REQUIRE(not tcStore.hasDataAtId(storeId));
|
|
||||||
REQUIRE(packetInfoList.empty());
|
|
||||||
REQUIRE(userMock.eofsRevd.size() == 1);
|
|
||||||
auto& eofId = userMock.eofsRevd.back();
|
|
||||||
CHECK(eofId == id);
|
|
||||||
REQUIRE(userMock.finishedRecvd.size() == 1);
|
|
||||||
auto& idParamPair = userMock.finishedRecvd.back();
|
|
||||||
CHECK(idParamPair.first == id);
|
|
||||||
CHECK(idParamPair.second.condCode == ConditionCode::NO_ERROR);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto fileDataPduCheck = [&](const cfdp::DestHandler::FsmResult& res,
|
|
||||||
const std::vector<store_address_t>& idsToCheck) {
|
|
||||||
REQUIRE(res.result == OK);
|
|
||||||
REQUIRE(res.state == CfdpStates::BUSY_CLASS_1_NACKED);
|
|
||||||
REQUIRE(res.step == DestHandler::TransactionStep::RECEIVING_FILE_DATA_PDUS);
|
|
||||||
for (const auto id : idsToCheck) {
|
|
||||||
REQUIRE(not tcStore.hasDataAtId(id));
|
|
||||||
}
|
|
||||||
REQUIRE(packetInfoList.empty());
|
|
||||||
};
|
|
||||||
|
|
||||||
SECTION("State") {
|
|
||||||
CHECK(destHandler.getCfdpState() == CfdpStates::IDLE);
|
|
||||||
CHECK(destHandler.getTransactionStep() == DestHandler::TransactionStep::IDLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("Idle State Machine Iteration") {
|
|
||||||
auto res = destHandler.performStateMachine();
|
|
||||||
CHECK(res.result == OK);
|
|
||||||
CHECK(res.callStatus == CallStatus::CALL_AFTER_DELAY);
|
|
||||||
CHECK(res.errors == 0);
|
|
||||||
CHECK(destHandler.getCfdpState() == CfdpStates::IDLE);
|
|
||||||
CHECK(destHandler.getTransactionStep() == DestHandler::TransactionStep::IDLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("Empty File Transfer") {
|
|
||||||
const DestHandler::FsmResult& res = destHandler.performStateMachine();
|
|
||||||
CHECK(res.result == OK);
|
|
||||||
FileSize cfdpFileSize(0);
|
|
||||||
metadataPreparation(cfdpFileSize, ChecksumTypes::NULL_CHECKSUM);
|
|
||||||
destHandler.performStateMachine();
|
|
||||||
metadataCheck(res, "hello.txt", "hello-cpy.txt", 0);
|
|
||||||
destHandler.performStateMachine();
|
|
||||||
REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY);
|
|
||||||
auto transactionId = destHandler.getTransactionId();
|
|
||||||
eofPreparation(cfdpFileSize, 0);
|
|
||||||
// After EOF, operation is done because no closure was requested
|
|
||||||
destHandler.performStateMachine();
|
|
||||||
eofCheck(res, transactionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("Small File Transfer") {
|
|
||||||
const DestHandler::FsmResult& res = destHandler.performStateMachine();
|
|
||||||
CHECK(res.result == OK);
|
|
||||||
std::string fileData = "hello test data";
|
|
||||||
etl::crc32 crcCalc;
|
|
||||||
crcCalc.add(fileData.begin(), fileData.end());
|
|
||||||
uint32_t crc32 = crcCalc.value();
|
|
||||||
FileSize cfdpFileSize(fileData.size());
|
|
||||||
metadataPreparation(cfdpFileSize, ChecksumTypes::CRC_32);
|
|
||||||
destHandler.performStateMachine();
|
|
||||||
metadataCheck(res, "hello.txt", "hello-cpy.txt", fileData.size());
|
|
||||||
destHandler.performStateMachine();
|
|
||||||
REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY);
|
|
||||||
auto transactionId = destHandler.getTransactionId();
|
|
||||||
FileSize offset(0);
|
|
||||||
FileDataInfo fdPduInfo(offset, reinterpret_cast<const uint8_t*>(fileData.data()),
|
|
||||||
fileData.size());
|
|
||||||
FileDataCreator fdPduCreator(conf, fdPduInfo);
|
|
||||||
REQUIRE(tcStore.getFreeElement(&storeId, fdPduCreator.getSerializedSize(), &buf) == OK);
|
|
||||||
REQUIRE(fdPduCreator.serialize(buf, serLen, fdPduCreator.getSerializedSize()) == OK);
|
|
||||||
PacketInfo packetInfo(fdPduCreator.getPduType(), storeId, std::nullopt);
|
|
||||||
packetInfoList.push_back(packetInfo);
|
|
||||||
destHandler.performStateMachine();
|
|
||||||
fileDataPduCheck(res, {storeId});
|
|
||||||
eofPreparation(cfdpFileSize, crc32);
|
|
||||||
// After EOF, operation is done because no closure was requested
|
|
||||||
destHandler.performStateMachine();
|
|
||||||
eofCheck(res, transactionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("Segmented File Transfer") {
|
|
||||||
const DestHandler::FsmResult& res = destHandler.performStateMachine();
|
|
||||||
CHECK(res.result == OK);
|
|
||||||
std::random_device dev;
|
|
||||||
std::mt19937 rng(dev());
|
|
||||||
std::uniform_int_distribution<std::mt19937::result_type> distU8(0, 255);
|
|
||||||
std::array<uint8_t, 1024> largerFileData{};
|
|
||||||
for (auto& val : largerFileData) {
|
|
||||||
val = distU8(rng);
|
|
||||||
}
|
|
||||||
etl::crc32 crcCalc;
|
|
||||||
crcCalc.add(largerFileData.begin(), largerFileData.end());
|
|
||||||
uint32_t crc32 = crcCalc.value();
|
|
||||||
FileSize cfdpFileSize(largerFileData.size());
|
|
||||||
metadataPreparation(cfdpFileSize, ChecksumTypes::CRC_32);
|
|
||||||
destHandler.performStateMachine();
|
|
||||||
metadataCheck(res, "hello.txt", "hello-cpy.txt", largerFileData.size());
|
|
||||||
destHandler.performStateMachine();
|
|
||||||
REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY);
|
|
||||||
auto transactionId = destHandler.getTransactionId();
|
|
||||||
|
|
||||||
std::vector<store_address_t> idsToCheck;
|
|
||||||
{
|
|
||||||
FileSize offset(0);
|
|
||||||
FileDataInfo fdPduInfo(offset, reinterpret_cast<const uint8_t*>(largerFileData.data()),
|
|
||||||
largerFileData.size() / 2);
|
|
||||||
FileDataCreator fdPduCreator(conf, fdPduInfo);
|
|
||||||
REQUIRE(tcStore.getFreeElement(&storeId, fdPduCreator.getSerializedSize(), &buf) == OK);
|
|
||||||
REQUIRE(fdPduCreator.serialize(buf, serLen, fdPduCreator.getSerializedSize()) == OK);
|
|
||||||
PacketInfo packetInfo(fdPduCreator.getPduType(), storeId, std::nullopt);
|
|
||||||
idsToCheck.push_back(storeId);
|
|
||||||
packetInfoList.push_back(packetInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
FileSize offset(512);
|
|
||||||
FileDataInfo fdPduInfo(offset, reinterpret_cast<const uint8_t*>(largerFileData.data() + 512),
|
|
||||||
largerFileData.size() / 2);
|
|
||||||
FileDataCreator fdPduCreator(conf, fdPduInfo);
|
|
||||||
REQUIRE(tcStore.getFreeElement(&storeId, fdPduCreator.getSerializedSize(), &buf) == OK);
|
|
||||||
REQUIRE(fdPduCreator.serialize(buf, serLen, fdPduCreator.getSerializedSize()) == OK);
|
|
||||||
PacketInfo packetInfo(fdPduCreator.getPduType(), storeId, std::nullopt);
|
|
||||||
idsToCheck.push_back(storeId);
|
|
||||||
packetInfoList.push_back(packetInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
destHandler.performStateMachine();
|
|
||||||
fileDataPduCheck(res, idsToCheck);
|
|
||||||
eofPreparation(cfdpFileSize, crc32);
|
|
||||||
// After EOF, operation is done because no closure was requested
|
|
||||||
destHandler.performStateMachine();
|
|
||||||
eofCheck(res, transactionId);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
#include <catch2/catch_test_macros.hpp>
|
|
||||||
|
|
||||||
TEST_CASE("CFDP Source Handler", "[cfdp]") {}
|
|
@ -2,6 +2,7 @@
|
|||||||
#include <catch2/catch_test_macros.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
#include "fsfw/cfdp.h"
|
#include "fsfw/cfdp.h"
|
||||||
|
#include "fsfw/cfdp/VarLenFields.h"
|
||||||
|
|
||||||
TEST_CASE("CFDP LV", "[cfdp][lv]") {
|
TEST_CASE("CFDP LV", "[cfdp][lv]") {
|
||||||
using namespace cfdp;
|
using namespace cfdp;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include <catch2/catch_test_macros.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
#include "fsfw/cfdp.h"
|
#include "fsfw/cfdp.h"
|
||||||
|
#include "fsfw/cfdp/VarLenFields.h"
|
||||||
|
|
||||||
TEST_CASE("CFDP TLV", "[cfdp][tlv]") {
|
TEST_CASE("CFDP TLV", "[cfdp][tlv]") {
|
||||||
using namespace cfdp;
|
using namespace cfdp;
|
||||||
|
Loading…
Reference in New Issue
Block a user