From 808e01dfd360e7894d0aba11f985ea42cc7318ac Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sat, 9 Apr 2022 14:43:06 +0200 Subject: [PATCH] DLE FRAM packets can be read now --- fsfw | 2 +- linux/boardtest/UartTestClass.cpp | 152 ++++++++++-------- linux/boardtest/UartTestClass.h | 20 ++- linux/devices/CMakeLists.txt | 1 + linux/devices/ScexDleParser.cpp | 6 + linux/devices/ScexDleParser.h | 12 ++ linux/devices/ScexUartReader.cpp | 37 +++-- linux/devices/ScexUartReader.h | 16 +- linux/fsfwconfig/OBSWConfig.h.in | 2 + mission/devices/CMakeLists.txt | 2 + .../devices/devicedefinitions/CMakeLists.txt | 3 + .../devicedefinitions/ScexDefinitions.cpp | 5 + .../{SCEXDefinitions.h => ScexDefinitions.h} | 11 +- 13 files changed, 176 insertions(+), 93 deletions(-) create mode 100644 linux/devices/ScexDleParser.cpp create mode 100644 linux/devices/ScexDleParser.h create mode 100644 mission/devices/devicedefinitions/CMakeLists.txt create mode 100644 mission/devices/devicedefinitions/ScexDefinitions.cpp rename mission/devices/devicedefinitions/{SCEXDefinitions.h => ScexDefinitions.h} (63%) diff --git a/fsfw b/fsfw index 85a6e4b1..bdddee4f 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit 85a6e4b12977f24247ed3ca3011c6f8b611a144e +Subproject commit bdddee4f81fbdff7f207fd03b3c592522e04c5aa diff --git a/linux/boardtest/UartTestClass.cpp b/linux/boardtest/UartTestClass.cpp index a59dc4ea..0a164c8b 100644 --- a/linux/boardtest/UartTestClass.cpp +++ b/linux/boardtest/UartTestClass.cpp @@ -4,6 +4,7 @@ #include // Contains file controls like O_RDWR #include #include +#include #include #include // write(), read(), close() @@ -20,10 +21,15 @@ #endif UartTestClass::UartTestClass(object_id_t objectId, ScexUartReader* reader) - : TestTask(objectId), reader(reader) { + : TestTask(objectId), reader(reader), decodeRingBuf(4096, true) { mode = TestModes::SCEX; scexMode = ScexModes::SIMPLE; - currCmd = scex::ScexCmds::ONE_CELL; + currCmd = scex::ScexCmds::FRAM; + if (mode == TestModes::SCEX) { + dleParser = + new ScexDleParser(decodeRingBuf, dleEncoder, {encodedBuf.data(), encodedBuf.size()}, + {decodedBuf.data(), decodedBuf.size()}, &foundDlePacketHandler, this); + } } ReturnValue_t UartTestClass::initialize() { @@ -145,8 +151,7 @@ void UartTestClass::scexInit() { #else std::string devname = "/dev/ul-scex"; #endif - uartCookie = - new UartCookie(this->getObjectId(), devname, UartModes::NON_CANONICAL, 57600, 4096); + uartCookie = new UartCookie(this->getObjectId(), devname, UartBaudRate::RATE_57600, 4096); reader->setDebugMode(true); ReturnValue_t result = reader->initializeInterface(uartCookie); if (result != HasReturnvaluesIF::RETURN_OK) { @@ -171,25 +176,6 @@ void UartTestClass::scexPeriodic() { } } -int UartTestClass::prepareScexCmd(scex::ScexCmds cmd, bool tempCheck, - uint8_t* cmdBuf, size_t* len) { - using namespace scex; - // Send ping command - cmdBuf[0] = scex::createCmdByte(cmd, false); - // These two fields are the packet counter and the total packet count. Those are 1 and 1 for each - // telecommand so far - cmdBuf[1] = 1; - cmdBuf[2] = 1; - uint16_t userDataLen = 0; - 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; -} - void UartTestClass::scexSimpleInit() { #if defined(RASPBERRY_PI) std::string devname = "/dev/serial0"; @@ -216,8 +202,8 @@ void UartTestClass::scexSimpleInit() { // 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] = 0; // In units of 0.1 seconds - tty.c_cc[VMIN] = 0; // Read up to 255 bytes + tty.c_cc[VTIME] = 10; // 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. #if !defined(XIPHOS_Q7S) @@ -226,53 +212,89 @@ void UartTestClass::scexSimpleInit() { } #endif - // Flush received and unread data - tcflush(serialPort, TCIOFLUSH); 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, TCIOFLUSH); } void UartTestClass::scexSimplePeriodic() { using namespace scex; - sif::info << "UartTestClass::scexInit: Sending ping command to SCEX" << std::endl; - uint8_t tmpCmdBuf[32] = {}; - size_t len = 0; - prepareScexCmd(currCmd, false, 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; - } - 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 << "Reading SCEX: Timeout or no bytes read" << std::endl; - } else 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; + ReturnValue_t result = RETURN_OK; + if (not cmdSent) { + // Flush received and unread data + tcflush(serialPort, TCIFLUSH); + uint8_t tmpCmdBuf[32] = {}; + size_t len = 0; + sif::info << "UartTestClass::scexSimplePeriodic: Sending command to SCEX" << std::endl; + prepareScexCmd(currCmd, false, tmpCmdBuf, &len); + 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 command to solar experiment failed" << std::endl; + } + cmdSent = true; + cmdDone = false; + } + if (not cmdDone) { + // Read back reply immediately + int bytesRead = 0; + do { + bytesRead = read(serialPort, reinterpret_cast(recBuf.data()), + static_cast(recBuf.size())); + if (bytesRead == 0) { + sif::warning << "Reading SCEX: Timeout or no bytes read" << std::endl; + } else 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) { + dleParser->passData(recBuf.data(), bytesRead); + if (currCmd == ScexCmds::PING) { + cmdDone = true; + cmdSent = false; + } + } + } while (bytesRead > 0); + } +} + +int UartTestClass::prepareScexCmd(scex::ScexCmds cmd, bool tempCheck, uint8_t* cmdBuf, + size_t* len) { + using namespace scex; + // Send ping command + cmdBuf[0] = scex::createCmdByte(cmd, false); + // These two fields are the packet counter and the total packet count. Those are 1 and 1 for each + // telecommand so far + cmdBuf[1] = 1; + cmdBuf[2] = 1; + uint16_t userDataLen = 0; + 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; +} + +void UartTestClass::foundDlePacketHandler(uint8_t* packet, size_t len, void* args) { + UartTestClass* obj = reinterpret_cast(args); + obj->handleFoundDlePacket(packet, len); +} + +void UartTestClass::handleFoundDlePacket(uint8_t* packet, size_t len) { + sif::info << "Detected DLE encoded packet with decoded size " << len << std::endl; } diff --git a/linux/boardtest/UartTestClass.h b/linux/boardtest/UartTestClass.h index 3836506c..b080f8a3 100644 --- a/linux/boardtest/UartTestClass.h +++ b/linux/boardtest/UartTestClass.h @@ -1,6 +1,7 @@ #ifndef LINUX_BOARDTEST_UARTTESTCLASS_H_ #define LINUX_BOARDTEST_UARTTESTCLASS_H_ +#include #include #include #include // Contains POSIX terminal control definitions @@ -8,10 +9,11 @@ #include #include "lwgps/lwgps.h" -#include "mission/devices/devicedefinitions/SCEXDefinitions.h" +#include "mission/devices/devicedefinitions/ScexDefinitions.h" #include "test/testtasks/TestTask.h" class ScexUartReader; +class ScexDleParser; class UartTestClass : public TestTask { public: @@ -40,6 +42,11 @@ class UartTestClass : public TestTask { void scexSimplePeriodic(); void scexSimpleInit(); + static void foundDlePacketHandler(uint8_t* packet, size_t len, void* args); + void handleFoundDlePacket(uint8_t* packet, size_t len); + + bool cmdSent = false; + bool cmdDone = false; scex::ScexCmds currCmd = scex::ScexCmds::PING; TestModes mode = TestModes::GPS; DleEncoder dleEncoder = DleEncoder(); @@ -48,10 +55,15 @@ class UartTestClass : public TestTask { lwgps_t gpsData = {}; struct termios tty = {}; int serialPort = 0; - std::array cmdBuf = {}; - std::array recBuf = {}; - uint8_t recvCnt = 0; + bool startFound = false; ScexUartReader* reader = nullptr; + SimpleRingBuffer decodeRingBuf; + std::array cmdBuf = {}; + std::array recBuf = {}; + std::array encodedBuf = {}; + std::array decodedBuf = {}; + ScexDleParser* dleParser; + uint8_t recvCnt = 0; }; #endif /* LINUX_BOARDTEST_UARTTESTCLASS_H_ */ diff --git a/linux/devices/CMakeLists.txt b/linux/devices/CMakeLists.txt index b8568560..6be5da2f 100644 --- a/linux/devices/CMakeLists.txt +++ b/linux/devices/CMakeLists.txt @@ -6,6 +6,7 @@ endif() target_sources(${OBSW_NAME} PRIVATE ScexUartReader.cpp + ScexDleParser.cpp ) add_subdirectory(ploc) add_subdirectory(startracker) diff --git a/linux/devices/ScexDleParser.cpp b/linux/devices/ScexDleParser.cpp new file mode 100644 index 00000000..f2620b8e --- /dev/null +++ b/linux/devices/ScexDleParser.cpp @@ -0,0 +1,6 @@ +#include "ScexDleParser.h" + +ScexDleParser::ScexDleParser(SimpleRingBuffer &decodeRingBuf, DleEncoder &decoder, + BufPair encodedBuf, BufPair decodedBuf, FoundPacketHandler handler, + void *args) + : DleParser(decodeRingBuf, decoder, encodedBuf, decodedBuf, handler, args) {} diff --git a/linux/devices/ScexDleParser.h b/linux/devices/ScexDleParser.h new file mode 100644 index 00000000..d914cdaf --- /dev/null +++ b/linux/devices/ScexDleParser.h @@ -0,0 +1,12 @@ +#ifndef LINUX_DEVICES_SCEXDLEPARSER_H_ +#define LINUX_DEVICES_SCEXDLEPARSER_H_ + +#include + +class ScexDleParser : public DleParser { + public: + ScexDleParser(SimpleRingBuffer& decodeRingBuf, DleEncoder& decoder, BufPair encodedBuf, + BufPair decodedBuf, FoundPacketHandler handler, void* args); +}; + +#endif /* LINUX_DEVICES_SCEXDLEPARSER_H_ */ diff --git a/linux/devices/ScexUartReader.cpp b/linux/devices/ScexUartReader.cpp index a35f153f..8017e8c6 100644 --- a/linux/devices/ScexUartReader.cpp +++ b/linux/devices/ScexUartReader.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include // write(), read(), close() #include // Error integer and strerror() function @@ -14,7 +15,12 @@ #include "OBSWConfig.h" ScexUartReader::ScexUartReader(object_id_t objectId) - : SystemObject(objectId), ringBuffer(200 * 2048, true), sizesQueue(200) { + : SystemObject(objectId), + decodeRingBuf(4096, true), + ipcRingBuf(200 * 2048, true), + ipcQueue(200), + dleParser(decodeRingBuf, dleEncoder, {encodedBuf.data(), encodedBuf.size()}, + {decodedBuf.data(), decodedBuf.size()}, &foundDlePacketHandler, this) { semaphore = SemaphoreFactory::instance()->createBinarySemaphore(); semaphore->acquire(); lock = MutexFactory::instance()->createMutex(); @@ -47,10 +53,10 @@ ReturnValue_t ScexUartReader::performOperation(uint8_t operationCode) { 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); + ipcQueue.insert(bytesRead); + ReturnValue_t result = dleParser.passData(recBuf.data(), bytesRead); if (result != HasReturnvaluesIF::RETURN_OK) { - sif::warning << "ScexUartReader::performOperation: Writing into ring buffer failed" + sif::warning << "ScexUartReader::performOperation: Passing data to DLE parser failed" << std::endl; } if (debugMode) { @@ -91,10 +97,9 @@ ReturnValue_t ScexUartReader::initializeInterface(CookieIF *cookie) { // 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 + // Non-blocking mode, use polling + tty.c_cc[VTIME] = 0; // 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) @@ -157,16 +162,26 @@ ReturnValue_t ScexUartReader::finish() { return RETURN_OK; } +void ScexUartReader::foundDlePacketHandler(uint8_t *packet, size_t len, void *args) { + ScexUartReader *obj = reinterpret_cast(args); + obj->handleFoundDlePacket(packet, len); +} + +void ScexUartReader::handleFoundDlePacket(uint8_t *packet, size_t len) { + // TODO: insert data into IPC ring buffer here + sif::info << "Detected DLE encoded packet with decoded size " << len << std::endl; +} + ReturnValue_t ScexUartReader::readReceivedMessage(CookieIF *cookie, uint8_t **buffer, size_t *size) { MutexGuard mg(lock); - if (sizesQueue.empty()) { + if (ipcQueue.empty()) { *size = 0; return RETURN_OK; } - *size = sizesQueue.pop(); + *size = ipcQueue.pop(); *buffer = ipcBuffer.data(); - ReturnValue_t result = ringBuffer.readData(ipcBuffer.data(), *size, true); + ReturnValue_t result = ipcRingBuf.readData(ipcBuffer.data(), *size, true); if (result != RETURN_OK) { sif::warning << "ScexUartReader::readReceivedMessage: Reading RingBuffer failed" << std::endl; } diff --git a/linux/devices/ScexUartReader.h b/linux/devices/ScexUartReader.h index 13ff7d73..246dd8f9 100644 --- a/linux/devices/ScexUartReader.h +++ b/linux/devices/ScexUartReader.h @@ -8,6 +8,7 @@ #include #include #include +#include #include // Contains POSIX terminal control definitions class SemaphoreIF; @@ -34,13 +35,20 @@ class ScexUartReader : public SystemObject, // strg+shift+n struct termios tty = {}; bool doFinish = false; DleEncoder dleEncoder = DleEncoder(); - SimpleRingBuffer ringBuffer; - DynamicFIFO sizesQueue; + SimpleRingBuffer decodeRingBuf; + Countdown finishCoutdown = Countdown(180 * 1000); std::array cmdbuf = {}; - std::array recBuf = {}; - + std::array recBuf = {}; + std::array encodedBuf = {}; + std::array decodedBuf = {}; std::array ipcBuffer = {}; + SimpleRingBuffer ipcRingBuf; + DynamicFIFO ipcQueue; + ScexDleParser dleParser; + + static void foundDlePacketHandler(uint8_t *packet, size_t len, void *args); + void handleFoundDlePacket(uint8_t *packet, size_t len); ReturnValue_t performOperation(uint8_t operationCode = 0) override; diff --git a/linux/fsfwconfig/OBSWConfig.h.in b/linux/fsfwconfig/OBSWConfig.h.in index bbf8da64..d288a0aa 100644 --- a/linux/fsfwconfig/OBSWConfig.h.in +++ b/linux/fsfwconfig/OBSWConfig.h.in @@ -163,6 +163,8 @@ debugging. */ #ifdef RASPBERRY_PI +#define OBSW_TC_FROM_PDEC 0 + #define OBSW_ENABLE_TIMERS 1 #define OBSW_ADD_STAR_TRACKER 0 #define OBSW_ADD_PLOC_SUPERVISOR 0 diff --git a/mission/devices/CMakeLists.txt b/mission/devices/CMakeLists.txt index 2919ff1f..fc013271 100644 --- a/mission/devices/CMakeLists.txt +++ b/mission/devices/CMakeLists.txt @@ -19,3 +19,5 @@ target_sources(${LIB_EIVE_MISSION} PRIVATE PayloadPcduHandler.cpp SolarArrayDeploymentHandler.cpp ) + +add_subdirectory(devicedefinitions) diff --git a/mission/devices/devicedefinitions/CMakeLists.txt b/mission/devices/devicedefinitions/CMakeLists.txt new file mode 100644 index 00000000..3ac1d9bc --- /dev/null +++ b/mission/devices/devicedefinitions/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(${LIB_EIVE_MISSION} PRIVATE + ScexDefinitions.cpp +) diff --git a/mission/devices/devicedefinitions/ScexDefinitions.cpp b/mission/devices/devicedefinitions/ScexDefinitions.cpp new file mode 100644 index 00000000..1e39f414 --- /dev/null +++ b/mission/devices/devicedefinitions/ScexDefinitions.cpp @@ -0,0 +1,5 @@ +#include "ScexDefinitions.h" + +uint8_t scex::createCmdByte(ScexCmds cmd, bool tempCheck) { + return (IDLE_BIT_0_DEF_STATE << 7) | (IDLE_BIT_1_DEF_STATE << 6) | (cmd << 1) | tempCheck; +} diff --git a/mission/devices/devicedefinitions/SCEXDefinitions.h b/mission/devices/devicedefinitions/ScexDefinitions.h similarity index 63% rename from mission/devices/devicedefinitions/SCEXDefinitions.h rename to mission/devices/devicedefinitions/ScexDefinitions.h index f9c532ff..704500f4 100644 --- a/mission/devices/devicedefinitions/SCEXDefinitions.h +++ b/mission/devices/devicedefinitions/ScexDefinitions.h @@ -6,18 +6,13 @@ // Definitions for the Solar Cell Experiment namespace scex { -enum ScexCmds: uint8_t { - PING = 0b00111, - ONE_CELL = 0b00110 -}; +enum ScexCmds : uint8_t { PING = 0b00111, ONE_CELL = 0b00110, FRAM = 0b00001 }; static constexpr uint8_t IDLE_BIT_0_DEF_STATE = 0; static constexpr uint8_t IDLE_BIT_1_DEF_STATE = 1; -uint8_t createCmdByte(ScexCmds cmd, bool tempCheck) { - return (IDLE_BIT_0_DEF_STATE << 7) | (IDLE_BIT_1_DEF_STATE << 6) | (cmd << 1) | tempCheck; -} +uint8_t createCmdByte(ScexCmds cmd, bool tempCheck); -} +} // namespace scex #endif /* MISSION_DEVICES_DEVICEDEFINITIONS_SCEXDEFINITIONS_H_ */