2022-09-14 19:29:43 +02:00
|
|
|
#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;
|
|
|
|
|
2023-07-17 10:25:09 +02:00
|
|
|
cfdp::DestHandler::DestHandler(DestHandlerParams params, FsfwParams fsfwParams)
|
2022-09-14 19:29:43 +02:00
|
|
|
: tlvVec(params.maxTlvsInOnePdu),
|
2023-07-24 10:06:45 +02:00
|
|
|
msgToUserVec(params.maxTlvsInOnePdu),
|
2023-07-27 14:55:46 +02:00
|
|
|
transactionParams(params.maxFilenameLen),
|
2023-06-30 11:59:22 +02:00
|
|
|
destParams(std::move(params)),
|
2023-07-27 14:55:46 +02:00
|
|
|
fsfwParams(fsfwParams) {
|
2023-06-30 11:59:22 +02:00
|
|
|
transactionParams.pduConf.direction = cfdp::Direction::TOWARDS_SENDER;
|
2022-09-14 19:29:43 +02:00
|
|
|
}
|
|
|
|
|
2023-08-14 20:47:27 +02:00
|
|
|
const cfdp::DestHandler::FsmResult& cfdp::DestHandler::stateMachine() {
|
2022-09-14 19:29:43 +02:00
|
|
|
ReturnValue_t result;
|
|
|
|
uint8_t errorIdx = 0;
|
|
|
|
fsmRes.resetOfIteration();
|
|
|
|
if (fsmRes.step == TransactionStep::IDLE) {
|
2023-06-30 11:59:22 +02:00
|
|
|
for (auto infoIter = destParams.packetListRef.begin();
|
|
|
|
infoIter != destParams.packetListRef.end();) {
|
2022-09-15 18:44:00 +02:00
|
|
|
if (infoIter->pduType == PduType::FILE_DIRECTIVE and
|
|
|
|
infoIter->directiveType == FileDirective::METADATA) {
|
2022-09-14 19:29:43 +02:00
|
|
|
result = handleMetadataPdu(*infoIter);
|
|
|
|
checkAndHandleError(result, errorIdx);
|
|
|
|
// Store data was deleted in PDU handler because a store guard is used
|
2023-06-30 11:59:22 +02:00
|
|
|
destParams.packetListRef.erase(infoIter++);
|
2022-09-14 19:29:43 +02:00
|
|
|
} 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.
|
2023-06-30 11:59:22 +02:00
|
|
|
for (auto infoIter = destParams.packetListRef.begin();
|
|
|
|
infoIter != destParams.packetListRef.end();) {
|
|
|
|
fsfwParams.tcStore->deleteData(infoIter->storeId);
|
2022-09-14 19:29:43 +02:00
|
|
|
infoIter++;
|
|
|
|
}
|
2023-06-30 11:59:22 +02:00
|
|
|
destParams.packetListRef.clear();
|
2022-09-14 19:29:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (fsmRes.step != TransactionStep::IDLE) {
|
|
|
|
fsmRes.callStatus = CallStatus::CALL_AGAIN;
|
|
|
|
}
|
|
|
|
return updateFsmRes(errorIdx);
|
|
|
|
}
|
2023-07-14 15:56:38 +02:00
|
|
|
if (fsmRes.state == CfdpState::BUSY_CLASS_1_NACKED) {
|
2022-09-14 19:29:43 +02:00
|
|
|
if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) {
|
2023-06-30 11:59:22 +02:00
|
|
|
for (auto infoIter = destParams.packetListRef.begin();
|
|
|
|
infoIter != destParams.packetListRef.end();) {
|
2022-09-15 18:44:00 +02:00
|
|
|
if (infoIter->pduType == PduType::FILE_DATA) {
|
2022-09-14 19:29:43 +02:00
|
|
|
result = handleFileDataPdu(*infoIter);
|
|
|
|
checkAndHandleError(result, errorIdx);
|
|
|
|
// Store data was deleted in PDU handler because a store guard is used
|
2023-06-30 11:59:22 +02:00
|
|
|
destParams.packetListRef.erase(infoIter++);
|
2022-09-15 18:44:00 +02:00
|
|
|
} else if (infoIter->pduType == PduType::FILE_DIRECTIVE and
|
|
|
|
infoIter->directiveType == FileDirective::EOF_DIRECTIVE) {
|
2022-09-14 19:29:43 +02:00
|
|
|
// 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
|
2023-06-30 11:59:22 +02:00
|
|
|
destParams.packetListRef.erase(infoIter++);
|
2022-09-14 19:29:43 +02:00
|
|
|
} 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);
|
|
|
|
}
|
2023-07-14 15:56:38 +02:00
|
|
|
if (fsmRes.state == CfdpState::BUSY_CLASS_2_ACKED) {
|
2022-09-14 19:29:43 +02:00
|
|
|
// 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) {
|
2023-06-30 11:59:22 +02:00
|
|
|
if (destParams.packetListRef.full()) {
|
2022-09-14 19:29:43 +02:00
|
|
|
return FAILED;
|
|
|
|
}
|
2023-06-30 11:59:22 +02:00
|
|
|
destParams.packetListRef.push_back(packet);
|
2022-09-14 19:29:43 +02:00
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t cfdp::DestHandler::initialize() {
|
2023-06-30 11:59:22 +02:00
|
|
|
if (fsfwParams.tmStore == nullptr) {
|
|
|
|
fsfwParams.tmStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TM_STORE);
|
|
|
|
if (fsfwParams.tmStore == nullptr) {
|
2022-09-14 19:29:43 +02:00
|
|
|
return FAILED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-30 11:59:22 +02:00
|
|
|
if (fsfwParams.tcStore == nullptr) {
|
|
|
|
fsfwParams.tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
|
|
|
|
if (fsfwParams.tcStore == nullptr) {
|
2022-09-14 19:29:43 +02:00
|
|
|
return FAILED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-30 11:59:22 +02:00
|
|
|
if (fsfwParams.msgQueue == nullptr) {
|
2022-09-14 19:29:43 +02:00
|
|
|
return FAILED;
|
|
|
|
}
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t cfdp::DestHandler::handleMetadataPdu(const PacketInfo& info) {
|
|
|
|
// Process metadata PDU
|
2023-06-30 11:59:22 +02:00
|
|
|
auto constAccessorPair = fsfwParams.tcStore->getData(info.storeId);
|
2022-09-14 19:29:43 +02:00
|
|
|
if (constAccessorPair.first != OK) {
|
|
|
|
// TODO: This is not a CFDP error. Event and/or warning?
|
|
|
|
return constAccessorPair.first;
|
|
|
|
}
|
|
|
|
cfdp::StringLv sourceFileName;
|
|
|
|
cfdp::StringLv destFileName;
|
2023-07-27 14:55:46 +02:00
|
|
|
MetadataGenericInfo metadataInfo(transactionParams.fileSize);
|
2022-09-14 19:29:43 +02:00
|
|
|
MetadataPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(),
|
2023-07-24 10:06:45 +02:00
|
|
|
metadataInfo, tlvVec.data(), tlvVec.size());
|
2022-09-14 19:29:43 +02:00
|
|
|
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
|
2023-06-30 11:59:22 +02:00
|
|
|
auto constAccessorPair = fsfwParams.tcStore->getData(info.storeId);
|
2022-09-14 19:29:43 +02:00
|
|
|
if (constAccessorPair.first != OK) {
|
|
|
|
// TODO: This is not a CFDP error. Event and/or warning?
|
|
|
|
return constAccessorPair.first;
|
|
|
|
}
|
2023-08-04 15:17:53 +02:00
|
|
|
FileDataInfo fdInfo;
|
2022-09-14 19:29:43 +02:00
|
|
|
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);
|
2023-06-30 11:59:22 +02:00
|
|
|
FileOpParams fileOpParams(transactionParams.destName.data(), fileSegmentLen);
|
2023-08-04 15:17:53 +02:00
|
|
|
fileOpParams.offset = fdInfo.getOffset().value();
|
2023-06-30 11:59:22 +02:00
|
|
|
if (destParams.cfg.indicCfg.fileSegmentRecvIndicRequired) {
|
2022-09-14 19:29:43 +02:00
|
|
|
FileSegmentRecvdParams segParams;
|
2023-08-04 15:17:53 +02:00
|
|
|
segParams.offset = fdInfo.getOffset().value();
|
2023-06-30 11:59:22 +02:00
|
|
|
segParams.id = transactionParams.transactionId;
|
2022-09-14 19:29:43 +02:00
|
|
|
segParams.length = fileSegmentLen;
|
|
|
|
segParams.recContState = fdInfo.getRecordContinuationState();
|
|
|
|
size_t segmentMetadatLen = 0;
|
|
|
|
auto* segMetadata = fdInfo.getSegmentMetadata(&segmentMetadatLen);
|
|
|
|
segParams.segmentMetadata = {segMetadata, segmentMetadatLen};
|
2023-06-30 11:59:22 +02:00
|
|
|
destParams.user.fileSegmentRecvdIndication(segParams);
|
2022-09-14 19:29:43 +02:00
|
|
|
}
|
2023-06-30 11:59:22 +02:00
|
|
|
result = destParams.user.vfs.writeToFile(fileOpParams, fileData);
|
2022-09-14 19:29:43 +02:00
|
|
|
if (result != returnvalue::OK) {
|
|
|
|
// TODO: Proper Error handling
|
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2023-02-24 15:49:05 +01:00
|
|
|
sif::error << "cfdp::DestHandler: VFS file write error with code 0x" << std::hex << std::setw(2)
|
|
|
|
<< result << std::endl;
|
2022-09-14 19:29:43 +02:00
|
|
|
#endif
|
2023-06-30 11:59:22 +02:00
|
|
|
transactionParams.vfsErrorCount++;
|
|
|
|
if (transactionParams.vfsErrorCount < 3) {
|
2023-02-24 15:49:05 +01:00
|
|
|
// TODO: Provide execution step as parameter
|
2023-06-30 11:59:22 +02:00
|
|
|
fsfwParams.eventReporter->forwardEvent(events::FILESTORE_ERROR,
|
|
|
|
static_cast<uint8_t>(fsmRes.step), result);
|
2023-02-24 15:49:05 +01:00
|
|
|
}
|
|
|
|
return result;
|
2022-09-14 19:29:43 +02:00
|
|
|
} else {
|
2023-06-30 11:59:22 +02:00
|
|
|
transactionParams.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE;
|
|
|
|
transactionParams.vfsErrorCount = 0;
|
2023-02-24 15:49:05 +01:00
|
|
|
}
|
2023-08-04 15:17:53 +02:00
|
|
|
if (fdInfo.getOffset().value() + fileSegmentLen > transactionParams.progress) {
|
|
|
|
transactionParams.progress = fdInfo.getOffset().value() + fileSegmentLen;
|
2022-09-14 19:29:43 +02:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t cfdp::DestHandler::handleEofPdu(const cfdp::PacketInfo& info) {
|
|
|
|
// Process EOF PDU
|
2023-06-30 11:59:22 +02:00
|
|
|
auto constAccessorPair = fsfwParams.tcStore->getData(info.storeId);
|
2022-09-14 19:29:43 +02:00
|
|
|
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
|
2022-09-15 18:44:00 +02:00
|
|
|
if (eofInfo.getConditionCode() == ConditionCode::NO_ERROR) {
|
2023-06-30 11:59:22 +02:00
|
|
|
transactionParams.crc = eofInfo.getChecksum();
|
2022-09-14 19:29:43 +02:00
|
|
|
uint64_t fileSizeFromEof = eofInfo.getFileSize().value();
|
|
|
|
// CFDP 4.6.1.2.9: Declare file size error if progress exceeds file size
|
2023-06-30 11:59:22 +02:00
|
|
|
if (fileSizeFromEof > transactionParams.progress) {
|
2022-09-14 19:29:43 +02:00
|
|
|
// TODO: File size error
|
|
|
|
}
|
2023-06-30 11:59:22 +02:00
|
|
|
transactionParams.fileSize.setFileSize(fileSizeFromEof, std::nullopt);
|
2022-09-14 19:29:43 +02:00
|
|
|
}
|
2023-06-30 11:59:22 +02:00
|
|
|
if (destParams.cfg.indicCfg.eofRecvIndicRequired) {
|
|
|
|
destParams.user.eofRecvIndication(getTransactionId());
|
2022-09-14 19:29:43 +02:00
|
|
|
}
|
|
|
|
if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) {
|
2023-07-14 15:56:38 +02:00
|
|
|
if (fsmRes.state == CfdpState::BUSY_CLASS_1_NACKED) {
|
2022-09-14 19:29:43 +02:00
|
|
|
fsmRes.step = TransactionStep::TRANSFER_COMPLETION;
|
2023-07-14 15:56:38 +02:00
|
|
|
} else if (fsmRes.state == CfdpState::BUSY_CLASS_2_ACKED) {
|
2022-09-14 19:29:43 +02:00
|
|
|
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;
|
2023-06-30 11:59:22 +02:00
|
|
|
if (not destParams.remoteCfgTable.getRemoteCfg(destId, &remoteCfg)) {
|
2022-09-14 19:29:43 +02:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2023-07-27 14:55:46 +02:00
|
|
|
ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader,
|
|
|
|
MetadataGenericInfo& info) {
|
2023-07-14 15:56:38 +02:00
|
|
|
if (fsmRes.state != CfdpState::IDLE) {
|
2022-09-14 19:29:43 +02:00
|
|
|
// According to standard, discard metadata PDU if we are busy
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
ReturnValue_t result = OK;
|
|
|
|
size_t sourceNameSize = 0;
|
2023-02-24 16:49:23 +01:00
|
|
|
|
2023-07-27 14:55:46 +02:00
|
|
|
const uint8_t* sourceNamePtr = reader.getSourceFileName().getValue(&sourceNameSize);
|
2023-06-30 11:59:22 +02:00
|
|
|
if (sourceNameSize + 1 > transactionParams.sourceName.size()) {
|
2023-02-24 16:49:23 +01:00
|
|
|
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "source filename too large");
|
2022-09-14 19:29:43 +02:00
|
|
|
return FAILED;
|
|
|
|
}
|
2023-06-30 11:59:22 +02:00
|
|
|
std::memcpy(transactionParams.sourceName.data(), sourceNamePtr, sourceNameSize);
|
|
|
|
transactionParams.sourceName[sourceNameSize] = '\0';
|
2022-09-14 19:29:43 +02:00
|
|
|
size_t destNameSize = 0;
|
2023-07-27 14:55:46 +02:00
|
|
|
const uint8_t* destNamePtr = reader.getDestFileName().getValue(&destNameSize);
|
2023-06-30 11:59:22 +02:00
|
|
|
if (destNameSize + 1 > transactionParams.destName.size()) {
|
2023-02-24 16:49:23 +01:00
|
|
|
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "dest filename too large");
|
2022-09-14 19:29:43 +02:00
|
|
|
return FAILED;
|
|
|
|
}
|
2023-06-30 11:59:22 +02:00
|
|
|
std::memcpy(transactionParams.destName.data(), destNamePtr, destNameSize);
|
|
|
|
transactionParams.destName[destNameSize] = '\0';
|
2023-02-24 15:49:05 +01:00
|
|
|
|
2022-09-14 19:29:43 +02:00
|
|
|
// 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) {
|
2023-06-30 11:59:22 +02:00
|
|
|
FilesystemParams fparams(transactionParams.destName.data());
|
2023-02-24 16:49:23 +01:00
|
|
|
// handling to allow only specifying target directory. Example:
|
|
|
|
// Source path /test/hello.txt, dest path /tmp -> dest path /tmp/hello.txt
|
2023-06-30 11:59:22 +02:00
|
|
|
if (destParams.user.vfs.isDirectory(transactionParams.destName.data())) {
|
2023-02-24 16:49:23 +01:00
|
|
|
result = tryBuildingAbsoluteDestName(destNameSize);
|
|
|
|
if (result != OK) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
2023-06-30 11:59:22 +02:00
|
|
|
if (destParams.user.vfs.fileExists(fparams)) {
|
|
|
|
result = destParams.user.vfs.truncateFile(fparams);
|
2023-02-24 15:49:05 +01:00
|
|
|
if (result != returnvalue::OK) {
|
2023-02-24 16:49:23 +01:00
|
|
|
fileErrorHandler(events::FILESTORE_ERROR, result, "file truncation error");
|
2023-02-24 15:49:05 +01:00
|
|
|
return FAILED;
|
|
|
|
// TODO: Relevant for filestore rejection error?
|
|
|
|
}
|
2022-09-14 19:29:43 +02:00
|
|
|
} else {
|
2023-06-30 11:59:22 +02:00
|
|
|
result = destParams.user.vfs.createFile(fparams);
|
2022-09-14 19:29:43 +02:00
|
|
|
if (result != OK) {
|
2023-02-24 16:49:23 +01:00
|
|
|
fileErrorHandler(events::FILESTORE_ERROR, result, "file creation error");
|
2023-02-24 15:49:05 +01:00
|
|
|
return FAILED;
|
|
|
|
// TODO: Relevant for filestore rejection error?
|
2022-09-14 19:29:43 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-02-24 15:49:05 +01:00
|
|
|
EntityId sourceId;
|
|
|
|
reader.getSourceId(sourceId);
|
2023-06-30 11:59:22 +02:00
|
|
|
if (not destParams.remoteCfgTable.getRemoteCfg(sourceId, &transactionParams.remoteCfg)) {
|
2023-02-24 15:49:05 +01:00
|
|
|
// TODO: Warning, event etc.
|
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
|
|
sif::warning << "cfdp::DestHandler" << __func__
|
|
|
|
<< ": No remote configuration found for destination ID "
|
2023-07-17 13:43:48 +02:00
|
|
|
<< transactionParams.pduConf.sourceId.getValue() << std::endl;
|
2023-02-24 15:49:05 +01:00
|
|
|
#endif
|
|
|
|
return FAILED;
|
|
|
|
}
|
|
|
|
fsmRes.step = TransactionStep::TRANSACTION_START;
|
|
|
|
if (reader.getTransmissionMode() == TransmissionMode::UNACKNOWLEDGED) {
|
2023-07-14 15:56:38 +02:00
|
|
|
fsmRes.state = CfdpState::BUSY_CLASS_1_NACKED;
|
2023-02-24 15:49:05 +01:00
|
|
|
} else if (reader.getTransmissionMode() == TransmissionMode::ACKNOWLEDGED) {
|
2023-07-14 15:56:38 +02:00
|
|
|
fsmRes.state = CfdpState::BUSY_CLASS_2_ACKED;
|
2023-02-24 15:49:05 +01:00
|
|
|
}
|
2023-06-30 11:59:22 +02:00
|
|
|
transactionParams.checksumType = info.getChecksumType();
|
|
|
|
transactionParams.closureRequested = info.isClosureRequested();
|
|
|
|
reader.fillConfig(transactionParams.pduConf);
|
|
|
|
transactionParams.pduConf.direction = Direction::TOWARDS_SENDER;
|
|
|
|
transactionParams.transactionId.entityId = transactionParams.pduConf.sourceId;
|
|
|
|
transactionParams.transactionId.seqNum = transactionParams.pduConf.seqNum;
|
2023-07-27 14:55:46 +02:00
|
|
|
transactionParams.fileSize = info.getFileSize();
|
2022-09-14 19:29:43 +02:00
|
|
|
fsmRes.step = TransactionStep::RECEIVING_FILE_DATA_PDUS;
|
2023-07-27 14:55:46 +02:00
|
|
|
MetadataRecvdParams params(transactionParams.transactionId, transactionParams.pduConf.sourceId,
|
|
|
|
transactionParams.fileSize);
|
2023-06-30 11:59:22 +02:00
|
|
|
params.destFileName = transactionParams.destName.data();
|
|
|
|
params.sourceFileName = transactionParams.sourceName.data();
|
2023-08-16 13:15:34 +02:00
|
|
|
params.numberOfMsgsToUser = 0;
|
2023-07-24 10:06:45 +02:00
|
|
|
for (const auto& opt : tlvVec) {
|
|
|
|
if (opt.getType() == TlvType::MSG_TO_USER) {
|
2023-08-16 13:15:34 +02:00
|
|
|
msgToUserVec[params.numberOfMsgsToUser] =
|
|
|
|
MessageToUserTlv(opt.getValue(), opt.getLengthField());
|
|
|
|
params.numberOfMsgsToUser++;
|
2023-07-24 10:06:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
params.msgsToUserArray = msgToUserVec.data();
|
2023-06-30 11:59:22 +02:00
|
|
|
destParams.user.metadataRecvdIndication(params);
|
2022-09-14 19:29:43 +02:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-07-14 15:56:38 +02:00
|
|
|
cfdp::CfdpState cfdp::DestHandler::getCfdpState() const { return fsmRes.state; }
|
2022-09-14 19:29:43 +02:00
|
|
|
|
|
|
|
ReturnValue_t cfdp::DestHandler::handleTransferCompletion() {
|
|
|
|
ReturnValue_t result;
|
2023-06-30 11:59:22 +02:00
|
|
|
if (transactionParams.checksumType != ChecksumType::NULL_CHECKSUM) {
|
2022-09-14 19:29:43 +02:00
|
|
|
result = checksumVerification();
|
|
|
|
if (result != OK) {
|
|
|
|
// TODO: Warning / error handling?
|
|
|
|
}
|
|
|
|
} else {
|
2023-06-30 11:59:22 +02:00
|
|
|
transactionParams.conditionCode = ConditionCode::NO_ERROR;
|
2022-09-14 19:29:43 +02:00
|
|
|
}
|
|
|
|
result = noticeOfCompletion();
|
|
|
|
if (result != OK) {
|
|
|
|
}
|
2023-07-14 15:56:38 +02:00
|
|
|
if (fsmRes.state == CfdpState::BUSY_CLASS_1_NACKED) {
|
2023-06-30 11:59:22 +02:00
|
|
|
if (transactionParams.closureRequested) {
|
2022-09-14 19:29:43 +02:00
|
|
|
fsmRes.step = TransactionStep::SENDING_FINISHED_PDU;
|
|
|
|
} else {
|
|
|
|
finish();
|
|
|
|
}
|
2023-07-14 15:56:38 +02:00
|
|
|
} else if (fsmRes.state == CfdpState::BUSY_CLASS_2_ACKED) {
|
2022-09-14 19:29:43 +02:00
|
|
|
fsmRes.step = TransactionStep::SENDING_FINISHED_PDU;
|
|
|
|
}
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
2023-02-24 16:49:23 +01:00
|
|
|
ReturnValue_t cfdp::DestHandler::tryBuildingAbsoluteDestName(size_t destNameSize) {
|
2023-06-30 11:59:22 +02:00
|
|
|
// A path may only have a maximum of 256 characters in CFDP, so this buffer should be sufficient
|
|
|
|
// for all use-cases.
|
|
|
|
char baseNameBuf[512]{};
|
|
|
|
FilesystemParams fparamsSrc(transactionParams.sourceName.data());
|
2023-02-24 16:49:23 +01:00
|
|
|
size_t baseNameLen = 0;
|
2023-06-30 11:59:22 +02:00
|
|
|
ReturnValue_t result = destParams.user.vfs.getBaseFilename(fparamsSrc, baseNameBuf,
|
|
|
|
sizeof(baseNameBuf), baseNameLen);
|
2023-02-24 16:49:23 +01:00
|
|
|
if (result != returnvalue::OK or baseNameLen == 0) {
|
|
|
|
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "error retrieving source base name");
|
|
|
|
return FAILED;
|
|
|
|
}
|
|
|
|
// Destination name + slash + base name + null termination
|
2023-06-30 11:59:22 +02:00
|
|
|
if (destNameSize + 1 + baseNameLen + 1 > transactionParams.destName.size()) {
|
2023-02-24 16:49:23 +01:00
|
|
|
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0,
|
|
|
|
"dest filename too large after adding source base name");
|
|
|
|
return FAILED;
|
|
|
|
}
|
2023-06-30 11:59:22 +02:00
|
|
|
transactionParams.destName[destNameSize++] = '/';
|
|
|
|
std::memcpy(transactionParams.destName.data() + destNameSize, baseNameBuf, baseNameLen);
|
2023-02-24 16:49:23 +01:00
|
|
|
destNameSize += baseNameLen;
|
2023-06-30 11:59:22 +02:00
|
|
|
transactionParams.destName[destNameSize++] = '\0';
|
2023-02-24 16:49:23 +01:00
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
2023-06-30 12:01:18 +02:00
|
|
|
void cfdp::DestHandler::fileErrorHandler(Event event, ReturnValue_t result,
|
|
|
|
const char* info) const {
|
|
|
|
fsfwParams.eventReporter->forwardEvent(event, static_cast<uint8_t>(fsmRes.step), result);
|
2023-02-24 16:49:23 +01:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
|
|
sif::warning << "cfdp::DestHandler: " << info << std::endl;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2022-09-14 19:29:43 +02:00
|
|
|
void cfdp::DestHandler::finish() {
|
2023-06-30 11:59:22 +02:00
|
|
|
transactionParams.reset();
|
|
|
|
destParams.packetListRef.clear();
|
2023-07-14 15:56:38 +02:00
|
|
|
fsmRes.state = CfdpState::IDLE;
|
2022-09-14 19:29:43 +02:00
|
|
|
fsmRes.step = TransactionStep::IDLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t cfdp::DestHandler::checksumVerification() {
|
|
|
|
std::array<uint8_t, 1024> buf{};
|
|
|
|
etl::crc32 crcCalc;
|
|
|
|
uint64_t currentOffset = 0;
|
2023-06-30 11:59:22 +02:00
|
|
|
FileOpParams params(transactionParams.destName.data(), transactionParams.fileSize.value());
|
|
|
|
while (currentOffset < transactionParams.fileSize.value()) {
|
2022-09-14 19:29:43 +02:00
|
|
|
uint64_t readLen;
|
2023-06-30 11:59:22 +02:00
|
|
|
if (currentOffset + buf.size() > transactionParams.fileSize.value()) {
|
|
|
|
readLen = transactionParams.fileSize.value() - currentOffset;
|
2022-09-14 19:29:43 +02:00
|
|
|
} else {
|
|
|
|
readLen = buf.size();
|
|
|
|
}
|
|
|
|
if (readLen > 0) {
|
|
|
|
params.offset = currentOffset;
|
|
|
|
params.size = readLen;
|
2023-06-30 11:59:22 +02:00
|
|
|
auto result = destParams.user.vfs.readFromFile(params, buf.data(), buf.size());
|
2022-09-14 19:29:43 +02:00
|
|
|
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();
|
2023-06-30 11:59:22 +02:00
|
|
|
if (value == transactionParams.crc) {
|
|
|
|
transactionParams.conditionCode = ConditionCode::NO_ERROR;
|
|
|
|
transactionParams.deliveryCode = FileDeliveryCode::DATA_COMPLETE;
|
2022-09-14 19:29:43 +02:00
|
|
|
} else {
|
|
|
|
// TODO: Proper error handling
|
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2023-07-17 13:43:48 +02:00
|
|
|
sif::warning << "CRC check for file " << transactionParams.destName.data() << " failed"
|
|
|
|
<< std::endl;
|
2022-09-14 19:29:43 +02:00
|
|
|
#endif
|
2023-06-30 11:59:22 +02:00
|
|
|
transactionParams.conditionCode = ConditionCode::FILE_CHECKSUM_FAILURE;
|
2022-09-14 19:29:43 +02:00
|
|
|
}
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t cfdp::DestHandler::noticeOfCompletion() {
|
2023-06-30 11:59:22 +02:00
|
|
|
if (destParams.cfg.indicCfg.transactionFinishedIndicRequired) {
|
|
|
|
TransactionFinishedParams params(
|
|
|
|
transactionParams.transactionId, transactionParams.conditionCode,
|
|
|
|
transactionParams.deliveryCode, transactionParams.deliveryStatus);
|
|
|
|
destParams.user.transactionFinishedIndication(params);
|
2022-09-14 19:29:43 +02:00
|
|
|
}
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t cfdp::DestHandler::sendFinishedPdu() {
|
2023-06-30 11:59:22 +02:00
|
|
|
FinishedInfo info(transactionParams.conditionCode, transactionParams.deliveryCode,
|
|
|
|
transactionParams.deliveryStatus);
|
|
|
|
FinishPduCreator finishedPdu(transactionParams.pduConf, info);
|
2022-09-14 19:29:43 +02:00
|
|
|
store_address_t storeId;
|
|
|
|
uint8_t* dataPtr = nullptr;
|
|
|
|
ReturnValue_t result =
|
2023-06-30 11:59:22 +02:00
|
|
|
fsfwParams.tmStore->getFreeElement(&storeId, finishedPdu.getSerializedSize(), &dataPtr);
|
2022-09-14 19:29:43 +02:00
|
|
|
if (result != OK) {
|
2022-10-17 12:19:31 +02:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
|
|
sif::warning << "cfdp::DestHandler:sendFinishedPdu: Getting store slot failed" << std::endl;
|
|
|
|
#endif
|
2023-06-30 11:59:22 +02:00
|
|
|
fsfwParams.eventReporter->forwardEvent(events::STORE_ERROR, result, 0);
|
2022-09-14 19:29:43 +02:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
size_t serLen = 0;
|
|
|
|
result = finishedPdu.serialize(dataPtr, serLen, finishedPdu.getSerializedSize());
|
|
|
|
if (result != OK) {
|
2022-10-17 12:19:31 +02:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
|
|
sif::warning << "cfdp::DestHandler::sendFinishedPdu: Serializing Finished PDU failed"
|
|
|
|
<< std::endl;
|
|
|
|
#endif
|
2023-06-30 11:59:22 +02:00
|
|
|
fsfwParams.eventReporter->forwardEvent(events::SERIALIZATION_ERROR, result, 0);
|
2022-09-14 19:29:43 +02:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
TmTcMessage msg(storeId);
|
2023-06-30 11:59:22 +02:00
|
|
|
result = fsfwParams.msgQueue->sendMessage(fsfwParams.packetDest.getReportReceptionQueue(), &msg);
|
2022-09-14 19:29:43 +02:00
|
|
|
if (result != OK) {
|
2022-10-17 12:19:31 +02:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
|
|
sif::warning << "cfdp::DestHandler::sendFinishedPdu: Sending PDU failed" << std::endl;
|
|
|
|
#endif
|
2023-06-30 11:59:22 +02:00
|
|
|
fsfwParams.eventReporter->forwardEvent(events::MSG_QUEUE_ERROR, result, 0);
|
2022-09-14 19:29:43 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-06-30 11:59:22 +02:00
|
|
|
const cfdp::TransactionId& cfdp::DestHandler::getTransactionId() const {
|
|
|
|
return transactionParams.transactionId;
|
|
|
|
}
|
2022-09-14 19:29:43 +02:00
|
|
|
|
|
|
|
void cfdp::DestHandler::checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx) {
|
|
|
|
if (result != OK and errorIdx < 3) {
|
|
|
|
fsmRes.errorCodes[errorIdx] = result;
|
|
|
|
errorIdx++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-30 11:59:22 +02:00
|
|
|
void cfdp::DestHandler::setMsgQueue(MessageQueueIF& queue) { fsfwParams.msgQueue = &queue; }
|
2022-09-14 19:29:43 +02:00
|
|
|
|
|
|
|
void cfdp::DestHandler::setEventReporter(EventReportingProxyIF& reporter) {
|
2023-06-30 11:59:22 +02:00
|
|
|
fsfwParams.eventReporter = &reporter;
|
2022-09-14 19:29:43 +02:00
|
|
|
}
|
|
|
|
|
2023-06-30 11:59:22 +02:00
|
|
|
const cfdp::DestHandlerParams& cfdp::DestHandler::getDestHandlerParams() const {
|
|
|
|
return destParams;
|
|
|
|
}
|
2022-09-14 19:29:43 +02:00
|
|
|
|
2023-06-30 11:59:22 +02:00
|
|
|
StorageManagerIF* cfdp::DestHandler::getTmStore() const { return fsfwParams.tmStore; }
|
|
|
|
StorageManagerIF* cfdp::DestHandler::getTcStore() const { return fsfwParams.tcStore; }
|