Added CFDP packet stack

This PR adds the packet stack for the CCSDS File Delivery Protocol.
It also refactors the existing TMTC infastructure to allow sending
of CFDP packets to the CCSDS handlers.

This includes the whole PDU (Protocol Data Unit) stack:

- File Data PDUs

and all file directive PDUs

- ACK PDU
- NAK PDU
- Metadata PDU
- Finished PDU
- Prompt PDU
- Keep Alive PDU
- EOF PDU

The PR includes a full set of unittests for the packet stack
with a coverage of 90+ %.

The refactoring of the existing TMTC infastructure includes non-ideal
solutions like diamond inheritance.
Avoiding this solution would require refactoring the packet stack.
This would be a good idea anyway because the existing stack is tightly
coupled to the FSFW, making reuse more difficult if only the stack is
planned to be used without the store functionalities etc.

The PDU implementation provided here is only weakly coupled to the FSFW,
only using components like returnvalues or the Serialization modules.
There are dedicated serializers and deserializers, which also helps in
creating small focused modules which are easy to test.

Some of the modules here were provied by Matthias Tompert.
This commit is contained in:
Robin Müller 2021-12-03 15:37:49 +01:00
parent bf31248a50
commit 5907f8ee9d
No known key found for this signature in database
GPG Key ID: 11D4952C8CCEF814
167 changed files with 7801 additions and 1121 deletions

View File

@ -189,13 +189,13 @@ if(FSFW_BUILD_UNITTESTS)
"--exclude-unreachable-branches"
)
set(COVERAGE_EXCLUDES
"/c/msys64/mingw64/*"
"/c/msys64/mingw64/*" "*/fsfw_hal/*"
)
elseif(UNIX)
set(COVERAGE_EXCLUDES
"/usr/include/*" "/usr/bin/*" "Catch2/*"
"/usr/local/include/*" "*/fsfw_tests/*"
"*/catch2-src/*"
"*/catch2-src/*" "*/fsfw_hal/*"
)
endif()

View File

@ -91,7 +91,7 @@ You can use the following commands inside the `fsfw` folder to set up the build
```sh
mkdir build-Unittest && cd build-Unittest
cmake -DFSFW_BUILD_UNITTESTS=ON -DFSFW_OSAL=host ..
cmake -DFSFW_BUILD_UNITTESTS=ON -DFSFW_OSAL=host -DCMAKE_BUILD_TYPE=Debug ..
```
You can also use `-DFSFW_OSAL=linux` on Linux systems.

View File

@ -10,7 +10,7 @@
*/
namespace addresses {
/* Logical addresses have uint32_t datatype */
enum logicalAddresses: address_t {
enum LogAddr: address_t {
};
}

View File

@ -1,6 +1,7 @@
# Core
add_subdirectory(action)
add_subdirectory(cfdp)
add_subdirectory(container)
add_subdirectory(controller)
add_subdirectory(datapool)

View File

@ -42,6 +42,10 @@
#define FSFW_USE_PUS_C_TELECOMMANDS 1
#endif
#ifndef FSFW_TCP_RECV_WIRETAPPING_ENABLED
#define FSFW_TCP_RECV_WIRETAPPING_ENABLED 0
#endif
// FSFW HAL defines
// Can be used for low-level debugging of the SPI bus

View File

@ -0,0 +1,60 @@
#include "fsfw/ipc/CommandMessage.h"
#include "fsfw/storagemanager/storeAddress.h"
#include "fsfw/cfdp/CFDPHandler.h"
#include "fsfw/cfdp/CFDPMessage.h"
#include "fsfw/tmtcservices/AcceptsTelemetryIF.h"
#include "fsfw/ipc/QueueFactory.h"
#include "fsfw/objectmanager/ObjectManager.h"
object_id_t CFDPHandler::packetSource = 0;
object_id_t CFDPHandler::packetDestination = 0;
CFDPHandler::CFDPHandler(object_id_t setObjectId, CFDPDistributor* dist) : SystemObject(setObjectId) {
requestQueue = QueueFactory::instance()->createMessageQueue(CFDP_HANDLER_MAX_RECEPTION);
distributor = dist;
}
CFDPHandler::~CFDPHandler() {}
ReturnValue_t CFDPHandler::initialize() {
ReturnValue_t result = SystemObject::initialize();
if (result != RETURN_OK) {
return result;
}
this->distributor->registerHandler(this);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t CFDPHandler::handleRequest(store_address_t storeId) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "CFDPHandler::handleRequest" << std::endl;
#else
sif::printDebug("CFDPHandler::handleRequest\n");
#endif /* !FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif
//TODO read out packet from store using storeId
return RETURN_OK;
}
ReturnValue_t CFDPHandler::performOperation(uint8_t opCode) {
ReturnValue_t status = RETURN_OK;
CommandMessage currentMessage;
for (status = this->requestQueue->receiveMessage(&currentMessage); status == RETURN_OK;
status = this->requestQueue->receiveMessage(&currentMessage)) {
store_address_t storeId = CFDPMessage::getStoreId(&currentMessage);
this->handleRequest(storeId);
}
return RETURN_OK;
}
uint16_t CFDPHandler::getIdentifier() {
return 0;
}
MessageQueueId_t CFDPHandler::getRequestQueue() {
return this->requestQueue->getId();
}

View File

@ -0,0 +1,62 @@
#ifndef FSFW_CFDP_CFDPHANDLER_H_
#define FSFW_CFDP_CFDPHANDLER_H_
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
#include "fsfw/objectmanager/SystemObject.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
#include "fsfw/tasks/ExecutableObjectIF.h"
#include "fsfw/tcdistribution/CFDPDistributor.h"
#include "fsfw/ipc/MessageQueueIF.h"
namespace Factory{
void setStaticFrameworkObjectIds();
}
class CFDPHandler :
public ExecutableObjectIF,
public AcceptsTelecommandsIF,
public SystemObject,
public HasReturnvaluesIF {
friend void (Factory::setStaticFrameworkObjectIds)();
public:
CFDPHandler(object_id_t setObjectId, CFDPDistributor* distributor);
/**
* The destructor is empty.
*/
virtual ~CFDPHandler();
virtual ReturnValue_t handleRequest(store_address_t storeId);
virtual ReturnValue_t initialize() override;
virtual uint16_t getIdentifier() override;
MessageQueueId_t getRequestQueue() override;
ReturnValue_t performOperation(uint8_t opCode) override;
protected:
/**
* This is a complete instance of the telecommand reception queue
* of the class. It is initialized on construction of the class.
*/
MessageQueueIF* requestQueue = nullptr;
CFDPDistributor* distributor = nullptr;
/**
* The current CFDP packet to be processed.
* It is deleted after handleRequest was executed.
*/
CFDPPacketStored currentPacket;
static object_id_t packetSource;
static object_id_t packetDestination;
private:
/**
* This constant sets the maximum number of packets accepted per call.
* Remember that one packet must be completely handled in one
* #handleRequest call.
*/
static const uint8_t CFDP_HANDLER_MAX_RECEPTION = 100;
};
#endif /* FSFW_CFDP_CFDPHANDLER_H_ */

View File

@ -0,0 +1,21 @@
#include "CFDPMessage.h"
CFDPMessage::CFDPMessage() {
}
CFDPMessage::~CFDPMessage() {
}
void CFDPMessage::setCommand(CommandMessage *message,
store_address_t cfdpPacket) {
message->setParameter(cfdpPacket.raw);
}
store_address_t CFDPMessage::getStoreId(const CommandMessage *message) {
store_address_t storeAddressCFDPPacket;
storeAddressCFDPPacket = message->getParameter();
return storeAddressCFDPPacket;
}
void CFDPMessage::clear(CommandMessage *message) {
}

View File

@ -0,0 +1,23 @@
#ifndef FSFW_CFDP_CFDPMESSAGE_H_
#define FSFW_CFDP_CFDPMESSAGE_H_
#include "fsfw/ipc/CommandMessage.h"
#include "fsfw/objectmanager/ObjectManagerIF.h"
#include "fsfw/storagemanager/StorageManagerIF.h"
class CFDPMessage {
private:
CFDPMessage();
public:
static const uint8_t MESSAGE_ID = messagetypes::CFDP;
virtual ~CFDPMessage();
static void setCommand(CommandMessage* message,
store_address_t cfdpPacket);
static store_address_t getStoreId(const CommandMessage* message);
static void clear(CommandMessage* message);
};
#endif /* FSFW_CFDP_CFDPMESSAGE_H_ */

View File

@ -0,0 +1,7 @@
target_sources(${LIB_FSFW_NAME} PRIVATE
CFDPHandler.cpp
CFDPMessage.cpp
)
add_subdirectory(pdu)
add_subdirectory(tlv)

83
src/fsfw/cfdp/FileSize.h Normal file
View File

@ -0,0 +1,83 @@
#ifndef FSFW_SRC_FSFW_CFDP_FILESIZE_H_
#define FSFW_SRC_FSFW_CFDP_FILESIZE_H_
#include "fsfw/serialize/SerializeAdapter.h"
#include "fsfw/serialize/SerializeIF.h"
namespace cfdp {
struct FileSize: public SerializeIF {
public:
FileSize(): largeFile(false) {};
FileSize(uint64_t fileSize, bool isLarge = false) {
setFileSize(fileSize, isLarge);
};
ReturnValue_t serialize(bool isLarge, uint8_t **buffer, size_t *size,size_t maxSize,
Endianness streamEndianness) {
this->largeFile = isLarge;
return serialize(buffer, size, maxSize, streamEndianness);
}
ReturnValue_t serialize(uint8_t **buffer, size_t *size,size_t maxSize,
Endianness streamEndianness) const override {
if(not largeFile) {
uint32_t fileSizeTyped = fileSize;
return SerializeAdapter::serialize(&fileSizeTyped, buffer, size, maxSize,
streamEndianness);
}
return SerializeAdapter::serialize(&fileSize, buffer, size, maxSize, streamEndianness);
}
size_t getSerializedSize() const override {
if (largeFile) {
return 8;
} else {
return 4;
}
}
ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
Endianness streamEndianness) override {
if(largeFile) {
return SerializeAdapter::deSerialize(&size, buffer, size, streamEndianness);
} else {
uint32_t sizeTmp = 0;
ReturnValue_t result = SerializeAdapter::deSerialize(&sizeTmp, buffer, size,
streamEndianness);
if(result == HasReturnvaluesIF::RETURN_OK) {
fileSize = sizeTmp;
}
return result;
}
}
ReturnValue_t setFileSize(uint64_t fileSize, bool largeFile) {
if (not largeFile and fileSize > UINT32_MAX) {
// TODO: emit warning here
return HasReturnvaluesIF::RETURN_FAILED;
}
this->fileSize = fileSize;
this->largeFile = largeFile;
return HasReturnvaluesIF::RETURN_OK;
}
bool isLargeFile() const {
return largeFile;
}
uint64_t getSize(bool* largeFile = nullptr) const {
if(largeFile != nullptr) {
*largeFile = this->largeFile;
}
return fileSize;
}
private:
uint64_t fileSize = 0;
bool largeFile = false;
};
}
#endif /* FSFW_SRC_FSFW_CFDP_FILESIZE_H_ */

153
src/fsfw/cfdp/definitions.h Normal file
View File

@ -0,0 +1,153 @@
#ifndef FSFW_SRC_FSFW_CFDP_PDU_DEFINITIONS_H_
#define FSFW_SRC_FSFW_CFDP_PDU_DEFINITIONS_H_
#include <fsfw/serialize/SerializeIF.h>
#include <cstdint>
#include <cstddef>
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
#include "fsfw/returnvalues/FwClassIds.h"
namespace cfdp {
static constexpr uint8_t VERSION_BITS = 0b00100000;
static constexpr uint8_t CFDP_CLASS_ID = CLASS_ID::CFDP;
static constexpr ReturnValue_t INVALID_TLV_TYPE =
HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 1);
static constexpr ReturnValue_t INVALID_DIRECTIVE_FIELDS =
HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 2);
static constexpr ReturnValue_t INVALID_PDU_DATAFIELD_LEN =
HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 3);
static constexpr ReturnValue_t INVALID_ACK_DIRECTIVE_FIELDS =
HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 4);
//! Can not parse options. This can also occur because there are options
//! available but the user did not pass a valid options array
static constexpr ReturnValue_t METADATA_CANT_PARSE_OPTIONS =
HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 5);
static constexpr ReturnValue_t NAK_CANT_PARSE_OPTIONS =
HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 6);
static constexpr ReturnValue_t FINISHED_CANT_PARSE_FS_RESPONSES =
HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 6);
static constexpr ReturnValue_t FILESTORE_REQUIRES_SECOND_FILE =
HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 8);
//! Can not parse filestore response because user did not pass a valid instance
//! or remaining size is invalid
static constexpr ReturnValue_t FILESTORE_RESPONSE_CANT_PARSE_FS_MESSAGE =
HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 9);
//! Checksum types according to the SANA Checksum Types registry
//! https://sanaregistry.org/r/checksum_identifiers/
enum ChecksumType {
// Modular legacy checksum
MODULAR = 0,
CRC_32_PROXIMITY_1 = 1,
CRC_32C = 2,
CRC_32 = 3,
NULL_CHECKSUM = 15
};
enum PduType: bool {
FILE_DIRECTIVE = 0,
FILE_DATA = 1
};
enum TransmissionModes: bool {
ACKNOWLEDGED = 0,
UNACKNOWLEDGED = 1
};
enum SegmentMetadataFlag: bool {
NOT_PRESENT = 0,
PRESENT = 1
};
enum Direction: bool {
TOWARDS_RECEIVER = 0,
TOWARDS_SENDER = 1
};
enum SegmentationControl: bool {
NO_RECORD_BOUNDARIES_PRESERVATION = 0,
RECORD_BOUNDARIES_PRESERVATION = 1
};
enum WidthInBytes: uint8_t {
// Only those are supported for now
ONE_BYTE = 1,
TWO_BYTES = 2,
FOUR_BYTES = 4,
};
enum FileDirectives: uint8_t {
INVALID_DIRECTIVE = 0x0f,
EOF_DIRECTIVE = 0x04,
FINISH = 0x05,
ACK = 0x06,
METADATA = 0x07,
NAK = 0x08,
PROMPT = 0x09,
KEEP_ALIVE = 0x0c
};
enum ConditionCode: uint8_t {
NO_CONDITION_FIELD = 0xff,
NO_ERROR = 0b0000,
POSITIVE_ACK_LIMIT_REACHED = 0b0001,
KEEP_ALIVE_LIMIT_REACHED = 0b0010,
INVALID_TRANSMISSION_MODE = 0b0011,
FILESTORE_REJECTION = 0b0100,
FILE_CHECKSUM_FAILURE = 0b0101,
FILE_SIZE_ERROR = 0b0110,
NAK_LIMIT_REACHED = 0b0111,
INACTIVITY_DETECTED = 0b1000,
CHECK_LIMIT_REACHED = 0b1010,
UNSUPPORTED_CHECKSUM_TYPE = 0b1011,
SUSPEND_REQUEST_RECEIVED = 0b1110,
CANCEL_REQUEST_RECEIVED = 0b1111
};
enum AckTransactionStatus {
UNDEFINED = 0b00,
ACTIVE = 0b01,
TERMINATED = 0b10,
UNRECOGNIZED = 0b11
};
enum FinishedDeliveryCode {
DATA_COMPLETE = 0,
DATA_INCOMPLETE = 1
};
enum FinishedFileStatus {
DISCARDED_DELIBERATELY = 0,
DISCARDED_FILESTORE_REJECTION = 1,
RETAINED_IN_FILESTORE = 2,
FILE_STATUS_UNREPORTED = 3
};
enum PromptResponseRequired: bool {
PROMPT_NAK = 0,
PROMPT_KEEP_ALIVE = 1
};
enum TlvTypes: uint8_t {
FILESTORE_REQUEST = 0x00,
FILESTORE_RESPONSE = 0x01,
MSG_TO_USER = 0x02,
FAULT_HANDLER = 0x04,
FLOW_LABEL = 0x05,
ENTITY_ID = 0x06,
INVALID_TLV = 0xff,
};
enum RecordContinuationState {
NO_START_NO_END = 0b00,
CONTAINS_START_NO_END = 0b01,
CONTAINS_END_NO_START = 0b10,
CONTAINS_START_AND_END = 0b11
};
}
#endif /* FSFW_SRC_FSFW_CFDP_PDU_DEFINITIONS_H_ */

View File

@ -0,0 +1,52 @@
#include "AckInfo.h"
AckInfo::AckInfo(cfdp::FileDirectives ackedDirective, cfdp::ConditionCode ackedConditionCode,
cfdp::AckTransactionStatus transactionStatus, uint8_t directiveSubtypeCode):
ackedDirective(ackedDirective), ackedConditionCode(ackedConditionCode),
transactionStatus(transactionStatus), directiveSubtypeCode(directiveSubtypeCode) {
if (ackedDirective == cfdp::FileDirectives::FINISH) {
this->directiveSubtypeCode = 0b0001;
} else {
this->directiveSubtypeCode = 0b0000;
}
}
cfdp::ConditionCode AckInfo::getAckedConditionCode() const {
return ackedConditionCode;
}
void AckInfo::setAckedConditionCode(cfdp::ConditionCode ackedConditionCode) {
this->ackedConditionCode = ackedConditionCode;
if (ackedDirective == cfdp::FileDirectives::FINISH) {
this->directiveSubtypeCode = 0b0001;
} else {
this->directiveSubtypeCode = 0b0000;
}
}
cfdp::FileDirectives AckInfo::getAckedDirective() const {
return ackedDirective;
}
void AckInfo::setAckedDirective(cfdp::FileDirectives ackedDirective) {
this->ackedDirective = ackedDirective;
}
uint8_t AckInfo::getDirectiveSubtypeCode() const {
return directiveSubtypeCode;
}
void AckInfo::setDirectiveSubtypeCode(uint8_t directiveSubtypeCode) {
this->directiveSubtypeCode = directiveSubtypeCode;
}
cfdp::AckTransactionStatus AckInfo::getTransactionStatus() const {
return transactionStatus;
}
AckInfo::AckInfo() {
}
void AckInfo::setTransactionStatus(cfdp::AckTransactionStatus transactionStatus) {
this->transactionStatus = transactionStatus;
}

View File

@ -0,0 +1,33 @@
#ifndef FSFW_SRC_FSFW_CFDP_PDU_ACKINFO_H_
#define FSFW_SRC_FSFW_CFDP_PDU_ACKINFO_H_
#include "../definitions.h"
class AckInfo {
public:
AckInfo();
AckInfo(cfdp::FileDirectives ackedDirective, cfdp::ConditionCode ackedConditionCode,
cfdp::AckTransactionStatus transactionStatus, uint8_t directiveSubtypeCode = 0);
cfdp::ConditionCode getAckedConditionCode() const;
void setAckedConditionCode(cfdp::ConditionCode ackedConditionCode);
cfdp::FileDirectives getAckedDirective() const;
void setAckedDirective(cfdp::FileDirectives ackedDirective);
uint8_t getDirectiveSubtypeCode() const;
void setDirectiveSubtypeCode(uint8_t directiveSubtypeCode);
cfdp::AckTransactionStatus getTransactionStatus() const;
void setTransactionStatus(cfdp::AckTransactionStatus transactionStatus);
private:
cfdp::FileDirectives ackedDirective = cfdp::FileDirectives::INVALID_DIRECTIVE;
cfdp::ConditionCode ackedConditionCode = cfdp::ConditionCode::NO_CONDITION_FIELD;
cfdp::AckTransactionStatus transactionStatus = cfdp::AckTransactionStatus::UNDEFINED;
uint8_t directiveSubtypeCode = 0;
};
#endif /* FSFW_SRC_FSFW_CFDP_PDU_ACKINFO_H_ */

View File

@ -0,0 +1,38 @@
#include "AckPduDeserializer.h"
AckPduDeserializer::AckPduDeserializer(const uint8_t *pduBuf, size_t maxSize, AckInfo& info):
FileDirectiveDeserializer(pduBuf, maxSize), info(info) {
}
ReturnValue_t AckPduDeserializer::parseData() {
ReturnValue_t result = FileDirectiveDeserializer::parseData();
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
size_t currentIdx = FileDirectiveDeserializer::getHeaderSize();
if (currentIdx + 2 > this->maxSize) {
return SerializeIF::BUFFER_TOO_SHORT;
}
if(not checkAndSetCodes(rawPtr[currentIdx], rawPtr[currentIdx + 1])) {
return cfdp::INVALID_ACK_DIRECTIVE_FIELDS;
}
return HasReturnvaluesIF::RETURN_OK;
}
bool AckPduDeserializer::checkAndSetCodes(uint8_t firstByte, uint8_t secondByte) {
uint8_t ackedDirective = static_cast<cfdp::FileDirectives>(firstByte >> 4);
if(ackedDirective != cfdp::FileDirectives::EOF_DIRECTIVE and
ackedDirective != cfdp::FileDirectives::FINISH) {
return false;
}
this->info.setAckedDirective(static_cast<cfdp::FileDirectives>(ackedDirective));
uint8_t directiveSubtypeCode = firstByte & 0x0f;
if(directiveSubtypeCode != 0b0000 and directiveSubtypeCode != 0b0001) {
return false;
}
this->info.setDirectiveSubtypeCode(directiveSubtypeCode);
this->info.setAckedConditionCode(static_cast<cfdp::ConditionCode>(secondByte >> 4));
this->info.setTransactionStatus(static_cast<cfdp::AckTransactionStatus>(secondByte & 0x0f));
return true;
}

View File

@ -0,0 +1,26 @@
#ifndef FSFW_SRC_FSFW_CFDP_PDU_ACKPDUDESERIALIZER_H_
#define FSFW_SRC_FSFW_CFDP_PDU_ACKPDUDESERIALIZER_H_
#include "fsfw/cfdp/pdu/FileDirectiveDeserializer.h"
#include "AckInfo.h"
class AckPduDeserializer: public FileDirectiveDeserializer {
public:
AckPduDeserializer(const uint8_t* pduBuf, size_t maxSize, AckInfo& info);
/**
*
* @return
* - cfdp::INVALID_DIRECTIVE_FIELDS: Invalid fields
*/
ReturnValue_t parseData();
private:
bool checkAndSetCodes(uint8_t rawAckedByte, uint8_t rawAckedConditionCode);
AckInfo& info;
};
#endif /* FSFW_SRC_FSFW_CFDP_PDU_ACKPDUDESERIALIZER_H_ */

View File

@ -0,0 +1,38 @@
#include "AckPduSerializer.h"
AckPduSerializer::AckPduSerializer(AckInfo& ackInfo, PduConfig &pduConf):
FileDirectiveSerializer(pduConf, cfdp::FileDirectives::ACK, 2),
ackInfo(ackInfo) {
}
size_t AckPduSerializer::getSerializedSize() const {
return FileDirectiveSerializer::getWholePduSize();
}
ReturnValue_t AckPduSerializer::serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const {
ReturnValue_t result = FileDirectiveSerializer::serialize(buffer, size, maxSize,
streamEndianness);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
cfdp::FileDirectives ackedDirective = ackInfo.getAckedDirective();
uint8_t directiveSubtypeCode = ackInfo.getDirectiveSubtypeCode();
cfdp::ConditionCode ackedConditionCode = ackInfo.getAckedConditionCode();
cfdp::AckTransactionStatus transactionStatus = ackInfo.getTransactionStatus();
if(ackedDirective != cfdp::FileDirectives::FINISH and
ackedDirective != cfdp::FileDirectives::EOF_DIRECTIVE) {
// TODO: better returncode
return HasReturnvaluesIF::RETURN_FAILED;
}
if(*size + 2 > maxSize) {
return SerializeIF::BUFFER_TOO_SHORT;
}
**buffer = ackedDirective << 4 | directiveSubtypeCode;
*buffer += 1;
*size += 1;
**buffer = ackedConditionCode << 4 | transactionStatus;
*buffer += 1;
*size += 1;
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -0,0 +1,30 @@
#ifndef FSFW_SRC_FSFW_CFDP_PDU_ACKPDUSERIALIZER_H_
#define FSFW_SRC_FSFW_CFDP_PDU_ACKPDUSERIALIZER_H_
#include "AckInfo.h"
#include "FileDirectiveDeserializer.h"
#include "FileDirectiveSerializer.h"
class AckPduSerializer: public FileDirectiveSerializer {
public:
/**
* @brief Serializer to pack ACK PDUs
* @details
* Please note that only Finished PDUs and EOF are acknowledged.
* @param ackedDirective
* @param ackedConditionCode
* @param transactionStatus
* @param pduConf
*/
AckPduSerializer(AckInfo& ackInfo, PduConfig& pduConf);
size_t getSerializedSize() const override;
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
Endianness streamEndianness) const override;
private:
AckInfo& ackInfo;
};
#endif /* FSFW_SRC_FSFW_CFDP_PDU_ACKPDUSERIALIZER_H_ */

View File

@ -0,0 +1,32 @@
target_sources(${LIB_FSFW_NAME} PRIVATE
PduConfig.cpp
VarLenField.cpp
HeaderSerializer.cpp
HeaderDeserializer.cpp
FileDirectiveDeserializer.cpp
FileDirectiveSerializer.cpp
AckInfo.cpp
AckPduSerializer.cpp
AckPduDeserializer.cpp
EofInfo.cpp
EofPduSerializer.cpp
EofPduDeserializer.cpp
NakInfo.cpp
NakPduSerializer.cpp
NakPduDeserializer.cpp
FinishedInfo.cpp
FinishedPduSerializer.cpp
FinishedPduDeserializer.cpp
MetadataInfo.cpp
MetadataPduSerializer.cpp
MetadataPduDeserializer.cpp
KeepAlivePduSerializer.cpp
KeepAlivePduDeserializer.cpp
PromptPduSerializer.cpp
PromptPduDeserializer.cpp
FileDataSerializer.cpp
FileDataDeserializer.cpp
FileDataInfo.cpp
)

View File

@ -0,0 +1,58 @@
#include "EofInfo.h"
EofInfo::EofInfo(cfdp::ConditionCode conditionCode, uint32_t checksum, cfdp::FileSize fileSize,
EntityIdTlv* faultLoc): conditionCode(conditionCode), checksum(checksum),
fileSize(fileSize), faultLoc(faultLoc) {
}
EofInfo::EofInfo(EntityIdTlv *faultLoc): conditionCode(cfdp::ConditionCode::NO_CONDITION_FIELD),
checksum(0), fileSize(0), faultLoc(faultLoc) {
}
uint32_t EofInfo::getChecksum() const {
return checksum;
}
cfdp::ConditionCode EofInfo::getConditionCode() const {
return conditionCode;
}
EntityIdTlv* EofInfo::getFaultLoc() const {
return faultLoc;
}
cfdp::FileSize& EofInfo::getFileSize() {
return fileSize;
}
void EofInfo::setChecksum(uint32_t checksum) {
this->checksum = checksum;
}
void EofInfo::setConditionCode(cfdp::ConditionCode conditionCode) {
this->conditionCode = conditionCode;
}
void EofInfo::setFaultLoc(EntityIdTlv *faultLoc) {
this->faultLoc = faultLoc;
}
size_t EofInfo::getSerializedSize(bool fssLarge) {
// Condition code + spare + 4 byte checksum
size_t size = 5;
if(fssLarge) {
size += 8;
} else {
size += 4;
}
// Do not account for fault location if the condition code is NO_ERROR. We assume that
// a serializer will not serialize the fault location here.
if(getFaultLoc() != nullptr and getConditionCode() != cfdp::ConditionCode::NO_ERROR) {
size+= faultLoc->getSerializedSize();
}
return size;
}
ReturnValue_t EofInfo::setFileSize(size_t fileSize, bool isLarge) {
return this->fileSize.setFileSize(fileSize, isLarge);
}

View File

@ -0,0 +1,33 @@
#ifndef FSFW_SRC_FSFW_CFDP_PDU_EOFINFO_H_
#define FSFW_SRC_FSFW_CFDP_PDU_EOFINFO_H_
#include "fsfw/cfdp/tlv/EntityIdTlv.h"
#include "../definitions.h"
#include "../FileSize.h"
struct EofInfo {
public:
EofInfo(EntityIdTlv* faultLoc = nullptr);
EofInfo(cfdp::ConditionCode conditionCode, uint32_t checksum, cfdp::FileSize fileSize,
EntityIdTlv* faultLoc = nullptr);
size_t getSerializedSize(bool fssLarge = false);
uint32_t getChecksum() const;
cfdp::ConditionCode getConditionCode() const;
EntityIdTlv* getFaultLoc() const;
cfdp::FileSize& getFileSize();
void setChecksum(uint32_t checksum);
void setConditionCode(cfdp::ConditionCode conditionCode);
void setFaultLoc(EntityIdTlv *faultLoc);
ReturnValue_t setFileSize(size_t size, bool isLarge);
private:
cfdp::ConditionCode conditionCode;
uint32_t checksum;
cfdp::FileSize fileSize;
EntityIdTlv* faultLoc = nullptr;
};
#endif /* FSFW_SRC_FSFW_CFDP_PDU_EOFINFO_H_ */

View File

@ -0,0 +1,68 @@
#include "EofPduDeserializer.h"
#include "fsfw/FSFW.h"
#include "fsfw/serviceinterface.h"
EofPduDeserializer::EofPduDeserializer(const uint8_t *pduBuf, size_t maxSize, EofInfo& eofInfo):
FileDirectiveDeserializer(pduBuf, maxSize), info(eofInfo) {
}
ReturnValue_t EofPduDeserializer::parseData() {
ReturnValue_t result = FileDirectiveDeserializer::parseData();
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
const uint8_t* bufPtr = rawPtr;
size_t expectedFileFieldLen = 4;
if(this->getLargeFileFlag()) {
expectedFileFieldLen = 8;
}
size_t currentIdx = FileDirectiveDeserializer::getHeaderSize();
size_t deserLen = maxSize;
if(maxSize < currentIdx + 5 + expectedFileFieldLen) {
return SerializeIF::STREAM_TOO_SHORT;
}
bufPtr += currentIdx;
deserLen -= currentIdx;
info.setConditionCode(static_cast<cfdp::ConditionCode>(*bufPtr >> 4));
bufPtr += 1;
deserLen -= 1;
uint32_t checksum = 0;
auto endianness = getEndianness();
result = SerializeAdapter::deSerialize(&checksum, &bufPtr, &deserLen, endianness);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
info.setChecksum(checksum);
if(this->getLargeFileFlag()) {
uint64_t fileSizeValue = 0;
result = SerializeAdapter::deSerialize(&fileSizeValue, &bufPtr, &deserLen, endianness);
info.setFileSize(fileSizeValue, true);
}
else {
uint32_t fileSizeValue = 0;
result = SerializeAdapter::deSerialize(&fileSizeValue, &bufPtr, &deserLen, endianness);
info.setFileSize(fileSizeValue, false);
}
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
if(info.getConditionCode() != cfdp::ConditionCode::NO_ERROR) {
EntityIdTlv* tlvPtr = info.getFaultLoc();
if(tlvPtr == nullptr) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "EofPduDeserializer::parseData: Ca not deserialize fault location,"
" given TLV pointer invalid" << std::endl;
#else
sif::printWarning("EofPduDeserializer::parseData: Ca not deserialize fault location,"
" given TLV pointer invalid");
#endif
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return HasReturnvaluesIF::RETURN_FAILED;
}
result = tlvPtr->deSerialize(&bufPtr, &deserLen, endianness);
}
return result;
}

View File

@ -0,0 +1,18 @@
#ifndef FSFW_SRC_FSFW_CFDP_PDU_EOFPDUDESERIALIZER_H_
#define FSFW_SRC_FSFW_CFDP_PDU_EOFPDUDESERIALIZER_H_
#include "fsfw/cfdp/pdu/FileDirectiveDeserializer.h"
#include "EofInfo.h"
class EofPduDeserializer: public FileDirectiveDeserializer {
public:
EofPduDeserializer(const uint8_t* pduBuf, size_t maxSize, EofInfo& eofInfo);
virtual ReturnValue_t parseData() override;
private:
EofInfo& info;
};
#endif /* FSFW_SRC_FSFW_CFDP_PDU_EOFPDUDESERIALIZER_H_ */

View File

@ -0,0 +1,46 @@
#include "fsfw/FSFW.h"
#include "fsfw/serviceinterface.h"
#include "EofPduSerializer.h"
EofPduSerializer::EofPduSerializer(PduConfig &conf, EofInfo& info):
FileDirectiveSerializer(conf, cfdp::FileDirectives::EOF_DIRECTIVE, 9), info(info) {
setDirectiveDataFieldLen(info.getSerializedSize(getLargeFileFlag()));
}
size_t EofPduSerializer::getSerializedSize() const {
return FileDirectiveSerializer::getWholePduSize();
}
ReturnValue_t EofPduSerializer::serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const {
ReturnValue_t result = FileDirectiveSerializer::serialize(buffer, size, maxSize,
streamEndianness);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
if(*size + 1 > maxSize) {
return SerializeIF::BUFFER_TOO_SHORT;
}
**buffer = info.getConditionCode() << 4;
*buffer += 1;
*size += 1;
uint32_t checksum = info.getChecksum();
result = SerializeAdapter::serialize(&checksum, buffer, size, maxSize, streamEndianness);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
if(info.getFileSize().isLargeFile()) {
uint64_t fileSizeValue = info.getFileSize().getSize();
result = SerializeAdapter::serialize(&fileSizeValue, buffer, size,
maxSize, streamEndianness);
}
else {
uint32_t fileSizeValue = info.getFileSize().getSize();
result = SerializeAdapter::serialize(&fileSizeValue, buffer, size,
maxSize, streamEndianness);
}
if(info.getFaultLoc() != nullptr and info.getConditionCode() != cfdp::ConditionCode::NO_ERROR) {
result = info.getFaultLoc()->serialize(buffer, size, maxSize, streamEndianness);
}
return result;
}

View File

@ -0,0 +1,22 @@
#ifndef FSFW_SRC_FSFW_CFDP_PDU_EOFPDUSERIALIZER_H_
#define FSFW_SRC_FSFW_CFDP_PDU_EOFPDUSERIALIZER_H_
#include "fsfw/cfdp/pdu/FileDirectiveSerializer.h"
#include "fsfw/cfdp/tlv/EntityIdTlv.h"
#include "EofInfo.h"
class EofPduSerializer: public FileDirectiveSerializer {
public:
EofPduSerializer(PduConfig &conf, EofInfo& info);
size_t getSerializedSize() const override;
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
Endianness streamEndianness) const override;
private:
EofInfo& info;
};
#endif /* FSFW_SRC_FSFW_CFDP_PDU_EOFPDUSERIALIZER_H_ */

View File

@ -0,0 +1,52 @@
#include "FileDataDeserializer.h"
FileDataDeserializer::FileDataDeserializer(const uint8_t *pduBuf, size_t maxSize,
FileDataInfo& info):
HeaderDeserializer(pduBuf, maxSize), info(info) {
}
ReturnValue_t FileDataDeserializer::parseData() {
ReturnValue_t result = HeaderDeserializer::parseData();
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
size_t currentIdx = HeaderDeserializer::getHeaderSize();
const uint8_t* buf = rawPtr + currentIdx;
size_t remSize = HeaderDeserializer::getWholePduSize() - currentIdx;
if (remSize < 1) {
return SerializeIF::STREAM_TOO_SHORT;
}
if(hasSegmentMetadataFlag()) {
info.setSegmentMetadataFlag(true);
info.setRecordContinuationState(static_cast<cfdp::RecordContinuationState>(
(*buf >> 6) & 0b11));
size_t segmentMetadataLen = *buf & 0b00111111;
info.setSegmentMetadataLen(segmentMetadataLen);
if(remSize < segmentMetadataLen + 1) {
return SerializeIF::STREAM_TOO_SHORT;
}
if(segmentMetadataLen > 0) {
buf += 1;
remSize -= 1;
info.setSegmentMetadata(buf);
buf += segmentMetadataLen;
remSize -= segmentMetadataLen;
}
}
result = info.getOffset().deSerialize(&buf, &remSize, this->getEndianness());
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
if(remSize > 0) {
info.setFileData(buf, remSize);
}
return HasReturnvaluesIF::RETURN_OK;
}
SerializeIF::Endianness FileDataDeserializer::getEndianness() const {
return endianness;
}
void FileDataDeserializer::setEndianness(SerializeIF::Endianness endianness) {
this->endianness = endianness;
}

View File

@ -0,0 +1,22 @@
#ifndef FSFW_SRC_FSFW_CFDP_PDU_FILEDATADESERIALIZER_H_
#define FSFW_SRC_FSFW_CFDP_PDU_FILEDATADESERIALIZER_H_
#include "FileDataInfo.h"
#include "HeaderDeserializer.h"
#include "../definitions.h"
class FileDataDeserializer: public HeaderDeserializer {
public:
FileDataDeserializer(const uint8_t* pduBuf, size_t maxSize, FileDataInfo& info);
ReturnValue_t parseData();
SerializeIF::Endianness getEndianness() const;
void setEndianness(SerializeIF::Endianness endianness = SerializeIF::Endianness::NETWORK);
private:
SerializeIF::Endianness endianness = SerializeIF::Endianness::NETWORK;
FileDataInfo& info;
};
#endif /* FSFW_SRC_FSFW_CFDP_PDU_FILEDATADESERIALIZER_H_ */

View File

@ -0,0 +1,104 @@
#include "FileDataInfo.h"
FileDataInfo::FileDataInfo(cfdp::FileSize &offset, const uint8_t *fileData, size_t fileSize):
offset(offset), fileData(fileData), fileSize(fileSize) {
}
FileDataInfo::FileDataInfo(cfdp::FileSize &offset): offset(offset) {
}
void FileDataInfo::setSegmentMetadataFlag(bool enable) {
if(enable) {
segmentMetadataFlag = cfdp::SegmentMetadataFlag::PRESENT;
} else {
segmentMetadataFlag = cfdp::SegmentMetadataFlag::NOT_PRESENT;
}
}
size_t FileDataInfo::getSerializedSize(bool largeFile) const {
size_t sz = 0;
if(segmentMetadataFlag == cfdp::SegmentMetadataFlag::PRESENT) {
sz += 1 + segmentMetadataLen;
}
if(largeFile) {
sz += 8;
} else {
sz += 4;
}
sz += fileSize;
return sz;
}
cfdp::SegmentMetadataFlag FileDataInfo::getSegmentMetadataFlag() const {
return this->segmentMetadataFlag;
}
bool FileDataInfo::hasSegmentMetadata() const {
if(segmentMetadataFlag == cfdp::SegmentMetadataFlag::PRESENT) {
return true;
}
return false;
}
cfdp::RecordContinuationState FileDataInfo::getRecordContinuationState() const {
return this->recContState;
}
size_t FileDataInfo::getSegmentMetadataLen() const {
return segmentMetadataLen;
}
ReturnValue_t FileDataInfo::addSegmentMetadataInfo(cfdp::RecordContinuationState recContState,
const uint8_t* segmentMetadata, size_t segmentMetadataLen) {
this->segmentMetadataFlag = cfdp::SegmentMetadataFlag::PRESENT;
this->recContState = recContState;
if(segmentMetadataLen > 63) {
return HasReturnvaluesIF::RETURN_FAILED;
}
this->segmentMetadata = segmentMetadata;
this->segmentMetadataLen = segmentMetadataLen;
return HasReturnvaluesIF::RETURN_OK;
}
const uint8_t* FileDataInfo::getFileData(size_t *fileSize) const {
if(fileSize != nullptr) {
*fileSize = this->fileSize;
}
return fileData;
}
const uint8_t* FileDataInfo::getSegmentMetadata(size_t *segmentMetadataLen) {
if(segmentMetadataLen != nullptr) {
*segmentMetadataLen = this->segmentMetadataLen;
}
return segmentMetadata;
}
cfdp::FileSize& FileDataInfo::getOffset() {
return offset;
}
void FileDataInfo::setRecordContinuationState(cfdp::RecordContinuationState recContState) {
this->recContState = recContState;
}
void FileDataInfo::setSegmentMetadataLen(size_t len) {
this->segmentMetadataLen = len;
}
void FileDataInfo::setSegmentMetadata(const uint8_t *ptr) {
this->segmentMetadata = ptr;
}
void FileDataInfo::setFileData(const uint8_t *fileData, size_t fileSize) {
this->fileData = fileData;
this->fileSize = fileSize;
}
cfdp::SegmentationControl FileDataInfo::getSegmentationControl() const {
return segCtrl;
}
void FileDataInfo::setSegmentationControl(cfdp::SegmentationControl segCtrl) {
this->segCtrl = segCtrl;
}

View File

@ -0,0 +1,45 @@
#ifndef FSFW_SRC_FSFW_CFDP_PDU_FILEDATAINFO_H_
#define FSFW_SRC_FSFW_CFDP_PDU_FILEDATAINFO_H_
#include <fsfw/cfdp/definitions.h>
#include <fsfw/cfdp/FileSize.h>
class FileDataInfo {
public:
FileDataInfo(cfdp::FileSize& offset);
FileDataInfo(cfdp::FileSize& offset, const uint8_t* fileData, size_t fileSize);
size_t getSerializedSize(bool largeFile = false) const;
cfdp::FileSize& getOffset();
const uint8_t* getFileData(size_t* fileSize = nullptr) const;
void setFileData(const uint8_t* fileData, size_t fileSize);
cfdp::SegmentMetadataFlag getSegmentMetadataFlag() const;
cfdp::SegmentationControl getSegmentationControl() const;
cfdp::RecordContinuationState getRecordContinuationState() const;
void setRecordContinuationState(cfdp::RecordContinuationState recContState);
void setSegmentationControl(cfdp::SegmentationControl segCtrl);
size_t getSegmentMetadataLen() const;
void setSegmentMetadataLen(size_t len);
void setSegmentMetadata(const uint8_t* ptr);
bool hasSegmentMetadata() const;
void setSegmentMetadataFlag(bool enable);
ReturnValue_t addSegmentMetadataInfo(cfdp::RecordContinuationState recContState,
const uint8_t* segmentMetadata, size_t segmentMetadataLen);
const uint8_t* getSegmentMetadata(size_t* segmentMetadataLen = nullptr);
private:
cfdp::SegmentMetadataFlag segmentMetadataFlag = cfdp::SegmentMetadataFlag::NOT_PRESENT;
cfdp::SegmentationControl segCtrl =
cfdp::SegmentationControl::NO_RECORD_BOUNDARIES_PRESERVATION;
cfdp::FileSize& offset;
const uint8_t* fileData = nullptr;
size_t fileSize = 0;
cfdp::RecordContinuationState recContState = cfdp::RecordContinuationState::NO_START_NO_END;
size_t segmentMetadataLen = 0;
const uint8_t* segmentMetadata = nullptr;
};
#endif /* FSFW_SRC_FSFW_CFDP_PDU_FILEDATAINFO_H_ */

View File

@ -0,0 +1,54 @@
#include "FileDataSerializer.h"
#include <cstring>
FileDataSerializer::FileDataSerializer(PduConfig& conf, FileDataInfo& info):
HeaderSerializer(conf, cfdp::PduType::FILE_DATA, 0, info.getSegmentMetadataFlag()),
info(info) {
update();
}
void FileDataSerializer::update() {
this->setSegmentMetadataFlag(info.getSegmentMetadataFlag());
this->setSegmentationControl(info.getSegmentationControl());
setPduDataFieldLen(info.getSerializedSize(this->getLargeFileFlag()));
}
ReturnValue_t FileDataSerializer::serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const {
ReturnValue_t result = HeaderSerializer::serialize(buffer, size, maxSize, streamEndianness);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
if(*size + this->getSerializedSize() > maxSize) {
return SerializeIF::BUFFER_TOO_SHORT;
}
const uint8_t* readOnlyPtr = nullptr;
if (this->hasSegmentMetadataFlag()) {
size_t segmentMetadataLen = info.getSegmentMetadataLen();
**buffer = info.getRecordContinuationState() << 6 | segmentMetadataLen;
*buffer += 1;
*size += 1;
readOnlyPtr = info.getSegmentMetadata();
std::memcpy(*buffer, readOnlyPtr, segmentMetadataLen);
*buffer += segmentMetadataLen;
*size += segmentMetadataLen;
}
cfdp::FileSize& offset = info.getOffset();
result = offset.serialize(this->getLargeFileFlag(), buffer, size, maxSize, streamEndianness);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
size_t fileSize = 0;
readOnlyPtr = info.getFileData(&fileSize);
if(*size + fileSize > maxSize) {
return SerializeIF::BUFFER_TOO_SHORT;
}
std::memcpy(*buffer, readOnlyPtr, fileSize);
*buffer += fileSize;
*size += fileSize;
return HasReturnvaluesIF::RETURN_OK;
}
size_t FileDataSerializer::getSerializedSize() const {
return HeaderSerializer::getSerializedSize() + info.getSerializedSize(this->getLargeFileFlag());
}

View File

@ -0,0 +1,23 @@
#ifndef FSFW_SRC_FSFW_CFDP_PDU_FILEDATASERIALIZER_H_
#define FSFW_SRC_FSFW_CFDP_PDU_FILEDATASERIALIZER_H_
#include "FileDataInfo.h"
#include "../definitions.h"
#include "HeaderSerializer.h"
class FileDataSerializer: public HeaderSerializer {
public:
FileDataSerializer(PduConfig& conf, FileDataInfo& info);
void update();
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
Endianness streamEndianness) const override;
size_t getSerializedSize() const override;
private:
FileDataInfo& info;
};
#endif /* FSFW_SRC_FSFW_CFDP_PDU_FILEDATADESERIALIZER_H_ */

View File

@ -0,0 +1,55 @@
#include "FileDirectiveDeserializer.h"
FileDirectiveDeserializer::FileDirectiveDeserializer(const uint8_t *pduBuf, size_t maxSize):
HeaderDeserializer(pduBuf, maxSize) {
}
cfdp::FileDirectives FileDirectiveDeserializer::getFileDirective() const {
return fileDirective;
}
ReturnValue_t FileDirectiveDeserializer::parseData() {
ReturnValue_t result = HeaderDeserializer::parseData();
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
if(this->getPduDataFieldLen() < 1) {
return cfdp::INVALID_PDU_DATAFIELD_LEN;
}
if(FileDirectiveDeserializer::getWholePduSize() > maxSize) {
return SerializeIF::STREAM_TOO_SHORT;
}
size_t currentIdx = HeaderDeserializer::getHeaderSize();
if(not checkFileDirective(rawPtr[currentIdx])) {
return cfdp::INVALID_DIRECTIVE_FIELDS;
}
setFileDirective(static_cast<cfdp::FileDirectives>(rawPtr[currentIdx]));
return HasReturnvaluesIF::RETURN_OK;
}
size_t FileDirectiveDeserializer::getHeaderSize() const {
// return size of header plus the directive byte
return HeaderDeserializer::getHeaderSize() + 1;
}
bool FileDirectiveDeserializer::checkFileDirective(uint8_t rawByte) {<