diff --git a/bsp_q7s/core/ObjectFactory.cpp b/bsp_q7s/core/ObjectFactory.cpp index 27d3225a..608bf254 100644 --- a/bsp_q7s/core/ObjectFactory.cpp +++ b/bsp_q7s/core/ObjectFactory.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -596,12 +597,13 @@ void ObjectFactory::createSyrlinksComponents(PowerSwitchIF* pwrSwitcher) { syrlinks::MAX_REPLY_SIZE, UartModes::NON_CANONICAL); syrlinksUartCookie->setParityEven(); + new SyrlinksComHandler(objects::SYRLINKS_COM_HANDLER); auto* syrlinksAssy = new SyrlinksAssembly(objects::SYRLINKS_ASSY); syrlinksAssy->connectModeTreeParent(satsystem::com::SUBSYSTEM); auto syrlinksFdir = new SyrlinksFdir(objects::SYRLINKS_HANDLER); auto syrlinksHandler = - new SyrlinksHandler(objects::SYRLINKS_HANDLER, objects::UART_COM_IF, syrlinksUartCookie, - pcdu::PDU1_CH1_SYRLINKS_12V, syrlinksFdir); + new SyrlinksHandler(objects::SYRLINKS_HANDLER, objects::SYRLINKS_COM_HANDLER, + syrlinksUartCookie, pcdu::PDU1_CH1_SYRLINKS_12V, syrlinksFdir); syrlinksHandler->setPowerSwitcher(pwrSwitcher); syrlinksHandler->connectModeTreeParent(*syrlinksAssy); #if OBSW_DEBUG_SYRLINKS == 1 diff --git a/common/config/eive/eventSubsystemIds.h b/common/config/eive/eventSubsystemIds.h index bbe9569a..624cd317 100644 --- a/common/config/eive/eventSubsystemIds.h +++ b/common/config/eive/eventSubsystemIds.h @@ -39,6 +39,7 @@ enum : uint8_t { TCS_CONTROLLER = 141, COM_SUBSYSTEM = 142, PERSISTENT_TM_STORE = 143, + SYRLINKS_COM = 144, COMMON_SUBSYSTEM_ID_END }; diff --git a/common/config/eive/objects.h b/common/config/eive/objects.h index 33eb9ad1..667067bb 100644 --- a/common/config/eive/objects.h +++ b/common/config/eive/objects.h @@ -123,8 +123,7 @@ enum commonObjects : uint32_t { SUS_11_R_LOC_XBYMZB_PT_ZB = 0x44120043, SYRLINKS_HANDLER = 0x445300A3, - // might be obsolete, was not used in Q7S FM SW - // CCSDS_IP_CORE_BRIDGE = 0x73500000, + SYRLINKS_COM_HANDLER = 0x445300A4, /* 0x49 ('I') for Communication Interfaces */ ACS_BOARD_POLLING_TASK = 0x49060004, diff --git a/fsfw b/fsfw index f8a7c1d4..cf6150cc 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit f8a7c1d4ed621a3375db0da9b9e9f8d5484abbc1 +Subproject commit cf6150cc184656481eaeb2beff23cd8e92a6ada9 diff --git a/linux/devices/CMakeLists.txt b/linux/devices/CMakeLists.txt index 8b23566b..7dbda12b 100644 --- a/linux/devices/CMakeLists.txt +++ b/linux/devices/CMakeLists.txt @@ -11,7 +11,8 @@ target_sources( ScexDleParser.cpp ScexHelper.cpp RwPollingTask.cpp - AcsBoardPolling.cpp) + AcsBoardPolling.cpp + SyrlinksComHandler.cpp) add_subdirectory(ploc) diff --git a/linux/devices/SusPolling.cpp b/linux/devices/SusPolling.cpp index 9ee0051a..dac0255b 100644 --- a/linux/devices/SusPolling.cpp +++ b/linux/devices/SusPolling.cpp @@ -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; diff --git a/linux/devices/SusPolling.h b/linux/devices/SusPolling.h index 3afb1d9d..e9bcf59d 100644 --- a/linux/devices/SusPolling.h +++ b/linux/devices/SusPolling.h @@ -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; diff --git a/linux/devices/SyrlinksComHandler.cpp b/linux/devices/SyrlinksComHandler.cpp new file mode 100644 index 00000000..3d8f8175 --- /dev/null +++ b/linux/devices/SyrlinksComHandler.cpp @@ -0,0 +1,206 @@ +#include "SyrlinksComHandler.h" + +#include +#include +#include +#include +#include +#include +#include + +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(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(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(recBuf.data()), + static_cast(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(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; +} diff --git a/linux/devices/SyrlinksComHandler.h b/linux/devices/SyrlinksComHandler.h new file mode 100644 index 00000000..c86b52c9 --- /dev/null +++ b/linux/devices/SyrlinksComHandler.h @@ -0,0 +1,52 @@ +#ifndef LINUX_DEVICES_SYRLINKSCOMHANDLER_H_ +#define LINUX_DEVICES_SYRLINKSCOMHANDLER_H_ + +#include +#include +#include +#include +#include +#include + +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 recBuf{}; + SimpleRingBuffer ringBuf; + std::array 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_ */ diff --git a/linux/devices/startracker/ArcsecDatalinkLayer.cpp b/linux/devices/startracker/ArcsecDatalinkLayer.cpp index eb62cec1..77c0f49f 100644 --- a/linux/devices/startracker/ArcsecDatalinkLayer.cpp +++ b/linux/devices/startracker/ArcsecDatalinkLayer.cpp @@ -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 = diff --git a/linux/devices/startracker/StrComHandler.cpp b/linux/devices/startracker/StrComHandler.cpp index 85be7871..7a9055d8 100644 --- a/linux/devices/startracker/StrComHandler.cpp +++ b/linux/devices/startracker/StrComHandler.cpp @@ -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(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(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; diff --git a/linux/devices/startracker/StrComHandler.h b/linux/devices/startracker/StrComHandler.h index 85637c1f..b581678c 100644 --- a/linux/devices/startracker/StrComHandler.h +++ b/linux/devices/startracker/StrComHandler.h @@ -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