Merge branch 'cfdp-source-handler' of https://egit.irs.uni-stuttgart.de/eive/fsfw into cfdp-source-handler

This commit is contained in:
Robin Müller 2023-07-21 16:09:59 +02:00
commit 4c9e731113
16 changed files with 219 additions and 44 deletions

View File

@ -32,6 +32,7 @@ add_subdirectory(timemanager)
add_subdirectory(tmtcpacket)
add_subdirectory(tmtcservices)
add_subdirectory(filesystem)
add_subdirectory(util)
# Optional

View File

@ -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,6 +108,10 @@ 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) {
@ -112,6 +126,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;
}

View File

@ -31,7 +31,8 @@ class VarLenField : public SerializeIF {
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);
ReturnValue_t setValue(uint64_t value);
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const override;
@ -64,7 +65,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 {

View File

@ -68,6 +68,7 @@ enum WidthInBytes : uint8_t {
ONE_BYTE = 1,
TWO_BYTES = 2,
FOUR_BYTES = 4,
EIGHT_BYTES = 8
};
enum FileDirective : uint8_t {

View File

@ -9,12 +9,33 @@
#include "fsfw/cfdp/pdu/MetadataPduCreator.h"
#include "fsfw/filesystem/HasFileSystemIF.h"
#include "fsfw/objectmanager.h"
#include "fsfw/serviceinterface.h"
#include "fsfw/tmtcservices/TmTcMessage.h"
using namespace returnvalue;
cfdp::SourceHandler::SourceHandler(SourceHandlerParams params, FsfwParams fsfwParams)
: sourceParams(std::move(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;
if (sourceParams.seqCountProvider.bitWidth() == 8) {
transactionParams.seqCountWidth = cfdp::WidthInBytes::ONE_BYTE;
} else if (sourceParams.seqCountProvider.bitWidth() == 16) {
transactionParams.seqCountWidth = cfdp::WidthInBytes::TWO_BYTES;
} else if (sourceParams.seqCountProvider.bitWidth() == 32) {
transactionParams.seqCountWidth = cfdp::WidthInBytes::FOUR_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.seqCountWidth = cfdp::WidthInBytes::ONE_BYTE;
}
}
cfdp::SourceHandler::FsmResult& cfdp::SourceHandler::fsmNacked() {
ReturnValue_t result;
@ -22,6 +43,7 @@ cfdp::SourceHandler::FsmResult& cfdp::SourceHandler::fsmNacked() {
step = TransactionStep::TRANSACTION_START;
}
if (step == TransactionStep::TRANSACTION_START) {
sourceParams.user.transactionIndication(transactionParams.id);
step = TransactionStep::CRC_PROCEDURE;
}
if (step == TransactionStep::CRC_PROCEDURE) {
@ -50,19 +72,23 @@ cfdp::SourceHandler::FsmResult& cfdp::SourceHandler::fsmNacked() {
if (result != OK) {
// TODO: Error handling
}
if (sourceParams.cfg.indicCfg.eofSentIndicRequired) {
sourceParams.user.eofSentIndication(transactionParams.id);
}
if (transactionParams.closureRequested) {
step = TransactionStep::WAIT_FOR_FINISH;
return fsmResult;
}
step = TransactionStep::NOTICE_OF_COMPLETION;
}
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) {
// TODO: Notice of completion
// We are done, go back to idle state.
// TODO: Possible reset state?
step = TransactionStep::IDLE;
state = CfdpState::IDLE;
noticeOfCompletion();
reset();
}
return fsmResult;
}
@ -78,6 +104,11 @@ cfdp::SourceHandler::FsmResult& cfdp::SourceHandler::stateMachine() {
}
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;
@ -135,6 +166,7 @@ ReturnValue_t cfdp::SourceHandler::putRequest(PutRequestFull& putRequest, Remote
// Only used for PDU forwarding, file is sent to file receiver regularly here.
transactionParams.pduConf.direction = Direction::TOWARDS_RECEIVER;
transactionParams.pduConf.sourceId = sourceParams.cfg.localId;
transactionParams.id.seqNum.setValue(sourceParams.seqCountProvider.getAndIncrement());
if (transactionParams.pduConf.mode == TransmissionMode::ACKNOWLEDGED) {
state = cfdp::CfdpState::BUSY_CLASS_2_ACKED;
@ -206,14 +238,13 @@ ReturnValue_t cfdp::SourceHandler::prepareAndSendNextFileDataPdu() {
}
ReturnValue_t cfdp::SourceHandler::prepareAndSendEofPdu() {
// TODO: Checksum
auto eofInfo = EofInfo(ConditionCode::NO_ERROR, 0, transactionParams.fileSize);
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;
}
step = TransactionStep::WAIT_FOR_FINISH;
return OK;
}
@ -255,3 +286,20 @@ ReturnValue_t cfdp::SourceHandler::sendGenericPdu(const SerializeIF& pdu) const
TmTcMessage tcMsg(storeId);
return fsfwParams.msgQueue->sendMessage(fsfwParams.packetDest.getReportReceptionQueue(), &tcMsg);
}
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;
transactionParams.reset();
return OK;
}

View File

@ -11,15 +11,17 @@
#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) : cfg(std::move(cfg)), user(user) {}
SourceHandlerParams(LocalEntityCfg cfg, UserBase& user, ProvidesSeqCountIF& seqCountProvider)
: cfg(std::move(cfg)), user(user), seqCountProvider(seqCountProvider) {}
LocalEntityCfg cfg;
UserBase& user;
size_t maxFilePathSize = 256;
ProvidesSeqCountIF& seqCountProvider;
};
class SourceHandler {
@ -69,7 +71,18 @@ class SourceHandler {
bool closureRequested = false;
RemoteEntityCfg remoteCfg;
PduConfig pduConf;
cfdp::TransactionId id{};
cfdp::WidthInBytes seqCountWidth;
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{};
@ -82,8 +95,10 @@ class SourceHandler {
ReturnValue_t prepareAndSendMetadataPdu();
ReturnValue_t prepareAndSendNextFileDataPdu();
ReturnValue_t prepareAndSendEofPdu();
ReturnValue_t noticeOfCompletion();
ReturnValue_t reset();
ReturnValue_t sendGenericPdu(const SerializeIF& pdu) const;
[[nodiscard]] ReturnValue_t sendGenericPdu(const SerializeIF& pdu) const;
};
} // namespace cfdp

View File

@ -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;
}
}

View File

@ -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;

View File

@ -0,0 +1 @@
target_sources(${LIB_FSFW_NAME} PRIVATE)

View 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;
}
};

View 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>;

View File

@ -5,6 +5,7 @@
#include "fsfw/cfdp/pdu/EofPduCreator.h"
#include "fsfw/cfdp/pdu/FileDataCreator.h"
#include "fsfw/cfdp/pdu/MetadataPduCreator.h"
#include "fsfw/util/SeqCountProvider.h"
#include "mocks/AcceptsTmMock.h"
#include "mocks/EventReportingProxyMock.h"
#include "mocks/FilesystemMock.h"
@ -26,7 +27,8 @@ TEST_CASE("CFDP Source Handler", "[cfdp]") {
LocalEntityCfg localEntityCfg(localId, IndicationCfg(), fhMock);
FilesystemMock fsMock;
UserMock userMock(fsMock);
SourceHandlerParams dp(localEntityCfg, userMock);
SeqCountProviderU16 seqCountProvider;
SourceHandlerParams dp(localEntityCfg, userMock, seqCountProvider);
EventReportingProxyMock eventReporterMock;
LocalPool::LocalPoolConfig storeCfg = {{10, 32}, {10, 64}, {10, 128}, {10, 1024}};

View File

@ -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);

View File

@ -40,7 +40,7 @@ TEST_CASE("CFDP TLV", "[cfdp][tlv]") {
SECTION("TLV Other Value") {
auto tlv = Tlv(TlvType::ENTITY_ID, rawBuf.data(), deserSize);
// Set new value
sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 12);
sourceId.setValueAndWidth(cfdp::WidthInBytes::FOUR_BYTES, 12);
REQUIRE(sourceId.serialize(&serPtr, &deserSize, rawBuf.size(),
SerializeIF::Endianness::NETWORK) == returnvalue::OK);
tlv.setValue(rawBuf.data(), cfdp::WidthInBytes::FOUR_BYTES);

View File

@ -1 +1,2 @@
target_sources(${FSFW_TEST_TGT} PRIVATE testUnsignedByteField.cpp)
target_sources(${FSFW_TEST_TGT} PRIVATE testUnsignedByteField.cpp
testSeqCountProvider.cpp)

View File

@ -0,0 +1,35 @@
#include <catch2/catch_test_macros.hpp>
#include "fsfw/util/SeqCountProvider.h"
TEST_CASE("Seq Count Providers", "[util]") {
auto genericProviderTest = [](ProvidesSeqCountIF& provider, unsigned expectedWidth) {
CHECK(provider.get() == 0);
CHECK(provider.bitWidth() == expectedWidth);
CHECK(provider.getAndIncrement() == 0);
CHECK(provider.getAndIncrement() == 1);
CHECK(provider.get() == 2);
provider.increment();
provider.increment();
CHECK(provider.get() == 4);
};
{
SeqCountProviderU16 provider;
genericProviderTest(provider, 16);
}
{
SeqCountProviderU32 provider;
genericProviderTest(provider, 32);
}
{
SeqCountProviderU8 provider;
genericProviderTest(provider, 8);
for (unsigned i = 4; i < UINT8_MAX + 1; i++) {
provider.increment();
}
// Verify wrap-around.
CHECK(provider.get() == 0);
}
}