From 10f7185e8137b3674a7ee5c24dfbaf8035d2251d Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 19 Jul 2021 13:08:40 +0200 Subject: [PATCH 01/16] 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 02/16] 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 03/16] 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 04/16] 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 05/16] 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 06/16] 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 07/16] 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 08/16] 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 09/16] 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 10/16] 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 11/16] 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 12/16] 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 13/16] 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 14/16] 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 15/16] 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 16/16] 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; }