Make syrlinks COM more reliable
This commit is contained in:
@ -11,7 +11,8 @@ target_sources(
|
||||
ScexDleParser.cpp
|
||||
ScexHelper.cpp
|
||||
RwPollingTask.cpp
|
||||
AcsBoardPolling.cpp)
|
||||
AcsBoardPolling.cpp
|
||||
SyrlinksComHandler.cpp)
|
||||
|
||||
add_subdirectory(ploc)
|
||||
|
||||
|
@ -77,7 +77,7 @@ ReturnValue_t SusPolling::sendMessage(CookieIF* cookie, const uint8_t* sendData,
|
||||
susDevs[susIdx].mode = susReq->mode;
|
||||
}
|
||||
if (state == InternalState::IDLE) {
|
||||
state = InternalState::BUSY;
|
||||
state = InternalState::IS_BUSY;
|
||||
semaphore->release();
|
||||
}
|
||||
return OK;
|
||||
|
@ -18,7 +18,7 @@ class SusPolling : public SystemObject, public ExecutableObjectIF, public Device
|
||||
ReturnValue_t initialize() override;
|
||||
|
||||
private:
|
||||
enum class InternalState { IDLE, BUSY } state = InternalState::IDLE;
|
||||
enum class InternalState { IDLE, IS_BUSY } state = InternalState::IDLE;
|
||||
|
||||
struct SusDev {
|
||||
SpiCookie* cookie = nullptr;
|
||||
|
206
linux/devices/SyrlinksComHandler.cpp
Normal file
206
linux/devices/SyrlinksComHandler.cpp
Normal file
@ -0,0 +1,206 @@
|
||||
#include "SyrlinksComHandler.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <fsfw/ipc/MutexGuard.h>
|
||||
#include <fsfw/tasks/SemaphoreFactory.h>
|
||||
#include <fsfw/tasks/TaskFactory.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();
|
||||
readOneReply();
|
||||
semaphore->acquire();
|
||||
}
|
||||
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::info << "Received " << bytesRead << " bytes from the STR" << 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 returnvalue::OK;
|
||||
}
|
||||
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;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
std::memcpy(ipcBuf.data(), recBuf.data() + startIdx, replyLen);
|
||||
ringBuf.deleteData(idx);
|
||||
return returnvalue::OK;
|
||||
} else {
|
||||
// Probably lost a packet. Discard broken packet.
|
||||
sif::warning << "SyrlinksComHandler: Detected 2 consecutive end markers" << std::endl;
|
||||
ringBuf.deleteData(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NO_PACKET_FOUND;
|
||||
}
|
52
linux/devices/SyrlinksComHandler.h
Normal file
52
linux/devices/SyrlinksComHandler.h
Normal file
@ -0,0 +1,52 @@
|
||||
#ifndef LINUX_DEVICES_SYRLINKSCOMHANDLER_H_
|
||||
#define LINUX_DEVICES_SYRLINKSCOMHANDLER_H_
|
||||
|
||||
#include <fsfw/container/SimpleRingBuffer.h>
|
||||
#include <fsfw/devicehandlers/DeviceCommunicationIF.h>
|
||||
#include <fsfw/objectmanager/SystemObject.h>
|
||||
#include <fsfw/tasks/ExecutableObjectIF.h>
|
||||
#include <fsfw/tasks/SemaphoreIF.h>
|
||||
#include <termios.h>
|
||||
|
||||
class SyrlinksComHandler : public DeviceCommunicationIF,
|
||||
public ExecutableObjectIF,
|
||||
public SystemObject {
|
||||
public:
|
||||
SyrlinksComHandler(object_id_t objectId);
|
||||
|
||||
private:
|
||||
static constexpr char START_MARKER = '<';
|
||||
static constexpr char END_MARKER = '>';
|
||||
|
||||
//! [EXPORT] : [SKIP]
|
||||
static constexpr ReturnValue_t NO_SERIAL_DATA_READ = returnvalue::makeCode(2, 0);
|
||||
static constexpr ReturnValue_t NO_PACKET_FOUND = returnvalue::makeCode(2, 1);
|
||||
|
||||
enum class State { SLEEPING, ACTIVE } state = State::SLEEPING;
|
||||
|
||||
MutexIF *lock;
|
||||
SemaphoreIF *semaphore;
|
||||
int serialPort = 0;
|
||||
struct termios tty {};
|
||||
Countdown replyTimeout{};
|
||||
std::array<uint8_t, 2048> recBuf{};
|
||||
SimpleRingBuffer ringBuf;
|
||||
std::array<uint8_t, 1024> ipcBuf{};
|
||||
size_t replyLen = 0;
|
||||
ReturnValue_t replyResult = returnvalue::OK;
|
||||
|
||||
ReturnValue_t handleSerialReception();
|
||||
|
||||
ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
|
||||
ReturnValue_t initializeInterface(CookieIF *cookie) override;
|
||||
ReturnValue_t sendMessage(CookieIF *cookie, const uint8_t *sendData, size_t sendLen) override;
|
||||
ReturnValue_t getSendSuccess(CookieIF *cookie) override;
|
||||
ReturnValue_t requestReceiveMessage(CookieIF *cookie, size_t requestLen) override;
|
||||
ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer, size_t *size) override;
|
||||
|
||||
ReturnValue_t readOneReply();
|
||||
ReturnValue_t tryReadingOneSyrlinksReply();
|
||||
};
|
||||
|
||||
#endif /* LINUX_DEVICES_SYRLINKSCOMHANDLER_H_ */
|
@ -7,6 +7,9 @@ ArcsecDatalinkLayer::~ArcsecDatalinkLayer() {}
|
||||
ReturnValue_t ArcsecDatalinkLayer::checkRingBufForFrame(const uint8_t** decodedFrame,
|
||||
size_t& frameLen) {
|
||||
size_t currentLen = decodeRingBuf.getAvailableReadData();
|
||||
if (currentLen == 0) {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
decodeRingBuf.readData(rxAnalysisBuffer, currentLen);
|
||||
for (size_t idx = 0; idx < currentLen; idx++) {
|
||||
enum arc_dec_result decResult =
|
||||
|
@ -155,9 +155,7 @@ ReturnValue_t StrComHandler::startImageDownload(std::string path) {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
void StrComHandler::stopProcess() {
|
||||
terminate = true;
|
||||
}
|
||||
void StrComHandler::stopProcess() { terminate = true; }
|
||||
|
||||
void StrComHandler::setDownloadImageName(std::string filename) {
|
||||
downloadImage.filename = filename;
|
||||
@ -652,10 +650,9 @@ ReturnValue_t StrComHandler::sendMessage(CookieIF* cookie, const uint8_t* sendDa
|
||||
const uint8_t* txFrame;
|
||||
size_t frameLen;
|
||||
datalinkLayer.encodeFrame(sendData, sendLen, &txFrame, frameLen);
|
||||
size_t bytesWritten = write(serialPort, txFrame, frameLen);
|
||||
if (bytesWritten != frameLen) {
|
||||
sif::warning << "ScexUartReader::sendMessage: Sending ping command to solar experiment failed"
|
||||
<< std::endl;
|
||||
ssize_t bytesWritten = write(serialPort, txFrame, frameLen);
|
||||
if (bytesWritten != static_cast<ssize_t>(frameLen)) {
|
||||
sif::warning << "StrComHandler: Sending packet failed" << std::endl;
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
// Hacky, but the alternatives look bleak. The raw data contains the information we need
|
||||
@ -746,12 +743,12 @@ ReturnValue_t StrComHandler::handleSerialReception() {
|
||||
if (bytesRead == 0) {
|
||||
return NO_SERIAL_DATA_READ;
|
||||
} else if (bytesRead < 0) {
|
||||
sif::warning << "PlocSupvHelper::performOperation: read call failed with error [" << errno
|
||||
<< ", " << strerror(errno) << "]" << std::endl;
|
||||
sif::warning << "StrComHandler: read call failed with error [" << errno << ", "
|
||||
<< strerror(errno) << "]" << std::endl;
|
||||
return FAILED;
|
||||
} else if (bytesRead >= static_cast<int>(recBuf.size())) {
|
||||
sif::error << "PlocSupvHelper::performOperation: Receive buffer too small for " << bytesRead
|
||||
<< " bytes" << std::endl;
|
||||
sif::error << "StrComHandler: Receive buffer too small for " << bytesRead << " bytes"
|
||||
<< std::endl;
|
||||
return FAILED;
|
||||
} else if (bytesRead > 0) {
|
||||
// sif::info << "Received " << bytesRead << " bytes from the STR" << std::endl;
|
||||
|
@ -28,7 +28,6 @@ class StrComHandler : public SystemObject, public DeviceCommunicationIF, public
|
||||
public:
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::STR_HELPER;
|
||||
|
||||
static const ReturnValue_t BUSY = MAKE_RETURN_CODE(0);
|
||||
//! [EXPORT] : [COMMENT] SD card specified in path string not mounted
|
||||
static const ReturnValue_t SD_NOT_MOUNTED = MAKE_RETURN_CODE(1);
|
||||
//! [EXPORT] : [COMMENT] Specified file does not exist on filesystem
|
||||
|
Reference in New Issue
Block a user