refactored throttle handling
All checks were successful
EIVE/eive-obsw/pipeline/pr-main This commit looks good

This commit is contained in:
Robin Müller 2023-10-13 10:57:58 +02:00
parent 031be000d4
commit 9f600a24ff
Signed by: muellerr
GPG Key ID: A649FB78196E3849
6 changed files with 37 additions and 21 deletions

View File

@ -15,7 +15,8 @@
using namespace returnvalue;
using namespace cfdp;
CfdpHandler::CfdpHandler(const FsfwHandlerParams& fsfwHandlerParams, const CfdpHandlerCfg& cfdpCfg)
CfdpHandler::CfdpHandler(const FsfwHandlerParams& fsfwHandlerParams, const CfdpHandlerCfg& cfdpCfg,
const std::atomic_bool& throttleSignal)
: SystemObject(fsfwHandlerParams.objectId),
pduQueue(fsfwHandlerParams.tmtcQueue),
cfdpRequestQueue(fsfwHandlerParams.cfdpQueue),
@ -28,7 +29,8 @@ CfdpHandler::CfdpHandler(const FsfwHandlerParams& fsfwHandlerParams, const CfdpH
this->fsfwParams),
srcHandler(SourceHandlerParams(localCfg, cfdpCfg.userHandler, seqCntProvider),
this->fsfwParams),
ipcStore(fsfwHandlerParams.ipcStore) {}
ipcStore(fsfwHandlerParams.ipcStore),
throttleSignal(throttleSignal) {}
[[nodiscard]] const char* CfdpHandler::getName() const { return "CFDP Handler"; }
@ -69,20 +71,11 @@ ReturnValue_t CfdpHandler::initialize() {
fsmCount++;
}
fsmCount = 0;
if (signals::CFDP_CHANNEL_THROTTLE_SIGNAL) {
throttlePeriodSourceHandler.resetTimer();
if (throttleSignal) {
throttlePeriodOngoing = true;
signals::CFDP_CHANNEL_THROTTLE_SIGNAL = false;
}
if (throttlePeriodOngoing) {
if (throttlePeriodSourceHandler.hasTimedOut()) {
throttlePeriodOngoing = false;
} else {
shortDelay = true;
}
}
// CFDP can be throttled by the slowest live TM handler to handle back pressure in a sensible
// way without requiring huge amounts of memory for large files.
if (!throttlePeriodOngoing) {

View File

@ -62,7 +62,8 @@ struct CfdpHandlerCfg {
class CfdpHandler : public SystemObject, public ExecutableObjectIF, public AcceptsTelecommandsIF {
public:
explicit CfdpHandler(const FsfwHandlerParams& fsfwParams, const CfdpHandlerCfg& cfdpCfg);
explicit CfdpHandler(const FsfwHandlerParams& fsfwParams, const CfdpHandlerCfg& cfdpCfg,
const std::atomic_bool& throttleSignal);
[[nodiscard]] const char* getName() const override;
[[nodiscard]] uint32_t getIdentifier() const override;
@ -74,7 +75,6 @@ class CfdpHandler : public SystemObject, public ExecutableObjectIF, public Accep
private:
MessageQueueIF& pduQueue;
MessageQueueIF& cfdpRequestQueue;
Countdown throttlePeriodSourceHandler = Countdown(80);
bool throttlePeriodOngoing = false;
cfdp::LocalEntityCfg localCfg;
@ -89,6 +89,8 @@ class CfdpHandler : public SystemObject, public ExecutableObjectIF, public Accep
StorageManagerIF* tcStore = nullptr;
StorageManagerIF* tmStore = nullptr;
const std::atomic_bool& throttleSignal;
ReturnValue_t handlePduPacketMessages();
ReturnValue_t handlePduPacket(TmTcMessage& msg);
ReturnValue_t handleCfdpRequest(CommandMessage& msg);

View File

@ -53,11 +53,14 @@ ReturnValue_t LiveTmTask::performOperation(uint8_t opCode) {
}
}
}
if (channel.isBusy() and not signals::CFDP_CHANNEL_THROTTLE_SIGNAL) {
if (channel.isBusy() and !throttlePeriodOngoing) {
// 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 cleared
// by the data creator.
signals::CFDP_CHANNEL_THROTTLE_SIGNAL = true;
// it is the easiest way to handle back pressure for now in a sensible way.
throttleCfdp();
} else if(!channel.isBusy() and throttlePeriodOngoing) {
if(minimumPeriodThrottleCd.hasTimedOut()) {
releaseCfdp();
}
}
if (!handledTm) {
if (tmFunnelCd.hasTimedOut()) {
@ -164,7 +167,7 @@ ReturnValue_t LiveTmTask::handleGenericTmQueue(MessageQueueIF& queue) {
result = channel.write(data, size, partiallyWrittenSize);
if (result == DirectTmSinkIF::PARTIALLY_WRITTEN) {
// Already throttle CFDP.
signals::CFDP_CHANNEL_THROTTLE_SIGNAL = true;
throttleCfdp();
result = channel.handleLastWriteSynchronously(data, size, partiallyWrittenSize, 200);
if (result != returnvalue::OK) {
// TODO: Event? Might lead to dangerous spam though..
@ -180,6 +183,17 @@ ReturnValue_t LiveTmTask::handleGenericTmQueue(MessageQueueIF& queue) {
return result;
}
void LiveTmTask::throttleCfdp() {
throttlePeriodOngoing = true;
minimumPeriodThrottleCd.resetTimer();
signals::CFDP_CHANNEL_THROTTLE_SIGNAL = true;
}
void LiveTmTask::releaseCfdp() {
throttlePeriodOngoing = false;
signals::CFDP_CHANNEL_THROTTLE_SIGNAL = false;
}
ModeTreeChildIF& LiveTmTask::getModeTreeChildIF() { return *this; }
ReturnValue_t LiveTmTask::initialize() {

View File

@ -39,6 +39,10 @@ class LiveTmTask : public SystemObject,
CfdpTmFunnel& cfdpFunnel;
VirtualChannel& channel;
const std::atomic_bool& ptmeLocked;
// This countdown ensures that the CFDP is always throttled with a minimum period. Only after
// this period, the CFDP can be released if the channel is not busy.
Countdown minimumPeriodThrottleCd = Countdown(40);
bool throttlePeriodOngoing = false;
void readCommandQueue(void);
@ -56,6 +60,8 @@ class LiveTmTask : public SystemObject,
void startTransition(Mode_t mode, Submode_t submode) override;
void announceMode(bool recursive) override;
void throttleCfdp();
void releaseCfdp();
object_id_t getObjectId() const override;
const HasHealthIF* getOptHealthIF() const override;

View File

@ -58,6 +58,7 @@ ReturnValue_t VirtualChannel::handleLastWriteSynchronously(const uint8_t* data,
delayMs += 10;
continue;
}
sif::debug << "last write after" << delayMs << std::endl;
return finishWrite(data, start, remLen);
}
return returnvalue::FAILED;

View File

@ -292,7 +292,7 @@ void ObjectFactory::produceGenericObjects(HealthTableIF** healthTable_, PusTmFun
GROUND_REMOTE_CFG.maxFileSegmentLen = config::CFDP_MAX_FILE_SEGMENT_LEN;
CfdpHandlerCfg cfdpCfg(localId, indicationCfg, *eiveUserHandler, EIVE_FAULT_HANDLER, PACKET_LIST,
LOST_SEGMENTS, REMOTE_CFG_PROVIDER);
auto* cfdpHandler = new CfdpHandler(params, cfdpCfg);
auto* cfdpHandler = new CfdpHandler(params, cfdpCfg, signals::CFDP_CHANNEL_THROTTLE_SIGNAL);
// All CFDP packets arrive wrapped inside CCSDS space packets
CcsdsDistributorIF::DestInfo info("CFDP Destination", config::EIVE_CFDP_APID,
cfdpHandler->getRequestQueue(), true);