From ffe1281eb9454ac0de0263f44ae53294b3bb1920 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 13 Oct 2023 09:20:51 +0200 Subject: [PATCH 1/4] fix PTME --- .../fsfwconfig/events/translateEvents.cpp | 2 +- .../fsfwconfig/objects/translateObjects.cpp | 2 +- common/config/eive/resultClassIds.h | 1 + generators/bsp_hosted_returnvalues.csv | 2 + generators/bsp_q7s_returnvalues.csv | 4 +- generators/events/translateEvents.cpp | 2 +- generators/objects/translateObjects.cpp | 2 +- linux/fsfwconfig/events/translateEvents.cpp | 2 +- linux/fsfwconfig/objects/translateObjects.cpp | 2 +- linux/ipcore/PapbVcInterface.cpp | 53 +++++++++---------- linux/ipcore/PapbVcInterface.h | 12 ++--- linux/ipcore/Ptme.cpp | 34 ++++-------- linux/ipcore/Ptme.h | 5 +- linux/ipcore/PtmeIF.h | 14 ++--- mission/com/TmStoreTaskBase.cpp | 13 ++++- mission/com/VirtualChannel.cpp | 51 +++++++++++++++--- mission/com/VirtualChannel.h | 11 +++- mission/com/VirtualChannelWithQueue.cpp | 13 ++++- mission/tmtc/DirectTmSinkIF.h | 8 ++- tmtc | 2 +- 20 files changed, 141 insertions(+), 94 deletions(-) diff --git a/bsp_hosted/fsfwconfig/events/translateEvents.cpp b/bsp_hosted/fsfwconfig/events/translateEvents.cpp index 9bb03ff0..13b2f7d5 100644 --- a/bsp_hosted/fsfwconfig/events/translateEvents.cpp +++ b/bsp_hosted/fsfwconfig/events/translateEvents.cpp @@ -1,7 +1,7 @@ /** * @brief Auto-generated event translation file. Contains 313 translations. * @details - * Generated on: 2023-10-11 10:54:39 + * Generated on: 2023-10-13 09:17:41 */ #include "translateEvents.h" diff --git a/bsp_hosted/fsfwconfig/objects/translateObjects.cpp b/bsp_hosted/fsfwconfig/objects/translateObjects.cpp index 7e795093..00170e41 100644 --- a/bsp_hosted/fsfwconfig/objects/translateObjects.cpp +++ b/bsp_hosted/fsfwconfig/objects/translateObjects.cpp @@ -2,7 +2,7 @@ * @brief Auto-generated object translation file. * @details * Contains 174 translations. - * Generated on: 2023-10-11 10:54:39 + * Generated on: 2023-10-13 09:17:41 */ #include "translateObjects.h" diff --git a/common/config/eive/resultClassIds.h b/common/config/eive/resultClassIds.h index 9e2a3f2f..35b2a419 100644 --- a/common/config/eive/resultClassIds.h +++ b/common/config/eive/resultClassIds.h @@ -41,6 +41,7 @@ enum commonClassIds : uint8_t { LOCAL_PARAM_HANDLER, // LPH PERSISTENT_TM_STORE, // PTM TM_SINK, // TMS + VIRTUAL_CHANNEL, // VCS COMMON_CLASS_ID_END // [EXPORT] : [END] }; } diff --git a/generators/bsp_hosted_returnvalues.csv b/generators/bsp_hosted_returnvalues.csv index 0dfc94c3..ea7717f8 100644 --- a/generators/bsp_hosted_returnvalues.csv +++ b/generators/bsp_hosted_returnvalues.csv @@ -513,3 +513,5 @@ Full ID (hex); Name; Description; Unique ID; Subsytem Name; File Path 0x6d00;PTM_DumpDone;No description;0;PERSISTENT_TM_STORE;mission/tmtc/PersistentTmStore.h 0x6d01;PTM_BusyDumping;No description;1;PERSISTENT_TM_STORE;mission/tmtc/PersistentTmStore.h 0x6e00;TMS_IsBusy;No description;0;TM_SINK;mission/tmtc/DirectTmSinkIF.h +0x6e01;TMS_PartiallyWritten;No description;1;TM_SINK;mission/tmtc/DirectTmSinkIF.h +0x6f00;VCS_ChannelDoesNotExist;No description;0;VIRTUAL_CHANNEL;mission/com/VirtualChannel.h diff --git a/generators/bsp_q7s_returnvalues.csv b/generators/bsp_q7s_returnvalues.csv index 0e804457..c47d15e1 100644 --- a/generators/bsp_q7s_returnvalues.csv +++ b/generators/bsp_q7s_returnvalues.csv @@ -608,4 +608,6 @@ Full ID (hex); Name; Description; Unique ID; Subsytem Name; File Path 0x6d00;PTM_DumpDone;No description;0;PERSISTENT_TM_STORE;mission/tmtc/PersistentTmStore.h 0x6d01;PTM_BusyDumping;No description;1;PERSISTENT_TM_STORE;mission/tmtc/PersistentTmStore.h 0x6e00;TMS_IsBusy;No description;0;TM_SINK;mission/tmtc/DirectTmSinkIF.h -0x7000;SCBU_KeyNotFound;No description;0;SCRATCH_BUFFER;bsp_q7s/memory/scratchApi.h +0x6e01;TMS_PartiallyWritten;No description;1;TM_SINK;mission/tmtc/DirectTmSinkIF.h +0x6f00;VCS_ChannelDoesNotExist;No description;0;VIRTUAL_CHANNEL;mission/com/VirtualChannel.h +0x7100;SCBU_KeyNotFound;No description;0;SCRATCH_BUFFER;bsp_q7s/memory/scratchApi.h diff --git a/generators/events/translateEvents.cpp b/generators/events/translateEvents.cpp index 9bb03ff0..13b2f7d5 100644 --- a/generators/events/translateEvents.cpp +++ b/generators/events/translateEvents.cpp @@ -1,7 +1,7 @@ /** * @brief Auto-generated event translation file. Contains 313 translations. * @details - * Generated on: 2023-10-11 10:54:39 + * Generated on: 2023-10-13 09:17:41 */ #include "translateEvents.h" diff --git a/generators/objects/translateObjects.cpp b/generators/objects/translateObjects.cpp index 0599cc18..06da3f47 100644 --- a/generators/objects/translateObjects.cpp +++ b/generators/objects/translateObjects.cpp @@ -2,7 +2,7 @@ * @brief Auto-generated object translation file. * @details * Contains 178 translations. - * Generated on: 2023-10-11 10:54:39 + * Generated on: 2023-10-13 09:17:41 */ #include "translateObjects.h" diff --git a/linux/fsfwconfig/events/translateEvents.cpp b/linux/fsfwconfig/events/translateEvents.cpp index 9bb03ff0..13b2f7d5 100644 --- a/linux/fsfwconfig/events/translateEvents.cpp +++ b/linux/fsfwconfig/events/translateEvents.cpp @@ -1,7 +1,7 @@ /** * @brief Auto-generated event translation file. Contains 313 translations. * @details - * Generated on: 2023-10-11 10:54:39 + * Generated on: 2023-10-13 09:17:41 */ #include "translateEvents.h" diff --git a/linux/fsfwconfig/objects/translateObjects.cpp b/linux/fsfwconfig/objects/translateObjects.cpp index 0599cc18..06da3f47 100644 --- a/linux/fsfwconfig/objects/translateObjects.cpp +++ b/linux/fsfwconfig/objects/translateObjects.cpp @@ -2,7 +2,7 @@ * @brief Auto-generated object translation file. * @details * Contains 178 translations. - * Generated on: 2023-10-11 10:54:39 + * Generated on: 2023-10-13 09:17:41 */ #include "translateObjects.h" diff --git a/linux/ipcore/PapbVcInterface.cpp b/linux/ipcore/PapbVcInterface.cpp index 5dcb4519..5e63aebc 100644 --- a/linux/ipcore/PapbVcInterface.cpp +++ b/linux/ipcore/PapbVcInterface.cpp @@ -23,7 +23,7 @@ ReturnValue_t PapbVcInterface::initialize() { return returnvalue::OK; } -ReturnValue_t PapbVcInterface::write(const uint8_t* data, size_t size) { +ReturnValue_t PapbVcInterface::write(const uint8_t* data, size_t size, size_t& writtenSize) { // There are no packets smaller than 4, this is considered a configuration error. if (size < 4) { return returnvalue::FAILED; @@ -37,19 +37,7 @@ ReturnValue_t PapbVcInterface::write(const uint8_t* data, size_t size) { abortPacketTransfer(); return returnvalue::FAILED; } - for (size_t idx = 0; idx < size; idx++) { - if (not pollReadyForOctet(MAX_BUSY_POLLS)) { - abortPacketTransfer(); - return returnvalue::FAILED; - } - *(vcBaseReg + DATA_REG_OFFSET) = static_cast(data[idx]); - } - if (not pollReadyForOctet(MAX_BUSY_POLLS)) { - abortPacketTransfer(); - return returnvalue::FAILED; - } - completePacketTransfer(); - return returnvalue::OK; + return finishWritePartialOpt(data, size, true); } void PapbVcInterface::startPacketTransfer(ByteWidthCfg initWidth) { @@ -65,6 +53,26 @@ bool PapbVcInterface::pollReadyForPacket() const { return (reg >> 6) & 0b1; } +ReturnValue_t PapbVcInterface::finishWritePartialOpt(const uint8_t* data, size_t remainingSize, + bool handlePartial) { + for (size_t idx = 0; idx < remainingSize; idx++) { + if (not pollReadyForOctet(MAX_BUSY_POLLS)) { + if (not pollReadyForPacket()) { + return PARTIALLY_WRITTEN; + } + abortPacketTransfer(); + return returnvalue::FAILED; + } + *(vcBaseReg + DATA_REG_OFFSET) = static_cast(data[idx]); + } + if (not pollReadyForOctet(MAX_BUSY_POLLS)) { + abortPacketTransfer(); + return returnvalue::FAILED; + } + completePacketTransfer(); + return returnvalue::OK; +} + bool PapbVcInterface::isVcInterfaceBufferEmpty() { ReturnValue_t result = returnvalue::OK; gpio::Levels papbEmptyState = gpio::Levels::HIGH; @@ -101,21 +109,8 @@ inline bool PapbVcInterface::pollReadyForOctet(uint32_t maxCycles) const { return false; } -ReturnValue_t PapbVcInterface::sendTestFrame() { - /** Size of one complete transfer frame data field amounts to 1105 bytes */ - uint8_t testPacket[1105]; - - /** Fill one test packet */ - for (int idx = 0; idx < 1105; idx++) { - testPacket[idx] = static_cast(idx & 0xFF); - } - - ReturnValue_t result = write(testPacket, 1105); - if (result != returnvalue::OK) { - return result; - } - - return returnvalue::OK; +ReturnValue_t PapbVcInterface::finishWrite(const uint8_t* data, size_t remainingSize) { + return finishWritePartialOpt(data, remainingSize, false); } void PapbVcInterface::abortPacketTransfer() { *vcBaseReg = CONFIG_ABORT; } diff --git a/linux/ipcore/PapbVcInterface.h b/linux/ipcore/PapbVcInterface.h index b5160748..72b9b9f3 100644 --- a/linux/ipcore/PapbVcInterface.h +++ b/linux/ipcore/PapbVcInterface.h @@ -40,7 +40,11 @@ class PapbVcInterface : public VirtualChannelIF { * @param size * @return returnvalue::OK on successfull write, PAPB_BUSY if PAPB is busy. */ - ReturnValue_t write(const uint8_t* data, size_t size) override; + ReturnValue_t write(const uint8_t* data, size_t size, size_t& writtenSize) override; + + ReturnValue_t finishWrite(const uint8_t* data, size_t remainingSize) override; + ReturnValue_t finishWritePartialOpt(const uint8_t* data, size_t remainingSize, + bool handlePartial); void cancelTransfer() override; @@ -126,12 +130,6 @@ class PapbVcInterface : public VirtualChannelIF { * the packet buffer of the virtual channel or not. */ bool isVcInterfaceBufferEmpty(); - - /** - * @brief This function sends a complete telemetry transfer frame data field (1105 bytes) - * to the papb interface of the PTME IP Core. Can be used to test the implementation. - */ - ReturnValue_t sendTestFrame(); }; #endif /* LINUX_OBC_PAPBVCINTERFACE_H_ */ diff --git a/linux/ipcore/Ptme.cpp b/linux/ipcore/Ptme.cpp index f33c8725..9b688d16 100644 --- a/linux/ipcore/Ptme.cpp +++ b/linux/ipcore/Ptme.cpp @@ -19,15 +19,12 @@ ReturnValue_t Ptme::initialize() { return returnvalue::OK; } -ReturnValue_t Ptme::writeToVc(uint8_t vcId, const uint8_t* data, size_t size) { - VcInterfaceMapIter vcInterfaceMapIter = vcInterfaceMap.find(vcId); - if (vcInterfaceMapIter == vcInterfaceMap.end()) { - sif::warning << "Ptme::writeToVc: No virtual channel interface found for the virtual " - "channel with id " - << static_cast(vcId) << std::endl; - return UNKNOWN_VC_ID; +bool Ptme::containsVc(uint8_t vcId) const { + auto channelIter = vcInterfaceMap.find(vcId); + if (channelIter == vcInterfaceMap.end()) { + return false; } - return vcInterfaceMapIter->second->write(data, size); + return true; } void Ptme::addVcInterface(VcId_t vcId, VirtualChannelIF* vc) { @@ -50,21 +47,10 @@ void Ptme::addVcInterface(VcId_t vcId, VirtualChannelIF* vc) { } } -bool Ptme::isBusy(uint8_t vcId) const { - const auto& vcInterfaceMapIter = vcInterfaceMap.find(vcId); - if (vcInterfaceMapIter == vcInterfaceMap.end()) { - sif::warning << "Ptme::writeToVc: No virtual channel interface found for the virtual " - "channel with id " - << static_cast(vcId) << std::endl; - return UNKNOWN_VC_ID; +VirtualChannelIF* Ptme::getVirtChannel(uint8_t vcId) { + auto channelIter = vcInterfaceMap.find(vcId); + if (channelIter == vcInterfaceMap.end()) { + return nullptr; } - return vcInterfaceMapIter->second->isBusy(); -} - -void Ptme::cancelTransfer(uint8_t vcId) { - VcInterfaceMapIter vcInterfaceMapIter = vcInterfaceMap.find(vcId); - if (vcInterfaceMapIter == vcInterfaceMap.end()) { - return; - } - return vcInterfaceMapIter->second->cancelTransfer(); + return channelIter->second; } diff --git a/linux/ipcore/Ptme.h b/linux/ipcore/Ptme.h index 2607fc90..d5e77024 100644 --- a/linux/ipcore/Ptme.h +++ b/linux/ipcore/Ptme.h @@ -34,9 +34,8 @@ class Ptme : public PtmeIF, public SystemObject { virtual ~Ptme(); ReturnValue_t initialize() override; - ReturnValue_t writeToVc(uint8_t vcId, const uint8_t* data, size_t size) override; - bool isBusy(uint8_t vcId) const override; - void cancelTransfer(uint8_t vcId) override; + bool containsVc(uint8_t vcId) const override; + VirtualChannelIF* getVirtChannel(uint8_t vcId) override; /** * @brief This function adds the reference to a virtual channel interface to the vcInterface diff --git a/linux/ipcore/PtmeIF.h b/linux/ipcore/PtmeIF.h index 38804484..a5ea0c95 100644 --- a/linux/ipcore/PtmeIF.h +++ b/linux/ipcore/PtmeIF.h @@ -1,6 +1,8 @@ #ifndef LINUX_OBC_PTMEIF_H_ #define LINUX_OBC_PTMEIF_H_ +#include + #include "fsfw/returnvalues/returnvalue.h" /** @@ -14,16 +16,8 @@ class PtmeIF { public: virtual ~PtmeIF(){}; - /** - * @brief Implements to function to write to a specific virtual channel. - * - * @param vcId Virtual channel to write to - * @param data Pointer to buffer holding the data to write - * @param size Number of bytes to write - */ - virtual ReturnValue_t writeToVc(uint8_t vcId, const uint8_t* data, size_t size) = 0; - virtual bool isBusy(uint8_t vcId) const = 0; - virtual void cancelTransfer(uint8_t vcId) = 0; + virtual bool containsVc(uint8_t vcId) const = 0; + virtual VirtualChannelIF* getVirtChannel(uint8_t vcId) = 0; }; #endif /* LINUX_OBC_PTMEIF_H_ */ diff --git a/mission/com/TmStoreTaskBase.cpp b/mission/com/TmStoreTaskBase.cpp index 80900975..8849b241 100644 --- a/mission/com/TmStoreTaskBase.cpp +++ b/mission/com/TmStoreTaskBase.cpp @@ -138,8 +138,17 @@ ReturnValue_t TmStoreTaskBase::performDump(PersistentTmStoreWithTmQueue& store, return result; } dumpedLen = tmReader.getFullPacketLen(); - result = channel.write(tmReader.getFullData(), dumpedLen); - if (result == DirectTmSinkIF::IS_BUSY) { + size_t partiallyWrittenSize = 0; + result = channel.write(tmReader.getFullData(), dumpedLen, partiallyWrittenSize); + if (result == VirtualChannelIF::PARTIALLY_WRITTEN) { + result = channel.handleLastWriteSynchronously(tmReader.getFullData(), partiallyWrittenSize, + dumpedLen - partiallyWrittenSize, 20); + if (result != returnvalue::OK) { + // TODO: Event? Might lead to dangerous spam though.. + sif::warning << "PersistentTmStore: Synchronous write of last segment failed with code 0x" + << std::setw(4) << std::hex << result << std::endl; + } + } else 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; diff --git a/mission/com/VirtualChannel.cpp b/mission/com/VirtualChannel.cpp index ff3749a9..b3201334 100644 --- a/mission/com/VirtualChannel.cpp +++ b/mission/com/VirtualChannel.cpp @@ -1,25 +1,64 @@ #include "VirtualChannel.h" +#include + VirtualChannel::VirtualChannel(object_id_t objectId, uint8_t vcId, const char* vcName, PtmeIF& ptme, const std::atomic_bool& txOn) : SystemObject(objectId), ptme(ptme), vcId(vcId), vcName(vcName), txOn(txOn) {} ReturnValue_t VirtualChannel::initialize() { return returnvalue::OK; } -ReturnValue_t VirtualChannel::sendNextTm(const uint8_t* data, size_t size) { - return write(data, size); +ReturnValue_t VirtualChannel::sendNextTm(const uint8_t* data, size_t size, size_t& writtenSize) { + return write(data, size, writtenSize); } -ReturnValue_t VirtualChannel::write(const uint8_t* data, size_t size) { - return ptme.writeToVc(vcId, data, size); +ReturnValue_t VirtualChannel::write(const uint8_t* data, size_t size, size_t& writtenSize) { + if (!ptme.containsVc(vcId)) { + return CHANNEL_DOES_NOT_EXIST; + } + return ptme.getVirtChannel(vcId)->write(data, size, writtenSize); } uint8_t VirtualChannel::getVcid() const { return vcId; } +ReturnValue_t VirtualChannel::finishWrite(const uint8_t* data, size_t remainingSize) { + if (!ptme.containsVc(vcId)) { + return CHANNEL_DOES_NOT_EXIST; + } + return ptme.getVirtChannel(vcId)->finishWrite(data, remainingSize); +} + const char* VirtualChannel::getName() const { return vcName.c_str(); } -bool VirtualChannel::isBusy() const { return ptme.isBusy(vcId); } +bool VirtualChannel::isBusy() const { + if (!ptme.containsVc(vcId)) { + return CHANNEL_DOES_NOT_EXIST; + } + return ptme.getVirtChannel(vcId)->isBusy(); +} -void VirtualChannel::cancelTransfer() { ptme.cancelTransfer(vcId); } +void VirtualChannel::cancelTransfer() { + if (!ptme.containsVc(vcId)) { + return; + } + ptme.getVirtChannel(vcId)->cancelTransfer(); +} bool VirtualChannel::isTxOn() const { return txOn; } + +ReturnValue_t VirtualChannel::handleLastWriteSynchronously(const uint8_t* data, size_t start, + size_t remLen, unsigned maxDelayMs) { + unsigned delayMs = 0; + while (true) { + if (isBusy()) { + if (delayMs >= maxDelayMs) { + break; + } + TaskFactory::delayTask(10); + delayMs += 10; + continue; + } + return finishWrite(data, start); + } + return returnvalue::FAILED; +} diff --git a/mission/com/VirtualChannel.h b/mission/com/VirtualChannel.h index 98aba903..9995772f 100644 --- a/mission/com/VirtualChannel.h +++ b/mission/com/VirtualChannel.h @@ -15,6 +15,10 @@ */ class VirtualChannel : public SystemObject, public VirtualChannelIF { public: + static constexpr uint8_t CLASS_ID = CLASS_ID::VIRTUAL_CHANNEL; + + static constexpr ReturnValue_t CHANNEL_DOES_NOT_EXIST = returnvalue::makeCode(CLASS_ID, 0); + /** * @brief Constructor * @@ -25,9 +29,12 @@ class VirtualChannel : public SystemObject, public VirtualChannelIF { const std::atomic_bool& linkStateProvider); ReturnValue_t initialize() override; - ReturnValue_t sendNextTm(const uint8_t* data, size_t size); + ReturnValue_t sendNextTm(const uint8_t* data, size_t size, size_t& writtenSize); bool isBusy() const override; - ReturnValue_t write(const uint8_t* data, size_t size) override; + ReturnValue_t write(const uint8_t* data, size_t size, size_t& writtenSize) override; + ReturnValue_t finishWrite(const uint8_t* data, size_t remainingSize) override; + ReturnValue_t handleLastWriteSynchronously(const uint8_t* data, size_t start, size_t remLen, + unsigned maxDelayMs); void cancelTransfer() override; uint8_t getVcid() const; bool isTxOn() const; diff --git a/mission/com/VirtualChannelWithQueue.cpp b/mission/com/VirtualChannelWithQueue.cpp index a90829ab..621a7268 100644 --- a/mission/com/VirtualChannelWithQueue.cpp +++ b/mission/com/VirtualChannelWithQueue.cpp @@ -36,8 +36,19 @@ ReturnValue_t VirtualChannelWithQueue::handleNextTm(bool performWriteOp) { return result; } + // TODO: Hnadle partial write handling + size_t partiallyWrittenSize = 0; if (performWriteOp) { - result = write(data, size); + result = write(data, size, partiallyWrittenSize); + if (result == PARTIALLY_WRITTEN) { + result = handleLastWriteSynchronously(data, size, partiallyWrittenSize, 20); + if (result != returnvalue::OK) { + // TODO: Event? Might lead to dangerous spam though.. + sif::warning + << "VirtualChannelWithQueue: Synchronous write of last segment failed with code 0x" + << std::setw(4) << std::hex << result << std::endl; + } + } } // Try delete in any case, ignore failures (which should not happen), it is more important to // propagate write errors. diff --git a/mission/tmtc/DirectTmSinkIF.h b/mission/tmtc/DirectTmSinkIF.h index 11a17c79..a5f3af42 100644 --- a/mission/tmtc/DirectTmSinkIF.h +++ b/mission/tmtc/DirectTmSinkIF.h @@ -13,6 +13,7 @@ class DirectTmSinkIF { static constexpr uint8_t CLASS_ID = CLASS_ID::TM_SINK; static constexpr ReturnValue_t IS_BUSY = returnvalue::makeCode(CLASS_ID, 0); + static constexpr ReturnValue_t PARTIALLY_WRITTEN = returnvalue::makeCode(CLASS_ID, 1); /** * @brief Implements the functionality to write to a TM sink directly @@ -20,9 +21,12 @@ class DirectTmSinkIF { * @param data Pointer to buffer holding the data to write * @param size Number of bytes to write * @return returnvalue::OK on success, returnvalue::FAILED on failure, IS_BUSY - * if the TM sink is busy. + * if the TM sink is busy, PARTIALLY_WRITTEN if only a portion of the bytes could be + * written. */ - virtual ReturnValue_t write(const uint8_t* data, size_t size) = 0; + virtual ReturnValue_t write(const uint8_t* data, size_t size, size_t& writtenSize) = 0; + + virtual ReturnValue_t finishWrite(const uint8_t* data, size_t remainingSize) = 0; virtual bool isBusy() const = 0; }; diff --git a/tmtc b/tmtc index e249f147..84df438e 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit e249f147bc1738003d31290df8f2b525d91c3482 +Subproject commit 84df438e9d74898cbb3c6319ba55193c0c8d0b0c -- 2.43.0 From 99192606a26d80a2942f1fdefeb106bc298e7a81 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 13 Oct 2023 09:27:24 +0200 Subject: [PATCH 2/4] bugfixes for PAPB IF --- linux/ipcore/PapbVcInterface.cpp | 19 ++++++++++++------- linux/ipcore/PapbVcInterface.h | 3 +-- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/linux/ipcore/PapbVcInterface.cpp b/linux/ipcore/PapbVcInterface.cpp index 5e63aebc..2329a32e 100644 --- a/linux/ipcore/PapbVcInterface.cpp +++ b/linux/ipcore/PapbVcInterface.cpp @@ -37,7 +37,7 @@ ReturnValue_t PapbVcInterface::write(const uint8_t* data, size_t size, size_t& w abortPacketTransfer(); return returnvalue::FAILED; } - return finishWritePartialOpt(data, size, true); + return finishWriteInternal(data, size, writtenSize); } void PapbVcInterface::startPacketTransfer(ByteWidthCfg initWidth) { @@ -53,11 +53,20 @@ bool PapbVcInterface::pollReadyForPacket() const { return (reg >> 6) & 0b1; } -ReturnValue_t PapbVcInterface::finishWritePartialOpt(const uint8_t* data, size_t remainingSize, - bool handlePartial) { +ReturnValue_t PapbVcInterface::finishWrite(const uint8_t* data, size_t remainingSize) { + if (not pollReadyForPacket()) { + return returnvalue::FAILED; + } + size_t dummy = 0; + return finishWriteInternal(data, remainingSize, dummy); +} + +ReturnValue_t PapbVcInterface::finishWriteInternal(const uint8_t* data, size_t remainingSize, + size_t& writtenSize) { for (size_t idx = 0; idx < remainingSize; idx++) { if (not pollReadyForOctet(MAX_BUSY_POLLS)) { if (not pollReadyForPacket()) { + writtenSize = idx; return PARTIALLY_WRITTEN; } abortPacketTransfer(); @@ -109,8 +118,4 @@ inline bool PapbVcInterface::pollReadyForOctet(uint32_t maxCycles) const { return false; } -ReturnValue_t PapbVcInterface::finishWrite(const uint8_t* data, size_t remainingSize) { - return finishWritePartialOpt(data, remainingSize, false); -} - void PapbVcInterface::abortPacketTransfer() { *vcBaseReg = CONFIG_ABORT; } diff --git a/linux/ipcore/PapbVcInterface.h b/linux/ipcore/PapbVcInterface.h index 72b9b9f3..201580bc 100644 --- a/linux/ipcore/PapbVcInterface.h +++ b/linux/ipcore/PapbVcInterface.h @@ -43,8 +43,7 @@ class PapbVcInterface : public VirtualChannelIF { ReturnValue_t write(const uint8_t* data, size_t size, size_t& writtenSize) override; ReturnValue_t finishWrite(const uint8_t* data, size_t remainingSize) override; - ReturnValue_t finishWritePartialOpt(const uint8_t* data, size_t remainingSize, - bool handlePartial); + ReturnValue_t finishWriteInternal(const uint8_t* data, size_t remainingSize, size_t& writtenSize); void cancelTransfer() override; -- 2.43.0 From 7c42e05c2374509d7a4ee14658d45ee4cee753c1 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 13 Oct 2023 09:29:57 +0200 Subject: [PATCH 3/4] wait duration fix --- mission/com/TmStoreTaskBase.cpp | 4 ++-- mission/com/VirtualChannelWithQueue.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mission/com/TmStoreTaskBase.cpp b/mission/com/TmStoreTaskBase.cpp index 8849b241..c51d6f9b 100644 --- a/mission/com/TmStoreTaskBase.cpp +++ b/mission/com/TmStoreTaskBase.cpp @@ -142,11 +142,11 @@ ReturnValue_t TmStoreTaskBase::performDump(PersistentTmStoreWithTmQueue& store, result = channel.write(tmReader.getFullData(), dumpedLen, partiallyWrittenSize); if (result == VirtualChannelIF::PARTIALLY_WRITTEN) { result = channel.handleLastWriteSynchronously(tmReader.getFullData(), partiallyWrittenSize, - dumpedLen - partiallyWrittenSize, 20); + dumpedLen - partiallyWrittenSize, 200); if (result != returnvalue::OK) { // TODO: Event? Might lead to dangerous spam though.. sif::warning << "PersistentTmStore: Synchronous write of last segment failed with code 0x" - << std::setw(4) << std::hex << result << std::endl; + << std::setw(4) << std::hex << result << std::dec << std::endl; } } else if (result == DirectTmSinkIF::IS_BUSY) { sif::warning << "PersistentTmStore: Unexpected VC channel busy" << std::endl; diff --git a/mission/com/VirtualChannelWithQueue.cpp b/mission/com/VirtualChannelWithQueue.cpp index 621a7268..53f2ee52 100644 --- a/mission/com/VirtualChannelWithQueue.cpp +++ b/mission/com/VirtualChannelWithQueue.cpp @@ -41,12 +41,12 @@ ReturnValue_t VirtualChannelWithQueue::handleNextTm(bool performWriteOp) { if (performWriteOp) { result = write(data, size, partiallyWrittenSize); if (result == PARTIALLY_WRITTEN) { - result = handleLastWriteSynchronously(data, size, partiallyWrittenSize, 20); + result = handleLastWriteSynchronously(data, size, partiallyWrittenSize, 200); if (result != returnvalue::OK) { // TODO: Event? Might lead to dangerous spam though.. sif::warning << "VirtualChannelWithQueue: Synchronous write of last segment failed with code 0x" - << std::setw(4) << std::hex << result << std::endl; + << std::setw(4) << std::hex << result << std::dec << std::endl; } } } -- 2.43.0 From 8dbc5cad48d24a2bf9ce90c7715c237a79ede1a4 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 13 Oct 2023 09:39:50 +0200 Subject: [PATCH 4/4] more bugfixes --- CHANGELOG.md | 8 ++++++++ linux/ipcore/PapbVcInterface.cpp | 26 +++++++++++++++++++------- linux/ipcore/PapbVcInterface.h | 6 ++++-- mission/com/VirtualChannel.cpp | 6 +++--- mission/com/VirtualChannel.h | 2 +- mission/tmtc/DirectTmSinkIF.h | 3 ++- 6 files changed, 37 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6d88025..b029d621 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,14 @@ will consitute of a breaking change warranting a new major release: # [unreleased] +## Fixed + +- If the PTME is driven in a way where it fills faster than it can be emptied, the interface + can become full during the process of a regular packet write. The interface of the PAPB VC + component was adapted to account for this partial success state. The caller must now check + for the `PARTIALLY_WRITTEN` state and must take care of finishing a write in some shape or + form before starting the next packet transfer. + # [v7.1.0] 2023-10-11 - Bumped `eive-tmtc` to v5.8.0. diff --git a/linux/ipcore/PapbVcInterface.cpp b/linux/ipcore/PapbVcInterface.cpp index 2329a32e..88684772 100644 --- a/linux/ipcore/PapbVcInterface.cpp +++ b/linux/ipcore/PapbVcInterface.cpp @@ -28,6 +28,10 @@ ReturnValue_t PapbVcInterface::write(const uint8_t* data, size_t size, size_t& w if (size < 4) { return returnvalue::FAILED; } + // The user must call finishWrite before starting a new packet transfer. + if (partialWriteActive) { + return INCOMPLETE_PARTIAL_WRITE; + } if (pollReadyForPacket()) { startPacketTransfer(ByteWidthCfg::ONE); } else { @@ -37,7 +41,7 @@ ReturnValue_t PapbVcInterface::write(const uint8_t* data, size_t size, size_t& w abortPacketTransfer(); return returnvalue::FAILED; } - return finishWriteInternal(data, size, writtenSize); + return finishWriteInternal(data, 0, size, writtenSize, false); } void PapbVcInterface::startPacketTransfer(ByteWidthCfg initWidth) { @@ -53,26 +57,34 @@ bool PapbVcInterface::pollReadyForPacket() const { return (reg >> 6) & 0b1; } -ReturnValue_t PapbVcInterface::finishWrite(const uint8_t* data, size_t remainingSize) { +ReturnValue_t PapbVcInterface::finishWrite(const uint8_t* data, size_t start, + size_t remainingSize) { if (not pollReadyForPacket()) { return returnvalue::FAILED; } size_t dummy = 0; - return finishWriteInternal(data, remainingSize, dummy); + return finishWriteInternal(data, start, remainingSize, dummy, true); } -ReturnValue_t PapbVcInterface::finishWriteInternal(const uint8_t* data, size_t remainingSize, - size_t& writtenSize) { +ReturnValue_t PapbVcInterface::finishWriteInternal(const uint8_t* data, size_t start, + size_t remainingSize, size_t& writtenSize, + bool abortOnPartialWrite) { for (size_t idx = 0; idx < remainingSize; idx++) { if (not pollReadyForOctet(MAX_BUSY_POLLS)) { if (not pollReadyForPacket()) { - writtenSize = idx; + writtenSize = start + idx; + partialWriteActive = true; + if (abortOnPartialWrite) { + abortPacketTransfer(); + partialWriteActive = false; + return returnvalue::FAILED; + } return PARTIALLY_WRITTEN; } abortPacketTransfer(); return returnvalue::FAILED; } - *(vcBaseReg + DATA_REG_OFFSET) = static_cast(data[idx]); + *(vcBaseReg + DATA_REG_OFFSET) = static_cast(data[start + idx]); } if (not pollReadyForOctet(MAX_BUSY_POLLS)) { abortPacketTransfer(); diff --git a/linux/ipcore/PapbVcInterface.h b/linux/ipcore/PapbVcInterface.h index 201580bc..35bd0439 100644 --- a/linux/ipcore/PapbVcInterface.h +++ b/linux/ipcore/PapbVcInterface.h @@ -42,8 +42,9 @@ class PapbVcInterface : public VirtualChannelIF { */ ReturnValue_t write(const uint8_t* data, size_t size, size_t& writtenSize) override; - ReturnValue_t finishWrite(const uint8_t* data, size_t remainingSize) override; - ReturnValue_t finishWriteInternal(const uint8_t* data, size_t remainingSize, size_t& writtenSize); + ReturnValue_t finishWrite(const uint8_t* data, size_t start, size_t remainingSize) override; + ReturnValue_t finishWriteInternal(const uint8_t* data, size_t start, size_t remainingSize, + size_t& writtenSize, bool abortOnPartialWrite); void cancelTransfer() override; @@ -91,6 +92,7 @@ class PapbVcInterface : public VirtualChannelIF { std::string uioFile; int mapNum = 0; + bool partialWriteActive = false; mutable struct timespec nextDelay = {.tv_sec = 0, .tv_nsec = 0}; const struct timespec BETWEEN_POLL_DELAY = {.tv_sec = 0, .tv_nsec = 10}; mutable struct timespec remDelay; diff --git a/mission/com/VirtualChannel.cpp b/mission/com/VirtualChannel.cpp index b3201334..140b23f6 100644 --- a/mission/com/VirtualChannel.cpp +++ b/mission/com/VirtualChannel.cpp @@ -21,11 +21,11 @@ ReturnValue_t VirtualChannel::write(const uint8_t* data, size_t size, size_t& wr uint8_t VirtualChannel::getVcid() const { return vcId; } -ReturnValue_t VirtualChannel::finishWrite(const uint8_t* data, size_t remainingSize) { +ReturnValue_t VirtualChannel::finishWrite(const uint8_t* data, size_t start, size_t remainingSize) { if (!ptme.containsVc(vcId)) { return CHANNEL_DOES_NOT_EXIST; } - return ptme.getVirtChannel(vcId)->finishWrite(data, remainingSize); + return ptme.getVirtChannel(vcId)->finishWrite(data, start, remainingSize); } const char* VirtualChannel::getName() const { return vcName.c_str(); } @@ -58,7 +58,7 @@ ReturnValue_t VirtualChannel::handleLastWriteSynchronously(const uint8_t* data, delayMs += 10; continue; } - return finishWrite(data, start); + return finishWrite(data, start, remLen); } return returnvalue::FAILED; } diff --git a/mission/com/VirtualChannel.h b/mission/com/VirtualChannel.h index 9995772f..3d61bd13 100644 --- a/mission/com/VirtualChannel.h +++ b/mission/com/VirtualChannel.h @@ -32,7 +32,7 @@ class VirtualChannel : public SystemObject, public VirtualChannelIF { ReturnValue_t sendNextTm(const uint8_t* data, size_t size, size_t& writtenSize); bool isBusy() const override; ReturnValue_t write(const uint8_t* data, size_t size, size_t& writtenSize) override; - ReturnValue_t finishWrite(const uint8_t* data, size_t remainingSize) override; + ReturnValue_t finishWrite(const uint8_t* data, size_t start, size_t remainingSize) override; ReturnValue_t handleLastWriteSynchronously(const uint8_t* data, size_t start, size_t remLen, unsigned maxDelayMs); void cancelTransfer() override; diff --git a/mission/tmtc/DirectTmSinkIF.h b/mission/tmtc/DirectTmSinkIF.h index a5f3af42..e1fcf54f 100644 --- a/mission/tmtc/DirectTmSinkIF.h +++ b/mission/tmtc/DirectTmSinkIF.h @@ -14,6 +14,7 @@ class DirectTmSinkIF { static constexpr ReturnValue_t IS_BUSY = returnvalue::makeCode(CLASS_ID, 0); static constexpr ReturnValue_t PARTIALLY_WRITTEN = returnvalue::makeCode(CLASS_ID, 1); + static constexpr ReturnValue_t INCOMPLETE_PARTIAL_WRITE = returnvalue::makeCode(CLASS_ID, 2); /** * @brief Implements the functionality to write to a TM sink directly @@ -26,7 +27,7 @@ class DirectTmSinkIF { */ virtual ReturnValue_t write(const uint8_t* data, size_t size, size_t& writtenSize) = 0; - virtual ReturnValue_t finishWrite(const uint8_t* data, size_t remainingSize) = 0; + virtual ReturnValue_t finishWrite(const uint8_t* data, size_t start, size_t remainingSize) = 0; virtual bool isBusy() const = 0; }; -- 2.43.0