Merge pull request 'Bump FSFW' (#31) from bump-fsfw into develop
Reviewed-on: #31
This commit is contained in:
commit
a4943f1cf0
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,5 +1,5 @@
|
||||
# PyCharm and CLion
|
||||
/.idea/*
|
||||
.idea/*
|
||||
!/.idea/runConfigurations
|
||||
!/.idea/cmake.xml
|
||||
!/.idea/codeStyles
|
||||
|
@ -2,7 +2,7 @@
|
||||
<project version="4">
|
||||
<component name="CMakeSharedSettings">
|
||||
<configurations>
|
||||
<configuration PROFILE_NAME="Debug Test" ENABLED="true" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DFSFW_BUILD_TESTS=ON -DFSFW_OSAL=host" />
|
||||
<configuration PROFILE_NAME="Debug Test" ENABLED="true" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON" NO_GENERATOR="true" />
|
||||
</configurations>
|
||||
</component>
|
||||
</project>
|
@ -32,6 +32,7 @@ add_subdirectory(timemanager)
|
||||
add_subdirectory(tmtcpacket)
|
||||
add_subdirectory(tmtcservices)
|
||||
add_subdirectory(filesystem)
|
||||
add_subdirectory(util)
|
||||
|
||||
# Optional
|
||||
|
||||
|
@ -4,8 +4,9 @@ CfdpMessage::CfdpMessage() = default;
|
||||
|
||||
CfdpMessage::~CfdpMessage() = default;
|
||||
|
||||
void CfdpMessage::setCommand(CommandMessage *message, store_address_t cfdpPacket) {
|
||||
message->setParameter(cfdpPacket.raw);
|
||||
void CfdpMessage::setPutRequest(CommandMessage *message, store_address_t putRequest) {
|
||||
message->setCommand(PUT_REQUEST);
|
||||
message->setParameter(putRequest.raw);
|
||||
}
|
||||
|
||||
store_address_t CfdpMessage::getStoreId(const CommandMessage *message) {
|
||||
|
@ -11,9 +11,11 @@ class CfdpMessage {
|
||||
|
||||
public:
|
||||
static const uint8_t MESSAGE_ID = messagetypes::CFDP;
|
||||
static const Command_t PUT_REQUEST = MAKE_COMMAND_ID(1);
|
||||
static const Command_t CANCEL_REQUEST = MAKE_COMMAND_ID(1);
|
||||
|
||||
virtual ~CfdpMessage();
|
||||
static void setCommand(CommandMessage* message, store_address_t cfdpPacket);
|
||||
static void setPutRequest(CommandMessage* message, store_address_t putRequest);
|
||||
|
||||
static store_address_t getStoreId(const CommandMessage* message);
|
||||
|
||||
|
@ -8,11 +8,14 @@
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
struct FileSize : public SerializeIF {
|
||||
/**
|
||||
* Helper type for the CFDP File Size Sensitive (FSS) fields.
|
||||
*/
|
||||
struct Fss : public SerializeIF {
|
||||
public:
|
||||
FileSize() = default;
|
||||
Fss() = default;
|
||||
|
||||
explicit FileSize(uint64_t fileSize, bool isLarge = false) { setFileSize(fileSize, isLarge); };
|
||||
explicit Fss(uint64_t fileSize, bool isLarge = false) { setFileSize(fileSize, isLarge); };
|
||||
|
||||
[[nodiscard]] uint64_t value() const { return fileSize; }
|
||||
|
@ -3,8 +3,8 @@
|
||||
#include "fsfw/serialize/SerializeAdapter.h"
|
||||
#include "fsfw/serviceinterface.h"
|
||||
|
||||
cfdp::VarLenField::VarLenField(cfdp::WidthInBytes width, size_t value) : VarLenField() {
|
||||
ReturnValue_t result = this->setValue(width, value);
|
||||
cfdp::VarLenField::VarLenField(cfdp::WidthInBytes width, uint64_t value) : VarLenField() {
|
||||
ReturnValue_t result = this->setValueAndWidth(width, value);
|
||||
if (result != returnvalue::OK) {
|
||||
#if FSFW_DISABLE_PRINTOUT == 0
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
@ -20,8 +20,8 @@ cfdp::VarLenField::VarLenField() : width(cfdp::WidthInBytes::ONE_BYTE) { value.o
|
||||
|
||||
cfdp::WidthInBytes cfdp::VarLenField::getWidth() const { return width; }
|
||||
|
||||
ReturnValue_t cfdp::VarLenField::setValue(cfdp::WidthInBytes widthInBytes, size_t value_) {
|
||||
switch (widthInBytes) {
|
||||
ReturnValue_t cfdp::VarLenField::setValueAndWidth(cfdp::WidthInBytes width_, uint64_t value_) {
|
||||
switch (width_) {
|
||||
case (cfdp::WidthInBytes::ONE_BYTE): {
|
||||
if (value_ > UINT8_MAX) {
|
||||
return returnvalue::FAILED;
|
||||
@ -43,15 +43,18 @@ ReturnValue_t cfdp::VarLenField::setValue(cfdp::WidthInBytes widthInBytes, size_
|
||||
this->value.fourBytes = value_;
|
||||
break;
|
||||
}
|
||||
case (cfdp::WidthInBytes::EIGHT_BYTES): {
|
||||
this->value.eightBytes = value_;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
this->width = widthInBytes;
|
||||
this->width = width_;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
size_t cfdp::VarLenField::getValue() const {
|
||||
uint64_t cfdp::VarLenField::getValue() const {
|
||||
switch (width) {
|
||||
case (cfdp::WidthInBytes::ONE_BYTE): {
|
||||
return value.oneByte;
|
||||
@ -62,6 +65,9 @@ size_t cfdp::VarLenField::getValue() const {
|
||||
case (cfdp::WidthInBytes::FOUR_BYTES): {
|
||||
return value.fourBytes;
|
||||
}
|
||||
case (cfdp::WidthInBytes::EIGHT_BYTES): {
|
||||
return value.eightBytes;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -84,6 +90,10 @@ ReturnValue_t cfdp::VarLenField::serialize(uint8_t **buffer, size_t *size, size_
|
||||
case (cfdp::WidthInBytes::FOUR_BYTES): {
|
||||
return SerializeAdapter::serialize(&value.fourBytes, buffer, size, maxSize, streamEndianness);
|
||||
}
|
||||
case (cfdp::WidthInBytes::EIGHT_BYTES): {
|
||||
return SerializeAdapter::serialize(&value.eightBytes, buffer, size, maxSize,
|
||||
streamEndianness);
|
||||
}
|
||||
default: {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
@ -98,11 +108,16 @@ ReturnValue_t cfdp::VarLenField::deSerialize(cfdp::WidthInBytes width_, const ui
|
||||
return deSerialize(buffer, size, streamEndianness);
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::VarLenField::setValue(uint64_t value_) {
|
||||
return setValueAndWidth(getWidth(), value_);
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::VarLenField::deSerialize(const uint8_t **buffer, size_t *size,
|
||||
Endianness streamEndianness) {
|
||||
switch (width) {
|
||||
case (cfdp::WidthInBytes::ONE_BYTE): {
|
||||
value.oneByte = **buffer;
|
||||
*buffer += 1;
|
||||
*size += 1;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
@ -112,6 +127,9 @@ ReturnValue_t cfdp::VarLenField::deSerialize(const uint8_t **buffer, size_t *siz
|
||||
case (cfdp::WidthInBytes::FOUR_BYTES): {
|
||||
return SerializeAdapter::deSerialize(&value.fourBytes, buffer, size, streamEndianness);
|
||||
}
|
||||
case (cfdp::WidthInBytes::EIGHT_BYTES): {
|
||||
return SerializeAdapter::deSerialize(&value.eightBytes, buffer, size, streamEndianness);
|
||||
}
|
||||
default: {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
@ -135,3 +153,5 @@ bool cfdp::VarLenField::operator==(const cfdp::VarLenField &other) const {
|
||||
bool cfdp::VarLenField::operator!=(const cfdp::VarLenField &other) const {
|
||||
return not(*this == other);
|
||||
}
|
||||
|
||||
void cfdp::VarLenField::setWidth(cfdp::WidthInBytes width_) { this->width = width_; }
|
||||
|
@ -25,13 +25,15 @@ class VarLenField : public SerializeIF {
|
||||
template <typename T>
|
||||
explicit VarLenField(UnsignedByteField<T> byteField);
|
||||
|
||||
VarLenField(cfdp::WidthInBytes width, size_t value);
|
||||
VarLenField(cfdp::WidthInBytes width, uint64_t value);
|
||||
|
||||
bool operator==(const VarLenField &other) const;
|
||||
bool operator!=(const VarLenField &other) const;
|
||||
bool operator<(const VarLenField &other) const;
|
||||
|
||||
ReturnValue_t setValue(cfdp::WidthInBytes, size_t value);
|
||||
ReturnValue_t setValueAndWidth(cfdp::WidthInBytes width, uint64_t value);
|
||||
void setWidth(cfdp::WidthInBytes width);
|
||||
ReturnValue_t setValue(uint64_t value);
|
||||
|
||||
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
||||
Endianness streamEndianness) const override;
|
||||
@ -42,7 +44,7 @@ class VarLenField : public SerializeIF {
|
||||
Endianness streamEndianness);
|
||||
|
||||
[[nodiscard]] cfdp::WidthInBytes getWidth() const;
|
||||
[[nodiscard]] size_t getValue() const;
|
||||
[[nodiscard]] uint64_t getValue() const;
|
||||
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
friend std::ostream &operator<<(std::ostream &os, const VarLenField &id) {
|
||||
@ -65,7 +67,7 @@ template <typename T>
|
||||
cfdp::VarLenField::VarLenField(UnsignedByteField<T> byteField)
|
||||
: width(static_cast<cfdp::WidthInBytes>(sizeof(T))) {
|
||||
static_assert((sizeof(T) % 2) == 0);
|
||||
setValue(width, byteField.getValue());
|
||||
setValueAndWidth(width, byteField.getValue());
|
||||
}
|
||||
|
||||
struct EntityId : public VarLenField {
|
||||
@ -74,6 +76,32 @@ struct EntityId : public VarLenField {
|
||||
template <typename T>
|
||||
explicit EntityId(UnsignedByteField<T> byteField) : VarLenField(byteField) {}
|
||||
EntityId(cfdp::WidthInBytes width, size_t entityId) : VarLenField(width, entityId) {}
|
||||
|
||||
ReturnValue_t serializeAsLv(uint8_t **buffer, size_t *size, size_t maxSize) const {
|
||||
if (buffer == nullptr or size == nullptr) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
if (*size + 1 + getWidth() > maxSize) {
|
||||
return SerializeIF::BUFFER_TOO_SHORT;
|
||||
}
|
||||
**buffer = getWidth();
|
||||
*buffer += 1;
|
||||
*size += 1;
|
||||
return serialize(buffer, size, maxSize, SerializeIF::Endianness::NETWORK);
|
||||
}
|
||||
|
||||
ReturnValue_t deSerializeFromLv(const uint8_t **buffer, size_t *deserLen) {
|
||||
if (buffer == nullptr or deserLen == nullptr) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
if (*deserLen < 2) {
|
||||
return SerializeIF::STREAM_TOO_SHORT;
|
||||
}
|
||||
auto width = static_cast<WidthInBytes>(**buffer);
|
||||
*buffer += 1;
|
||||
*deserLen -= 1;
|
||||
return VarLenField::deSerialize(width, buffer, deserLen, SerializeIF::Endianness::NETWORK);
|
||||
}
|
||||
};
|
||||
|
||||
struct TransactionSeqNum : public VarLenField {
|
||||
|
@ -17,7 +17,7 @@ static constexpr char CFDP_VERSION_2_NAME[] = "CCSDS 727.0-B-5";
|
||||
static constexpr uint8_t CFDP_VERSION_2 = 0b001;
|
||||
static constexpr uint8_t VERSION_BITS = CFDP_VERSION_2 << 5;
|
||||
|
||||
static constexpr uint8_t CFDP_CLASS_ID = CLASS_ID::CFDP;
|
||||
static constexpr uint8_t CFDP_CLASS_ID = CLASS_ID::CFDP_BASE;
|
||||
|
||||
static constexpr ReturnValue_t INVALID_TLV_TYPE = returnvalue::makeCode(CFDP_CLASS_ID, 1);
|
||||
static constexpr ReturnValue_t INVALID_DIRECTIVE_FIELD = returnvalue::makeCode(CFDP_CLASS_ID, 2);
|
||||
@ -68,6 +68,7 @@ enum WidthInBytes : uint8_t {
|
||||
ONE_BYTE = 1,
|
||||
TWO_BYTES = 2,
|
||||
FOUR_BYTES = 4,
|
||||
EIGHT_BYTES = 8
|
||||
};
|
||||
|
||||
enum FileDirective : uint8_t {
|
||||
@ -142,6 +143,20 @@ enum RecordContinuationState {
|
||||
CONTAINS_START_AND_END = 0b11
|
||||
};
|
||||
|
||||
enum class ProxyOpMessageType : uint8_t {
|
||||
PUT_REQUEST = 0x00,
|
||||
MSG_TO_USR = 0x01,
|
||||
FS_REQUEST = 0x02,
|
||||
FAULT_HANDLER_OVERRIDE = 0x03,
|
||||
TRANSMISSION_MODE = 0x04,
|
||||
FLOW_LABEL = 0x05,
|
||||
SEG_CTRL = 0x06,
|
||||
PUT_RESPONSE = 0x07,
|
||||
FS_RESPONSE = 0x08,
|
||||
PUT_CANCEL = 0x09,
|
||||
CLOSURE = 0x0b
|
||||
};
|
||||
|
||||
} // namespace cfdp
|
||||
|
||||
#endif /* FSFW_SRC_FSFW_CFDP_PDU_DEFINITIONS_H_ */
|
||||
|
@ -1,2 +1,4 @@
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE SourceHandler.cpp DestHandler.cpp
|
||||
FaultHandlerBase.cpp UserBase.cpp)
|
||||
target_sources(
|
||||
${LIB_FSFW_NAME}
|
||||
PRIVATE SourceHandler.cpp DestHandler.cpp PutRequest.cpp
|
||||
ReservedMessageParser.cpp FaultHandlerBase.cpp UserBase.cpp)
|
||||
|
@ -16,25 +16,26 @@ 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;
|
||||
msgToUserVec(params.maxTlvsInOnePdu),
|
||||
transactionParams(params.maxFilenameLen),
|
||||
destParams(std::move(params)),
|
||||
fsfwParams(fsfwParams) {
|
||||
transactionParams.pduConf.direction = cfdp::Direction::TOWARDS_SENDER;
|
||||
}
|
||||
|
||||
const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() {
|
||||
const cfdp::DestHandler::FsmResult& cfdp::DestHandler::stateMachine() {
|
||||
ReturnValue_t result;
|
||||
uint8_t errorIdx = 0;
|
||||
fsmRes.resetOfIteration();
|
||||
if (fsmRes.step == TransactionStep::IDLE) {
|
||||
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
|
||||
for (auto infoIter = destParams.packetListRef.begin();
|
||||
infoIter != destParams.packetListRef.end();) {
|
||||
if (infoIter->pduType == PduType::FILE_DIRECTIVE and
|
||||
infoIter->directiveType == FileDirective::METADATA) {
|
||||
result = handleMetadataPdu(*infoIter);
|
||||
checkAndHandleError(result, errorIdx);
|
||||
// Store data was deleted in PDU handler because a store guard is used
|
||||
dp.packetListRef.erase(infoIter++);
|
||||
destParams.packetListRef.erase(infoIter++);
|
||||
} else {
|
||||
infoIter++;
|
||||
}
|
||||
@ -42,11 +43,12 @@ const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() {
|
||||
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);
|
||||
for (auto infoIter = destParams.packetListRef.begin();
|
||||
infoIter != destParams.packetListRef.end();) {
|
||||
fsfwParams.tcStore->deleteData(infoIter->storeId);
|
||||
infoIter++;
|
||||
}
|
||||
dp.packetListRef.clear();
|
||||
destParams.packetListRef.clear();
|
||||
}
|
||||
|
||||
if (fsmRes.step != TransactionStep::IDLE) {
|
||||
@ -54,21 +56,22 @@ const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() {
|
||||
}
|
||||
return updateFsmRes(errorIdx);
|
||||
}
|
||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
|
||||
if (fsmRes.state == CfdpState::BUSY_CLASS_1_NACKED) {
|
||||
if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) {
|
||||
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
|
||||
for (auto infoIter = destParams.packetListRef.begin();
|
||||
infoIter != destParams.packetListRef.end();) {
|
||||
if (infoIter->pduType == PduType::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++);
|
||||
destParams.packetListRef.erase(infoIter++);
|
||||
} else if (infoIter->pduType == PduType::FILE_DIRECTIVE and
|
||||
infoIter->directiveType == FileDirective::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++);
|
||||
destParams.packetListRef.erase(infoIter++);
|
||||
} else {
|
||||
infoIter++;
|
||||
}
|
||||
@ -85,7 +88,7 @@ const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() {
|
||||
}
|
||||
return updateFsmRes(errorIdx);
|
||||
}
|
||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
|
||||
if (fsmRes.state == CfdpState::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;
|
||||
@ -95,29 +98,29 @@ const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() {
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::passPacket(PacketInfo packet) {
|
||||
if (dp.packetListRef.full()) {
|
||||
if (destParams.packetListRef.full()) {
|
||||
return FAILED;
|
||||
}
|
||||
dp.packetListRef.push_back(packet);
|
||||
destParams.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) {
|
||||
if (fsfwParams.tmStore == nullptr) {
|
||||
fsfwParams.tmStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TM_STORE);
|
||||
if (fsfwParams.tmStore == nullptr) {
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (fp.tcStore == nullptr) {
|
||||
fp.tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
|
||||
if (fp.tcStore == nullptr) {
|
||||
if (fsfwParams.tcStore == nullptr) {
|
||||
fsfwParams.tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
|
||||
if (fsfwParams.tcStore == nullptr) {
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (fp.msgQueue == nullptr) {
|
||||
if (fsfwParams.msgQueue == nullptr) {
|
||||
return FAILED;
|
||||
}
|
||||
return OK;
|
||||
@ -125,18 +128,16 @@ ReturnValue_t cfdp::DestHandler::initialize() {
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::handleMetadataPdu(const PacketInfo& info) {
|
||||
// Process metadata PDU
|
||||
auto constAccessorPair = fp.tcStore->getData(info.storeId);
|
||||
auto constAccessorPair = fsfwParams.tcStore->getData(info.storeId);
|
||||
if (constAccessorPair.first != OK) {
|
||||
// TODO: This is not a CFDP error. Event and/or warning?
|
||||
return constAccessorPair.first;
|
||||
}
|
||||
cfdp::StringLv sourceFileName;
|
||||
cfdp::StringLv destFileName;
|
||||
MetadataInfo metadataInfo(tp.fileSize, sourceFileName, destFileName);
|
||||
cfdp::Tlv* tlvArrayAsPtr = tlvVec.data();
|
||||
metadataInfo.setOptionsArray(&tlvArrayAsPtr, std::nullopt, tlvVec.size());
|
||||
MetadataGenericInfo metadataInfo(transactionParams.fileSize);
|
||||
MetadataPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(),
|
||||
metadataInfo);
|
||||
metadataInfo, tlvVec.data(), tlvVec.size());
|
||||
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
|
||||
@ -145,18 +146,17 @@ ReturnValue_t cfdp::DestHandler::handleMetadataPdu(const PacketInfo& info) {
|
||||
return handleMetadataParseError(result, constAccessorPair.second.data(),
|
||||
constAccessorPair.second.size());
|
||||
}
|
||||
return startTransaction(reader, metadataInfo);
|
||||
return startTransaction(reader);
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::handleFileDataPdu(const cfdp::PacketInfo& info) {
|
||||
// Process file data PDU
|
||||
auto constAccessorPair = fp.tcStore->getData(info.storeId);
|
||||
auto constAccessorPair = fsfwParams.tcStore->getData(info.storeId);
|
||||
if (constAccessorPair.first != OK) {
|
||||
// TODO: This is not a CFDP error. Event and/or warning?
|
||||
return constAccessorPair.first;
|
||||
}
|
||||
cfdp::FileSize offset;
|
||||
FileDataInfo fdInfo(offset);
|
||||
FileDataInfo fdInfo;
|
||||
FileDataReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), fdInfo);
|
||||
ReturnValue_t result = reader.parseData();
|
||||
if (result != OK) {
|
||||
@ -164,46 +164,46 @@ ReturnValue_t cfdp::DestHandler::handleFileDataPdu(const cfdp::PacketInfo& info)
|
||||
}
|
||||
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) {
|
||||
FileOpParams fileOpParams(transactionParams.destName.data(), fileSegmentLen);
|
||||
fileOpParams.offset = fdInfo.getOffset().value();
|
||||
if (destParams.cfg.indicCfg.fileSegmentRecvIndicRequired) {
|
||||
FileSegmentRecvdParams segParams;
|
||||
segParams.offset = offset.value();
|
||||
segParams.id = tp.transactionId;
|
||||
segParams.offset = fdInfo.getOffset().value();
|
||||
segParams.id = transactionParams.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);
|
||||
destParams.user.fileSegmentRecvdIndication(segParams);
|
||||
}
|
||||
result = dp.user.vfs.writeToFile(fileOpParams, fileData);
|
||||
result = destParams.user.vfs.writeToFile(fileOpParams, fileData);
|
||||
if (result != returnvalue::OK) {
|
||||
// TODO: Proper Error handling
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "cfdp::DestHandler: VFS file write error with code 0x" << std::hex << std::setw(2)
|
||||
<< result << std::endl;
|
||||
#endif
|
||||
tp.vfsErrorCount++;
|
||||
if (tp.vfsErrorCount < 3) {
|
||||
transactionParams.vfsErrorCount++;
|
||||
if (transactionParams.vfsErrorCount < 3) {
|
||||
// TODO: Provide execution step as parameter
|
||||
fp.eventReporter->forwardEvent(events::FILESTORE_ERROR, static_cast<uint8_t>(fsmRes.step),
|
||||
result);
|
||||
fsfwParams.eventReporter->forwardEvent(events::FILESTORE_ERROR,
|
||||
static_cast<uint8_t>(fsmRes.step), result);
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
tp.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE;
|
||||
tp.vfsErrorCount = 0;
|
||||
transactionParams.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE;
|
||||
transactionParams.vfsErrorCount = 0;
|
||||
}
|
||||
if (offset.value() + fileSegmentLen > tp.progress) {
|
||||
tp.progress = offset.value() + fileSegmentLen;
|
||||
if (fdInfo.getOffset().value() + fileSegmentLen > transactionParams.progress) {
|
||||
transactionParams.progress = fdInfo.getOffset().value() + fileSegmentLen;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::handleEofPdu(const cfdp::PacketInfo& info) {
|
||||
// Process EOF PDU
|
||||
auto constAccessorPair = fp.tcStore->getData(info.storeId);
|
||||
auto constAccessorPair = fsfwParams.tcStore->getData(info.storeId);
|
||||
if (constAccessorPair.first != OK) {
|
||||
// TODO: This is not a CFDP error. Event and/or warning?
|
||||
return constAccessorPair.first;
|
||||
@ -216,21 +216,21 @@ ReturnValue_t cfdp::DestHandler::handleEofPdu(const cfdp::PacketInfo& info) {
|
||||
}
|
||||
// TODO: Error handling
|
||||
if (eofInfo.getConditionCode() == ConditionCode::NO_ERROR) {
|
||||
tp.crc = eofInfo.getChecksum();
|
||||
transactionParams.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) {
|
||||
if (fileSizeFromEof > transactionParams.progress) {
|
||||
// TODO: File size error
|
||||
}
|
||||
tp.fileSize.setFileSize(fileSizeFromEof, std::nullopt);
|
||||
transactionParams.fileSize.setFileSize(fileSizeFromEof, std::nullopt);
|
||||
}
|
||||
if (dp.cfg.indicCfg.eofRecvIndicRequired) {
|
||||
dp.user.eofRecvIndication(getTransactionId());
|
||||
if (destParams.cfg.indicCfg.eofRecvIndicRequired) {
|
||||
destParams.user.eofRecvIndication(getTransactionId());
|
||||
}
|
||||
if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) {
|
||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
|
||||
if (fsmRes.state == CfdpState::BUSY_CLASS_1_NACKED) {
|
||||
fsmRes.step = TransactionStep::TRANSFER_COMPLETION;
|
||||
} else if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
|
||||
} else if (fsmRes.state == CfdpState::BUSY_CLASS_2_ACKED) {
|
||||
fsmRes.step = TransactionStep::SENDING_ACK_PDU;
|
||||
}
|
||||
}
|
||||
@ -260,7 +260,7 @@ ReturnValue_t cfdp::DestHandler::handleMetadataParseError(ReturnValue_t result,
|
||||
cfdp::EntityId destId;
|
||||
headerReader.getDestId(destId);
|
||||
RemoteEntityCfg* remoteCfg;
|
||||
if (not dp.remoteCfgTable.getRemoteCfg(destId, &remoteCfg)) {
|
||||
if (not destParams.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
|
||||
@ -274,51 +274,57 @@ ReturnValue_t cfdp::DestHandler::handleMetadataParseError(ReturnValue_t result,
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader, MetadataInfo& info) {
|
||||
if (fsmRes.state != CfdpStates::IDLE) {
|
||||
ReturnValue_t cfdp::DestHandler::startTransaction(const MetadataPduReader& reader) {
|
||||
if (fsmRes.state != CfdpState::IDLE) {
|
||||
// According to standard, discard metadata PDU if we are busy
|
||||
return OK;
|
||||
}
|
||||
ReturnValue_t result = OK;
|
||||
size_t sourceNameSize = 0;
|
||||
|
||||
const uint8_t* sourceNamePtr = info.getSourceFileName().getValue(&sourceNameSize);
|
||||
if (sourceNameSize + 1 > tp.sourceName.size()) {
|
||||
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "source filename too large");
|
||||
return FAILED;
|
||||
if (not reader.getSourceFileName().isEmpty()) {
|
||||
const uint8_t* sourceNamePtr = reader.getSourceFileName().getValue(&sourceNameSize);
|
||||
if (sourceNameSize + 1 > transactionParams.sourceName.size()) {
|
||||
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "source filename too large");
|
||||
return FAILED;
|
||||
}
|
||||
std::memcpy(transactionParams.sourceName.data(), sourceNamePtr, sourceNameSize);
|
||||
transactionParams.sourceName[sourceNameSize] = '\0';
|
||||
}
|
||||
std::memcpy(tp.sourceName.data(), sourceNamePtr, sourceNameSize);
|
||||
tp.sourceName[sourceNameSize] = '\0';
|
||||
size_t destNameSize = 0;
|
||||
const uint8_t* destNamePtr = info.getDestFileName().getValue(&destNameSize);
|
||||
if (destNameSize + 1 > tp.destName.size()) {
|
||||
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "dest filename too large");
|
||||
return FAILED;
|
||||
if (not reader.getDestFileName().isEmpty()) {
|
||||
const uint8_t* destNamePtr = reader.getDestFileName().getValue(&destNameSize);
|
||||
if (destNameSize + 1 > transactionParams.destName.size()) {
|
||||
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "dest filename too large");
|
||||
return FAILED;
|
||||
}
|
||||
std::memcpy(transactionParams.destName.data(), destNamePtr, destNameSize);
|
||||
transactionParams.destName[destNameSize] = '\0';
|
||||
}
|
||||
std::memcpy(tp.destName.data(), destNamePtr, destNameSize);
|
||||
tp.destName[destNameSize] = '\0';
|
||||
|
||||
transactionParams.metadataOnly = true;
|
||||
// If both dest name size and source name size are 0, we are dealing with a metadata only PDU,
|
||||
// so there is no need to create a file or truncate an existing file
|
||||
if (destNameSize > 0 and sourceNameSize > 0) {
|
||||
FilesystemParams fparams(tp.destName.data());
|
||||
transactionParams.metadataOnly = false;
|
||||
FilesystemParams fparams(transactionParams.destName.data());
|
||||
// handling to allow only specifying target directory. Example:
|
||||
// Source path /test/hello.txt, dest path /tmp -> dest path /tmp/hello.txt
|
||||
if (dp.user.vfs.isDirectory(tp.destName.data())) {
|
||||
if (destParams.user.vfs.isDirectory(transactionParams.destName.data())) {
|
||||
result = tryBuildingAbsoluteDestName(destNameSize);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (dp.user.vfs.fileExists(fparams)) {
|
||||
result = dp.user.vfs.truncateFile(fparams);
|
||||
if (destParams.user.vfs.fileExists(fparams)) {
|
||||
result = destParams.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);
|
||||
result = destParams.user.vfs.createFile(fparams);
|
||||
if (result != OK) {
|
||||
fileErrorHandler(events::FILESTORE_ERROR, result, "file creation error");
|
||||
return FAILED;
|
||||
@ -328,122 +334,135 @@ ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader, Met
|
||||
}
|
||||
EntityId sourceId;
|
||||
reader.getSourceId(sourceId);
|
||||
if (not dp.remoteCfgTable.getRemoteCfg(sourceId, &tp.remoteCfg)) {
|
||||
if (not destParams.remoteCfgTable.getRemoteCfg(sourceId, &transactionParams.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;
|
||||
<< transactionParams.pduConf.sourceId.getValue() << std::endl;
|
||||
#endif
|
||||
return FAILED;
|
||||
}
|
||||
fsmRes.step = TransactionStep::TRANSACTION_START;
|
||||
if (reader.getTransmissionMode() == TransmissionMode::UNACKNOWLEDGED) {
|
||||
fsmRes.state = CfdpStates::BUSY_CLASS_1_NACKED;
|
||||
fsmRes.state = CfdpState::BUSY_CLASS_1_NACKED;
|
||||
} else if (reader.getTransmissionMode() == TransmissionMode::ACKNOWLEDGED) {
|
||||
fsmRes.state = CfdpStates::BUSY_CLASS_2_ACKED;
|
||||
fsmRes.state = CfdpState::BUSY_CLASS_2_ACKED;
|
||||
}
|
||||
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;
|
||||
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);
|
||||
if (transactionParams.metadataOnly) {
|
||||
fsmRes.step = TransactionStep::TRANSFER_COMPLETION;
|
||||
} else {
|
||||
// Kind of ugly, make FSM working on packet per packet basis..
|
||||
fsmRes.step = TransactionStep::TRANSACTION_START;
|
||||
fsmRes.step = TransactionStep::RECEIVING_FILE_DATA_PDUS;
|
||||
}
|
||||
auto& info = reader.getGenericInfo();
|
||||
transactionParams.checksumType = info.getChecksumType();
|
||||
transactionParams.closureRequested = info.isClosureRequested();
|
||||
reader.fillConfig(transactionParams.pduConf);
|
||||
transactionParams.pduConf.direction = Direction::TOWARDS_SENDER;
|
||||
transactionParams.transactionId.entityId = transactionParams.pduConf.sourceId;
|
||||
transactionParams.transactionId.seqNum = transactionParams.pduConf.seqNum;
|
||||
transactionParams.fileSize = info.getFileSize();
|
||||
MetadataRecvdParams params(transactionParams.transactionId, transactionParams.pduConf.sourceId,
|
||||
transactionParams.fileSize);
|
||||
params.destFileName = transactionParams.destName.data();
|
||||
params.sourceFileName = transactionParams.sourceName.data();
|
||||
params.numberOfMsgsToUser = 0;
|
||||
for (const auto& opt : tlvVec) {
|
||||
if (opt.getType() == TlvType::MSG_TO_USER) {
|
||||
msgToUserVec[params.numberOfMsgsToUser] =
|
||||
MessageToUserTlv(opt.getValue(), opt.getLengthField());
|
||||
params.numberOfMsgsToUser++;
|
||||
}
|
||||
}
|
||||
params.msgsToUserArray = msgToUserVec.data();
|
||||
destParams.user.metadataRecvdIndication(params);
|
||||
return result;
|
||||
}
|
||||
|
||||
cfdp::CfdpStates cfdp::DestHandler::getCfdpState() const { return fsmRes.state; }
|
||||
cfdp::CfdpState cfdp::DestHandler::getCfdpState() const { return fsmRes.state; }
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::handleTransferCompletion() {
|
||||
ReturnValue_t result;
|
||||
if (tp.checksumType != ChecksumType::NULL_CHECKSUM) {
|
||||
if (transactionParams.checksumType != ChecksumType::NULL_CHECKSUM) {
|
||||
result = checksumVerification();
|
||||
if (result != OK) {
|
||||
// TODO: Warning / error handling?
|
||||
}
|
||||
} else {
|
||||
tp.conditionCode = ConditionCode::NO_ERROR;
|
||||
transactionParams.conditionCode = ConditionCode::NO_ERROR;
|
||||
}
|
||||
result = noticeOfCompletion();
|
||||
if (result != OK) {
|
||||
}
|
||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
|
||||
if (tp.closureRequested) {
|
||||
if (fsmRes.state == CfdpState::BUSY_CLASS_1_NACKED) {
|
||||
if (transactionParams.closureRequested) {
|
||||
fsmRes.step = TransactionStep::SENDING_FINISHED_PDU;
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
} else if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
|
||||
} else if (fsmRes.state == CfdpState::BUSY_CLASS_2_ACKED) {
|
||||
fsmRes.step = TransactionStep::SENDING_FINISHED_PDU;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::tryBuildingAbsoluteDestName(size_t destNameSize) {
|
||||
// Maximum allowed path size is 255 characters, so this should be enough to hold the full
|
||||
// base name in any case.
|
||||
char baseNameBuf[524]{};
|
||||
FilesystemParams fparamsSrc(tp.sourceName.data());
|
||||
// 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());
|
||||
size_t baseNameLen = 0;
|
||||
ReturnValue_t result =
|
||||
dp.user.vfs.getBaseFilename(fparamsSrc, baseNameBuf, sizeof(baseNameBuf), baseNameLen);
|
||||
ReturnValue_t result = destParams.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()) {
|
||||
if (destNameSize + 1 + baseNameLen + 1 > transactionParams.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);
|
||||
transactionParams.destName[destNameSize++] = '/';
|
||||
std::memcpy(transactionParams.destName.data() + destNameSize, baseNameBuf, baseNameLen);
|
||||
destNameSize += baseNameLen;
|
||||
tp.destName[destNameSize++] = '\0';
|
||||
transactionParams.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);
|
||||
void cfdp::DestHandler::fileErrorHandler(Event event, ReturnValue_t result,
|
||||
const char* info) const {
|
||||
fsfwParams.eventReporter->forwardEvent(event, 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() {
|
||||
tp.reset();
|
||||
dp.packetListRef.clear();
|
||||
fsmRes.state = CfdpStates::IDLE;
|
||||
transactionParams.reset();
|
||||
destParams.packetListRef.clear();
|
||||
fsmRes.state = CfdpState::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()) {
|
||||
FileOpParams params(transactionParams.destName.data(), transactionParams.fileSize.value());
|
||||
while (currentOffset < transactionParams.fileSize.value()) {
|
||||
uint64_t readLen;
|
||||
if (currentOffset + buf.size() > tp.fileSize.value()) {
|
||||
readLen = tp.fileSize.value() - currentOffset;
|
||||
if (currentOffset + buf.size() > transactionParams.fileSize.value()) {
|
||||
readLen = transactionParams.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());
|
||||
auto result = destParams.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
|
||||
@ -455,40 +474,43 @@ ReturnValue_t cfdp::DestHandler::checksumVerification() {
|
||||
}
|
||||
|
||||
uint32_t value = crcCalc.value();
|
||||
if (value == tp.crc) {
|
||||
tp.conditionCode = ConditionCode::NO_ERROR;
|
||||
tp.deliveryCode = FileDeliveryCode::DATA_COMPLETE;
|
||||
if (value == transactionParams.crc) {
|
||||
transactionParams.conditionCode = ConditionCode::NO_ERROR;
|
||||
transactionParams.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;
|
||||
sif::warning << "CRC check for file " << transactionParams.destName.data() << " failed"
|
||||
<< std::endl;
|
||||
#endif
|
||||
tp.conditionCode = ConditionCode::FILE_CHECKSUM_FAILURE;
|
||||
transactionParams.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);
|
||||
if (destParams.cfg.indicCfg.transactionFinishedIndicRequired) {
|
||||
TransactionFinishedParams params(
|
||||
transactionParams.transactionId, transactionParams.conditionCode,
|
||||
transactionParams.deliveryCode, transactionParams.deliveryStatus);
|
||||
destParams.user.transactionFinishedIndication(params);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::sendFinishedPdu() {
|
||||
FinishedInfo info(tp.conditionCode, tp.deliveryCode, tp.deliveryStatus);
|
||||
FinishPduCreator finishedPdu(tp.pduConf, info);
|
||||
FinishedInfo info(transactionParams.conditionCode, transactionParams.deliveryCode,
|
||||
transactionParams.deliveryStatus);
|
||||
FinishPduCreator finishedPdu(transactionParams.pduConf, info);
|
||||
store_address_t storeId;
|
||||
uint8_t* dataPtr = nullptr;
|
||||
ReturnValue_t result =
|
||||
fp.tmStore->getFreeElement(&storeId, finishedPdu.getSerializedSize(), &dataPtr);
|
||||
fsfwParams.tmStore->getFreeElement(&storeId, finishedPdu.getSerializedSize(), &dataPtr);
|
||||
if (result != OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "cfdp::DestHandler:sendFinishedPdu: Getting store slot failed" << std::endl;
|
||||
#endif
|
||||
fp.eventReporter->forwardEvent(events::STORE_ERROR, result, 0);
|
||||
fsfwParams.eventReporter->forwardEvent(events::STORE_ERROR, result, 0);
|
||||
return result;
|
||||
}
|
||||
size_t serLen = 0;
|
||||
@ -498,16 +520,16 @@ ReturnValue_t cfdp::DestHandler::sendFinishedPdu() {
|
||||
sif::warning << "cfdp::DestHandler::sendFinishedPdu: Serializing Finished PDU failed"
|
||||
<< std::endl;
|
||||
#endif
|
||||
fp.eventReporter->forwardEvent(events::SERIALIZATION_ERROR, result, 0);
|
||||
fsfwParams.eventReporter->forwardEvent(events::SERIALIZATION_ERROR, result, 0);
|
||||
return result;
|
||||
}
|
||||
TmTcMessage msg(storeId);
|
||||
result = fp.msgQueue->sendMessage(fp.packetDest.getReportReceptionQueue(), &msg);
|
||||
result = fsfwParams.msgQueue->sendMessage(fsfwParams.packetDest.getReportReceptionQueue(), &msg);
|
||||
if (result != OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "cfdp::DestHandler::sendFinishedPdu: Sending PDU failed" << std::endl;
|
||||
#endif
|
||||
fp.eventReporter->forwardEvent(events::MSG_QUEUE_ERROR, result, 0);
|
||||
fsfwParams.eventReporter->forwardEvent(events::MSG_QUEUE_ERROR, result, 0);
|
||||
return result;
|
||||
}
|
||||
fsmRes.packetsSent++;
|
||||
@ -527,7 +549,9 @@ const cfdp::DestHandler::FsmResult& cfdp::DestHandler::updateFsmRes(uint8_t erro
|
||||
return fsmRes;
|
||||
}
|
||||
|
||||
const cfdp::TransactionId& cfdp::DestHandler::getTransactionId() const { return tp.transactionId; }
|
||||
const cfdp::TransactionId& cfdp::DestHandler::getTransactionId() const {
|
||||
return transactionParams.transactionId;
|
||||
}
|
||||
|
||||
void cfdp::DestHandler::checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx) {
|
||||
if (result != OK and errorIdx < 3) {
|
||||
@ -536,13 +560,15 @@ void cfdp::DestHandler::checkAndHandleError(ReturnValue_t result, uint8_t& error
|
||||
}
|
||||
}
|
||||
|
||||
void cfdp::DestHandler::setMsgQueue(MessageQueueIF& queue) { fp.msgQueue = &queue; }
|
||||
void cfdp::DestHandler::setMsgQueue(MessageQueueIF& queue) { fsfwParams.msgQueue = &queue; }
|
||||
|
||||
void cfdp::DestHandler::setEventReporter(EventReportingProxyIF& reporter) {
|
||||
fp.eventReporter = &reporter;
|
||||
fsfwParams.eventReporter = &reporter;
|
||||
}
|
||||
|
||||
const cfdp::DestHandlerParams& cfdp::DestHandler::getDestHandlerParams() const { return dp; }
|
||||
const cfdp::DestHandlerParams& cfdp::DestHandler::getDestHandlerParams() const {
|
||||
return destParams;
|
||||
}
|
||||
|
||||
StorageManagerIF* cfdp::DestHandler::getTmStore() const { return fp.tmStore; }
|
||||
StorageManagerIF* cfdp::DestHandler::getTcStore() const { return fp.tcStore; }
|
||||
StorageManagerIF* cfdp::DestHandler::getTmStore() const { return fsfwParams.tmStore; }
|
||||
StorageManagerIF* cfdp::DestHandler::getTcStore() const { return fsfwParams.tcStore; }
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "fsfw/cfdp/handler/mib.h"
|
||||
#include "fsfw/cfdp/pdu/MetadataPduReader.h"
|
||||
#include "fsfw/cfdp/pdu/PduConfig.h"
|
||||
#include "fsfw/cfdp/tlv/MessageToUserTlv.h"
|
||||
#include "fsfw/container/DynamicFIFO.h"
|
||||
#include "fsfw/storagemanager/StorageManagerIF.h"
|
||||
#include "fsfw/storagemanager/storeAddress.h"
|
||||
@ -21,23 +22,9 @@
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
struct PacketInfo {
|
||||
PacketInfo(PduType type, store_address_t storeId,
|
||||
std::optional<FileDirective> directive = std::nullopt)
|
||||
: pduType(type), directiveType(directive), storeId(storeId) {}
|
||||
|
||||
PduType pduType = PduType::FILE_DATA;
|
||||
std::optional<FileDirective> directiveType = FileDirective::INVALID_DIRECTIVE;
|
||||
store_address_t storeId = store_address_t::invalid();
|
||||
PacketInfo() = default;
|
||||
};
|
||||
|
||||
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,
|
||||
@ -45,6 +32,9 @@ struct DestHandlerParams {
|
||||
// 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
|
||||
// TODO: Actually, we can provide a better abstraction via interface, which
|
||||
// allows using something like a bounded map. This simplifies
|
||||
// the implementation significantly.
|
||||
LostSegmentsListBase& lostSegmentsContainer)
|
||||
: cfg(std::move(cfg)),
|
||||
user(user),
|
||||
@ -58,31 +48,10 @@ struct DestHandlerParams {
|
||||
|
||||
PacketInfoListBase& packetListRef;
|
||||
LostSegmentsListBase& lostSegmentsContainer;
|
||||
uint8_t maxTlvsInOnePdu = 10;
|
||||
uint8_t maxTlvsInOnePdu = 20;
|
||||
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 : uint8_t {
|
||||
@ -99,7 +68,7 @@ class DestHandler {
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
CallStatus callStatus = CallStatus::CALL_AFTER_DELAY;
|
||||
TransactionStep step = TransactionStep::IDLE;
|
||||
CfdpStates state = CfdpStates::IDLE;
|
||||
CfdpState state = CfdpState::IDLE;
|
||||
uint32_t packetsSent = 0;
|
||||
uint8_t errors = 0;
|
||||
std::array<ReturnValue_t, 3> errorCodes = {};
|
||||
@ -124,7 +93,7 @@ class DestHandler {
|
||||
* - @c returnvalue::OK State machine OK for this execution cycle
|
||||
* - @c CALL_FSM_AGAIN State machine should be called again.
|
||||
*/
|
||||
const FsmResult& performStateMachine();
|
||||
const FsmResult& stateMachine();
|
||||
void setMsgQueue(MessageQueueIF& queue);
|
||||
void setEventReporter(EventReportingProxyIF& reporter);
|
||||
|
||||
@ -132,7 +101,7 @@ class DestHandler {
|
||||
|
||||
ReturnValue_t initialize();
|
||||
|
||||
[[nodiscard]] CfdpStates getCfdpState() const;
|
||||
[[nodiscard]] CfdpState getCfdpState() const;
|
||||
[[nodiscard]] TransactionStep getTransactionStep() const;
|
||||
[[nodiscard]] const TransactionId& getTransactionId() const;
|
||||
[[nodiscard]] const DestHandlerParams& getDestHandlerParams() const;
|
||||
@ -157,17 +126,19 @@ class DestHandler {
|
||||
crc = 0;
|
||||
progress = 0;
|
||||
remoteCfg = nullptr;
|
||||
metadataOnly = false;
|
||||
closureRequested = false;
|
||||
vfsErrorCount = 0;
|
||||
checksumType = ChecksumType::NULL_CHECKSUM;
|
||||
}
|
||||
|
||||
bool metadataOnly = false;
|
||||
ChecksumType checksumType = ChecksumType::NULL_CHECKSUM;
|
||||
bool closureRequested = false;
|
||||
uint16_t vfsErrorCount = 0;
|
||||
std::vector<char> sourceName;
|
||||
std::vector<char> destName;
|
||||
cfdp::FileSize fileSize;
|
||||
cfdp::Fss fileSize;
|
||||
TransactionId transactionId;
|
||||
PduConfig pduConf;
|
||||
ConditionCode conditionCode = ConditionCode::NO_ERROR;
|
||||
@ -179,13 +150,13 @@ class DestHandler {
|
||||
};
|
||||
|
||||
std::vector<cfdp::Tlv> tlvVec;
|
||||
std::vector<cfdp::Tlv> userTlvVec;
|
||||
DestHandlerParams dp;
|
||||
FsfwParams fp;
|
||||
TransactionParams tp;
|
||||
std::vector<MessageToUserTlv> msgToUserVec;
|
||||
TransactionParams transactionParams;
|
||||
DestHandlerParams destParams;
|
||||
cfdp::FsfwParams fsfwParams;
|
||||
FsmResult fsmRes;
|
||||
|
||||
ReturnValue_t startTransaction(MetadataPduReader& reader, MetadataInfo& info);
|
||||
ReturnValue_t startTransaction(const MetadataPduReader& reader);
|
||||
ReturnValue_t handleMetadataPdu(const PacketInfo& info);
|
||||
ReturnValue_t handleFileDataPdu(const PacketInfo& info);
|
||||
ReturnValue_t handleEofPdu(const PacketInfo& info);
|
||||
@ -196,7 +167,7 @@ class DestHandler {
|
||||
ReturnValue_t sendFinishedPdu();
|
||||
ReturnValue_t noticeOfCompletion();
|
||||
ReturnValue_t checksumVerification();
|
||||
void fileErrorHandler(Event event, ReturnValue_t result, const char* info);
|
||||
void fileErrorHandler(Event event, ReturnValue_t result, const char* info) const;
|
||||
const FsmResult& updateFsmRes(uint8_t errors);
|
||||
void checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx);
|
||||
void finish();
|
||||
|
201
src/fsfw/cfdp/handler/PutRequest.cpp
Normal file
201
src/fsfw/cfdp/handler/PutRequest.cpp
Normal file
@ -0,0 +1,201 @@
|
||||
#include "PutRequest.h"
|
||||
|
||||
using namespace returnvalue;
|
||||
|
||||
cfdp::PutRequest::PutRequest(cfdp::EntityId destId, const uint8_t *msgsToUser,
|
||||
size_t msgsToUserTotalSize, const uint8_t *fsRequests,
|
||||
size_t fsRequestsSize)
|
||||
: destId(std::move(destId)),
|
||||
metadataOnly(true),
|
||||
msgsToUsersTotalSize(msgsToUserTotalSize),
|
||||
msgsToUserStartPtr(msgsToUser),
|
||||
fsRequestsTotalSize(fsRequestsSize),
|
||||
fsRequestStartPtr(fsRequests) {}
|
||||
|
||||
cfdp::PutRequest::PutRequest(cfdp::EntityId destId, cfdp::StringLv &sourceName,
|
||||
cfdp::StringLv &destName)
|
||||
: destId(std::move(destId)), sourceName(std::move(sourceName)), destName(std::move(destName)) {}
|
||||
|
||||
[[nodiscard]] bool cfdp::PutRequest::isMetadataOnly() const { return metadataOnly; }
|
||||
|
||||
ReturnValue_t cfdp::PutRequest::serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
||||
SerializeIF::Endianness streamEndianness) const {
|
||||
if (buffer == nullptr or size == nullptr) {
|
||||
return FAILED;
|
||||
}
|
||||
if (*size + getSerializedSize() > maxSize) {
|
||||
return SerializeIF::BUFFER_TOO_SHORT;
|
||||
}
|
||||
ReturnValue_t result = destId.serializeAsLv(buffer, size, maxSize);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
result = SerializeAdapter::serialize(&metadataOnly, buffer, size, maxSize, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
if (!metadataOnly) {
|
||||
result = sourceName.serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
result = destName.serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
result =
|
||||
SerializeAdapter::serialize(&hasTransmissionMode, buffer, size, maxSize, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
result =
|
||||
SerializeAdapter::serialize(&transmissionMode, buffer, size, maxSize, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
result =
|
||||
SerializeAdapter::serialize(&hasClosureRequested, buffer, size, maxSize, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
result =
|
||||
SerializeAdapter::serialize(&closureRequested, buffer, size, maxSize, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
result =
|
||||
SerializeAdapter::serialize(&msgsToUsersTotalSize, buffer, size, maxSize, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
std::memcpy(*buffer, msgsToUserStartPtr, msgsToUsersTotalSize);
|
||||
*buffer += msgsToUsersTotalSize;
|
||||
*size += msgsToUsersTotalSize;
|
||||
|
||||
result =
|
||||
SerializeAdapter::serialize(&fsRequestsTotalSize, buffer, size, maxSize, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
std::memcpy(*buffer, fsRequestStartPtr, fsRequestsTotalSize);
|
||||
*buffer += fsRequestsTotalSize;
|
||||
*size += fsRequestsTotalSize;
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::PutRequest::deSerialize(const uint8_t **buffer, size_t *size,
|
||||
SerializeIF::Endianness streamEndianness) {
|
||||
if (buffer == nullptr or size == nullptr) {
|
||||
return FAILED;
|
||||
}
|
||||
ReturnValue_t result = destId.deSerializeFromLv(buffer, size);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
result = SerializeAdapter::deSerialize(&metadataOnly, buffer, size, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
if (!metadataOnly) {
|
||||
result = sourceName.deSerialize(buffer, size, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
result = destName.deSerialize(buffer, size, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
result = SerializeAdapter::deSerialize(&hasTransmissionMode, buffer, size, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
result = SerializeAdapter::deSerialize(&transmissionMode, buffer, size, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
result = SerializeAdapter::deSerialize(&hasClosureRequested, buffer, size, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
result = SerializeAdapter::deSerialize(&closureRequested, buffer, size, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
result = SerializeAdapter::deSerialize(&msgsToUsersTotalSize, buffer, size, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
msgsToUserStartPtr = *buffer;
|
||||
*buffer += msgsToUsersTotalSize;
|
||||
*size += msgsToUsersTotalSize;
|
||||
|
||||
result = SerializeAdapter::deSerialize(&fsRequestsTotalSize, buffer, size, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
fsRequestStartPtr = *buffer;
|
||||
*buffer += fsRequestsTotalSize;
|
||||
*size += fsRequestsTotalSize;
|
||||
return OK;
|
||||
}
|
||||
|
||||
size_t cfdp::PutRequest::getSerializedSize() const {
|
||||
// Entity ID LV (1 leading size byte) and the metadata only flag.
|
||||
size_t baseSize = 1 + destId.getSerializedSize() + 1;
|
||||
if (!metadataOnly) {
|
||||
baseSize += sourceName.getSerializedSize() + destName.getSerializedSize() + 4;
|
||||
}
|
||||
baseSize += sizeof(msgsToUsersTotalSize) + msgsToUsersTotalSize + sizeof(fsRequestsTotalSize) +
|
||||
fsRequestsTotalSize;
|
||||
return baseSize;
|
||||
}
|
||||
|
||||
void cfdp::PutRequest::setSourceAndDestName(cfdp::StringLv &sourceName_,
|
||||
cfdp::StringLv &destName_) {
|
||||
metadataOnly = false;
|
||||
this->sourceName = std::move(sourceName_);
|
||||
this->destName = std::move(destName_);
|
||||
}
|
||||
|
||||
const cfdp::StringLv &cfdp::PutRequest::getSourceName() const { return sourceName; }
|
||||
|
||||
const cfdp::StringLv &cfdp::PutRequest::getDestName() const { return destName; }
|
||||
|
||||
const cfdp::EntityId &cfdp::PutRequest::getDestId() const { return destId; }
|
||||
|
||||
void cfdp::PutRequest::setDestId(cfdp::EntityId id) { destId = std::move(id); }
|
||||
|
||||
void cfdp::PutRequest::setTransmissionMode(cfdp::TransmissionMode transmissionMode_) {
|
||||
this->transmissionMode = transmissionMode_;
|
||||
hasTransmissionMode = true;
|
||||
}
|
||||
|
||||
void cfdp::PutRequest::clearTransmissionMode() { hasTransmissionMode = false; }
|
||||
|
||||
void cfdp::PutRequest::clearClosureRequest() { hasClosureRequested = false; }
|
||||
|
||||
void cfdp::PutRequest::setClosureRequest(bool closureRequested_) {
|
||||
this->closureRequested = closureRequested_;
|
||||
hasClosureRequested = true;
|
||||
}
|
||||
|
||||
const uint8_t *cfdp::PutRequest::getMessagesToUser(size_t &totalSize) {
|
||||
totalSize = this->msgsToUsersTotalSize;
|
||||
return msgsToUserStartPtr;
|
||||
}
|
||||
|
||||
bool cfdp::PutRequest::getClosureRequested(bool &closureRequested_) const {
|
||||
if (hasClosureRequested) {
|
||||
closureRequested_ = this->closureRequested;
|
||||
}
|
||||
return hasClosureRequested;
|
||||
}
|
||||
|
||||
bool cfdp::PutRequest::getTransmissionMode(cfdp::TransmissionMode &mode) const {
|
||||
if (hasTransmissionMode) {
|
||||
mode = static_cast<cfdp::TransmissionMode>(this->transmissionMode);
|
||||
}
|
||||
return hasTransmissionMode;
|
||||
}
|
82
src/fsfw/cfdp/handler/PutRequest.h
Normal file
82
src/fsfw/cfdp/handler/PutRequest.h
Normal file
@ -0,0 +1,82 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "fsfw/cfdp/VarLenFields.h"
|
||||
#include "fsfw/cfdp/tlv/FilestoreRequestTlv.h"
|
||||
#include "fsfw/cfdp/tlv/MessageToUserTlv.h"
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
class PutRequest : public SerializeIF {
|
||||
public:
|
||||
/**
|
||||
* Metadata only constructor.
|
||||
* @param destId
|
||||
* @param msgsToUser
|
||||
* @param msgsToUserTotalSize
|
||||
* @param fsRequests
|
||||
* @param fsRequestsSize
|
||||
*/
|
||||
PutRequest(EntityId destId, const uint8_t* msgsToUser, size_t msgsToUserTotalSize,
|
||||
const uint8_t* fsRequests, size_t fsRequestsSize);
|
||||
/**
|
||||
* Put request to initiate file transfers. By default, the transmission mode and closure requested
|
||||
* parameter are not present, thereby being derived from the remote configuration for a
|
||||
* particular destination ID.
|
||||
* @param destId
|
||||
* @param sourceName
|
||||
* @param destName
|
||||
*/
|
||||
PutRequest(EntityId destId, cfdp::StringLv& sourceName, cfdp::StringLv& destName);
|
||||
|
||||
/**
|
||||
* Default constructor for deserialization.
|
||||
*/
|
||||
PutRequest() = default;
|
||||
|
||||
[[nodiscard]] ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
Endianness streamEndianness) const override;
|
||||
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
Endianness streamEndianness) override;
|
||||
[[nodiscard]] size_t getSerializedSize() const override;
|
||||
void setSourceAndDestName(cfdp::StringLv& sourceName, cfdp::StringLv& destName);
|
||||
|
||||
[[nodiscard]] const cfdp::StringLv& getSourceName() const;
|
||||
[[nodiscard]] const cfdp::StringLv& getDestName() const;
|
||||
|
||||
void setTransmissionMode(cfdp::TransmissionMode transmissionMode);
|
||||
void clearTransmissionMode();
|
||||
void setClosureRequest(bool closureRequested);
|
||||
void clearClosureRequest();
|
||||
|
||||
const uint8_t* getMessagesToUser(size_t& msgSize);
|
||||
|
||||
[[nodiscard]] bool isMetadataOnly() const;
|
||||
|
||||
bool getTransmissionMode(TransmissionMode& mode) const;
|
||||
bool getClosureRequested(bool& closureRequested) const;
|
||||
|
||||
[[nodiscard]] const EntityId& getDestId() const;
|
||||
void setDestId(EntityId id);
|
||||
|
||||
private:
|
||||
EntityId destId;
|
||||
uint8_t metadataOnly = true;
|
||||
// Transaction parameters. Omitted if the put request is metadata only.
|
||||
cfdp::StringLv sourceName;
|
||||
|
||||
cfdp::StringLv destName;
|
||||
bool hasTransmissionMode = false;
|
||||
uint8_t transmissionMode = TransmissionMode::UNACKNOWLEDGED;
|
||||
bool hasClosureRequested = false;
|
||||
uint8_t closureRequested = false;
|
||||
// Metadata
|
||||
size_t msgsToUsersTotalSize = 0;
|
||||
const uint8_t* msgsToUserStartPtr = nullptr;
|
||||
size_t fsRequestsTotalSize = 0;
|
||||
const uint8_t* fsRequestStartPtr = nullptr;
|
||||
};
|
||||
|
||||
} // namespace cfdp
|
@ -16,7 +16,7 @@ class RemoteConfigTableIF {
|
||||
*/
|
||||
class OneRemoteConfigProvider : public RemoteConfigTableIF {
|
||||
public:
|
||||
explicit OneRemoteConfigProvider(RemoteEntityCfg cfg) : cfg(std::move(cfg)) {}
|
||||
explicit OneRemoteConfigProvider(RemoteEntityCfg& cfg) : cfg(cfg) {}
|
||||
|
||||
bool getRemoteCfg(const EntityId& remoteId, cfdp::RemoteEntityCfg** cfg_) override {
|
||||
if (remoteId != cfg.remoteId) {
|
||||
@ -27,7 +27,7 @@ class OneRemoteConfigProvider : public RemoteConfigTableIF {
|
||||
}
|
||||
|
||||
private:
|
||||
RemoteEntityCfg cfg;
|
||||
RemoteEntityCfg& cfg;
|
||||
};
|
||||
|
||||
} // namespace cfdp
|
||||
|
74
src/fsfw/cfdp/handler/ReservedMessageParser.cpp
Normal file
74
src/fsfw/cfdp/handler/ReservedMessageParser.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
#include "ReservedMessageParser.h"
|
||||
|
||||
#include "fsfw/cfdp/CfdpMessage.h"
|
||||
#include "fsfw/cfdp/handler/PutRequest.h"
|
||||
#include "fsfw/cfdp/tlv/MessageToUserTlv.h"
|
||||
#include "fsfw/ipc/CommandMessage.h"
|
||||
#include "fsfw/ipc/QueueFactory.h"
|
||||
|
||||
using namespace returnvalue;
|
||||
|
||||
cfdp::ReservedMessageParser::ReservedMessageParser(StorageManagerIF& ipcStore,
|
||||
MessageQueueIF& msgQueue,
|
||||
MessageQueueId_t userDestination)
|
||||
: msgQueue(msgQueue), ipcStore(ipcStore), userDestination(userDestination) {}
|
||||
|
||||
ReturnValue_t cfdp::ReservedMessageParser::parse(const MessageToUserTlv* msgsToUserArray,
|
||||
size_t numMsgToUser) {
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
cfdp::StringLv sourceFileName;
|
||||
cfdp::StringLv destFileName;
|
||||
PutRequest putRequest;
|
||||
const uint8_t* currentPtr = nullptr;
|
||||
size_t deserSize = 0;
|
||||
bool needToSendPutRequest = false;
|
||||
for (size_t idx = 0; idx < numMsgToUser; idx++) {
|
||||
if (&msgsToUserArray[idx] == nullptr) {
|
||||
continue;
|
||||
}
|
||||
uint8_t messageType = 0;
|
||||
if (msgsToUserArray[idx].isReservedCfdpMessage(messageType, ¤tPtr, deserSize)) {
|
||||
if (messageType == static_cast<uint8_t>(ProxyOpMessageType::PUT_REQUEST)) {
|
||||
EntityId entityIdLv;
|
||||
result = entityIdLv.deSerializeFromLv(¤tPtr, &deserSize);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
putRequest.setDestId(entityIdLv);
|
||||
result =
|
||||
sourceFileName.deSerialize(¤tPtr, &deserSize, SerializeIF::Endianness::NETWORK);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
result =
|
||||
destFileName.deSerialize(¤tPtr, &deserSize, SerializeIF::Endianness::NETWORK);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
putRequest.setSourceAndDestName(sourceFileName, destFileName);
|
||||
needToSendPutRequest = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (needToSendPutRequest) {
|
||||
store_address_t storeId;
|
||||
uint8_t* dataPtr;
|
||||
result = ipcStore.getFreeElement(&storeId, putRequest.getSerializedSize(), &dataPtr);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
size_t serLen = 0;
|
||||
result = putRequest.serialize(&dataPtr, &serLen, putRequest.getSerializedSize(),
|
||||
SerializeIF::Endianness::MACHINE);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
CommandMessage msg;
|
||||
CfdpMessage::setPutRequest(&msg, storeId);
|
||||
result = msgQueue.sendMessage(userDestination, &msg);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
}
|
27
src/fsfw/cfdp/handler/ReservedMessageParser.h
Normal file
27
src/fsfw/cfdp/handler/ReservedMessageParser.h
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "fsfw/cfdp/tlv/MessageToUserTlv.h"
|
||||
#include "fsfw/ipc/MessageQueueIF.h"
|
||||
#include "fsfw/storagemanager/StorageManagerIF.h"
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
/**
|
||||
* This class parses messages to user for special CFDP messages and converts them to appropriate
|
||||
* CFDP requests sent via the IPC store where applicable. It also provides an API to retrieve
|
||||
* custom messages which are not special CFDP messages from a provided bytestream.
|
||||
*/
|
||||
class ReservedMessageParser {
|
||||
public:
|
||||
ReservedMessageParser(StorageManagerIF& ipcStore, MessageQueueIF& msgQueue,
|
||||
MessageQueueId_t userDestination);
|
||||
|
||||
ReturnValue_t parse(const MessageToUserTlv* msgsToUserArray, size_t numMsgsToUser);
|
||||
|
||||
private:
|
||||
MessageQueueIF& msgQueue;
|
||||
StorageManagerIF& ipcStore;
|
||||
MessageQueueId_t userDestination;
|
||||
};
|
||||
|
||||
} // namespace cfdp
|
@ -1 +1,376 @@
|
||||
#include "SourceHandler.h"
|
||||
|
||||
#include <etl/crc32.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "fsfw/cfdp/pdu/EofPduCreator.h"
|
||||
#include "fsfw/cfdp/pdu/FileDataCreator.h"
|
||||
#include "fsfw/cfdp/pdu/MetadataPduCreator.h"
|
||||
#include "fsfw/filesystem/HasFileSystemIF.h"
|
||||
#include "fsfw/globalfunctions/arrayprinter.h"
|
||||
#include "fsfw/objectmanager.h"
|
||||
#include "fsfw/serviceinterface.h"
|
||||
#include "fsfw/tasks/TaskFactory.h"
|
||||
#include "fsfw/tmtcservices/TmTcMessage.h"
|
||||
|
||||
using namespace returnvalue;
|
||||
|
||||
cfdp::SourceHandler::SourceHandler(SourceHandlerParams params, FsfwParams fsfwParams)
|
||||
: sourceParams(std::move(params)), fsfwParams(fsfwParams) {
|
||||
// The entity ID portion of the transaction ID will always remain fixed.
|
||||
transactionParams.id.entityId = sourceParams.cfg.localId;
|
||||
transactionParams.pduConf.sourceId = sourceParams.cfg.localId;
|
||||
if (sourceParams.seqCountProvider.bitWidth() == 8) {
|
||||
transactionParams.pduConf.seqNum.setWidth(cfdp::WidthInBytes::ONE_BYTE);
|
||||
} else if (sourceParams.seqCountProvider.bitWidth() == 16) {
|
||||
transactionParams.pduConf.seqNum.setWidth(cfdp::WidthInBytes::TWO_BYTES);
|
||||
} else if (sourceParams.seqCountProvider.bitWidth() == 32) {
|
||||
transactionParams.pduConf.seqNum.setWidth(cfdp::WidthInBytes::FOUR_BYTES);
|
||||
} else if (sourceParams.seqCountProvider.bitWidth() == 64) {
|
||||
transactionParams.pduConf.seqNum.setWidth(cfdp::WidthInBytes::EIGHT_BYTES);
|
||||
} else {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "cfdp::SourceHandler: Seq count provider bit width "
|
||||
<< sourceParams.seqCountProvider.bitWidth() << " not allowed" << std::endl;
|
||||
#else
|
||||
sif::printError("cfdp::SourceHandler: Seq count provider bit width %d not allowed\n",
|
||||
sourceParams.seqCountProvider.bitWidth());
|
||||
#endif
|
||||
// Yeah, what am I supposed to do here? Can't throw an exception in the FSFW..
|
||||
transactionParams.pduConf.seqNum.setWidth(cfdp::WidthInBytes::ONE_BYTE);
|
||||
}
|
||||
transactionParams.pduConf.seqNum.setValue(0);
|
||||
}
|
||||
|
||||
cfdp::SourceHandler::FsmResult& cfdp::SourceHandler::fsmNacked() {
|
||||
ReturnValue_t result;
|
||||
if (step == TransactionStep::IDLE) {
|
||||
step = TransactionStep::TRANSACTION_START;
|
||||
}
|
||||
if (step == TransactionStep::TRANSACTION_START) {
|
||||
sourceParams.user.transactionIndication(transactionParams.id);
|
||||
result = checksumGeneration();
|
||||
if (result != OK) {
|
||||
addError(result);
|
||||
}
|
||||
step = TransactionStep::SENDING_METADATA;
|
||||
}
|
||||
if (step == TransactionStep::SENDING_METADATA) {
|
||||
result = prepareAndSendMetadataPdu();
|
||||
if (result != OK) {
|
||||
addError(result);
|
||||
}
|
||||
fsmResult.callStatus = CallStatus::CALL_AGAIN;
|
||||
return fsmResult;
|
||||
}
|
||||
if (step == TransactionStep::SENDING_FILE_DATA) {
|
||||
bool noFdPdu = false;
|
||||
result = prepareAndSendNextFileDataPdu(noFdPdu);
|
||||
if (result == OK and !noFdPdu) {
|
||||
fsmResult.callStatus = CallStatus::CALL_AGAIN;
|
||||
return fsmResult;
|
||||
}
|
||||
}
|
||||
if (step == TransactionStep::SENDING_EOF) {
|
||||
result = prepareAndSendEofPdu();
|
||||
if (result != OK) {
|
||||
addError(result);
|
||||
}
|
||||
if (sourceParams.cfg.indicCfg.eofSentIndicRequired) {
|
||||
sourceParams.user.eofSentIndication(transactionParams.id);
|
||||
}
|
||||
if (transactionParams.closureRequested) {
|
||||
step = TransactionStep::WAIT_FOR_FINISH;
|
||||
fsmResult.callStatus = CallStatus::CALL_AFTER_DELAY;
|
||||
} else {
|
||||
step = TransactionStep::NOTICE_OF_COMPLETION;
|
||||
fsmResult.callStatus = CallStatus::CALL_AGAIN;
|
||||
}
|
||||
return fsmResult;
|
||||
}
|
||||
if (step == TransactionStep::WAIT_FOR_FINISH) {
|
||||
// TODO: In case this is a request with closure, wait for finish.
|
||||
// Done, issue notice of completion
|
||||
step = TransactionStep::NOTICE_OF_COMPLETION;
|
||||
}
|
||||
if (step == TransactionStep::NOTICE_OF_COMPLETION) {
|
||||
noticeOfCompletion();
|
||||
reset();
|
||||
}
|
||||
return fsmResult;
|
||||
}
|
||||
|
||||
const cfdp::SourceHandler::FsmResult& cfdp::SourceHandler::stateMachine() {
|
||||
fsmResult.packetsSent = 0;
|
||||
fsmResult.errors = 0;
|
||||
fsmResult.callStatus = CallStatus::DONE;
|
||||
if (state == cfdp::CfdpState::IDLE) {
|
||||
return fsmResult;
|
||||
}
|
||||
if (state == cfdp::CfdpState::BUSY_CLASS_1_NACKED) {
|
||||
return fsmNacked();
|
||||
}
|
||||
return fsmResult;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::SourceHandler::checksumGeneration() {
|
||||
if (transactionParams.fileSize.value() == 0) {
|
||||
// NULL checksum for empty file.
|
||||
transactionParams.crc = 0;
|
||||
return OK;
|
||||
}
|
||||
std::array<uint8_t, 1024> buf{};
|
||||
etl::crc32 crcCalc;
|
||||
uint64_t currentOffset = 0;
|
||||
FileOpParams params(transactionParams.sourceName.data(), transactionParams.fileSize.value());
|
||||
while (currentOffset < transactionParams.fileSize.value()) {
|
||||
uint64_t readLen;
|
||||
if (currentOffset + buf.size() > transactionParams.fileSize.value()) {
|
||||
readLen = transactionParams.fileSize.value() - currentOffset;
|
||||
} else {
|
||||
readLen = buf.size();
|
||||
}
|
||||
if (readLen > 0) {
|
||||
params.offset = currentOffset;
|
||||
params.size = readLen;
|
||||
auto result = sourceParams.user.vfs.readFromFile(params, buf.data(), buf.size());
|
||||
if (result != OK) {
|
||||
addError(result);
|
||||
return FAILED;
|
||||
}
|
||||
crcCalc.add(buf.begin(), buf.begin() + readLen);
|
||||
}
|
||||
currentOffset += readLen;
|
||||
}
|
||||
|
||||
transactionParams.crc = crcCalc.value();
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::SourceHandler::transactionStart(PutRequest& putRequest, RemoteEntityCfg& cfg) {
|
||||
if (state != CfdpState::IDLE) {
|
||||
return SOURCE_TRANSACTION_PENDING;
|
||||
}
|
||||
if (cfg.remoteId != putRequest.getDestId()) {
|
||||
return WRONG_REMOTE_CFG_ENTITY_ID;
|
||||
}
|
||||
if (putRequest.getSourceName().getValueLen() == 0) {
|
||||
return SOURCE_NAME_EMPTY;
|
||||
}
|
||||
if (putRequest.getDestName().getValueLen() == 0) {
|
||||
return DEST_NAME_EMPTY;
|
||||
}
|
||||
const char* srcNamePtr = putRequest.getSourceName().getCString(transactionParams.sourceNameSize);
|
||||
const char* destNamePtr = putRequest.getDestName().getCString(transactionParams.destNameSize);
|
||||
std::strncpy(transactionParams.sourceName.data(), srcNamePtr, transactionParams.sourceNameSize);
|
||||
std::strncpy(transactionParams.destName.data(), destNamePtr, transactionParams.destNameSize);
|
||||
// Add 0 termination. The source and dest name size can not be larger than UINT8_MAX, so this
|
||||
// operation is safe.
|
||||
transactionParams.sourceName[transactionParams.sourceNameSize] = '\0';
|
||||
transactionParams.destName[transactionParams.destNameSize] = '\0';
|
||||
FilesystemParams params(transactionParams.sourceName.data());
|
||||
if (!sourceParams.user.vfs.fileExists(params)) {
|
||||
return FILE_DOES_NOT_EXIST;
|
||||
}
|
||||
if (cfg.maxFileSegmentLen > fileBuf.size() or cfg.maxFileSegmentLen == 0) {
|
||||
return FILE_SEGMENT_LEN_INVALID;
|
||||
}
|
||||
// If transmission mode is not set, use default transmission mode for the remote entity.
|
||||
if (not putRequest.getTransmissionMode(transactionParams.pduConf.mode)) {
|
||||
transactionParams.pduConf.mode = cfg.defaultTransmissionMode;
|
||||
}
|
||||
// If closure request field is not set, use default option for the remote entity.
|
||||
if (not putRequest.getClosureRequested(transactionParams.closureRequested)) {
|
||||
transactionParams.closureRequested = cfg.closureRequested;
|
||||
}
|
||||
const EntityId& destId = putRequest.getDestId();
|
||||
// The width of the source and destination ID must be the same. Use the larger ID value to
|
||||
// ensure the width is large enough for both IDs
|
||||
if (destId.getWidth() > transactionParams.pduConf.sourceId.getWidth()) {
|
||||
transactionParams.pduConf.destId = destId;
|
||||
transactionParams.pduConf.sourceId.setWidth(destId.getWidth());
|
||||
} else {
|
||||
transactionParams.pduConf.destId.setValueAndWidth(transactionParams.pduConf.sourceId.getWidth(),
|
||||
destId.getValue());
|
||||
}
|
||||
// Only used for PDU forwarding, file is sent to file receiver regularly here.
|
||||
transactionParams.pduConf.direction = Direction::TOWARDS_RECEIVER;
|
||||
transactionParams.pduConf.seqNum.setValue(sourceParams.seqCountProvider.getAndIncrement());
|
||||
transactionParams.id.seqNum = transactionParams.pduConf.seqNum;
|
||||
|
||||
if (transactionParams.pduConf.mode == TransmissionMode::ACKNOWLEDGED) {
|
||||
state = cfdp::CfdpState::BUSY_CLASS_2_ACKED;
|
||||
} else if (transactionParams.pduConf.mode == TransmissionMode::UNACKNOWLEDGED) {
|
||||
state = cfdp::CfdpState::BUSY_CLASS_1_NACKED;
|
||||
}
|
||||
step = TransactionStep::IDLE;
|
||||
uint64_t fileSize = 0;
|
||||
sourceParams.user.vfs.getFileSize(params, fileSize);
|
||||
transactionParams.pduConf.largeFile = false;
|
||||
if (fileSize > UINT32_MAX) {
|
||||
transactionParams.pduConf.largeFile = true;
|
||||
}
|
||||
if (fileSize == 0) {
|
||||
transactionParams.checksumType = ChecksumType::NULL_CHECKSUM;
|
||||
} else {
|
||||
transactionParams.checksumType = ChecksumType::CRC_32;
|
||||
}
|
||||
transactionParams.fileSize.setFileSize(fileSize, transactionParams.pduConf.largeFile);
|
||||
transactionParams.progress = 0;
|
||||
transactionParams.remoteCfg = cfg;
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::SourceHandler::prepareAndSendMetadataPdu() {
|
||||
cfdp::StringLv sourceName(transactionParams.sourceName.data(), transactionParams.sourceNameSize);
|
||||
cfdp::StringLv destName(transactionParams.destName.data(), transactionParams.destNameSize);
|
||||
auto metadataInfo =
|
||||
MetadataGenericInfo(transactionParams.closureRequested, transactionParams.checksumType,
|
||||
transactionParams.fileSize);
|
||||
auto metadataPdu =
|
||||
MetadataPduCreator(transactionParams.pduConf, metadataInfo, sourceName, destName, nullptr, 0);
|
||||
ReturnValue_t result = sendGenericPdu(metadataPdu);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
// Advance FSM if everything works
|
||||
step = TransactionStep::SENDING_FILE_DATA;
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::SourceHandler::prepareAndSendNextFileDataPdu(bool& noFileDataPdu) {
|
||||
cfdp::Fss offset(transactionParams.progress);
|
||||
uint64_t readLen;
|
||||
uint64_t fileSize = transactionParams.fileSize.value();
|
||||
noFileDataPdu = false;
|
||||
if (fileSize == 0) {
|
||||
// We are done, no need to send file data PDUs for an empty file.
|
||||
step = TransactionStep::SENDING_EOF;
|
||||
noFileDataPdu = true;
|
||||
return OK;
|
||||
}
|
||||
if (fileSize < transactionParams.remoteCfg.maxFileSegmentLen) {
|
||||
readLen = transactionParams.fileSize.value();
|
||||
} else {
|
||||
if (transactionParams.progress + transactionParams.remoteCfg.maxFileSegmentLen > fileSize) {
|
||||
readLen = fileSize - transactionParams.progress;
|
||||
} else {
|
||||
readLen = transactionParams.remoteCfg.maxFileSegmentLen;
|
||||
}
|
||||
}
|
||||
FileOpParams fileParams(transactionParams.sourceName.data(), readLen);
|
||||
fileParams.offset = transactionParams.progress;
|
||||
ReturnValue_t result =
|
||||
sourceParams.user.vfs.readFromFile(fileParams, fileBuf.data(), fileBuf.size());
|
||||
if (result != returnvalue::OK) {
|
||||
addError(result);
|
||||
return result;
|
||||
}
|
||||
auto fileDataInfo = FileDataInfo(offset, fileBuf.data(), readLen);
|
||||
auto fileDataPdu = FileDataCreator(transactionParams.pduConf, fileDataInfo);
|
||||
result = sendGenericPdu(fileDataPdu);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
transactionParams.progress += readLen;
|
||||
if (transactionParams.progress >= fileSize) {
|
||||
// Advance FSM after all file data PDUs were sent.
|
||||
step = TransactionStep::SENDING_EOF;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::SourceHandler::prepareAndSendEofPdu() {
|
||||
auto eofInfo =
|
||||
EofInfo(ConditionCode::NO_ERROR, transactionParams.crc, transactionParams.fileSize);
|
||||
auto eofPdu = EofPduCreator(transactionParams.pduConf, eofInfo);
|
||||
ReturnValue_t result = sendGenericPdu(eofPdu);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::SourceHandler::initialize() {
|
||||
if (fsfwParams.tmStore == nullptr) {
|
||||
fsfwParams.tmStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TM_STORE);
|
||||
if (fsfwParams.tmStore == nullptr) {
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (fsfwParams.tcStore == nullptr) {
|
||||
fsfwParams.tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
|
||||
if (fsfwParams.tcStore == nullptr) {
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (fsfwParams.msgQueue == nullptr) {
|
||||
return FAILED;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::SourceHandler::sendGenericPdu(const SerializeIF& pdu) {
|
||||
uint8_t* dataPtr;
|
||||
store_address_t storeId;
|
||||
ReturnValue_t result =
|
||||
fsfwParams.tmStore->getFreeElement(&storeId, pdu.getSerializedSize(), &dataPtr);
|
||||
if (result != OK) {
|
||||
addError(result);
|
||||
fsmResult.callStatus = CallStatus::CALL_AFTER_DELAY;
|
||||
if (result == StorageManagerIF::DATA_STORAGE_FULL) {
|
||||
return TM_STORE_FULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
size_t serializedLen = 0;
|
||||
result = pdu.serializeBe(dataPtr, serializedLen, pdu.getSerializedSize());
|
||||
if (result != OK) {
|
||||
addError(result);
|
||||
return result;
|
||||
}
|
||||
TmTcMessage tmMsg(storeId);
|
||||
result =
|
||||
fsfwParams.msgQueue->sendMessage(fsfwParams.packetDest.getReportReceptionQueue(), &tmMsg);
|
||||
if (result != OK) {
|
||||
fsmResult.callStatus = CallStatus::CALL_AFTER_DELAY;
|
||||
}
|
||||
if (result == MessageQueueIF::FULL) {
|
||||
return TARGET_MSG_QUEUE_FULL;
|
||||
} else if (result == OK) {
|
||||
fsmResult.packetsSent += 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::SourceHandler::noticeOfCompletion() {
|
||||
if (sourceParams.cfg.indicCfg.transactionFinishedIndicRequired) {
|
||||
cfdp::TransactionFinishedParams params(transactionParams.id, ConditionCode::NO_ERROR,
|
||||
FileDeliveryCode::DATA_COMPLETE,
|
||||
FileDeliveryStatus::RETAINED_IN_FILESTORE);
|
||||
sourceParams.user.transactionFinishedIndication(params);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::SourceHandler::reset() {
|
||||
step = TransactionStep::IDLE;
|
||||
state = cfdp::CfdpState::IDLE;
|
||||
fsmResult.callStatus = CallStatus::DONE;
|
||||
transactionParams.reset();
|
||||
return OK;
|
||||
}
|
||||
cfdp::CfdpState cfdp::SourceHandler::getState() const { return state; }
|
||||
|
||||
cfdp::SourceHandler::TransactionStep cfdp::SourceHandler::getStep() const { return step; }
|
||||
|
||||
void cfdp::SourceHandler::addError(ReturnValue_t error) {
|
||||
if (fsmResult.errors < fsmResult.errorCodes.size()) {
|
||||
fsmResult.errorCodes[fsmResult.errors] = error;
|
||||
fsmResult.errors++;
|
||||
fsmResult.result = error;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,110 @@
|
||||
#ifndef FSFW_CFDP_CFDPSOURCEHANDLER_H
|
||||
#define FSFW_CFDP_CFDPSOURCEHANDLER_H
|
||||
|
||||
class SourceHandler {};
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "UserBase.h"
|
||||
#include "defs.h"
|
||||
#include "fsfw/cfdp/Fss.h"
|
||||
#include "fsfw/cfdp/handler/PutRequest.h"
|
||||
#include "fsfw/cfdp/handler/mib.h"
|
||||
#include "fsfw/events/EventReportingProxyIF.h"
|
||||
#include "fsfw/storagemanager/StorageManagerIF.h"
|
||||
#include "fsfw/tmtcservices/AcceptsTelemetryIF.h"
|
||||
#include "fsfw/util/ProvidesSeqCountIF.h"
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
struct SourceHandlerParams {
|
||||
SourceHandlerParams(LocalEntityCfg cfg, UserBase& user, ProvidesSeqCountIF& seqCountProvider)
|
||||
: cfg(std::move(cfg)), user(user), seqCountProvider(seqCountProvider) {}
|
||||
|
||||
LocalEntityCfg cfg;
|
||||
UserBase& user;
|
||||
ProvidesSeqCountIF& seqCountProvider;
|
||||
};
|
||||
|
||||
class SourceHandler {
|
||||
public:
|
||||
enum class TransactionStep : uint8_t {
|
||||
IDLE = 0,
|
||||
TRANSACTION_START = 1,
|
||||
SENDING_METADATA = 3,
|
||||
SENDING_FILE_DATA = 4,
|
||||
SENDING_EOF = 5,
|
||||
WAIT_FOR_ACK = 6,
|
||||
WAIT_FOR_FINISH = 7,
|
||||
NOTICE_OF_COMPLETION = 8
|
||||
};
|
||||
struct FsmResult {
|
||||
public:
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
CallStatus callStatus = CallStatus::CALL_AFTER_DELAY;
|
||||
CfdpState state = CfdpState::IDLE;
|
||||
uint32_t packetsSent = 0;
|
||||
uint8_t errors = 0;
|
||||
std::array<ReturnValue_t, 3> errorCodes = {};
|
||||
};
|
||||
|
||||
SourceHandler(SourceHandlerParams params, FsfwParams fsfwParams);
|
||||
|
||||
[[nodiscard]] CfdpState getState() const;
|
||||
[[nodiscard]] TransactionStep getStep() const;
|
||||
|
||||
/**
|
||||
* Pass a put request to the source handler, which might initiate a CFDP transaction and start
|
||||
* the state machine
|
||||
* @return
|
||||
*/
|
||||
ReturnValue_t transactionStart(PutRequest& putRequest, RemoteEntityCfg& cfg);
|
||||
const FsmResult& stateMachine();
|
||||
|
||||
ReturnValue_t initialize();
|
||||
|
||||
private:
|
||||
struct TransactionParams {
|
||||
uint32_t crc{};
|
||||
std::array<char, UINT8_MAX + 1> sourceName{};
|
||||
size_t sourceNameSize = 0;
|
||||
std::array<char, UINT8_MAX + 1> destName{};
|
||||
size_t destNameSize = 0;
|
||||
cfdp::Fss fileSize;
|
||||
size_t progress = 0;
|
||||
bool closureRequested = false;
|
||||
ChecksumType checksumType = ChecksumType::NULL_CHECKSUM;
|
||||
RemoteEntityCfg remoteCfg;
|
||||
PduConfig pduConf;
|
||||
cfdp::TransactionId id{};
|
||||
|
||||
void reset() {
|
||||
sourceNameSize = 0;
|
||||
destNameSize = 0;
|
||||
fileSize.setFileSize(0, false);
|
||||
progress = 0;
|
||||
closureRequested = false;
|
||||
}
|
||||
} transactionParams;
|
||||
|
||||
cfdp::CfdpState state = cfdp::CfdpState::IDLE;
|
||||
TransactionStep step = TransactionStep::IDLE;
|
||||
std::array<uint8_t, 4096> fileBuf{};
|
||||
SourceHandlerParams sourceParams;
|
||||
cfdp::FsfwParams fsfwParams;
|
||||
FsmResult fsmResult;
|
||||
|
||||
FsmResult& fsmNacked();
|
||||
ReturnValue_t checksumGeneration();
|
||||
ReturnValue_t prepareAndSendMetadataPdu();
|
||||
ReturnValue_t prepareAndSendNextFileDataPdu(bool& noFileDataPdu);
|
||||
ReturnValue_t prepareAndSendEofPdu();
|
||||
ReturnValue_t noticeOfCompletion();
|
||||
ReturnValue_t reset();
|
||||
|
||||
[[nodiscard]] ReturnValue_t sendGenericPdu(const SerializeIF& pdu);
|
||||
void addError(ReturnValue_t error);
|
||||
};
|
||||
|
||||
} // namespace cfdp
|
||||
|
||||
#endif // FSFW_CFDP_CFDPSOURCEHANDLER_H
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "StatusReportIF.h"
|
||||
#include "fsfw/cfdp/Fss.h"
|
||||
#include "fsfw/cfdp/VarLenFields.h"
|
||||
#include "fsfw/cfdp/tlv/FilestoreResponseTlv.h"
|
||||
#include "fsfw/cfdp/tlv/MessageToUserTlv.h"
|
||||
@ -27,14 +28,14 @@ struct TransactionFinishedParams {
|
||||
};
|
||||
|
||||
struct MetadataRecvdParams {
|
||||
MetadataRecvdParams(const TransactionId& id, const EntityId& sourceId)
|
||||
: id(id), sourceId(sourceId) {}
|
||||
MetadataRecvdParams(const TransactionId& id, const EntityId& sourceId, Fss fileSize)
|
||||
: id(id), sourceId(sourceId), fileSize(std::move(fileSize)) {}
|
||||
const TransactionId& id;
|
||||
const EntityId& sourceId;
|
||||
uint64_t fileSize = 0;
|
||||
Fss fileSize{};
|
||||
const char* sourceFileName = "";
|
||||
const char* destFileName = "";
|
||||
size_t msgsToUserLen = 0;
|
||||
size_t numberOfMsgsToUser = 0;
|
||||
const MessageToUserTlv* msgsToUserArray = nullptr;
|
||||
};
|
||||
|
||||
@ -65,6 +66,7 @@ struct FileSegmentRecvdParams {
|
||||
*/
|
||||
class UserBase {
|
||||
friend class DestHandler;
|
||||
friend class SourceHandler;
|
||||
|
||||
public:
|
||||
explicit UserBase(HasFileSystemIF& vfs);
|
||||
|
@ -1,11 +1,54 @@
|
||||
#ifndef FSFW_CFDP_HANDLER_DEFS_H
|
||||
#define FSFW_CFDP_HANDLER_DEFS_H
|
||||
|
||||
#include <etl/list.h>
|
||||
|
||||
#include "fsfw/storagemanager/StorageManagerIF.h"
|
||||
#include "fsfw/storagemanager/storeAddress.h"
|
||||
#include "fsfw/tmtcservices/AcceptsTelemetryIF.h"
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
enum class CfdpStates { IDLE, BUSY_CLASS_1_NACKED, BUSY_CLASS_2_ACKED, SUSPENDED };
|
||||
enum class CfdpState { IDLE, BUSY_CLASS_1_NACKED, BUSY_CLASS_2_ACKED, SUSPENDED };
|
||||
|
||||
static constexpr uint8_t SSID = SUBSYSTEM_ID::CFDP;
|
||||
static constexpr uint8_t CID = CLASS_ID::CFDP_HANDLER;
|
||||
|
||||
struct PacketInfo {
|
||||
PacketInfo(PduType type, store_address_t storeId,
|
||||
std::optional<FileDirective> directive = std::nullopt)
|
||||
: pduType(type), directiveType(directive), storeId(storeId) {}
|
||||
|
||||
PduType pduType = PduType::FILE_DATA;
|
||||
std::optional<FileDirective> directiveType = FileDirective::INVALID_DIRECTIVE;
|
||||
store_address_t storeId = store_address_t::invalid();
|
||||
PacketInfo() = default;
|
||||
};
|
||||
|
||||
struct FsfwParams {
|
||||
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;
|
||||
};
|
||||
|
||||
template <size_t SIZE>
|
||||
using PacketInfoList = etl::list<PacketInfo, SIZE>;
|
||||
using PacketInfoListBase = etl::ilist<PacketInfo>;
|
||||
|
||||
enum class CallStatus { DONE, CALL_AFTER_DELAY, CALL_AGAIN };
|
||||
|
||||
namespace events {
|
||||
|
||||
@ -15,8 +58,19 @@ static constexpr Event SERIALIZATION_ERROR = event::makeEvent(SSID, 2, severity:
|
||||
static constexpr Event FILESTORE_ERROR = event::makeEvent(SSID, 3, severity::LOW);
|
||||
//! [EXPORT] : [COMMENT] P1: Transaction step ID, P2: 0 for source file name, 1 for dest file name
|
||||
static constexpr Event FILENAME_TOO_LARGE_ERROR = event::makeEvent(SSID, 4, severity::LOW);
|
||||
//! [EXPORT] : [COMMENT] CFDP request handling failed. P2: Returncode.
|
||||
static constexpr Event HANDLING_CFDP_REQUEST_FAILED = event::makeEvent(SSID, 5, severity::LOW);
|
||||
|
||||
} // namespace events
|
||||
|
||||
static constexpr ReturnValue_t SOURCE_TRANSACTION_PENDING = returnvalue::makeCode(CID, 0);
|
||||
static constexpr ReturnValue_t FILE_DOES_NOT_EXIST = returnvalue::makeCode(CID, 1);
|
||||
static constexpr ReturnValue_t FILE_SEGMENT_LEN_INVALID = returnvalue::makeCode(CID, 2);
|
||||
static constexpr ReturnValue_t SOURCE_NAME_EMPTY = returnvalue::makeCode(CID, 3);
|
||||
static constexpr ReturnValue_t DEST_NAME_EMPTY = returnvalue::makeCode(CID, 4);
|
||||
static constexpr ReturnValue_t WRONG_REMOTE_CFG_ENTITY_ID = returnvalue::makeCode(CID, 5);
|
||||
static constexpr ReturnValue_t TARGET_MSG_QUEUE_FULL = returnvalue::makeCode(CID, 6);
|
||||
static constexpr ReturnValue_t TM_STORE_FULL = returnvalue::makeCode(CID, 7);
|
||||
|
||||
} // namespace cfdp
|
||||
#endif // FSFW_CFDP_HANDLER_DEFS_H
|
||||
|
@ -27,14 +27,15 @@ struct LocalEntityCfg {
|
||||
};
|
||||
|
||||
struct RemoteEntityCfg {
|
||||
RemoteEntityCfg() = default;
|
||||
explicit RemoteEntityCfg(EntityId id) : remoteId(std::move(id)) {}
|
||||
EntityId remoteId;
|
||||
size_t maxFileSegmentLen = 2048;
|
||||
size_t maxFileSegmentLen = 1024;
|
||||
bool closureRequested = false;
|
||||
bool crcOnTransmission = false;
|
||||
TransmissionMode defaultTransmissionMode = TransmissionMode::UNACKNOWLEDGED;
|
||||
ChecksumType defaultChecksum = ChecksumType::NULL_CHECKSUM;
|
||||
const uint8_t version = CFDP_VERSION_2;
|
||||
uint8_t version = CFDP_VERSION_2;
|
||||
};
|
||||
|
||||
} // namespace cfdp
|
||||
|
@ -17,7 +17,7 @@ target_sources(
|
||||
FinishedInfo.cpp
|
||||
FinishedPduCreator.cpp
|
||||
FinishedPduReader.cpp
|
||||
MetadataInfo.cpp
|
||||
MetadataGenericInfo.cpp
|
||||
MetadataPduCreator.cpp
|
||||
MetadataPduReader.cpp
|
||||
KeepAlivePduCreator.cpp
|
||||
|
@ -1,8 +1,13 @@
|
||||
#include "EofInfo.h"
|
||||
|
||||
EofInfo::EofInfo(cfdp::ConditionCode conditionCode, uint32_t checksum, cfdp::FileSize fileSize,
|
||||
#include <utility>
|
||||
|
||||
EofInfo::EofInfo(cfdp::ConditionCode conditionCode, uint32_t checksum, cfdp::Fss fileSize,
|
||||
EntityIdTlv* faultLoc)
|
||||
: conditionCode(conditionCode), checksum(checksum), fileSize(fileSize), faultLoc(faultLoc) {}
|
||||
: conditionCode(conditionCode),
|
||||
checksum(checksum),
|
||||
fileSize(std::move(fileSize)),
|
||||
faultLoc(faultLoc) {}
|
||||
|
||||
EofInfo::EofInfo(EntityIdTlv* faultLoc)
|
||||
: conditionCode(cfdp::ConditionCode::NO_CONDITION_FIELD),
|
||||
@ -16,15 +21,15 @@ cfdp::ConditionCode EofInfo::getConditionCode() const { return conditionCode; }
|
||||
|
||||
EntityIdTlv* EofInfo::getFaultLoc() const { return faultLoc; }
|
||||
|
||||
cfdp::FileSize& EofInfo::getFileSize() { return fileSize; }
|
||||
cfdp::Fss& EofInfo::getFileSize() { return fileSize; }
|
||||
|
||||
void EofInfo::setChecksum(uint32_t checksum) { this->checksum = checksum; }
|
||||
void EofInfo::setChecksum(uint32_t checksum_) { this->checksum = checksum_; }
|
||||
|
||||
void EofInfo::setConditionCode(cfdp::ConditionCode conditionCode) {
|
||||
this->conditionCode = conditionCode;
|
||||
void EofInfo::setConditionCode(cfdp::ConditionCode conditionCode_) {
|
||||
this->conditionCode = conditionCode_;
|
||||
}
|
||||
|
||||
void EofInfo::setFaultLoc(EntityIdTlv* faultLoc) { this->faultLoc = faultLoc; }
|
||||
void EofInfo::setFaultLoc(EntityIdTlv* faultLoc_) { this->faultLoc = faultLoc_; }
|
||||
|
||||
size_t EofInfo::getSerializedSize(bool fssLarge) {
|
||||
// Condition code + spare + 4 byte checksum
|
||||
@ -42,6 +47,6 @@ size_t EofInfo::getSerializedSize(bool fssLarge) {
|
||||
return size;
|
||||
}
|
||||
|
||||
ReturnValue_t EofInfo::setFileSize(size_t fileSize, bool isLarge) {
|
||||
return this->fileSize.setFileSize(fileSize, isLarge);
|
||||
ReturnValue_t EofInfo::setFileSize(size_t fileSize_, bool isLarge) {
|
||||
return this->fileSize.setFileSize(fileSize_, isLarge);
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
#ifndef FSFW_SRC_FSFW_CFDP_PDU_EOFINFO_H_
|
||||
#define FSFW_SRC_FSFW_CFDP_PDU_EOFINFO_H_
|
||||
|
||||
#include "../FileSize.h"
|
||||
#include "../Fss.h"
|
||||
#include "../definitions.h"
|
||||
#include "fsfw/cfdp/tlv/EntityIdTlv.h"
|
||||
|
||||
struct EofInfo {
|
||||
public:
|
||||
explicit EofInfo(EntityIdTlv* faultLoc = nullptr);
|
||||
EofInfo(cfdp::ConditionCode conditionCode, uint32_t checksum, cfdp::FileSize fileSize,
|
||||
EofInfo(cfdp::ConditionCode conditionCode, uint32_t checksum, cfdp::Fss fileSize,
|
||||
EntityIdTlv* faultLoc = nullptr);
|
||||
|
||||
size_t getSerializedSize(bool fssLarge = false);
|
||||
@ -17,7 +17,7 @@ struct EofInfo {
|
||||
[[nodiscard]] cfdp::ConditionCode getConditionCode() const;
|
||||
|
||||
[[nodiscard]] EntityIdTlv* getFaultLoc() const;
|
||||
cfdp::FileSize& getFileSize();
|
||||
cfdp::Fss& getFileSize();
|
||||
void setChecksum(uint32_t checksum);
|
||||
void setConditionCode(cfdp::ConditionCode conditionCode);
|
||||
void setFaultLoc(EntityIdTlv* faultLoc);
|
||||
@ -26,7 +26,7 @@ struct EofInfo {
|
||||
private:
|
||||
cfdp::ConditionCode conditionCode;
|
||||
uint32_t checksum;
|
||||
cfdp::FileSize fileSize;
|
||||
cfdp::Fss fileSize;
|
||||
EntityIdTlv* faultLoc = nullptr;
|
||||
};
|
||||
|
||||
|
@ -37,7 +37,7 @@ ReturnValue_t FileDataCreator::serialize(uint8_t** buffer, size_t* size, size_t
|
||||
*buffer += segmentMetadataLen;
|
||||
*size += segmentMetadataLen;
|
||||
}
|
||||
cfdp::FileSize& offset = info.getOffset();
|
||||
cfdp::Fss& offset = info.getOffset();
|
||||
result = offset.serialize(this->getLargeFileFlag(), buffer, size, maxSize, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
|
@ -1,9 +1,9 @@
|
||||
#include "FileDataInfo.h"
|
||||
|
||||
FileDataInfo::FileDataInfo(cfdp::FileSize &offset, const uint8_t *fileData, size_t fileSize)
|
||||
: offset(offset), fileData(fileData), fileSize(fileSize) {}
|
||||
#include <utility>
|
||||
|
||||
FileDataInfo::FileDataInfo(cfdp::FileSize &offset) : offset(offset) {}
|
||||
FileDataInfo::FileDataInfo(cfdp::Fss offset, const uint8_t *fileData, size_t fileSize)
|
||||
: offset(std::move(offset)), fileData(fileData), fileSize(fileSize) {}
|
||||
|
||||
void FileDataInfo::setSegmentMetadataFlag(bool enable) {
|
||||
if (enable) {
|
||||
@ -71,7 +71,7 @@ const uint8_t *FileDataInfo::getSegmentMetadata(size_t *segmentMetadataLen_) {
|
||||
return segmentMetadata;
|
||||
}
|
||||
|
||||
cfdp::FileSize &FileDataInfo::getOffset() { return offset; }
|
||||
cfdp::Fss &FileDataInfo::getOffset() { return offset; }
|
||||
|
||||
void FileDataInfo::setRecordContinuationState(cfdp::RecordContinuationState recContState) {
|
||||
this->recContState = recContState;
|
||||
|
@ -1,17 +1,17 @@
|
||||
#ifndef FSFW_SRC_FSFW_CFDP_PDU_FILEDATAINFO_H_
|
||||
#define FSFW_SRC_FSFW_CFDP_PDU_FILEDATAINFO_H_
|
||||
|
||||
#include <fsfw/cfdp/FileSize.h>
|
||||
#include <fsfw/cfdp/Fss.h>
|
||||
#include <fsfw/cfdp/definitions.h>
|
||||
|
||||
class FileDataInfo {
|
||||
public:
|
||||
explicit FileDataInfo(cfdp::FileSize& offset);
|
||||
FileDataInfo(cfdp::FileSize& offset, const uint8_t* fileData, size_t fileSize);
|
||||
FileDataInfo() = default;
|
||||
FileDataInfo(cfdp::Fss offset, const uint8_t* fileData, size_t fileSize);
|
||||
|
||||
[[nodiscard]] size_t getSerializedSize(bool largeFile = false) const;
|
||||
|
||||
cfdp::FileSize& getOffset();
|
||||
cfdp::Fss& getOffset();
|
||||
const uint8_t* getFileData(size_t* fileSize = nullptr) const;
|
||||
void setFileData(const uint8_t* fileData, size_t fileSize);
|
||||
|
||||
@ -33,7 +33,7 @@ class FileDataInfo {
|
||||
private:
|
||||
cfdp::SegmentMetadataFlag segmentMetadataFlag = cfdp::SegmentMetadataFlag::NOT_PRESENT;
|
||||
cfdp::SegmentationControl segCtrl = cfdp::SegmentationControl::NO_RECORD_BOUNDARIES_PRESERVATION;
|
||||
cfdp::FileSize& offset;
|
||||
cfdp::Fss offset;
|
||||
const uint8_t* fileData = nullptr;
|
||||
size_t fileSize = 0;
|
||||
cfdp::RecordContinuationState recContState = cfdp::RecordContinuationState::NO_START_NO_END;
|
||||
|
@ -103,11 +103,11 @@ void PduHeaderReader::getTransactionSeqNum(cfdp::TransactionSeqNum &seqNum) cons
|
||||
}
|
||||
|
||||
void PduHeaderReader::assignVarLenField(cfdp::VarLenField *field, cfdp::WidthInBytes width,
|
||||
void *sourcePtr) const {
|
||||
void *sourcePtr) {
|
||||
switch (width) {
|
||||
case (cfdp::WidthInBytes::ONE_BYTE): {
|
||||
auto *fieldTyped = static_cast<uint8_t *>(sourcePtr);
|
||||
field->setValue(width, *fieldTyped);
|
||||
field->setValueAndWidth(width, *fieldTyped);
|
||||
break;
|
||||
}
|
||||
case (cfdp::WidthInBytes::TWO_BYTES): {
|
||||
@ -115,7 +115,7 @@ void PduHeaderReader::assignVarLenField(cfdp::VarLenField *field, cfdp::WidthInB
|
||||
size_t deserSize = 0;
|
||||
SerializeAdapter::deSerialize(&fieldTyped, static_cast<uint8_t *>(sourcePtr), &deserSize,
|
||||
SerializeIF::Endianness::NETWORK);
|
||||
field->setValue(width, fieldTyped);
|
||||
field->setValueAndWidth(width, fieldTyped);
|
||||
break;
|
||||
}
|
||||
case (cfdp::WidthInBytes::FOUR_BYTES): {
|
||||
@ -123,7 +123,15 @@ void PduHeaderReader::assignVarLenField(cfdp::VarLenField *field, cfdp::WidthInB
|
||||
size_t deserSize = 0;
|
||||
SerializeAdapter::deSerialize(&fieldTyped, static_cast<uint8_t *>(sourcePtr), &deserSize,
|
||||
SerializeIF::Endianness::NETWORK);
|
||||
field->setValue(width, fieldTyped);
|
||||
field->setValueAndWidth(width, fieldTyped);
|
||||
break;
|
||||
}
|
||||
case (cfdp::WidthInBytes::EIGHT_BYTES): {
|
||||
uint64_t fieldTyped = 0;
|
||||
size_t deserSize = 0;
|
||||
SerializeAdapter::deSerialize(&fieldTyped, static_cast<uint8_t *>(sourcePtr), &deserSize,
|
||||
SerializeIF::Endianness::NETWORK);
|
||||
field->setValueAndWidth(width, fieldTyped);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "KeepAlivePduCreator.h"
|
||||
|
||||
KeepAlivePduCreator::KeepAlivePduCreator(PduConfig &conf, cfdp::FileSize &progress)
|
||||
KeepAlivePduCreator::KeepAlivePduCreator(PduConfig &conf, cfdp::Fss &progress)
|
||||
: FileDirectiveCreator(conf, cfdp::FileDirective::KEEP_ALIVE, 4), progress(progress) {
|
||||
updateDirectiveFieldLen();
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
#ifndef FSFW_CFDP_PDU_KEEPALIVEPDUSERIALIZER_H_
|
||||
#define FSFW_CFDP_PDU_KEEPALIVEPDUSERIALIZER_H_
|
||||
|
||||
#include "fsfw/cfdp/FileSize.h"
|
||||
#include "fsfw/cfdp/Fss.h"
|
||||
#include "fsfw/cfdp/pdu/FileDirectiveCreator.h"
|
||||
|
||||
class KeepAlivePduCreator : public FileDirectiveCreator {
|
||||
public:
|
||||
KeepAlivePduCreator(PduConfig& conf, cfdp::FileSize& progress);
|
||||
KeepAlivePduCreator(PduConfig& conf, cfdp::Fss& progress);
|
||||
|
||||
void updateDirectiveFieldLen();
|
||||
|
||||
@ -16,7 +16,7 @@ class KeepAlivePduCreator : public FileDirectiveCreator {
|
||||
Endianness streamEndianness) const override;
|
||||
|
||||
private:
|
||||
cfdp::FileSize& progress;
|
||||
cfdp::Fss& progress;
|
||||
};
|
||||
|
||||
#endif /* FSFW_CFDP_PDU_KEEPALIVEPDUSERIALIZER_H_ */
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include "KeepAlivePduReader.h"
|
||||
|
||||
KeepAlivePduReader::KeepAlivePduReader(const uint8_t* pduBuf, size_t maxSize,
|
||||
cfdp::FileSize& progress)
|
||||
KeepAlivePduReader::KeepAlivePduReader(const uint8_t* pduBuf, size_t maxSize, cfdp::Fss& progress)
|
||||
: FileDirectiveReader(pduBuf, maxSize), progress(progress) {}
|
||||
|
||||
ReturnValue_t KeepAlivePduReader::parseData() {
|
||||
@ -15,4 +14,4 @@ ReturnValue_t KeepAlivePduReader::parseData() {
|
||||
return progress.deSerialize(&buffer, &remLen, getEndianness());
|
||||
}
|
||||
|
||||
cfdp::FileSize& KeepAlivePduReader::getProgress() { return progress; }
|
||||
cfdp::Fss& KeepAlivePduReader::getProgress() { return progress; }
|
||||
|
@ -1,19 +1,19 @@
|
||||
#ifndef FSFW_CFDP_PDU_KEEPALIVEREADER_H_
|
||||
#define FSFW_CFDP_PDU_KEEPALIVEREADER_H_
|
||||
|
||||
#include "fsfw/cfdp/FileSize.h"
|
||||
#include "fsfw/cfdp/Fss.h"
|
||||
#include "fsfw/cfdp/pdu/FileDirectiveReader.h"
|
||||
|
||||
class KeepAlivePduReader : public FileDirectiveReader {
|
||||
public:
|
||||
KeepAlivePduReader(const uint8_t* pduBuf, size_t maxSize, cfdp::FileSize& progress);
|
||||
KeepAlivePduReader(const uint8_t* pduBuf, size_t maxSize, cfdp::Fss& progress);
|
||||
|
||||
ReturnValue_t parseData() override;
|
||||
|
||||
cfdp::FileSize& getProgress();
|
||||
cfdp::Fss& getProgress();
|
||||
|
||||
private:
|
||||
cfdp::FileSize& progress;
|
||||
cfdp::Fss& progress;
|
||||
};
|
||||
|
||||
#endif /* FSFW_CFDP_PDU_KEEPALIVEPDUREADER_H_ */
|
||||
|
35
src/fsfw/cfdp/pdu/MetadataGenericInfo.cpp
Normal file
35
src/fsfw/cfdp/pdu/MetadataGenericInfo.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
#include "MetadataGenericInfo.h"
|
||||
|
||||
MetadataGenericInfo::MetadataGenericInfo(bool closureRequested, cfdp::ChecksumType checksumType,
|
||||
cfdp::Fss fileSize)
|
||||
: MetadataGenericInfo(std::move(fileSize)) {
|
||||
this->closureRequested = closureRequested;
|
||||
this->checksumType = checksumType;
|
||||
}
|
||||
|
||||
MetadataGenericInfo::MetadataGenericInfo(cfdp::Fss fileSize) : fileSize(std::move(fileSize)) {}
|
||||
|
||||
cfdp::ChecksumType MetadataGenericInfo::getChecksumType() const { return checksumType; }
|
||||
|
||||
void MetadataGenericInfo::setChecksumType(cfdp::ChecksumType checksumType_) {
|
||||
checksumType = checksumType_;
|
||||
}
|
||||
|
||||
bool MetadataGenericInfo::isClosureRequested() const { return closureRequested; }
|
||||
|
||||
void MetadataGenericInfo::setClosureRequested(bool closureRequested_) {
|
||||
closureRequested = closureRequested_;
|
||||
}
|
||||
|
||||
const cfdp::Fss& MetadataGenericInfo::getFileSize() const { return fileSize; }
|
||||
|
||||
size_t MetadataGenericInfo::getSerializedSize(bool fssLarge) {
|
||||
// 1 byte + minimal FSS 4 bytes
|
||||
size_t size = 5;
|
||||
if (fssLarge) {
|
||||
size += 4;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
cfdp::Fss& MetadataGenericInfo::getMutFileSize() { return fileSize; }
|
35
src/fsfw/cfdp/pdu/MetadataGenericInfo.h
Normal file
35
src/fsfw/cfdp/pdu/MetadataGenericInfo.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_
|
||||
#define FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "fsfw/cfdp/Fss.h"
|
||||
#include "fsfw/cfdp/definitions.h"
|
||||
#include "fsfw/cfdp/tlv/Lv.h"
|
||||
#include "fsfw/cfdp/tlv/StringLv.h"
|
||||
#include "fsfw/cfdp/tlv/Tlv.h"
|
||||
|
||||
class MetadataGenericInfo {
|
||||
public:
|
||||
MetadataGenericInfo() = default;
|
||||
explicit MetadataGenericInfo(cfdp::Fss fileSize);
|
||||
MetadataGenericInfo(bool closureRequested, cfdp::ChecksumType checksumType, cfdp::Fss fileSize);
|
||||
|
||||
static size_t getSerializedSize(bool fssLarge = false);
|
||||
|
||||
[[nodiscard]] cfdp::ChecksumType getChecksumType() const;
|
||||
void setChecksumType(cfdp::ChecksumType checksumType);
|
||||
[[nodiscard]] bool isClosureRequested() const;
|
||||
void setClosureRequested(bool closureRequested = false);
|
||||
|
||||
[[nodiscard]] const cfdp::Fss& getFileSize() const;
|
||||
|
||||
cfdp::Fss& getMutFileSize();
|
||||
|
||||
private:
|
||||
bool closureRequested = false;
|
||||
cfdp::ChecksumType checksumType = cfdp::ChecksumType::NULL_CHECKSUM;
|
||||
cfdp::Fss fileSize;
|
||||
};
|
||||
|
||||
#endif /* FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_ */
|
@ -1,103 +0,0 @@
|
||||
#include "MetadataInfo.h"
|
||||
|
||||
MetadataInfo::MetadataInfo(bool closureRequested, cfdp::ChecksumType checksumType,
|
||||
cfdp::FileSize& fileSize, cfdp::StringLv& sourceFileName,
|
||||
cfdp::StringLv& destFileName)
|
||||
: MetadataInfo(fileSize, sourceFileName, destFileName) {
|
||||
this->closureRequested = closureRequested;
|
||||
this->checksumType = checksumType;
|
||||
}
|
||||
|
||||
MetadataInfo::MetadataInfo(cfdp::FileSize& fileSize, cfdp::StringLv& sourceFileName,
|
||||
cfdp::StringLv& destFileName)
|
||||
: fileSize(fileSize), sourceFileName(sourceFileName), destFileName(destFileName) {}
|
||||
|
||||
void MetadataInfo::setOptionsArray(cfdp::Tlv** optionsArray_, std::optional<size_t> optionsLen_,
|
||||
std::optional<size_t> maxOptionsLen_) {
|
||||
this->optionsArray = optionsArray_;
|
||||
if (maxOptionsLen_) {
|
||||
this->maxOptionsLen = maxOptionsLen_.value();
|
||||
}
|
||||
if (optionsLen_) {
|
||||
this->optionsLen = optionsLen_.value();
|
||||
}
|
||||
}
|
||||
|
||||
cfdp::ChecksumType MetadataInfo::getChecksumType() const { return checksumType; }
|
||||
|
||||
void MetadataInfo::setChecksumType(cfdp::ChecksumType checksumType_) {
|
||||
checksumType = checksumType_;
|
||||
}
|
||||
|
||||
bool MetadataInfo::isClosureRequested() const { return closureRequested; }
|
||||
|
||||
void MetadataInfo::setClosureRequested(bool closureRequested_) {
|
||||
closureRequested = closureRequested_;
|
||||
}
|
||||
|
||||
cfdp::StringLv& MetadataInfo::getDestFileName() { return destFileName; }
|
||||
|
||||
cfdp::FileSize& MetadataInfo::getFileSize() { return fileSize; }
|
||||
|
||||
ReturnValue_t MetadataInfo::getOptions(cfdp::Tlv*** optionsArray_, size_t* optionsLen_,
|
||||
size_t* maxOptsLen) {
|
||||
if (optionsArray_ == nullptr or optionsArray == nullptr) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
*optionsArray_ = optionsArray;
|
||||
if (optionsLen_ != nullptr) {
|
||||
*optionsLen_ = this->optionsLen;
|
||||
}
|
||||
if (maxOptsLen != nullptr) {
|
||||
*maxOptsLen = this->maxOptionsLen;
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
bool MetadataInfo::hasOptions() const {
|
||||
if (optionsArray != nullptr and optionsLen > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MetadataInfo::canHoldOptions() const {
|
||||
if (optionsArray != nullptr and maxOptionsLen > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t MetadataInfo::getSerializedSize(bool fssLarge) {
|
||||
// 1 byte + minimal FSS 4 bytes
|
||||
size_t size = 5;
|
||||
if (fssLarge) {
|
||||
size += 4;
|
||||
}
|
||||
size += sourceFileName.getSerializedSize();
|
||||
size += destFileName.getSerializedSize();
|
||||
if (hasOptions()) {
|
||||
for (size_t idx = 0; idx < optionsLen; idx++) {
|
||||
size += optionsArray[idx]->getSerializedSize();
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void MetadataInfo::setDestFileName(cfdp::StringLv& destFileName_) {
|
||||
this->destFileName = destFileName_;
|
||||
}
|
||||
|
||||
void MetadataInfo::setSourceFileName(cfdp::StringLv& sourceFileName_) {
|
||||
this->sourceFileName = sourceFileName_;
|
||||
}
|
||||
|
||||
size_t MetadataInfo::getMaxOptionsLen() const { return maxOptionsLen; }
|
||||
|
||||
void MetadataInfo::setMaxOptionsLen(size_t maxOptionsLen_) { this->maxOptionsLen = maxOptionsLen_; }
|
||||
|
||||
size_t MetadataInfo::getOptionsLen() const { return optionsLen; }
|
||||
|
||||
void MetadataInfo::setOptionsLen(size_t optionsLen_) { this->optionsLen = optionsLen_; }
|
||||
|
||||
cfdp::StringLv& MetadataInfo::getSourceFileName() { return sourceFileName; }
|
@ -1,55 +0,0 @@
|
||||
#ifndef FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_
|
||||
#define FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "fsfw/cfdp/FileSize.h"
|
||||
#include "fsfw/cfdp/definitions.h"
|
||||
#include "fsfw/cfdp/tlv/Lv.h"
|
||||
#include "fsfw/cfdp/tlv/StringLv.h"
|
||||
#include "fsfw/cfdp/tlv/Tlv.h"
|
||||
|
||||
class MetadataInfo {
|
||||
public:
|
||||
MetadataInfo(cfdp::FileSize& fileSize, cfdp::StringLv& sourceFileName,
|
||||
cfdp::StringLv& destFileName);
|
||||
MetadataInfo(bool closureRequested, cfdp::ChecksumType checksumType, cfdp::FileSize& fileSize,
|
||||
cfdp::StringLv& sourceFileName, cfdp::StringLv& destFileName);
|
||||
|
||||
size_t getSerializedSize(bool fssLarge = false);
|
||||
|
||||
void setOptionsArray(cfdp::Tlv** optionsArray, std::optional<size_t> optionsLen,
|
||||
std::optional<size_t> maxOptionsLen);
|
||||
[[nodiscard]] cfdp::ChecksumType getChecksumType() const;
|
||||
void setChecksumType(cfdp::ChecksumType checksumType);
|
||||
[[nodiscard]] bool isClosureRequested() const;
|
||||
void setClosureRequested(bool closureRequested = false);
|
||||
|
||||
void setDestFileName(cfdp::StringLv& destFileName);
|
||||
void setSourceFileName(cfdp::StringLv& sourceFileName);
|
||||
|
||||
cfdp::StringLv& getDestFileName();
|
||||
cfdp::StringLv& getSourceFileName();
|
||||
cfdp::FileSize& getFileSize();
|
||||
|
||||
[[nodiscard]] bool hasOptions() const;
|
||||
[[nodiscard]] bool canHoldOptions() const;
|
||||
ReturnValue_t getOptions(cfdp::Tlv*** optionsArray, size_t* optionsLen, size_t* maxOptsLen);
|
||||
void setOptionsLen(size_t optionsLen);
|
||||
[[nodiscard]] size_t getOptionsLen() const;
|
||||
void setMaxOptionsLen(size_t maxOptionsLen);
|
||||
[[nodiscard]] size_t getMaxOptionsLen() const;
|
||||
|
||||
private:
|
||||
bool closureRequested = false;
|
||||
cfdp::ChecksumType checksumType = cfdp::ChecksumType::NULL_CHECKSUM;
|
||||
cfdp::FileSize& fileSize;
|
||||
cfdp::StringLv& sourceFileName;
|
||||
cfdp::StringLv& destFileName;
|
||||
|
||||
cfdp::Tlv** optionsArray = nullptr;
|
||||
size_t optionsLen = 0;
|
||||
size_t maxOptionsLen = 0;
|
||||
};
|
||||
|
||||
#endif /* FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_ */
|
@ -1,12 +1,26 @@
|
||||
#include "MetadataPduCreator.h"
|
||||
|
||||
MetadataPduCreator::MetadataPduCreator(PduConfig &conf, MetadataInfo &info)
|
||||
: FileDirectiveCreator(conf, cfdp::FileDirective::METADATA, 5), info(info) {
|
||||
MetadataPduCreator::MetadataPduCreator(PduConfig &conf, MetadataGenericInfo &info,
|
||||
cfdp::StringLv &srcFileName, cfdp::StringLv &destFileName,
|
||||
cfdp::Tlv **optionsArray, size_t optionsLen)
|
||||
: FileDirectiveCreator(conf, cfdp::FileDirective::METADATA, 5),
|
||||
info(info),
|
||||
srcFileName(srcFileName),
|
||||
destFileName(destFileName),
|
||||
optionsArray(optionsArray),
|
||||
optionsLen(optionsLen) {
|
||||
updateDirectiveFieldLen();
|
||||
}
|
||||
|
||||
void MetadataPduCreator::updateDirectiveFieldLen() {
|
||||
setDirectiveDataFieldLen(info.getSerializedSize(getLargeFileFlag()));
|
||||
size_t dirFieldLen = MetadataGenericInfo::getSerializedSize(HeaderCreator::getLargeFileFlag()) +
|
||||
srcFileName.getSerializedSize() + destFileName.getSerializedSize();
|
||||
if (optionsLen > 0 and optionsArray != nullptr) {
|
||||
for (size_t idx = 0; idx < optionsLen; idx++) {
|
||||
dirFieldLen += optionsArray[idx]->getSerializedSize();
|
||||
}
|
||||
}
|
||||
setDirectiveDataFieldLen(dirFieldLen);
|
||||
}
|
||||
|
||||
size_t MetadataPduCreator::getSerializedSize() const {
|
||||
@ -29,21 +43,18 @@ ReturnValue_t MetadataPduCreator::serialize(uint8_t **buffer, size_t *size, size
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
result = info.getSourceFileName().serialize(buffer, size, maxSize, streamEndianness);
|
||||
result = srcFileName.serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
result = info.getDestFileName().serialize(buffer, size, maxSize, streamEndianness);
|
||||
result = destFileName.serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (info.hasOptions()) {
|
||||
cfdp::Tlv **optsArray = nullptr;
|
||||
size_t optsLen = 0;
|
||||
info.getOptions(&optsArray, &optsLen, nullptr);
|
||||
for (size_t idx = 0; idx < optsLen; idx++) {
|
||||
result = optsArray[idx]->serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (optionsLen > 0 and optionsArray != nullptr) {
|
||||
for (size_t idx = 0; idx < optionsLen; idx++) {
|
||||
result = optionsArray[idx]->serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
@ -51,3 +62,5 @@ ReturnValue_t MetadataPduCreator::serialize(uint8_t **buffer, size_t *size, size
|
||||
}
|
||||
return result;
|
||||
}
|
||||
const cfdp::StringLv &MetadataPduCreator::getSourceFileName() const { return srcFileName; }
|
||||
const cfdp::StringLv &MetadataPduCreator::getDestFileName() const { return destFileName; }
|
||||
|
@ -2,22 +2,30 @@
|
||||
#define FSFW_CFDP_PDU_METADATAPDUCREATOR_H_
|
||||
|
||||
#include "fsfw/cfdp/pdu/FileDirectiveCreator.h"
|
||||
#include "fsfw/cfdp/pdu/MetadataInfo.h"
|
||||
#include "fsfw/cfdp/pdu/MetadataGenericInfo.h"
|
||||
|
||||
class MetadataPduCreator : public FileDirectiveCreator {
|
||||
public:
|
||||
MetadataPduCreator(PduConfig& conf, MetadataInfo& info);
|
||||
MetadataPduCreator(PduConfig& conf, MetadataGenericInfo& info, cfdp::StringLv& srcFileName,
|
||||
cfdp::StringLv& destFileName, cfdp::Tlv** optionsArray, size_t optionsLen);
|
||||
|
||||
void updateDirectiveFieldLen();
|
||||
|
||||
[[nodiscard]] size_t getSerializedSize() const override;
|
||||
|
||||
const cfdp::StringLv& getSourceFileName() const;
|
||||
const cfdp::StringLv& getDestFileName() const;
|
||||
|
||||
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
Endianness streamEndianness) const override;
|
||||
using FileDirectiveCreator::serialize;
|
||||
|
||||
private:
|
||||
MetadataInfo& info;
|
||||
MetadataGenericInfo& info;
|
||||
cfdp::StringLv& srcFileName;
|
||||
cfdp::StringLv& destFileName;
|
||||
cfdp::Tlv** optionsArray;
|
||||
size_t optionsLen;
|
||||
};
|
||||
|
||||
#endif /* FSFW_CFDP_PDU_METADATAPDUCREATOR_H_ */
|
||||
|
@ -1,9 +1,15 @@
|
||||
#include "MetadataPduReader.h"
|
||||
|
||||
MetadataPduReader::MetadataPduReader(const uint8_t* pduBuf, size_t maxSize, MetadataInfo& info)
|
||||
: FileDirectiveReader(pduBuf, maxSize), info(info) {}
|
||||
MetadataPduReader::MetadataPduReader(const uint8_t* pduBuf, size_t maxSize,
|
||||
MetadataGenericInfo& info, cfdp::Tlv* optionsArray,
|
||||
size_t optArrayMaxSize)
|
||||
: FileDirectiveReader(pduBuf, maxSize),
|
||||
info(info),
|
||||
optionArray(optionsArray),
|
||||
optionArrayMaxSize(optArrayMaxSize) {}
|
||||
|
||||
ReturnValue_t MetadataPduReader::parseData() {
|
||||
parsedOptions = 0;
|
||||
ReturnValue_t result = FileDirectiveReader::parseData();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
@ -19,39 +25,43 @@ ReturnValue_t MetadataPduReader::parseData() {
|
||||
remSize -= 1;
|
||||
buf += 1;
|
||||
auto endianness = getEndianness();
|
||||
result = info.getFileSize().deSerialize(&buf, &remSize, endianness);
|
||||
result = info.getMutFileSize().deSerialize(&buf, &remSize, endianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
result = info.getSourceFileName().deSerialize(&buf, &remSize, endianness);
|
||||
result = srcFileName.deSerialize(&buf, &remSize, endianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
result = info.getDestFileName().deSerialize(&buf, &remSize, endianness);
|
||||
result = destFileName.deSerialize(&buf, &remSize, endianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
info.setOptionsLen(0);
|
||||
if (remSize > 0) {
|
||||
if (not info.canHoldOptions()) {
|
||||
if (optionArrayMaxSize == 0 or optionArray == nullptr) {
|
||||
return cfdp::METADATA_CANT_PARSE_OPTIONS;
|
||||
}
|
||||
cfdp::Tlv** optionsArray = nullptr;
|
||||
size_t optsMaxLen = 0;
|
||||
size_t optsIdx = 0;
|
||||
info.getOptions(&optionsArray, nullptr, &optsMaxLen);
|
||||
while (remSize > 0) {
|
||||
if (optsIdx > optsMaxLen) {
|
||||
if (optsIdx > optionArrayMaxSize) {
|
||||
return cfdp::METADATA_CANT_PARSE_OPTIONS;
|
||||
}
|
||||
result = optionsArray[optsIdx]->deSerialize(&buf, &remSize, endianness);
|
||||
result = optionArray[optsIdx].deSerialize(&buf, &remSize, endianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
optsIdx++;
|
||||
}
|
||||
info.setOptionsLen(optsIdx);
|
||||
parsedOptions = optsIdx;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t MetadataPduReader::getNumberOfParsedOptions() const { return parsedOptions; }
|
||||
|
||||
const cfdp::StringLv& MetadataPduReader::getSourceFileName() const { return srcFileName; }
|
||||
|
||||
const cfdp::StringLv& MetadataPduReader::getDestFileName() const { return destFileName; }
|
||||
|
||||
const MetadataGenericInfo& MetadataPduReader::getGenericInfo() const { return info; }
|
||||
|
@ -2,16 +2,28 @@
|
||||
#define FSFW_CFDP_PDU_METADATAPDUREADER_H_
|
||||
|
||||
#include "fsfw/cfdp/pdu/FileDirectiveReader.h"
|
||||
#include "fsfw/cfdp/pdu/MetadataInfo.h"
|
||||
#include "fsfw/cfdp/pdu/MetadataGenericInfo.h"
|
||||
|
||||
class MetadataPduReader : public FileDirectiveReader {
|
||||
public:
|
||||
MetadataPduReader(const uint8_t* pduBuf, size_t maxSize, MetadataInfo& info);
|
||||
MetadataPduReader(const uint8_t* pduBuf, size_t maxSize, MetadataGenericInfo& info,
|
||||
cfdp::Tlv* optionsArray, size_t optArrayMaxSize);
|
||||
|
||||
ReturnValue_t parseData() override;
|
||||
|
||||
[[nodiscard]] const MetadataGenericInfo& getGenericInfo() const;
|
||||
[[nodiscard]] const cfdp::StringLv& getSourceFileName() const;
|
||||
[[nodiscard]] const cfdp::StringLv& getDestFileName() const;
|
||||
|
||||
[[nodiscard]] size_t getNumberOfParsedOptions() const;
|
||||
|
||||
private:
|
||||
MetadataInfo& info;
|
||||
cfdp::StringLv srcFileName;
|
||||
cfdp::StringLv destFileName;
|
||||
MetadataGenericInfo& info;
|
||||
cfdp::Tlv* optionArray;
|
||||
size_t optionArrayMaxSize;
|
||||
size_t parsedOptions = 0;
|
||||
};
|
||||
|
||||
#endif /* FSFW_CFDP_PDU_METADATAPDUREADER_H_ */
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "NakInfo.h"
|
||||
|
||||
NakInfo::NakInfo(cfdp::FileSize startOfScope, cfdp::FileSize endOfScope)
|
||||
NakInfo::NakInfo(cfdp::Fss startOfScope, cfdp::Fss endOfScope)
|
||||
: startOfScope(startOfScope), endOfScope(endOfScope) {}
|
||||
|
||||
size_t NakInfo::getSerializedSize(bool fssLarge) {
|
||||
@ -57,9 +57,9 @@ void NakInfo::setSegmentRequests(SegmentRequest* segmentRequests, size_t* segmen
|
||||
}
|
||||
}
|
||||
|
||||
cfdp::FileSize& NakInfo::getStartOfScope() { return startOfScope; }
|
||||
cfdp::Fss& NakInfo::getStartOfScope() { return startOfScope; }
|
||||
|
||||
cfdp::FileSize& NakInfo::getEndOfScope() { return endOfScope; }
|
||||
cfdp::Fss& NakInfo::getEndOfScope() { return endOfScope; }
|
||||
|
||||
size_t NakInfo::getSegmentRequestsLen() const { return segmentRequestsLen; }
|
||||
|
||||
|
@ -3,21 +3,21 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "fsfw/cfdp/FileSize.h"
|
||||
#include "fsfw/cfdp/Fss.h"
|
||||
|
||||
class NakInfo {
|
||||
public:
|
||||
using SegmentRequest = std::pair<cfdp::FileSize, cfdp::FileSize>;
|
||||
using SegmentRequest = std::pair<cfdp::Fss, cfdp::Fss>;
|
||||
|
||||
NakInfo(cfdp::FileSize startOfScope, cfdp::FileSize endOfScope);
|
||||
NakInfo(cfdp::Fss startOfScope, cfdp::Fss endOfScope);
|
||||
|
||||
void setSegmentRequests(SegmentRequest* segmentRequests, size_t* segmentRequestLen,
|
||||
size_t* maxSegmentRequestLen);
|
||||
|
||||
size_t getSerializedSize(bool fssLarge = false);
|
||||
|
||||
cfdp::FileSize& getStartOfScope();
|
||||
cfdp::FileSize& getEndOfScope();
|
||||
cfdp::Fss& getStartOfScope();
|
||||
cfdp::Fss& getEndOfScope();
|
||||
|
||||
bool hasSegmentRequests() const;
|
||||
bool canHoldSegmentRequests() const;
|
||||
@ -31,8 +31,8 @@ class NakInfo {
|
||||
void setSegmentRequestLen(size_t readLen);
|
||||
|
||||
private:
|
||||
cfdp::FileSize startOfScope;
|
||||
cfdp::FileSize endOfScope;
|
||||
cfdp::Fss startOfScope;
|
||||
cfdp::Fss endOfScope;
|
||||
SegmentRequest* segmentRequests = nullptr;
|
||||
size_t segmentRequestsLen = 0;
|
||||
size_t maxSegmentRequestsLen = 0;
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "NakInfo.h"
|
||||
#include "fsfw/cfdp/FileSize.h"
|
||||
#include "fsfw/cfdp/Fss.h"
|
||||
#include "fsfw/cfdp/definitions.h"
|
||||
#include "fsfw/cfdp/pdu/FileDirectiveCreator.h"
|
||||
|
||||
|
@ -105,7 +105,8 @@ class PduHeaderReader : public RedirectableDataPointerIF, public PduHeaderIF {
|
||||
* @return
|
||||
*/
|
||||
ReturnValue_t setData(uint8_t* dataPtr, size_t maxSize, void* args) override;
|
||||
void assignVarLenField(cfdp::VarLenField* field, cfdp::WidthInBytes width, void* sourcePtr) const;
|
||||
static void assignVarLenField(cfdp::VarLenField* field, cfdp::WidthInBytes width,
|
||||
void* sourcePtr);
|
||||
void* sourceIdRaw = nullptr;
|
||||
void* seqNumRaw = nullptr;
|
||||
void* destIdRaw = nullptr;
|
||||
|
@ -8,4 +8,5 @@ target_sources(
|
||||
StringLv.cpp
|
||||
FlowLabelTlv.cpp
|
||||
MessageToUserTlv.cpp
|
||||
FaultHandlerOverrideTlv.cpp)
|
||||
FaultHandlerOverrideTlv.cpp
|
||||
ReservedMessageCreator.cpp)
|
||||
|
@ -14,23 +14,6 @@ cfdp::Lv::Lv(const std::vector<uint8_t>& data) : value(data.data(), data.size(),
|
||||
|
||||
cfdp::Lv::Lv() : value(static_cast<uint8_t*>(nullptr), 0, true) {}
|
||||
|
||||
cfdp::Lv::Lv(const Lv& other)
|
||||
: value(other.value.getConstBuffer(), other.value.getSerializedSize() - 1, true) {
|
||||
if (other.value.getSerializedSize() - 1 > 0) {
|
||||
zeroLen = false;
|
||||
}
|
||||
}
|
||||
|
||||
cfdp::Lv& cfdp::Lv::operator=(const Lv& other) {
|
||||
size_t otherSize = 0;
|
||||
auto* otherVal = const_cast<uint8_t*>(other.getValue(&otherSize));
|
||||
if (otherVal == nullptr or otherSize == 0) {
|
||||
this->zeroLen = true;
|
||||
}
|
||||
this->value.setConstBuffer(otherVal, otherSize);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::Lv::serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
Endianness streamEndianness) const {
|
||||
if (maxSize < 1) {
|
||||
@ -49,10 +32,8 @@ ReturnValue_t cfdp::Lv::serialize(uint8_t** buffer, size_t* size, size_t maxSize
|
||||
}
|
||||
|
||||
size_t cfdp::Lv::getSerializedSize() const {
|
||||
if (zeroLen) {
|
||||
if (zeroLen or value.getConstBuffer() == nullptr) {
|
||||
return 1;
|
||||
} else if (value.getConstBuffer() == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return value.getSerializedSize();
|
||||
}
|
||||
@ -85,7 +66,34 @@ ReturnValue_t cfdp::Lv::deSerialize(const uint8_t** buffer, size_t* size,
|
||||
const uint8_t* cfdp::Lv::getValue(size_t* size) const {
|
||||
if (size != nullptr) {
|
||||
// Length without length field
|
||||
*size = value.getSerializedSize() - 1;
|
||||
*size = getSerializedSize() - 1;
|
||||
}
|
||||
return value.getConstBuffer();
|
||||
}
|
||||
cfdp::Lv::Lv(cfdp::Lv&& other) noexcept
|
||||
: value(other.value.getConstBuffer(), other.value.getSerializedSize() - 1, true) {
|
||||
if (other.value.getSerializedSize() - 1 > 0) {
|
||||
zeroLen = false;
|
||||
}
|
||||
// Leave other class in intact state.
|
||||
other.zeroLen = false;
|
||||
other.value = SerialBufferAdapter<uint8_t>();
|
||||
}
|
||||
|
||||
cfdp::Lv& cfdp::Lv::operator=(cfdp::Lv&& other) noexcept {
|
||||
size_t otherSize = 0;
|
||||
this->zeroLen = false;
|
||||
auto* otherVal = const_cast<uint8_t*>(other.getValue(&otherSize));
|
||||
if (otherVal == nullptr or otherSize == 0) {
|
||||
this->zeroLen = true;
|
||||
}
|
||||
this->value.setConstBuffer(otherVal, otherSize);
|
||||
// Leave other class in intact state.
|
||||
other.zeroLen = false;
|
||||
other.value = SerialBufferAdapter<uint8_t>();
|
||||
return *this;
|
||||
}
|
||||
|
||||
size_t cfdp::Lv::getValueLen() const { return getSerializedSize() - 1; }
|
||||
|
||||
bool cfdp::Lv::isEmpty() const { return zeroLen; }
|
||||
|
@ -18,8 +18,12 @@ class Lv : public SerializeIF {
|
||||
Lv(const uint8_t* value, size_t size);
|
||||
Lv();
|
||||
|
||||
Lv(const Lv&);
|
||||
Lv& operator=(const Lv&);
|
||||
// Semantically, this class is a zero-copy helper, so the copy ctor and copy assigment do not
|
||||
// really make sense here.
|
||||
Lv(const Lv&) = delete;
|
||||
Lv& operator=(const Lv&) = delete;
|
||||
Lv(Lv&&) noexcept;
|
||||
Lv& operator=(Lv&&) noexcept;
|
||||
|
||||
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
Endianness streamEndianness) const override;
|
||||
@ -36,6 +40,8 @@ class Lv : public SerializeIF {
|
||||
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
Endianness streamEndianness) override;
|
||||
|
||||
size_t getValueLen() const;
|
||||
|
||||
/**
|
||||
* Get value field and its size.
|
||||
* @param size Optionally retrieve size. Size will be the size of the actual value field
|
||||
@ -44,6 +50,8 @@ class Lv : public SerializeIF {
|
||||
*/
|
||||
const uint8_t* getValue(size_t* size) const;
|
||||
|
||||
bool isEmpty() const;
|
||||
|
||||
private:
|
||||
bool zeroLen = true;
|
||||
SerialBufferAdapter<uint8_t> value;
|
||||
|
@ -7,3 +7,22 @@ MessageToUserTlv::MessageToUserTlv() : Tlv() {}
|
||||
|
||||
MessageToUserTlv::MessageToUserTlv(const std::vector<uint8_t>& data)
|
||||
: Tlv(cfdp::TlvType::MSG_TO_USER, data.data(), data.size()) {}
|
||||
|
||||
MessageToUserTlv::MessageToUserTlv(const uint8_t* value, size_t size)
|
||||
: Tlv(cfdp::TlvType::MSG_TO_USER, value, size) {}
|
||||
|
||||
bool MessageToUserTlv::isReservedCfdpMessage(uint8_t& messageType, const uint8_t** msgDataStart,
|
||||
size_t& msgLen) const {
|
||||
if (cfdp::Tlv::getLengthField() < 5) {
|
||||
return false;
|
||||
}
|
||||
if (std::strncmp(reinterpret_cast<const char*>(getValue()), "cfdp", 4) == 0) {
|
||||
messageType = getValue()[4];
|
||||
if (msgDataStart != nullptr) {
|
||||
*msgDataStart = getValue() + 5;
|
||||
}
|
||||
msgLen = cfdp::Tlv::getSerializedSize() - 5;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -9,8 +9,12 @@ class MessageToUserTlv : public cfdp::Tlv {
|
||||
public:
|
||||
MessageToUserTlv();
|
||||
MessageToUserTlv(uint8_t* value, size_t size);
|
||||
MessageToUserTlv(const uint8_t* value, size_t size);
|
||||
explicit MessageToUserTlv(const std::vector<uint8_t>& data);
|
||||
|
||||
bool isReservedCfdpMessage(uint8_t& messageType, const uint8_t** msgDataStart,
|
||||
size_t& msgLen) const;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
39
src/fsfw/cfdp/tlv/ReservedMessageCreator.cpp
Normal file
39
src/fsfw/cfdp/tlv/ReservedMessageCreator.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
#include "ReservedMessageCreator.h"
|
||||
|
||||
cfdp::ReservedMessageCreator::ReservedMessageCreator(uint8_t messageType, uint8_t *msgData,
|
||||
size_t msgLen)
|
||||
: messageType(messageType), msgData(msgData), msgSize(msgLen) {}
|
||||
|
||||
ReturnValue_t cfdp::ReservedMessageCreator::serialize(
|
||||
uint8_t **buffer, size_t *size, size_t maxSize,
|
||||
SerializeIF::Endianness streamEndianness) const {
|
||||
if (*size + getSerializedSize() > maxSize) {
|
||||
return SerializeIF::BUFFER_TOO_SHORT;
|
||||
}
|
||||
**buffer = TlvType::MSG_TO_USER;
|
||||
*buffer += 1;
|
||||
*size += 1;
|
||||
**buffer = getSerializedSize() - 2;
|
||||
*size += 1;
|
||||
*buffer += 1;
|
||||
std::memcpy(*buffer, MSG_HEADER, 4);
|
||||
*buffer += 4;
|
||||
*size += 4;
|
||||
**buffer = messageType;
|
||||
*buffer += 1;
|
||||
*size += 1;
|
||||
std::memcpy(*buffer, msgData, msgSize);
|
||||
*buffer += msgSize;
|
||||
*size += msgSize;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
size_t cfdp::ReservedMessageCreator::getSerializedSize() const {
|
||||
// 2 bytes type and length, 4 bytes CFDP, 1 byte reserved message type, message data.
|
||||
return 2 + 5 + msgSize;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::ReservedMessageCreator::deSerialize(const uint8_t **buffer, size_t *size,
|
||||
SerializeIF::Endianness streamEndianness) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
24
src/fsfw/cfdp/tlv/ReservedMessageCreator.h
Normal file
24
src/fsfw/cfdp/tlv/ReservedMessageCreator.h
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "Tlv.h"
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
class ReservedMessageCreator : public SerializeIF {
|
||||
public:
|
||||
static constexpr char MSG_HEADER[] = "cfdp";
|
||||
|
||||
ReservedMessageCreator(uint8_t messageType, uint8_t *msgData, size_t msgLen);
|
||||
[[nodiscard]] ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
||||
Endianness streamEndianness) const override;
|
||||
[[nodiscard]] size_t getSerializedSize() const override;
|
||||
ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
|
||||
Endianness streamEndianness) override;
|
||||
|
||||
private:
|
||||
uint8_t messageType;
|
||||
uint8_t *msgData;
|
||||
size_t msgSize;
|
||||
};
|
||||
|
||||
} // namespace cfdp
|
@ -7,3 +7,12 @@ cfdp::StringLv::StringLv(const char* filename, size_t len)
|
||||
: Lv(reinterpret_cast<const uint8_t*>(filename), len) {}
|
||||
|
||||
cfdp::StringLv::StringLv() : Lv() {}
|
||||
|
||||
const char* cfdp::StringLv::getCString(size_t& fileSize) const {
|
||||
return reinterpret_cast<const char*>(getValue(&fileSize));
|
||||
}
|
||||
|
||||
std::string cfdp::StringLv::getString() const {
|
||||
size_t fileSize;
|
||||
return {getCString(fileSize), fileSize};
|
||||
}
|
||||
|
@ -13,6 +13,8 @@ class StringLv : public Lv {
|
||||
explicit StringLv(const std::string& fileName);
|
||||
explicit StringLv(const char* filename, size_t len);
|
||||
|
||||
const char* getCString(size_t& fileSize) const;
|
||||
std::string getString() const;
|
||||
// Delete the move constructor to avoid passing in a temporary
|
||||
StringLv(const std::string&&) = delete;
|
||||
};
|
||||
|
@ -54,6 +54,7 @@ ReturnValue_t cfdp::Tlv::deSerialize(const uint8_t **buffer, size_t *size,
|
||||
return STREAM_TOO_SHORT;
|
||||
}
|
||||
|
||||
rawData = *buffer;
|
||||
uint8_t rawType = **buffer;
|
||||
if (not checkType(rawType)) {
|
||||
return INVALID_TLV_TYPE;
|
||||
@ -102,3 +103,5 @@ void cfdp::Tlv::setValue(uint8_t *value, size_t len) {
|
||||
uint8_t cfdp::Tlv::getLengthField() const { return this->value.getSerializedSize() - 1; }
|
||||
|
||||
void cfdp::Tlv::setType(TlvType type) { this->type = type; }
|
||||
|
||||
const uint8_t *cfdp::Tlv::getRawData() const { return rawData; }
|
||||
|
@ -47,6 +47,7 @@ class Tlv : public TlvIF {
|
||||
void setValue(uint8_t *value, size_t len);
|
||||
|
||||
[[nodiscard]] const uint8_t *getValue() const;
|
||||
[[nodiscard]] const uint8_t *getRawData() const;
|
||||
void setType(TlvType type);
|
||||
[[nodiscard]] TlvType getType() const override;
|
||||
[[nodiscard]] uint8_t getLengthField() const override;
|
||||
@ -55,6 +56,7 @@ class Tlv : public TlvIF {
|
||||
bool checkType(uint8_t rawType);
|
||||
|
||||
bool zeroLen = true;
|
||||
const uint8_t *rawData = nullptr;
|
||||
TlvType type = TlvType::INVALID_TLV;
|
||||
SerialBufferAdapter<uint8_t> value;
|
||||
};
|
||||
|
@ -72,18 +72,17 @@ void ControllerBase::getMode(Mode_t* mode_, Submode_t* submode_) {
|
||||
*submode_ = this->submode;
|
||||
}
|
||||
|
||||
void ControllerBase::setToExternalControl() { healthHelper.setHealth(EXTERNAL_CONTROL); }
|
||||
|
||||
void ControllerBase::announceMode(bool recursive) { triggerEvent(MODE_INFO, mode, submode); }
|
||||
|
||||
void ControllerBase::modeChanged(Mode_t mode_, Submode_t submode_) {}
|
||||
|
||||
void ControllerBase::setToExternalControl() { healthHelper.setHealth(EXTERNAL_CONTROL); }
|
||||
|
||||
ReturnValue_t ControllerBase::performOperation(uint8_t opCode) {
|
||||
handleQueue();
|
||||
performControlOperation(opCode);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
void ControllerBase::modeChanged(Mode_t mode_, Submode_t submode_) {}
|
||||
|
||||
ReturnValue_t ControllerBase::setHealth(HealthState health) {
|
||||
switch (health) {
|
||||
case HEALTHY:
|
||||
|
@ -166,9 +166,9 @@ ReturnValue_t Sgp4Propagator::propagate(double* position, double* velocity, time
|
||||
timeval timeSinceEpoch = time - epoch;
|
||||
double minutesSinceEpoch = timeSinceEpoch.tv_sec / 60. + timeSinceEpoch.tv_usec / 60000000.;
|
||||
|
||||
double monthsSinceEpoch = minutesSinceEpoch / 60 / 24 / 30;
|
||||
double daysSinceEpoch = minutesSinceEpoch / 60 / 24;
|
||||
|
||||
if ((monthsSinceEpoch > 1) || (monthsSinceEpoch < -1)) {
|
||||
if ((daysSinceEpoch > 7) || (daysSinceEpoch < -7)) {
|
||||
return TLE_TOO_OLD;
|
||||
}
|
||||
|
||||
|
@ -7,4 +7,5 @@ target_sources(
|
||||
DeviceHandlerFailureIsolation.cpp
|
||||
DeviceHandlerMessage.cpp
|
||||
DeviceTmReportingWrapper.cpp
|
||||
FreshDeviceHandlerBase.cpp
|
||||
HealthDevice.cpp)
|
||||
|
@ -85,6 +85,7 @@ class DeviceHandlerIF {
|
||||
static const ReturnValue_t NO_REPLY_EXPECTED = MAKE_RETURN_CODE(0xA8);
|
||||
static const ReturnValue_t NON_OP_TEMPERATURE = MAKE_RETURN_CODE(0xA9);
|
||||
static const ReturnValue_t COMMAND_NOT_IMPLEMENTED = MAKE_RETURN_CODE(0xAA);
|
||||
static const ReturnValue_t NON_OP_STATE_OF_CHARGE = MAKE_RETURN_CODE(0xAB);
|
||||
|
||||
// Standard codes used in scanForReply
|
||||
static const ReturnValue_t CHECKSUM_ERROR = MAKE_RETURN_CODE(0xB0);
|
||||
|
201
src/fsfw/devicehandlers/FreshDeviceHandlerBase.cpp
Normal file
201
src/fsfw/devicehandlers/FreshDeviceHandlerBase.cpp
Normal file
@ -0,0 +1,201 @@
|
||||
#include "FreshDeviceHandlerBase.h"
|
||||
|
||||
#include "fsfw/devicehandlers/DeviceHandlerFailureIsolation.h"
|
||||
#include "fsfw/ipc/QueueFactory.h"
|
||||
#include "fsfw/subsystem/helper.h"
|
||||
|
||||
FreshDeviceHandlerBase::FreshDeviceHandlerBase(DhbConfig config)
|
||||
: SystemObject(config.objectId),
|
||||
actionHelper(this, nullptr),
|
||||
modeHelper(this),
|
||||
healthHelper(this, getObjectId()),
|
||||
paramHelper(this),
|
||||
poolManager(this, nullptr),
|
||||
defaultFdirParent(config.defaultFdirParent) {
|
||||
auto mqArgs = MqArgs(config.objectId, static_cast<void*>(this));
|
||||
messageQueue = QueueFactory::instance()->createMessageQueue(
|
||||
config.msgQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
}
|
||||
FreshDeviceHandlerBase::~FreshDeviceHandlerBase() {
|
||||
QueueFactory::instance()->deleteMessageQueue(messageQueue);
|
||||
if (not hasCustomFdir) {
|
||||
delete fdirInstance;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] object_id_t FreshDeviceHandlerBase::getObjectId() const {
|
||||
return SystemObject::getObjectId();
|
||||
}
|
||||
|
||||
ReturnValue_t FreshDeviceHandlerBase::performOperation(uint8_t opCode) {
|
||||
performDeviceOperationPreQueueHandling(opCode);
|
||||
handleQueue();
|
||||
performDeviceOperation(opCode);
|
||||
poolManager.performHkOperation();
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t FreshDeviceHandlerBase::performDeviceOperationPreQueueHandling(uint8_t opCode) {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
void FreshDeviceHandlerBase::startTransition(Mode_t mode_, Submode_t submode_) {
|
||||
triggerEvent(CHANGING_MODE, mode_, submode_);
|
||||
// Complete mode transition immediately by default.
|
||||
setMode(mode_, submode_);
|
||||
}
|
||||
|
||||
void FreshDeviceHandlerBase::setMode(Mode_t newMode, Submode_t newSubmode) {
|
||||
mode = newMode;
|
||||
submode = newSubmode;
|
||||
modeHelper.modeChanged(mode, submode);
|
||||
modeChanged(mode, submode);
|
||||
announceMode(false);
|
||||
}
|
||||
|
||||
void FreshDeviceHandlerBase::setMode(Mode_t newMode) { setMode(newMode, submode); }
|
||||
|
||||
void FreshDeviceHandlerBase::getMode(Mode_t* mode_, Submode_t* submode_) {
|
||||
*mode_ = this->mode;
|
||||
*submode_ = this->submode;
|
||||
}
|
||||
|
||||
void FreshDeviceHandlerBase::announceMode(bool recursive) {
|
||||
triggerEvent(MODE_INFO, mode, submode);
|
||||
}
|
||||
|
||||
void FreshDeviceHandlerBase::modeChanged(Mode_t mode_, Submode_t submode_) {}
|
||||
|
||||
[[nodiscard]] MessageQueueId_t FreshDeviceHandlerBase::getCommandQueue() const {
|
||||
return messageQueue->getId();
|
||||
}
|
||||
|
||||
ReturnValue_t FreshDeviceHandlerBase::handleQueue() {
|
||||
CommandMessage command;
|
||||
ReturnValue_t result;
|
||||
for (result = messageQueue->receiveMessage(&command); result == returnvalue::OK;
|
||||
result = messageQueue->receiveMessage(&command)) {
|
||||
result = actionHelper.handleActionMessage(&command);
|
||||
if (result == returnvalue::OK) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result = modeHelper.handleModeCommand(&command);
|
||||
if (result == returnvalue::OK) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result = healthHelper.handleHealthCommand(&command);
|
||||
if (result == returnvalue::OK) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result = paramHelper.handleParameterMessage(&command);
|
||||
if (result == returnvalue::OK) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result = poolManager.handleHousekeepingMessage(&command);
|
||||
if (result == returnvalue::OK) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result = handleCommandMessage(&command);
|
||||
if (result == returnvalue::OK) {
|
||||
continue;
|
||||
}
|
||||
command.setToUnknownCommand();
|
||||
messageQueue->reply(&command);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
HasHealthIF::HealthState FreshDeviceHandlerBase::getHealth() { return healthHelper.getHealth(); }
|
||||
|
||||
const HasHealthIF* FreshDeviceHandlerBase::getOptHealthIF() const { return this; }
|
||||
|
||||
const HasModesIF& FreshDeviceHandlerBase::getModeIF() const { return *this; }
|
||||
|
||||
ModeTreeChildIF& FreshDeviceHandlerBase::getModeTreeChildIF() { return *this; }
|
||||
|
||||
ReturnValue_t FreshDeviceHandlerBase::connectModeTreeParent(HasModeTreeChildrenIF& parent) {
|
||||
return modetree::connectModeTreeParent(parent, *this, &healthHelper, modeHelper);
|
||||
}
|
||||
|
||||
// Executable Overrides.
|
||||
void FreshDeviceHandlerBase::setTaskIF(PeriodicTaskIF* task_) { executingTask = task_; }
|
||||
|
||||
// Pool Manager overrides.
|
||||
LocalDataPoolManager* FreshDeviceHandlerBase::getHkManagerHandle() { return &poolManager; }
|
||||
|
||||
[[nodiscard]] uint32_t FreshDeviceHandlerBase::getPeriodicOperationFrequency() const {
|
||||
return this->executingTask->getPeriodMs();
|
||||
}
|
||||
|
||||
ReturnValue_t FreshDeviceHandlerBase::initializeAfterTaskCreation() {
|
||||
return poolManager.initializeAfterTaskCreation();
|
||||
}
|
||||
|
||||
ReturnValue_t FreshDeviceHandlerBase::setHealth(HasHealthIF::HealthState health) {
|
||||
// Assembly should handle commanding to OFF.
|
||||
healthHelper.setHealth(health);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
void FreshDeviceHandlerBase::triggerEvent(Event event, uint32_t parameter1, uint32_t parameter2) {
|
||||
fdirInstance->triggerEvent(event, parameter1, parameter2);
|
||||
}
|
||||
|
||||
void FreshDeviceHandlerBase::forwardEvent(Event event, uint32_t parameter1,
|
||||
uint32_t parameter2) const {
|
||||
fdirInstance->triggerEvent(event, parameter1, parameter2);
|
||||
}
|
||||
|
||||
void FreshDeviceHandlerBase::setToExternalControl() { setHealth(HealthState::EXTERNAL_CONTROL); }
|
||||
|
||||
// System Object overrides.
|
||||
ReturnValue_t FreshDeviceHandlerBase::initialize() {
|
||||
ReturnValue_t result = modeHelper.initialize();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
result = healthHelper.initialize();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
result = actionHelper.initialize(messageQueue);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
result = paramHelper.initialize();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = poolManager.initialize(messageQueue);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
if (fdirInstance == nullptr) {
|
||||
hasCustomFdir = false;
|
||||
fdirInstance = new DeviceHandlerFailureIsolation(getObjectId(), defaultFdirParent);
|
||||
}
|
||||
|
||||
result = fdirInstance->initialize();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
return SystemObject::initialize();
|
||||
}
|
||||
|
||||
ReturnValue_t FreshDeviceHandlerBase::getParameter(uint8_t domainId, uint8_t uniqueId,
|
||||
ParameterWrapper* parameterWrapper,
|
||||
const ParameterWrapper* newValues,
|
||||
uint16_t startAtIndex) {
|
||||
ReturnValue_t result =
|
||||
fdirInstance->getParameter(domainId, uniqueId, parameterWrapper, newValues, startAtIndex);
|
||||
if (result != INVALID_DOMAIN_ID) {
|
||||
return result;
|
||||
}
|
||||
return INVALID_DOMAIN_ID;
|
||||
}
|
167
src/fsfw/devicehandlers/FreshDeviceHandlerBase.h
Normal file
167
src/fsfw/devicehandlers/FreshDeviceHandlerBase.h
Normal file
@ -0,0 +1,167 @@
|
||||
#pragma once
|
||||
|
||||
#include "fsfw/action.h"
|
||||
#include "fsfw/datapoollocal/HasLocalDataPoolIF.h"
|
||||
#include "fsfw/datapoollocal/LocalDataPoolManager.h"
|
||||
#include "fsfw/devicehandlers/DeviceHandlerIF.h"
|
||||
#include "fsfw/fdir/FailureIsolationBase.h"
|
||||
#include "fsfw/health/HasHealthIF.h"
|
||||
#include "fsfw/health/HealthHelper.h"
|
||||
#include "fsfw/modes/HasModesIF.h"
|
||||
#include "fsfw/objectmanager.h"
|
||||
#include "fsfw/parameters/ParameterHelper.h"
|
||||
#include "fsfw/parameters/ReceivesParameterMessagesIF.h"
|
||||
#include "fsfw/retval.h"
|
||||
#include "fsfw/subsystem/ModeTreeChildIF.h"
|
||||
#include "fsfw/subsystem/ModeTreeConnectionIF.h"
|
||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||
#include "fsfw/tasks/PeriodicTaskIF.h"
|
||||
|
||||
struct DhbConfig {
|
||||
explicit DhbConfig(object_id_t objectId) : objectId(objectId) {}
|
||||
object_id_t objectId;
|
||||
FailureIsolationBase* fdirInstance = nullptr;
|
||||
object_id_t defaultFdirParent = objects::NO_OBJECT;
|
||||
uint32_t msgQueueDepth = 10;
|
||||
};
|
||||
|
||||
class FreshDeviceHandlerBase : public SystemObject,
|
||||
public DeviceHandlerIF,
|
||||
public HasModesIF,
|
||||
public HasHealthIF,
|
||||
public ExecutableObjectIF,
|
||||
public ModeTreeChildIF,
|
||||
public ModeTreeConnectionIF,
|
||||
public HasActionsIF,
|
||||
public ReceivesParameterMessagesIF,
|
||||
public HasLocalDataPoolIF {
|
||||
public:
|
||||
explicit FreshDeviceHandlerBase(DhbConfig config);
|
||||
~FreshDeviceHandlerBase() override;
|
||||
|
||||
/**
|
||||
* Periodic helper executed function, implemented by child class.
|
||||
*/
|
||||
virtual void performDeviceOperation(uint8_t opCode) = 0;
|
||||
|
||||
[[nodiscard]] object_id_t getObjectId() const override;
|
||||
|
||||
[[nodiscard]] MessageQueueId_t getCommandQueue() const override;
|
||||
|
||||
HasHealthIF::HealthState getHealth() override;
|
||||
|
||||
// Mode Tree Overrides.
|
||||
[[nodiscard]] const HasHealthIF* getOptHealthIF() const override;
|
||||
[[nodiscard]] const HasModesIF& getModeIF() const override;
|
||||
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF& parent) override;
|
||||
ModeTreeChildIF& getModeTreeChildIF() override;
|
||||
|
||||
[[nodiscard]] uint32_t getPeriodicOperationFrequency() const override;
|
||||
|
||||
protected:
|
||||
// Pool Manager overrides.
|
||||
LocalDataPoolManager* getHkManagerHandle() override;
|
||||
ActionHelper actionHelper;
|
||||
ModeHelper modeHelper;
|
||||
HealthHelper healthHelper;
|
||||
ParameterHelper paramHelper;
|
||||
LocalDataPoolManager poolManager;
|
||||
|
||||
bool hasCustomFdir = false;
|
||||
FailureIsolationBase* fdirInstance;
|
||||
object_id_t defaultFdirParent;
|
||||
|
||||
/**
|
||||
* Pointer to the task which executes this component,
|
||||
* is invalid before setTaskIF was called.
|
||||
*/
|
||||
PeriodicTaskIF* executingTask = nullptr;
|
||||
|
||||
Mode_t mode = HasModesIF::MODE_UNDEFINED;
|
||||
Submode_t submode = 0;
|
||||
|
||||
MessageQueueIF* messageQueue;
|
||||
|
||||
/**
|
||||
* The default queue handler will process all messages for the interfaces implemented
|
||||
* by this class. If there are special requirements, for example that action commands are
|
||||
* received on a different queue, the user can override this function for those special
|
||||
* requirements.
|
||||
*/
|
||||
virtual ReturnValue_t handleQueue();
|
||||
|
||||
// Mode Helpers.
|
||||
virtual void modeChanged(Mode_t mode, Submode_t submode);
|
||||
/**
|
||||
* The default implementation sets the new mode immediately. If this is not applicable for
|
||||
* certain modes, the user should provide a custom implementation, which performs rougly
|
||||
* the same functionality of this function, when all the steps have been taken to reach the
|
||||
* new mode.
|
||||
*/
|
||||
void startTransition(Mode_t mode, Submode_t submode) override;
|
||||
virtual void setMode(Mode_t newMode, Submode_t newSubmode);
|
||||
virtual void setMode(Mode_t newMode);
|
||||
void getMode(Mode_t* mode, Submode_t* submode) override;
|
||||
void setToExternalControl() override;
|
||||
void announceMode(bool recursive) override;
|
||||
// System Object overrides.
|
||||
ReturnValue_t initialize() override;
|
||||
|
||||
/**
|
||||
* Implemented by child class. Handle all command messages which are
|
||||
* not health, mode, action or housekeeping messages.
|
||||
* @param message
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t handleCommandMessage(CommandMessage* message) = 0;
|
||||
|
||||
// HK manager abstract functions.
|
||||
LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override = 0;
|
||||
ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
||||
LocalDataPoolManager& poolManager) override = 0;
|
||||
|
||||
// Mode abstract functions
|
||||
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
uint32_t* msToReachTheMode) override = 0;
|
||||
// Health Overrides.
|
||||
ReturnValue_t setHealth(HealthState health) override;
|
||||
// Action override. Forward to user.
|
||||
ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
|
||||
const uint8_t* data, size_t size) override = 0;
|
||||
// Executable overrides.
|
||||
ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
ReturnValue_t initializeAfterTaskCreation() override;
|
||||
|
||||
/**
|
||||
* This calls the FDIR instance event trigger function.
|
||||
* @param event
|
||||
* @param parameter1
|
||||
* @param parameter2
|
||||
*/
|
||||
void triggerEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0) override;
|
||||
/**
|
||||
* This calls the FDIR instance event forward function.
|
||||
* @param event
|
||||
* @param parameter1
|
||||
* @param parameter2
|
||||
*/
|
||||
void forwardEvent(Event event, uint32_t parameter1, uint32_t parameter2) const override;
|
||||
/**
|
||||
* This implementation handles the FDIR parameters. The user can override this to handle
|
||||
* custom parameters.
|
||||
* @param domainId
|
||||
* @param uniqueId
|
||||
* @param parameterWrapper
|
||||
* @param newValues
|
||||
* @param startAtIndex
|
||||
* @return
|
||||
*/
|
||||
ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId, ParameterWrapper* parameterWrapper,
|
||||
const ParameterWrapper* newValues, uint16_t startAtIndex) override;
|
||||
|
||||
virtual ReturnValue_t performDeviceOperationPreQueueHandling(uint8_t opCode);
|
||||
|
||||
private:
|
||||
// Executable Overrides.
|
||||
void setTaskIF(PeriodicTaskIF* task) override;
|
||||
};
|
@ -17,7 +17,7 @@ struct FilesystemParams {
|
||||
};
|
||||
|
||||
struct FileOpParams {
|
||||
FileOpParams(const char* path, size_t size) : fsParams(path), size(size) {}
|
||||
FileOpParams(const char* path, size_t opSize) : fsParams(path), size(opSize) {}
|
||||
|
||||
[[nodiscard]] const char* path() const { return fsParams.path; }
|
||||
|
||||
@ -80,6 +80,8 @@ class HasFileSystemIF {
|
||||
|
||||
virtual bool isDirectory(const char* path) = 0;
|
||||
|
||||
virtual bool getFileSize(FilesystemParams params, uint64_t& fileSize) = 0;
|
||||
|
||||
virtual bool fileExists(FilesystemParams params) = 0;
|
||||
|
||||
/**
|
||||
|
@ -39,6 +39,39 @@ void QuaternionOperations::inverse(const double* quaternion, double* inverseQuat
|
||||
VectorOperations<double>::mulScalar(inverseQuaternion, -1, inverseQuaternion, 3);
|
||||
}
|
||||
|
||||
void QuaternionOperations::slerp(const double q1[4], const double q2[4], const double weight,
|
||||
double q[4]) {
|
||||
double q1s[4] = {0, 0, 0, 0}, q2I[4] = {0, 0, 0, 0}, qD[4] = {0, 0, 0, 0}, left[4] = {0, 0, 0, 0},
|
||||
right[4] = {0, 0, 0, 0}, angle = 0;
|
||||
|
||||
// we need to be able to invert this quaternion
|
||||
std::memcpy(q1s, q1, 4 * sizeof(double));
|
||||
// calculate angle between orientations
|
||||
inverse(q2, q2I);
|
||||
multiply(q1s, q2I, qD);
|
||||
angle = std::acos(qD[3]);
|
||||
|
||||
if (std::cos(angle) < 0.0) {
|
||||
// we need to invert one quaternion
|
||||
VectorOperations<double>::mulScalar(q1s, -1, q1s, 4);
|
||||
multiply(q1s, q2I, qD);
|
||||
angle = std::acos(qD[3]);
|
||||
}
|
||||
|
||||
if (std::sin(angle) == 0.0) {
|
||||
// nothing to calculate here
|
||||
std::memcpy(q, q1s, 4 * sizeof(double));
|
||||
return;
|
||||
}
|
||||
|
||||
VectorOperations<double>::mulScalar(q1s, std::sin((1 - weight) * angle) / std::sin(angle), left,
|
||||
4);
|
||||
VectorOperations<double>::mulScalar(q2, std::sin(weight * angle) / std::sin(angle), right, 4);
|
||||
VectorOperations<double>::add(left, right, q, 4);
|
||||
|
||||
normalize(q);
|
||||
}
|
||||
|
||||
QuaternionOperations::QuaternionOperations() {}
|
||||
|
||||
void QuaternionOperations::normalize(const double* quaternion, double* unitQuaternion) {
|
||||
|
@ -23,6 +23,8 @@ class QuaternionOperations {
|
||||
|
||||
static void inverse(const double *quaternion, double *inverseQuaternion);
|
||||
|
||||
static void slerp(const double q1[4], const double q2[4], const double weight, double q[4]);
|
||||
|
||||
/**
|
||||
* returns angle in ]-Pi;Pi] or [0;Pi] if abs == true
|
||||
*/
|
||||
|
@ -118,8 +118,8 @@ void ObjectManager::initialize() {
|
||||
<< result << std::dec << std::setfill(' ') << std::endl;
|
||||
#else
|
||||
sif::printError(
|
||||
"ObjectManager::initialize: Object 0x%08x failed to initialize with code 0x%04x\n", var,
|
||||
result);
|
||||
"ObjectManager::initialize: Object 0x%08x failed to initialize with code 0x%04x\n",
|
||||
it.first, result);
|
||||
#endif
|
||||
errorCount++;
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ TcpTmTcBridge::TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
|
||||
: TmTcBridge("TCP TMTC Bridge", objectId, tcDestination, msgQueueDepth, tmStoreId, tcStoreId) {
|
||||
mutex = MutexFactory::instance()->createMutex();
|
||||
// Connection is always up, TM is requested by connecting to server and receiving packets
|
||||
registerCommConnect();
|
||||
TmTcBridge::registerCommConnect();
|
||||
}
|
||||
|
||||
ReturnValue_t TcpTmTcBridge::initialize() {
|
||||
|
@ -123,6 +123,7 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
|
||||
StorageManagerIF* tmStore = nullptr;
|
||||
|
||||
private:
|
||||
//! [EXPORT] : [SKIP]
|
||||
static constexpr ReturnValue_t CONN_BROKEN = returnvalue::makeCode(1, 0);
|
||||
//! TMTC bridge is cached.
|
||||
object_id_t tmtcBridgeId = objects::NO_OBJECT;
|
||||
|
@ -38,6 +38,8 @@ class PowerSwitcherComponent : public SystemObject,
|
||||
|
||||
protected:
|
||||
PowerSwitcher switcher;
|
||||
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
uint32_t *msToReachTheMode) override;
|
||||
|
||||
private:
|
||||
MessageQueueIF *queue = nullptr;
|
||||
@ -56,8 +58,6 @@ class PowerSwitcherComponent : public SystemObject,
|
||||
|
||||
[[nodiscard]] MessageQueueId_t getCommandQueue() const override;
|
||||
void getMode(Mode_t *mode, Submode_t *submode) override;
|
||||
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
uint32_t *msToReachTheMode) override;
|
||||
void startTransition(Mode_t mode, Submode_t submode) override;
|
||||
virtual void performFaultyOperation();
|
||||
void setToExternalControl() override;
|
||||
|
@ -43,6 +43,7 @@ class Service11TelecommandScheduling final : public PusServiceBase {
|
||||
static constexpr ReturnValue_t INVALID_RELATIVE_TIME = returnvalue::makeCode(CLASS_ID, 4);
|
||||
static constexpr ReturnValue_t CONTAINED_TC_TOO_SMALL = returnvalue::makeCode(CLASS_ID, 5);
|
||||
static constexpr ReturnValue_t CONTAINED_TC_CRC_MISSMATCH = returnvalue::makeCode(CLASS_ID, 6);
|
||||
static constexpr ReturnValue_t MAP_IS_FULL = returnvalue::makeCode(CLASS_ID, 7);
|
||||
|
||||
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_11;
|
||||
|
||||
|
@ -150,6 +150,9 @@ inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::handleResetCom
|
||||
template <size_t MAX_NUM_TCS>
|
||||
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::doInsertActivity(
|
||||
const uint8_t *data, size_t size) {
|
||||
if(telecommandMap.full()) {
|
||||
return MAP_IS_FULL;
|
||||
}
|
||||
uint32_t timestamp = 0;
|
||||
ReturnValue_t result = SerializeAdapter::deSerialize(×tamp, &data, &size, DEF_END);
|
||||
if (result != returnvalue::OK) {
|
||||
|
@ -61,7 +61,8 @@ enum : uint8_t {
|
||||
HAS_ACTIONS_IF, // HF
|
||||
DEVICE_COMMUNICATION_IF, // DC
|
||||
BSP, // BSP
|
||||
CFDP, // CFDP
|
||||
CFDP_BASE, // CFDP
|
||||
CFDP_HANDLER, // CFDP
|
||||
TIME_STAMPER_IF, // TSI
|
||||
SGP4PROPAGATOR_CLASS, // SGP4
|
||||
MUTEX_IF, // MUX
|
||||
|
@ -107,14 +107,6 @@ uint8_t* SerialBufferAdapter<count_t>::getBuffer() {
|
||||
|
||||
template <typename count_t>
|
||||
const uint8_t* SerialBufferAdapter<count_t>::getConstBuffer() const {
|
||||
if (constBuffer == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "SerialBufferAdapter::getConstBuffer:"
|
||||
" Buffers are unitialized!"
|
||||
<< std::endl;
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
return constBuffer;
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,17 @@ class SerialBufferAdapter : public SerializeIF {
|
||||
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
Endianness streamEndianness) override;
|
||||
|
||||
/**
|
||||
* Please note that this function can also return a nullpointer in case the length field contains
|
||||
* 0.
|
||||
* @return
|
||||
*/
|
||||
uint8_t* getBuffer();
|
||||
/**
|
||||
* Please note that this function can also return a nullpointer in case the length field contains
|
||||
* 0.
|
||||
* @return
|
||||
*/
|
||||
[[nodiscard]] const uint8_t* getConstBuffer() const;
|
||||
void setConstBuffer(const uint8_t* buf, count_t bufLen);
|
||||
|
||||
|
@ -89,7 +89,7 @@ ReturnValue_t LocalPool::deleteData(store_address_t storeId) {
|
||||
ReturnValue_t status = returnvalue::OK;
|
||||
size_type pageSize = getSubpoolElementSize(storeId.poolIndex);
|
||||
if ((pageSize != 0) and (storeId.packetIndex < numberOfElements[storeId.poolIndex])) {
|
||||
uint16_t packetPosition = getRawPosition(storeId);
|
||||
size_type packetPosition = getRawPosition(storeId);
|
||||
uint8_t* ptr = &store[storeId.poolIndex][packetPosition];
|
||||
std::memset(ptr, 0, pageSize);
|
||||
// Set free list
|
||||
|
@ -23,18 +23,8 @@ TmTcBridge::TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDes
|
||||
|
||||
TmTcBridge::~TmTcBridge() { QueueFactory::instance()->deleteMessageQueue(tmTcReceptionQueue); }
|
||||
|
||||
ReturnValue_t TmTcBridge::setNumberOfSentPacketsPerCycle(uint8_t sentPacketsPerCycle) {
|
||||
if (sentPacketsPerCycle <= LIMIT_STORED_DATA_SENT_PER_CYCLE) {
|
||||
this->sentPacketsPerCycle = sentPacketsPerCycle;
|
||||
return returnvalue::OK;
|
||||
} else {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "TmTcBridge::setNumberOfSentPacketsPerCycle: Number of "
|
||||
<< "packets sent per cycle exceeds limits. "
|
||||
<< "Keeping default value." << std::endl;
|
||||
#endif
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
void TmTcBridge::setNumberOfSentPacketsPerCycle(uint32_t sentPacketsPerCycle_) {
|
||||
this->sentPacketsPerCycle = sentPacketsPerCycle_;
|
||||
}
|
||||
|
||||
ReturnValue_t TmTcBridge::setMaxNumberOfPacketsStored(unsigned int maxNumberOfPacketsStored) {
|
||||
@ -144,7 +134,7 @@ ReturnValue_t TmTcBridge::handleTmQueue() {
|
||||
#endif
|
||||
#endif /* FSFW_VERBOSE_LEVEL >= 3 */
|
||||
|
||||
if (communicationLinkUp == false or packetSentCounter >= sentPacketsPerCycle) {
|
||||
if (!communicationLinkUp or packetSentCounter >= sentPacketsPerCycle) {
|
||||
result = storeDownlinkData(&message);
|
||||
if (result != returnvalue::OK) {
|
||||
tmStore->deleteData(message.getStorageId());
|
||||
|
@ -15,10 +15,9 @@ class TmTcBridge : public AcceptsTelemetryIF,
|
||||
public ExecutableObjectIF,
|
||||
public SystemObject {
|
||||
public:
|
||||
static constexpr uint8_t LIMIT_STORED_DATA_SENT_PER_CYCLE = 15;
|
||||
static constexpr unsigned int LIMIT_DOWNLINK_PACKETS_STORED = 500;
|
||||
|
||||
static constexpr uint8_t DEFAULT_STORED_DATA_SENT_PER_CYCLE = 5;
|
||||
static constexpr uint8_t DEFAULT_STORED_DATA_SENT_PER_CYCLE = 20;
|
||||
static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10;
|
||||
|
||||
TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDestination,
|
||||
@ -32,7 +31,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
|
||||
* @return -@c returnvalue::OK if value was set successfully
|
||||
* -@c returnvalue::FAILED otherwise, stored value stays the same
|
||||
*/
|
||||
ReturnValue_t setNumberOfSentPacketsPerCycle(uint8_t sentPacketsPerCycle);
|
||||
void setNumberOfSentPacketsPerCycle(uint32_t sentPacketsPerCycle);
|
||||
|
||||
/**
|
||||
* Set number of packets sent per performOperation().Please note that this
|
||||
@ -151,7 +150,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
|
||||
* This FIFO can be used to store downlink data which can not be sent at the moment.
|
||||
*/
|
||||
DynamicFIFO<store_address_t>* tmFifo = nullptr;
|
||||
uint8_t sentPacketsPerCycle = DEFAULT_STORED_DATA_SENT_PER_CYCLE;
|
||||
uint32_t sentPacketsPerCycle = DEFAULT_STORED_DATA_SENT_PER_CYCLE;
|
||||
unsigned int maxNumberOfPacketsStored = DEFAULT_DOWNLINK_PACKETS_STORED;
|
||||
};
|
||||
|
||||
|
1
src/fsfw/util/CMakeLists.txt
Normal file
1
src/fsfw/util/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE)
|
19
src/fsfw/util/ProvidesSeqCountIF.h
Normal file
19
src/fsfw/util/ProvidesSeqCountIF.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
class ProvidesSeqCountIF {
|
||||
public:
|
||||
virtual ~ProvidesSeqCountIF() = default;
|
||||
|
||||
[[nodiscard]] virtual unsigned int bitWidth() const = 0;
|
||||
|
||||
virtual uint64_t get() = 0;
|
||||
virtual void increment() = 0;
|
||||
|
||||
virtual uint64_t getAndIncrement() {
|
||||
uint64_t val = get();
|
||||
increment();
|
||||
return val;
|
||||
}
|
||||
};
|
25
src/fsfw/util/SeqCountProvider.h
Normal file
25
src/fsfw/util/SeqCountProvider.h
Normal file
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "ProvidesSeqCountIF.h"
|
||||
|
||||
template <typename T>
|
||||
class SeqCountProvider : public ProvidesSeqCountIF {
|
||||
static_assert(std::is_same<T, uint8_t>::value || std::is_same<T, uint16_t>::value ||
|
||||
std::is_same<T, uint32_t>::value,
|
||||
"Only uint8_t, uint16_t, and uint32_t are allowed.");
|
||||
|
||||
public:
|
||||
[[nodiscard]] unsigned int bitWidth() const override { return sizeof(T) * 8; }
|
||||
uint64_t get() override { return counter; }
|
||||
// I'm also abusing the primitive C variable overflow wrap around here.
|
||||
void increment() override { counter++; }
|
||||
|
||||
private:
|
||||
T counter{};
|
||||
};
|
||||
|
||||
using SeqCountProviderU8 = SeqCountProvider<uint8_t>;
|
||||
using SeqCountProviderU16 = SeqCountProvider<uint16_t>;
|
||||
using SeqCountProviderU32 = SeqCountProvider<uint32_t>;
|
@ -184,3 +184,11 @@ ReturnValue_t HostFilesystem::getBaseFilename(FilesystemParams params, char *nam
|
||||
baseNameLen = baseName.size();
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
bool HostFilesystem::getFileSize(FilesystemParams params, uint64_t &fileSize) {
|
||||
if (!fileExists(params)) {
|
||||
return false;
|
||||
}
|
||||
fileSize = std::filesystem::file_size(params.path);
|
||||
return true;
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ class HostFilesystem : public HasFileSystemIF {
|
||||
|
||||
ReturnValue_t getBaseFilename(FilesystemParams params, char *nameBuf, size_t maxLen,
|
||||
size_t &baseNameLen) override;
|
||||
virtual bool getFileSize(FilesystemParams params, uint64_t &fileSize) override;
|
||||
bool isDirectory(const char *path) override;
|
||||
bool fileExists(FilesystemParams params) override;
|
||||
ReturnValue_t truncateFile(FilesystemParams params) override;
|
||||
|
@ -282,7 +282,7 @@ ReturnValue_t SpiComIF::handlePollingSendOperation(uint8_t *recvPtr, SPI_HandleT
|
||||
#endif
|
||||
#endif
|
||||
spiCookie.setTransferState(spi::TransferStates::FAILURE);
|
||||
return spi::HAL_TIMEOUT_RETVAL;
|
||||
return spi::TIMEOUT;
|
||||
}
|
||||
case (HAL_ERROR):
|
||||
default: {
|
||||
@ -296,7 +296,7 @@ ReturnValue_t SpiComIF::handlePollingSendOperation(uint8_t *recvPtr, SPI_HandleT
|
||||
#endif
|
||||
#endif
|
||||
spiCookie.setTransferState(spi::TransferStates::FAILURE);
|
||||
return spi::HAL_ERROR_RETVAL;
|
||||
return spi::GENERIC_ERROR;
|
||||
}
|
||||
}
|
||||
return returnvalue::OK;
|
||||
|
@ -9,11 +9,6 @@
|
||||
|
||||
namespace spi {
|
||||
|
||||
static constexpr uint8_t HAL_SPI_ID = CLASS_ID::HAL_SPI;
|
||||
static constexpr ReturnValue_t HAL_TIMEOUT_RETVAL = returnvalue::makeCode(HAL_SPI_ID, 0);
|
||||
static constexpr ReturnValue_t HAL_BUSY_RETVAL = returnvalue::makeCode(HAL_SPI_ID, 1);
|
||||
static constexpr ReturnValue_t HAL_ERROR_RETVAL = returnvalue::makeCode(HAL_SPI_ID, 2);
|
||||
|
||||
enum class TransferStates { IDLE, WAIT, SUCCESS, FAILURE };
|
||||
|
||||
enum SpiBus { SPI_1, SPI_2 };
|
||||
|
@ -32,7 +32,7 @@ void Factory::produceFrameworkObjects(void* args) {
|
||||
setStaticFrameworkObjectIds();
|
||||
new EventManager(objects::EVENT_MANAGER, 80);
|
||||
new HealthTable(objects::HEALTH_TABLE);
|
||||
new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER, 20, false, 1.0);
|
||||
new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER, 20, false, 5.0);
|
||||
|
||||
{
|
||||
PoolManager::LocalPoolConfig poolCfg = {{100, 16}, {50, 32}, {25, 64}, {15, 128}, {5, 1024}};
|
||||
|
@ -57,7 +57,7 @@ TEST_CASE("Action Helper", "[action]") {
|
||||
step += 1;
|
||||
CHECK(testMqMock.wasMessageSent());
|
||||
CommandMessage testMessage;
|
||||
REQUIRE(testMqMock.getNextSentMessage(testMessage) == returnvalue::OK);
|
||||
REQUIRE(testMqMock.getNextSentMessageToDefaultDest(testMessage) == returnvalue::OK);
|
||||
REQUIRE(testMessage.getCommand() == static_cast<uint32_t>(ActionMessage::STEP_FAILED));
|
||||
REQUIRE(testMessage.getParameter() == static_cast<uint32_t>(testActionId));
|
||||
uint32_t parameter2 = ((uint32_t)step << 16) | (uint32_t)status;
|
||||
@ -71,7 +71,7 @@ TEST_CASE("Action Helper", "[action]") {
|
||||
actionHelper.finish(false, testMqMock.getId(), testActionId, status);
|
||||
CHECK(testMqMock.wasMessageSent());
|
||||
CommandMessage testMessage;
|
||||
REQUIRE(testMqMock.getNextSentMessage(testMessage) == returnvalue::OK);
|
||||
REQUIRE(testMqMock.getNextSentMessageToDefaultDest(testMessage) == returnvalue::OK);
|
||||
REQUIRE(testMessage.getCommand() == static_cast<uint32_t>(ActionMessage::COMPLETION_FAILED));
|
||||
REQUIRE(ActionMessage::getActionId(&testMessage) == testActionId);
|
||||
REQUIRE(ActionMessage::getReturnCode(&testMessage) == static_cast<uint32_t>(status));
|
||||
@ -87,7 +87,7 @@ TEST_CASE("Action Helper", "[action]") {
|
||||
REQUIRE(ipcStore->getData(toLongParamAddress).first ==
|
||||
static_cast<uint32_t>(StorageManagerIF::DATA_DOES_NOT_EXIST));
|
||||
CommandMessage testMessage;
|
||||
REQUIRE(testMqMock.getNextSentMessage(testMessage) == returnvalue::OK);
|
||||
REQUIRE(testMqMock.getNextSentMessageToDefaultDest(testMessage) == returnvalue::OK);
|
||||
REQUIRE(testMessage.getCommand() == static_cast<uint32_t>(ActionMessage::STEP_FAILED));
|
||||
REQUIRE(ActionMessage::getReturnCode(&testMessage) == 0xAFFE);
|
||||
REQUIRE(ActionMessage::getStep(&testMessage) == 0);
|
||||
|
@ -1,5 +1,6 @@
|
||||
target_sources(${FSFW_TEST_TGT} PRIVATE testCfdp.cpp testOtherTlvs.cpp
|
||||
testTlv.cpp testLvs.cpp)
|
||||
target_sources(
|
||||
${FSFW_TEST_TGT} PRIVATE testCfdp.cpp testOtherTlvs.cpp
|
||||
testReservedMsgCreator.cpp testTlv.cpp testLvs.cpp)
|
||||
|
||||
add_subdirectory(handler)
|
||||
add_subdirectory(pdu)
|
||||
|
@ -1,3 +1,4 @@
|
||||
target_sources(
|
||||
${FSFW_TEST_TGT} PRIVATE testDistributor.cpp testDestHandler.cpp
|
||||
testSourceHandler.cpp testFaultHandler.cpp)
|
||||
${FSFW_TEST_TGT}
|
||||
PRIVATE testDistributor.cpp testDestHandler.cpp testReservedMsgParser.cpp
|
||||
testPutRequest.cpp testSourceHandler.cpp testFaultHandler.cpp)
|
||||
|
@ -50,18 +50,18 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
|
||||
auto destHandler = DestHandler(dp, fp);
|
||||
CHECK(destHandler.initialize() == OK);
|
||||
|
||||
auto metadataPreparation = [&](FileSize cfdpFileSize, ChecksumType checksumType) {
|
||||
auto metadataPreparation = [&](Fss cfdpFileSize, ChecksumType 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);
|
||||
MetadataGenericInfo info(false, checksumType, std::move(cfdpFileSize));
|
||||
TransactionSeqNum seqNum(UnsignedByteField<uint16_t>(1));
|
||||
conf.sourceId = remoteId;
|
||||
conf.destId = localId;
|
||||
conf.mode = TransmissionMode::UNACKNOWLEDGED;
|
||||
conf.seqNum = seqNum;
|
||||
MetadataPduCreator metadataCreator(conf, info);
|
||||
MetadataPduCreator metadataCreator(conf, info, srcName, destName, nullptr, 0);
|
||||
REQUIRE(tcStore.getFreeElement(&storeId, metadataCreator.getSerializedSize(), &buf) == OK);
|
||||
REQUIRE(metadataCreator.serialize(buf, serLen, metadataCreator.getSerializedSize()) == OK);
|
||||
PacketInfo packetInfo(metadataCreator.getPduType(), storeId,
|
||||
@ -81,17 +81,17 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
|
||||
auto& idMetadataPair = userMock.metadataRecvd.back();
|
||||
REQUIRE(idMetadataPair.first == destHandler.getTransactionId());
|
||||
REQUIRE(idMetadataPair.second.sourceId.getValue() == 3);
|
||||
REQUIRE(idMetadataPair.second.fileSize == fileLen);
|
||||
REQUIRE(idMetadataPair.second.fileSize.getSize(nullptr) == 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.state == CfdpState::BUSY_CLASS_1_NACKED);
|
||||
REQUIRE(res.step == DestHandler::TransactionStep::RECEIVING_FILE_DATA_PDUS);
|
||||
};
|
||||
|
||||
auto eofPreparation = [&](FileSize cfdpFileSize, uint32_t crc) {
|
||||
auto eofPreparation = [&](Fss 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);
|
||||
@ -102,14 +102,14 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
|
||||
|
||||
auto eofCheck = [&](const cfdp::DestHandler::FsmResult& res, const TransactionId& id) {
|
||||
REQUIRE(res.result == OK);
|
||||
REQUIRE(res.state == CfdpStates::IDLE);
|
||||
REQUIRE(res.state == CfdpState::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();
|
||||
REQUIRE(userMock.eofRecvdRecvd.size() == 1);
|
||||
auto& eofId = userMock.eofRecvdRecvd.back();
|
||||
CHECK(eofId == id);
|
||||
REQUIRE(userMock.finishedRecvd.size() == 1);
|
||||
auto& idParamPair = userMock.finishedRecvd.back();
|
||||
@ -120,7 +120,7 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
|
||||
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.state == CfdpState::BUSY_CLASS_1_NACKED);
|
||||
REQUIRE(res.step == DestHandler::TransactionStep::RECEIVING_FILE_DATA_PDUS);
|
||||
for (const auto id : idsToCheck) {
|
||||
REQUIRE(not tcStore.hasDataAtId(id));
|
||||
@ -129,50 +129,50 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
|
||||
};
|
||||
|
||||
SECTION("State") {
|
||||
CHECK(destHandler.getCfdpState() == CfdpStates::IDLE);
|
||||
CHECK(destHandler.getCfdpState() == CfdpState::IDLE);
|
||||
CHECK(destHandler.getTransactionStep() == DestHandler::TransactionStep::IDLE);
|
||||
}
|
||||
|
||||
SECTION("Idle State Machine Iteration") {
|
||||
auto res = destHandler.performStateMachine();
|
||||
auto res = destHandler.stateMachine();
|
||||
CHECK(res.result == OK);
|
||||
CHECK(res.callStatus == CallStatus::CALL_AFTER_DELAY);
|
||||
CHECK(res.errors == 0);
|
||||
CHECK(destHandler.getCfdpState() == CfdpStates::IDLE);
|
||||
CHECK(destHandler.getCfdpState() == CfdpState::IDLE);
|
||||
CHECK(destHandler.getTransactionStep() == DestHandler::TransactionStep::IDLE);
|
||||
}
|
||||
|
||||
SECTION("Empty File Transfer") {
|
||||
const DestHandler::FsmResult& res = destHandler.performStateMachine();
|
||||
const DestHandler::FsmResult& res = destHandler.stateMachine();
|
||||
CHECK(res.result == OK);
|
||||
FileSize cfdpFileSize(0);
|
||||
Fss cfdpFileSize(0);
|
||||
metadataPreparation(cfdpFileSize, ChecksumType::NULL_CHECKSUM);
|
||||
destHandler.performStateMachine();
|
||||
destHandler.stateMachine();
|
||||
metadataCheck(res, "hello.txt", "hello-cpy.txt", 0);
|
||||
destHandler.performStateMachine();
|
||||
destHandler.stateMachine();
|
||||
REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY);
|
||||
auto transactionId = destHandler.getTransactionId();
|
||||
eofPreparation(cfdpFileSize, 0);
|
||||
// After EOF, operation is done because no closure was requested
|
||||
destHandler.performStateMachine();
|
||||
destHandler.stateMachine();
|
||||
eofCheck(res, transactionId);
|
||||
}
|
||||
|
||||
SECTION("Small File Transfer") {
|
||||
const DestHandler::FsmResult& res = destHandler.performStateMachine();
|
||||
const DestHandler::FsmResult& res = destHandler.stateMachine();
|
||||
CHECK(res.result == OK);
|
||||
std::string fileData = "hello test data";
|
||||
etl::crc32 crcCalc;
|
||||
crcCalc.add(fileData.begin(), fileData.end());
|
||||
uint32_t crc32 = crcCalc.value();
|
||||
FileSize cfdpFileSize(fileData.size());
|
||||
Fss cfdpFileSize(fileData.size());
|
||||
metadataPreparation(cfdpFileSize, ChecksumType::CRC_32);
|
||||
destHandler.performStateMachine();
|
||||
destHandler.stateMachine();
|
||||
metadataCheck(res, "hello.txt", "hello-cpy.txt", fileData.size());
|
||||
destHandler.performStateMachine();
|
||||
destHandler.stateMachine();
|
||||
REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY);
|
||||
auto transactionId = destHandler.getTransactionId();
|
||||
FileSize offset(0);
|
||||
Fss offset(0);
|
||||
FileDataInfo fdPduInfo(offset, reinterpret_cast<const uint8_t*>(fileData.data()),
|
||||
fileData.size());
|
||||
FileDataCreator fdPduCreator(conf, fdPduInfo);
|
||||
@ -180,16 +180,16 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
|
||||
REQUIRE(fdPduCreator.serialize(buf, serLen, fdPduCreator.getSerializedSize()) == OK);
|
||||
PacketInfo packetInfo(fdPduCreator.getPduType(), storeId, std::nullopt);
|
||||
packetInfoList.push_back(packetInfo);
|
||||
destHandler.performStateMachine();
|
||||
destHandler.stateMachine();
|
||||
fileDataPduCheck(res, {storeId});
|
||||
eofPreparation(cfdpFileSize, crc32);
|
||||
// After EOF, operation is done because no closure was requested
|
||||
destHandler.performStateMachine();
|
||||
destHandler.stateMachine();
|
||||
eofCheck(res, transactionId);
|
||||
}
|
||||
|
||||
SECTION("Segmented File Transfer") {
|
||||
const DestHandler::FsmResult& res = destHandler.performStateMachine();
|
||||
const DestHandler::FsmResult& res = destHandler.stateMachine();
|
||||
CHECK(res.result == OK);
|
||||
std::random_device dev;
|
||||
std::mt19937 rng(dev());
|
||||
@ -201,17 +201,17 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
|
||||
etl::crc32 crcCalc;
|
||||
crcCalc.add(largerFileData.begin(), largerFileData.end());
|
||||
uint32_t crc32 = crcCalc.value();
|
||||
FileSize cfdpFileSize(largerFileData.size());
|
||||
Fss cfdpFileSize(largerFileData.size());
|
||||
metadataPreparation(cfdpFileSize, ChecksumType::CRC_32);
|
||||
destHandler.performStateMachine();
|
||||
destHandler.stateMachine();
|
||||
metadataCheck(res, "hello.txt", "hello-cpy.txt", largerFileData.size());
|
||||
destHandler.performStateMachine();
|
||||
destHandler.stateMachine();
|
||||
REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY);
|
||||
auto transactionId = destHandler.getTransactionId();
|
||||
|
||||
std::vector<store_address_t> idsToCheck;
|
||||
{
|
||||
FileSize offset(0);
|
||||
Fss offset(0);
|
||||
FileDataInfo fdPduInfo(offset, reinterpret_cast<const uint8_t*>(largerFileData.data()),
|
||||
largerFileData.size() / 2);
|
||||
FileDataCreator fdPduCreator(conf, fdPduInfo);
|
||||
@ -223,7 +223,7 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
|
||||
}
|
||||
|
||||
{
|
||||
FileSize offset(512);
|
||||
Fss offset(512);
|
||||
FileDataInfo fdPduInfo(offset, reinterpret_cast<const uint8_t*>(largerFileData.data() + 512),
|
||||
largerFileData.size() / 2);
|
||||
FileDataCreator fdPduCreator(conf, fdPduInfo);
|
||||
@ -234,11 +234,11 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
|
||||
packetInfoList.push_back(packetInfo);
|
||||
}
|
||||
|
||||
destHandler.performStateMachine();
|
||||
destHandler.stateMachine();
|
||||
fileDataPduCheck(res, idsToCheck);
|
||||
eofPreparation(cfdpFileSize, crc32);
|
||||
// After EOF, operation is done because no closure was requested
|
||||
destHandler.performStateMachine();
|
||||
destHandler.stateMachine();
|
||||
eofCheck(res, transactionId);
|
||||
}
|
||||
}
|
@ -21,7 +21,7 @@ TEST_CASE("CFDP Distributor", "[cfdp][distributor]") {
|
||||
auto tcAcceptor = AcceptsTcMock("CFDP Receiver", 0, receiverQueueId);
|
||||
|
||||
// Set up Metadata PDU for generate test data.
|
||||
cfdp::FileSize fileSize(12);
|
||||
cfdp::Fss fileSize(12);
|
||||
const cfdp::EntityId& sourceId(groundEntityId);
|
||||
const cfdp::EntityId& destId(obswEntityId);
|
||||
cfdp::TransactionSeqNum seqNum(UnsignedByteField<uint16_t>(12));
|
||||
@ -30,9 +30,8 @@ TEST_CASE("CFDP Distributor", "[cfdp][distributor]") {
|
||||
cfdp::StringLv sourceFileName(sourceFileString);
|
||||
std::string destFileString = "hello2.txt";
|
||||
cfdp::StringLv destFileName(destFileString);
|
||||
MetadataInfo metadataInfo(false, cfdp::ChecksumType::CRC_32, fileSize, sourceFileName,
|
||||
destFileName);
|
||||
MetadataPduCreator creator(pduConf, metadataInfo);
|
||||
MetadataGenericInfo metadataInfo(false, cfdp::ChecksumType::CRC_32, fileSize);
|
||||
MetadataPduCreator creator(pduConf, metadataInfo, sourceFileName, destFileName, nullptr, 0);
|
||||
uint8_t* dataPtr = nullptr;
|
||||
|
||||
SECTION("State") {
|
||||
|
59
unittests/cfdp/handler/testPutRequest.cpp
Normal file
59
unittests/cfdp/handler/testPutRequest.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
#include <array>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include "fsfw/cfdp/handler/PutRequest.h"
|
||||
#include "fsfw/cfdp/tlv/ReservedMessageCreator.h"
|
||||
|
||||
TEST_CASE("Put Request", "[cfdp]") {
|
||||
using namespace cfdp;
|
||||
using namespace returnvalue;
|
||||
|
||||
std::array<uint8_t, 32> reservedMsgCustomData{};
|
||||
std::array<uint8_t, 128> reservedMsgBuf{};
|
||||
std::array<uint8_t, 128> buffer{};
|
||||
EntityId destId(WidthInBytes::ONE_BYTE, 5);
|
||||
std::string srcFileName = "hello.txt";
|
||||
std::string destFileName = "hello2.txt";
|
||||
uint8_t* msgBufPtr = reservedMsgCustomData.data();
|
||||
size_t msgSize = 0;
|
||||
cfdp::StringLv srcName(srcFileName);
|
||||
cfdp::StringLv destName(destFileName);
|
||||
CHECK(destId.serializeAsLv(&msgBufPtr, &msgSize, reservedMsgCustomData.size()) == OK);
|
||||
CHECK(srcName.serialize(&msgBufPtr, &msgSize, reservedMsgCustomData.size(),
|
||||
SerializeIF::Endianness::NETWORK) == OK);
|
||||
CHECK(destName.serialize(&msgBufPtr, &msgSize, reservedMsgCustomData.size(),
|
||||
SerializeIF::Endianness::NETWORK) == OK);
|
||||
ReservedMessageCreator creator(static_cast<uint8_t>(ProxyOpMessageType::PUT_REQUEST),
|
||||
reservedMsgCustomData.data(), msgSize);
|
||||
msgSize = 0;
|
||||
ReturnValue_t result = creator.serializeBe(reservedMsgBuf.data(), msgSize, buffer.size());
|
||||
CHECK(result == returnvalue::OK);
|
||||
|
||||
SECTION("Put Request with reserved message") {
|
||||
PutRequest putRequest(destId, reservedMsgBuf.data(), msgSize, nullptr, 0);
|
||||
uint8_t* bufPtr = buffer.data();
|
||||
size_t serLen = 0;
|
||||
REQUIRE(putRequest.serialize(&bufPtr, &serLen, buffer.size(),
|
||||
SerializeIF::Endianness::NETWORK) == OK);
|
||||
|
||||
CHECK(putRequest.getSerializedSize() == serLen);
|
||||
PutRequest requestDeserialized;
|
||||
size_t deserLen = putRequest.getSerializedSize();
|
||||
const uint8_t* deserPtr = buffer.data();
|
||||
REQUIRE(requestDeserialized.deSerialize(&deserPtr, &deserLen,
|
||||
SerializeIF::Endianness::NETWORK) == OK);
|
||||
CHECK(requestDeserialized.getDestId().getWidth() == destId.getWidth());
|
||||
CHECK(requestDeserialized.getDestId().getValue() == destId.getValue());
|
||||
size_t totalMsgsSize = 0;
|
||||
const uint8_t* msgsToUserStart = requestDeserialized.getMessagesToUser(totalMsgsSize);
|
||||
CHECK(totalMsgsSize == msgSize);
|
||||
cfdp::Tlv genericTlv;
|
||||
genericTlv.deSerialize(&msgsToUserStart, &totalMsgsSize, SerializeIF::Endianness::NETWORK);
|
||||
CHECK(genericTlv.getType() == TlvType::MSG_TO_USER);
|
||||
CHECK(genericTlv.getLengthField() == genericTlv.getSerializedSize() - 2);
|
||||
CHECK(genericTlv.getValue()[0] == 'c');
|
||||
CHECK(genericTlv.getValue()[1] == 'f');
|
||||
CHECK(genericTlv.getValue()[2] == 'd');
|
||||
CHECK(genericTlv.getValue()[3] == 'p');
|
||||
}
|
||||
}
|
67
unittests/cfdp/handler/testReservedMsgParser.cpp
Normal file
67
unittests/cfdp/handler/testReservedMsgParser.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include "fsfw/cfdp/CfdpMessage.h"
|
||||
#include "fsfw/cfdp/VarLenFields.h"
|
||||
#include "fsfw/cfdp/handler/PutRequest.h"
|
||||
#include "fsfw/cfdp/handler/ReservedMessageParser.h"
|
||||
#include "fsfw/cfdp/tlv/Lv.h"
|
||||
#include "fsfw/cfdp/tlv/ReservedMessageCreator.h"
|
||||
#include "fsfw/cfdp/tlv/StringLv.h"
|
||||
#include "fsfw/globalfunctions/arrayprinter.h"
|
||||
#include "fsfw/serialize.h"
|
||||
#include "mocks/MessageQueueMock.h"
|
||||
#include "mocks/StorageManagerMock.h"
|
||||
|
||||
TEST_CASE("Reserved Message Parser", "[cfdp]") {
|
||||
using namespace cfdp;
|
||||
using namespace returnvalue;
|
||||
|
||||
std::string srcFileName = "hello.txt";
|
||||
std::string destFileName = "hello2.txt";
|
||||
MessageQueueId_t destQueueId = 2;
|
||||
MessageQueueMock msgQueue(1);
|
||||
LocalPool::LocalPoolConfig storeCfg = {{10, 32}, {10, 64}, {10, 128}, {10, 1024}};
|
||||
StorageManagerMock ipcStore(0, storeCfg);
|
||||
std::array<uint8_t, 128> buffer{};
|
||||
uint8_t msgBuf[32]{};
|
||||
|
||||
EntityId entityId(cfdp::WidthInBytes::ONE_BYTE, 5);
|
||||
uint8_t* msgBufPtr = msgBuf;
|
||||
size_t serLen = 0;
|
||||
cfdp::StringLv srcName(srcFileName);
|
||||
cfdp::StringLv destName(destFileName);
|
||||
CHECK(entityId.serializeAsLv(&msgBufPtr, &serLen, sizeof(msgBuf)) == OK);
|
||||
CHECK(srcName.serialize(&msgBufPtr, &serLen, sizeof(msgBuf), SerializeIF::Endianness::NETWORK) ==
|
||||
OK);
|
||||
CHECK(destName.serialize(&msgBufPtr, &serLen, sizeof(msgBuf), SerializeIF::Endianness::NETWORK) ==
|
||||
OK);
|
||||
ReservedMessageCreator creator(static_cast<uint8_t>(ProxyOpMessageType::PUT_REQUEST), msgBuf,
|
||||
serLen);
|
||||
serLen = 0;
|
||||
ReturnValue_t result = creator.serializeBe(buffer.data(), serLen, buffer.size());
|
||||
CHECK(result == returnvalue::OK);
|
||||
MessageToUserTlv msgToUser;
|
||||
CHECK(msgToUser.deSerializeBe(buffer.data(), serLen, buffer.size()) == OK);
|
||||
ReservedMessageParser parser(ipcStore, msgQueue, destQueueId);
|
||||
REQUIRE(parser.parse(&msgToUser, 1) == OK);
|
||||
CommandMessage msg;
|
||||
CHECK(msgQueue.wasMessageSent());
|
||||
CHECK(msgQueue.numberOfSentMessages() == 1);
|
||||
CHECK(msgQueue.getNextSentMessage(destQueueId, msg) == OK);
|
||||
store_address_t storeId = CfdpMessage::getStoreId(&msg);
|
||||
const uint8_t* data;
|
||||
size_t packetLen;
|
||||
CHECK(ipcStore.getData(storeId, &data, &packetLen) == OK);
|
||||
CHECK(packetLen > 0);
|
||||
PutRequest putRequest;
|
||||
size_t dummy = packetLen;
|
||||
REQUIRE(putRequest.deSerialize(&data, &dummy, SerializeIF::Endianness::MACHINE) == OK);
|
||||
CHECK(putRequest.getDestId().getValue() == entityId.getValue());
|
||||
CHECK(putRequest.getDestId().getWidth() == entityId.getWidth());
|
||||
auto& sourceNameLv = putRequest.getSourceName();
|
||||
std::string srcNameRead = sourceNameLv.getString();
|
||||
CHECK(srcNameRead == srcFileName);
|
||||
auto& destNameLv = putRequest.getDestName();
|
||||
std::string destNameRead = destNameLv.getString();
|
||||
CHECK(destNameRead == destFileName);
|
||||
}
|
@ -1,3 +1,286 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <etl/crc32.h>
|
||||
|
||||
TEST_CASE("CFDP Source Handler", "[cfdp]") {}
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <filesystem>
|
||||
#include <random>
|
||||
|
||||
#include "fsfw/cfdp.h"
|
||||
#include "fsfw/cfdp/handler/PutRequest.h"
|
||||
#include "fsfw/cfdp/handler/SourceHandler.h"
|
||||
#include "fsfw/cfdp/pdu/EofPduCreator.h"
|
||||
#include "fsfw/cfdp/pdu/EofPduReader.h"
|
||||
#include "fsfw/cfdp/pdu/FileDataReader.h"
|
||||
#include "fsfw/cfdp/pdu/MetadataPduCreator.h"
|
||||
#include "fsfw/cfdp/pdu/MetadataPduReader.h"
|
||||
#include "fsfw/tmtcservices/TmTcMessage.h"
|
||||
#include "fsfw/util/SeqCountProvider.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 Source Handler", "[cfdp]") {
|
||||
using namespace cfdp;
|
||||
using namespace returnvalue;
|
||||
using namespace std::filesystem;
|
||||
const size_t MAX_FILE_SEGMENT_SIZE = 255;
|
||||
|
||||
MessageQueueId_t destQueueId = 2;
|
||||
AcceptsTmMock tmReceiver(destQueueId);
|
||||
MessageQueueMock mqMock(destQueueId);
|
||||
EntityId localId = EntityId(UnsignedByteField<uint16_t>(2));
|
||||
EntityId remoteId = EntityId(UnsignedByteField<uint16_t>(5));
|
||||
FaultHandlerMock fhMock;
|
||||
LocalEntityCfg localEntityCfg(localId, IndicationCfg(), fhMock);
|
||||
FilesystemMock fsMock;
|
||||
UserMock userMock(fsMock);
|
||||
SeqCountProviderU16 seqCountProvider;
|
||||
SourceHandlerParams dp(localEntityCfg, userMock, seqCountProvider);
|
||||
|
||||
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);
|
||||
fp.tcStore = &tcStore;
|
||||
fp.tmStore = &tmStore;
|
||||
auto sourceHandler = SourceHandler(dp, fp);
|
||||
|
||||
RemoteEntityCfg cfg;
|
||||
cfg.maxFileSegmentLen = MAX_FILE_SEGMENT_SIZE;
|
||||
cfg.remoteId = remoteId;
|
||||
std::string srcFileName = "/tmp/cfdp-test.txt";
|
||||
std::string destFileName = "/tmp/cfdp-test2.txt";
|
||||
FilesystemParams srcFileNameFs(srcFileName.c_str());
|
||||
fsMock.createFile(srcFileNameFs);
|
||||
cfdp::StringLv srcNameLv(srcFileNameFs.path, std::strlen(srcFileNameFs.path));
|
||||
FilesystemParams destFileNameFs(destFileName.c_str());
|
||||
cfdp::StringLv destNameLv(destFileNameFs.path, std::strlen(destFileNameFs.path));
|
||||
PutRequest putRequest(remoteId, srcNameLv, destNameLv);
|
||||
CHECK(sourceHandler.initialize() == OK);
|
||||
|
||||
auto onePduSentCheck = [&](const SourceHandler::FsmResult& fsmResult, TmTcMessage& tmtcMessage,
|
||||
const uint8_t** pduPtr) {
|
||||
CHECK(fsmResult.errors == 0);
|
||||
CHECK(fsmResult.packetsSent == 1);
|
||||
CHECK(mqMock.numberOfSentMessages() == 1);
|
||||
REQUIRE(mqMock.getNextSentMessage(destQueueId, tmtcMessage) == OK);
|
||||
auto accessor = tmStore.getData(tmtcMessage.getStorageId());
|
||||
REQUIRE(accessor.first == OK);
|
||||
*pduPtr = accessor.second.data();
|
||||
return std::move(accessor);
|
||||
};
|
||||
auto genericMetadataCheck = [&](const SourceHandler::FsmResult& fsmResult,
|
||||
size_t expectedFileSize, uint16_t expectedSeqNum) {
|
||||
CHECK(fsmResult.errors == 0);
|
||||
CHECK(fsmResult.callStatus == CallStatus::CALL_AGAIN);
|
||||
TmTcMessage tmtcMessage;
|
||||
const uint8_t* pduPtr;
|
||||
auto accessor = onePduSentCheck(fsmResult, tmtcMessage, &pduPtr);
|
||||
CHECK(accessor.second.size() == 55);
|
||||
MetadataGenericInfo metadataInfo;
|
||||
MetadataPduReader metadataReader(pduPtr, accessor.second.size(), metadataInfo, nullptr, 0);
|
||||
REQUIRE(metadataReader.parseData() == OK);
|
||||
std::string srcNameRead = metadataReader.getSourceFileName().getString();
|
||||
CHECK(srcNameRead == srcFileName);
|
||||
TransactionSeqNum seqNum;
|
||||
metadataReader.getTransactionSeqNum(seqNum);
|
||||
CHECK(seqNum.getValue() == expectedSeqNum);
|
||||
CHECK(userMock.transactionIndicRecvd.size() == 1);
|
||||
CHECK(userMock.transactionIndicRecvd.back() == TransactionId(localId, seqNum));
|
||||
EntityId srcId;
|
||||
metadataReader.getSourceId(srcId);
|
||||
EntityId destId;
|
||||
metadataReader.getDestId(destId);
|
||||
CHECK(srcId.getValue() == localId.getValue());
|
||||
CHECK(destId.getValue() == remoteId.getValue());
|
||||
std::string destNameRead = metadataReader.getDestFileName().getString();
|
||||
CHECK(destNameRead == destFileName);
|
||||
if (expectedFileSize == 0) {
|
||||
CHECK(metadataInfo.getChecksumType() == ChecksumType::NULL_CHECKSUM);
|
||||
} else {
|
||||
CHECK(metadataInfo.getChecksumType() == ChecksumType::CRC_32);
|
||||
}
|
||||
CHECK(metadataInfo.getFileSize().value() == expectedFileSize);
|
||||
CHECK(!metadataInfo.isClosureRequested());
|
||||
mqMock.clearMessages();
|
||||
};
|
||||
auto genericEofCheck = [&](const SourceHandler::FsmResult& fsmResult, size_t expectedFileSize,
|
||||
uint32_t expectedChecksum, uint16_t expectedSeqNum) {
|
||||
CHECK(fsmResult.errors == 0);
|
||||
CHECK(fsmResult.callStatus == CallStatus::CALL_AGAIN);
|
||||
TmTcMessage tmtcMessage;
|
||||
const uint8_t* pduPtr;
|
||||
auto accessor = onePduSentCheck(fsmResult, tmtcMessage, &pduPtr);
|
||||
// 10 byte PDU header, 1 byte directive field, 1 byte condition code, 4 byte checksum,
|
||||
// 4 byte FSS
|
||||
CHECK(accessor.second.size() == 20);
|
||||
EofInfo eofInfo;
|
||||
EofPduReader eofReader(pduPtr, accessor.second.size(), eofInfo);
|
||||
REQUIRE(eofReader.parseData() == OK);
|
||||
TransactionSeqNum seqNum;
|
||||
eofReader.getTransactionSeqNum(seqNum);
|
||||
CHECK(seqNum.getValue() == expectedSeqNum);
|
||||
auto transactionId = TransactionId(localId, seqNum);
|
||||
CHECK(userMock.eofSentRecvd.size() == 1);
|
||||
CHECK(userMock.eofSentRecvd.back() == transactionId);
|
||||
CHECK(eofInfo.getChecksum() == expectedChecksum);
|
||||
CHECK(eofInfo.getConditionCode() == ConditionCode::NO_ERROR);
|
||||
CHECK(eofInfo.getFileSize().value() == expectedFileSize);
|
||||
};
|
||||
auto genericNoticeOfCompletionCheck = [&](const SourceHandler::FsmResult& fsmResult,
|
||||
uint16_t expectedSeqNum) {
|
||||
CHECK(fsmResult.callStatus == CallStatus::DONE);
|
||||
CHECK(userMock.finishedRecvd.size() == 1);
|
||||
CHECK(userMock.finishedRecvd.back().first ==
|
||||
TransactionId(localId, TransactionSeqNum(cfdp::WidthInBytes::TWO_BYTES, expectedSeqNum)));
|
||||
CHECK(sourceHandler.getStep() == SourceHandler::TransactionStep::IDLE);
|
||||
CHECK(sourceHandler.getState() == CfdpState::IDLE);
|
||||
};
|
||||
|
||||
SECTION("Test Basic") {
|
||||
CHECK(sourceHandler.getState() == CfdpState::IDLE);
|
||||
CHECK(sourceHandler.getStep() == SourceHandler::TransactionStep::IDLE);
|
||||
}
|
||||
|
||||
SECTION("Transfer empty file") {
|
||||
CHECK(sourceHandler.transactionStart(putRequest, cfg) == OK);
|
||||
|
||||
size_t expectedFileSize = 0;
|
||||
const SourceHandler::FsmResult& fsmResult = sourceHandler.stateMachine();
|
||||
// Verify metadata PDU was sent.
|
||||
genericMetadataCheck(fsmResult, expectedFileSize, 0);
|
||||
|
||||
sourceHandler.stateMachine();
|
||||
// Verify EOF PDU was sent. No file data PDU is sent for an empty file and the checksum is 0.
|
||||
genericEofCheck(fsmResult, expectedFileSize, 0, 0);
|
||||
|
||||
// Verify notice of completion.
|
||||
sourceHandler.stateMachine();
|
||||
genericNoticeOfCompletionCheck(fsmResult, 0);
|
||||
}
|
||||
|
||||
SECTION("Transfer small file") {
|
||||
uint16_t expectedSeqNum = 0;
|
||||
fsMock.createFile(srcFileNameFs);
|
||||
std::string fileContent = "hello world\n";
|
||||
size_t expectedFileSize = fileContent.size();
|
||||
FileOpParams params(srcFileName.c_str(), expectedFileSize);
|
||||
fsMock.writeToFile(params, reinterpret_cast<const uint8_t*>(fileContent.data()));
|
||||
CHECK(sourceHandler.transactionStart(putRequest, cfg) == OK);
|
||||
const SourceHandler::FsmResult& fsmResult = sourceHandler.stateMachine();
|
||||
|
||||
// Verify metadata PDU was sent.
|
||||
genericMetadataCheck(fsmResult, expectedFileSize, expectedSeqNum);
|
||||
|
||||
// Verify that a small file data PDU was sent.
|
||||
sourceHandler.stateMachine();
|
||||
TmTcMessage tmtcMessage;
|
||||
const uint8_t* pduPtr;
|
||||
auto accessor = onePduSentCheck(fsmResult, tmtcMessage, &pduPtr);
|
||||
FileDataInfo fdInfo;
|
||||
FileDataReader fdReader(pduPtr, accessor.second.size(), fdInfo);
|
||||
// 10 byte PDU header, 4 byte offset, 12 bytes file data.
|
||||
CHECK(accessor.second.size() == 26);
|
||||
CHECK(fdReader.parseData() == OK);
|
||||
CHECK(fdInfo.getOffset().value() == 0);
|
||||
size_t fileSize = 0;
|
||||
const uint8_t* fileData = fdInfo.getFileData(&fileSize);
|
||||
REQUIRE(fileSize == fileContent.size());
|
||||
CHECK(fileData != nullptr);
|
||||
std::string dataReadBack(reinterpret_cast<const char*>(fileData), fileSize);
|
||||
CHECK(dataReadBack == fileContent);
|
||||
mqMock.clearMessages();
|
||||
|
||||
sourceHandler.stateMachine();
|
||||
|
||||
etl::crc32 crcCalc;
|
||||
crcCalc.add(fileContent.data(), fileContent.data() + fileContent.size());
|
||||
// Verify EOF PDU was sent.
|
||||
genericEofCheck(fsmResult, expectedFileSize, crcCalc.value(), expectedSeqNum);
|
||||
|
||||
// Verify notice of completion.
|
||||
sourceHandler.stateMachine();
|
||||
genericNoticeOfCompletionCheck(fsmResult, expectedSeqNum);
|
||||
}
|
||||
|
||||
SECTION("Transfer two segment file") {
|
||||
uint16_t expectedSeqNum = 0;
|
||||
// Create 400 bytes of random data. This should result in two file segments, with one
|
||||
// having the maximum size.
|
||||
std::random_device dev;
|
||||
std::mt19937 rng(dev());
|
||||
std::uniform_int_distribution<std::mt19937::result_type> distU8(0, 255);
|
||||
std::array<uint8_t, 400> largerFileData{};
|
||||
for (auto& val : largerFileData) {
|
||||
val = distU8(rng);
|
||||
}
|
||||
size_t expectedFileSize = largerFileData.size();
|
||||
fsMock.createFile(srcFileNameFs);
|
||||
FileOpParams params(srcFileName.c_str(), expectedFileSize);
|
||||
fsMock.writeToFile(params, reinterpret_cast<const uint8_t*>(largerFileData.data()));
|
||||
CHECK(sourceHandler.transactionStart(putRequest, cfg) == OK);
|
||||
const SourceHandler::FsmResult& fsmResult = sourceHandler.stateMachine();
|
||||
// Verify metadata PDU was sent.
|
||||
genericMetadataCheck(fsmResult, expectedFileSize, expectedSeqNum);
|
||||
|
||||
// Check first file data PDU. It should have the maximum file segment size.
|
||||
sourceHandler.stateMachine();
|
||||
TmTcMessage tmtcMessage;
|
||||
const uint8_t* pduPtr;
|
||||
FileDataInfo fdInfo;
|
||||
{
|
||||
CHECK(fsmResult.callStatus == CallStatus::CALL_AGAIN);
|
||||
auto accessor = onePduSentCheck(fsmResult, tmtcMessage, &pduPtr);
|
||||
FileDataReader fdReader(pduPtr, accessor.second.size(), fdInfo);
|
||||
// 10 byte PDU header, 4 byte offset, 255 byte file data
|
||||
CHECK(accessor.second.size() == 269);
|
||||
CHECK(fdReader.parseData() == OK);
|
||||
CHECK(fdInfo.getOffset().value() == 0);
|
||||
size_t fileSize = 0;
|
||||
const uint8_t* fileData = fdInfo.getFileData(&fileSize);
|
||||
// Maximum file segment size.
|
||||
REQUIRE(fileSize == MAX_FILE_SEGMENT_SIZE);
|
||||
for (unsigned i = 0; i < fileSize; i++) {
|
||||
CHECK(fileData[i] == largerFileData[i]);
|
||||
}
|
||||
}
|
||||
mqMock.clearMessages();
|
||||
|
||||
// Check second file data PDU.
|
||||
sourceHandler.stateMachine();
|
||||
{
|
||||
CHECK(fsmResult.callStatus == CallStatus::CALL_AGAIN);
|
||||
auto accessor = onePduSentCheck(fsmResult, tmtcMessage, &pduPtr);
|
||||
FileDataReader fdReader(pduPtr, accessor.second.size(), fdInfo);
|
||||
// 10 byte PDU header, 4 byte offset, remaining file data (400 - 255 == 145).
|
||||
CHECK(accessor.second.size() == 10 + 4 + largerFileData.size() - MAX_FILE_SEGMENT_SIZE);
|
||||
CHECK(fdReader.parseData() == OK);
|
||||
CHECK(fdInfo.getOffset().value() == MAX_FILE_SEGMENT_SIZE);
|
||||
size_t fileDataSize = 0;
|
||||
const uint8_t* fileData = fdInfo.getFileData(&fileDataSize);
|
||||
// Maximum file segment size.
|
||||
REQUIRE(fileDataSize == largerFileData.size() - MAX_FILE_SEGMENT_SIZE);
|
||||
for (unsigned i = 0; i < fileDataSize; i++) {
|
||||
CHECK(fileData[i] == largerFileData[MAX_FILE_SEGMENT_SIZE + i]);
|
||||
}
|
||||
}
|
||||
mqMock.clearMessages();
|
||||
|
||||
// Check EOF and verify checksum.
|
||||
sourceHandler.stateMachine();
|
||||
|
||||
etl::crc32 crcCalc;
|
||||
crcCalc.add(largerFileData.data(), largerFileData.data() + largerFileData.size());
|
||||
// Verify EOF PDU was sent.
|
||||
genericEofCheck(fsmResult, expectedFileSize, crcCalc.value(), expectedSeqNum);
|
||||
|
||||
// Verify notice of completion.
|
||||
sourceHandler.stateMachine();
|
||||
genericNoticeOfCompletionCheck(fsmResult, expectedSeqNum);
|
||||
}
|
||||
}
|
@ -110,9 +110,9 @@ TEST_CASE("CFDP Header", "[cfdp]") {
|
||||
}
|
||||
|
||||
SECTION("Other variable sized fields") {
|
||||
pduConf.seqNum.setValue(cfdp::WidthInBytes::TWO_BYTES, 0x0fff);
|
||||
pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00);
|
||||
pduConf.destId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff);
|
||||
pduConf.seqNum.setValueAndWidth(cfdp::WidthInBytes::TWO_BYTES, 0x0fff);
|
||||
pduConf.sourceId.setValueAndWidth(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00);
|
||||
pduConf.destId.setValueAndWidth(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff);
|
||||
REQUIRE(pduConf.sourceId.getSerializedSize() == 4);
|
||||
REQUIRE(creator.getSerializedSize() == 14);
|
||||
REQUIRE(creator.serialize(&serTarget, &serSize, serBuf.size(),
|
||||
@ -146,9 +146,9 @@ TEST_CASE("CFDP Header", "[cfdp]") {
|
||||
}
|
||||
|
||||
SECTION("Buffer Too Short") {
|
||||
pduConf.seqNum.setValue(cfdp::WidthInBytes::TWO_BYTES, 0x0fff);
|
||||
pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00);
|
||||
pduConf.destId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff);
|
||||
pduConf.seqNum.setValueAndWidth(cfdp::WidthInBytes::TWO_BYTES, 0x0fff);
|
||||
pduConf.sourceId.setValueAndWidth(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00);
|
||||
pduConf.destId.setValueAndWidth(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff);
|
||||
for (uint8_t idx = 0; idx < 14; idx++) {
|
||||
REQUIRE(creator.serialize(&serTarget, &serSize, idx, SerializeIF::Endianness::BIG) ==
|
||||
SerializeIF::BUFFER_TOO_SHORT);
|
||||
@ -157,11 +157,11 @@ TEST_CASE("CFDP Header", "[cfdp]") {
|
||||
}
|
||||
|
||||
SECTION("Invalid Variable Sized Fields") {
|
||||
result = pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 0xfff);
|
||||
result = pduConf.sourceId.setValueAndWidth(cfdp::WidthInBytes::ONE_BYTE, 0xfff);
|
||||
REQUIRE(result == returnvalue::FAILED);
|
||||
result = pduConf.sourceId.setValue(cfdp::WidthInBytes::TWO_BYTES, 0xfffff);
|
||||
result = pduConf.sourceId.setValueAndWidth(cfdp::WidthInBytes::TWO_BYTES, 0xfffff);
|
||||
REQUIRE(result == returnvalue::FAILED);
|
||||
result = pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xfffffffff);
|
||||
result = pduConf.sourceId.setValueAndWidth(cfdp::WidthInBytes::FOUR_BYTES, 0xfffffffff);
|
||||
REQUIRE(result == returnvalue::FAILED);
|
||||
}
|
||||
|
||||
@ -207,7 +207,7 @@ TEST_CASE("CFDP Header", "[cfdp]") {
|
||||
SerializeIF::Endianness::MACHINE);
|
||||
REQUIRE(pduConf.sourceId.getValue() == 0xf0f0f0f0);
|
||||
|
||||
pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 1);
|
||||
pduConf.sourceId.setValueAndWidth(cfdp::WidthInBytes::ONE_BYTE, 1);
|
||||
serTarget = serBuf.data();
|
||||
serSize = 1;
|
||||
result = pduConf.sourceId.serialize(&serTarget, &serSize, 1, SerializeIF::Endianness::MACHINE);
|
||||
@ -257,11 +257,11 @@ TEST_CASE("CFDP Header", "[cfdp]") {
|
||||
creator.setSegmentationControl(cfdp::SegmentationControl::RECORD_BOUNDARIES_PRESERVATION);
|
||||
creator.setPduType(cfdp::PduType::FILE_DATA);
|
||||
creator.setSegmentMetadataFlag(cfdp::SegmentMetadataFlag::PRESENT);
|
||||
result = pduConf.seqNum.setValue(cfdp::WidthInBytes::TWO_BYTES, 0x0fff);
|
||||
result = pduConf.seqNum.setValueAndWidth(cfdp::WidthInBytes::TWO_BYTES, 0x0fff);
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
result = pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00);
|
||||
result = pduConf.sourceId.setValueAndWidth(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00);
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
result = pduConf.destId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff);
|
||||
result = pduConf.destId.setValueAndWidth(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff);
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
serTarget = serBuf.data();
|
||||
serSize = 0;
|
||||
@ -302,8 +302,8 @@ TEST_CASE("CFDP Header", "[cfdp]") {
|
||||
SECTION("Manipulate Source Dest ID") {
|
||||
serTarget = serBuf.data();
|
||||
serSize = 0;
|
||||
pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 22);
|
||||
pduConf.destId.setValue(cfdp::WidthInBytes::ONE_BYTE, 48);
|
||||
pduConf.sourceId.setValueAndWidth(cfdp::WidthInBytes::ONE_BYTE, 22);
|
||||
pduConf.destId.setValueAndWidth(cfdp::WidthInBytes::ONE_BYTE, 48);
|
||||
result = creator.serialize(&serTarget, &serSize, serBuf.size(), SerializeIF::Endianness::BIG);
|
||||
reader.getSourceId(sourceDestId);
|
||||
REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::ONE_BYTE);
|
||||
|
@ -14,7 +14,7 @@ TEST_CASE("EOF PDU", "[cfdp][pdu]") {
|
||||
size_t sz = 0;
|
||||
EntityId destId(WidthInBytes::TWO_BYTES, 2);
|
||||
EntityIdTlv faultLoc(destId);
|
||||
FileSize fileSize(12);
|
||||
Fss fileSize(12);
|
||||
// We can already set the fault location, it will be ignored
|
||||
EofInfo eofInfo(cfdp::ConditionCode::NO_ERROR, 5, fileSize, &faultLoc);
|
||||
TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15);
|
||||
|
@ -22,7 +22,7 @@ TEST_CASE("File Data PDU", "[cfdp][pdu]") {
|
||||
for (uint8_t idx = 0; idx < 10; idx++) {
|
||||
fileBuffer[idx] = idx;
|
||||
}
|
||||
FileSize offset(50);
|
||||
Fss offset(50);
|
||||
FileDataInfo info(offset, fileBuffer.data(), 10);
|
||||
|
||||
SECTION("Serialization") {
|
||||
@ -107,8 +107,7 @@ TEST_CASE("File Data PDU", "[cfdp][pdu]") {
|
||||
serializer.serialize(&buffer, &sz, fileDataBuffer.size(), SerializeIF::Endianness::NETWORK);
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
|
||||
FileSize emptyOffset;
|
||||
FileDataInfo emptyInfo(emptyOffset);
|
||||
FileDataInfo emptyInfo;
|
||||
FileDataReader deserializer(fileDataBuffer.data(), fileDataBuffer.size(), emptyInfo);
|
||||
result = deserializer.parseData();
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
|
@ -16,7 +16,7 @@ TEST_CASE("Keep Alive PDU", "[cfdp][pdu]") {
|
||||
EntityId sourceId(WidthInBytes::TWO_BYTES, 1);
|
||||
PduConfig pduConf(sourceId, destId, TransmissionMode::ACKNOWLEDGED, seqNum);
|
||||
|
||||
FileSize progress(0x50);
|
||||
Fss progress(0x50);
|
||||
|
||||
SECTION("Serialize") {
|
||||
KeepAlivePduCreator serializer(pduConf, progress);
|
||||
|
@ -6,11 +6,10 @@
|
||||
#include "fsfw/cfdp/pdu/MetadataPduReader.h"
|
||||
#include "fsfw/cfdp/tlv/FilestoreResponseTlv.h"
|
||||
#include "fsfw/cfdp/tlv/MessageToUserTlv.h"
|
||||
#include "fsfw/globalfunctions/arrayprinter.h"
|
||||
|
||||
TEST_CASE("Metadata PDU", "[cfdp][pdu]") {
|
||||
using namespace cfdp;
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
ReturnValue_t result;
|
||||
std::array<uint8_t, 256> mdBuffer = {};
|
||||
uint8_t* buffer = mdBuffer.data();
|
||||
size_t sz = 0;
|
||||
@ -22,30 +21,22 @@ TEST_CASE("Metadata PDU", "[cfdp][pdu]") {
|
||||
std::string firstFileName = "hello.txt";
|
||||
cfdp::StringLv sourceFileName(firstFileName);
|
||||
cfdp::StringLv destFileName;
|
||||
FileSize fileSize(35);
|
||||
MetadataInfo info(false, ChecksumType::MODULAR, fileSize, sourceFileName, destFileName);
|
||||
Fss fileSize(35);
|
||||
MetadataGenericInfo info(false, ChecksumType::MODULAR, fileSize);
|
||||
|
||||
FilestoreResponseTlv response(FilestoreActionCode::CREATE_DIRECTORY, FSR_CREATE_NOT_ALLOWED,
|
||||
sourceFileName, nullptr);
|
||||
std::array<uint8_t, 3> msg = {0x41, 0x42, 0x43};
|
||||
cfdp::Tlv responseTlv;
|
||||
std::array<uint8_t, 64> responseBuf = {};
|
||||
uint8_t* responseBufPtr = responseBuf.data();
|
||||
response.convertToTlv(responseTlv, buffer, responseBuf.size(), SerializeIF::Endianness::MACHINE);
|
||||
MessageToUserTlv msgToUser(msg.data(), msg.size());
|
||||
std::array<Tlv*, 2> options{&responseTlv, &msgToUser};
|
||||
std::array<Tlv, 5> tlvDeser{};
|
||||
REQUIRE(options[0]->getSerializedSize() == 2 + 1 + 10 + 1);
|
||||
REQUIRE(options[1]->getSerializedSize() == 5);
|
||||
|
||||
SECTION("Serialize") {
|
||||
MetadataPduCreator serializer(pduConf, info);
|
||||
result = serializer.serialize(&buffer, &sz, mdBuffer.size(), SerializeIF::Endianness::NETWORK);
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
REQUIRE(serializer.getWholePduSize() == 27);
|
||||
REQUIRE(info.getSourceFileName().getSerializedSize() == 10);
|
||||
REQUIRE(info.getDestFileName().getSerializedSize() == 1);
|
||||
REQUIRE(info.getSerializedSize() == 16);
|
||||
REQUIRE((mdBuffer[1] << 8 | mdBuffer[2]) == 17);
|
||||
auto metadataCheckPartOne = [&]() {
|
||||
REQUIRE(mdBuffer[10] == FileDirective::METADATA);
|
||||
// no closure requested and checksum type is modular => 0x00
|
||||
REQUIRE(mdBuffer[11] == 0x00);
|
||||
@ -64,20 +55,59 @@ TEST_CASE("Metadata PDU", "[cfdp][pdu]") {
|
||||
REQUIRE(mdBuffer[23] == 't');
|
||||
REQUIRE(mdBuffer[24] == 'x');
|
||||
REQUIRE(mdBuffer[25] == 't');
|
||||
REQUIRE(mdBuffer[26] == 0);
|
||||
};
|
||||
|
||||
SECTION("Serialize with empty dest name") {
|
||||
MetadataPduCreator serializer(pduConf, info, sourceFileName, destFileName, nullptr, 0);
|
||||
result = serializer.serialize(&buffer, &sz, mdBuffer.size(), SerializeIF::Endianness::NETWORK);
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
CHECK(sz == serializer.getSerializedSize());
|
||||
// 10 byte heater + 1 byte PDU directive field + 1 byte PDU content + FSS field (4) + source
|
||||
// name field (10) + dest name field (1).
|
||||
REQUIRE(serializer.getWholePduSize() == 27);
|
||||
REQUIRE(serializer.getSourceFileName().getSerializedSize() == 10);
|
||||
REQUIRE(serializer.getDestFileName().getSerializedSize() == 1);
|
||||
REQUIRE(info.getSerializedSize() == 5);
|
||||
REQUIRE((mdBuffer[1] << 8 | mdBuffer[2]) == 17);
|
||||
REQUIRE(serializer.getSerializedSize() == serializer.getWholePduSize());
|
||||
metadataCheckPartOne();
|
||||
REQUIRE(mdBuffer[26] == 0);
|
||||
}
|
||||
|
||||
SECTION("Serialize with dest name") {
|
||||
std::string secondFileName = "hello2.txt";
|
||||
cfdp::StringLv destFileName2(secondFileName);
|
||||
MetadataPduCreator serializer(pduConf, info, sourceFileName, destFileName2, nullptr, 0);
|
||||
result = serializer.serialize(&buffer, &sz, mdBuffer.size(), SerializeIF::Endianness::NETWORK);
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
// 10 byte heater + 1 byte PDU directive field + 1 byte PDU content + FSS field (4) + source
|
||||
// name field (10) + dest name field (11).
|
||||
REQUIRE(serializer.getWholePduSize() == 37);
|
||||
CHECK(sz == serializer.getSerializedSize());
|
||||
REQUIRE((mdBuffer[1] << 8 | mdBuffer[2]) == 27);
|
||||
REQUIRE(serializer.getSerializedSize() == serializer.getWholePduSize());
|
||||
metadataCheckPartOne();
|
||||
// Size of destination name field
|
||||
REQUIRE(mdBuffer[26] == 10);
|
||||
REQUIRE(mdBuffer[27] == 'h');
|
||||
REQUIRE(mdBuffer[28] == 'e');
|
||||
REQUIRE(mdBuffer[29] == 'l');
|
||||
REQUIRE(mdBuffer[30] == 'l');
|
||||
REQUIRE(mdBuffer[31] == 'o');
|
||||
REQUIRE(mdBuffer[32] == '2');
|
||||
REQUIRE(mdBuffer[33] == '.');
|
||||
REQUIRE(mdBuffer[34] == 't');
|
||||
REQUIRE(mdBuffer[35] == 'x');
|
||||
REQUIRE(mdBuffer[36] == 't');
|
||||
}
|
||||
|
||||
SECTION("Serialize with 2 options") {
|
||||
std::string otherFileName = "hello2.txt";
|
||||
cfdp::StringLv otherFileNameLv(otherFileName.data(), otherFileName.size());
|
||||
info.setSourceFileName(otherFileNameLv);
|
||||
size_t sizeOfOptions = options.size();
|
||||
info.setOptionsArray(options.data(), sizeOfOptions, sizeOfOptions);
|
||||
REQUIRE(info.getMaxOptionsLen() == 2);
|
||||
info.setMaxOptionsLen(3);
|
||||
REQUIRE(info.getMaxOptionsLen() == 3);
|
||||
MetadataPduCreator serializer(pduConf, info, otherFileNameLv, destFileName, options.data(),
|
||||
options.size());
|
||||
info.setChecksumType(cfdp::ChecksumType::CRC_32C);
|
||||
info.setClosureRequested(true);
|
||||
uint8_t* buffer = mdBuffer.data();
|
||||
size_t sz = 0;
|
||||
serializer.updateDirectiveFieldLen();
|
||||
|
||||
result = serializer.serialize(&buffer, &sz, mdBuffer.size(), SerializeIF::Endianness::NETWORK);
|
||||
@ -98,49 +128,47 @@ TEST_CASE("Metadata PDU", "[cfdp][pdu]") {
|
||||
// TLV unittests
|
||||
REQUIRE(sz == 10 + 37);
|
||||
for (size_t maxSz = 0; maxSz < sz; maxSz++) {
|
||||
uint8_t* buffer = mdBuffer.data();
|
||||
size_t sz = 0;
|
||||
buffer = mdBuffer.data();
|
||||
sz = 0;
|
||||
result = serializer.serialize(&buffer, &sz, maxSz, SerializeIF::Endianness::NETWORK);
|
||||
REQUIRE(result == SerializeIF::BUFFER_TOO_SHORT);
|
||||
}
|
||||
for (size_t initSz = 1; initSz < 47; initSz++) {
|
||||
uint8_t* buffer = mdBuffer.data();
|
||||
size_t sz = initSz;
|
||||
buffer = mdBuffer.data();
|
||||
sz = initSz;
|
||||
result = serializer.serialize(&buffer, &sz, 46, SerializeIF::Endianness::NETWORK);
|
||||
REQUIRE(result == SerializeIF::BUFFER_TOO_SHORT);
|
||||
}
|
||||
info.setDestFileName(destFileName);
|
||||
}
|
||||
|
||||
SECTION("Deserialize") {
|
||||
MetadataPduCreator serializer(pduConf, info);
|
||||
MetadataPduCreator serializer(pduConf, info, sourceFileName, destFileName, nullptr, 0);
|
||||
result = serializer.serialize(&buffer, &sz, mdBuffer.size(), SerializeIF::Endianness::NETWORK);
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
|
||||
MetadataPduReader deserializer(mdBuffer.data(), mdBuffer.size(), info);
|
||||
MetadataPduReader deserializer(mdBuffer.data(), mdBuffer.size(), info, nullptr, 0);
|
||||
result = deserializer.parseData();
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
size_t fullSize = deserializer.getWholePduSize();
|
||||
for (size_t maxSz = 0; maxSz < fullSize; maxSz++) {
|
||||
MetadataPduReader invalidSzDeser(mdBuffer.data(), maxSz, info);
|
||||
MetadataPduReader invalidSzDeser(mdBuffer.data(), maxSz, info, nullptr, 0);
|
||||
result = invalidSzDeser.parseData();
|
||||
REQUIRE(result != returnvalue::OK);
|
||||
}
|
||||
size_t sizeOfOptions = options.size();
|
||||
size_t maxSize = 4;
|
||||
info.setOptionsArray(options.data(), sizeOfOptions, maxSize);
|
||||
REQUIRE(info.getOptionsLen() == 2);
|
||||
}
|
||||
|
||||
SECTION("Deserialize with 2 options") {
|
||||
MetadataPduCreator serializer(pduConf, info, sourceFileName, destFileName, options.data(),
|
||||
options.size());
|
||||
info.setChecksumType(cfdp::ChecksumType::CRC_32C);
|
||||
info.setClosureRequested(true);
|
||||
uint8_t* buffer = mdBuffer.data();
|
||||
size_t sz = 0;
|
||||
serializer.updateDirectiveFieldLen();
|
||||
|
||||
info.setSourceFileName(sourceFileName);
|
||||
result = serializer.serialize(&buffer, &sz, mdBuffer.size(), SerializeIF::Endianness::NETWORK);
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
|
||||
MetadataPduReader deserializer2(mdBuffer.data(), mdBuffer.size(), info);
|
||||
MetadataPduReader deserializer2(mdBuffer.data(), mdBuffer.size(), info, tlvDeser.data(),
|
||||
tlvDeser.max_size());
|
||||
result = deserializer2.parseData();
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
REQUIRE(options[0]->getType() == cfdp::TlvType::FILESTORE_RESPONSE);
|
||||
@ -151,12 +179,15 @@ TEST_CASE("Metadata PDU", "[cfdp][pdu]") {
|
||||
for (size_t invalidFieldLen = 0; invalidFieldLen < 36; invalidFieldLen++) {
|
||||
mdBuffer[1] = (invalidFieldLen >> 8) & 0xff;
|
||||
mdBuffer[2] = invalidFieldLen & 0xff;
|
||||
if (invalidFieldLen == 17) {
|
||||
volatile uint32_t dummy = 0;
|
||||
}
|
||||
result = deserializer2.parseData();
|
||||
if (invalidFieldLen == 17) {
|
||||
REQUIRE(info.getOptionsLen() == 0);
|
||||
REQUIRE(deserializer2.getNumberOfParsedOptions() == 0);
|
||||
}
|
||||
if (invalidFieldLen == 31) {
|
||||
REQUIRE(info.getOptionsLen() == 1);
|
||||
REQUIRE(deserializer2.getNumberOfParsedOptions() == 1);
|
||||
}
|
||||
// This is the precise length where there are no options or one option
|
||||
if (invalidFieldLen != 17 and invalidFieldLen != 31) {
|
||||
@ -165,11 +196,25 @@ TEST_CASE("Metadata PDU", "[cfdp][pdu]") {
|
||||
}
|
||||
mdBuffer[1] = (36 >> 8) & 0xff;
|
||||
mdBuffer[2] = 36 & 0xff;
|
||||
info.setOptionsArray(nullptr, std::nullopt, std::nullopt);
|
||||
}
|
||||
|
||||
SECTION("Can not parse options") {
|
||||
MetadataPduCreator serializer(pduConf, info, sourceFileName, destFileName, options.data(),
|
||||
options.size());
|
||||
info.setChecksumType(cfdp::ChecksumType::CRC_32C);
|
||||
info.setClosureRequested(true);
|
||||
buffer = mdBuffer.data();
|
||||
sz = 0;
|
||||
serializer.updateDirectiveFieldLen();
|
||||
|
||||
// info.setSourceFileName(sourceFileName);
|
||||
result = serializer.serialize(&buffer, &sz, mdBuffer.size(), SerializeIF::Endianness::NETWORK);
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
|
||||
MetadataPduReader deserializer2(mdBuffer.data(), mdBuffer.size(), info, nullptr, 0);
|
||||
REQUIRE(deserializer2.parseData() == cfdp::METADATA_CANT_PARSE_OPTIONS);
|
||||
info.setOptionsArray(options.data(), sizeOfOptions, std::nullopt);
|
||||
for (size_t maxSz = 0; maxSz < 46; maxSz++) {
|
||||
MetadataPduReader invalidSzDeser(mdBuffer.data(), maxSz, info);
|
||||
MetadataPduReader invalidSzDeser(mdBuffer.data(), maxSz, info, nullptr, 0);
|
||||
if (not invalidSzDeser.isNull()) {
|
||||
result = invalidSzDeser.parseData();
|
||||
REQUIRE(result == SerializeIF::STREAM_TOO_SHORT);
|
||||
|
@ -17,8 +17,8 @@ TEST_CASE("NAK PDU", "[cfdp][pdu]") {
|
||||
EntityId sourceId(WidthInBytes::TWO_BYTES, 1);
|
||||
PduConfig pduConf(sourceId, destId, TransmissionMode::ACKNOWLEDGED, seqNum);
|
||||
|
||||
FileSize startOfScope(50);
|
||||
FileSize endOfScope(1050);
|
||||
Fss startOfScope(50);
|
||||
Fss endOfScope(1050);
|
||||
NakInfo info(startOfScope, endOfScope);
|
||||
SECTION("Serializer") {
|
||||
NakPduCreator serializer(pduConf, info);
|
||||
@ -40,8 +40,8 @@ TEST_CASE("NAK PDU", "[cfdp][pdu]") {
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
REQUIRE(scope == 1050);
|
||||
|
||||
NakInfo::SegmentRequest segReq0(cfdp::FileSize(2020), cfdp::FileSize(2520));
|
||||
NakInfo::SegmentRequest segReq1(cfdp::FileSize(2932), cfdp::FileSize(3021));
|
||||
NakInfo::SegmentRequest segReq0(cfdp::Fss(2020), cfdp::Fss(2520));
|
||||
NakInfo::SegmentRequest segReq1(cfdp::Fss(2932), cfdp::Fss(3021));
|
||||
// Now add 2 segment requests to NAK info and serialize them as well
|
||||
std::array<NakInfo::SegmentRequest, 2> segReqs = {segReq0, segReq1};
|
||||
size_t segReqsLen = segReqs.size();
|
||||
@ -100,8 +100,8 @@ TEST_CASE("NAK PDU", "[cfdp][pdu]") {
|
||||
REQUIRE(info.getStartOfScope().getSize() == 50);
|
||||
REQUIRE(info.getEndOfScope().getSize() == 1050);
|
||||
|
||||
NakInfo::SegmentRequest segReq0(cfdp::FileSize(2020), cfdp::FileSize(2520));
|
||||
NakInfo::SegmentRequest segReq1(cfdp::FileSize(2932), cfdp::FileSize(3021));
|
||||
NakInfo::SegmentRequest segReq0(cfdp::Fss(2020), cfdp::Fss(2520));
|
||||
NakInfo::SegmentRequest segReq1(cfdp::Fss(2932), cfdp::Fss(3021));
|
||||
// Now add 2 segment requests to NAK info and serialize them as well
|
||||
std::array<NakInfo::SegmentRequest, 2> segReqs = {segReq0, segReq1};
|
||||
size_t segReqsLen = segReqs.size();
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <cstring>
|
||||
|
||||
#include "fsfw/cfdp/FileSize.h"
|
||||
#include "fsfw/cfdp/Fss.h"
|
||||
#include "fsfw/cfdp/pdu/FileDirectiveCreator.h"
|
||||
#include "fsfw/cfdp/pdu/FileDirectiveReader.h"
|
||||
#include "fsfw/globalfunctions/arrayprinter.h"
|
||||
@ -79,7 +79,7 @@ TEST_CASE("CFDP Base", "[cfdp]") {
|
||||
std::array<uint8_t, 8> fssBuf = {};
|
||||
uint8_t* buffer = fssBuf.data();
|
||||
size_t size = 0;
|
||||
cfdp::FileSize fss;
|
||||
cfdp::Fss fss;
|
||||
REQUIRE(fss.getSize() == 0);
|
||||
fss.setFileSize(0x20, false);
|
||||
result = fss.serialize(&buffer, &size, fssBuf.size(), SerializeIF::Endianness::MACHINE);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user