CFDP Source Handler Testing #803

Merged
muellerr merged 14 commits from cfdp-source-handler-testing into cfdp-source-handler 2023-10-13 17:10:44 +02:00
10 changed files with 80 additions and 63 deletions
Showing only changes of commit 4431883b4d - Show all commits

View File

@ -750,14 +750,18 @@ ReturnValue_t ObjectFactory::createCcsdsComponents(CcsdsComponentArgs& args) {
gpioChecker(args.gpioComIF.addGpios(gpioCookiePtmeIp), "PTME PAPB VCs"); gpioChecker(args.gpioComIF.addGpios(gpioCookiePtmeIp), "PTME PAPB VCs");
// Creating virtual channel interfaces // Creating virtual channel interfaces
VirtualChannelIF* vc0 = new PapbVcInterface(&args.gpioComIF, gpioIds::VC0_PAPB_EMPTY, VirtualChannelIF* vc0 =
q7s::UIO_PTME, q7s::uiomapids::PTME_VC0); new PapbVcInterface(&args.gpioComIF, gpioIds::VC0_PAPB_EMPTY, q7s::UIO_PTME,
VirtualChannelIF* vc1 = new PapbVcInterface(&args.gpioComIF, gpioIds::VC1_PAPB_EMPTY, q7s::uiomapids::PTME_VC0, config::MAX_SPACEPACKET_TC_SIZE);
q7s::UIO_PTME, q7s::uiomapids::PTME_VC1); VirtualChannelIF* vc1 =
VirtualChannelIF* vc2 = new PapbVcInterface(&args.gpioComIF, gpioIds::VC2_PAPB_EMPTY, new PapbVcInterface(&args.gpioComIF, gpioIds::VC1_PAPB_EMPTY, q7s::UIO_PTME,
q7s::UIO_PTME, q7s::uiomapids::PTME_VC2); q7s::uiomapids::PTME_VC1, config::MAX_SPACEPACKET_TC_SIZE);
VirtualChannelIF* vc3 = new PapbVcInterface(&args.gpioComIF, gpioIds::VC3_PAPB_EMPTY, VirtualChannelIF* vc2 =
q7s::UIO_PTME, q7s::uiomapids::PTME_VC3); new PapbVcInterface(&args.gpioComIF, gpioIds::VC2_PAPB_EMPTY, q7s::UIO_PTME,
q7s::uiomapids::PTME_VC2, config::MAX_SPACEPACKET_TC_SIZE);
VirtualChannelIF* vc3 =
new PapbVcInterface(&args.gpioComIF, gpioIds::VC3_PAPB_EMPTY, q7s::UIO_PTME,
q7s::uiomapids::PTME_VC3, config::MAX_SPACEPACKET_TC_SIZE);
// Creating ptme object and adding virtual channel interfaces // Creating ptme object and adding virtual channel interfaces
Ptme* ptme = new Ptme(objects::PTME); Ptme* ptme = new Ptme(objects::PTME);
ptme->addVcInterface(ccsds::VC0, vc0); ptme->addVcInterface(ccsds::VC0, vc0);

View File

@ -35,6 +35,8 @@ static constexpr uint32_t STR_IMG_HELPER_QUEUE_SIZE = 50;
static constexpr uint8_t LIVE_TM = 0; static constexpr uint8_t LIVE_TM = 0;
static constexpr size_t MAX_SPACEPACKET_TC_SIZE = 2048;
/* Limits for filename and path checks */ /* Limits for filename and path checks */
static constexpr uint32_t MAX_PATH_SIZE = 200; static constexpr uint32_t MAX_PATH_SIZE = 200;
static constexpr uint32_t MAX_FILENAME_SIZE = 100; static constexpr uint32_t MAX_FILENAME_SIZE = 100;

View File

@ -8,8 +8,12 @@
#include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/serviceinterface/ServiceInterface.h"
PapbVcInterface::PapbVcInterface(LinuxLibgpioIF* gpioComIF, gpioId_t papbEmptyId, PapbVcInterface::PapbVcInterface(LinuxLibgpioIF* gpioComIF, gpioId_t papbEmptyId,
std::string uioFile, int mapNum) std::string uioFile, int mapNum, size_t maxPacketSize)
: gpioComIF(gpioComIF), papbEmptyId(papbEmptyId), uioFile(std::move(uioFile)), mapNum(mapNum) {} : gpioComIF(gpioComIF),
papbEmptyId(papbEmptyId),
packetBuf(maxPacketSize),
uioFile(std::move(uioFile)),
mapNum(mapNum) {}
PapbVcInterface::~PapbVcInterface() {} PapbVcInterface::~PapbVcInterface() {}
@ -29,9 +33,17 @@ ReturnValue_t PapbVcInterface::write(const uint8_t* data, size_t size, size_t& w
return returnvalue::FAILED; return returnvalue::FAILED;
} }
// The user must call finishWrite before starting a new packet transfer. // The user must call finishWrite before starting a new packet transfer.
if (partialWriteActive) { if (writeActive) {
return INCOMPLETE_PARTIAL_WRITE; return IS_BUSY;
} }
if (size > packetBuf.capacity()) {
sif::error << "PapbVcInterface: Packet with size " << size << " larger than maximum configured"
<< " byte size " << packetBuf.capacity() << std::endl;
return returnvalue::FAILED;
}
std::memcpy(packetBuf.data(), data, size);
currentPacketSize = size;
currentPacketIndex = 0;
if (pollReadyForPacket()) { if (pollReadyForPacket()) {
startPacketTransfer(ByteWidthCfg::ONE); startPacketTransfer(ByteWidthCfg::ONE);
} else { } else {
@ -41,14 +53,17 @@ ReturnValue_t PapbVcInterface::write(const uint8_t* data, size_t size, size_t& w
abortPacketTransfer(); abortPacketTransfer();
return returnvalue::FAILED; return returnvalue::FAILED;
} }
return finishWriteInternal(data, 0, size, writtenSize, false); return advanceWrite(writtenSize);
} }
void PapbVcInterface::startPacketTransfer(ByteWidthCfg initWidth) { void PapbVcInterface::startPacketTransfer(ByteWidthCfg initWidth) {
*vcBaseReg = CONFIG_DATA_INPUT | initWidth; *vcBaseReg = CONFIG_DATA_INPUT | initWidth;
} }
void PapbVcInterface::completePacketTransfer() { *vcBaseReg = CONFIG_END; } void PapbVcInterface::completePacketTransfer() {
*vcBaseReg = CONFIG_END;
writeActive = false;
}
bool PapbVcInterface::pollReadyForPacket() const { bool PapbVcInterface::pollReadyForPacket() const {
// Check if PAPB interface is ready to receive data. Use the configuration register for this. // Check if PAPB interface is ready to receive data. Use the configuration register for this.
@ -57,34 +72,20 @@ bool PapbVcInterface::pollReadyForPacket() const {
return (reg >> 6) & 0b1; return (reg >> 6) & 0b1;
} }
ReturnValue_t PapbVcInterface::finishWrite(const uint8_t* data, size_t start, ReturnValue_t PapbVcInterface::advanceWrite(size_t& writtenSize) {
size_t remainingSize) {
if (not pollReadyForPacket()) { if (not pollReadyForPacket()) {
return returnvalue::FAILED; return IS_BUSY;
} }
size_t dummy = 0; for (size_t idx = currentPacketIndex; idx < currentPacketSize; idx++) {
return finishWriteInternal(data, start, remainingSize, dummy, true);
}
ReturnValue_t PapbVcInterface::finishWriteInternal(const uint8_t* data, size_t start,
size_t remainingSize, size_t& writtenSize,
bool abortOnPartialWrite) {
for (size_t idx = 0; idx < remainingSize; idx++) {
if (not pollReadyForOctet(MAX_BUSY_POLLS)) { if (not pollReadyForOctet(MAX_BUSY_POLLS)) {
if (not pollReadyForPacket()) { if (not pollReadyForPacket()) {
writtenSize = start + idx;
partialWriteActive = true;
if (abortOnPartialWrite) {
abortPacketTransfer();
partialWriteActive = false;
return returnvalue::FAILED;
}
return PARTIALLY_WRITTEN; return PARTIALLY_WRITTEN;
} }
abortPacketTransfer(); abortPacketTransfer();
return returnvalue::FAILED; return returnvalue::FAILED;
} }
*(vcBaseReg + DATA_REG_OFFSET) = static_cast<uint32_t>(data[start + idx]); *(vcBaseReg + DATA_REG_OFFSET) = static_cast<uint32_t>(packetBuf[currentPacketIndex]);
writtenSize++;
} }
if (not pollReadyForOctet(MAX_BUSY_POLLS)) { if (not pollReadyForOctet(MAX_BUSY_POLLS)) {
abortPacketTransfer(); abortPacketTransfer();

View File

@ -6,6 +6,7 @@
#include <linux/ipcore/VirtualChannelIF.h> #include <linux/ipcore/VirtualChannelIF.h>
#include <atomic> #include <atomic>
#include <vector>
#include "OBSWConfig.h" #include "OBSWConfig.h"
#include "fsfw/returnvalues/returnvalue.h" #include "fsfw/returnvalues/returnvalue.h"
@ -30,7 +31,8 @@ class PapbVcInterface : public VirtualChannelIF {
* @param uioFile UIO file providing access to the PAPB bus * @param uioFile UIO file providing access to the PAPB bus
* @param mapNum Map number of UIO map associated with this virtual channel * @param mapNum Map number of UIO map associated with this virtual channel
*/ */
PapbVcInterface(LinuxLibgpioIF* gpioComIF, gpioId_t papbEmptyId, std::string uioFile, int mapNum); PapbVcInterface(LinuxLibgpioIF* gpioComIF, gpioId_t papbEmptyId, std::string uioFile, int mapNum,
size_t maxPacketSize);
virtual ~PapbVcInterface(); virtual ~PapbVcInterface();
bool isBusy() const override; bool isBusy() const override;
@ -42,9 +44,9 @@ class PapbVcInterface : public VirtualChannelIF {
*/ */
ReturnValue_t write(const uint8_t* data, size_t size, size_t& writtenSize) override; ReturnValue_t write(const uint8_t* data, size_t size, size_t& writtenSize) override;
ReturnValue_t finishWrite(const uint8_t* data, size_t start, size_t remainingSize) override; ReturnValue_t advanceWrite(size_t& remainingSize) override;
ReturnValue_t finishWriteInternal(const uint8_t* data, size_t start, size_t remainingSize, // ReturnValue_t finishWriteInternal(const uint8_t* data, size_t start, size_t remainingSize,
size_t& writtenSize, bool abortOnPartialWrite); // size_t& writtenSize, bool abortOnPartialWrite);
void cancelTransfer() override; void cancelTransfer() override;
@ -90,9 +92,12 @@ class PapbVcInterface : public VirtualChannelIF {
/** High when external buffer memory of virtual channel is empty */ /** High when external buffer memory of virtual channel is empty */
gpioId_t papbEmptyId = gpio::NO_GPIO; gpioId_t papbEmptyId = gpio::NO_GPIO;
std::vector<uint8_t> packetBuf;
std::string uioFile; std::string uioFile;
int mapNum = 0; int mapNum = 0;
bool partialWriteActive = false; bool writeActive = false;
size_t currentPacketIndex = 0;
size_t currentPacketSize = 0;
mutable struct timespec nextDelay = {.tv_sec = 0, .tv_nsec = 0}; mutable struct timespec nextDelay = {.tv_sec = 0, .tv_nsec = 0};
const struct timespec BETWEEN_POLL_DELAY = {.tv_sec = 0, .tv_nsec = 10}; const struct timespec BETWEEN_POLL_DELAY = {.tv_sec = 0, .tv_nsec = 10};
mutable struct timespec remDelay; mutable struct timespec remDelay;

View File

@ -53,11 +53,11 @@ ReturnValue_t LiveTmTask::performOperation(uint8_t opCode) {
consecutiveRegularCounter++; consecutiveRegularCounter++;
} }
} }
} else if (result != MessageQueueIF::EMPTY) {
sif::warning << "LiveTmTask: TM queue failure, returncode 0x" << std::hex << std::setw(4)
<< result << std::dec << std::endl;
} }
} }
if (channelIsBusy) {
sif::debug << "busy" << std::endl;
}
if (channelIsBusy and !throttlePeriodOngoing) { if (channelIsBusy and !throttlePeriodOngoing) {
// Throttle CFDP packet creator. It is by far the most relevant data creator, so throttling // Throttle CFDP packet creator. It is by far the most relevant data creator, so throttling
// it is the easiest way to handle back pressure for now in a sensible way. // it is the easiest way to handle back pressure for now in a sensible way.
@ -174,12 +174,12 @@ ReturnValue_t LiveTmTask::handleGenericTmQueue(MessageQueueIF& queue, bool isCfd
} }
if (!ptmeLocked) { if (!ptmeLocked) {
size_t partiallyWrittenSize = 0; size_t writtenSize = 0;
result = channel.write(data, size, partiallyWrittenSize); result = channel.write(data, size, writtenSize);
if (result == DirectTmSinkIF::PARTIALLY_WRITTEN) { if (result == DirectTmSinkIF::PARTIALLY_WRITTEN) {
// Already throttle CFDP. // Already throttle CFDP.
throttleCfdp(); throttleCfdp();
result = channel.handleLastWriteSynchronously(data, size, partiallyWrittenSize, 200); result = channel.handleWriteCompletionSynchronously(writtenSize, 200);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
// TODO: Event? Might lead to dangerous spam though.. // TODO: Event? Might lead to dangerous spam though..
sif::warning << "LiveTmTask: Synchronous write of last segment failed with code 0x" sif::warning << "LiveTmTask: Synchronous write of last segment failed with code 0x"

View File

@ -138,11 +138,10 @@ ReturnValue_t TmStoreTaskBase::performDump(PersistentTmStoreWithTmQueue& store,
return result; return result;
} }
dumpedLen = tmReader.getFullPacketLen(); dumpedLen = tmReader.getFullPacketLen();
size_t partiallyWrittenSize = 0; size_t writtenSize = 0;
result = channel.write(tmReader.getFullData(), dumpedLen, partiallyWrittenSize); result = channel.write(tmReader.getFullData(), dumpedLen, writtenSize);
if (result == VirtualChannelIF::PARTIALLY_WRITTEN) { if (result == VirtualChannelIF::PARTIALLY_WRITTEN) {
result = channel.handleLastWriteSynchronously(tmReader.getFullData(), partiallyWrittenSize, result = channel.handleWriteCompletionSynchronously(writtenSize, 200);
dumpedLen - partiallyWrittenSize, 200);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
// TODO: Event? Might lead to dangerous spam though.. // TODO: Event? Might lead to dangerous spam though..
sif::warning << "PersistentTmStore: Synchronous write of last segment failed with code 0x" sif::warning << "PersistentTmStore: Synchronous write of last segment failed with code 0x"

View File

@ -21,11 +21,11 @@ ReturnValue_t VirtualChannel::write(const uint8_t* data, size_t size, size_t& wr
uint8_t VirtualChannel::getVcid() const { return vcId; } uint8_t VirtualChannel::getVcid() const { return vcId; }
ReturnValue_t VirtualChannel::finishWrite(const uint8_t* data, size_t start, size_t remainingSize) { ReturnValue_t VirtualChannel::advanceWrite(size_t& writtenSize) {
if (!ptme.containsVc(vcId)) { if (!ptme.containsVc(vcId)) {
return CHANNEL_DOES_NOT_EXIST; return CHANNEL_DOES_NOT_EXIST;
} }
return ptme.getVirtChannel(vcId)->finishWrite(data, start, remainingSize); return ptme.getVirtChannel(vcId)->advanceWrite(writtenSize);
} }
const char* VirtualChannel::getName() const { return vcName.c_str(); } const char* VirtualChannel::getName() const { return vcName.c_str(); }
@ -46,20 +46,27 @@ void VirtualChannel::cancelTransfer() {
bool VirtualChannel::isTxOn() const { return txOn; } bool VirtualChannel::isTxOn() const { return txOn; }
ReturnValue_t VirtualChannel::handleLastWriteSynchronously(const uint8_t* data, size_t start, ReturnValue_t VirtualChannel::handleWriteCompletionSynchronously(size_t& writtenSize,
size_t remLen, unsigned maxDelayMs) { unsigned maxCompletionTimeMs) {
unsigned delayMs = 0; unsigned delayMs = 0;
while (true) { while (true) {
if (isBusy()) { if (isBusy()) {
if (delayMs >= maxDelayMs) { if (delayMs >= maxCompletionTimeMs) {
break; break;
} }
TaskFactory::delayTask(10); TaskFactory::delayTask(10);
delayMs += 10; delayMs += 10;
continue; continue;
} }
ReturnValue_t result = advanceWrite(writtenSize);
if (result == returnvalue::OK) {
sif::debug << "last write after" << delayMs << std::endl; sif::debug << "last write after" << delayMs << std::endl;
return finishWrite(data, start, remLen); // Transfer complete
return result;
} else if (result != PARTIALLY_WRITTEN) {
// Some error where we can not or should not continue the transfer.
return result;
}
} }
return returnvalue::FAILED; return returnvalue::FAILED;
} }

View File

@ -32,9 +32,9 @@ class VirtualChannel : public SystemObject, public VirtualChannelIF {
ReturnValue_t sendNextTm(const uint8_t* data, size_t size, size_t& writtenSize); ReturnValue_t sendNextTm(const uint8_t* data, size_t size, size_t& writtenSize);
bool isBusy() const override; bool isBusy() const override;
ReturnValue_t write(const uint8_t* data, size_t size, size_t& writtenSize) override; ReturnValue_t write(const uint8_t* data, size_t size, size_t& writtenSize) override;
ReturnValue_t finishWrite(const uint8_t* data, size_t start, size_t remainingSize) override; ReturnValue_t advanceWrite(size_t& writtenSize) override;
ReturnValue_t handleLastWriteSynchronously(const uint8_t* data, size_t start, size_t remLen, ReturnValue_t handleWriteCompletionSynchronously(size_t& writtenSize,
unsigned maxDelayMs); unsigned maxCompletionTimeMs);
void cancelTransfer() override; void cancelTransfer() override;
uint8_t getVcid() const; uint8_t getVcid() const;
bool isTxOn() const; bool isTxOn() const;

View File

@ -37,11 +37,11 @@ ReturnValue_t VirtualChannelWithQueue::handleNextTm(bool performWriteOp) {
} }
// TODO: Hnadle partial write handling // TODO: Hnadle partial write handling
size_t partiallyWrittenSize = 0; size_t writtenSize = 0;
if (performWriteOp) { if (performWriteOp) {
result = write(data, size, partiallyWrittenSize); result = write(data, size, writtenSize);
if (result == PARTIALLY_WRITTEN) { if (result == PARTIALLY_WRITTEN) {
result = handleLastWriteSynchronously(data, size, partiallyWrittenSize, 200); result = handleWriteCompletionSynchronously(writtenSize, 200);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
// TODO: Event? Might lead to dangerous spam though.. // TODO: Event? Might lead to dangerous spam though..
sif::warning sif::warning

View File

@ -14,7 +14,6 @@ class DirectTmSinkIF {
static constexpr ReturnValue_t IS_BUSY = returnvalue::makeCode(CLASS_ID, 0); static constexpr ReturnValue_t IS_BUSY = returnvalue::makeCode(CLASS_ID, 0);
static constexpr ReturnValue_t PARTIALLY_WRITTEN = returnvalue::makeCode(CLASS_ID, 1); static constexpr ReturnValue_t PARTIALLY_WRITTEN = returnvalue::makeCode(CLASS_ID, 1);
static constexpr ReturnValue_t INCOMPLETE_PARTIAL_WRITE = returnvalue::makeCode(CLASS_ID, 2);
/** /**
* @brief Implements the functionality to write to a TM sink directly * @brief Implements the functionality to write to a TM sink directly
@ -27,7 +26,7 @@ class DirectTmSinkIF {
*/ */
virtual ReturnValue_t write(const uint8_t* data, size_t size, size_t& writtenSize) = 0; virtual ReturnValue_t write(const uint8_t* data, size_t size, size_t& writtenSize) = 0;
virtual ReturnValue_t finishWrite(const uint8_t* data, size_t start, size_t remainingSize) = 0; virtual ReturnValue_t advanceWrite(size_t& writtenSize) = 0;
virtual bool isBusy() const = 0; virtual bool isBusy() const = 0;
}; };