From 78e996b2beae31d5dea25168eb41b53844bd9d25 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 16 Jun 2021 19:19:45 +0200 Subject: [PATCH] extended uart com if --- linux/uart/UartComIF.cpp | 171 ++++++++++++++++++++++++-------------- linux/uart/UartComIF.h | 1 + linux/uart/UartCookie.cpp | 16 ++++ linux/uart/UartCookie.h | 18 ++++ 4 files changed, 144 insertions(+), 62 deletions(-) diff --git a/linux/uart/UartComIF.cpp b/linux/uart/UartComIF.cpp index 95cc5a3..95ff46b 100644 --- a/linux/uart/UartComIF.cpp +++ b/linux/uart/UartComIF.cpp @@ -1,6 +1,7 @@ #include "UartComIF.h" +#include "OBSWConfig.h" -#include +#include "fsfw/serviceinterface/ServiceInterface.h" #include #include @@ -15,12 +16,12 @@ UartComIF::~UartComIF() {} ReturnValue_t UartComIF::initializeInterface(CookieIF * cookie) { - std::string deviceFile; - UartDeviceMapIter uartDeviceMapIter; + std::string deviceFile; + UartDeviceMapIter uartDeviceMapIter; - if(cookie == nullptr) { - return NULLPOINTER; - } + if(cookie == nullptr) { + return NULLPOINTER; + } UartCookie* uartCookie = dynamic_cast(cookie); if (uartCookie == nullptr) { @@ -31,32 +32,32 @@ ReturnValue_t UartComIF::initializeInterface(CookieIF * cookie) { deviceFile = uartCookie->getDeviceFile(); uartDeviceMapIter = uartDeviceMap.find(deviceFile); - if(uartDeviceMapIter == uartDeviceMap.end()) { - int fileDescriptor = configureUartPort(uartCookie); - if (fileDescriptor < 0) { - return RETURN_FAILED; - } - size_t maxReplyLen = uartCookie->getMaxReplyLen(); - UartElements uartElements = {fileDescriptor, std::vector(maxReplyLen), 0}; - auto status = uartDeviceMap.emplace(deviceFile, uartElements); + if(uartDeviceMapIter == uartDeviceMap.end()) { + int fileDescriptor = configureUartPort(uartCookie); + if (fileDescriptor < 0) { + return RETURN_FAILED; + } + size_t maxReplyLen = uartCookie->getMaxReplyLen(); + UartElements uartElements = {fileDescriptor, std::vector(maxReplyLen), 0}; + auto status = uartDeviceMap.emplace(deviceFile, uartElements); if (status.second == false) { sif::warning << "UartComIF::initializeInterface: Failed to insert device " << deviceFile << "to UART device map" << std::endl; return RETURN_FAILED; } - } - else { - sif::warning << "UartComIF::initializeInterface: UART device " << deviceFile << - " already in use" << std::endl; - return RETURN_FAILED; - } + } + else { + sif::warning << "UartComIF::initializeInterface: UART device " << deviceFile << + " already in use" << std::endl; + return RETURN_FAILED; + } - return RETURN_OK; + return RETURN_OK; } int UartComIF::configureUartPort(UartCookie* uartCookie) { - struct termios options; + struct termios options = {}; std::string deviceFile = uartCookie->getDeviceFile(); int fd = open(deviceFile.c_str(), O_RDWR); @@ -78,6 +79,9 @@ int UartComIF::configureUartPort(UartCookie* uartCookie) { setStopBitOptions(&options, uartCookie); setDatasizeOptions(&options, uartCookie); setFixedOptions(&options); + if(uartCookie->getInputShouldBeFlushed()) { + tcflush(fd, TCIFLUSH); + } /* Sets uart to non-blocking mode. Read returns immediately when there are no data available */ options.c_cc[VTIME] = 0; @@ -255,46 +259,46 @@ 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; + int fd = 0; + std::string deviceFile; + UartDeviceMapIter uartDeviceMapIter; - if(sendData == nullptr) { + if(sendData == nullptr) { sif::debug << "UartComIF::sendMessage: Send Data is nullptr" << std::endl; - return RETURN_FAILED; - } + return RETURN_FAILED; + } - if(sendLen == 0) { - return RETURN_OK; - } + if(sendLen == 0) { + return RETURN_OK; + } - UartCookie* uartCookie = dynamic_cast(cookie); - if(uartCookie == nullptr) { + UartCookie* uartCookie = dynamic_cast(cookie); + if(uartCookie == nullptr) { sif::debug << "UartComIF::sendMessasge: Invalid UART Cookie!" << std::endl; - return NULLPOINTER; - } + return NULLPOINTER; + } - deviceFile = uartCookie->getDeviceFile(); - uartDeviceMapIter = uartDeviceMap.find(deviceFile); - if (uartDeviceMapIter == uartDeviceMap.end()) { - sif::debug << "UartComIF::sendMessage: Device file " << deviceFile << - "not in UART map" << std::endl; - return RETURN_FAILED; - } + deviceFile = uartCookie->getDeviceFile(); + uartDeviceMapIter = uartDeviceMap.find(deviceFile); + if (uartDeviceMapIter == uartDeviceMap.end()) { + sif::debug << "UartComIF::sendMessage: Device file " << deviceFile << + "not in UART map" << std::endl; + return RETURN_FAILED; + } - fd = uartDeviceMapIter->second.fileDescriptor; + fd = uartDeviceMapIter->second.fileDescriptor; - if (write(fd, sendData, sendLen) != (int)sendLen) { - sif::error << "UartComIF::sendMessage: Failed to send data with error code " << - errno << ": Error description: " << strerror(errno) << std::endl; - return RETURN_FAILED; - } + if (write(fd, sendData, sendLen) != (int)sendLen) { + sif::error << "UartComIF::sendMessage: Failed to send data with error code " << + errno << ": Error description: " << strerror(errno) << std::endl; + return RETURN_FAILED; + } - return RETURN_OK; + return RETURN_OK; } ReturnValue_t UartComIF::getSendSuccess(CookieIF *cookie) { - return RETURN_OK; + return RETURN_OK; } ReturnValue_t UartComIF::requestReceiveMessage(CookieIF *cookie, size_t requestLen) { @@ -325,10 +329,53 @@ ReturnValue_t UartComIF::requestReceiveMessage(CookieIF *cookie, size_t requestL fd = uartDeviceMapIter->second.fileDescriptor; bufferPtr = uartDeviceMapIter->second.replyBuffer.data(); if (uartMode == UartModes::CANONICAL) { - int bytesRead = read(fd, bufferPtr, uartCookie->getMaxReplyLen()); - uartDeviceMapIter->second.replyLen = bytesRead; + uint8_t maxReadCycles = uartCookie->getReadCycles(); + uint8_t currentReadCycles = 0; + int bytesRead = 0; + size_t currentBytesRead = 0; + size_t maxReplySize = uartCookie->getMaxReplyLen(); + 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. + // TODO: Emit event + // TODO: Return error? +#if OBSW_VERBOSE_LEVEL >= 1 + sif::warning << "UartComIF::requestReceiveMessage: Next read would cause overflow!" + << std::endl; +#endif + break; + } + else { + allowedReadSize = maxReplySize - currentBytesRead; + } + + bytesRead = read(fd, bufferPtr, allowedReadSize); + if (bytesRead < 0) { + return RETURN_FAILED; + } + else if (bytesRead != static_cast(requestLen)) { + sif::debug << "UartComIF::requestReceiveMessage: Only read " << bytesRead << + " of " << requestLen << " bytes" << std::endl; + return RETURN_FAILED; + } + else if(bytesRead > 0) { + uartDeviceMapIter->second.replyLen += bytesRead; + bufferPtr += bytesRead; + currentBytesRead += bytesRead; + } + currentReadCycles++; + } while(bytesRead > 0 and currentReadCycles < maxReadCycles); } else if (uartMode == UartModes::NON_CANONICAL) { + // Size check to prevent buffer overflow + if(requestLen > uartCookie->getMaxReplyLen()) { + // TODO: Emit warning + // TODO: Emit event + // TODO: Better returnvalue + return HasReturnvaluesIF::RETURN_FAILED; + } int bytesRead = read(fd, bufferPtr, requestLen); if (bytesRead < 0) { return RETURN_FAILED; @@ -346,18 +393,18 @@ ReturnValue_t UartComIF::requestReceiveMessage(CookieIF *cookie, size_t requestL } ReturnValue_t UartComIF::readReceivedMessage(CookieIF *cookie, - uint8_t **buffer, size_t* size) { + uint8_t **buffer, size_t* size) { std::string deviceFile; UartDeviceMapIter uartDeviceMapIter; UartCookie* uartCookie = dynamic_cast(cookie); - if(uartCookie == nullptr) { + if(uartCookie == nullptr) { sif::debug << "UartComIF::readReceivedMessage: Invalid uart cookie!" << std::endl; - return NULLPOINTER; - } + return NULLPOINTER; + } - deviceFile = uartCookie->getDeviceFile(); + deviceFile = uartCookie->getDeviceFile(); uartDeviceMapIter = uartDeviceMap.find(deviceFile); if (uartDeviceMapIter == uartDeviceMap.end()) { sif::debug << "UartComIF::readReceivedMessage: Device file " << deviceFile << @@ -365,13 +412,13 @@ ReturnValue_t UartComIF::readReceivedMessage(CookieIF *cookie, return RETURN_FAILED; } - *buffer = uartDeviceMapIter->second.replyBuffer.data(); - *size = uartDeviceMapIter->second.replyLen; + *buffer = uartDeviceMapIter->second.replyBuffer.data(); + *size = uartDeviceMapIter->second.replyLen; - /* Length is reset to 0 to prevent reading the same data twice */ - uartDeviceMapIter->second.replyLen = 0; + /* Length is reset to 0 to prevent reading the same data twice */ + uartDeviceMapIter->second.replyLen = 0; - return RETURN_OK; + return RETURN_OK; } void UartComIF::setUartMode(struct termios *options, UartCookie &uartCookie) { diff --git a/linux/uart/UartComIF.h b/linux/uart/UartComIF.h index dc0a509..b4fad48 100644 --- a/linux/uart/UartComIF.h +++ b/linux/uart/UartComIF.h @@ -98,6 +98,7 @@ private: void configureBaudrate(struct termios* options, UartCookie* uartCookie); void setUartMode(struct termios* options, UartCookie& uartCookie); + }; #endif /* BSP_Q7S_COMIF_UARTCOMIF_H_ */ diff --git a/linux/uart/UartCookie.cpp b/linux/uart/UartCookie.cpp index d263c29..f06790b 100644 --- a/linux/uart/UartCookie.cpp +++ b/linux/uart/UartCookie.cpp @@ -66,3 +66,19 @@ void UartCookie::setOneStopBit() { UartModes UartCookie::getUartMode() const { return uartMode; } + +void UartCookie::setReadCycles(uint8_t readCycles) { + this->readCycles = readCycles; +} + +void UartCookie::setToFlushInput(bool enable) { + this->flushInput = enable; +} + +uint8_t UartCookie::getReadCycles() const { + return readCycles; +} + +bool UartCookie::getInputShouldBeFlushed() { + return this->flushInput; +} diff --git a/linux/uart/UartCookie.h b/linux/uart/UartCookie.h index 406ee62..a26a5de 100644 --- a/linux/uart/UartCookie.h +++ b/linux/uart/UartCookie.h @@ -56,6 +56,22 @@ public: uint8_t getBitsPerWord() const; StopBits getStopBits() const; UartModes getUartMode() const; + /** + * The UART ComIF will only perform a specified number of read cycles for the canonical mode. + * The user can specify how many of those read cycles are performed for one device handler + * communication cycle. An example use-case would be to read all available GPS NMEA strings + * at once. + * @param readCycles + */ + void setReadCycles(uint8_t readCycles); + uint8_t getReadCycles() const; + + /** + * Allows to flush the data which was received but has not been read yet. This is useful + * to discard obsolete data at software startup. + */ + void setToFlushInput(bool enable); + bool getInputShouldBeFlushed(); /** * Functions two enable parity checking. @@ -78,10 +94,12 @@ private: std::string deviceFile; const UartModes uartMode; + bool flushInput = false; uint32_t baudrate; size_t maxReplyLen = 0; Parity parity = Parity::NONE; uint8_t bitsPerWord = 8; + uint8_t readCycles = 1; StopBits stopBits = StopBits::ONE_STOP_BIT; };