From 01d86a0c7b9e0e3dc8f1d63642d3860d45332662 Mon Sep 17 00:00:00 2001 From: Irini Kosmidou Date: Fri, 8 Apr 2022 19:12:21 +0200 Subject: [PATCH] huge progress --- bsp_linux_board/InitMission.cpp | 13 +- bsp_linux_board/ObjectFactory.cpp | 7 +- linux/boardtest/UartTestClass.cpp | 183 ++++++++++++-------- linux/boardtest/UartTestClass.h | 11 +- linux/devices/ScexUartReader.cpp | 176 +++++++++++++++++-- linux/devices/ScexUartReader.h | 53 +++++- linux/fsfwconfig/objects/systemObjectList.h | 1 - 7 files changed, 339 insertions(+), 105 deletions(-) diff --git a/bsp_linux_board/InitMission.cpp b/bsp_linux_board/InitMission.cpp index 7814b61d..f634e8d6 100644 --- a/bsp_linux_board/InitMission.cpp +++ b/bsp_linux_board/InitMission.cpp @@ -229,14 +229,13 @@ void initmission::createTestTasks(TaskFactory& factory, initmission::printAddObjectError("UART_TEST", objects::UART_TEST); } PeriodicTaskIF* scexReaderTask = factory.createPeriodicTask( - "SCEX_UART_READER", 20, PeriodicTaskIF::MINIMUM_STACK_SIZE, 2.0, missedDeadlineFunc); - result = scexReaderTask->addComponent(objects::SCEX_UART_READER); - if (result != HasReturnvaluesIF::RETURN_OK) { - initmission::printAddObjectError("SCEX_UART_READER", objects::SCEX_UART_READER); - } - -#endif /* RPI_ADD_GPIO_TEST == 1 */ + "SCEX_UART_READER", 20, PeriodicTaskIF::MINIMUM_STACK_SIZE, 2.0, missedDeadlineFunc); + result = scexReaderTask->addComponent(objects::SCEX_UART_READER); + if (result != HasReturnvaluesIF::RETURN_OK) { + initmission::printAddObjectError("SCEX_UART_READER", objects::SCEX_UART_READER); + } taskVec.push_back(scexReaderTask); +#endif /* RPI_ADD_GPIO_TEST == 1 */ taskVec.push_back(testTask); bool startTestPst = true; diff --git a/bsp_linux_board/ObjectFactory.cpp b/bsp_linux_board/ObjectFactory.cpp index 76d35c6b..6bfa487f 100644 --- a/bsp_linux_board/ObjectFactory.cpp +++ b/bsp_linux_board/ObjectFactory.cpp @@ -1,6 +1,7 @@ -#include #include "ObjectFactory.h" +#include + #include "OBSWConfig.h" #include "devConf.h" #include "devices/addresses.h" @@ -198,8 +199,8 @@ void ObjectFactory::createTestTasks() { #endif #if OBSW_ADD_UART_TEST_CODE == 1 - new ScexUartReader(objects::SCEX_UART_READER); - new UartTestClass(objects::UART_TEST); + auto scexReader = new ScexUartReader(objects::SCEX_UART_READER); + new UartTestClass(objects::UART_TEST, scexReader); #else new UartComIF(objects::UART_COM_IF); #endif diff --git a/linux/boardtest/UartTestClass.cpp b/linux/boardtest/UartTestClass.cpp index bfa735e9..0941e423 100644 --- a/linux/boardtest/UartTestClass.cpp +++ b/linux/boardtest/UartTestClass.cpp @@ -3,6 +3,8 @@ #include // Error integer and strerror() function #include // Contains file controls like O_RDWR #include +#include +#include #include // write(), read(), close() #include "OBSWConfig.h" @@ -18,7 +20,11 @@ #define RPI_TEST_GPS_HANDLER 0 #endif -UartTestClass::UartTestClass(object_id_t objectId) : TestTask(objectId) { mode = TestModes::SCEX; } +UartTestClass::UartTestClass(object_id_t objectId, ScexUartReader* reader) + : TestTask(objectId), reader(reader) { + mode = TestModes::SCEX; + scexMode = ScexModes::READER_TASK; +} ReturnValue_t UartTestClass::initialize() { if (mode == TestModes::GPS) { @@ -127,100 +133,129 @@ void UartTestClass::gpsPeriodic() { } void UartTestClass::scexInit() { -#if defined(RASPBERRY_PI) - std::string devname = "/dev/serial0"; -#else - std::string devname = "/dev/ul-scex"; -#endif - /* Get file descriptor */ - serialPort = open(devname.c_str(), O_RDWR); - if (serialPort < 0) { - sif::warning << "open call failed with error [" << errno << ", " << strerror(errno) - << std::endl; + if (reader == nullptr) { + sif::warning << "UartTestClass::scexInit: Reader invalid" << std::endl; return; } - // Setting up UART parameters - tty.c_cflag &= ~PARENB; // Clear parity bit - tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication - tty.c_cflag &= ~CSIZE; // Clear all the size bits - tty.c_cflag |= CS8; // 8 bits per byte - tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control - tty.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1) + if (scexMode == ScexModes::SIMPLE) { +#if defined(RASPBERRY_PI) + std::string devname = "/dev/serial0"; +#else + std::string devname = "/dev/ul-scex"; +#endif + /* Get file descriptor */ + serialPort = open(devname.c_str(), O_RDWR); + if (serialPort < 0) { + sif::warning << "open call failed with error [" << errno << ", " << strerror(errno) + << std::endl; + return; + } + // Setting up UART parameters + tty.c_cflag &= ~PARENB; // Clear parity bit + tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication + tty.c_cflag &= ~CSIZE; // Clear all the size bits + tty.c_cflag |= CS8; // 8 bits per byte + tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control + tty.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1) - // Use non-canonical mode and clear echo flag - tty.c_lflag &= ~(ICANON | ECHO); + // Use non-canonical mode and clear echo flag + tty.c_lflag &= ~(ICANON | ECHO); - // Non-blocking mode, read until either line is 0.1 second idle or maximum of 255 bytes are - // received in one go - tty.c_cc[VTIME] = 1; // In units of 0.1 seconds - tty.c_cc[VMIN] = 255; // Read up to 255 bytes + // Non-blocking mode, read until either line is 0.1 second idle or maximum of 255 bytes are + // received in one go + tty.c_cc[VTIME] = 1; // In units of 0.1 seconds + tty.c_cc[VMIN] = 255; // Read up to 255 bytes - // Q7S UART Lite has fixed baud rate. For other linux systems, set baud rate here. + // Q7S UART Lite has fixed baud rate. For other linux systems, set baud rate here. #if !defined(XIPHOS_Q7S) - if (cfsetispeed(&tty, B57600) != 0) { - sif::warning << "UartTestClass::scexInit: Setting baud rate failed" << std::endl; - } + if (cfsetispeed(&tty, B57600) != 0) { + sif::warning << "UartTestClass::scexInit: Setting baud rate failed" << std::endl; + } #endif - if (tcsetattr(serialPort, TCSANOW, &tty) != 0) { - sif::warning << "tcsetattr call failed with error [" << errno << ", " << strerror(errno) - << std::endl; + if (tcsetattr(serialPort, TCSANOW, &tty) != 0) { + sif::warning << "tcsetattr call failed with error [" << errno << ", " << strerror(errno) + << std::endl; + } + // Flush received and unread data + tcflush(serialPort, TCIFLUSH); + } else { +#if defined(RASPBERRY_PI) + std::string devname = "/dev/serial0"; +#else + std::string devname = "/dev/ul-scex"; +#endif + uartCookie = + new UartCookie(this->getObjectId(), devname, UartModes::NON_CANONICAL, 57600, 4096); + reader->setDebugMode(true); + ReturnValue_t result = reader->initializeInterface(uartCookie); } - // Flush received and unread data - tcflush(serialPort, TCIFLUSH); } void UartTestClass::scexPeriodic() { - sif::info << "UartTestClass::scexInit: Sending ping command to SCEX" << std::endl; - int result = prepareScexPing(); - if (result != 0) { + if (reader == nullptr) { return; - }; - size_t bytesWritten = write(serialPort, cmdBuf.data(), encodedLen); - if (bytesWritten != encodedLen) { - sif::warning << "Sending ping command to solar experiment failed" << std::endl; } - // Read back reply immediately - int bytesRead = 0; - do { - bytesRead = read(serialPort, reinterpret_cast(recBuf.data()), - static_cast(recBuf.size())); - if (bytesRead < 0) { - sif::warning << "UartTestClass::performPeriodicAction: read call failed with error [" << errno - << ", " << strerror(errno) << "]" << std::endl; - break; - } else if (bytesRead >= static_cast(recBuf.size())) { - sif::debug << "UartTestClass::performPeriodicAction: recv buffer might not be large enough" - << std::endl; - } else if (bytesRead > 0) { - sif::info << "Received " << bytesRead - << " bytes from the Solar Cell Experiment:" << std::endl; - arrayprinter::print(recBuf.data(), bytesRead, OutputType::HEX, false); - break; + if (scexMode == ScexModes::SIMPLE) { + sif::info << "UartTestClass::scexInit: Sending ping command to SCEX" << std::endl; + // reader->sendMessage(nullptr, nullptr, 0); + uint8_t tmpCmdBuf[32] = {}; + size_t len = 0; + prepareScexPing(tmpCmdBuf, &len); + ReturnValue_t result = + dleEncoder.encode(tmpCmdBuf, len, cmdBuf.data(), cmdBuf.size(), &encodedLen, true); + if (result != HasReturnvaluesIF::RETURN_OK) { + sif::warning << "UartTestClass::scexInit: Encoding failed" << std::endl; + return; } - } while (bytesRead > 0); + if (result != 0) { + return; + }; + size_t bytesWritten = write(serialPort, cmdBuf.data(), encodedLen); + if (bytesWritten != encodedLen) { + sif::warning << "Sending ping command to solar experiment failed" << std::endl; + } + + // Read back reply immediately + int bytesRead = 0; + do { + bytesRead = read(serialPort, reinterpret_cast(recBuf.data()), + static_cast(recBuf.size())); + if (bytesRead < 0) { + sif::warning << "UartTestClass::performPeriodicAction: read call failed with error [" + << errno << ", " << strerror(errno) << "]" << std::endl; + break; + } else if (bytesRead >= static_cast(recBuf.size())) { + sif::debug << "UartTestClass::performPeriodicAction: recv buffer might not be large enough" + << std::endl; + } else if (bytesRead > 0) { + sif::info << "Received " << bytesRead + << " bytes from the Solar Cell Experiment:" << std::endl; + arrayprinter::print(recBuf.data(), bytesRead, OutputType::HEX, false); + break; + } + } while (bytesRead > 0); + } else { + size_t len = 0; + prepareScexPing(cmdBuf.data(), &len); + reader->sendMessage(uartCookie, cmdBuf.data(), len); + } } -int UartTestClass::prepareScexPing() { - std::array tmpCmdBuf = {}; +int UartTestClass::prepareScexPing(uint8_t* cmdBuf, size_t* len) { // Send ping command - tmpCmdBuf[0] = scex::CMD_PING; + cmdBuf[0] = scex::CMD_PING; // These two fields are the packet counter and the total packet count. Those are 1 and 1 for each // telecommand so far - tmpCmdBuf[1] = 1; - tmpCmdBuf[2] = 1; + cmdBuf[1] = 1; + cmdBuf[2] = 1; uint16_t userDataLen = 0; - tmpCmdBuf[3] = (userDataLen >> 8) & 0xff; - tmpCmdBuf[4] = userDataLen & 0xff; - uint16_t crc = CRC::crc16ccitt(tmpCmdBuf.data(), 5); - tmpCmdBuf[5] = (crc >> 8) & 0xff; - tmpCmdBuf[6] = crc & 0xff; - ReturnValue_t result = - dleEncoder.encode(tmpCmdBuf.data(), 7, cmdBuf.data(), cmdBuf.size(), &encodedLen, true); - if (result != HasReturnvaluesIF::RETURN_OK) { - sif::warning << "UartTestClass::scexInit: Encoding failed" << std::endl; - return -1; - } + cmdBuf[3] = (userDataLen >> 8) & 0xff; + cmdBuf[4] = userDataLen & 0xff; + uint16_t crc = CRC::crc16ccitt(cmdBuf, 5); + cmdBuf[5] = (crc >> 8) & 0xff; + cmdBuf[6] = crc & 0xff; + *len = 7; return 0; } diff --git a/linux/boardtest/UartTestClass.h b/linux/boardtest/UartTestClass.h index 786d01ce..17fdca59 100644 --- a/linux/boardtest/UartTestClass.h +++ b/linux/boardtest/UartTestClass.h @@ -2,6 +2,7 @@ #define LINUX_BOARDTEST_UARTTESTCLASS_H_ #include +#include #include // Contains POSIX terminal control definitions #include @@ -9,9 +10,11 @@ #include "lwgps/lwgps.h" #include "test/testtasks/TestTask.h" +class ScexUartReader; + class UartTestClass : public TestTask { public: - UartTestClass(object_id_t objectId); + UartTestClass(object_id_t objectId, ScexUartReader* reader); ReturnValue_t initialize() override; ReturnValue_t performOneShotAction() override; @@ -24,14 +27,17 @@ class UartTestClass : public TestTask { SCEX }; + enum ScexModes { SIMPLE, READER_TASK } scexMode; + void gpsInit(); void gpsPeriodic(); void scexInit(); void scexPeriodic(); - int prepareScexPing(); + int prepareScexPing(uint8_t* cmdBuf, size_t* len); TestModes mode = TestModes::GPS; DleEncoder dleEncoder = DleEncoder(); + UartCookie* uartCookie = nullptr; size_t encodedLen = 0; lwgps_t gpsData = {}; struct termios tty = {}; @@ -39,6 +45,7 @@ class UartTestClass : public TestTask { std::array cmdBuf = {}; std::array recBuf = {}; uint8_t recvCnt = 0; + ScexUartReader* reader = nullptr; }; #endif /* LINUX_BOARDTEST_UARTTESTCLASS_H_ */ diff --git a/linux/devices/ScexUartReader.cpp b/linux/devices/ScexUartReader.cpp index 4aa78357..a35f153f 100644 --- a/linux/devices/ScexUartReader.cpp +++ b/linux/devices/ScexUartReader.cpp @@ -1,18 +1,174 @@ #include "ScexUartReader.h" + +#include // Contains file controls like O_RDWR +#include +#include +#include +#include +#include +#include // write(), read(), close() + +#include // Error integer and strerror() function #include +#include "OBSWConfig.h" -ScexUartReader::ScexUartReader(object_id_t objectId):SystemObject(objectId) { +ScexUartReader::ScexUartReader(object_id_t objectId) + : SystemObject(objectId), ringBuffer(200 * 2048, true), sizesQueue(200) { + semaphore = SemaphoreFactory::instance()->createBinarySemaphore(); + semaphore->acquire(); + lock = MutexFactory::instance()->createMutex(); } -void ScexUartRead::start() { - semaphore->give(); -} +// void ScexUartRead::start() { /* semaphore->give(); */ } ReturnValue_t ScexUartReader::performOperation(uint8_t operationCode) { - std::cout<<"hallo welt"<take(); - while(true) { - semaphore->take(); - } - return RETURN_OK; + lock->lockMutex(); + state = States::IDLE; + lock->unlockMutex(); + while (true) { + semaphore->acquire(); + std::cout << "task was started" << std::endl; + int bytesRead = 0; + do { + bytesRead = read(serialPort, reinterpret_cast(recBuf.data()), + static_cast(recBuf.size())); + if (bytesRead == 0) { + MutexGuard mg(lock); + States currentState = state; + if (currentState == States::FINISH) { + state = States::IDLE; + break; + } + } else if (bytesRead < 0) { + sif::warning << "ScexUartReader::performOperation: read call failed with error [" << errno + << ", " << strerror(errno) << "]" << std::endl; + break; + } else if (bytesRead >= static_cast(recBuf.size())) { + sif::error << "ScexUartReader::performOperation: Receive buffer too small" << std::endl; + } else if (bytesRead > 0) { + MutexGuard mg(lock); + sizesQueue.insert(bytesRead); + ReturnValue_t result = ringBuffer.writeData(recBuf.data(), bytesRead); + if (result != HasReturnvaluesIF::RETURN_OK) { + sif::warning << "ScexUartReader::performOperation: Writing into ring buffer failed" + << std::endl; + } + if (debugMode) { + sif::info << "Received " << bytesRead + << " bytes from the Solar Cell Experiment:" << std::endl; + arrayprinter::print(recBuf.data(), bytesRead, OutputType::HEX, false); + } + break; + } + } while (bytesRead > 0); + // task block comes here + std::cout << "done" << std::endl; + } + return RETURN_OK; +} + +ReturnValue_t ScexUartReader::initializeInterface(CookieIF *cookie) { + UartCookie *uartCookie = dynamic_cast(cookie); + if (uartCookie) { + return RETURN_FAILED; + } + std::string devname = uartCookie->getDeviceFile(); + /* Get file descriptor */ + serialPort = open(devname.c_str(), O_RDWR); + if (serialPort < 0) { + sif::warning << "open call failed with error [" << errno << ", " << strerror(errno) + << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + // Setting up UART parameters + tty.c_cflag &= ~PARENB; // Clear parity bit + tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication + tty.c_cflag &= ~CSIZE; // Clear all the size bits + tty.c_cflag |= CS8; // 8 bits per byte + tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control + tty.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1) + + // Use non-canonical mode and clear echo flag + tty.c_lflag &= ~(ICANON | ECHO); + + // Non-blocking mode, read until either line is 0.1 second idle or maximum of 255 bytes are + // received in one go + tty.c_cc[VTIME] = 20; // Read for up to 2 seconds + tty.c_cc[VMIN] = 0; // Read as much as there is available + + // Q7S UART Lite has fixed baud rate. For other linux systems, set baud rate here. +#if !defined(XIPHOS_Q7S) + if (cfsetispeed(&tty, B57600) != 0) { + sif::warning << "ScexUartReader::initializeInterface: Setting baud rate failed" << std::endl; + } +#endif + + if (tcsetattr(serialPort, TCSANOW, &tty) != 0) { + sif::warning << "tcsetattr call failed with error [" << errno << ", " << strerror(errno) + << std::endl; + } + // Flush received and unread data + tcflush(serialPort, TCIFLUSH); + return RETURN_OK; +} + +ReturnValue_t ScexUartReader::sendMessage(CookieIF *cookie, const uint8_t *sendData, + size_t sendLen) { + lock->lockMutex(); + if (state == States::NOT_READY or state == States::RUNNING) { + lock->unlockMutex(); + return HasReturnvaluesIF::RETURN_FAILED; + } + state = States::RUNNING; + lock->unlockMutex(); + size_t encodedLen = 0; + ReturnValue_t result = + dleEncoder.encode(sendData, sendLen, cmdbuf.data(), cmdbuf.size(), &encodedLen, true); + if (result != HasReturnvaluesIF::RETURN_OK) { + sif::warning << "UartTestClass::scexInit: Encoding failed" << std::endl; + return RETURN_FAILED; + } + size_t bytesWritten = write(serialPort, cmdbuf.data(), encodedLen); + if (bytesWritten != encodedLen) { + sif::warning << "Sending ping command to solar experiment failed" << std::endl; + return RETURN_FAILED; + } + result = semaphore->release(); + if (result != HasReturnvaluesIF::RETURN_OK) { + std::cout << "ScexUartReader::sendMessag: Releasing semaphore failed" << std::endl; + } + return RETURN_OK; +} + +ReturnValue_t ScexUartReader::getSendSuccess(CookieIF *cookie) { return RETURN_OK; } + +ReturnValue_t ScexUartReader::requestReceiveMessage(CookieIF *cookie, size_t requestLen) { + return RETURN_OK; +} + +void ScexUartReader::setDebugMode(bool enable) { this->debugMode = enable; } + +ReturnValue_t ScexUartReader::finish() { + MutexGuard mg(lock); + if (state == States::IDLE) { + return HasReturnvaluesIF::RETURN_FAILED; + } + state = States::FINISH; + return RETURN_OK; +} + +ReturnValue_t ScexUartReader::readReceivedMessage(CookieIF *cookie, uint8_t **buffer, + size_t *size) { + MutexGuard mg(lock); + if (sizesQueue.empty()) { + *size = 0; + return RETURN_OK; + } + *size = sizesQueue.pop(); + *buffer = ipcBuffer.data(); + ReturnValue_t result = ringBuffer.readData(ipcBuffer.data(), *size, true); + if (result != RETURN_OK) { + sif::warning << "ScexUartReader::readReceivedMessage: Reading RingBuffer failed" << std::endl; + } + return RETURN_OK; } diff --git a/linux/devices/ScexUartReader.h b/linux/devices/ScexUartReader.h index 70eafcf7..13ff7d73 100644 --- a/linux/devices/ScexUartReader.h +++ b/linux/devices/ScexUartReader.h @@ -1,18 +1,55 @@ #ifndef LINUX_DEVICES_SCEXUARTREADER_H_ #define LINUX_DEVICES_SCEXUARTREADER_H_ + +#include +#include +#include +#include #include #include +#include +#include // Contains POSIX terminal control definitions +class SemaphoreIF; +class MutexIF; -class ScexUartReader: public SystemObject, //strg+shift+n -public ExecutableObjectIF, -public HasReturnvaluesIF { -public: - ScexUartReader(object_id_t objectId); -private: - ReturnValue_t performOperation(uint8_t operationCode = 0) override; +class ScexUartReader : public SystemObject, // strg+shift+n + public ExecutableObjectIF, + public DeviceCommunicationIF { + friend class UartTestClass; + public: + enum class States { NOT_READY, IDLE, RUNNING, FINISH }; + ScexUartReader(object_id_t objectId); + + ReturnValue_t finish(); + void setDebugMode(bool enable); + + private: + SemaphoreIF *semaphore; + bool debugMode = false; + MutexIF *lock; + int serialPort = 0; + States state = States::IDLE; + struct termios tty = {}; + bool doFinish = false; + DleEncoder dleEncoder = DleEncoder(); + SimpleRingBuffer ringBuffer; + DynamicFIFO sizesQueue; + Countdown finishCoutdown = Countdown(180 * 1000); + std::array cmdbuf = {}; + std::array recBuf = {}; + + std::array ipcBuffer = {}; + + ReturnValue_t performOperation(uint8_t operationCode = 0) override; + + // DeviceCommunicationIF implementation + 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; }; - #endif /* LINUX_DEVICES_SCEXUARTREADER_H_ */ diff --git a/linux/fsfwconfig/objects/systemObjectList.h b/linux/fsfwconfig/objects/systemObjectList.h index 5fbc99d5..3d8edba2 100644 --- a/linux/fsfwconfig/objects/systemObjectList.h +++ b/linux/fsfwconfig/objects/systemObjectList.h @@ -58,7 +58,6 @@ enum sourceObjects : uint32_t { HEATER_HANDLER = 0x444100A4, RAD_SENSOR = 0x443200A5, - /* 0x54 ('T') for test handlers */ TEST_TASK = 0x54694269, LIBGPIOD_TEST = 0x54123456,