From 10f7185e8137b3674a7ee5c24dfbaf8035d2251d Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 19 Jul 2021 13:08:40 +0200 Subject: [PATCH 001/131] added includes --- inc/fsfw/tasks/Typedef.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/inc/fsfw/tasks/Typedef.h b/inc/fsfw/tasks/Typedef.h index 55f6bda2..f2f9fe65 100644 --- a/inc/fsfw/tasks/Typedef.h +++ b/inc/fsfw/tasks/Typedef.h @@ -1,5 +1,8 @@ -#ifndef FRAMEWORK_TASKS_TYPEDEF_H_ -#define FRAMEWORK_TASKS_TYPEDEF_H_ +#ifndef FSFW_TASKS_TYPEDEF_H_ +#define FSFW_TASKS_TYPEDEF_H_ + +#include +#include typedef const char* TaskName; typedef uint32_t TaskPriority; @@ -7,4 +10,4 @@ typedef size_t TaskStackSize; typedef double TaskPeriod; typedef void (*TaskDeadlineMissedFunction)(); -#endif /* FRAMEWORK_TASKS_TYPEDEF_H_ */ +#endif /* FSFW_TASKS_TYPEDEF_H_ */ From a7a4e0f219eb3f23e644f519605a79772a3c951a Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 19 Jul 2021 19:03:20 +0200 Subject: [PATCH 002/131] api consistent now --- src/fsfw/memory/HasFileSystemIF.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fsfw/memory/HasFileSystemIF.h b/src/fsfw/memory/HasFileSystemIF.h index ec941f59..c897f0db 100644 --- a/src/fsfw/memory/HasFileSystemIF.h +++ b/src/fsfw/memory/HasFileSystemIF.h @@ -81,7 +81,7 @@ public: * @param args Any other arguments which an implementation might require * @return */ - virtual ReturnValue_t deleteFile(const char* repositoryPath, + virtual ReturnValue_t removeFile(const char* repositoryPath, const char* filename, void* args = nullptr) = 0; /** From b83259592a1f0ae5af20b00d1aef813fa26cd350 Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" <–meierj@irs.uni-stuttgart.de> Date: Fri, 23 Jul 2021 18:06:36 +0200 Subject: [PATCH 003/131] uart flush function --- hal/src/fsfw/hal/linux/uart/UartComIF.cpp | 45 +++++++++++++++++++++++ hal/src/fsfw/hal/linux/uart/UartComIF.h | 15 ++++++++ 2 files changed, 60 insertions(+) diff --git a/hal/src/fsfw/hal/linux/uart/UartComIF.cpp b/hal/src/fsfw/hal/linux/uart/UartComIF.cpp index e5fc90c3..e543f60e 100644 --- a/hal/src/fsfw/hal/linux/uart/UartComIF.cpp +++ b/hal/src/fsfw/hal/linux/uart/UartComIF.cpp @@ -443,6 +443,51 @@ ReturnValue_t UartComIF::readReceivedMessage(CookieIF *cookie, return RETURN_OK; } +ReturnValue_t UartComIF::flushUartRxBuffer(CookieIF *cookie) { + std::string deviceFile; + UartDeviceMapIter uartDeviceMapIter; + UartCookie* uartCookie = dynamic_cast(cookie); + if(uartCookie == nullptr) { + sif::warning << "UartComIF::flushUartRxBuffer: Invalid uart cookie!" << std::endl; + return NULLPOINTER; + } + deviceFile = uartCookie->getDeviceFile(); + uartDeviceMapIter = uartDeviceMap.find(deviceFile); + int fd = uartDeviceMapIter->second.fileDescriptor; + tcflush(fd, TCIFLUSH); + return RETURN_OK; +} + +ReturnValue_t UartComIF::flushUartTxBuffer(CookieIF *cookie) { + std::string deviceFile; + UartDeviceMapIter uartDeviceMapIter; + UartCookie* uartCookie = dynamic_cast(cookie); + if(uartCookie == nullptr) { + sif::warning << "UartComIF::flushUartTxBuffer: Invalid uart cookie!" << std::endl; + return NULLPOINTER; + } + deviceFile = uartCookie->getDeviceFile(); + uartDeviceMapIter = uartDeviceMap.find(deviceFile); + int fd = uartDeviceMapIter->second.fileDescriptor; + tcflush(fd, TCOFLUSH); + return RETURN_OK; +} + +ReturnValue_t UartComIF::flushUartTxAndRxBuf(CookieIF *cookie) { + std::string deviceFile; + UartDeviceMapIter uartDeviceMapIter; + UartCookie* uartCookie = dynamic_cast(cookie); + if(uartCookie == nullptr) { + sif::warning << "UartComIF::flushUartTxAndRxBuf: Invalid uart cookie!" << std::endl; + return NULLPOINTER; + } + deviceFile = uartCookie->getDeviceFile(); + uartDeviceMapIter = uartDeviceMap.find(deviceFile); + int fd = uartDeviceMapIter->second.fileDescriptor; + tcflush(fd, TCIOFLUSH); + return RETURN_OK; +} + void UartComIF::setUartMode(struct termios *options, UartCookie &uartCookie) { UartModes uartMode = uartCookie.getUartMode(); if(uartMode == UartModes::NON_CANONICAL) { diff --git a/hal/src/fsfw/hal/linux/uart/UartComIF.h b/hal/src/fsfw/hal/linux/uart/UartComIF.h index e513aa86..68d2b9f5 100644 --- a/hal/src/fsfw/hal/linux/uart/UartComIF.h +++ b/hal/src/fsfw/hal/linux/uart/UartComIF.h @@ -41,6 +41,21 @@ public: ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer, size_t *size) override; + /** + * @brief This function discards all data received but not read in the UART buffer. + */ + ReturnValue_t flushUartRxBuffer(CookieIF *cookie); + + /** + * @brief This function discards all data in the transmit buffer of the UART driver. + */ + ReturnValue_t flushUartTxBuffer(CookieIF *cookie); + + /** + * @brief This function discards both data in the transmit and receive buffer of the UART. + */ + ReturnValue_t flushUartTxAndRxBuf(CookieIF *cookie); + private: using UartDeviceFile_t = std::string; From 3e422f51bd1b5f934a138f5e496675b398e27827 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sat, 24 Jul 2021 13:43:13 +0200 Subject: [PATCH 004/131] corrected version number --- src/fsfw/FSFWVersion.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/fsfw/FSFWVersion.h b/src/fsfw/FSFWVersion.h index df2d49a5..8bc439ee 100644 --- a/src/fsfw/FSFWVersion.h +++ b/src/fsfw/FSFWVersion.h @@ -1,12 +1,10 @@ -#ifndef FSFW_DEFAULTCFG_VERSION_H_ -#define FSFW_DEFAULTCFG_VERSION_H_ +#ifndef FSFW_VERSION_H_ +#define FSFW_VERSION_H_ const char* const FSFW_VERSION_NAME = "ASTP"; #define FSFW_VERSION 1 -#define FSFW_SUBVERSION 0 +#define FSFW_SUBVERSION 2 #define FSFW_REVISION 0 - - -#endif /* FSFW_DEFAULTCFG_VERSION_H_ */ +#endif /* FSFW_VERSION_H_ */ From c5420c7b538ec12f841b27f95b91d75e41b53f94 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sat, 24 Jul 2021 14:39:43 +0200 Subject: [PATCH 005/131] bumped subversion --- src/fsfw/FSFWVersion.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fsfw/FSFWVersion.h b/src/fsfw/FSFWVersion.h index 8bc439ee..7aa2500c 100644 --- a/src/fsfw/FSFWVersion.h +++ b/src/fsfw/FSFWVersion.h @@ -4,7 +4,7 @@ const char* const FSFW_VERSION_NAME = "ASTP"; #define FSFW_VERSION 1 -#define FSFW_SUBVERSION 2 +#define FSFW_SUBVERSION 3 #define FSFW_REVISION 0 #endif /* FSFW_VERSION_H_ */ From 1f6a5e635fcd6bd812e262cc65a15a8a054f7ecf Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 26 Jul 2021 11:46:58 +0200 Subject: [PATCH 006/131] naming fixes --- src/fsfw/osal/common/TcpTmTcBridge.cpp | 2 +- src/fsfw/osal/common/TcpTmTcBridge.h | 4 ++-- src/fsfw/osal/common/UdpTmTcBridge.cpp | 2 +- src/fsfw/osal/common/tcpipCommon.h | 3 ++- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/fsfw/osal/common/TcpTmTcBridge.cpp b/src/fsfw/osal/common/TcpTmTcBridge.cpp index 24f1a281..dacdcd5a 100644 --- a/src/fsfw/osal/common/TcpTmTcBridge.cpp +++ b/src/fsfw/osal/common/TcpTmTcBridge.cpp @@ -17,7 +17,7 @@ #endif -const std::string TcpTmTcBridge::DEFAULT_UDP_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; +const std::string TcpTmTcBridge::DEFAULT_TCP_SERVER_PORT = tcpip::DEFAULT_TCP_SERVER_PORT; TcpTmTcBridge::TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination, object_id_t tmStoreId, object_id_t tcStoreId): diff --git a/src/fsfw/osal/common/TcpTmTcBridge.h b/src/fsfw/osal/common/TcpTmTcBridge.h index 6cfacb9f..4cb89510 100644 --- a/src/fsfw/osal/common/TcpTmTcBridge.h +++ b/src/fsfw/osal/common/TcpTmTcBridge.h @@ -29,8 +29,8 @@ class TcpTmTcBridge: public TmTcBridge { friend class TcpTmTcServer; public: - /* The ports chosen here should not be used by any other process. */ - static const std::string DEFAULT_UDP_SERVER_PORT; + // The ports chosen here should not be used by any other process + static const std::string DEFAULT_TCP_SERVER_PORT; /** * Constructor diff --git a/src/fsfw/osal/common/UdpTmTcBridge.cpp b/src/fsfw/osal/common/UdpTmTcBridge.cpp index 7015cf4a..21ea3ba2 100644 --- a/src/fsfw/osal/common/UdpTmTcBridge.cpp +++ b/src/fsfw/osal/common/UdpTmTcBridge.cpp @@ -17,7 +17,7 @@ #define FSFW_UDP_SEND_WIRETAPPING_ENABLED 0 #endif -const std::string UdpTmTcBridge::DEFAULT_UDP_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; +const std::string UdpTmTcBridge::DEFAULT_UDP_SERVER_PORT = tcpip::DEFAULT_UDP_SERVER_PORT; UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, std::string udpServerPort, object_id_t tmStoreId, object_id_t tcStoreId): diff --git a/src/fsfw/osal/common/tcpipCommon.h b/src/fsfw/osal/common/tcpipCommon.h index ce7a90cd..4b67ab24 100644 --- a/src/fsfw/osal/common/tcpipCommon.h +++ b/src/fsfw/osal/common/tcpipCommon.h @@ -13,7 +13,8 @@ namespace tcpip { -const char* const DEFAULT_SERVER_PORT = "7301"; +const char* const DEFAULT_UDP_SERVER_PORT = "7301"; +const char* const DEFAULT_TCP_SERVER_PORT = "7303"; enum class Protocol { UDP, From 54c028f913e81077855aa1ed727bac43e7efea82 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 26 Jul 2021 13:50:45 +0200 Subject: [PATCH 007/131] naming adaptions --- src/fsfw/osal/common/TcpTmTcBridge.cpp | 2 +- src/fsfw/osal/common/TcpTmTcBridge.h | 2 +- src/fsfw/osal/common/UdpTmTcBridge.cpp | 4 ++-- src/fsfw/osal/common/UdpTmTcBridge.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/fsfw/osal/common/TcpTmTcBridge.cpp b/src/fsfw/osal/common/TcpTmTcBridge.cpp index dacdcd5a..ad5b2ea1 100644 --- a/src/fsfw/osal/common/TcpTmTcBridge.cpp +++ b/src/fsfw/osal/common/TcpTmTcBridge.cpp @@ -17,7 +17,7 @@ #endif -const std::string TcpTmTcBridge::DEFAULT_TCP_SERVER_PORT = tcpip::DEFAULT_TCP_SERVER_PORT; +const std::string TcpTmTcBridge::DEFAULT_SERVER_PORT = tcpip::DEFAULT_TCP_SERVER_PORT; TcpTmTcBridge::TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination, object_id_t tmStoreId, object_id_t tcStoreId): diff --git a/src/fsfw/osal/common/TcpTmTcBridge.h b/src/fsfw/osal/common/TcpTmTcBridge.h index 4cb89510..b965c880 100644 --- a/src/fsfw/osal/common/TcpTmTcBridge.h +++ b/src/fsfw/osal/common/TcpTmTcBridge.h @@ -30,7 +30,7 @@ class TcpTmTcBridge: friend class TcpTmTcServer; public: // The ports chosen here should not be used by any other process - static const std::string DEFAULT_TCP_SERVER_PORT; + static const std::string DEFAULT_SERVER_PORT; /** * Constructor diff --git a/src/fsfw/osal/common/UdpTmTcBridge.cpp b/src/fsfw/osal/common/UdpTmTcBridge.cpp index 21ea3ba2..06caadc1 100644 --- a/src/fsfw/osal/common/UdpTmTcBridge.cpp +++ b/src/fsfw/osal/common/UdpTmTcBridge.cpp @@ -17,13 +17,13 @@ #define FSFW_UDP_SEND_WIRETAPPING_ENABLED 0 #endif -const std::string UdpTmTcBridge::DEFAULT_UDP_SERVER_PORT = tcpip::DEFAULT_UDP_SERVER_PORT; +const std::string UdpTmTcBridge::DEFAULT_SERVER_PORT = tcpip::DEFAULT_UDP_SERVER_PORT; UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, std::string udpServerPort, object_id_t tmStoreId, object_id_t tcStoreId): TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) { if(udpServerPort == "") { - this->udpServerPort = DEFAULT_UDP_SERVER_PORT; + this->udpServerPort = DEFAULT_SERVER_PORT; } else { this->udpServerPort = udpServerPort; diff --git a/src/fsfw/osal/common/UdpTmTcBridge.h b/src/fsfw/osal/common/UdpTmTcBridge.h index 7a346de5..93c7511e 100644 --- a/src/fsfw/osal/common/UdpTmTcBridge.h +++ b/src/fsfw/osal/common/UdpTmTcBridge.h @@ -28,7 +28,7 @@ class UdpTmTcBridge: friend class UdpTcPollingTask; public: /* The ports chosen here should not be used by any other process. */ - static const std::string DEFAULT_UDP_SERVER_PORT; + static const std::string DEFAULT_SERVER_PORT; UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, std::string udpServerPort = "", object_id_t tmStoreId = objects::TM_STORE, From fc4324a2fa1d99c060fb7823c87730c97654ceaf Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Mon, 26 Jul 2021 18:35:53 +0200 Subject: [PATCH 008/131] type missmatch --- hal/src/fsfw/hal/linux/spi/SpiComIF.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/src/fsfw/hal/linux/spi/SpiComIF.cpp b/hal/src/fsfw/hal/linux/spi/SpiComIF.cpp index f3d8ab09..8510f929 100644 --- a/hal/src/fsfw/hal/linux/spi/SpiComIF.cpp +++ b/hal/src/fsfw/hal/linux/spi/SpiComIF.cpp @@ -82,7 +82,7 @@ ReturnValue_t SpiComIF::initializeInterface(CookieIF *cookie) { gpioComIF->pullHigh(gpioId); } - size_t spiSpeed = 0; + uint32_t spiSpeed = 0; spi::SpiModes spiMode = spi::SpiModes::MODE_0; SpiCookie::UncommonParameters params; From b6e243b8b36d23261eaae4321990c69eb3a5a7d7 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 2 Aug 2021 12:49:40 +0200 Subject: [PATCH 009/131] var name clarification --- src/fsfw/returnvalues/HasReturnvaluesIF.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fsfw/returnvalues/HasReturnvaluesIF.h b/src/fsfw/returnvalues/HasReturnvaluesIF.h index 4a3835b6..e9321ace 100644 --- a/src/fsfw/returnvalues/HasReturnvaluesIF.h +++ b/src/fsfw/returnvalues/HasReturnvaluesIF.h @@ -22,9 +22,9 @@ public: * @param number * @return */ - static constexpr ReturnValue_t makeReturnCode(uint8_t interfaceId, + static constexpr ReturnValue_t makeReturnCode(uint8_t classId, uint8_t number) { - return (static_cast(interfaceId) << 8) + number; + return (static_cast(classId) << 8) + number; } }; From 296c587e3de10c579847e04af3176b3acaa2d701 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 3 Aug 2021 15:29:22 +0200 Subject: [PATCH 010/131] additional nullptr check --- src/fsfw/action/ActionHelper.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/fsfw/action/ActionHelper.cpp b/src/fsfw/action/ActionHelper.cpp index 3dfe8b50..3e9d121a 100644 --- a/src/fsfw/action/ActionHelper.cpp +++ b/src/fsfw/action/ActionHelper.cpp @@ -55,7 +55,19 @@ void ActionHelper::setQueueToUse(MessageQueueIF* queue) { void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId, store_address_t dataAddress) { - const uint8_t* dataPtr = NULL; + if(ipcStore == nullptr) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "ActionHelper::prepareExecution: IPC Store not set. Call initialize first" + << std::endl; +#else + sif::printWarning("ActionHelper::prepareExecution: " + "IPC Store not set. Call initialize first\n"); +#endif +#endif /* FSFW_VERBOSE_LEVEL >= 1 */ + return; + } + const uint8_t* dataPtr = nullptr; size_t size = 0; ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size); if (result != HasReturnvaluesIF::RETURN_OK) { From 7922bf76daa9bd168e2aa5fcdd1af16dae2aeb87 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 3 Aug 2021 18:38:18 +0200 Subject: [PATCH 011/131] corrected README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 484d65c0..48d2b8e7 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![FSFW Logo](logo/FSFW_Logo_V3_bw.png) +![FSFW Logo](misc/logo/FSFW_Logo_V3_bw.png) # Flight Software Framework (FSFW) From c8472beb5f31b8f33491b5fccfecdd18bce26542 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 5 Aug 2021 15:42:47 +0200 Subject: [PATCH 012/131] added new command executor --- src/fsfw/osal/linux/CMakeLists.txt | 1 + src/fsfw/osal/linux/CommandExecutor.cpp | 180 ++++++++++++++++++++++++ src/fsfw/osal/linux/CommandExecutor.h | 133 +++++++++++++++++ src/fsfw/returnvalues/FwClassIds.h | 1 + 4 files changed, 315 insertions(+) create mode 100644 src/fsfw/osal/linux/CommandExecutor.cpp create mode 100644 src/fsfw/osal/linux/CommandExecutor.h diff --git a/src/fsfw/osal/linux/CMakeLists.txt b/src/fsfw/osal/linux/CMakeLists.txt index 0fb66b3e..fa2e8aa0 100644 --- a/src/fsfw/osal/linux/CMakeLists.txt +++ b/src/fsfw/osal/linux/CMakeLists.txt @@ -16,6 +16,7 @@ target_sources(${LIB_FSFW_NAME} Timer.cpp tcpipHelpers.cpp unixUtility.cpp + CommandExecutor.cpp ) find_package(Threads REQUIRED) diff --git a/src/fsfw/osal/linux/CommandExecutor.cpp b/src/fsfw/osal/linux/CommandExecutor.cpp new file mode 100644 index 00000000..bd23f97d --- /dev/null +++ b/src/fsfw/osal/linux/CommandExecutor.cpp @@ -0,0 +1,180 @@ +#include "CommandExecutor.h" + +#include "fsfw/serviceinterface.h" +#include "fsfw/container/SimpleRingBuffer.h" +#include "fsfw/container/DynamicFIFO.h" + +#include + +#include + +CommandExecutor::CommandExecutor(const size_t maxSize): +readVec(maxSize) { + waiter.events = POLLIN; +} + +ReturnValue_t CommandExecutor::load(std::string command, bool blocking, bool printOutput) { + if(state == States::PENDING) { + return COMMAND_PENDING; + } + + currentCmd = command; + this->blocking = blocking; + this->printOutput = printOutput; + if(state == States::IDLE) { + state = States::COMMAND_LOADED; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t CommandExecutor::execute() { + if(state == States::IDLE) { + return NO_COMMAND_LOADED_OR_PENDING; + } + else if(state == States::PENDING) { + return COMMAND_PENDING; + } + currentCmdFile = popen(currentCmd.c_str(), "r"); + if(currentCmdFile == nullptr) { + lastError = errno; + return HasReturnvaluesIF::RETURN_FAILED; + } + if(blocking) { + return executeBlocking(); + } + else { + currentFd = fileno(currentCmdFile); + waiter.fd = currentFd; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t CommandExecutor::close() { + if(state == States::PENDING) { + // Attempt to close process, irrespective of if it is running or not + if(currentCmdFile != nullptr) { + pclose(currentCmdFile); + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +void CommandExecutor::printLastError(std::string funcName) const { + if(lastError != 0) { + sif::error << funcName << " pclose failed with code " << + lastError << ": " << strerror(lastError) << std::endl; + } +} + +void CommandExecutor::setRingBuffer(SimpleRingBuffer *ringBuffer, + DynamicFIFO* sizesFifo) { + this->ringBuffer = ringBuffer; + this->sizesFifo = sizesFifo; +} + +ReturnValue_t CommandExecutor::check(bool& bytesRead) { + if(blocking) { + return HasReturnvaluesIF::RETURN_OK; + } + switch(state) { + case(States::IDLE): + case(States::COMMAND_LOADED): { + return NO_COMMAND_LOADED_OR_PENDING; + } + case(States::PENDING): { + break; + } + } + + int result = poll(&waiter, 1, 0); + switch(result) { + case(0): { + return HasReturnvaluesIF::RETURN_OK; + break; + } + case(1): { + if (waiter.revents & POLLIN) { + ssize_t readBytes = read(currentFd, readVec.data(), readVec.size()); + if(readBytes == 0) { + // Should not happen + sif::warning << "CommandExecutor::check: " + "No bytes read after poll event.." << std::endl; + break; + } + else if(readBytes > 0) { + bytesRead = true; + if(printOutput) { + // It is assumed the command output is line terminated + sif::info << currentCmd << " | " << readVec.data(); + } + if(ringBuffer != nullptr) { + ringBuffer->writeData(reinterpret_cast( + readVec.data()), readBytes); + } + if(sizesFifo != nullptr) { + if(not sizesFifo->full()) { + sizesFifo->insert(readBytes); + } + } + return BYTES_READ; + } + else { + // Should also not happen + sif::warning << "CommandExecutor::check: Error " << errno << ": " << + strerror(errno) << std::endl; + } + } + else if(waiter.revents & POLLERR) { + sif::warning << "CommandExecuter::check: Poll error" << std::endl; + return COMMAND_ERROR; + } + else if(waiter.revents & POLLHUP) { + int result = pclose(currentCmdFile); + if(result != 0) { + lastError = result; + return HasReturnvaluesIF::RETURN_FAILED; + } + state = States::IDLE; + currentCmdFile = nullptr; + currentFd = 0; + return EXECUTION_FINISHED; + } + break; + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +void CommandExecutor::reset() { + CommandExecutor::close(); + currentCmdFile = nullptr; + currentFd = 0; + state = States::IDLE; +} + +int CommandExecutor::getLastError() const { + return this->lastError; +} + +ReturnValue_t CommandExecutor::executeBlocking() { + while(fgets(readVec.data(), readVec.size(), currentCmdFile) != nullptr) { + std::string output(readVec.data()); + if(printOutput) { + sif::info << currentCmd << " | " << output; + } + if(ringBuffer != nullptr) { + ringBuffer->writeData(reinterpret_cast(output.data()), output.size()); + } + if(sizesFifo != nullptr) { + if(not sizesFifo->full()) { + sizesFifo->insert(output.size()); + } + } + } + int result = pclose(currentCmdFile); + if(result != 0) { + lastError = result; + return HasReturnvaluesIF::RETURN_FAILED; + } + return EXECUTION_FINISHED; +} diff --git a/src/fsfw/osal/linux/CommandExecutor.h b/src/fsfw/osal/linux/CommandExecutor.h new file mode 100644 index 00000000..2810b67d --- /dev/null +++ b/src/fsfw/osal/linux/CommandExecutor.h @@ -0,0 +1,133 @@ +#ifndef FSFW_SRC_FSFW_OSAL_LINUX_COMMANDEXECUTOR_H_ +#define FSFW_SRC_FSFW_OSAL_LINUX_COMMANDEXECUTOR_H_ + +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/returnvalues/FwClassIds.h" + +#include + +#include +#include + +class SimpleRingBuffer; +template class DynamicFIFO; + +/** + * @brief Helper class to execute shell commands in blocking and non-blocking mode + * @details + * This class is able to execute processes by using the Linux popen call. It also has the + * capability of writing the read output of a process into a provided ring buffer. + * + * The executor works by first loading the command which should be executed and specifying + * whether it should be executed blocking or non-blocking. After that, execution can be started + * with the execute command. In blocking mode, the execute command will block until the command + * has finished + */ +class CommandExecutor { +public: + enum class States { + IDLE, + COMMAND_LOADED, + PENDING + }; + + static constexpr uint8_t CLASS_ID = CLASS_ID::LINUX_OSAL; + + //! [EXPORT] : [COMMENT] Execution of the current command has finished + static constexpr ReturnValue_t EXECUTION_FINISHED = + HasReturnvaluesIF::makeReturnCode(CLASS_ID, 0); + + //! [EXPORT] : [COMMENT] Command is pending. This will also be returned if the user tries + //! to load another command but a command is still pending + static constexpr ReturnValue_t COMMAND_PENDING = + HasReturnvaluesIF::makeReturnCode(CLASS_ID, 1); + //! [EXPORT] : [COMMENT] Some bytes have been read from the executing process + static constexpr ReturnValue_t BYTES_READ = + HasReturnvaluesIF::makeReturnCode(CLASS_ID, 2); + //! [EXPORT] : [COMMENT] Command execution failed + static constexpr ReturnValue_t COMMAND_ERROR = + HasReturnvaluesIF::makeReturnCode(CLASS_ID, 3); + //! [EXPORT] : [COMMENT] + static constexpr ReturnValue_t NO_COMMAND_LOADED_OR_PENDING = + HasReturnvaluesIF::makeReturnCode(CLASS_ID, 4); + static constexpr ReturnValue_t PCLOSE_CALL_ERROR = + HasReturnvaluesIF::makeReturnCode(CLASS_ID, 6); + + /** + * Constructor. Is initialized with maximum size of internal buffer to read data from the + * executed process. + * @param maxSize + */ + CommandExecutor(const size_t maxSize); + + /** + * Load a new command which should be executed + * @param command + * @param blocking + * @param printOutput + * @return + */ + ReturnValue_t load(std::string command, bool blocking, bool printOutput = true); + /** + * Execute the loaded command. + * @return + * - In blocking mode, it will return RETURN_FAILED if + * the result of the system call was not 0. The error value can be accessed using + * getLastError + * - In non-blocking mode, this call will start + * the execution and then return RETURN_OK + */ + ReturnValue_t execute(); + /** + * Only used in non-blocking mode. Checks the currently running command. + * @param bytesRead Will be set to the number of bytes read, if bytes have been read + * @return + * - BYTES_READ if bytes have been read from the executing process. It is recommended to call + * check again after this + * - RETURN_OK execution is pending, but no bytes have been read from the executing process + * - RETURN_FAILED if execution has failed, error value can be accessed using getLastError + * - EXECUTION_FINISHED if the process was executed successfully + * - COMMAND_ERROR internal poll error + */ + ReturnValue_t check(bool& bytesRead); + /** + * Abort the current command. Should normally not be necessary, check can be used to find + * out whether command execution was successful + * @return RETURN_OK + */ + ReturnValue_t close(); + + int getLastError() const; + void printLastError(std::string funcName) const; + + /** + * Assign a ring buffer and a FIFO which will be filled by the executor with the output + * read from the started process + * @param ringBuffer + * @param sizesFifo + */ + void setRingBuffer(SimpleRingBuffer* ringBuffer, DynamicFIFO* sizesFifo); + + /** + * Reset the executor. This calls close internally and then reset the state machine so new + * commands can be loaded and executed + */ + void reset(); +private: + std::string currentCmd; + bool blocking = true; + FILE* currentCmdFile = nullptr; + int currentFd = 0; + bool printOutput = true; + std::vector readVec; + struct pollfd waiter {}; + SimpleRingBuffer* ringBuffer = nullptr; + DynamicFIFO* sizesFifo = nullptr; + + States state = States::IDLE; + int lastError = 0; + + ReturnValue_t executeBlocking(); +}; + +#endif /* FSFW_SRC_FSFW_OSAL_LINUX_COMMANDEXECUTOR_H_ */ diff --git a/src/fsfw/returnvalues/FwClassIds.h b/src/fsfw/returnvalues/FwClassIds.h index af32f9a7..7f355c40 100644 --- a/src/fsfw/returnvalues/FwClassIds.h +++ b/src/fsfw/returnvalues/FwClassIds.h @@ -72,6 +72,7 @@ enum: uint8_t { PUS_SERVICE_3, //PUS3 PUS_SERVICE_9, //PUS9 FILE_SYSTEM, //FILS + LINUX_OSAL, //UXOS HAL_SPI, //HSPI HAL_UART, //HURT HAL_I2C, //HI2C From 4202205182aa007b9be5279ce40056e18f0b8782 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 5 Aug 2021 16:02:17 +0200 Subject: [PATCH 013/131] getter function for current state --- src/fsfw/osal/linux/CommandExecutor.cpp | 4 ++++ src/fsfw/osal/linux/CommandExecutor.h | 1 + 2 files changed, 5 insertions(+) diff --git a/src/fsfw/osal/linux/CommandExecutor.cpp b/src/fsfw/osal/linux/CommandExecutor.cpp index bd23f97d..3ec9b982 100644 --- a/src/fsfw/osal/linux/CommandExecutor.cpp +++ b/src/fsfw/osal/linux/CommandExecutor.cpp @@ -156,6 +156,10 @@ int CommandExecutor::getLastError() const { return this->lastError; } +CommandExecutor::States CommandExecutor::getCurrentState() const { + return state; +} + ReturnValue_t CommandExecutor::executeBlocking() { while(fgets(readVec.data(), readVec.size(), currentCmdFile) != nullptr) { std::string output(readVec.data()); diff --git a/src/fsfw/osal/linux/CommandExecutor.h b/src/fsfw/osal/linux/CommandExecutor.h index 2810b67d..21876c6f 100644 --- a/src/fsfw/osal/linux/CommandExecutor.h +++ b/src/fsfw/osal/linux/CommandExecutor.h @@ -97,6 +97,7 @@ public: */ ReturnValue_t close(); + States getCurrentState() const; int getLastError() const; void printLastError(std::string funcName) const; From b2c102b2c1300cfcc35e0eba7898b6bc4e4e3cd7 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 5 Aug 2021 16:13:22 +0200 Subject: [PATCH 014/131] Service Interface and Bugfix 1. Service Interface looks better now 2. Bugfix in CommandExecutor blocking mode --- src/fsfw/osal/linux/CommandExecutor.cpp | 2 +- src/fsfw/serviceinterface/ServiceInterfaceBuffer.cpp | 4 ++-- src/fsfw/serviceinterface/ServiceInterfacePrinter.cpp | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/fsfw/osal/linux/CommandExecutor.cpp b/src/fsfw/osal/linux/CommandExecutor.cpp index 3ec9b982..cd05a553 100644 --- a/src/fsfw/osal/linux/CommandExecutor.cpp +++ b/src/fsfw/osal/linux/CommandExecutor.cpp @@ -180,5 +180,5 @@ ReturnValue_t CommandExecutor::executeBlocking() { lastError = result; return HasReturnvaluesIF::RETURN_FAILED; } - return EXECUTION_FINISHED; + return HasReturnvaluesIF::RETURN_OK; } diff --git a/src/fsfw/serviceinterface/ServiceInterfaceBuffer.cpp b/src/fsfw/serviceinterface/ServiceInterfaceBuffer.cpp index 25828fe3..0411e674 100644 --- a/src/fsfw/serviceinterface/ServiceInterfaceBuffer.cpp +++ b/src/fsfw/serviceinterface/ServiceInterfaceBuffer.cpp @@ -146,8 +146,8 @@ std::string* ServiceInterfaceBuffer::getPreamble(size_t * preambleSize) { #endif int32_t charCount = sprintf(parsePosition, - "%s: | %02" SCNu32 ":%02" SCNu32 ":%02" SCNu32 ".%03" SCNu32 " | ", - this->logMessage.c_str(), loggerTime.hour, + "%s%s | %02" SCNu32 ":%02" SCNu32 ":%02" SCNu32 ".%03" SCNu32 " | ", + this->logMessage.c_str(), sif::ANSI_COLOR_RESET, loggerTime.hour, loggerTime.minute, loggerTime.second, loggerTime.usecond /1000); diff --git a/src/fsfw/serviceinterface/ServiceInterfacePrinter.cpp b/src/fsfw/serviceinterface/ServiceInterfacePrinter.cpp index 9b62e91d..422b47fc 100644 --- a/src/fsfw/serviceinterface/ServiceInterfacePrinter.cpp +++ b/src/fsfw/serviceinterface/ServiceInterfacePrinter.cpp @@ -69,6 +69,10 @@ void fsfwPrint(sif::PrintLevel printType, const char* fmt, va_list arg) { len += sprintf(bufferPosition + len, "ERROR: "); } +#if FSFW_COLORED_OUTPUT == 1 + len += sprintf(bufferPosition, sif::ANSI_COLOR_RESET); +#endif + Clock::TimeOfDay_t now; Clock::getDateAndTime(&now); /* From 6073abb12db23decbc9d69f4b6342f4f6f1247bd Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 5 Aug 2021 18:13:01 +0200 Subject: [PATCH 015/131] added some utility to timer module --- src/fsfw/osal/linux/Timer.cpp | 12 ++++++++++++ src/fsfw/osal/linux/Timer.h | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/src/fsfw/osal/linux/Timer.cpp b/src/fsfw/osal/linux/Timer.cpp index dca3112d..899ca4a5 100644 --- a/src/fsfw/osal/linux/Timer.cpp +++ b/src/fsfw/osal/linux/Timer.cpp @@ -27,6 +27,7 @@ int Timer::setTimer(uint32_t intervalMs) { timer.it_value.tv_nsec = (intervalMs * 1000000) % (1000000000); timer.it_interval.tv_sec = 0; timer.it_interval.tv_nsec = 0; + set = true; return timer_settime(timerId, 0, &timer, NULL); } @@ -43,3 +44,14 @@ int Timer::getTimer(uint32_t* remainingTimeMs){ return status; } + +bool Timer::isSet() const { + return this->set; +} + +void Timer::resetTimer() { + if(not this->set) { + set = false; + } + setTimer(0); +} diff --git a/src/fsfw/osal/linux/Timer.h b/src/fsfw/osal/linux/Timer.h index f94bca59..6d8c1b9e 100644 --- a/src/fsfw/osal/linux/Timer.h +++ b/src/fsfw/osal/linux/Timer.h @@ -38,7 +38,11 @@ public: */ int getTimer(uint32_t* remainingTimeMs); + bool isSet() const; + void resetTimer(); + private: + bool set = true; timer_t timerId; }; From 3704d2b8295152652a4c7836b595223d8fa3767d Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 5 Aug 2021 18:24:56 +0200 Subject: [PATCH 016/131] bugfix --- src/fsfw/osal/linux/CommandExecutor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/fsfw/osal/linux/CommandExecutor.cpp b/src/fsfw/osal/linux/CommandExecutor.cpp index cd05a553..5d131472 100644 --- a/src/fsfw/osal/linux/CommandExecutor.cpp +++ b/src/fsfw/osal/linux/CommandExecutor.cpp @@ -46,6 +46,7 @@ ReturnValue_t CommandExecutor::execute() { currentFd = fileno(currentCmdFile); waiter.fd = currentFd; } + state = States::PENDING; return HasReturnvaluesIF::RETURN_OK; } From 8d3fceea8f08c4f8f3aadc34e0d3aa3f5a7f75f6 Mon Sep 17 00:00:00 2001 From: "Jakob.Meier" <–meierj@irs.uni-stuttgart.de> Date: Sun, 8 Aug 2021 15:26:18 +0200 Subject: [PATCH 017/131] set sequence flags in space packet base --- src/fsfw/action/ActionHelper.cpp | 11 +++++++++++ src/fsfw/tmtcpacket/SpacePacketBase.cpp | 5 +++++ src/fsfw/tmtcpacket/SpacePacketBase.h | 7 +++++++ 3 files changed, 23 insertions(+) diff --git a/src/fsfw/action/ActionHelper.cpp b/src/fsfw/action/ActionHelper.cpp index 3e9d121a..85c39f05 100644 --- a/src/fsfw/action/ActionHelper.cpp +++ b/src/fsfw/action/ActionHelper.cpp @@ -32,6 +32,17 @@ ReturnValue_t ActionHelper::initialize(MessageQueueIF* queueToUse_) { setQueueToUse(queueToUse_); } + if(queueToUse == nullptr) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "ActionHelper::initialize: No queue set" << std::endl; +#else + sif::printWarning("ActionHelper::initialize: No queue set\n"); +#endif +#endif /* FSFW_VERBOSE_LEVEL >= 1 */ + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; } diff --git a/src/fsfw/tmtcpacket/SpacePacketBase.cpp b/src/fsfw/tmtcpacket/SpacePacketBase.cpp index e9a0b836..5dae94c9 100644 --- a/src/fsfw/tmtcpacket/SpacePacketBase.cpp +++ b/src/fsfw/tmtcpacket/SpacePacketBase.cpp @@ -54,6 +54,11 @@ void SpacePacketBase::setAPID( uint16_t new_apid ) { this->data->header.packet_id_l = ( new_apid & 0x00FF ); } +void SpacePacketBase::setSequenceFlags( uint8_t sequenceflags ) { + this->data->header.sequence_control_h &= 0x3F; + this->data->header.sequence_control_h |= sequenceflags << 6; +} + uint16_t SpacePacketBase::getPacketSequenceControl( void ) { return ( (this->data->header.sequence_control_h) << 8 ) + this->data->header.sequence_control_l; diff --git a/src/fsfw/tmtcpacket/SpacePacketBase.h b/src/fsfw/tmtcpacket/SpacePacketBase.h index 13cb3130..3cd3e552 100644 --- a/src/fsfw/tmtcpacket/SpacePacketBase.h +++ b/src/fsfw/tmtcpacket/SpacePacketBase.h @@ -109,6 +109,13 @@ public: * ignored. */ void setAPID( uint16_t setAPID ); + + /** + * Sets the sequence flags of a packet, which are bit 17 and 18 in the space packet header. + * @param The sequence flags to set + */ + void setSequenceFlags( uint8_t sequenceflags ); + /** * Returns the CCSDS packet sequence control field, which are the third and * the fourth byte of the CCSDS primary header. From ba5e2ad8bb97faf22702fa9aaaf47931db7ca6bb Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 9 Aug 2021 16:57:24 +0200 Subject: [PATCH 018/131] Cleaning up TCP and UDP code Same port number used as before, but some inconsistencies fixed --- src/fsfw/osal/common/TcpTmTcBridge.cpp | 2 +- src/fsfw/osal/common/TcpTmTcBridge.h | 2 +- src/fsfw/osal/common/TcpTmTcServer.cpp | 4 ++-- src/fsfw/osal/common/TcpTmTcServer.h | 3 +-- src/fsfw/osal/common/UdpTmTcBridge.cpp | 4 ++-- src/fsfw/osal/common/UdpTmTcBridge.h | 2 +- 6 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/fsfw/osal/common/TcpTmTcBridge.cpp b/src/fsfw/osal/common/TcpTmTcBridge.cpp index 24f1a281..f873d5c7 100644 --- a/src/fsfw/osal/common/TcpTmTcBridge.cpp +++ b/src/fsfw/osal/common/TcpTmTcBridge.cpp @@ -17,7 +17,7 @@ #endif -const std::string TcpTmTcBridge::DEFAULT_UDP_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; +const std::string TcpTmTcBridge::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; TcpTmTcBridge::TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination, object_id_t tmStoreId, object_id_t tcStoreId): diff --git a/src/fsfw/osal/common/TcpTmTcBridge.h b/src/fsfw/osal/common/TcpTmTcBridge.h index 6cfacb9f..be0d0d52 100644 --- a/src/fsfw/osal/common/TcpTmTcBridge.h +++ b/src/fsfw/osal/common/TcpTmTcBridge.h @@ -30,7 +30,7 @@ class TcpTmTcBridge: friend class TcpTmTcServer; public: /* The ports chosen here should not be used by any other process. */ - static const std::string DEFAULT_UDP_SERVER_PORT; + static const std::string DEFAULT_SERVER_PORT; /** * Constructor diff --git a/src/fsfw/osal/common/TcpTmTcServer.cpp b/src/fsfw/osal/common/TcpTmTcServer.cpp index f94449bb..057cd538 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.cpp +++ b/src/fsfw/osal/common/TcpTmTcServer.cpp @@ -22,14 +22,14 @@ #define FSFW_TCP_RECV_WIRETAPPING_ENABLED 0 #endif -const std::string TcpTmTcServer::DEFAULT_TCP_SERVER_PORT = "7303"; +const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = TcpTmTcBridge::DEFAULT_SERVER_PORT; TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, size_t receptionBufferSize, std::string customTcpServerPort): SystemObject(objectId), tmtcBridgeId(tmtcTcpBridge), tcpPort(customTcpServerPort), receptionBuffer(receptionBufferSize) { if(tcpPort == "") { - tcpPort = DEFAULT_TCP_SERVER_PORT; + tcpPort = DEFAULT_SERVER_PORT; } } diff --git a/src/fsfw/osal/common/TcpTmTcServer.h b/src/fsfw/osal/common/TcpTmTcServer.h index f7c36d69..6588f111 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.h +++ b/src/fsfw/osal/common/TcpTmTcServer.h @@ -41,8 +41,7 @@ class TcpTmTcServer: public TcpIpBase, public ExecutableObjectIF { public: - /* The ports chosen here should not be used by any other process. */ - static const std::string DEFAULT_TCP_SERVER_PORT; + static const std::string DEFAULT_SERVER_PORT; static constexpr size_t ETHERNET_MTU_SIZE = 1500; diff --git a/src/fsfw/osal/common/UdpTmTcBridge.cpp b/src/fsfw/osal/common/UdpTmTcBridge.cpp index 7015cf4a..db2546cd 100644 --- a/src/fsfw/osal/common/UdpTmTcBridge.cpp +++ b/src/fsfw/osal/common/UdpTmTcBridge.cpp @@ -17,13 +17,13 @@ #define FSFW_UDP_SEND_WIRETAPPING_ENABLED 0 #endif -const std::string UdpTmTcBridge::DEFAULT_UDP_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; +const std::string UdpTmTcBridge::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, std::string udpServerPort, object_id_t tmStoreId, object_id_t tcStoreId): TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) { if(udpServerPort == "") { - this->udpServerPort = DEFAULT_UDP_SERVER_PORT; + this->udpServerPort = DEFAULT_SERVER_PORT; } else { this->udpServerPort = udpServerPort; diff --git a/src/fsfw/osal/common/UdpTmTcBridge.h b/src/fsfw/osal/common/UdpTmTcBridge.h index 7a346de5..93c7511e 100644 --- a/src/fsfw/osal/common/UdpTmTcBridge.h +++ b/src/fsfw/osal/common/UdpTmTcBridge.h @@ -28,7 +28,7 @@ class UdpTmTcBridge: friend class UdpTcPollingTask; public: /* The ports chosen here should not be used by any other process. */ - static const std::string DEFAULT_UDP_SERVER_PORT; + static const std::string DEFAULT_SERVER_PORT; UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, std::string udpServerPort = "", object_id_t tmStoreId = objects::TM_STORE, From fb36dc45019c0b57e79a7ac8af8d154cb3d6817b Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 9 Aug 2021 18:12:25 +0200 Subject: [PATCH 019/131] More improvements for TCP/UDP port definition --- src/fsfw/osal/common/TcpTmTcBridge.cpp | 3 --- src/fsfw/osal/common/TcpTmTcBridge.h | 4 +--- src/fsfw/osal/common/TcpTmTcServer.cpp | 6 +++++- src/fsfw/osal/common/TcpTmTcServer.h | 19 +++++++++++-------- src/fsfw/osal/common/UdpTmTcBridge.h | 4 ++-- src/fsfw/osal/common/tcpipCommon.h | 4 ++-- 6 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/fsfw/osal/common/TcpTmTcBridge.cpp b/src/fsfw/osal/common/TcpTmTcBridge.cpp index f873d5c7..3cd03c36 100644 --- a/src/fsfw/osal/common/TcpTmTcBridge.cpp +++ b/src/fsfw/osal/common/TcpTmTcBridge.cpp @@ -1,6 +1,5 @@ #include "fsfw/platform.h" #include "fsfw/osal/common/TcpTmTcBridge.h" -#include "fsfw/osal/common/tcpipHelpers.h" #include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/ipc/MutexGuard.h" @@ -17,8 +16,6 @@ #endif -const std::string TcpTmTcBridge::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; - TcpTmTcBridge::TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination, object_id_t tmStoreId, object_id_t tcStoreId): TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) { diff --git a/src/fsfw/osal/common/TcpTmTcBridge.h b/src/fsfw/osal/common/TcpTmTcBridge.h index be0d0d52..dc46f1f0 100644 --- a/src/fsfw/osal/common/TcpTmTcBridge.h +++ b/src/fsfw/osal/common/TcpTmTcBridge.h @@ -2,7 +2,7 @@ #define FSFW_OSAL_COMMON_TCPTMTCBRIDGE_H_ #include "TcpIpBase.h" -#include "../../tmtcservices/TmTcBridge.h" +#include "fsfw/tmtcservices/TmTcBridge.h" #ifdef _WIN32 @@ -29,8 +29,6 @@ class TcpTmTcBridge: public TmTcBridge { friend class TcpTmTcServer; public: - /* The ports chosen here should not be used by any other process. */ - static const std::string DEFAULT_SERVER_PORT; /** * Constructor diff --git a/src/fsfw/osal/common/TcpTmTcServer.cpp b/src/fsfw/osal/common/TcpTmTcServer.cpp index 057cd538..11ab71af 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.cpp +++ b/src/fsfw/osal/common/TcpTmTcServer.cpp @@ -22,7 +22,7 @@ #define FSFW_TCP_RECV_WIRETAPPING_ENABLED 0 #endif -const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = TcpTmTcBridge::DEFAULT_SERVER_PORT; +const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, size_t receptionBufferSize, std::string customTcpServerPort): @@ -200,6 +200,10 @@ void TcpTmTcServer::setTcpBacklog(uint8_t tcpBacklog) { this->tcpBacklog = tcpBacklog; } +std::string TcpTmTcServer::getTcpPort() const { + return tcpPort; +} + ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket) { // Access to the FIFO is mutex protected because it is filled by the bridge MutexGuard(tmtcBridge->mutex, tmtcBridge->timeoutType, tmtcBridge->mutexTimeoutMs); diff --git a/src/fsfw/osal/common/TcpTmTcServer.h b/src/fsfw/osal/common/TcpTmTcServer.h index 6588f111..c6916080 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.h +++ b/src/fsfw/osal/common/TcpTmTcServer.h @@ -3,13 +3,14 @@ #include "TcpIpBase.h" -#include "../../platform.h" -#include "../../ipc/messageQueueDefinitions.h" -#include "../../ipc/MessageQueueIF.h" -#include "../../objectmanager/frameworkObjects.h" -#include "../../objectmanager/SystemObject.h" -#include "../../storagemanager/StorageManagerIF.h" -#include "../../tasks/ExecutableObjectIF.h" +#include "fsfw/platform.h" +#include "fsfw/osal/common/tcpipHelpers.h" +#include "fsfw/ipc/messageQueueDefinitions.h" +#include "fsfw/ipc/MessageQueueIF.h" +#include "fsfw/objectmanager/frameworkObjects.h" +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/storagemanager/StorageManagerIF.h" +#include "fsfw/tasks/ExecutableObjectIF.h" #ifdef PLATFORM_UNIX #include @@ -43,7 +44,7 @@ class TcpTmTcServer: public: static const std::string DEFAULT_SERVER_PORT; - static constexpr size_t ETHERNET_MTU_SIZE = 1500; + static constexpr size_t ETHERNET_MTU_SIZE = 1500; /** * TCP Server Constructor @@ -64,6 +65,8 @@ public: ReturnValue_t performOperation(uint8_t opCode) override; ReturnValue_t initializeAfterTaskCreation() override; + std::string getTcpPort() const; + protected: StorageManagerIF* tcStore = nullptr; StorageManagerIF* tmStore = nullptr; diff --git a/src/fsfw/osal/common/UdpTmTcBridge.h b/src/fsfw/osal/common/UdpTmTcBridge.h index 93c7511e..dc695c81 100644 --- a/src/fsfw/osal/common/UdpTmTcBridge.h +++ b/src/fsfw/osal/common/UdpTmTcBridge.h @@ -2,8 +2,8 @@ #define FSFW_OSAL_COMMON_TMTCUDPBRIDGE_H_ #include "TcpIpBase.h" -#include "../../platform.h" -#include "../../tmtcservices/TmTcBridge.h" +#include "fsfw/platform.h" +#include "fsfw/tmtcservices/TmTcBridge.h" #ifdef PLATFORM_WIN #include diff --git a/src/fsfw/osal/common/tcpipCommon.h b/src/fsfw/osal/common/tcpipCommon.h index ce7a90cd..5a04144e 100644 --- a/src/fsfw/osal/common/tcpipCommon.h +++ b/src/fsfw/osal/common/tcpipCommon.h @@ -1,7 +1,7 @@ #ifndef FSFW_OSAL_COMMON_TCPIPCOMMON_H_ #define FSFW_OSAL_COMMON_TCPIPCOMMON_H_ -#include "../../timemanager/clockDefinitions.h" +#include "fsfw/timemanager/clockDefinitions.h" #include #ifdef _WIN32 @@ -13,7 +13,7 @@ namespace tcpip { -const char* const DEFAULT_SERVER_PORT = "7301"; +static constexpr char DEFAULT_SERVER_PORT[] = "7301"; enum class Protocol { UDP, From 1ac372cb89fabc868aa9cc6ef024f822c744eaed Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 9 Aug 2021 18:22:22 +0200 Subject: [PATCH 020/131] getter function for UDP port --- src/fsfw/osal/common/UdpTmTcBridge.cpp | 4 ++++ src/fsfw/osal/common/UdpTmTcBridge.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/fsfw/osal/common/UdpTmTcBridge.cpp b/src/fsfw/osal/common/UdpTmTcBridge.cpp index db2546cd..734a2b15 100644 --- a/src/fsfw/osal/common/UdpTmTcBridge.cpp +++ b/src/fsfw/osal/common/UdpTmTcBridge.cpp @@ -108,6 +108,10 @@ UdpTmTcBridge::~UdpTmTcBridge() { } } +std::string UdpTmTcBridge::getUdpPort() const { + return udpServerPort; +} + ReturnValue_t UdpTmTcBridge::sendTm(const uint8_t *data, size_t dataLen) { int flags = 0; diff --git a/src/fsfw/osal/common/UdpTmTcBridge.h b/src/fsfw/osal/common/UdpTmTcBridge.h index dc695c81..4d634e64 100644 --- a/src/fsfw/osal/common/UdpTmTcBridge.h +++ b/src/fsfw/osal/common/UdpTmTcBridge.h @@ -44,6 +44,8 @@ public: void checkAndSetClientAddress(sockaddr& clientAddress); + std::string getUdpPort() const; + protected: virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override; From 406b77ea81816c2113aec9239b3e5d2ed71e7cb5 Mon Sep 17 00:00:00 2001 From: IRS Cleanroom Laptop Date: Tue, 17 Aug 2021 16:34:25 +0200 Subject: [PATCH 021/131] moved SPI wiretapping cfg --- hal/src/fsfw_hal/linux/spi/SpiComIF.cpp | 5 ----- hal/src/fsfw_hal/linux/spi/SpiComIF.h | 1 + src/fsfw/FSFW.h.in | 5 +++++ 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp b/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp index fafe67be..fe6841f0 100644 --- a/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp +++ b/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp @@ -15,11 +15,6 @@ #include #include -/* Can be used for low-level debugging of the SPI bus */ -#ifndef FSFW_HAL_LINUX_SPI_WIRETAPPING -#define FSFW_HAL_LINUX_SPI_WIRETAPPING 0 -#endif - SpiComIF::SpiComIF(object_id_t objectId, GpioIF* gpioComIF): SystemObject(objectId), gpioComIF(gpioComIF) { if(gpioComIF == nullptr) { diff --git a/hal/src/fsfw_hal/linux/spi/SpiComIF.h b/hal/src/fsfw_hal/linux/spi/SpiComIF.h index d43e2505..bcca7462 100644 --- a/hal/src/fsfw_hal/linux/spi/SpiComIF.h +++ b/hal/src/fsfw_hal/linux/spi/SpiComIF.h @@ -1,6 +1,7 @@ #ifndef LINUX_SPI_SPICOMIF_H_ #define LINUX_SPI_SPICOMIF_H_ +#include "fsfw/FSFW.h" #include "spiDefinitions.h" #include "returnvalues/classIds.h" #include "fsfw_hal/common/gpio/GpioIF.h" diff --git a/src/fsfw/FSFW.h.in b/src/fsfw/FSFW.h.in index 4d4b8aee..a3666058 100644 --- a/src/fsfw/FSFW.h.in +++ b/src/fsfw/FSFW.h.in @@ -11,6 +11,11 @@ #cmakedefine FSFW_ADD_MONITORING #cmakedefine FSFW_ADD_SGP4_PROPAGATOR +/* Can be used for low-level debugging of the SPI bus */ +#ifndef FSFW_HAL_LINUX_SPI_WIRETAPPING +#define FSFW_HAL_LINUX_SPI_WIRETAPPING 0 +#endif + #ifndef FSFW_HAL_L3GD20_GYRO_DEBUG #define FSFW_HAL_L3GD20_GYRO_DEBUG 0 #endif /* FSFW_HAL_L3GD20_GYRO_DEBUG */ From e3697d6d8c38b278ebc34704fa772f671e36eb57 Mon Sep 17 00:00:00 2001 From: IRS Cleanroom Laptop Date: Tue, 17 Aug 2021 19:50:01 +0200 Subject: [PATCH 022/131] fixed printout --- hal/src/fsfw_hal/linux/UnixFileGuard.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/hal/src/fsfw_hal/linux/UnixFileGuard.cpp b/hal/src/fsfw_hal/linux/UnixFileGuard.cpp index f7901018..ad875623 100644 --- a/hal/src/fsfw_hal/linux/UnixFileGuard.cpp +++ b/hal/src/fsfw_hal/linux/UnixFileGuard.cpp @@ -1,5 +1,10 @@ +#include "fsfw/FSFW.h" +#include "fsfw/serviceinterface.h" #include "fsfw_hal/linux/UnixFileGuard.h" +#include +#include + UnixFileGuard::UnixFileGuard(std::string device, int* fileDescriptor, int flags, std::string diagnosticPrefix): fileDescriptor(fileDescriptor) { @@ -10,12 +15,11 @@ UnixFileGuard::UnixFileGuard(std::string device, int* fileDescriptor, int flags, if (*fileDescriptor < 0) { #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << diagnosticPrefix <<"Opening device failed with error code " << errno << - "." << std::endl; - sif::warning << "Error description: " << strerror(errno) << std::endl; + sif::warning << diagnosticPrefix << "Opening device failed with error code " << + errno << ": " << strerror(errno) << std::endl; #else - sif::printError("%sOpening device failed with error code %d.\n", diagnosticPrefix); - sif::printWarning("Error description: %s\n", strerror(errno)); + sif::printWarning("%sOpening device failed with error code %d: %s\n", + diagnosticPrefix, errno, strerror(errno)); #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ #endif /* FSFW_VERBOSE_LEVEL >= 1 */ openStatus = OPEN_FILE_FAILED; From 1183e5739d73da42978e0ab3218b3ca53fff4489 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 18 Aug 2021 11:23:45 +0200 Subject: [PATCH 023/131] using upstream action helper Will be merged upstream soon --- src/fsfw/action/ActionHelper.cpp | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/src/fsfw/action/ActionHelper.cpp b/src/fsfw/action/ActionHelper.cpp index 85c39f05..3dfe8b50 100644 --- a/src/fsfw/action/ActionHelper.cpp +++ b/src/fsfw/action/ActionHelper.cpp @@ -32,17 +32,6 @@ ReturnValue_t ActionHelper::initialize(MessageQueueIF* queueToUse_) { setQueueToUse(queueToUse_); } - if(queueToUse == nullptr) { -#if FSFW_VERBOSE_LEVEL >= 1 -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "ActionHelper::initialize: No queue set" << std::endl; -#else - sif::printWarning("ActionHelper::initialize: No queue set\n"); -#endif -#endif /* FSFW_VERBOSE_LEVEL >= 1 */ - return HasReturnvaluesIF::RETURN_FAILED; - } - return HasReturnvaluesIF::RETURN_OK; } @@ -66,19 +55,7 @@ void ActionHelper::setQueueToUse(MessageQueueIF* queue) { void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId, store_address_t dataAddress) { - if(ipcStore == nullptr) { -#if FSFW_VERBOSE_LEVEL >= 1 -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "ActionHelper::prepareExecution: IPC Store not set. Call initialize first" - << std::endl; -#else - sif::printWarning("ActionHelper::prepareExecution: " - "IPC Store not set. Call initialize first\n"); -#endif -#endif /* FSFW_VERBOSE_LEVEL >= 1 */ - return; - } - const uint8_t* dataPtr = nullptr; + const uint8_t* dataPtr = NULL; size_t size = 0; ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size); if (result != HasReturnvaluesIF::RETURN_OK) { From 7d0377845bd1bde75fcb81a8bf5fb4234718576a Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 20 Aug 2021 15:46:34 +0200 Subject: [PATCH 024/131] printout for unknown command --- src/fsfw/devicehandlers/DeviceHandlerBase.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp index 96fe031a..478fc041 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp @@ -1336,10 +1336,20 @@ void DeviceHandlerBase::buildInternalCommand(void) { DeviceCommandMap::iterator iter = deviceCommandMap.find( deviceCommandId); if (iter == deviceCommandMap.end()) { +#if FSFW_VERBOSE_LEVEL >= 1 + char output[36]; + sprintf(output, "Command 0x%08x unknown", + static_cast(deviceCommandId)); + // so we can track misconfigurations + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "buildInternalCommand", + COMMAND_NOT_SUPPORTED, + output); +#endif result = COMMAND_NOT_SUPPORTED; } else if (iter->second.isExecuting) { -#if FSFW_DISABLE_PRINTOUT == 0 +#if FSFW_VERBOSE_LEVEL >= 1 char output[36]; sprintf(output, "Command 0x%08x is executing", static_cast(deviceCommandId)); From 5454169e2056985428d36fee80e5a28a6952bf19 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sun, 22 Aug 2021 19:48:35 +0200 Subject: [PATCH 025/131] UartComIF: set O_NONBLOCK in canonical mode When using the non-canonical mode, the file descriptor can be opened in blocking mode because the VTIME and VMIN termios parameters are used to configure non-blocking mode. However, in canonical mode, the fd needs to be opened with O_NONBLOCK --- hal/src/fsfw_hal/linux/uart/UartComIF.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/hal/src/fsfw_hal/linux/uart/UartComIF.cpp b/hal/src/fsfw_hal/linux/uart/UartComIF.cpp index f52b6b1e..29a79205 100644 --- a/hal/src/fsfw_hal/linux/uart/UartComIF.cpp +++ b/hal/src/fsfw_hal/linux/uart/UartComIF.cpp @@ -60,7 +60,13 @@ int UartComIF::configureUartPort(UartCookie* uartCookie) { struct termios options = {}; std::string deviceFile = uartCookie->getDeviceFile(); - int fd = open(deviceFile.c_str(), O_RDWR); + int flags = O_RDWR; + if(uartCookie->getUartMode() == UartModes::CANONICAL) { + // In non-canonical mode, don't specify O_NONBLOCK because these properties will be + // controlled by the VTIME and VMIN parameters and O_NONBLOCK would override this + flags |= O_NONBLOCK; + } + int fd = open(deviceFile.c_str(), flags); if (fd < 0) { sif::warning << "UartComIF::configureUartPort: Failed to open uart " << deviceFile << From afd375a7f86730dd865aebac257f40c58fc690df Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sun, 22 Aug 2021 20:24:50 +0200 Subject: [PATCH 026/131] minor fix for canonical read handling --- hal/src/fsfw_hal/linux/uart/UartComIF.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/hal/src/fsfw_hal/linux/uart/UartComIF.cpp b/hal/src/fsfw_hal/linux/uart/UartComIF.cpp index 29a79205..99f5f8df 100644 --- a/hal/src/fsfw_hal/linux/uart/UartComIF.cpp +++ b/hal/src/fsfw_hal/linux/uart/UartComIF.cpp @@ -1,6 +1,7 @@ -#include "fsfw_hal/linux/uart/UartComIF.h" +#include "UartComIF.h" #include "OBSWConfig.h" +#include "fsfw_hal/linux/utility.h" #include "fsfw/serviceinterface/ServiceInterface.h" #include @@ -353,12 +354,13 @@ ReturnValue_t UartComIF::handleCanonicalRead(UartCookie& uartCookie, UartDeviceM size_t maxReplySize = uartCookie.getMaxReplyLen(); int fd = iter->second.fileDescriptor; auto bufferPtr = iter->second.replyBuffer.data(); + iter->second.replyLen = 0; do { size_t allowedReadSize = 0; if(currentBytesRead >= maxReplySize) { // Overflow risk. Emit warning, trigger event and break. If this happens, // the reception buffer is not large enough or data is not polled often enough. -#if OBSW_VERBOSE_LEVEL >= 1 +#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "UartComIF::requestReceiveMessage: Next read would cause overflow!" << std::endl; @@ -376,7 +378,20 @@ ReturnValue_t UartComIF::handleCanonicalRead(UartCookie& uartCookie, UartDeviceM bytesRead = read(fd, bufferPtr, allowedReadSize); if (bytesRead < 0) { - return RETURN_FAILED; + // EAGAIN: No data available in non-blocking mode + if(errno != EAGAIN) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "UartComIF::handleCanonicalRead: read failed with code" << + errno << ": " << strerror(errno) << std::endl; +#else + sif::printWarning("UartComIF::handleCanonicalRead: read failed with code %d: %s\n", + errno, strerror(errno)); +#endif +#endif + return RETURN_FAILED; + } + } else if(bytesRead > 0) { iter->second.replyLen += bytesRead; From fd2916af1162aabbf5dc2b7914885b251700f907 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 23 Aug 2021 09:40:02 +0200 Subject: [PATCH 027/131] moved TCP cfg --- src/fsfw/FSFW.h.in | 4 ++++ src/fsfw/osal/common/TcpTmTcServer.cpp | 14 ++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/fsfw/FSFW.h.in b/src/fsfw/FSFW.h.in index a3666058..4702c6ac 100644 --- a/src/fsfw/FSFW.h.in +++ b/src/fsfw/FSFW.h.in @@ -11,6 +11,10 @@ #cmakedefine FSFW_ADD_MONITORING #cmakedefine FSFW_ADD_SGP4_PROPAGATOR +#ifndef FSFW_TCP_RECV_WIRETAPPING_ENABLED +#define FSFW_TCP_RECV_WIRETAPPING_ENABLED 0 +#endif + /* Can be used for low-level debugging of the SPI bus */ #ifndef FSFW_HAL_LINUX_SPI_WIRETAPPING #define FSFW_HAL_LINUX_SPI_WIRETAPPING 0 diff --git a/src/fsfw/osal/common/TcpTmTcServer.cpp b/src/fsfw/osal/common/TcpTmTcServer.cpp index 11ab71af..534f5e7c 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.cpp +++ b/src/fsfw/osal/common/TcpTmTcServer.cpp @@ -1,8 +1,10 @@ -#include "fsfw/osal/common/TcpTmTcServer.h" -#include "fsfw/osal/common/TcpTmTcBridge.h" -#include "fsfw/osal/common/tcpipHelpers.h" - #include "fsfw/platform.h" +#include "fsfw/FSFW.h" + +#include "TcpTmTcServer.h" +#include "TcpTmTcBridge.h" +#include "tcpipHelpers.h" + #include "fsfw/container/SharedRingBuffer.h" #include "fsfw/ipc/MessageQueueSenderIF.h" #include "fsfw/ipc/MutexGuard.h" @@ -18,10 +20,6 @@ #include #endif -#ifndef FSFW_TCP_RECV_WIRETAPPING_ENABLED -#define FSFW_TCP_RECV_WIRETAPPING_ENABLED 0 -#endif - const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, From 469eba3ce2f82c7b2fcdd494d4ac279eef308195 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 6 Sep 2021 11:35:14 +0200 Subject: [PATCH 028/131] raised limit --- src/fsfw/tmtcservices/TmTcBridge.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fsfw/tmtcservices/TmTcBridge.h b/src/fsfw/tmtcservices/TmTcBridge.h index d3689d19..4980caff 100644 --- a/src/fsfw/tmtcservices/TmTcBridge.h +++ b/src/fsfw/tmtcservices/TmTcBridge.h @@ -19,7 +19,7 @@ class TmTcBridge : public AcceptsTelemetryIF, public: static constexpr uint8_t TMTC_RECEPTION_QUEUE_DEPTH = 20; static constexpr uint8_t LIMIT_STORED_DATA_SENT_PER_CYCLE = 15; - static constexpr uint8_t LIMIT_DOWNLINK_PACKETS_STORED = 20; + static constexpr uint8_t LIMIT_DOWNLINK_PACKETS_STORED = 200; static constexpr uint8_t DEFAULT_STORED_DATA_SENT_PER_CYCLE = 5; static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10; From 924c150af27484f9eb4439ec80c048b46c226890 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 6 Sep 2021 12:05:30 +0200 Subject: [PATCH 029/131] Possible bugfix in DHB The delayCycles variables needs to be initialized differently for periodic replies. It is initialized to the maxDelayCycles value now --- src/fsfw/devicehandlers/DeviceHandlerBase.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp index 478fc041..dcce736e 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp @@ -430,7 +430,12 @@ ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId, DeviceReplyInfo info; info.maxDelayCycles = maxDelayCycles; info.periodic = periodic; - info.delayCycles = 0; + if(info.periodic) { + info.delayCycles = info.maxDelayCycles; + } + else { + info.delayCycles = 0; + } info.replyLen = replyLen; info.dataSet = dataSet; info.command = deviceCommandMap.end(); From 73eb11f4f1e7cc80f61d04ad7722fe53608f8051 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 8 Sep 2021 16:01:46 +0200 Subject: [PATCH 030/131] bugfixes and improvements --- hal/src/fsfw_hal/linux/uart/UartComIF.cpp | 13 ++++++------- hal/src/fsfw_hal/linux/uart/UartCookie.cpp | 4 ++-- src/fsfw/devicehandlers/DeviceCommunicationIF.h | 7 ++++--- src/fsfw/devicehandlers/DeviceHandlerBase.cpp | 8 ++++---- src/fsfw/devicehandlers/DeviceHandlerBase.h | 8 +++++--- src/fsfw/devicehandlers/DeviceHandlerIF.h | 3 ++- src/fsfw/pus/Service8FunctionManagement.cpp | 4 ++-- src/fsfw/pus/servicepackets/Service1Packets.h | 8 ++++---- 8 files changed, 29 insertions(+), 26 deletions(-) diff --git a/hal/src/fsfw_hal/linux/uart/UartComIF.cpp b/hal/src/fsfw_hal/linux/uart/UartComIF.cpp index 99f5f8df..f5754c6e 100644 --- a/hal/src/fsfw_hal/linux/uart/UartComIF.cpp +++ b/hal/src/fsfw_hal/linux/uart/UartComIF.cpp @@ -266,23 +266,22 @@ void UartComIF::configureBaudrate(struct termios* options, UartCookie* uartCooki ReturnValue_t UartComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, size_t sendLen) { - int fd = 0; std::string deviceFile; UartDeviceMapIter uartDeviceMapIter; - if(sendData == nullptr) { - sif::debug << "UartComIF::sendMessage: Send Data is nullptr" << std::endl; - return RETURN_FAILED; - } - if(sendLen == 0) { return RETURN_OK; } + if(sendData == nullptr) { + sif::warning << "UartComIF::sendMessage: Send data is nullptr" << std::endl; + return RETURN_FAILED; + } + UartCookie* uartCookie = dynamic_cast(cookie); if(uartCookie == nullptr) { - sif::debug << "UartComIF::sendMessasge: Invalid UART Cookie!" << std::endl; + sif::warning << "UartComIF::sendMessasge: Invalid UART Cookie!" << std::endl; return NULLPOINTER; } diff --git a/hal/src/fsfw_hal/linux/uart/UartCookie.cpp b/hal/src/fsfw_hal/linux/uart/UartCookie.cpp index 339c7451..1c52e9cd 100644 --- a/hal/src/fsfw_hal/linux/uart/UartCookie.cpp +++ b/hal/src/fsfw_hal/linux/uart/UartCookie.cpp @@ -4,8 +4,8 @@ UartCookie::UartCookie(object_id_t handlerId, std::string deviceFile, UartModes uartMode, uint32_t baudrate, size_t maxReplyLen): - handlerId(handlerId), deviceFile(deviceFile), uartMode(uartMode), baudrate(baudrate), - maxReplyLen(maxReplyLen) { + handlerId(handlerId), deviceFile(deviceFile), uartMode(uartMode), + baudrate(baudrate), maxReplyLen(maxReplyLen) { } UartCookie::~UartCookie() {} diff --git a/src/fsfw/devicehandlers/DeviceCommunicationIF.h b/src/fsfw/devicehandlers/DeviceCommunicationIF.h index e0b473d3..527e4700 100644 --- a/src/fsfw/devicehandlers/DeviceCommunicationIF.h +++ b/src/fsfw/devicehandlers/DeviceCommunicationIF.h @@ -85,9 +85,10 @@ public: * Called by DHB in the GET_WRITE doGetWrite(). * Get send confirmation that the data in sendMessage() was sent successfully. * @param cookie - * @return - @c RETURN_OK if data was sent successfull - * - Everything else triggers falure event with - * returnvalue as parameter 1 + * @return + * - @c RETURN_OK if data was sent successfully but a reply is expected + * - NO_REPLY_EXPECTED if data was sent successfully and no reply is expected + * - Everything else to indicate failure */ virtual ReturnValue_t getSendSuccess(CookieIF *cookie) = 0; diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp index dcce736e..b52cd83e 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp @@ -653,11 +653,11 @@ void DeviceHandlerBase::doGetWrite() { replyRawData(rawPacket, rawPacketLen, requestedRawTraffic, true); } - //We need to distinguish here, because a raw command never expects a reply. - //(Could be done in eRIRM, but then child implementations need to be careful. + // We need to distinguish here, because a raw command never expects a reply. + // (Could be done in eRIRM, but then child implementations need to be careful. result = enableReplyInReplyMap(cookieInfo.pendingCommand); - } else { - //always generate a failure event, so that FDIR knows what's up + } else if (result != NO_REPLY_EXPECTED) { + // always generate a failure event, so that FDIR knows what's up triggerEvent(DEVICE_SENDING_COMMAND_FAILED, result, cookieInfo.pendingCommand->first); } diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.h b/src/fsfw/devicehandlers/DeviceHandlerBase.h index 53bd1e65..f6c22f0a 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.h +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.h @@ -327,15 +327,17 @@ protected: * The existence of the command in the command map and the command size check against 0 are * done by the base class. * + * The base class will generate a finish reply or a step automatically as long as the + * send success is confirmed in the #getSendSuccess function call of the communication + * interface. NO_REPLY_EXPECTED should be returned for a finish reply, RETURN_OK should be + * returned for a step reply and everything else will trigger a step failure. + * * @param deviceCommand The command to build, already checked against deviceCommandMap * @param commandData Pointer to the data from the direct command * @param commandDataLen Length of commandData * @return * - @c RETURN_OK to send command after #rawPacket and #rawPacketLen * have been set. - * - @c HasActionsIF::EXECUTION_COMPLETE to generate a finish reply immediately. This can - * be used if no reply is expected. Otherwise, the developer can call #actionHelper.finish - * to finish the command handling. * - Anything else triggers an event with the return code as a parameter as well as a * step reply failed with the return code */ diff --git a/src/fsfw/devicehandlers/DeviceHandlerIF.h b/src/fsfw/devicehandlers/DeviceHandlerIF.h index 1933c571..1fc57c42 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerIF.h +++ b/src/fsfw/devicehandlers/DeviceHandlerIF.h @@ -120,7 +120,8 @@ public: static const ReturnValue_t WRONG_MODE_FOR_COMMAND = MAKE_RETURN_CODE(0xA5); static const ReturnValue_t TIMEOUT = MAKE_RETURN_CODE(0xA6); static const ReturnValue_t BUSY = MAKE_RETURN_CODE(0xA7); - static const ReturnValue_t NO_REPLY_EXPECTED = MAKE_RETURN_CODE(0xA8); //!< Used to indicate that this is a command-only command. + //!< Used to indicate that this is a command-only command. + static const ReturnValue_t NO_REPLY_EXPECTED = MAKE_RETURN_CODE(0xA8); static const ReturnValue_t NON_OP_TEMPERATURE = MAKE_RETURN_CODE(0xA9); static const ReturnValue_t COMMAND_NOT_IMPLEMENTED = MAKE_RETURN_CODE(0xAA); diff --git a/src/fsfw/pus/Service8FunctionManagement.cpp b/src/fsfw/pus/Service8FunctionManagement.cpp index 39e872a0..48820d6e 100644 --- a/src/fsfw/pus/Service8FunctionManagement.cpp +++ b/src/fsfw/pus/Service8FunctionManagement.cpp @@ -33,8 +33,8 @@ ReturnValue_t Service8FunctionManagement::getMessageQueueAndObject( if(tcDataLen < sizeof(object_id_t)) { return CommandingServiceBase::INVALID_TC; } - SerializeAdapter::deSerialize(objectId, &tcData, - &tcDataLen, SerializeIF::Endianness::BIG); + // Can't fail, size was checked before + SerializeAdapter::deSerialize(objectId, &tcData, &tcDataLen, SerializeIF::Endianness::BIG); return checkInterfaceAndAcquireMessageQueue(id,objectId); } diff --git a/src/fsfw/pus/servicepackets/Service1Packets.h b/src/fsfw/pus/servicepackets/Service1Packets.h index 2249b4b0..02ae339f 100644 --- a/src/fsfw/pus/servicepackets/Service1Packets.h +++ b/src/fsfw/pus/servicepackets/Service1Packets.h @@ -13,10 +13,10 @@ /** * @brief FailureReport class to serialize a failure report - * @brief Subservice 1, 3, 5, 7 + * @brief Subservice 2, 4, 6, 8 * @ingroup spacepackets */ -class FailureReport: public SerializeIF { //!< [EXPORT] : [SUBSERVICE] 1, 3, 5, 7 +class FailureReport: public SerializeIF { //!< [EXPORT] : [SUBSERVICE] 2, 4, 6, 8 public: FailureReport(uint8_t failureSubtype_, uint16_t packetId_, uint16_t packetSequenceControl_, uint8_t stepNumber_, @@ -108,10 +108,10 @@ private: }; /** - * @brief Subservices 2, 4, 6, 8 + * @brief Subservices 1, 3, 5, 7 * @ingroup spacepackets */ -class SuccessReport: public SerializeIF { //!< [EXPORT] : [SUBSERVICE] 2, 4, 6, 8 +class SuccessReport: public SerializeIF { //!< [EXPORT] : [SUBSERVICE] 1, 3, 5, 7 public: SuccessReport(uint8_t subtype_, uint16_t packetId_, uint16_t packetSequenceControl_,uint8_t stepNumber_) : From dfe49cc1e5fd21851bb935e6b3f9714bfefef373 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 8 Sep 2021 16:08:13 +0200 Subject: [PATCH 031/131] DHB improvements --- .../devicehandlers/DeviceCommunicationIF.h | 7 ++++--- src/fsfw/devicehandlers/DeviceHandlerBase.cpp | 21 ++++++++++++++----- src/fsfw/devicehandlers/DeviceHandlerBase.h | 8 ++++--- src/fsfw/devicehandlers/DeviceHandlerIF.h | 3 ++- 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/fsfw/devicehandlers/DeviceCommunicationIF.h b/src/fsfw/devicehandlers/DeviceCommunicationIF.h index e0b473d3..527e4700 100644 --- a/src/fsfw/devicehandlers/DeviceCommunicationIF.h +++ b/src/fsfw/devicehandlers/DeviceCommunicationIF.h @@ -85,9 +85,10 @@ public: * Called by DHB in the GET_WRITE doGetWrite(). * Get send confirmation that the data in sendMessage() was sent successfully. * @param cookie - * @return - @c RETURN_OK if data was sent successfull - * - Everything else triggers falure event with - * returnvalue as parameter 1 + * @return + * - @c RETURN_OK if data was sent successfully but a reply is expected + * - NO_REPLY_EXPECTED if data was sent successfully and no reply is expected + * - Everything else to indicate failure */ virtual ReturnValue_t getSendSuccess(CookieIF *cookie) = 0; diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp index 96fe031a..c7944796 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp @@ -648,11 +648,12 @@ void DeviceHandlerBase::doGetWrite() { replyRawData(rawPacket, rawPacketLen, requestedRawTraffic, true); } - //We need to distinguish here, because a raw command never expects a reply. - //(Could be done in eRIRM, but then child implementations need to be careful. + // We need to distinguish here, because a raw command never expects a reply. + // This could be done in the #enableReplyInReplyMap call, + // but then child implementations would need to be careful. result = enableReplyInReplyMap(cookieInfo.pendingCommand); - } else { - //always generate a failure event, so that FDIR knows what's up + } else if (result != NO_REPLY_EXPECTED) { + // always generate a failure event, so that FDIR knows what's up triggerEvent(DEVICE_SENDING_COMMAND_FAILED, result, cookieInfo.pendingCommand->first); } @@ -1336,10 +1337,20 @@ void DeviceHandlerBase::buildInternalCommand(void) { DeviceCommandMap::iterator iter = deviceCommandMap.find( deviceCommandId); if (iter == deviceCommandMap.end()) { +#if FSFW_VERBOSE_LEVEL >= 1 + char output[36]; + sprintf(output, "Command 0x%08x unknown", + static_cast(deviceCommandId)); + // so we can track misconfigurations + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "buildInternalCommand", + COMMAND_NOT_SUPPORTED, + output); +#endif result = COMMAND_NOT_SUPPORTED; } else if (iter->second.isExecuting) { -#if FSFW_DISABLE_PRINTOUT == 0 +#if FSFW_VERBOSE_LEVEL >= 1 char output[36]; sprintf(output, "Command 0x%08x is executing", static_cast(deviceCommandId)); diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.h b/src/fsfw/devicehandlers/DeviceHandlerBase.h index 53bd1e65..f6c22f0a 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.h +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.h @@ -327,15 +327,17 @@ protected: * The existence of the command in the command map and the command size check against 0 are * done by the base class. * + * The base class will generate a finish reply or a step automatically as long as the + * send success is confirmed in the #getSendSuccess function call of the communication + * interface. NO_REPLY_EXPECTED should be returned for a finish reply, RETURN_OK should be + * returned for a step reply and everything else will trigger a step failure. + * * @param deviceCommand The command to build, already checked against deviceCommandMap * @param commandData Pointer to the data from the direct command * @param commandDataLen Length of commandData * @return * - @c RETURN_OK to send command after #rawPacket and #rawPacketLen * have been set. - * - @c HasActionsIF::EXECUTION_COMPLETE to generate a finish reply immediately. This can - * be used if no reply is expected. Otherwise, the developer can call #actionHelper.finish - * to finish the command handling. * - Anything else triggers an event with the return code as a parameter as well as a * step reply failed with the return code */ diff --git a/src/fsfw/devicehandlers/DeviceHandlerIF.h b/src/fsfw/devicehandlers/DeviceHandlerIF.h index 1933c571..1fc57c42 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerIF.h +++ b/src/fsfw/devicehandlers/DeviceHandlerIF.h @@ -120,7 +120,8 @@ public: static const ReturnValue_t WRONG_MODE_FOR_COMMAND = MAKE_RETURN_CODE(0xA5); static const ReturnValue_t TIMEOUT = MAKE_RETURN_CODE(0xA6); static const ReturnValue_t BUSY = MAKE_RETURN_CODE(0xA7); - static const ReturnValue_t NO_REPLY_EXPECTED = MAKE_RETURN_CODE(0xA8); //!< Used to indicate that this is a command-only command. + //!< Used to indicate that this is a command-only command. + static const ReturnValue_t NO_REPLY_EXPECTED = MAKE_RETURN_CODE(0xA8); static const ReturnValue_t NON_OP_TEMPERATURE = MAKE_RETURN_CODE(0xA9); static const ReturnValue_t COMMAND_NOT_IMPLEMENTED = MAKE_RETURN_CODE(0xAA); From 41f3d7cf9a5a0360a2abda34dc5abb0a2dc71802 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 8 Sep 2021 16:58:30 +0200 Subject: [PATCH 032/131] better name for function --- src/fsfw/devicehandlers/DeviceHandlerBase.cpp | 2 +- src/fsfw/devicehandlers/DeviceHandlerBase.h | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp index 4d1d09bc..e7de914b 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp @@ -1566,7 +1566,7 @@ LocalDataPoolManager* DeviceHandlerBase::getHkManagerHandle() { return &poolManager; } -MessageQueueId_t DeviceHandlerBase::getCommanderId(DeviceCommandId_t replyId) const { +MessageQueueId_t DeviceHandlerBase::getCommanderQueueId(DeviceCommandId_t replyId) const { auto commandIter = deviceCommandMap.find(replyId); if(commandIter == deviceCommandMap.end()) { return MessageQueueIF::NO_QUEUE; diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.h b/src/fsfw/devicehandlers/DeviceHandlerBase.h index f6c22f0a..e8ef9ada 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.h +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.h @@ -332,6 +332,9 @@ protected: * interface. NO_REPLY_EXPECTED should be returned for a finish reply, RETURN_OK should be * returned for a step reply and everything else will trigger a step failure. * + * If the commander ID is required for generating a finish reply immediately, it can be + * retrieved using the #getCommanderQueueId function. + * * @param deviceCommand The command to build, already checked against deviceCommandMap * @param commandData Pointer to the data from the direct command * @param commandDataLen Length of commandData @@ -401,7 +404,7 @@ protected: */ virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) = 0; - MessageQueueId_t getCommanderId(DeviceCommandId_t replyId) const; + MessageQueueId_t getCommanderQueueId(DeviceCommandId_t replyId) const; /** * Helper function to get pending command. This is useful for devices * like SPI sensors to identify the last sent command. From a8167f5431b73ea67b82b84740b48646a4b6e35a Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 8 Sep 2021 17:02:08 +0200 Subject: [PATCH 033/131] added another helper function --- src/fsfw/devicehandlers/DeviceHandlerBase.cpp | 8 ++++++++ src/fsfw/devicehandlers/DeviceHandlerBase.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp index e7de914b..b14a46e9 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp @@ -1573,3 +1573,11 @@ MessageQueueId_t DeviceHandlerBase::getCommanderQueueId(DeviceCommandId_t replyI } return commandIter->second.sendReplyTo; } + +void DeviceHandlerBase::finishCommandExecution(DeviceCommandId_t replyId) { + auto commandIter = deviceCommandMap.find(replyId); + if(commandIter == deviceCommandMap.end()) { + return; + } + commandIter->second.isExecuting = false; +} diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.h b/src/fsfw/devicehandlers/DeviceHandlerBase.h index e8ef9ada..aaf9d4ab 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.h +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.h @@ -405,6 +405,8 @@ protected: virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) = 0; MessageQueueId_t getCommanderQueueId(DeviceCommandId_t replyId) const; + void finishCommandExecution(DeviceCommandId_t replyId); + /** * Helper function to get pending command. This is useful for devices * like SPI sensors to identify the last sent command. From 40adca5f1d13ef8d6c712842ebc37e37fe449446 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 8 Sep 2021 17:24:33 +0200 Subject: [PATCH 034/131] set reply recipient --- src/fsfw/devicehandlers/DeviceHandlerBase.cpp | 7 ++++++- src/fsfw/osal/linux/MessageQueue.cpp | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp index b14a46e9..f73f027e 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp @@ -1294,19 +1294,24 @@ ReturnValue_t DeviceHandlerBase::executeAction(ActionId_t actionId, return result; } DeviceCommandMap::iterator iter = deviceCommandMap.find(actionId); + MessageQueueId_t previousReplyRecipient = iter->second.sendReplyTo; if (iter == deviceCommandMap.end()) { result = COMMAND_NOT_SUPPORTED; } else if (iter->second.isExecuting) { result = COMMAND_ALREADY_SENT; } else { + // Set this so it can be used to finish a command immediately + iter->second.sendReplyTo = commandedBy; result = buildCommandFromCommand(actionId, data, size); } if (result == RETURN_OK) { - iter->second.sendReplyTo = commandedBy; iter->second.isExecuting = true; cookieInfo.pendingCommand = iter; cookieInfo.state = COOKIE_WRITE_READY; } + else { + iter->second.sendReplyTo = previousReplyRecipient; + } return result; } diff --git a/src/fsfw/osal/linux/MessageQueue.cpp b/src/fsfw/osal/linux/MessageQueue.cpp index b068c04f..d028f9f7 100644 --- a/src/fsfw/osal/linux/MessageQueue.cpp +++ b/src/fsfw/osal/linux/MessageQueue.cpp @@ -285,10 +285,10 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, utility::printUnixErrorGeneric(CLASS_NAME, "sendMessageFromMessageQueue", "EBADF"); #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "mq_send to: " << sendTo << " sent from " - << sentFrom << "failed" << std::endl; + sif::warning << "mq_send to " << sendTo << " sent from " + << sentFrom << " failed" << std::endl; #else - sif::printWarning("mq_send to: %d sent from %d failed\n", sendTo, sentFrom); + sif::printWarning("mq_send to %d sent from %d failed\n", sendTo, sentFrom); #endif return DESTINATION_INVALID; } From 6db5011b14f7f17605c939c6164ccd6a79c425d8 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 15 Sep 2021 16:55:24 +0200 Subject: [PATCH 035/131] spi and gyro l3g updates --- .../devicehandlers/GyroL3GD20Handler.cpp | 42 +++++++++---------- .../devicehandlers/GyroL3GD20Handler.h | 11 ++--- hal/src/fsfw_hal/linux/spi/SpiComIF.cpp | 3 +- hal/src/fsfw_hal/linux/spi/SpiCookie.cpp | 2 +- hal/src/fsfw_hal/linux/spi/SpiCookie.h | 6 +-- 5 files changed, 30 insertions(+), 34 deletions(-) diff --git a/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp index 96d284e1..4a492e5d 100644 --- a/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp +++ b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp @@ -3,9 +3,9 @@ #include "fsfw/datapool/PoolReadGuard.h" GyroHandlerL3GD20H::GyroHandlerL3GD20H(object_id_t objectId, object_id_t deviceCommunication, - CookieIF *comCookie): + CookieIF *comCookie, uint8_t switchId, uint32_t transitionDelayMs): DeviceHandlerBase(objectId, deviceCommunication, comCookie), - dataset(this) { + switchId(switchId), transitionDelayMs(transitionDelayMs), dataset(this) { #if FSFW_HAL_L3GD20_GYRO_DEBUG == 1 debugDivider = new PeriodicOperationDivider(5); #endif @@ -47,7 +47,7 @@ ReturnValue_t GyroHandlerL3GD20H::buildTransitionDeviceCommand(DeviceCommandId_t switch(internalState) { case(InternalState::NONE): case(InternalState::NORMAL): { - return HasReturnvaluesIF::RETURN_OK; + return NOTHING_TO_SEND; } case(InternalState::CONFIGURE): { *id = L3GD20H::CONFIGURE_CTRL_REGS; @@ -66,10 +66,11 @@ ReturnValue_t GyroHandlerL3GD20H::buildTransitionDeviceCommand(DeviceCommandId_t default: #if FSFW_CPP_OSTREAM_ENABLED == 1 /* Might be a configuration error. */ - sif::debug << "GyroHandler::buildTransitionDeviceCommand: Unknown internal state!" << - std::endl; + sif::warning << "GyroL3GD20Handler::buildTransitionDeviceCommand: " + "Unknown internal state!" << std::endl; #else - sif::printDebug("GyroHandler::buildTransitionDeviceCommand: Unknown internal state!\n"); + sif::printDebug("GyroL3GD20Handler::buildTransitionDeviceCommand: " + "Unknown internal state!\n"); #endif return HasReturnvaluesIF::RETURN_OK; } @@ -144,7 +145,7 @@ ReturnValue_t GyroHandlerL3GD20H::buildCommandFromCommand( ReturnValue_t GyroHandlerL3GD20H::scanForReply(const uint8_t *start, size_t len, DeviceCommandId_t *foundId, size_t *foundLen) { - /* For SPI, the ID will always be the one of the last sent command. */ + // For SPI, the ID will always be the one of the last sent command *foundId = this->getPendingCommand(); *foundLen = this->rawPacketLen; @@ -166,7 +167,7 @@ ReturnValue_t GyroHandlerL3GD20H::interpretDeviceReply(DeviceCommandId_t id, commandExecuted = true; } else { - /* Attempt reconfiguration. */ + // Attempt reconfiguration internalState = InternalState::CONFIGURE; return DeviceHandlerIF::DEVICE_REPLY_INVALID; } @@ -199,13 +200,12 @@ ReturnValue_t GyroHandlerL3GD20H::interpretDeviceReply(DeviceCommandId_t id, if(debugDivider->checkAndIncrement()) { /* Set terminal to utf-8 if there is an issue with micro printout. */ #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::info << "GyroHandlerL3GD20H: Angular velocities in degrees per second:" << - std::endl; - sif::info << "X: " << angVelocX << " \xC2\xB0" << std::endl; - sif::info << "Y: " << angVelocY << " \xC2\xB0" << std::endl; - sif::info << "Z: " << angVelocZ << " \xC2\xB0" << std::endl; + sif::info << "GyroHandlerL3GD20H: Angular velocities (deg/s):" << std::endl; + sif::info << "X: " << angVelocX << std::endl; + sif::info << "Y: " << angVelocY << std::endl; + sif::info << "Z: " << angVelocZ << std::endl; #else - sif::printInfo("GyroHandlerL3GD20H: Angular velocities in degrees per second:\n"); + sif::printInfo("GyroHandlerL3GD20H: Angular velocities (deg/s):\n"); sif::printInfo("X: %f\n", angVelocX); sif::printInfo("Y: %f\n", angVelocY); sif::printInfo("Z: %f\n", angVelocZ); @@ -231,7 +231,7 @@ ReturnValue_t GyroHandlerL3GD20H::interpretDeviceReply(DeviceCommandId_t id, uint32_t GyroHandlerL3GD20H::getTransitionDelayMs(Mode_t from, Mode_t to) { - return 10000; + return this->transitionDelayMs; } void GyroHandlerL3GD20H::setGoNormalModeAtStartup() { @@ -240,14 +240,10 @@ void GyroHandlerL3GD20H::setGoNormalModeAtStartup() { ReturnValue_t GyroHandlerL3GD20H::initializeLocalDataPool( localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { - localDataPoolMap.emplace(L3GD20H::ANG_VELOC_X, - new PoolEntry({0.0})); - localDataPoolMap.emplace(L3GD20H::ANG_VELOC_Y, - new PoolEntry({0.0})); - localDataPoolMap.emplace(L3GD20H::ANG_VELOC_Z, - new PoolEntry({0.0})); - localDataPoolMap.emplace(L3GD20H::TEMPERATURE, - new PoolEntry({0.0})); + localDataPoolMap.emplace(L3GD20H::ANG_VELOC_X, new PoolEntry({0.0})); + localDataPoolMap.emplace(L3GD20H::ANG_VELOC_Y, new PoolEntry({0.0})); + localDataPoolMap.emplace(L3GD20H::ANG_VELOC_Z, new PoolEntry({0.0})); + localDataPoolMap.emplace(L3GD20H::TEMPERATURE, new PoolEntry({0.0})); return HasReturnvaluesIF::RETURN_OK; } diff --git a/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h index 020c5a32..bc1d9c1c 100644 --- a/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h +++ b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h @@ -7,10 +7,6 @@ #include #include -#ifndef FSFW_HAL_L3GD20_GYRO_DEBUG -#define FSFW_HAL_L3GD20_GYRO_DEBUG 0 -#endif /* FSFW_HAL_L3GD20_GYRO_DEBUG */ - /** * @brief Device Handler for the L3GD20H gyroscope sensor * (https://www.st.com/en/mems-and-sensors/l3gd20h.html) @@ -23,9 +19,12 @@ class GyroHandlerL3GD20H: public DeviceHandlerBase { public: GyroHandlerL3GD20H(object_id_t objectId, object_id_t deviceCommunication, - CookieIF* comCookie); + CookieIF* comCookie, uint8_t switchId, uint32_t transitionDelayMs = 10000); virtual ~GyroHandlerL3GD20H(); + /** + * @brief Configure device handler to go to normal mode immediately + */ void setGoNormalModeAtStartup(); protected: @@ -51,6 +50,8 @@ protected: LocalDataPoolManager &poolManager) override; private: + uint8_t switchId = 0; + uint32_t transitionDelayMs = 0; GyroPrimaryDataset dataset; enum class InternalState { diff --git a/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp b/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp index 2acf41e6..6cf6675f 100644 --- a/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp +++ b/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp @@ -188,7 +188,7 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie *spiCookie, const spiCookie->getSpiParameters(spiMode, spiSpeed, nullptr); setSpiSpeedAndMode(fileDescriptor, spiMode, spiSpeed); spiCookie->assignWriteBuffer(sendData); - spiCookie->assignTransferSize(sendLen); + spiCookie->setTransferSize(sendLen); bool fullDuplex = spiCookie->isFullDuplex(); gpioId_t gpioId = spiCookie->getChipSelectPin(); @@ -330,6 +330,7 @@ ReturnValue_t SpiComIF::readReceivedMessage(CookieIF *cookie, uint8_t **buffer, *buffer = rxBuf; *size = spiCookie->getCurrentTransferSize(); + spiCookie->setTransferSize(0); return HasReturnvaluesIF::RETURN_OK; } diff --git a/hal/src/fsfw_hal/linux/spi/SpiCookie.cpp b/hal/src/fsfw_hal/linux/spi/SpiCookie.cpp index 54d8aa16..f07954e9 100644 --- a/hal/src/fsfw_hal/linux/spi/SpiCookie.cpp +++ b/hal/src/fsfw_hal/linux/spi/SpiCookie.cpp @@ -121,7 +121,7 @@ bool SpiCookie::isFullDuplex() const { return not this->halfDuplex; } -void SpiCookie::assignTransferSize(size_t transferSize) { +void SpiCookie::setTransferSize(size_t transferSize) { spiTransferStruct.len = transferSize; } diff --git a/hal/src/fsfw_hal/linux/spi/SpiCookie.h b/hal/src/fsfw_hal/linux/spi/SpiCookie.h index acf7c77c..844fd421 100644 --- a/hal/src/fsfw_hal/linux/spi/SpiCookie.h +++ b/hal/src/fsfw_hal/linux/spi/SpiCookie.h @@ -103,10 +103,10 @@ public: void assignReadBuffer(uint8_t* rx); void assignWriteBuffer(const uint8_t* tx); /** - * Assign size for the next transfer. + * Set size for the next transfer. Set to 0 for no transfer * @param transferSize */ - void assignTransferSize(size_t transferSize); + void setTransferSize(size_t transferSize); size_t getCurrentTransferSize() const; struct UncommonParameters { @@ -158,8 +158,6 @@ private: std::string spiDev, const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed, spi::send_callback_function_t callback, void* args); - size_t currentTransferSize = 0; - address_t spiAddress; gpioId_t chipSelectPin; std::string spiDevice; From bdd7d59d82a0b9290d77844fbcc5be61c61bcbcb Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 15 Sep 2021 17:05:52 +0200 Subject: [PATCH 036/131] reverted some changes --- src/fsfw/devicehandlers/DeviceHandlerBase.cpp | 38 +++++----------- src/fsfw/devicehandlers/DeviceHandlerBase.h | 45 ++++++++----------- 2 files changed, 31 insertions(+), 52 deletions(-) diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp index 71f31de0..535113fd 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp @@ -461,7 +461,7 @@ size_t DeviceHandlerBase::getNextReplyLength(DeviceCommandId_t commandId){ return iter->second.replyLen; }else{ return 0; - } + } } ReturnValue_t DeviceHandlerBase::updateReplyMapEntry(DeviceCommandId_t deviceReply, @@ -612,15 +612,15 @@ void DeviceHandlerBase::replyToReply(const DeviceCommandId_t command, DeviceRepl } DeviceCommandInfo* info = &replyInfo.command->second; if (info == nullptr){ - printWarningOrError(sif::OutputTypes::OUT_ERROR, - "replyToReply", HasReturnvaluesIF::RETURN_FAILED, - "Command pointer not found"); - return; + printWarningOrError(sif::OutputTypes::OUT_ERROR, + "replyToReply", HasReturnvaluesIF::RETURN_FAILED, + "Command pointer not found"); + return; } if (info->expectedReplies > 0){ - // Check before to avoid underflow - info->expectedReplies--; + // Check before to avoid underflow + info->expectedReplies--; } // Check if more replies are expected. If so, do nothing. if (info->expectedReplies == 0) { @@ -667,12 +667,11 @@ void DeviceHandlerBase::doGetWrite() { replyRawData(rawPacket, rawPacketLen, requestedRawTraffic, true); } - // We need to distinguish here, because a raw command never expects a reply. - // This could be done in the #enableReplyInReplyMap call, - // but then child implementations would need to be careful. + //We need to distinguish here, because a raw command never expects a reply. + //(Could be done in eRIRM, but then child implementations need to be careful. result = enableReplyInReplyMap(cookieInfo.pendingCommand); - } else if (result != NO_REPLY_EXPECTED) { - // always generate a failure event, so that FDIR knows what's up + } else { + //always generate a failure event, so that FDIR knows what's up triggerEvent(DEVICE_SENDING_COMMAND_FAILED, result, cookieInfo.pendingCommand->first); } @@ -1308,24 +1307,19 @@ ReturnValue_t DeviceHandlerBase::executeAction(ActionId_t actionId, return result; } DeviceCommandMap::iterator iter = deviceCommandMap.find(actionId); - MessageQueueId_t previousReplyRecipient = iter->second.sendReplyTo; if (iter == deviceCommandMap.end()) { result = COMMAND_NOT_SUPPORTED; } else if (iter->second.isExecuting) { result = COMMAND_ALREADY_SENT; } else { - // Set this so it can be used to finish a command immediately - iter->second.sendReplyTo = commandedBy; result = buildCommandFromCommand(actionId, data, size); } if (result == RETURN_OK) { + iter->second.sendReplyTo = commandedBy; iter->second.isExecuting = true; cookieInfo.pendingCommand = iter; cookieInfo.state = COOKIE_WRITE_READY; } - else { - iter->second.sendReplyTo = previousReplyRecipient; - } return result; } @@ -1592,11 +1586,3 @@ MessageQueueId_t DeviceHandlerBase::getCommanderQueueId(DeviceCommandId_t replyI } return commandIter->second.sendReplyTo; } - -void DeviceHandlerBase::finishCommandExecution(DeviceCommandId_t replyId) { - auto commandIter = deviceCommandMap.find(replyId); - if(commandIter == deviceCommandMap.end()) { - return; - } - commandIter->second.isExecuting = false; -} diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.h b/src/fsfw/devicehandlers/DeviceHandlerBase.h index 2843e5ea..b182b611 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.h +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.h @@ -6,22 +6,22 @@ #include "DeviceHandlerFailureIsolation.h" #include "DeviceHandlerThermalSet.h" -#include "../serviceinterface/ServiceInterface.h" -#include "../serviceinterface/serviceInterfaceDefintions.h" -#include "../objectmanager/SystemObject.h" -#include "../tasks/ExecutableObjectIF.h" -#include "../returnvalues/HasReturnvaluesIF.h" -#include "../action/HasActionsIF.h" -#include "../datapool/PoolVariableIF.h" -#include "../modes/HasModesIF.h" -#include "../power/PowerSwitchIF.h" -#include "../ipc/MessageQueueIF.h" -#include "../tasks/PeriodicTaskIF.h" -#include "../action/ActionHelper.h" -#include "../health/HealthHelper.h" -#include "../parameters/ParameterHelper.h" -#include "../datapoollocal/HasLocalDataPoolIF.h" -#include "../datapoollocal/LocalDataPoolManager.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/serviceinterface/serviceInterfaceDefintions.h" +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/tasks/ExecutableObjectIF.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/action/HasActionsIF.h" +#include "fsfw/datapool/PoolVariableIF.h" +#include "fsfw/modes/HasModesIF.h" +#include "fsfw/power/PowerSwitchIF.h" +#include "fsfw/ipc/MessageQueueIF.h" +#include "fsfw/tasks/PeriodicTaskIF.h" +#include "fsfw/action/ActionHelper.h" +#include "fsfw/health/HealthHelper.h" +#include "fsfw/parameters/ParameterHelper.h" +#include "fsfw/datapoollocal/HasLocalDataPoolIF.h" +#include "fsfw/datapoollocal/LocalDataPoolManager.h" #include @@ -327,20 +327,15 @@ protected: * The existence of the command in the command map and the command size check against 0 are * done by the base class. * - * The base class will generate a finish reply or a step automatically as long as the - * send success is confirmed in the #getSendSuccess function call of the communication - * interface. NO_REPLY_EXPECTED should be returned for a finish reply, RETURN_OK should be - * returned for a step reply and everything else will trigger a step failure. - * - * If the commander ID is required for generating a finish reply immediately, it can be - * retrieved using the #getCommanderQueueId function. - * * @param deviceCommand The command to build, already checked against deviceCommandMap * @param commandData Pointer to the data from the direct command * @param commandDataLen Length of commandData * @return * - @c RETURN_OK to send command after #rawPacket and #rawPacketLen * have been set. + * - @c HasActionsIF::EXECUTION_COMPLETE to generate a finish reply immediately. This can + * be used if no reply is expected. Otherwise, the developer can call #actionHelper.finish + * to finish the command handling. * - Anything else triggers an event with the return code as a parameter as well as a * step reply failed with the return code */ @@ -405,8 +400,6 @@ protected: virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) = 0; MessageQueueId_t getCommanderQueueId(DeviceCommandId_t replyId) const; - void finishCommandExecution(DeviceCommandId_t replyId); - /** * Helper function to get pending command. This is useful for devices * like SPI sensors to identify the last sent command. From d986ab77200ae28e69d8818443856e7812e81ed4 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 15 Sep 2021 18:37:44 +0200 Subject: [PATCH 037/131] bugfix for TM packet stored PUS C --- src/fsfw/tmtcpacket/SpacePacketBase.cpp | 21 +++++++--- src/fsfw/tmtcpacket/SpacePacketBase.h | 4 +- src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp | 8 +++- src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h | 2 +- .../tmtcpacket/pus/tm/TmPacketStoredPusC.cpp | 41 ++++++++++++++++--- 5 files changed, 61 insertions(+), 15 deletions(-) diff --git a/src/fsfw/tmtcpacket/SpacePacketBase.cpp b/src/fsfw/tmtcpacket/SpacePacketBase.cpp index 5dae94c9..cffdec9a 100644 --- a/src/fsfw/tmtcpacket/SpacePacketBase.cpp +++ b/src/fsfw/tmtcpacket/SpacePacketBase.cpp @@ -3,8 +3,8 @@ #include -SpacePacketBase::SpacePacketBase( const uint8_t* set_address ) { - this->data = (SpacePacketPointer*) set_address; +SpacePacketBase::SpacePacketBase(const uint8_t* setAddress) { + this->data = reinterpret_cast(const_cast(setAddress)); } SpacePacketBase::~SpacePacketBase() { @@ -15,10 +15,21 @@ uint8_t SpacePacketBase::getPacketVersionNumber( void ) { return (this->data->header.packet_id_h & 0b11100000) >> 5; } -void SpacePacketBase::initSpacePacketHeader(bool isTelecommand, +ReturnValue_t SpacePacketBase::initSpacePacketHeader(bool isTelecommand, bool hasSecondaryHeader, uint16_t apid, uint16_t sequenceCount) { + if(data == nullptr) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "SpacePacketBase::initSpacePacketHeader: Data pointer is invalid" + << std::endl; +#else + sif::printWarning("SpacePacketBase::initSpacePacketHeader: Data pointer is invalid!\n"); +#endif +#endif + return HasReturnvaluesIF::RETURN_FAILED; + } //reset header to zero: - memset(data,0, sizeof(this->data->header) ); + memset(data, 0, sizeof(this->data->header) ); //Set TC/TM bit. data->header.packet_id_h = ((isTelecommand? 1 : 0)) << 4; //Set secondaryHeader bit @@ -27,7 +38,7 @@ void SpacePacketBase::initSpacePacketHeader(bool isTelecommand, //Always initialize as standalone packets. data->header.sequence_control_h = 0b11000000; setPacketSequenceCount(sequenceCount); - + return HasReturnvaluesIF::RETURN_OK; } bool SpacePacketBase::isTelecommand( void ) { diff --git a/src/fsfw/tmtcpacket/SpacePacketBase.h b/src/fsfw/tmtcpacket/SpacePacketBase.h index 3cd3e552..fae64745 100644 --- a/src/fsfw/tmtcpacket/SpacePacketBase.h +++ b/src/fsfw/tmtcpacket/SpacePacketBase.h @@ -2,6 +2,8 @@ #define FSFW_TMTCPACKET_SPACEPACKETBASE_H_ #include "ccsds_header.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" + #include /** @@ -82,7 +84,7 @@ public: */ bool isTelecommand( void ); - void initSpacePacketHeader(bool isTelecommand, bool hasSecondaryHeader, + ReturnValue_t initSpacePacketHeader(bool isTelecommand, bool hasSecondaryHeader, uint16_t apid, uint16_t sequenceCount = 0); /** * The CCSDS header provides a secondary header flag (the fifth-highest bit), diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp index ea25f5d2..2c6e1d97 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp @@ -53,11 +53,14 @@ uint8_t* TmPacketPusC::getPacketTimeRaw() const{ } -void TmPacketPusC::initializeTmPacket(uint16_t apid, uint8_t service, +ReturnValue_t TmPacketPusC::initializeTmPacket(uint16_t apid, uint8_t service, uint8_t subservice, uint16_t packetSubcounter, uint16_t destinationId, uint8_t timeRefField) { //Set primary header: - initSpacePacketHeader(false, true, apid); + ReturnValue_t result = initSpacePacketHeader(false, true, apid); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } //Set data Field Header: //First, set to zero. memset(&tmData->dataField, 0, sizeof(tmData->dataField)); @@ -76,6 +79,7 @@ void TmPacketPusC::initializeTmPacket(uint16_t apid, uint8_t service, timeStamper->addTimeStamp(tmData->dataField.time, sizeof(tmData->dataField.time)); } + return HasReturnvaluesIF::RETURN_OK; } void TmPacketPusC::setSourceDataSize(uint16_t size) { diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h index fe373c6f..3a9be132 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h @@ -100,7 +100,7 @@ protected: * @param subservice PUS Subservice * @param packetSubcounter Additional subcounter used. */ - void initializeTmPacket(uint16_t apid, uint8_t service, uint8_t subservice, + ReturnValue_t initializeTmPacket(uint16_t apid, uint8_t service, uint8_t subservice, uint16_t packetSubcounter, uint16_t destinationId = 0, uint8_t timeRefField = 0); /** diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp index add4f4b9..84f8d28e 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp @@ -43,27 +43,56 @@ TmPacketStoredPusC::TmPacketStoredPusC(uint16_t apid, uint8_t service, return; } size_t sourceDataSize = 0; - if (content != NULL) { + if (content != nullptr) { sourceDataSize += content->getSerializedSize(); } - if (header != NULL) { + if (header != nullptr) { sourceDataSize += header->getSerializedSize(); } - uint8_t *p_data = NULL; + uint8_t *p_data = nullptr; + size_t sizeToReserve = getPacketMinimumSize() + sourceDataSize; ReturnValue_t returnValue = store->getFreeElement(&storeAddress, - (getPacketMinimumSize() + sourceDataSize), &p_data); + sizeToReserve, &p_data); if (returnValue != store->RETURN_OK) { +#if FSFW_VERBOSE_LEVEL >= 1 + switch(returnValue) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + case(StorageManagerIF::DATA_STORAGE_FULL): { + sif::warning << "TmPacketStoredPusC::TmPacketStoredPusC: Store full for packet with " + "size " << sizeToReserve << std::endl; + break; + } + case(StorageManagerIF::DATA_TOO_LARGE): { + sif::warning << "TmPacketStoredPusC::TmPacketStoredPusC: Data with size " << + sizeToReserve << " too large" << std::endl; + break; + } +#else + case(StorageManagerIF::DATA_STORAGE_FULL): { + sif::printWarning("TmPacketStoredPusC::TmPacketStoredPusC: Store full for packet with " + "size %d\n", sizeToReserve); + break; + } + case(StorageManagerIF::DATA_TOO_LARGE): { + sif::printWarning("TmPacketStoredPusC::TmPacketStoredPusC: Data with size " + "%d too large\n", sizeToReserve); + break; + } +#endif +#endif + } TmPacketStoredBase::checkAndReportLostTm(); + return; } setData(p_data); initializeTmPacket(apid, service, subservice, packetSubcounter, destinationId, timeRefField); uint8_t *putDataHere = getSourceData(); size_t size = 0; - if (header != NULL) { + if (header != nullptr) { header->serialize(&putDataHere, &size, sourceDataSize, SerializeIF::Endianness::BIG); } - if (content != NULL) { + if (content != nullptr) { content->serialize(&putDataHere, &size, sourceDataSize, SerializeIF::Endianness::BIG); } From bc6b29e652a90f5a14bb32a1bcc2a956e410e678 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 15 Sep 2021 18:48:09 +0200 Subject: [PATCH 038/131] use warning instead of debug --- src/fsfw/pus/Service5EventReporting.cpp | 10 ++++++---- src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp | 7 +++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/fsfw/pus/Service5EventReporting.cpp b/src/fsfw/pus/Service5EventReporting.cpp index 36aa7e70..2293ab20 100644 --- a/src/fsfw/pus/Service5EventReporting.cpp +++ b/src/fsfw/pus/Service5EventReporting.cpp @@ -41,8 +41,7 @@ ReturnValue_t Service5EventReporting::performService() { } } #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "Service5EventReporting::generateEventReport:" - " Too many events" << std::endl; + sif::warning << "Service5EventReporting::generateEventReport: Too many events" << std::endl; #endif return HasReturnvaluesIF::RETURN_OK; } @@ -64,8 +63,11 @@ ReturnValue_t Service5EventReporting::generateEventReport( requestQueue->getDefaultDestination(),requestQueue->getId()); if(result != HasReturnvaluesIF::RETURN_OK) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "Service5EventReporting::generateEventReport:" - " Could not send TM packet" << std::endl; + sif::warning << "Service5EventReporting::generateEventReport: " + "Could not send TM packet" << std::endl; +#else + sif::printWarning("Service5EventReporting::generateEventReport: " + "Could not send TM packet\n"); #endif } return result; diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp index 84f8d28e..4a6e4d21 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp @@ -49,10 +49,9 @@ TmPacketStoredPusC::TmPacketStoredPusC(uint16_t apid, uint8_t service, if (header != nullptr) { sourceDataSize += header->getSerializedSize(); } - uint8_t *p_data = nullptr; + uint8_t *pData = nullptr; size_t sizeToReserve = getPacketMinimumSize() + sourceDataSize; - ReturnValue_t returnValue = store->getFreeElement(&storeAddress, - sizeToReserve, &p_data); + ReturnValue_t returnValue = store->getFreeElement(&storeAddress, sizeToReserve, &pData); if (returnValue != store->RETURN_OK) { #if FSFW_VERBOSE_LEVEL >= 1 switch(returnValue) { @@ -84,7 +83,7 @@ TmPacketStoredPusC::TmPacketStoredPusC(uint16_t apid, uint8_t service, TmPacketStoredBase::checkAndReportLostTm(); return; } - setData(p_data); + setData(pData); initializeTmPacket(apid, service, subservice, packetSubcounter, destinationId, timeRefField); uint8_t *putDataHere = getSourceData(); size_t size = 0; From 823c6ec5fc6357d342f4d0e3edc68d89ff492b87 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 16 Sep 2021 11:33:50 +0200 Subject: [PATCH 039/131] added RM3100 handler --- .../fsfw_hal/devicehandlers/CMakeLists.txt | 1 + .../devicehandlers/MgmRM3100Handler.cpp | 370 ++++++++++++++++++ .../devicehandlers/MgmRM3100Handler.h | 117 ++++++ .../devicedefinitions/MgmRM3100HandlerDefs.h | 132 +++++++ src/fsfw/FSFW.h.in | 10 +- 5 files changed, 627 insertions(+), 3 deletions(-) create mode 100644 hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp create mode 100644 hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.h create mode 100644 hal/src/fsfw_hal/devicehandlers/devicedefinitions/MgmRM3100HandlerDefs.h diff --git a/hal/src/fsfw_hal/devicehandlers/CMakeLists.txt b/hal/src/fsfw_hal/devicehandlers/CMakeLists.txt index cf542d8d..eb48d190 100644 --- a/hal/src/fsfw_hal/devicehandlers/CMakeLists.txt +++ b/hal/src/fsfw_hal/devicehandlers/CMakeLists.txt @@ -1,3 +1,4 @@ target_sources(${LIB_FSFW_NAME} PRIVATE GyroL3GD20Handler.cpp + MgmRM3100Handler.cpp ) diff --git a/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp b/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp new file mode 100644 index 00000000..71193913 --- /dev/null +++ b/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp @@ -0,0 +1,370 @@ +#include "MgmRM3100Handler.h" + +#include "fsfw/datapool/PoolReadGuard.h" +#include "fsfw/globalfunctions/bitutility.h" +#include "fsfw/devicehandlers/DeviceHandlerMessage.h" +#include "fsfw/objectmanager/SystemObjectIF.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" + + +MgmRM3100Handler::MgmRM3100Handler(object_id_t objectId, + object_id_t deviceCommunication, CookieIF* comCookie, uint8_t switchId, + uint32_t transitionDelay): + DeviceHandlerBase(objectId, deviceCommunication, comCookie), + primaryDataset(this), switchId(switchId), transitionDelay(transitionDelay) { +#if FSFW_HAL_RM3100_MGM_DEBUG == 1 + debugDivider = new PeriodicOperationDivider(5); +#endif +} + +MgmRM3100Handler::~MgmRM3100Handler() {} + +void MgmRM3100Handler::doStartUp() { + switch(internalState) { + case(InternalState::NONE): { + internalState = InternalState::CONFIGURE_CMM; + break; + } + case(InternalState::CONFIGURE_CMM): { + internalState = InternalState::READ_CMM; + break; + } + case(InternalState::READ_CMM): { + if(commandExecuted) { + internalState = InternalState::STATE_CONFIGURE_TMRC; + } + break; + } + case(InternalState::STATE_CONFIGURE_TMRC): { + if(commandExecuted) { + internalState = InternalState::STATE_READ_TMRC; + } + break; + } + case(InternalState::STATE_READ_TMRC): { + if(commandExecuted) { + internalState = InternalState::NORMAL; + if(goToNormalModeAtStartup) { + setMode(MODE_NORMAL); + } + else { + setMode(_MODE_TO_ON); + } + } + break; + } + default: { + break; + } + } +} + +void MgmRM3100Handler::doShutDown() { + setMode(_MODE_POWER_DOWN); +} + +ReturnValue_t MgmRM3100Handler::buildTransitionDeviceCommand( + DeviceCommandId_t *id) { + size_t commandLen = 0; + switch(internalState) { + case(InternalState::NONE): + case(InternalState::NORMAL): { + return HasReturnvaluesIF::RETURN_OK; + } + case(InternalState::CONFIGURE_CMM): { + *id = RM3100::CONFIGURE_CMM; + break; + } + case(InternalState::READ_CMM): { + *id = RM3100::READ_CMM; + break; + } + case(InternalState::STATE_CONFIGURE_TMRC): { + commandBuffer[0] = RM3100::TMRC_DEFAULT_VALUE; + commandLen = 1; + *id = RM3100::CONFIGURE_TMRC; + break; + } + case(InternalState::STATE_READ_TMRC): { + *id = RM3100::READ_TMRC; + break; + } + default: + // Might be a configuration error + sif::warning << "MgmRM3100Handler::buildTransitionDeviceCommand: Unknown internal state!" << + std::endl; + return HasReturnvaluesIF::RETURN_OK; + } + + return buildCommandFromCommand(*id, commandBuffer, commandLen); +} + +ReturnValue_t MgmRM3100Handler::buildCommandFromCommand(DeviceCommandId_t deviceCommand, + const uint8_t *commandData, size_t commandDataLen) { + switch(deviceCommand) { + case(RM3100::CONFIGURE_CMM): { + commandBuffer[0] = RM3100::CMM_REGISTER; + commandBuffer[1] = RM3100::CMM_VALUE; + rawPacket = commandBuffer; + rawPacketLen = 2; + break; + } + case(RM3100::READ_CMM): { + commandBuffer[0] = RM3100::CMM_REGISTER | RM3100::READ_MASK; + commandBuffer[1] = 0; + rawPacket = commandBuffer; + rawPacketLen = 2; + break; + } + case(RM3100::CONFIGURE_TMRC): { + return handleTmrcConfigCommand(deviceCommand, commandData, commandDataLen); + } + case(RM3100::READ_TMRC): { + commandBuffer[0] = RM3100::TMRC_REGISTER | RM3100::READ_MASK; + commandBuffer[1] = 0; + rawPacket = commandBuffer; + rawPacketLen = 2; + break; + } + case(RM3100::CONFIGURE_CYCLE_COUNT): { + return handleCycleCountConfigCommand(deviceCommand, commandData, commandDataLen); + } + case(RM3100::READ_CYCLE_COUNT): { + commandBuffer[0] = RM3100::CYCLE_COUNT_START_REGISTER | RM3100::READ_MASK; + std::memset(commandBuffer + 1, 0, 6); + rawPacket = commandBuffer; + rawPacketLen = 7; + break; + } + case(RM3100::READ_DATA): { + commandBuffer[0] = RM3100::MEASUREMENT_REG_START | RM3100::READ_MASK; + std::memset(commandBuffer + 1, 0, 9); + rawPacketLen = 10; + break; + } + default: + return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED; + } + return RETURN_OK; +} + +ReturnValue_t MgmRM3100Handler::buildNormalDeviceCommand( + DeviceCommandId_t *id) { + *id = RM3100::READ_DATA; + return buildCommandFromCommand(*id, nullptr, 0); +} + +ReturnValue_t MgmRM3100Handler::scanForReply(const uint8_t *start, + size_t len, DeviceCommandId_t *foundId, + size_t *foundLen) { + + /* For SPI, ID will always be the one of the last sent command. */ + *foundId = this->getPendingCommand(); + *foundLen = len; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t MgmRM3100Handler::interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + switch(id) { + case(RM3100::CONFIGURE_CMM): + case(RM3100::CONFIGURE_CYCLE_COUNT): + case(RM3100::CONFIGURE_TMRC): { + /* We can only check whether write was successful with read operation. */ + if(mode == _MODE_START_UP) { + commandExecuted = true; + } + break; + } + case(RM3100::READ_CMM): { + uint8_t cmmValue = packet[1]; + /* We clear the seventh bit in any case + * because this one is zero sometimes for some reason */ + bitutil::bitClear(&cmmValue, 6); + if(cmmValue == cmmRegValue and internalState == InternalState::READ_CMM) { + commandExecuted = true; + } + else { + /* Attempt reconfiguration. */ + internalState = InternalState::CONFIGURE_CMM; + return DeviceHandlerIF::DEVICE_REPLY_INVALID; + } + break; + } + case(RM3100::READ_TMRC): { + if(packet[1] == tmrcRegValue) { + commandExecuted = true; + /* Reading TMRC was commanded. Trigger event to inform ground. */ + if(mode != _MODE_START_UP) { + triggerEvent(tmrcSet, tmrcRegValue, 0); + } + } + else { + /* Attempt reconfiguration. */ + internalState = InternalState::STATE_CONFIGURE_TMRC; + return DeviceHandlerIF::DEVICE_REPLY_INVALID; + } + break; + } + case(RM3100::READ_CYCLE_COUNT): { + uint16_t cycleCountX = packet[1] << 8 | packet[2]; + uint16_t cycleCountY = packet[3] << 8 | packet[4]; + uint16_t cycleCountZ = packet[5] << 8 | packet[6]; + if(cycleCountX != cycleCountRegValueX or cycleCountY != cycleCountRegValueY or + cycleCountZ != cycleCountRegValueZ) { + return DeviceHandlerIF::DEVICE_REPLY_INVALID; + } + /* Reading TMRC was commanded. Trigger event to inform ground. */ + if(mode != _MODE_START_UP) { + uint32_t eventParam1 = (cycleCountX << 16) | cycleCountY; + triggerEvent(cycleCountersSet, eventParam1, cycleCountZ); + } + break; + } + case(RM3100::READ_DATA): { + result = handleDataReadout(packet); + break; + } + default: + return DeviceHandlerIF::UNKNOWN_DEVICE_REPLY; + } + + return result; +} + +ReturnValue_t MgmRM3100Handler::handleCycleCountConfigCommand(DeviceCommandId_t deviceCommand, + const uint8_t *commandData, size_t commandDataLen) { + if(commandData == nullptr) { + return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; + } + + // Set cycle count + if(commandDataLen == 2) { + handleCycleCommand(true, commandData, commandDataLen); + } + else if(commandDataLen == 6) { + handleCycleCommand(false, commandData, commandDataLen); + } + else { + return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; + } + + commandBuffer[0] = RM3100::CYCLE_COUNT_VALUE; + std::memcpy(commandBuffer + 1, &cycleCountRegValueX, 2); + std::memcpy(commandBuffer + 3, &cycleCountRegValueY, 2); + std::memcpy(commandBuffer + 5, &cycleCountRegValueZ, 2); + rawPacketLen = 7; + rawPacket = commandBuffer; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t MgmRM3100Handler::handleCycleCommand(bool oneCycleValue, + const uint8_t *commandData, size_t commandDataLen) { + RM3100::CycleCountCommand command(oneCycleValue); + ReturnValue_t result = command.deSerialize(&commandData, &commandDataLen, + SerializeIF::Endianness::BIG); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + /* Data sheet p.30 "while noise limits the useful upper range to ~400 cycle counts." */ + if(command.cycleCountX > 450 ) { + return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; + } + + if(not oneCycleValue and (command.cycleCountY > 450 or command.cycleCountZ > 450)) { + return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; + } + + cycleCountRegValueX = command.cycleCountX; + cycleCountRegValueY = command.cycleCountY; + cycleCountRegValueZ = command.cycleCountZ; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t MgmRM3100Handler::handleTmrcConfigCommand(DeviceCommandId_t deviceCommand, + const uint8_t *commandData, size_t commandDataLen) { + if(commandData == nullptr or commandDataLen != 1) { + return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; + } + + commandBuffer[0] = RM3100::TMRC_REGISTER; + commandBuffer[1] = commandData[0]; + tmrcRegValue = commandData[0]; + rawPacketLen = 2; + rawPacket = commandBuffer; + return HasReturnvaluesIF::RETURN_OK; +} + +void MgmRM3100Handler::fillCommandAndReplyMap() { + insertInCommandAndReplyMap(RM3100::CONFIGURE_CMM, 3); + insertInCommandAndReplyMap(RM3100::READ_CMM, 3); + + insertInCommandAndReplyMap(RM3100::CONFIGURE_TMRC, 3); + insertInCommandAndReplyMap(RM3100::READ_TMRC, 3); + + insertInCommandAndReplyMap(RM3100::CONFIGURE_CYCLE_COUNT, 3); + insertInCommandAndReplyMap(RM3100::READ_CYCLE_COUNT, 3); + + insertInCommandAndReplyMap(RM3100::READ_DATA, 3, &primaryDataset); +} + +void MgmRM3100Handler::modeChanged(void) { + internalState = InternalState::NONE; +} + +ReturnValue_t MgmRM3100Handler::initializeLocalDataPool( + localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { + localDataPoolMap.emplace(RM3100::FIELD_STRENGTH_X, new PoolEntry({0.0})); + localDataPoolMap.emplace(RM3100::FIELD_STRENGTH_Y, new PoolEntry({0.0})); + localDataPoolMap.emplace(RM3100::FIELD_STRENGTH_Z, new PoolEntry({0.0})); + return HasReturnvaluesIF::RETURN_OK; +} + +uint32_t MgmRM3100Handler::getTransitionDelayMs(Mode_t from, Mode_t to) { + return 25000; +} + +ReturnValue_t MgmRM3100Handler::getSwitches(const uint8_t **switches, uint8_t *numberOfSwitches) { + *switches = &switchId; + *numberOfSwitches = 1; + return HasReturnvaluesIF::RETURN_OK; +} + +void MgmRM3100Handler::setToGoToNormalMode(bool enable) { + goToNormalModeAtStartup = enable; +} + +ReturnValue_t MgmRM3100Handler::handleDataReadout(const uint8_t *packet) { + /* Analyze data here. The sensor generates 24 bit signed values so we need to do some bitshift + * trickery here to calculate the raw values first */ + int32_t fieldStrengthRawX = ((packet[1] << 24) | (packet[2] << 16) | (packet[3] << 8)) >> 8; + int32_t fieldStrengthRawY = ((packet[4] << 24) | (packet[5] << 16) | (packet[6] << 8)) >> 8; + int32_t fieldStrengthRawZ = ((packet[7] << 24) | (packet[8] << 16) | (packet[3] << 8)) >> 8; + + /* Now scale to physical value in microtesla */ + float fieldStrengthX = fieldStrengthRawX * scaleFactorX; + float fieldStrengthY = fieldStrengthRawY * scaleFactorX; + float fieldStrengthZ = fieldStrengthRawZ * scaleFactorX; + +#if FSFW_HAL_RM3100_MGM_DEBUG == 1 + if(debugDivider->checkAndIncrement()) { + sif::info << "MgmRM3100Handler: Magnetic field strength in" + " microtesla:" << std::endl; + /* Set terminal to utf-8 if there is an issue with micro printout. */ + sif::info << "X: " << fieldStrengthX << " uT" << std::endl; + sif::info << "Y: " << fieldStrengthY << " uT" << std::endl; + sif::info << "Z: " << fieldStrengthZ << " uT" << std::endl; + } +#endif + + /* TODO: Sanity check on values */ + PoolReadGuard readGuard(&primaryDataset); + if(readGuard.getReadResult() == HasReturnvaluesIF::RETURN_OK) { + primaryDataset.fieldStrengthX = fieldStrengthX; + primaryDataset.fieldStrengthY = fieldStrengthY; + primaryDataset.fieldStrengthZ = fieldStrengthZ; + primaryDataset.setValidity(true, true); + } + return RETURN_OK; +} diff --git a/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.h b/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.h new file mode 100644 index 00000000..eb6e62bc --- /dev/null +++ b/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.h @@ -0,0 +1,117 @@ +#ifndef MISSION_DEVICES_MGMRM3100HANDLER_H_ +#define MISSION_DEVICES_MGMRM3100HANDLER_H_ + +#include "fsfw/FSFW.h" +#include "devices/powerSwitcherList.h" +#include "devicedefinitions/MgmRM3100HandlerDefs.h" +#include "fsfw/devicehandlers/DeviceHandlerBase.h" + +#if FSFW_HAL_RM3100_MGM_DEBUG == 1 +#include "fsfw/globalfunctions/PeriodicOperationDivider.h" +#endif + +/** + * @brief Device Handler for the RM3100 geomagnetic magnetometer sensor + * (https://www.pnicorp.com/rm3100/) + * @details + * Flight manual: + * https://egit.irs.uni-stuttgart.de/redmine/projects/eive-flight-manual/wiki/RM3100_MGM + */ +class MgmRM3100Handler: public DeviceHandlerBase { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::MGM_RM3100; + + //! [EXPORT] : [COMMENT] P1: TMRC value which was set, P2: 0 + static constexpr Event tmrcSet = event::makeEvent(SUBSYSTEM_ID::MGM_RM3100, + 0x00, severity::INFO); + + //! [EXPORT] : [COMMENT] Cycle counter set. P1: First two bytes new Cycle Count X + //! P1: Second two bytes new Cycle Count Y + //! P2: New cycle count Z + static constexpr Event cycleCountersSet = event::makeEvent( + SUBSYSTEM_ID::MGM_RM3100, 0x01, severity::INFO); + + MgmRM3100Handler(object_id_t objectId, object_id_t deviceCommunication, + CookieIF* comCookie, uint8_t switchId, uint32_t transitionDelay = 10000); + virtual ~MgmRM3100Handler(); + + /** + * Configure device handler to go to normal mode after startup immediately + * @param enable + */ + void setToGoToNormalMode(bool enable); + +protected: + + /* DeviceHandlerBase overrides */ + ReturnValue_t buildTransitionDeviceCommand( + DeviceCommandId_t *id) override; + void doStartUp() override; + void doShutDown() override; + ReturnValue_t buildNormalDeviceCommand( + DeviceCommandId_t *id) override; + ReturnValue_t buildCommandFromCommand( + DeviceCommandId_t deviceCommand, const uint8_t *commandData, + size_t commandDataLen) override; + ReturnValue_t scanForReply(const uint8_t *start, size_t len, + DeviceCommandId_t *foundId, size_t *foundLen) override; + ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, + const uint8_t *packet) override; + ReturnValue_t getSwitches(const uint8_t **switches, + uint8_t *numberOfSwitches) override; + + void fillCommandAndReplyMap() override; + void modeChanged(void) override; + uint32_t getTransitionDelayMs(Mode_t from, Mode_t to) override; + ReturnValue_t initializeLocalDataPool(localpool::DataPool &localDataPoolMap, + LocalDataPoolManager &poolManager) override; + +private: + + enum class InternalState { + NONE, + CONFIGURE_CMM, + READ_CMM, + // The cycle count states are propably not going to be used because + // the default cycle count will be used. + STATE_CONFIGURE_CYCLE_COUNT, + STATE_READ_CYCLE_COUNT, + STATE_CONFIGURE_TMRC, + STATE_READ_TMRC, + NORMAL + }; + InternalState internalState = InternalState::NONE; + bool commandExecuted = false; + RM3100::Rm3100PrimaryDataset primaryDataset; + + uint8_t commandBuffer[10]; + uint8_t commandBufferLen = 0; + + uint8_t cmmRegValue = RM3100::CMM_VALUE; + uint8_t tmrcRegValue = RM3100::TMRC_DEFAULT_VALUE; + uint16_t cycleCountRegValueX = RM3100::CYCLE_COUNT_VALUE; + uint16_t cycleCountRegValueY = RM3100::CYCLE_COUNT_VALUE; + uint16_t cycleCountRegValueZ = RM3100::CYCLE_COUNT_VALUE; + float scaleFactorX = 1.0 / RM3100::DEFAULT_GAIN; + float scaleFactorY = 1.0 / RM3100::DEFAULT_GAIN; + float scaleFactorZ = 1.0 / RM3100::DEFAULT_GAIN; + + bool goToNormalModeAtStartup = false; + uint8_t switchId; + uint32_t transitionDelay; + + ReturnValue_t handleCycleCountConfigCommand(DeviceCommandId_t deviceCommand, + const uint8_t *commandData,size_t commandDataLen); + ReturnValue_t handleCycleCommand(bool oneCycleValue, + const uint8_t *commandData, size_t commandDataLen); + + ReturnValue_t handleTmrcConfigCommand(DeviceCommandId_t deviceCommand, + const uint8_t *commandData,size_t commandDataLen); + + ReturnValue_t handleDataReadout(const uint8_t* packet); +#if FSFW_HAL_RM3100_MGM_DEBUG == 1 + PeriodicOperationDivider* debugDivider; +#endif +}; + +#endif /* MISSION_DEVICEHANDLING_MGMRM3100HANDLER_H_ */ diff --git a/hal/src/fsfw_hal/devicehandlers/devicedefinitions/MgmRM3100HandlerDefs.h b/hal/src/fsfw_hal/devicehandlers/devicedefinitions/MgmRM3100HandlerDefs.h new file mode 100644 index 00000000..08f80dd9 --- /dev/null +++ b/hal/src/fsfw_hal/devicehandlers/devicedefinitions/MgmRM3100HandlerDefs.h @@ -0,0 +1,132 @@ +#ifndef MISSION_DEVICES_DEVICEDEFINITIONS_MGMHANDLERRM3100DEFINITIONS_H_ +#define MISSION_DEVICES_DEVICEDEFINITIONS_MGMHANDLERRM3100DEFINITIONS_H_ + +#include +#include +#include +#include +#include + +namespace RM3100 { + +/* Actually 10, we round up a little bit */ +static constexpr size_t MAX_BUFFER_SIZE = 12; + +static constexpr uint8_t READ_MASK = 0x80; + +/*----------------------------------------------------------------------------*/ +/* CMM Register */ +/*----------------------------------------------------------------------------*/ +static constexpr uint8_t SET_CMM_CMZ = 1 << 6; +static constexpr uint8_t SET_CMM_CMY = 1 << 5; +static constexpr uint8_t SET_CMM_CMX = 1 << 4; +static constexpr uint8_t SET_CMM_DRDM = 1 << 2; +static constexpr uint8_t SET_CMM_START = 1; +static constexpr uint8_t CMM_REGISTER = 0x01; + +static constexpr uint8_t CMM_VALUE = SET_CMM_CMZ | SET_CMM_CMY | SET_CMM_CMX | + SET_CMM_DRDM | SET_CMM_START; + +/*----------------------------------------------------------------------------*/ +/* Cycle count register */ +/*----------------------------------------------------------------------------*/ +// Default value (200) +static constexpr uint8_t CYCLE_COUNT_VALUE = 0xC8; + +static constexpr float DEFAULT_GAIN = static_cast(CYCLE_COUNT_VALUE) / + 100 * 38; +static constexpr uint8_t CYCLE_COUNT_START_REGISTER = 0x04; + +/*----------------------------------------------------------------------------*/ +/* TMRC register */ +/*----------------------------------------------------------------------------*/ +static constexpr uint8_t TMRC_150HZ_VALUE = 0x94; +static constexpr uint8_t TMRC_75HZ_VALUE = 0x95; +static constexpr uint8_t TMRC_DEFAULT_37HZ_VALUE = 0x96; + +static constexpr uint8_t TMRC_REGISTER = 0x0B; +static constexpr uint8_t TMRC_DEFAULT_VALUE = TMRC_DEFAULT_37HZ_VALUE; + +static constexpr uint8_t MEASUREMENT_REG_START = 0x24; +static constexpr uint8_t BIST_REGISTER = 0x33; +static constexpr uint8_t DATA_READY_VAL = 0b1000'0000; +static constexpr uint8_t STATUS_REGISTER = 0x34; +static constexpr uint8_t REVID_REGISTER = 0x36; + +// Range in Microtesla. 1 T equals 10000 Gauss (for comparison with LIS3 MGM) +static constexpr uint16_t RANGE = 800; + +static constexpr DeviceCommandId_t READ_DATA = 0; + +static constexpr DeviceCommandId_t CONFIGURE_CMM = 1; +static constexpr DeviceCommandId_t READ_CMM = 2; + +static constexpr DeviceCommandId_t CONFIGURE_TMRC = 3; +static constexpr DeviceCommandId_t READ_TMRC = 4; + +static constexpr DeviceCommandId_t CONFIGURE_CYCLE_COUNT = 5; +static constexpr DeviceCommandId_t READ_CYCLE_COUNT = 6; + +class CycleCountCommand: public SerialLinkedListAdapter { +public: + CycleCountCommand(bool oneCycleCount = true): oneCycleCount(oneCycleCount) { + setLinks(oneCycleCount); + } + + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) override { + ReturnValue_t result = SerialLinkedListAdapter::deSerialize(buffer, + size, streamEndianness); + if(oneCycleCount) { + cycleCountY = cycleCountX; + cycleCountZ = cycleCountX; + } + return result; + } + + SerializeElement cycleCountX; + SerializeElement cycleCountY; + SerializeElement cycleCountZ; + +private: + void setLinks(bool oneCycleCount) { + setStart(&cycleCountX); + if(not oneCycleCount) { + cycleCountX.setNext(&cycleCountY); + cycleCountY.setNext(&cycleCountZ); + } + } + + bool oneCycleCount; +}; + +static constexpr uint32_t MGM_DATASET_ID = READ_DATA; + +enum MgmPoolIds: lp_id_t { + FIELD_STRENGTH_X, + FIELD_STRENGTH_Y, + FIELD_STRENGTH_Z, +}; + +class Rm3100PrimaryDataset: public StaticLocalDataSet<3 * sizeof(float)> { +public: + Rm3100PrimaryDataset(HasLocalDataPoolIF* hkOwner): + StaticLocalDataSet(hkOwner, MGM_DATASET_ID) {} + + Rm3100PrimaryDataset(object_id_t mgmId): + StaticLocalDataSet(sid_t(mgmId, MGM_DATASET_ID)) {} + + // Field strengths in micro Tesla. + lp_var_t fieldStrengthX = lp_var_t(sid.objectId, + FIELD_STRENGTH_X, this); + lp_var_t fieldStrengthY = lp_var_t(sid.objectId, + FIELD_STRENGTH_Y, this); + lp_var_t fieldStrengthZ = lp_var_t(sid.objectId, + FIELD_STRENGTH_Z, this); +}; + +} + + + +#endif /* MISSION_DEVICES_DEVICEDEFINITIONS_MGMHANDLERRM3100DEFINITIONS_H_ */ diff --git a/src/fsfw/FSFW.h.in b/src/fsfw/FSFW.h.in index d053d3c0..e6dd2f8f 100644 --- a/src/fsfw/FSFW.h.in +++ b/src/fsfw/FSFW.h.in @@ -17,16 +17,20 @@ #cmakedefine FSFW_ADD_SGP4_PROPAGATOR #ifndef FSFW_TCP_RECV_WIRETAPPING_ENABLED -#define FSFW_TCP_RECV_WIRETAPPING_ENABLED 0 +#define FSFW_TCP_RECV_WIRETAPPING_ENABLED 0 #endif /* Can be used for low-level debugging of the SPI bus */ #ifndef FSFW_HAL_LINUX_SPI_WIRETAPPING -#define FSFW_HAL_LINUX_SPI_WIRETAPPING 0 +#define FSFW_HAL_LINUX_SPI_WIRETAPPING 0 #endif #ifndef FSFW_HAL_L3GD20_GYRO_DEBUG -#define FSFW_HAL_L3GD20_GYRO_DEBUG 0 +#define FSFW_HAL_L3GD20_GYRO_DEBUG 0 #endif /* FSFW_HAL_L3GD20_GYRO_DEBUG */ +#ifndef FSFW_HAL_RM3100_MGM_DEBUG +#define FSFW_HAL_RM3100_MGM_DEBUG 0 +#endif /* FSFW_HAL_RM3100_MGM_DEBUG */ + #endif /* FSFW_FSFW_H_ */ From 0df8d358020be603d0224104882951813656233a Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 16 Sep 2021 11:36:32 +0200 Subject: [PATCH 040/131] comment format --- .../devicehandlers/MgmRM3100Handler.cpp | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp b/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp index 71193913..3f9fdce2 100644 --- a/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp +++ b/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp @@ -158,7 +158,7 @@ ReturnValue_t MgmRM3100Handler::scanForReply(const uint8_t *start, size_t len, DeviceCommandId_t *foundId, size_t *foundLen) { - /* For SPI, ID will always be the one of the last sent command. */ + // For SPI, ID will always be the one of the last sent command *foundId = this->getPendingCommand(); *foundLen = len; return HasReturnvaluesIF::RETURN_OK; @@ -170,7 +170,7 @@ ReturnValue_t MgmRM3100Handler::interpretDeviceReply(DeviceCommandId_t id, const case(RM3100::CONFIGURE_CMM): case(RM3100::CONFIGURE_CYCLE_COUNT): case(RM3100::CONFIGURE_TMRC): { - /* We can only check whether write was successful with read operation. */ + // We can only check whether write was successful with read operation if(mode == _MODE_START_UP) { commandExecuted = true; } @@ -178,14 +178,14 @@ ReturnValue_t MgmRM3100Handler::interpretDeviceReply(DeviceCommandId_t id, const } case(RM3100::READ_CMM): { uint8_t cmmValue = packet[1]; - /* We clear the seventh bit in any case - * because this one is zero sometimes for some reason */ + // We clear the seventh bit in any case + // because this one is zero sometimes for some reason bitutil::bitClear(&cmmValue, 6); if(cmmValue == cmmRegValue and internalState == InternalState::READ_CMM) { commandExecuted = true; } else { - /* Attempt reconfiguration. */ + // Attempt reconfiguration internalState = InternalState::CONFIGURE_CMM; return DeviceHandlerIF::DEVICE_REPLY_INVALID; } @@ -194,13 +194,13 @@ ReturnValue_t MgmRM3100Handler::interpretDeviceReply(DeviceCommandId_t id, const case(RM3100::READ_TMRC): { if(packet[1] == tmrcRegValue) { commandExecuted = true; - /* Reading TMRC was commanded. Trigger event to inform ground. */ + // Reading TMRC was commanded. Trigger event to inform ground if(mode != _MODE_START_UP) { triggerEvent(tmrcSet, tmrcRegValue, 0); } } else { - /* Attempt reconfiguration. */ + // Attempt reconfiguration internalState = InternalState::STATE_CONFIGURE_TMRC; return DeviceHandlerIF::DEVICE_REPLY_INVALID; } @@ -214,7 +214,7 @@ ReturnValue_t MgmRM3100Handler::interpretDeviceReply(DeviceCommandId_t id, const cycleCountZ != cycleCountRegValueZ) { return DeviceHandlerIF::DEVICE_REPLY_INVALID; } - /* Reading TMRC was commanded. Trigger event to inform ground. */ + // Reading TMRC was commanded. Trigger event to inform ground if(mode != _MODE_START_UP) { uint32_t eventParam1 = (cycleCountX << 16) | cycleCountY; triggerEvent(cycleCountersSet, eventParam1, cycleCountZ); @@ -267,7 +267,7 @@ ReturnValue_t MgmRM3100Handler::handleCycleCommand(bool oneCycleValue, return result; } - /* Data sheet p.30 "while noise limits the useful upper range to ~400 cycle counts." */ + // Data sheet p.30 "while noise limits the useful upper range to ~400 cycle counts." if(command.cycleCountX > 450 ) { return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; } @@ -336,13 +336,13 @@ void MgmRM3100Handler::setToGoToNormalMode(bool enable) { } ReturnValue_t MgmRM3100Handler::handleDataReadout(const uint8_t *packet) { - /* Analyze data here. The sensor generates 24 bit signed values so we need to do some bitshift - * trickery here to calculate the raw values first */ + // Analyze data here. The sensor generates 24 bit signed values so we need to do some bitshift + // trickery here to calculate the raw values first int32_t fieldStrengthRawX = ((packet[1] << 24) | (packet[2] << 16) | (packet[3] << 8)) >> 8; int32_t fieldStrengthRawY = ((packet[4] << 24) | (packet[5] << 16) | (packet[6] << 8)) >> 8; int32_t fieldStrengthRawZ = ((packet[7] << 24) | (packet[8] << 16) | (packet[3] << 8)) >> 8; - /* Now scale to physical value in microtesla */ + // Now scale to physical value in microtesla float fieldStrengthX = fieldStrengthRawX * scaleFactorX; float fieldStrengthY = fieldStrengthRawY * scaleFactorX; float fieldStrengthZ = fieldStrengthRawZ * scaleFactorX; @@ -358,7 +358,7 @@ ReturnValue_t MgmRM3100Handler::handleDataReadout(const uint8_t *packet) { } #endif - /* TODO: Sanity check on values */ + // TODO: Sanity check on values? PoolReadGuard readGuard(&primaryDataset); if(readGuard.getReadResult() == HasReturnvaluesIF::RETURN_OK) { primaryDataset.fieldStrengthX = fieldStrengthX; From 6d0d04ac230962024580ef3769cc8ec063db4093 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 16 Sep 2021 17:33:37 +0200 Subject: [PATCH 041/131] minor bugfix --- hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp b/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp index 3f9fdce2..60ad01b7 100644 --- a/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp +++ b/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp @@ -69,7 +69,7 @@ ReturnValue_t MgmRM3100Handler::buildTransitionDeviceCommand( switch(internalState) { case(InternalState::NONE): case(InternalState::NORMAL): { - return HasReturnvaluesIF::RETURN_OK; + return NOTHING_TO_SEND; } case(InternalState::CONFIGURE_CMM): { *id = RM3100::CONFIGURE_CMM; From b1a56a71cdba538e82b4052413e1663b34cfee90 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 16 Sep 2021 18:50:20 +0200 Subject: [PATCH 042/131] Added LIS3MDL to FSFW, per op divider tweak --- .../fsfw_hal/devicehandlers/CMakeLists.txt | 1 + .../devicehandlers/MgmLIS3MDLHandler.cpp | 503 ++++++++++++++++++ .../devicehandlers/MgmLIS3MDLHandler.h | 167 ++++++ .../devicehandlers/MgmRM3100Handler.cpp | 2 +- .../devicedefinitions/MgmLIS3HandlerDefs.h | 178 +++++++ src/fsfw/FSFW.h.in | 4 + .../PeriodicOperationDivider.cpp | 39 +- .../PeriodicOperationDivider.h | 78 +-- 8 files changed, 913 insertions(+), 59 deletions(-) create mode 100644 hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp create mode 100644 hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h create mode 100644 hal/src/fsfw_hal/devicehandlers/devicedefinitions/MgmLIS3HandlerDefs.h diff --git a/hal/src/fsfw_hal/devicehandlers/CMakeLists.txt b/hal/src/fsfw_hal/devicehandlers/CMakeLists.txt index eb48d190..94e67c72 100644 --- a/hal/src/fsfw_hal/devicehandlers/CMakeLists.txt +++ b/hal/src/fsfw_hal/devicehandlers/CMakeLists.txt @@ -1,4 +1,5 @@ target_sources(${LIB_FSFW_NAME} PRIVATE GyroL3GD20Handler.cpp MgmRM3100Handler.cpp + MgmLIS3MDLHandler.cpp ) diff --git a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp new file mode 100644 index 00000000..c023dbda --- /dev/null +++ b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp @@ -0,0 +1,503 @@ +#include "MgmLIS3MDLHandler.h" + +#include "fsfw/datapool/PoolReadGuard.h" +#if FSFW_HAL_LIS3MDL_MGM_DEBUG == 1 +#include "fsfw/globalfunctions/PeriodicOperationDivider.h" +#endif + +MgmLIS3MDLHandler::MgmLIS3MDLHandler(object_id_t objectId, object_id_t deviceCommunication, + CookieIF* comCookie, uint8_t switchId, uint32_t transitionDelay): + DeviceHandlerBase(objectId, deviceCommunication, comCookie), + dataset(this), transitionDelay(transitionDelay) { +#if FSFW_HAL_LIS3MDL_MGM_DEBUG == 1 + debugDivider = new PeriodicOperationDivider(5); +#endif + /* Set to default values right away. */ + registers[0] = MGMLIS3MDL::CTRL_REG1_DEFAULT; + registers[1] = MGMLIS3MDL::CTRL_REG2_DEFAULT; + registers[2] = MGMLIS3MDL::CTRL_REG3_DEFAULT; + registers[3] = MGMLIS3MDL::CTRL_REG4_DEFAULT; + registers[4] = MGMLIS3MDL::CTRL_REG5_DEFAULT; + +} + +MgmLIS3MDLHandler::~MgmLIS3MDLHandler() { +} + + +void MgmLIS3MDLHandler::doStartUp() { + switch (internalState) { + case(InternalState::STATE_NONE): { + internalState = InternalState::STATE_FIRST_CONTACT; + break; + } + case(InternalState::STATE_FIRST_CONTACT): { + /* Will be set by checking device ID (WHO AM I register) */ + if(commandExecuted) { + commandExecuted = false; + internalState = InternalState::STATE_SETUP; + } + break; + } + case(InternalState::STATE_SETUP): { + internalState = InternalState::STATE_CHECK_REGISTERS; + break; + } + case(InternalState::STATE_CHECK_REGISTERS): { + /* Set up cached registers which will be used to configure the MGM. */ + if(commandExecuted) { + commandExecuted = false; + if(goToNormalMode) { + setMode(MODE_NORMAL); + } + else { + setMode(_MODE_TO_ON); + } + } + break; + } + default: + break; + } + +} + +void MgmLIS3MDLHandler::doShutDown() { + setMode(_MODE_POWER_DOWN); +} + +ReturnValue_t MgmLIS3MDLHandler::buildTransitionDeviceCommand( + DeviceCommandId_t *id) { + switch (internalState) { + case(InternalState::STATE_NONE): + case(InternalState::STATE_NORMAL): { + return HasReturnvaluesIF::RETURN_OK; + } + case(InternalState::STATE_FIRST_CONTACT): { + *id = MGMLIS3MDL::IDENTIFY_DEVICE; + break; + } + case(InternalState::STATE_SETUP): { + *id = MGMLIS3MDL::SETUP_MGM; + break; + } + case(InternalState::STATE_CHECK_REGISTERS): { + *id = MGMLIS3MDL::READ_CONFIG_AND_DATA; + break; + } + default: { + /* might be a configuration error. */ +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "GyroHandler::buildTransitionDeviceCommand: Unknown internal state!" << + std::endl; +#else + sif::printWarning("GyroHandler::buildTransitionDeviceCommand: Unknown internal state!\n"); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ + return HasReturnvaluesIF::RETURN_OK; + } + + } + return buildCommandFromCommand(*id, NULL, 0); +} + +uint8_t MgmLIS3MDLHandler::readCommand(uint8_t command, bool continuousCom) { + command |= (1 << MGMLIS3MDL::RW_BIT); + if (continuousCom == true) { + command |= (1 << MGMLIS3MDL::MS_BIT); + } + return command; +} + +uint8_t MgmLIS3MDLHandler::writeCommand(uint8_t command, bool continuousCom) { + command &= ~(1 << MGMLIS3MDL::RW_BIT); + if (continuousCom == true) { + command |= (1 << MGMLIS3MDL::MS_BIT); + } + return command; +} + +void MgmLIS3MDLHandler::setupMgm() { + + registers[0] = MGMLIS3MDL::CTRL_REG1_DEFAULT; + registers[1] = MGMLIS3MDL::CTRL_REG2_DEFAULT; + registers[2] = MGMLIS3MDL::CTRL_REG3_DEFAULT; + registers[3] = MGMLIS3MDL::CTRL_REG4_DEFAULT; + registers[4] = MGMLIS3MDL::CTRL_REG5_DEFAULT; + + prepareCtrlRegisterWrite(); +} + +ReturnValue_t MgmLIS3MDLHandler::buildNormalDeviceCommand( + DeviceCommandId_t *id) { + // Data/config register will be read in an alternating manner. + if(communicationStep == CommunicationStep::DATA) { + *id = MGMLIS3MDL::READ_CONFIG_AND_DATA; + communicationStep = CommunicationStep::TEMPERATURE; + return buildCommandFromCommand(*id, NULL, 0); + } + else { + *id = MGMLIS3MDL::READ_TEMPERATURE; + communicationStep = CommunicationStep::DATA; + return buildCommandFromCommand(*id, NULL, 0); + } + +} + +ReturnValue_t MgmLIS3MDLHandler::buildCommandFromCommand( + DeviceCommandId_t deviceCommand, const uint8_t *commandData, + size_t commandDataLen) { + switch(deviceCommand) { + case(MGMLIS3MDL::READ_CONFIG_AND_DATA): { + std::memset(commandBuffer, 0, sizeof(commandBuffer)); + commandBuffer[0] = readCommand(MGMLIS3MDL::CTRL_REG1, true); + + rawPacket = commandBuffer; + rawPacketLen = MGMLIS3MDL::NR_OF_DATA_AND_CFG_REGISTERS + 1; + return RETURN_OK; + } + case(MGMLIS3MDL::READ_TEMPERATURE): { + std::memset(commandBuffer, 0, 3); + commandBuffer[0] = readCommand(MGMLIS3MDL::TEMP_LOWBYTE, true); + + rawPacket = commandBuffer; + rawPacketLen = 3; + return RETURN_OK; + } + case(MGMLIS3MDL::IDENTIFY_DEVICE): { + return identifyDevice(); + } + case(MGMLIS3MDL::TEMP_SENSOR_ENABLE): { + return enableTemperatureSensor(commandData, commandDataLen); + } + case(MGMLIS3MDL::SETUP_MGM): { + setupMgm(); + return HasReturnvaluesIF::RETURN_OK; + } + case(MGMLIS3MDL::ACCURACY_OP_MODE_SET): { + return setOperatingMode(commandData, commandDataLen); + } + default: + return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED; + } + return HasReturnvaluesIF::RETURN_FAILED; +} + +ReturnValue_t MgmLIS3MDLHandler::identifyDevice() { + uint32_t size = 2; + commandBuffer[0] = readCommand(MGMLIS3MDL::IDENTIFY_DEVICE_REG_ADDR); + commandBuffer[1] = 0x00; + + rawPacket = commandBuffer; + rawPacketLen = size; + + return RETURN_OK; +} + +ReturnValue_t MgmLIS3MDLHandler::scanForReply(const uint8_t *start, + size_t len, DeviceCommandId_t *foundId, size_t *foundLen) { + *foundLen = len; + if (len == MGMLIS3MDL::NR_OF_DATA_AND_CFG_REGISTERS + 1) { + *foundLen = len; + *foundId = MGMLIS3MDL::READ_CONFIG_AND_DATA; + // Check validity by checking config registers + if (start[1] != registers[0] or start[2] != registers[1] or + start[3] != registers[2] or start[4] != registers[3] or + start[5] != registers[4]) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "MGMHandlerLIS3MDL::scanForReply: Invalid registers!" << std::endl; +#else + sif::printWarning("MGMHandlerLIS3MDL::scanForReply: Invalid registers!\n"); +#endif +#endif + return DeviceHandlerIF::INVALID_DATA; + } + if(mode == _MODE_START_UP) { + commandExecuted = true; + } + + } + else if(len == MGMLIS3MDL::TEMPERATURE_REPLY_LEN) { + *foundLen = len; + *foundId = MGMLIS3MDL::READ_TEMPERATURE; + } + else if (len == MGMLIS3MDL::SETUP_REPLY_LEN) { + *foundLen = len; + *foundId = MGMLIS3MDL::SETUP_MGM; + } + else if (len == SINGLE_COMMAND_ANSWER_LEN) { + *foundLen = len; + *foundId = getPendingCommand(); + if(*foundId == MGMLIS3MDL::IDENTIFY_DEVICE) { + if(start[1] != MGMLIS3MDL::DEVICE_ID) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "MGMHandlerLIS3MDL::scanForReply: Invalid registers!" << std::endl; +#else + sif::printWarning("MGMHandlerLIS3MDL::scanForReply: Invalid registers!\n"); +#endif +#endif + return DeviceHandlerIF::INVALID_DATA; + } + + if(mode == _MODE_START_UP) { + commandExecuted = true; + } + } + } + else { + return DeviceHandlerIF::INVALID_DATA; + } + + /* Data with SPI Interface always has this answer */ + if (start[0] == 0b11111111) { + return RETURN_OK; + } + else { + return DeviceHandlerIF::INVALID_DATA; + } + +} +ReturnValue_t MgmLIS3MDLHandler::interpretDeviceReply(DeviceCommandId_t id, + const uint8_t *packet) { + + switch (id) { + case MGMLIS3MDL::IDENTIFY_DEVICE: { + break; + } + case MGMLIS3MDL::SETUP_MGM: { + break; + } + case MGMLIS3MDL::READ_CONFIG_AND_DATA: { + // TODO: Store configuration in new local datasets. + float sensitivityFactor = getSensitivityFactor(getSensitivity(registers[2])); + + int16_t mgmMeasurementRawX = packet[MGMLIS3MDL::X_HIGHBYTE_IDX] << 8 + | packet[MGMLIS3MDL::X_LOWBYTE_IDX] ; + int16_t mgmMeasurementRawY = packet[MGMLIS3MDL::Y_HIGHBYTE_IDX] << 8 + | packet[MGMLIS3MDL::Y_LOWBYTE_IDX] ; + int16_t mgmMeasurementRawZ = packet[MGMLIS3MDL::Z_HIGHBYTE_IDX] << 8 + | packet[MGMLIS3MDL::Z_LOWBYTE_IDX] ; + + /* Target value in microtesla */ + float mgmX = static_cast(mgmMeasurementRawX) * sensitivityFactor + * MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; + float mgmY = static_cast(mgmMeasurementRawY) * sensitivityFactor + * MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; + float mgmZ = static_cast(mgmMeasurementRawZ) * sensitivityFactor + * MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; + +#if FSFW_HAL_LIS3MDL_MGM_DEBUG == 1 + if(debugDivider->checkAndIncrement()) { + /* Set terminal to utf-8 if there is an issue with micro printout. */ +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "MGMHandlerLIS3: Magnetic field strength in" + " microtesla:" << std::endl; + sif::info << "X: " << mgmX << " uT" << std::endl; + sif::info << "Y: " << mgmY << " uT" << std::endl; + sif::info << "Z: " << mgmZ << " uT" << std::endl; +#else + sif::printInfo("MGMHandlerLIS3: Magnetic field strength in microtesla:\n"); + sif::printInfo("X: %f uT\n", mgmX); + sif::printInfo("Y: %f uT\n", mgmY); + sif::printInfo("Z: %f uT\n", mgmZ); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 0 */ + } +#endif /* OBSW_VERBOSE_LEVEL >= 1 */ + PoolReadGuard readHelper(&dataset); + if(readHelper.getReadResult() == HasReturnvaluesIF::RETURN_OK) { + dataset.fieldStrengthX = mgmX; + dataset.fieldStrengthY = mgmY; + dataset.fieldStrengthZ = mgmZ; + dataset.setValidity(true, true); + } + break; + } + + case MGMLIS3MDL::READ_TEMPERATURE: { + int16_t tempValueRaw = packet[2] << 8 | packet[1]; + float tempValue = 25.0 + ((static_cast(tempValueRaw)) / 8.0); + #if FSFW_HAL_LIS3MDL_MGM_DEBUG == 1 + if(debugDivider->check()) { + /* Set terminal to utf-8 if there is an issue with micro printout. */ +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "MGMHandlerLIS3: Temperature: " << tempValue << " C" << + std::endl; +#else + sif::printInfo("MGMHandlerLIS3: Temperature: %f C\n"); +#endif + } +#endif + ReturnValue_t result = dataset.read(); + if(result == HasReturnvaluesIF::RETURN_OK) { + dataset.temperature = tempValue; + dataset.commit(); + } + break; + } + + default: { + return DeviceHandlerIF::UNKNOWN_DEVICE_REPLY; + } + + } + return RETURN_OK; +} + +MGMLIS3MDL::Sensitivies MgmLIS3MDLHandler::getSensitivity(uint8_t ctrlRegister2) { + bool fs0Set = ctrlRegister2 & (1 << MGMLIS3MDL::FSO); // Checks if FS0 bit is set + bool fs1Set = ctrlRegister2 & (1 << MGMLIS3MDL::FS1); // Checks if FS1 bit is set + + if (fs0Set && fs1Set) + return MGMLIS3MDL::Sensitivies::GAUSS_16; + else if (!fs0Set && fs1Set) + return MGMLIS3MDL::Sensitivies::GAUSS_12; + else if (fs0Set && !fs1Set) + return MGMLIS3MDL::Sensitivies::GAUSS_8; + else + return MGMLIS3MDL::Sensitivies::GAUSS_4; +} + +float MgmLIS3MDLHandler::getSensitivityFactor(MGMLIS3MDL::Sensitivies sens) { + switch(sens) { + case(MGMLIS3MDL::GAUSS_4): { + return MGMLIS3MDL::FIELD_LSB_PER_GAUSS_4_SENS; + } + case(MGMLIS3MDL::GAUSS_8): { + return MGMLIS3MDL::FIELD_LSB_PER_GAUSS_8_SENS; + } + case(MGMLIS3MDL::GAUSS_12): { + return MGMLIS3MDL::FIELD_LSB_PER_GAUSS_12_SENS; + } + case(MGMLIS3MDL::GAUSS_16): { + return MGMLIS3MDL::FIELD_LSB_PER_GAUSS_16_SENS; + } + default: { + // Should never happen + return MGMLIS3MDL::FIELD_LSB_PER_GAUSS_4_SENS; + } + } +} + + +ReturnValue_t MgmLIS3MDLHandler::enableTemperatureSensor( + const uint8_t *commandData, size_t commandDataLen) { + triggerEvent(CHANGE_OF_SETUP_PARAMETER); + uint32_t size = 2; + commandBuffer[0] = writeCommand(MGMLIS3MDL::CTRL_REG1); + if (commandDataLen > 1) { + return INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS; + } + switch (*commandData) { + case (MGMLIS3MDL::ON): { + commandBuffer[1] = registers[0] | (1 << 7); + break; + } + case (MGMLIS3MDL::OFF): { + commandBuffer[1] = registers[0] & ~(1 << 7); + break; + } + default: + return INVALID_COMMAND_PARAMETER; + } + registers[0] = commandBuffer[1]; + + rawPacket = commandBuffer; + rawPacketLen = size; + + return RETURN_OK; +} + +ReturnValue_t MgmLIS3MDLHandler::setOperatingMode(const uint8_t *commandData, + size_t commandDataLen) { + triggerEvent(CHANGE_OF_SETUP_PARAMETER); + if (commandDataLen != 1) { + return INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS; + } + + switch (commandData[0]) { + case MGMLIS3MDL::LOW: + registers[0] = (registers[0] & (~(1 << MGMLIS3MDL::OM1))) & (~(1 << MGMLIS3MDL::OM0)); + registers[3] = (registers[3] & (~(1 << MGMLIS3MDL::OMZ1))) & (~(1 << MGMLIS3MDL::OMZ0)); + break; + case MGMLIS3MDL::MEDIUM: + registers[0] = (registers[0] & (~(1 << MGMLIS3MDL::OM1))) | (1 << MGMLIS3MDL::OM0); + registers[3] = (registers[3] & (~(1 << MGMLIS3MDL::OMZ1))) | (1 << MGMLIS3MDL::OMZ0); + break; + + case MGMLIS3MDL::HIGH: + registers[0] = (registers[0] | (1 << MGMLIS3MDL::OM1)) & (~(1 << MGMLIS3MDL::OM0)); + registers[3] = (registers[3] | (1 << MGMLIS3MDL::OMZ1)) & (~(1 << MGMLIS3MDL::OMZ0)); + break; + + case MGMLIS3MDL::ULTRA: + registers[0] = (registers[0] | (1 << MGMLIS3MDL::OM1)) | (1 << MGMLIS3MDL::OM0); + registers[3] = (registers[3] | (1 << MGMLIS3MDL::OMZ1)) | (1 << MGMLIS3MDL::OMZ0); + break; + default: + break; + } + + return prepareCtrlRegisterWrite(); +} + +void MgmLIS3MDLHandler::fillCommandAndReplyMap() { + /* + * Regarding ArduinoBoard: + * Actually SPI answers directly, but as commanding ArduinoBoard the + * communication could be delayed + * SPI always has to be triggered, so there could be no periodic answer of + * the device, the device has to asked with a command, so periodic is zero. + * + * We dont read single registers, we just expect special + * reply from he Readall_MGM + */ + insertInCommandAndReplyMap(MGMLIS3MDL::READ_CONFIG_AND_DATA, 1, &dataset); + insertInCommandAndReplyMap(MGMLIS3MDL::READ_TEMPERATURE, 1); + insertInCommandAndReplyMap(MGMLIS3MDL::SETUP_MGM, 1); + insertInCommandAndReplyMap(MGMLIS3MDL::IDENTIFY_DEVICE, 1); + insertInCommandAndReplyMap(MGMLIS3MDL::TEMP_SENSOR_ENABLE, 1); + insertInCommandAndReplyMap(MGMLIS3MDL::ACCURACY_OP_MODE_SET, 1); +} + +void MgmLIS3MDLHandler::setToGoToNormalMode(bool enable) { + this->goToNormalMode = enable; +} + +ReturnValue_t MgmLIS3MDLHandler::prepareCtrlRegisterWrite() { + commandBuffer[0] = writeCommand(MGMLIS3MDL::CTRL_REG1, true); + + for (size_t i = 0; i < MGMLIS3MDL::NR_OF_CTRL_REGISTERS; i++) { + commandBuffer[i + 1] = registers[i]; + } + rawPacket = commandBuffer; + rawPacketLen = MGMLIS3MDL::NR_OF_CTRL_REGISTERS + 1; + + /* We dont have to check if this is working because we just did it */ + return RETURN_OK; +} + +void MgmLIS3MDLHandler::doTransition(Mode_t modeFrom, Submode_t subModeFrom) { + +} + +uint32_t MgmLIS3MDLHandler::getTransitionDelayMs(Mode_t from, Mode_t to) { + return transitionDelay; +} + +void MgmLIS3MDLHandler::modeChanged(void) { + internalState = InternalState::STATE_NONE; +} + +ReturnValue_t MgmLIS3MDLHandler::initializeLocalDataPool( + localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { + localDataPoolMap.emplace(MGMLIS3MDL::FIELD_STRENGTH_X, + new PoolEntry({0.0})); + localDataPoolMap.emplace(MGMLIS3MDL::FIELD_STRENGTH_Y, + new PoolEntry({0.0})); + localDataPoolMap.emplace(MGMLIS3MDL::FIELD_STRENGTH_Z, + new PoolEntry({0.0})); + localDataPoolMap.emplace(MGMLIS3MDL::TEMPERATURE_CELCIUS, + new PoolEntry({0.0})); + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h new file mode 100644 index 00000000..9fb41156 --- /dev/null +++ b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h @@ -0,0 +1,167 @@ +#ifndef MISSION_DEVICES_MGMLIS3MDLHANDLER_H_ +#define MISSION_DEVICES_MGMLIS3MDLHANDLER_H_ + +#include "fsfw/FSFW.h" +#include "events/subsystemIdRanges.h" +#include "devicedefinitions/MgmLIS3HandlerDefs.h" + +#include "fsfw/devicehandlers/DeviceHandlerBase.h" + +class PeriodicOperationDivider; + +/** + * @brief Device handler object for the LIS3MDL 3-axis magnetometer + * by STMicroeletronics + * @details + * Datasheet can be found online by googling LIS3MDL. + * Flight manual: + * https://egit.irs.uni-stuttgart.de/redmine/projects/eive-flight-manual/wiki/LIS3MDL_MGM + * @author L. Loidold, R. Mueller + */ +class MgmLIS3MDLHandler: public DeviceHandlerBase { +public: + enum class CommunicationStep { + DATA, + TEMPERATURE + }; + + static const uint8_t INTERFACE_ID = CLASS_ID::MGM_LIS3MDL; + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::MGM_LIS3MDL; + //Notifies a command to change the setup parameters + static const Event CHANGE_OF_SETUP_PARAMETER = MAKE_EVENT(0, severity::LOW); + + MgmLIS3MDLHandler(uint32_t objectId, object_id_t deviceCommunication, CookieIF* comCookie, + uint8_t switchId, uint32_t transitionDelay = 10000); + virtual ~MgmLIS3MDLHandler(); + + void setToGoToNormalMode(bool enable); + +protected: + + /** DeviceHandlerBase overrides */ + void doShutDown() override; + void doStartUp() override; + void doTransition(Mode_t modeFrom, Submode_t subModeFrom) override; + uint32_t getTransitionDelayMs(Mode_t from, Mode_t to) override; + ReturnValue_t buildCommandFromCommand( + DeviceCommandId_t deviceCommand, const uint8_t *commandData, + size_t commandDataLen) override; + ReturnValue_t buildTransitionDeviceCommand( + DeviceCommandId_t *id) override; + ReturnValue_t buildNormalDeviceCommand( + DeviceCommandId_t *id) override; + ReturnValue_t scanForReply(const uint8_t *start, size_t len, + DeviceCommandId_t *foundId, size_t *foundLen) override; + ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, + const uint8_t *packet) override; + void fillCommandAndReplyMap() override; + void modeChanged(void) override; + ReturnValue_t initializeLocalDataPool(localpool::DataPool &localDataPoolMap, + LocalDataPoolManager &poolManager) override; + +private: + MGMLIS3MDL::MgmPrimaryDataset dataset; + //Length a sindgle command SPI answer + static const uint8_t SINGLE_COMMAND_ANSWER_LEN = 2; + + uint32_t transitionDelay; + //Single SPIcommand has 2 bytes, first for adress, second for content + size_t singleComandSize = 2; + //has the size for all adresses of the lis3mdl + the continous write bit + uint8_t commandBuffer[MGMLIS3MDL::NR_OF_DATA_AND_CFG_REGISTERS + 1]; + + /** + * We want to save the registers we set, so we dont have to read the + * registers when we want to change something. + * --> everytime we change set a register we have to save it + */ + uint8_t registers[MGMLIS3MDL::NR_OF_CTRL_REGISTERS]; + + uint8_t statusRegister = 0; + bool goToNormalMode = false; + + enum class InternalState { + STATE_NONE, + STATE_FIRST_CONTACT, + STATE_SETUP, + STATE_CHECK_REGISTERS, + STATE_NORMAL + }; + + InternalState internalState = InternalState::STATE_NONE; + CommunicationStep communicationStep = CommunicationStep::DATA; + bool commandExecuted = false; + + /*------------------------------------------------------------------------*/ + /* Device specific commands and variables */ + /*------------------------------------------------------------------------*/ + /** + * Sets the read bit for the command + * @param single command to set the read-bit at + * @param boolean to select a continuous read bit, default = false + */ + uint8_t readCommand(uint8_t command, bool continuousCom = false); + + /** + * Sets the write bit for the command + * @param single command to set the write-bit at + * @param boolean to select a continuous write bit, default = false + */ + uint8_t writeCommand(uint8_t command, bool continuousCom = false); + + /** + * This Method gets the full scale for the measurement range + * e.g.: +- 4 gauss. See p.25 datasheet. + * @return The ReturnValue does not contain the sign of the value + */ + MGMLIS3MDL::Sensitivies getSensitivity(uint8_t ctrlReg2); + + /** + * The 16 bit value needs to be multiplied with a sensitivity factor + * which depends on the sensitivity configuration + * + * @param sens Configured sensitivity of the LIS3 device + * @return Multiplication factor to get the sensor value from raw data. + */ + float getSensitivityFactor(MGMLIS3MDL::Sensitivies sens); + + /** + * This Command detects the device ID + */ + ReturnValue_t identifyDevice(); + + virtual void setupMgm(); + + /*------------------------------------------------------------------------*/ + /* Non normal commands */ + /*------------------------------------------------------------------------*/ + /** + * Enables/Disables the integrated Temperaturesensor + * @param commandData On or Off + * @param length of the commandData: has to be 1 + */ + virtual ReturnValue_t enableTemperatureSensor(const uint8_t *commandData, + size_t commandDataLen); + + /** + * Sets the accuracy of the measurement of the axis. The noise is changing. + * @param commandData LOW, MEDIUM, HIGH, ULTRA + * @param length of the command, has to be 1 + */ + virtual ReturnValue_t setOperatingMode(const uint8_t *commandData, + size_t commandDataLen); + + /** + * We always update all registers together, so this method updates + * the rawpacket and rawpacketLen, so we just manipulate the local + * saved register + * + */ + ReturnValue_t prepareCtrlRegisterWrite(); + +#if FSFW_HAL_LIS3MDL_MGM_DEBUG == 1 + PeriodicOperationDivider* debugDivider; +#endif +}; + +#endif /* MISSION_DEVICES_MGMLIS3MDLHANDLER_H_ */ diff --git a/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp b/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp index 60ad01b7..b483b6bf 100644 --- a/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp +++ b/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp @@ -13,7 +13,7 @@ MgmRM3100Handler::MgmRM3100Handler(object_id_t objectId, DeviceHandlerBase(objectId, deviceCommunication, comCookie), primaryDataset(this), switchId(switchId), transitionDelay(transitionDelay) { #if FSFW_HAL_RM3100_MGM_DEBUG == 1 - debugDivider = new PeriodicOperationDivider(5); + debugDivider = new PeriodicOperationDivider(1); #endif } diff --git a/hal/src/fsfw_hal/devicehandlers/devicedefinitions/MgmLIS3HandlerDefs.h b/hal/src/fsfw_hal/devicehandlers/devicedefinitions/MgmLIS3HandlerDefs.h new file mode 100644 index 00000000..b6f3fd84 --- /dev/null +++ b/hal/src/fsfw_hal/devicehandlers/devicedefinitions/MgmLIS3HandlerDefs.h @@ -0,0 +1,178 @@ +#ifndef MISSION_DEVICES_DEVICEDEFINITIONS_MGMLIS3HANDLERDEFS_H_ +#define MISSION_DEVICES_DEVICEDEFINITIONS_MGMLIS3HANDLERDEFS_H_ + +#include +#include +#include +#include + +namespace MGMLIS3MDL { + +enum Set { + ON, OFF +}; +enum OpMode { + LOW, MEDIUM, HIGH, ULTRA +}; + +enum Sensitivies: uint8_t { + GAUSS_4 = 4, + GAUSS_8 = 8, + GAUSS_12 = 12, + GAUSS_16 = 16 +}; + +/* Actually 15, we just round up a bit */ +static constexpr size_t MAX_BUFFER_SIZE = 16; + +/* Field data register scaling */ +static constexpr uint8_t GAUSS_TO_MICROTESLA_FACTOR = 100; +static constexpr float FIELD_LSB_PER_GAUSS_4_SENS = 1.0 / 6842.0; +static constexpr float FIELD_LSB_PER_GAUSS_8_SENS = 1.0 / 3421.0; +static constexpr float FIELD_LSB_PER_GAUSS_12_SENS = 1.0 / 2281.0; +static constexpr float FIELD_LSB_PER_GAUSS_16_SENS = 1.0 / 1711.0; + +static const DeviceCommandId_t READ_CONFIG_AND_DATA = 0x00; +static const DeviceCommandId_t SETUP_MGM = 0x01; +static const DeviceCommandId_t READ_TEMPERATURE = 0x02; +static const DeviceCommandId_t IDENTIFY_DEVICE = 0x03; +static const DeviceCommandId_t TEMP_SENSOR_ENABLE = 0x04; +static const DeviceCommandId_t ACCURACY_OP_MODE_SET = 0x05; + +/* Number of all control registers */ +static const uint8_t NR_OF_CTRL_REGISTERS = 5; +/* Number of registers in the MGM */ +static const uint8_t NR_OF_REGISTERS = 19; +/* Total number of adresses for all registers */ +static const uint8_t TOTAL_NR_OF_ADRESSES = 52; +static const uint8_t NR_OF_DATA_AND_CFG_REGISTERS = 14; +static const uint8_t TEMPERATURE_REPLY_LEN = 3; +static const uint8_t SETUP_REPLY_LEN = 6; + +/*------------------------------------------------------------------------*/ +/* Register adresses */ +/*------------------------------------------------------------------------*/ +/* Register adress returns identifier of device with default 0b00111101 */ +static const uint8_t IDENTIFY_DEVICE_REG_ADDR = 0b00001111; +static const uint8_t DEVICE_ID = 0b00111101; // Identifier for Device + +/* Register adress to access register 1 */ +static const uint8_t CTRL_REG1 = 0b00100000; +/* Register adress to access register 2 */ +static const uint8_t CTRL_REG2 = 0b00100001; +/* Register adress to access register 3 */ +static const uint8_t CTRL_REG3 = 0b00100010; +/* Register adress to access register 4 */ +static const uint8_t CTRL_REG4 = 0b00100011; +/* Register adress to access register 5 */ +static const uint8_t CTRL_REG5 = 0b00100100; + +/* Register adress to access status register */ +static const uint8_t STATUS_REG_IDX = 8; +static const uint8_t STATUS_REG = 0b00100111; + +/* Register adress to access low byte of x-axis */ +static const uint8_t X_LOWBYTE_IDX = 9; +static const uint8_t X_LOWBYTE = 0b00101000; +/* Register adress to access high byte of x-axis */ +static const uint8_t X_HIGHBYTE_IDX = 10; +static const uint8_t X_HIGHBYTE = 0b00101001; +/* Register adress to access low byte of y-axis */ +static const uint8_t Y_LOWBYTE_IDX = 11; +static const uint8_t Y_LOWBYTE = 0b00101010; +/* Register adress to access high byte of y-axis */ +static const uint8_t Y_HIGHBYTE_IDX = 12; +static const uint8_t Y_HIGHBYTE = 0b00101011; +/* Register adress to access low byte of z-axis */ +static const uint8_t Z_LOWBYTE_IDX = 13; +static const uint8_t Z_LOWBYTE = 0b00101100; +/* Register adress to access high byte of z-axis */ +static const uint8_t Z_HIGHBYTE_IDX = 14; +static const uint8_t Z_HIGHBYTE = 0b00101101; + +/* Register adress to access low byte of temperature sensor */ +static const uint8_t TEMP_LOWBYTE = 0b00101110; +/* Register adress to access high byte of temperature sensor */ +static const uint8_t TEMP_HIGHBYTE = 0b00101111; + +/*------------------------------------------------------------------------*/ +/* Initialize Setup Register set bits */ +/*------------------------------------------------------------------------*/ +/* General transfer bits */ +// Read=1 / Write=0 Bit +static const uint8_t RW_BIT = 7; +// Continous Read/Write Bit, increment adress +static const uint8_t MS_BIT = 6; + +/* CTRL_REG1 bits */ +static const uint8_t ST = 0; // Self test enable bit, enabled = 1 +// Enable rates higher than 80 Hz enabled = 1 +static const uint8_t FAST_ODR = 1; +static const uint8_t DO0 = 2; // Output data rate bit 2 +static const uint8_t DO1 = 3; // Output data rate bit 3 +static const uint8_t DO2 = 4; // Output data rate bit 4 +static const uint8_t OM0 = 5; // XY operating mode bit 5 +static const uint8_t OM1 = 6; // XY operating mode bit 6 +static const uint8_t TEMP_EN = 7; // Temperature sensor enable enabled = 1 +static const uint8_t CTRL_REG1_DEFAULT = (1 << TEMP_EN) | (1 << OM1) | + (1 << DO0) | (1 << DO1) | (1 << DO2); + +/* CTRL_REG2 bits */ +//reset configuration registers and user registers +static const uint8_t SOFT_RST = 2; +static const uint8_t REBOOT = 3; //reboot memory content +static const uint8_t FSO = 5; //full-scale selection bit 5 +static const uint8_t FS1 = 6; //full-scale selection bit 6 +static const uint8_t CTRL_REG2_DEFAULT = 0; + +/* CTRL_REG3 bits */ +static const uint8_t MD0 = 0; //Operating mode bit 0 +static const uint8_t MD1 = 1; //Operating mode bit 1 +//SPI serial interface mode selection enabled = 3-wire-mode +static const uint8_t SIM = 2; +static const uint8_t LP = 5; //low-power mode +static const uint8_t CTRL_REG3_DEFAULT = 0; + +/* CTRL_REG4 bits */ +//big/little endian data selection enabled = MSb at lower adress +static const uint8_t BLE = 1; +static const uint8_t OMZ0 = 2; //Z operating mode bit 2 +static const uint8_t OMZ1 = 3; //Z operating mode bit 3 +static const uint8_t CTRL_REG4_DEFAULT = (1 << OMZ1); + +/* CTRL_REG5 bits */ +static const uint8_t BDU = 6; //Block data update +static const uint8_t FAST_READ = 7; //Fast read enabled = 1 +static const uint8_t CTRL_REG5_DEFAULT = 0; + +static const uint32_t MGM_DATA_SET_ID = READ_CONFIG_AND_DATA; + +enum MgmPoolIds: lp_id_t { + FIELD_STRENGTH_X, + FIELD_STRENGTH_Y, + FIELD_STRENGTH_Z, + TEMPERATURE_CELCIUS +}; + +class MgmPrimaryDataset: public StaticLocalDataSet<5> { +public: + MgmPrimaryDataset(HasLocalDataPoolIF* hkOwner): + StaticLocalDataSet(hkOwner, MGM_DATA_SET_ID) {} + + MgmPrimaryDataset(object_id_t mgmId): + StaticLocalDataSet(sid_t(mgmId, MGM_DATA_SET_ID)) {} + + lp_var_t fieldStrengthX = lp_var_t(sid.objectId, + FIELD_STRENGTH_X, this); + lp_var_t fieldStrengthY = lp_var_t(sid.objectId, + FIELD_STRENGTH_Y, this); + lp_var_t fieldStrengthZ = lp_var_t(sid.objectId, + FIELD_STRENGTH_Z, this); + lp_var_t temperature = lp_var_t(sid.objectId, + TEMPERATURE_CELCIUS, this); +}; + +} + + +#endif /* MISSION_DEVICES_DEVICEDEFINITIONS_MGMLIS3HANDLERDEFS_H_ */ diff --git a/src/fsfw/FSFW.h.in b/src/fsfw/FSFW.h.in index e6dd2f8f..3f005387 100644 --- a/src/fsfw/FSFW.h.in +++ b/src/fsfw/FSFW.h.in @@ -33,4 +33,8 @@ #define FSFW_HAL_RM3100_MGM_DEBUG 0 #endif /* FSFW_HAL_RM3100_MGM_DEBUG */ +#ifndef FSFW_HAL_LIS3MDL_MGM_DEBUG +#define FSFW_HAL_LIS3MDL_MGM_DEBUG 0 +#endif /* FSFW_HAL_LIS3MDL_MGM_DEBUG */ + #endif /* FSFW_FSFW_H_ */ diff --git a/src/fsfw/globalfunctions/PeriodicOperationDivider.cpp b/src/fsfw/globalfunctions/PeriodicOperationDivider.cpp index 62cc6f4c..d3b03c2b 100644 --- a/src/fsfw/globalfunctions/PeriodicOperationDivider.cpp +++ b/src/fsfw/globalfunctions/PeriodicOperationDivider.cpp @@ -2,43 +2,44 @@ PeriodicOperationDivider::PeriodicOperationDivider(uint32_t divider, - bool resetAutomatically): resetAutomatically(resetAutomatically), - counter(divider), divider(divider) { + bool resetAutomatically): resetAutomatically(resetAutomatically), + counter(divider), divider(divider) { } bool PeriodicOperationDivider::checkAndIncrement() { - bool opNecessary = check(); - if(opNecessary) { - if(resetAutomatically) { - counter = 0; - } - return opNecessary; - } - counter ++; - return opNecessary; + counter++; + bool opNecessary = check(); + if(opNecessary) { + if(resetAutomatically) { + counter = 0; + } + return opNecessary; + } + + return opNecessary; } bool PeriodicOperationDivider::check() { - if(counter >= divider) { - return true; - } - return false; + if(counter >= divider) { + return true; + } + return false; } void PeriodicOperationDivider::resetCounter() { - counter = 0; + counter = 0; } void PeriodicOperationDivider::setDivider(uint32_t newDivider) { - divider = newDivider; + divider = newDivider; } uint32_t PeriodicOperationDivider::getCounter() const { - return counter; + return counter; } uint32_t PeriodicOperationDivider::getDivider() const { - return divider; + return divider; } diff --git a/src/fsfw/globalfunctions/PeriodicOperationDivider.h b/src/fsfw/globalfunctions/PeriodicOperationDivider.h index 7f7fb469..bfc81eea 100644 --- a/src/fsfw/globalfunctions/PeriodicOperationDivider.h +++ b/src/fsfw/globalfunctions/PeriodicOperationDivider.h @@ -13,51 +13,51 @@ */ class PeriodicOperationDivider { public: - /** - * Initialize with the desired divider and specify whether the internal - * counter will be reset automatically. - * @param divider - * @param resetAutomatically - */ - PeriodicOperationDivider(uint32_t divider, bool resetAutomatically = true); + /** + * Initialize with the desired divider and specify whether the internal + * counter will be reset automatically. + * @param divider + * @param resetAutomatically + */ + PeriodicOperationDivider(uint32_t divider, bool resetAutomatically = true); - /** - * Check whether operation is necessary. - * If an operation is necessary and the class has been - * configured to be reset automatically, the counter will be reset. - * - * @return - * -@c true if the counter is larger or equal to the divider - * -@c false otherwise - */ - bool checkAndIncrement(); + /** + * Check whether operation is necessary. + * If an operation is necessary and the class has been + * configured to be reset automatically, the counter will be reset. + * + * @return + * -@c true if the counter is larger or equal to the divider + * -@c false otherwise + */ + bool checkAndIncrement(); - /** - * Checks whether an operation is necessary. - * This function will not increment the counter! - * @return - * -@c true if the counter is larger or equal to the divider - * -@c false otherwise - */ - bool check(); + /** + * Checks whether an operation is necessary. + * This function will not increment the counter! + * @return + * -@c true if the counter is larger or equal to the divider + * -@c false otherwise + */ + bool check(); - /** - * Can be used to reset the counter to 0 manually. - */ - void resetCounter(); - uint32_t getCounter() const; + /** + * Can be used to reset the counter to 0 manually. + */ + void resetCounter(); + uint32_t getCounter() const; - /** - * Can be used to set a new divider value. - * @param newDivider - */ - void setDivider(uint32_t newDivider); - uint32_t getDivider() const; + /** + * Can be used to set a new divider value. + * @param newDivider + */ + void setDivider(uint32_t newDivider); + uint32_t getDivider() const; private: - bool resetAutomatically = true; - uint32_t counter = 0; - uint32_t divider = 0; + bool resetAutomatically = true; + uint32_t counter = 0; + uint32_t divider = 0; }; From 7d44aab98e6861bc7999541e97085ba5a62b6633 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 17 Sep 2021 13:07:43 +0200 Subject: [PATCH 043/131] some tweaks for op divider --- src/fsfw/globalfunctions/PeriodicOperationDivider.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/fsfw/globalfunctions/PeriodicOperationDivider.cpp b/src/fsfw/globalfunctions/PeriodicOperationDivider.cpp index d3b03c2b..92f7e792 100644 --- a/src/fsfw/globalfunctions/PeriodicOperationDivider.cpp +++ b/src/fsfw/globalfunctions/PeriodicOperationDivider.cpp @@ -7,15 +7,13 @@ PeriodicOperationDivider::PeriodicOperationDivider(uint32_t divider, } bool PeriodicOperationDivider::checkAndIncrement() { - counter++; bool opNecessary = check(); if(opNecessary) { if(resetAutomatically) { - counter = 0; + counter = 1; } - return opNecessary; } - + counter++; return opNecessary; } From e8050183f4f54452caceba67a9d4da50bd230770 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 17 Sep 2021 16:52:31 +0200 Subject: [PATCH 044/131] better printout --- hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp index c023dbda..63dabfc9 100644 --- a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp +++ b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp @@ -232,9 +232,11 @@ ReturnValue_t MgmLIS3MDLHandler::scanForReply(const uint8_t *start, if(start[1] != MGMLIS3MDL::DEVICE_ID) { #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "MGMHandlerLIS3MDL::scanForReply: Invalid registers!" << std::endl; + sif::warning << "MGMHandlerLIS3MDL::scanForReply: " + "Device identification failed!" << std::endl; #else - sif::printWarning("MGMHandlerLIS3MDL::scanForReply: Invalid registers!\n"); + sif::printWarning("MGMHandlerLIS3MDL::scanForReply: " + "Device identification failed!\n"); #endif #endif return DeviceHandlerIF::INVALID_DATA; From 635432d7ba68faf5a2cdfd0721ed3a70fdf67b37 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 20 Sep 2021 18:29:57 +0200 Subject: [PATCH 045/131] missing return --- src/fsfw/globalfunctions/PeriodicOperationDivider.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/fsfw/globalfunctions/PeriodicOperationDivider.cpp b/src/fsfw/globalfunctions/PeriodicOperationDivider.cpp index 92f7e792..5d9e1624 100644 --- a/src/fsfw/globalfunctions/PeriodicOperationDivider.cpp +++ b/src/fsfw/globalfunctions/PeriodicOperationDivider.cpp @@ -12,6 +12,7 @@ bool PeriodicOperationDivider::checkAndIncrement() { if(resetAutomatically) { counter = 1; } + return opNecessary; } counter++; return opNecessary; From 784a0140f4fb510a2ba92a7d2e1b750272d45265 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 20 Sep 2021 18:31:52 +0200 Subject: [PATCH 046/131] tweak op divider divisor --- hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp b/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp index b483b6bf..467141de 100644 --- a/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp +++ b/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp @@ -13,7 +13,7 @@ MgmRM3100Handler::MgmRM3100Handler(object_id_t objectId, DeviceHandlerBase(objectId, deviceCommunication, comCookie), primaryDataset(this), switchId(switchId), transitionDelay(transitionDelay) { #if FSFW_HAL_RM3100_MGM_DEBUG == 1 - debugDivider = new PeriodicOperationDivider(1); + debugDivider = new PeriodicOperationDivider(3); #endif } From 70a3749dbe2cf7d23c685b0e3b3ce350a7c9db05 Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Mon, 20 Sep 2021 18:38:18 +0200 Subject: [PATCH 047/131] added option to open gpio by label instead of gpiochip* --- .../fsfw_hal/common/gpio/gpioDefinitions.h | 14 ++++++++- .../fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp | 29 +++++++++++++++---- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h b/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h index 710b2e2c..f3bafc42 100644 --- a/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h +++ b/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h @@ -85,7 +85,19 @@ public: GpioBase(gpio::GpioTypes::GPIO_REGULAR, consumer_, gpio::Direction::IN, 0), chipname(chipname_), lineNum(lineNum_) { } - std::string chipname; + + GpiodRegular(std::string consumer_, gpio::Direction direction_, int initValue_, + std::string label_, int lineNum_) : + GpioBase(gpio::GpioTypes::GPIO_REGULAR, consumer_, direction_, initValue_), label( + label_), lineNum(lineNum_) { + } + + GpiodRegular(std::string consumer_, std::string label_, int lineNum_) : + GpioBase(gpio::GpioTypes::GPIO_REGULAR, consumer_, gpio::Direction::IN, 0), label( + label_), lineNum(lineNum_) { + } + std::string chipname = "NONE"; + std::string label = "NONE"; int lineNum = 0; struct gpiod_line* lineHandle = nullptr; }; diff --git a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp index eef61e58..4ee0749b 100644 --- a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp +++ b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp @@ -20,7 +20,7 @@ LinuxLibgpioIF::~LinuxLibgpioIF() { ReturnValue_t LinuxLibgpioIF::addGpios(GpioCookie* gpioCookie) { ReturnValue_t result; if(gpioCookie == nullptr) { - sif::error << "LinuxLibgpioIF::initialize: Invalid cookie" << std::endl; + sif::error << "LinuxLibgpioIF::addGpios: Invalid cookie" << std::endl; return RETURN_FAILED; } @@ -72,6 +72,7 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) { ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, GpiodRegular *regularGpio) { std::string chipname; + std::string label; unsigned int lineNum; struct gpiod_chip *chip; gpio::Direction direction; @@ -80,11 +81,27 @@ ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, GpiodRegular int result = 0; chipname = regularGpio->chipname; - chip = gpiod_chip_open_by_name(chipname.c_str()); - if (!chip) { - sif::warning << "LinuxLibgpioIF::configureRegularGpio: Failed to open chip " - << chipname << ". Gpio ID: " << gpioId << std::endl; - return RETURN_FAILED; + + if (chipname != "NONE") { + chip = gpiod_chip_open_by_name(chipname.c_str()); + if (!chip) { + sif::warning << "LinuxLibgpioIF::configureRegularGpio: Failed to open chip " + << chipname << ". Gpio ID: " << gpioId << std::endl; + return RETURN_FAILED; + } + } + else if (label != "NONE") { + label = regularGpio->label; + chip = gpiod_chip_open_by_label(label.c_str()); + if (!chip) { + sif::warning << "LinuxLibgpioIF::configureRegularGpio: Failed to open gpio from gpio " + << "group with label " << label << ". Gpio ID: " << gpioId << std::endl; + return RETURN_FAILED; + } + } + else { + sif::warning << "LinuxLibgpioIF::configureRegularGpio: No gpio group specified" + << std::endl; } lineNum = regularGpio->lineNum; From 8e65d2d3fcbccc9cfda4803f9cf6461981266356 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 21 Sep 2021 17:31:03 +0200 Subject: [PATCH 048/131] refactored GPIO components --- .../fsfw_hal/common/gpio/gpioDefinitions.h | 76 ++++++---- .../fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp | 142 ++++++++++-------- hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h | 11 +- 3 files changed, 137 insertions(+), 92 deletions(-) diff --git a/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h b/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h index f3bafc42..688d9c9b 100644 --- a/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h +++ b/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h @@ -26,7 +26,8 @@ enum GpioOperation { enum GpioTypes { NONE, - GPIO_REGULAR, + GPIO_REGULAR_BY_CHIP, + GPIO_REGULAR_BY_LABEL, CALLBACK }; @@ -68,40 +69,57 @@ public: int initValue = 0; }; -class GpiodRegular: public GpioBase { +class GpiodRegularBase: public GpioBase { public: - GpiodRegular() : - GpioBase(gpio::GpioTypes::GPIO_REGULAR, std::string(), gpio::Direction::IN, 0) { + GpiodRegularBase(gpio::GpioTypes gpioType, std::string consumer, gpio::Direction direction, + int initValue, int lineNum): GpioBase(gpioType, consumer, direction, initValue), + lineNum(lineNum) { } - ; - - GpiodRegular(std::string chipname_, int lineNum_, std::string consumer_, - gpio::Direction direction_, int initValue_) : - GpioBase(gpio::GpioTypes::GPIO_REGULAR, consumer_, direction_, initValue_), - chipname(chipname_), lineNum(lineNum_) { - } - - GpiodRegular(std::string chipname_, int lineNum_, std::string consumer_) : - GpioBase(gpio::GpioTypes::GPIO_REGULAR, consumer_, gpio::Direction::IN, 0), - chipname(chipname_), lineNum(lineNum_) { - } - - GpiodRegular(std::string consumer_, gpio::Direction direction_, int initValue_, - std::string label_, int lineNum_) : - GpioBase(gpio::GpioTypes::GPIO_REGULAR, consumer_, direction_, initValue_), label( - label_), lineNum(lineNum_) { - } - - GpiodRegular(std::string consumer_, std::string label_, int lineNum_) : - GpioBase(gpio::GpioTypes::GPIO_REGULAR, consumer_, gpio::Direction::IN, 0), label( - label_), lineNum(lineNum_) { - } - std::string chipname = "NONE"; - std::string label = "NONE"; int lineNum = 0; struct gpiod_line* lineHandle = nullptr; }; +class GpiodRegularByChip: public GpiodRegularBase { +public: + GpiodRegularByChip() : + GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP, + std::string(), gpio::Direction::IN, gpio::LOW, 0) { + } + + GpiodRegularByChip(std::string chipname_, int lineNum_, std::string consumer_, + gpio::Direction direction_, int initValue_) : + GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP, + consumer_, direction_, initValue_, lineNum_), + chipname(chipname_){ + } + + GpiodRegularByChip(std::string chipname_, int lineNum_, std::string consumer_) : + GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP, consumer_, + gpio::Direction::IN, gpio::LOW, lineNum_), + chipname(chipname_) { + } + + std::string chipname; +}; + +class GpiodRegularByLabel: public GpiodRegularBase { +public: + GpiodRegularByLabel(std::string label_, int lineNum_, std::string consumer_, + gpio::Direction direction_, int initValue_) : + GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL, consumer_, + direction_, initValue_, lineNum_), + label(label_) { + } + + GpiodRegularByLabel(std::string label_, int lineNum_, std::string consumer_) : + GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL, consumer_, + gpio::Direction::IN, gpio::LOW, lineNum_), + label(label_) { + } + + std::string label; +}; + class GpioCallback: public GpioBase { public: GpioCallback(std::string consumer, gpio::Direction direction_, int initValue_, diff --git a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp index 4ee0749b..bcc48e58 100644 --- a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp +++ b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp @@ -45,16 +45,25 @@ ReturnValue_t LinuxLibgpioIF::addGpios(GpioCookie* gpioCookie) { ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) { for(auto& gpioConfig: mapToAdd) { - switch(gpioConfig.second->gpioType) { + auto& gpioType = gpioConfig.second->gpioType; + switch(gpioType) { case(gpio::GpioTypes::NONE): { return GPIO_INVALID_INSTANCE; } - case(gpio::GpioTypes::GPIO_REGULAR): { - GpiodRegular* regularGpio = dynamic_cast(gpioConfig.second); + case(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP): { + auto regularGpio = dynamic_cast(gpioConfig.second); if(regularGpio == nullptr) { return GPIO_INVALID_INSTANCE; } - configureRegularGpio(gpioConfig.first, regularGpio); + configureGpioByChip(gpioConfig.first, *regularGpio); + break; + } + case(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL):{ + auto regularGpio = dynamic_cast(gpioConfig.second); + if(regularGpio == nullptr) { + return GPIO_INVALID_INSTANCE; + } + configureGpioByLabel(gpioConfig.first, *regularGpio); break; } case(gpio::GpioTypes::CALLBACK): { @@ -70,58 +79,59 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) { return RETURN_OK; } -ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, GpiodRegular *regularGpio) { - std::string chipname; - std::string label; +ReturnValue_t LinuxLibgpioIF::configureGpioByLabel(gpioId_t gpioId, + GpiodRegularByLabel &gpioByLabel) { + std::string& label = gpioByLabel.label; + struct gpiod_chip* chip = gpiod_chip_open_by_label(label.c_str()); + if (chip == nullptr) { + sif::warning << "LinuxLibgpioIF::configureRegularGpio: Failed to open gpio from gpio " + << "group with label " << label << ". Gpio ID: " << gpioId << std::endl; + return RETURN_FAILED; + + } + std::string failOutput = "label: " + label; + return configureRegularGpio(gpioId, gpioByLabel.gpioType, chip, gpioByLabel, failOutput); +} + +ReturnValue_t LinuxLibgpioIF::configureGpioByChip(gpioId_t gpioId, + GpiodRegularByChip &gpioByChip) { + std::string& chipname = gpioByChip.chipname; + struct gpiod_chip* chip = gpiod_chip_open_by_name(chipname.c_str()); + if (chip == nullptr) { + sif::warning << "LinuxLibgpioIF::configureRegularGpio: Failed to open chip " + << chipname << ". Gpio ID: " << gpioId << std::endl; + return RETURN_FAILED; + } + std::string failOutput = "chipname: " + chipname; + return configureRegularGpio(gpioId, gpioByChip.gpioType, chip, gpioByChip, failOutput); +} + +ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, gpio::GpioTypes gpioType, + struct gpiod_chip* chip, GpiodRegularBase& regularGpio, std::string failOutput) { unsigned int lineNum; - struct gpiod_chip *chip; gpio::Direction direction; std::string consumer; struct gpiod_line *lineHandle; int result = 0; - chipname = regularGpio->chipname; - - if (chipname != "NONE") { - chip = gpiod_chip_open_by_name(chipname.c_str()); - if (!chip) { - sif::warning << "LinuxLibgpioIF::configureRegularGpio: Failed to open chip " - << chipname << ". Gpio ID: " << gpioId << std::endl; - return RETURN_FAILED; - } - } - else if (label != "NONE") { - label = regularGpio->label; - chip = gpiod_chip_open_by_label(label.c_str()); - if (!chip) { - sif::warning << "LinuxLibgpioIF::configureRegularGpio: Failed to open gpio from gpio " - << "group with label " << label << ". Gpio ID: " << gpioId << std::endl; - return RETURN_FAILED; - } - } - else { - sif::warning << "LinuxLibgpioIF::configureRegularGpio: No gpio group specified" - << std::endl; - } - - lineNum = regularGpio->lineNum; + lineNum = regularGpio.lineNum; lineHandle = gpiod_chip_get_line(chip, lineNum); if (!lineHandle) { - sif::debug << "LinuxLibgpioIF::configureRegularGpio: Failed to open line " << std::endl; - sif::debug << "GPIO ID: " << gpioId << ", line number: " << lineNum << - ", chipname: " << chipname << std::endl; - sif::debug << "Check if linux GPIO configuration has changed. " << std::endl; + sif::warning << "LinuxLibgpioIF::configureRegularGpio: Failed to open line " << std::endl; + sif::warning << "GPIO ID: " << gpioId << ", line number: " << lineNum << + ", " << failOutput << std::endl; + sif::warning << "Check if Linux GPIO configuration has changed. " << std::endl; gpiod_chip_close(chip); return RETURN_FAILED; } - direction = regularGpio->direction; - consumer = regularGpio->consumer; + direction = regularGpio.direction; + consumer = regularGpio.consumer; /* Configure direction and add a description to the GPIO */ switch (direction) { case(gpio::OUT): { result = gpiod_line_request_output(lineHandle, consumer.c_str(), - regularGpio->initValue); + regularGpio.initValue); if (result < 0) { sif::error << "LinuxLibgpioIF::configureRegularGpio: Failed to request line " << lineNum << " from GPIO instance with ID: " << gpioId << std::endl; @@ -151,7 +161,7 @@ ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, GpiodRegular * Write line handle to GPIO configuration instance so it can later be used to set or * read states of GPIOs. */ - regularGpio->lineHandle = lineHandle; + regularGpio.lineHandle = lineHandle; return RETURN_OK; } @@ -162,8 +172,14 @@ ReturnValue_t LinuxLibgpioIF::pullHigh(gpioId_t gpioId) { return UNKNOWN_GPIO_ID; } - if(gpioMapIter->second->gpioType == gpio::GpioTypes::GPIO_REGULAR) { - return driveGpio(gpioId, dynamic_cast(gpioMapIter->second), 1); + auto gpioType = gpioMapIter->second->gpioType; + if(gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_CHIP or + gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LABEL) { + auto regularGpio = dynamic_cast(gpioMapIter->second); + if(regularGpio == nullptr) { + return GPIO_TYPE_FAILURE; + } + return driveGpio(gpioId, *regularGpio, gpio::HIGH); } else { auto gpioCallback = dynamic_cast(gpioMapIter->second); @@ -184,8 +200,14 @@ ReturnValue_t LinuxLibgpioIF::pullLow(gpioId_t gpioId) { return UNKNOWN_GPIO_ID; } - if(gpioMapIter->second->gpioType == gpio::GpioTypes::GPIO_REGULAR) { - return driveGpio(gpioId, dynamic_cast(gpioMapIter->second), 0); + auto gpioType = gpioMapIter->second->gpioType; + if(gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_CHIP or + gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LABEL) { + auto regularGpio = dynamic_cast(gpioMapIter->second); + if(regularGpio == nullptr) { + return GPIO_TYPE_FAILURE; + } + return driveGpio(gpioId, *regularGpio, gpio::LOW); } else { auto gpioCallback = dynamic_cast(gpioMapIter->second); @@ -200,12 +222,8 @@ ReturnValue_t LinuxLibgpioIF::pullLow(gpioId_t gpioId) { } ReturnValue_t LinuxLibgpioIF::driveGpio(gpioId_t gpioId, - GpiodRegular* regularGpio, unsigned int logicLevel) { - if(regularGpio == nullptr) { - return GPIO_TYPE_FAILURE; - } - - int result = gpiod_line_set_value(regularGpio->lineHandle, logicLevel); + GpiodRegularBase& regularGpio, gpio::Levels logicLevel) { + int result = gpiod_line_set_value(regularGpio.lineHandle, logicLevel); if (result < 0) { sif::warning << "LinuxLibgpioIF::driveGpio: Failed to pull GPIO with ID " << gpioId << " to logic level " << logicLevel << std::endl; @@ -221,9 +239,10 @@ ReturnValue_t LinuxLibgpioIF::readGpio(gpioId_t gpioId, int* gpioState) { sif::warning << "LinuxLibgpioIF::readGpio: Unknown GPIOD ID " << gpioId << std::endl; return UNKNOWN_GPIO_ID; } - - if(gpioMapIter->second->gpioType == gpio::GpioTypes::GPIO_REGULAR) { - GpiodRegular* regularGpio = dynamic_cast(gpioMapIter->second); + auto gpioType = gpioMapIter->second->gpioType; + if(gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_CHIP or + gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LABEL) { + auto regularGpio = dynamic_cast(gpioMapIter->second); if(regularGpio == nullptr) { return GPIO_TYPE_FAILURE; } @@ -242,13 +261,14 @@ ReturnValue_t LinuxLibgpioIF::checkForConflicts(GpioMap& mapToAdd){ ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; for(auto& gpioConfig: mapToAdd) { switch(gpioConfig.second->gpioType) { - case(gpio::GpioTypes::GPIO_REGULAR): { - auto regularGpio = dynamic_cast(gpioConfig.second); + case(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP): + case(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL): { + auto regularGpio = dynamic_cast(gpioConfig.second); if(regularGpio == nullptr) { return GPIO_TYPE_FAILURE; } /* Check for conflicts and remove duplicates if necessary */ - result = checkForConflictsRegularGpio(gpioConfig.first, regularGpio, mapToAdd); + result = checkForConflictsRegularGpio(gpioConfig.first, *regularGpio, mapToAdd); if(result != HasReturnvaluesIF::RETURN_OK) { status = result; } @@ -276,17 +296,19 @@ ReturnValue_t LinuxLibgpioIF::checkForConflicts(GpioMap& mapToAdd){ ReturnValue_t LinuxLibgpioIF::checkForConflictsRegularGpio(gpioId_t gpioIdToCheck, - GpiodRegular* gpioToCheck, GpioMap& mapToAdd) { + GpiodRegularBase& gpioToCheck, GpioMap& mapToAdd) { /* Cross check with private map */ gpioMapIter = gpioMap.find(gpioIdToCheck); if(gpioMapIter != gpioMap.end()) { - if(gpioMapIter->second->gpioType != gpio::GpioTypes::GPIO_REGULAR) { + auto& gpioType = gpioMapIter->second->gpioType; + if(gpioType != gpio::GpioTypes::GPIO_REGULAR_BY_CHIP and + gpioType != gpio::GpioTypes::GPIO_REGULAR_BY_LABEL) { sif::warning << "LinuxLibgpioIF::checkForConflicts: ID already exists for different " "GPIO type" << gpioIdToCheck << ". Removing duplicate." << std::endl; mapToAdd.erase(gpioIdToCheck); return HasReturnvaluesIF::RETURN_OK; } - auto ownRegularGpio = dynamic_cast(gpioMapIter->second); + auto ownRegularGpio = dynamic_cast(gpioMapIter->second); if(ownRegularGpio == nullptr) { return GPIO_TYPE_FAILURE; } diff --git a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h index 00e1bdfe..31e4a7e8 100644 --- a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h +++ b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h @@ -6,6 +6,7 @@ #include class GpioCookie; +class GpiodRegularIF; /** * @brief This class implements the GpioIF for a linux based system. The @@ -47,9 +48,13 @@ private: * @param gpioId The GPIO ID of the GPIO to drive. * @param logiclevel The logic level to set. O or 1. */ - ReturnValue_t driveGpio(gpioId_t gpioId, GpiodRegular* regularGpio, unsigned int logiclevel); + ReturnValue_t driveGpio(gpioId_t gpioId, GpiodRegularBase& regularGpio, + gpio::Levels logicLevel); - ReturnValue_t configureRegularGpio(gpioId_t gpioId, GpiodRegular* regularGpio); + ReturnValue_t configureGpioByLabel(gpioId_t gpioId, GpiodRegularByLabel& gpioByLabel); + ReturnValue_t configureGpioByChip(gpioId_t gpioId, GpiodRegularByChip& gpioByChip); + ReturnValue_t configureRegularGpio(gpioId_t gpioId, gpio::GpioTypes gpioType, + struct gpiod_chip* chip, GpiodRegularBase& regularGpio, std::string failOutput); /** * @brief This function checks if GPIOs are already registered and whether @@ -62,7 +67,7 @@ private: */ ReturnValue_t checkForConflicts(GpioMap& mapToAdd); - ReturnValue_t checkForConflictsRegularGpio(gpioId_t gpiodId, GpiodRegular* regularGpio, + ReturnValue_t checkForConflictsRegularGpio(gpioId_t gpiodId, GpiodRegularBase& regularGpio, GpioMap& mapToAdd); ReturnValue_t checkForConflictsCallbackGpio(gpioId_t gpiodId, GpioCallback* regularGpio, GpioMap& mapToAdd); From 3d1be94e120b76f7d1c86ff8f2a82e596f13c165 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 21 Sep 2021 19:27:33 +0200 Subject: [PATCH 049/131] more checks and printouts --- hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp | 2 +- hal/src/fsfw_hal/linux/spi/SpiComIF.cpp | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp index bcc48e58..15c3d118 100644 --- a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp +++ b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp @@ -200,7 +200,7 @@ ReturnValue_t LinuxLibgpioIF::pullLow(gpioId_t gpioId) { return UNKNOWN_GPIO_ID; } - auto gpioType = gpioMapIter->second->gpioType; + auto& gpioType = gpioMapIter->second->gpioType; if(gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_CHIP or gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LABEL) { auto regularGpio = dynamic_cast(gpioMapIter->second); diff --git a/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp b/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp index 6cf6675f..ec55f863 100644 --- a/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp +++ b/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp @@ -197,12 +197,26 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie *spiCookie, const if(gpioId != gpio::NO_GPIO) { result = spiMutex->lockMutex(timeoutType, timeoutMs); if (result != RETURN_OK) { +#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "SpiComIF::sendMessage: Failed to lock mutex" << std::endl; +#else + sif::printError("SpiComIF::sendMessage: Failed to lock mutex\n"); +#endif +#endif + return result; + } + ReturnValue_t result = gpioComIF->pullLow(gpioId); + if(result != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "SpiComIF::sendMessage: Pulling low CS pin failed" << std::endl; +#else + sif::printWarning("SpiComIF::sendMessage: Pulling low CS pin failed"); +#endif #endif return result; } - gpioComIF->pullLow(gpioId); } /* Execute transfer */ From 5c56eda61077e3aef00d32133c5546987b476e8c Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 22 Sep 2021 12:19:30 +0200 Subject: [PATCH 050/131] fix for raspberry pi code --- hal/src/fsfw_hal/linux/rpi/GpioRPi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/src/fsfw_hal/linux/rpi/GpioRPi.cpp b/hal/src/fsfw_hal/linux/rpi/GpioRPi.cpp index 6a71f291..e1c274c0 100644 --- a/hal/src/fsfw_hal/linux/rpi/GpioRPi.cpp +++ b/hal/src/fsfw_hal/linux/rpi/GpioRPi.cpp @@ -12,7 +12,7 @@ ReturnValue_t gpio::createRpiGpioConfig(GpioCookie* cookie, gpioId_t gpioId, int return HasReturnvaluesIF::RETURN_FAILED; } - GpiodRegular* config = new GpiodRegular(); + auto config = new GpiodRegularByChip(); /* Default chipname for Raspberry Pi. There is still gpiochip1 for expansion, but most users will not need this */ config->chipname = "gpiochip0"; From d3b83f3cf9d702f76ddc5a00ac715dc3a9ef5343 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 22 Sep 2021 15:02:34 +0200 Subject: [PATCH 051/131] API made more consistent --- hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp | 2 +- hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp index 4a492e5d..5b58bb46 100644 --- a/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp +++ b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp @@ -234,7 +234,7 @@ uint32_t GyroHandlerL3GD20H::getTransitionDelayMs(Mode_t from, Mode_t to) { return this->transitionDelayMs; } -void GyroHandlerL3GD20H::setGoNormalModeAtStartup() { +void GyroHandlerL3GD20H::setToGoToNormalMode(bool enable) { this->goNormalModeImmediately = true; } diff --git a/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h index bc1d9c1c..07d9835f 100644 --- a/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h +++ b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h @@ -25,7 +25,7 @@ public: /** * @brief Configure device handler to go to normal mode immediately */ - void setGoNormalModeAtStartup(); + void setToGoToNormalMode(bool enable); protected: /* DeviceHandlerBase overrides */ From c51d2df43dca317175a9448e662f7f469e5f8725 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 22 Sep 2021 16:00:18 +0200 Subject: [PATCH 052/131] printout fix --- hal/src/fsfw_hal/linux/spi/SpiComIF.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp b/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp index ec55f863..e940cf32 100644 --- a/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp +++ b/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp @@ -141,8 +141,8 @@ ReturnValue_t SpiComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, s if(sendLen > spiCookie->getMaxBufferSize()) { #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "SpiComIF::sendMessage: Too much data sent, send length" << sendLen << - "larger than maximum buffer length" << spiCookie->getMaxBufferSize() << std::endl; + sif::warning << "SpiComIF::sendMessage: Too much data sent, send length " << sendLen << + "larger than maximum buffer length " << spiCookie->getMaxBufferSize() << std::endl; #else sif::printWarning("SpiComIF::sendMessage: Too much data sent, send length %lu larger " "than maximum buffer length %lu!\n", static_cast(sendLen), From 29c74283f117bb68186d1161896d82e3361680c2 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 22 Sep 2021 18:36:53 +0200 Subject: [PATCH 053/131] sanity checks --- .../devicehandlers/GyroL3GD20Handler.cpp | 29 ++++++++++++++++--- .../devicehandlers/GyroL3GD20Handler.h | 9 +++++- .../devicehandlers/MgmLIS3MDLHandler.cpp | 27 ++++++++++++++--- .../devicehandlers/MgmLIS3MDLHandler.h | 9 +++++- 4 files changed, 64 insertions(+), 10 deletions(-) diff --git a/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp index 5b58bb46..06b4548b 100644 --- a/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp +++ b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp @@ -215,11 +215,32 @@ ReturnValue_t GyroHandlerL3GD20H::interpretDeviceReply(DeviceCommandId_t id, PoolReadGuard readSet(&dataset); if(readSet.getReadResult() == HasReturnvaluesIF::RETURN_OK) { - dataset.angVelocX = angVelocX; - dataset.angVelocY = angVelocY; - dataset.angVelocZ = angVelocZ; + if(std::abs(angVelocX) > 100) { + dataset.angVelocX = angVelocX; + dataset.angVelocX.setValid(true); + } + else { + dataset.angVelocX.setValid(false); + } + + if(std::abs(angVelocY) > 100) { + dataset.angVelocY = angVelocY; + dataset.angVelocY.setValid(true); + } + else { + dataset.angVelocY.setValid(false); + } + + if(std::abs(angVelocZ) > 100) { + dataset.angVelocZ = angVelocZ; + dataset.angVelocZ.setValid(true); + } + else { + dataset.angVelocZ.setValid(false); + } + dataset.temperature = temperature; - dataset.setValidity(true, true); + dataset.temperature.setValid(true); } break; } diff --git a/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h index 07d9835f..de2884e8 100644 --- a/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h +++ b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h @@ -40,7 +40,14 @@ protected: size_t commandDataLen) override; ReturnValue_t scanForReply(const uint8_t *start, size_t len, DeviceCommandId_t *foundId, size_t *foundLen) override; - ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, + /** + * This implementation is tailored towards space systems and flags angular velocities + * larger than 100 as invalid + * @param id + * @param packet + * @return + */ + virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) override; void fillCommandAndReplyMap() override; diff --git a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp index 63dabfc9..6bc8a19e 100644 --- a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp +++ b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp @@ -308,10 +308,29 @@ ReturnValue_t MgmLIS3MDLHandler::interpretDeviceReply(DeviceCommandId_t id, #endif /* OBSW_VERBOSE_LEVEL >= 1 */ PoolReadGuard readHelper(&dataset); if(readHelper.getReadResult() == HasReturnvaluesIF::RETURN_OK) { - dataset.fieldStrengthX = mgmX; - dataset.fieldStrengthY = mgmY; - dataset.fieldStrengthZ = mgmZ; - dataset.setValidity(true, true); + if(std::abs(mgmX) > 100.0) { + dataset.fieldStrengthX = mgmX; + dataset.fieldStrengthX.setValid(true); + } + else { + dataset.fieldStrengthX.setValid(false); + } + + if(std::abs(mgmY) > 100.0) { + dataset.fieldStrengthY = mgmY; + dataset.fieldStrengthY.setValid(true); + } + else { + dataset.fieldStrengthY.setValid(false); + } + + if(std::abs(mgmZ) > 150.0) { + dataset.fieldStrengthZ = mgmZ; + dataset.fieldStrengthZ.setValid(true); + } + else { + dataset.fieldStrengthZ.setValid(false); + } } break; } diff --git a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h index 9fb41156..b0f249a9 100644 --- a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h +++ b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h @@ -52,7 +52,14 @@ protected: DeviceCommandId_t *id) override; ReturnValue_t scanForReply(const uint8_t *start, size_t len, DeviceCommandId_t *foundId, size_t *foundLen) override; - ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, + /** + * This implementation is tailored towards space applications and will flag values larger + * than 100 microtesla on X,Y and 150 microtesla on Z as invalid + * @param id + * @param packet + * @return + */ + virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) override; void fillCommandAndReplyMap() override; void modeChanged(void) override; From 81c33d2dc657b853cc7ec63b01123fce04e6e103 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 23 Sep 2021 14:56:20 +0200 Subject: [PATCH 054/131] added functions to set x,y,z limits --- .../devicehandlers/GyroL3GD20Handler.cpp | 12 ++++++--- .../devicehandlers/GyroL3GD20Handler.h | 20 +++++++++----- .../devicehandlers/MgmLIS3MDLHandler.cpp | 26 +++++++------------ .../devicehandlers/MgmLIS3MDLHandler.h | 12 +++++++++ 4 files changed, 44 insertions(+), 26 deletions(-) diff --git a/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp index 06b4548b..4c8495b3 100644 --- a/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp +++ b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp @@ -215,7 +215,7 @@ ReturnValue_t GyroHandlerL3GD20H::interpretDeviceReply(DeviceCommandId_t id, PoolReadGuard readSet(&dataset); if(readSet.getReadResult() == HasReturnvaluesIF::RETURN_OK) { - if(std::abs(angVelocX) > 100) { + if(std::abs(angVelocX) < this->absLimitX) { dataset.angVelocX = angVelocX; dataset.angVelocX.setValid(true); } @@ -223,7 +223,7 @@ ReturnValue_t GyroHandlerL3GD20H::interpretDeviceReply(DeviceCommandId_t id, dataset.angVelocX.setValid(false); } - if(std::abs(angVelocY) > 100) { + if(std::abs(angVelocY) < this->absLimitY) { dataset.angVelocY = angVelocY; dataset.angVelocY.setValid(true); } @@ -231,7 +231,7 @@ ReturnValue_t GyroHandlerL3GD20H::interpretDeviceReply(DeviceCommandId_t id, dataset.angVelocY.setValid(false); } - if(std::abs(angVelocZ) > 100) { + if(std::abs(angVelocZ) < this->absLimitZ) { dataset.angVelocZ = angVelocZ; dataset.angVelocZ.setValid(true); } @@ -277,3 +277,9 @@ void GyroHandlerL3GD20H::fillCommandAndReplyMap() { void GyroHandlerL3GD20H::modeChanged() { internalState = InternalState::NONE; } + +void GyroHandlerL3GD20H::setAxisLimits(float limitX, float limitY, float limitZ) { + this->absLimitX = limitX; + this->absLimitY = limitY; + this->absLimitZ = limitZ; +} diff --git a/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h index de2884e8..030833be 100644 --- a/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h +++ b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h @@ -22,6 +22,15 @@ public: CookieIF* comCookie, uint8_t switchId, uint32_t transitionDelayMs = 10000); virtual ~GyroHandlerL3GD20H(); + /** + * Set the absolute limit for the values on the axis in degrees per second. + * The dataset values will be marked as invalid if that limit is exceeded + * @param xLimit + * @param yLimit + * @param zLimit + */ + void setAbsoluteLimits(float limitX, float limitY, float limitZ); + /** * @brief Configure device handler to go to normal mode immediately */ @@ -40,13 +49,6 @@ protected: size_t commandDataLen) override; ReturnValue_t scanForReply(const uint8_t *start, size_t len, DeviceCommandId_t *foundId, size_t *foundLen) override; - /** - * This implementation is tailored towards space systems and flags angular velocities - * larger than 100 as invalid - * @param id - * @param packet - * @return - */ virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) override; @@ -61,6 +63,10 @@ private: uint32_t transitionDelayMs = 0; GyroPrimaryDataset dataset; + float absLimitX = L3GD20H::RANGE_DPS_00; + float absLimitY = L3GD20H::RANGE_DPS_00; + float absLimitZ = L3GD20H::RANGE_DPS_00; + enum class InternalState { NONE, CONFIGURE, diff --git a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp index 6bc8a19e..4f164d79 100644 --- a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp +++ b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp @@ -291,7 +291,6 @@ ReturnValue_t MgmLIS3MDLHandler::interpretDeviceReply(DeviceCommandId_t id, #if FSFW_HAL_LIS3MDL_MGM_DEBUG == 1 if(debugDivider->checkAndIncrement()) { - /* Set terminal to utf-8 if there is an issue with micro printout. */ #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "MGMHandlerLIS3: Magnetic field strength in" " microtesla:" << std::endl; @@ -308,7 +307,7 @@ ReturnValue_t MgmLIS3MDLHandler::interpretDeviceReply(DeviceCommandId_t id, #endif /* OBSW_VERBOSE_LEVEL >= 1 */ PoolReadGuard readHelper(&dataset); if(readHelper.getReadResult() == HasReturnvaluesIF::RETURN_OK) { - if(std::abs(mgmX) > 100.0) { + if(std::abs(mgmX) < absLimitX) { dataset.fieldStrengthX = mgmX; dataset.fieldStrengthX.setValid(true); } @@ -316,7 +315,7 @@ ReturnValue_t MgmLIS3MDLHandler::interpretDeviceReply(DeviceCommandId_t id, dataset.fieldStrengthX.setValid(false); } - if(std::abs(mgmY) > 100.0) { + if(std::abs(mgmY) < absLimitY) { dataset.fieldStrengthY = mgmY; dataset.fieldStrengthY.setValid(true); } @@ -324,7 +323,7 @@ ReturnValue_t MgmLIS3MDLHandler::interpretDeviceReply(DeviceCommandId_t id, dataset.fieldStrengthY.setValid(false); } - if(std::abs(mgmZ) > 150.0) { + if(std::abs(mgmZ) < absLimitZ) { dataset.fieldStrengthZ = mgmZ; dataset.fieldStrengthZ.setValid(true); } @@ -340,7 +339,6 @@ ReturnValue_t MgmLIS3MDLHandler::interpretDeviceReply(DeviceCommandId_t id, float tempValue = 25.0 + ((static_cast(tempValueRaw)) / 8.0); #if FSFW_HAL_LIS3MDL_MGM_DEBUG == 1 if(debugDivider->check()) { - /* Set terminal to utf-8 if there is an issue with micro printout. */ #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "MGMHandlerLIS3: Temperature: " << tempValue << " C" << std::endl; @@ -463,16 +461,6 @@ ReturnValue_t MgmLIS3MDLHandler::setOperatingMode(const uint8_t *commandData, } void MgmLIS3MDLHandler::fillCommandAndReplyMap() { - /* - * Regarding ArduinoBoard: - * Actually SPI answers directly, but as commanding ArduinoBoard the - * communication could be delayed - * SPI always has to be triggered, so there could be no periodic answer of - * the device, the device has to asked with a command, so periodic is zero. - * - * We dont read single registers, we just expect special - * reply from he Readall_MGM - */ insertInCommandAndReplyMap(MGMLIS3MDL::READ_CONFIG_AND_DATA, 1, &dataset); insertInCommandAndReplyMap(MGMLIS3MDL::READ_TEMPERATURE, 1); insertInCommandAndReplyMap(MGMLIS3MDL::SETUP_MGM, 1); @@ -494,7 +482,7 @@ ReturnValue_t MgmLIS3MDLHandler::prepareCtrlRegisterWrite() { rawPacket = commandBuffer; rawPacketLen = MGMLIS3MDL::NR_OF_CTRL_REGISTERS + 1; - /* We dont have to check if this is working because we just did it */ + // We dont have to check if this is working because we just did i return RETURN_OK; } @@ -522,3 +510,9 @@ ReturnValue_t MgmLIS3MDLHandler::initializeLocalDataPool( new PoolEntry({0.0})); return HasReturnvaluesIF::RETURN_OK; } + +void MgmLIS3MDLHandler::setAbsoluteLimits(float xLimit, float yLimit, float zLimit) { + this->absLimitX = xLimit; + this->absLimitY = yLimit; + this->absLimitZ = zLimit; +} diff --git a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h index b0f249a9..7181d8a0 100644 --- a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h +++ b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h @@ -34,6 +34,14 @@ public: uint8_t switchId, uint32_t transitionDelay = 10000); virtual ~MgmLIS3MDLHandler(); + /** + * Set the absolute limit for the values on the axis in microtesla. The dataset values will + * be marked as invalid if that limit is exceeded + * @param xLimit + * @param yLimit + * @param zLimit + */ + void setAbsoluteLimits(float xLimit, float yLimit, float zLimit); void setToGoToNormalMode(bool enable); protected: @@ -77,6 +85,10 @@ private: //has the size for all adresses of the lis3mdl + the continous write bit uint8_t commandBuffer[MGMLIS3MDL::NR_OF_DATA_AND_CFG_REGISTERS + 1]; + float absLimitX = 100; + float absLimitY = 100; + float absLimitZ = 150; + /** * We want to save the registers we set, so we dont have to read the * registers when we want to change something. From c9b343ebcd92de1d214a9b1d7abafee4a7e79888 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 23 Sep 2021 15:20:10 +0200 Subject: [PATCH 055/131] op divider fixes --- .../devicehandlers/GyroL3GD20Handler.cpp | 8 ++++---- .../devicehandlers/GyroL3GD20Handler.h | 4 ++-- .../devicehandlers/MgmLIS3MDLHandler.cpp | 6 +++--- .../devicehandlers/MgmLIS3MDLHandler.h | 10 +++++----- .../devicehandlers/MgmRM3100Handler.cpp | 13 +++---------- .../fsfw_hal/devicehandlers/MgmRM3100Handler.h | 18 ++++++------------ .../PeriodicOperationDivider.cpp | 5 ++--- 7 files changed, 25 insertions(+), 39 deletions(-) diff --git a/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp index 4c8495b3..70ba49eb 100644 --- a/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp +++ b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp @@ -3,11 +3,11 @@ #include "fsfw/datapool/PoolReadGuard.h" GyroHandlerL3GD20H::GyroHandlerL3GD20H(object_id_t objectId, object_id_t deviceCommunication, - CookieIF *comCookie, uint8_t switchId, uint32_t transitionDelayMs): + CookieIF *comCookie, uint32_t transitionDelayMs): DeviceHandlerBase(objectId, deviceCommunication, comCookie), - switchId(switchId), transitionDelayMs(transitionDelayMs), dataset(this) { + transitionDelayMs(transitionDelayMs), dataset(this) { #if FSFW_HAL_L3GD20_GYRO_DEBUG == 1 - debugDivider = new PeriodicOperationDivider(5); + debugDivider = new PeriodicOperationDivider(3); #endif } @@ -278,7 +278,7 @@ void GyroHandlerL3GD20H::modeChanged() { internalState = InternalState::NONE; } -void GyroHandlerL3GD20H::setAxisLimits(float limitX, float limitY, float limitZ) { +void GyroHandlerL3GD20H::setAbsoluteLimits(float limitX, float limitY, float limitZ) { this->absLimitX = limitX; this->absLimitY = limitY; this->absLimitZ = limitZ; diff --git a/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h index 030833be..870f551d 100644 --- a/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h +++ b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h @@ -19,7 +19,7 @@ class GyroHandlerL3GD20H: public DeviceHandlerBase { public: GyroHandlerL3GD20H(object_id_t objectId, object_id_t deviceCommunication, - CookieIF* comCookie, uint8_t switchId, uint32_t transitionDelayMs = 10000); + CookieIF* comCookie, uint32_t transitionDelayMs); virtual ~GyroHandlerL3GD20H(); /** @@ -54,7 +54,7 @@ protected: void fillCommandAndReplyMap() override; void modeChanged() override; - uint32_t getTransitionDelayMs(Mode_t from, Mode_t to) override; + virtual uint32_t getTransitionDelayMs(Mode_t from, Mode_t to) override; ReturnValue_t initializeLocalDataPool(localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) override; diff --git a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp index 4f164d79..891d6fdc 100644 --- a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp +++ b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp @@ -6,13 +6,13 @@ #endif MgmLIS3MDLHandler::MgmLIS3MDLHandler(object_id_t objectId, object_id_t deviceCommunication, - CookieIF* comCookie, uint8_t switchId, uint32_t transitionDelay): + CookieIF* comCookie, uint32_t transitionDelay): DeviceHandlerBase(objectId, deviceCommunication, comCookie), dataset(this), transitionDelay(transitionDelay) { #if FSFW_HAL_LIS3MDL_MGM_DEBUG == 1 - debugDivider = new PeriodicOperationDivider(5); + debugDivider = new PeriodicOperationDivider(3); #endif - /* Set to default values right away. */ + // Set to default values right away registers[0] = MGMLIS3MDL::CTRL_REG1_DEFAULT; registers[1] = MGMLIS3MDL::CTRL_REG2_DEFAULT; registers[2] = MGMLIS3MDL::CTRL_REG3_DEFAULT; diff --git a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h index 7181d8a0..6bf89a49 100644 --- a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h +++ b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h @@ -31,7 +31,7 @@ public: static const Event CHANGE_OF_SETUP_PARAMETER = MAKE_EVENT(0, severity::LOW); MgmLIS3MDLHandler(uint32_t objectId, object_id_t deviceCommunication, CookieIF* comCookie, - uint8_t switchId, uint32_t transitionDelay = 10000); + uint32_t transitionDelay); virtual ~MgmLIS3MDLHandler(); /** @@ -50,7 +50,7 @@ protected: void doShutDown() override; void doStartUp() override; void doTransition(Mode_t modeFrom, Submode_t subModeFrom) override; - uint32_t getTransitionDelayMs(Mode_t from, Mode_t to) override; + virtual uint32_t getTransitionDelayMs(Mode_t from, Mode_t to) override; ReturnValue_t buildCommandFromCommand( DeviceCommandId_t deviceCommand, const uint8_t *commandData, size_t commandDataLen) override; @@ -76,13 +76,13 @@ protected: private: MGMLIS3MDL::MgmPrimaryDataset dataset; - //Length a sindgle command SPI answer + //Length a single command SPI answer static const uint8_t SINGLE_COMMAND_ANSWER_LEN = 2; uint32_t transitionDelay; - //Single SPIcommand has 2 bytes, first for adress, second for content + // Single SPI command has 2 bytes, first for adress, second for content size_t singleComandSize = 2; - //has the size for all adresses of the lis3mdl + the continous write bit + // Has the size for all adresses of the lis3mdl + the continous write bit uint8_t commandBuffer[MGMLIS3MDL::NR_OF_DATA_AND_CFG_REGISTERS + 1]; float absLimitX = 100; diff --git a/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp b/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp index 467141de..20cf95d2 100644 --- a/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp +++ b/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp @@ -8,10 +8,9 @@ MgmRM3100Handler::MgmRM3100Handler(object_id_t objectId, - object_id_t deviceCommunication, CookieIF* comCookie, uint8_t switchId, - uint32_t transitionDelay): + object_id_t deviceCommunication, CookieIF* comCookie, uint32_t transitionDelay): DeviceHandlerBase(objectId, deviceCommunication, comCookie), - primaryDataset(this), switchId(switchId), transitionDelay(transitionDelay) { + primaryDataset(this), transitionDelay(transitionDelay) { #if FSFW_HAL_RM3100_MGM_DEBUG == 1 debugDivider = new PeriodicOperationDivider(3); #endif @@ -322,13 +321,7 @@ ReturnValue_t MgmRM3100Handler::initializeLocalDataPool( } uint32_t MgmRM3100Handler::getTransitionDelayMs(Mode_t from, Mode_t to) { - return 25000; -} - -ReturnValue_t MgmRM3100Handler::getSwitches(const uint8_t **switches, uint8_t *numberOfSwitches) { - *switches = &switchId; - *numberOfSwitches = 1; - return HasReturnvaluesIF::RETURN_OK; + return this->transitionDelay; } void MgmRM3100Handler::setToGoToNormalMode(bool enable) { diff --git a/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.h b/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.h index eb6e62bc..1ba680cb 100644 --- a/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.h +++ b/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.h @@ -32,7 +32,7 @@ public: SUBSYSTEM_ID::MGM_RM3100, 0x01, severity::INFO); MgmRM3100Handler(object_id_t objectId, object_id_t deviceCommunication, - CookieIF* comCookie, uint8_t switchId, uint32_t transitionDelay = 10000); + CookieIF* comCookie, uint32_t transitionDelay); virtual ~MgmRM3100Handler(); /** @@ -48,21 +48,16 @@ protected: DeviceCommandId_t *id) override; void doStartUp() override; void doShutDown() override; - ReturnValue_t buildNormalDeviceCommand( - DeviceCommandId_t *id) override; - ReturnValue_t buildCommandFromCommand( - DeviceCommandId_t deviceCommand, const uint8_t *commandData, - size_t commandDataLen) override; + ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t *id) override; + ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand, + const uint8_t *commandData, size_t commandDataLen) override; ReturnValue_t scanForReply(const uint8_t *start, size_t len, DeviceCommandId_t *foundId, size_t *foundLen) override; - ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, - const uint8_t *packet) override; - ReturnValue_t getSwitches(const uint8_t **switches, - uint8_t *numberOfSwitches) override; + ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) override; void fillCommandAndReplyMap() override; void modeChanged(void) override; - uint32_t getTransitionDelayMs(Mode_t from, Mode_t to) override; + virtual uint32_t getTransitionDelayMs(Mode_t from, Mode_t to) override; ReturnValue_t initializeLocalDataPool(localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) override; @@ -97,7 +92,6 @@ private: float scaleFactorZ = 1.0 / RM3100::DEFAULT_GAIN; bool goToNormalModeAtStartup = false; - uint8_t switchId; uint32_t transitionDelay; ReturnValue_t handleCycleCountConfigCommand(DeviceCommandId_t deviceCommand, diff --git a/src/fsfw/globalfunctions/PeriodicOperationDivider.cpp b/src/fsfw/globalfunctions/PeriodicOperationDivider.cpp index 5d9e1624..ffba7574 100644 --- a/src/fsfw/globalfunctions/PeriodicOperationDivider.cpp +++ b/src/fsfw/globalfunctions/PeriodicOperationDivider.cpp @@ -7,14 +7,13 @@ PeriodicOperationDivider::PeriodicOperationDivider(uint32_t divider, } bool PeriodicOperationDivider::checkAndIncrement() { + counter++; bool opNecessary = check(); if(opNecessary) { if(resetAutomatically) { - counter = 1; + counter = 0; } - return opNecessary; } - counter++; return opNecessary; } From 350fbc385cedae73ea2396dafdeb5b74b28be74d Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 23 Sep 2021 15:22:27 +0200 Subject: [PATCH 056/131] small tweak --- src/fsfw/globalfunctions/PeriodicOperationDivider.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fsfw/globalfunctions/PeriodicOperationDivider.cpp b/src/fsfw/globalfunctions/PeriodicOperationDivider.cpp index ffba7574..98f83d04 100644 --- a/src/fsfw/globalfunctions/PeriodicOperationDivider.cpp +++ b/src/fsfw/globalfunctions/PeriodicOperationDivider.cpp @@ -11,7 +11,7 @@ bool PeriodicOperationDivider::checkAndIncrement() { bool opNecessary = check(); if(opNecessary) { if(resetAutomatically) { - counter = 0; + resetCounter(); } } return opNecessary; From dccc2f0ba77184933e3d551d95950a5b0801d2f2 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 23 Sep 2021 15:57:50 +0200 Subject: [PATCH 057/131] printout fix SpiComIF --- hal/src/fsfw_hal/linux/spi/SpiComIF.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp b/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp index e940cf32..1fa87121 100644 --- a/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp +++ b/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp @@ -398,11 +398,11 @@ GpioIF* SpiComIF::getGpioInterface() { void SpiComIF::setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed) { int retval = ioctl(spiFd, SPI_IOC_WR_MODE, reinterpret_cast(&mode)); if(retval != 0) { - utility::handleIoctlError("SpiTestClass::performRm3100Test: Setting SPI mode failed!"); + utility::handleIoctlError("SpiComIF::setSpiSpeedAndMode: Setting SPI mode failed"); } retval = ioctl(spiFd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); if(retval != 0) { - utility::handleIoctlError("SpiTestClass::performRm3100Test: Setting SPI speed failed!"); + utility::handleIoctlError("SpiComIF::setSpiSpeedAndMode: Setting SPI speed failed"); } } From a3eb870ba06659d598d6f67c2baef731474ec468 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 23 Sep 2021 16:45:37 +0200 Subject: [PATCH 058/131] Corrected comment --- src/fsfw/devicehandlers/DeviceHandlerBase.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.h b/src/fsfw/devicehandlers/DeviceHandlerBase.h index b182b611..4bc54ac4 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.h +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.h @@ -334,8 +334,7 @@ protected: * - @c RETURN_OK to send command after #rawPacket and #rawPacketLen * have been set. * - @c HasActionsIF::EXECUTION_COMPLETE to generate a finish reply immediately. This can - * be used if no reply is expected. Otherwise, the developer can call #actionHelper.finish - * to finish the command handling. + * be used if no reply is expected * - Anything else triggers an event with the return code as a parameter as well as a * step reply failed with the return code */ From e1a85b47c5018590e58b9b1130b1754b0079450f Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 23 Sep 2021 17:13:53 +0200 Subject: [PATCH 059/131] tiny tweaks --- src/fsfw/devicehandlers/AssemblyBase.h | 2 +- src/fsfw/subsystem/SubsystemBase.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/fsfw/devicehandlers/AssemblyBase.h b/src/fsfw/devicehandlers/AssemblyBase.h index 6cac81b4..7d54f14d 100644 --- a/src/fsfw/devicehandlers/AssemblyBase.h +++ b/src/fsfw/devicehandlers/AssemblyBase.h @@ -7,7 +7,7 @@ /** * @brief Base class to implement reconfiguration and failure handling for - * redundant devices by monitoring their modes health states. + * redundant devices by monitoring their modes and health states. * @details * Documentation: Dissertation Baetz p.156, 157. * diff --git a/src/fsfw/subsystem/SubsystemBase.h b/src/fsfw/subsystem/SubsystemBase.h index 6b2e9b5f..a1de077d 100644 --- a/src/fsfw/subsystem/SubsystemBase.h +++ b/src/fsfw/subsystem/SubsystemBase.h @@ -62,7 +62,8 @@ protected: struct ChildInfo { MessageQueueId_t commandQueue; Mode_t mode; - Submode_t submode;bool healthChanged; + Submode_t submode; + bool healthChanged; }; Mode_t mode; From 0987a160c9c200e1b7b72e992ae158d826147c30 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 23 Sep 2021 17:33:45 +0200 Subject: [PATCH 060/131] new retval for empty slot list --- src/fsfw/returnvalues/FwClassIds.h | 1 + src/fsfw/tasks/FixedSlotSequence.cpp | 6 +++--- src/fsfw/tasks/FixedSlotSequence.h | 4 +++- src/fsfw/tasks/FixedTimeslotTaskIF.h | 5 ++++- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/fsfw/returnvalues/FwClassIds.h b/src/fsfw/returnvalues/FwClassIds.h index 7f355c40..ce093b09 100644 --- a/src/fsfw/returnvalues/FwClassIds.h +++ b/src/fsfw/returnvalues/FwClassIds.h @@ -77,6 +77,7 @@ enum: uint8_t { HAL_UART, //HURT HAL_I2C, //HI2C HAL_GPIO, //HGIO + FIXED_SLOT_TASK_IF, //FTIF FW_CLASS_ID_COUNT // [EXPORT] : [END] }; diff --git a/src/fsfw/tasks/FixedSlotSequence.cpp b/src/fsfw/tasks/FixedSlotSequence.cpp index 2e5384b7..5e896af4 100644 --- a/src/fsfw/tasks/FixedSlotSequence.cpp +++ b/src/fsfw/tasks/FixedSlotSequence.cpp @@ -1,4 +1,5 @@ #include "fsfw/tasks/FixedSlotSequence.h" +#include "fsfw/tasks/FixedTimeslotTaskIF.h" #include "fsfw/serviceinterface/ServiceInterface.h" #include @@ -92,10 +93,9 @@ void FixedSlotSequence::addSlot(object_id_t componentId, uint32_t slotTimeMs, ReturnValue_t FixedSlotSequence::checkSequence() const { if(slotList.empty()) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "FixedSlotSequence::checkSequence:" - << " Slot list is empty!" << std::endl; + sif::warning << "FixedSlotSequence::checkSequence: Slot list is empty!" << std::endl; #endif - return HasReturnvaluesIF::RETURN_FAILED; + return FixedTimeslotTaskIF::SLOT_LIST_EMPTY; } if(customCheckFunction != nullptr) { diff --git a/src/fsfw/tasks/FixedSlotSequence.h b/src/fsfw/tasks/FixedSlotSequence.h index 077dd10b..7f49ea0c 100644 --- a/src/fsfw/tasks/FixedSlotSequence.h +++ b/src/fsfw/tasks/FixedSlotSequence.h @@ -2,7 +2,7 @@ #define FSFW_TASKS_FIXEDSLOTSEQUENCE_H_ #include "FixedSequenceSlot.h" -#include "../objectmanager/SystemObject.h" +#include "fsfw/objectmanager/SystemObject.h" #include @@ -136,6 +136,7 @@ public: * @details * Checks if timing is ok (must be ascending) and if all handlers were found. * @return + * - SLOT_LIST_EMPTY if the slot list is empty */ ReturnValue_t checkSequence() const; @@ -147,6 +148,7 @@ public: * The general check will be continued for now if the custom check function * fails but a diagnostic debug output will be given. * @param customCheckFunction + * */ void addCustomCheck(ReturnValue_t (*customCheckFunction)(const SlotList &)); diff --git a/src/fsfw/tasks/FixedTimeslotTaskIF.h b/src/fsfw/tasks/FixedTimeslotTaskIF.h index 2fc7e092..605239a4 100644 --- a/src/fsfw/tasks/FixedTimeslotTaskIF.h +++ b/src/fsfw/tasks/FixedTimeslotTaskIF.h @@ -2,7 +2,8 @@ #define FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_ #include "PeriodicTaskIF.h" -#include "../objectmanager/ObjectManagerIF.h" +#include "fsfw/objectmanager/ObjectManagerIF.h" +#include "fsfw/returnvalues/FwClassIds.h" /** * @brief Following the same principle as the base class IF. @@ -12,6 +13,8 @@ class FixedTimeslotTaskIF : public PeriodicTaskIF { public: virtual ~FixedTimeslotTaskIF() {} + static constexpr ReturnValue_t SLOT_LIST_EMPTY = HasReturnvaluesIF::makeReturnCode( + CLASS_ID::FIXED_SLOT_TASK_IF, 0); /** * Add an object with a slot time and the execution step to the task. * The execution step will be passed to the object (e.g. as an operation From e7df520780242f98f9a1189906c0ade1a8a99f29 Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Thu, 23 Sep 2021 17:54:41 +0200 Subject: [PATCH 061/131] fixed merge conflicts --- .../fsfw_hal/common/gpio/gpioDefinitions.h | 29 +++++++ .../fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp | 79 ++++++++++++++++--- hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h | 13 ++- 3 files changed, 107 insertions(+), 14 deletions(-) diff --git a/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h b/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h index 688d9c9b..b030ebc3 100644 --- a/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h +++ b/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h @@ -26,8 +26,10 @@ enum GpioOperation { enum GpioTypes { NONE, + GPIO_REGULAR, GPIO_REGULAR_BY_CHIP, GPIO_REGULAR_BY_LABEL, + GPIO_REGULAR_BY_LINE_NAME, CALLBACK }; @@ -75,6 +77,12 @@ public: int initValue, int lineNum): GpioBase(gpioType, consumer, direction, initValue), lineNum(lineNum) { } + + // line number will be configured at a later point for the open by line name configuration + GpiodRegularBase(gpio::GpioTypes gpioType, std::string consumer, gpio::Direction direction, + int initValue): GpioBase(gpioType, consumer, direction, initValue) { + } + int lineNum = 0; struct gpiod_line* lineHandle = nullptr; }; @@ -120,6 +128,27 @@ public: std::string label; }; +/** + * @brief Passing this GPIO configuration to the GPIO IF object will try to open the GPIO by its + * line name. This line name can be set in the device tree and must be unique. Otherwise + * the driver will open the first line with the given name. + */ +class GpiodRegularByLineName: public GpiodRegularBase { +public: + GpiodRegularByLineName(std::string lineName_, std::string consumer_, gpio::Direction direction_, + int initValue_) : + GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME, consumer_, direction_, + initValue_), lineName(lineName_) { + } + + GpiodRegularByLineName(std::string lineName_, std::string consumer_) : + GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME, consumer_, gpio::Direction::IN, + gpio::LOW), lineName(lineName_) { + } + + std::string lineName; +}; + class GpioCallback: public GpioBase { public: GpioCallback(std::string consumer, gpio::Direction direction_, int initValue_, diff --git a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp index 15c3d118..43cd63ce 100644 --- a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp +++ b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp @@ -66,6 +66,14 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) { configureGpioByLabel(gpioConfig.first, *regularGpio); break; } + case(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME):{ + auto regularGpio = dynamic_cast(gpioConfig.second); + if(regularGpio == nullptr) { + return GPIO_INVALID_INSTANCE; + } + configureGpioByLineName(gpioConfig.first, *regularGpio); + break; + } case(gpio::GpioTypes::CALLBACK): { auto gpioCallback = dynamic_cast(gpioConfig.second); if(gpioCallback->callback == nullptr) { @@ -84,13 +92,13 @@ ReturnValue_t LinuxLibgpioIF::configureGpioByLabel(gpioId_t gpioId, std::string& label = gpioByLabel.label; struct gpiod_chip* chip = gpiod_chip_open_by_label(label.c_str()); if (chip == nullptr) { - sif::warning << "LinuxLibgpioIF::configureRegularGpio: Failed to open gpio from gpio " + sif::warning << "LinuxLibgpioIF::configureGpioByLabel: Failed to open gpio from gpio " << "group with label " << label << ". Gpio ID: " << gpioId << std::endl; return RETURN_FAILED; } std::string failOutput = "label: " + label; - return configureRegularGpio(gpioId, gpioByLabel.gpioType, chip, gpioByLabel, failOutput); + return configureRegularGpio(gpioId, chip, gpioByLabel, failOutput); } ReturnValue_t LinuxLibgpioIF::configureGpioByChip(gpioId_t gpioId, @@ -98,16 +106,41 @@ ReturnValue_t LinuxLibgpioIF::configureGpioByChip(gpioId_t gpioId, std::string& chipname = gpioByChip.chipname; struct gpiod_chip* chip = gpiod_chip_open_by_name(chipname.c_str()); if (chip == nullptr) { - sif::warning << "LinuxLibgpioIF::configureRegularGpio: Failed to open chip " + sif::warning << "LinuxLibgpioIF::configureGpioByChip: Failed to open chip " << chipname << ". Gpio ID: " << gpioId << std::endl; return RETURN_FAILED; } std::string failOutput = "chipname: " + chipname; - return configureRegularGpio(gpioId, gpioByChip.gpioType, chip, gpioByChip, failOutput); + return configureRegularGpio(gpioId, chip, gpioByChip, failOutput); } -ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, gpio::GpioTypes gpioType, - struct gpiod_chip* chip, GpiodRegularBase& regularGpio, std::string failOutput) { +ReturnValue_t LinuxLibgpioIF::configureGpioByLineName(gpioId_t gpioId, + GpiodRegularByLineName &gpioByLineName) { + std::string& lineName = gpioByLineName.lineName; + char chipname[MAX_CHIPNAME_LENGTH]; + unsigned int lineOffset; + + int result = gpiod_ctxless_find_line(lineName.c_str(), chipname, MAX_CHIPNAME_LENGTH, + &lineOffset); + if (result != LINE_FOUND) { + parseFindeLineResult(result, lineName); + return RETURN_FAILED; + } + + gpioByLineName.lineNum = static_cast(lineOffset); + + struct gpiod_chip* chip = gpiod_chip_open_by_name(chipname); + if (chip == nullptr) { + sif::warning << "LinuxLibgpioIF::configureGpioByLineName: Failed to open chip " + << chipname << ". second->gpioType; - if(gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_CHIP or - gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LABEL) { + if (gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_CHIP + or gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LABEL + or gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME) { auto regularGpio = dynamic_cast(gpioMapIter->second); if(regularGpio == nullptr) { return GPIO_TYPE_FAILURE; @@ -201,8 +235,9 @@ ReturnValue_t LinuxLibgpioIF::pullLow(gpioId_t gpioId) { } auto& gpioType = gpioMapIter->second->gpioType; - if(gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_CHIP or - gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LABEL) { + if (gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_CHIP + or gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LABEL + or gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME) { auto regularGpio = dynamic_cast(gpioMapIter->second); if(regularGpio == nullptr) { return GPIO_TYPE_FAILURE; @@ -239,9 +274,11 @@ ReturnValue_t LinuxLibgpioIF::readGpio(gpioId_t gpioId, int* gpioState) { sif::warning << "LinuxLibgpioIF::readGpio: Unknown GPIOD ID " << gpioId << std::endl; return UNKNOWN_GPIO_ID; } + auto gpioType = gpioMapIter->second->gpioType; - if(gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_CHIP or - gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LABEL) { + if (gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_CHIP + or gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LABEL + or gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME) { auto regularGpio = dynamic_cast(gpioMapIter->second); if(regularGpio == nullptr) { return GPIO_TYPE_FAILURE; @@ -342,3 +379,21 @@ ReturnValue_t LinuxLibgpioIF::checkForConflictsCallbackGpio(gpioId_t gpioIdToChe } return HasReturnvaluesIF::RETURN_OK; } + +void LinuxLibgpioIF::parseFindeLineResult(int result, std::string& lineName) { + switch (result) { + case LINE_NOT_EXISTS: + sif::warning << "LinuxLibgpioIF::parseFindeLineResult: Line with name " << lineName + << " does not exist" << std::endl; + break; + case LINE_ERROR: + sif::warning << "LinuxLibgpioIF::parseFindeLineResult: " << "Line with name " + << lineName << " does not exist" << std::endl; + break; + default: + sif::warning << "LinuxLibgpioIF::parseFindeLineResult: Unknown return code for line with " + << "name " << lineName << std::endl; + break; + } + +} diff --git a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h index 31e4a7e8..d458c362 100644 --- a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h +++ b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h @@ -38,6 +38,12 @@ public: ReturnValue_t readGpio(gpioId_t gpioId, int* gpioState) override; private: + + static const size_t MAX_CHIPNAME_LENGTH = 11; + static const int LINE_NOT_EXISTS = 0; + static const int LINE_ERROR = -1; + static const int LINE_FOUND = 1; + /* Holds the information and configuration of all used GPIOs */ GpioUnorderedMap gpioMap; GpioUnorderedMapIter gpioMapIter; @@ -53,8 +59,10 @@ private: ReturnValue_t configureGpioByLabel(gpioId_t gpioId, GpiodRegularByLabel& gpioByLabel); ReturnValue_t configureGpioByChip(gpioId_t gpioId, GpiodRegularByChip& gpioByChip); - ReturnValue_t configureRegularGpio(gpioId_t gpioId, gpio::GpioTypes gpioType, - struct gpiod_chip* chip, GpiodRegularBase& regularGpio, std::string failOutput); + ReturnValue_t configureGpioByLineName(gpioId_t gpioId, + GpiodRegularByLineName &gpioByLineName); + ReturnValue_t configureRegularGpio(gpioId_t gpioId, struct gpiod_chip* chip, + GpiodRegularBase& regularGpio, std::string failOutput); /** * @brief This function checks if GPIOs are already registered and whether @@ -77,6 +85,7 @@ private: */ ReturnValue_t configureGpios(GpioMap& mapToAdd); + void parseFindeLineResult(int result, std::string& lineName); }; #endif /* LINUX_GPIO_LINUXLIBGPIOIF_H_ */ From 665be0d417a04b7bea5a4e18f1434153b166e37a Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 23 Sep 2021 18:05:17 +0200 Subject: [PATCH 062/131] better name for wiretapping define --- hal/src/fsfw_hal/linux/spi/SpiComIF.cpp | 2 +- src/fsfw/FSFW.h.in | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp b/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp index 1fa87121..9c4e66ae 100644 --- a/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp +++ b/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp @@ -227,7 +227,7 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie *spiCookie, const utility::handleIoctlError("SpiComIF::sendMessage: ioctl error."); result = FULL_DUPLEX_TRANSFER_FAILED; } -#if FSFW_HAL_LINUX_SPI_WIRETAPPING == 1 +#if FSFW_HAL_SPI_WIRETAPPING == 1 performSpiWiretapping(spiCookie); #endif /* FSFW_LINUX_SPI_WIRETAPPING == 1 */ } diff --git a/src/fsfw/FSFW.h.in b/src/fsfw/FSFW.h.in index 3f005387..628cd521 100644 --- a/src/fsfw/FSFW.h.in +++ b/src/fsfw/FSFW.h.in @@ -20,9 +20,9 @@ #define FSFW_TCP_RECV_WIRETAPPING_ENABLED 0 #endif -/* Can be used for low-level debugging of the SPI bus */ -#ifndef FSFW_HAL_LINUX_SPI_WIRETAPPING -#define FSFW_HAL_LINUX_SPI_WIRETAPPING 0 +// Can be used for low-level debugging of the SPI bus +#ifndef FSFW_HAL_SPI_WIRETAPPING +#define FSFW_HAL_SPI_WIRETAPPING 0 #endif #ifndef FSFW_HAL_L3GD20_GYRO_DEBUG From e0671a395ebea9d2297b2096293db80a2e412f4a Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 23 Sep 2021 18:14:40 +0200 Subject: [PATCH 063/131] indentation --- src/fsfw/FSFW.h.in | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/fsfw/FSFW.h.in b/src/fsfw/FSFW.h.in index 628cd521..12703add 100644 --- a/src/fsfw/FSFW.h.in +++ b/src/fsfw/FSFW.h.in @@ -22,7 +22,7 @@ // Can be used for low-level debugging of the SPI bus #ifndef FSFW_HAL_SPI_WIRETAPPING -#define FSFW_HAL_SPI_WIRETAPPING 0 +#define FSFW_HAL_SPI_WIRETAPPING 0 #endif #ifndef FSFW_HAL_L3GD20_GYRO_DEBUG @@ -34,7 +34,6 @@ #endif /* FSFW_HAL_RM3100_MGM_DEBUG */ #ifndef FSFW_HAL_LIS3MDL_MGM_DEBUG -#define FSFW_HAL_LIS3MDL_MGM_DEBUG 0 +#define FSFW_HAL_LIS3MDL_MGM_DEBUG 0 #endif /* FSFW_HAL_LIS3MDL_MGM_DEBUG */ - #endif /* FSFW_FSFW_H_ */ From 48a24d7dba4a9bf4a1922255e37a8176ae775220 Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Fri, 24 Sep 2021 10:21:40 +0200 Subject: [PATCH 064/131] removed gpio type GPIO_REGULAR --- hal/src/fsfw_hal/common/gpio/gpioDefinitions.h | 1 - 1 file changed, 1 deletion(-) diff --git a/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h b/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h index b030ebc3..53182058 100644 --- a/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h +++ b/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h @@ -26,7 +26,6 @@ enum GpioOperation { enum GpioTypes { NONE, - GPIO_REGULAR, GPIO_REGULAR_BY_CHIP, GPIO_REGULAR_BY_LABEL, GPIO_REGULAR_BY_LINE_NAME, From 10f8a0fd0eb603840b8eb75e43611fe1af554302 Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Fri, 24 Sep 2021 15:33:55 +0200 Subject: [PATCH 065/131] MgmLIS3MDLHandler fix in buildTransitionDeviceCommand --- hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp index 891d6fdc..a0059451 100644 --- a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp +++ b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp @@ -71,7 +71,7 @@ ReturnValue_t MgmLIS3MDLHandler::buildTransitionDeviceCommand( switch (internalState) { case(InternalState::STATE_NONE): case(InternalState::STATE_NORMAL): { - return HasReturnvaluesIF::RETURN_OK; + return DeviceHandlerBase::NOTHING_TO_SEND; } case(InternalState::STATE_FIRST_CONTACT): { *id = MGMLIS3MDL::IDENTIFY_DEVICE; From 95464955079b7c704b0073ae73699aafb1cebafe Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 27 Sep 2021 10:38:47 +0200 Subject: [PATCH 066/131] improvements for linux libgpioIF --- .../fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp | 169 +++++++++++------- hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h | 7 +- 2 files changed, 108 insertions(+), 68 deletions(-) diff --git a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp index 43cd63ce..3f8e1f3c 100644 --- a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp +++ b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp @@ -122,7 +122,7 @@ ReturnValue_t LinuxLibgpioIF::configureGpioByLineName(gpioId_t gpioId, int result = gpiod_ctxless_find_line(lineName.c_str(), chipname, MAX_CHIPNAME_LENGTH, &lineOffset); - if (result != LINE_FOUND) { + if (result != LINE_FOUND) { parseFindeLineResult(result, lineName); return RETURN_FAILED; } @@ -140,7 +140,7 @@ ReturnValue_t LinuxLibgpioIF::configureGpioByLineName(gpioId_t gpioId, } ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, struct gpiod_chip* chip, - GpiodRegularBase& regularGpio, std::string failOutput) { + GpiodRegularBase& regularGpio, std::string failOutput) { unsigned int lineNum; gpio::Direction direction; std::string consumer; @@ -165,22 +165,10 @@ ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, struct gpiod case(gpio::OUT): { result = gpiod_line_request_output(lineHandle, consumer.c_str(), regularGpio.initValue); - if (result < 0) { - sif::error << "LinuxLibgpioIF::configureRegularGpio: Failed to request line " << lineNum << - " from GPIO instance with ID: " << gpioId << std::endl; - gpiod_line_release(lineHandle); - return RETURN_FAILED; - } break; } case(gpio::IN): { result = gpiod_line_request_input(lineHandle, consumer.c_str()); - if (result < 0) { - sif::error << "LinuxLibgpioIF::configureGpios: Failed to request line " - << lineNum << " from GPIO instance with ID: " << gpioId << std::endl; - gpiod_line_release(lineHandle); - return RETURN_FAILED; - } break; } default: { @@ -189,6 +177,18 @@ ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, struct gpiod return GPIO_INVALID_INSTANCE; } + if (result < 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "LinuxLibgpioIF::configureRegularGpio: Failed to request line " << + lineNum << " from GPIO instance with ID: " << gpioId << std::endl; +#else + sif::printError("LinuxLibgpioIF::configureRegularGpio: " + "Failed to request line %d from GPIO instance with ID: %d\n", lineNum, gpioId); +#endif + gpiod_line_release(lineHandle); + return RETURN_FAILED; + } + } /** * Write line handle to GPIO configuration instance so it can later be used to set or @@ -230,7 +230,11 @@ ReturnValue_t LinuxLibgpioIF::pullHigh(gpioId_t gpioId) { ReturnValue_t LinuxLibgpioIF::pullLow(gpioId_t gpioId) { gpioMapIter = gpioMap.find(gpioId); if (gpioMapIter == gpioMap.end()) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "LinuxLibgpioIF::pullLow: Unknown GPIO ID " << gpioId << std::endl; +#else + sif::printWarning("LinuxLibgpioIF::pullLow: Unknown GPIO ID %d\n", gpioId); +#endif return UNKNOWN_GPIO_ID; } @@ -260,8 +264,13 @@ ReturnValue_t LinuxLibgpioIF::driveGpio(gpioId_t gpioId, GpiodRegularBase& regularGpio, gpio::Levels logicLevel) { int result = gpiod_line_set_value(regularGpio.lineHandle, logicLevel); if (result < 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "LinuxLibgpioIF::driveGpio: Failed to pull GPIO with ID " << gpioId << " to logic level " << logicLevel << std::endl; +#else + sif::printWarning("LinuxLibgpioIF::driveGpio: Failed to pull GPIO with ID %d to " + "logic level %d\n", gpioId, logicLevel); +#endif return DRIVE_GPIO_FAILURE; } @@ -271,7 +280,11 @@ ReturnValue_t LinuxLibgpioIF::driveGpio(gpioId_t gpioId, ReturnValue_t LinuxLibgpioIF::readGpio(gpioId_t gpioId, int* gpioState) { gpioMapIter = gpioMap.find(gpioId); if (gpioMapIter == gpioMap.end()){ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "LinuxLibgpioIF::readGpio: Unknown GPIOD ID " << gpioId << std::endl; +#else + sif::printWarning("LinuxLibgpioIF::readGpio: Unknown GPIOD ID %d\n", gpioId); +#endif return UNKNOWN_GPIO_ID; } @@ -299,13 +312,14 @@ ReturnValue_t LinuxLibgpioIF::checkForConflicts(GpioMap& mapToAdd){ for(auto& gpioConfig: mapToAdd) { switch(gpioConfig.second->gpioType) { case(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP): - case(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL): { + case(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL): + case(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME): { auto regularGpio = dynamic_cast(gpioConfig.second); if(regularGpio == nullptr) { return GPIO_TYPE_FAILURE; } - /* Check for conflicts and remove duplicates if necessary */ - result = checkForConflictsRegularGpio(gpioConfig.first, *regularGpio, mapToAdd); + // Check for conflicts and remove duplicates if necessary + result = checkForConflictsById(gpioConfig.first, gpioConfig.second->gpioType, mapToAdd); if(result != HasReturnvaluesIF::RETURN_OK) { status = result; } @@ -316,15 +330,22 @@ ReturnValue_t LinuxLibgpioIF::checkForConflicts(GpioMap& mapToAdd){ if(callbackGpio == nullptr) { return GPIO_TYPE_FAILURE; } - /* Check for conflicts and remove duplicates if necessary */ - result = checkForConflictsCallbackGpio(gpioConfig.first, callbackGpio, mapToAdd); + // Check for conflicts and remove duplicates if necessary + result = checkForConflictsById(gpioConfig.first, + gpioConfig.second->gpioType, mapToAdd); if(result != HasReturnvaluesIF::RETURN_OK) { status = result; } break; } default: { - +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "Invalid GPIO type detected for GPIO ID " << gpioConfig.first + << std::endl; +#else + sif::printWarning("Invalid GPIO type detected for GPIO ID %d\n", gpioConfig.first); +#endif + status = GPIO_TYPE_FAILURE; } } } @@ -332,68 +353,86 @@ ReturnValue_t LinuxLibgpioIF::checkForConflicts(GpioMap& mapToAdd){ } -ReturnValue_t LinuxLibgpioIF::checkForConflictsRegularGpio(gpioId_t gpioIdToCheck, - GpiodRegularBase& gpioToCheck, GpioMap& mapToAdd) { - /* Cross check with private map */ +ReturnValue_t LinuxLibgpioIF::checkForConflictsById(gpioId_t gpioIdToCheck, + gpio::GpioTypes expectedType, GpioMap& mapToAdd) { + // Cross check with private map gpioMapIter = gpioMap.find(gpioIdToCheck); if(gpioMapIter != gpioMap.end()) { auto& gpioType = gpioMapIter->second->gpioType; - if(gpioType != gpio::GpioTypes::GPIO_REGULAR_BY_CHIP and - gpioType != gpio::GpioTypes::GPIO_REGULAR_BY_LABEL) { - sif::warning << "LinuxLibgpioIF::checkForConflicts: ID already exists for different " - "GPIO type" << gpioIdToCheck << ". Removing duplicate." << std::endl; + bool eraseDuplicateDifferentType = false; + switch(expectedType) { + case(gpio::GpioTypes::NONE): { + break; + } + case(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP): + case(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL): + case(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME): { + if(gpioType == gpio::GpioTypes::NONE or gpioType == gpio::GpioTypes::CALLBACK) { + eraseDuplicateDifferentType = true; + } + break; + } + case(gpio::GpioTypes::CALLBACK): { + if(gpioType != gpio::GpioTypes::CALLBACK) { + eraseDuplicateDifferentType = true; + } + } + } + if(eraseDuplicateDifferentType) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "LinuxLibgpioIF::checkForConflicts: ID already exists for " + "different GPIO type " << gpioIdToCheck << + ". Removing duplicate from map to add" << std::endl; +#else + sif::printWarning("LinuxLibgpioIF::checkForConflicts: ID already exists for " + "different GPIO type %d. Removing duplicate from map to add\n", gpioIdToCheck); +#endif mapToAdd.erase(gpioIdToCheck); - return HasReturnvaluesIF::RETURN_OK; - } - auto ownRegularGpio = dynamic_cast(gpioMapIter->second); - if(ownRegularGpio == nullptr) { - return GPIO_TYPE_FAILURE; + return GPIO_DUPLICATE_DETECTED; } - /* Remove element from map to add because a entry for this GPIO - already exists */ - sif::warning << "LinuxLibgpioIF::checkForConflictsRegularGpio: Duplicate GPIO definition" - << " detected. Duplicate will be removed from map to add." << std::endl; - mapToAdd.erase(gpioIdToCheck); - } - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t LinuxLibgpioIF::checkForConflictsCallbackGpio(gpioId_t gpioIdToCheck, - GpioCallback *callbackGpio, GpioMap& mapToAdd) { - /* Cross check with private map */ - gpioMapIter = gpioMap.find(gpioIdToCheck); - if(gpioMapIter != gpioMap.end()) { - if(gpioMapIter->second->gpioType != gpio::GpioTypes::CALLBACK) { - sif::warning << "LinuxLibgpioIF::checkForConflicts: ID already exists for different " - "GPIO type" << gpioIdToCheck << ". Removing duplicate." << std::endl; - mapToAdd.erase(gpioIdToCheck); - return HasReturnvaluesIF::RETURN_OK; - } - - /* Remove element from map to add because a entry for this GPIO - already exists */ - sif::warning << "LinuxLibgpioIF::checkForConflictsRegularGpio: Duplicate GPIO definition" - << " detected. Duplicate will be removed from map to add." << std::endl; + // Remove element from map to add because a entry for this GPIO already exists +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "LinuxLibgpioIF::checkForConflictsRegularGpio: Duplicate GPIO " + "definition with ID " << gpioIdToCheck << " detected. " << + "Duplicate will be removed from map to add" << std::endl; +#else + sif::printWarning("LinuxLibgpioIF::checkForConflictsRegularGpio: Duplicate GPIO definition " + "with ID %d detected. Duplicate will be removed from map to add\n", gpioIdToCheck); +#endif mapToAdd.erase(gpioIdToCheck); + return GPIO_DUPLICATE_DETECTED; } return HasReturnvaluesIF::RETURN_OK; } void LinuxLibgpioIF::parseFindeLineResult(int result, std::string& lineName) { switch (result) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 case LINE_NOT_EXISTS: - sif::warning << "LinuxLibgpioIF::parseFindeLineResult: Line with name " << lineName - << " does not exist" << std::endl; + case LINE_ERROR: { + sif::warning << "LinuxLibgpioIF::parseFindeLineResult: Line with name " << lineName << + " does not exist" << std::endl; break; - case LINE_ERROR: - sif::warning << "LinuxLibgpioIF::parseFindeLineResult: " << "Line with name " - << lineName << " does not exist" << std::endl; + } + default: { + sif::warning << "LinuxLibgpioIF::parseFindeLineResult: Unknown return code for line " + "with name " << lineName << std::endl; break; - default: - sif::warning << "LinuxLibgpioIF::parseFindeLineResult: Unknown return code for line with " - << "name " << lineName << std::endl; + } +#else + case LINE_NOT_EXISTS: + case LINE_ERROR: { + sif::printWarning("LinuxLibgpioIF::parseFindeLineResult: Line with name %s " + "does not exist\n", lineName); break; } + default: { + sif::printWarning("LinuxLibgpioIF::parseFindeLineResult: Unknown return code for line " + "with name %s\n", lineName); + break; + } +#endif + } } diff --git a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h index d458c362..6489d749 100644 --- a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h +++ b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h @@ -28,6 +28,8 @@ public: HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 3); static constexpr ReturnValue_t GPIO_INVALID_INSTANCE = HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 4); + static constexpr ReturnValue_t GPIO_DUPLICATE_DETECTED = + HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 5); LinuxLibgpioIF(object_id_t objectId); virtual ~LinuxLibgpioIF(); @@ -75,10 +77,9 @@ private: */ ReturnValue_t checkForConflicts(GpioMap& mapToAdd); - ReturnValue_t checkForConflictsRegularGpio(gpioId_t gpiodId, GpiodRegularBase& regularGpio, + ReturnValue_t checkForConflictsById(gpioId_t gpiodId, gpio::GpioTypes type, GpioMap& mapToAdd); - ReturnValue_t checkForConflictsCallbackGpio(gpioId_t gpiodId, GpioCallback* regularGpio, - GpioMap& mapToAdd); + //ReturnValue_t checkForConflictsCallbackGpio(gpioId_t gpiodId, GpioMap& mapToAdd); /** * @brief Performs the initial configuration of all GPIOs specified in the GpioMap mapToAdd. From a84c770dfb8447325c263da42d5cecd99b38d1f0 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 27 Sep 2021 10:51:31 +0200 Subject: [PATCH 067/131] type improvements and bugfixes --- .../fsfw_hal/common/gpio/gpioDefinitions.h | 34 ++++++++++--------- .../fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp | 19 +++++++---- hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h | 19 +++++------ 3 files changed, 39 insertions(+), 33 deletions(-) diff --git a/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h b/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h index 53182058..c6f21195 100644 --- a/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h +++ b/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h @@ -9,12 +9,13 @@ using gpioId_t = uint16_t; namespace gpio { -enum Levels { +enum Levels: uint8_t { LOW = 0, - HIGH = 1 + HIGH = 1, + NONE = 99 }; -enum Direction { +enum Direction: uint8_t { IN = 0, OUT = 1 }; @@ -24,7 +25,7 @@ enum GpioOperation { WRITE }; -enum GpioTypes { +enum class GpioTypes { NONE, GPIO_REGULAR_BY_CHIP, GPIO_REGULAR_BY_LABEL, @@ -34,7 +35,8 @@ enum GpioTypes { static constexpr gpioId_t NO_GPIO = -1; -using gpio_cb_t = void (*) (gpioId_t gpioId, gpio::GpioOperation gpioOp, int value, void* args); +using gpio_cb_t = void (*) (gpioId_t gpioId, gpio::GpioOperation gpioOp, gpio::Levels value, + void* args); } @@ -58,7 +60,7 @@ public: GpioBase() = default; GpioBase(gpio::GpioTypes gpioType, std::string consumer, gpio::Direction direction, - int initValue): + gpio::Levels initValue): gpioType(gpioType), consumer(consumer),direction(direction), initValue(initValue) {} virtual~ GpioBase() {}; @@ -67,19 +69,19 @@ public: gpio::GpioTypes gpioType = gpio::GpioTypes::NONE; std::string consumer; gpio::Direction direction = gpio::Direction::IN; - int initValue = 0; + gpio::Levels initValue = gpio::Levels::NONE; }; class GpiodRegularBase: public GpioBase { public: GpiodRegularBase(gpio::GpioTypes gpioType, std::string consumer, gpio::Direction direction, - int initValue, int lineNum): GpioBase(gpioType, consumer, direction, initValue), - lineNum(lineNum) { + gpio::Levels initValue, int lineNum): + GpioBase(gpioType, consumer, direction, initValue), lineNum(lineNum) { } // line number will be configured at a later point for the open by line name configuration GpiodRegularBase(gpio::GpioTypes gpioType, std::string consumer, gpio::Direction direction, - int initValue): GpioBase(gpioType, consumer, direction, initValue) { + gpio::Levels initValue): GpioBase(gpioType, consumer, direction, initValue) { } int lineNum = 0; @@ -94,7 +96,7 @@ public: } GpiodRegularByChip(std::string chipname_, int lineNum_, std::string consumer_, - gpio::Direction direction_, int initValue_) : + gpio::Direction direction_, gpio::Levels initValue_) : GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP, consumer_, direction_, initValue_, lineNum_), chipname(chipname_){ @@ -112,7 +114,7 @@ public: class GpiodRegularByLabel: public GpiodRegularBase { public: GpiodRegularByLabel(std::string label_, int lineNum_, std::string consumer_, - gpio::Direction direction_, int initValue_) : + gpio::Direction direction_, gpio::Levels initValue_) : GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL, consumer_, direction_, initValue_, lineNum_), label(label_) { @@ -135,14 +137,14 @@ public: class GpiodRegularByLineName: public GpiodRegularBase { public: GpiodRegularByLineName(std::string lineName_, std::string consumer_, gpio::Direction direction_, - int initValue_) : + gpio::Levels initValue_) : GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME, consumer_, direction_, initValue_), lineName(lineName_) { } GpiodRegularByLineName(std::string lineName_, std::string consumer_) : - GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME, consumer_, gpio::Direction::IN, - gpio::LOW), lineName(lineName_) { + GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME, consumer_, + gpio::Direction::IN, gpio::LOW), lineName(lineName_) { } std::string lineName; @@ -150,7 +152,7 @@ public: class GpioCallback: public GpioBase { public: - GpioCallback(std::string consumer, gpio::Direction direction_, int initValue_, + GpioCallback(std::string consumer, gpio::Direction direction_, gpio::Levels initValue_, gpio::gpio_cb_t callback, void* callbackArgs): GpioBase(gpio::GpioTypes::CALLBACK, consumer, direction_, initValue_), callback(callback), callbackArgs(callbackArgs) {} diff --git a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp index 3f8e1f3c..004e1e7f 100644 --- a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp +++ b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp @@ -1,8 +1,9 @@ -#include "fsfw_hal/linux/gpio/LinuxLibgpioIF.h" +#include "LinuxLibgpioIF.h" + #include "fsfw_hal/common/gpio/gpioDefinitions.h" #include "fsfw_hal/common/gpio/GpioCookie.h" -#include +#include "fsfw/serviceinterface/ServiceInterface.h" #include #include @@ -221,7 +222,7 @@ ReturnValue_t LinuxLibgpioIF::pullHigh(gpioId_t gpioId) { return GPIO_INVALID_INSTANCE; } gpioCallback->callback(gpioMapIter->first, gpio::GpioOperation::WRITE, - 1, gpioCallback->callbackArgs); + gpio::Levels::HIGH, gpioCallback->callbackArgs); return RETURN_OK; } return GPIO_TYPE_FAILURE; @@ -254,7 +255,7 @@ ReturnValue_t LinuxLibgpioIF::pullLow(gpioId_t gpioId) { return GPIO_INVALID_INSTANCE; } gpioCallback->callback(gpioMapIter->first, gpio::GpioOperation::WRITE, - 0, gpioCallback->callbackArgs); + gpio::Levels::LOW, gpioCallback->callbackArgs); return RETURN_OK; } return GPIO_TYPE_FAILURE; @@ -299,10 +300,14 @@ ReturnValue_t LinuxLibgpioIF::readGpio(gpioId_t gpioId, int* gpioState) { *gpioState = gpiod_line_get_value(regularGpio->lineHandle); } else { - + auto gpioCallback = dynamic_cast(gpioMapIter->second); + if(gpioCallback->callback == nullptr) { + return GPIO_INVALID_INSTANCE; + } + gpioCallback->callback(gpioMapIter->first, gpio::GpioOperation::READ, + gpio::Levels::NONE, gpioCallback->callbackArgs); + return RETURN_OK; } - - return RETURN_OK; } diff --git a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h index 6489d749..cc32bd70 100644 --- a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h +++ b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h @@ -1,19 +1,19 @@ #ifndef LINUX_GPIO_LINUXLIBGPIOIF_H_ #define LINUX_GPIO_LINUXLIBGPIOIF_H_ -#include "../../common/gpio/GpioIF.h" -#include -#include +#include "fsfw/returnvalues/FwClassIds.h" +#include "fsfw_hal/common/gpio/GpioIF.h" +#include "fsfw/objectmanager/SystemObject.h" class GpioCookie; class GpiodRegularIF; /** - * @brief This class implements the GpioIF for a linux based system. The - * implementation is based on the libgpiod lib which requires linux 4.8 - * or higher. - * @note The Petalinux SDK from Xilinx supports libgpiod since Petalinux - * 2019.1. + * @brief This class implements the GpioIF for a linux based system. + * @details + * This implementation is based on the libgpiod lib which requires Linux 4.8 or higher. + * @note + * The Petalinux SDK from Xilinx supports libgpiod since Petalinux 2019.1. */ class LinuxLibgpioIF : public GpioIF, public SystemObject { public: @@ -46,7 +46,7 @@ private: static const int LINE_ERROR = -1; static const int LINE_FOUND = 1; - /* Holds the information and configuration of all used GPIOs */ + // Holds the information and configuration of all used GPIOs GpioUnorderedMap gpioMap; GpioUnorderedMapIter gpioMapIter; @@ -79,7 +79,6 @@ private: ReturnValue_t checkForConflictsById(gpioId_t gpiodId, gpio::GpioTypes type, GpioMap& mapToAdd); - //ReturnValue_t checkForConflictsCallbackGpio(gpioId_t gpiodId, GpioMap& mapToAdd); /** * @brief Performs the initial configuration of all GPIOs specified in the GpioMap mapToAdd. From ba6cbde28afaf55ff7689db1a18b13793c051d6a Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 27 Sep 2021 11:05:26 +0200 Subject: [PATCH 068/131] Increased TM stack robustness 1. More nullptr check 2. returnvalue for inititalize function which can fail --- src/fsfw/tmtcpacket/SpacePacket.h | 3 +- src/fsfw/tmtcpacket/SpacePacketBase.cpp | 102 ++++--- src/fsfw/tmtcpacket/SpacePacketBase.h | 276 +++++++++--------- src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp | 8 +- src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h | 2 +- .../tmtcpacket/pus/tm/TmPacketStoredPusC.cpp | 44 ++- 6 files changed, 248 insertions(+), 187 deletions(-) diff --git a/src/fsfw/tmtcpacket/SpacePacket.h b/src/fsfw/tmtcpacket/SpacePacket.h index 49dd5ae5..2957576f 100644 --- a/src/fsfw/tmtcpacket/SpacePacket.h +++ b/src/fsfw/tmtcpacket/SpacePacket.h @@ -19,7 +19,8 @@ public: /** * The constructor initializes the packet and sets all header information * according to the passed parameters. - * @param packetDataLength Sets the packet data length field and therefore specifies the size of the packet. + * @param packetDataLength Sets the packet data length field and therefore specifies + * the size of the packet. * @param isTelecommand Sets the packet type field to either TC (true) or TM (false). * @param apid Sets the packet's APID field. The default value describes an idle packet. * @param sequenceCount ets the packet's Source Sequence Count field. diff --git a/src/fsfw/tmtcpacket/SpacePacketBase.cpp b/src/fsfw/tmtcpacket/SpacePacketBase.cpp index e9a0b836..16883d7f 100644 --- a/src/fsfw/tmtcpacket/SpacePacketBase.cpp +++ b/src/fsfw/tmtcpacket/SpacePacketBase.cpp @@ -3,8 +3,8 @@ #include -SpacePacketBase::SpacePacketBase( const uint8_t* set_address ) { - this->data = (SpacePacketPointer*) set_address; +SpacePacketBase::SpacePacketBase(const uint8_t* setAddress) { + this->data = reinterpret_cast(const_cast(setAddress)); } SpacePacketBase::~SpacePacketBase() { @@ -12,94 +12,112 @@ SpacePacketBase::~SpacePacketBase() { //CCSDS Methods: uint8_t SpacePacketBase::getPacketVersionNumber( void ) { - return (this->data->header.packet_id_h & 0b11100000) >> 5; + return (this->data->header.packet_id_h & 0b11100000) >> 5; } -void SpacePacketBase::initSpacePacketHeader(bool isTelecommand, - bool hasSecondaryHeader, uint16_t apid, uint16_t sequenceCount) { - //reset header to zero: - memset(data,0, sizeof(this->data->header) ); - //Set TC/TM bit. - data->header.packet_id_h = ((isTelecommand? 1 : 0)) << 4; - //Set secondaryHeader bit - data->header.packet_id_h |= ((hasSecondaryHeader? 1 : 0)) << 3; - this->setAPID( apid ); - //Always initialize as standalone packets. - data->header.sequence_control_h = 0b11000000; - setPacketSequenceCount(sequenceCount); - +ReturnValue_t SpacePacketBase::initSpacePacketHeader(bool isTelecommand, + bool hasSecondaryHeader, uint16_t apid, uint16_t sequenceCount) { + if(data == nullptr) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "SpacePacketBase::initSpacePacketHeader: Data pointer is invalid" + << std::endl; +#else + sif::printWarning("SpacePacketBase::initSpacePacketHeader: Data pointer is invalid!\n"); +#endif +#endif + return HasReturnvaluesIF::RETURN_FAILED; + } + //reset header to zero: + memset(data, 0, sizeof(this->data->header) ); + //Set TC/TM bit. + data->header.packet_id_h = ((isTelecommand? 1 : 0)) << 4; + //Set secondaryHeader bit + data->header.packet_id_h |= ((hasSecondaryHeader? 1 : 0)) << 3; + this->setAPID( apid ); + //Always initialize as standalone packets. + data->header.sequence_control_h = 0b11000000; + setPacketSequenceCount(sequenceCount); + return HasReturnvaluesIF::RETURN_OK; } bool SpacePacketBase::isTelecommand( void ) { - return (this->data->header.packet_id_h & 0b00010000) >> 4; + return (this->data->header.packet_id_h & 0b00010000) >> 4; } bool SpacePacketBase::hasSecondaryHeader( void ) { - return (this->data->header.packet_id_h & 0b00001000) >> 3; + return (this->data->header.packet_id_h & 0b00001000) >> 3; } uint16_t SpacePacketBase::getPacketId() { - return ( (this->data->header.packet_id_h) << 8 ) + - this->data->header.packet_id_l; + return ( (this->data->header.packet_id_h) << 8 ) + + this->data->header.packet_id_l; } uint16_t SpacePacketBase::getAPID( void ) const { - return ( (this->data->header.packet_id_h & 0b00000111) << 8 ) + - this->data->header.packet_id_l; + return ( (this->data->header.packet_id_h & 0b00000111) << 8 ) + + this->data->header.packet_id_l; } void SpacePacketBase::setAPID( uint16_t new_apid ) { - //Use first three bits of new APID, but keep rest of packet id as it was (see specification). - this->data->header.packet_id_h = (this->data->header.packet_id_h & 0b11111000) | ( ( new_apid & 0x0700 ) >> 8 ); - this->data->header.packet_id_l = ( new_apid & 0x00FF ); + // Use first three bits of new APID, but keep rest of packet id as it was (see specification). + this->data->header.packet_id_h = (this->data->header.packet_id_h & 0b11111000) | + ( ( new_apid & 0x0700 ) >> 8 ); + this->data->header.packet_id_l = ( new_apid & 0x00FF ); +} + +void SpacePacketBase::setSequenceFlags( uint8_t sequenceflags ) { + this->data->header.sequence_control_h &= 0x3F; + this->data->header.sequence_control_h |= sequenceflags << 6; } uint16_t SpacePacketBase::getPacketSequenceControl( void ) { - return ( (this->data->header.sequence_control_h) << 8 ) - + this->data->header.sequence_control_l; + return ( (this->data->header.sequence_control_h) << 8 ) + + this->data->header.sequence_control_l; } uint8_t SpacePacketBase::getSequenceFlags( void ) { - return (this->data->header.sequence_control_h & 0b11000000) >> 6 ; + return (this->data->header.sequence_control_h & 0b11000000) >> 6 ; } uint16_t SpacePacketBase::getPacketSequenceCount( void ) const { - return ( (this->data->header.sequence_control_h & 0b00111111) << 8 ) - + this->data->header.sequence_control_l; + return ( (this->data->header.sequence_control_h & 0b00111111) << 8 ) + + this->data->header.sequence_control_l; } void SpacePacketBase::setPacketSequenceCount( uint16_t new_count) { - this->data->header.sequence_control_h = ( this->data->header.sequence_control_h & 0b11000000 ) | ( ( (new_count%LIMIT_SEQUENCE_COUNT) & 0x3F00 ) >> 8 ); - this->data->header.sequence_control_l = ( (new_count%LIMIT_SEQUENCE_COUNT) & 0x00FF ); + this->data->header.sequence_control_h = ( this->data->header.sequence_control_h & 0b11000000 ) | + ( ( (new_count%LIMIT_SEQUENCE_COUNT) & 0x3F00 ) >> 8 ); + this->data->header.sequence_control_l = ( (new_count%LIMIT_SEQUENCE_COUNT) & 0x00FF ); } uint16_t SpacePacketBase::getPacketDataLength() const { - return ( (this->data->header.packet_length_h) << 8 ) - + this->data->header.packet_length_l; + return ( (this->data->header.packet_length_h) << 8 ) + + this->data->header.packet_length_l; } void SpacePacketBase::setPacketDataLength( uint16_t new_length) { - this->data->header.packet_length_h = ( ( new_length & 0xFF00 ) >> 8 ); - this->data->header.packet_length_l = ( new_length & 0x00FF ); + this->data->header.packet_length_h = ( ( new_length & 0xFF00 ) >> 8 ); + this->data->header.packet_length_l = ( new_length & 0x00FF ); } size_t SpacePacketBase::getFullSize() { - //+1 is done because size in packet data length field is: size of data field -1 - return this->getPacketDataLength() + sizeof(this->data->header) + 1; + // +1 is done because size in packet data length field is: size of data field -1 + return this->getPacketDataLength() + sizeof(this->data->header) + 1; } uint8_t* SpacePacketBase::getWholeData() { - return (uint8_t*)this->data; + return (uint8_t*)this->data; } void SpacePacketBase::setData( const uint8_t* p_Data ) { - this->data = (SpacePacketPointer*)p_Data; + this->data = (SpacePacketPointer*)p_Data; } uint32_t SpacePacketBase::getApidAndSequenceCount() const { - return (getAPID() << 16) + getPacketSequenceCount(); + return (getAPID() << 16) + getPacketSequenceCount(); } uint8_t* SpacePacketBase::getPacketData() { - return &(data->packet_data); + return &(data->packet_data); } diff --git a/src/fsfw/tmtcpacket/SpacePacketBase.h b/src/fsfw/tmtcpacket/SpacePacketBase.h index 13cb3130..1ebc484f 100644 --- a/src/fsfw/tmtcpacket/SpacePacketBase.h +++ b/src/fsfw/tmtcpacket/SpacePacketBase.h @@ -2,6 +2,8 @@ #define FSFW_TMTCPACKET_SPACEPACKETBASE_H_ #include "ccsds_header.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" + #include /** @@ -20,8 +22,8 @@ * @ingroup tmtcpackets */ struct SpacePacketPointer { - CCSDSPrimaryHeader header; - uint8_t packet_data; + CCSDSPrimaryHeader header; + uint8_t packet_data; }; /** @@ -37,143 +39,151 @@ struct SpacePacketPointer { */ class SpacePacketBase { protected: - /** - * A pointer to a structure which defines the data structure of - * the packet header. - * To be hardware-safe, all elements are of byte size. - */ - SpacePacketPointer* data; + /** + * A pointer to a structure which defines the data structure of + * the packet header. + * To be hardware-safe, all elements are of byte size. + */ + SpacePacketPointer* data; public: - static const uint16_t LIMIT_APID = 2048; //2^1 - static const uint16_t LIMIT_SEQUENCE_COUNT = 16384; // 2^14 - static const uint16_t APID_IDLE_PACKET = 0x7FF; - static const uint8_t TELECOMMAND_PACKET = 1; - static const uint8_t TELEMETRY_PACKET = 0; - /** - * This definition defines the CRC size in byte. - */ - static const uint8_t CRC_SIZE = 2; - /** - * This is the minimum size of a SpacePacket. - */ - static const uint16_t MINIMUM_SIZE = sizeof(CCSDSPrimaryHeader) + CRC_SIZE; - /** - * This is the default constructor. - * It sets its internal data pointer to the address passed. - * @param set_address The position where the packet data lies. - */ - SpacePacketBase( const uint8_t* set_address ); - /** - * No data is allocated, so the destructor is empty. - */ - virtual ~SpacePacketBase(); + static const uint16_t LIMIT_APID = 2048; //2^1 + static const uint16_t LIMIT_SEQUENCE_COUNT = 16384; // 2^14 + static const uint16_t APID_IDLE_PACKET = 0x7FF; + static const uint8_t TELECOMMAND_PACKET = 1; + static const uint8_t TELEMETRY_PACKET = 0; + /** + * This definition defines the CRC size in byte. + */ + static const uint8_t CRC_SIZE = 2; + /** + * This is the minimum size of a SpacePacket. + */ + static const uint16_t MINIMUM_SIZE = sizeof(CCSDSPrimaryHeader) + CRC_SIZE; + /** + * This is the default constructor. + * It sets its internal data pointer to the address passed. + * @param set_address The position where the packet data lies. + */ + SpacePacketBase( const uint8_t* set_address ); + /** + * No data is allocated, so the destructor is empty. + */ + virtual ~SpacePacketBase(); - //CCSDS Methods: - /** - * Getter for the packet version number field. - * @return Returns the highest three bit of the packet in one byte. - */ - uint8_t getPacketVersionNumber( void ); - /** - * This method checks the type field in the header. - * This bit specifies, if the command is interpreted as Telecommand of - * as Telemetry. For a Telecommand, the bit is set. - * @return Returns true if the bit is set and false if not. - */ - bool isTelecommand( void ); + //CCSDS Methods - void initSpacePacketHeader(bool isTelecommand, bool hasSecondaryHeader, - uint16_t apid, uint16_t sequenceCount = 0); - /** - * The CCSDS header provides a secondary header flag (the fifth-highest bit), - * which is checked with this method. - * @return Returns true if the bit is set and false if not. - */ - bool hasSecondaryHeader( void ); - /** - * Returns the complete first two bytes of the packet, which together form - * the CCSDS packet id. - * @return The CCSDS packet id. - */ - uint16_t getPacketId( void ); - /** - * Returns the APID of a packet, which are the lowest 11 bit of the packet - * id. - * @return The CCSDS APID. - */ - uint16_t getAPID( void ) const; - /** - * Sets the APID of a packet, which are the lowest 11 bit of the packet - * id. - * @param The APID to set. The highest five bits of the parameter are - * ignored. - */ - void setAPID( uint16_t setAPID ); - /** - * Returns the CCSDS packet sequence control field, which are the third and - * the fourth byte of the CCSDS primary header. - * @return The CCSDS packet sequence control field. - */ - uint16_t getPacketSequenceControl( void ); - /** - * Returns the SequenceFlags, which are the highest two bit of the packet - * sequence control field. - * @return The CCSDS sequence flags. - */ - uint8_t getSequenceFlags( void ); - /** - * Returns the packet sequence count, which are the lowest 14 bit of the - * packet sequence control field. - * @return The CCSDS sequence count. - */ - uint16_t getPacketSequenceCount( void ) const; - /** - * Sets the packet sequence count, which are the lowest 14 bit of the - * packet sequence control field. - * setCount is modulo-divided by \c LIMIT_SEQUENCE_COUNT to avoid overflows. - * @param setCount The value to set the count to. - */ - void setPacketSequenceCount( uint16_t setCount ); - /** - * Returns the packet data length, which is the fifth and sixth byte of the - * CCSDS Primary Header. The packet data length is the size of every kind - * of data \b after the CCSDS Primary Header \b -1. - * @return - * The CCSDS packet data length. uint16_t is sufficient, - * because this is limit in CCSDS standard - */ - uint16_t getPacketDataLength(void) const; - /** - * Sets the packet data length, which is the fifth and sixth byte of the - * CCSDS Primary Header. - * @param setLength The value of the length to set. It must fit the true - * CCSDS packet data length . The packet data length is - * the size of every kind of data \b after the CCSDS - * Primary Header \b -1. - */ - void setPacketDataLength( uint16_t setLength ); + /** + * Getter for the packet version number field. + * @return Returns the highest three bit of the packet in one byte. + */ + uint8_t getPacketVersionNumber( void ); + /** + * This method checks the type field in the header. + * This bit specifies, if the command is interpreted as Telecommand of + * as Telemetry. For a Telecommand, the bit is set. + * @return Returns true if the bit is set and false if not. + */ + bool isTelecommand( void ); - //Helper methods: - /** - * This method returns a raw uint8_t pointer to the packet. - * @return A \c uint8_t pointer to the first byte of the CCSDS primary header. - */ - virtual uint8_t* getWholeData( void ); + ReturnValue_t initSpacePacketHeader(bool isTelecommand, bool hasSecondaryHeader, + uint16_t apid, uint16_t sequenceCount = 0); + /** + * The CCSDS header provides a secondary header flag (the fifth-highest bit), + * which is checked with this method. + * @return Returns true if the bit is set and false if not. + */ + bool hasSecondaryHeader( void ); + /** + * Returns the complete first two bytes of the packet, which together form + * the CCSDS packet id. + * @return The CCSDS packet id. + */ + uint16_t getPacketId( void ); + /** + * Returns the APID of a packet, which are the lowest 11 bit of the packet + * id. + * @return The CCSDS APID. + */ + uint16_t getAPID( void ) const; + /** + * Sets the APID of a packet, which are the lowest 11 bit of the packet + * id. + * @param The APID to set. The highest five bits of the parameter are + * ignored. + */ + void setAPID( uint16_t setAPID ); - uint8_t* getPacketData(); - /** - * With this method, the packet data pointer can be redirected to another - * location. - * @param p_Data A pointer to another raw Space Packet. - */ - virtual void setData( const uint8_t* p_Data ); - /** - * This method returns the full raw packet size. - * @return The full size of the packet in bytes. - */ - size_t getFullSize(); + /** + * Sets the sequence flags of a packet, which are bit 17 and 18 in the space packet header. + * @param The sequence flags to set + */ + void setSequenceFlags( uint8_t sequenceflags ); - uint32_t getApidAndSequenceCount() const; + /** + * Returns the CCSDS packet sequence control field, which are the third and + * the fourth byte of the CCSDS primary header. + * @return The CCSDS packet sequence control field. + */ + uint16_t getPacketSequenceControl( void ); + /** + * Returns the SequenceFlags, which are the highest two bit of the packet + * sequence control field. + * @return The CCSDS sequence flags. + */ + uint8_t getSequenceFlags( void ); + /** + * Returns the packet sequence count, which are the lowest 14 bit of the + * packet sequence control field. + * @return The CCSDS sequence count. + */ + uint16_t getPacketSequenceCount( void ) const; + /** + * Sets the packet sequence count, which are the lowest 14 bit of the + * packet sequence control field. + * setCount is modulo-divided by \c LIMIT_SEQUENCE_COUNT to avoid overflows. + * @param setCount The value to set the count to. + */ + void setPacketSequenceCount( uint16_t setCount ); + /** + * Returns the packet data length, which is the fifth and sixth byte of the + * CCSDS Primary Header. The packet data length is the size of every kind + * of data \b after the CCSDS Primary Header \b -1. + * @return + * The CCSDS packet data length. uint16_t is sufficient, + * because this is limit in CCSDS standard + */ + uint16_t getPacketDataLength(void) const; + /** + * Sets the packet data length, which is the fifth and sixth byte of the + * CCSDS Primary Header. + * @param setLength The value of the length to set. It must fit the true + * CCSDS packet data length . The packet data length is + * the size of every kind of data \b after the CCSDS + * Primary Header \b -1. + */ + void setPacketDataLength( uint16_t setLength ); + + // Helper methods + /** + * This method returns a raw uint8_t pointer to the packet. + * @return A \c uint8_t pointer to the first byte of the CCSDS primary header. + */ + virtual uint8_t* getWholeData( void ); + + uint8_t* getPacketData(); + /** + * With this method, the packet data pointer can be redirected to another + * location. + * @param p_Data A pointer to another raw Space Packet. + */ + virtual void setData( const uint8_t* p_Data ); + /** + * This method returns the full raw packet size. + * @return The full size of the packet in bytes. + */ + size_t getFullSize(); + + uint32_t getApidAndSequenceCount() const; }; diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp index ea25f5d2..2c6e1d97 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp @@ -53,11 +53,14 @@ uint8_t* TmPacketPusC::getPacketTimeRaw() const{ } -void TmPacketPusC::initializeTmPacket(uint16_t apid, uint8_t service, +ReturnValue_t TmPacketPusC::initializeTmPacket(uint16_t apid, uint8_t service, uint8_t subservice, uint16_t packetSubcounter, uint16_t destinationId, uint8_t timeRefField) { //Set primary header: - initSpacePacketHeader(false, true, apid); + ReturnValue_t result = initSpacePacketHeader(false, true, apid); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } //Set data Field Header: //First, set to zero. memset(&tmData->dataField, 0, sizeof(tmData->dataField)); @@ -76,6 +79,7 @@ void TmPacketPusC::initializeTmPacket(uint16_t apid, uint8_t service, timeStamper->addTimeStamp(tmData->dataField.time, sizeof(tmData->dataField.time)); } + return HasReturnvaluesIF::RETURN_OK; } void TmPacketPusC::setSourceDataSize(uint16_t size) { diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h index fe373c6f..3a9be132 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h @@ -100,7 +100,7 @@ protected: * @param subservice PUS Subservice * @param packetSubcounter Additional subcounter used. */ - void initializeTmPacket(uint16_t apid, uint8_t service, uint8_t subservice, + ReturnValue_t initializeTmPacket(uint16_t apid, uint8_t service, uint8_t subservice, uint16_t packetSubcounter, uint16_t destinationId = 0, uint8_t timeRefField = 0); /** diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp index add4f4b9..4a6e4d21 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp @@ -43,27 +43,55 @@ TmPacketStoredPusC::TmPacketStoredPusC(uint16_t apid, uint8_t service, return; } size_t sourceDataSize = 0; - if (content != NULL) { + if (content != nullptr) { sourceDataSize += content->getSerializedSize(); } - if (header != NULL) { + if (header != nullptr) { sourceDataSize += header->getSerializedSize(); } - uint8_t *p_data = NULL; - ReturnValue_t returnValue = store->getFreeElement(&storeAddress, - (getPacketMinimumSize() + sourceDataSize), &p_data); + uint8_t *pData = nullptr; + size_t sizeToReserve = getPacketMinimumSize() + sourceDataSize; + ReturnValue_t returnValue = store->getFreeElement(&storeAddress, sizeToReserve, &pData); if (returnValue != store->RETURN_OK) { +#if FSFW_VERBOSE_LEVEL >= 1 + switch(returnValue) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + case(StorageManagerIF::DATA_STORAGE_FULL): { + sif::warning << "TmPacketStoredPusC::TmPacketStoredPusC: Store full for packet with " + "size " << sizeToReserve << std::endl; + break; + } + case(StorageManagerIF::DATA_TOO_LARGE): { + sif::warning << "TmPacketStoredPusC::TmPacketStoredPusC: Data with size " << + sizeToReserve << " too large" << std::endl; + break; + } +#else + case(StorageManagerIF::DATA_STORAGE_FULL): { + sif::printWarning("TmPacketStoredPusC::TmPacketStoredPusC: Store full for packet with " + "size %d\n", sizeToReserve); + break; + } + case(StorageManagerIF::DATA_TOO_LARGE): { + sif::printWarning("TmPacketStoredPusC::TmPacketStoredPusC: Data with size " + "%d too large\n", sizeToReserve); + break; + } +#endif +#endif + } TmPacketStoredBase::checkAndReportLostTm(); + return; } - setData(p_data); + setData(pData); initializeTmPacket(apid, service, subservice, packetSubcounter, destinationId, timeRefField); uint8_t *putDataHere = getSourceData(); size_t size = 0; - if (header != NULL) { + if (header != nullptr) { header->serialize(&putDataHere, &size, sourceDataSize, SerializeIF::Endianness::BIG); } - if (content != NULL) { + if (content != nullptr) { content->serialize(&putDataHere, &size, sourceDataSize, SerializeIF::Endianness::BIG); } From df0adfb33c376adb386a2b1df46ff79848a563e1 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 27 Sep 2021 15:35:09 +0200 Subject: [PATCH 069/131] added new tcp code --- src/fsfw/osal/common/TcpTmTcServer.cpp | 77 ++++++++++++++++++++------ 1 file changed, 61 insertions(+), 16 deletions(-) diff --git a/src/fsfw/osal/common/TcpTmTcServer.cpp b/src/fsfw/osal/common/TcpTmTcServer.cpp index c819f9e7..06cace2d 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.cpp +++ b/src/fsfw/osal/common/TcpTmTcServer.cpp @@ -5,6 +5,7 @@ #include "TcpTmTcBridge.h" #include "tcpipHelpers.h" +#include "fsfw/tasks/TaskFactory.h" #include "fsfw/container/SharedRingBuffer.h" #include "fsfw/ipc/MessageQueueSenderIF.h" #include "fsfw/ipc/MutexGuard.h" @@ -19,6 +20,7 @@ #elif defined(PLATFORM_UNIX) #include #endif +#include #ifndef FSFW_TCP_RECV_WIRETAPPING_ENABLED #define FSFW_TCP_RECV_WIRETAPPING_ENABLED 0 @@ -28,8 +30,8 @@ const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_POR TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, size_t receptionBufferSize, std::string customTcpServerPort): - SystemObject(objectId), tmtcBridgeId(tmtcTcpBridge), - tcpPort(customTcpServerPort), receptionBuffer(receptionBufferSize) { + SystemObject(objectId), tmtcBridgeId(tmtcTcpBridge), + tcpPort(customTcpServerPort), receptionBuffer(receptionBufferSize) { if(tcpPort == "") { tcpPort = DEFAULT_SERVER_PORT; } @@ -148,24 +150,67 @@ ReturnValue_t TcpTmTcServer::initializeAfterTaskCreation() { void TcpTmTcServer::handleServerOperation(socket_t connSocket) { int retval = 0; - do { - // Read all telecommands sent by the client - retval = recv(connSocket, - reinterpret_cast(receptionBuffer.data()), - receptionBuffer.capacity(), - tcpFlags); - if (retval > 0) { - handleTcReception(retval); + using namespace std::chrono_literals; + + // Receive until the peer shuts down the connection, use select to do this + fd_set rfds; + fd_set efds; + + FD_ZERO(&rfds); + FD_SET(connSocket, &rfds); + + FD_ZERO(&efds); + FD_SET(connSocket, &efds); + + timeval tv; + tv.tv_sec = 1; + tv.tv_usec = 0; + + int nfds = connSocket + 1; + + // do { + // // Read all telecommands sent by the client + // retval = recv( + // connSocket, + // reinterpret_cast(receptionBuffer.data()), + // receptionBuffer.capacity(), + // tcpFlags + // ); + // if (retval > 0) { + // handleTcReception(retval); + // } + // else if(retval == 0) { + // // Client has finished sending telecommands, send telemetry now + // handleTmSending(connSocket); + // } + // else { + // // Should not happen + // tcpip::handleError(tcpip::Protocol::TCP, tcpip::ErrorSources::RECV_CALL); + // } + // } while(retval > 0); + while (true) { + uint32_t index = 0; + int retval = select(nfds, &rfds, nullptr, &efds, &tv); + if(retval < 0) { + // client might have shut down connection? } - else if(retval == 0) { - // Client has finished sending telecommands, send telemetry now - handleTmSending(connSocket); + else if(retval > 0) { + if(FD_ISSET(connSocket, &rfds)) { + // data available + //int result = receiveData(); + //if(result == 0) { + // break; + //} + } + if(FD_ISSET(connSocket, &efds)) { + //spdlog::error("{}: Exception detected on receive FD", tcpip::SERVER_PR); + } } else { - // Should not happen - tcpip::handleError(tcpip::Protocol::TCP, tcpip::ErrorSources::RECV_CALL); + // no data available + TaskFactory::delayTask(500); } - } while(retval > 0); + } } ReturnValue_t TcpTmTcServer::handleTcReception(size_t bytesRecvd) { From 45c0074bd705673448f5978375df792a83dafaf0 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 27 Sep 2021 15:50:23 +0200 Subject: [PATCH 070/131] printout improvements --- src/fsfw/osal/common/TcpTmTcServer.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/fsfw/osal/common/TcpTmTcServer.cpp b/src/fsfw/osal/common/TcpTmTcServer.cpp index 06cace2d..ee1b0f23 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.cpp +++ b/src/fsfw/osal/common/TcpTmTcServer.cpp @@ -222,20 +222,27 @@ ReturnValue_t TcpTmTcServer::handleTcReception(size_t bytesRecvd) { if (result != HasReturnvaluesIF::RETURN_OK) { #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning<< "TcpTmTcServer::handleServerOperation: Data storage failed." << std::endl; - sif::warning << "Packet size: " << bytesRecvd << std::endl; + sif::warning << "TcpTmTcServer::handleServerOperation: Data storage with packet size" << + bytesRecvd << " failed" << std::endl; +#else + sif::printWarning("TcpTmTcServer::handleServerOperation: Data storage with packet size %d " + "failed\n", bytesRecvd); #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ #endif /* FSFW_VERBOSE_LEVEL >= 1 */ + return result; } TmTcMessage message(storeId); - result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message); + result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message); if (result != HasReturnvaluesIF::RETURN_OK) { #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "UdpTcPollingTask::handleSuccessfullTcRead: " + sif::warning << "TcpTmTcServer::handleServerOperation: " " Sending message to queue failed" << std::endl; +#else + sif::printWarning("TcpTmTcServer::handleServerOperation: " + " Sending message to queue failed\n"); #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ #endif /* FSFW_VERBOSE_LEVEL >= 1 */ tcStore->deleteData(storeId); From 62a6e5da0bc18f5913ed794accfca6c96abdd59b Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 27 Sep 2021 16:11:48 +0200 Subject: [PATCH 071/131] added PUS again --- src/fsfw/osal/common/TcpTmTcServer.cpp | 25 +++-- src/fsfw/osal/common/TcpTmTcServer.h | 3 + src/fsfw/tmtcservices/PusParser.cpp | 141 +++++++++++++++++++++++++ src/fsfw/tmtcservices/PusParser.h | 83 +++++++++++++++ 4 files changed, 244 insertions(+), 8 deletions(-) create mode 100644 src/fsfw/tmtcservices/PusParser.cpp create mode 100644 src/fsfw/tmtcservices/PusParser.h diff --git a/src/fsfw/osal/common/TcpTmTcServer.cpp b/src/fsfw/osal/common/TcpTmTcServer.cpp index ee1b0f23..1de0816d 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.cpp +++ b/src/fsfw/osal/common/TcpTmTcServer.cpp @@ -30,8 +30,8 @@ const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_POR TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, size_t receptionBufferSize, std::string customTcpServerPort): - SystemObject(objectId), tmtcBridgeId(tmtcTcpBridge), - tcpPort(customTcpServerPort), receptionBuffer(receptionBufferSize) { + SystemObject(objectId), tmtcBridgeId(tmtcTcpBridge), + tcpPort(customTcpServerPort), receptionBuffer(receptionBufferSize) { if(tcpPort == "") { tcpPort = DEFAULT_SERVER_PORT; } @@ -127,7 +127,7 @@ ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) { handleServerOperation(connSocket); // Done, shut down connection and go back to listening for client requests - retval = shutdown(connSocket, SHUT_SEND); + retval = shutdown(connSocket, SHUT_BOTH); if(retval != 0) { handleError(Protocol::TCP, ErrorSources::SHUTDOWN_CALL); } @@ -163,8 +163,8 @@ void TcpTmTcServer::handleServerOperation(socket_t connSocket) { FD_SET(connSocket, &efds); timeval tv; - tv.tv_sec = 1; - tv.tv_usec = 0; + tv.tv_sec = selectTimeoutMs / 1000; + tv.tv_usec = (selectTimeoutMs % 1000) * 1000; int nfds = connSocket + 1; @@ -192,11 +192,19 @@ void TcpTmTcServer::handleServerOperation(socket_t connSocket) { uint32_t index = 0; int retval = select(nfds, &rfds, nullptr, &efds, &tv); if(retval < 0) { - // client might have shut down connection? + // client might have shut down connection + return; } else if(retval > 0) { if(FD_ISSET(connSocket, &rfds)) { // data available + int retval = recv( + connSocket, + reinterpret_cast(receptionBuffer.data()), + receptionBuffer.capacity(), + tcpFlags + ); + handleTcReception(retval); //int result = receiveData(); //if(result == 0) { // break; @@ -207,8 +215,9 @@ void TcpTmTcServer::handleServerOperation(socket_t connSocket) { } } else { - // no data available - TaskFactory::delayTask(500); + // no data available. Send back telemetry now + handleTmSending(connSocket); + //TaskFactory::delayTask(500); } } } diff --git a/src/fsfw/osal/common/TcpTmTcServer.h b/src/fsfw/osal/common/TcpTmTcServer.h index c6916080..a33a0427 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.h +++ b/src/fsfw/osal/common/TcpTmTcServer.h @@ -45,6 +45,7 @@ public: static const std::string DEFAULT_SERVER_PORT; static constexpr size_t ETHERNET_MTU_SIZE = 1500; + static constexpr uint32_t DEFAULT_SELECT_TIMEOUT_MS = 200; /** * TCP Server Constructor @@ -59,6 +60,7 @@ public: std::string customTcpServerPort = ""); virtual~ TcpTmTcServer(); + void setSelectTimeout(uint32_t timeout); void setTcpBacklog(uint8_t tcpBacklog); ReturnValue_t initialize() override; @@ -77,6 +79,7 @@ private: std::string tcpPort; int tcpFlags = 0; + uint32_t selectTimeoutMs = DEFAULT_SELECT_TIMEOUT_MS; socket_t listenerTcpSocket = 0; struct sockaddr tcpAddress; MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE; diff --git a/src/fsfw/tmtcservices/PusParser.cpp b/src/fsfw/tmtcservices/PusParser.cpp new file mode 100644 index 00000000..42044da3 --- /dev/null +++ b/src/fsfw/tmtcservices/PusParser.cpp @@ -0,0 +1,141 @@ +#include "PusParser.h" +#include + +PusParser::PusParser(uint16_t maxExpectedPusPackets, + bool storeSplitPackets): indexSizePairFIFO(maxExpectedPusPackets) { +} + +ReturnValue_t PusParser::parsePusPackets(const uint8_t *frame, + size_t frameSize) { + if(frame == nullptr or frameSize < 5) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "PusParser::parsePusPackets: Frame invalid!" << std::endl; +#else + sif::printError("PusParser::parsePusPackets: Frame invalid!\n"); +#endif + return HasReturnvaluesIF::RETURN_FAILED; + } + + if(indexSizePairFIFO.full()) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "PusParser::parsePusPackets: FIFO is full!" << std::endl; +#else + sif::printError("PusParser::parsePusPackets: FIFO is full!\n"); +#endif + return HasReturnvaluesIF::RETURN_FAILED; + } + + size_t lengthField = frame[4] << 8 | frame[5]; + + if(lengthField == 0) { + return NO_PACKET_FOUND; + } + + size_t packetSize = lengthField + 7; + // sif::debug << frameSize << std::endl; + // Size of a pus packet is the value in the packet length field plus 7. + if(packetSize > frameSize) { + if(storeSplitPackets) { + indexSizePairFIFO.insert(indexSizePair(0, frameSize)); + } + else { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::debug << "TcSerialPollingTask::readNextPacket: Next packet " + << "larger than remaining frame," << std::endl; + sif::debug << "Throwing away packet. Detected packet size: " + << packetSize << std::endl; +#else + sif::printDebug("TcSerialPollingTask::readNextPacket: Next packet " + "larger than remaining frame.\n"); + sif::printDebug("Throwing away packet. Detected packet size: %lu", + static_cast(packetSize)); +#endif + } + return SPLIT_PACKET; + } + else { + indexSizePairFIFO.insert(indexSizePair(0, packetSize)); + if(packetSize == frameSize) { + return HasReturnvaluesIF::RETURN_OK; + } + } + + // packet size is smaller than frame size, parse for more packets. + return readMultiplePackets(frame, frameSize, packetSize); +} + +ReturnValue_t PusParser::readMultiplePackets(const uint8_t *frame, + size_t frameSize, size_t startIndex) { + while (startIndex < frameSize) { + ReturnValue_t result = readNextPacket(frame, frameSize, startIndex); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +DynamicFIFO* PusParser::fifo(){ + return &indexSizePairFIFO; +} + +PusParser::indexSizePair PusParser::getNextFifoPair() { + indexSizePair nextIndexSizePair; + indexSizePairFIFO.retrieve(&nextIndexSizePair); + return nextIndexSizePair; +} + +ReturnValue_t PusParser::readNextPacket(const uint8_t *frame, + size_t frameSize, size_t& currentIndex) { + // sif::debug << startIndex << std::endl; + if(currentIndex + 5 > frameSize) { + currentIndex = frameSize; + return HasReturnvaluesIF::RETURN_OK; + } + + uint16_t lengthField = frame[currentIndex + 4] << 8 | + frame[currentIndex + 5]; + if(lengthField == 0) { + // It is assumed that no packet follows. + currentIndex = frameSize; + return HasReturnvaluesIF::RETURN_OK; + } + size_t nextPacketSize = lengthField + 7; + size_t remainingSize = frameSize - currentIndex; + if(nextPacketSize > remainingSize) + { + if(storeSplitPackets) { + indexSizePairFIFO.insert(indexSizePair(currentIndex, remainingSize)); + } + else { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::debug << "TcSerialPollingTask::readNextPacket: Next packet " + << "larger than remaining frame." << std::endl; + sif::debug << "Throwing away packet. Detected packet size: " + << nextPacketSize << std::endl; +#else + sif::printDebug("TcSerialPollingTask::readNextPacket: Next packet " + "larger than remaining frame.\n"); + sif::printDebug("Throwing away packet. Detected packet size: %lu\n", + static_cast(nextPacketSize)); +#endif + } + return SPLIT_PACKET; + } + + ReturnValue_t result = indexSizePairFIFO.insert(indexSizePair(currentIndex, + nextPacketSize)); + if (result != HasReturnvaluesIF::RETURN_OK) { + // FIFO full. +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::debug << "PusParser: Issue inserting into start index size " + << "FIFO, it is full!" << std::endl; +#else + sif::printDebug("PusParser: Issue inserting into start index size " + "FIFO, it is full!\n"); +#endif + } + currentIndex += nextPacketSize; + + return result; +} diff --git a/src/fsfw/tmtcservices/PusParser.h b/src/fsfw/tmtcservices/PusParser.h new file mode 100644 index 00000000..0efbdcc5 --- /dev/null +++ b/src/fsfw/tmtcservices/PusParser.h @@ -0,0 +1,83 @@ +#ifndef FRAMEWORK_TMTCSERVICES_PUSPARSER_H_ +#define FRAMEWORK_TMTCSERVICES_PUSPARSER_H_ + +#include +#include +#include + +/** + * @brief This small helper class scans a given buffer for PUS packets. + * Can be used if PUS packets are serialized in a tightly packed frame. + * @details + * The parser uses the payload length field of PUS packets to find + * the respective PUS packet sizes. + * + * The parser parses a buffer by taking a pointer and the maximum size to scan. + * If PUS packets are found, they are stored in a FIFO which stores pairs + * consisting of the index in the buffer and the respective packet sizes. + * + * If the parser detects split packets (which means that the size of the + * next packet is larger than the remaining size to scan), it can either + * store that split packet or throw away the packet. + * @author R. Mueller + */ +class PusParser { +public: + //! The first entry is the index inside the buffer while the second index + //! is the size of the PUS packet starting at that index. + using indexSizePair = std::pair; + + static constexpr uint8_t INTERFACE_ID = CLASS_ID::PUS_PARSER; + static constexpr ReturnValue_t NO_PACKET_FOUND = MAKE_RETURN_CODE(0x00); + static constexpr ReturnValue_t SPLIT_PACKET = MAKE_RETURN_CODE(0x01); + /** + * Parser constructor. + * @param maxExpectedPusPackets + * Maximum expected number of PUS packets. A good estimate is to divide + * the frame size by the minimum size of a PUS packet (12 bytes) + * @param storeSplitPackets + * Specifies whether split packets are also stored inside the FIFO, + * with the size being the remaining frame size. + */ + PusParser(uint16_t maxExpectedPusPackets, bool storeSplitPackets); + + /** + * Parse a given frame for PUS packets + * @param frame + * @param frameSize + * @return -@c NO_PACKET_FOUND if no packet was found. + */ + ReturnValue_t parsePusPackets(const uint8_t* frame, size_t frameSize); + + /** + * Accessor function to get a reference to the internal FIFO which + * stores pairs of indexi and packet sizes. This FIFO is filled + * by the parsePusPackets() function. + * @return + */ + DynamicFIFO* fifo(); + + /** + * Retrieve the next index and packet size pair from the FIFO. + * This also removed it from the FIFO. Please note that if the FIFO + * is empty, an empty pair will be returned. + * @return + */ + indexSizePair getNextFifoPair(); + +private: + /** A FIFO is used to store information about multiple PUS packets + * inside the receive buffer. The maximum number of entries is defined + * by the first constructor argument. + */ + DynamicFIFO indexSizePairFIFO; + + bool storeSplitPackets = false; + + ReturnValue_t readMultiplePackets(const uint8_t *frame, size_t frameSize, + size_t startIndex); + ReturnValue_t readNextPacket(const uint8_t *frame, + size_t frameSize, size_t& startIndex); +}; + +#endif /* FRAMEWORK_TMTCSERVICES_PUSPARSER_H_ */ From 68fe94d5944a5462cd0ba05d96ded321c1f52e20 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 27 Sep 2021 16:15:51 +0200 Subject: [PATCH 072/131] PusParser integration --- src/fsfw/returnvalues/FwClassIds.h | 1 + src/fsfw/tmtcservices/PusParser.cpp | 26 +++++++++++++++----------- src/fsfw/tmtcservices/PusParser.h | 7 +++++-- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/fsfw/returnvalues/FwClassIds.h b/src/fsfw/returnvalues/FwClassIds.h index 4a3a578a..8422baa5 100644 --- a/src/fsfw/returnvalues/FwClassIds.h +++ b/src/fsfw/returnvalues/FwClassIds.h @@ -80,6 +80,7 @@ enum: uint8_t { FIXED_SLOT_TASK_IF, //FTIF MGM_LIS3MDL, //MGMLIS3 MGM_RM3100, //MGMRM3100 + PUS_PARSER, //PUSP FW_CLASS_ID_COUNT // [EXPORT] : [END] }; diff --git a/src/fsfw/tmtcservices/PusParser.cpp b/src/fsfw/tmtcservices/PusParser.cpp index 42044da3..5b63710c 100644 --- a/src/fsfw/tmtcservices/PusParser.cpp +++ b/src/fsfw/tmtcservices/PusParser.cpp @@ -1,8 +1,8 @@ #include "PusParser.h" #include -PusParser::PusParser(uint16_t maxExpectedPusPackets, - bool storeSplitPackets): indexSizePairFIFO(maxExpectedPusPackets) { +PusParser::PusParser(uint16_t maxExpectedPusPackets, bool storeSplitPackets): + indexSizePairFIFO(maxExpectedPusPackets) { } ReturnValue_t PusParser::parsePusPackets(const uint8_t *frame, @@ -39,17 +39,19 @@ ReturnValue_t PusParser::parsePusPackets(const uint8_t *frame, indexSizePairFIFO.insert(indexSizePair(0, frameSize)); } else { +#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "TcSerialPollingTask::readNextPacket: Next packet " + sif::warning << "TcSerialPollingTask::readNextPacket: Next packet " << "larger than remaining frame," << std::endl; - sif::debug << "Throwing away packet. Detected packet size: " + sif::warning << "Throwing away packet. Detected packet size: " << packetSize << std::endl; #else - sif::printDebug("TcSerialPollingTask::readNextPacket: Next packet " + sif::printWarning("TcSerialPollingTask::readNextPacket: Next packet " "larger than remaining frame.\n"); - sif::printDebug("Throwing away packet. Detected packet size: %lu", + sif::printWarning("Throwing away packet. Detected packet size: %lu", static_cast(packetSize)); -#endif +#endif +#endif /* FSFW_VERBOSE_LEVEL >= 1 */ } return SPLIT_PACKET; } @@ -108,16 +110,18 @@ ReturnValue_t PusParser::readNextPacket(const uint8_t *frame, indexSizePairFIFO.insert(indexSizePair(currentIndex, remainingSize)); } else { +#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "TcSerialPollingTask::readNextPacket: Next packet " + sif::warning << "TcSerialPollingTask::readNextPacket: Next packet " << "larger than remaining frame." << std::endl; - sif::debug << "Throwing away packet. Detected packet size: " + sif::warning << "Throwing away packet. Detected packet size: " << nextPacketSize << std::endl; #else - sif::printDebug("TcSerialPollingTask::readNextPacket: Next packet " + sif::printWarning("TcSerialPollingTask::readNextPacket: Next packet " "larger than remaining frame.\n"); - sif::printDebug("Throwing away packet. Detected packet size: %lu\n", + sif::printWarning("Throwing away packet. Detected packet size: %lu\n", static_cast(nextPacketSize)); +#endif #endif } return SPLIT_PACKET; diff --git a/src/fsfw/tmtcservices/PusParser.h b/src/fsfw/tmtcservices/PusParser.h index 0efbdcc5..851f1a5d 100644 --- a/src/fsfw/tmtcservices/PusParser.h +++ b/src/fsfw/tmtcservices/PusParser.h @@ -1,7 +1,9 @@ #ifndef FRAMEWORK_TMTCSERVICES_PUSPARSER_H_ #define FRAMEWORK_TMTCSERVICES_PUSPARSER_H_ -#include +#include "fsfw/container/DynamicFIFO.h" +#include "fsfw/returnvalues/FwClassIds.h" + #include #include @@ -66,7 +68,8 @@ public: indexSizePair getNextFifoPair(); private: - /** A FIFO is used to store information about multiple PUS packets + /** + * A FIFO is used to store information about multiple PUS packets * inside the receive buffer. The maximum number of entries is defined * by the first constructor argument. */ From d6b31679223f734c84eccb0fb23ea6dec2828b01 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 27 Sep 2021 18:05:45 +0200 Subject: [PATCH 073/131] tcp keep open implementation done --- src/fsfw/container/SimpleRingBuffer.h | 15 +- src/fsfw/osal/common/TcpTmTcServer.cpp | 170 ++++++++++++++---- src/fsfw/osal/common/TcpTmTcServer.h | 68 +++++-- src/fsfw/tmtcservices/CMakeLists.txt | 1 + .../{PusParser.cpp => SpacePacketParser.cpp} | 26 +-- .../{PusParser.h => SpacePacketParser.h} | 32 ++-- 6 files changed, 227 insertions(+), 85 deletions(-) rename src/fsfw/tmtcservices/{PusParser.cpp => SpacePacketParser.cpp} (80%) rename src/fsfw/tmtcservices/{PusParser.h => SpacePacketParser.h} (70%) diff --git a/src/fsfw/container/SimpleRingBuffer.h b/src/fsfw/container/SimpleRingBuffer.h index 6f31c5fb..dc0aeba8 100644 --- a/src/fsfw/container/SimpleRingBuffer.h +++ b/src/fsfw/container/SimpleRingBuffer.h @@ -5,8 +5,7 @@ #include /** - * @brief Circular buffer implementation, useful for buffering - * into data streams. + * @brief Circular buffer implementation, useful for buffering into data streams. * @details * Note that the deleteData() has to be called to increment the read pointer. * This class allocated dynamically, so @@ -20,8 +19,8 @@ public: * @param size * @param overwriteOld If the ring buffer is overflowing at a write * operation, the oldest data will be overwritten. - * @param maxExcessBytes These additional bytes will be allocated in addtion - * to the specified size to accomodate contiguous write operations + * @param maxExcessBytes These additional bytes will be allocated in addition + * to the specified size to accommodate continuous write operations * with getFreeElement. * */ @@ -32,10 +31,10 @@ public: * @param buffer * @param size * @param overwriteOld - * If the ring buffer is overflowing at a write operartion, the oldest data + * If the ring buffer is overflowing at a write operation, the oldest data * will be overwritten. * @param maxExcessBytes - * If the buffer can accomodate additional bytes for contigous write + * If the buffer can accommodate additional bytes for contiguous write * operations with getFreeElement, this is the maximum allowed additional * size */ @@ -48,7 +47,7 @@ public: * Write to circular buffer and increment write pointer by amount. * @param data * @param amount - * @return -@c RETURN_OK if write operation was successfull + * @return -@c RETURN_OK if write operation was successful * -@c RETURN_FAILED if */ ReturnValue_t writeData(const uint8_t* data, size_t amount); @@ -108,7 +107,7 @@ public: * Delete data by incrementing read pointer. * @param amount * @param deleteRemaining - * If the amount specified is larger than the remaing size to read and this + * If the amount specified is larger than the remaining size to read and this * is set to true, the remaining amount will be deleted as well * @param trueAmount [out] * If deleteRemaining was set to true, the amount deleted will be assigned diff --git a/src/fsfw/osal/common/TcpTmTcServer.cpp b/src/fsfw/osal/common/TcpTmTcServer.cpp index 1de0816d..fbbf83e4 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.cpp +++ b/src/fsfw/osal/common/TcpTmTcServer.cpp @@ -29,12 +29,11 @@ const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, - size_t receptionBufferSize, std::string customTcpServerPort): - SystemObject(objectId), tmtcBridgeId(tmtcTcpBridge), - tcpPort(customTcpServerPort), receptionBuffer(receptionBufferSize) { - if(tcpPort == "") { - tcpPort = DEFAULT_SERVER_PORT; - } + size_t receptionBufferSize, size_t ringBufferSize, std::string customTcpServerPort, + ReceptionModes receptionMode): + SystemObject(objectId), tmtcBridgeId(tmtcTcpBridge), receptionMode(receptionMode), + tcpConfig(customTcpServerPort), receptionBuffer(receptionBufferSize), + ringBuffer(ringBufferSize, true) { } ReturnValue_t TcpTmTcServer::initialize() { @@ -45,6 +44,16 @@ ReturnValue_t TcpTmTcServer::initialize() { return result; } + switch(receptionMode) { + case(ReceptionModes::SPACE_PACKETS): { + // For now, hardcode a maximum of 5 store packets here and no split packets are allowed + spacePacketParser = new SpacePacketParser(5, false); + if(spacePacketParser == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + } + tcStore = ObjectManager::instance()->get(objects::TC_STORE); if (tcStore == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 @@ -67,7 +76,7 @@ ReturnValue_t TcpTmTcServer::initialize() { hints.ai_flags = AI_PASSIVE; // Listen to all addresses (0.0.0.0) by using AI_PASSIVE in the hint flags - retval = getaddrinfo(nullptr, tcpPort.c_str(), &hints, &addrResult); + retval = getaddrinfo(nullptr, tcpConfig.tcpPort.c_str(), &hints, &addrResult); if (retval != 0) { handleError(Protocol::TCP, ErrorSources::GETADDRINFO_CALL); return HasReturnvaluesIF::RETURN_FAILED; @@ -109,7 +118,7 @@ ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) { // Listen for connection requests permanently for lifetime of program while(true) { - retval = listen(listenerTcpSocket, tcpBacklog); + retval = listen(listenerTcpSocket, tcpConfig.tcpBacklog); if(retval == SOCKET_ERROR) { handleError(Protocol::TCP, ErrorSources::LISTEN_CALL, 500); continue; @@ -149,7 +158,7 @@ ReturnValue_t TcpTmTcServer::initializeAfterTaskCreation() { } void TcpTmTcServer::handleServerOperation(socket_t connSocket) { - int retval = 0; + //int retval = 0; using namespace std::chrono_literals; // Receive until the peer shuts down the connection, use select to do this @@ -163,8 +172,8 @@ void TcpTmTcServer::handleServerOperation(socket_t connSocket) { FD_SET(connSocket, &efds); timeval tv; - tv.tv_sec = selectTimeoutMs / 1000; - tv.tv_usec = (selectTimeoutMs % 1000) * 1000; + tv.tv_sec = 0;//tcpConfig.selectTimeoutMs / 1000; + tv.tv_usec = 0;//(tcpConfig.selectTimeoutMs % 1000) * 1000; int nfds = connSocket + 1; @@ -189,7 +198,6 @@ void TcpTmTcServer::handleServerOperation(socket_t connSocket) { // } // } while(retval > 0); while (true) { - uint32_t index = 0; int retval = select(nfds, &rfds, nullptr, &efds, &tv); if(retval < 0) { // client might have shut down connection @@ -202,40 +210,57 @@ void TcpTmTcServer::handleServerOperation(socket_t connSocket) { connSocket, reinterpret_cast(receptionBuffer.data()), receptionBuffer.capacity(), - tcpFlags + tcpConfig.tcpFlags ); - handleTcReception(retval); - //int result = receiveData(); - //if(result == 0) { - // break; - //} + ringBuffer.writeData(receptionBuffer.data(), retval); } if(FD_ISSET(connSocket, &efds)) { - //spdlog::error("{}: Exception detected on receive FD", tcpip::SERVER_PR); +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "TcpTmTcServer::handleServerOperation: " + "Exception detected" << std::endl; +#else + sif::printWarning("TcpTmTcServer::handleServerOperation: Exception detected\n"); +#endif } } else { - // no data available. Send back telemetry now - handleTmSending(connSocket); - //TaskFactory::delayTask(500); + // no data available. Check whether any packets have been read, then send back + // telemetry now + bool tcAvailable = false; + bool tmSent = false; + size_t availableReadData = ringBuffer.getAvailableReadData(); + if(availableReadData > lastRingBufferSize) { + tcAvailable = true; + handleRingBufferData(availableReadData); + } + ReturnValue_t result = handleTmSending(connSocket, tmSent); + if(result == CONN_BROKEN) { + return; + } + if(not tcAvailable and not tmSent) { + TaskFactory::delayTask(DEFAULT_LOOP_DELAY_MS); + } } } } -ReturnValue_t TcpTmTcServer::handleTcReception(size_t bytesRecvd) { +ReturnValue_t TcpTmTcServer::handleTcReception(uint8_t* spacePacket, size_t packetSize) { #if FSFW_TCP_RECV_WIRETAPPING_ENABLED == 1 arrayprinter::print(receptionBuffer.data(), bytesRead); #endif + if(spacePacket == nullptr or packetSize == 0) { + return HasReturnvaluesIF::RETURN_FAILED; + } store_address_t storeId; - ReturnValue_t result = tcStore->addData(&storeId, receptionBuffer.data(), bytesRecvd); + ReturnValue_t result = tcStore->addData(&storeId, spacePacket, packetSize); if (result != HasReturnvaluesIF::RETURN_OK) { #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "TcpTmTcServer::handleServerOperation: Data storage with packet size" << - bytesRecvd << " failed" << std::endl; + packetSize << " failed" << std::endl; #else sif::printWarning("TcpTmTcServer::handleServerOperation: Data storage with packet size %d " - "failed\n", bytesRecvd); + "failed\n", packetSize); #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ #endif /* FSFW_VERBOSE_LEVEL >= 1 */ return result; @@ -259,21 +284,25 @@ ReturnValue_t TcpTmTcServer::handleTcReception(size_t bytesRecvd) { return result; } -void TcpTmTcServer::setTcpBacklog(uint8_t tcpBacklog) { - this->tcpBacklog = tcpBacklog; -} - std::string TcpTmTcServer::getTcpPort() const { - return tcpPort; + return tcpConfig.tcpPort; } -ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket) { +void TcpTmTcServer::setSpacePacketParsingOptions(uint8_t parserFifoSize) { +} + +TcpTmTcServer::TcpConfig& TcpTmTcServer::getTcpConfigStruct() { + return tcpConfig; +} + +ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent) { // Access to the FIFO is mutex protected because it is filled by the bridge MutexGuard(tmtcBridge->mutex, tmtcBridge->timeoutType, tmtcBridge->mutexTimeoutMs); store_address_t storeId; while((not tmtcBridge->tmFifo->empty()) and (tmtcBridge->packetSentCounter < tmtcBridge->sentPacketsPerCycle)) { - tmtcBridge->tmFifo->retrieve(&storeId); + // Send can fail, so only peek from the FIFO + tmtcBridge->tmFifo->peek(&storeId); // Using the store accessor will take care of deleting TM from the store automatically ConstStorageAccessor storeAccessor(storeId); @@ -284,10 +313,81 @@ ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket) { int retval = send(connSocket, reinterpret_cast(storeAccessor.data()), storeAccessor.size(), - tcpTmFlags); + tcpConfig.tcpTmFlags); if(retval != static_cast(storeAccessor.size())) { - tcpip::handleError(tcpip::Protocol::TCP, tcpip::ErrorSources::SEND_CALL); + // Assume that the client has closed the connection here for now + handleSocketError(storeAccessor); + return CONN_BROKEN; + } + else { + // Packet sent, clear FIFO entry + tmtcBridge->tmFifo->pop(); + tmSent = true; } } return HasReturnvaluesIF::RETURN_OK; } + +ReturnValue_t TcpTmTcServer::handleRingBufferData(size_t availableReadData) { + ReturnValue_t status = HasReturnvaluesIF::RETURN_OK; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + lastRingBufferSize = availableReadData; + if(availableReadData == ringBuffer.getMaxSize()) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + // Possible configuration error, too much data or/and data coming in too fast, + // requiring larger buffers + sif::warning << "TcpTmTcServer::handleServerOperation: Ring buffer reached " << + "fill count" << std::endl; +#else + sif::printWarning("TcpTmTcServer::handleServerOperation: Ring buffer reached " + "fill count"); +#endif +#endif + } + ringBuffer.readData(receptionBuffer.data(), availableReadData, true); + result = spacePacketParser->parsePusPackets(receptionBuffer.data(), + receptionBuffer.size()); + if(result == SpacePacketParser::NO_PACKET_FOUND) { + ringBuffer.deleteData(availableReadData); + lastRingBufferSize = ringBuffer.getAvailableReadData(); + } + else if(result == HasReturnvaluesIF::RETURN_OK) { + // Space Packets were found. Handle them here + auto fifo = spacePacketParser->fifo(); + SpacePacketParser::IndexSizePair idxSizePair; + while(not fifo.empty()) { + fifo.retrieve(&idxSizePair); + result = handleTcReception(receptionBuffer.data() + idxSizePair.first, + idxSizePair.second); + if(result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + } + } + return status; +} + +void TcpTmTcServer::handleSocketError(ConstStorageAccessor &accessor) { + // Don't delete data + accessor.release(); + auto socketError = getLastSocketError(); + switch(socketError) { +#if defined PLATFORM_WIN + case(WSAECONNRESET): { + // See https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-send + // Remote client might have shut down connection + return; + } +#else + case(EPIPE): { + // See https://man7.org/linux/man-pages/man2/send.2.html + // Remote client might have shut down connection + return; + } +#endif + default: { + tcpip::handleError(tcpip::Protocol::TCP, tcpip::ErrorSources::SEND_CALL); + } + } +} diff --git a/src/fsfw/osal/common/TcpTmTcServer.h b/src/fsfw/osal/common/TcpTmTcServer.h index a33a0427..64785a46 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.h +++ b/src/fsfw/osal/common/TcpTmTcServer.h @@ -1,11 +1,13 @@ #ifndef FSFW_OSAL_COMMON_TCP_TMTC_SERVER_H_ #define FSFW_OSAL_COMMON_TCP_TMTC_SERVER_H_ +#include #include "TcpIpBase.h" #include "fsfw/platform.h" #include "fsfw/osal/common/tcpipHelpers.h" #include "fsfw/ipc/messageQueueDefinitions.h" +#include "fsfw/container/SimpleRingBuffer.h" #include "fsfw/ipc/MessageQueueIF.h" #include "fsfw/objectmanager/frameworkObjects.h" #include "fsfw/objectmanager/SystemObject.h" @@ -42,10 +44,37 @@ class TcpTmTcServer: public TcpIpBase, public ExecutableObjectIF { public: + enum class ReceptionModes { + SPACE_PACKETS + }; + + struct TcpConfig { + public: + TcpConfig(std::string tcpPort): tcpPort(tcpPort) {} + + /** + * Passed to the recv call + */ + int tcpFlags = 0; + int tcpBacklog = 3; + + /** + * Passed to the select call which is used to ensure non-blocking TC reception + */ + //uint32_t selectTimeoutMs = DEFAULT_SELECT_TIMEOUT_MS; + /** + * Passed to the send call + */ + int tcpTmFlags = 0; + + const std::string tcpPort; + }; + static const std::string DEFAULT_SERVER_PORT; static constexpr size_t ETHERNET_MTU_SIZE = 1500; - static constexpr uint32_t DEFAULT_SELECT_TIMEOUT_MS = 200; + static constexpr size_t RING_BUFFER_SIZE = ETHERNET_MTU_SIZE * 3; + static constexpr uint32_t DEFAULT_LOOP_DELAY_MS = 200; /** * TCP Server Constructor @@ -56,12 +85,19 @@ public: * @param customTcpServerPort The user can specify another port than the default (7301) here. */ TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, - size_t receptionBufferSize = ETHERNET_MTU_SIZE + 1, - std::string customTcpServerPort = ""); + size_t receptionBufferSize = RING_BUFFER_SIZE, + size_t ringBufferSize = RING_BUFFER_SIZE, + std::string customTcpServerPort = DEFAULT_SERVER_PORT, + ReceptionModes receptionMode = ReceptionModes::SPACE_PACKETS); virtual~ TcpTmTcServer(); - void setSelectTimeout(uint32_t timeout); - void setTcpBacklog(uint8_t tcpBacklog); + /** + * Get a handle to the TCP configuration struct, which can be used to configure TCP + * properties + * @return + */ + TcpConfig& getTcpConfigStruct(); + void setSpacePacketParsingOptions(uint8_t parserFifoSize); ReturnValue_t initialize() override; ReturnValue_t performOperation(uint8_t opCode) override; @@ -73,26 +109,28 @@ protected: StorageManagerIF* tcStore = nullptr; StorageManagerIF* tmStore = nullptr; private: + static constexpr ReturnValue_t CONN_BROKEN = HasReturnvaluesIF::makeReturnCode(1, 0); //! TMTC bridge is cached. object_id_t tmtcBridgeId = objects::NO_OBJECT; TcpTmTcBridge* tmtcBridge = nullptr; - std::string tcpPort; - int tcpFlags = 0; - uint32_t selectTimeoutMs = DEFAULT_SELECT_TIMEOUT_MS; - socket_t listenerTcpSocket = 0; + ReceptionModes receptionMode; + TcpConfig tcpConfig; struct sockaddr tcpAddress; + socket_t listenerTcpSocket = 0; + MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE; - int tcpAddrLen = sizeof(tcpAddress); - int tcpBacklog = 3; std::vector receptionBuffer; - int tcpSockOpt = 0; - int tcpTmFlags = 0; + SimpleRingBuffer ringBuffer; + SpacePacketParser* spacePacketParser = nullptr; + uint8_t lastRingBufferSize = 0; void handleServerOperation(socket_t connSocket); - ReturnValue_t handleTcReception(size_t bytesRecvd); - ReturnValue_t handleTmSending(socket_t connSocket); + ReturnValue_t handleTcReception(uint8_t* spacePacket, size_t packetSize); + ReturnValue_t handleTmSending(socket_t connSocket, bool& tmSent); + ReturnValue_t handleRingBufferData(size_t availableReadData); + void handleSocketError(ConstStorageAccessor& accessor); }; #endif /* FSFW_OSAL_COMMON_TCP_TMTC_SERVER_H_ */ diff --git a/src/fsfw/tmtcservices/CMakeLists.txt b/src/fsfw/tmtcservices/CMakeLists.txt index c30af214..96cf99b5 100644 --- a/src/fsfw/tmtcservices/CMakeLists.txt +++ b/src/fsfw/tmtcservices/CMakeLists.txt @@ -6,4 +6,5 @@ target_sources(${LIB_FSFW_NAME} TmTcBridge.cpp TmTcMessage.cpp VerificationReporter.cpp + SpacePacketParser.cpp ) \ No newline at end of file diff --git a/src/fsfw/tmtcservices/PusParser.cpp b/src/fsfw/tmtcservices/SpacePacketParser.cpp similarity index 80% rename from src/fsfw/tmtcservices/PusParser.cpp rename to src/fsfw/tmtcservices/SpacePacketParser.cpp index 5b63710c..7e510900 100644 --- a/src/fsfw/tmtcservices/PusParser.cpp +++ b/src/fsfw/tmtcservices/SpacePacketParser.cpp @@ -1,11 +1,11 @@ -#include "PusParser.h" #include +#include -PusParser::PusParser(uint16_t maxExpectedPusPackets, bool storeSplitPackets): +SpacePacketParser::SpacePacketParser(uint16_t maxExpectedPusPackets, bool storeSplitPackets): indexSizePairFIFO(maxExpectedPusPackets) { } -ReturnValue_t PusParser::parsePusPackets(const uint8_t *frame, +ReturnValue_t SpacePacketParser::parsePusPackets(const uint8_t *frame, size_t frameSize) { if(frame == nullptr or frameSize < 5) { #if FSFW_CPP_OSTREAM_ENABLED == 1 @@ -36,7 +36,7 @@ ReturnValue_t PusParser::parsePusPackets(const uint8_t *frame, // Size of a pus packet is the value in the packet length field plus 7. if(packetSize > frameSize) { if(storeSplitPackets) { - indexSizePairFIFO.insert(indexSizePair(0, frameSize)); + indexSizePairFIFO.insert(IndexSizePair(0, frameSize)); } else { #if FSFW_VERBOSE_LEVEL >= 1 @@ -56,7 +56,7 @@ ReturnValue_t PusParser::parsePusPackets(const uint8_t *frame, return SPLIT_PACKET; } else { - indexSizePairFIFO.insert(indexSizePair(0, packetSize)); + indexSizePairFIFO.insert(IndexSizePair(0, packetSize)); if(packetSize == frameSize) { return HasReturnvaluesIF::RETURN_OK; } @@ -66,7 +66,7 @@ ReturnValue_t PusParser::parsePusPackets(const uint8_t *frame, return readMultiplePackets(frame, frameSize, packetSize); } -ReturnValue_t PusParser::readMultiplePackets(const uint8_t *frame, +ReturnValue_t SpacePacketParser::readMultiplePackets(const uint8_t *frame, size_t frameSize, size_t startIndex) { while (startIndex < frameSize) { ReturnValue_t result = readNextPacket(frame, frameSize, startIndex); @@ -77,17 +77,17 @@ ReturnValue_t PusParser::readMultiplePackets(const uint8_t *frame, return HasReturnvaluesIF::RETURN_OK; } -DynamicFIFO* PusParser::fifo(){ - return &indexSizePairFIFO; +DynamicFIFO& SpacePacketParser::fifo(){ + return indexSizePairFIFO; } -PusParser::indexSizePair PusParser::getNextFifoPair() { - indexSizePair nextIndexSizePair; +SpacePacketParser::IndexSizePair SpacePacketParser::getNextFifoPair() { + IndexSizePair nextIndexSizePair; indexSizePairFIFO.retrieve(&nextIndexSizePair); return nextIndexSizePair; } -ReturnValue_t PusParser::readNextPacket(const uint8_t *frame, +ReturnValue_t SpacePacketParser::readNextPacket(const uint8_t *frame, size_t frameSize, size_t& currentIndex) { // sif::debug << startIndex << std::endl; if(currentIndex + 5 > frameSize) { @@ -107,7 +107,7 @@ ReturnValue_t PusParser::readNextPacket(const uint8_t *frame, if(nextPacketSize > remainingSize) { if(storeSplitPackets) { - indexSizePairFIFO.insert(indexSizePair(currentIndex, remainingSize)); + indexSizePairFIFO.insert(IndexSizePair(currentIndex, remainingSize)); } else { #if FSFW_VERBOSE_LEVEL >= 1 @@ -127,7 +127,7 @@ ReturnValue_t PusParser::readNextPacket(const uint8_t *frame, return SPLIT_PACKET; } - ReturnValue_t result = indexSizePairFIFO.insert(indexSizePair(currentIndex, + ReturnValue_t result = indexSizePairFIFO.insert(IndexSizePair(currentIndex, nextPacketSize)); if (result != HasReturnvaluesIF::RETURN_OK) { // FIFO full. diff --git a/src/fsfw/tmtcservices/PusParser.h b/src/fsfw/tmtcservices/SpacePacketParser.h similarity index 70% rename from src/fsfw/tmtcservices/PusParser.h rename to src/fsfw/tmtcservices/SpacePacketParser.h index 851f1a5d..d0d7bc4d 100644 --- a/src/fsfw/tmtcservices/PusParser.h +++ b/src/fsfw/tmtcservices/SpacePacketParser.h @@ -11,11 +11,11 @@ * @brief This small helper class scans a given buffer for PUS packets. * Can be used if PUS packets are serialized in a tightly packed frame. * @details - * The parser uses the payload length field of PUS packets to find - * the respective PUS packet sizes. + * The parser uses the length field field of the space packets to find + * the respective space packet sizes. * * The parser parses a buffer by taking a pointer and the maximum size to scan. - * If PUS packets are found, they are stored in a FIFO which stores pairs + * If space packets are found, they are stored in a FIFO which stores pairs * consisting of the index in the buffer and the respective packet sizes. * * If the parser detects split packets (which means that the size of the @@ -23,17 +23,18 @@ * store that split packet or throw away the packet. * @author R. Mueller */ -class PusParser { +class SpacePacketParser { public: //! The first entry is the index inside the buffer while the second index //! is the size of the PUS packet starting at that index. - using indexSizePair = std::pair; + using IndexSizePair = std::pair; static constexpr uint8_t INTERFACE_ID = CLASS_ID::PUS_PARSER; static constexpr ReturnValue_t NO_PACKET_FOUND = MAKE_RETURN_CODE(0x00); static constexpr ReturnValue_t SPLIT_PACKET = MAKE_RETURN_CODE(0x01); + /** - * Parser constructor. + * @brief Parser constructor. * @param maxExpectedPusPackets * Maximum expected number of PUS packets. A good estimate is to divide * the frame size by the minimum size of a PUS packet (12 bytes) @@ -41,31 +42,34 @@ public: * Specifies whether split packets are also stored inside the FIFO, * with the size being the remaining frame size. */ - PusParser(uint16_t maxExpectedPusPackets, bool storeSplitPackets); + SpacePacketParser(uint16_t maxExpectedPusPackets, bool storeSplitPackets); /** * Parse a given frame for PUS packets * @param frame * @param frameSize - * @return -@c NO_PACKET_FOUND if no packet was found. + * @return + * -@c NO_PACKET_FOUND if no packet was found + * -@c SPLIT_PACKET if splitting is enabled and a split packet was found + * -@c RETURN_OK if a packet was found. The index and sizes are stored in the internal FIFO */ ReturnValue_t parsePusPackets(const uint8_t* frame, size_t frameSize); /** * Accessor function to get a reference to the internal FIFO which - * stores pairs of indexi and packet sizes. This FIFO is filled - * by the parsePusPackets() function. + * stores pairs of index and packet sizes. This FIFO is filled + * by the #parsePusPackets function. * @return */ - DynamicFIFO* fifo(); + DynamicFIFO& fifo(); /** * Retrieve the next index and packet size pair from the FIFO. - * This also removed it from the FIFO. Please note that if the FIFO + * This also removes it from the FIFO. Please note that if the FIFO * is empty, an empty pair will be returned. * @return */ - indexSizePair getNextFifoPair(); + IndexSizePair getNextFifoPair(); private: /** @@ -73,7 +77,7 @@ private: * inside the receive buffer. The maximum number of entries is defined * by the first constructor argument. */ - DynamicFIFO indexSizePairFIFO; + DynamicFIFO indexSizePairFIFO; bool storeSplitPackets = false; From 71036bf6b168ecd9c4bd524cd1ec820211df29f8 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 27 Sep 2021 18:35:50 +0200 Subject: [PATCH 074/131] something wrong with the socket.. --- src/fsfw/osal/common/TcpTmTcServer.cpp | 17 ++++++++++++++++- src/fsfw/osal/common/TcpTmTcServer.h | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/fsfw/osal/common/TcpTmTcServer.cpp b/src/fsfw/osal/common/TcpTmTcServer.cpp index fbbf83e4..9c5a8304 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.cpp +++ b/src/fsfw/osal/common/TcpTmTcServer.cpp @@ -135,6 +135,7 @@ ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) { handleServerOperation(connSocket); + sif::debug << "Shutting down" << std::endl; // Done, shut down connection and go back to listening for client requests retval = shutdown(connSocket, SHUT_BOTH); if(retval != 0) { @@ -157,7 +158,7 @@ ReturnValue_t TcpTmTcServer::initializeAfterTaskCreation() { return HasReturnvaluesIF::RETURN_OK; } -void TcpTmTcServer::handleServerOperation(socket_t connSocket) { +void TcpTmTcServer::handleServerOperation(socket_t& connSocket) { //int retval = 0; using namespace std::chrono_literals; @@ -198,12 +199,23 @@ void TcpTmTcServer::handleServerOperation(socket_t connSocket) { // } // } while(retval > 0); while (true) { + sif::debug << "polling fd.." << std::endl; int retval = select(nfds, &rfds, nullptr, &efds, &tv); + // data available + int test = recv( + connSocket, + reinterpret_cast(receptionBuffer.data()), + receptionBuffer.capacity(), + tcpConfig.tcpFlags + ); + sif::debug << "Received " << retval << " bytes" << std::endl; if(retval < 0) { // client might have shut down connection return; } + else if(retval > 0) { + sif::debug << "some descriptor set.." << std::endl; if(FD_ISSET(connSocket, &rfds)) { // data available int retval = recv( @@ -212,6 +224,7 @@ void TcpTmTcServer::handleServerOperation(socket_t connSocket) { receptionBuffer.capacity(), tcpConfig.tcpFlags ); + sif::debug << "Received " << retval << " bytes" << std::endl; ringBuffer.writeData(receptionBuffer.data(), retval); } if(FD_ISSET(connSocket, &efds)) { @@ -229,7 +242,9 @@ void TcpTmTcServer::handleServerOperation(socket_t connSocket) { bool tcAvailable = false; bool tmSent = false; size_t availableReadData = ringBuffer.getAvailableReadData(); + //sif::debug << "ring buffer data: " << availableReadData << std::endl; if(availableReadData > lastRingBufferSize) { + sif::debug << "ring buffer size changed" << std::endl; tcAvailable = true; handleRingBufferData(availableReadData); } diff --git a/src/fsfw/osal/common/TcpTmTcServer.h b/src/fsfw/osal/common/TcpTmTcServer.h index 64785a46..ff7757d0 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.h +++ b/src/fsfw/osal/common/TcpTmTcServer.h @@ -126,7 +126,7 @@ private: SpacePacketParser* spacePacketParser = nullptr; uint8_t lastRingBufferSize = 0; - void handleServerOperation(socket_t connSocket); + void handleServerOperation(socket_t& connSocket); ReturnValue_t handleTcReception(uint8_t* spacePacket, size_t packetSize); ReturnValue_t handleTmSending(socket_t connSocket, bool& tmSent); ReturnValue_t handleRingBufferData(size_t availableReadData); From 9b7da4d9e6b4570d1a2677c567365fbeab05598e Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 27 Sep 2021 20:00:01 +0200 Subject: [PATCH 075/131] fixing last bugs --- src/fsfw/osal/common/TcpTmTcServer.cpp | 157 ++++++++++++++----------- 1 file changed, 89 insertions(+), 68 deletions(-) diff --git a/src/fsfw/osal/common/TcpTmTcServer.cpp b/src/fsfw/osal/common/TcpTmTcServer.cpp index 9c5a8304..03145e20 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.cpp +++ b/src/fsfw/osal/common/TcpTmTcServer.cpp @@ -31,9 +31,9 @@ const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_POR TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, size_t receptionBufferSize, size_t ringBufferSize, std::string customTcpServerPort, ReceptionModes receptionMode): - SystemObject(objectId), tmtcBridgeId(tmtcTcpBridge), receptionMode(receptionMode), - tcpConfig(customTcpServerPort), receptionBuffer(receptionBufferSize), - ringBuffer(ringBufferSize, true) { + SystemObject(objectId), tmtcBridgeId(tmtcTcpBridge), receptionMode(receptionMode), + tcpConfig(customTcpServerPort), receptionBuffer(receptionBufferSize), + ringBuffer(ringBufferSize, true) { } ReturnValue_t TcpTmTcServer::initialize() { @@ -127,6 +127,7 @@ ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) { //connSocket = accept(listenerTcpSocket, &clientSockAddr, &connectorSockAddrLen); connSocket = accept(listenerTcpSocket, nullptr, nullptr); + sif::debug << "accepted new conn socket " << connSocket << std::endl; if(connSocket == INVALID_SOCKET) { handleError(Protocol::TCP, ErrorSources::ACCEPT_CALL, 500); closeSocket(connSocket); @@ -142,6 +143,7 @@ ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) { handleError(Protocol::TCP, ErrorSources::SHUTDOWN_CALL); } closeSocket(connSocket); + connSocket = 0; } return HasReturnvaluesIF::RETURN_OK; } @@ -160,24 +162,24 @@ ReturnValue_t TcpTmTcServer::initializeAfterTaskCreation() { void TcpTmTcServer::handleServerOperation(socket_t& connSocket) { //int retval = 0; - using namespace std::chrono_literals; - - // Receive until the peer shuts down the connection, use select to do this - fd_set rfds; - fd_set efds; - - FD_ZERO(&rfds); - FD_SET(connSocket, &rfds); - - FD_ZERO(&efds); - FD_SET(connSocket, &efds); - - timeval tv; - tv.tv_sec = 0;//tcpConfig.selectTimeoutMs / 1000; - tv.tv_usec = 0;//(tcpConfig.selectTimeoutMs % 1000) * 1000; - - int nfds = connSocket + 1; - + // using namespace std::chrono_literals; + // + // // Receive until the peer shuts down the connection, use select to do this + // fd_set rfds; + // fd_set efds; + // + // FD_ZERO(&rfds); + // FD_SET(connSocket, &rfds); + // + // FD_ZERO(&efds); + // FD_SET(connSocket, &efds); + // + // timeval tv = {}; + // tv.tv_sec = 0;//tcpConfig.selectTimeoutMs / 1000; + // tv.tv_usec = 0;// DEFAULT_LOOP_DELAY_MS * 1000;//(tcpConfig.selectTimeoutMs % 1000) * 1000; + // + // int nfds = connSocket + 1; + //setsockopt(connSocket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv); // do { // // Read all telecommands sent by the client // retval = recv( @@ -198,64 +200,73 @@ void TcpTmTcServer::handleServerOperation(socket_t& connSocket) { // tcpip::handleError(tcpip::Protocol::TCP, tcpip::ErrorSources::RECV_CALL); // } // } while(retval > 0); + // data available + // int test = recv( + // connSocket, + // reinterpret_cast(receptionBuffer.data()), + // receptionBuffer.capacity(), + // tcpConfig.tcpFlags + // ); + // sif::debug << "Received " << test << " bytes" << std::endl; while (true) { - sif::debug << "polling fd.." << std::endl; - int retval = select(nfds, &rfds, nullptr, &efds, &tv); - // data available - int test = recv( + int retval = recv( connSocket, reinterpret_cast(receptionBuffer.data()), receptionBuffer.capacity(), - tcpConfig.tcpFlags + MSG_DONTWAIT//tcpConfig.tcpFlags ); - sif::debug << "Received " << retval << " bytes" << std::endl; - if(retval < 0) { - // client might have shut down connection + + if(retval == 0) { + // Client closed connection return; } - else if(retval > 0) { - sif::debug << "some descriptor set.." << std::endl; - if(FD_ISSET(connSocket, &rfds)) { - // data available - int retval = recv( - connSocket, - reinterpret_cast(receptionBuffer.data()), - receptionBuffer.capacity(), - tcpConfig.tcpFlags - ); - sif::debug << "Received " << retval << " bytes" << std::endl; - ringBuffer.writeData(receptionBuffer.data(), retval); + sif::debug << "Received " << retval << " bytes" << std::endl; + ringBuffer.writeData(receptionBuffer.data(), retval); + sif::debug << "select retval: " << retval << std::endl; + } + else if(retval < 0) { + if(errno == EAGAIN) { + // no data available. Check whether any packets have been read, then send back + // telemetry now + bool tcAvailable = false; + bool tmSent = false; + size_t availableReadData = ringBuffer.getAvailableReadData(); + //sif::debug << "ring buffer data: " << availableReadData << std::endl; + //sif::debug << "last buf size: " << lastRingBufferSize << std::endl; + if(availableReadData > lastRingBufferSize) { + sif::debug << "ring buffer size changed" << std::endl; + tcAvailable = true; + handleRingBufferData(availableReadData); + } + ReturnValue_t result = handleTmSending(connSocket, tmSent); + if(result == CONN_BROKEN) { + return; + } + if(not tcAvailable and not tmSent) { + TaskFactory::delayTask(DEFAULT_LOOP_DELAY_MS); + } } - if(FD_ISSET(connSocket, &efds)) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "TcpTmTcServer::handleServerOperation: " - "Exception detected" << std::endl; -#else - sif::printWarning("TcpTmTcServer::handleServerOperation: Exception detected\n"); -#endif - } - } - else { - // no data available. Check whether any packets have been read, then send back - // telemetry now - bool tcAvailable = false; - bool tmSent = false; - size_t availableReadData = ringBuffer.getAvailableReadData(); - //sif::debug << "ring buffer data: " << availableReadData << std::endl; - if(availableReadData > lastRingBufferSize) { - sif::debug << "ring buffer size changed" << std::endl; - tcAvailable = true; - handleRingBufferData(availableReadData); - } - ReturnValue_t result = handleTmSending(connSocket, tmSent); - if(result == CONN_BROKEN) { - return; - } - if(not tcAvailable and not tmSent) { - TaskFactory::delayTask(DEFAULT_LOOP_DELAY_MS); + if(errno == ETIMEDOUT) { + + retval = 0; } } + // data available + // int retval = recv( + // connSocket, + // reinterpret_cast(receptionBuffer.data()), + // receptionBuffer.capacity(), + // tcpConfig.tcpFlags + // ); + //sif::debug << "recv retval: " << retval << std::endl; + // data available + // int test = recv( + // connSocket, + // reinterpret_cast(receptionBuffer.data()), + // receptionBuffer.capacity(), + // tcpConfig.tcpFlags + // ); } } @@ -317,12 +328,14 @@ ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent) while((not tmtcBridge->tmFifo->empty()) and (tmtcBridge->packetSentCounter < tmtcBridge->sentPacketsPerCycle)) { // Send can fail, so only peek from the FIFO + sif::debug << "sending TM" << std::endl; tmtcBridge->tmFifo->peek(&storeId); // Using the store accessor will take care of deleting TM from the store automatically ConstStorageAccessor storeAccessor(storeId); ReturnValue_t result = tmStore->getData(storeId, storeAccessor); if(result != HasReturnvaluesIF::RETURN_OK) { + sif::debug << "oh no" << std::endl; return result; } int retval = send(connSocket, @@ -331,12 +344,14 @@ ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent) tcpConfig.tcpTmFlags); if(retval != static_cast(storeAccessor.size())) { // Assume that the client has closed the connection here for now + sif::debug << "conn broken?" << std::endl; handleSocketError(storeAccessor); return CONN_BROKEN; } else { // Packet sent, clear FIFO entry tmtcBridge->tmFifo->pop(); + sif::debug << "fifo size: " << tmtcBridge->tmFifo->size() << std::endl; tmSent = true; } } @@ -366,6 +381,7 @@ ReturnValue_t TcpTmTcServer::handleRingBufferData(size_t availableReadData) { if(result == SpacePacketParser::NO_PACKET_FOUND) { ringBuffer.deleteData(availableReadData); lastRingBufferSize = ringBuffer.getAvailableReadData(); + sif::debug << lastRingBufferSize << std::endl; } else if(result == HasReturnvaluesIF::RETURN_OK) { // Space Packets were found. Handle them here @@ -373,13 +389,18 @@ ReturnValue_t TcpTmTcServer::handleRingBufferData(size_t availableReadData) { SpacePacketParser::IndexSizePair idxSizePair; while(not fifo.empty()) { fifo.retrieve(&idxSizePair); + sif::debug << "handle tc" << std::endl; result = handleTcReception(receptionBuffer.data() + idxSizePair.first, idxSizePair.second); + ringBuffer.deleteData(idxSizePair.second); if(result != HasReturnvaluesIF::RETURN_OK) { status = result; } + lastRingBufferSize = ringBuffer.getAvailableReadData(); + sif::debug << lastRingBufferSize << std::endl; } } + std::memset(receptionBuffer.data(), 0, receptionBuffer.size()); return status; } From 254aac51ec1234b44eefafd7425b62e54f348958 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 28 Sep 2021 10:57:21 +0200 Subject: [PATCH 076/131] cleaning up --- src/fsfw/osal/common/TcpTmTcServer.cpp | 136 ++++++-------------- src/fsfw/tcdistribution/PUSDistributor.cpp | 27 +++- src/fsfw/tmtcservices/SpacePacketParser.cpp | 30 +++-- src/fsfw/tmtcservices/SpacePacketParser.h | 6 +- 4 files changed, 80 insertions(+), 119 deletions(-) diff --git a/src/fsfw/osal/common/TcpTmTcServer.cpp b/src/fsfw/osal/common/TcpTmTcServer.cpp index 03145e20..2e65429f 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.cpp +++ b/src/fsfw/osal/common/TcpTmTcServer.cpp @@ -31,9 +31,9 @@ const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_POR TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, size_t receptionBufferSize, size_t ringBufferSize, std::string customTcpServerPort, ReceptionModes receptionMode): - SystemObject(objectId), tmtcBridgeId(tmtcTcpBridge), receptionMode(receptionMode), - tcpConfig(customTcpServerPort), receptionBuffer(receptionBufferSize), - ringBuffer(ringBufferSize, true) { + SystemObject(objectId), tmtcBridgeId(tmtcTcpBridge), receptionMode(receptionMode), + tcpConfig(customTcpServerPort), receptionBuffer(receptionBufferSize), + ringBuffer(ringBufferSize, true) { } ReturnValue_t TcpTmTcServer::initialize() { @@ -51,6 +51,7 @@ ReturnValue_t TcpTmTcServer::initialize() { if(spacePacketParser == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } + tcpConfig.tcpFlags |= MSG_DONTWAIT; } } @@ -127,7 +128,6 @@ ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) { //connSocket = accept(listenerTcpSocket, &clientSockAddr, &connectorSockAddrLen); connSocket = accept(listenerTcpSocket, nullptr, nullptr); - sif::debug << "accepted new conn socket " << connSocket << std::endl; if(connSocket == INVALID_SOCKET) { handleError(Protocol::TCP, ErrorSources::ACCEPT_CALL, 500); closeSocket(connSocket); @@ -136,7 +136,6 @@ ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) { handleServerOperation(connSocket); - sif::debug << "Shutting down" << std::endl; // Done, shut down connection and go back to listening for client requests retval = shutdown(connSocket, SHUT_BOTH); if(retval != 0) { @@ -161,81 +160,30 @@ ReturnValue_t TcpTmTcServer::initializeAfterTaskCreation() { } void TcpTmTcServer::handleServerOperation(socket_t& connSocket) { - //int retval = 0; - // using namespace std::chrono_literals; - // - // // Receive until the peer shuts down the connection, use select to do this - // fd_set rfds; - // fd_set efds; - // - // FD_ZERO(&rfds); - // FD_SET(connSocket, &rfds); - // - // FD_ZERO(&efds); - // FD_SET(connSocket, &efds); - // - // timeval tv = {}; - // tv.tv_sec = 0;//tcpConfig.selectTimeoutMs / 1000; - // tv.tv_usec = 0;// DEFAULT_LOOP_DELAY_MS * 1000;//(tcpConfig.selectTimeoutMs % 1000) * 1000; - // - // int nfds = connSocket + 1; - //setsockopt(connSocket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv); - // do { - // // Read all telecommands sent by the client - // retval = recv( - // connSocket, - // reinterpret_cast(receptionBuffer.data()), - // receptionBuffer.capacity(), - // tcpFlags - // ); - // if (retval > 0) { - // handleTcReception(retval); - // } - // else if(retval == 0) { - // // Client has finished sending telecommands, send telemetry now - // handleTmSending(connSocket); - // } - // else { - // // Should not happen - // tcpip::handleError(tcpip::Protocol::TCP, tcpip::ErrorSources::RECV_CALL); - // } - // } while(retval > 0); - // data available - // int test = recv( - // connSocket, - // reinterpret_cast(receptionBuffer.data()), - // receptionBuffer.capacity(), - // tcpConfig.tcpFlags - // ); - // sif::debug << "Received " << test << " bytes" << std::endl; while (true) { int retval = recv( connSocket, reinterpret_cast(receptionBuffer.data()), receptionBuffer.capacity(), - MSG_DONTWAIT//tcpConfig.tcpFlags + tcpConfig.tcpFlags ); - if(retval == 0) { // Client closed connection return; } else if(retval > 0) { - sif::debug << "Received " << retval << " bytes" << std::endl; + // The ring buffer was configured for overwrite, so the returnvalue does not need to + // be checked for now ringBuffer.writeData(receptionBuffer.data(), retval); - sif::debug << "select retval: " << retval << std::endl; } else if(retval < 0) { if(errno == EAGAIN) { - // no data available. Check whether any packets have been read, then send back - // telemetry now + // No data available. Check whether any packets have been read, then send back + // telemetry if available bool tcAvailable = false; bool tmSent = false; size_t availableReadData = ringBuffer.getAvailableReadData(); - //sif::debug << "ring buffer data: " << availableReadData << std::endl; - //sif::debug << "last buf size: " << lastRingBufferSize << std::endl; if(availableReadData > lastRingBufferSize) { - sif::debug << "ring buffer size changed" << std::endl; tcAvailable = true; handleRingBufferData(availableReadData); } @@ -247,26 +195,10 @@ void TcpTmTcServer::handleServerOperation(socket_t& connSocket) { TaskFactory::delayTask(DEFAULT_LOOP_DELAY_MS); } } - if(errno == ETIMEDOUT) { - - retval = 0; + else { + tcpip::handleError(tcpip::Protocol::TCP, tcpip::ErrorSources::RECV_CALL); } } - // data available - // int retval = recv( - // connSocket, - // reinterpret_cast(receptionBuffer.data()), - // receptionBuffer.capacity(), - // tcpConfig.tcpFlags - // ); - //sif::debug << "recv retval: " << retval << std::endl; - // data available - // int test = recv( - // connSocket, - // reinterpret_cast(receptionBuffer.data()), - // receptionBuffer.capacity(), - // tcpConfig.tcpFlags - // ); } } @@ -328,31 +260,28 @@ ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent) while((not tmtcBridge->tmFifo->empty()) and (tmtcBridge->packetSentCounter < tmtcBridge->sentPacketsPerCycle)) { // Send can fail, so only peek from the FIFO - sif::debug << "sending TM" << std::endl; tmtcBridge->tmFifo->peek(&storeId); // Using the store accessor will take care of deleting TM from the store automatically ConstStorageAccessor storeAccessor(storeId); ReturnValue_t result = tmStore->getData(storeId, storeAccessor); if(result != HasReturnvaluesIF::RETURN_OK) { - sif::debug << "oh no" << std::endl; return result; } int retval = send(connSocket, reinterpret_cast(storeAccessor.data()), storeAccessor.size(), tcpConfig.tcpTmFlags); - if(retval != static_cast(storeAccessor.size())) { - // Assume that the client has closed the connection here for now - sif::debug << "conn broken?" << std::endl; - handleSocketError(storeAccessor); - return CONN_BROKEN; - } - else { + if(retval == static_cast(storeAccessor.size())) { // Packet sent, clear FIFO entry tmtcBridge->tmFifo->pop(); - sif::debug << "fifo size: " << tmtcBridge->tmFifo->size() << std::endl; tmSent = true; + + } + else if(retval <= 0) { + // Assume that the client has closed the connection here for now + handleSocketError(storeAccessor); + return CONN_BROKEN; } } return HasReturnvaluesIF::RETURN_OK; @@ -361,8 +290,9 @@ ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent) ReturnValue_t TcpTmTcServer::handleRingBufferData(size_t availableReadData) { ReturnValue_t status = HasReturnvaluesIF::RETURN_OK; ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + size_t readAmount = availableReadData; lastRingBufferSize = availableReadData; - if(availableReadData == ringBuffer.getMaxSize()) { + if(readAmount >= ringBuffer.getMaxSize()) { #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 // Possible configuration error, too much data or/and data coming in too fast, @@ -375,32 +305,42 @@ ReturnValue_t TcpTmTcServer::handleRingBufferData(size_t availableReadData) { #endif #endif } - ringBuffer.readData(receptionBuffer.data(), availableReadData, true); - result = spacePacketParser->parsePusPackets(receptionBuffer.data(), - receptionBuffer.size()); + if(readAmount >= receptionBuffer.size()) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + // Possible configuration error, too much data or/and data coming in too fast, + // requiring larger buffers + sif::warning << "TcpTmTcServer::handleServerOperation: " + "Reception buffer too small " << std::endl; +#else + sif::printWarning("TcpTmTcServer::handleServerOperation: Reception buffer too small\n"); +#endif +#endif + readAmount = receptionBuffer.size(); + } + ringBuffer.readData(receptionBuffer.data(), readAmount, true); + uint32_t readPackets = 0; + result = spacePacketParser->parseSpacePackets(receptionBuffer.data(), readAmount, readPackets); if(result == SpacePacketParser::NO_PACKET_FOUND) { ringBuffer.deleteData(availableReadData); lastRingBufferSize = ringBuffer.getAvailableReadData(); - sif::debug << lastRingBufferSize << std::endl; } else if(result == HasReturnvaluesIF::RETURN_OK) { // Space Packets were found. Handle them here - auto fifo = spacePacketParser->fifo(); + auto& fifo = spacePacketParser->fifo(); SpacePacketParser::IndexSizePair idxSizePair; while(not fifo.empty()) { fifo.retrieve(&idxSizePair); - sif::debug << "handle tc" << std::endl; result = handleTcReception(receptionBuffer.data() + idxSizePair.first, idxSizePair.second); + std::memset(receptionBuffer.data() + idxSizePair.first, 0, idxSizePair.second); ringBuffer.deleteData(idxSizePair.second); if(result != HasReturnvaluesIF::RETURN_OK) { status = result; } lastRingBufferSize = ringBuffer.getAvailableReadData(); - sif::debug << lastRingBufferSize << std::endl; } } - std::memset(receptionBuffer.data(), 0, receptionBuffer.size()); return status; } diff --git a/src/fsfw/tcdistribution/PUSDistributor.cpp b/src/fsfw/tcdistribution/PUSDistributor.cpp index eec02429..1a5f713d 100644 --- a/src/fsfw/tcdistribution/PUSDistributor.cpp +++ b/src/fsfw/tcdistribution/PUSDistributor.cpp @@ -29,12 +29,31 @@ PUSDistributor::TcMqMapIter PUSDistributor::selectDestination() { tcStatus = checker.checkPacket(currentPacket); if(tcStatus != HasReturnvaluesIF::RETURN_OK) { #if FSFW_VERBOSE_LEVEL >= 1 + std::string keyword; + if(tcStatus == TcPacketCheck::INCORRECT_CHECKSUM) { + keyword = "checksum"; + } + else if(tcStatus == TcPacketCheck::INCORRECT_PRIMARY_HEADER) { + keyword = "incorrect primary header"; + } + else if(tcStatus == TcPacketCheck::ILLEGAL_APID) { + keyword = "illegal APID"; + } + else if(tcStatus == TcPacketCheck::INCORRECT_SECONDARY_HEADER) { + keyword = "incorrect secondary header"; + } + else if(tcStatus == TcPacketCheck::INCOMPLETE_PACKET) { + keyword = "incomplete packet"; + } + else { + keyword = "unnamed error"; + } #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "PUSDistributor::handlePacket: Packet format invalid, code " << - static_cast(tcStatus) << std::endl; + sif::warning << "PUSDistributor::handlePacket: Packet format invalid, " + << keyword << " error" << std::endl; #else - sif::printDebug("PUSDistributor::handlePacket: Packet format invalid, code %d\n", - static_cast(tcStatus)); + sif::printWarning("PUSDistributor::handlePacket: Packet format invalid, " + "%s error\n", keyword); #endif #endif } diff --git a/src/fsfw/tmtcservices/SpacePacketParser.cpp b/src/fsfw/tmtcservices/SpacePacketParser.cpp index 7e510900..e48fe525 100644 --- a/src/fsfw/tmtcservices/SpacePacketParser.cpp +++ b/src/fsfw/tmtcservices/SpacePacketParser.cpp @@ -5,22 +5,22 @@ SpacePacketParser::SpacePacketParser(uint16_t maxExpectedPusPackets, bool storeS indexSizePairFIFO(maxExpectedPusPackets) { } -ReturnValue_t SpacePacketParser::parsePusPackets(const uint8_t *frame, - size_t frameSize) { +ReturnValue_t SpacePacketParser::parseSpacePackets(const uint8_t *frame, + size_t frameSize, uint32_t& foundPackets) { if(frame == nullptr or frameSize < 5) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "PusParser::parsePusPackets: Frame invalid!" << std::endl; + sif::error << "PusParser::parsePusPackets: Frame invalid" << std::endl; #else - sif::printError("PusParser::parsePusPackets: Frame invalid!\n"); + sif::printError("PusParser::parsePusPackets: Frame invalid\n"); #endif return HasReturnvaluesIF::RETURN_FAILED; } if(indexSizePairFIFO.full()) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "PusParser::parsePusPackets: FIFO is full!" << std::endl; + sif::error << "PusParser::parsePusPackets: FIFO is full" << std::endl; #else - sif::printError("PusParser::parsePusPackets: FIFO is full!\n"); + sif::printError("PusParser::parsePusPackets: FIFO is full\n"); #endif return HasReturnvaluesIF::RETURN_FAILED; } @@ -31,12 +31,12 @@ ReturnValue_t SpacePacketParser::parsePusPackets(const uint8_t *frame, return NO_PACKET_FOUND; } + // Size of a space packet is the value in the packet length field plus 7 size_t packetSize = lengthField + 7; - // sif::debug << frameSize << std::endl; - // Size of a pus packet is the value in the packet length field plus 7. if(packetSize > frameSize) { if(storeSplitPackets) { indexSizePairFIFO.insert(IndexSizePair(0, frameSize)); + foundPackets = 1; } else { #if FSFW_VERBOSE_LEVEL >= 1 @@ -57,19 +57,20 @@ ReturnValue_t SpacePacketParser::parsePusPackets(const uint8_t *frame, } else { indexSizePairFIFO.insert(IndexSizePair(0, packetSize)); - if(packetSize == frameSize) { + if(packetSize >= frameSize) { + foundPackets = 1; return HasReturnvaluesIF::RETURN_OK; } } // packet size is smaller than frame size, parse for more packets. - return readMultiplePackets(frame, frameSize, packetSize); + return readMultiplePackets(frame, frameSize, packetSize, foundPackets); } ReturnValue_t SpacePacketParser::readMultiplePackets(const uint8_t *frame, - size_t frameSize, size_t startIndex) { + size_t frameSize, size_t startIndex, uint32_t& foundPackets) { while (startIndex < frameSize) { - ReturnValue_t result = readNextPacket(frame, frameSize, startIndex); + ReturnValue_t result = readNextPacket(frame, frameSize, startIndex, foundPackets); if(result != HasReturnvaluesIF::RETURN_OK) { return result; } @@ -88,8 +89,7 @@ SpacePacketParser::IndexSizePair SpacePacketParser::getNextFifoPair() { } ReturnValue_t SpacePacketParser::readNextPacket(const uint8_t *frame, - size_t frameSize, size_t& currentIndex) { - // sif::debug << startIndex << std::endl; + size_t frameSize, size_t& currentIndex, uint32_t& foundPackets) { if(currentIndex + 5 > frameSize) { currentIndex = frameSize; return HasReturnvaluesIF::RETURN_OK; @@ -108,6 +108,7 @@ ReturnValue_t SpacePacketParser::readNextPacket(const uint8_t *frame, { if(storeSplitPackets) { indexSizePairFIFO.insert(IndexSizePair(currentIndex, remainingSize)); + foundPackets += 1; } else { #if FSFW_VERBOSE_LEVEL >= 1 @@ -139,6 +140,7 @@ ReturnValue_t SpacePacketParser::readNextPacket(const uint8_t *frame, "FIFO, it is full!\n"); #endif } + foundPackets += 1; currentIndex += nextPacketSize; return result; diff --git a/src/fsfw/tmtcservices/SpacePacketParser.h b/src/fsfw/tmtcservices/SpacePacketParser.h index d0d7bc4d..5cd093dd 100644 --- a/src/fsfw/tmtcservices/SpacePacketParser.h +++ b/src/fsfw/tmtcservices/SpacePacketParser.h @@ -53,7 +53,7 @@ public: * -@c SPLIT_PACKET if splitting is enabled and a split packet was found * -@c RETURN_OK if a packet was found. The index and sizes are stored in the internal FIFO */ - ReturnValue_t parsePusPackets(const uint8_t* frame, size_t frameSize); + ReturnValue_t parseSpacePackets(const uint8_t* frame, size_t frameSize, uint32_t& foundPackets); /** * Accessor function to get a reference to the internal FIFO which @@ -82,9 +82,9 @@ private: bool storeSplitPackets = false; ReturnValue_t readMultiplePackets(const uint8_t *frame, size_t frameSize, - size_t startIndex); + size_t startIndex, uint32_t& foundPackets); ReturnValue_t readNextPacket(const uint8_t *frame, - size_t frameSize, size_t& startIndex); + size_t frameSize, size_t& startIndex, uint32_t& foundPackets); }; #endif /* FRAMEWORK_TMTCSERVICES_PUSPARSER_H_ */ From 5fd7a8c9b76bae2d7d019e0175b481083e7ba460 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 28 Sep 2021 11:03:17 +0200 Subject: [PATCH 077/131] smaller tweaks --- src/fsfw/osal/common/TcpTmTcServer.cpp | 4 ++-- src/fsfw/osal/common/TcpTmTcServer.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/fsfw/osal/common/TcpTmTcServer.cpp b/src/fsfw/osal/common/TcpTmTcServer.cpp index 2e65429f..6c8ec781 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.cpp +++ b/src/fsfw/osal/common/TcpTmTcServer.cpp @@ -185,7 +185,7 @@ void TcpTmTcServer::handleServerOperation(socket_t& connSocket) { size_t availableReadData = ringBuffer.getAvailableReadData(); if(availableReadData > lastRingBufferSize) { tcAvailable = true; - handleRingBufferData(availableReadData); + handleTcRingBufferData(availableReadData); } ReturnValue_t result = handleTmSending(connSocket, tmSent); if(result == CONN_BROKEN) { @@ -287,7 +287,7 @@ ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent) return HasReturnvaluesIF::RETURN_OK; } -ReturnValue_t TcpTmTcServer::handleRingBufferData(size_t availableReadData) { +ReturnValue_t TcpTmTcServer::handleTcRingBufferData(size_t availableReadData) { ReturnValue_t status = HasReturnvaluesIF::RETURN_OK; ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; size_t readAmount = availableReadData; diff --git a/src/fsfw/osal/common/TcpTmTcServer.h b/src/fsfw/osal/common/TcpTmTcServer.h index ff7757d0..4a5b3e64 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.h +++ b/src/fsfw/osal/common/TcpTmTcServer.h @@ -129,7 +129,7 @@ private: void handleServerOperation(socket_t& connSocket); ReturnValue_t handleTcReception(uint8_t* spacePacket, size_t packetSize); ReturnValue_t handleTmSending(socket_t connSocket, bool& tmSent); - ReturnValue_t handleRingBufferData(size_t availableReadData); + ReturnValue_t handleTcRingBufferData(size_t availableReadData); void handleSocketError(ConstStorageAccessor& accessor); }; From 80ccaede025480a3e3d803c2ba220786a0d42ff2 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 28 Sep 2021 14:14:59 +0200 Subject: [PATCH 078/131] refactored space packet parser --- src/fsfw/osal/common/TcpTmTcServer.cpp | 45 +++-- src/fsfw/osal/common/TcpTmTcServer.h | 3 +- src/fsfw/tmtcservices/SpacePacketParser.cpp | 202 +++++++------------- src/fsfw/tmtcservices/SpacePacketParser.h | 26 ++- 4 files changed, 109 insertions(+), 167 deletions(-) diff --git a/src/fsfw/osal/common/TcpTmTcServer.cpp b/src/fsfw/osal/common/TcpTmTcServer.cpp index 6c8ec781..b2a5b007 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.cpp +++ b/src/fsfw/osal/common/TcpTmTcServer.cpp @@ -33,7 +33,7 @@ TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, ReceptionModes receptionMode): SystemObject(objectId), tmtcBridgeId(tmtcTcpBridge), receptionMode(receptionMode), tcpConfig(customTcpServerPort), receptionBuffer(receptionBufferSize), - ringBuffer(ringBufferSize, true) { + ringBuffer(ringBufferSize, true), validPacketIds() { } ReturnValue_t TcpTmTcServer::initialize() { @@ -46,8 +46,7 @@ ReturnValue_t TcpTmTcServer::initialize() { switch(receptionMode) { case(ReceptionModes::SPACE_PACKETS): { - // For now, hardcode a maximum of 5 store packets here and no split packets are allowed - spacePacketParser = new SpacePacketParser(5, false); + spacePacketParser = new SpacePacketParser(validPacketIds); if(spacePacketParser == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } @@ -246,7 +245,8 @@ std::string TcpTmTcServer::getTcpPort() const { return tcpConfig.tcpPort; } -void TcpTmTcServer::setSpacePacketParsingOptions(uint8_t parserFifoSize) { +void TcpTmTcServer::setSpacePacketParsingOptions(std::vector validPacketIds) { + this->validPacketIds = validPacketIds; } TcpTmTcServer::TcpConfig& TcpTmTcServer::getTcpConfigStruct() { @@ -319,27 +319,32 @@ ReturnValue_t TcpTmTcServer::handleTcRingBufferData(size_t availableReadData) { readAmount = receptionBuffer.size(); } ringBuffer.readData(receptionBuffer.data(), readAmount, true); - uint32_t readPackets = 0; - result = spacePacketParser->parseSpacePackets(receptionBuffer.data(), readAmount, readPackets); - if(result == SpacePacketParser::NO_PACKET_FOUND) { - ringBuffer.deleteData(availableReadData); - lastRingBufferSize = ringBuffer.getAvailableReadData(); - } - else if(result == HasReturnvaluesIF::RETURN_OK) { - // Space Packets were found. Handle them here - auto& fifo = spacePacketParser->fifo(); - SpacePacketParser::IndexSizePair idxSizePair; - while(not fifo.empty()) { - fifo.retrieve(&idxSizePair); - result = handleTcReception(receptionBuffer.data() + idxSizePair.first, - idxSizePair.second); - std::memset(receptionBuffer.data() + idxSizePair.first, 0, idxSizePair.second); - ringBuffer.deleteData(idxSizePair.second); + const uint8_t* bufPtr = receptionBuffer.data(); + const uint8_t** bufPtrPtr = &bufPtr; + size_t startIdx = 0; + size_t foundSize = 0; + size_t readLen = 0; + while(readLen <= readAmount) { + result = spacePacketParser->parseSpacePackets(bufPtrPtr, readAmount, + startIdx, foundSize, readLen); + if(result == SpacePacketParser::NO_PACKET_FOUND) { + ringBuffer.deleteData(foundSize); + lastRingBufferSize = ringBuffer.getAvailableReadData(); + } + else if(result == SpacePacketParser::SPLIT_PACKET) { + // might be half of a packet? Skip it for now + ringBuffer.deleteData(foundSize); + lastRingBufferSize = ringBuffer.getAvailableReadData(); + } + else if(result == HasReturnvaluesIF::RETURN_OK) { + result = handleTcReception(receptionBuffer.data() + startIdx, foundSize); + ringBuffer.deleteData(foundSize); if(result != HasReturnvaluesIF::RETURN_OK) { status = result; } lastRingBufferSize = ringBuffer.getAvailableReadData(); } + std::memset(receptionBuffer.data() + startIdx, 0, foundSize); } return status; } diff --git a/src/fsfw/osal/common/TcpTmTcServer.h b/src/fsfw/osal/common/TcpTmTcServer.h index 4a5b3e64..559b2c8c 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.h +++ b/src/fsfw/osal/common/TcpTmTcServer.h @@ -97,7 +97,7 @@ public: * @return */ TcpConfig& getTcpConfigStruct(); - void setSpacePacketParsingOptions(uint8_t parserFifoSize); + void setSpacePacketParsingOptions(std::vector validPacketIds); ReturnValue_t initialize() override; ReturnValue_t performOperation(uint8_t opCode) override; @@ -123,6 +123,7 @@ private: std::vector receptionBuffer; SimpleRingBuffer ringBuffer; + std::vector validPacketIds; SpacePacketParser* spacePacketParser = nullptr; uint8_t lastRingBufferSize = 0; diff --git a/src/fsfw/tmtcservices/SpacePacketParser.cpp b/src/fsfw/tmtcservices/SpacePacketParser.cpp index e48fe525..84f861cf 100644 --- a/src/fsfw/tmtcservices/SpacePacketParser.cpp +++ b/src/fsfw/tmtcservices/SpacePacketParser.cpp @@ -1,147 +1,77 @@ #include #include +#include -SpacePacketParser::SpacePacketParser(uint16_t maxExpectedPusPackets, bool storeSplitPackets): - indexSizePairFIFO(maxExpectedPusPackets) { +SpacePacketParser::SpacePacketParser(std::vector validPacketIds): + validPacketIds(validPacketIds) { } -ReturnValue_t SpacePacketParser::parseSpacePackets(const uint8_t *frame, - size_t frameSize, uint32_t& foundPackets) { - if(frame == nullptr or frameSize < 5) { +ReturnValue_t SpacePacketParser::parseSpacePackets(const uint8_t *buffer, + const size_t maxSize, size_t& startIndex, size_t& foundSize) { + const uint8_t** tempPtr = &buffer; + size_t readLen = 0; + return parseSpacePackets(tempPtr, maxSize, startIndex, foundSize, readLen); +} + +ReturnValue_t SpacePacketParser::parseSpacePackets(const uint8_t **buffer, const size_t maxSize, + size_t &startIndex, size_t &foundSize, size_t& readLen) { + if(buffer == nullptr or maxSize < 5) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "PusParser::parsePusPackets: Frame invalid" << std::endl; -#else - sif::printError("PusParser::parsePusPackets: Frame invalid\n"); + sif::warning << "SpacePacketParser::parseSpacePackets: Frame invalid" << std::endl; +#else + sif::printWarning("SpacePacketParser::parseSpacePackets: Frame invalid\n"); #endif - return HasReturnvaluesIF::RETURN_FAILED; - } - - if(indexSizePairFIFO.full()) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "PusParser::parsePusPackets: FIFO is full" << std::endl; -#else - sif::printError("PusParser::parsePusPackets: FIFO is full\n"); -#endif - return HasReturnvaluesIF::RETURN_FAILED; - } - - size_t lengthField = frame[4] << 8 | frame[5]; - - if(lengthField == 0) { - return NO_PACKET_FOUND; - } - - // Size of a space packet is the value in the packet length field plus 7 - size_t packetSize = lengthField + 7; - if(packetSize > frameSize) { - if(storeSplitPackets) { - indexSizePairFIFO.insert(IndexSizePair(0, frameSize)); - foundPackets = 1; - } - else { -#if FSFW_VERBOSE_LEVEL >= 1 -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "TcSerialPollingTask::readNextPacket: Next packet " - << "larger than remaining frame," << std::endl; - sif::warning << "Throwing away packet. Detected packet size: " - << packetSize << std::endl; -#else - sif::printWarning("TcSerialPollingTask::readNextPacket: Next packet " - "larger than remaining frame.\n"); - sif::printWarning("Throwing away packet. Detected packet size: %lu", - static_cast(packetSize)); -#endif -#endif /* FSFW_VERBOSE_LEVEL >= 1 */ - } - return SPLIT_PACKET; - } - else { - indexSizePairFIFO.insert(IndexSizePair(0, packetSize)); - if(packetSize >= frameSize) { - foundPackets = 1; - return HasReturnvaluesIF::RETURN_OK; - } - } - - // packet size is smaller than frame size, parse for more packets. - return readMultiplePackets(frame, frameSize, packetSize, foundPackets); -} - -ReturnValue_t SpacePacketParser::readMultiplePackets(const uint8_t *frame, - size_t frameSize, size_t startIndex, uint32_t& foundPackets) { - while (startIndex < frameSize) { - ReturnValue_t result = readNextPacket(frame, frameSize, startIndex, foundPackets); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - } - return HasReturnvaluesIF::RETURN_OK; -} - -DynamicFIFO& SpacePacketParser::fifo(){ - return indexSizePairFIFO; -} - -SpacePacketParser::IndexSizePair SpacePacketParser::getNextFifoPair() { - IndexSizePair nextIndexSizePair; - indexSizePairFIFO.retrieve(&nextIndexSizePair); - return nextIndexSizePair; -} - -ReturnValue_t SpacePacketParser::readNextPacket(const uint8_t *frame, - size_t frameSize, size_t& currentIndex, uint32_t& foundPackets) { - if(currentIndex + 5 > frameSize) { - currentIndex = frameSize; - return HasReturnvaluesIF::RETURN_OK; + return HasReturnvaluesIF::RETURN_FAILED; } + const uint8_t* bufPtr = *buffer; - uint16_t lengthField = frame[currentIndex + 4] << 8 | - frame[currentIndex + 5]; - if(lengthField == 0) { - // It is assumed that no packet follows. - currentIndex = frameSize; - return HasReturnvaluesIF::RETURN_OK; - } - size_t nextPacketSize = lengthField + 7; - size_t remainingSize = frameSize - currentIndex; - if(nextPacketSize > remainingSize) - { - if(storeSplitPackets) { - indexSizePairFIFO.insert(IndexSizePair(currentIndex, remainingSize)); - foundPackets += 1; - } - else { -#if FSFW_VERBOSE_LEVEL >= 1 -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "TcSerialPollingTask::readNextPacket: Next packet " - << "larger than remaining frame." << std::endl; - sif::warning << "Throwing away packet. Detected packet size: " - << nextPacketSize << std::endl; -#else - sif::printWarning("TcSerialPollingTask::readNextPacket: Next packet " - "larger than remaining frame.\n"); - sif::printWarning("Throwing away packet. Detected packet size: %lu\n", - static_cast(nextPacketSize)); -#endif -#endif - } - return SPLIT_PACKET; - } + auto verifyLengthField = [&](size_t idx) { + uint16_t lengthField = bufPtr[idx + 4] << 8 | bufPtr[idx + 5]; + size_t packetSize = lengthField + 7; + startIndex = idx; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + if(lengthField == 0) { + // Skip whole header for now + foundSize = 6; + result = NO_PACKET_FOUND; + } + else if(packetSize + idx > maxSize) { + // Don't increment buffer and read length here, user has to decide what to do + foundSize = packetSize; + return SPLIT_PACKET; + } + else { + foundSize = packetSize; + } + *buffer += foundSize; + readLen += foundSize; + return result; + }; - ReturnValue_t result = indexSizePairFIFO.insert(IndexSizePair(currentIndex, - nextPacketSize)); - if (result != HasReturnvaluesIF::RETURN_OK) { - // FIFO full. -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "PusParser: Issue inserting into start index size " - << "FIFO, it is full!" << std::endl; -#else - sif::printDebug("PusParser: Issue inserting into start index size " - "FIFO, it is full!\n"); -#endif - } - foundPackets += 1; - currentIndex += nextPacketSize; - - return result; + size_t idx = 0; + // Space packet ID as start marker + if(validPacketIds.size() > 0) { + while(idx < maxSize - 5) { + uint16_t currentPacketId = bufPtr[idx] << 8 | bufPtr[idx + 1]; + if(std::find(validPacketIds.begin(), validPacketIds.end(), currentPacketId) != + validPacketIds.end()) { + if(idx + 5 >= maxSize) { + return SPLIT_PACKET; + } + return verifyLengthField(idx); + } + else { + idx++; + } + } + startIndex = 0; + foundSize = maxSize; + *buffer += foundSize; + readLen += foundSize; + return NO_PACKET_FOUND; + } + // Assume that the user verified a valid start of a space packet + else { + return verifyLengthField(idx); + } } diff --git a/src/fsfw/tmtcservices/SpacePacketParser.h b/src/fsfw/tmtcservices/SpacePacketParser.h index 5cd093dd..16b53ea4 100644 --- a/src/fsfw/tmtcservices/SpacePacketParser.h +++ b/src/fsfw/tmtcservices/SpacePacketParser.h @@ -42,26 +42,30 @@ public: * Specifies whether split packets are also stored inside the FIFO, * with the size being the remaining frame size. */ - SpacePacketParser(uint16_t maxExpectedPusPackets, bool storeSplitPackets); + SpacePacketParser(std::vector validPacketIds); /** * Parse a given frame for PUS packets * @param frame * @param frameSize + * @param foundPackets The number of found packets will be stored here * @return * -@c NO_PACKET_FOUND if no packet was found * -@c SPLIT_PACKET if splitting is enabled and a split packet was found * -@c RETURN_OK if a packet was found. The index and sizes are stored in the internal FIFO */ - ReturnValue_t parseSpacePackets(const uint8_t* frame, size_t frameSize, uint32_t& foundPackets); + ReturnValue_t parseSpacePackets(const uint8_t* buffer, const size_t maxSize, + size_t& startIndex, size_t& foundSize); + ReturnValue_t parseSpacePackets(const uint8_t **buffer, const size_t maxSize, + size_t& startIndex, size_t& foundSize, size_t& readLen); /** * Accessor function to get a reference to the internal FIFO which * stores pairs of index and packet sizes. This FIFO is filled * by the #parsePusPackets function. * @return */ - DynamicFIFO& fifo(); + //DynamicFIFO& fifo(); /** * Retrieve the next index and packet size pair from the FIFO. @@ -69,7 +73,7 @@ public: * is empty, an empty pair will be returned. * @return */ - IndexSizePair getNextFifoPair(); + //IndexSizePair getNextFifoPair(); private: /** @@ -77,14 +81,16 @@ private: * inside the receive buffer. The maximum number of entries is defined * by the first constructor argument. */ - DynamicFIFO indexSizePairFIFO; + //DynamicFIFO indexSizePairFIFO; - bool storeSplitPackets = false; + std::vector validPacketIds; - ReturnValue_t readMultiplePackets(const uint8_t *frame, size_t frameSize, - size_t startIndex, uint32_t& foundPackets); - ReturnValue_t readNextPacket(const uint8_t *frame, - size_t frameSize, size_t& startIndex, uint32_t& foundPackets); + //bool storeSplitPackets = false; + +// ReturnValue_t readMultiplePackets(const uint8_t *frame, size_t frameSize, +// size_t startIndex, uint32_t& foundPackets); +// ReturnValue_t readNextPacket(const uint8_t *frame, +// size_t frameSize, size_t& startIndex, uint32_t& foundPackets); }; #endif /* FRAMEWORK_TMTCSERVICES_PUSPARSER_H_ */ From c7ce568a302538ef98e308add1bcae632563c48e Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 28 Sep 2021 14:50:50 +0200 Subject: [PATCH 079/131] added function to determine space packet ID from APID --- src/fsfw/osal/common/TcpTmTcServer.cpp | 21 ++--- src/fsfw/osal/common/TcpTmTcServer.h | 2 +- src/fsfw/tmtcpacket/SpacePacket.h | 110 ++++++++++++++----------- 3 files changed, 70 insertions(+), 63 deletions(-) diff --git a/src/fsfw/osal/common/TcpTmTcServer.cpp b/src/fsfw/osal/common/TcpTmTcServer.cpp index b2a5b007..e320b46b 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.cpp +++ b/src/fsfw/osal/common/TcpTmTcServer.cpp @@ -324,26 +324,23 @@ ReturnValue_t TcpTmTcServer::handleTcRingBufferData(size_t availableReadData) { size_t startIdx = 0; size_t foundSize = 0; size_t readLen = 0; - while(readLen <= readAmount) { + while(readLen < readAmount) { result = spacePacketParser->parseSpacePackets(bufPtrPtr, readAmount, startIdx, foundSize, readLen); - if(result == SpacePacketParser::NO_PACKET_FOUND) { - ringBuffer.deleteData(foundSize); - lastRingBufferSize = ringBuffer.getAvailableReadData(); + switch(result) { + case(SpacePacketParser::NO_PACKET_FOUND): + case(SpacePacketParser::SPLIT_PACKET): { + break; } - else if(result == SpacePacketParser::SPLIT_PACKET) { - // might be half of a packet? Skip it for now - ringBuffer.deleteData(foundSize); - lastRingBufferSize = ringBuffer.getAvailableReadData(); - } - else if(result == HasReturnvaluesIF::RETURN_OK) { + case(HasReturnvaluesIF::RETURN_OK): { result = handleTcReception(receptionBuffer.data() + startIdx, foundSize); - ringBuffer.deleteData(foundSize); if(result != HasReturnvaluesIF::RETURN_OK) { status = result; } - lastRingBufferSize = ringBuffer.getAvailableReadData(); } + } + ringBuffer.deleteData(foundSize); + lastRingBufferSize = ringBuffer.getAvailableReadData(); std::memset(receptionBuffer.data() + startIdx, 0, foundSize); } return status; diff --git a/src/fsfw/osal/common/TcpTmTcServer.h b/src/fsfw/osal/common/TcpTmTcServer.h index 559b2c8c..a0a31655 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.h +++ b/src/fsfw/osal/common/TcpTmTcServer.h @@ -127,7 +127,7 @@ private: SpacePacketParser* spacePacketParser = nullptr; uint8_t lastRingBufferSize = 0; - void handleServerOperation(socket_t& connSocket); + virtual void handleServerOperation(socket_t& connSocket); ReturnValue_t handleTcReception(uint8_t* spacePacket, size_t packetSize); ReturnValue_t handleTmSending(socket_t connSocket, bool& tmSent); ReturnValue_t handleTcRingBufferData(size_t availableReadData); diff --git a/src/fsfw/tmtcpacket/SpacePacket.h b/src/fsfw/tmtcpacket/SpacePacket.h index 2957576f..9eec87a8 100644 --- a/src/fsfw/tmtcpacket/SpacePacket.h +++ b/src/fsfw/tmtcpacket/SpacePacket.h @@ -15,57 +15,67 @@ */ class SpacePacket: public SpacePacketBase { public: - static const uint16_t PACKET_MAX_SIZE = 1024; - /** - * The constructor initializes the packet and sets all header information - * according to the passed parameters. - * @param packetDataLength Sets the packet data length field and therefore specifies - * the size of the packet. - * @param isTelecommand Sets the packet type field to either TC (true) or TM (false). - * @param apid Sets the packet's APID field. The default value describes an idle packet. - * @param sequenceCount ets the packet's Source Sequence Count field. - */ - SpacePacket(uint16_t packetDataLength, bool isTelecommand = false, - uint16_t apid = APID_IDLE_PACKET, uint16_t sequenceCount = 0); - /** - * The class's default destructor. - */ - virtual ~SpacePacket(); - /** - * With this call, the complete data content (including the CCSDS Primary - * Header) is overwritten with the byte stream given. - * @param p_data Pointer to data to overwrite the content with - * @param packet_size Size of the data - * @return @li \c true if packet_size is smaller than \c MAX_PACKET_SIZE. - * @li \c false else. - */ - bool addWholeData(const uint8_t* p_data, uint32_t packet_size); + static const uint16_t PACKET_MAX_SIZE = 1024; + /** + * The constructor initializes the packet and sets all header information + * according to the passed parameters. + * @param packetDataLength Sets the packet data length field and therefore specifies + * the size of the packet. + * @param isTelecommand Sets the packet type field to either TC (true) or TM (false). + * @param apid Sets the packet's APID field. The default value describes an idle packet. + * @param sequenceCount ets the packet's Source Sequence Count field. + */ + SpacePacket(uint16_t packetDataLength, bool isTelecommand = false, + uint16_t apid = APID_IDLE_PACKET, uint16_t sequenceCount = 0); + /** + * The class's default destructor. + */ + virtual ~SpacePacket(); + + static constexpr uint16_t getTcSpacePacketIdFromApid(uint16_t apid) { + uint16_t tcPacketId = (0x18 << 8) | (((apid >> 8) & 0x07) << 8) | (apid & 0x00ff); + return tcPacketId; + } + static constexpr uint16_t getTmSpacePacketIdFromApid(uint16_t apid) { + uint16_t tmPacketId = (0x08 << 8) | (((apid >> 8) & 0x07) << 8) | (apid & 0x00ff); + return tmPacketId; + } + + /** + * With this call, the complete data content (including the CCSDS Primary + * Header) is overwritten with the byte stream given. + * @param p_data Pointer to data to overwrite the content with + * @param packet_size Size of the data + * @return @li \c true if packet_size is smaller than \c MAX_PACKET_SIZE. + * @li \c false else. + */ + bool addWholeData(const uint8_t* p_data, uint32_t packet_size); protected: - /** - * This structure defines the data structure of a Space Packet as local data. - * There's a buffer which corresponds to the Space Packet Data Field with a - * maximum size of \c PACKET_MAX_SIZE. - */ - struct PacketStructured { - CCSDSPrimaryHeader header; - uint8_t buffer[PACKET_MAX_SIZE]; - }; - /** - * This union simplifies accessing the full data content of the Space Packet. - * This is achieved by putting the \c PacketStructured struct in a union with - * a plain buffer. - */ - union SpacePacketData { - PacketStructured fields; - uint8_t byteStream[PACKET_MAX_SIZE + sizeof(CCSDSPrimaryHeader)]; - }; - /** - * This is the data representation of the class. - * It is a struct of CCSDS Primary Header and a data field, which again is - * packed in an union, so the data can be accessed as a byte stream without - * a cast. - */ - SpacePacketData localData; + /** + * This structure defines the data structure of a Space Packet as local data. + * There's a buffer which corresponds to the Space Packet Data Field with a + * maximum size of \c PACKET_MAX_SIZE. + */ + struct PacketStructured { + CCSDSPrimaryHeader header; + uint8_t buffer[PACKET_MAX_SIZE]; + }; + /** + * This union simplifies accessing the full data content of the Space Packet. + * This is achieved by putting the \c PacketStructured struct in a union with + * a plain buffer. + */ + union SpacePacketData { + PacketStructured fields; + uint8_t byteStream[PACKET_MAX_SIZE + sizeof(CCSDSPrimaryHeader)]; + }; + /** + * This is the data representation of the class. + * It is a struct of CCSDS Primary Header and a data field, which again is + * packed in an union, so the data can be accessed as a byte stream without + * a cast. + */ + SpacePacketData localData; }; #endif /* SPACEPACKET_H_ */ From 5a045d03a542a9201aaacba7c7e96fc040d0bba6 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 28 Sep 2021 15:10:50 +0200 Subject: [PATCH 080/131] wiretapping in runtime config now --- src/fsfw/osal/common/TcpTmTcServer.cpp | 24 +++++++++++++++--------- src/fsfw/osal/common/TcpTmTcServer.h | 5 ++++- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/fsfw/osal/common/TcpTmTcServer.cpp b/src/fsfw/osal/common/TcpTmTcServer.cpp index e320b46b..5be9373e 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.cpp +++ b/src/fsfw/osal/common/TcpTmTcServer.cpp @@ -5,12 +5,13 @@ #include "TcpTmTcBridge.h" #include "tcpipHelpers.h" +#include "fsfw/tmtcservices/SpacePacketParser.h" #include "fsfw/tasks/TaskFactory.h" +#include "fsfw/globalfunctions/arrayprinter.h" #include "fsfw/container/SharedRingBuffer.h" #include "fsfw/ipc/MessageQueueSenderIF.h" #include "fsfw/ipc/MutexGuard.h" #include "fsfw/objectmanager/ObjectManager.h" - #include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/tmtcservices/TmTcMessage.h" @@ -20,11 +21,6 @@ #elif defined(PLATFORM_UNIX) #include #endif -#include - -#ifndef FSFW_TCP_RECV_WIRETAPPING_ENABLED -#define FSFW_TCP_RECV_WIRETAPPING_ENABLED 0 -#endif const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; @@ -202,9 +198,11 @@ void TcpTmTcServer::handleServerOperation(socket_t& connSocket) { } ReturnValue_t TcpTmTcServer::handleTcReception(uint8_t* spacePacket, size_t packetSize) { -#if FSFW_TCP_RECV_WIRETAPPING_ENABLED == 1 - arrayprinter::print(receptionBuffer.data(), bytesRead); -#endif + if(wiretappingEnabled) { + sif::info << "Received TC:" << std::endl; + arrayprinter::print(spacePacket, packetSize); + } + if(spacePacket == nullptr or packetSize == 0) { return HasReturnvaluesIF::RETURN_FAILED; } @@ -268,6 +266,10 @@ ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent) if(result != HasReturnvaluesIF::RETURN_OK) { return result; } + if(wiretappingEnabled) { + sif::info << "Sending TM:" << std::endl; + arrayprinter::print(storeAccessor.data(), storeAccessor.size()); + } int retval = send(connSocket, reinterpret_cast(storeAccessor.data()), storeAccessor.size(), @@ -346,6 +348,10 @@ ReturnValue_t TcpTmTcServer::handleTcRingBufferData(size_t availableReadData) { return status; } +void TcpTmTcServer::enableWiretapping(bool enable) { + this->wiretappingEnabled = enable; +} + void TcpTmTcServer::handleSocketError(ConstStorageAccessor &accessor) { // Don't delete data accessor.release(); diff --git a/src/fsfw/osal/common/TcpTmTcServer.h b/src/fsfw/osal/common/TcpTmTcServer.h index a0a31655..d5214848 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.h +++ b/src/fsfw/osal/common/TcpTmTcServer.h @@ -1,7 +1,6 @@ #ifndef FSFW_OSAL_COMMON_TCP_TMTC_SERVER_H_ #define FSFW_OSAL_COMMON_TCP_TMTC_SERVER_H_ -#include #include "TcpIpBase.h" #include "fsfw/platform.h" @@ -22,6 +21,7 @@ #include class TcpTmTcBridge; +class SpacePacketParser; /** * @brief TCP server implementation @@ -91,6 +91,8 @@ public: ReceptionModes receptionMode = ReceptionModes::SPACE_PACKETS); virtual~ TcpTmTcServer(); + void enableWiretapping(bool enable); + /** * Get a handle to the TCP configuration struct, which can be used to configure TCP * properties @@ -113,6 +115,7 @@ private: //! TMTC bridge is cached. object_id_t tmtcBridgeId = objects::NO_OBJECT; TcpTmTcBridge* tmtcBridge = nullptr; + bool wiretappingEnabled = false; ReceptionModes receptionMode; TcpConfig tcpConfig; From f2020b24923b77390ff5234e579a5aa9fc492f4e Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 28 Sep 2021 15:12:23 +0200 Subject: [PATCH 081/131] removed obsolete empty ctor --- src/fsfw/osal/common/TcpTmTcServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fsfw/osal/common/TcpTmTcServer.cpp b/src/fsfw/osal/common/TcpTmTcServer.cpp index 5be9373e..fb421fc7 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.cpp +++ b/src/fsfw/osal/common/TcpTmTcServer.cpp @@ -29,7 +29,7 @@ TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, ReceptionModes receptionMode): SystemObject(objectId), tmtcBridgeId(tmtcTcpBridge), receptionMode(receptionMode), tcpConfig(customTcpServerPort), receptionBuffer(receptionBufferSize), - ringBuffer(ringBufferSize, true), validPacketIds() { + ringBuffer(ringBufferSize, true) { } ReturnValue_t TcpTmTcServer::initialize() { From 304d7e8e32a45d4223ba833a7ca490ea810de2c0 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 28 Sep 2021 15:30:31 +0200 Subject: [PATCH 082/131] space packet parser cleaned up, documentation --- src/fsfw/tmtcservices/SpacePacketParser.cpp | 2 +- src/fsfw/tmtcservices/SpacePacketParser.h | 100 ++++++++------------ 2 files changed, 42 insertions(+), 60 deletions(-) diff --git a/src/fsfw/tmtcservices/SpacePacketParser.cpp b/src/fsfw/tmtcservices/SpacePacketParser.cpp index 84f861cf..3d442458 100644 --- a/src/fsfw/tmtcservices/SpacePacketParser.cpp +++ b/src/fsfw/tmtcservices/SpacePacketParser.cpp @@ -44,7 +44,7 @@ ReturnValue_t SpacePacketParser::parseSpacePackets(const uint8_t **buffer, const foundSize = packetSize; } *buffer += foundSize; - readLen += foundSize; + readLen += idx + foundSize; return result; }; diff --git a/src/fsfw/tmtcservices/SpacePacketParser.h b/src/fsfw/tmtcservices/SpacePacketParser.h index 16b53ea4..82b15010 100644 --- a/src/fsfw/tmtcservices/SpacePacketParser.h +++ b/src/fsfw/tmtcservices/SpacePacketParser.h @@ -8,19 +8,11 @@ #include /** - * @brief This small helper class scans a given buffer for PUS packets. - * Can be used if PUS packets are serialized in a tightly packed frame. + * @brief This small helper class scans a given buffer for space packets. + * Can be used if space packets are serialized in a tightly packed frame. * @details - * The parser uses the length field field of the space packets to find - * the respective space packet sizes. - * - * The parser parses a buffer by taking a pointer and the maximum size to scan. - * If space packets are found, they are stored in a FIFO which stores pairs - * consisting of the index in the buffer and the respective packet sizes. - * - * If the parser detects split packets (which means that the size of the - * next packet is larger than the remaining size to scan), it can either - * store that split packet or throw away the packet. + * The parser uses the length field field and the 16-bit TC packet ID of the space packets to find + * find space packets in a given data stream * @author R. Mueller */ class SpacePacketParser { @@ -35,62 +27,52 @@ public: /** * @brief Parser constructor. - * @param maxExpectedPusPackets - * Maximum expected number of PUS packets. A good estimate is to divide - * the frame size by the minimum size of a PUS packet (12 bytes) - * @param storeSplitPackets - * Specifies whether split packets are also stored inside the FIFO, - * with the size being the remaining frame size. + * @param validPacketIds This vector contains the allowed 16-bit TC packet ID start markers + * The parser will search for these stark markers to detect the start of a space packet. + * It is also possible to pass an empty vector here, but this is not recommended. + * If an empty vector is passed, the parser will assume that the start of the given stream + * contains the start of a new space packet. */ SpacePacketParser(std::vector validPacketIds); + /** + * Parse a given frame for space packets but also increment the given buffer and assign the + * total number of bytes read so far + * @param buffer Parser will look for space packets in this buffer + * @param maxSize Maximum size of the buffer + * @param startIndex Start index of a found space packet + * @param foundSize Found size of the space packet + * @param readLen Length read so far. This value is incremented by the number of parsed + * bytes which also includes the size of a found packet + * -@c NO_PACKET_FOUND if no packet was found in the given buffer or the length field is + * invalid. foundSize will be set to the size of the space packet header. buffer and + * readLen will be incremented accordingly. + * -@c SPLIT_PACKET if a packet was found but the detected size exceeds maxSize. foundSize + * will be set to the detected packet size and startIndex will be set to the start of the + * detected packet. buffer and read length will not be incremented but the found length + * will be assigned. + * -@c RETURN_OK if a packet was found + */ + ReturnValue_t parseSpacePackets(const uint8_t **buffer, const size_t maxSize, + size_t& startIndex, size_t& foundSize, size_t& readLen); + /** - * Parse a given frame for PUS packets - * @param frame - * @param frameSize - * @param foundPackets The number of found packets will be stored here - * @return - * -@c NO_PACKET_FOUND if no packet was found - * -@c SPLIT_PACKET if splitting is enabled and a split packet was found - * -@c RETURN_OK if a packet was found. The index and sizes are stored in the internal FIFO + * Parse a given frame for space packets + * @param buffer Parser will look for space packets in this buffer + * @param maxSize Maximum size of the buffer + * @param startIndex Start index of a found space packet + * @param foundSize Found size of the space packet + * -@c NO_PACKET_FOUND if no packet was found in the given buffer or the length field is + * invalid. foundSize will be set to the size of the space packet header + * -@c SPLIT_PACKET if a packet was found but the detected size exceeds maxSize. foundSize + * will be set to the detected packet size and startIndex will be set to the start of the + * detected packet + * -@c RETURN_OK if a packet was found */ ReturnValue_t parseSpacePackets(const uint8_t* buffer, const size_t maxSize, size_t& startIndex, size_t& foundSize); - - ReturnValue_t parseSpacePackets(const uint8_t **buffer, const size_t maxSize, - size_t& startIndex, size_t& foundSize, size_t& readLen); - /** - * Accessor function to get a reference to the internal FIFO which - * stores pairs of index and packet sizes. This FIFO is filled - * by the #parsePusPackets function. - * @return - */ - //DynamicFIFO& fifo(); - - /** - * Retrieve the next index and packet size pair from the FIFO. - * This also removes it from the FIFO. Please note that if the FIFO - * is empty, an empty pair will be returned. - * @return - */ - //IndexSizePair getNextFifoPair(); - private: - /** - * A FIFO is used to store information about multiple PUS packets - * inside the receive buffer. The maximum number of entries is defined - * by the first constructor argument. - */ - //DynamicFIFO indexSizePairFIFO; - std::vector validPacketIds; - - //bool storeSplitPackets = false; - -// ReturnValue_t readMultiplePackets(const uint8_t *frame, size_t frameSize, -// size_t startIndex, uint32_t& foundPackets); -// ReturnValue_t readNextPacket(const uint8_t *frame, -// size_t frameSize, size_t& startIndex, uint32_t& foundPackets); }; #endif /* FRAMEWORK_TMTCSERVICES_PUSPARSER_H_ */ From be8623a4f85d4445b218873bddd6bcf0ed24fb5f Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 28 Sep 2021 15:32:58 +0200 Subject: [PATCH 083/131] delay configurable --- src/fsfw/osal/common/TcpTmTcServer.cpp | 2 +- src/fsfw/osal/common/TcpTmTcServer.h | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/fsfw/osal/common/TcpTmTcServer.cpp b/src/fsfw/osal/common/TcpTmTcServer.cpp index fb421fc7..c3936146 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.cpp +++ b/src/fsfw/osal/common/TcpTmTcServer.cpp @@ -187,7 +187,7 @@ void TcpTmTcServer::handleServerOperation(socket_t& connSocket) { return; } if(not tcAvailable and not tmSent) { - TaskFactory::delayTask(DEFAULT_LOOP_DELAY_MS); + TaskFactory::delayTask(tcpConfig.tcpLoopDelay); } } else { diff --git a/src/fsfw/osal/common/TcpTmTcServer.h b/src/fsfw/osal/common/TcpTmTcServer.h index d5214848..da0e8bd5 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.h +++ b/src/fsfw/osal/common/TcpTmTcServer.h @@ -59,9 +59,10 @@ public: int tcpBacklog = 3; /** - * Passed to the select call which is used to ensure non-blocking TC reception + * If no telecommands packets are being received and no telemetry is being sent, + * the TCP server will delay periodically by this amount to decrease the CPU load */ - //uint32_t selectTimeoutMs = DEFAULT_SELECT_TIMEOUT_MS; + uint32_t tcpLoopDelay = DEFAULT_LOOP_DELAY_MS ; /** * Passed to the send call */ From d4bdf314f74e75f3260042682718299d0655d494 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 28 Sep 2021 16:31:53 +0200 Subject: [PATCH 084/131] C++11 adaptions --- src/fsfw/tmtcpacket/SpacePacket.h | 17 ++++++++--------- src/fsfw/tmtcservices/SpacePacketParser.h | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/fsfw/tmtcpacket/SpacePacket.h b/src/fsfw/tmtcpacket/SpacePacket.h index 9eec87a8..67746859 100644 --- a/src/fsfw/tmtcpacket/SpacePacket.h +++ b/src/fsfw/tmtcpacket/SpacePacket.h @@ -32,15 +32,6 @@ public: */ virtual ~SpacePacket(); - static constexpr uint16_t getTcSpacePacketIdFromApid(uint16_t apid) { - uint16_t tcPacketId = (0x18 << 8) | (((apid >> 8) & 0x07) << 8) | (apid & 0x00ff); - return tcPacketId; - } - static constexpr uint16_t getTmSpacePacketIdFromApid(uint16_t apid) { - uint16_t tmPacketId = (0x08 << 8) | (((apid >> 8) & 0x07) << 8) | (apid & 0x00ff); - return tmPacketId; - } - /** * With this call, the complete data content (including the CCSDS Primary * Header) is overwritten with the byte stream given. @@ -78,4 +69,12 @@ protected: SpacePacketData localData; }; +constexpr uint16_t getTcSpacePacketIdFromApid(uint16_t apid) { + return (0x18 << 8) | (((apid >> 8) & 0x07) << 8) | (apid & 0x00ff); +} + +constexpr uint16_t getTmSpacePacketIdFromApid(uint16_t apid) { + return (0x08 << 8) | (((apid >> 8) & 0x07) << 8) | (apid & 0x00ff); +} + #endif /* SPACEPACKET_H_ */ diff --git a/src/fsfw/tmtcservices/SpacePacketParser.h b/src/fsfw/tmtcservices/SpacePacketParser.h index 82b15010..bed3369b 100644 --- a/src/fsfw/tmtcservices/SpacePacketParser.h +++ b/src/fsfw/tmtcservices/SpacePacketParser.h @@ -21,7 +21,7 @@ public: //! is the size of the PUS packet starting at that index. using IndexSizePair = std::pair; - static constexpr uint8_t INTERFACE_ID = CLASS_ID::PUS_PARSER; + static constexpr uint8_t INTERFACE_ID = CLASS_ID::SPACE_PACKET_PARSER; static constexpr ReturnValue_t NO_PACKET_FOUND = MAKE_RETURN_CODE(0x00); static constexpr ReturnValue_t SPLIT_PACKET = MAKE_RETURN_CODE(0x01); From 6881c6b66a5a3d11756485f8f845928aea9a705e Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 28 Sep 2021 16:32:43 +0200 Subject: [PATCH 085/131] class id renamed --- src/fsfw/returnvalues/FwClassIds.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fsfw/returnvalues/FwClassIds.h b/src/fsfw/returnvalues/FwClassIds.h index 8422baa5..9fa0c9ae 100644 --- a/src/fsfw/returnvalues/FwClassIds.h +++ b/src/fsfw/returnvalues/FwClassIds.h @@ -80,7 +80,7 @@ enum: uint8_t { FIXED_SLOT_TASK_IF, //FTIF MGM_LIS3MDL, //MGMLIS3 MGM_RM3100, //MGMRM3100 - PUS_PARSER, //PUSP + SPACE_PACKET_PARSER, //SPPA FW_CLASS_ID_COUNT // [EXPORT] : [END] }; From 01e380c85897706b1be3a17ef5692dc82dc1ac2d Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 28 Sep 2021 17:36:27 +0200 Subject: [PATCH 086/131] windows fixes --- src/fsfw/osal/common/TcpTmTcServer.cpp | 33 +++++++++++++++++++++++--- src/fsfw/osal/common/TcpTmTcServer.h | 3 +++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/fsfw/osal/common/TcpTmTcServer.cpp b/src/fsfw/osal/common/TcpTmTcServer.cpp index c3936146..4348e21e 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.cpp +++ b/src/fsfw/osal/common/TcpTmTcServer.cpp @@ -46,10 +46,11 @@ ReturnValue_t TcpTmTcServer::initialize() { if(spacePacketParser == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } +#if defined PLATFORM_UNIX tcpConfig.tcpFlags |= MSG_DONTWAIT; +#endif } } - tcStore = ObjectManager::instance()->get(objects::TC_STORE); if (tcStore == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 @@ -155,6 +156,10 @@ ReturnValue_t TcpTmTcServer::initializeAfterTaskCreation() { } void TcpTmTcServer::handleServerOperation(socket_t& connSocket) { +#if defined PLATFORM_WIN + setSocketNonBlocking(connSocket); +#endif + while (true) { int retval = recv( connSocket, @@ -172,7 +177,13 @@ void TcpTmTcServer::handleServerOperation(socket_t& connSocket) { ringBuffer.writeData(receptionBuffer.data(), retval); } else if(retval < 0) { - if(errno == EAGAIN) { + int errorValue = GetLastError(); +#if defined PLATFORM_UNIX + int wouldBlockValue = EAGAIN; +#elif defined PLATFORM_WIN + int wouldBlockValue = WSAEWOULDBLOCK; +#endif + if(errorValue == wouldBlockValue) { // No data available. Check whether any packets have been read, then send back // telemetry if available bool tcAvailable = false; @@ -191,7 +202,7 @@ void TcpTmTcServer::handleServerOperation(socket_t& connSocket) { } } else { - tcpip::handleError(tcpip::Protocol::TCP, tcpip::ErrorSources::RECV_CALL); + tcpip::handleError(tcpip::Protocol::TCP, tcpip::ErrorSources::RECV_CALL, 300); } } } @@ -375,3 +386,19 @@ void TcpTmTcServer::handleSocketError(ConstStorageAccessor &accessor) { } } } + +void TcpTmTcServer::setSocketNonBlocking(socket_t &connSocket) { + u_long iMode = 1; + int iResult = ioctlsocket(connSocket, FIONBIO, &iMode); + if(iResult != NO_ERROR) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "TcpTmTcServer::handleServerOperation: Setting socket" + " non-blocking failed with error " << iResult; +#else + sif::printWarning("TcpTmTcServer::handleServerOperation: Setting socket" + " non-blocking failed with error %d\n", iResult); +#endif +#endif + } +} diff --git a/src/fsfw/osal/common/TcpTmTcServer.h b/src/fsfw/osal/common/TcpTmTcServer.h index da0e8bd5..64726a30 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.h +++ b/src/fsfw/osal/common/TcpTmTcServer.h @@ -136,6 +136,9 @@ private: ReturnValue_t handleTmSending(socket_t connSocket, bool& tmSent); ReturnValue_t handleTcRingBufferData(size_t availableReadData); void handleSocketError(ConstStorageAccessor& accessor); +#if defined PLATFORM_WIN + void setSocketNonBlocking(socket_t& connSocket); +#endif }; #endif /* FSFW_OSAL_COMMON_TCP_TMTC_SERVER_H_ */ From 69922e77c501ddaef84481c96e25801dc1889c11 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 28 Sep 2021 17:38:35 +0200 Subject: [PATCH 087/131] this should work for both OSes --- src/fsfw/osal/common/TcpTmTcServer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/fsfw/osal/common/TcpTmTcServer.cpp b/src/fsfw/osal/common/TcpTmTcServer.cpp index 4348e21e..519df547 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.cpp +++ b/src/fsfw/osal/common/TcpTmTcServer.cpp @@ -177,7 +177,7 @@ void TcpTmTcServer::handleServerOperation(socket_t& connSocket) { ringBuffer.writeData(receptionBuffer.data(), retval); } else if(retval < 0) { - int errorValue = GetLastError(); + int errorValue = getLastSocketError(); #if defined PLATFORM_UNIX int wouldBlockValue = EAGAIN; #elif defined PLATFORM_WIN @@ -387,6 +387,7 @@ void TcpTmTcServer::handleSocketError(ConstStorageAccessor &accessor) { } } +#if defined PLATFORM_WIN void TcpTmTcServer::setSocketNonBlocking(socket_t &connSocket) { u_long iMode = 1; int iResult = ioctlsocket(connSocket, FIONBIO, &iMode); @@ -402,3 +403,4 @@ void TcpTmTcServer::setSocketNonBlocking(socket_t &connSocket) { #endif } } +#endif From 5ee315f8ca3b0bb27d5a368948ecd115c6a055c9 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 28 Sep 2021 17:42:29 +0200 Subject: [PATCH 088/131] put functions in namespace --- src/fsfw/tmtcpacket/SpacePacket.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/fsfw/tmtcpacket/SpacePacket.h b/src/fsfw/tmtcpacket/SpacePacket.h index 67746859..fe8a1044 100644 --- a/src/fsfw/tmtcpacket/SpacePacket.h +++ b/src/fsfw/tmtcpacket/SpacePacket.h @@ -69,6 +69,8 @@ protected: SpacePacketData localData; }; +namespace spacepacket { + constexpr uint16_t getTcSpacePacketIdFromApid(uint16_t apid) { return (0x18 << 8) | (((apid >> 8) & 0x07) << 8) | (apid & 0x00ff); } @@ -77,4 +79,6 @@ constexpr uint16_t getTmSpacePacketIdFromApid(uint16_t apid) { return (0x08 << 8) | (((apid >> 8) & 0x07) << 8) | (apid & 0x00ff); } +} + #endif /* SPACEPACKET_H_ */ From 354e158cc196d7deaf7de24ebcc96f5f6f5f20eb Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 29 Sep 2021 09:30:50 +0200 Subject: [PATCH 089/131] format fixes --- tests/user/testcfg/CMakeLists.txt | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/user/testcfg/CMakeLists.txt b/tests/user/testcfg/CMakeLists.txt index dbf0256f..46808ec4 100644 --- a/tests/user/testcfg/CMakeLists.txt +++ b/tests/user/testcfg/CMakeLists.txt @@ -1,11 +1,9 @@ -target_sources(${TARGET_NAME} - PRIVATE - ipc/MissionMessageTypes.cpp - pollingsequence/PollingSequenceFactory.cpp +target_sources(${TARGET_NAME} PRIVATE + ipc/MissionMessageTypes.cpp + pollingsequence/PollingSequenceFactory.cpp ) # Add include paths for the executable -target_include_directories(${TARGET_NAME} - PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} -) +target_include_directories(${TARGET_NAME} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) \ No newline at end of file From 04cb8e82f1aaae89e20985539c74c1e36bb85ae3 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 29 Sep 2021 10:52:21 +0200 Subject: [PATCH 090/131] improvements and fixes --- CMakeLists.txt | 2 +- src/fsfw/FSFW.h.in | 8 +++++ src/fsfw/osal/common/TcpTmTcServer.cpp | 8 +++++ src/fsfw/osal/linux/CommandExecutor.cpp | 33 ++++++++++++++++--- .../tmtcpacket/pus/tm/TmPacketStoredPusC.cpp | 2 +- 5 files changed, 47 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ff66a6d..584dd943 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -186,4 +186,4 @@ target_compile_options(${LIB_FSFW_NAME} PRIVATE target_link_libraries(${LIB_FSFW_NAME} PRIVATE ${FSFW_ADDITIONAL_LINK_LIBS} -) \ No newline at end of file +) diff --git a/src/fsfw/FSFW.h.in b/src/fsfw/FSFW.h.in index 4da49b16..76c535ed 100644 --- a/src/fsfw/FSFW.h.in +++ b/src/fsfw/FSFW.h.in @@ -20,6 +20,14 @@ #define FSFW_TCP_RECV_WIRETAPPING_ENABLED 0 #endif +#ifndef FSFW_USE_PUS_C_TELEMETRY +#define FSFW_USE_PUS_C_TELEMETRY 1 +#endif + +#ifndef FSFW_USE_PUS_C_TELECOMMANDS +#define FSFW_USE_PUS_C_TELECOMMANDS 1 +#endif + // Can be used for low-level debugging of the SPI bus #ifndef FSFW_HAL_SPI_WIRETAPPING #define FSFW_HAL_SPI_WIRETAPPING 0 diff --git a/src/fsfw/osal/common/TcpTmTcServer.cpp b/src/fsfw/osal/common/TcpTmTcServer.cpp index 519df547..8b34b1a3 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.cpp +++ b/src/fsfw/osal/common/TcpTmTcServer.cpp @@ -210,7 +210,11 @@ void TcpTmTcServer::handleServerOperation(socket_t& connSocket) { ReturnValue_t TcpTmTcServer::handleTcReception(uint8_t* spacePacket, size_t packetSize) { if(wiretappingEnabled) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "Received TC:" << std::endl; +#else + sif::printInfo("Received TC:\n"); +#endif arrayprinter::print(spacePacket, packetSize); } @@ -278,7 +282,11 @@ ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent) return result; } if(wiretappingEnabled) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "Sending TM:" << std::endl; +#else + sif::printInfo("Sending TM:\n"); +#endif arrayprinter::print(storeAccessor.data(), storeAccessor.size()); } int retval = send(connSocket, diff --git a/src/fsfw/osal/linux/CommandExecutor.cpp b/src/fsfw/osal/linux/CommandExecutor.cpp index 5d131472..8216e591 100644 --- a/src/fsfw/osal/linux/CommandExecutor.cpp +++ b/src/fsfw/osal/linux/CommandExecutor.cpp @@ -62,8 +62,13 @@ ReturnValue_t CommandExecutor::close() { void CommandExecutor::printLastError(std::string funcName) const { if(lastError != 0) { - sif::error << funcName << " pclose failed with code " << - lastError << ": " << strerror(lastError) << std::endl; +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << funcName << " pclose failed with code " << lastError << ": " << + strerror(lastError) << std::endl; +#else + sif::printError("%s pclose failed with code %d: %s\n", + funcName, lastError, strerror(lastError)); +#endif } } @@ -98,15 +103,23 @@ ReturnValue_t CommandExecutor::check(bool& bytesRead) { ssize_t readBytes = read(currentFd, readVec.data(), readVec.size()); if(readBytes == 0) { // Should not happen - sif::warning << "CommandExecutor::check: " - "No bytes read after poll event.." << std::endl; +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "CommandExecutor::check: No bytes read " + "after poll event.." << std::endl; +#else + sif::printWarning("CommandExecutor::check: No bytes read after poll event..\n"); +#endif break; } else if(readBytes > 0) { bytesRead = true; if(printOutput) { // It is assumed the command output is line terminated +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << currentCmd << " | " << readVec.data(); +#else + sif::printInfo("%s | %s", currentCmd, readVec.data()); +#endif } if(ringBuffer != nullptr) { ringBuffer->writeData(reinterpret_cast( @@ -121,12 +134,20 @@ ReturnValue_t CommandExecutor::check(bool& bytesRead) { } else { // Should also not happen +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "CommandExecutor::check: Error " << errno << ": " << strerror(errno) << std::endl; +#else + sif::printWarning("CommandExecutor::check: Error %d: %s\n", errno, strerror(errno)); +#endif } } else if(waiter.revents & POLLERR) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "CommandExecuter::check: Poll error" << std::endl; +#else + sif::printWarning("CommandExecuter::check: Poll error\n"); +#endif return COMMAND_ERROR; } else if(waiter.revents & POLLHUP) { @@ -165,7 +186,11 @@ ReturnValue_t CommandExecutor::executeBlocking() { while(fgets(readVec.data(), readVec.size(), currentCmdFile) != nullptr) { std::string output(readVec.data()); if(printOutput) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << currentCmd << " | " << output; +#else + sif::printInfo("%s | %s", currentCmd, output); +#endif } if(ringBuffer != nullptr) { ringBuffer->writeData(reinterpret_cast(output.data()), output.size()); diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp index 4a6e4d21..7f75407d 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp @@ -77,9 +77,9 @@ TmPacketStoredPusC::TmPacketStoredPusC(uint16_t apid, uint8_t service, "%d too large\n", sizeToReserve); break; } -#endif #endif } +#endif TmPacketStoredBase::checkAndReportLostTm(); return; } From 3d0ce1998114c5d7a43034233ee03a800c8821b0 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 29 Sep 2021 10:58:01 +0200 Subject: [PATCH 091/131] additional options for c ustom main --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 584dd943..6acd9770 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,10 @@ option(FSFW_ADD_INTERNAL_TESTS "Add internal unit tests" ON) option(FSFW_ADD_UNITTESTS "Add regular unittests. Requires Catch2" OFF) option(FSFW_ADD_HAL "Add Hardware Abstraction Layer" ON) +if(FSFW_ADD_UNITTESTS) + option(FSFW_CUSTOM_UNITTEST_RUNNER "Add FSFW custom main runner" ON) +endif() + # Optional sources option(FSFW_ADD_PUS "Compile with PUS sources" ON) option(FSFW_ADD_MONITORING "Compile with monitoring components" ON) From 94bd4c7b56f9f22cdec118df8e681ed30a2f47b3 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 5 Oct 2021 01:23:56 +0200 Subject: [PATCH 092/131] using correct version number now --- src/fsfw/tmtcpacket/pus/tm/TmPacketBase.h | 2 -- src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.cpp | 7 +------ src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.h | 3 +++ src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp | 2 +- src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h | 3 +++ src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp | 3 +-- src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp | 3 +-- 7 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketBase.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketBase.h index 0379b977..31bfe3c8 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketBase.h +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketBase.h @@ -31,8 +31,6 @@ public: //! Maximum size of a TM Packet in this mission. //! TODO: Make this dependant on a config variable. static const uint32_t MISSION_TM_PACKET_MAX_SIZE = 2048; - //! First four bits of first byte of secondary header - static const uint8_t VERSION_NUMBER_BYTE = 0b00010000; /** * This is the default constructor. diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.cpp index c6540af5..a70fc45e 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.cpp @@ -62,12 +62,7 @@ void TmPacketPusA::initializeTmPacket(uint16_t apid, uint8_t service, //First, set to zero. memset(&tmData->data_field, 0, sizeof(tmData->data_field)); - // NOTE: In PUS-C, the PUS Version is 2 and specified for the first 4 bits. - // The other 4 bits of the first byte are the spacecraft time reference - // status. To change to PUS-C, set 0b00100000. - // Set CCSDS_secondary header flag to 0, version number to 001 and ack - // to 0000 - tmData->data_field.version_type_ack = 0b00010000; + tmData->data_field.version_type_ack = TM_PUS_VERSION_NUMBER << 4; tmData->data_field.service_type = service; tmData->data_field.service_subtype = subservice; tmData->data_field.subcounter = packetSubcounter; diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.h index 3856c779..839a6302 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.h +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.h @@ -52,6 +52,9 @@ public: sizeof(PUSTmDataFieldHeaderPusA) + 2); //! Maximum size of a TM Packet in this mission. static const uint32_t MISSION_TM_PACKET_MAX_SIZE = fsfwconfig::FSFW_MAX_TM_PACKET_SIZE; + //! First four bits of first byte of secondary header. Set to 1 according + //! to ECSS-E-ST-70-41C p.439 + static constexpr uint8_t TM_PUS_VERSION_NUMBER = 1; /** * This is the default constructor. diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp index 2c6e1d97..e309843d 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp @@ -67,7 +67,7 @@ ReturnValue_t TmPacketPusC::initializeTmPacket(uint16_t apid, uint8_t service, /* Only account for last 4 bytes for time reference field */ timeRefField &= 0b1111; - tmData->dataField.versionTimeReferenceField = VERSION_NUMBER_BYTE | timeRefField; + tmData->dataField.versionTimeReferenceField = (TM_PUS_VERSION_NUMBER << 4) | timeRefField; tmData->dataField.serviceType = service; tmData->dataField.serviceSubtype = subservice; tmData->dataField.subcounterMsb = packetSubcounter << 8 & 0xff; diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h index 3a9be132..e5dee662 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h @@ -54,6 +54,9 @@ public: sizeof(PUSTmDataFieldHeaderPusC) + 2); //! Maximum size of a TM Packet in this mission. static const uint32_t MISSION_TM_PACKET_MAX_SIZE = fsfwconfig::FSFW_MAX_TM_PACKET_SIZE; + //! First four bits of first byte of secondary header. Set to 2 according + //! to ECSS-E-ST-70-41C p.439 + static constexpr uint8_t TM_PUS_VERSION_NUMBER = 2; /** * This is the default constructor. diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp index 538dc95e..6f249667 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp @@ -29,8 +29,7 @@ TmPacketStoredPusA::TmPacketStoredPusA(uint16_t apid, uint8_t service, initializeTmPacket(apid, service, subservice, packetSubcounter); memcpy(getSourceData(), headerData, headerSize); memcpy(getSourceData() + headerSize, data, size); - setPacketDataLength( - size + headerSize + sizeof(PUSTmDataFieldHeaderPusA) + CRC_SIZE - 1); + setPacketDataLength(size + headerSize + sizeof(PUSTmDataFieldHeaderPusA) + CRC_SIZE - 1); } TmPacketStoredPusA::TmPacketStoredPusA(uint16_t apid, uint8_t service, diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp index 7f75407d..570d9d4e 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp @@ -30,8 +30,7 @@ TmPacketStoredPusC::TmPacketStoredPusC(uint16_t apid, uint8_t service, initializeTmPacket(apid, service, subservice, packetSubcounter, destinationId, timeRefField); memcpy(getSourceData(), headerData, headerSize); memcpy(getSourceData() + headerSize, data, size); - setPacketDataLength( - size + headerSize + sizeof(PUSTmDataFieldHeaderPusC) + CRC_SIZE - 1); + setPacketDataLength(size + headerSize + sizeof(PUSTmDataFieldHeaderPusC) + CRC_SIZE - 1); } TmPacketStoredPusC::TmPacketStoredPusC(uint16_t apid, uint8_t service, From a8a1148c65d0f4b7249374bbc31244762ca6765b Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 5 Oct 2021 12:39:57 +0200 Subject: [PATCH 093/131] fixes for PUS A stored --- .../tmtcpacket/pus/tm/TmPacketStoredPusA.cpp | 49 +++++++++++++++---- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp index 6f249667..3b183f09 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp @@ -29,7 +29,8 @@ TmPacketStoredPusA::TmPacketStoredPusA(uint16_t apid, uint8_t service, initializeTmPacket(apid, service, subservice, packetSubcounter); memcpy(getSourceData(), headerData, headerSize); memcpy(getSourceData() + headerSize, data, size); - setPacketDataLength(size + headerSize + sizeof(PUSTmDataFieldHeaderPusA) + CRC_SIZE - 1); + setPacketDataLength( + size + headerSize + sizeof(PUSTmDataFieldHeaderPusA) + CRC_SIZE - 1); } TmPacketStoredPusA::TmPacketStoredPusA(uint16_t apid, uint8_t service, @@ -41,32 +42,60 @@ TmPacketStoredPusA::TmPacketStoredPusA(uint16_t apid, uint8_t service, return; } size_t sourceDataSize = 0; - if (content != NULL) { + if (content != nullptr) { sourceDataSize += content->getSerializedSize(); } - if (header != NULL) { + if (header != nullptr) { sourceDataSize += header->getSerializedSize(); } - uint8_t *p_data = NULL; + uint8_t *pData = nullptr; + size_t sizeToReserve = getPacketMinimumSize() + sourceDataSize; ReturnValue_t returnValue = store->getFreeElement(&storeAddress, - (getPacketMinimumSize() + sourceDataSize), &p_data); + sizeToReserve, &pData); if (returnValue != store->RETURN_OK) { TmPacketStoredBase::checkAndReportLostTm(); +#if FSFW_VERBOSE_LEVEL >= 1 + switch(returnValue) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + case(StorageManagerIF::DATA_STORAGE_FULL): { + sif::warning << "TmPacketStoredPusA::TmPacketStoredPusC: Store full for packet with " + "size " << sizeToReserve << std::endl; + break; + } + case(StorageManagerIF::DATA_TOO_LARGE): { + sif::warning << "TmPacketStoredPusA::TmPacketStoredPusC: Data with size " << + sizeToReserve << " too large" << std::endl; + break; + } +#else + case(StorageManagerIF::DATA_STORAGE_FULL): { + sif::printWarning("TmPacketStoredPusA::TmPacketStoredPusC: Store full for packet with " + "size %d\n", sizeToReserve); + break; + } + case(StorageManagerIF::DATA_TOO_LARGE): { + sif::printWarning("TmPacketStoredPusA::TmPacketStoredPusC: Data with size " + "%d too large\n", sizeToReserve); + break; + } +#endif +#endif + } + return; } - setData(p_data); + setData(pData); initializeTmPacket(apid, service, subservice, packetSubcounter); uint8_t *putDataHere = getSourceData(); size_t size = 0; - if (header != NULL) { + if (header != nullptr) { header->serialize(&putDataHere, &size, sourceDataSize, SerializeIF::Endianness::BIG); } - if (content != NULL) { + if (content != nullptr) { content->serialize(&putDataHere, &size, sourceDataSize, SerializeIF::Endianness::BIG); } - setPacketDataLength( - sourceDataSize + sizeof(PUSTmDataFieldHeaderPusA) + CRC_SIZE - 1); + setPacketDataLength(sourceDataSize + sizeof(PUSTmDataFieldHeaderPusA) + CRC_SIZE - 1); } uint8_t* TmPacketStoredPusA::getAllTmData() { From 91f43d00a25ce69639c89f976bcab0e10998b570 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 5 Oct 2021 12:47:30 +0200 Subject: [PATCH 094/131] moved store failure to separate function --- .../tmtcpacket/pus/tm/TmPacketStoredBase.cpp | 32 ++++++++++++++++- .../tmtcpacket/pus/tm/TmPacketStoredBase.h | 3 ++ .../tmtcpacket/pus/tm/TmPacketStoredPusA.cpp | 34 +++---------------- .../tmtcpacket/pus/tm/TmPacketStoredPusC.cpp | 34 +++---------------- 4 files changed, 42 insertions(+), 61 deletions(-) diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.cpp index 466e4cd2..20a8ed89 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.cpp @@ -91,4 +91,34 @@ void TmPacketStoredBase::checkAndReportLostTm() { } } - +void TmPacketStoredBase::handleStoreFailure(const char *const packetType, ReturnValue_t result, + size_t sizeToReserve) { + checkAndReportLostTm(); +#if FSFW_VERBOSE_LEVEL >= 1 + switch(result) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + case(StorageManagerIF::DATA_STORAGE_FULL): { + sif::warning << "TmPacketStoredPus" << packetType << ": " << + "Store full for packet with size" << sizeToReserve << std::endl; + break; + } + case(StorageManagerIF::DATA_TOO_LARGE): { + sif::warning << "TmPacketStoredPus" << packetType << ": Data with size " << + sizeToReserve << " too large" << std::endl; + break; + } +#else + case(StorageManagerIF::DATA_STORAGE_FULL): { + sif::printWarning("TmPacketStoredPus%s: Store full for packet with " + "size %d\n", packetType, sizeToReserve); + break; + } + case(StorageManagerIF::DATA_TOO_LARGE): { + sif::printWarning("TmPacketStoredPus%s: Data with size " + "%d too large\n", packetType, sizeToReserve); + break; + } +#endif +#endif + } +} diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.h index 8e8b9c70..91ca2f93 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.h +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.h @@ -82,6 +82,9 @@ protected: bool checkAndSetStore(); void checkAndReportLostTm(); + + void handleStoreFailure(const char* const packetType, ReturnValue_t result, + size_t sizeToReserve); }; diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp index 3b183f09..a8a10da6 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp @@ -18,11 +18,12 @@ TmPacketStoredPusA::TmPacketStoredPusA(uint16_t apid, uint8_t service, return; } uint8_t *pData = nullptr; + size_t sizeToReserve = getPacketMinimumSize() + size + headerSize; ReturnValue_t returnValue = store->getFreeElement(&storeAddress, - (getPacketMinimumSize() + size + headerSize), &pData); + sizeToReserve, &pData); if (returnValue != store->RETURN_OK) { - TmPacketStoredBase::checkAndReportLostTm(); + handleStoreFailure("A", returnValue, sizeToReserve); return; } setData(pData); @@ -53,34 +54,7 @@ TmPacketStoredPusA::TmPacketStoredPusA(uint16_t apid, uint8_t service, ReturnValue_t returnValue = store->getFreeElement(&storeAddress, sizeToReserve, &pData); if (returnValue != store->RETURN_OK) { - TmPacketStoredBase::checkAndReportLostTm(); -#if FSFW_VERBOSE_LEVEL >= 1 - switch(returnValue) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - case(StorageManagerIF::DATA_STORAGE_FULL): { - sif::warning << "TmPacketStoredPusA::TmPacketStoredPusC: Store full for packet with " - "size " << sizeToReserve << std::endl; - break; - } - case(StorageManagerIF::DATA_TOO_LARGE): { - sif::warning << "TmPacketStoredPusA::TmPacketStoredPusC: Data with size " << - sizeToReserve << " too large" << std::endl; - break; - } -#else - case(StorageManagerIF::DATA_STORAGE_FULL): { - sif::printWarning("TmPacketStoredPusA::TmPacketStoredPusC: Store full for packet with " - "size %d\n", sizeToReserve); - break; - } - case(StorageManagerIF::DATA_TOO_LARGE): { - sif::printWarning("TmPacketStoredPusA::TmPacketStoredPusC: Data with size " - "%d too large\n", sizeToReserve); - break; - } -#endif -#endif - } + handleStoreFailure("A", returnValue, sizeToReserve); return; } setData(pData); diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp index 570d9d4e..ee574299 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp @@ -19,11 +19,12 @@ TmPacketStoredPusC::TmPacketStoredPusC(uint16_t apid, uint8_t service, return; } uint8_t *pData = nullptr; + size_t sizeToReserve = getPacketMinimumSize() + size + headerSize; ReturnValue_t returnValue = store->getFreeElement(&storeAddress, - (getPacketMinimumSize() + size + headerSize), &pData); + sizeToReserve, &pData); if (returnValue != store->RETURN_OK) { - TmPacketStoredBase::checkAndReportLostTm(); + handleStoreFailure("C", returnValue, sizeToReserve); return; } setData(pData); @@ -52,34 +53,7 @@ TmPacketStoredPusC::TmPacketStoredPusC(uint16_t apid, uint8_t service, size_t sizeToReserve = getPacketMinimumSize() + sourceDataSize; ReturnValue_t returnValue = store->getFreeElement(&storeAddress, sizeToReserve, &pData); if (returnValue != store->RETURN_OK) { -#if FSFW_VERBOSE_LEVEL >= 1 - switch(returnValue) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - case(StorageManagerIF::DATA_STORAGE_FULL): { - sif::warning << "TmPacketStoredPusC::TmPacketStoredPusC: Store full for packet with " - "size " << sizeToReserve << std::endl; - break; - } - case(StorageManagerIF::DATA_TOO_LARGE): { - sif::warning << "TmPacketStoredPusC::TmPacketStoredPusC: Data with size " << - sizeToReserve << " too large" << std::endl; - break; - } -#else - case(StorageManagerIF::DATA_STORAGE_FULL): { - sif::printWarning("TmPacketStoredPusC::TmPacketStoredPusC: Store full for packet with " - "size %d\n", sizeToReserve); - break; - } - case(StorageManagerIF::DATA_TOO_LARGE): { - sif::printWarning("TmPacketStoredPusC::TmPacketStoredPusC: Data with size " - "%d too large\n", sizeToReserve); - break; - } -#endif - } -#endif - TmPacketStoredBase::checkAndReportLostTm(); + handleStoreFailure("C", returnValue, sizeToReserve); return; } setData(pData); From 2124f36e36318bc4567c341bb7459cf61b4ab52f Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 5 Oct 2021 12:47:30 +0200 Subject: [PATCH 095/131] moved store failure to separate function --- .../tmtcpacket/pus/tm/TmPacketStoredPusA.cpp | 114 +++++++++--------- .../tmtcpacket/pus/tm/TmPacketStoredPusA.h | 74 ++++++------ 2 files changed, 94 insertions(+), 94 deletions(-) diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp index a8a10da6..067b4f8f 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp @@ -5,71 +5,71 @@ #include -TmPacketStoredPusA::TmPacketStoredPusA(store_address_t setAddress) : - TmPacketStoredBase(setAddress), TmPacketPusA(nullptr){ +TmPacketStoredPusA::TmPacketStoredPusA(store_address_t setAddress): + TmPacketStoredBase(setAddress), TmPacketPusA(nullptr){ } TmPacketStoredPusA::TmPacketStoredPusA(uint16_t apid, uint8_t service, - uint8_t subservice, uint8_t packetSubcounter, const uint8_t *data, - uint32_t size, const uint8_t *headerData, uint32_t headerSize) : + uint8_t subservice, uint8_t packetSubcounter, const uint8_t *data, + uint32_t size, const uint8_t *headerData, uint32_t headerSize): TmPacketPusA(nullptr) { - storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - if (not TmPacketStoredBase::checkAndSetStore()) { - return; - } - uint8_t *pData = nullptr; - size_t sizeToReserve = getPacketMinimumSize() + size + headerSize; - ReturnValue_t returnValue = store->getFreeElement(&storeAddress, - sizeToReserve, &pData); + storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; + if (not TmPacketStoredBase::checkAndSetStore()) { + return; + } + uint8_t *pData = nullptr; + size_t sizeToReserve = getPacketMinimumSize() + size + headerSize; + ReturnValue_t returnValue = store->getFreeElement(&storeAddress, + sizeToReserve, &pData); - if (returnValue != store->RETURN_OK) { - handleStoreFailure("A", returnValue, sizeToReserve); - return; - } - setData(pData); - initializeTmPacket(apid, service, subservice, packetSubcounter); - memcpy(getSourceData(), headerData, headerSize); - memcpy(getSourceData() + headerSize, data, size); - setPacketDataLength( - size + headerSize + sizeof(PUSTmDataFieldHeaderPusA) + CRC_SIZE - 1); + if (returnValue != store->RETURN_OK) { + handleStoreFailure("A", returnValue, sizeToReserve); + return; + } + setData(pData); + initializeTmPacket(apid, service, subservice, packetSubcounter); + memcpy(getSourceData(), headerData, headerSize); + memcpy(getSourceData() + headerSize, data, size); + setPacketDataLength( + size + headerSize + sizeof(PUSTmDataFieldHeaderPusA) + CRC_SIZE - 1); } TmPacketStoredPusA::TmPacketStoredPusA(uint16_t apid, uint8_t service, - uint8_t subservice, uint8_t packetSubcounter, SerializeIF *content, - SerializeIF *header) : - TmPacketPusA(nullptr) { - storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - if (not TmPacketStoredBase::checkAndSetStore()) { - return; - } - size_t sourceDataSize = 0; - if (content != nullptr) { - sourceDataSize += content->getSerializedSize(); - } - if (header != nullptr) { - sourceDataSize += header->getSerializedSize(); - } - uint8_t *pData = nullptr; - size_t sizeToReserve = getPacketMinimumSize() + sourceDataSize; - ReturnValue_t returnValue = store->getFreeElement(&storeAddress, - sizeToReserve, &pData); - if (returnValue != store->RETURN_OK) { - handleStoreFailure("A", returnValue, sizeToReserve); - return; - } - setData(pData); - initializeTmPacket(apid, service, subservice, packetSubcounter); - uint8_t *putDataHere = getSourceData(); - size_t size = 0; - if (header != nullptr) { - header->serialize(&putDataHere, &size, sourceDataSize, - SerializeIF::Endianness::BIG); - } - if (content != nullptr) { - content->serialize(&putDataHere, &size, sourceDataSize, - SerializeIF::Endianness::BIG); - } - setPacketDataLength(sourceDataSize + sizeof(PUSTmDataFieldHeaderPusA) + CRC_SIZE - 1); + uint8_t subservice, uint8_t packetSubcounter, SerializeIF *content, + SerializeIF *header) : + TmPacketPusA(nullptr) { + storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; + if (not TmPacketStoredBase::checkAndSetStore()) { + return; + } + size_t sourceDataSize = 0; + if (content != nullptr) { + sourceDataSize += content->getSerializedSize(); + } + if (header != nullptr) { + sourceDataSize += header->getSerializedSize(); + } + uint8_t *pData = nullptr; + size_t sizeToReserve = getPacketMinimumSize() + sourceDataSize; + ReturnValue_t returnValue = store->getFreeElement(&storeAddress, + sizeToReserve, &pData); + if (returnValue != store->RETURN_OK) { + handleStoreFailure("A", returnValue, sizeToReserve); + return; + } + setData(pData); + initializeTmPacket(apid, service, subservice, packetSubcounter); + uint8_t *putDataHere = getSourceData(); + size_t size = 0; + if (header != nullptr) { + header->serialize(&putDataHere, &size, sourceDataSize, + SerializeIF::Endianness::BIG); + } + if (content != nullptr) { + content->serialize(&putDataHere, &size, sourceDataSize, + SerializeIF::Endianness::BIG); + } + setPacketDataLength(sourceDataSize + sizeof(PUSTmDataFieldHeaderPusA) + CRC_SIZE - 1); } uint8_t* TmPacketStoredPusA::getAllTmData() { diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.h index 0cfcf0b8..6a338cd5 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.h +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.h @@ -15,46 +15,46 @@ * packets in a store with the help of a storeAddress. * @ingroup tmtcpackets */ -class TmPacketStoredPusA : +class TmPacketStoredPusA: public TmPacketStoredBase, public TmPacketPusA { public: - /** - * This is a default constructor which does not set the data pointer. - * However, it does try to set the packet store. - */ - TmPacketStoredPusA( store_address_t setAddress ); - /** - * With this constructor, new space is allocated in the packet store and - * a new PUS Telemetry Packet is created there. - * Packet Application Data passed in data is copied into the packet. - * The Application data is passed in two parts, first a header, then a - * data field. This allows building a Telemetry Packet from two separate - * data sources. - * @param apid Sets the packet's APID field. - * @param service Sets the packet's Service ID field. - * This specifies the source service. - * @param subservice Sets the packet's Service Subtype field. - * This specifies the source sub-service. - * @param packet_counter Sets the Packet counter field of this packet - * @param data The payload data to be copied to the - * Application Data Field - * @param size The amount of data to be copied. - * @param headerData The header Data of the Application field, - * will be copied in front of data - * @param headerSize The size of the headerDataF - */ - TmPacketStoredPusA( uint16_t apid, uint8_t service, uint8_t subservice, - uint8_t packet_counter = 0, const uint8_t* data = nullptr, - uint32_t size = 0, const uint8_t* headerData = nullptr, - uint32_t headerSize = 0); - /** - * Another ctor to directly pass structured content and header data to the - * packet to avoid additional buffers. - */ - TmPacketStoredPusA( uint16_t apid, uint8_t service, uint8_t subservice, - uint8_t packet_counter, SerializeIF* content, - SerializeIF* header = nullptr); + /** + * This is a default constructor which does not set the data pointer. + * However, it does try to set the packet store. + */ + TmPacketStoredPusA( store_address_t setAddress ); + /** + * With this constructor, new space is allocated in the packet store and + * a new PUS Telemetry Packet is created there. + * Packet Application Data passed in data is copied into the packet. + * The Application data is passed in two parts, first a header, then a + * data field. This allows building a Telemetry Packet from two separate + * data sources. + * @param apid Sets the packet's APID field. + * @param service Sets the packet's Service ID field. + * This specifies the source service. + * @param subservice Sets the packet's Service Subtype field. + * This specifies the source sub-service. + * @param packet_counter Sets the Packet counter field of this packet + * @param data The payload data to be copied to the + * Application Data Field + * @param size The amount of data to be copied. + * @param headerData The header Data of the Application field, + * will be copied in front of data + * @param headerSize The size of the headerDataF + */ + TmPacketStoredPusA( uint16_t apid, uint8_t service, uint8_t subservice, + uint8_t packet_counter = 0, const uint8_t* data = nullptr, + uint32_t size = 0, const uint8_t* headerData = nullptr, + uint32_t headerSize = 0); + /** + * Another ctor to directly pass structured content and header data to the + * packet to avoid additional buffers. + */ + TmPacketStoredPusA( uint16_t apid, uint8_t service, uint8_t subservice, + uint8_t packet_counter, SerializeIF* content, + SerializeIF* header = nullptr); uint8_t* getAllTmData() override; void setDataPointer(const uint8_t* newPointer) override; From 3502ddca7ff29d443bb6991d18c683496d26c313 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 5 Oct 2021 13:13:36 +0200 Subject: [PATCH 096/131] using pus version enum now --- src/fsfw/tmtcpacket/pus/definitions.h | 16 ++++++++++++++++ src/fsfw/tmtcpacket/pus/tc/TcPacketPus.cpp | 11 +++++------ src/fsfw/tmtcpacket/pus/tc/TcPacketPus.h | 4 +++- src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.cpp | 7 ++++++- src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.cpp | 7 ++++--- src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.h | 3 --- src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp | 8 +++++--- 7 files changed, 39 insertions(+), 17 deletions(-) create mode 100644 src/fsfw/tmtcpacket/pus/definitions.h diff --git a/src/fsfw/tmtcpacket/pus/definitions.h b/src/fsfw/tmtcpacket/pus/definitions.h new file mode 100644 index 00000000..d92ab312 --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/definitions.h @@ -0,0 +1,16 @@ +#ifndef FSFW_SRC_FSFW_TMTCPACKET_PUS_TM_DEFINITIONS_H_ +#define FSFW_SRC_FSFW_TMTCPACKET_PUS_TM_DEFINITIONS_H_ + +#include + +namespace pus { + +//! Version numbers according to ECSS-E-ST-70-41C p.439 +enum PusVersion: uint8_t { + PUS_A_VERSION = 1, + PUS_C_VERSION = 2 +}; + +} + +#endif /* FSFW_SRC_FSFW_TMTCPACKET_PUS_TM_DEFINITIONS_H_ */ diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.cpp b/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.cpp index 28533754..2b97b0d2 100644 --- a/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.cpp +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.cpp @@ -1,4 +1,4 @@ -#include "fsfw/tmtcpacket/pus/tc/TcPacketPus.h" +#include "TcPacketPus.h" #include "fsfw/globalfunctions/CRC.h" #include @@ -8,14 +8,13 @@ TcPacketPus::TcPacketPus(const uint8_t *setData): TcPacketBase(setData) { } void TcPacketPus::initializeTcPacket(uint16_t apid, uint16_t sequenceCount, - uint8_t ack, uint8_t service, uint8_t subservice, uint16_t sourceId) { + uint8_t ack, uint8_t service, uint8_t subservice, pus::PusVersion pusVersion, + uint16_t sourceId) { initSpacePacketHeader(true, true, apid, sequenceCount); std::memset(&tcData->dataField, 0, sizeof(tcData->dataField)); setPacketDataLength(sizeof(PUSTcDataFieldHeader) + CRC_SIZE - 1); - // Data Field Header: - // Set CCSDS_secondary_header_flag to 0 and version number to 001 - tcData->dataField.versionTypeAck = 0b00010000; - tcData->dataField.versionTypeAck |= (ack & 0x0F); + // Data Field Header. For PUS A, the first bit (CCSDS Secondary Header Flag) is zero + tcData->dataField.versionTypeAck = pusVersion << 4 | (ack & 0x0F); tcData->dataField.serviceType = service; tcData->dataField.serviceSubtype = subservice; #if FSFW_USE_PUS_C_TELECOMMANDS == 1 diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.h b/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.h index 082541ba..1bacc3a7 100644 --- a/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.h +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.h @@ -2,6 +2,7 @@ #define FSFW_TMTCPACKET_PUS_TCPACKETPUSA_H_ #include "fsfw/FSFW.h" +#include "../definitions.h" #include "fsfw/tmtcpacket/ccsds_header.h" #include "TcPacketBase.h" @@ -75,7 +76,8 @@ protected: * @param subservice PUS Subservice */ void initializeTcPacket(uint16_t apid, uint16_t sequenceCount, uint8_t ack, - uint8_t service, uint8_t subservice, uint16_t sourceId = 0); + uint8_t service, uint8_t subservice, pus::PusVersion pusVersion, + uint16_t sourceId = 0); /** * A pointer to a structure which defines the data structure of diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.cpp b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.cpp index 5ea9f5b1..7f8f4ac8 100644 --- a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.cpp +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.cpp @@ -23,7 +23,12 @@ TcPacketStoredPus::TcPacketStoredPus(uint16_t apid, uint8_t service, return; } this->setData(pData); - initializeTcPacket(apid, sequenceCount, ack, service, subservice); +#if FSFW_USE_PUS_C_TELECOMMANDS == 1 + pus::PusVersion pusVersion = pus::PusVersion::PUS_C_VERSION; +#else + pus::PusVersion pusVersion = pus::PusVersion::PUS_A_VERSION; +#endif + initializeTcPacket(apid, sequenceCount, ack, service, subservice, pusVersion); std::memcpy(&tcData->appData, data, size); this->setPacketDataLength( size + sizeof(PUSTcDataFieldHeader) + CRC_SIZE - 1); diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.cpp index a70fc45e..ccf5a8ac 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.cpp @@ -1,5 +1,6 @@ -#include "fsfw/tmtcpacket/pus/tm/TmPacketPusA.h" -#include "fsfw/tmtcpacket/pus/tm/TmPacketBase.h" +#include "../definitions.h" +#include "TmPacketPusA.h" +#include "TmPacketBase.h" #include "fsfw/globalfunctions/CRC.h" #include "fsfw/globalfunctions/arrayprinter.h" @@ -62,7 +63,7 @@ void TmPacketPusA::initializeTmPacket(uint16_t apid, uint8_t service, //First, set to zero. memset(&tmData->data_field, 0, sizeof(tmData->data_field)); - tmData->data_field.version_type_ack = TM_PUS_VERSION_NUMBER << 4; + tmData->data_field.version_type_ack = pus::PusVersion::PUS_A_VERSION << 4; tmData->data_field.service_type = service; tmData->data_field.service_subtype = subservice; tmData->data_field.subcounter = packetSubcounter; diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.h index 839a6302..3856c779 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.h +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.h @@ -52,9 +52,6 @@ public: sizeof(PUSTmDataFieldHeaderPusA) + 2); //! Maximum size of a TM Packet in this mission. static const uint32_t MISSION_TM_PACKET_MAX_SIZE = fsfwconfig::FSFW_MAX_TM_PACKET_SIZE; - //! First four bits of first byte of secondary header. Set to 1 according - //! to ECSS-E-ST-70-41C p.439 - static constexpr uint8_t TM_PUS_VERSION_NUMBER = 1; /** * This is the default constructor. diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp index e309843d..003d565e 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp @@ -1,5 +1,6 @@ -#include "fsfw/tmtcpacket/pus/tm/TmPacketPusC.h" -#include "fsfw/tmtcpacket/pus/tm/TmPacketBase.h" +#include "../definitions.h" +#include "TmPacketPusC.h" +#include "TmPacketBase.h" #include "fsfw/globalfunctions/CRC.h" #include "fsfw/globalfunctions/arrayprinter.h" @@ -67,7 +68,8 @@ ReturnValue_t TmPacketPusC::initializeTmPacket(uint16_t apid, uint8_t service, /* Only account for last 4 bytes for time reference field */ timeRefField &= 0b1111; - tmData->dataField.versionTimeReferenceField = (TM_PUS_VERSION_NUMBER << 4) | timeRefField; + tmData->dataField.versionTimeReferenceField = + (pus::PusVersion::PUS_C_VERSION << 4) | timeRefField; tmData->dataField.serviceType = service; tmData->dataField.serviceSubtype = subservice; tmData->dataField.subcounterMsb = packetSubcounter << 8 & 0xff; From db801a0ecc7323f3bc552be0de383c6bb1b29fb7 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 5 Oct 2021 13:17:12 +0200 Subject: [PATCH 097/131] removed unneeded static constexpr --- src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h index e5dee662..3a9be132 100644 --- a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h @@ -54,9 +54,6 @@ public: sizeof(PUSTmDataFieldHeaderPusC) + 2); //! Maximum size of a TM Packet in this mission. static const uint32_t MISSION_TM_PACKET_MAX_SIZE = fsfwconfig::FSFW_MAX_TM_PACKET_SIZE; - //! First four bits of first byte of secondary header. Set to 2 according - //! to ECSS-E-ST-70-41C p.439 - static constexpr uint8_t TM_PUS_VERSION_NUMBER = 2; /** * This is the default constructor. From 8e65833d607614996510a6a30a261c0c2ccf4e3f Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Fri, 8 Oct 2021 13:24:51 +0200 Subject: [PATCH 098/131] added bind call error string --- src/fsfw/osal/common/tcpipCommon.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/fsfw/osal/common/tcpipCommon.cpp b/src/fsfw/osal/common/tcpipCommon.cpp index 0fdbf867..2551496d 100644 --- a/src/fsfw/osal/common/tcpipCommon.cpp +++ b/src/fsfw/osal/common/tcpipCommon.cpp @@ -21,6 +21,9 @@ void tcpip::determineErrorStrings(Protocol protocol, ErrorSources errorSrc, std: if(errorSrc == ErrorSources::SETSOCKOPT_CALL) { srcString = "setsockopt call"; } + if(errorSrc == ErrorSources::BIND_CALL) { + srcString = "bind call"; + } else if(errorSrc == ErrorSources::SOCKET_CALL) { srcString = "socket call"; } From a578f0390bce6c0a3d1d1e8d59764072f1075867 Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Fri, 8 Oct 2021 13:51:32 +0200 Subject: [PATCH 099/131] tcp server also parses TCs when client closes connection --- src/fsfw/osal/common/TcpTmTcServer.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/fsfw/osal/common/TcpTmTcServer.cpp b/src/fsfw/osal/common/TcpTmTcServer.cpp index 8b34b1a3..7e6853fc 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.cpp +++ b/src/fsfw/osal/common/TcpTmTcServer.cpp @@ -168,7 +168,10 @@ void TcpTmTcServer::handleServerOperation(socket_t& connSocket) { tcpConfig.tcpFlags ); if(retval == 0) { - // Client closed connection + size_t availableReadData = ringBuffer.getAvailableReadData(); + if(availableReadData > lastRingBufferSize) { + handleTcRingBufferData(availableReadData); + } return; } else if(retval > 0) { From 2e37bd73e26d42c8f14de4a2427b3bda871a40aa Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 11 Oct 2021 19:35:35 +0200 Subject: [PATCH 100/131] deleted timer object --- src/fsfw/osal/linux/Timer.cpp | 57 ----------------------------------- src/fsfw/osal/linux/Timer.h | 49 ------------------------------ 2 files changed, 106 deletions(-) delete mode 100644 src/fsfw/osal/linux/Timer.cpp delete mode 100644 src/fsfw/osal/linux/Timer.h diff --git a/src/fsfw/osal/linux/Timer.cpp b/src/fsfw/osal/linux/Timer.cpp deleted file mode 100644 index 899ca4a5..00000000 --- a/src/fsfw/osal/linux/Timer.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "fsfw/osal/linux/Timer.h" -#include "fsfw/serviceinterface/ServiceInterfaceStream.h" -#include - - -Timer::Timer() { - sigevent sigEvent; - sigEvent.sigev_notify = SIGEV_NONE; - sigEvent.sigev_signo = 0; - sigEvent.sigev_value.sival_ptr = &timerId; - int status = timer_create(CLOCK_MONOTONIC, &sigEvent, &timerId); - if(status!=0){ -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "Timer creation failed with: " << status << - " errno: " << errno << std::endl; -#endif - } -} - -Timer::~Timer() { - timer_delete(timerId); -} - -int Timer::setTimer(uint32_t intervalMs) { - itimerspec timer; - timer.it_value.tv_sec = intervalMs / 1000; - timer.it_value.tv_nsec = (intervalMs * 1000000) % (1000000000); - timer.it_interval.tv_sec = 0; - timer.it_interval.tv_nsec = 0; - set = true; - return timer_settime(timerId, 0, &timer, NULL); -} - - -int Timer::getTimer(uint32_t* remainingTimeMs){ - itimerspec timer; - timer.it_value.tv_sec = 0; - timer.it_value.tv_nsec = 0; - timer.it_interval.tv_sec = 0; - timer.it_interval.tv_nsec = 0; - int status = timer_gettime(timerId, &timer); - - *remainingTimeMs = timer.it_value.tv_sec * 1000 + timer.it_value.tv_nsec / 1000000; - - return status; -} - -bool Timer::isSet() const { - return this->set; -} - -void Timer::resetTimer() { - if(not this->set) { - set = false; - } - setTimer(0); -} diff --git a/src/fsfw/osal/linux/Timer.h b/src/fsfw/osal/linux/Timer.h deleted file mode 100644 index 6d8c1b9e..00000000 --- a/src/fsfw/osal/linux/Timer.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef FRAMEWORK_OSAL_LINUX_TIMER_H_ -#define FRAMEWORK_OSAL_LINUX_TIMER_H_ - -#include -#include -#include - -/** - * This class is a helper for the creation of a Clock Monotonic timer which does not trigger a signal - */ -class Timer { -public: - /** - * Creates the Timer sets the timerId Member - */ - Timer(); - /** - * Deletes the timer - * - * Careful! According to POSIX documentation: - * The treatment of any pending signal generated by the deleted timer is unspecified. - */ - virtual ~Timer(); - - /** - * Set the timer given in timerId to the given interval - * - * @param intervalMs Interval in ms to be set - * @return 0 on Success 1 else - */ - int setTimer(uint32_t intervalMs); - - /** - * Get the remaining time of the timer - * - * @param remainingTimeMs Pointer to integer value which is used to return the remaining time - * @return 0 on Success 1 else (see timer_getime documentation of posix function) - */ - int getTimer(uint32_t* remainingTimeMs); - - bool isSet() const; - void resetTimer(); - -private: - bool set = true; - timer_t timerId; -}; - -#endif /* FRAMEWORK_OSAL_LINUX_TIMER_H_ */ From 4130dd9e32eb1d4a5b0e993408ae614952bdd005 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 11 Oct 2021 19:38:53 +0200 Subject: [PATCH 101/131] using cmakelists from upstream --- CMakeLists.txt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6acd9770..5ff66a6d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,10 +13,6 @@ option(FSFW_ADD_INTERNAL_TESTS "Add internal unit tests" ON) option(FSFW_ADD_UNITTESTS "Add regular unittests. Requires Catch2" OFF) option(FSFW_ADD_HAL "Add Hardware Abstraction Layer" ON) -if(FSFW_ADD_UNITTESTS) - option(FSFW_CUSTOM_UNITTEST_RUNNER "Add FSFW custom main runner" ON) -endif() - # Optional sources option(FSFW_ADD_PUS "Compile with PUS sources" ON) option(FSFW_ADD_MONITORING "Compile with monitoring components" ON) @@ -190,4 +186,4 @@ target_compile_options(${LIB_FSFW_NAME} PRIVATE target_link_libraries(${LIB_FSFW_NAME} PRIVATE ${FSFW_ADDITIONAL_LINK_LIBS} -) +) \ No newline at end of file From f3dbf68f7c03d0863d380173ff842b3ec44c6760 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 11 Oct 2021 20:03:29 +0200 Subject: [PATCH 102/131] moved command executor --- .../src/fsfw_hal}/linux/CommandExecutor.cpp | 0 .../src/fsfw_hal}/linux/CommandExecutor.h | 0 src/fsfw/osal/linux/CMakeLists.txt | 34 +++++++++---------- 3 files changed, 16 insertions(+), 18 deletions(-) rename {src/fsfw/osal => hal/src/fsfw_hal}/linux/CommandExecutor.cpp (100%) rename {src/fsfw/osal => hal/src/fsfw_hal}/linux/CommandExecutor.h (100%) diff --git a/src/fsfw/osal/linux/CommandExecutor.cpp b/hal/src/fsfw_hal/linux/CommandExecutor.cpp similarity index 100% rename from src/fsfw/osal/linux/CommandExecutor.cpp rename to hal/src/fsfw_hal/linux/CommandExecutor.cpp diff --git a/src/fsfw/osal/linux/CommandExecutor.h b/hal/src/fsfw_hal/linux/CommandExecutor.h similarity index 100% rename from src/fsfw/osal/linux/CommandExecutor.h rename to hal/src/fsfw_hal/linux/CommandExecutor.h diff --git a/src/fsfw/osal/linux/CMakeLists.txt b/src/fsfw/osal/linux/CMakeLists.txt index 63206cb2..dcdade67 100644 --- a/src/fsfw/osal/linux/CMakeLists.txt +++ b/src/fsfw/osal/linux/CMakeLists.txt @@ -1,21 +1,19 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - Clock.cpp - BinarySemaphore.cpp - CountingSemaphore.cpp - FixedTimeslotTask.cpp - InternalErrorCodes.cpp - MessageQueue.cpp - Mutex.cpp - MutexFactory.cpp - PeriodicPosixTask.cpp - PosixThread.cpp - QueueFactory.cpp - SemaphoreFactory.cpp - TaskFactory.cpp - tcpipHelpers.cpp - unixUtility.cpp - CommandExecutor.cpp +target_sources(${LIB_FSFW_NAME} PRIVATE + Clock.cpp + BinarySemaphore.cpp + CountingSemaphore.cpp + FixedTimeslotTask.cpp + InternalErrorCodes.cpp + MessageQueue.cpp + Mutex.cpp + MutexFactory.cpp + PeriodicPosixTask.cpp + PosixThread.cpp + QueueFactory.cpp + SemaphoreFactory.cpp + TaskFactory.cpp + tcpipHelpers.cpp + unixUtility.cpp ) find_package(Threads REQUIRED) From d693817158af209b34c49ea09c6863a7a2bc1fbe Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 11 Oct 2021 20:05:11 +0200 Subject: [PATCH 103/131] added cmakelists source addition --- hal/src/fsfw_hal/linux/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/hal/src/fsfw_hal/linux/CMakeLists.txt b/hal/src/fsfw_hal/linux/CMakeLists.txt index 5944b0e5..0ec77524 100644 --- a/hal/src/fsfw_hal/linux/CMakeLists.txt +++ b/hal/src/fsfw_hal/linux/CMakeLists.txt @@ -4,6 +4,7 @@ endif() target_sources(${LIB_FSFW_NAME} PRIVATE UnixFileGuard.cpp + CommandExecutor.cpp utility.cpp ) From eba2f87b36429fc814f9d4768c68fd2827f4c410 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 13 Oct 2021 15:49:58 +0200 Subject: [PATCH 104/131] formatting tweak --- src/fsfw/osal/linux/CMakeLists.txt | 34 +++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/fsfw/osal/linux/CMakeLists.txt b/src/fsfw/osal/linux/CMakeLists.txt index dcdade67..679b2931 100644 --- a/src/fsfw/osal/linux/CMakeLists.txt +++ b/src/fsfw/osal/linux/CMakeLists.txt @@ -1,29 +1,29 @@ target_sources(${LIB_FSFW_NAME} PRIVATE Clock.cpp - BinarySemaphore.cpp - CountingSemaphore.cpp - FixedTimeslotTask.cpp - InternalErrorCodes.cpp - MessageQueue.cpp - Mutex.cpp - MutexFactory.cpp - PeriodicPosixTask.cpp - PosixThread.cpp - QueueFactory.cpp - SemaphoreFactory.cpp - TaskFactory.cpp - tcpipHelpers.cpp - unixUtility.cpp + BinarySemaphore.cpp + CountingSemaphore.cpp + FixedTimeslotTask.cpp + InternalErrorCodes.cpp + MessageQueue.cpp + Mutex.cpp + MutexFactory.cpp + PeriodicPosixTask.cpp + PosixThread.cpp + QueueFactory.cpp + SemaphoreFactory.cpp + TaskFactory.cpp + tcpipHelpers.cpp + unixUtility.cpp ) find_package(Threads REQUIRED) target_link_libraries(${LIB_FSFW_NAME} PRIVATE - ${CMAKE_THREAD_LIBS_INIT} - rt + ${CMAKE_THREAD_LIBS_INIT} + rt ) target_link_libraries(${LIB_FSFW_NAME} INTERFACE - ${CMAKE_THREAD_LIBS_INIT} + ${CMAKE_THREAD_LIBS_INIT} ) From 15687f6f6e0ca284dbe502f082ef3ab2f0b27b71 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 18 Oct 2021 18:21:15 +0200 Subject: [PATCH 105/131] this should have been in the PR.. --- src/fsfw/tmtcpacket/SpacePacket.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fsfw/tmtcpacket/SpacePacket.h b/src/fsfw/tmtcpacket/SpacePacket.h index 677ba023..16673319 100644 --- a/src/fsfw/tmtcpacket/SpacePacket.h +++ b/src/fsfw/tmtcpacket/SpacePacket.h @@ -77,12 +77,12 @@ constexpr uint16_t getSpacePacketIdFromApid(bool isTc, uint16_t apid, ((apid >> 8) & 0x07)) << 8 | (apid & 0x00ff); } -constexpr uint16_t getTcSpacketIdFromApid(uint16_t apid, +constexpr uint16_t getTcSpacePacketIdFromApid(uint16_t apid, bool secondaryHeaderFlag = true) { return getSpacePacketIdFromApid(true, apid, secondaryHeaderFlag); } -constexpr uint16_t getTmSpacketIdFromApid(uint16_t apid, +constexpr uint16_t getTmSpacePacketIdFromApid(uint16_t apid, bool secondaryHeaderFlag = true) { return getSpacePacketIdFromApid(false, apid, secondaryHeaderFlag); } From 30217aa42b9ca23b1a0a8a8a972953277b124c34 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 10 Nov 2021 18:51:56 +0100 Subject: [PATCH 106/131] updated SerializeAdapter.h - Updates `SerializerAdapter` to also take simple pointer and simply assign the serialized and deSerialized size - Added related unittests --- src/fsfw/serialize/SerializeAdapter.h | 400 +++++++++++------- .../unit/serialize/TestSerialization.cpp | 297 ++++++++----- 2 files changed, 429 insertions(+), 268 deletions(-) diff --git a/src/fsfw/serialize/SerializeAdapter.h b/src/fsfw/serialize/SerializeAdapter.h index e6cd247e..2831472c 100644 --- a/src/fsfw/serialize/SerializeAdapter.h +++ b/src/fsfw/serialize/SerializeAdapter.h @@ -7,7 +7,7 @@ #include #include - /** +/** * @brief These adapters provides an interface to use the SerializeIF functions * with arbitrary template objects to facilitate and simplify the * serialization of classes with different multiple different data types @@ -20,174 +20,250 @@ */ class SerializeAdapter { public: - /*** - * This function can be used to serialize a trivial copy-able type or a - * child of SerializeIF. - * The right template to be called is determined in the function itself. - * For objects of non trivial copy-able type this function is almost never - * called by the user directly. Instead helpers for specific types like - * SerialArrayListAdapter or SerialLinkedListAdapter is the right choice here. - * - * @param[in] object Object to serialize, the used type is deduced from this pointer - * @param[in/out] buffer Buffer to serialize into. Will be moved by the function. - * @param[in/out] size Size of current written buffer. Will be incremented by the function. - * @param[in] maxSize Max size of Buffer - * @param[in] streamEndianness Endianness of serialized element as in according to SerializeIF::Endianness - * @return - * - @c BUFFER_TOO_SHORT The given buffer in is too short - * - @c RETURN_FAILED Generic Error - * - @c RETURN_OK Successful serialization - */ - template - static ReturnValue_t serialize(const T *object, uint8_t **buffer, - size_t *size, size_t maxSize, - SerializeIF::Endianness streamEndianness) { - InternalSerializeAdapter::value> adapter; - return adapter.serialize(object, buffer, size, maxSize, - streamEndianness); - } - /** - * Function to return the serialized size of the object in the pointer. - * May be a trivially copy-able object or a Child of SerializeIF - * - * @param object Pointer to Object - * @return Serialized size of object - */ - template - static size_t getSerializedSize(const T *object){ - InternalSerializeAdapter::value> adapter; - return adapter.getSerializedSize(object); - } - /** - * @brief - * Deserializes a object from a given buffer of given size. - * Object Must be trivially copy-able or a child of SerializeIF. - * - * @details - * Buffer will be moved to the current read location. Size will be decreased by the function. - * - * @param[in/out] buffer Buffer to deSerialize from. Will be moved by the function. - * @param[in/out] size Remaining size of the buffer to read from. Will be decreased by function. - * @param[in] streamEndianness Endianness as in according to SerializeIF::Endianness - * @return - * - @c STREAM_TOO_SHORT The input stream is too short to deSerialize the object - * - @c TOO_MANY_ELEMENTS The buffer has more inputs than expected - * - @c RETURN_FAILED Generic Error - * - @c RETURN_OK Successful deserialization - */ - template - static ReturnValue_t deSerialize(T *object, const uint8_t **buffer, - size_t *size, SerializeIF::Endianness streamEndianness) { - InternalSerializeAdapter::value> adapter; - return adapter.deSerialize(object, buffer, size, streamEndianness); - } + /*** + * @brief Serialize a trivial copy-able type or a child of SerializeIF. + * @details + * The right template to be called is determined in the function itself. + * For objects of non trivial copy-able type this function is almost never + * called by the user directly. Instead helpers for specific types like + * SerialArrayListAdapter or SerialLinkedListAdapter are the right choice here. + * + * @param[in] object: Object to serialize, the used type is deduced from this pointer + * @param[in/out] buffer: Pointer to the buffer to serialize into. Buffer position will be + * incremented by the function. + * @param[in/out] size: Pointer to size of current written buffer. + * SIze will be incremented by the function. + * @param[in] maxSize: Max size of Buffer + * @param[in] streamEndianness: Endianness of serialized element as in according to + * SerializeIF::Endianness + * @return + * - @c BUFFER_TOO_SHORT The given buffer in is too short + * - @c RETURN_FAILED Generic Error + * - @c RETURN_OK Successful serialization + */ + template + static ReturnValue_t serialize(const T *object, uint8_t **buffer, + size_t *size, size_t maxSize, + SerializeIF::Endianness streamEndianness) { + InternalSerializeAdapter::value> adapter; + return adapter.serialize(object, buffer, size, maxSize, + streamEndianness); + } + + /*** + * This function can be used to serialize a trivial copy-able type or a child of SerializeIF. + * The right template to be called is determined in the function itself. + * For objects of non trivial copy-able type this function is almost never + * called by the user directly. Instead helpers for specific types like + * SerialArrayListAdapter or SerialLinkedListAdapter are the right choice here. + * + * @param[in] object: Object to serialize, the used type is deduced from this pointer + * @param[in/out] buffer: Buffer to serialize into. + * @param[out] serSize: Serialized size + * @param[in] maxSize: Max size of buffer + * @param[in] streamEndianness: Endianness of serialized element as in according to + * SerializeIF::Endianness + * @return + * - @c BUFFER_TOO_SHORT The given buffer in is too short + * - @c RETURN_FAILED Generic Error + * - @c RETURN_OK Successful serialization + */ + template + static ReturnValue_t serialize(const T *object, uint8_t* const buffer, size_t* serSize, + size_t maxSize, SerializeIF::Endianness streamEndianness) { + if(object == nullptr or buffer == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + InternalSerializeAdapter::value> adapter; + uint8_t** tempPtr = const_cast(&buffer); + size_t tmpSize = 0; + ReturnValue_t result = adapter.serialize(object, tempPtr, &tmpSize, maxSize, + streamEndianness); + if(serSize != nullptr) { + *serSize = tmpSize; + } + return result; + } + + /** + * @brief Function to return the serialized size of the object in the pointer. + * @details + * May be a trivially copy-able object or a child of SerializeIF. + * + * @param object Pointer to Object + * @return Serialized size of object + */ + template + static size_t getSerializedSize(const T *object){ + InternalSerializeAdapter::value> adapter; + return adapter.getSerializedSize(object); + } + + /** + * @brief Deserializes a object from a given buffer of given size. + * + * @details + * Object Must be trivially copy-able or a child of SerializeIF. + * Buffer will be moved to the current read location. Size will be decreased by the function. + * + * @param[in] object: Pointer to object to deserialize + * @param[in/out] buffer: Pointer to the buffer to deSerialize from. Buffer position will be + * incremented by the function + * @param[in/out] size: Pointer to remaining size of the buffer to read from. + * Will be decreased by function. + * @param[in] streamEndianness: Endianness as in according to SerializeIF::Endianness + * @return + * - @c STREAM_TOO_SHORT The input stream is too short to deSerialize the object + * - @c TOO_MANY_ELEMENTS The buffer has more inputs than expected + * - @c RETURN_FAILED Generic Error + * - @c RETURN_OK Successful deserialization + */ + template + static ReturnValue_t deSerialize(T *object, const uint8_t **buffer, + size_t *size, SerializeIF::Endianness streamEndianness) { + InternalSerializeAdapter::value> adapter; + return adapter.deSerialize(object, buffer, size, streamEndianness); + } + + /** + * @brief Deserializes a object from a given buffer of given size. + * + * @details + * Object Must be trivially copy-able or a child of SerializeIF. + * + * @param[in] object: Pointer to object to deserialize + * @param[in] buffer: Buffer to deSerialize from + * @param[out] deserSize: Deserialized length + * @param[in] streamEndianness: Endianness as in according to SerializeIF::Endianness + * @return + * - @c STREAM_TOO_SHORT The input stream is too short to deSerialize the object + * - @c TOO_MANY_ELEMENTS The buffer has more inputs than expected + * - @c RETURN_FAILED Generic Error + * - @c RETURN_OK Successful deserialization + */ + template + static ReturnValue_t deSerialize(T *object, const uint8_t* buffer, + size_t* deserSize, SerializeIF::Endianness streamEndianness) { + if(object == nullptr or buffer == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + InternalSerializeAdapter::value> adapter; + const uint8_t** tempPtr = &buffer; + size_t maxVal = -1; + ReturnValue_t result = adapter.deSerialize(object, tempPtr, &maxVal, streamEndianness); + if(deserSize != nullptr) { + *deserSize = -1 - maxVal; + } + return result; + } + private: - /** - * Internal template to deduce the right function calls at compile time - */ - template class InternalSerializeAdapter; + /** + * Internal template to deduce the right function calls at compile time + */ + template class InternalSerializeAdapter; - /** - * Template to be used if T is not a child of SerializeIF - * - * @tparam T T must be trivially_copyable - */ - template - class InternalSerializeAdapter { - static_assert (std::is_trivially_copyable::value, - "If a type needs to be serialized it must be a child of " - "SerializeIF or trivially copy-able"); - public: - static ReturnValue_t serialize(const T *object, uint8_t **buffer, - size_t *size, size_t max_size, - SerializeIF::Endianness streamEndianness) { - size_t ignoredSize = 0; - if (size == nullptr) { - size = &ignoredSize; - } - // Check remaining size is large enough and check integer - // overflow of *size - size_t newSize = sizeof(T) + *size; - if ((newSize <= max_size) and (newSize > *size)) { - T tmp; - switch (streamEndianness) { - case SerializeIF::Endianness::BIG: - tmp = EndianConverter::convertBigEndian(*object); - break; - case SerializeIF::Endianness::LITTLE: - tmp = EndianConverter::convertLittleEndian(*object); - break; - default: - case SerializeIF::Endianness::MACHINE: - tmp = *object; - break; - } - std::memcpy(*buffer, &tmp, sizeof(T)); - *size += sizeof(T); - (*buffer) += sizeof(T); - return HasReturnvaluesIF::RETURN_OK; - } else { - return SerializeIF::BUFFER_TOO_SHORT; - } - } + /** + * Template to be used if T is not a child of SerializeIF + * + * @tparam T T must be trivially_copyable + */ + template + class InternalSerializeAdapter { + static_assert (std::is_trivially_copyable::value, + "If a type needs to be serialized it must be a child of " + "SerializeIF or trivially copy-able"); + public: + static ReturnValue_t serialize(const T *object, uint8_t **buffer, + size_t *size, size_t max_size, + SerializeIF::Endianness streamEndianness) { + size_t ignoredSize = 0; + if (size == nullptr) { + size = &ignoredSize; + } + // Check remaining size is large enough and check integer + // overflow of *size + size_t newSize = sizeof(T) + *size; + if ((newSize <= max_size) and (newSize > *size)) { + T tmp; + switch (streamEndianness) { + case SerializeIF::Endianness::BIG: + tmp = EndianConverter::convertBigEndian(*object); + break; + case SerializeIF::Endianness::LITTLE: + tmp = EndianConverter::convertLittleEndian(*object); + break; + default: + case SerializeIF::Endianness::MACHINE: + tmp = *object; + break; + } + std::memcpy(*buffer, &tmp, sizeof(T)); + *size += sizeof(T); + (*buffer) += sizeof(T); + return HasReturnvaluesIF::RETURN_OK; + } else { + return SerializeIF::BUFFER_TOO_SHORT; + } + } - ReturnValue_t deSerialize(T *object, const uint8_t **buffer, - size_t *size, SerializeIF::Endianness streamEndianness) { - T tmp; - if (*size >= sizeof(T)) { - *size -= sizeof(T); - std::memcpy(&tmp, *buffer, sizeof(T)); - switch (streamEndianness) { - case SerializeIF::Endianness::BIG: - *object = EndianConverter::convertBigEndian(tmp); - break; - case SerializeIF::Endianness::LITTLE: - *object = EndianConverter::convertLittleEndian(tmp); - break; - default: - case SerializeIF::Endianness::MACHINE: - *object = tmp; - break; - } + ReturnValue_t deSerialize(T *object, const uint8_t **buffer, + size_t *size, SerializeIF::Endianness streamEndianness) { + T tmp; + if (*size >= sizeof(T)) { + *size -= sizeof(T); + std::memcpy(&tmp, *buffer, sizeof(T)); + switch (streamEndianness) { + case SerializeIF::Endianness::BIG: + *object = EndianConverter::convertBigEndian(tmp); + break; + case SerializeIF::Endianness::LITTLE: + *object = EndianConverter::convertLittleEndian(tmp); + break; + default: + case SerializeIF::Endianness::MACHINE: + *object = tmp; + break; + } - *buffer += sizeof(T); - return HasReturnvaluesIF::RETURN_OK; - } else { - return SerializeIF::STREAM_TOO_SHORT; - } - } + *buffer += sizeof(T); + return HasReturnvaluesIF::RETURN_OK; + } else { + return SerializeIF::STREAM_TOO_SHORT; + } + } - uint32_t getSerializedSize(const T *object) { - return sizeof(T); - } - }; + uint32_t getSerializedSize(const T *object) { + return sizeof(T); + } + }; - /** - * Template for objects that inherit from SerializeIF - * - * @tparam T A child of SerializeIF - */ - template - class InternalSerializeAdapter { - public: - ReturnValue_t serialize(const T *object, uint8_t **buffer, size_t *size, - size_t max_size, - SerializeIF::Endianness streamEndianness) const { - size_t ignoredSize = 0; - if (size == nullptr) { - size = &ignoredSize; - } - return object->serialize(buffer, size, max_size, streamEndianness); - } - size_t getSerializedSize(const T *object) const { - return object->getSerializedSize(); - } + /** + * Template for objects that inherit from SerializeIF + * + * @tparam T A child of SerializeIF + */ + template + class InternalSerializeAdapter { + public: + ReturnValue_t serialize(const T *object, uint8_t **buffer, size_t *size, + size_t max_size, + SerializeIF::Endianness streamEndianness) const { + size_t ignoredSize = 0; + if (size == nullptr) { + size = &ignoredSize; + } + return object->serialize(buffer, size, max_size, streamEndianness); + } + size_t getSerializedSize(const T *object) const { + return object->getSerializedSize(); + } - ReturnValue_t deSerialize(T *object, const uint8_t **buffer, - size_t *size, SerializeIF::Endianness streamEndianness) { - return object->deSerialize(buffer, size, streamEndianness); - } - }; + ReturnValue_t deSerialize(T *object, const uint8_t **buffer, + size_t *size, SerializeIF::Endianness streamEndianness) { + return object->deSerialize(buffer, size, streamEndianness); + } + }; }; #endif /* _FSFW_SERIALIZE_SERIALIZEADAPTER_H_ */ diff --git a/tests/src/fsfw_tests/unit/serialize/TestSerialization.cpp b/tests/src/fsfw_tests/unit/serialize/TestSerialization.cpp index 64deae3b..f883fe78 100644 --- a/tests/src/fsfw_tests/unit/serialize/TestSerialization.cpp +++ b/tests/src/fsfw_tests/unit/serialize/TestSerialization.cpp @@ -3,128 +3,213 @@ #include #include +#include #include -static bool test_value_bool = true; -static uint8_t tv_uint8 {5}; -static uint16_t tv_uint16 {283}; -static uint32_t tv_uint32 {929221}; -static uint64_t tv_uint64 {2929329429}; +static bool testBool = true; +static uint8_t tvUint8 {5}; +static uint16_t tvUint16 {283}; +static uint32_t tvUint32 {929221}; +static uint64_t tvUint64 {2929329429}; -static int8_t tv_int8 {-16}; -static int16_t tv_int16 {-829}; -static int32_t tv_int32 {-2312}; +static int8_t tvInt8 {-16}; +static int16_t tvInt16 {-829}; +static int32_t tvInt32 {-2312}; -static float tv_float {8.2149214}; -static float tv_sfloat = {-922.2321321}; -static double tv_double {9.2132142141e8}; -static double tv_sdouble {-2.2421e19}; +static float tvFloat {8.2149214}; +static float tvSfloat = {-922.2321321}; +static double tvDouble {9.2132142141e8}; +static double tvSdouble {-2.2421e19}; -static std::array test_array; +static std::array TEST_ARRAY; -TEST_CASE( "Serialization size tests", "[TestSerialization]") { +TEST_CASE( "Serialization size tests", "[SerSizeTest]") { //REQUIRE(unitTestClass.test_autoserialization() == 0); - REQUIRE(SerializeAdapter::getSerializedSize(&test_value_bool) == - sizeof(test_value_bool)); - REQUIRE(SerializeAdapter::getSerializedSize(&tv_uint8) == - sizeof(tv_uint8)); - REQUIRE(SerializeAdapter::getSerializedSize(&tv_uint16) == - sizeof(tv_uint16)); - REQUIRE(SerializeAdapter::getSerializedSize(&tv_uint32 ) == - sizeof(tv_uint32)); - REQUIRE(SerializeAdapter::getSerializedSize(&tv_uint64) == - sizeof(tv_uint64)); - REQUIRE(SerializeAdapter::getSerializedSize(&tv_int8) == - sizeof(tv_int8)); - REQUIRE(SerializeAdapter::getSerializedSize(&tv_int16) == - sizeof(tv_int16)); - REQUIRE(SerializeAdapter::getSerializedSize(&tv_int32) == - sizeof(tv_int32)); - REQUIRE(SerializeAdapter::getSerializedSize(&tv_float) == - sizeof(tv_float)); - REQUIRE(SerializeAdapter::getSerializedSize(&tv_sfloat) == - sizeof(tv_sfloat )); - REQUIRE(SerializeAdapter::getSerializedSize(&tv_double) == - sizeof(tv_double)); - REQUIRE(SerializeAdapter::getSerializedSize(&tv_sdouble) == - sizeof(tv_sdouble)); + REQUIRE(SerializeAdapter::getSerializedSize(&testBool) == + sizeof(testBool)); + REQUIRE(SerializeAdapter::getSerializedSize(&tvUint8) == + sizeof(tvUint8)); + REQUIRE(SerializeAdapter::getSerializedSize(&tvUint16) == + sizeof(tvUint16)); + REQUIRE(SerializeAdapter::getSerializedSize(&tvUint32 ) == + sizeof(tvUint32)); + REQUIRE(SerializeAdapter::getSerializedSize(&tvUint64) == + sizeof(tvUint64)); + REQUIRE(SerializeAdapter::getSerializedSize(&tvInt8) == + sizeof(tvInt8)); + REQUIRE(SerializeAdapter::getSerializedSize(&tvInt16) == + sizeof(tvInt16)); + REQUIRE(SerializeAdapter::getSerializedSize(&tvInt32) == + sizeof(tvInt32)); + REQUIRE(SerializeAdapter::getSerializedSize(&tvFloat) == + sizeof(tvFloat)); + REQUIRE(SerializeAdapter::getSerializedSize(&tvSfloat) == + sizeof(tvSfloat )); + REQUIRE(SerializeAdapter::getSerializedSize(&tvDouble) == + sizeof(tvDouble)); + REQUIRE(SerializeAdapter::getSerializedSize(&tvSdouble) == + sizeof(tvSdouble)); } +TEST_CASE("Auto Serialize Adapter", "[SerAdapter]") { + size_t serializedSize = 0; + uint8_t * pArray = TEST_ARRAY.data(); -TEST_CASE("Auto Serialize Adapter testing", "[single-file]") { - size_t serialized_size = 0; - uint8_t * p_array = test_array.data(); + SECTION("SerDe") { + size_t deserSize = 0; + SerializeAdapter::serialize(&testBool, TEST_ARRAY.data(), &deserSize, TEST_ARRAY.size(), + SerializeIF::Endianness::MACHINE); + REQUIRE(deserSize == 1); + REQUIRE(TEST_ARRAY[0] == true); + bool readBack = false; + SerializeAdapter::deSerialize(&readBack, TEST_ARRAY.data(), &deserSize, + SerializeIF::Endianness::MACHINE); + REQUIRE(deserSize == 1); + REQUIRE(readBack == true); + SerializeAdapter::serialize(&tvUint8, TEST_ARRAY.data(), &deserSize, TEST_ARRAY.size(), + SerializeIF::Endianness::MACHINE); + REQUIRE(deserSize == 1); + REQUIRE(TEST_ARRAY[0] == 5); + uint8_t readBackUint8 = 0; + uint8_t* const testPtr = TEST_ARRAY.data(); + uint8_t* const shouldStayConst = testPtr; + SerializeAdapter::deSerialize(&readBackUint8, testPtr, &deserSize, + SerializeIF::Endianness::MACHINE); + REQUIRE(testPtr == shouldStayConst); + REQUIRE(deserSize == 1); + REQUIRE(readBackUint8 == 5); + SerializeAdapter::serialize(&tvUint16, TEST_ARRAY.data(), &deserSize, TEST_ARRAY.size(), + SerializeIF::Endianness::MACHINE); + REQUIRE(deserSize == 2); + deserSize = 0; + uint16_t readBackUint16 = 0; + SerializeAdapter::deSerialize(&readBackUint16, TEST_ARRAY.data(), &deserSize, + SerializeIF::Endianness::MACHINE); + REQUIRE(deserSize == 2); + REQUIRE(readBackUint16 == 283); - SECTION("Serializing...") { - SerializeAdapter::serialize(&test_value_bool, &p_array, - &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); - SerializeAdapter::serialize(&tv_uint8, &p_array, - &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); - SerializeAdapter::serialize(&tv_uint16, &p_array, - &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); - SerializeAdapter::serialize(&tv_uint32, &p_array, - &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); - SerializeAdapter::serialize(&tv_int8, &p_array, - &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); - SerializeAdapter::serialize(&tv_int16, &p_array, - &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); - SerializeAdapter::serialize(&tv_int32, &p_array, - &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); - SerializeAdapter::serialize(&tv_uint64, &p_array, - &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); - SerializeAdapter::serialize(&tv_float, &p_array, - &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); - SerializeAdapter::serialize(&tv_double, &p_array, - &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); - SerializeAdapter::serialize(&tv_sfloat, &p_array, - &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); - SerializeAdapter::serialize(&tv_sdouble, &p_array, - &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); - REQUIRE (serialized_size == 47); + SerializeAdapter::serialize(&tvUint32, TEST_ARRAY.data(), &deserSize, TEST_ARRAY.size(), + SerializeIF::Endianness::MACHINE); + REQUIRE(deserSize == 4); + uint32_t readBackUint32 = 0; + deserSize = 0; + SerializeAdapter::deSerialize(&readBackUint32, TEST_ARRAY.data(), &deserSize, + SerializeIF::Endianness::MACHINE); + REQUIRE(deserSize == 4); + REQUIRE(readBackUint32 == 929221); + + SerializeAdapter::serialize(&tvInt16, TEST_ARRAY.data(), &deserSize, TEST_ARRAY.size(), + SerializeIF::Endianness::MACHINE); + REQUIRE(deserSize == 2); + int16_t readBackInt16 = 0; + SerializeAdapter::deSerialize(&readBackInt16, TEST_ARRAY.data(), &deserSize, + SerializeIF::Endianness::MACHINE); + REQUIRE(readBackInt16 == -829); + REQUIRE(deserSize == 2); + + SerializeAdapter::serialize(&tvFloat, TEST_ARRAY.data(), &deserSize, TEST_ARRAY.size(), + SerializeIF::Endianness::MACHINE); + float readBackFloat = 0.0; + SerializeAdapter::deSerialize(&readBackFloat, TEST_ARRAY.data(), &deserSize, + SerializeIF::Endianness::MACHINE); + REQUIRE(readBackFloat == Catch::Approx(8.214921)); + + SerializeAdapter::serialize(&tvSdouble, TEST_ARRAY.data(), &deserSize, TEST_ARRAY.size(), + SerializeIF::Endianness::MACHINE); + double readBackSignedDouble = 0.0; + SerializeAdapter::deSerialize(&readBackSignedDouble, TEST_ARRAY.data(), &deserSize, + SerializeIF::Endianness::MACHINE); + REQUIRE(readBackSignedDouble == Catch::Approx(-2.2421e19)); + + uint8_t testBuf[4] = {1, 2, 3, 4}; + SerialBufferAdapter bufferAdapter(testBuf, sizeof(testBuf)); + SerializeAdapter::serialize(&bufferAdapter, TEST_ARRAY.data(), &deserSize, + TEST_ARRAY.size(), SerializeIF::Endianness::MACHINE); + REQUIRE(deserSize == 4); + for(uint8_t idx = 0; idx < 4; idx++) { + REQUIRE(TEST_ARRAY[idx] == idx + 1); + } + deserSize = 0; + testBuf[0] = 0; + testBuf[1] = 12; + SerializeAdapter::deSerialize(&bufferAdapter, TEST_ARRAY.data(), &deserSize, + SerializeIF::Endianness::MACHINE); + REQUIRE(deserSize == 4); + for(uint8_t idx = 0; idx < 4; idx++) { + REQUIRE(testBuf[idx] == idx + 1); + } + } + + SECTION("Serialize incrementing") { + SerializeAdapter::serialize(&testBool, &pArray, &serializedSize, + TEST_ARRAY.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tvUint8, &pArray, &serializedSize, + TEST_ARRAY.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tvUint16, &pArray, &serializedSize, + TEST_ARRAY.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tvUint32, &pArray, &serializedSize, + TEST_ARRAY.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tvInt8, &pArray, &serializedSize, + TEST_ARRAY.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tvInt16, &pArray, &serializedSize, + TEST_ARRAY.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tvInt32, &pArray, &serializedSize, + TEST_ARRAY.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tvUint64, &pArray, &serializedSize, + TEST_ARRAY.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tvFloat, &pArray, &serializedSize, + TEST_ARRAY.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tvDouble, &pArray, &serializedSize, TEST_ARRAY.size(), + SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tvSfloat, &pArray, &serializedSize, TEST_ARRAY.size(), + SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tvSdouble, &pArray, &serializedSize, TEST_ARRAY.size(), + SerializeIF::Endianness::MACHINE); + REQUIRE (serializedSize == 47); } - SECTION("Deserializing") { - p_array = test_array.data(); - size_t remaining_size = serialized_size; - SerializeAdapter::deSerialize(&test_value_bool, - const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); - SerializeAdapter::deSerialize(&tv_uint8, - const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); - SerializeAdapter::deSerialize(&tv_uint16, - const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); - SerializeAdapter::deSerialize(&tv_uint32, - const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); - SerializeAdapter::deSerialize(&tv_int8, - const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); - SerializeAdapter::deSerialize(&tv_int16, - const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); - SerializeAdapter::deSerialize(&tv_int32, - const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); - SerializeAdapter::deSerialize(&tv_uint64, - const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); - SerializeAdapter::deSerialize(&tv_float, - const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); - SerializeAdapter::deSerialize(&tv_double, - const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); - SerializeAdapter::deSerialize(&tv_sfloat, - const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); - SerializeAdapter::deSerialize(&tv_sdouble, - const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); + SECTION("Deserialize decrementing") { + pArray = TEST_ARRAY.data(); + size_t remaining_size = serializedSize; + SerializeAdapter::deSerialize(&testBool, const_cast(&pArray), + &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tvUint8, const_cast(&pArray), + &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tvUint16, const_cast(&pArray), + &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tvUint32, const_cast(&pArray), + &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tvInt8, const_cast(&pArray), + &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tvInt16, const_cast(&pArray), + &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tvInt32, const_cast(&pArray), + &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tvUint64, + const_cast(&pArray), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tvFloat, + const_cast(&pArray), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tvDouble, + const_cast(&pArray), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tvSfloat, + const_cast(&pArray), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tvSdouble, + const_cast(&pArray), &remaining_size, SerializeIF::Endianness::MACHINE); - REQUIRE(test_value_bool == true); - REQUIRE(tv_uint8 == 5); - REQUIRE(tv_uint16 == 283); - REQUIRE(tv_uint32 == 929221); - REQUIRE(tv_uint64 == 2929329429); - REQUIRE(tv_int8 == -16); - REQUIRE(tv_int16 == -829); - REQUIRE(tv_int32 == -2312); + REQUIRE(testBool == true); + REQUIRE(tvUint8 == 5); + REQUIRE(tvUint16 == 283); + REQUIRE(tvUint32 == 929221); + REQUIRE(tvUint64 == 2929329429); + REQUIRE(tvInt8 == -16); + REQUIRE(tvInt16 == -829); + REQUIRE(tvInt32 == -2312); - REQUIRE(tv_float == Catch::Approx(8.214921)); - REQUIRE(tv_double == Catch::Approx(9.2132142141e8)); - REQUIRE(tv_sfloat == Catch::Approx(-922.2321321)); - REQUIRE(tv_sdouble == Catch::Approx(-2.2421e19)); + REQUIRE(tvFloat == Catch::Approx(8.214921)); + REQUIRE(tvDouble == Catch::Approx(9.2132142141e8)); + REQUIRE(tvSfloat == Catch::Approx(-922.2321321)); + REQUIRE(tvSdouble == Catch::Approx(-2.2421e19)); } } From 190848d00e32274eb844e0f930669b65ffe7eb4e Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 18 Nov 2021 18:52:50 +0100 Subject: [PATCH 107/131] important fix for getter function --- src/fsfw/tmtcpacket/SpacePacket.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fsfw/tmtcpacket/SpacePacket.h b/src/fsfw/tmtcpacket/SpacePacket.h index 16673319..a092712c 100644 --- a/src/fsfw/tmtcpacket/SpacePacket.h +++ b/src/fsfw/tmtcpacket/SpacePacket.h @@ -73,7 +73,7 @@ namespace spacepacket { constexpr uint16_t getSpacePacketIdFromApid(bool isTc, uint16_t apid, bool secondaryHeaderFlag = true) { - return (((isTc << 5) & 0x10) | ((secondaryHeaderFlag << 4) & 0x08) | + return ((isTc << 4) | (secondaryHeaderFlag << 3) | ((apid >> 8) & 0x07)) << 8 | (apid & 0x00ff); } From 400eafcae74cc191d32ba0d9555286d9a4ad2bd8 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 18 Nov 2021 19:51:01 +0100 Subject: [PATCH 108/131] added first unittests space packets - Also added helper scripts --- scripts/coverage.py | 7 +++++++ scripts/gen-unittest.sh | 3 +++ tests/src/fsfw_tests/unit/tmtcpacket/CMakeLists.txt | 2 +- tests/src/fsfw_tests/unit/tmtcpacket/PusTmTest.cpp | 3 --- tests/src/fsfw_tests/unit/tmtcpacket/testCcsds.cpp | 11 +++++++++++ 5 files changed, 22 insertions(+), 4 deletions(-) create mode 100755 scripts/gen-unittest.sh delete mode 100644 tests/src/fsfw_tests/unit/tmtcpacket/PusTmTest.cpp create mode 100644 tests/src/fsfw_tests/unit/tmtcpacket/testCcsds.cpp diff --git a/scripts/coverage.py b/scripts/coverage.py index 71b6fb03..b5bd7745 100755 --- a/scripts/coverage.py +++ b/scripts/coverage.py @@ -6,6 +6,7 @@ import platform import sys import time import argparse +import webbrowser from typing import List @@ -18,6 +19,10 @@ information how to set up the build folder. def main(): parser = argparse.ArgumentParser(description="Processing arguments for LCOV helper script.") + parser.add_argument( + '-o', '--open', action='store_true', help='Open coverage data in webbrowser' + ) + args = parser.parse_args() build_dir_list = [] if not os.path.isfile('README.md'): @@ -41,6 +46,8 @@ def main(): print("Multiple build directories found!") build_directory = determine_build_dir(build_dir_list) perform_lcov_operation(build_directory) + if os.path.isdir('fsfw-tests_coverage') and args.open: + webbrowser.open('fsfw-tests_coverage/index.html') def check_for_cmake_build_dir(build_dir_dict: list): diff --git a/scripts/gen-unittest.sh b/scripts/gen-unittest.sh new file mode 100755 index 00000000..9ca8c399 --- /dev/null +++ b/scripts/gen-unittest.sh @@ -0,0 +1,3 @@ +#!/bin/sh +mkdir build-Unittest && cd build-Unittest +cmake -DFSFW_BUILD_UNITTESTS=ON -DFSFW_OSAL=host -DCMAKE_BUILD_TYPE=Debug .. diff --git a/tests/src/fsfw_tests/unit/tmtcpacket/CMakeLists.txt b/tests/src/fsfw_tests/unit/tmtcpacket/CMakeLists.txt index 36838b24..958bda40 100644 --- a/tests/src/fsfw_tests/unit/tmtcpacket/CMakeLists.txt +++ b/tests/src/fsfw_tests/unit/tmtcpacket/CMakeLists.txt @@ -1,3 +1,3 @@ target_sources(${FSFW_TEST_TGT} PRIVATE - PusTmTest.cpp + testCcsds.cpp ) diff --git a/tests/src/fsfw_tests/unit/tmtcpacket/PusTmTest.cpp b/tests/src/fsfw_tests/unit/tmtcpacket/PusTmTest.cpp deleted file mode 100644 index b28b04f6..00000000 --- a/tests/src/fsfw_tests/unit/tmtcpacket/PusTmTest.cpp +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/tests/src/fsfw_tests/unit/tmtcpacket/testCcsds.cpp b/tests/src/fsfw_tests/unit/tmtcpacket/testCcsds.cpp new file mode 100644 index 00000000..1416a556 --- /dev/null +++ b/tests/src/fsfw_tests/unit/tmtcpacket/testCcsds.cpp @@ -0,0 +1,11 @@ +#include + +#include "fsfw/tmtcpacket/SpacePacket.h" + +TEST_CASE( "CCSDS Test" , "[ccsds]") { + REQUIRE(spacepacket::getTcSpacePacketIdFromApid(0x22) == 0x1822); + REQUIRE(spacepacket::getTmSpacePacketIdFromApid(0x22) == 0x0822); + + REQUIRE(spacepacket::getTcSpacePacketIdFromApid(0x7ff) == 0x1fff) + REQUIRE(spacepacket::getTmSpacePacketIdFromApid(0x7ff) == 0xfff); +} From 0a94f84f5a75a86a52a5731c4a8c7ac9a8d73f23 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 18 Nov 2021 19:52:27 +0100 Subject: [PATCH 109/131] update cmakelists files --- CMakeLists.txt | 16 ++++++++-------- src/CMakeLists.txt | 2 -- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 923d5cc5..e78e8929 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -93,14 +93,6 @@ target_include_directories(${LIB_FSFW_NAME} INTERFACE ${CMAKE_CURRENT_BINARY_DIR} ) -if(FSFW_BUILD_UNITTESTS) - configure_file(src/fsfw/FSFW.h.in fsfw/FSFW.h) - configure_file(src/fsfw/FSFWVersion.h.in fsfw/FSFWVersion.h) -else() - configure_file(src/fsfw/FSFW.h.in FSFW.h) - configure_file(src/fsfw/FSFWVersion.h.in FSFWVersion.h) -endif() - if(NOT CMAKE_CXX_STANDARD) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED True) @@ -155,6 +147,14 @@ else() set(OS_FSFW "host") endif() +if(FSFW_BUILD_UNITTESTS) + configure_file(src/fsfw/FSFW.h.in fsfw/FSFW.h) + configure_file(src/fsfw/FSFWVersion.h.in fsfw/FSFWVersion.h) +else() + configure_file(src/fsfw/FSFW.h.in FSFW.h) + configure_file(src/fsfw/FSFWVersion.h.in FSFWVersion.h) +endif() + message(STATUS "Compiling FSFW for the ${FSFW_OS_NAME} operating system.") add_subdirectory(src) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5a8f139b..e4670807 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,5 +16,3 @@ target_include_directories(${LIB_FSFW_NAME} PRIVATE target_include_directories(${LIB_FSFW_NAME} INTERFACE ${CMAKE_CURRENT_BINARY_DIR} ) - -configure_file(fsfw/FSFW.h.in fsfw/FSFW.h) From 1f7cc7a558941d8436aebc6bf32f9275dbdcd934 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 18 Nov 2021 19:54:52 +0100 Subject: [PATCH 110/131] tests running --- tests/src/fsfw_tests/unit/tmtcpacket/testCcsds.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/src/fsfw_tests/unit/tmtcpacket/testCcsds.cpp b/tests/src/fsfw_tests/unit/tmtcpacket/testCcsds.cpp index 1416a556..8f531805 100644 --- a/tests/src/fsfw_tests/unit/tmtcpacket/testCcsds.cpp +++ b/tests/src/fsfw_tests/unit/tmtcpacket/testCcsds.cpp @@ -6,6 +6,6 @@ TEST_CASE( "CCSDS Test" , "[ccsds]") { REQUIRE(spacepacket::getTcSpacePacketIdFromApid(0x22) == 0x1822); REQUIRE(spacepacket::getTmSpacePacketIdFromApid(0x22) == 0x0822); - REQUIRE(spacepacket::getTcSpacePacketIdFromApid(0x7ff) == 0x1fff) + REQUIRE(spacepacket::getTcSpacePacketIdFromApid(0x7ff) == 0x1fff); REQUIRE(spacepacket::getTmSpacePacketIdFromApid(0x7ff) == 0xfff); } From 05c4f4fadca0ba73f1e51bd4ac50d278df11aabd Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 18 Nov 2021 19:56:24 +0100 Subject: [PATCH 111/131] Bugfix for Packet ID getters - Also added related unittests --- src/fsfw/tmtcpacket/SpacePacket.h | 2 +- tests/src/fsfw_tests/unit/tmtcpacket/CMakeLists.txt | 2 +- tests/src/fsfw_tests/unit/tmtcpacket/testCcsds.cpp | 11 +++++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 tests/src/fsfw_tests/unit/tmtcpacket/testCcsds.cpp diff --git a/src/fsfw/tmtcpacket/SpacePacket.h b/src/fsfw/tmtcpacket/SpacePacket.h index 16673319..a092712c 100644 --- a/src/fsfw/tmtcpacket/SpacePacket.h +++ b/src/fsfw/tmtcpacket/SpacePacket.h @@ -73,7 +73,7 @@ namespace spacepacket { constexpr uint16_t getSpacePacketIdFromApid(bool isTc, uint16_t apid, bool secondaryHeaderFlag = true) { - return (((isTc << 5) & 0x10) | ((secondaryHeaderFlag << 4) & 0x08) | + return ((isTc << 4) | (secondaryHeaderFlag << 3) | ((apid >> 8) & 0x07)) << 8 | (apid & 0x00ff); } diff --git a/tests/src/fsfw_tests/unit/tmtcpacket/CMakeLists.txt b/tests/src/fsfw_tests/unit/tmtcpacket/CMakeLists.txt index 36838b24..958bda40 100644 --- a/tests/src/fsfw_tests/unit/tmtcpacket/CMakeLists.txt +++ b/tests/src/fsfw_tests/unit/tmtcpacket/CMakeLists.txt @@ -1,3 +1,3 @@ target_sources(${FSFW_TEST_TGT} PRIVATE - PusTmTest.cpp + testCcsds.cpp ) diff --git a/tests/src/fsfw_tests/unit/tmtcpacket/testCcsds.cpp b/tests/src/fsfw_tests/unit/tmtcpacket/testCcsds.cpp new file mode 100644 index 00000000..8f531805 --- /dev/null +++ b/tests/src/fsfw_tests/unit/tmtcpacket/testCcsds.cpp @@ -0,0 +1,11 @@ +#include + +#include "fsfw/tmtcpacket/SpacePacket.h" + +TEST_CASE( "CCSDS Test" , "[ccsds]") { + REQUIRE(spacepacket::getTcSpacePacketIdFromApid(0x22) == 0x1822); + REQUIRE(spacepacket::getTmSpacePacketIdFromApid(0x22) == 0x0822); + + REQUIRE(spacepacket::getTcSpacePacketIdFromApid(0x7ff) == 0x1fff); + REQUIRE(spacepacket::getTmSpacePacketIdFromApid(0x7ff) == 0xfff); +} From 24e45c57d19d9f313748662bc2ca8a2c5e142ea3 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 19 Nov 2021 13:49:59 +0100 Subject: [PATCH 112/131] removed testcfg file --- tests/user/testcfg/CMakeLists.txt | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 tests/user/testcfg/CMakeLists.txt diff --git a/tests/user/testcfg/CMakeLists.txt b/tests/user/testcfg/CMakeLists.txt deleted file mode 100644 index 46808ec4..00000000 --- a/tests/user/testcfg/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -target_sources(${TARGET_NAME} PRIVATE - ipc/MissionMessageTypes.cpp - pollingsequence/PollingSequenceFactory.cpp -) - -# Add include paths for the executable -target_include_directories(${TARGET_NAME} PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} -) \ No newline at end of file From 00dced31ee17f06a112b473b4b54fea8982c5f92 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 19 Nov 2021 13:50:46 +0100 Subject: [PATCH 113/131] update unittest helper scripts - Added functionality to open HTML report immediately - Added another helper script to automatically generate unittest build folder --- scripts/coverage.py | 7 +++++++ scripts/gen-unittest.sh | 3 +++ 2 files changed, 10 insertions(+) create mode 100755 scripts/gen-unittest.sh diff --git a/scripts/coverage.py b/scripts/coverage.py index 71b6fb03..b5bd7745 100755 --- a/scripts/coverage.py +++ b/scripts/coverage.py @@ -6,6 +6,7 @@ import platform import sys import time import argparse +import webbrowser from typing import List @@ -18,6 +19,10 @@ information how to set up the build folder. def main(): parser = argparse.ArgumentParser(description="Processing arguments for LCOV helper script.") + parser.add_argument( + '-o', '--open', action='store_true', help='Open coverage data in webbrowser' + ) + args = parser.parse_args() build_dir_list = [] if not os.path.isfile('README.md'): @@ -41,6 +46,8 @@ def main(): print("Multiple build directories found!") build_directory = determine_build_dir(build_dir_list) perform_lcov_operation(build_directory) + if os.path.isdir('fsfw-tests_coverage') and args.open: + webbrowser.open('fsfw-tests_coverage/index.html') def check_for_cmake_build_dir(build_dir_dict: list): diff --git a/scripts/gen-unittest.sh b/scripts/gen-unittest.sh new file mode 100755 index 00000000..9ca8c399 --- /dev/null +++ b/scripts/gen-unittest.sh @@ -0,0 +1,3 @@ +#!/bin/sh +mkdir build-Unittest && cd build-Unittest +cmake -DFSFW_BUILD_UNITTESTS=ON -DFSFW_OSAL=host -DCMAKE_BUILD_TYPE=Debug .. From ceb87b5abb2992a18266328e0ea34d9af15db7af Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 30 Nov 2021 14:53:49 +0100 Subject: [PATCH 114/131] added warning latch to avoid spam --- src/fsfw/tmtcservices/TmTcBridge.cpp | 17 ++++++++++------- src/fsfw/tmtcservices/TmTcBridge.h | 1 + 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/fsfw/tmtcservices/TmTcBridge.cpp b/src/fsfw/tmtcservices/TmTcBridge.cpp index 7346cfe2..be45b698 100644 --- a/src/fsfw/tmtcservices/TmTcBridge.cpp +++ b/src/fsfw/tmtcservices/TmTcBridge.cpp @@ -183,13 +183,16 @@ ReturnValue_t TmTcBridge::storeDownlinkData(TmTcMessage *message) { } if(tmFifo->full()) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "TmTcBridge::storeDownlinkData: TM downlink max. number " - "of stored packet IDs reached!" << std::endl; -#else - sif::printWarning("TmTcBridge::storeDownlinkData: TM downlink max. number " - "of stored packet IDs reached!\n"); -#endif + if(warningLatch) { + #if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "TmTcBridge::storeDownlinkData: TM downlink max. number " + "of stored packet IDs reached!" << std::endl; + #else + sif::printWarning("TmTcBridge::storeDownlinkData: TM downlink max. number " + "of stored packet IDs reached!\n"); + #endif + warningLatch = true; + } if(overwriteOld) { tmFifo->retrieve(&storeId); tmStore->deleteData(storeId); diff --git a/src/fsfw/tmtcservices/TmTcBridge.h b/src/fsfw/tmtcservices/TmTcBridge.h index 4980caff..490d57fa 100644 --- a/src/fsfw/tmtcservices/TmTcBridge.h +++ b/src/fsfw/tmtcservices/TmTcBridge.h @@ -75,6 +75,7 @@ public: virtual uint16_t getIdentifier() override; virtual MessageQueueId_t getRequestQueue() override; + bool warningLatch = true; protected: //! Cached for initialize function. object_id_t tmStoreId = objects::NO_OBJECT; From c2bf09d506899d3ef893c0d8932898b158eef23d Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 1 Dec 2021 11:04:24 +0100 Subject: [PATCH 115/131] Introducing documentation with Sphinx This PR introduces the generation of documentation based on this excellent blog post: https://devblogs.microsoft.com/cppblog/clear-functional-c-documentation-with-sphinx-breathe-doxygen-cmake/ It combines the tools Sphinx, Doxygen and Breathe to generate good looking HTML documentation conveniently which can be hosted easily. The helper scripts were unified and there is now one helper.py script which can be used to create, build and open both tests and documentation. "./helper.py -h" can be used to get the different options. This PR also contains some smaller fixes which were necessary for the docs to build --- CMakeLists.txt | 18 +- README.md | 18 +- cmake/FindSphinx.cmake | 13 ++ docs/CMakeLists.txt | 66 +++++++ docs/Doxyfile.in | 7 + docs/Makefile | 20 ++ {doc => docs}/README-config.md | 0 {doc => docs}/README-controllers.md | 0 {doc => docs}/README-core.md | 0 {doc => docs}/README-devicehandlers.md | 0 {doc => docs}/README-highlevel.md | 0 {doc => docs}/README-localpools.md | 4 +- {doc => docs}/README-osal.md | 0 {doc => docs}/README-pus.md | 0 docs/api.rst | 16 ++ docs/api/action.rst | 15 ++ docs/api/controller.rst | 16 ++ docs/api/devicehandler.rst | 16 ++ docs/api/event.rst | 6 + docs/api/health.rst | 9 + docs/api/ipc.rst | 9 + docs/api/modes.rst | 10 + docs/api/objectmanager.rst | 30 +++ docs/api/returnvalue.rst | 10 + docs/api/task.rst | 8 + docs/conf.py | 56 ++++++ docs/config.rst | 41 ++++ docs/controllers.rst | 2 + docs/core.rst | 70 +++++++ docs/devicehandlers.rst | 3 + {doc => docs}/doxy/.gitignore | 0 {doc => docs}/doxy/OPUS.doxyfile | 0 docs/getting_started.rst | 115 +++++++++++ docs/highlevel.rst | 149 ++++++++++++++ {doc => docs}/images/PoolArchitecture.png | Bin docs/index.rst | 69 +++++++ docs/localpools.rst | 181 ++++++++++++++++++ docs/make.bat | 35 ++++ docs/osal.rst | 63 ++++++ docs/pus.rst | 2 + misc/defaultcfg/fsfwconfig/CMakeLists.txt | 60 ++++-- .../fsfwconfig/objects/FsfwFactory.cpp | 4 +- scripts/coverage.py | 83 -------- scripts/gen-unittest.sh | 3 - scripts/helper.py | 181 ++++++++++++++++++ .../integration/task/CMakeLists.txt | 2 +- 46 files changed, 1290 insertions(+), 120 deletions(-) create mode 100644 cmake/FindSphinx.cmake create mode 100644 docs/CMakeLists.txt create mode 100644 docs/Doxyfile.in create mode 100644 docs/Makefile rename {doc => docs}/README-config.md (100%) rename {doc => docs}/README-controllers.md (100%) rename {doc => docs}/README-core.md (100%) rename {doc => docs}/README-devicehandlers.md (100%) rename {doc => docs}/README-highlevel.md (100%) rename {doc => docs}/README-localpools.md (98%) rename {doc => docs}/README-osal.md (100%) rename {doc => docs}/README-pus.md (100%) create mode 100644 docs/api.rst create mode 100644 docs/api/action.rst create mode 100644 docs/api/controller.rst create mode 100644 docs/api/devicehandler.rst create mode 100644 docs/api/event.rst create mode 100644 docs/api/health.rst create mode 100644 docs/api/ipc.rst create mode 100644 docs/api/modes.rst create mode 100644 docs/api/objectmanager.rst create mode 100644 docs/api/returnvalue.rst create mode 100644 docs/api/task.rst create mode 100644 docs/conf.py create mode 100644 docs/config.rst create mode 100644 docs/controllers.rst create mode 100644 docs/core.rst create mode 100644 docs/devicehandlers.rst rename {doc => docs}/doxy/.gitignore (100%) rename {doc => docs}/doxy/OPUS.doxyfile (100%) create mode 100644 docs/getting_started.rst create mode 100644 docs/highlevel.rst rename {doc => docs}/images/PoolArchitecture.png (100%) create mode 100644 docs/index.rst create mode 100644 docs/localpools.rst create mode 100644 docs/make.bat create mode 100644 docs/osal.rst create mode 100644 docs/pus.rst delete mode 100755 scripts/coverage.py delete mode 100755 scripts/gen-unittest.sh create mode 100755 scripts/helper.py diff --git a/CMakeLists.txt b/CMakeLists.txt index e78e8929..bb3d48b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,9 @@ set(FSFW_VERSION 2) set(FSFW_SUBVERSION 0) set(FSFW_REVISION 0) +# Add the cmake folder so the FindSphinx module is found +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) + option(FSFW_GENERATE_SECTIONS "Generate function and data sections. Required to remove unused code" ON ) @@ -12,6 +15,7 @@ if(FSFW_GENERATE_SECTIONS) endif() option(FSFW_BUILD_UNITTESTS "Build unittest binary in addition to static library" OFF) +option(FSFW_BUILD_DOCS "Build documentation with Sphinx and Doxygen" OFF) if(FSFW_BUILD_UNITTESTS) option(FSFW_TESTS_GEN_COV "Generate coverage data for unittests" ON) endif() @@ -36,7 +40,9 @@ option(FSFW_ADD_SGP4_PROPAGATOR "Add SGP4 propagator code" OFF) set(LIB_FSFW_NAME fsfw) set(FSFW_TEST_TGT fsfw-tests) +set(FSFW_DUMMY_TGT fsfw-dummy) +project(${LIB_FSFW_NAME}) add_library(${LIB_FSFW_NAME}) if(FSFW_BUILD_UNITTESTS) @@ -59,7 +65,6 @@ if(FSFW_BUILD_UNITTESTS) set(FSFW_CONFIG_PATH tests/src/fsfw_tests/unit/testcfg) configure_file(tests/src/fsfw_tests/unit/testcfg/FSFWConfig.h.in FSFWConfig.h) configure_file(tests/src/fsfw_tests/unit/testcfg/TestsConfig.h.in tests/TestsConfig.h) - configure_file(tests/src/fsfw_tests/unit/testcfg/OBSWConfig.h.in OBSWConfig.h) project(${FSFW_TEST_TGT} CXX C) add_executable(${FSFW_TEST_TGT}) @@ -147,7 +152,7 @@ else() set(OS_FSFW "host") endif() -if(FSFW_BUILD_UNITTESTS) +if(FSFW_BUILD_UNITTESTS OR FSFW_BUILD_DOCS) configure_file(src/fsfw/FSFW.h.in fsfw/FSFW.h) configure_file(src/fsfw/FSFWVersion.h.in fsfw/FSFWVersion.h) else() @@ -163,6 +168,9 @@ if(FSFW_ADD_HAL) add_subdirectory(hal) endif() add_subdirectory(contrib) +if(FSFW_BUILD_DOCS) + add_subdirectory(docs) +endif() if(FSFW_BUILD_UNITTESTS) if(FSFW_TESTS_GEN_COV) @@ -234,9 +242,11 @@ endif() # The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it. # If this is not given, we include the default configuration and emit a warning. if(NOT FSFW_CONFIG_PATH) - message(WARNING "Flight Software Framework configuration path not set!") set(DEF_CONF_PATH misc/defaultcfg/fsfwconfig) - message(WARNING "Setting default configuration from ${DEF_CONF_PATH} ..") + if(NOT FSFW_BUILD_DOCS) + message(WARNING "Flight Software Framework configuration path not set!") + message(WARNING "Setting default configuration from ${DEF_CONF_PATH} ..") + endif() add_subdirectory(${DEF_CONF_PATH}) set(FSFW_CONFIG_PATH ${DEF_CONF_PATH}) endif() diff --git a/README.md b/README.md index 312bc077..0facfc9a 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ There are some functions like `printChar` which are different depending on the t and need to be implemented by the mission developer. A template configuration folder was provided and can be copied into the project root to have -a starting point. The [configuration section](doc/README-config.md#top) provides more specific +a starting point. The [configuration section](docs/README-config.md#top) provides more specific information about the possible options. ## Adding the library @@ -109,14 +109,14 @@ The `coverage.py` script located in the `script` folder can also be used to do t ## Index -[1. High-level overview](doc/README-highlevel.md#top)
-[2. Core components](doc/README-core.md#top)
-[3. Configuration](doc/README-config.md#top)
-[4. OSAL overview](doc/README-osal.md#top)
-[5. PUS services](doc/README-pus.md#top)
-[6. Device Handler overview](doc/README-devicehandlers.md#top)
-[7. Controller overview](doc/README-controllers.md#top)
-[8. Local Data Pools](doc/README-localpools.md#top)
+[1. High-level overview](docs/README-highlevel.md#top)
+[2. Core components](docs/README-core.md#top)
+[3. Configuration](docs/README-config.md#top)
+[4. OSAL overview](docs/README-osal.md#top)
+[5. PUS services](docs/README-pus.md#top)
+[6. Device Handler overview](docs/README-devicehandlers.md#top)
+[7. Controller overview](docs/README-controllers.md#top)
+[8. Local Data Pools](docs/README-localpools.md#top)
diff --git a/cmake/FindSphinx.cmake b/cmake/FindSphinx.cmake new file mode 100644 index 00000000..4a5b0700 --- /dev/null +++ b/cmake/FindSphinx.cmake @@ -0,0 +1,13 @@ +# Look for an executable called sphinx-build +find_program(SPHINX_EXECUTABLE + NAMES sphinx-build + DOC "Path to sphinx-build executable") + +include(FindPackageHandleStandardArgs) + +# Handle standard arguments to find_package like REQUIRED and QUIET +find_package_handle_standard_args( + Sphinx + "Failed to find sphinx-build executable" + SPHINX_EXECUTABLE +) \ No newline at end of file diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt new file mode 100644 index 00000000..fa5790db --- /dev/null +++ b/docs/CMakeLists.txt @@ -0,0 +1,66 @@ +# This is based on this excellent posting provided by Sy: +# https://devblogs.microsoft.com/cppblog/clear-functional-c-documentation-with-sphinx-breathe-doxygen-cmake/ +find_package(Doxygen REQUIRED) +find_package(Sphinx REQUIRED) + +get_target_property(LIB_FSFW_PUBLIC_HEADER_DIRS ${LIB_FSFW_NAME} INTERFACE_INCLUDE_DIRECTORIES) +# TODO: Add HAL as well +file(GLOB_RECURSE LIB_FSFW_PUBLIC_HEADERS ${PROJECT_SOURCE_DIR}/src/*.h) +file(GLOB_RECURSE RST_DOC_FILES ${PROJECT_SOURCE_DIR}/docs/*.rst) + +set(DOXYGEN_INPUT_DIR ${PROJECT_SOURCE_DIR}/src) +set(DOXYGEN_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/doxygen) +set(DOXYGEN_INDEX_FILE ${DOXYGEN_OUTPUT_DIR}/xml/index.xml) +set(DOXYFILE_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in) +set(DOXYFILE_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) + +# Replace variables inside @@ with the current values +configure_file(${DOXYFILE_IN} ${DOXYFILE_OUT} @ONLY) + +# Doxygen won't create this for us +file(MAKE_DIRECTORY ${DOXYGEN_OUTPUT_DIR}) + +# Only regenerate Doxygen when the Doxyfile or public headers change +add_custom_command( + OUTPUT ${DOXYGEN_INDEX_FILE} + DEPENDS ${LIB_FSFW_PUBLIC_HEADERS} + COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE_OUT} + MAIN_DEPENDENCY ${DOXYFILE_OUT} ${DOXYFILE_IN} + COMMENT "Generating docs" + VERBATIM +) + +# Nice named target so we can run the job easily +add_custom_target(Doxygen ALL DEPENDS ${DOXYGEN_INDEX_FILE}) + +set(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}) +set(SPHINX_BUILD ${CMAKE_CURRENT_BINARY_DIR}/sphinx) +set(SPHINX_INDEX_FILE ${SPHINX_BUILD}/index.html) + +# Only regenerate Sphinx when: +# - Doxygen has rerun +# - Our doc files have been updated +# - The Sphinx config has been updated +add_custom_command( + OUTPUT ${SPHINX_INDEX_FILE} + COMMAND + ${SPHINX_EXECUTABLE} -b html + # Tell Breathe where to find the Doxygen output + -Dbreathe_projects.fsfw=${DOXYGEN_OUTPUT_DIR}/xml + ${SPHINX_SOURCE} ${SPHINX_BUILD} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS + # Other docs files you want to track should go here (or in some variable) + ${RST_DOC_FILES} + ${DOXYGEN_INDEX_FILE} + MAIN_DEPENDENCY ${SPHINX_SOURCE}/conf.py + COMMENT "Generating documentation with Sphinx" +) + +# Nice named target so we can run the job easily +add_custom_target(Sphinx ALL DEPENDS ${SPHINX_INDEX_FILE}) + +# Add an install target to install the docs +include(GNUInstallDirs) +install(DIRECTORY ${SPHINX_BUILD} +DESTINATION ${CMAKE_INSTALL_DOCDIR}) diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in new file mode 100644 index 00000000..3d01d126 --- /dev/null +++ b/docs/Doxyfile.in @@ -0,0 +1,7 @@ +INPUT = "@DOXYGEN_INPUT_DIR@" + +RECURSIVE = YES + +OUTPUT_DIRECTORY = "@DOXYGEN_OUTPUT_DIR@" + +GENERATE_XML = YES diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..d4bb2cbb --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/doc/README-config.md b/docs/README-config.md similarity index 100% rename from doc/README-config.md rename to docs/README-config.md diff --git a/doc/README-controllers.md b/docs/README-controllers.md similarity index 100% rename from doc/README-controllers.md rename to docs/README-controllers.md diff --git a/doc/README-core.md b/docs/README-core.md similarity index 100% rename from doc/README-core.md rename to docs/README-core.md diff --git a/doc/README-devicehandlers.md b/docs/README-devicehandlers.md similarity index 100% rename from doc/README-devicehandlers.md rename to docs/README-devicehandlers.md diff --git a/doc/README-highlevel.md b/docs/README-highlevel.md similarity index 100% rename from doc/README-highlevel.md rename to docs/README-highlevel.md diff --git a/doc/README-localpools.md b/docs/README-localpools.md similarity index 98% rename from doc/README-localpools.md rename to docs/README-localpools.md index 96ae2d0a..2ee75189 100644 --- a/doc/README-localpools.md +++ b/docs/README-localpools.md @@ -31,7 +31,9 @@ cohesive pool variables. These sets simply iterator over the list of variables a `read` and `commit` functions of each variable. The following diagram shows the high-level architecture of the local data pools. -
+.. image:: ../misc/logo/FSFW_Logo_V3_bw.png + :alt: FSFW Logo + An example is shown for using the local data pools with a Gyroscope. For example, the following code shows an implementation to access data from a Gyroscope taken diff --git a/doc/README-osal.md b/docs/README-osal.md similarity index 100% rename from doc/README-osal.md rename to docs/README-osal.md diff --git a/doc/README-pus.md b/docs/README-pus.md similarity index 100% rename from doc/README-pus.md rename to docs/README-pus.md diff --git a/docs/api.rst b/docs/api.rst new file mode 100644 index 00000000..d2ee6c69 --- /dev/null +++ b/docs/api.rst @@ -0,0 +1,16 @@ +API +==== + +.. toctree:: + :maxdepth: 4 + + api/objectmanager + api/task + api/ipc + api/returnvalue + api/event + api/modes + api/health + api/action + api/devicehandler + api/controller diff --git a/docs/api/action.rst b/docs/api/action.rst new file mode 100644 index 00000000..31825b89 --- /dev/null +++ b/docs/api/action.rst @@ -0,0 +1,15 @@ +Action Module API +================= + +``ActionHelper`` +----------------- + +.. doxygenclass:: ActionHelper + :members: + +``HasActionsIF`` +----------------- + +.. doxygenclass:: HasActionsIF + :members: + :protected-members: diff --git a/docs/api/controller.rst b/docs/api/controller.rst new file mode 100644 index 00000000..27136be6 --- /dev/null +++ b/docs/api/controller.rst @@ -0,0 +1,16 @@ +Controller API +================= + +``ControllerBase`` +------------------------- + +.. doxygenclass:: ControllerBase + :members: + :protected-members: + +``ExtendedControllerBase`` +----------------------------- + +.. doxygenclass:: ExtendedControllerBase + :members: + :protected-members: diff --git a/docs/api/devicehandler.rst b/docs/api/devicehandler.rst new file mode 100644 index 00000000..f709b640 --- /dev/null +++ b/docs/api/devicehandler.rst @@ -0,0 +1,16 @@ +Device Handler Base API +========================= + +``DeviceHandlerBase`` +----------------------- + +.. doxygenclass:: DeviceHandlerBase + :members: + :protected-members: + +``DeviceHandlerIF`` +----------------------- + +.. doxygenclass:: DeviceHandlerIF + :members: + :protected-members: diff --git a/docs/api/event.rst b/docs/api/event.rst new file mode 100644 index 00000000..7553c963 --- /dev/null +++ b/docs/api/event.rst @@ -0,0 +1,6 @@ +.. _eventapi: + +Event API +============ + +.. doxygenfile:: Event.h diff --git a/docs/api/health.rst b/docs/api/health.rst new file mode 100644 index 00000000..b1d4c1b2 --- /dev/null +++ b/docs/api/health.rst @@ -0,0 +1,9 @@ +Health API +=========== + +``HasHealthIF`` +------------------ + +.. doxygenclass:: HasHealthIF + :members: + :protected-members: diff --git a/docs/api/ipc.rst b/docs/api/ipc.rst new file mode 100644 index 00000000..17a91f00 --- /dev/null +++ b/docs/api/ipc.rst @@ -0,0 +1,9 @@ +IPC Module API +================= + +``MessageQueueIF`` +------------------- + +.. doxygenclass:: MessageQueueIF + :members: + :protected-members: diff --git a/docs/api/modes.rst b/docs/api/modes.rst new file mode 100644 index 00000000..7b6b0dca --- /dev/null +++ b/docs/api/modes.rst @@ -0,0 +1,10 @@ +Modes API +========= + + +``HasModesIF`` +--------------- + +.. doxygenclass:: HasModesIF + :members: + :protected-members: diff --git a/docs/api/objectmanager.rst b/docs/api/objectmanager.rst new file mode 100644 index 00000000..e90deb57 --- /dev/null +++ b/docs/api/objectmanager.rst @@ -0,0 +1,30 @@ +Object Manager API +========================= + +``SystemObject`` +-------------------- + +.. doxygenclass:: SystemObject + :members: + :protected-members: + +``ObjectManager`` +----------------------- + +.. doxygenclass:: ObjectManager + :members: + :protected-members: + +``SystemObjectIF`` +-------------------- + +.. doxygenclass:: SystemObjectIF + :members: + :protected-members: + +``ObjectManagerIF`` +----------------------- + +.. doxygenclass:: ObjectManagerIF + :members: + :protected-members: diff --git a/docs/api/returnvalue.rst b/docs/api/returnvalue.rst new file mode 100644 index 00000000..b0d43916 --- /dev/null +++ b/docs/api/returnvalue.rst @@ -0,0 +1,10 @@ +.. _retvalapi: + +Returnvalue API +================== + +.. doxygenfile:: HasReturnvaluesIF.h + +.. _fwclassids: + +.. doxygenfile:: FwClassIds.h diff --git a/docs/api/task.rst b/docs/api/task.rst new file mode 100644 index 00000000..b218dac1 --- /dev/null +++ b/docs/api/task.rst @@ -0,0 +1,8 @@ +Task API +========= + +``ExecutableObjectIF`` +----------------------- + +.. doxygenclass:: ExecutableObjectIF + :members: diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 00000000..44fd90c4 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,56 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + + +# -- Project information ----------------------------------------------------- + +project = 'Flight Software Framework' +copyright = '2021, Institute of Space Systems (IRS)' +author = 'Institute of Space Systems (IRS)' + +# The full version, including alpha/beta/rc tags +release = '2.0.1' + + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ "breathe" ] + +breathe_default_project = "fsfw" + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'alabaster' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] \ No newline at end of file diff --git a/docs/config.rst b/docs/config.rst new file mode 100644 index 00000000..ed317aed --- /dev/null +++ b/docs/config.rst @@ -0,0 +1,41 @@ +Configuring the FSFW +===================== + +The FSFW can be configured via the ``fsfwconfig`` folder. A template folder has been provided in +``misc/defaultcfg`` to have a starting point for this. The folder should be added +to the include path. The primary configuration file is the ``FSFWConfig.h`` folder. Some +of the available options will be explained in more detail here. + +Auto-Translation of Events +---------------------------- + +The FSFW allows the automatic translation of events, which allows developers to track triggered +events directly via console output. Using this feature requires: + +1. ``FSFW_OBJ_EVENT_TRANSLATION`` set to 1 in the configuration file. +2. Special auto-generated translation files which translate event IDs and object IDs into + human readable strings. These files can be generated using the + `fsfwgen Python scripts `_. +3. The generated translation files for the object IDs should be named ``translatesObjects.cpp`` + and ``translateObjects.h`` and should be copied to the ``fsfwconfig/objects`` folder +4. The generated translation files for the event IDs should be named ``translateEvents.cpp`` and + ``translateEvents.h`` and should be copied to the ``fsfwconfig/events`` folder + +An example implementations of these translation file generators can be found as part +of the `SOURCE project here `_ +or the `FSFW example `_ + +Configuring the Event Manager +---------------------------------- + +The number of allowed subscriptions can be modified with the following +parameters: + +.. code-block:: cpp + + namespace fsfwconfig { + //! Configure the allocated pool sizes for the event manager. + static constexpr size_t FSFW_EVENTMGMR_MATCHTREE_NODES = 240; + static constexpr size_t FSFW_EVENTMGMT_EVENTIDMATCHERS = 120; + static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120; + } diff --git a/docs/controllers.rst b/docs/controllers.rst new file mode 100644 index 00000000..28f57393 --- /dev/null +++ b/docs/controllers.rst @@ -0,0 +1,2 @@ +Controllers +============= diff --git a/docs/core.rst b/docs/core.rst new file mode 100644 index 00000000..ef6f6165 --- /dev/null +++ b/docs/core.rst @@ -0,0 +1,70 @@ +.. _core: + +Core Modules +============= + +The core modules provide the most important functionalities of the Flight Software Framework. + +Clock +------ + +- This is a class of static functions that can be used at anytime +- Leap Seconds must be set if any time conversions from UTC to other times is used + +Object Manager +--------------- + +- Must be created during program startup +- The component which handles all references. All :cpp:class:`SystemObject`\s register at this + component. +- All :cpp:class:`SystemObject`\s needs to have a unique Object ID. Those can be managed like + framework objects. +- A reference to an object can be retrieved by calling the ``get`` function of + :cpp:class:`ObjectManagerIF`. The target type must be specified as a template argument. + A ``nullptr`` check of the returning pointer must be done. This function is based on + run-time type information. + + .. code-block:: cpp + + template T* ObjectManagerIF::get(object_id_t id); + +- A typical way to create all objects on startup is a handing a static produce function to the + ObjectManager on creation. By calling ``ObjectManager::instance()->initialize(produceFunc)`` the + produce function will be called and all :cpp:class:`SystemObject`\s will be initialized + afterwards. + +Event Manager +--------------- + +- Component which allows routing of events +- Other objects can subscribe to specific events, ranges of events or all events of an object. +- Subscriptions can be done during runtime but should be done during initialization +- Amounts of allowed subscriptions can be configured in ``FSFWConfig.h`` + +Health Table +--------------- + +- A component which holds every health state +- Provides a thread safe way to access all health states without the need of message exchanges + +Stores +-------------- + +- The message based communication can only exchange a few bytes of information inside the message + itself. Therefore, additional information can be exchanged with Stores. With this, only the + store address must be exchanged in the message. +- Internally, the FSFW uses an IPC Store to exchange data between processes. For incoming TCs a TC + Store is used. For outgoing TM a TM store is used. +- All of them should use the Thread Safe Class storagemanager/PoolManager + +Tasks +--------- + +There are two different types of tasks: + +- The PeriodicTask just executes objects that are of type ExecutableObjectIF in the order of the + insertion to the Tasks. +- FixedTimeslotTask executes a list of calls in the order of the given list. This is intended for + DeviceHandlers, where polling should be in a defined order. An example can be found in + ``defaultcfg/fsfwconfig/pollingSequence`` folder + diff --git a/docs/devicehandlers.rst b/docs/devicehandlers.rst new file mode 100644 index 00000000..58c2df78 --- /dev/null +++ b/docs/devicehandlers.rst @@ -0,0 +1,3 @@ +Device Handlers +================== + diff --git a/doc/doxy/.gitignore b/docs/doxy/.gitignore similarity index 100% rename from doc/doxy/.gitignore rename to docs/doxy/.gitignore diff --git a/doc/doxy/OPUS.doxyfile b/docs/doxy/OPUS.doxyfile similarity index 100% rename from doc/doxy/OPUS.doxyfile rename to docs/doxy/OPUS.doxyfile diff --git a/docs/getting_started.rst b/docs/getting_started.rst new file mode 100644 index 00000000..069e98cd --- /dev/null +++ b/docs/getting_started.rst @@ -0,0 +1,115 @@ +Getting Started +================ + + +Getting started +---------------- + +The `Hosted FSFW example`_ provides a good starting point and a demo to see the FSFW capabilities. +It is recommended to get started by building and playing around with the demo application. +There are also other examples provided for all OSALs using the popular embedded platforms +Raspberry Pi, Beagle Bone Black and STM32H7. + +Generally, the FSFW is included in a project by providing +a configuration folder, building the static library and linking against it. +There are some functions like ``printChar`` which are different depending on the target architecture +and need to be implemented by the mission developer. + +A template configuration folder was provided and can be copied into the project root to have +a starting point. The [configuration section](docs/README-config.md#top) provides more specific +information about the possible options. + +Adding the library +------------------- + +The following steps show how to add and use FSFW components. It is still recommended to +try out the example mentioned above to get started, but the following steps show how to +add and link against the FSFW library in general. + +1. Add this repository as a submodule + + .. code-block:: console + + git submodule add https://egit.irs.uni-stuttgart.de/fsfw/fsfw.git fsfw + +2. Add the following directive inside the uppermost ``CMakeLists.txt`` file of your project + + .. code-block:: cmake + + add_subdirectory(fsfw) + +3. Make sure to provide a configuration folder and supply the path to that folder with + the `FSFW_CONFIG_PATH` CMake variable from the uppermost `CMakeLists.txt` file. + It is also necessary to provide the `printChar` function. You can find an example + implementation for a hosted build + `here `_. + +4. Link against the FSFW library + + .. code-block:: cmake + + target_link_libraries( PRIVATE fsfw) + + +5. It should now be possible use the FSFW as a static library from the user code. + +Building the unittests +------------------------- + +The FSFW also has unittests which use the `Catch2 library`_. +These are built by setting the CMake option ``FSFW_BUILD_UNITTESTS`` to ``ON`` or `TRUE` +from your project `CMakeLists.txt` file or from the command line. + +The fsfw-tests binary will be built as part of the static library and dropped alongside it. +If the unittests are built, the library and the tests will be built with coverage information by +default. This can be disabled by setting the `FSFW_TESTS_COV_GEN` option to `OFF` or `FALSE`. + +You can use the following commands inside the ``fsfw`` folder to set up the build system + +.. code-block:: console + + mkdir build-tests && cd build-tests + cmake -DFSFW_BUILD_UNITTESTS=ON -DFSFW_OSAL=host .. + + +You can also use ``-DFSFW_OSAL=linux`` on Linux systems. + +Coverage data in HTML format can be generated using the `Code coverage`_ CMake module. +To build the unittests, run them and then generare the coverage data in this format, +the following command can be used inside the build directory after the build system was set up + +.. code-block:: console + + cmake --build . -- fsfw-tests_coverage -j + + +The ``helper.py`` script located in the ``script`` folder can also be used to create, build +and open the unittests conveniently. Try ``helper.py -h`` for more information. + +Building the documentation +---------------------------- + +The FSFW documentation is built using the tools Sphinx, doxygen and breathe based on the +instructions provided in `this blogpost `_. You can set up a +documentation build system using the following commands + +.. code-block:: bash + + mkdir build-docs && cd build-docs + cmake -DFSFW_BUILD_DOCS=ON -DFSFW_OSAL=host .. + +Then you can generate the documentation using + +.. code-block:: bash + + cmake --build . -j + +You can find the generated documentation inside the ``docs/sphinx`` folder inside the build +folder. Simply open the ``index.html`` in the webbrowser of your choice. + +The ``helper.py`` script located in the ``script`` folder can also be used to create, build +and open the documentation conveniently. Try ``helper.py -h`` for more information. + +.. _`Hosted FSFW example`: https://egit.irs.uni-stuttgart.de/fsfw/fsfw-example-hosted +.. _`Catch2 library`: https://github.com/catchorg/Catch2 +.. _`Code coverage`: https://github.com/bilke/cmake-modules/tree/master diff --git a/docs/highlevel.rst b/docs/highlevel.rst new file mode 100644 index 00000000..08f44777 --- /dev/null +++ b/docs/highlevel.rst @@ -0,0 +1,149 @@ +.. _highlevel: + +High-level overview +=================== + +Structure +---------- + +The general structure is driven by the usage of interfaces provided by objects. +The FSFW uses C++11 as baseline. The intention behind this is that this C++ Standard should be +widely available, even with older compilers. +The FSFW uses dynamic allocation during the initialization but provides static containers during runtime. +This simplifies the instantiation of objects and allows the usage of some standard containers. +Dynamic Allocation after initialization is discouraged and different solutions are provided in the +FSFW to achieve that. The fsfw uses run-time type information but exceptions are not allowed. + +Failure Handling +----------------- + +Functions should return a defined :cpp:type:`ReturnValue_t` to signal to the caller that something has +gone wrong. Returnvalues must be unique. For this the function :cpp:func:`HasReturnvaluesIF::makeReturnCode` +or the :ref:`macro MAKE_RETURN_CODE ` can be used. The ``CLASS_ID`` is a unique ID for that type of object. +See the :ref:`FSFW Class IDs file `. The user can add custom ``CLASS_ID``\s via the +``fsfwconfig`` folder. + +OSAL +------------ + +The FSFW provides operation system abstraction layers for Linux, FreeRTOS and RTEMS. +The OSAL provides periodic tasks, message queues, clocks and semaphores as well as mutexes. +The :ref:`OSAL README ` provides more detailed information on provided components +and how to use them. + +Core Components +---------------- + +The FSFW has following core components. More detailed informations can be found in the +:ref:`core component section `: + +1. Tasks: Abstraction for different (periodic) task types like periodic tasks or tasks + with fixed timeslots +2. ObjectManager: This module stores all `SystemObjects` by mapping a provided unique object ID + to the object handles. +3. Static Stores: Different stores are provided to store data of variable size (like telecommands + or small telemetry) in a pool structure without using dynamic memory allocation. + These pools are allocated up front. +4. Clock: This module provided common time related functions +5. EventManager: This module allows routing of events generated by `SystemObjects` +6. HealthTable: A component which stores the health states of objects + +Static IDs in the framework +-------------------------------- + +Some parts of the framework use a static routing address for communication. +An example setup of IDs can be found in the example config in ``misc/defaultcfg/fsfwconfig/objects`` +inside the function ``Factory::setStaticFrameworkObjectIds``. + +Events +---------------- + +Events are tied to objects. EventIds can be generated by calling the +:ref:`macro MAKE_EVENT ` or the function :cpp:func:`event::makeEvent`. +This works analog to the returnvalues. Every object that needs own Event IDs has to get a +unique ``SUBSYSTEM_ID``. Every :cpp:class:`SystemObject` can call +:cpp:func:`SystemObject::triggerEvent` from the parent class. +Therefore, event messages contain the specific EventId and the objectId of the object that +has triggered. + +Internal Communication +------------------------- + +Components communicate mostly via Messages through Queues. +Those queues are created by calling the singleton ``QueueFactory::instance()->create`` which +will create `MessageQueue` instances for the used OSAL. + +External Communication +-------------------------- + +The external communication with the mission control system is mostly up to the user implementation. +The FSFW provides PUS Services which can be used to but don't need to be used. +The services can be seen as a conversion from a TC to a message based communication and back. + +TMTC Communication +~~~~~~~~~~~~~~~~~~~ + +The FSFW provides some components to facilitate TMTC handling via the PUS commands. +For example, a UDP or TCP PUS server socket can be opened on a specific port using the +files located in ``osal/common``. The FSFW example uses this functionality to allow sending +telecommands and receiving telemetry using the +`TMTC commander application `_. + +Simple commands like the PUS Service 17 ping service can be tested by simply running the +``tmtc_client_cli.py`` or ``tmtc_client_gui.py`` utility in +the `example tmtc folder `_ +while the `fsfw_example` application is running. + +More generally, any class responsible for handling incoming telecommands and sending telemetry +can implement the generic ``TmTcBridge`` class located in ``tmtcservices``. Many applications +also use a dedicated polling task for reading telecommands which passes telecommands +to the ``TmTcBridge`` implementation. + +CCSDS Frames, CCSDS Space Packets and PUS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If the communication is based on CCSDS Frames and Space Packets, several classes can be used to +distributed the packets to the corresponding services. Those can be found in ``tcdistribution``. +If Space Packets are used, a timestamper has to be provided by the user. +An example can be found in the ``timemanager`` folder, which uses ``CCSDSTime::CDS_short``. + +Device Handlers +-------------------------- + +DeviceHandlers are another important component of the FSFW. The idea is, to have a software +counterpart of every physical device to provide a simple mode, health and commanding interface. +By separating the underlying Communication Interface with +``DeviceCommunicationIF``, a device handler (DH) can be tested on different hardware. +The DH has mechanisms to monitor the communication with the physical device which allow +for FDIR reaction. Device Handlers can be created by implementing ``DeviceHandlerBase``. +A standard FDIR component for the DH will be created automatically but can +be overwritten by the user. More information on DeviceHandlers can be found in the +related [documentation section](doc/README-devicehandlers.md#top). + +Modes and Health +-------------------- + +The two interfaces ``HasModesIF`` and ``HasHealthIF`` provide access for commanding and monitoring +of components. On-board mode management is implement in hierarchy system. + +- Device handlers and controllers are the lowest part of the hierarchy. +- The next layer are assemblies. Those assemblies act as a component which handle + redundancies of handlers. Assemblies share a common core with the top level subsystem components +- The top level subsystem components are used to group assemblies, controllers and device handlers. + For example, a spacecraft can have a atttitude control subsystem and a power subsystem. + +Those assemblies are intended to act as auto-generated components from a database which describes +the subsystem modes. The definitions contain transition and target tables which contain the DH, +Assembly and Controller Modes to be commanded. +Transition tables contain as many steps as needed to reach the mode from any other mode, e.g. a +switch into any higher AOCS mode might first turn on the sensors, than the actuators and the +controller as last component. +The target table is used to describe the state that is checked continuously by the subsystem. +All of this allows System Modes to be generated as Subsystem object as well from the same database. +This System contains list of subsystem modes in the transition and target tables. +Therefore, it allows a modular system to create system modes and easy commanding of those, because +only the highest components must be commanded. + +The health state represents if the component is able to perform its tasks. +This can be used to signal the system to avoid using this component instead of a redundant one. +The on-board FDIR uses the health state for isolation and recovery. diff --git a/doc/images/PoolArchitecture.png b/docs/images/PoolArchitecture.png similarity index 100% rename from doc/images/PoolArchitecture.png rename to docs/images/PoolArchitecture.png diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 00000000..b37c0904 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,69 @@ +.. Flight Software Framework documentation master file, created by + sphinx-quickstart on Tue Nov 30 10:56:03 2021. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Flight Software Framework (FSFW) documentation +================================================ + +.. image:: ../misc/logo/FSFW_Logo_V3_bw.png + :alt: FSFW Logo + +The Flight Software Framework is a C++ Object Oriented Framework for unmanned, +automated systems like Satellites. + +The initial version of the Flight Software Framework was developed during +the Flying Laptop Project by the University of Stuttgart in cooperation +with Airbus Defence and Space GmbH. + +Quick facts +--------------- + +The framework is designed for systems, which communicate with external devices, perform control +loops, receive telecommands and send telemetry, and need to maintain a high level of availability. +Therefore, a mode and health system provides control over the states of the software and the +controlled devices. In addition, a simple mechanism of event based fault detection, isolation and +recovery is implemented as well. + +The FSFW provides abstraction layers for operating systems to provide a uniform operating system +abstraction layer (OSAL). Some components of this OSAL are required internally by the FSFW but is +also very useful for developers to implement the same application logic on different operating +systems with a uniform interface. + +Currently, the FSFW provides the following OSALs: + +- Linux +- Host +- FreeRTOS +- RTEMS + +The recommended hardware is a microprocessor with more than 1 MB of RAM and 1 MB of non-volatile +memory. For reference, current applications use a Cobham Gaisler UT699 (LEON3FT), a +ISISPACE IOBC or a Zynq-7020 SoC. The ``fsfw`` was also successfully run on the +STM32H743ZI-Nucleo board and on a Raspberry Pi and is currently running on the active +satellite mission Flying Laptop. + +Index +------- + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + getting_started + highlevel + core + config + osal + pus + devicehandlers + controllers + localpools + api + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/localpools.rst b/docs/localpools.rst new file mode 100644 index 00000000..d2afd0a0 --- /dev/null +++ b/docs/localpools.rst @@ -0,0 +1,181 @@ +Local Data Pools +========================================= + +The following text is targeted towards mission software developers which would like +to use the local data pools provided by the FSFW to store data like sensor values so they can be +used by other software objects like controllers as well. If a custom class should have a local +pool which can be used by other software objects as well, following steps have to be performed: + +1. Create a ``LocalDataPoolManager`` member object in the custom class +2. Implement the ``HasLocalDataPoolIF`` with specifies the interface between the local pool + manager and the class owning the local pool. + +The local data pool manager is also able to process housekeeping service requests in form +of messages, generate periodic housekeeping packet, generate notification and snapshots of changed +variables and datasets and process notifications and snapshots coming from other objects. +The two former tasks are related to the external interface using telemetry and telecommands (TMTC) +while the later two are related to data consumers like controllers only acting on data change +detected by the data creator instead of checking the data manually each cycle. Two important +framework classes ``DeviceHandlerBase`` and ``ExtendedControllerBase`` already perform the two steps +shown above so the steps required are altered slightly. + +Storing and Accessing pool data +------------------------------------- + +The pool manager is responsible for thread-safe access of the pool data, but the actual +access to the pool data from the point of view of a mission software developer happens via proxy +classes like pool variable classes. These classes store a copy +of the pool variable with the matching datatype and copy the actual data from the local pool +on a ``read`` call. Changed variables can then be written to the local pool with a ``commit`` call. +The ``read`` and ``commit`` calls are thread-safe and can be called concurrently from data creators +and data consumers. Generally, a user will create a dataset class which in turn groups all +cohesive pool variables. These sets simply iterator over the list of variables and call the +``read`` and ``commit`` functions of each variable. The following diagram shows the +high-level architecture of the local data pools. + +.. image:: ../docs/images/PoolArchitecture.png + :alt: Pool Architecture + +An example is shown for using the local data pools with a Gyroscope. +For example, the following code shows an implementation to access data from a Gyroscope taken +from the SOURCE CubeSat project: + +.. code-block:: cpp + + class GyroPrimaryDataset: public StaticLocalDataSet<3 * sizeof(float)> { + public: + /** + * Constructor for data users + * @param gyroId + */ + GyroPrimaryDataset(object_id_t gyroId): + StaticLocalDataSet(sid_t(gyroId, gyrodefs::GYRO_DATA_SET_ID)) { + setAllVariablesReadOnly(); + } + + lp_var_t angVelocityX = lp_var_t(sid.objectId, + gyrodefs::ANGULAR_VELOCITY_X, this); + lp_var_t angVelocityY = lp_var_t(sid.objectId, + gyrodefs::ANGULAR_VELOCITY_Y, this); + lp_var_t angVelocityZ = lp_var_t(sid.objectId, + gyrodefs::ANGULAR_VELOCITY_Z, this); + private: + + friend class GyroHandler; + /** + * Constructor for data creator + * @param hkOwner + */ + GyroPrimaryDataset(HasLocalDataPoolIF* hkOwner): + StaticLocalDataSet(hkOwner, gyrodefs::GYRO_DATA_SET_ID) {} + }; + +There is a public constructor for users which sets all variables to read-only and there is a +constructor for the GyroHandler data creator by marking it private and declaring the ``GyroHandler`` +as a friend class. Both the atittude controller and the ``GyroHandler`` can now +use the same class definition to access the pool variables with ``read`` and ``commit`` semantics +in a thread-safe way. Generally, each class requiring access will have the set class as a member +class. The data creator will also be generally a ``DeviceHandlerBase`` subclass and some additional +steps are necessary to expose the set for housekeeping purposes. + +Using the local data pools in a ``DeviceHandlerBase`` subclass +-------------------------------------------------------------- + +It is very common to store data generated by devices like a sensor into a pool which can +then be used by other objects. Therefore, the ``DeviceHandlerBase`` already has a +local pool. Using the aforementioned example, the ``GyroHandler`` will now have the set class +as a member: + +.. code-block:: cpp + + class GyroHandler: ... { + + public: + ... + private: + ... + GyroPrimaryDataset gyroData; + ... + }; + + +The constructor used for the creators expects the owner class as a parameter, so we initialize +the object in the `GyroHandler` constructor like this: + +.. code-block:: cpp + + GyroHandler::GyroHandler(object_id_t objectId, object_id_t comIF, + CookieIF *comCookie, uint8_t switchId): + DeviceHandlerBase(objectId, comIF, comCookie), switchId(switchId), + gyroData(this) {} + + +We need to assign the set to a reply ID used in the ``DeviceHandlerBase``. +The combination of the ``GyroHandler`` object ID and the reply ID will be the 64-bit structure ID +``sid_t`` and is used to globally identify the set, for example when requesting housekeeping data or +generating update messages. We need to assign our custom set class in some way so that the local +pool manager can access the custom data sets as well. +By default, the ``getDataSetHandle`` will take care of this tasks. The default implementation for a +``DeviceHandlerBase`` subclass will use the internal command map to retrieve +a handle to a dataset from a given reply ID. Therefore, +we assign the set in the ``fillCommandAndReplyMap`` function: + +.. code-block:: cpp + + void GyroHandler::fillCommandAndReplyMap() { + ... + this->insertInCommandAndReplyMap(gyrodefs::GYRO_DATA, 3, &gyroData); + ... + } + + +Now, we need to create the actual pool entries as well, using the ``initializeLocalDataPool`` +function. Here, we also immediately subscribe for periodic housekeeping packets +with an interval of 4 seconds. They are still disabled in this example and can be enabled +with a housekeeping service command. + +.. code-block:: cpp + + ReturnValue_t GyroHandler::initializeLocalDataPool(localpool::DataPool &localDataPoolMap, + LocalDataPoolManager &poolManager) { + localDataPoolMap.emplace(gyrodefs::ANGULAR_VELOCITY_X, + new PoolEntry({0.0})); + localDataPoolMap.emplace(gyrodefs::ANGULAR_VELOCITY_Y, + new PoolEntry({0.0})); + localDataPoolMap.emplace(gyrodefs::ANGULAR_VELOCITY_Z, + new PoolEntry({0.0})); + localDataPoolMap.emplace(gyrodefs::GENERAL_CONFIG_REG42, + new PoolEntry({0})); + localDataPoolMap.emplace(gyrodefs::RANGE_CONFIG_REG43, + new PoolEntry({0})); + + poolManager.subscribeForPeriodicPacket(gyroData.getSid(), false, 4.0, false); + return HasReturnvaluesIF::RETURN_OK; + } + +Now, if we receive some sensor data and converted them into the right format, +we can write it into the pool like this, using a guard class to ensure the set is commited back +in any case: + +.. code-block:: cpp + + PoolReadGuard readHelper(&gyroData); + if(readHelper.getReadResult() == HasReturnvaluesIF::RETURN_OK) { + if(not gyroData.isValid()) { + gyroData.setValidity(true, true); + } + + gyroData.angVelocityX = angularVelocityX; + gyroData.angVelocityY = angularVelocityY; + gyroData.angVelocityZ = angularVelocityZ; + } + + +The guard class will commit the changed data on destruction automatically. + +Using the local data pools in a ``ExtendedControllerBase`` subclass +---------------------------------------------------------------------- + +Coming soon + + diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 00000000..922152e9 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/osal.rst b/docs/osal.rst new file mode 100644 index 00000000..7ac66e47 --- /dev/null +++ b/docs/osal.rst @@ -0,0 +1,63 @@ +.. _osal: + +Operating System Abstraction Layer (OSAL) +============================================ + +Some specific information on the provided OSALs are provided. + +Linux +------- + +This OSAL can be used to compile for Linux host systems like Ubuntu 20.04 or for +embedded Linux targets like the Raspberry Pi. This OSAL generally requires threading support +and real-time functionalities. For most UNIX systems, this is done by adding ``-lrt`` and +``-lpthread`` to the linked libraries in the compilation process. The CMake build support provided +will do this automatically for the ``fsfw`` target. It should be noted that most UNIX systems need +to be configured specifically to allow the real-time functionalities required by the FSFW. + +Hosted OSAL +------------------- + +This is the newest OSAL. Support for Semaphores has not been implemented yet and will propably be +implemented as soon as C++20 with Semaphore support has matured. This OSAL can be used to run the +FSFW on any host system, but currently has only been tested on Windows 10 and Ubuntu 20.04. Unlike +the other OSALs, it uses dynamic memory allocation (e.g. for the message queue implementation). +Cross-platform serial port (USB) support might be added soon. + +FreeRTOS OSAL +------------------ + +FreeRTOS is not included and the developer needs to take care of compiling the FreeRTOS sources and +adding the ``FreeRTOSConfig.h`` file location to the include path. This OSAL has only been tested +extensively with the pre-emptive scheduler configuration so far but it should in principle also be +possible to use a cooperative scheduler. It is recommended to use the `heap_4` allocation scheme. +When using newlib (nano), it is also recommended to add ``#define configUSE_NEWLIB_REENTRANT`` to +the FreeRTOS configuration file to ensure thread-safety. + +When using this OSAL, developers also need to provide an implementation for the +``vRequestContextSwitchFromISR`` function. This has been done because the call to request a context +switch from an ISR is generally located in the ``portmacro.h`` header and is different depending on +the target architecture or device. + +RTEMS OSAL +--------------- + +The RTEMS OSAL was the first implemented OSAL which is also used on the active satellite Flying Laptop. + +TCP/IP socket abstraction +------------------------------ + +The Linux and Host OSAL provide abstraction layers for the socket API. Currently, only UDP sockets +have been imlemented. This is very useful to test TMTC handling either on the host computer +directly (targeting localhost with a TMTC application) or on embedded Linux devices, sending +TMTC packets via Ethernet. + +Example Applications +---------------------- + +There are example applications available for each OSAL + +- `Hosted OSAL `_ +- `Linux OSAL for MCUs `_ +- `FreeRTOS OSAL on the STM32H743ZIT `_ +- `RTEMS OSAL on the STM32H743ZIT `_ diff --git a/docs/pus.rst b/docs/pus.rst new file mode 100644 index 00000000..8dbb2104 --- /dev/null +++ b/docs/pus.rst @@ -0,0 +1,2 @@ +PUS Services +============== diff --git a/misc/defaultcfg/fsfwconfig/CMakeLists.txt b/misc/defaultcfg/fsfwconfig/CMakeLists.txt index 178fc273..3b2064ba 100644 --- a/misc/defaultcfg/fsfwconfig/CMakeLists.txt +++ b/misc/defaultcfg/fsfwconfig/CMakeLists.txt @@ -1,23 +1,49 @@ -target_include_directories(${TARGET_NAME} PRIVATE +if(DEFINED TARGET_NAME) + target_include_directories(${TARGET_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} -) - -target_sources(${TARGET_NAME} PRIVATE - ipc/missionMessageTypes.cpp - pollingsequence/PollingSequenceFactory.cpp - objects/FsfwFactory.cpp -) - -# If a special translation file for object IDs exists, compile it. -if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/objects/translateObjects.cpp") - target_sources(${TARGET_NAME} PRIVATE - objects/translateObjects.cpp ) -endif() -# If a special translation file for events exists, compile it. -if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/objects/translateObjects.cpp") target_sources(${TARGET_NAME} PRIVATE - events/translateEvents.cpp + ipc/missionMessageTypes.cpp + pollingsequence/PollingSequenceFactory.cpp + objects/FsfwFactory.cpp ) + + # If a special translation file for object IDs exists, compile it. + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/objects/translateObjects.cpp") + target_sources(${TARGET_NAME} PRIVATE + objects/translateObjects.cpp + ) + endif() + + # If a special translation file for events exists, compile it. + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/objects/translateObjects.cpp") + target_sources(${TARGET_NAME} PRIVATE + events/translateEvents.cpp + ) + endif() +else() + target_include_directories(${LIB_FSFW_NAME} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ) + + target_sources(${LIB_FSFW_NAME} PRIVATE + ipc/missionMessageTypes.cpp + pollingsequence/PollingSequenceFactory.cpp + objects/FsfwFactory.cpp + ) + + # If a special translation file for object IDs exists, compile it. + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/objects/translateObjects.cpp") + target_sources(${LIB_FSFW_NAME} PRIVATE + objects/translateObjects.cpp + ) + endif() + + # If a special translation file for events exists, compile it. + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/objects/translateObjects.cpp") + target_sources(${LIB_FSFW_NAME} PRIVATE + events/translateEvents.cpp + ) + endif() endif() diff --git a/misc/defaultcfg/fsfwconfig/objects/FsfwFactory.cpp b/misc/defaultcfg/fsfwconfig/objects/FsfwFactory.cpp index 08ad41ec..5aef4980 100644 --- a/misc/defaultcfg/fsfwconfig/objects/FsfwFactory.cpp +++ b/misc/defaultcfg/fsfwconfig/objects/FsfwFactory.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include @@ -48,6 +48,6 @@ void Factory::setStaticFrameworkObjectIds() { DeviceHandlerFailureIsolation::powerConfirmationId = objects::NO_OBJECT; - TmPacketStored::timeStamperId = objects::NO_OBJECT; + TmPacketBase::timeStamperId = objects::NO_OBJECT; } diff --git a/scripts/coverage.py b/scripts/coverage.py deleted file mode 100755 index b5bd7745..00000000 --- a/scripts/coverage.py +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -* -"""Small portable helper script to generate LCOV HTML coverage data""" -import os -import platform -import sys -import time -import argparse -import webbrowser -from typing import List - - -"""Copy this helper script into your project folder. It will try to determine a CMake build folder -and then attempt to build your project with coverage information. - -See Unittest documentation at https://egit.irs.uni-stuttgart.de/fsfw/fsfw for more -information how to set up the build folder. -""" -def main(): - - parser = argparse.ArgumentParser(description="Processing arguments for LCOV helper script.") - parser.add_argument( - '-o', '--open', action='store_true', help='Open coverage data in webbrowser' - ) - args = parser.parse_args() - - build_dir_list = [] - if not os.path.isfile('README.md'): - os.chdir('..') - for directory in os.listdir("."): - if os.path.isdir(directory): - os.chdir(directory) - check_for_cmake_build_dir(build_dir_list) - os.chdir("..") - - if len(build_dir_list) == 0: - print("No valid CMake build directory found. Trying to set up hosted build") - build_directory = 'build-Debug-Host' - os.mkdir(build_directory) - os.chdir(build_directory) - os.system('cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON ..') - os.chdir('..') - elif len(build_dir_list) == 1: - build_directory = build_dir_list[0] - else: - print("Multiple build directories found!") - build_directory = determine_build_dir(build_dir_list) - perform_lcov_operation(build_directory) - if os.path.isdir('fsfw-tests_coverage') and args.open: - webbrowser.open('fsfw-tests_coverage/index.html') - - -def check_for_cmake_build_dir(build_dir_dict: list): - if os.path.isfile("CMakeCache.txt"): - build_dir_dict.append(os.getcwd()) - - -def perform_lcov_operation(directory): - os.chdir(directory) - os.system("cmake --build . -- fsfw-tests_coverage -j") - - -def determine_build_dir(build_dir_list: List[str]): - build_directory = "" - for idx, directory in enumerate(build_dir_list): - print(f"{idx + 1}: {directory}") - while True: - idx = input("Pick the directory to perform LCOV HTML generation by index: ") - if not idx.isdigit(): - print("Invalid input!") - continue - - idx = int(idx) - if idx > len(build_dir_list) or idx < 1: - print("Invalid input!") - continue - build_directory = build_dir_list[idx - 1] - break - return build_directory - - -if __name__ == "__main__": - main() diff --git a/scripts/gen-unittest.sh b/scripts/gen-unittest.sh deleted file mode 100755 index 9ca8c399..00000000 --- a/scripts/gen-unittest.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -mkdir build-Unittest && cd build-Unittest -cmake -DFSFW_BUILD_UNITTESTS=ON -DFSFW_OSAL=host -DCMAKE_BUILD_TYPE=Debug .. diff --git a/scripts/helper.py b/scripts/helper.py new file mode 100755 index 00000000..5ceff8c4 --- /dev/null +++ b/scripts/helper.py @@ -0,0 +1,181 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -* +"""Small portable helper script to generate test or doc configuration for the +flight software framework +""" +import os +import argparse +import webbrowser +import shutil +import sys +from typing import List + + +UNITTEST_FOLDER_NAME = 'build-tests' +DOCS_FOLDER_NAME = 'build-docs' + + +def main(): + + parser = argparse.ArgumentParser(description="FSFW helper script") + choices = ('docs', 'tests') + parser.add_argument( + 'type', metavar='type', choices=choices, + help=f'Target type. Choices: {choices}' + ) + parser.add_argument( + '-a', '--all', action='store_true', + help='Create, build and open specified type' + ) + parser.add_argument( + '-c', '--create', action='store_true', + help='Create docs or test build configuration' + ) + parser.add_argument( + '-b', '--build', action='store_true', + help='Build the specified type' + ) + parser.add_argument( + '-o', '--open', action='store_true', + help='Open test or documentation data in webbrowser' + ) + + args = parser.parse_args() + if args.all: + args.build = True + args.create = True + args.open = True + elif not args.build and not args.create and not args.open: + print( + 'Please select at least one operation to perform. ' + 'Use helper.py -h for more information' + ) + sys.exit(1) + + # This script can be called from root and from script folder + if not os.path.isfile('README.md'): + os.chdir('..') + build_dir_list = [] + if not args.create: + build_dir_list = build_build_dir_list() + + if args.type == 'tests': + handle_tests_type(args, build_dir_list) + elif args.type == 'docs': + handle_docs_type(args, build_dir_list) + else: + print('Invalid or unknown type') + sys.exit(1) + + +def handle_docs_type(args, build_dir_list: list): + if args.create: + shutil.rmtree(DOCS_FOLDER_NAME) + create_docs_build_cfg() + build_directory = DOCS_FOLDER_NAME + elif len(build_dir_list) == 0: + print('No valid CMake docs build directory found. Trying to set up docs build system') + shutil.rmtree(DOCS_FOLDER_NAME) + create_docs_build_cfg() + build_directory = DOCS_FOLDER_NAME + elif len(build_dir_list) == 1: + build_directory = build_dir_list[0] + else: + print("Multiple build directories found!") + build_directory = determine_build_dir(build_dir_list) + os.chdir(build_directory) + if args.build: + os.system('cmake --build . -j') + if args.open: + if not os.path.isfile('docs/sphinx/index.html'): + print( + "No Sphinx documentation file detected. " + "Try to build it first with the -b argument" + ) + sys.exit(1) + webbrowser.open('docs/sphinx/index.html') + + +def handle_tests_type(args, build_dir_list: list): + if args.create: + shutil.rmtree(UNITTEST_FOLDER_NAME) + create_tests_build_cfg() + build_directory = UNITTEST_FOLDER_NAME + elif len(build_dir_list) == 0: + print( + 'No valid CMake tests build directory found. ' + 'Trying to set up test build system' + ) + create_tests_build_cfg() + build_directory = UNITTEST_FOLDER_NAME + elif len(build_dir_list) == 1: + build_directory = build_dir_list[0] + else: + print("Multiple build directories found!") + build_directory = determine_build_dir(build_dir_list) + os.chdir(build_directory) + if args.build: + perform_lcov_operation(build_directory) + if args.open: + if not os.path.isdir('fsfw-tests_coverage'): + print("No Unittest folder detected. Try to build them first with the -b argument") + sys.exit(1) + webbrowser.open('fsfw-tests_coverage/index.html') + + +def create_tests_build_cfg(): + os.mkdir(UNITTEST_FOLDER_NAME) + os.chdir(UNITTEST_FOLDER_NAME) + os.system('cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON ..') + os.chdir('..') + + +def create_docs_build_cfg(): + os.mkdir(DOCS_FOLDER_NAME) + os.chdir(DOCS_FOLDER_NAME) + os.system('cmake -DFSFW_OSAL=host -DFSFW_BUILD_DOCS=ON ..') + os.chdir('..') + + +def build_build_dir_list() -> list: + build_dir_list = [] + for directory in os.listdir("."): + if os.path.isdir(directory): + os.chdir(directory) + build_dir_list = check_for_cmake_build_dir(build_dir_list) + os.chdir("..") + return build_dir_list + + +def check_for_cmake_build_dir(build_dir_list: list) -> list: + if os.path.isfile("CMakeCache.txt"): + build_dir_list.append(os.getcwd()) + return build_dir_list + + +def perform_lcov_operation(directory): + os.chdir(directory) + os.system("cmake --build . -- fsfw-tests_coverage -j") + + +def determine_build_dir(build_dir_list: List[str]): + build_directory = "" + for idx, directory in enumerate(build_dir_list): + print(f"{idx + 1}: {directory}") + while True: + idx = input("Pick the directory: ") + if not idx.isdigit(): + print("Invalid input!") + continue + + idx = int(idx) + if idx > len(build_dir_list) or idx < 1: + print("Invalid input!") + continue + build_directory = build_dir_list[idx - 1] + break + return build_directory + + +if __name__ == "__main__": + main() diff --git a/tests/src/fsfw_tests/integration/task/CMakeLists.txt b/tests/src/fsfw_tests/integration/task/CMakeLists.txt index 0402d093..4cd481bf 100644 --- a/tests/src/fsfw_tests/integration/task/CMakeLists.txt +++ b/tests/src/fsfw_tests/integration/task/CMakeLists.txt @@ -1,3 +1,3 @@ -target_sources(${TARGET_NAME} PRIVATE +target_sources(${LIB_FSFW_NAME} PRIVATE TestTask.cpp ) \ No newline at end of file From fd7581f8babebdd9eeb13cc4a9800dbb80f893a4 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 1 Dec 2021 16:08:28 +0100 Subject: [PATCH 116/131] Added formatting scripts 1. Added .clang-format file which contains information for the clang-format tool on how to format source files 2. Added shell helper script to apply all changes on HAL soures, test sources and primary sources The shell script was not applied yet. This should be done shortly before introducing the release. Also, it might be good idea to provide instructions on how to set up the formatter for Eclipse --- .clang-format | 7 +++++++ scripts/apply-clang-format.sh | 8 ++++++++ 2 files changed, 15 insertions(+) create mode 100644 .clang-format create mode 100755 scripts/apply-clang-format.sh diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..a3cf6a1f --- /dev/null +++ b/.clang-format @@ -0,0 +1,7 @@ +--- +BasedOnStyle: Google +IndentWidth: 2 +--- +Language: Cpp +ColumnWidth: 100 +--- diff --git a/scripts/apply-clang-format.sh b/scripts/apply-clang-format.sh new file mode 100755 index 00000000..36f5ee92 --- /dev/null +++ b/scripts/apply-clang-format.sh @@ -0,0 +1,8 @@ +#!/bin/bash +if [[ ! -f README.md ]]; then + cd .. +fi + +find ./src -iname *.h -o -iname *.cpp | xargs clang-format --style=file -i +find ./hal -iname *.h -o -iname *.cpp | xargs clang-format --style=file -i +find ./tests -iname *.h -o -iname *.cpp | xargs clang-format --style=file -i From 15dddd7fc407fa72d752c76c64279944986b2dc1 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 1 Dec 2021 16:17:27 +0100 Subject: [PATCH 117/131] small README section for formatting --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 312bc077..5feda92c 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,12 @@ cmake --build . -- fsfw-tests_coverage -j The `coverage.py` script located in the `script` folder can also be used to do this conveniently. +## Formatting the sources + +The formatting is done by the `clang-format` tool. The configuration is contained within the +`.clang-format` file in the repository root. As long as `clang-format` is installed, you +can run the `apply-clang-format.sh` helper script to format all source files consistently. + ## Index [1. High-level overview](doc/README-highlevel.md#top)
From df45f02c393bde14b232d1668f6004256615e68a Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 3 Dec 2021 14:55:00 +0100 Subject: [PATCH 118/131] script fixes, odd behaviour --- docs/conf.py | 2 +- scripts/helper.py | 20 +++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 44fd90c4..62b17192 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -53,4 +53,4 @@ html_theme = 'alabaster' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] \ No newline at end of file +html_static_path = [] \ No newline at end of file diff --git a/scripts/helper.py b/scripts/helper.py index 5ceff8c4..5c5c202b 100755 --- a/scripts/helper.py +++ b/scripts/helper.py @@ -8,6 +8,7 @@ import argparse import webbrowser import shutil import sys +import time from typing import List @@ -70,7 +71,8 @@ def main(): def handle_docs_type(args, build_dir_list: list): if args.create: - shutil.rmtree(DOCS_FOLDER_NAME) + if os.path.exists(DOCS_FOLDER_NAME): + shutil.rmtree(DOCS_FOLDER_NAME) create_docs_build_cfg() build_directory = DOCS_FOLDER_NAME elif len(build_dir_list) == 0: @@ -88,17 +90,21 @@ def handle_docs_type(args, build_dir_list: list): os.system('cmake --build . -j') if args.open: if not os.path.isfile('docs/sphinx/index.html'): - print( - "No Sphinx documentation file detected. " - "Try to build it first with the -b argument" - ) - sys.exit(1) + # try again.. + os.system('cmake --build . -j') + if not os.path.isfile('docs/sphinx/index.html'): + print( + "No Sphinx documentation file detected. " + "Try to build it first with the -b argument" + ) + sys.exit(1) webbrowser.open('docs/sphinx/index.html') def handle_tests_type(args, build_dir_list: list): if args.create: - shutil.rmtree(UNITTEST_FOLDER_NAME) + if os.path.exists(UNITTEST_FOLDER_NAME): + shutil.rmtree(UNITTEST_FOLDER_NAME) create_tests_build_cfg() build_directory = UNITTEST_FOLDER_NAME elif len(build_dir_list) == 0: From 4a5204d6f614053fea03bc10eea18613222000c0 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 6 Dec 2021 14:46:31 +0100 Subject: [PATCH 119/131] small fix for helper script --- scripts/helper.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/helper.py b/scripts/helper.py index 5c5c202b..0bb430ee 100755 --- a/scripts/helper.py +++ b/scripts/helper.py @@ -121,7 +121,7 @@ def handle_tests_type(args, build_dir_list: list): build_directory = determine_build_dir(build_dir_list) os.chdir(build_directory) if args.build: - perform_lcov_operation(build_directory) + perform_lcov_operation(build_directory, False) if args.open: if not os.path.isdir('fsfw-tests_coverage'): print("No Unittest folder detected. Try to build them first with the -b argument") @@ -159,8 +159,9 @@ def check_for_cmake_build_dir(build_dir_list: list) -> list: return build_dir_list -def perform_lcov_operation(directory): - os.chdir(directory) +def perform_lcov_operation(directory: str, chdir: bool): + if chdir: + os.chdir(directory) os.system("cmake --build . -- fsfw-tests_coverage -j") From e952a82b6565292d649260b1441383b1d484f706 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 7 Dec 2021 13:14:57 +0100 Subject: [PATCH 120/131] small tweaks and fixes --- .clang-format | 2 +- scripts/apply-clang-format.sh | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.clang-format b/.clang-format index a3cf6a1f..ec53b72b 100644 --- a/.clang-format +++ b/.clang-format @@ -3,5 +3,5 @@ BasedOnStyle: Google IndentWidth: 2 --- Language: Cpp -ColumnWidth: 100 +ColumnLimit: 100 --- diff --git a/scripts/apply-clang-format.sh b/scripts/apply-clang-format.sh index 36f5ee92..27202324 100755 --- a/scripts/apply-clang-format.sh +++ b/scripts/apply-clang-format.sh @@ -3,6 +3,6 @@ if [[ ! -f README.md ]]; then cd .. fi -find ./src -iname *.h -o -iname *.cpp | xargs clang-format --style=file -i -find ./hal -iname *.h -o -iname *.cpp | xargs clang-format --style=file -i -find ./tests -iname *.h -o -iname *.cpp | xargs clang-format --style=file -i +find ./src -iname *.h -o -iname *.cpp -o -iname *.c | xargs clang-format --style=file -i +find ./hal -iname *.h -o -iname *.cpp -o -iname *.c | xargs clang-format --style=file -i +find ./tests -iname *.h -o -iname *.cpp -o -iname *.c | xargs clang-format --style=file -i From e4999fe01c0446f9820ceede55be3970aa22bbad Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 8 Dec 2021 17:22:53 +0100 Subject: [PATCH 121/131] fixes for windows --- hal/src/fsfw_hal/common/gpio/gpioDefinitions.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h b/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h index c6f21195..e5446c82 100644 --- a/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h +++ b/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h @@ -16,8 +16,8 @@ enum Levels: uint8_t { }; enum Direction: uint8_t { - IN = 0, - OUT = 1 + DIR_IN = 0, + DIR_OUT = 1 }; enum GpioOperation { @@ -30,7 +30,7 @@ enum class GpioTypes { GPIO_REGULAR_BY_CHIP, GPIO_REGULAR_BY_LABEL, GPIO_REGULAR_BY_LINE_NAME, - CALLBACK + TYPE_CALLBACK }; static constexpr gpioId_t NO_GPIO = -1; @@ -68,7 +68,7 @@ public: // Can be used to cast GpioBase to a concrete child implementation gpio::GpioTypes gpioType = gpio::GpioTypes::NONE; std::string consumer; - gpio::Direction direction = gpio::Direction::IN; + gpio::Direction direction = gpio::Direction::DIR_IN; gpio::Levels initValue = gpio::Levels::NONE; }; @@ -92,7 +92,7 @@ class GpiodRegularByChip: public GpiodRegularBase { public: GpiodRegularByChip() : GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP, - std::string(), gpio::Direction::IN, gpio::LOW, 0) { + std::string(), gpio::Direction::DIR_IN, gpio::LOW, 0) { } GpiodRegularByChip(std::string chipname_, int lineNum_, std::string consumer_, @@ -104,7 +104,7 @@ public: GpiodRegularByChip(std::string chipname_, int lineNum_, std::string consumer_) : GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP, consumer_, - gpio::Direction::IN, gpio::LOW, lineNum_), + gpio::Direction::DIR_IN, gpio::LOW, lineNum_), chipname(chipname_) { } @@ -122,7 +122,7 @@ public: GpiodRegularByLabel(std::string label_, int lineNum_, std::string consumer_) : GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL, consumer_, - gpio::Direction::IN, gpio::LOW, lineNum_), + gpio::Direction::DIR_IN, gpio::LOW, lineNum_), label(label_) { } @@ -144,7 +144,7 @@ public: GpiodRegularByLineName(std::string lineName_, std::string consumer_) : GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME, consumer_, - gpio::Direction::IN, gpio::LOW), lineName(lineName_) { + gpio::Direction::DIR_IN, gpio::LOW), lineName(lineName_) { } std::string lineName; @@ -154,7 +154,7 @@ class GpioCallback: public GpioBase { public: GpioCallback(std::string consumer, gpio::Direction direction_, gpio::Levels initValue_, gpio::gpio_cb_t callback, void* callbackArgs): - GpioBase(gpio::GpioTypes::CALLBACK, consumer, direction_, initValue_), + GpioBase(gpio::GpioTypes::TYPE_CALLBACK, consumer, direction_, initValue_), callback(callback), callbackArgs(callbackArgs) {} gpio::gpio_cb_t callback = nullptr; From bda02b464a2ad00b1a8e373d4c6b80b0a7c8de95 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 9 Dec 2021 13:42:54 +0100 Subject: [PATCH 122/131] linux HAL fixes --- hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp index 020ba964..e2e4e46d 100644 --- a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp +++ b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp @@ -75,7 +75,7 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) { configureGpioByLineName(gpioConfig.first, *regularGpio); break; } - case(gpio::GpioTypes::CALLBACK): { + case(gpio::GpioTypes::TYPE_CALLBACK): { auto gpioCallback = dynamic_cast(gpioConfig.second); if(gpioCallback->callback == nullptr) { return GPIO_INVALID_INSTANCE; @@ -163,12 +163,12 @@ ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, struct gpiod consumer = regularGpio.consumer; /* Configure direction and add a description to the GPIO */ switch (direction) { - case(gpio::OUT): { + case(gpio::DIR_OUT): { result = gpiod_line_request_output(lineHandle, consumer.c_str(), regularGpio.initValue); break; } - case(gpio::IN): { + case(gpio::DIR_IN): { result = gpiod_line_request_input(lineHandle, consumer.c_str()); break; } @@ -330,7 +330,7 @@ ReturnValue_t LinuxLibgpioIF::checkForConflicts(GpioMap& mapToAdd){ } break; } - case(gpio::GpioTypes::CALLBACK): { + case(gpio::GpioTypes::TYPE_CALLBACK): { auto callbackGpio = dynamic_cast(gpioConfig.second); if(callbackGpio == nullptr) { return GPIO_TYPE_FAILURE; @@ -371,13 +371,13 @@ ReturnValue_t LinuxLibgpioIF::checkForConflictsById(gpioId_t gpioIdToCheck, case(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP): case(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL): case(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME): { - if(gpioType == gpio::GpioTypes::NONE or gpioType == gpio::GpioTypes::CALLBACK) { + if(gpioType == gpio::GpioTypes::NONE or gpioType == gpio::GpioTypes::TYPE_CALLBACK) { eraseDuplicateDifferentType = true; } break; } - case(gpio::GpioTypes::CALLBACK): { - if(gpioType != gpio::GpioTypes::CALLBACK) { + case(gpio::GpioTypes::TYPE_CALLBACK): { + if(gpioType != gpio::GpioTypes::TYPE_CALLBACK) { eraseDuplicateDifferentType = true; } } From 661b7b44e070f20b0162c530ed315abaa8bcbb41 Mon Sep 17 00:00:00 2001 From: David Date: Sun, 12 Dec 2021 18:53:29 +0100 Subject: [PATCH 123/131] improved win32 define --- src/fsfw/globalfunctions/timevalOperations.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fsfw/globalfunctions/timevalOperations.h b/src/fsfw/globalfunctions/timevalOperations.h index db68f330..41f4e52f 100644 --- a/src/fsfw/globalfunctions/timevalOperations.h +++ b/src/fsfw/globalfunctions/timevalOperations.h @@ -2,8 +2,9 @@ #define TIMEVALOPERATIONS_H_ #include +#include -#ifdef WIN32 +#ifdef PLATFORM_WIN #include #else #include From 9a858eb54c5603ccd3cbd2423cdaf87b20f0c0c4 Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Tue, 14 Dec 2021 19:39:38 +0100 Subject: [PATCH 124/131] introduced protected function to break doSendRead --- src/fsfw/devicehandlers/DeviceHandlerBase.cpp | 9 +++++++++ src/fsfw/devicehandlers/DeviceHandlerBase.h | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp index 535113fd..a4e30448 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp @@ -684,6 +684,11 @@ void DeviceHandlerBase::doGetWrite() { void DeviceHandlerBase::doSendRead() { ReturnValue_t result; + result = doSendReadHook(); + if (result != RETURN_OK){ + return; + } + size_t replyLen = 0; if(cookieInfo.pendingCommand != deviceCommandMap.end()) { replyLen = getNextReplyLength(cookieInfo.pendingCommand->first); @@ -950,6 +955,10 @@ void DeviceHandlerBase::commandSwitch(ReturnValue_t onOff) { } } +ReturnValue_t DeviceHandlerBase::doSendReadHook() { + return RETURN_OK; +} + ReturnValue_t DeviceHandlerBase::getSwitches(const uint8_t **switches, uint8_t *numberOfSwitches) { return DeviceHandlerBase::NO_SWITCH; diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.h b/src/fsfw/devicehandlers/DeviceHandlerBase.h index 4bc54ac4..1de70ad5 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.h +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.h @@ -1094,6 +1094,12 @@ protected: */ void commandSwitch(ReturnValue_t onOff); + /** + * @brief This function can be used to insert device specific code during the do-send-read + * step. + */ + virtual ReturnValue_t doSendReadHook(); + private: /** From 54e56ec522f485525de7b17458b22132003c5047 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 15 Dec 2021 11:18:47 +0100 Subject: [PATCH 125/131] LIS3 bugfix --- hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp index 1a61bfe2..6176b1bb 100644 --- a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp +++ b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp @@ -283,7 +283,7 @@ ReturnValue_t MgmLIS3MDLHandler::interpretDeviceReply(DeviceCommandId_t id, int16_t mgmMeasurementRawZ = packet[MGMLIS3MDL::Z_HIGHBYTE_IDX] << 8 | packet[MGMLIS3MDL::Z_LOWBYTE_IDX] ; - /* Target value in microtesla */ + // Target value in microtesla float mgmX = static_cast(mgmMeasurementRawX) * sensitivityFactor * MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; float mgmY = static_cast(mgmMeasurementRawY) * sensitivityFactor @@ -339,7 +339,7 @@ ReturnValue_t MgmLIS3MDLHandler::interpretDeviceReply(DeviceCommandId_t id, case MGMLIS3MDL::READ_TEMPERATURE: { int16_t tempValueRaw = packet[2] << 8 | packet[1]; float tempValue = 25.0 + ((static_cast(tempValueRaw)) / 8.0); - #if FSFW_HAL_LIS3MDL_MGM_DEBUG == 1 +#if FSFW_HAL_LIS3MDL_MGM_DEBUG == 1 if(debugDivider->check()) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "MGMHandlerLIS3: Temperature: " << tempValue << " C" << @@ -489,7 +489,7 @@ ReturnValue_t MgmLIS3MDLHandler::prepareCtrlRegisterWrite() { } void MgmLIS3MDLHandler::doTransition(Mode_t modeFrom, Submode_t subModeFrom) { - + DeviceHandlerBase::doTransition(modeFrom, subModeFrom); } uint32_t MgmLIS3MDLHandler::getTransitionDelayMs(Mode_t from, Mode_t to) { From ddcb37a81be135c858b2eb210ad259abef2ad3de Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 15 Dec 2021 14:16:56 +0100 Subject: [PATCH 126/131] more diagnostic output --- src/fsfw/datapoollocal/LocalPoolObjectBase.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/fsfw/datapoollocal/LocalPoolObjectBase.cpp b/src/fsfw/datapoollocal/LocalPoolObjectBase.cpp index 96b849c6..644220a5 100644 --- a/src/fsfw/datapoollocal/LocalPoolObjectBase.cpp +++ b/src/fsfw/datapoollocal/LocalPoolObjectBase.cpp @@ -46,11 +46,12 @@ LocalPoolObjectBase::LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId, HasLocalDataPoolIF* hkOwner = ObjectManager::instance()->get(poolOwner); if(hkOwner == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "LocalPoolVariable: The supplied pool owner did not implement the correct " - "interface HasLocalDataPoolIF!" << std::endl; + sif::error << "LocalPoolVariable: The supplied pool owner 0x" << std::hex << + poolOwner << " did not implement the correct interface HasLocalDataPoolIF" << + std::endl; #else - sif::printError( "LocalPoolVariable: The supplied pool owner did not implement the correct " - "interface HasLocalDataPoolIF!\n"); + sif::printError( "LocalPoolVariable: The supplied pool owner 0x%08x did not implement the correct " + "interface HasLocalDataPoolIF\n", poolOwner); #endif return; } From a45fb1bb1ff839c487581e1b787db966a1cf80cb Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 15 Dec 2021 14:19:15 +0100 Subject: [PATCH 127/131] go back to deciaml as well --- src/fsfw/datapoollocal/LocalPoolObjectBase.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fsfw/datapoollocal/LocalPoolObjectBase.cpp b/src/fsfw/datapoollocal/LocalPoolObjectBase.cpp index 644220a5..ba0f74d7 100644 --- a/src/fsfw/datapoollocal/LocalPoolObjectBase.cpp +++ b/src/fsfw/datapoollocal/LocalPoolObjectBase.cpp @@ -47,8 +47,8 @@ LocalPoolObjectBase::LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId, if(hkOwner == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "LocalPoolVariable: The supplied pool owner 0x" << std::hex << - poolOwner << " did not implement the correct interface HasLocalDataPoolIF" << - std::endl; + poolOwner << std::dec << " did not implement the correct interface " << + "HasLocalDataPoolIF" << std::endl; #else sif::printError( "LocalPoolVariable: The supplied pool owner 0x%08x did not implement the correct " "interface HasLocalDataPoolIF\n", poolOwner); From e5b568bc2b0b819bfb5c9dc90026d534852df4ff Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 17 Dec 2021 13:46:51 +0100 Subject: [PATCH 128/131] op divider fixes --- hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp | 2 +- hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp | 2 +- hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp index d27351d7..90bf357a 100644 --- a/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp +++ b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp @@ -9,7 +9,7 @@ GyroHandlerL3GD20H::GyroHandlerL3GD20H(object_id_t objectId, object_id_t deviceC DeviceHandlerBase(objectId, deviceCommunication, comCookie), transitionDelayMs(transitionDelayMs), dataset(this) { #if FSFW_HAL_L3GD20_GYRO_DEBUG == 1 - debugDivider = new PeriodicOperationDivider(3); + debugDivider = new PeriodicOperationDivider(10); #endif } diff --git a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp index 6176b1bb..b4a951d2 100644 --- a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp +++ b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp @@ -12,7 +12,7 @@ MgmLIS3MDLHandler::MgmLIS3MDLHandler(object_id_t objectId, object_id_t deviceCom DeviceHandlerBase(objectId, deviceCommunication, comCookie), dataset(this), transitionDelay(transitionDelay) { #if FSFW_HAL_LIS3MDL_MGM_DEBUG == 1 - debugDivider = new PeriodicOperationDivider(3); + debugDivider = new PeriodicOperationDivider(10); #endif // Set to default values right away registers[0] = MGMLIS3MDL::CTRL_REG1_DEFAULT; diff --git a/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp b/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp index db4ea607..78fbdafb 100644 --- a/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp +++ b/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp @@ -12,7 +12,7 @@ MgmRM3100Handler::MgmRM3100Handler(object_id_t objectId, DeviceHandlerBase(objectId, deviceCommunication, comCookie), primaryDataset(this), transitionDelay(transitionDelay) { #if FSFW_HAL_RM3100_MGM_DEBUG == 1 - debugDivider = new PeriodicOperationDivider(3); + debugDivider = new PeriodicOperationDivider(10); #endif } From eb58a8d954139918f518fcf2d3929601e7089485 Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Sun, 19 Dec 2021 11:33:12 +0100 Subject: [PATCH 129/131] virtual printset function --- src/fsfw/datapoollocal/LocalPoolDataSetBase.cpp | 4 ++++ src/fsfw/datapoollocal/LocalPoolDataSetBase.h | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/fsfw/datapoollocal/LocalPoolDataSetBase.cpp b/src/fsfw/datapoollocal/LocalPoolDataSetBase.cpp index d1ac0c7f..3f68a881 100644 --- a/src/fsfw/datapoollocal/LocalPoolDataSetBase.cpp +++ b/src/fsfw/datapoollocal/LocalPoolDataSetBase.cpp @@ -321,3 +321,7 @@ float LocalPoolDataSetBase::getCollectionInterval() const { return 0.0; } } + +void LocalPoolDataSetBase::printSet() { + return; +} diff --git a/src/fsfw/datapoollocal/LocalPoolDataSetBase.h b/src/fsfw/datapoollocal/LocalPoolDataSetBase.h index 822e2cb8..aa99f5b5 100644 --- a/src/fsfw/datapoollocal/LocalPoolDataSetBase.h +++ b/src/fsfw/datapoollocal/LocalPoolDataSetBase.h @@ -176,6 +176,11 @@ public: */ float getCollectionInterval() const; + /** + * @brief Can be overwritten by a specific implementation of a dataset to print the set. + */ + virtual void printSet(); + protected: sid_t sid; //! This mutex is used if the data is created by one object only. @@ -234,7 +239,6 @@ protected: PeriodicHousekeepingHelper* periodicHelper = nullptr; LocalDataPoolManager* poolManager = nullptr; - }; From 5214f8a449d195ecfa69f978cc0fe001ef76130a Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 11 Jan 2022 14:44:45 +0100 Subject: [PATCH 130/131] bugfix for updated HAL --- hal/src/fsfw_hal/linux/rpi/GpioRPi.cpp | 2 +- hal/src/fsfw_hal/linux/rpi/GpioRPi.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hal/src/fsfw_hal/linux/rpi/GpioRPi.cpp b/hal/src/fsfw_hal/linux/rpi/GpioRPi.cpp index e1c274c0..b42a4c89 100644 --- a/hal/src/fsfw_hal/linux/rpi/GpioRPi.cpp +++ b/hal/src/fsfw_hal/linux/rpi/GpioRPi.cpp @@ -7,7 +7,7 @@ ReturnValue_t gpio::createRpiGpioConfig(GpioCookie* cookie, gpioId_t gpioId, int bcmPin, - std::string consumer, gpio::Direction direction, int initValue) { + std::string consumer, gpio::Direction direction, gpio::Levels initValue) { if(cookie == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } diff --git a/hal/src/fsfw_hal/linux/rpi/GpioRPi.h b/hal/src/fsfw_hal/linux/rpi/GpioRPi.h index 54917e6d..d13faef4 100644 --- a/hal/src/fsfw_hal/linux/rpi/GpioRPi.h +++ b/hal/src/fsfw_hal/linux/rpi/GpioRPi.h @@ -20,7 +20,7 @@ namespace gpio { * @return */ ReturnValue_t createRpiGpioConfig(GpioCookie* cookie, gpioId_t gpioId, int bcmPin, - std::string consumer, gpio::Direction direction, int initValue); + std::string consumer, gpio::Direction direction, gpio::Levels initValue); } #endif /* BSP_RPI_GPIO_GPIORPI_H_ */ From c1e0bcee6db652d6c474c87a4099e61ecf86b694 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sat, 15 Jan 2022 13:03:53 +0100 Subject: [PATCH 131/131] added additional conversion function --- src/fsfw/osal/linux/Clock.cpp | 2 -- src/fsfw/timemanager/Clock.h | 8 ++++++++ src/fsfw/timemanager/ClockCommon.cpp | 14 ++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/fsfw/osal/linux/Clock.cpp b/src/fsfw/osal/linux/Clock.cpp index d79c72be..8f133b46 100644 --- a/src/fsfw/osal/linux/Clock.cpp +++ b/src/fsfw/osal/linux/Clock.cpp @@ -108,8 +108,6 @@ ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) { return HasReturnvaluesIF::RETURN_OK; } - - ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { timespec timeUnix; int status = clock_gettime(CLOCK_REALTIME,&timeUnix); diff --git a/src/fsfw/timemanager/Clock.h b/src/fsfw/timemanager/Clock.h index b1d6bfaf..7116adb7 100644 --- a/src/fsfw/timemanager/Clock.h +++ b/src/fsfw/timemanager/Clock.h @@ -99,6 +99,14 @@ public: */ static ReturnValue_t getDateAndTime(TimeOfDay_t *time); + /** + * Convert to time of day struct given the POSIX timeval struct + * @param from + * @param to + * @return + */ + static ReturnValue_t convertTimevalToTimeOfDay(const timeval *from, + TimeOfDay_t *to); /** * Converts a time of day struct to POSIX seconds. * @param time The time of day as input diff --git a/src/fsfw/timemanager/ClockCommon.cpp b/src/fsfw/timemanager/ClockCommon.cpp index 82c65b96..86866d7a 100644 --- a/src/fsfw/timemanager/ClockCommon.cpp +++ b/src/fsfw/timemanager/ClockCommon.cpp @@ -42,6 +42,20 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t *leapSeconds_) { return HasReturnvaluesIF::RETURN_OK; } +ReturnValue_t Clock::convertTimevalToTimeOfDay(const timeval* from, TimeOfDay_t* to) { + struct tm* timeInfo; + timeInfo = gmtime(&from->tv_sec); + to->year = timeInfo->tm_year + 1900; + to->month = timeInfo->tm_mon+1; + to->day = timeInfo->tm_mday; + to->hour = timeInfo->tm_hour; + to->minute = timeInfo->tm_min; + to->second = timeInfo->tm_sec; + to->usecond = from->tv_usec; + return HasReturnvaluesIF::RETURN_OK; +} + + ReturnValue_t Clock::checkOrCreateClockMutex() { if (timeMutex == nullptr) { MutexFactory *mutexFactory = MutexFactory::instance();