extended uart com if

This commit is contained in:
Robin Müller 2021-06-16 19:19:45 +02:00
parent c0287eb4a6
commit 78e996b2be
No known key found for this signature in database
GPG Key ID: 9C287E88FED11DF3
4 changed files with 144 additions and 62 deletions

View File

@ -1,6 +1,7 @@
#include "UartComIF.h" #include "UartComIF.h"
#include "OBSWConfig.h"
#include <fsfw/serviceinterface/ServiceInterface.h> #include "fsfw/serviceinterface/ServiceInterface.h"
#include <cstring> #include <cstring>
#include <fcntl.h> #include <fcntl.h>
@ -15,12 +16,12 @@ UartComIF::~UartComIF() {}
ReturnValue_t UartComIF::initializeInterface(CookieIF * cookie) { ReturnValue_t UartComIF::initializeInterface(CookieIF * cookie) {
std::string deviceFile; std::string deviceFile;
UartDeviceMapIter uartDeviceMapIter; UartDeviceMapIter uartDeviceMapIter;
if(cookie == nullptr) { if(cookie == nullptr) {
return NULLPOINTER; return NULLPOINTER;
} }
UartCookie* uartCookie = dynamic_cast<UartCookie*>(cookie); UartCookie* uartCookie = dynamic_cast<UartCookie*>(cookie);
if (uartCookie == nullptr) { if (uartCookie == nullptr) {
@ -31,32 +32,32 @@ ReturnValue_t UartComIF::initializeInterface(CookieIF * cookie) {
deviceFile = uartCookie->getDeviceFile(); deviceFile = uartCookie->getDeviceFile();
uartDeviceMapIter = uartDeviceMap.find(deviceFile); uartDeviceMapIter = uartDeviceMap.find(deviceFile);
if(uartDeviceMapIter == uartDeviceMap.end()) { if(uartDeviceMapIter == uartDeviceMap.end()) {
int fileDescriptor = configureUartPort(uartCookie); int fileDescriptor = configureUartPort(uartCookie);
if (fileDescriptor < 0) { if (fileDescriptor < 0) {
return RETURN_FAILED; return RETURN_FAILED;
} }
size_t maxReplyLen = uartCookie->getMaxReplyLen(); size_t maxReplyLen = uartCookie->getMaxReplyLen();
UartElements uartElements = {fileDescriptor, std::vector<uint8_t>(maxReplyLen), 0}; UartElements uartElements = {fileDescriptor, std::vector<uint8_t>(maxReplyLen), 0};
auto status = uartDeviceMap.emplace(deviceFile, uartElements); auto status = uartDeviceMap.emplace(deviceFile, uartElements);
if (status.second == false) { if (status.second == false) {
sif::warning << "UartComIF::initializeInterface: Failed to insert device " << sif::warning << "UartComIF::initializeInterface: Failed to insert device " <<
deviceFile << "to UART device map" << std::endl; deviceFile << "to UART device map" << std::endl;
return RETURN_FAILED; return RETURN_FAILED;
} }
} }
else { else {
sif::warning << "UartComIF::initializeInterface: UART device " << deviceFile << sif::warning << "UartComIF::initializeInterface: UART device " << deviceFile <<
" already in use" << std::endl; " already in use" << std::endl;
return RETURN_FAILED; return RETURN_FAILED;
} }
return RETURN_OK; return RETURN_OK;
} }
int UartComIF::configureUartPort(UartCookie* uartCookie) { int UartComIF::configureUartPort(UartCookie* uartCookie) {
struct termios options; struct termios options = {};
std::string deviceFile = uartCookie->getDeviceFile(); std::string deviceFile = uartCookie->getDeviceFile();
int fd = open(deviceFile.c_str(), O_RDWR); int fd = open(deviceFile.c_str(), O_RDWR);
@ -78,6 +79,9 @@ int UartComIF::configureUartPort(UartCookie* uartCookie) {
setStopBitOptions(&options, uartCookie); setStopBitOptions(&options, uartCookie);
setDatasizeOptions(&options, uartCookie); setDatasizeOptions(&options, uartCookie);
setFixedOptions(&options); setFixedOptions(&options);
if(uartCookie->getInputShouldBeFlushed()) {
tcflush(fd, TCIFLUSH);
}
/* Sets uart to non-blocking mode. Read returns immediately when there are no data available */ /* Sets uart to non-blocking mode. Read returns immediately when there are no data available */
options.c_cc[VTIME] = 0; options.c_cc[VTIME] = 0;
@ -255,46 +259,46 @@ void UartComIF::configureBaudrate(struct termios* options, UartCookie* uartCooki
ReturnValue_t UartComIF::sendMessage(CookieIF *cookie, ReturnValue_t UartComIF::sendMessage(CookieIF *cookie,
const uint8_t *sendData, size_t sendLen) { const uint8_t *sendData, size_t sendLen) {
int fd = 0; int fd = 0;
std::string deviceFile; std::string deviceFile;
UartDeviceMapIter uartDeviceMapIter; UartDeviceMapIter uartDeviceMapIter;
if(sendData == nullptr) { if(sendData == nullptr) {
sif::debug << "UartComIF::sendMessage: Send Data is nullptr" << std::endl; sif::debug << "UartComIF::sendMessage: Send Data is nullptr" << std::endl;
return RETURN_FAILED; return RETURN_FAILED;
} }
if(sendLen == 0) { if(sendLen == 0) {
return RETURN_OK; return RETURN_OK;
} }
UartCookie* uartCookie = dynamic_cast<UartCookie*>(cookie); UartCookie* uartCookie = dynamic_cast<UartCookie*>(cookie);
if(uartCookie == nullptr) { if(uartCookie == nullptr) {
sif::debug << "UartComIF::sendMessasge: Invalid UART Cookie!" << std::endl; sif::debug << "UartComIF::sendMessasge: Invalid UART Cookie!" << std::endl;
return NULLPOINTER; return NULLPOINTER;
} }
deviceFile = uartCookie->getDeviceFile(); deviceFile = uartCookie->getDeviceFile();
uartDeviceMapIter = uartDeviceMap.find(deviceFile); uartDeviceMapIter = uartDeviceMap.find(deviceFile);
if (uartDeviceMapIter == uartDeviceMap.end()) { if (uartDeviceMapIter == uartDeviceMap.end()) {
sif::debug << "UartComIF::sendMessage: Device file " << deviceFile << sif::debug << "UartComIF::sendMessage: Device file " << deviceFile <<
"not in UART map" << std::endl; "not in UART map" << std::endl;
return RETURN_FAILED; return RETURN_FAILED;
} }
fd = uartDeviceMapIter->second.fileDescriptor; fd = uartDeviceMapIter->second.fileDescriptor;
if (write(fd, sendData, sendLen) != (int)sendLen) { if (write(fd, sendData, sendLen) != (int)sendLen) {
sif::error << "UartComIF::sendMessage: Failed to send data with error code " << sif::error << "UartComIF::sendMessage: Failed to send data with error code " <<
errno << ": Error description: " << strerror(errno) << std::endl; errno << ": Error description: " << strerror(errno) << std::endl;
return RETURN_FAILED; return RETURN_FAILED;
} }
return RETURN_OK; return RETURN_OK;
} }
ReturnValue_t UartComIF::getSendSuccess(CookieIF *cookie) { ReturnValue_t UartComIF::getSendSuccess(CookieIF *cookie) {
return RETURN_OK; return RETURN_OK;
} }
ReturnValue_t UartComIF::requestReceiveMessage(CookieIF *cookie, size_t requestLen) { 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; fd = uartDeviceMapIter->second.fileDescriptor;
bufferPtr = uartDeviceMapIter->second.replyBuffer.data(); bufferPtr = uartDeviceMapIter->second.replyBuffer.data();
if (uartMode == UartModes::CANONICAL) { if (uartMode == UartModes::CANONICAL) {
int bytesRead = read(fd, bufferPtr, uartCookie->getMaxReplyLen()); uint8_t maxReadCycles = uartCookie->getReadCycles();
uartDeviceMapIter->second.replyLen = bytesRead; 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<int>(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) { 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); int bytesRead = read(fd, bufferPtr, requestLen);
if (bytesRead < 0) { if (bytesRead < 0) {
return RETURN_FAILED; return RETURN_FAILED;
@ -346,18 +393,18 @@ ReturnValue_t UartComIF::requestReceiveMessage(CookieIF *cookie, size_t requestL
} }
ReturnValue_t UartComIF::readReceivedMessage(CookieIF *cookie, ReturnValue_t UartComIF::readReceivedMessage(CookieIF *cookie,
uint8_t **buffer, size_t* size) { uint8_t **buffer, size_t* size) {
std::string deviceFile; std::string deviceFile;
UartDeviceMapIter uartDeviceMapIter; UartDeviceMapIter uartDeviceMapIter;
UartCookie* uartCookie = dynamic_cast<UartCookie*>(cookie); UartCookie* uartCookie = dynamic_cast<UartCookie*>(cookie);
if(uartCookie == nullptr) { if(uartCookie == nullptr) {
sif::debug << "UartComIF::readReceivedMessage: Invalid uart cookie!" << std::endl; sif::debug << "UartComIF::readReceivedMessage: Invalid uart cookie!" << std::endl;
return NULLPOINTER; return NULLPOINTER;
} }
deviceFile = uartCookie->getDeviceFile(); deviceFile = uartCookie->getDeviceFile();
uartDeviceMapIter = uartDeviceMap.find(deviceFile); uartDeviceMapIter = uartDeviceMap.find(deviceFile);
if (uartDeviceMapIter == uartDeviceMap.end()) { if (uartDeviceMapIter == uartDeviceMap.end()) {
sif::debug << "UartComIF::readReceivedMessage: Device file " << deviceFile << sif::debug << "UartComIF::readReceivedMessage: Device file " << deviceFile <<
@ -365,13 +412,13 @@ ReturnValue_t UartComIF::readReceivedMessage(CookieIF *cookie,
return RETURN_FAILED; return RETURN_FAILED;
} }
*buffer = uartDeviceMapIter->second.replyBuffer.data(); *buffer = uartDeviceMapIter->second.replyBuffer.data();
*size = uartDeviceMapIter->second.replyLen; *size = uartDeviceMapIter->second.replyLen;
/* Length is reset to 0 to prevent reading the same data twice */ /* Length is reset to 0 to prevent reading the same data twice */
uartDeviceMapIter->second.replyLen = 0; uartDeviceMapIter->second.replyLen = 0;
return RETURN_OK; return RETURN_OK;
} }
void UartComIF::setUartMode(struct termios *options, UartCookie &uartCookie) { void UartComIF::setUartMode(struct termios *options, UartCookie &uartCookie) {

View File

@ -98,6 +98,7 @@ private:
void configureBaudrate(struct termios* options, UartCookie* uartCookie); void configureBaudrate(struct termios* options, UartCookie* uartCookie);
void setUartMode(struct termios* options, UartCookie& uartCookie); void setUartMode(struct termios* options, UartCookie& uartCookie);
}; };
#endif /* BSP_Q7S_COMIF_UARTCOMIF_H_ */ #endif /* BSP_Q7S_COMIF_UARTCOMIF_H_ */

View File

@ -66,3 +66,19 @@ void UartCookie::setOneStopBit() {
UartModes UartCookie::getUartMode() const { UartModes UartCookie::getUartMode() const {
return uartMode; 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;
}

View File

@ -56,6 +56,22 @@ public:
uint8_t getBitsPerWord() const; uint8_t getBitsPerWord() const;
StopBits getStopBits() const; StopBits getStopBits() const;
UartModes getUartMode() 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. * Functions two enable parity checking.
@ -78,10 +94,12 @@ private:
std::string deviceFile; std::string deviceFile;
const UartModes uartMode; const UartModes uartMode;
bool flushInput = false;
uint32_t baudrate; uint32_t baudrate;
size_t maxReplyLen = 0; size_t maxReplyLen = 0;
Parity parity = Parity::NONE; Parity parity = Parity::NONE;
uint8_t bitsPerWord = 8; uint8_t bitsPerWord = 8;
uint8_t readCycles = 1;
StopBits stopBits = StopBits::ONE_STOP_BIT; StopBits stopBits = StopBits::ONE_STOP_BIT;
}; };