From c42eb59d2e6947c51dcc6e952e7e626e5a1531ea Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 8 Sep 2021 16:10:18 +0200 Subject: [PATCH 1/4] UART bugfixes and improvements --- hal/src/fsfw_hal/linux/uart/UartComIF.cpp | 42 ++++++++++++++++------ hal/src/fsfw_hal/linux/uart/UartCookie.cpp | 4 +-- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/hal/src/fsfw_hal/linux/uart/UartComIF.cpp b/hal/src/fsfw_hal/linux/uart/UartComIF.cpp index f52b6b1e..f5754c6e 100644 --- a/hal/src/fsfw_hal/linux/uart/UartComIF.cpp +++ b/hal/src/fsfw_hal/linux/uart/UartComIF.cpp @@ -1,6 +1,7 @@ -#include "fsfw_hal/linux/uart/UartComIF.h" +#include "UartComIF.h" #include "OBSWConfig.h" +#include "fsfw_hal/linux/utility.h" #include "fsfw/serviceinterface/ServiceInterface.h" #include @@ -60,7 +61,13 @@ int UartComIF::configureUartPort(UartCookie* uartCookie) { struct termios options = {}; std::string deviceFile = uartCookie->getDeviceFile(); - int fd = open(deviceFile.c_str(), O_RDWR); + int flags = O_RDWR; + if(uartCookie->getUartMode() == UartModes::CANONICAL) { + // In non-canonical mode, don't specify O_NONBLOCK because these properties will be + // controlled by the VTIME and VMIN parameters and O_NONBLOCK would override this + flags |= O_NONBLOCK; + } + int fd = open(deviceFile.c_str(), flags); if (fd < 0) { sif::warning << "UartComIF::configureUartPort: Failed to open uart " << deviceFile << @@ -259,23 +266,22 @@ void UartComIF::configureBaudrate(struct termios* options, UartCookie* uartCooki ReturnValue_t UartComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, size_t sendLen) { - int fd = 0; std::string deviceFile; UartDeviceMapIter uartDeviceMapIter; - if(sendData == nullptr) { - sif::debug << "UartComIF::sendMessage: Send Data is nullptr" << std::endl; - return RETURN_FAILED; - } - if(sendLen == 0) { return RETURN_OK; } + if(sendData == nullptr) { + sif::warning << "UartComIF::sendMessage: Send data is nullptr" << std::endl; + return RETURN_FAILED; + } + UartCookie* uartCookie = dynamic_cast(cookie); if(uartCookie == nullptr) { - sif::debug << "UartComIF::sendMessasge: Invalid UART Cookie!" << std::endl; + sif::warning << "UartComIF::sendMessasge: Invalid UART Cookie!" << std::endl; return NULLPOINTER; } @@ -347,12 +353,13 @@ ReturnValue_t UartComIF::handleCanonicalRead(UartCookie& uartCookie, UartDeviceM size_t maxReplySize = uartCookie.getMaxReplyLen(); int fd = iter->second.fileDescriptor; auto bufferPtr = iter->second.replyBuffer.data(); + iter->second.replyLen = 0; do { size_t allowedReadSize = 0; if(currentBytesRead >= maxReplySize) { // Overflow risk. Emit warning, trigger event and break. If this happens, // the reception buffer is not large enough or data is not polled often enough. -#if OBSW_VERBOSE_LEVEL >= 1 +#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "UartComIF::requestReceiveMessage: Next read would cause overflow!" << std::endl; @@ -370,7 +377,20 @@ ReturnValue_t UartComIF::handleCanonicalRead(UartCookie& uartCookie, UartDeviceM bytesRead = read(fd, bufferPtr, allowedReadSize); if (bytesRead < 0) { - return RETURN_FAILED; + // EAGAIN: No data available in non-blocking mode + if(errno != EAGAIN) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "UartComIF::handleCanonicalRead: read failed with code" << + errno << ": " << strerror(errno) << std::endl; +#else + sif::printWarning("UartComIF::handleCanonicalRead: read failed with code %d: %s\n", + errno, strerror(errno)); +#endif +#endif + return RETURN_FAILED; + } + } else if(bytesRead > 0) { iter->second.replyLen += bytesRead; diff --git a/hal/src/fsfw_hal/linux/uart/UartCookie.cpp b/hal/src/fsfw_hal/linux/uart/UartCookie.cpp index 339c7451..1c52e9cd 100644 --- a/hal/src/fsfw_hal/linux/uart/UartCookie.cpp +++ b/hal/src/fsfw_hal/linux/uart/UartCookie.cpp @@ -4,8 +4,8 @@ UartCookie::UartCookie(object_id_t handlerId, std::string deviceFile, UartModes uartMode, uint32_t baudrate, size_t maxReplyLen): - handlerId(handlerId), deviceFile(deviceFile), uartMode(uartMode), baudrate(baudrate), - maxReplyLen(maxReplyLen) { + handlerId(handlerId), deviceFile(deviceFile), uartMode(uartMode), + baudrate(baudrate), maxReplyLen(maxReplyLen) { } UartCookie::~UartCookie() {} From c9bfc8464aede0f79c167e18c5c0c79ded2444ce Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sat, 11 Sep 2021 17:39:42 +0200 Subject: [PATCH 2/4] added function to enable periodic reply --- src/fsfw/devicehandlers/DeviceHandlerBase.cpp | 23 +++++++++++------ src/fsfw/devicehandlers/DeviceHandlerBase.h | 25 +++++++++++++------ 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp index 1a7fbc91..95e25b74 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp @@ -430,12 +430,7 @@ ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId, DeviceReplyInfo info; info.maxDelayCycles = maxDelayCycles; info.periodic = periodic; - if(info.periodic) { - info.delayCycles = info.maxDelayCycles; - } - else { - info.delayCycles = 0; - } + info.delayCycles = 0; info.replyLen = replyLen; info.dataSet = dataSet; info.command = deviceCommandMap.end(); @@ -474,7 +469,7 @@ ReturnValue_t DeviceHandlerBase::updateReplyMapEntry(DeviceCommandId_t deviceRep auto replyIter = deviceReplyMap.find(deviceReply); if (replyIter == deviceReplyMap.end()) { triggerEvent(INVALID_DEVICE_COMMAND, deviceReply); - return RETURN_FAILED; + return COMMAND_NOT_SUPPORTED; } else { DeviceReplyInfo *info = &(replyIter->second); if (maxDelayCycles != 0) { @@ -486,6 +481,20 @@ ReturnValue_t DeviceHandlerBase::updateReplyMapEntry(DeviceCommandId_t deviceRep } } +ReturnValue_t DeviceHandlerBase::enablePeriodicReply(DeviceCommandId_t deviceReply) { + auto replyIter = deviceReplyMap.find(deviceReply); + if (replyIter == deviceReplyMap.end()) { + triggerEvent(INVALID_DEVICE_COMMAND, deviceReply); + return COMMAND_NOT_SUPPORTED; + } else { + DeviceReplyInfo *info = &(replyIter->second); + if(not info->periodic) { + return COMMAND_NOT_SUPPORTED; + } + info->delayCycles = info->maxDelayCycles; + } + return HasReturnvaluesIF::RETURN_OK; +} ReturnValue_t DeviceHandlerBase::setReplyDataset(DeviceCommandId_t replyId, LocalPoolDataSetBase *dataSet) { diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.h b/src/fsfw/devicehandlers/DeviceHandlerBase.h index 53bd1e65..d478b0fa 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.h +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.h @@ -449,7 +449,9 @@ protected: * @param replyLen Will be supplied to the requestReceiveMessage call of * the communication interface. * @param periodic Indicates if the command is periodic (i.e. it is sent - * by the device repeatedly without request) or not. Default is aperiodic (0) + * by the device repeatedly without request) or not. Default is aperiodic (0). + * Please note that periodic replies are disabled by default. You can enable them with + * #enablePeriodicReplies * @return - @c RETURN_OK when the command was successfully inserted, * - @c RETURN_FAILED else. */ @@ -464,7 +466,9 @@ protected: * @param maxDelayCycles The maximum number of delay cycles the reply waits * until it times out. * @param periodic Indicates if the command is periodic (i.e. it is sent - * by the device repeatedly without request) or not. Default is aperiodic (0) + * by the device repeatedly without request) or not. Default is aperiodic (0). + * Please note that periodic replies are disabled by default. You can enable them with + * #enablePeriodicReplies * @return - @c RETURN_OK when the command was successfully inserted, * - @c RETURN_FAILED else. */ @@ -480,6 +484,13 @@ protected: */ ReturnValue_t insertInCommandMap(DeviceCommandId_t deviceCommand); + /** + * Enables a periodic reply for a given command. It sets to delay cycles to the specified + * maximum delay cycles for a given reply ID. + * @return + */ + ReturnValue_t enablePeriodicReply(DeviceCommandId_t deviceReply); + /** * @brief This function returns the reply length of the next reply to read. * @@ -493,16 +504,14 @@ protected: virtual size_t getNextReplyLength(DeviceCommandId_t deviceCommand); /** - * @brief This is a helper method to facilitate updating entries - * in the reply map. + * @brief This is a helper method to facilitate updating entries in the reply map. * @param deviceCommand Identifier of the reply to update. - * @param delayCycles The current number of delay cycles to wait. - * As stated in #fillCommandAndCookieMap, to disable periodic commands, - * this is set to zero. + * @param delayCycles The current number of delay cycles to wait. As stated in + * #fillCommandAndReplyMap, to disable periodic commands, this is set to zero. * @param maxDelayCycles The maximum number of delay cycles the reply waits * until it times out. By passing 0 the entry remains untouched. * @param periodic Indicates if the command is periodic (i.e. it is sent - * by the device repeatedly without request) or not.Default is aperiodic (0). + * by the device repeatedly without request) or not. Default is aperiodic (0). * Warning: The setting always overrides the value that was entered in the map. * @return - @c RETURN_OK when the command was successfully inserted, * - @c RETURN_FAILED else. From 11a3c8c21f8a80d5c0872e99e39bd655f18acfa7 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sat, 11 Sep 2021 17:42:29 +0200 Subject: [PATCH 3/4] added option to disable it as well --- src/fsfw/devicehandlers/DeviceHandlerBase.cpp | 9 +++++++-- src/fsfw/devicehandlers/DeviceHandlerBase.h | 5 +++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp index 95e25b74..aab3aa16 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp @@ -481,7 +481,7 @@ ReturnValue_t DeviceHandlerBase::updateReplyMapEntry(DeviceCommandId_t deviceRep } } -ReturnValue_t DeviceHandlerBase::enablePeriodicReply(DeviceCommandId_t deviceReply) { +ReturnValue_t DeviceHandlerBase::enablePeriodicReply(bool enable, DeviceCommandId_t deviceReply) { auto replyIter = deviceReplyMap.find(deviceReply); if (replyIter == deviceReplyMap.end()) { triggerEvent(INVALID_DEVICE_COMMAND, deviceReply); @@ -491,7 +491,12 @@ ReturnValue_t DeviceHandlerBase::enablePeriodicReply(DeviceCommandId_t deviceRep if(not info->periodic) { return COMMAND_NOT_SUPPORTED; } - info->delayCycles = info->maxDelayCycles; + if(enable) { + info->delayCycles = info->maxDelayCycles; + } + else { + info->delayCycles = 0; + } } return HasReturnvaluesIF::RETURN_OK; } diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.h b/src/fsfw/devicehandlers/DeviceHandlerBase.h index d478b0fa..138b429e 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.h +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.h @@ -486,10 +486,11 @@ protected: /** * Enables a periodic reply for a given command. It sets to delay cycles to the specified - * maximum delay cycles for a given reply ID. + * maximum delay cycles for a given reply ID if enabled or to 0 if disabled. + * @param enable Specify whether to enable or disable a given periodic reply * @return */ - ReturnValue_t enablePeriodicReply(DeviceCommandId_t deviceReply); + ReturnValue_t enablePeriodicReply(bool enable, DeviceCommandId_t deviceReply); /** * @brief This function returns the reply length of the next reply to read. From 134deb3f433988513617a0d510fbbf8629b34fbc Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sat, 11 Sep 2021 17:43:58 +0200 Subject: [PATCH 4/4] renamed function --- src/fsfw/devicehandlers/DeviceHandlerBase.cpp | 2 +- src/fsfw/devicehandlers/DeviceHandlerBase.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp index aab3aa16..c3fc023e 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp @@ -481,7 +481,7 @@ ReturnValue_t DeviceHandlerBase::updateReplyMapEntry(DeviceCommandId_t deviceRep } } -ReturnValue_t DeviceHandlerBase::enablePeriodicReply(bool enable, DeviceCommandId_t deviceReply) { +ReturnValue_t DeviceHandlerBase::updatePeriodicReply(bool enable, DeviceCommandId_t deviceReply) { auto replyIter = deviceReplyMap.find(deviceReply); if (replyIter == deviceReplyMap.end()) { triggerEvent(INVALID_DEVICE_COMMAND, deviceReply); diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.h b/src/fsfw/devicehandlers/DeviceHandlerBase.h index 138b429e..30d36ef0 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.h +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.h @@ -451,7 +451,7 @@ protected: * @param periodic Indicates if the command is periodic (i.e. it is sent * by the device repeatedly without request) or not. Default is aperiodic (0). * Please note that periodic replies are disabled by default. You can enable them with - * #enablePeriodicReplies + * #updatePeriodicReply * @return - @c RETURN_OK when the command was successfully inserted, * - @c RETURN_FAILED else. */ @@ -468,7 +468,7 @@ protected: * @param periodic Indicates if the command is periodic (i.e. it is sent * by the device repeatedly without request) or not. Default is aperiodic (0). * Please note that periodic replies are disabled by default. You can enable them with - * #enablePeriodicReplies + * #updatePeriodicReply * @return - @c RETURN_OK when the command was successfully inserted, * - @c RETURN_FAILED else. */ @@ -490,7 +490,7 @@ protected: * @param enable Specify whether to enable or disable a given periodic reply * @return */ - ReturnValue_t enablePeriodicReply(bool enable, DeviceCommandId_t deviceReply); + ReturnValue_t updatePeriodicReply(bool enable, DeviceCommandId_t deviceReply); /** * @brief This function returns the reply length of the next reply to read.