From f6f4db525cac3a589eeae1103753a52249cb2213 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 30 Mar 2023 23:52:37 +0200 Subject: [PATCH 01/12] read reg instead of polling GPIO --- bsp_q7s/core/ObjectFactory.cpp | 4 +--- linux/ipcore/PapbVcInterface.cpp | 19 ++++++------------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/bsp_q7s/core/ObjectFactory.cpp b/bsp_q7s/core/ObjectFactory.cpp index e7a5fca0..76bb39f3 100644 --- a/bsp_q7s/core/ObjectFactory.cpp +++ b/bsp_q7s/core/ObjectFactory.cpp @@ -754,10 +754,8 @@ ReturnValue_t ObjectFactory::createCcsdsComponents(CcsdsComponentArgs& args) { gpioCookiePtmeIp->addGpio(gpioIds::VC3_PAPB_BUSY, gpio); gpio = new GpiodRegularByLineName(q7s::gpioNames::PAPB_EMPTY_SIGNAL_VC3, "PAPB VC3"); gpioCookiePtmeIp->addGpio(gpioIds::VC3_PAPB_EMPTY, gpio); - // Initialise to low and then pull high to do a PTME reset, which puts the PTME in reset - // state. It will be put out of reset in the CCSDS handler initialize function. gpio = new GpiodRegularByLineName(q7s::gpioNames::PTME_RESETN, "PTME RESETN", - gpio::Direction::OUT, gpio::Levels::LOW); + gpio::Direction::OUT, gpio::Levels::HIGH); gpioCookiePtmeIp->addGpio(gpioIds::PTME_RESETN, gpio); gpioChecker(args.gpioComIF.addGpios(gpioCookiePtmeIp), "PTME PAPB VCs"); diff --git a/linux/ipcore/PapbVcInterface.cpp b/linux/ipcore/PapbVcInterface.cpp index eacfce33..e2c0805c 100644 --- a/linux/ipcore/PapbVcInterface.cpp +++ b/linux/ipcore/PapbVcInterface.cpp @@ -18,12 +18,11 @@ PapbVcInterface::~PapbVcInterface() {} ReturnValue_t PapbVcInterface::initialize() { UioMapper uioMapper(uioFile, mapNum); - uint32_t* baseReg; - ReturnValue_t result = uioMapper.getMappedAdress(&baseReg, UioMapper::Permissions::WRITE_ONLY); + ReturnValue_t result = uioMapper.getMappedAdress(const_cast(&vcBaseReg), + UioMapper::Permissions::WRITE_ONLY); if (result != returnvalue::OK) { return result; } - vcBaseReg = baseReg; return returnvalue::OK; } @@ -62,20 +61,14 @@ void PapbVcInterface::startPacketTransfer() { *vcBaseReg = CONFIG_START; } void PapbVcInterface::completePacketTransfer() { *vcBaseReg = CONFIG_END; } ReturnValue_t PapbVcInterface::pollPapbBusySignal(uint32_t maxPollRetries) const { - gpio::Levels papbBusyState = gpio::Levels::LOW; - ReturnValue_t result; uint32_t busyIdx = 0; nextDelay.tv_nsec = 0; while (true) { - /** Check if PAPB interface is ready to receive data */ - result = gpioComIF->readGpio(papbBusyId, papbBusyState); - if (result != returnvalue::OK) { - sif::warning << "PapbVcInterface::pollPapbBusySignal: Failed to read papb busy signal" - << std::endl; - return returnvalue::FAILED; - } - if (papbBusyState == gpio::Levels::HIGH) { + // Check if PAPB interface is ready to receive data. Use the configuration register for this. + // Bit 5, see PTME ptme_001_01-0-7-r2 Table 31. + bool busy = ((*vcBaseReg) >> 5) & 0b1; + if (not busy) { return returnvalue::OK; } -- 2.43.0 From 4b1221ab998689a6a5940835bd80bd0428aadc7c Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 31 Mar 2023 01:14:59 +0200 Subject: [PATCH 02/12] modes for VC/stores --- CHANGELOG.md | 4 + bsp_q7s/core/ObjectFactory.cpp | 8 +- bsp_q7s/core/ObjectFactory.h | 2 +- linux/ipcore/PapbVcInterface.cpp | 6 +- linux/ipcore/PapbVcInterface.h | 2 + mission/com/CMakeLists.txt | 13 ++- mission/com/CcsdsIpCoreHandler.h | 2 +- mission/com/LiveTmTask.cpp | 101 ++++++++++++++++++ mission/com/LiveTmTask.h | 55 ++++++++++ .../PersistentLogTmStoreTask.cpp | 16 +++ .../{tmtc => com}/PersistentLogTmStoreTask.h | 5 +- .../PersistentSingleTmStoreTask.cpp | 17 ++- .../PersistentSingleTmStoreTask.h | 7 +- mission/{tmtc => com}/TmStoreTaskBase.cpp | 68 +++++++++++- mission/{tmtc => com}/TmStoreTaskBase.h | 33 +++++- mission/{tmtc => com}/VirtualChannel.cpp | 0 mission/{tmtc => com}/VirtualChannel.h | 0 .../{tmtc => com}/VirtualChannelWithQueue.cpp | 8 +- .../{tmtc => com}/VirtualChannelWithQueue.h | 4 +- mission/config/comCfg.cpp | 2 + mission/system/com/comModeTree.cpp | 24 ++++- mission/tmtc/CMakeLists.txt | 8 +- mission/tmtc/LiveTmTask.cpp | 27 ----- mission/tmtc/LiveTmTask.h | 25 ----- 24 files changed, 347 insertions(+), 90 deletions(-) create mode 100644 mission/com/LiveTmTask.cpp create mode 100644 mission/com/LiveTmTask.h rename mission/{tmtc => com}/PersistentLogTmStoreTask.cpp (79%) rename mission/{tmtc => com}/PersistentLogTmStoreTask.h (90%) rename mission/{tmtc => com}/PersistentSingleTmStoreTask.cpp (72%) rename mission/{tmtc => com}/PersistentSingleTmStoreTask.h (85%) rename mission/{tmtc => com}/TmStoreTaskBase.cpp (67%) rename mission/{tmtc => com}/TmStoreTaskBase.h (66%) rename mission/{tmtc => com}/VirtualChannel.cpp (100%) rename mission/{tmtc => com}/VirtualChannel.h (100%) rename mission/{tmtc => com}/VirtualChannelWithQueue.cpp (91%) rename mission/{tmtc => com}/VirtualChannelWithQueue.h (93%) delete mode 100644 mission/tmtc/LiveTmTask.cpp delete mode 100644 mission/tmtc/LiveTmTask.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d982765..dd4976a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,10 @@ will consitute of a breaking change warranting a new major release: ## Changed - SCEX filename updates. Also use T as the file ID / date separator between date and time. +- COM TM store and dump handling: Introduce modes for all 4 TM VC/store tasks. The OFF mode can be + used to disable ongoing dumps or to prevent writes to the PTME VC. This allows cleaner reset + handling of the PTME. All 4 VC/store tasks were attached to the COM mode tree and are commanded + as part of the COM sequence as well to ensure consistent state with the CCSDS IP core handler. ## Fixed diff --git a/bsp_q7s/core/ObjectFactory.cpp b/bsp_q7s/core/ObjectFactory.cpp index 76bb39f3..26d19dcd 100644 --- a/bsp_q7s/core/ObjectFactory.cpp +++ b/bsp_q7s/core/ObjectFactory.cpp @@ -20,15 +20,15 @@ #include #include #include +#include +#include +#include #include #include #include #include #include #include -#include -#include -#include #include "OBSWConfig.h" #include "bsp_q7s/boardtest/Q7STestTask.h" @@ -81,6 +81,7 @@ using gpio::Levels; #include #include #include +#include #include #include #include @@ -96,7 +97,6 @@ using gpio::Levels; #include #include #include -#include #include diff --git a/bsp_q7s/core/ObjectFactory.h b/bsp_q7s/core/ObjectFactory.h index dc65e1f4..1d971a5e 100644 --- a/bsp_q7s/core/ObjectFactory.h +++ b/bsp_q7s/core/ObjectFactory.h @@ -4,11 +4,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include diff --git a/linux/ipcore/PapbVcInterface.cpp b/linux/ipcore/PapbVcInterface.cpp index e2c0805c..446e3afd 100644 --- a/linux/ipcore/PapbVcInterface.cpp +++ b/linux/ipcore/PapbVcInterface.cpp @@ -19,7 +19,7 @@ PapbVcInterface::~PapbVcInterface() {} ReturnValue_t PapbVcInterface::initialize() { UioMapper uioMapper(uioFile, mapNum); ReturnValue_t result = uioMapper.getMappedAdress(const_cast(&vcBaseReg), - UioMapper::Permissions::WRITE_ONLY); + UioMapper::Permissions::WRITE_ONLY); if (result != returnvalue::OK) { return result; } @@ -38,7 +38,7 @@ ReturnValue_t PapbVcInterface::write(const uint8_t* data, size_t size) { // TODO: Maybe this should not be done like this. It would be better if there was a custom // FPGA module which can accept packets and then takes care of dumping that packet into // the PTME. DMA would be an ideal solution for this. - nanosleep(&BETWEEN_POLL_DELAY, &remDelay); + // nanosleep(&BETWEEN_POLL_DELAY, &remDelay); if (pollPapbBusySignal(2) == returnvalue::OK) { *(vcBaseReg + DATA_REG_OFFSET) = static_cast(data[idx]); } else { @@ -46,7 +46,7 @@ ReturnValue_t PapbVcInterface::write(const uint8_t* data, size_t size) { return returnvalue::FAILED; } } - nanosleep(&BETWEEN_POLL_DELAY, &remDelay); + // nanosleep(&BETWEEN_POLL_DELAY, &remDelay); if (pollPapbBusySignal(2) == returnvalue::OK) { completePacketTransfer(); } else { diff --git a/linux/ipcore/PapbVcInterface.h b/linux/ipcore/PapbVcInterface.h index b4454dae..22b8ee5f 100644 --- a/linux/ipcore/PapbVcInterface.h +++ b/linux/ipcore/PapbVcInterface.h @@ -5,6 +5,8 @@ #include #include +#include + #include "OBSWConfig.h" #include "fsfw/returnvalues/returnvalue.h" diff --git a/mission/com/CMakeLists.txt b/mission/com/CMakeLists.txt index 94d3e7f0..90e90c88 100644 --- a/mission/com/CMakeLists.txt +++ b/mission/com/CMakeLists.txt @@ -1,2 +1,11 @@ -target_sources(${LIB_EIVE_MISSION} PRIVATE SyrlinksHandler.cpp - CcsdsIpCoreHandler.cpp) +target_sources( + ${LIB_EIVE_MISSION} + PRIVATE SyrlinksHandler.cpp + CcsdsIpCoreHandler.cpp + LiveTmTask.cpp + PersistentLogTmStoreTask.cpp + TmStoreTaskBase.cpp + VirtualChannel.cpp + VirtualChannelWithQueue.cpp + PersistentSingleTmStoreTask.cpp + LiveTmTask.cpp) diff --git a/mission/com/CcsdsIpCoreHandler.h b/mission/com/CcsdsIpCoreHandler.h index 0fad0aae..fc686230 100644 --- a/mission/com/CcsdsIpCoreHandler.h +++ b/mission/com/CcsdsIpCoreHandler.h @@ -2,7 +2,7 @@ #define CCSDSHANDLER_H_ #include -#include +#include #include #include diff --git a/mission/com/LiveTmTask.cpp b/mission/com/LiveTmTask.cpp new file mode 100644 index 00000000..70e8303f --- /dev/null +++ b/mission/com/LiveTmTask.cpp @@ -0,0 +1,101 @@ +#include "LiveTmTask.h" + +#include +#include +#include +#include + +LiveTmTask::LiveTmTask(object_id_t objectId, PusTmFunnel& pusFunnel, CfdpTmFunnel& cfdpFunnel, + VirtualChannelWithQueue& channel) + : SystemObject(objectId), + modeHelper(this), + pusFunnel(pusFunnel), + cfdpFunnel(cfdpFunnel), + channel(channel) { + requestQueue = QueueFactory::instance()->createMessageQueue(); +} + +ReturnValue_t LiveTmTask::performOperation(uint8_t opCode) { + readCommandQueue(); + while (true) { + bool performWriteOp = true; + if (mode == MODE_OFF) { + performWriteOp = false; + } + + // The funnel tasks are scheduled here directly as well. + ReturnValue_t result = channel.handleNextTm(performWriteOp); + if (result == DirectTmSinkIF::IS_BUSY) { + sif::error << "Lost live TM, PAPB busy" << std::endl; + } + if (result == MessageQueueIF::EMPTY) { + if (tmFunnelCd.hasTimedOut()) { + pusFunnel.performOperation(0); + cfdpFunnel.performOperation(0); + tmFunnelCd.resetTimer(); + } + // Read command queue during idle times. + readCommandQueue(); + // 40 ms IDLE delay. Might tweak this in the future. + TaskFactory::delayTask(40); + } else { + packetCounter++; + } + } +} + +MessageQueueId_t LiveTmTask::getCommandQueue() const { return requestQueue->getId(); } + +void LiveTmTask::getMode(Mode_t* mode, Submode_t* submode) { + if (mode != nullptr) { + *mode = this->mode; + } + if (submode != nullptr) { + *submode = SUBMODE_NONE; + } +} + +ReturnValue_t LiveTmTask::checkModeCommand(Mode_t mode, Submode_t submode, + uint32_t* msToReachTheMode) { + if (mode == MODE_ON or mode == MODE_OFF) { + return returnvalue::OK; + } + return returnvalue::FAILED; +} + +void LiveTmTask::startTransition(Mode_t mode, Submode_t submode) { + this->mode = mode; + modeHelper.modeChanged(mode, submode); + announceMode(false); +} + +void LiveTmTask::announceMode(bool recursive) { triggerEvent(MODE_INFO, mode, SUBMODE_NONE); } + +object_id_t LiveTmTask::getObjectId() const { return SystemObject::getObjectId(); } + +const HasHealthIF* LiveTmTask::getOptHealthIF() const { return nullptr; } + +const HasModesIF& LiveTmTask::getModeIF() const { return *this; } + +ReturnValue_t LiveTmTask::connectModeTreeParent(HasModeTreeChildrenIF& parent) { + return modetree::connectModeTreeParent(parent, *this, nullptr, modeHelper); +} + +void LiveTmTask::readCommandQueue(void) { + CommandMessage commandMessage; + ReturnValue_t result = returnvalue::FAILED; + + result = requestQueue->receiveMessage(&commandMessage); + if (result == returnvalue::OK) { + result = modeHelper.handleModeCommand(&commandMessage); + if (result == returnvalue::OK) { + return; + } + CommandMessage reply; + reply.setReplyRejected(CommandMessage::UNKNOWN_COMMAND, commandMessage.getCommand()); + requestQueue->reply(&reply); + return; + } +} + +ModeTreeChildIF& LiveTmTask::getModeTreeChildIF() { return *this; } diff --git a/mission/com/LiveTmTask.h b/mission/com/LiveTmTask.h new file mode 100644 index 00000000..e8eb7fc0 --- /dev/null +++ b/mission/com/LiveTmTask.h @@ -0,0 +1,55 @@ +#ifndef MISSION_TMTC_LIVETMTASK_H_ +#define MISSION_TMTC_LIVETMTASK_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class LiveTmTask : public SystemObject, + public HasModesIF, + public ExecutableObjectIF, + public ModeTreeChildIF, + public ModeTreeConnectionIF { + public: + LiveTmTask(object_id_t objectId, PusTmFunnel& pusFunnel, CfdpTmFunnel& cfdpFunnel, + VirtualChannelWithQueue& channel); + + ReturnValue_t performOperation(uint8_t opCode) override; + + private: + MessageQueueIF* requestQueue; + ModeHelper modeHelper; + Mode_t mode = HasModesIF::MODE_OFF; + Countdown tmFunnelCd = Countdown(100); + PusTmFunnel& pusFunnel; + CfdpTmFunnel& cfdpFunnel; + VirtualChannelWithQueue& channel; + uint32_t packetCounter = 0; + + void readCommandQueue(void); + + 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; + + void announceMode(bool recursive) override; + + object_id_t getObjectId() const override; + const HasHealthIF* getOptHealthIF() const override; + const HasModesIF& getModeIF() const override; + ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF& parent) override; + ModeTreeChildIF& getModeTreeChildIF() override; +}; + +#endif /* MISSION_TMTC_LIVETMTASK_H_ */ diff --git a/mission/tmtc/PersistentLogTmStoreTask.cpp b/mission/com/PersistentLogTmStoreTask.cpp similarity index 79% rename from mission/tmtc/PersistentLogTmStoreTask.cpp rename to mission/com/PersistentLogTmStoreTask.cpp index dcd78b54..07fe5ad6 100644 --- a/mission/tmtc/PersistentLogTmStoreTask.cpp +++ b/mission/com/PersistentLogTmStoreTask.cpp @@ -27,6 +27,8 @@ ReturnValue_t PersistentLogTmStoreTask::performOperation(uint8_t opCode) { } }; while (true) { + readCommandQueue(); + if (not cyclicStoreCheck()) { continue; } @@ -54,3 +56,17 @@ bool PersistentLogTmStoreTask::initStoresIfPossible() { } return false; } + +void PersistentLogTmStoreTask::startTransition(Mode_t mode, Submode_t submode) { + if (mode == MODE_OFF) { + bool channelIsOn = channel.isTxOn(); + cancelDump(okStoreContext, stores.okStore, channelIsOn); + cancelDump(notOkStoreContext, stores.notOkStore, channelIsOn); + cancelDump(miscStoreContext, stores.miscStore, channelIsOn); + this->mode = MODE_OFF; + } else if (mode == MODE_ON) { + this->mode = MODE_ON; + } + modeHelper.modeChanged(mode, submode); + announceMode(false); +} diff --git a/mission/tmtc/PersistentLogTmStoreTask.h b/mission/com/PersistentLogTmStoreTask.h similarity index 90% rename from mission/tmtc/PersistentLogTmStoreTask.h rename to mission/com/PersistentLogTmStoreTask.h index 116b369e..51431e2f 100644 --- a/mission/tmtc/PersistentLogTmStoreTask.h +++ b/mission/com/PersistentLogTmStoreTask.h @@ -5,11 +5,11 @@ #include #include #include +#include +#include #include #include #include -#include -#include struct LogStores { LogStores(PersistentTmStores& stores) @@ -36,6 +36,7 @@ class PersistentLogTmStoreTask : public TmStoreTaskBase, public ExecutableObject bool someFileWasSwapped = false; bool initStoresIfPossible() override; + void startTransition(Mode_t mode, Submode_t submode) override; }; #endif /* MISSION_TMTC_PERSISTENTLOGTMSTORETASK_H_ */ diff --git a/mission/tmtc/PersistentSingleTmStoreTask.cpp b/mission/com/PersistentSingleTmStoreTask.cpp similarity index 72% rename from mission/tmtc/PersistentSingleTmStoreTask.cpp rename to mission/com/PersistentSingleTmStoreTask.cpp index a2d57208..f84738ad 100644 --- a/mission/tmtc/PersistentSingleTmStoreTask.cpp +++ b/mission/com/PersistentSingleTmStoreTask.cpp @@ -1,17 +1,21 @@ +#include "PersistentSingleTmStoreTask.h" + #include #include -#include #include PersistentSingleTmStoreTask::PersistentSingleTmStoreTask( object_id_t objectId, StorageManagerIF& ipcStore, PersistentTmStoreWithTmQueue& tmStore, VirtualChannel& channel, Event eventIfDumpDone, Event eventIfCancelled, SdCardMountedIF& sdcMan) : TmStoreTaskBase(objectId, ipcStore, channel, sdcMan), + modeHelper(this), storeWithQueue(tmStore), dumpContext(eventIfDumpDone, eventIfCancelled) {} ReturnValue_t PersistentSingleTmStoreTask::performOperation(uint8_t opCode) { while (true) { + readCommandQueue(); + // Delay done by the check if (not cyclicStoreCheck()) { continue; @@ -33,3 +37,14 @@ bool PersistentSingleTmStoreTask::initStoresIfPossible() { } return false; } + +void PersistentSingleTmStoreTask::startTransition(Mode_t mode, Submode_t submode) { + if (mode == MODE_OFF) { + cancelDump(dumpContext, storeWithQueue, channel.isTxOn()); + this->mode = MODE_OFF; + } else if (mode == MODE_ON) { + this->mode = MODE_ON; + } + modeHelper.modeChanged(mode, submode); + announceMode(false); +} diff --git a/mission/tmtc/PersistentSingleTmStoreTask.h b/mission/com/PersistentSingleTmStoreTask.h similarity index 85% rename from mission/tmtc/PersistentSingleTmStoreTask.h rename to mission/com/PersistentSingleTmStoreTask.h index 1529928f..d8a1979b 100644 --- a/mission/tmtc/PersistentSingleTmStoreTask.h +++ b/mission/com/PersistentSingleTmStoreTask.h @@ -3,9 +3,9 @@ #include #include +#include +#include #include -#include -#include class PersistentSingleTmStoreTask : public TmStoreTaskBase, public ExecutableObjectIF { public: @@ -17,12 +17,15 @@ class PersistentSingleTmStoreTask : public TmStoreTaskBase, public ExecutableObj ReturnValue_t performOperation(uint8_t opCode) override; private: + ModeHelper modeHelper; PersistentTmStoreWithTmQueue& storeWithQueue; DumpContext dumpContext; Countdown tcHandlingCd = Countdown(400); Countdown graceDelayDuringDumping = Countdown(100); bool initStoresIfPossible() override; + + void startTransition(Mode_t mode, Submode_t submode) override; }; #endif /* MISSION_TMTC_PERSISTENTSINGLETMSTORETASK_H_ */ diff --git a/mission/tmtc/TmStoreTaskBase.cpp b/mission/com/TmStoreTaskBase.cpp similarity index 67% rename from mission/tmtc/TmStoreTaskBase.cpp rename to mission/com/TmStoreTaskBase.cpp index 7ca03488..b2f21a83 100644 --- a/mission/tmtc/TmStoreTaskBase.cpp +++ b/mission/com/TmStoreTaskBase.cpp @@ -1,6 +1,8 @@ #include "TmStoreTaskBase.h" #include +#include +#include #include #include #include @@ -9,7 +11,13 @@ TmStoreTaskBase::TmStoreTaskBase(object_id_t objectId, StorageManagerIF& ipcStore, VirtualChannel& channel, SdCardMountedIF& sdcMan) - : SystemObject(objectId), ipcStore(ipcStore), channel(channel), sdcMan(sdcMan) {} + : SystemObject(objectId), + modeHelper(this), + ipcStore(ipcStore), + channel(channel), + sdcMan(sdcMan) { + requestQueue = QueueFactory::instance()->createMessageQueue(10); +} bool TmStoreTaskBase::handleOneStore(PersistentTmStoreWithTmQueue& store, DumpContext& dumpContext) { @@ -26,8 +34,8 @@ bool TmStoreTaskBase::handleOneStore(PersistentTmStoreWithTmQueue& store, if (result == returnvalue::OK) { tmToStoreReceived = true; } - // Dump TMs when applicable - if (store.getState() == PersistentTmStore::State::DUMPING) { + // Dump TMs when applicable and allowed (mode is on) + if (mode == MODE_ON and store.getState() == PersistentTmStore::State::DUMPING) { if (handleOneDump(store, dumpContext, dumpPerformed) != returnvalue::OK) { return result; } @@ -129,3 +137,57 @@ ReturnValue_t TmStoreTaskBase::handleOneDump(PersistentTmStoreWithTmQueue& store } return result; } + +ReturnValue_t TmStoreTaskBase::initialize() { + modeHelper.initialize(); + return returnvalue::OK; +} + +void TmStoreTaskBase::getMode(Mode_t* mode, Submode_t* submode) { + if (mode != nullptr) { + *mode = this->mode; + } + if (submode != nullptr) { + *submode = SUBMODE_NONE; + } +} + +ReturnValue_t TmStoreTaskBase::checkModeCommand(Mode_t mode, Submode_t submode, + uint32_t* msToReachTheMode) { + if (mode == MODE_ON or mode == MODE_OFF) { + return returnvalue::OK; + } + return returnvalue::FAILED; +} + +MessageQueueId_t TmStoreTaskBase::getCommandQueue() const { return requestQueue->getId(); } + +void TmStoreTaskBase::announceMode(bool recursive) { triggerEvent(MODE_INFO, mode, SUBMODE_NONE); } + +object_id_t TmStoreTaskBase::getObjectId() const { return SystemObject::getObjectId(); } + +const HasHealthIF* TmStoreTaskBase::getOptHealthIF() const { return nullptr; } + +const HasModesIF& TmStoreTaskBase::getModeIF() const { return *this; } + +ReturnValue_t TmStoreTaskBase::connectModeTreeParent(HasModeTreeChildrenIF& parent) { + return modetree::connectModeTreeParent(parent, *this, nullptr, modeHelper); +} + +ModeTreeChildIF& TmStoreTaskBase::getModeTreeChildIF() { return *this; } +void TmStoreTaskBase::readCommandQueue(void) { + CommandMessage commandMessage; + ReturnValue_t result = returnvalue::FAILED; + + result = requestQueue->receiveMessage(&commandMessage); + if (result == returnvalue::OK) { + result = modeHelper.handleModeCommand(&commandMessage); + if (result == returnvalue::OK) { + return; + } + CommandMessage reply; + reply.setReplyRejected(CommandMessage::UNKNOWN_COMMAND, commandMessage.getCommand()); + requestQueue->reply(&reply); + return; + } +} diff --git a/mission/tmtc/TmStoreTaskBase.h b/mission/com/TmStoreTaskBase.h similarity index 66% rename from mission/tmtc/TmStoreTaskBase.h rename to mission/com/TmStoreTaskBase.h index 5fef74ff..c9f0b9a3 100644 --- a/mission/tmtc/TmStoreTaskBase.h +++ b/mission/com/TmStoreTaskBase.h @@ -1,15 +1,21 @@ #ifndef MISSION_TMTC_TMSTORETASKBASE_H_ #define MISSION_TMTC_TMSTORETASKBASE_H_ +#include +#include +#include #include +#include #include -#include /** * Generic class which composes a Virtual Channel and a persistent TM stores. This allows dumping * the TM store into the virtual channel directly. */ -class TmStoreTaskBase : public SystemObject { +class TmStoreTaskBase : public SystemObject, + public HasModesIF, + public ModeTreeChildIF, + public ModeTreeConnectionIF { public: struct DumpContext { DumpContext(Event eventIfDone, Event eventIfCancelled) @@ -35,8 +41,13 @@ class TmStoreTaskBase : public SystemObject { TmStoreTaskBase(object_id_t objectId, StorageManagerIF& ipcStore, VirtualChannel& channel, SdCardMountedIF& sdcMan); + ReturnValue_t initialize() override; + protected: + MessageQueueIF* requestQueue; + ModeHelper modeHelper; StorageManagerIF& ipcStore; + Mode_t mode = HasModesIF::MODE_OFF; Countdown sdCardCheckCd = Countdown(800); // 20 minutes are allowed as maximum dump time. Countdown cancelDumpCd = Countdown(60 * 20 * 1000); @@ -47,6 +58,11 @@ class TmStoreTaskBase : public SystemObject { bool fileHasSwapped = false; SdCardMountedIF& sdcMan; + void readCommandQueue(void); + + virtual bool initStoresIfPossible() = 0; + virtual void startTransition(Mode_t mode, Submode_t submode) = 0; + void cancelDump(DumpContext& ctx, PersistentTmStore& store, bool isTxOn); /** * @@ -65,7 +81,18 @@ class TmStoreTaskBase : public SystemObject { */ bool cyclicStoreCheck(); - virtual bool initStoresIfPossible() = 0; + 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 announceMode(bool recursive) override; + object_id_t getObjectId() const override; + const HasHealthIF* getOptHealthIF() const override; + const HasModesIF& getModeIF() const override; + ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF& parent) override; + ModeTreeChildIF& getModeTreeChildIF() override; }; #endif /* MISSION_TMTC_TMSTORETASKBASE_H_ */ diff --git a/mission/tmtc/VirtualChannel.cpp b/mission/com/VirtualChannel.cpp similarity index 100% rename from mission/tmtc/VirtualChannel.cpp rename to mission/com/VirtualChannel.cpp diff --git a/mission/tmtc/VirtualChannel.h b/mission/com/VirtualChannel.h similarity index 100% rename from mission/tmtc/VirtualChannel.h rename to mission/com/VirtualChannel.h diff --git a/mission/tmtc/VirtualChannelWithQueue.cpp b/mission/com/VirtualChannelWithQueue.cpp similarity index 91% rename from mission/tmtc/VirtualChannelWithQueue.cpp rename to mission/com/VirtualChannelWithQueue.cpp index 44a20031..a90829ab 100644 --- a/mission/tmtc/VirtualChannelWithQueue.cpp +++ b/mission/com/VirtualChannelWithQueue.cpp @@ -1,4 +1,4 @@ -#include +#include "VirtualChannelWithQueue.h" #include "OBSWConfig.h" #include "fsfw/ipc/QueueFactory.h" @@ -19,7 +19,7 @@ VirtualChannelWithQueue::VirtualChannelWithQueue(object_id_t objectId, uint8_t v const char* VirtualChannelWithQueue::getName() const { return VirtualChannel::getName(); } -ReturnValue_t VirtualChannelWithQueue::sendNextTm() { +ReturnValue_t VirtualChannelWithQueue::handleNextTm(bool performWriteOp) { TmTcMessage message; ReturnValue_t result = tmQueue->receiveMessage(&message); if (result == MessageQueueIF::EMPTY) { @@ -36,7 +36,9 @@ ReturnValue_t VirtualChannelWithQueue::sendNextTm() { return result; } - result = write(data, size); + if (performWriteOp) { + result = write(data, size); + } // Try delete in any case, ignore failures (which should not happen), it is more important to // propagate write errors. tmStore.deleteData(storeId); diff --git a/mission/tmtc/VirtualChannelWithQueue.h b/mission/com/VirtualChannelWithQueue.h similarity index 93% rename from mission/tmtc/VirtualChannelWithQueue.h rename to mission/com/VirtualChannelWithQueue.h index 0c060a06..04c7f965 100644 --- a/mission/tmtc/VirtualChannelWithQueue.h +++ b/mission/com/VirtualChannelWithQueue.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include @@ -34,7 +34,7 @@ class VirtualChannelWithQueue : public VirtualChannel, public AcceptsTelemetryIF MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel = 0) const override; [[nodiscard]] const char* getName() const override; - ReturnValue_t sendNextTm(); + ReturnValue_t handleNextTm(bool performWriteOp); private: MessageQueueIF* tmQueue = nullptr; diff --git a/mission/config/comCfg.cpp b/mission/config/comCfg.cpp index 8387214d..664a2e55 100644 --- a/mission/config/comCfg.cpp +++ b/mission/config/comCfg.cpp @@ -3,6 +3,8 @@ #include #include +#include + com::Datarate DATARATE_CFG_RAW = com::Datarate::LOW_RATE_MODULATION_BPSK; MutexIF* DATARATE_LOCK = nullptr; diff --git a/mission/system/com/comModeTree.cpp b/mission/system/com/comModeTree.cpp index 9501262d..bb9a8d10 100644 --- a/mission/system/com/comModeTree.cpp +++ b/mission/system/com/comModeTree.cpp @@ -22,7 +22,7 @@ auto COM_SEQUENCE_RX_ONLY = auto COM_TABLE_RX_ONLY_TGT = std::make_pair( static_cast(::com::Submode::RX_ONLY << 24) | 1, FixedArrayList()); auto COM_TABLE_RX_ONLY_TRANS_0 = std::make_pair( - static_cast(::com::Submode::RX_ONLY << 24) | 2, FixedArrayList()); + static_cast(::com::Submode::RX_ONLY << 24) | 2, FixedArrayList()); auto COM_TABLE_RX_ONLY_TRANS_1 = std::make_pair( static_cast(::com::Submode::RX_ONLY << 24) | 3, FixedArrayList()); @@ -36,7 +36,7 @@ auto COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_0 = FixedArrayList()); auto COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1 = std::make_pair(static_cast(::com::Submode::RX_AND_TX_LOW_DATARATE << 24) | 3, - FixedArrayList()); + FixedArrayList()); auto COM_SEQUENCE_RX_AND_TX_HIGH_RATE = std::make_pair(::com::Submode::RX_AND_TX_HIGH_DATARATE, FixedArrayList()); @@ -48,7 +48,7 @@ auto COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_0 = FixedArrayList()); auto COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1 = std::make_pair(static_cast(::com::Submode::RX_AND_TX_HIGH_DATARATE << 24) | 3, - FixedArrayList()); + FixedArrayList()); auto COM_SEQUENCE_RX_AND_TX_DEFAULT_RATE = std::make_pair(::com::Submode::RX_AND_TX_DEFAULT_DATARATE, FixedArrayList()); @@ -60,7 +60,7 @@ auto COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_0 = FixedArrayList()); auto COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1 = std::make_pair(static_cast(::com::Submode::RX_AND_TX_DEFAULT_DATARATE << 24) | 3, - FixedArrayList()); + FixedArrayList()); namespace { @@ -110,6 +110,10 @@ void buildRxOnlySequence(Subsystem& ss, ModeListEntry& eh) { // Build RX Only transition 0 iht(objects::SYRLINKS_ASSY, NML, ::com::Submode::RX_ONLY, COM_TABLE_RX_ONLY_TRANS_0.second); + iht(objects::LOG_STORE_AND_TM_TASK, OFF, 0, COM_TABLE_RX_ONLY_TRANS_0.second); + iht(objects::HK_STORE_AND_TM_TASK, OFF, 0, COM_TABLE_RX_ONLY_TRANS_0.second); + iht(objects::CFDP_STORE_AND_TM_TASK, OFF, 0, COM_TABLE_RX_ONLY_TRANS_0.second); + iht(objects::LIVE_TM_TASK, OFF, 0, COM_TABLE_RX_ONLY_TRANS_0.second); check(ss.addTable(TableEntry(COM_TABLE_RX_ONLY_TRANS_0.first, &COM_TABLE_RX_ONLY_TRANS_0.second)), ctxc); @@ -165,6 +169,10 @@ void buildTxAndRxLowRateSequence(Subsystem& ss, ModeListEntry& eh) { // Build TX and RX low transition 1 iht(objects::SYRLINKS_ASSY, NML, ::com::Submode::RX_AND_TX_LOW_DATARATE, COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1.second); + iht(objects::LOG_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1.second); + iht(objects::HK_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1.second); + iht(objects::CFDP_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1.second); + iht(objects::LIVE_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1.second); check(ss.addTable(TableEntry(COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1.first, &COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1.second)), ctxc); @@ -217,6 +225,10 @@ void buildTxAndRxHighRateSequence(Subsystem& ss, ModeListEntry& eh) { // Build TX and RX high transition 1 iht(objects::SYRLINKS_ASSY, NML, ::com::Submode::RX_AND_TX_HIGH_DATARATE, COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1.second); + iht(objects::LOG_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1.second); + iht(objects::HK_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1.second); + iht(objects::CFDP_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1.second); + iht(objects::LIVE_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1.second); check(ss.addTable(TableEntry(COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1.first, &COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1.second)), ctxc); @@ -271,6 +283,10 @@ void buildTxAndRxDefaultRateSequence(Subsystem& ss, ModeListEntry& eh) { // Build TX and RX default transition 1 iht(objects::SYRLINKS_ASSY, NML, ::com::Submode::RX_AND_TX_DEFAULT_DATARATE, COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1.second); + iht(objects::LOG_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1.second); + iht(objects::HK_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1.second); + iht(objects::CFDP_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1.second); + iht(objects::LIVE_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1.second); check(ss.addTable(TableEntry(COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1.first, &COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1.second)), ctxc); diff --git a/mission/tmtc/CMakeLists.txt b/mission/tmtc/CMakeLists.txt index c797e315..a8388d83 100644 --- a/mission/tmtc/CMakeLists.txt +++ b/mission/tmtc/CMakeLists.txt @@ -1,17 +1,11 @@ target_sources( ${LIB_EIVE_MISSION} - PRIVATE VirtualChannelWithQueue.cpp - PersistentTmStoreWithTmQueue.cpp - LiveTmTask.cpp - VirtualChannel.cpp + PRIVATE PersistentTmStoreWithTmQueue.cpp TmFunnelHandler.cpp TmFunnelBase.cpp CfdpTmFunnel.cpp tmFilters.cpp PusLiveDemux.cpp - PersistentSingleTmStoreTask.cpp - PersistentLogTmStoreTask.cpp - TmStoreTaskBase.cpp PusPacketFilter.cpp PusTmRouteByFilterHelper.cpp Service15TmStorage.cpp diff --git a/mission/tmtc/LiveTmTask.cpp b/mission/tmtc/LiveTmTask.cpp deleted file mode 100644 index 7e6d3de6..00000000 --- a/mission/tmtc/LiveTmTask.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "LiveTmTask.h" - -#include -#include - -LiveTmTask::LiveTmTask(object_id_t objectId, PusTmFunnel& pusFunnel, CfdpTmFunnel& cfdpFunnel, - VirtualChannelWithQueue& channel) - : SystemObject(objectId), pusFunnel(pusFunnel), cfdpFunnel(cfdpFunnel), channel(channel) {} - -ReturnValue_t LiveTmTask::performOperation(uint8_t opCode) { - while (true) { - // The funnel tasks are scheduled here directly as well. - ReturnValue_t result = channel.sendNextTm(); - if (result == DirectTmSinkIF::IS_BUSY) { - sif::error << "Lost live TM, PAPB busy" << std::endl; - } - if (result == MessageQueueIF::EMPTY) { - if (tmFunnelCd.hasTimedOut()) { - pusFunnel.performOperation(0); - cfdpFunnel.performOperation(0); - tmFunnelCd.resetTimer(); - } - // 40 ms IDLE delay. Might tweak this in the future. - TaskFactory::delayTask(40); - } - } -} diff --git a/mission/tmtc/LiveTmTask.h b/mission/tmtc/LiveTmTask.h deleted file mode 100644 index a0ca6b83..00000000 --- a/mission/tmtc/LiveTmTask.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef MISSION_TMTC_LIVETMTASK_H_ -#define MISSION_TMTC_LIVETMTASK_H_ - -#include -#include -#include -#include -#include -#include - -class LiveTmTask : public SystemObject, public ExecutableObjectIF { - public: - LiveTmTask(object_id_t objectId, PusTmFunnel& pusFunnel, CfdpTmFunnel& cfdpFunnel, - VirtualChannelWithQueue& channel); - - ReturnValue_t performOperation(uint8_t opCode) override; - - private: - Countdown tmFunnelCd = Countdown(100); - PusTmFunnel& pusFunnel; - CfdpTmFunnel& cfdpFunnel; - VirtualChannelWithQueue& channel; -}; - -#endif /* MISSION_TMTC_LIVETMTASK_H_ */ -- 2.43.0 From 795486ae6c8dbc7924063707716968b1409f08dd Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 31 Mar 2023 12:11:31 +0200 Subject: [PATCH 03/12] trying to find out whats wrong --- CMakeLists.txt | 3 ++- bsp_q7s/core/ObjectFactory.cpp | 24 ++++++++++++++-------- bsp_q7s/em/emObjectFactory.cpp | 2 +- dummies/CMakeLists.txt | 2 +- dummies/{helpers.cpp => helperFactory.cpp} | 5 ++++- dummies/{helpers.h => helperFactory.h} | 0 mission/com/LiveTmTask.cpp | 5 +++++ mission/com/LiveTmTask.h | 3 ++- mission/com/SyrlinksHandler.cpp | 18 ++++++++++++++-- mission/com/SyrlinksHandler.h | 1 + mission/com/TmStoreTaskBase.cpp | 7 +++++-- mission/com/TmStoreTaskBase.h | 2 +- mission/pollingSeqTables.cpp | 6 ++++-- 13 files changed, 57 insertions(+), 21 deletions(-) rename dummies/{helpers.cpp => helperFactory.cpp} (98%) rename dummies/{helpers.h => helperFactory.h} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index e0ec4dd7..3a2842a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -486,7 +486,8 @@ endif() target_link_libraries(${LIB_EIVE_MISSION} PUBLIC ${LIB_FSFW_NAME} ${LIB_OS_NAME}) -target_link_libraries(${LIB_DUMMIES} PUBLIC ${LIB_FSFW_NAME} ${LIB_JSON_NAME}) +target_link_libraries(${LIB_DUMMIES} PUBLIC ${LIB_EIVE_MISSION} + ${LIB_FSFW_NAME} ${LIB_JSON_NAME}) target_link_libraries(${OBSW_NAME} PRIVATE ${LIB_EIVE_MISSION} ${LIB_DUMMIES}) diff --git a/bsp_q7s/core/ObjectFactory.cpp b/bsp_q7s/core/ObjectFactory.cpp index 26d19dcd..629cf44c 100644 --- a/bsp_q7s/core/ObjectFactory.cpp +++ b/bsp_q7s/core/ObjectFactory.cpp @@ -795,28 +795,34 @@ ReturnValue_t ObjectFactory::createCcsdsComponents(CcsdsComponentArgs& args) { new VirtualChannelWithQueue(objects::PTME_VC0_LIVE_TM, ccsds::VC0, "PTME VC0 LIVE TM", *ptme, LINK_STATE, args.tmStore, 500); args.liveDestination = vcWithQueue; - new LiveTmTask(objects::LIVE_TM_TASK, args.pusFunnel, args.cfdpFunnel, *vcWithQueue); + auto* liveTask = + new LiveTmTask(objects::LIVE_TM_TASK, args.pusFunnel, args.cfdpFunnel, *vcWithQueue); + liveTask->connectModeTreeParent(satsystem::com::SUBSYSTEM); // Set up log store. auto* vc = new VirtualChannel(objects::PTME_VC1_LOG_TM, ccsds::VC1, "PTME VC1 LOG TM", *ptme, LINK_STATE); LogStores logStores(args.stores); // Core task which handles the LOG store and takes care of dumping it as TM using a VC directly - new PersistentLogTmStoreTask(objects::LOG_STORE_AND_TM_TASK, args.ipcStore, logStores, *vc, - *SdCardManager::instance()); + auto* logStore = new PersistentLogTmStoreTask(objects::LOG_STORE_AND_TM_TASK, args.ipcStore, + logStores, *vc, *SdCardManager::instance()); + logStore->connectModeTreeParent(satsystem::com::SUBSYSTEM); vc = new VirtualChannel(objects::PTME_VC2_HK_TM, ccsds::VC2, "PTME VC2 HK TM", *ptme, LINK_STATE); // Core task which handles the HK store and takes care of dumping it as TM using a VC directly - new PersistentSingleTmStoreTask(objects::HK_STORE_AND_TM_TASK, args.ipcStore, - *args.stores.hkStore, *vc, persTmStore::DUMP_HK_STORE_DONE, - persTmStore::DUMP_HK_STORE_DONE, *SdCardManager::instance()); + auto* hkStore = new PersistentSingleTmStoreTask( + objects::HK_STORE_AND_TM_TASK, args.ipcStore, *args.stores.hkStore, *vc, + persTmStore::DUMP_HK_STORE_DONE, persTmStore::DUMP_HK_STORE_DONE, *SdCardManager::instance()); + hkStore->connectModeTreeParent(satsystem::com::SUBSYSTEM); vc = new VirtualChannel(objects::PTME_VC3_CFDP_TM, ccsds::VC3, "PTME VC3 CFDP TM", *ptme, LINK_STATE); // Core task which handles the CFDP store and takes care of dumping it as TM using a VC directly - new PersistentSingleTmStoreTask(objects::CFDP_STORE_AND_TM_TASK, args.ipcStore, - *args.stores.cfdpStore, *vc, persTmStore::DUMP_CFDP_STORE_DONE, - persTmStore::DUMP_CFDP_CANCELLED, *SdCardManager::instance()); + auto* cfdpTask = new PersistentSingleTmStoreTask( + objects::CFDP_STORE_AND_TM_TASK, args.ipcStore, *args.stores.cfdpStore, *vc, + persTmStore::DUMP_CFDP_STORE_DONE, persTmStore::DUMP_CFDP_CANCELLED, + *SdCardManager::instance()); + cfdpTask->connectModeTreeParent(satsystem::com::SUBSYSTEM); ReturnValue_t result = (*args.ipCoreHandler)->connectModeTreeParent(satsystem::com::SUBSYSTEM); if (result != returnvalue::OK) { diff --git a/bsp_q7s/em/emObjectFactory.cpp b/bsp_q7s/em/emObjectFactory.cpp index c0852c05..1f873b99 100644 --- a/bsp_q7s/em/emObjectFactory.cpp +++ b/bsp_q7s/em/emObjectFactory.cpp @@ -13,7 +13,7 @@ #include "bsp_q7s/core/ObjectFactory.h" #include "busConf.h" #include "devConf.h" -#include "dummies/helpers.h" +#include "dummies/helperFactory.h" #include "eive/objects.h" #include "fsfw_hal/linux/gpio/LinuxLibgpioIF.h" #include "linux/ObjectFactory.h" diff --git a/dummies/CMakeLists.txt b/dummies/CMakeLists.txt index 75dd1364..6a49fcc6 100644 --- a/dummies/CMakeLists.txt +++ b/dummies/CMakeLists.txt @@ -26,6 +26,6 @@ target_sources( CoreControllerDummy.cpp PlocMpsocDummy.cpp PlocSupervisorDummy.cpp - helpers.cpp + helperFactory.cpp MgmRm3100Dummy.cpp Tmp1075Dummy.cpp) diff --git a/dummies/helpers.cpp b/dummies/helperFactory.cpp similarity index 98% rename from dummies/helpers.cpp rename to dummies/helperFactory.cpp index 1a541dfd..c0390a5e 100644 --- a/dummies/helpers.cpp +++ b/dummies/helperFactory.cpp @@ -1,4 +1,4 @@ -#include "helpers.h" +#include "helperFactory.h" #include #include @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -98,6 +99,8 @@ void dummy::createDummies(DummyCfg cfg, PowerSwitchIF& pwrSwitcher, GpioIF* gpio new GyroAdisDummy(objects::GYRO_2_ADIS_HANDLER, objects::DUMMY_COM_IF, comCookieDummy); assemblyDhbs[7] = new GyroL3GD20Dummy(objects::GYRO_3_L3G_HANDLER, objects::DUMMY_COM_IF, comCookieDummy); + new HealthDevice(objects::GPS_0_HEALTH_DEV, objects::ACS_BOARD_ASS); + new HealthDevice(objects::GPS_1_HEALTH_DEV, objects::ACS_BOARD_ASS); auto* gpsCtrl = new GpsCtrlDummy(objects::GPS_CONTROLLER); ObjectFactory::createAcsBoardAssy(pwrSwitcher, assemblyDhbs, gpsCtrl, gpioIF); } diff --git a/dummies/helpers.h b/dummies/helperFactory.h similarity index 100% rename from dummies/helpers.h rename to dummies/helperFactory.h diff --git a/mission/com/LiveTmTask.cpp b/mission/com/LiveTmTask.cpp index 70e8303f..236a3292 100644 --- a/mission/com/LiveTmTask.cpp +++ b/mission/com/LiveTmTask.cpp @@ -99,3 +99,8 @@ void LiveTmTask::readCommandQueue(void) { } ModeTreeChildIF& LiveTmTask::getModeTreeChildIF() { return *this; } + +ReturnValue_t LiveTmTask::initialize() { + modeHelper.initialize(); + return returnvalue::OK; +} diff --git a/mission/com/LiveTmTask.h b/mission/com/LiveTmTask.h index e8eb7fc0..ca63cd02 100644 --- a/mission/com/LiveTmTask.h +++ b/mission/com/LiveTmTask.h @@ -21,6 +21,8 @@ class LiveTmTask : public SystemObject, VirtualChannelWithQueue& channel); ReturnValue_t performOperation(uint8_t opCode) override; + ReturnValue_t initialize() override; + ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF& parent) override; private: MessageQueueIF* requestQueue; @@ -48,7 +50,6 @@ class LiveTmTask : public SystemObject, object_id_t getObjectId() const override; const HasHealthIF* getOptHealthIF() const override; const HasModesIF& getModeIF() const override; - ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF& parent) override; ModeTreeChildIF& getModeTreeChildIF() override; }; diff --git a/mission/com/SyrlinksHandler.cpp b/mission/com/SyrlinksHandler.cpp index 5065f219..84eebeda 100644 --- a/mission/com/SyrlinksHandler.cpp +++ b/mission/com/SyrlinksHandler.cpp @@ -21,6 +21,7 @@ SyrlinksHandler::~SyrlinksHandler() = default; void SyrlinksHandler::doStartUp() { if (internalState == InternalState::OFF) { + transitionCommandPending = false; internalState = InternalState::ENABLE_TEMPERATURE_PROTECTION; commandExecuted = false; } @@ -38,6 +39,7 @@ void SyrlinksHandler::doShutDown() { // In any case, always disable TX first. if (internalState != InternalState::SET_TX_STANDBY) { internalState = InternalState::SET_TX_STANDBY; + transitionCommandPending = false; commandExecuted = false; } if (internalState == InternalState::SET_TX_STANDBY) { @@ -97,6 +99,10 @@ ReturnValue_t SyrlinksHandler::buildNormalDeviceCommand(DeviceCommandId_t* id) { } ReturnValue_t SyrlinksHandler::buildTransitionDeviceCommand(DeviceCommandId_t* id) { + if (transitionCommandPending) { + return NOTHING_TO_SEND; + } + transitionCommandPending = true; switch (internalState) { case InternalState::ENABLE_TEMPERATURE_PROTECTION: { *id = syrlinks::WRITE_LCL_CONFIG; @@ -122,8 +128,10 @@ ReturnValue_t SyrlinksHandler::buildTransitionDeviceCommand(DeviceCommandId_t* i *id = syrlinks::SET_TX_MODE_STANDBY; return buildCommandFromCommand(*id, nullptr, 0); } - default: + default: { + transitionCommandPending = false; break; + } } return NOTHING_TO_SEND; } @@ -442,7 +450,6 @@ ReturnValue_t SyrlinksHandler::interpretDeviceReply(DeviceCommandId_t id, const return DeviceHandlerIF::UNKNOWN_DEVICE_REPLY; } } - return returnvalue::OK; } @@ -682,6 +689,9 @@ ReturnValue_t SyrlinksHandler::handleAckReply(const uint8_t* packet) { } break; } + default: { + sif::error << "Syrlinks: Unexpected ACK reply" << std::endl; + } } switch (rememberCommandId) { case (syrlinks::SET_TX_MODE_STANDBY): { @@ -728,16 +738,19 @@ void SyrlinksHandler::doTransition(Mode_t modeFrom, Submode_t subModeFrom) { Mode_t tgtMode = getBaseMode(getMode()); auto commandDone = [&]() { setMode(tgtMode); + transitionCommandPending = false; internalState = InternalState::IDLE; }; auto txOnHandler = [&](InternalState selMod) { if (internalState == InternalState::IDLE) { + transitionCommandPending = false; commandExecuted = false; internalState = selMod; } // Select modulation first (BPSK or 0QPSK). if (internalState == selMod) { if (commandExecuted) { + transitionCommandPending = false; internalState = InternalState::SET_TX_MODULATION; commandExecuted = false; } @@ -753,6 +766,7 @@ void SyrlinksHandler::doTransition(Mode_t modeFrom, Submode_t subModeFrom) { }; auto txStandbyHandler = [&]() { if (internalState == InternalState::IDLE) { + transitionCommandPending = false; internalState = InternalState::SET_TX_STANDBY; commandExecuted = false; } diff --git a/mission/com/SyrlinksHandler.h b/mission/com/SyrlinksHandler.h index 7d2d7227..97541ecb 100644 --- a/mission/com/SyrlinksHandler.h +++ b/mission/com/SyrlinksHandler.h @@ -112,6 +112,7 @@ class SyrlinksHandler : public DeviceHandlerBase { float tempPowerAmplifier = 0; float tempBasebandBoard = 0; bool commandExecuted = false; + bool transitionCommandPending = false; uint8_t commandBuffer[syrlinks::MAX_COMMAND_SIZE]; diff --git a/mission/com/TmStoreTaskBase.cpp b/mission/com/TmStoreTaskBase.cpp index b2f21a83..e5e3e241 100644 --- a/mission/com/TmStoreTaskBase.cpp +++ b/mission/com/TmStoreTaskBase.cpp @@ -35,7 +35,7 @@ bool TmStoreTaskBase::handleOneStore(PersistentTmStoreWithTmQueue& store, tmToStoreReceived = true; } // Dump TMs when applicable and allowed (mode is on) - if (mode == MODE_ON and store.getState() == PersistentTmStore::State::DUMPING) { + if (store.getState() == PersistentTmStore::State::DUMPING) { if (handleOneDump(store, dumpContext, dumpPerformed) != returnvalue::OK) { return result; } @@ -78,8 +78,10 @@ bool TmStoreTaskBase::cyclicStoreCheck() { } void TmStoreTaskBase::cancelDump(DumpContext& ctx, PersistentTmStore& store, bool isTxOn) { - triggerEvent(ctx.eventIfCancelled, ctx.numberOfDumpedPackets, ctx.dumpedBytes); ctx.reset(); + if (store.getState() == PersistentTmStore::State::DUMPING) { + triggerEvent(ctx.eventIfCancelled, ctx.numberOfDumpedPackets, ctx.dumpedBytes); + } store.cancelDump(); if (isTxOn) { channel.cancelTransfer(); @@ -175,6 +177,7 @@ ReturnValue_t TmStoreTaskBase::connectModeTreeParent(HasModeTreeChildrenIF& pare } ModeTreeChildIF& TmStoreTaskBase::getModeTreeChildIF() { return *this; } + void TmStoreTaskBase::readCommandQueue(void) { CommandMessage commandMessage; ReturnValue_t result = returnvalue::FAILED; diff --git a/mission/com/TmStoreTaskBase.h b/mission/com/TmStoreTaskBase.h index c9f0b9a3..1cb16439 100644 --- a/mission/com/TmStoreTaskBase.h +++ b/mission/com/TmStoreTaskBase.h @@ -42,6 +42,7 @@ class TmStoreTaskBase : public SystemObject, SdCardMountedIF& sdcMan); ReturnValue_t initialize() override; + ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF& parent) override; protected: MessageQueueIF* requestQueue; @@ -91,7 +92,6 @@ class TmStoreTaskBase : public SystemObject, object_id_t getObjectId() const override; const HasHealthIF* getOptHealthIF() const override; const HasModesIF& getModeIF() const override; - ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF& parent) override; ModeTreeChildIF& getModeTreeChildIF() override; }; diff --git a/mission/pollingSeqTables.cpp b/mission/pollingSeqTables.cpp index 8d172132..4225e977 100644 --- a/mission/pollingSeqTables.cpp +++ b/mission/pollingSeqTables.cpp @@ -26,10 +26,12 @@ ReturnValue_t pst::pstSyrlinks(FixedTimeslotTaskIF *thisSequence) { thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0, DeviceHandlerIF::GET_WRITE); thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.25, DeviceHandlerIF::SEND_READ); thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.25, DeviceHandlerIF::GET_READ); + thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.4, + DeviceHandlerIF::PERFORM_OPERATION); thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.4, DeviceHandlerIF::SEND_WRITE); thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.4, DeviceHandlerIF::GET_WRITE); - thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.7, DeviceHandlerIF::SEND_READ); - thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.7, DeviceHandlerIF::GET_READ); + thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.75, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.75, DeviceHandlerIF::GET_READ); static_cast(length); -- 2.43.0 From a1380a6e3a6010a5cbb24a27d6b5a296c2ba479e Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 31 Mar 2023 12:11:55 +0200 Subject: [PATCH 04/12] syrlinks bugfix --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd4976a7..c3edceff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ will consitute of a breaking change warranting a new major release: - Bugfix for side lane transitions of the dual lane assemblies, which only worked when the assembly was directly commanded +- Syrlinks Handler: Only send transition commands once. ## Added -- 2.43.0 From e0f94039b46ed3939d4b5c5e2a8fbe8193154262 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 31 Mar 2023 12:47:55 +0200 Subject: [PATCH 05/12] found some bugs --- mission/com/PersistentSingleTmStoreTask.cpp | 1 - mission/com/PersistentSingleTmStoreTask.h | 1 - mission/com/SyrlinksHandler.cpp | 5 ----- 3 files changed, 7 deletions(-) diff --git a/mission/com/PersistentSingleTmStoreTask.cpp b/mission/com/PersistentSingleTmStoreTask.cpp index f84738ad..2d05b25f 100644 --- a/mission/com/PersistentSingleTmStoreTask.cpp +++ b/mission/com/PersistentSingleTmStoreTask.cpp @@ -8,7 +8,6 @@ PersistentSingleTmStoreTask::PersistentSingleTmStoreTask( object_id_t objectId, StorageManagerIF& ipcStore, PersistentTmStoreWithTmQueue& tmStore, VirtualChannel& channel, Event eventIfDumpDone, Event eventIfCancelled, SdCardMountedIF& sdcMan) : TmStoreTaskBase(objectId, ipcStore, channel, sdcMan), - modeHelper(this), storeWithQueue(tmStore), dumpContext(eventIfDumpDone, eventIfCancelled) {} diff --git a/mission/com/PersistentSingleTmStoreTask.h b/mission/com/PersistentSingleTmStoreTask.h index d8a1979b..4cbf1544 100644 --- a/mission/com/PersistentSingleTmStoreTask.h +++ b/mission/com/PersistentSingleTmStoreTask.h @@ -17,7 +17,6 @@ class PersistentSingleTmStoreTask : public TmStoreTaskBase, public ExecutableObj ReturnValue_t performOperation(uint8_t opCode) override; private: - ModeHelper modeHelper; PersistentTmStoreWithTmQueue& storeWithQueue; DumpContext dumpContext; Countdown tcHandlingCd = Countdown(400); diff --git a/mission/com/SyrlinksHandler.cpp b/mission/com/SyrlinksHandler.cpp index 84eebeda..297ffd88 100644 --- a/mission/com/SyrlinksHandler.cpp +++ b/mission/com/SyrlinksHandler.cpp @@ -99,10 +99,6 @@ ReturnValue_t SyrlinksHandler::buildNormalDeviceCommand(DeviceCommandId_t* id) { } ReturnValue_t SyrlinksHandler::buildTransitionDeviceCommand(DeviceCommandId_t* id) { - if (transitionCommandPending) { - return NOTHING_TO_SEND; - } - transitionCommandPending = true; switch (internalState) { case InternalState::ENABLE_TEMPERATURE_PROTECTION: { *id = syrlinks::WRITE_LCL_CONFIG; @@ -129,7 +125,6 @@ ReturnValue_t SyrlinksHandler::buildTransitionDeviceCommand(DeviceCommandId_t* i return buildCommandFromCommand(*id, nullptr, 0); } default: { - transitionCommandPending = false; break; } } -- 2.43.0 From 3871c8b8dee7496462decf1993bbc3a3c4fbf659 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 31 Mar 2023 13:17:15 +0200 Subject: [PATCH 06/12] change layering --- mission/com/TmStoreTaskBase.cpp | 78 ++++++++++++++++++++---------- mission/com/TmStoreTaskBase.h | 10 +++- mission/tmtc/PersistentTmStore.cpp | 40 +++++++-------- mission/tmtc/PersistentTmStore.h | 29 +++++++---- 4 files changed, 98 insertions(+), 59 deletions(-) diff --git a/mission/com/TmStoreTaskBase.cpp b/mission/com/TmStoreTaskBase.cpp index e5e3e241..91555f04 100644 --- a/mission/com/TmStoreTaskBase.cpp +++ b/mission/com/TmStoreTaskBase.cpp @@ -14,6 +14,7 @@ TmStoreTaskBase::TmStoreTaskBase(object_id_t objectId, StorageManagerIF& ipcStor : SystemObject(objectId), modeHelper(this), ipcStore(ipcStore), + tmReader(&timeReader), channel(channel), sdcMan(sdcMan) { requestQueue = QueueFactory::instance()->createMessageQueue(10); @@ -34,7 +35,7 @@ bool TmStoreTaskBase::handleOneStore(PersistentTmStoreWithTmQueue& store, if (result == returnvalue::OK) { tmToStoreReceived = true; } - // Dump TMs when applicable and allowed (mode is on) + // Dump TMs if (store.getState() == PersistentTmStore::State::DUMPING) { if (handleOneDump(store, dumpContext, dumpPerformed) != returnvalue::OK) { return result; @@ -93,35 +94,13 @@ ReturnValue_t TmStoreTaskBase::handleOneDump(PersistentTmStoreWithTmQueue& store ReturnValue_t result = returnvalue::OK; // The PTME might have been reset an transmitter state change, so there is no point in continuing // the dump. + // TODO: Will be solved in a cleaner way, this is kind of a hack. if (not channel.isTxOn()) { cancelDump(dumpContext, store, false); return returnvalue::FAILED; } - size_t dumpedLen = 0; if (not channel.isBusy()) { - // Dump the next packet into the PTME. - dumpContext.ptmeBusyCounter = 0; - tmSinkBusyCd.resetTimer(); - result = store.dumpNextPacket(channel, dumpedLen, fileHasSwapped); - if (result == DirectTmSinkIF::IS_BUSY) { - sif::warning << "Unexpected PAPB busy" << std::endl; - } - if ((result == PersistentTmStore::DUMP_DONE or result == returnvalue::OK)) { - dumpPerformed = true; - if (dumpedLen > 0) { - dumpContext.dumpedBytes += dumpedLen; - dumpContext.numberOfDumpedPackets += 1; - dumpContext.packetWasDumped = true; - } - } - if (result == PersistentTmStore::DUMP_DONE) { - uint32_t startTime; - uint32_t endTime; - store.getStartAndEndTimeCurrentOrLastDump(startTime, endTime); - triggerEvent(dumpContext.eventIfDone, dumpContext.numberOfDumpedPackets, - dumpContext.dumpedBytes); - dumpContext.reset(); - } + performDump(store, dumpContext, dumpPerformed); } else { // The PTME might be at full load, so it might sense to delay for a bit to let it do // its work until some more bandwidth is available. Set a flag here so the upper layer can @@ -140,6 +119,55 @@ ReturnValue_t TmStoreTaskBase::handleOneDump(PersistentTmStoreWithTmQueue& store return result; } +ReturnValue_t TmStoreTaskBase::performDump(PersistentTmStoreWithTmQueue& store, + DumpContext& dumpContext, bool& dumpPerformed) { + size_t dumpedLen = 0; + + auto dumpDoneHandler = [&]() { + uint32_t startTime; + uint32_t endTime; + store.getStartAndEndTimeCurrentOrLastDump(startTime, endTime); + triggerEvent(dumpContext.eventIfDone, dumpContext.numberOfDumpedPackets, + dumpContext.dumpedBytes); + dumpContext.reset(); + }; + // Dump the next packet into the PTME. + dumpContext.ptmeBusyCounter = 0; + tmSinkBusyCd.resetTimer(); + ReturnValue_t result = store.getNextDumpPacket(tmReader, fileHasSwapped); + if (result != returnvalue::OK) { + sif::error << "PersistentTmStore: Getting next dump packet failed" << std::endl; + } else if (fileHasSwapped or result == PersistentTmStore::DUMP_DONE) { + // This can happen if a file is corrupted and the next file swap completes the dump. + dumpDoneHandler(); + return returnvalue::OK; + } + // Only write to VC if mode is on, but always confirm the dump. + // If the mode is OFF, it is assumed the PTME is not usable and is not allowed to be written + // (e.g. to confirm a reset or the transmitter is off anyway). + if (mode == MODE_ON) { + result = channel.write(tmReader.getFullData(), tmReader.getFullPacketLen()); + if (result == DirectTmSinkIF::IS_BUSY) { + sif::warning << "PersistentTmStore: Unexpected VC channel busy" << std::endl; + } else if (result != returnvalue::OK) { + sif::warning << "PersistentTmStore: Unexpected VC channel write failure" << std::endl; + } + } + result = store.confirmDump(tmReader, fileHasSwapped); + if ((result == PersistentTmStore::DUMP_DONE or result == returnvalue::OK)) { + dumpPerformed = true; + if (dumpedLen > 0) { + dumpContext.dumpedBytes += dumpedLen; + dumpContext.numberOfDumpedPackets += 1; + dumpContext.packetWasDumped = true; + } + } + if (result == PersistentTmStore::DUMP_DONE) { + dumpDoneHandler(); + } + return returnvalue::OK; +} + ReturnValue_t TmStoreTaskBase::initialize() { modeHelper.initialize(); return returnvalue::OK; diff --git a/mission/com/TmStoreTaskBase.h b/mission/com/TmStoreTaskBase.h index 1cb16439..55448cde 100644 --- a/mission/com/TmStoreTaskBase.h +++ b/mission/com/TmStoreTaskBase.h @@ -45,16 +45,20 @@ class TmStoreTaskBase : public SystemObject, ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF& parent) override; protected: - MessageQueueIF* requestQueue; ModeHelper modeHelper; + MessageQueueIF* requestQueue; StorageManagerIF& ipcStore; + PusTmReader tmReader; + CdsShortTimeStamper timeReader; + VirtualChannel& channel; + Mode_t mode = HasModesIF::MODE_OFF; Countdown sdCardCheckCd = Countdown(800); // 20 minutes are allowed as maximum dump time. Countdown cancelDumpCd = Countdown(60 * 20 * 1000); // If the TM sink is busy for 1 minute for whatever reason, cancel the dump. Countdown tmSinkBusyCd = Countdown(60 * 1000); - VirtualChannel& channel; + bool storesInitialized = false; bool fileHasSwapped = false; SdCardMountedIF& sdcMan; @@ -75,6 +79,8 @@ class TmStoreTaskBase : public SystemObject, ReturnValue_t handleOneDump(PersistentTmStoreWithTmQueue& store, DumpContext& dumpContext, bool& dumpPerformed); + ReturnValue_t performDump(PersistentTmStoreWithTmQueue& store, DumpContext& dumpContext, + bool& dumpPerformed); /** * Occasionally check whether SD card is okay to be used. If not, poll whether it is ready to diff --git a/mission/tmtc/PersistentTmStore.cpp b/mission/tmtc/PersistentTmStore.cpp index bf8f2a4f..a5f0ec66 100644 --- a/mission/tmtc/PersistentTmStore.cpp +++ b/mission/tmtc/PersistentTmStore.cpp @@ -251,41 +251,37 @@ ReturnValue_t PersistentTmStore::loadNextDumpFile() { return DUMP_DONE; } -ReturnValue_t PersistentTmStore::dumpNextPacket(DirectTmSinkIF& tmSink, size_t& dumpedLen, - bool& fileHasSwapped) { - if (state == State::IDLE) { +ReturnValue_t PersistentTmStore::getNextDumpPacket(PusTmReader& reader, bool& fileHasSwapped) { + if (state == State::IDLE or dumpParams.pendingPacketDump) { return returnvalue::FAILED; } - PusTmReader reader(&timeReader, fileBuf.data() + dumpParams.currentSize, - fileBuf.size() - dumpParams.currentSize); + reader.setReadOnlyData(fileBuf.data() + dumpParams.currentSize, + fileBuf.size() - dumpParams.currentSize); // CRC check to fully ensure this is a valid TM ReturnValue_t result = reader.parseDataWithCrcCheck(); - if (result == returnvalue::OK) { - result = tmSink.write(fileBuf.data() + dumpParams.currentSize, reader.getFullPacketLen()); - if (result == DirectTmSinkIF::IS_BUSY) { - return result; - } else if (result != returnvalue::OK) { - // TODO: Event? - sif::error << "PersistentTmStore: Writing to TM sink failed" << std::endl; - return result; - } - dumpParams.currentSize += reader.getFullPacketLen(); - dumpedLen = reader.getFullPacketLen(); - if (dumpParams.currentSize >= dumpParams.fileSize) { - fileHasSwapped = true; - return loadNextDumpFile(); - } - } else { + if (result != returnvalue::OK) { sif::error << "PersistentTmStore: Parsing of PUS TM failed with code " << result << std::endl; triggerEvent(persTmStore::POSSIBLE_FILE_CORRUPTION, result, dumpParams.currentFileUnixStamp); // Delete the file and load next. Could use better algorithm to partially // restore the file dump, but for now do not trust the file. - dumpedLen = 0; std::error_code e; std::filesystem::remove(dumpParams.dirEntry.path().c_str(), e); fileHasSwapped = true; return loadNextDumpFile(); } + fileHasSwapped = false; + dumpParams.pendingPacketDump = true; + return returnvalue::OK; +} + +ReturnValue_t PersistentTmStore::confirmDump(const PusTmReader& reader, bool& fileHasSwapped) { + dumpParams.pendingPacketDump = false; + dumpParams.currentSize += reader.getFullPacketLen(); + if (dumpParams.currentSize >= dumpParams.fileSize) { + fileHasSwapped = true; + return loadNextDumpFile(); + } + fileHasSwapped = false; return returnvalue::OK; } diff --git a/mission/tmtc/PersistentTmStore.h b/mission/tmtc/PersistentTmStore.h index a0910026..4839f2fb 100644 --- a/mission/tmtc/PersistentTmStore.h +++ b/mission/tmtc/PersistentTmStore.h @@ -4,12 +4,10 @@ #include #include #include -#include #include #include #include #include -#include #include @@ -57,13 +55,25 @@ class PersistentTmStore : public TmStoreFrontendSimpleIF, public SystemObject { ReturnValue_t startDumpFromUpTo(uint32_t fromUnixSeconds, uint32_t upToUnixSeconds); /** * - * @param tmSink - * @param dumpedLen - * @param fileHasSwapped - * @return DUMP_DONE if dump is finished, returnvalue::OK if dump of next packet was a success, - * and DirectTmSinkIF::IS_BUSY is TM sink is busy. + * @param tmReader: Next packet will be loaded into the PUS TM reader. A CRC check will be + * performed on the packet. If that check fails, the file is considered corrupted and will + * be deleted for now. + * @param fileHasSwapped: If the CRC check fails, the file will be deleted and a new one has to + * be loaded. The dump can reach completion during that process. If a file is swapped, this + * boolean is set to true + * @return DUMP_DONE if dump is finished, returnvalue::OK if the next packet was loaded into the + * TM reader, and the returnvalue of the file swap operation if the CRC check failed and + * a new file was loaded. */ - ReturnValue_t dumpNextPacket(DirectTmSinkIF& tmSink, size_t& dumpedLen, bool& fileHasSwapped); + ReturnValue_t getNextDumpPacket(PusTmReader& tmReader, bool& fileHasSwapped); + /** + * Confirm the dump to advance the dump state machine. + * @param tmReader + * @param fileHasSwapped: If the confirmed dumps completes the current file, a new file will + * be loaded and this parameter will be set to true. + * @return If a file is swapped, the retrunvalue of the file swap operation. + */ + ReturnValue_t confirmDump(const PusTmReader& tmReader, bool& fileHasSwapped); void getStartAndEndTimeCurrentOrLastDump(uint32_t& startTime, uint32_t& endTime) const; ReturnValue_t storePacket(PusTmReader& reader); @@ -83,8 +93,6 @@ class PersistentTmStore : public TmStoreFrontendSimpleIF, public SystemObject { MessageQueueIF* tcQueue; State state = State::IDLE; - // PacketFilter filter; - CdsShortTimeStamper timeReader; bool baseDirUninitialized = true; const char* baseDir; std::string baseName; @@ -96,6 +104,7 @@ class PersistentTmStore : public TmStoreFrontendSimpleIF, public SystemObject { timeval activeFileTv{}; struct ActiveDumpParams { + bool pendingPacketDump = false; uint32_t fromUnixTime = 0; uint32_t untilUnixTime = 0; uint32_t currentFileUnixStamp = 0; -- 2.43.0 From 76ea3f79797b26819f2aaecf7b0ac313a9e5db28 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 31 Mar 2023 13:21:38 +0200 Subject: [PATCH 07/12] compile fixes --- bsp_hosted/ObjectFactory.cpp | 2 +- mission/com/TmStoreTaskBase.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/bsp_hosted/ObjectFactory.cpp b/bsp_hosted/ObjectFactory.cpp index b49bbf61..77ea7828 100644 --- a/bsp_hosted/ObjectFactory.cpp +++ b/bsp_hosted/ObjectFactory.cpp @@ -29,7 +29,7 @@ #include #include -#include "dummies/helpers.h" +#include "dummies/helperFactory.h" #ifdef PLATFORM_UNIX #include diff --git a/mission/com/TmStoreTaskBase.h b/mission/com/TmStoreTaskBase.h index 55448cde..440e142e 100644 --- a/mission/com/TmStoreTaskBase.h +++ b/mission/com/TmStoreTaskBase.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include -- 2.43.0 From 6ee3fe2eefac2d20e67c80294aca20e42aab40db Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 31 Mar 2023 13:22:07 +0200 Subject: [PATCH 08/12] changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3edceff..86aa5b6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,7 @@ will consitute of a breaking change warranting a new major release: - Bugfix for side lane transitions of the dual lane assemblies, which only worked when the assembly was directly commanded -- Syrlinks Handler: Only send transition commands once. +- Syrlinks Handler: Bugfix so transition command is only sent once. ## Added -- 2.43.0 From caa7c20adf03443e5aaded9b15091ff93d54392c Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 31 Mar 2023 15:12:05 +0200 Subject: [PATCH 09/12] tweaks --- linux/ipcore/PapbVcInterface.cpp | 30 ++++++++++++--------- linux/ipcore/PapbVcInterface.h | 4 +-- mission/com/PersistentSingleTmStoreTask.cpp | 3 +++ mission/com/TmStoreTaskBase.cpp | 3 ++- 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/linux/ipcore/PapbVcInterface.cpp b/linux/ipcore/PapbVcInterface.cpp index 446e3afd..c0deb5fc 100644 --- a/linux/ipcore/PapbVcInterface.cpp +++ b/linux/ipcore/PapbVcInterface.cpp @@ -27,27 +27,27 @@ ReturnValue_t PapbVcInterface::initialize() { } ReturnValue_t PapbVcInterface::write(const uint8_t* data, size_t size) { - if (pollPapbBusySignal(0) == returnvalue::OK) { + if (pollInterfaceReadiness(0, true) == returnvalue::OK) { startPacketTransfer(); } else { return DirectTmSinkIF::IS_BUSY; } for (size_t idx = 0; idx < size; idx++) { // This delay is super-important, DO NOT REMOVE! - // Polling the GPIO too often can mess up the scheduler. + // Polling the GPIO or the config register too often messes up the scheduler. // TODO: Maybe this should not be done like this. It would be better if there was a custom // FPGA module which can accept packets and then takes care of dumping that packet into // the PTME. DMA would be an ideal solution for this. - // nanosleep(&BETWEEN_POLL_DELAY, &remDelay); - if (pollPapbBusySignal(2) == returnvalue::OK) { + nanosleep(&BETWEEN_POLL_DELAY, &remDelay); + if (pollInterfaceReadiness(2, false) == returnvalue::OK) { *(vcBaseReg + DATA_REG_OFFSET) = static_cast(data[idx]); } else { abortPacketTransfer(); return returnvalue::FAILED; } } - // nanosleep(&BETWEEN_POLL_DELAY, &remDelay); - if (pollPapbBusySignal(2) == returnvalue::OK) { + nanosleep(&BETWEEN_POLL_DELAY, &remDelay); + if (pollInterfaceReadiness(2, false) == returnvalue::OK) { completePacketTransfer(); } else { abortPacketTransfer(); @@ -60,17 +60,23 @@ void PapbVcInterface::startPacketTransfer() { *vcBaseReg = CONFIG_START; } void PapbVcInterface::completePacketTransfer() { *vcBaseReg = CONFIG_END; } -ReturnValue_t PapbVcInterface::pollPapbBusySignal(uint32_t maxPollRetries) const { +ReturnValue_t PapbVcInterface::pollInterfaceReadiness(uint32_t maxPollRetries, + bool checkReadyState) const { uint32_t busyIdx = 0; - nextDelay.tv_nsec = 0; + nextDelay.tv_nsec = FIRST_NON_NULL_DELAY_NS; while (true) { // Check if PAPB interface is ready to receive data. Use the configuration register for this. // Bit 5, see PTME ptme_001_01-0-7-r2 Table 31. - bool busy = ((*vcBaseReg) >> 5) & 0b1; + uint32_t reg = *vcBaseReg; + bool busy = (reg >> 5) & 0b1; + bool ready = (reg >> 6) & 0b1; if (not busy) { return returnvalue::OK; } + if(checkReadyState and not ready) { + return PAPB_BUSY; + } busyIdx++; if (busyIdx >= maxPollRetries) { @@ -80,9 +86,7 @@ ReturnValue_t PapbVcInterface::pollPapbBusySignal(uint32_t maxPollRetries) const // Ignore signal handling here for now. nanosleep(&nextDelay, &remDelay); // Adaptive delay. - if (nextDelay.tv_nsec == 0) { - nextDelay.tv_nsec = FIRST_NON_NULL_DELAY_NS; - } else if (nextDelay.tv_nsec * 2 <= MAX_DELAY_PAPB_POLLING_NS) { + if (nextDelay.tv_nsec * 2 <= MAX_DELAY_PAPB_POLLING_NS) { nextDelay.tv_nsec *= 2; } } @@ -109,7 +113,7 @@ void PapbVcInterface::isVcInterfaceBufferEmpty() { return; } -bool PapbVcInterface::isBusy() const { return pollPapbBusySignal(0) == PAPB_BUSY; } +bool PapbVcInterface::isBusy() const { return pollInterfaceReadiness(0, true) == PAPB_BUSY; } void PapbVcInterface::cancelTransfer() { abortPacketTransfer(); } diff --git a/linux/ipcore/PapbVcInterface.h b/linux/ipcore/PapbVcInterface.h index 22b8ee5f..42cfbc19 100644 --- a/linux/ipcore/PapbVcInterface.h +++ b/linux/ipcore/PapbVcInterface.h @@ -91,7 +91,7 @@ class PapbVcInterface : public VirtualChannelIF { std::string uioFile; int mapNum = 0; mutable struct timespec nextDelay = {.tv_sec = 0, .tv_nsec = 0}; - const struct timespec BETWEEN_POLL_DELAY = {.tv_sec = 0, .tv_nsec = 5}; + const struct timespec BETWEEN_POLL_DELAY = {.tv_sec = 0, .tv_nsec = 10}; mutable struct timespec remDelay; volatile uint32_t* vcBaseReg = nullptr; @@ -119,7 +119,7 @@ class PapbVcInterface : public VirtualChannelIF { * * @return returnvalue::OK when ready to receive data else PAPB_BUSY. */ - inline ReturnValue_t pollPapbBusySignal(uint32_t maxPollRetries) const; + inline ReturnValue_t pollInterfaceReadiness(uint32_t maxPollRetries, bool checkReadyState) const; /** * @brief This function can be used for debugging to check whether there are packets in diff --git a/mission/com/PersistentSingleTmStoreTask.cpp b/mission/com/PersistentSingleTmStoreTask.cpp index 2d05b25f..421f2a74 100644 --- a/mission/com/PersistentSingleTmStoreTask.cpp +++ b/mission/com/PersistentSingleTmStoreTask.cpp @@ -25,6 +25,9 @@ ReturnValue_t PersistentSingleTmStoreTask::performOperation(uint8_t opCode) { } else if (dumpContext.vcBusyDuringDump) { // TODO: Might not be necessary TaskFactory::delayTask(10); + } else { + // TODO: Would be best to remove this, but not delaying here can lead to evil issues. + TaskFactory::delayTask(2); } } } diff --git a/mission/com/TmStoreTaskBase.cpp b/mission/com/TmStoreTaskBase.cpp index 91555f04..d6db4095 100644 --- a/mission/com/TmStoreTaskBase.cpp +++ b/mission/com/TmStoreTaskBase.cpp @@ -142,11 +142,12 @@ ReturnValue_t TmStoreTaskBase::performDump(PersistentTmStoreWithTmQueue& store, dumpDoneHandler(); return returnvalue::OK; } + dumpedLen = tmReader.getFullPacketLen(); // Only write to VC if mode is on, but always confirm the dump. // If the mode is OFF, it is assumed the PTME is not usable and is not allowed to be written // (e.g. to confirm a reset or the transmitter is off anyway). if (mode == MODE_ON) { - result = channel.write(tmReader.getFullData(), tmReader.getFullPacketLen()); + result = channel.write(tmReader.getFullData(), dumpedLen); if (result == DirectTmSinkIF::IS_BUSY) { sif::warning << "PersistentTmStore: Unexpected VC channel busy" << std::endl; } else if (result != returnvalue::OK) { -- 2.43.0 From 55a22c840cca3c002073dc76fd151b9e0bdee791 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 31 Mar 2023 16:51:30 +0200 Subject: [PATCH 10/12] PTME_LOCK atomic boolean and related handling --- CHANGELOG.md | 3 + bsp_q7s/core/ObjectFactory.cpp | 17 +- bsp_q7s/core/ObjectFactory.h | 1 + linux/ipcore/PapbVcInterface.cpp | 4 +- mission/com/CcsdsIpCoreHandler.cpp | 178 ++++++++++++-------- mission/com/CcsdsIpCoreHandler.h | 23 ++- mission/com/LiveTmTask.cpp | 7 +- mission/com/LiveTmTask.h | 3 +- mission/com/PersistentLogTmStoreTask.cpp | 5 +- mission/com/PersistentLogTmStoreTask.h | 3 +- mission/com/PersistentSingleTmStoreTask.cpp | 7 +- mission/com/PersistentSingleTmStoreTask.h | 2 +- mission/com/TmStoreTaskBase.cpp | 9 +- mission/com/TmStoreTaskBase.h | 5 +- 14 files changed, 165 insertions(+), 102 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 86aa5b6e..b69ce243 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,9 @@ will consitute of a breaking change warranting a new major release: used to disable ongoing dumps or to prevent writes to the PTME VC. This allows cleaner reset handling of the PTME. All 4 VC/store tasks were attached to the COM mode tree and are commanded as part of the COM sequence as well to ensure consistent state with the CCSDS IP core handler. +- Added `PTME_LOCKED` boolean lock which is used to lock the PTME so it is not used by the VC tasks + anymore. This lock will be controlled by the CCSDS IP core handler and is locked when the PTME + needs to be reset. Examples for this are datarate changes. ## Fixed diff --git a/bsp_q7s/core/ObjectFactory.cpp b/bsp_q7s/core/ObjectFactory.cpp index 629cf44c..c1b8ea4e 100644 --- a/bsp_q7s/core/ObjectFactory.cpp +++ b/bsp_q7s/core/ObjectFactory.cpp @@ -125,6 +125,7 @@ using gpio::Levels; ResetArgs RESET_ARGS_GNSS; std::atomic_bool LINK_STATE = CcsdsIpCoreHandler::LINK_DOWN; +std::atomic_bool PTME_LOCKED = false; std::atomic_uint16_t I2C_FATAL_ERRORS = 0; void Factory::setStaticFrameworkObjectIds() { @@ -789,14 +790,14 @@ ReturnValue_t ObjectFactory::createCcsdsComponents(CcsdsComponentArgs& args) { *args.ipCoreHandler = new CcsdsIpCoreHandler(objects::CCSDS_HANDLER, objects::CCSDS_PACKET_DISTRIBUTOR, *ptmeConfig, - LINK_STATE, &args.gpioComIF, gpios); + LINK_STATE, &args.gpioComIF, gpios, PTME_LOCKED); // This VC will receive all live TM auto* vcWithQueue = new VirtualChannelWithQueue(objects::PTME_VC0_LIVE_TM, ccsds::VC0, "PTME VC0 LIVE TM", *ptme, LINK_STATE, args.tmStore, 500); args.liveDestination = vcWithQueue; - auto* liveTask = - new LiveTmTask(objects::LIVE_TM_TASK, args.pusFunnel, args.cfdpFunnel, *vcWithQueue); + auto* liveTask = new LiveTmTask(objects::LIVE_TM_TASK, args.pusFunnel, args.cfdpFunnel, + *vcWithQueue, PTME_LOCKED); liveTask->connectModeTreeParent(satsystem::com::SUBSYSTEM); // Set up log store. @@ -804,15 +805,17 @@ ReturnValue_t ObjectFactory::createCcsdsComponents(CcsdsComponentArgs& args) { LINK_STATE); LogStores logStores(args.stores); // Core task which handles the LOG store and takes care of dumping it as TM using a VC directly - auto* logStore = new PersistentLogTmStoreTask(objects::LOG_STORE_AND_TM_TASK, args.ipcStore, - logStores, *vc, *SdCardManager::instance()); + auto* logStore = + new PersistentLogTmStoreTask(objects::LOG_STORE_AND_TM_TASK, args.ipcStore, logStores, *vc, + *SdCardManager::instance(), PTME_LOCKED); logStore->connectModeTreeParent(satsystem::com::SUBSYSTEM); vc = new VirtualChannel(objects::PTME_VC2_HK_TM, ccsds::VC2, "PTME VC2 HK TM", *ptme, LINK_STATE); // Core task which handles the HK store and takes care of dumping it as TM using a VC directly auto* hkStore = new PersistentSingleTmStoreTask( objects::HK_STORE_AND_TM_TASK, args.ipcStore, *args.stores.hkStore, *vc, - persTmStore::DUMP_HK_STORE_DONE, persTmStore::DUMP_HK_STORE_DONE, *SdCardManager::instance()); + persTmStore::DUMP_HK_STORE_DONE, persTmStore::DUMP_HK_STORE_DONE, *SdCardManager::instance(), + PTME_LOCKED); hkStore->connectModeTreeParent(satsystem::com::SUBSYSTEM); vc = new VirtualChannel(objects::PTME_VC3_CFDP_TM, ccsds::VC3, "PTME VC3 CFDP TM", *ptme, @@ -821,7 +824,7 @@ ReturnValue_t ObjectFactory::createCcsdsComponents(CcsdsComponentArgs& args) { auto* cfdpTask = new PersistentSingleTmStoreTask( objects::CFDP_STORE_AND_TM_TASK, args.ipcStore, *args.stores.cfdpStore, *vc, persTmStore::DUMP_CFDP_STORE_DONE, persTmStore::DUMP_CFDP_CANCELLED, - *SdCardManager::instance()); + *SdCardManager::instance(), PTME_LOCKED); cfdpTask->connectModeTreeParent(satsystem::com::SUBSYSTEM); ReturnValue_t result = (*args.ipCoreHandler)->connectModeTreeParent(satsystem::com::SUBSYSTEM); diff --git a/bsp_q7s/core/ObjectFactory.h b/bsp_q7s/core/ObjectFactory.h index 1d971a5e..b7380f2a 100644 --- a/bsp_q7s/core/ObjectFactory.h +++ b/bsp_q7s/core/ObjectFactory.h @@ -24,6 +24,7 @@ class AcsBoardAssembly; class GpioIF; extern std::atomic_uint16_t I2C_FATAL_ERRORS; +extern std::atomic_bool PTME_LOCKED; namespace ObjectFactory { diff --git a/linux/ipcore/PapbVcInterface.cpp b/linux/ipcore/PapbVcInterface.cpp index c0deb5fc..f00475c8 100644 --- a/linux/ipcore/PapbVcInterface.cpp +++ b/linux/ipcore/PapbVcInterface.cpp @@ -61,7 +61,7 @@ void PapbVcInterface::startPacketTransfer() { *vcBaseReg = CONFIG_START; } void PapbVcInterface::completePacketTransfer() { *vcBaseReg = CONFIG_END; } ReturnValue_t PapbVcInterface::pollInterfaceReadiness(uint32_t maxPollRetries, - bool checkReadyState) const { + bool checkReadyState) const { uint32_t busyIdx = 0; nextDelay.tv_nsec = FIRST_NON_NULL_DELAY_NS; @@ -74,7 +74,7 @@ ReturnValue_t PapbVcInterface::pollInterfaceReadiness(uint32_t maxPollRetries, if (not busy) { return returnvalue::OK; } - if(checkReadyState and not ready) { + if (checkReadyState and not ready) { return PAPB_BUSY; } diff --git a/mission/com/CcsdsIpCoreHandler.cpp b/mission/com/CcsdsIpCoreHandler.cpp index 806096b8..d4608191 100644 --- a/mission/com/CcsdsIpCoreHandler.cpp +++ b/mission/com/CcsdsIpCoreHandler.cpp @@ -15,9 +15,11 @@ CcsdsIpCoreHandler::CcsdsIpCoreHandler(object_id_t objectId, object_id_t tcDestination, PtmeConfig& ptmeConfig, std::atomic_bool& linkState, - GpioIF* gpioIF, PtmeGpios gpioIds) + GpioIF* gpioIF, PtmeGpios gpioIds, + std::atomic_bool& ptmeLocked) : SystemObject(objectId), linkState(linkState), + ptmeLocked(ptmeLocked), tcDestination(tcDestination), parameterHelper(this), actionHelper(this, nullptr), @@ -35,6 +37,7 @@ CcsdsIpCoreHandler::~CcsdsIpCoreHandler() = default; ReturnValue_t CcsdsIpCoreHandler::performOperation(uint8_t operationCode) { readCommandQueue(); + performPtmeUpdateWhenApplicable(); return returnvalue::OK; } @@ -127,10 +130,15 @@ ReturnValue_t CcsdsIpCoreHandler::getParameter(uint8_t domainId, uint8_t uniqueI return HasParametersIF::INVALID_VALUE; } parameterWrapper->set(batPriorityParam); - if (mode == MODE_ON) { - updateBatPriorityOnTxOff = true; - } else if (mode == MODE_OFF) { - updateBatPriorityFromParam(); + if (newVal != batPriorityParam) { + // This ensures that the BAT priority is updated at some point when an update of the PTME is + // allowed + updateContext.updateBatPrio = true; + // If we are off, we can do the update after X cycles. Otherwise, wait until the transmitter + // goes off. + if (mode == MODE_OFF) { + initPtmeUpdateAfterXCycles(); + } } return returnvalue::OK; } @@ -148,36 +156,12 @@ ReturnValue_t CcsdsIpCoreHandler::executeAction(ActionId_t actionId, MessageQueu const uint8_t* data, size_t size) { ReturnValue_t result = returnvalue::OK; switch (actionId) { - case SET_LOW_RATE: { - submode = static_cast(com::CcsdsSubmode::DATARATE_LOW); - result = ptmeConfig.setRate(RATE_100KBPS); - break; - } - case SET_HIGH_RATE: { - submode = static_cast(com::CcsdsSubmode::DATARATE_HIGH); - result = ptmeConfig.setRate(RATE_500KBPS); - break; - } case ARBITRARY_RATE: { uint32_t bitrate = 0; SerializeAdapter::deSerialize(&bitrate, &data, &size, SerializeIF::Endianness::BIG); result = ptmeConfig.setRate(bitrate); break; } - case EN_TRANSMITTER: { - enableTransmit(); - if (mode == HasModesIF::MODE_OFF) { - mode = HasModesIF::MODE_ON; - } - return EXECUTION_FINISHED; - } - case DISABLE_TRANSMITTER: { - disableTransmit(); - if (mode == HasModesIF::MODE_ON) { - mode = HasModesIF::MODE_OFF; - } - return EXECUTION_FINISHED; - } case ENABLE_TX_CLK_MANIPULATOR: { result = ptmeConfig.configTxManipulator(true); break; @@ -206,12 +190,8 @@ ReturnValue_t CcsdsIpCoreHandler::executeAction(ActionId_t actionId, MessageQueu void CcsdsIpCoreHandler::updateLinkState() { linkState = LINK_UP; } void CcsdsIpCoreHandler::enableTransmit() { - // Reset PTME on each transmit enable. - updateBatPriorityFromParam(); -#ifndef TE0720_1CFA gpioIF->pullHigh(ptmeGpios.enableTxClock); gpioIF->pullHigh(ptmeGpios.enableTxData); -#endif linkState = LINK_UP; } @@ -236,34 +216,23 @@ ReturnValue_t CcsdsIpCoreHandler::checkModeCommand(Mode_t mode, Submode_t submod } void CcsdsIpCoreHandler::startTransition(Mode_t mode, Submode_t submode) { - auto rateSet = [&](uint32_t rate) { - ReturnValue_t result = ptmeConfig.setRate(rate); - if (result == returnvalue::OK) { - this->mode = HasModesIF::MODE_ON; - } - }; + triggerEvent(CHANGING_MODE, mode, submode); if (mode == HasModesIF::MODE_ON) { - enableTransmit(); - if (submode == static_cast(com::CcsdsSubmode::DATARATE_DEFAULT)) { - com::Datarate currentDatarate = com::getCurrentDatarate(); - if (currentDatarate == com::Datarate::LOW_RATE_MODULATION_BPSK) { - rateSet(RATE_100KBPS); - } else if (currentDatarate == com::Datarate::HIGH_RATE_MODULATION_0QPSK) { - rateSet(RATE_500KBPS); - } - } else if (submode == static_cast(com::CcsdsSubmode::DATARATE_HIGH)) { - rateSet(RATE_500KBPS); - } else if (submode == static_cast(com::CcsdsSubmode::DATARATE_LOW)) { - rateSet(RATE_100KBPS); + if (this->submode != submode) { + initPtmeUpdateAfterXCycles(); + updateContext.enableTransmitAfterPtmeUpdate = true; + updateContext.updateClockRate = true; + this->submode = submode; + this->mode = mode; + updateContext.setModeAfterUpdate = true; + return; } - + // No rate change, so enable transmitter right away. + enableTransmit(); } else if (mode == HasModesIF::MODE_OFF) { disableTransmit(); - this->mode = HasModesIF::MODE_OFF; } - this->submode = submode; - modeHelper.modeChanged(mode, submode); - announceMode(false); + setMode(mode, submode); } void CcsdsIpCoreHandler::announceMode(bool recursive) { triggerEvent(MODE_INFO, mode, submode); } @@ -274,9 +243,9 @@ void CcsdsIpCoreHandler::disableTransmit() { gpioIF->pullLow(ptmeGpios.enableTxData); #endif linkState = LINK_DOWN; - if (updateBatPriorityOnTxOff) { - updateBatPriorityFromParam(); - updateBatPriorityOnTxOff = false; + // Some parameters need update and transmitter is off now. + if (updateContext.updateBatPrio or updateContext.updateClockRate) { + initPtmeUpdateAfterXCycles(); } } @@ -294,21 +263,9 @@ ModeTreeChildIF& CcsdsIpCoreHandler::getModeTreeChildIF() { return *this; } object_id_t CcsdsIpCoreHandler::getObjectId() const { return SystemObject::getObjectId(); } -void CcsdsIpCoreHandler::enablePrioritySelectMode() { - ptmeConfig.enableBatPriorityBit(true); - // Reset the PTME - gpioIF->pullLow(ptmeGpios.ptmeResetn); - usleep(10); - gpioIF->pullHigh(ptmeGpios.ptmeResetn); -} +void CcsdsIpCoreHandler::enablePrioritySelectMode() { ptmeConfig.enableBatPriorityBit(true); } -void CcsdsIpCoreHandler::disablePrioritySelectMode() { - ptmeConfig.enableBatPriorityBit(false); - // Reset the PTME - gpioIF->pullLow(ptmeGpios.ptmeResetn); - usleep(10); - gpioIF->pullHigh(ptmeGpios.ptmeResetn); -} +void CcsdsIpCoreHandler::disablePrioritySelectMode() { ptmeConfig.enableBatPriorityBit(false); } void CcsdsIpCoreHandler::updateBatPriorityFromParam() { if (batPriorityParam == 0) { @@ -317,3 +274,78 @@ void CcsdsIpCoreHandler::updateBatPriorityFromParam() { enablePrioritySelectMode(); } } + +void CcsdsIpCoreHandler::setMode(Mode_t mode, Submode_t submode) { + this->submode = submode; + this->mode = mode; + modeHelper.modeChanged(mode, submode); + announceMode(false); +} + +void CcsdsIpCoreHandler::performPtmeUpdateWhenApplicable() { + if (not updateContext.performPtmeUpdateAfterXCycles) { + return; + } + if (updateContext.ptmeUpdateCycleCount >= 2) { + if (updateContext.updateBatPrio) { + updateBatPriorityFromParam(); + updateContext.updateBatPrio = false; + } + ReturnValue_t result; + if (updateContext.updateClockRate) { + if (submode == static_cast(com::CcsdsSubmode::DATARATE_DEFAULT)) { + com::Datarate currentDatarate = com::getCurrentDatarate(); + if (currentDatarate == com::Datarate::LOW_RATE_MODULATION_BPSK) { + result = ptmeConfig.setRate(RATE_100KBPS); + } else if (currentDatarate == com::Datarate::HIGH_RATE_MODULATION_0QPSK) { + result = ptmeConfig.setRate(RATE_500KBPS); + } + } else if (submode == static_cast(com::CcsdsSubmode::DATARATE_HIGH)) { + result = ptmeConfig.setRate(RATE_500KBPS); + } else if (submode == static_cast(com::CcsdsSubmode::DATARATE_LOW)) { + result = ptmeConfig.setRate(RATE_100KBPS); + } + if (result != returnvalue::OK) { + sif::error << "CcsdsIpCoreHandler: Setting datarate failed" << std::endl; + } + updateContext.updateClockRate = false; + } + bool doResetPtme = true; + if (not updateContext.updateBatPrio and not updateContext.updateClockRate) { + doResetPtme = false; + } + finishPtmeUpdateAfterXCycles(doResetPtme); + return; + } + updateContext.ptmeUpdateCycleCount++; +} + +void CcsdsIpCoreHandler::resetPtme() { + gpioIF->pullLow(ptmeGpios.ptmeResetn); + usleep(10); + gpioIF->pullHigh(ptmeGpios.ptmeResetn); +} + +void CcsdsIpCoreHandler::initPtmeUpdateAfterXCycles() { + if (not updateContext.performPtmeUpdateAfterXCycles) { + updateContext.performPtmeUpdateAfterXCycles = true; + updateContext.ptmeUpdateCycleCount = 0; + } +} + +void CcsdsIpCoreHandler::finishPtmeUpdateAfterXCycles(bool doResetPtme) { + if (doResetPtme) { + resetPtme(); + } + ptmeLocked = false; + updateContext.performPtmeUpdateAfterXCycles = false; + updateContext.ptmeUpdateCycleCount = 0; + if (updateContext.enableTransmitAfterPtmeUpdate) { + enableTransmit(); + updateContext.enableTransmitAfterPtmeUpdate = false; + } + if (updateContext.setModeAfterUpdate) { + setMode(mode, submode); + updateContext.setModeAfterUpdate = false; + } +} diff --git a/mission/com/CcsdsIpCoreHandler.h b/mission/com/CcsdsIpCoreHandler.h index fc686230..785f84a5 100644 --- a/mission/com/CcsdsIpCoreHandler.h +++ b/mission/com/CcsdsIpCoreHandler.h @@ -79,7 +79,8 @@ class CcsdsIpCoreHandler : public SystemObject, * @param enTxData GPIO ID of RS485 tx data enable */ CcsdsIpCoreHandler(object_id_t objectId, object_id_t tcDestination, PtmeConfig& ptmeConfig, - std::atomic_bool& linkState, GpioIF* gpioIF, PtmeGpios gpioIds); + std::atomic_bool& linkState, GpioIF* gpioIF, PtmeGpios gpioIds, + std::atomic_bool& ptmeLocked); ~CcsdsIpCoreHandler(); @@ -137,9 +138,8 @@ class CcsdsIpCoreHandler : public SystemObject, //! [EXPORT] : [COMMENT] Received action message with unknown action id static const ReturnValue_t COMMAND_NOT_IMPLEMENTED = MAKE_RETURN_CODE(0xA0); - // using VirtualChannelMap = std::unordered_map; - // VirtualChannelMap virtualChannelMap; std::atomic_bool& linkState; + std::atomic_bool& ptmeLocked; object_id_t tcDestination; @@ -158,7 +158,15 @@ class CcsdsIpCoreHandler : public SystemObject, PtmeGpios ptmeGpios; // BAT priority bit on by default to enable priority selection mode for the PTME. uint8_t batPriorityParam = 0; - bool updateBatPriorityOnTxOff = false; + + struct UpdateContext { + bool updateBatPrio = false; + bool updateClockRate = false; + bool enableTransmitAfterPtmeUpdate = false; + uint8_t ptmeUpdateCycleCount = 0; + bool performPtmeUpdateAfterXCycles = false; + bool setModeAfterUpdate = false; + } updateContext{}; GpioIF* gpioIF = nullptr; @@ -180,6 +188,8 @@ class CcsdsIpCoreHandler : public SystemObject, */ void disableTransmit(); + void performPtmeUpdateWhenApplicable(); + /** * The following set of functions configure the mode of the PTME bandwith allocation table (BAT) * module. This consists of the following 2 steps: @@ -189,6 +199,11 @@ class CcsdsIpCoreHandler : public SystemObject, void enablePrioritySelectMode(); void disablePrioritySelectMode(); void updateBatPriorityFromParam(); + + void setMode(Mode_t mode, Submode_t submode); + void resetPtme(); + void initPtmeUpdateAfterXCycles(); + void finishPtmeUpdateAfterXCycles(bool doResetPtme); }; #endif /* CCSDSHANDLER_H_ */ diff --git a/mission/com/LiveTmTask.cpp b/mission/com/LiveTmTask.cpp index 236a3292..d09c6ced 100644 --- a/mission/com/LiveTmTask.cpp +++ b/mission/com/LiveTmTask.cpp @@ -6,12 +6,13 @@ #include LiveTmTask::LiveTmTask(object_id_t objectId, PusTmFunnel& pusFunnel, CfdpTmFunnel& cfdpFunnel, - VirtualChannelWithQueue& channel) + VirtualChannelWithQueue& channel, const std::atomic_bool& ptmeLocked) : SystemObject(objectId), modeHelper(this), pusFunnel(pusFunnel), cfdpFunnel(cfdpFunnel), - channel(channel) { + channel(channel), + ptmeLocked(ptmeLocked) { requestQueue = QueueFactory::instance()->createMessageQueue(); } @@ -19,7 +20,7 @@ ReturnValue_t LiveTmTask::performOperation(uint8_t opCode) { readCommandQueue(); while (true) { bool performWriteOp = true; - if (mode == MODE_OFF) { + if (mode == MODE_OFF or ptmeLocked) { performWriteOp = false; } diff --git a/mission/com/LiveTmTask.h b/mission/com/LiveTmTask.h index ca63cd02..c203f1de 100644 --- a/mission/com/LiveTmTask.h +++ b/mission/com/LiveTmTask.h @@ -18,7 +18,7 @@ class LiveTmTask : public SystemObject, public ModeTreeConnectionIF { public: LiveTmTask(object_id_t objectId, PusTmFunnel& pusFunnel, CfdpTmFunnel& cfdpFunnel, - VirtualChannelWithQueue& channel); + VirtualChannelWithQueue& channel, const std::atomic_bool& ptmeLocked); ReturnValue_t performOperation(uint8_t opCode) override; ReturnValue_t initialize() override; @@ -33,6 +33,7 @@ class LiveTmTask : public SystemObject, CfdpTmFunnel& cfdpFunnel; VirtualChannelWithQueue& channel; uint32_t packetCounter = 0; + const std::atomic_bool& ptmeLocked; void readCommandQueue(void); diff --git a/mission/com/PersistentLogTmStoreTask.cpp b/mission/com/PersistentLogTmStoreTask.cpp index 07fe5ad6..8ba7200f 100644 --- a/mission/com/PersistentLogTmStoreTask.cpp +++ b/mission/com/PersistentLogTmStoreTask.cpp @@ -5,8 +5,9 @@ PersistentLogTmStoreTask::PersistentLogTmStoreTask(object_id_t objectId, StorageManagerIF& ipcStore, LogStores stores, VirtualChannel& channel, - SdCardMountedIF& sdcMan) - : TmStoreTaskBase(objectId, ipcStore, channel, sdcMan), + SdCardMountedIF& sdcMan, + const std::atomic_bool& ptmeLocked) + : TmStoreTaskBase(objectId, ipcStore, channel, sdcMan, ptmeLocked), stores(stores), okStoreContext(persTmStore::DUMP_OK_STORE_DONE, persTmStore::DUMP_OK_CANCELLED), notOkStoreContext(persTmStore::DUMP_NOK_STORE_DONE, persTmStore::DUMP_NOK_CANCELLED), diff --git a/mission/com/PersistentLogTmStoreTask.h b/mission/com/PersistentLogTmStoreTask.h index 51431e2f..18da93f5 100644 --- a/mission/com/PersistentLogTmStoreTask.h +++ b/mission/com/PersistentLogTmStoreTask.h @@ -22,7 +22,8 @@ struct LogStores { class PersistentLogTmStoreTask : public TmStoreTaskBase, public ExecutableObjectIF { public: PersistentLogTmStoreTask(object_id_t objectId, StorageManagerIF& ipcStore, LogStores tmStore, - VirtualChannel& channel, SdCardMountedIF& sdcMan); + VirtualChannel& channel, SdCardMountedIF& sdcMan, + const std::atomic_bool& ptmeLocked); ReturnValue_t performOperation(uint8_t opCode) override; diff --git a/mission/com/PersistentSingleTmStoreTask.cpp b/mission/com/PersistentSingleTmStoreTask.cpp index 421f2a74..10bedee5 100644 --- a/mission/com/PersistentSingleTmStoreTask.cpp +++ b/mission/com/PersistentSingleTmStoreTask.cpp @@ -6,8 +6,9 @@ PersistentSingleTmStoreTask::PersistentSingleTmStoreTask( object_id_t objectId, StorageManagerIF& ipcStore, PersistentTmStoreWithTmQueue& tmStore, - VirtualChannel& channel, Event eventIfDumpDone, Event eventIfCancelled, SdCardMountedIF& sdcMan) - : TmStoreTaskBase(objectId, ipcStore, channel, sdcMan), + VirtualChannel& channel, Event eventIfDumpDone, Event eventIfCancelled, SdCardMountedIF& sdcMan, + const std::atomic_bool& ptmeLocked) + : TmStoreTaskBase(objectId, ipcStore, channel, sdcMan, ptmeLocked), storeWithQueue(tmStore), dumpContext(eventIfDumpDone, eventIfCancelled) {} @@ -27,7 +28,7 @@ ReturnValue_t PersistentSingleTmStoreTask::performOperation(uint8_t opCode) { TaskFactory::delayTask(10); } else { // TODO: Would be best to remove this, but not delaying here can lead to evil issues. - TaskFactory::delayTask(2); + TaskFactory::delayTask(10); } } } diff --git a/mission/com/PersistentSingleTmStoreTask.h b/mission/com/PersistentSingleTmStoreTask.h index 4cbf1544..1a4c8683 100644 --- a/mission/com/PersistentSingleTmStoreTask.h +++ b/mission/com/PersistentSingleTmStoreTask.h @@ -12,7 +12,7 @@ class PersistentSingleTmStoreTask : public TmStoreTaskBase, public ExecutableObj PersistentSingleTmStoreTask(object_id_t objectId, StorageManagerIF& ipcStore, PersistentTmStoreWithTmQueue& storeWithQueue, VirtualChannel& channel, Event eventIfDumpDone, Event eventIfCancelled, - SdCardMountedIF& sdcMan); + SdCardMountedIF& sdcMan, const std::atomic_bool& ptmeLocked); ReturnValue_t performOperation(uint8_t opCode) override; diff --git a/mission/com/TmStoreTaskBase.cpp b/mission/com/TmStoreTaskBase.cpp index d6db4095..6598225d 100644 --- a/mission/com/TmStoreTaskBase.cpp +++ b/mission/com/TmStoreTaskBase.cpp @@ -10,13 +10,15 @@ #include "mission/persistentTmStoreDefs.h" TmStoreTaskBase::TmStoreTaskBase(object_id_t objectId, StorageManagerIF& ipcStore, - VirtualChannel& channel, SdCardMountedIF& sdcMan) + VirtualChannel& channel, SdCardMountedIF& sdcMan, + const std::atomic_bool& ptmeLocked) : SystemObject(objectId), modeHelper(this), ipcStore(ipcStore), tmReader(&timeReader), channel(channel), - sdcMan(sdcMan) { + sdcMan(sdcMan), + ptmeLocked(ptmeLocked) { requestQueue = QueueFactory::instance()->createMessageQueue(10); } @@ -99,7 +101,8 @@ ReturnValue_t TmStoreTaskBase::handleOneDump(PersistentTmStoreWithTmQueue& store cancelDump(dumpContext, store, false); return returnvalue::FAILED; } - if (not channel.isBusy()) { + // It is assumed that the PTME will only be locked for a short period (e.g. to change datarate). + if (not channel.isBusy() and not ptmeLocked) { performDump(store, dumpContext, dumpPerformed); } else { // The PTME might be at full load, so it might sense to delay for a bit to let it do diff --git a/mission/com/TmStoreTaskBase.h b/mission/com/TmStoreTaskBase.h index 440e142e..ef61bd19 100644 --- a/mission/com/TmStoreTaskBase.h +++ b/mission/com/TmStoreTaskBase.h @@ -40,7 +40,7 @@ class TmStoreTaskBase : public SystemObject, }; TmStoreTaskBase(object_id_t objectId, StorageManagerIF& ipcStore, VirtualChannel& channel, - SdCardMountedIF& sdcMan); + SdCardMountedIF& sdcMan, const std::atomic_bool& ptmeLocked); ReturnValue_t initialize() override; ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF& parent) override; @@ -52,6 +52,8 @@ class TmStoreTaskBase : public SystemObject, PusTmReader tmReader; CdsShortTimeStamper timeReader; VirtualChannel& channel; + SdCardMountedIF& sdcMan; + const std::atomic_bool& ptmeLocked; Mode_t mode = HasModesIF::MODE_OFF; Countdown sdCardCheckCd = Countdown(800); @@ -62,7 +64,6 @@ class TmStoreTaskBase : public SystemObject, bool storesInitialized = false; bool fileHasSwapped = false; - SdCardMountedIF& sdcMan; void readCommandQueue(void); -- 2.43.0 From f16d92c1b18a85efe239c1880887f7af8d8f79a8 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 31 Mar 2023 17:05:01 +0200 Subject: [PATCH 11/12] some more lock handling --- mission/com/CcsdsIpCoreHandler.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mission/com/CcsdsIpCoreHandler.cpp b/mission/com/CcsdsIpCoreHandler.cpp index d4608191..84c49e8b 100644 --- a/mission/com/CcsdsIpCoreHandler.cpp +++ b/mission/com/CcsdsIpCoreHandler.cpp @@ -31,6 +31,7 @@ CcsdsIpCoreHandler::CcsdsIpCoreHandler(object_id_t objectId, object_id_t tcDesti auto mqArgs = MqArgs(objectId, static_cast(this)); eventQueue = QueueFactory::instance()->createMessageQueue(10, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs); + ptmeLocked = true; } CcsdsIpCoreHandler::~CcsdsIpCoreHandler() = default; @@ -79,6 +80,8 @@ ReturnValue_t CcsdsIpCoreHandler::initialize() { } else { enablePrioritySelectMode(); } + resetPtme(); + ptmeLocked = false; #if OBSW_SYRLINKS_SIMULATED == 1 // Update data on rising edge @@ -330,6 +333,7 @@ void CcsdsIpCoreHandler::initPtmeUpdateAfterXCycles() { if (not updateContext.performPtmeUpdateAfterXCycles) { updateContext.performPtmeUpdateAfterXCycles = true; updateContext.ptmeUpdateCycleCount = 0; + ptmeLocked = true; } } -- 2.43.0 From 6c8eeeab315576498b60bfd25c6603302a1e8e2b Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 31 Mar 2023 17:12:11 +0200 Subject: [PATCH 12/12] init result --- mission/com/CcsdsIpCoreHandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mission/com/CcsdsIpCoreHandler.cpp b/mission/com/CcsdsIpCoreHandler.cpp index 84c49e8b..d260d50e 100644 --- a/mission/com/CcsdsIpCoreHandler.cpp +++ b/mission/com/CcsdsIpCoreHandler.cpp @@ -294,7 +294,7 @@ void CcsdsIpCoreHandler::performPtmeUpdateWhenApplicable() { updateBatPriorityFromParam(); updateContext.updateBatPrio = false; } - ReturnValue_t result; + ReturnValue_t result = returnvalue::OK; if (updateContext.updateClockRate) { if (submode == static_cast(com::CcsdsSubmode::DATARATE_DEFAULT)) { com::Datarate currentDatarate = com::getCurrentDatarate(); -- 2.43.0