Merge branch 'develop' into stopwatch-fix
This commit is contained in:
commit
c2d9370aa1
@ -178,16 +178,25 @@ ReturnValue_t cfdp::DestHandler::handleFileDataPdu(const cfdp::PacketInfo& info)
|
|||||||
dp.user.fileSegmentRecvdIndication(segParams);
|
dp.user.fileSegmentRecvdIndication(segParams);
|
||||||
}
|
}
|
||||||
result = dp.user.vfs.writeToFile(fileOpParams, fileData);
|
result = dp.user.vfs.writeToFile(fileOpParams, fileData);
|
||||||
if (offset.value() + fileSegmentLen > tp.progress) {
|
|
||||||
tp.progress = offset.value() + 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
|
||||||
sif::error << "File write error" << std::endl;
|
sif::error << "cfdp::DestHandler: VFS file write error with code 0x" << std::hex << std::setw(2)
|
||||||
|
<< result << std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
tp.vfsErrorCount++;
|
||||||
|
if (tp.vfsErrorCount < 3) {
|
||||||
|
// TODO: Provide execution step as parameter
|
||||||
|
fp.eventReporter->forwardEvent(events::FILESTORE_ERROR, static_cast<uint8_t>(fsmRes.step),
|
||||||
|
result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
} else {
|
} else {
|
||||||
tp.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE;
|
tp.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE;
|
||||||
|
tp.vfsErrorCount = 0;
|
||||||
|
}
|
||||||
|
if (offset.value() + fileSegmentLen > tp.progress) {
|
||||||
|
tp.progress = offset.value() + fileSegmentLen;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -271,35 +280,55 @@ ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader, Met
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
ReturnValue_t result = OK;
|
ReturnValue_t result = OK;
|
||||||
fsmRes.step = TransactionStep::TRANSACTION_START;
|
|
||||||
if (reader.getTransmissionMode() == TransmissionMode::UNACKNOWLEDGED) {
|
|
||||||
fsmRes.state = CfdpStates::BUSY_CLASS_1_NACKED;
|
|
||||||
} else if (reader.getTransmissionMode() == TransmissionMode::ACKNOWLEDGED) {
|
|
||||||
fsmRes.state = CfdpStates::BUSY_CLASS_2_ACKED;
|
|
||||||
}
|
|
||||||
tp.checksumType = info.getChecksumType();
|
|
||||||
tp.closureRequested = info.isClosureRequested();
|
|
||||||
size_t sourceNameSize = 0;
|
size_t sourceNameSize = 0;
|
||||||
|
|
||||||
const uint8_t* sourceNamePtr = info.getSourceFileName().getValue(&sourceNameSize);
|
const uint8_t* sourceNamePtr = info.getSourceFileName().getValue(&sourceNameSize);
|
||||||
if (sourceNameSize > tp.sourceName.size()) {
|
if (sourceNameSize + 1 > tp.sourceName.size()) {
|
||||||
// TODO: Warning, event etc.
|
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "source filename too large");
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
std::memcpy(tp.sourceName.data(), sourceNamePtr, sourceNameSize);
|
std::memcpy(tp.sourceName.data(), sourceNamePtr, sourceNameSize);
|
||||||
tp.sourceName[sourceNameSize] = '\0';
|
tp.sourceName[sourceNameSize] = '\0';
|
||||||
size_t destNameSize = 0;
|
size_t destNameSize = 0;
|
||||||
const uint8_t* destNamePtr = info.getDestFileName().getValue(&destNameSize);
|
const uint8_t* destNamePtr = info.getDestFileName().getValue(&destNameSize);
|
||||||
if (destNameSize > tp.destName.size()) {
|
if (destNameSize + 1 > tp.destName.size()) {
|
||||||
// TODO: Warning, event etc.
|
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "dest filename too large");
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
std::memcpy(tp.destName.data(), destNamePtr, destNameSize);
|
std::memcpy(tp.destName.data(), destNamePtr, destNameSize);
|
||||||
tp.destName[destNameSize] = '\0';
|
tp.destName[destNameSize] = '\0';
|
||||||
reader.fillConfig(tp.pduConf);
|
|
||||||
tp.pduConf.direction = Direction::TOWARDS_SENDER;
|
// If both dest name size and source name size are 0, we are dealing with a metadata only PDU,
|
||||||
tp.transactionId.entityId = tp.pduConf.sourceId;
|
// so there is no need to create a file or truncate an existing file
|
||||||
tp.transactionId.seqNum = tp.pduConf.seqNum;
|
if (destNameSize > 0 and sourceNameSize > 0) {
|
||||||
if (not dp.remoteCfgTable.getRemoteCfg(tp.pduConf.sourceId, &tp.remoteCfg)) {
|
FilesystemParams fparams(tp.destName.data());
|
||||||
|
// handling to allow only specifying target directory. Example:
|
||||||
|
// Source path /test/hello.txt, dest path /tmp -> dest path /tmp/hello.txt
|
||||||
|
if (dp.user.vfs.isDirectory(tp.destName.data())) {
|
||||||
|
result = tryBuildingAbsoluteDestName(destNameSize);
|
||||||
|
if (result != OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dp.user.vfs.fileExists(fparams)) {
|
||||||
|
result = dp.user.vfs.truncateFile(fparams);
|
||||||
|
if (result != returnvalue::OK) {
|
||||||
|
fileErrorHandler(events::FILESTORE_ERROR, result, "file truncation error");
|
||||||
|
return FAILED;
|
||||||
|
// TODO: Relevant for filestore rejection error?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = dp.user.vfs.createFile(fparams);
|
||||||
|
if (result != OK) {
|
||||||
|
fileErrorHandler(events::FILESTORE_ERROR, result, "file creation error");
|
||||||
|
return FAILED;
|
||||||
|
// TODO: Relevant for filestore rejection error?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EntityId sourceId;
|
||||||
|
reader.getSourceId(sourceId);
|
||||||
|
if (not dp.remoteCfgTable.getRemoteCfg(sourceId, &tp.remoteCfg)) {
|
||||||
// TODO: Warning, event etc.
|
// TODO: Warning, event etc.
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning << "cfdp::DestHandler" << __func__
|
sif::warning << "cfdp::DestHandler" << __func__
|
||||||
@ -308,22 +337,18 @@ ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader, Met
|
|||||||
#endif
|
#endif
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
// If both dest name size and source name size are 0, we are dealing with a metadata only PDU,
|
fsmRes.step = TransactionStep::TRANSACTION_START;
|
||||||
// so there is no need to create a file or truncate an existing file
|
if (reader.getTransmissionMode() == TransmissionMode::UNACKNOWLEDGED) {
|
||||||
if (destNameSize > 0 and sourceNameSize > 0) {
|
fsmRes.state = CfdpStates::BUSY_CLASS_1_NACKED;
|
||||||
FilesystemParams fparams(tp.destName.data());
|
} else if (reader.getTransmissionMode() == TransmissionMode::ACKNOWLEDGED) {
|
||||||
// TODO: Filesystem errors?
|
fsmRes.state = CfdpStates::BUSY_CLASS_2_ACKED;
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
tp.checksumType = info.getChecksumType();
|
||||||
|
tp.closureRequested = info.isClosureRequested();
|
||||||
|
reader.fillConfig(tp.pduConf);
|
||||||
|
tp.pduConf.direction = Direction::TOWARDS_SENDER;
|
||||||
|
tp.transactionId.entityId = tp.pduConf.sourceId;
|
||||||
|
tp.transactionId.seqNum = tp.pduConf.seqNum;
|
||||||
fsmRes.step = TransactionStep::RECEIVING_FILE_DATA_PDUS;
|
fsmRes.step = TransactionStep::RECEIVING_FILE_DATA_PDUS;
|
||||||
MetadataRecvdParams params(tp.transactionId, tp.pduConf.sourceId);
|
MetadataRecvdParams params(tp.transactionId, tp.pduConf.sourceId);
|
||||||
params.fileSize = tp.fileSize.getSize();
|
params.fileSize = tp.fileSize.getSize();
|
||||||
@ -362,6 +387,37 @@ ReturnValue_t cfdp::DestHandler::handleTransferCompletion() {
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReturnValue_t cfdp::DestHandler::tryBuildingAbsoluteDestName(size_t destNameSize) {
|
||||||
|
char baseNameBuf[tp.destName.size()]{};
|
||||||
|
FilesystemParams fparamsSrc(tp.sourceName.data());
|
||||||
|
size_t baseNameLen = 0;
|
||||||
|
ReturnValue_t result =
|
||||||
|
dp.user.vfs.getBaseFilename(fparamsSrc, baseNameBuf, sizeof(baseNameBuf), baseNameLen);
|
||||||
|
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
|
||||||
|
if (destNameSize + 1 + baseNameLen + 1 > tp.destName.size()) {
|
||||||
|
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0,
|
||||||
|
"dest filename too large after adding source base name");
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
tp.destName[destNameSize++] = '/';
|
||||||
|
std::memcpy(tp.destName.data() + destNameSize, baseNameBuf, baseNameLen);
|
||||||
|
destNameSize += baseNameLen;
|
||||||
|
tp.destName[destNameSize++] = '\0';
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cfdp::DestHandler::fileErrorHandler(Event event, ReturnValue_t result, const char* info) {
|
||||||
|
fp.eventReporter->forwardEvent(events::FILENAME_TOO_LARGE_ERROR,
|
||||||
|
static_cast<uint8_t>(fsmRes.step), result);
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::warning << "cfdp::DestHandler: " << info << std::endl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void cfdp::DestHandler::finish() {
|
void cfdp::DestHandler::finish() {
|
||||||
tp.reset();
|
tp.reset();
|
||||||
dp.packetListRef.clear();
|
dp.packetListRef.clear();
|
||||||
|
@ -84,7 +84,7 @@ enum class CallStatus { DONE, CALL_AFTER_DELAY, CALL_AGAIN };
|
|||||||
|
|
||||||
class DestHandler {
|
class DestHandler {
|
||||||
public:
|
public:
|
||||||
enum class TransactionStep {
|
enum class TransactionStep : uint8_t {
|
||||||
IDLE = 0,
|
IDLE = 0,
|
||||||
TRANSACTION_START = 1,
|
TRANSACTION_START = 1,
|
||||||
RECEIVING_FILE_DATA_PDUS = 2,
|
RECEIVING_FILE_DATA_PDUS = 2,
|
||||||
@ -157,11 +157,13 @@ class DestHandler {
|
|||||||
progress = 0;
|
progress = 0;
|
||||||
remoteCfg = nullptr;
|
remoteCfg = nullptr;
|
||||||
closureRequested = false;
|
closureRequested = false;
|
||||||
|
vfsErrorCount = 0;
|
||||||
checksumType = ChecksumType::NULL_CHECKSUM;
|
checksumType = ChecksumType::NULL_CHECKSUM;
|
||||||
}
|
}
|
||||||
|
|
||||||
ChecksumType checksumType = ChecksumType::NULL_CHECKSUM;
|
ChecksumType checksumType = ChecksumType::NULL_CHECKSUM;
|
||||||
bool closureRequested = false;
|
bool closureRequested = false;
|
||||||
|
uint16_t vfsErrorCount = 0;
|
||||||
std::vector<char> sourceName;
|
std::vector<char> sourceName;
|
||||||
std::vector<char> destName;
|
std::vector<char> destName;
|
||||||
cfdp::FileSize fileSize;
|
cfdp::FileSize fileSize;
|
||||||
@ -189,9 +191,11 @@ class DestHandler {
|
|||||||
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();
|
||||||
|
ReturnValue_t tryBuildingAbsoluteDestName(size_t destNameSize);
|
||||||
ReturnValue_t sendFinishedPdu();
|
ReturnValue_t sendFinishedPdu();
|
||||||
ReturnValue_t noticeOfCompletion();
|
ReturnValue_t noticeOfCompletion();
|
||||||
ReturnValue_t checksumVerification();
|
ReturnValue_t checksumVerification();
|
||||||
|
void fileErrorHandler(Event event, ReturnValue_t result, const char* info);
|
||||||
const FsmResult& updateFsmRes(uint8_t errors);
|
const FsmResult& updateFsmRes(uint8_t errors);
|
||||||
void checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx);
|
void checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx);
|
||||||
void finish();
|
void finish();
|
||||||
|
@ -12,6 +12,9 @@ namespace events {
|
|||||||
static constexpr Event STORE_ERROR = event::makeEvent(SSID, 0, 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 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);
|
||||||
|
//! [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);
|
||||||
|
|
||||||
} // namespace events
|
} // namespace events
|
||||||
|
|
||||||
|
@ -74,6 +74,12 @@ class HasFileSystemIF {
|
|||||||
return MessageQueueIF::NO_QUEUE;
|
return MessageQueueIF::NO_QUEUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the base filename without the full directory path
|
||||||
|
virtual ReturnValue_t getBaseFilename(FilesystemParams params, char* nameBuf, size_t maxLen,
|
||||||
|
size_t& baseNameLen) = 0;
|
||||||
|
|
||||||
|
virtual bool isDirectory(const char* path) = 0;
|
||||||
|
|
||||||
virtual bool fileExists(FilesystemParams params) = 0;
|
virtual bool fileExists(FilesystemParams params) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -79,7 +79,7 @@ ReturnValue_t CServiceHealthCommanding::prepareCommand(CommandMessage *message,
|
|||||||
}
|
}
|
||||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH): {
|
case (Subservice::COMMAND_ANNOUNCE_HEALTH): {
|
||||||
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE);
|
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE);
|
||||||
break;
|
return CommandingServiceBase::EXECUTION_COMPLETE;
|
||||||
}
|
}
|
||||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): {
|
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): {
|
||||||
ReturnValue_t result = iterateHealthTable(true);
|
ReturnValue_t result = iterateHealthTable(true);
|
||||||
|
@ -160,3 +160,18 @@ ReturnValue_t HostFilesystem::truncateFile(FilesystemParams params) {
|
|||||||
ofstream of(path);
|
ofstream of(path);
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HostFilesystem::isDirectory(const char *path) { return filesystem::is_directory(path); }
|
||||||
|
|
||||||
|
ReturnValue_t HostFilesystem::getBaseFilename(FilesystemParams params, char *nameBuf, size_t maxLen,
|
||||||
|
size_t &baseNameLen) {
|
||||||
|
std::string path(params.path);
|
||||||
|
std::string baseName = path.substr(path.find_last_of("/\\") + 1);
|
||||||
|
if (baseName.size() + 1 > maxLen) {
|
||||||
|
return returnvalue::FAILED;
|
||||||
|
}
|
||||||
|
std::memcpy(nameBuf, baseName.c_str(), baseName.size());
|
||||||
|
nameBuf[baseName.size()] = '\0';
|
||||||
|
baseNameLen = baseName.size();
|
||||||
|
return returnvalue::OK;
|
||||||
|
}
|
||||||
|
@ -9,6 +9,9 @@ class HostFilesystem : public HasFileSystemIF {
|
|||||||
public:
|
public:
|
||||||
HostFilesystem();
|
HostFilesystem();
|
||||||
|
|
||||||
|
ReturnValue_t getBaseFilename(FilesystemParams params, char *nameBuf, size_t maxLen,
|
||||||
|
size_t &baseNameLen) override;
|
||||||
|
bool isDirectory(const char *path) override;
|
||||||
bool fileExists(FilesystemParams params) override;
|
bool fileExists(FilesystemParams params) override;
|
||||||
ReturnValue_t truncateFile(FilesystemParams params) override;
|
ReturnValue_t truncateFile(FilesystemParams params) override;
|
||||||
ReturnValue_t writeToFile(FileOpParams params, const uint8_t *data) override;
|
ReturnValue_t writeToFile(FileOpParams params, const uint8_t *data) override;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <fsfw_hal/linux/spi/SpiCookie.h>
|
#include <fsfw_hal/linux/spi/SpiCookie.h>
|
||||||
|
|
||||||
#include "fsfw/ipc/MutexIF.h"
|
#include "fsfw/ipc/MutexIF.h"
|
||||||
#include "fsfw/returnvalues/returnvalue.h"
|
#include "fsfw/returnvalues/returnvalue.h"
|
||||||
#include "fsfw_hal/common/gpio/GpioIF.h"
|
#include "fsfw_hal/common/gpio/GpioIF.h"
|
||||||
|
@ -138,3 +138,10 @@ ReturnValue_t FilesystemMock::truncateFile(FilesystemParams params) {
|
|||||||
truncateCalledOnFile = params.path;
|
truncateCalledOnFile = params.path;
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReturnValue_t FilesystemMock::getBaseFilename(FilesystemParams params, char *nameBuf, size_t maxLen,
|
||||||
|
size_t &baseNameLen) {
|
||||||
|
return returnvalue::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FilesystemMock::isDirectory(const char *path) { return false; }
|
||||||
|
@ -56,6 +56,10 @@ 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,
|
||||||
|
size_t &baseNameLen) override;
|
||||||
|
|
||||||
|
bool isDirectory(const char *path) override;
|
||||||
bool fileExists(FilesystemParams params) override;
|
bool fileExists(FilesystemParams params) override;
|
||||||
ReturnValue_t truncateFile(FilesystemParams params) override;
|
ReturnValue_t truncateFile(FilesystemParams params) override;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user