210 lines
6.6 KiB
C++
210 lines
6.6 KiB
C++
#include "SyrlinksComHandler.h"
|
|
|
|
#include <fcntl.h>
|
|
#include <fsfw/ipc/MutexGuard.h>
|
|
#include <fsfw/tasks/SemaphoreFactory.h>
|
|
#include <fsfw/tasks/TaskFactory.h>
|
|
#include <fsfw/timemanager/Stopwatch.h>
|
|
#include <fsfw_hal/linux/serial/SerialCookie.h>
|
|
#include <fsfw_hal/linux/serial/helper.h>
|
|
#include <unistd.h>
|
|
|
|
using namespace returnvalue;
|
|
|
|
SyrlinksComHandler::SyrlinksComHandler(object_id_t objectId)
|
|
: SystemObject(objectId), ringBuf(2048, true) {
|
|
lock = MutexFactory::instance()->createMutex();
|
|
semaphore = SemaphoreFactory::instance()->createBinarySemaphore();
|
|
semaphore->acquire();
|
|
}
|
|
|
|
ReturnValue_t SyrlinksComHandler::performOperation(uint8_t opCode) {
|
|
while (true) {
|
|
lock->lockMutex();
|
|
state = State::SLEEPING;
|
|
lock->unlockMutex();
|
|
semaphore->acquire();
|
|
// Stopwatch watch;
|
|
readOneReply();
|
|
}
|
|
return returnvalue::OK;
|
|
}
|
|
|
|
ReturnValue_t SyrlinksComHandler::initializeInterface(CookieIF *cookie) {
|
|
if (cookie == nullptr) {
|
|
return returnvalue::FAILED;
|
|
}
|
|
SerialCookie *serCookie = dynamic_cast<SerialCookie *>(cookie);
|
|
if (serCookie == nullptr) {
|
|
return DeviceCommunicationIF::INVALID_COOKIE_TYPE;
|
|
}
|
|
// comCookie = serCookie;
|
|
std::string devname = serCookie->getDeviceFile();
|
|
/* Get file descriptor */
|
|
serialPort = open(devname.c_str(), O_RDWR);
|
|
if (serialPort < 0) {
|
|
sif::warning << "SyrlinksComHandler: open call failed with error [" << errno << ", "
|
|
<< strerror(errno) << std::endl;
|
|
return returnvalue::FAILED;
|
|
}
|
|
// Setting up UART parameters
|
|
serial::setStopbits(tty, serCookie->getStopBits());
|
|
serial::setParity(tty, serCookie->getParity());
|
|
serial::setBitsPerWord(tty, BitsPerWord::BITS_8);
|
|
tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control
|
|
serial::enableRead(tty);
|
|
serial::ignoreCtrlLines(tty);
|
|
|
|
// Use non-canonical mode and clear echo flag
|
|
tty.c_lflag &= ~(ICANON | ECHO);
|
|
|
|
// Non-blocking mode, use polling
|
|
tty.c_cc[VTIME] = 0;
|
|
tty.c_cc[VMIN] = 0;
|
|
|
|
serial::setBaudrate(tty, serCookie->getBaudrate());
|
|
if (tcsetattr(serialPort, TCSANOW, &tty) != 0) {
|
|
sif::warning << "ScexUartReader::initializeInterface: tcsetattr call failed with error ["
|
|
<< errno << ", " << strerror(errno) << std::endl;
|
|
}
|
|
// Flush received and unread data
|
|
tcflush(serialPort, TCIOFLUSH);
|
|
return returnvalue::OK;
|
|
}
|
|
|
|
ReturnValue_t SyrlinksComHandler::sendMessage(CookieIF *cookie, const uint8_t *sendData,
|
|
size_t sendLen) {
|
|
{
|
|
MutexGuard mg(lock);
|
|
if (state != State::SLEEPING) {
|
|
return BUSY;
|
|
}
|
|
}
|
|
serial::flushRxBuf(serialPort);
|
|
|
|
ssize_t writtenBytes = write(serialPort, sendData, sendLen);
|
|
if (writtenBytes != static_cast<ssize_t>(sendLen)) {
|
|
sif::warning << "StrComHandler: Sending packet failed" << std::endl;
|
|
return returnvalue::FAILED;
|
|
}
|
|
{
|
|
MutexGuard mg(lock);
|
|
state = State::ACTIVE;
|
|
}
|
|
semaphore->release();
|
|
return returnvalue::OK;
|
|
}
|
|
|
|
ReturnValue_t SyrlinksComHandler::getSendSuccess(CookieIF *cookie) { return returnvalue::OK; }
|
|
|
|
ReturnValue_t SyrlinksComHandler::requestReceiveMessage(CookieIF *cookie, size_t requestLen) {
|
|
return returnvalue::OK;
|
|
}
|
|
|
|
ReturnValue_t SyrlinksComHandler::handleSerialReception() {
|
|
ssize_t bytesRead = read(serialPort, reinterpret_cast<void *>(recBuf.data()),
|
|
static_cast<unsigned int>(recBuf.size()));
|
|
if (bytesRead == 0) {
|
|
return NO_SERIAL_DATA_READ;
|
|
} else if (bytesRead < 0) {
|
|
sif::warning << "SyrlinksComHandler: read call failed with error [" << errno << ", "
|
|
<< strerror(errno) << "]" << std::endl;
|
|
return FAILED;
|
|
} else if (bytesRead >= static_cast<int>(recBuf.size())) {
|
|
sif::error << "SyrlinksComHandler: Receive buffer too small for " << bytesRead << " bytes"
|
|
<< std::endl;
|
|
return FAILED;
|
|
} else if (bytesRead > 0) {
|
|
// sif::debug << "Received " << bytesRead << " bytes from the Syrlinks" << std::endl;
|
|
// arrayprinter::print(recBuf.data(), bytesRead);
|
|
ringBuf.writeData(recBuf.data(), bytesRead);
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
ReturnValue_t SyrlinksComHandler::readReceivedMessage(CookieIF *cookie, uint8_t **buffer,
|
|
size_t *size) {
|
|
MutexGuard mg(lock);
|
|
if (replyResult != returnvalue::OK) {
|
|
ReturnValue_t tmp = replyResult;
|
|
replyResult = returnvalue::OK;
|
|
return tmp;
|
|
}
|
|
if (replyLen == 0) {
|
|
*size = 0;
|
|
return returnvalue::OK;
|
|
}
|
|
*buffer = ipcBuf.data();
|
|
*size = replyLen;
|
|
replyLen = 0;
|
|
return returnvalue::OK;
|
|
}
|
|
|
|
ReturnValue_t SyrlinksComHandler::readOneReply() {
|
|
ReturnValue_t result;
|
|
uint32_t nextDelayMs = 1;
|
|
replyTimeout.resetTimer();
|
|
while (true) {
|
|
handleSerialReception();
|
|
result = tryReadingOneSyrlinksReply();
|
|
if (result == returnvalue::OK) {
|
|
return returnvalue::OK;
|
|
}
|
|
if (replyTimeout.hasTimedOut()) {
|
|
{
|
|
MutexGuard mg(lock);
|
|
replyResult = DeviceCommunicationIF::NO_REPLY_RECEIVED;
|
|
}
|
|
return returnvalue::FAILED;
|
|
}
|
|
TaskFactory::delayTask(nextDelayMs);
|
|
if (nextDelayMs < 32) {
|
|
nextDelayMs *= 2;
|
|
}
|
|
}
|
|
}
|
|
ReturnValue_t SyrlinksComHandler::tryReadingOneSyrlinksReply() {
|
|
size_t bytesToRead = ringBuf.getAvailableReadData();
|
|
if (bytesToRead == 0) {
|
|
return NO_PACKET_FOUND;
|
|
}
|
|
bool startMarkerFound = false;
|
|
size_t startIdx = 0;
|
|
ringBuf.readData(recBuf.data(), bytesToRead);
|
|
for (size_t idx = 0; idx < bytesToRead; idx++) {
|
|
if (recBuf[idx] == START_MARKER) {
|
|
if (startMarkerFound) {
|
|
// Probably lost a packet. Discard broken packet.
|
|
sif::warning << "SyrlinksComHandler: Detected 2 consecutive start markers" << std::endl;
|
|
ringBuf.deleteData(idx);
|
|
} else {
|
|
startMarkerFound = true;
|
|
startIdx = idx;
|
|
}
|
|
}
|
|
if (recBuf[idx] == END_MARKER) {
|
|
if (startMarkerFound) {
|
|
{
|
|
MutexGuard mg(lock);
|
|
replyLen = idx - startIdx + 1;
|
|
}
|
|
// Copy detected packet to IPC buffer so it can be passed back to the device handler.
|
|
if (replyLen > ipcBuf.size()) {
|
|
sif::error << "SyrlinksComHandler: Detected reply too large" << std::endl;
|
|
ringBuf.deleteData(idx);
|
|
return returnvalue::FAILED;
|
|
}
|
|
// sif::debug << "Detected Syrlinks reply with length " << replyLen << std::endl;
|
|
std::memcpy(ipcBuf.data(), recBuf.data() + startIdx, replyLen);
|
|
ringBuf.deleteData(idx + 1);
|
|
return returnvalue::OK;
|
|
} else {
|
|
// Probably lost a packet. Discard broken packet.
|
|
sif::warning << "SyrlinksComHandler: Detected 2 consecutive end markers" << std::endl;
|
|
ringBuf.deleteData(idx + 1);
|
|
}
|
|
}
|
|
}
|
|
return NO_PACKET_FOUND;
|
|
}
|