diff --git a/CHANGELOG.md b/CHANGELOG.md index f6e47418..e08cd12a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,15 +12,22 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## Fixes +- Bugfix in `Service11TelecommandScheduling` which allowed commands + time tagged in the past to be inserted. + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/738 - `CService200ModeManagement`: Various bugfixes which lead to now execution complete being generated on mode announcements, duplicate mode reply generated on announce commands, and the mode read subservice not working properly. +- Memory leak fixes for the TCP/IP TMTC bridge. + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/737 - `Service9TimeManagement`: Fix the time dump at the `SET_TIME` subservice: Include clock timeval seconds instead of uptime. PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/726 - HAL MGM3100 Handler: Use axis specific gain/scaling factors. Previously, only the X scaling factor was used. PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/724 +- Bugfix for RM3100 MGM sensors. Z value was previously calculated + with bytes of the X value. - DHB `setNormalDatapoolEntriesInvalid`: The default implementation did not set the validity to false correctly because the `read` and `write` calls were missing. - PUS TMTC creator module: Sequence flags were set to continuation segment (0b00) instead @@ -43,6 +50,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - `CServiceHealthCommanding`: Add announce all health info implementation PR: https://egit.irs.uni-stuttgart.de/eive/fsfw/pulls/122 +- Empty constructor for `CdsShortTimeStamper` which does not do an object manager registration. + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/730 - `Service9TimeManagement`: Add `DUMP_TIME` (129) subservice. - `TcpTmTcServer`: Allow setting the `SO_REUSEADDR` and `SO_REUSEPORT` option on the TCP server. CTOR prototype has changed and expects an explicit diff --git a/CMakeLists.txt b/CMakeLists.txt index 9025537a..56601aaa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,12 +153,12 @@ if(FSFW_BUILD_TESTS) "${MSG_PREFIX} Building the FSFW unittests in addition to the static library" ) # Check whether the user has already installed Catch2 first - find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION}) + find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION} QUIET) # Not installed, so use FetchContent to download and provide Catch2 if(NOT Catch2_FOUND) message( STATUS - "${MSG_PREFIX} Catch2 installation not found. Downloading Catch2 library with FetchContent" + "${MSG_PREFIX} Catch2 installation not found. Downloading Catch2 library with FetchContent." ) include(FetchContent) @@ -196,13 +196,13 @@ message( ) # Check whether the user has already installed ETL first -find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} CONFIG QUIET) +find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET) # Not installed, so use FetchContent to download and provide etl if(NOT ${FSFW_ETL_LIB_NAME}_FOUND) message( STATUS - "${MSG_PREFIX} No ETL installation was found with find_package. Installing and providing " - "etl with FindPackage") + "${MSG_PREFIX} ETL installation not found. Downloading ETL with FetchContent." + ) include(FetchContent) FetchContent_Declare( diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp index b2505344..ec627142 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp @@ -58,12 +58,7 @@ void DeviceHandlerBase::setHkDestination(object_id_t hkDestination) { this->hkDestination = hkDestination; } -void DeviceHandlerBase::setThermalStateRequestPoolIds(lp_id_t thermalStatePoolId, - lp_id_t heaterRequestPoolId, - uint32_t thermalSetId) { - thermalSet = - new DeviceHandlerThermalSet(this, thermalSetId, thermalStatePoolId, heaterRequestPoolId); -} +void DeviceHandlerBase::enableThermalModule(ThermalStateCfg cfg) { this->thermalStateCfg = cfg; } DeviceHandlerBase::~DeviceHandlerBase() { if (comCookie != nullptr) { @@ -227,12 +222,11 @@ ReturnValue_t DeviceHandlerBase::initialize() { fillCommandAndReplyMap(); if (thermalSet != nullptr) { + PoolReadGuard pg(thermalSet); // Set temperature target state to NON_OP. - result = thermalSet->read(); - if (result == returnvalue::OK) { + if (pg.getReadResult() == returnvalue::OK) { thermalSet->heaterRequest.value = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL; thermalSet->heaterRequest.setValid(true); - thermalSet->commit(); } } @@ -594,12 +588,12 @@ void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) { Clock::getUptime(&timeoutStart); if (mode == MODE_OFF and thermalSet != nullptr) { - ReturnValue_t result = thermalSet->read(); - if (result == returnvalue::OK) { + PoolReadGuard pg(thermalSet); + if (pg.getReadResult() == returnvalue::OK) { if (thermalSet->heaterRequest.value != ThermalComponentIF::STATE_REQUEST_IGNORE) { thermalSet->heaterRequest.value = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL; } - thermalSet->heaterRequest.commit(PoolVariableIF::VALID); + thermalSet->heaterRequest.setValid(true); } } /* TODO: This will probably be done by the LocalDataPoolManager now */ @@ -1088,8 +1082,8 @@ ReturnValue_t DeviceHandlerBase::checkModeCommand(Mode_t commandedMode, Submode_ // Do not check thermal state for MODE_RAW if ((mode == MODE_OFF) and ((commandedMode == MODE_ON) or (commandedMode == MODE_NORMAL)) and (thermalSet != nullptr)) { - ReturnValue_t result = thermalSet->read(); - if (result == returnvalue::OK) { + PoolReadGuard pg(thermalSet); + if (pg.getReadResult() == returnvalue::OK) { if ((thermalSet->heaterRequest.value != ThermalComponentIF::STATE_REQUEST_IGNORE) and (not ThermalComponentIF::isOperational(thermalSet->thermalState.value))) { triggerEvent(ThermalComponentIF::TEMP_NOT_IN_OP_RANGE, thermalSet->thermalState.value); @@ -1150,11 +1144,10 @@ void DeviceHandlerBase::handleTransitionToOnMode(Mode_t commandedMode, Submode_t childTransitionDelay = getTransitionDelayMs(_MODE_START_UP, MODE_ON); triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode); if (thermalSet != nullptr) { - ReturnValue_t result = thermalSet->read(); - if (result == returnvalue::OK) { + PoolReadGuard pg(thermalSet); + if (pg.getReadResult() == returnvalue::OK) { if (thermalSet->heaterRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) { thermalSet->heaterRequest = ThermalComponentIF::STATE_REQUEST_OPERATIONAL; - thermalSet->commit(); } } } @@ -1477,11 +1470,11 @@ void DeviceHandlerBase::performOperationHook() {} ReturnValue_t DeviceHandlerBase::initializeLocalDataPool(localpool::DataPool& localDataPoolMap, LocalDataPoolManager& poolManager) { - if (thermalSet != nullptr) { - localDataPoolMap.emplace(thermalSet->thermalStatePoolId, - new PoolEntry); - localDataPoolMap.emplace(thermalSet->heaterRequestPoolId, - new PoolEntry); + if (thermalStateCfg.has_value()) { + localDataPoolMap.emplace(thermalStateCfg.value().thermalStatePoolId, + new PoolEntry()); + localDataPoolMap.emplace(thermalStateCfg.value().thermalRequestPoolId, + new PoolEntry()); } return returnvalue::OK; } @@ -1494,6 +1487,10 @@ ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() { } this->poolManager.initializeAfterTaskCreation(); + if (thermalStateCfg.has_value()) { + ThermalStateCfg& cfg = thermalStateCfg.value(); + thermalSet = new DeviceHandlerThermalSet(this, cfg); + } if (setStartupImmediately) { startTransition(MODE_ON, getInitialSubmode()); } diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.h b/src/fsfw/devicehandlers/DeviceHandlerBase.h index b06815d1..5e05c3a8 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.h +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.h @@ -2,6 +2,7 @@ #define FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ #include +#include #include "DeviceCommunicationIF.h" #include "DeviceHandlerFailureIsolation.h" @@ -163,13 +164,8 @@ class DeviceHandlerBase : public DeviceHandlerIF, * The device handler will then take care of creating local pool entries * for the device thermal state and device heating request. * Custom local pool IDs can be assigned as well. - * @param thermalStatePoolId - * @param thermalRequestPoolId */ - void setThermalStateRequestPoolIds( - lp_id_t thermalStatePoolId = DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID, - lp_id_t thermalRequestPoolId = DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID, - uint32_t thermalSetId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID); + void enableThermalModule(ThermalStateCfg cfg); ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF &parent) override; ModeTreeChildIF &getModeTreeChildIF() override; @@ -931,6 +927,8 @@ class DeviceHandlerBase : public DeviceHandlerIF, //! Object which may be the root cause of an identified fault. static object_id_t defaultFdirParentId; + std::optional thermalStateCfg; + /** * @brief Send a reply to a received device handler command. * diff --git a/src/fsfw/devicehandlers/DeviceHandlerIF.h b/src/fsfw/devicehandlers/DeviceHandlerIF.h index 474c3a75..5e1fdd2f 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerIF.h +++ b/src/fsfw/devicehandlers/DeviceHandlerIF.h @@ -136,4 +136,10 @@ class DeviceHandlerIF { virtual MessageQueueId_t getCommandQueue() const = 0; }; +struct ThermalStateCfg { + lp_id_t thermalStatePoolId = DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID; + lp_id_t thermalRequestPoolId = DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID; + uint32_t thermalSetId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID; +}; + #endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERIF_H_ */ diff --git a/src/fsfw/devicehandlers/DeviceHandlerThermalSet.h b/src/fsfw/devicehandlers/DeviceHandlerThermalSet.h index 944d7c0f..49ebd5f4 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerThermalSet.h +++ b/src/fsfw/devicehandlers/DeviceHandlerThermalSet.h @@ -7,27 +7,21 @@ class DeviceHandlerThermalSet : public StaticLocalDataSet<2> { public: - DeviceHandlerThermalSet( - HasLocalDataPoolIF* hkOwner, uint32_t setId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID, - lp_id_t thermalStateId = DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID, - lp_id_t heaterRequestId = DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID) - : DeviceHandlerThermalSet(hkOwner->getObjectId(), setId, thermalStateId, heaterRequestId) {} + DeviceHandlerThermalSet(HasLocalDataPoolIF* hkOwner, ThermalStateCfg cfg) + : DeviceHandlerThermalSet(hkOwner->getObjectId(), cfg) {} - DeviceHandlerThermalSet( - object_id_t deviceHandler, uint32_t setId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID, - lp_id_t thermalStateId = DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID, - lp_id_t thermalStateRequestId = DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID) - : StaticLocalDataSet(sid_t(deviceHandler, setId)), - thermalStatePoolId(thermalStateId), - heaterRequestPoolId(thermalStateRequestId) {} + DeviceHandlerThermalSet(object_id_t deviceHandler, ThermalStateCfg cfg) + : StaticLocalDataSet(sid_t(deviceHandler, cfg.thermalSetId)), + thermalStatePoolId(cfg.thermalStatePoolId), + heaterRequestPoolId(cfg.thermalRequestPoolId) {} const lp_id_t thermalStatePoolId; const lp_id_t heaterRequestPoolId; lp_var_t thermalState = - lp_var_t(thermalStatePoolId, sid.objectId, this); + lp_var_t(sid.objectId, thermalStatePoolId, this); lp_var_t heaterRequest = - lp_var_t(heaterRequestPoolId, sid.objectId, this); + lp_var_t(sid.objectId, heaterRequestPoolId, this); }; #endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERTHERMALSET_H_ */ diff --git a/src/fsfw/osal/common/TcpIpBase.cpp b/src/fsfw/osal/common/TcpIpBase.cpp index 486a5171..3e760f0e 100644 --- a/src/fsfw/osal/common/TcpIpBase.cpp +++ b/src/fsfw/osal/common/TcpIpBase.cpp @@ -41,6 +41,7 @@ int TcpIpBase::closeSocket(socket_t socket) { #elif defined(PLATFORM_UNIX) return close(socket); #endif + return -1; } int TcpIpBase::getLastSocketError() { @@ -49,4 +50,5 @@ int TcpIpBase::getLastSocketError() { #elif defined(PLATFORM_UNIX) return errno; #endif + return 0; } diff --git a/src/fsfw/pus/CService200ModeCommanding.cpp b/src/fsfw/pus/CService200ModeCommanding.cpp index 814c1c92..0dbdedfe 100644 --- a/src/fsfw/pus/CService200ModeCommanding.cpp +++ b/src/fsfw/pus/CService200ModeCommanding.cpp @@ -19,7 +19,7 @@ ReturnValue_t CService200ModeCommanding::isValidSubservice(uint8_t subservice) { switch (subservice) { case (Subservice::COMMAND_MODE_COMMAND): case (Subservice::COMMAND_MODE_READ): - case (Subservice::COMMAND_MODE_ANNCOUNCE): + case (Subservice::COMMAND_MODE_ANNOUNCE): case (Subservice::COMMAND_MODE_ANNOUNCE_RECURSIVELY): return returnvalue::OK; default: @@ -54,6 +54,7 @@ ReturnValue_t CService200ModeCommanding::checkInterfaceAndAcquireMessageQueue( ReturnValue_t CService200ModeCommanding::prepareCommand(CommandMessage *message, uint8_t subservice, const uint8_t *tcData, size_t tcDataLen, uint32_t *state, object_id_t objectId) { + bool recursive = false; switch (subservice) { case (Subservice::COMMAND_MODE_COMMAND): { ModePacket modeCommandPacket; @@ -67,22 +68,17 @@ ReturnValue_t CService200ModeCommanding::prepareCommand(CommandMessage *message, modeCommandPacket.getMode(), modeCommandPacket.getSubmode()); return returnvalue::OK; } - case (Subservice::COMMAND_MODE_ANNCOUNCE): - case (Subservice::COMMAND_MODE_ANNOUNCE_RECURSIVELY): { - bool recursive = true; - if (subservice == Subservice::COMMAND_MODE_ANNCOUNCE) { - recursive = false; - } + case (Subservice::COMMAND_MODE_ANNOUNCE_RECURSIVELY): + recursive = true; + [[fallthrough]]; + case (Subservice::COMMAND_MODE_ANNOUNCE): ModeMessage::setModeAnnounceMessage(*message, recursive); return EXECUTION_COMPLETE; - } - case (Subservice::COMMAND_MODE_READ): { + case (Subservice::COMMAND_MODE_READ): ModeMessage::setModeReadMessage(*message); return returnvalue::OK; - } - default: { + default: return CommandingServiceBase::INVALID_SUBSERVICE; - } } } diff --git a/src/fsfw/pus/CService200ModeCommanding.h b/src/fsfw/pus/CService200ModeCommanding.h index 830e5950..cf2baf7e 100644 --- a/src/fsfw/pus/CService200ModeCommanding.h +++ b/src/fsfw/pus/CService200ModeCommanding.h @@ -52,7 +52,7 @@ class CService200ModeCommanding : public CommandingServiceBase { COMMAND_MODE_READ = 3, //!< [EXPORT] : [COMMAND] Trigger an ModeInfo Event. //! This command does NOT have a reply - COMMAND_MODE_ANNCOUNCE = 4, + COMMAND_MODE_ANNOUNCE = 4, //!< [EXPORT] : [COMMAND] Trigger a ModeInfo Event and to send this //! command to every child. This command does NOT have a reply. COMMAND_MODE_ANNOUNCE_RECURSIVELY = 5, diff --git a/src/fsfw/pus/Service11TelecommandScheduling.tpp b/src/fsfw/pus/Service11TelecommandScheduling.tpp index 2ad11277..2a20e822 100644 --- a/src/fsfw/pus/Service11TelecommandScheduling.tpp +++ b/src/fsfw/pus/Service11TelecommandScheduling.tpp @@ -160,7 +160,7 @@ inline ReturnValue_t Service11TelecommandScheduling::doInsertActivi // (See requirement for Time margin) timeval tNow = {}; Clock::getClock_timeval(&tNow); - if (timestamp - tNow.tv_sec <= RELEASE_TIME_MARGIN_SECONDS) { + if (timestamp < tNow.tv_sec + RELEASE_TIME_MARGIN_SECONDS) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "Service11TelecommandScheduling::doInsertActivity: Release time too close to " "current time" diff --git a/src/fsfw/tmtcservices/TmTcBridge.cpp b/src/fsfw/tmtcservices/TmTcBridge.cpp index 9ff58766..ba851a85 100644 --- a/src/fsfw/tmtcservices/TmTcBridge.cpp +++ b/src/fsfw/tmtcservices/TmTcBridge.cpp @@ -145,13 +145,17 @@ ReturnValue_t TmTcBridge::handleTmQueue() { #endif /* FSFW_VERBOSE_LEVEL >= 3 */ if (communicationLinkUp == false or packetSentCounter >= sentPacketsPerCycle) { - storeDownlinkData(&message); + ReturnValue_t result = storeDownlinkData(&message); + if (result != returnvalue::OK) { + tmStore->deleteData(message.getStorageId()); + } continue; } result = tmStore->getData(message.getStorageId(), &data, &size); if (result != returnvalue::OK) { status = result; + tmStore->deleteData(message.getStorageId()); continue; } @@ -159,9 +163,9 @@ ReturnValue_t TmTcBridge::handleTmQueue() { if (result != returnvalue::OK) { status = result; } else { - tmStore->deleteData(message.getStorageId()); packetSentCounter++; } + tmStore->deleteData(message.getStorageId()); } return status; } diff --git a/src/fsfw/tmtcservices/TmTcBridge.h b/src/fsfw/tmtcservices/TmTcBridge.h index f2637abd..3df3419c 100644 --- a/src/fsfw/tmtcservices/TmTcBridge.h +++ b/src/fsfw/tmtcservices/TmTcBridge.h @@ -17,7 +17,7 @@ class TmTcBridge : public AcceptsTelemetryIF, public: static constexpr uint8_t TMTC_RECEPTION_QUEUE_DEPTH = 20; static constexpr uint8_t LIMIT_STORED_DATA_SENT_PER_CYCLE = 15; - static constexpr unsigned int LIMIT_DOWNLINK_PACKETS_STORED = 1000; + static constexpr unsigned int LIMIT_DOWNLINK_PACKETS_STORED = 500; static constexpr uint8_t DEFAULT_STORED_DATA_SENT_PER_CYCLE = 5; static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10; diff --git a/src/fsfw/version.cpp b/src/fsfw/version.cpp index 050187a9..27d44c03 100644 --- a/src/fsfw/version.cpp +++ b/src/fsfw/version.cpp @@ -1,6 +1,7 @@ #include "version.h" #include +#include #include "fsfw/FSFWVersion.h" @@ -20,7 +21,7 @@ fsfw::Version::Version(int major, int minor, int revision, const char* addInfo) void fsfw::Version::getVersion(char* str, size_t maxLen) const { size_t len = snprintf(str, maxLen, "%d.%d.%d", major, minor, revision); - if (addInfo != nullptr) { + if (addInfo != nullptr and std::strcmp(addInfo, "") != 0) { snprintf(str + len, maxLen - len, "-%s", addInfo); } } @@ -30,7 +31,7 @@ namespace fsfw { #if FSFW_CPP_OSTREAM_ENABLED == 1 std::ostream& operator<<(std::ostream& os, const Version& v) { os << v.major << "." << v.minor << "." << v.revision; - if (v.addInfo != nullptr) { + if (v.addInfo != nullptr and std::strcmp(v.addInfo, "") != 0) { os << "-" << v.addInfo; } return os; diff --git a/src/fsfw_hal/linux/spi/SpiComIF.cpp b/src/fsfw_hal/linux/spi/SpiComIF.cpp index 11db7cfe..ea25e837 100644 --- a/src/fsfw_hal/linux/spi/SpiComIF.cpp +++ b/src/fsfw_hal/linux/spi/SpiComIF.cpp @@ -179,12 +179,11 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const uint32_t spiSpeed = 0; spiCookie->getSpiParameters(spiMode, spiSpeed, nullptr); setSpiSpeedAndMode(fileDescriptor, spiMode, spiSpeed); - spiCookie->assignWriteBuffer(sendData); - spiCookie->setTransferSize(sendLen); bool fullDuplex = spiCookie->isFullDuplex(); gpioId_t gpioId = spiCookie->getChipSelectPin(); bool csLockManual = spiCookie->getCsLockManual(); + spiCookie->setTransferSize(0); MutexIF::TimeoutType csType; dur_millis_t csTimeout = 0; @@ -195,9 +194,13 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const if (result != returnvalue::OK) { #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "SpiComIF::sendMessage: Failed to lock mutex with code " - << "0x" << std::hex << std::setfill('0') << std::setw(4) << result << std::dec - << std::endl; + if (result == MutexIF::MUTEX_TIMEOUT) { + sif::error << "SpiComIF::sendMessage: Lock timeout" << std::endl; + } else { + sif::error << "SpiComIF::sendMessage: Failed to lock mutex with code " + << "0x" << std::hex << std::setfill('0') << std::setw(4) << result << std::dec + << std::endl; + } #else sif::printError("SpiComIF::sendMessage: Failed to lock mutex with code %d\n", result); #endif @@ -214,17 +217,22 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const sif::printWarning("SpiComIF::sendMessage: Pulling low CS pin failed"); #endif #endif + csMutex->unlockMutex(); return result; } } else { updateLinePolarity(fileDescriptor); } + spiCookie->assignWriteBuffer(sendData); + spiCookie->setTransferSize(sendLen); + /* Execute transfer */ if (fullDuplex) { /* Initiate a full duplex SPI transfer. */ retval = ioctl(fileDescriptor, SPI_IOC_MESSAGE(1), spiCookie->getTransferStructHandle()); if (retval < 0) { + spiCookie->setTransferSize(0); utility::handleIoctlError("SpiComIF::sendMessage: ioctl error."); result = FULL_DUPLEX_TRANSFER_FAILED; } @@ -234,6 +242,7 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const } else { /* We write with a blocking half-duplex transfer here */ if (write(fileDescriptor, sendData, sendLen) != static_cast(sendLen)) { + spiCookie->setTransferSize(0); #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "SpiComIF::sendMessage: Half-Duplex write operation failed!" << std::endl;