From 63d5bf0dc7ca4762e240832394b0b0cfb97c0978 Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Thu, 15 Aug 2024 16:33:57 -0700 Subject: [PATCH 01/10] FPP v2.1.0 (#2811) * Update fpp version * Update FPP version to v2.1.0 --- requirements.txt | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/requirements.txt b/requirements.txt index c3893fb9ab..a512e7db45 100644 --- a/requirements.txt +++ b/requirements.txt @@ -18,18 +18,18 @@ fprime-fpl-convert-xml==1.0.3 fprime-fpl-extract-xml==1.0.3 fprime-fpl-layout==1.0.3 fprime-fpl-write-pic==1.0.3 -fprime-fpp-check==2.1.0a12 -fprime-fpp-depend==2.1.0a12 -fprime-fpp-filenames==2.1.0a12 -fprime-fpp-format==2.1.0a12 -fprime-fpp-from-xml==2.1.0a12 -fprime-fpp-locate-defs==2.1.0a12 -fprime-fpp-locate-uses==2.1.0a12 -fprime-fpp-syntax==2.1.0a12 -fprime-fpp-to-cpp==2.1.0a12 -fprime-fpp-to-dict==2.1.0a12 -fprime-fpp-to-json==2.1.0a12 -fprime-fpp-to-xml==2.1.0a12 +fprime-fpp-check==2.1.0 +fprime-fpp-depend==2.1.0 +fprime-fpp-filenames==2.1.0 +fprime-fpp-format==2.1.0 +fprime-fpp-from-xml==2.1.0 +fprime-fpp-locate-defs==2.1.0 +fprime-fpp-locate-uses==2.1.0 +fprime-fpp-syntax==2.1.0 +fprime-fpp-to-cpp==2.1.0 +fprime-fpp-to-dict==2.1.0 +fprime-fpp-to-json==2.1.0 +fprime-fpp-to-xml==2.1.0 fprime-gds==3.4.3 fprime-tools==3.4.4 fprime-visual==1.0.2 From 7159e7e34710a70b14144cdd8cabccdd145fa1c8 Mon Sep 17 00:00:00 2001 From: M Starch Date: Thu, 15 Aug 2024 18:53:36 -0700 Subject: [PATCH 02/10] Implements #2723: Adds Os::Console to replace Os::Log (#2831) * Initial logging refactor - WIP * Removing LogAssert as it is not used * Working on Fw::Logger rewrite * Initial Os::Console refactor * Fixing Fw::Logger unit tests * Fixing up UT build * Adding Os::Stub::Console implementation * Added interface UTs * Adding posix console tests * Fixing Linux errors * Spelling * Initial review requests * Fixing RPI build issues * Fixing codeql errors * Fixing code QL * Validating 'message' parameter --- Drv/Ip/IpSocket.cpp | 3 +- Drv/Ip/SocketReadTask.cpp | 6 +- Drv/Ip/TcpClientSocket.cpp | 2 +- Drv/Ip/TcpServerSocket.cpp | 4 +- Drv/Ip/UdpSocket.cpp | 12 +- Drv/Ip/test/ut/TestTcp.cpp | 4 +- Drv/Ip/test/ut/TestUdp.cpp | 4 +- Drv/LinuxI2cDriver/LinuxI2cDriver.cpp | 36 +- Drv/TcpClient/test/ut/TcpClientTester.cpp | 5 +- Drv/TcpServer/test/ut/TcpServerTester.cpp | 5 +- Drv/Udp/test/ut/UdpTester.cpp | 4 +- Fw/FilePacket/PathName.cpp | 2 +- Fw/Logger/CMakeLists.txt | 3 +- Fw/Logger/LogAssert.cpp | 116 ------- Fw/Logger/LogAssert.hpp | 38 --- Fw/Logger/Logger.cpp | 45 +-- Fw/Logger/Logger.hpp | 120 +++---- Fw/Logger/test/ut/FakeLogger.cpp | 79 +---- Fw/Logger/test/ut/FakeLogger.hpp | 113 ++----- Fw/Logger/test/ut/LoggerMain.cpp | 35 +- Fw/Logger/test/ut/LoggerRules.cpp | 310 ++++++++++-------- Fw/Logger/test/ut/LoggerRules.hpp | 104 +++--- Fw/Obj/SimpleObjRegistry.cpp | 22 +- Fw/Port/OutputPortBase.cpp | 2 +- Fw/Port/PortBase.cpp | 4 +- Fw/Types/StringBase.cpp | 19 +- Fw/Types/StringBase.hpp | 2 + Fw/Types/StringUtils.cpp | 20 +- Fw/Types/StringUtils.hpp | 27 ++ Fw/Types/test/ut/TypesTest.cpp | 14 +- Os/CMakeLists.txt | 2 +- Os/Console.cpp | 69 ++++ Os/Console.hpp | 140 ++++++++ Os/File.hpp | 2 +- Os/Log.hpp | 52 --- Os/LogDefault.cpp | 12 +- Os/LogPrintf.cpp | 36 -- Os/Posix/CMakeLists.txt | 21 ++ Os/Posix/Console.cpp | 46 +++ Os/Posix/Console.hpp | 85 +++++ Os/Posix/DefaultConsole.cpp | 13 + Os/Posix/Task.cpp | 70 ++-- Os/Posix/test/ut/PosixConsoleTests.cpp | 29 ++ Os/Pthreads/MaxHeap/MaxHeap.cpp | 24 +- Os/Stub/CMakeLists.txt | 26 ++ Os/Stub/Console.cpp | 23 ++ Os/Stub/Console.hpp | 68 ++++ Os/Stub/DefaultConsole.cpp | 13 + Os/Stub/test/Console.cpp | 41 +++ Os/Stub/test/Console.hpp | 98 ++++++ Os/Stub/test/DefaultConsole.cpp | 13 + Os/Stub/test/ut/StubConsoleTests.cpp | 53 +++ RPI/Main.cpp | 3 +- RPI/Top/RPITopologyDefs.hpp | 2 +- RPI/Top/instances.fpp | 16 +- Ref/Main.cpp | 4 + Ref/RecvBuffApp/RecvBuffComponentImpl.cpp | 2 +- Ref/SendBuffApp/SendBuffComponentImpl.cpp | 2 +- Ref/Top/RefTopology.cpp | 6 +- Svc/ActiveRateGroup/ActiveRateGroup.cpp | 2 +- Svc/ActiveTextLogger/ActiveTextLogger.cpp | 2 +- Svc/ActiveTextLogger/LogFile.cpp | 2 +- .../test/ut/ActiveTextLoggerTester.cpp | 4 +- .../AssertFatalAdapterComponentImpl.cpp | 2 +- .../test/ut/AssertFatalAdapterTester.cpp | 2 +- Svc/ComLogger/ComLogger.cpp | 6 +- Svc/Deframer/Deframer.cpp | 6 +- .../ut-fprime-protocol/DeframerTestMain.cpp | 2 +- .../FatalHandlerComponentBaremetalImpl.cpp | 4 +- .../FatalHandlerComponentLinuxImpl.cpp | 4 +- .../FatalHandlerComponentVxWorksImpl.cpp | 2 +- Svc/FileDownlink/FileDownlink.cpp | 12 +- Svc/Framer/Framer.cpp | 2 +- Svc/Framer/docs/sdd.md | 2 +- Svc/Framer/test/ut/FramerTestMain.cpp | 4 +- .../LinuxTimerComponentImplTimerFd.cpp | 2 +- .../ConsoleTextLoggerImplCommon.cpp | 2 +- Svc/PassiveRateGroup/PassiveRateGroup.cpp | 2 +- Utils/Types/CircularBuffer.cpp | 6 +- cmake/platform/Darwin.cmake | 1 + cmake/platform/Linux.cmake | 1 + config/FpConfig.h | 8 + docs/Tutorials/GpsTutorial/Tutorial.md | 4 +- docs/UsersGuide/dev/os-docs.md | 4 + 84 files changed, 1350 insertions(+), 869 deletions(-) delete mode 100644 Fw/Logger/LogAssert.cpp delete mode 100644 Fw/Logger/LogAssert.hpp create mode 100644 Os/Console.cpp create mode 100644 Os/Console.hpp delete mode 100644 Os/Log.hpp delete mode 100644 Os/LogPrintf.cpp create mode 100644 Os/Posix/Console.cpp create mode 100644 Os/Posix/Console.hpp create mode 100644 Os/Posix/DefaultConsole.cpp create mode 100644 Os/Posix/test/ut/PosixConsoleTests.cpp create mode 100644 Os/Stub/Console.cpp create mode 100644 Os/Stub/Console.hpp create mode 100644 Os/Stub/DefaultConsole.cpp create mode 100644 Os/Stub/test/Console.cpp create mode 100644 Os/Stub/test/Console.hpp create mode 100644 Os/Stub/test/DefaultConsole.cpp create mode 100644 Os/Stub/test/ut/StubConsoleTests.cpp diff --git a/Drv/Ip/IpSocket.cpp b/Drv/Ip/IpSocket.cpp index d15c8fc295..267c080e80 100644 --- a/Drv/Ip/IpSocket.cpp +++ b/Drv/Ip/IpSocket.cpp @@ -53,11 +53,12 @@ IpSocket::IpSocket() : m_fd(-1), m_timeoutSeconds(0), m_timeoutMicroseconds(0), SocketIpStatus IpSocket::configure(const char* const hostname, const U16 port, const U32 timeout_seconds, const U32 timeout_microseconds) { FW_ASSERT(timeout_microseconds < 1000000, static_cast(timeout_microseconds)); FW_ASSERT(this->isValidPort(port)); + FW_ASSERT(hostname != nullptr); this->m_lock.lock(); this->m_timeoutSeconds = timeout_seconds; this->m_timeoutMicroseconds = timeout_microseconds; this->m_port = port; - (void) Fw::StringUtils::string_copy(this->m_hostname, hostname, SOCKET_MAX_HOSTNAME_SIZE); + (void) Fw::StringUtils::string_copy(this->m_hostname, hostname, static_cast(SOCKET_MAX_HOSTNAME_SIZE)); this->m_lock.unlock(); return SOCK_SUCCESS; } diff --git a/Drv/Ip/SocketReadTask.cpp b/Drv/Ip/SocketReadTask.cpp index da9f34c01c..10d6e3c953 100644 --- a/Drv/Ip/SocketReadTask.cpp +++ b/Drv/Ip/SocketReadTask.cpp @@ -75,7 +75,7 @@ void SocketReadTask::readTask(void* pointer) { // Open a network connection if it has not already been open if ((not self->getSocketHandler().isStarted()) and (not self->m_stop) and ((status = self->startup()) != SOCK_SUCCESS)) { - Fw::Logger::logMsg( + Fw::Logger::log( "[WARNING] Failed to open port with status %d and errno %d\n", static_cast(status), static_cast(errno)); @@ -86,7 +86,7 @@ void SocketReadTask::readTask(void* pointer) { // Open a network connection if it has not already been open if ((not self->getSocketHandler().isOpened()) and (not self->m_stop) and ((status = self->open()) != SOCK_SUCCESS)) { - Fw::Logger::logMsg( + Fw::Logger::log( "[WARNING] Failed to open port with status %d and errno %d\n", static_cast(status), static_cast(errno)); @@ -102,7 +102,7 @@ void SocketReadTask::readTask(void* pointer) { U32 size = buffer.getSize(); status = self->getSocketHandler().recv(data, size); if ((status != SOCK_SUCCESS) && (status != SOCK_INTERRUPTED_TRY_AGAIN)) { - Fw::Logger::logMsg("[WARNING] Failed to recv from port with status %d and errno %d\n", + Fw::Logger::log("[WARNING] Failed to recv from port with status %d and errno %d\n", static_cast(status), static_cast(errno)); self->getSocketHandler().close(); diff --git a/Drv/Ip/TcpClientSocket.cpp b/Drv/Ip/TcpClientSocket.cpp index 31808ce606..9c93184e44 100644 --- a/Drv/Ip/TcpClientSocket.cpp +++ b/Drv/Ip/TcpClientSocket.cpp @@ -84,7 +84,7 @@ SocketIpStatus TcpClientSocket::openProtocol(NATIVE_INT_TYPE& fd) { return SOCK_FAILED_TO_CONNECT; } fd = socketFd; - Fw::Logger::logMsg("Connected to %s:%hu as a tcp client\n", reinterpret_cast(m_hostname), m_port); + Fw::Logger::log("Connected to %s:%hu as a tcp client\n", m_hostname, m_port); return SOCK_SUCCESS; } diff --git a/Drv/Ip/TcpServerSocket.cpp b/Drv/Ip/TcpServerSocket.cpp index a9281aa6e0..a26727dd2f 100644 --- a/Drv/Ip/TcpServerSocket.cpp +++ b/Drv/Ip/TcpServerSocket.cpp @@ -83,7 +83,7 @@ SocketIpStatus TcpServerSocket::startup() { return SOCK_FAILED_TO_READ_BACK_PORT; } U16 port = ntohs(address.sin_port); - Fw::Logger::logMsg("Listening for single client at %s:%hu\n", reinterpret_cast(m_hostname), port); + Fw::Logger::log("Listening for single client at %s:%hu\n", m_hostname, port); // TCP requires listening on the socket. Since we only expect a single client, set the TCP backlog (second argument) to 1 to prevent queuing of multiple clients. if (::listen(serverFd, 1) < 0) { ::close(serverFd); @@ -133,7 +133,7 @@ SocketIpStatus TcpServerSocket::openProtocol(NATIVE_INT_TYPE& fd) { return SOCK_FAILED_TO_SET_SOCKET_OPTIONS; } - Fw::Logger::logMsg("Accepted client at %s:%hu\n", reinterpret_cast(m_hostname), m_port); + Fw::Logger::log("Accepted client at %s:%hu\n", m_hostname, m_port); fd = clientFd; return SOCK_SUCCESS; } diff --git a/Drv/Ip/UdpSocket.cpp b/Drv/Ip/UdpSocket.cpp index 1cc685117d..52902454cd 100644 --- a/Drv/Ip/UdpSocket.cpp +++ b/Drv/Ip/UdpSocket.cpp @@ -62,14 +62,16 @@ UdpSocket::~UdpSocket() { SocketIpStatus UdpSocket::configureSend(const char* const hostname, const U16 port, const U32 timeout_seconds, const U32 timeout_microseconds) { //Timeout is for the send, so configure send will work with the base class FW_ASSERT(port != 0, port); // Send cannot be on port 0 + FW_ASSERT(hostname != nullptr); return this->IpSocket::configure(hostname, port, timeout_seconds, timeout_microseconds); } SocketIpStatus UdpSocket::configureRecv(const char* hostname, const U16 port) { FW_ASSERT(this->isValidPort(port)); + FW_ASSERT(hostname != nullptr); this->m_lock.lock(); this->m_recv_port = port; - (void) Fw::StringUtils::string_copy(this->m_recv_hostname, hostname, SOCKET_MAX_HOSTNAME_SIZE); + (void) Fw::StringUtils::string_copy(this->m_recv_hostname, hostname, static_cast(SOCKET_MAX_HOSTNAME_SIZE)); this->m_lock.unlock(); return SOCK_SUCCESS; } @@ -175,13 +177,13 @@ SocketIpStatus UdpSocket::openProtocol(NATIVE_INT_TYPE& fd) { this->m_lock.unlock(); // Log message for UDP if (port == 0) { - Fw::Logger::logMsg("Setup to receive udp at %s:%hu\n", reinterpret_cast(m_recv_hostname), + Fw::Logger::log("Setup to receive udp at %s:%hu\n", m_recv_hostname, recv_port); } else { - Fw::Logger::logMsg("Setup to receive udp at %s:%hu and send to %s:%hu\n", - reinterpret_cast(m_recv_hostname), + Fw::Logger::log("Setup to receive udp at %s:%hu and send to %s:%hu\n", + m_recv_hostname, recv_port, - reinterpret_cast(m_hostname), + m_hostname, port); } FW_ASSERT(status == SOCK_SUCCESS, status); diff --git a/Drv/Ip/test/ut/TestTcp.cpp b/Drv/Ip/test/ut/TestTcp.cpp index 051cd1a270..d06f0dd5d4 100644 --- a/Drv/Ip/test/ut/TestTcp.cpp +++ b/Drv/Ip/test/ut/TestTcp.cpp @@ -5,11 +5,11 @@ #include #include #include -#include +#include #include #include -Os::Log logger; +Os::Console logger; void test_with_loop(U32 iterations) { diff --git a/Drv/Ip/test/ut/TestUdp.cpp b/Drv/Ip/test/ut/TestUdp.cpp index 44c65f9bab..76fe4591d1 100644 --- a/Drv/Ip/test/ut/TestUdp.cpp +++ b/Drv/Ip/test/ut/TestUdp.cpp @@ -4,12 +4,12 @@ #include #include #include -#include +#include #include #include #include -Os::Log logger; +Os::Console logger; void test_with_loop(U32 iterations, bool duplex) { Drv::SocketIpStatus status1 = Drv::SOCK_SUCCESS; diff --git a/Drv/LinuxI2cDriver/LinuxI2cDriver.cpp b/Drv/LinuxI2cDriver/LinuxI2cDriver.cpp index be160c4eb0..2f01887d8c 100644 --- a/Drv/LinuxI2cDriver/LinuxI2cDriver.cpp +++ b/Drv/LinuxI2cDriver/LinuxI2cDriver.cpp @@ -81,18 +81,18 @@ namespace Drv { } #if DEBUG_PRINT - Fw::Logger::logMsg("I2c addr: 0x%02X\n",addr); + Fw::Logger::log("I2c addr: 0x%02X\n",addr); for (U32 byte = 0; byte < serBuffer.getSize(); byte++) { - Fw::Logger::logMsg("0x%02X ",serBuffer.getData()[byte]); + Fw::Logger::log("0x%02X ",serBuffer.getData()[byte]); } - Fw::Logger::logMsg("\n"); + Fw::Logger::log("\n"); #endif // select slave address int stat = ioctl(this->m_fd, I2C_SLAVE, addr); if (stat == -1) { #if DEBUG_PRINT - Fw::Logger::logMsg("Status: %d Errno: %d\n", stat, errno); + Fw::Logger::log("Status: %d Errno: %d\n", stat, errno); #endif return I2cStatus::I2C_ADDRESS_ERR; } @@ -102,7 +102,7 @@ namespace Drv { stat = static_cast(write(this->m_fd, serBuffer.getData(), serBuffer.getSize())); if (stat == -1) { #if DEBUG_PRINT - Fw::Logger::logMsg("Status: %d Errno: %d\n", stat, errno); + Fw::Logger::log("Status: %d Errno: %d\n", stat, errno); #endif return I2cStatus::I2C_WRITE_ERR; } @@ -122,13 +122,13 @@ namespace Drv { } #if DEBUG_PRINT - Fw::Logger::logMsg("I2c addr: 0x%02X\n",addr); + Fw::Logger::log("I2c addr: 0x%02X\n",addr); #endif // select slave address int stat = ioctl(this->m_fd, I2C_SLAVE, addr); if (stat == -1) { #if DEBUG_PRINT - Fw::Logger::logMsg("Status: %d Errno: %d\n", stat, errno); + Fw::Logger::log("Status: %d Errno: %d\n", stat, errno); #endif return I2cStatus::I2C_ADDRESS_ERR; } @@ -138,16 +138,16 @@ namespace Drv { stat = static_cast(read(this->m_fd, serBuffer.getData(), serBuffer.getSize())); if (stat == -1) { #if DEBUG_PRINT - Fw::Logger::logMsg("Status: %d Errno: %d\n", stat, errno); + Fw::Logger::log("Status: %d Errno: %d\n", stat, errno); #endif return I2cStatus::I2C_READ_ERR; } #if DEBUG_PRINT for (U32 byte = 0; byte < serBuffer.getSize(); byte++) { - Fw::Logger::logMsg("0x%02X ",serBuffer.getData()[byte]); + Fw::Logger::log("0x%02X ",serBuffer.getData()[byte]); } - Fw::Logger::logMsg("\n"); + Fw::Logger::log("\n"); #endif return I2cStatus::I2C_OK; } @@ -171,7 +171,7 @@ namespace Drv { FW_ASSERT(readBuffer.getData()); #if DEBUG_PRINT - Fw::Logger::logMsg("I2c addr: 0x%02X\n",addr); + Fw::Logger::log("I2c addr: 0x%02X\n",addr); #endif struct i2c_msg rdwr_msgs[2]; @@ -197,25 +197,25 @@ namespace Drv { if(stat == -1){ #if DEBUG_PRINT - Fw::Logger::logMsg("Status: %d Errno: %d\n", stat, errno); + Fw::Logger::log("Status: %d Errno: %d\n", stat, errno); #endif //Because we're using ioctl to perform the transaction we dont know exactly the type of error that occurred return I2cStatus::I2C_OTHER_ERR; } #if DEBUG_PRINT - Fw::Logger::logMsg("Wrote:\n"); + Fw::Logger::log("Wrote:\n"); for (U32 byte = 0; byte < writeBuffer.getSize(); byte++) { - Fw::Logger::logMsg("0x%02X ",writeBuffer.getData()[byte]); + Fw::Logger::log("0x%02X ",writeBuffer.getData()[byte]); } - Fw::Logger::logMsg("\n"); - Fw::Logger::logMsg("Read:\n"); + Fw::Logger::log("\n"); + Fw::Logger::log("Read:\n"); for (U32 byte = 0; byte < readBuffer.getSize(); byte++) { - Fw::Logger::logMsg("0x%02X ",readBuffer.getData()[byte]); + Fw::Logger::log("0x%02X ",readBuffer.getData()[byte]); } - Fw::Logger::logMsg("\n"); + Fw::Logger::log("\n"); #endif return I2cStatus::I2C_OK; diff --git a/Drv/TcpClient/test/ut/TcpClientTester.cpp b/Drv/TcpClient/test/ut/TcpClientTester.cpp index 2319874e5d..dcc3520f27 100644 --- a/Drv/TcpClient/test/ut/TcpClientTester.cpp +++ b/Drv/TcpClient/test/ut/TcpClientTester.cpp @@ -11,10 +11,11 @@ // ====================================================================== #include "TcpClientTester.hpp" #include "STest/Pick/Pick.hpp" -#include +#include +#include #include -Os::Log logger; +Os::Console logger; namespace Drv { diff --git a/Drv/TcpServer/test/ut/TcpServerTester.cpp b/Drv/TcpServer/test/ut/TcpServerTester.cpp index 1000bd5e0b..40f0d13a2e 100644 --- a/Drv/TcpServer/test/ut/TcpServerTester.cpp +++ b/Drv/TcpServer/test/ut/TcpServerTester.cpp @@ -11,10 +11,11 @@ // ====================================================================== #include "TcpServerTester.hpp" #include "STest/Pick/Pick.hpp" -#include "Os/Log.hpp" +#include "Os/Console.hpp" +#include #include -Os::Log logger; +Os::Console logger; namespace Drv { diff --git a/Drv/Udp/test/ut/UdpTester.cpp b/Drv/Udp/test/ut/UdpTester.cpp index 819ba127be..be06a59137 100644 --- a/Drv/Udp/test/ut/UdpTester.cpp +++ b/Drv/Udp/test/ut/UdpTester.cpp @@ -13,10 +13,10 @@ #include "STest/Pick/Pick.hpp" #include #include -#include "Os/Log.hpp" +#include "Os/Console.hpp" #include -Os::Log logger; +Os::Console logger; namespace Drv { diff --git a/Fw/FilePacket/PathName.cpp b/Fw/FilePacket/PathName.cpp index 7f66f62ca8..91741c828a 100644 --- a/Fw/FilePacket/PathName.cpp +++ b/Fw/FilePacket/PathName.cpp @@ -21,7 +21,7 @@ namespace Fw { void FilePacket::PathName :: initialize(const char *const value) { - const U8 length = static_cast(StringUtils::string_length(value, MAX_LENGTH)); + const U8 length = static_cast(StringUtils::string_length(value, static_cast(MAX_LENGTH))); this->m_length = length; this->m_value = value; } diff --git a/Fw/Logger/CMakeLists.txt b/Fw/Logger/CMakeLists.txt index 0c10a94b0b..e89d0262c7 100644 --- a/Fw/Logger/CMakeLists.txt +++ b/Fw/Logger/CMakeLists.txt @@ -11,7 +11,6 @@ set(MOD_DEPS ) set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Logger.cpp" - "${CMAKE_CURRENT_LIST_DIR}/LogAssert.cpp" ) register_fprime_module() @@ -26,4 +25,4 @@ set(UT_SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/test/ut/LoggerMain.cpp" ) # STest Includes for this UT -register_fprime_ut("Logger_Rules_Testing") +register_fprime_ut() diff --git a/Fw/Logger/LogAssert.cpp b/Fw/Logger/LogAssert.cpp deleted file mode 100644 index 13ddb6fd47..0000000000 --- a/Fw/Logger/LogAssert.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * LogAssert.cpp - * - * Created on: Sep 9, 2016 - * Author: tcanham - * Note: this file was originally a log assert file, under Fw::Types. It now made generic - * to log asserts to Fw::Logger - */ - -#include -#include - -#if FW_ASSERT_LEVEL == FW_NO_ASSERT - -#else - -#if FW_ASSERT_LEVEL == FW_FILEID_ASSERT -#define fileIdFs "Assert: %d:%d" -#define ASSERT_CAST static_cast -#else -#define fileIdFs "Assert: \"%s:%d\"" -#define ASSERT_CAST reinterpret_cast -#endif - - -namespace Fw { - - LogAssertHook::LogAssertHook() { - - } - - LogAssertHook::~LogAssertHook() { - } - - void LogAssertHook::reportAssert( - FILE_NAME_ARG file, - NATIVE_UINT_TYPE lineNo, - NATIVE_UINT_TYPE numArgs, - FwAssertArgType arg1, - FwAssertArgType arg2, - FwAssertArgType arg3, - FwAssertArgType arg4, - FwAssertArgType arg5, - FwAssertArgType arg6 - ) { - // Assumption is that file (when string) goes back to static macro in the code and will persist - switch (numArgs) { - case 0: - Fw::Logger::logMsg( - fileIdFs, - ASSERT_CAST(file), - lineNo, - 0, - 0, - 0, - 0); - break; - case 1: - Fw::Logger::logMsg( - fileIdFs " %d\n", - ASSERT_CAST(file),lineNo, - static_cast(arg1), - 0, - 0, - 0); - break; - case 2: - Fw::Logger::logMsg( - fileIdFs " %d %d\n", - ASSERT_CAST(file),lineNo, - static_cast(arg1), - static_cast(arg2), - 0, - 0); - break; - case 3: - Fw::Logger::logMsg( - fileIdFs " %d %d %d\n", - ASSERT_CAST(file),lineNo, - static_cast(arg1), - static_cast(arg2), - static_cast(arg3), - 0); - break; - case 4: - Fw::Logger::logMsg( - fileIdFs " %d %d %d %d\n", - ASSERT_CAST(file),lineNo, - static_cast(arg1), - static_cast(arg2), - static_cast(arg3), - static_cast(arg4)); - break; - default: // can't fit remainder of arguments in log message - Fw::Logger::logMsg( - fileIdFs " %d %d %d %d +\n", - ASSERT_CAST(file),lineNo, - static_cast(arg1), - static_cast(arg2), - static_cast(arg3), - static_cast(arg4)); - break; - } - - } - - void LogAssertHook::printAssert(const CHAR* msg) { - // do nothing since reportAssert() sends message - } - - void LogAssertHook::doAssert() { - } - -} // namespace Fw - -#endif diff --git a/Fw/Logger/LogAssert.hpp b/Fw/Logger/LogAssert.hpp deleted file mode 100644 index 6927b06d90..0000000000 --- a/Fw/Logger/LogAssert.hpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * LogAssert.hpp - * - * Created on: Sep 9, 2016 - * Author: tcanham - * Note: this file was originally a log assert file, under Fw::Types. It now made generic - * to log asserts to Fw::Logger - */ - -#ifndef LOGGER_LOGASSERT_HPP_ -#define LOGGER_LOGASSERT_HPP_ - -#include - -namespace Fw { - - class LogAssertHook: public Fw::AssertHook { - public: - LogAssertHook(); - virtual ~LogAssertHook(); - void reportAssert( - FILE_NAME_ARG file, - NATIVE_UINT_TYPE lineNo, - NATIVE_UINT_TYPE numArgs, - FwAssertArgType arg1, - FwAssertArgType arg2, - FwAssertArgType arg3, - FwAssertArgType arg4, - FwAssertArgType arg5, - FwAssertArgType arg6 - ); - void printAssert(const CHAR* msg); - void doAssert(); - }; - -} - -#endif /* VXWORKSLOGASSERT_HPP_ */ diff --git a/Fw/Logger/Logger.cpp b/Fw/Logger/Logger.cpp index 07d08becad..9493cf4fea 100644 --- a/Fw/Logger/Logger.cpp +++ b/Fw/Logger/Logger.cpp @@ -4,31 +4,38 @@ * Author: mstarch * * This file adds in support to the core 'Fw' package, to separate it from Os and other loggers, and - * allow the architect of the system to select which core framework logging should be used. + * allow the architect of the system to select which core framework logging should be used. */ - #include +#include +#include +#include +#include +#include namespace Fw { -//Initial logger is NULL - Logger* Logger::s_current_logger = nullptr; +// Initial logger is NULL +Logger* Logger::s_current_logger = nullptr; -// Basic log implementation - void Logger::logMsg(const char* fmt, POINTER_CAST a0, POINTER_CAST a1, - POINTER_CAST a2, POINTER_CAST a3, POINTER_CAST a4, POINTER_CAST a5, - POINTER_CAST a6, POINTER_CAST a7, POINTER_CAST a8, POINTER_CAST a9) { - // Log if capable, otherwise drop - if (Logger::s_current_logger != nullptr) { - Logger::s_current_logger->log(fmt, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); - } - } -// Register the logger - void Logger::registerLogger(Logger* logger) { - Logger::s_current_logger = logger; - } +void Logger::log(const char* format, ...) { + Fw::String formatted_string; + // Forward the variable arguments to the vformat format implementation + va_list args; + va_start(args, format); + formatted_string.vformat(format, args); + va_end(args); + Logger::log(formatted_string); +} - Logger::~Logger() { +void Logger::log(const StringBase& string) { + if (Logger::s_current_logger != nullptr) { + Logger::s_current_logger->writeMessage(string); } +} + +void Logger::registerLogger(Logger* logger) { + Logger::s_current_logger = logger; +} -} //End namespace Fw +} // End namespace Fw diff --git a/Fw/Logger/Logger.hpp b/Fw/Logger/Logger.hpp index 981612b09c..53f3f017e7 100644 --- a/Fw/Logger/Logger.hpp +++ b/Fw/Logger/Logger.hpp @@ -4,87 +4,59 @@ * Author: mstarch * * This file adds in support to the core 'Fw' package, to separate it from Os and other loggers, and - * allow the architect of the system to select which core framework logging should be used. + * allow the architect of the system to select which core framework logging should be used. */ -#ifndef _Fw_Logger_hpp_ -#define _Fw_Logger_hpp_ - +#ifndef Fw_Logger_hpp_ +#define Fw_Logger_hpp_ #include +#include +#include + +// Unit testing predeclaration hook +namespace LoggerRules { +struct Register; +} namespace Fw { - class Logger { - public: - /** - * Function called on the logger to log a message. This is abstract virtual method and - * must be supplied by the subclass. This logger object should be registered with the - * Fw::Log::registerLogger function. - * \param fmt: format string in which to place arguments - * \param a0: zeroth argument. (Default: 0) - * \param a1: first argument. (Default: 0) - * \param a2: second argument. (Default: 0) - * \param a3: third argument. (Default: 0) - * \param a4: fourth argument. (Default: 0) - * \param a5: fifth argument. (Default: 0) - * \param a6: sixth argument. (Default: 0) - * \param a7: seventh argument. (Default: 0) - * \param a8: eighth argument. (Default: 0) - * \param a9: ninth argument. (Default: 0) - */ - virtual void log( - const char* fmt, - POINTER_CAST a0 = 0, - POINTER_CAST a1 = 0, - POINTER_CAST a2 = 0, - POINTER_CAST a3 = 0, - POINTER_CAST a4 = 0, - POINTER_CAST a5 = 0, - POINTER_CAST a6 = 0, - POINTER_CAST a7 = 0, - POINTER_CAST a8 = 0, - POINTER_CAST a9 = 0 - ) = 0; +class Logger { + friend struct LoggerRules::Register; - /** - * Logs a message using the currently specified static logger. If a logger is not - * registered, then the log message is dropped. - * \param fmt: format string in which to place arguments - * \param a0: zeroth argument. (Default: 0) - * \param a1: first argument. (Default: 0) - * \param a2: second argument. (Default: 0) - * \param a3: third argument. (Default: 0) - * \param a4: fourth argument. (Default: 0) - * \param a5: fifth argument. (Default: 0) - * \param a6: sixth argument. (Default: 0) - * \param a7: seventh argument. (Default: 0) - * \param a8: eighth argument. (Default: 0) - * \param a9: ninth argument. (Default: 0) - */ - static void logMsg( - const char* fmt, - POINTER_CAST a0 = 0, - POINTER_CAST a1 = 0, - POINTER_CAST a2 = 0, - POINTER_CAST a3 = 0, - POINTER_CAST a4 = 0, - POINTER_CAST a5 = 0, - POINTER_CAST a6 = 0, - POINTER_CAST a7 = 0, - POINTER_CAST a8 = 0, - POINTER_CAST a9 = 0 - ); + public: + //! \brief log a formated string with supplied arguments + //! + //! Logs a format string with the arguments filled-in. This delegates to StringBase.format, which in-turn + //! delegates to snprintf. This implies that the caller is fully responsible for handling the type safety of + //! the supplied format string. The format string uses C-style (printf function family) formatting. + //! \param format: format string + //! \param ...: var-args list of arguments to inject into format string. + static void log(const char* format, ...); - /** - * Registers the static logger for use with the Fw::Log::logMsg function. This must be - * a subclass of Fw::Log. - * \param logger: logger to log to when Fw::Log::logMsg is called. - */ - static void registerLogger(Logger* logger); + //! \brief log a string message directly + //! + //! Logs the string directly to the backing store without any formatting changes. + //! \param message: message to log + static void log(const Fw::StringBase& message); - //!< Static logger to use when calling the above 'logMsg' function - static Logger* s_current_logger; + //! \brief register a logger implementation + //! + //! This registers the supplied logger as the system logger used for calls to Fw::Logger::log. + //! \param logger: logger to register as the system logger + static void registerLogger(Logger* logger); - virtual ~Logger(); - }; -} + //! Virtual destructor + virtual ~Logger() = default; + + protected: + //! \brief write the output of the log message + //! + //! Log implementations must provide this method used to write the output of a string to the log backing. + //! + //! \param message: message to log + virtual void writeMessage(const StringBase& message) = 0; + + private: + static Logger* s_current_logger; //!< Static logger to use when calling Fw::Logger::log function +}; +} // namespace Fw #endif diff --git a/Fw/Logger/test/ut/FakeLogger.cpp b/Fw/Logger/test/ut/FakeLogger.cpp index f4652d4dc1..b8a48ceff0 100644 --- a/Fw/Logger/test/ut/FakeLogger.cpp +++ b/Fw/Logger/test/ut/FakeLogger.cpp @@ -10,76 +10,19 @@ #include namespace MockLogging { - Fw::Logger* FakeLogger::s_current = nullptr; +Fw::Logger* FakeLogger::s_current = nullptr; - FakeLogger::FakeLogger() { - memset(&m_last, 0, sizeof(m_last)); - } +FakeLogger::FakeLogger(): m_last("") {} - void FakeLogger::log( - const char *fmt, - POINTER_CAST a0, - POINTER_CAST a1, - POINTER_CAST a2, - POINTER_CAST a3, - POINTER_CAST a4, - POINTER_CAST a5, - POINTER_CAST a6, - POINTER_CAST a7, - POINTER_CAST a8, - POINTER_CAST a9 - ) { - m_last.fmt = fmt; - m_last.a0 = a0; - m_last.a1 = a1; - m_last.a2 = a2; - m_last.a3 = a3; - m_last.a4 = a4; - m_last.a5 = a5; - m_last.a6 = a6; - m_last.a7 = a7; - m_last.a8 = a8; - m_last.a9 = a9; - } - - void FakeLogger::check( - const char *fmt, - POINTER_CAST a0, - POINTER_CAST a1, - POINTER_CAST a2, - POINTER_CAST a3, - POINTER_CAST a4, - POINTER_CAST a5, - POINTER_CAST a6, - POINTER_CAST a7, - POINTER_CAST a8, - POINTER_CAST a9 +void FakeLogger::writeMessage(const Fw::StringBase& message) { + m_last = message.toChar(); +} - ) { - ASSERT_EQ(m_last.fmt, fmt); - ASSERT_EQ(m_last.a0, a0); - ASSERT_EQ(m_last.a1, a1); - ASSERT_EQ(m_last.a2, a2); - ASSERT_EQ(m_last.a3, a3); - ASSERT_EQ(m_last.a4, a4); - ASSERT_EQ(m_last.a5, a5); - ASSERT_EQ(m_last.a6, a6); - ASSERT_EQ(m_last.a7, a7); - ASSERT_EQ(m_last.a8, a8); - ASSERT_EQ(m_last.a9, a9); - } +void FakeLogger::check(const char* message) { + ASSERT_EQ(m_last, std::string(message)); +} - void FakeLogger::reset() { - m_last.fmt = nullptr; - m_last.a0 = 0; - m_last.a1 = 0; - m_last.a2 = 0; - m_last.a3 = 0; - m_last.a4 = 0; - m_last.a5 = 0; - m_last.a6 = 0; - m_last.a7 = 0; - m_last.a8 = 0; - m_last.a9 = 0; - } +void FakeLogger::reset() { + m_last = ""; } +} // namespace MockLogging diff --git a/Fw/Logger/test/ut/FakeLogger.hpp b/Fw/Logger/test/ut/FakeLogger.hpp index 125023d4b9..353d408e58 100644 --- a/Fw/Logger/test/ut/FakeLogger.hpp +++ b/Fw/Logger/test/ut/FakeLogger.hpp @@ -8,100 +8,43 @@ */ #include +#include #include +#include #ifndef FPRIME_FAKELOGGER_HPP #define FPRIME_FAKELOGGER_HPP namespace MockLogging { +/** + * Fake logger used for two purposes: + * 1. it acts as logging truth for the test + * 2. it intercepts logging calls bound for the system + */ +class FakeLogger : public Fw::Logger { + public: + //!< Constructor + FakeLogger(); + /** - * LogMessage data type to map inputs too. + * Fake implementation of the logger. + * @param message: formatted message to log */ - struct LogMessage { - const char *fmt; - POINTER_CAST a0; - POINTER_CAST a1; - POINTER_CAST a2; - POINTER_CAST a3; - POINTER_CAST a4; - POINTER_CAST a5; - POINTER_CAST a6; - POINTER_CAST a7; - POINTER_CAST a8; - POINTER_CAST a9; - }; + void writeMessage(const Fw::StringBase& message); + /** - * Fake logger used for two purposes: - * 1. it acts as logging truth for the test - * 2. it intercepts logging calls bound for the system + * Check last message. + * @param message: formatted message to check + * @param size: size to log */ - class FakeLogger : public Fw::Logger { - public: - //!< Constructor - FakeLogger(); - - /** - * Fake implementation of the logger. - * @param fmt: format - * @param a0: arg0 - * @param a1: arg1 - * @param a2: arg2 - * @param a3: arg3 - * @param a4: arg4 - * @param a5: arg5 - * @param a6: arg6 - * @param a7: arg7 - * @param a8: arg8 - * @param a9: arg9 - */ - void log( - const char *fmt, - POINTER_CAST a0 = 0, - POINTER_CAST a1 = 0, - POINTER_CAST a2 = 0, - POINTER_CAST a3 = 0, - POINTER_CAST a4 = 0, - POINTER_CAST a5 = 0, - POINTER_CAST a6 = 0, - POINTER_CAST a7 = 0, - POINTER_CAST a8 = 0, - POINTER_CAST a9 = 0 - ); - - /** - * Check last message. - * @param fmt: format - * @param a0: arg1 - * @param a1: arg1 - * @param a2: arg2 - * @param a3: arg3 - * @param a4: arg4 - * @param a5: arg5 - * @param a6: arg6 - * @param a7: arg6 - * @param a8: arg6 - * @param a9: arg6 - */ - virtual void check( - const char *fmt, - POINTER_CAST a0 = 0, - POINTER_CAST a1 = 0, - POINTER_CAST a2 = 0, - POINTER_CAST a3 = 0, - POINTER_CAST a4 = 0, - POINTER_CAST a5 = 0, - POINTER_CAST a6 = 0, - POINTER_CAST a7 = 0, - POINTER_CAST a8 = 0, - POINTER_CAST a9 = 0 - ); + virtual void check(const char* message); - //!< Reset this logger - void reset(); + //!< Reset this logger + void reset(); - //!< Last message that came in - LogMessage m_last; - //!< Logger to use within the system - static Fw::Logger* s_current; - }; + //!< Last message that came in + std::string m_last; + //!< Logger to use within the system + static Fw::Logger* s_current; }; -#endif //FPRIME_FAKELOGGER_HPP +}; // namespace MockLogging +#endif // FPRIME_FAKELOGGER_HPP diff --git a/Fw/Logger/test/ut/LoggerMain.cpp b/Fw/Logger/test/ut/LoggerMain.cpp index 8ef9dc8d02..7dfe126e4f 100644 --- a/Fw/Logger/test/ut/LoggerMain.cpp +++ b/Fw/Logger/test/ut/LoggerMain.cpp @@ -6,13 +6,13 @@ * Created on: May 23, 2019 * Author: mstarch */ -#include -#include #include +#include +#include -#include -#include #include +#include +#include #include @@ -28,20 +28,15 @@ TEST(LoggerTests, RandomLoggerTests) { LoggerRules::Register reg(Fw::String("Register")); LoggerRules::LogGood log(Fw::String("Log Successfully")); LoggerRules::LogBad nolog(Fw::String("Log unsuccessfully")); + LoggerRules::LogBad string_log(Fw::String("Log Successfully (String)")); // Setup a list of rules to choose from - STest::Rule* rules[] = { - ®, - &log, - &nolog - }; + STest::Rule* rules[] = {®, &log, &nolog, &string_log}; // Construct the random scenario and run it with the defined bounds - STest::RandomScenario random("Random Rules", rules, - FW_NUM_ARRAY_ELEMENTS(rules)); + STest::RandomScenario random("Random Rules", rules, FW_NUM_ARRAY_ELEMENTS(rules)); // Setup a bounded scenario to run rules a set number of times - STest::BoundedScenario bounded("Bounded Random Rules Scenario", - random, STEP_COUNT); + STest::BoundedScenario bounded("Bounded Random Rules Scenario", random, STEP_COUNT); // Run! const U32 numSteps = bounded.run(logger); printf("Ran %u steps.\n", numSteps); @@ -58,6 +53,19 @@ TEST(LoggerTests, BasicGoodLogger) { LoggerRules::LogGood log(Fw::String("Log Successfully")); log.apply(logger); } +/** + * Test that the most basic logging function works. + */ +TEST(LoggerTests, BasicGoodStringLogger) { + // Setup and register logger + MockLogging::FakeLogger logger; + Fw::Logger::registerLogger(&logger); + logger.s_current = &logger; + // Basic logging + LoggerRules::LogGoodStringObject log(Fw::String("Log Successfully")); + log.apply(logger); +} + /** * Test that null-logging function works. */ @@ -86,7 +94,6 @@ TEST(LoggerTests, BasicRegLogger) { reg.apply(logger); } - int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); STest::Random::seed(); diff --git a/Fw/Logger/test/ut/LoggerRules.cpp b/Fw/Logger/test/ut/LoggerRules.cpp index 547f44f181..45ee2519f4 100644 --- a/Fw/Logger/test/ut/LoggerRules.cpp +++ b/Fw/Logger/test/ut/LoggerRules.cpp @@ -16,161 +16,183 @@ namespace LoggerRules { - // Constructor - Register::Register(const Fw::String& name) : STest::Rule(name.toChar()) {} +// Constructor +Register::Register(const Fw::String& name) : STest::Rule(name.toChar()) {} - // Check for registration, always allowed - bool Register::precondition(const MockLogging::FakeLogger& truth) { - return true; - } +// Check for registration, always allowed +bool Register::precondition(const MockLogging::FakeLogger& truth) { + return true; +} - // Register NULL or truth as the system logger - void Register::action(MockLogging::FakeLogger& truth) { - // Select a registration value: 1 -> logger, 0 -> NULL - NATIVE_INT_TYPE random = STest::Pick::lowerUpper(0, 1); - if (random == 1) { - Fw::Logger::registerLogger(&truth); - truth.s_current = &truth; - } - else { - Fw::Logger::registerLogger(nullptr); - truth.s_current = nullptr; - } - ASSERT_EQ(truth.s_current, Fw::Logger::s_current_logger); +// Register NULL or truth as the system logger +void Register::action(MockLogging::FakeLogger& truth) { + // Select a registration value: 1 -> logger, 0 -> NULL + NATIVE_INT_TYPE random = STest::Pick::lowerUpper(0, 1); + if (random == 1) { + Fw::Logger::registerLogger(&truth); + truth.s_current = &truth; + } else { + Fw::Logger::registerLogger(nullptr); + truth.s_current = nullptr; } + ASSERT_EQ(truth.s_current, Fw::Logger::s_current_logger); +} - // Constructor - LogGood::LogGood(const Fw::String& name) : STest::Rule(name.toChar()) {} +// Constructor +LogGood::LogGood(const Fw::String& name) : STest::Rule(name.toChar()) {} - // Check for logging, only when not NULL - bool LogGood::precondition(const MockLogging::FakeLogger& truth) { - return truth.s_current != nullptr; - } +// Check for logging, only when not NULL +bool LogGood::precondition(const MockLogging::FakeLogger& truth) { + return truth.s_current != nullptr; +} - // Log valid messages - void LogGood::action(MockLogging::FakeLogger& truth) { - NATIVE_INT_TYPE random = STest::Pick::lowerUpper(0, 10); - NATIVE_INT_TYPE ra[10]; - for (int i = 0; i < 10; ++i) { - ra[i] = STest::Pick::lowerUpper(0, 0xffffffff); - } - - switch (random) { - case 0: - Fw::Logger::logMsg("No args"); - truth.check("No args"); - break; - case 1: - Fw::Logger::logMsg("One arg: %lu", ra[0]); - truth.check("One arg: %lu", ra[0]); - break; - case 2: - Fw::Logger::logMsg("Two arg: %lu", ra[0], ra[1]); - truth.check("Two arg: %lu", ra[0], ra[1]); - break; - case 3: - Fw::Logger::logMsg("Three arg: %lu", ra[0], ra[1], ra[2]); - truth.check("Three arg: %lu", ra[0], ra[1], ra[2]); - break; - case 4: - Fw::Logger::logMsg("Four arg: %lu", ra[0], ra[1], ra[2], ra[3]); - truth.check("Four arg: %lu", ra[0], ra[1], ra[2], ra[3]); - break; - case 5: - Fw::Logger::logMsg("Five arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4]); - truth.check("Five arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4]); - break; - case 6: - Fw::Logger::logMsg("Six arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5]); - truth.check("Six arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5]); - break; - case 7: - Fw::Logger::logMsg("Seven arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6]); - truth.check("Seven arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6]); - break; - case 8: - Fw::Logger::logMsg("Eight arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6], ra[7]); - truth.check("Eight arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6], ra[7]); - break; - case 9: - Fw::Logger::logMsg("Nine arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6], ra[7], ra[8]); - truth.check("Nine arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6], ra[7], ra[8]); - break; - case 10: - Fw::Logger::logMsg("Ten arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6], ra[7], ra[8], ra[9]); - truth.check("Ten arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6], ra[7], ra[8], ra[9]); - break; +// Log valid messages +void LogGood::action(MockLogging::FakeLogger& truth) { + NATIVE_INT_TYPE random = STest::Pick::lowerUpper(0, 10); + NATIVE_INT_TYPE ra[10]; + for (int i = 0; i < 10; ++i) { + ra[i] = STest::Pick::lowerUpper(0, 0xffffffff); + } + Fw::String correct; + switch (random) { + case 0: + Fw::Logger::log("No args"); + correct = "No args"; + break; + case 1: + Fw::Logger::log("One arg: %lu", ra[0]); + correct.format("One arg: %lu", ra[0]); + break; + case 2: + Fw::Logger::log("Two arg: %lu %lu", ra[0], ra[1]); + correct.format("Two arg: %lu %lu", ra[0], ra[1]); + break; + case 3: + Fw::Logger::log("Three arg: %lu %lu %lu", ra[0], ra[1], ra[2]); + correct.format("Three arg: %lu %lu %lu", ra[0], ra[1], ra[2]); + break; + case 4: + Fw::Logger::log("Four arg: %lu %lu %lu %lu", ra[0], ra[1], ra[2], ra[3]); + correct.format("Four arg: %lu %lu %lu %lu", ra[0], ra[1], ra[2], ra[3]); + break; + case 5: + Fw::Logger::log("Five arg: %lu %lu %lu %lu %lu", ra[0], ra[1], ra[2], ra[3], ra[4]); + correct.format("Five arg: %lu %lu %lu %lu %lu", ra[0], ra[1], ra[2], ra[3], ra[4]); + break; + case 6: + Fw::Logger::log("Six arg: %lu %lu %lu %lu %lu %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5]); + correct.format("Six arg: %lu %lu %lu %lu %lu %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5]); + break; + case 7: + Fw::Logger::log("Seven arg: %lu %lu %lu %lu %lu %lu %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], + ra[6]); + correct.format("Seven arg: %lu %lu %lu %lu %lu %lu %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], + ra[6]); + break; + case 8: + Fw::Logger::log("Eight arg: %lu %lu %lu %lu %lu %lu %lu %lu", ra[0], ra[1], ra[2], ra[3], ra[4], + ra[5], ra[6], ra[7]); + correct.format("Eight arg: %lu %lu %lu %lu %lu %lu %lu %lu", ra[0], ra[1], ra[2], ra[3], ra[4], + ra[5], ra[6], ra[7]); + break; + case 9: + Fw::Logger::log("Nine arg: %lu %lu %lu %lu %lu %lu %lu %lu %lu", ra[0], ra[1], ra[2], ra[3], ra[4], + ra[5], ra[6], ra[7], ra[8]); + correct.format("Nine arg: %lu %lu %lu %lu %lu %lu %lu %lu %lu", ra[0], ra[1], ra[2], ra[3], ra[4], + ra[5], ra[6], ra[7], ra[8]); + break; + case 10: + Fw::Logger::log("Ten arg: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", ra[0], ra[1], ra[2], ra[3], + ra[4], ra[5], ra[6], ra[7], ra[8], ra[9]); + correct.format("Ten arg: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", ra[0], ra[1], ra[2], ra[3], + ra[4], ra[5], ra[6], ra[7], ra[8], ra[9]); + break; - default: - ASSERT_EQ(0, 1); - } - truth.reset(); + default: + ASSERT_EQ(0, 1); } + truth.check(correct.toChar()); + truth.reset(); +} + +// Constructor +LogGoodStringObject::LogGoodStringObject(const Fw::String& name) + : STest::Rule(name.toChar()) {} - // Constructor - LogBad::LogBad(const Fw::String& name) : STest::Rule(name.toChar()) {} +// Check for logging, only when not NULL +bool LogGoodStringObject::precondition(const MockLogging::FakeLogger& truth) { + return truth.s_current != nullptr; +} - // Check for logging, only when not NULL - bool LogBad::precondition(const MockLogging::FakeLogger& truth) { - return truth.s_current == nullptr; +// Log valid messages +void LogGoodStringObject::action(MockLogging::FakeLogger& truth) { + Fw::String my_string; + NATIVE_INT_TYPE random = STest::Pick::lowerUpper(0, my_string.getCapacity() - 1); + for (int i = 0; i < random; ++i) { + const_cast(my_string.toChar())[i] = + static_cast(STest::Pick::lowerUpper(0, std::numeric_limits::max())); } + const_cast(my_string.toChar())[random] = 0; + Fw::String copy1 = my_string.toChar(); + Fw::Logger::log(copy1); + truth.check(my_string.toChar()); + truth.reset(); +} - // Log valid messages - void LogBad::action(MockLogging::FakeLogger& truth) { - NATIVE_INT_TYPE random = STest::Pick::lowerUpper(0, 10); - NATIVE_INT_TYPE ra[10]; - for (int i = 0; i < 10; ++i) { - ra[i] = STest::Pick::lowerUpper(0, 0xffffffff); - } +// Constructor +LogBad::LogBad(const Fw::String& name) : STest::Rule(name.toChar()) {} + +// Check for logging, only when not NULL +bool LogBad::precondition(const MockLogging::FakeLogger& truth) { + return truth.s_current == nullptr; +} + +// Log valid messages +void LogBad::action(MockLogging::FakeLogger& truth) { + NATIVE_INT_TYPE random = STest::Pick::lowerUpper(0, 10); + NATIVE_INT_TYPE ra[10]; + for (int i = 0; i < 10; ++i) { + ra[i] = STest::Pick::lowerUpper(0, 0xffffffff); + } - switch (random) { - case 0: - Fw::Logger::logMsg("No args"); - truth.check(nullptr); - break; - case 1: - Fw::Logger::logMsg("One arg: %lu", ra[0]); - truth.check(nullptr); - break; - case 2: - Fw::Logger::logMsg("Two arg: %lu", ra[0], ra[1]); - truth.check(nullptr); - break; - case 3: - Fw::Logger::logMsg("Three arg: %lu", ra[0], ra[1], ra[2]); - truth.check(nullptr); - break; - case 4: - Fw::Logger::logMsg("Four arg: %lu", ra[0], ra[1], ra[2], ra[3]); - truth.check(nullptr); - break; - case 5: - Fw::Logger::logMsg("Five arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4]); - truth.check(nullptr); - break; - case 6: - Fw::Logger::logMsg("Six arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5]); - truth.check(nullptr); - break; - case 7: - Fw::Logger::logMsg("Seven arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6]); - truth.check(nullptr); - break; - case 8: - Fw::Logger::logMsg("Eight arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6], ra[7]); - truth.check(nullptr); - break; - case 9: - Fw::Logger::logMsg("Nine arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6], ra[7], ra[8]); - truth.check(nullptr); - break; - case 10: - Fw::Logger::logMsg("Ten arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6], ra[7], ra[8], ra[9]); - truth.check(nullptr); - break; - default: - ASSERT_EQ(0, 1); - } - truth.reset(); + switch (random) { + case 0: + Fw::Logger::log("No args"); + break; + case 1: + Fw::Logger::log("One arg: %lu", ra[0]); + break; + case 2: + Fw::Logger::log("Two arg: %lu", ra[0], ra[1]); + break; + case 3: + Fw::Logger::log("Three arg: %lu", ra[0], ra[1], ra[2]); + break; + case 4: + Fw::Logger::log("Four arg: %lu", ra[0], ra[1], ra[2], ra[3]); + break; + case 5: + Fw::Logger::log("Five arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4]); + break; + case 6: + Fw::Logger::log("Six arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5]); + break; + case 7: + Fw::Logger::log("Seven arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6]); + break; + case 8: + Fw::Logger::log("Eight arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6], ra[7]); + break; + case 9: + Fw::Logger::log("Nine arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6], ra[7], ra[8]); + break; + case 10: + Fw::Logger::log("Ten arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6], ra[7], ra[8], ra[9]); + break; + default: + ASSERT_EQ(0, 1); } -}; + truth.check(""); + truth.reset(); +} +}; // namespace LoggerRules diff --git a/Fw/Logger/test/ut/LoggerRules.hpp b/Fw/Logger/test/ut/LoggerRules.hpp index a0f34a4948..015c017733 100644 --- a/Fw/Logger/test/ut/LoggerRules.hpp +++ b/Fw/Logger/test/ut/LoggerRules.hpp @@ -16,60 +16,76 @@ #define FPRIME_LOGGERRULES_HPP #include -#include #include -#include +#include #include - +#include namespace LoggerRules { - /** - * Register: - * - * Rule to handle the registration of a logger to the global logger. It may also register a "NULL" logger and thus - * stop output logging. - */ - struct Register : public STest::Rule { - // Constructor - Register(const Fw::String& name); +/** + * Register: + * + * Rule to handle the registration of a logger to the global logger. It may also register a "NULL" logger and thus + * stop output logging. + */ +struct Register : public STest::Rule { + // Constructor + explicit Register(const Fw::String& name); + + // Check for registration, always allowed + bool precondition(const MockLogging::FakeLogger& truth); + + // Register NULL or truth as the system logger + void action(MockLogging::FakeLogger& truth); +}; + +/** + * LogGood: + * + * As long as a non-NULL logger is set as the system logger, then valid log messages should be processed. + */ +struct LogGood : public STest::Rule { + // Constructor + explicit LogGood(const Fw::String& name); - // Check for registration, always allowed - bool precondition(const MockLogging::FakeLogger& truth); + // Check for logging, only when not NULL + bool precondition(const MockLogging::FakeLogger& truth); - // Register NULL or truth as the system logger - void action(MockLogging::FakeLogger& truth); - }; - /** - * LogGood: - * - * As long as a non-NULL logger is set as the system logger, then valid log messages should be processed. - */ - struct LogGood : public STest::Rule { - // Constructor - LogGood(const Fw::String& name); + // Log valid messages + void action(MockLogging::FakeLogger& truth); +}; + +/** + * LogBad: + * + * As long as a non-NULL logger is set as the system logger, then valid log messages should be processed. + */ +struct LogBad : public STest::Rule { + // Constructor + explicit LogBad(const Fw::String& name); - // Check for logging, only when not NULL - bool precondition(const MockLogging::FakeLogger& truth); + // Check for logging, only when not NULL + bool precondition(const MockLogging::FakeLogger& truth); - // Log valid messages - void action(MockLogging::FakeLogger& truth); - }; + // Log valid messages + void action(MockLogging::FakeLogger& truth); +}; - /** - * LogBad: - * - * As long as a non-NULL logger is set as the system logger, then valid log messages should be processed. - */ - struct LogBad : public STest::Rule { - // Constructor - LogBad(const Fw::String& name); +/** + * LogGoodStringObject: + * + * As long as a non-NULL logger is set as the system logger, then valid log messages should be processed. + */ +struct LogGoodStringObject : public STest::Rule { + // Constructor + explicit LogGoodStringObject(const Fw::String& name); - // Check for logging, only when not NULL - bool precondition(const MockLogging::FakeLogger& truth); + // Check for logging, only when not NULL + bool precondition(const MockLogging::FakeLogger& truth); - // Log valid messages - void action(MockLogging::FakeLogger& truth); - }; + // Log valid messages + void action(MockLogging::FakeLogger& truth); }; -#endif //FPRIME_LOGGERRULES_HPP +}; // namespace LoggerRules +#endif // FPRIME_LOGGERRULES_HPP diff --git a/Fw/Obj/SimpleObjRegistry.cpp b/Fw/Obj/SimpleObjRegistry.cpp index e743d6ea50..2521349fa7 100644 --- a/Fw/Obj/SimpleObjRegistry.cpp +++ b/Fw/Obj/SimpleObjRegistry.cpp @@ -28,15 +28,15 @@ namespace Fw { #if FW_OBJECT_TO_STRING == 1 char objDump[FW_OBJ_SIMPLE_REG_BUFF_SIZE]; this->m_objPtrArray[obj]->toString(objDump,sizeof(objDump)); - Fw::Logger::logMsg("Entry: %d Ptr: %p Str: %s\n", static_cast(obj), - reinterpret_cast(this->m_objPtrArray[obj]), reinterpret_cast(objDump)); + Fw::Logger::log("Entry: %d Ptr: %p Str: %s\n", obj, + this->m_objPtrArray[obj], objDump); #else - Fw::Logger::logMsg("Entry: %d Ptr: %p Name: %s\n",static_cast(obj), - reinterpret_cast(this->m_objPtrArray[obj]), - reinterpret_cast(this->m_objPtrArray[obj]->getObjName())); + Fw::Logger::log("Entry: %d Ptr: %p Name: %s\n", obj, + this->m_objPtrArray[obj], + this->m_objPtrArray[obj]->getObjName()); #endif // FW_OBJECT_TO_STRING #else - Fw::Logger::logMsg("Entry: %d Ptr: %p Str:\n", obj, reinterpret_cast(this->m_objPtrArray[obj])); + Fw::Logger::log("Entry: %d Ptr: %p\n", obj, this->m_objPtrArray[obj]); #endif } } @@ -48,12 +48,12 @@ namespace Fw { if (strncmp(objName,this->m_objPtrArray[obj]->getObjName(),sizeof(objDump)) == 0) { #if FW_OBJECT_TO_STRING == 1 this->m_objPtrArray[obj]->toString(objDump,sizeof(objDump)); - Fw::Logger::logMsg("Entry: %d Ptr: %p Str: %s\n", static_cast(obj), - reinterpret_cast(this->m_objPtrArray[obj]), reinterpret_cast(objDump)); + Fw::Logger::log("Entry: %d Ptr: %p Str: %s\n", obj, + this->m_objPtrArray[obj], objDump); #else - Fw::Logger::logMsg("Entry: %d Ptr: %p Name: %s\n",static_cast(obj), - reinterpret_cast(this->m_objPtrArray[obj]), - reinterpret_cast(this->m_objPtrArray[obj]->getObjName())); + Fw::Logger::log("Entry: %d Ptr: %p Name: %s\n",obj, + this->m_objPtrArray[obj], + this->m_objPtrArray[obj]->getObjName()); #endif } } diff --git a/Fw/Port/OutputPortBase.cpp b/Fw/Port/OutputPortBase.cpp index 84a05522a7..009a51c6b4 100644 --- a/Fw/Port/OutputPortBase.cpp +++ b/Fw/Port/OutputPortBase.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/Fw/Port/PortBase.cpp b/Fw/Port/PortBase.cpp index e53242c0f5..5a63bb1b0a 100644 --- a/Fw/Port/PortBase.cpp +++ b/Fw/Port/PortBase.cpp @@ -57,9 +57,9 @@ namespace Fw { if (do_trace) { #if FW_OBJECT_NAMES == 1 - Fw::Logger::logMsg("Trace: %s\n", reinterpret_cast(this->m_objName.toChar()), 0, 0, 0, 0, 0); + Fw::Logger::log("Trace: %s\n", this->m_objName.toChar()); #else - Fw::Logger::logMsg("Trace: %p\n", reinterpret_cast(this), 0, 0, 0, 0, 0); + Fw::Logger::log("Trace: %p\n", this); #endif } } diff --git a/Fw/Types/StringBase.cpp b/Fw/Types/StringBase.cpp index 5fc9820488..c3ff506b17 100644 --- a/Fw/Types/StringBase.cpp +++ b/Fw/Types/StringBase.cpp @@ -54,14 +54,23 @@ bool StringBase::operator==(const CHAR* other) const { } void StringBase::format(const CHAR* formatString, ...) { - CHAR* us = const_cast(this->toChar()); - SizeType cap = this->getCapacity(); - FW_ASSERT(us); va_list args; va_start(args, formatString); - (void)vsnprintf(us, cap, formatString, args); + this->vformat(formatString, args); va_end(args); - // null terminate +} + +void StringBase::vformat(const CHAR* formatString, va_list args) { + CHAR* us = const_cast(this->toChar()); + SizeType cap = this->getCapacity(); + FW_ASSERT(us != nullptr); + FW_ASSERT(formatString != nullptr); +#if FW_USE_PRINTF_FAMILY_FUNCTIONS_IN_STRING_FORMATTING + (void) vsnprintf(us, cap, formatString, args); +#else + *this = formatString; +#endif + // Force null terminate us[cap - 1] = 0; } diff --git a/Fw/Types/StringBase.hpp b/Fw/Types/StringBase.hpp index 11fcc7dfca..a0fddc0cbd 100644 --- a/Fw/Types/StringBase.hpp +++ b/Fw/Types/StringBase.hpp @@ -15,6 +15,7 @@ #include #include +#include #ifdef BUILD_UT #include #endif @@ -62,6 +63,7 @@ class StringBase : public Serializable { StringBase& operator=(const StringBase& src); //!< Assign another StringBase void format(const CHAR* formatString, ...); //!< write formatted string to buffer + void vformat(const CHAR* formatString, va_list args); //!< write formatted string to buffer using va_list virtual SerializeStatus serialize(SerializeBufferBase& buffer) const; //!< serialization function virtual SerializeStatus serialize(SerializeBufferBase& buffer, SizeType maxLen) const; //!< serialization function diff --git a/Fw/Types/StringUtils.cpp b/Fw/Types/StringUtils.cpp index 4f1417b587..f865836d36 100644 --- a/Fw/Types/StringUtils.cpp +++ b/Fw/Types/StringUtils.cpp @@ -4,6 +4,22 @@ #include char* Fw::StringUtils::string_copy(char* destination, const char* source, U32 num) { + // Check for size support + FW_ASSERT(std::numeric_limits::max() <= std::numeric_limits::max()); + char* returned = Fw::StringUtils::string_copy(destination, source, static_cast(num)); + return returned; +} + +U32 Fw::StringUtils::string_length(const CHAR* source, U32 max_len) { + // Check for size support + FW_ASSERT(std::numeric_limits::max() <= std::numeric_limits::max()); + FwSizeType returned = Fw::StringUtils::string_length(source, static_cast(max_len)); + // Range checking for type remapping + FW_ASSERT(returned <= static_cast(std::numeric_limits::max())); + return static_cast(returned); +} + +char* Fw::StringUtils::string_copy(char* destination, const char* source, FwSizeType num) { // Handle self-copy and 0 bytes copy if (destination == source || num == 0) { return destination; @@ -12,7 +28,7 @@ char* Fw::StringUtils::string_copy(char* destination, const char* source, U32 nu FW_ASSERT(destination != nullptr); // Copying an overlapping range is undefined - U32 source_len = string_length(source, num) + 1; + FwSizeType source_len = string_length(source, num) + 1; FW_ASSERT(source + source_len <= destination || destination + num <= source); char* returned = strncpy(destination, source, num); @@ -20,7 +36,7 @@ char* Fw::StringUtils::string_copy(char* destination, const char* source, U32 nu return returned; } -U32 Fw::StringUtils::string_length(const CHAR* source, U32 max_len) { +FwSizeType Fw::StringUtils::string_length(const CHAR* source, FwSizeType max_len) { U32 length = 0; FW_ASSERT(source != nullptr); for (length = 0; length < max_len; length++) { diff --git a/Fw/Types/StringUtils.hpp b/Fw/Types/StringUtils.hpp index 800efc7bcd..be1a46ea37 100644 --- a/Fw/Types/StringUtils.hpp +++ b/Fw/Types/StringUtils.hpp @@ -32,6 +32,33 @@ char* string_copy(char* destination, const char* source, U32 num); */ U32 string_length(const CHAR* source, U32 max_len); +/** + * \brief copy string with null-termination guaranteed + * + * Standard implementations of strncpy fail to guarantee the termination of a + * string with the null terminator. This implementation guarantees the string is + * properly null-terminated at the possible expense of the last character of the + * copied string being lost. The user is responsible for providing a destination + * large enough for the content and a null-character. Other behavior retains the + * behavior of strncpy. + * + * \param destination: destination buffer to hold copied contents + * \param source: source buffer to read content to copy + * \param num: length of destination buffer + * \return destination buffer + */ +char* string_copy(char* destination, const char* source, FwSizeType num); + +/** + * \brief get the length of the source string or max_len if the string is + * longer than max_len. + * + * \param source: string to calculate the length + * \param max_len: the maximum length of the source string + * \return length of the source string or max_len + */ +FwSizeType string_length(const CHAR* source, FwSizeType max_len); + /** * \brief find the first occurrence of a substring * diff --git a/Fw/Types/test/ut/TypesTest.cpp b/Fw/Types/test/ut/TypesTest.cpp index 197aade022..20b801306a 100644 --- a/Fw/Types/test/ut/TypesTest.cpp +++ b/Fw/Types/test/ut/TypesTest.cpp @@ -1249,8 +1249,8 @@ TEST(Nominal, string_copy) { char buffer_out_test[10]; char buffer_out_truth[10]; - char* out_truth = ::strncpy(buffer_out_truth, copy_string, sizeof(buffer_out_truth)); - char* out_test = Fw::StringUtils::string_copy(buffer_out_test, copy_string, sizeof(buffer_out_test)); + char* out_truth = ::strncpy(buffer_out_truth, copy_string, static_cast(sizeof(buffer_out_truth))); + char* out_test = Fw::StringUtils::string_copy(buffer_out_test, copy_string, static_cast(sizeof(buffer_out_test))); ASSERT_EQ(sizeof(buffer_out_truth), sizeof(buffer_out_test)) << "Buffer size mismatch"; @@ -1275,8 +1275,8 @@ TEST(OffNominal, string_copy) { char buffer_out_test[sizeof(copy_string) - 1]; char buffer_out_truth[sizeof(copy_string) - 1]; - char* out_truth = ::strncpy(buffer_out_truth, copy_string, sizeof(buffer_out_truth)); - char* out_test = Fw::StringUtils::string_copy(buffer_out_test, copy_string, sizeof(buffer_out_test)); + char* out_truth = ::strncpy(buffer_out_truth, copy_string, static_cast(sizeof(buffer_out_truth))); + char* out_test = Fw::StringUtils::string_copy(buffer_out_test, copy_string, static_cast(sizeof(buffer_out_test))); ASSERT_EQ(sizeof(buffer_out_truth), sizeof(buffer_out_test)) << "Buffer size mismatch"; @@ -1296,13 +1296,13 @@ TEST(OffNominal, string_copy) { TEST(Nominal, string_len) { const char* test_string = "abc123"; - ASSERT_EQ(Fw::StringUtils::string_length(test_string, 50), 6); - ASSERT_EQ(Fw::StringUtils::string_length(test_string, 3), 3); + ASSERT_EQ(Fw::StringUtils::string_length(test_string, static_cast(50)), 6); + ASSERT_EQ(Fw::StringUtils::string_length(test_string, static_cast(3)), 3); } TEST(OffNominal, string_len_zero) { const char* test_string = "abc123"; - ASSERT_EQ(Fw::StringUtils::string_length(test_string, 0), 0); + ASSERT_EQ(Fw::StringUtils::string_length(test_string, static_cast(0)), 0); } TEST(OffNominal, sub_string_no_match) { diff --git a/Os/CMakeLists.txt b/Os/CMakeLists.txt index 6119e93668..f208c3184f 100644 --- a/Os/CMakeLists.txt +++ b/Os/CMakeLists.txt @@ -48,7 +48,7 @@ endif() # Posix systems typically share these if (FPRIME_USE_POSIX) list(APPEND SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/LogPrintf.cpp" + "${CMAKE_CURRENT_LIST_DIR}/Console.cpp" "${CMAKE_CURRENT_LIST_DIR}/Pthreads/Queue.cpp" "${CMAKE_CURRENT_LIST_DIR}/Pthreads/BufferQueueCommon.cpp" "${CMAKE_CURRENT_LIST_DIR}/Pthreads/PriorityBufferQueue.cpp" diff --git a/Os/Console.cpp b/Os/Console.cpp new file mode 100644 index 0000000000..5cdd52bde3 --- /dev/null +++ b/Os/Console.cpp @@ -0,0 +1,69 @@ +// ====================================================================== +// \title Os/Console.cpp +// \brief common function implementation for Os::Console +// ====================================================================== +#include +#include + +namespace Os { + Console* Console::s_singleton; + + Console::Console() : ConsoleInterface(), Fw::Logger(), m_handle_storage(), m_delegate(*ConsoleInterface::getDelegate(m_handle_storage)) {} + + Console::~Console() { + FW_ASSERT(&this->m_delegate == reinterpret_cast(&this->m_handle_storage[0])); + m_delegate.~ConsoleInterface(); + } + + Console::Console(const Console& other) : + m_handle_storage(), + m_delegate(*Console::getDelegate(m_handle_storage, &other.m_delegate)) { + FW_ASSERT(&this->m_delegate == reinterpret_cast(&this->m_handle_storage[0])); + } + + Console& Console::operator=(const Console& other) { + FW_ASSERT(&this->m_delegate == reinterpret_cast(&this->m_handle_storage[0])); + if (this != &other) { + this->m_delegate = *ConsoleInterface::getDelegate(m_handle_storage, &other.m_delegate); + } + return *this; + } + + void Console::writeMessage(const CHAR *message, const FwSizeType size) { + FW_ASSERT(&this->m_delegate == reinterpret_cast(&this->m_handle_storage)); + FW_ASSERT(message != nullptr || size == 0); + this->m_delegate.writeMessage(message, size); + } + + void Console::writeMessage(const Fw::StringBase& message) { + this->writeMessage(message.toChar(), message.length()); + } + + ConsoleHandle* Console::getHandle() { + FW_ASSERT(&this->m_delegate == reinterpret_cast(&this->m_handle_storage)); + return this->m_delegate.getHandle(); + } + + void Console::write(const CHAR *message, const FwSizeType size) { + Console::getSingleton().writeMessage(message, size); + } + + void Console::write(const Fw::StringBase& message) { + Console::getSingleton().writeMessage(message.toChar(), message.length()); + } + + void Console::init() { + // Force trigger on the fly singleton setup + (void) Console::getSingleton(); + } + + Console& Console::getSingleton() { + // On the fly construction of singleton + if (s_singleton == nullptr) { + s_singleton = new Console(); + Fw::Logger::registerLogger(s_singleton); + } + return *s_singleton; + } +} + diff --git a/Os/Console.hpp b/Os/Console.hpp new file mode 100644 index 0000000000..9ff47ab3f8 --- /dev/null +++ b/Os/Console.hpp @@ -0,0 +1,140 @@ +// ====================================================================== +// \title Os/Console.hpp +// \brief common function definitions for Os::Console +// ====================================================================== +#ifndef Os_Console_hpp_ +#define Os_Console_hpp_ + +#include +#include +#include +#include + +namespace Os { + //! \brief Base class for storing implementation specific handle information + struct ConsoleHandle { + }; + + // \brief Interface defining the properties of the console + class ConsoleInterface { + public: + //! \brief Default constructor + ConsoleInterface() = default; + + //! \brief Default destructor + virtual ~ConsoleInterface() = default; + + //! \brief write message to console + //! + //! Write a message to the console with a bounded size. + //! + //! \param message: raw message to write + //! \param size: size of the message to write to the console + virtual void writeMessage(const CHAR *message, const FwSizeType size) = 0; + + //! \brief returns the raw console handle + //! + //! Gets the raw console handle from the implementation. Note: users must include the implementation specific + //! header to make any real use of this handle. Otherwise it will be as an opaque type. + //! + //! \return raw console handle + //! + virtual ConsoleHandle *getHandle() = 0; + + //! \brief provide a pointer to a console delegate object + //! + //! This function must return a pointer to a `ConsoleInterface` object that contains the real implementation of + //! the console functions as defined by the implementor. This function must do several things to be considered + //! correctly implemented: + //! + //! 1. Assert that their implementation fits within FW_HANDLE_MAX_SIZE. + //! e.g. `static_assert(sizeof(PosixFileImplementation) <= sizeof Os::File::m_handle_storage, + //! "FW_HANDLE_MAX_SIZE too small");` + //! 2. Assert that their implementation aligns within FW_HANDLE_ALIGNMENT. + //! e.g. `static_assert((FW_HANDLE_ALIGNMENT % alignof(PosixFileImplementation)) == 0, "Bad handle alignment");` + //! 3. If to_copy is null, placement new their implementation into `aligned_placement_new_memory` + //! e.g. `FileInterface* interface = new (aligned_placement_new_memory) PosixFileImplementation;` + //! 4. If to_copy is non-null, placement new using copy constructor their implementation into + //! `aligned_placement_new_memory` + //! e.g. `FileInterface* interface = new (aligned_placement_new_memory) PosixFileImplementation(*to_copy);` + //! 5. Return the result of the placement new + //! e.g. `return interface;` + //! + //! \return result of placement new, must be equivalent to `aligned_placement_new_memory` + //! + static ConsoleInterface* getDelegate(HandleStorage& aligned_placement_new_memory, const ConsoleInterface* to_copy=nullptr); + }; + + class Console : public ConsoleInterface, public Fw::Logger { + public: + //! \brief Default constructor + Console(); + + //! \brief Default destructor + ~Console(); + + //! \brief copy constructor that copies the internal representation + Console(const Console& other); + + //! \brief assignment operator that copies the internal representation + Console& operator=(const Console& other); + + //! \brief write message to console + //! + //! Write a message to the console with a bounded size. This will delegate to the implementation defined write + //! method. + //! + //! \param message: raw message to write + //! \param size: size of the message to write to the console + void writeMessage(const CHAR *message, const FwSizeType size) override; + + //! \brief write message to console + //! + //! Write a message to the console as stored as a StringBase + //! + //! \param message: raw message to write (StringBase) + void writeMessage(const Fw::StringBase& message) override; + + //! \brief returns the raw console handle + //! + //! Gets the raw console handle from the implementation. Note: users must include the implementation specific + //! header to make any real use of this handle. Otherwise it will be as an opaque type. + //! + //! \return raw console handle + //! + ConsoleHandle *getHandle() override; + + //! \brief write message to console + //! + //! Write a message to the console as stored as a StringBase + //! + //! \param message: raw message to write (StringBase) + static void write(const Fw::StringBase& message); + + //! \brief write message to the global console + //! + //! Write a message to the console with a bounded size. This will delegate to the global singleton + //! implementation. + //! + //! \param message: raw message to write + //! \param size: size of the message to write to the console + static void write(const CHAR *message, const FwSizeType size); + + //! \brief initialize singleton + static void init(); + + //! \brief get a reference to singleton + //! \return reference to singleton + static Console& getSingleton(); + + private: + static Console* s_singleton; + // This section is used to store the implementation-defined console handle. To Os::Console and fprime, this type + // is opaque and thus normal allocation cannot be done. Instead, we allow the implementor to store then handle + // in the byte-array here and set `handle` to that address for storage. + alignas(FW_HANDLE_ALIGNMENT) HandleStorage m_handle_storage; // Storage for the delegate + ConsoleInterface &m_delegate; //!< Delegate for the real implementation + }; +} + +#endif diff --git a/Os/File.hpp b/Os/File.hpp index 0e7c926851..64103b47ee 100644 --- a/Os/File.hpp +++ b/Os/File.hpp @@ -179,7 +179,7 @@ namespace Os { //! \brief returns the raw file handle //! //! Gets the raw file handle from the implementation. Note: users must include the implementation specific - //! header to make any real use of this handle. Otherwise it//!must* be passed as an opaque type. + //! header to make any real use of this handle. Otherwise it will be as an opaque type. //! //! \return raw file handle //! diff --git a/Os/Log.hpp b/Os/Log.hpp deleted file mode 100644 index 0690b19cd4..0000000000 --- a/Os/Log.hpp +++ /dev/null @@ -1,52 +0,0 @@ -/** - * File: Os/Log.hpp - * Description: this file provides an implementation of the Fw::Logger class that is backed by the - * Os abstraction layer. - */ -#ifndef _Log_hpp_ -#define _Log_hpp_ - -#include -#include - -namespace Os { - class Log : public Fw::Logger { - public: - /** - * Constructor for the Os::Log object. - */ - Log(); - - /** - * Function called on the logger to log a message. This is abstract virtual method and - * must be supplied by the subclass. This logger object should be registered with the - * Fw::Log::registerLogger function. - * \param fmt: format string in which to place arguments - * \param a0: zeroth argument. (Default: 0) - * \param a1: first argument. (Default: 0) - * \param a2: second argument. (Default: 0) - * \param a3: third argument. (Default: 0) - * \param a4: fourth argument. (Default: 0) - * \param a5: fifth argument. (Default: 0) - * \param a6: sixth argument. (Default: 0) - * \param a7: seventh argument. (Default: 0) - * \param a8: eighth argument. (Default: 0) - * \param a9: ninth argument. (Default: 0) - */ - void log( - const char* fmt, - POINTER_CAST a0 = 0, - POINTER_CAST a1 = 0, - POINTER_CAST a2 = 0, - POINTER_CAST a3 = 0, - POINTER_CAST a4 = 0, - POINTER_CAST a5 = 0, - POINTER_CAST a6 = 0, - POINTER_CAST a7 = 0, - POINTER_CAST a8 = 0, - POINTER_CAST a9 = 0 - ); - }; -} - -#endif diff --git a/Os/LogDefault.cpp b/Os/LogDefault.cpp index e3dff44f0e..732c41a100 100644 --- a/Os/LogDefault.cpp +++ b/Os/LogDefault.cpp @@ -1,10 +1,10 @@ /** - * LogDefault.cpp: + * ConsoleDefault.cpp: * - * This file ensures that the Os::Log has a default instance. This means it will be created in static space here, and - * registered as the default implementation. If the user does not intend to use the default implementation of Os::Log, - * then this file can safely be ignored. + * This file ensures that the Os::Console has a default instance. This means it will be created in static space, and + * registered as the default implementation. If the user does not intend to use the default implementation of + * Os::Console, then this file Should be excluded from the build. */ -#include -Os::Log __default_logger__; // Create a default instance which will register itself in the constructor +#include +Os::Console __default_console__; // Create a default instance which will register itself in the constructor diff --git a/Os/LogPrintf.cpp b/Os/LogPrintf.cpp deleted file mode 100644 index c972599dc4..0000000000 --- a/Os/LogPrintf.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/** - * File: Os/LogPrintf.cpp - * Description: an implementation on the Os::Log abstraction that routes log messages into standard - * printf calls. - */ -#include - -#include - -namespace Os { - Log::Log() { - - // Register myself as a logger at construction time. If used in unison with LogDefault.cpp, this will - // automatically create this as a default logger. - this->registerLogger(this); - } - - // Instance implementation - void Log::log( - const char* fmt, - POINTER_CAST a0, - POINTER_CAST a1, - POINTER_CAST a2, - POINTER_CAST a3, - POINTER_CAST a4, - POINTER_CAST a5, - POINTER_CAST a6, - POINTER_CAST a7, - POINTER_CAST a8, - POINTER_CAST a9 - ) { - (void) printf(fmt, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); - (void) fflush(stdout); - } -} - diff --git a/Os/Posix/CMakeLists.txt b/Os/Posix/CMakeLists.txt index c9f3b32317..9502490067 100644 --- a/Os/Posix/CMakeLists.txt +++ b/Os/Posix/CMakeLists.txt @@ -28,6 +28,27 @@ set(MOD_DEPS Os_Posix_Shared) register_fprime_module(Os_File_Posix) register_fprime_implementation(Os/File Os_File_Posix "${CMAKE_CURRENT_LIST_DIR}/DefaultFile.cpp") +#### Os/Console/Posix Section #### +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/Console.cpp" +) +set(HEADER_FILES + "${CMAKE_CURRENT_LIST_DIR}/Console.hpp" +) +set(MOD_DEPS) +register_fprime_module(Os_Console_Posix) +register_fprime_implementation(Os/Console Os_Console_Posix "${CMAKE_CURRENT_LIST_DIR}/DefaultConsole.cpp") + +#### Os/Task/Posix Unit Tests #### +set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/test/ut/PosixConsoleTests.cpp" +) +set(UT_MOD_DEPS + Os +) +choose_fprime_implementation(Os/Console Os_Console_Posix) +register_fprime_ut(PosixConsoleTest) + #### Os/File/Posix Unit Tests #### set(UT_SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/../test/ut/file/CommonTests.cpp" diff --git a/Os/Posix/Console.cpp b/Os/Posix/Console.cpp new file mode 100644 index 0000000000..477495ab45 --- /dev/null +++ b/Os/Posix/Console.cpp @@ -0,0 +1,46 @@ +// ====================================================================== +// \title Os/Posix/Console.cpp +// \brief posix implementation for Os::Console +// ====================================================================== +#include +#include +#include +#include + +namespace Os { +namespace Posix { +namespace Console { + + +void PosixConsole::writeMessage(const CHAR *message, const FwSizeType size) { + // size_t is defined as different sizes on different platforms. Since FwSizeType is likely larger than size_t + // on these platforms, and the user is unlikely to console-log more than size_t-max data, we cap the total + // size at the limit of the interface. + FwSizeType capped_size = (size <= std::numeric_limits::max()) ? size : std::numeric_limits::max(); + if (message != nullptr) { + (void)::fwrite(message, sizeof(CHAR), static_cast(capped_size), this->m_handle.m_file_descriptor); + } +} + +ConsoleHandle* PosixConsole::getHandle() { + return &this->m_handle; +} + +void PosixConsole ::setOutputStream(Stream stream) { + switch (stream) { + case STANDARD_OUT: + this->m_handle.m_file_descriptor = stdout; + break; + case STANDARD_ERROR: + this->m_handle.m_file_descriptor = stderr; + break; + default: + FW_ASSERT(0); + break; + } +} + + +} // namespace Console +} // namespace Posix +} // namespace Os diff --git a/Os/Posix/Console.hpp b/Os/Posix/Console.hpp new file mode 100644 index 0000000000..7004d1e02c --- /dev/null +++ b/Os/Posix/Console.hpp @@ -0,0 +1,85 @@ +// ====================================================================== +// \title Os/Posix/Console.hpp +// \brief posix implementation for Os::Console, header and test definitions +// ====================================================================== +#include +#include +#ifndef OS_POSIX_Console_HPP +#define OS_POSIX_Console_HPP + +namespace Os { +namespace Posix { +namespace Console { + +//! ConsoleHandle class definition for posix implementations. +//! +struct PosixConsoleHandle : public ConsoleHandle { + //! Posix console file descriptor + FILE* m_file_descriptor = stdout; +}; + +//! \brief posix implementation of Os::ConsoleInterface +//! +//! Posix implementation of `ConsoleInterface` for use as a delegate class handling posix console operations. Posix +//! consoles write to either standard out or standard error. The default file descriptor used is standard out. This may +//! be changed by calling `setOutputStream`. +//! +class PosixConsole : public ConsoleInterface { + public: + //! Stream selection enumeration + enum Stream { + STANDARD_OUT = 0, //!< Use standard output stream + STANDARD_ERROR = 1 //!< Use standard error stream + }; + //! \brief constructor + //! + PosixConsole() = default; + + //! \brief copy constructor + PosixConsole(const PosixConsole& other) = default; + + //! \brief assignment operator that copies the internal representation + PosixConsole& operator=(const PosixConsole& other) = default; + + //! \brief destructor + //! + ~PosixConsole() override = default; + + // ------------------------------------ + // Functions overrides + // ------------------------------------ + + //! \brief write message to console + //! + //! Write a message to the console with a bounded size. This will use the active file descriptor as the output + //! destination. + //! + //! \param message: raw message to write + //! \param size: size of the message to write to the console + void writeMessage(const CHAR *message, const FwSizeType size) override; + + + //! \brief returns the raw console handle + //! + //! Gets the raw console handle from the implementation. Note: users must include the implementation specific + //! header to make any real use of this handle. Otherwise it will be as an opaque type. + //! + //! \return raw console handle + //! + ConsoleHandle *getHandle() override; + + //! \brief select the output stream + //! + //! There are two streams defined: standard out, and standard error. This allows users of the posix log + //! implementation to chose which stream to use. + void setOutputStream(Stream stream); + + private: + //! File handle for PosixFile + PosixConsoleHandle m_handle; +}; +} // namespace Console +} // namespace Posix +} // namespace Os + +#endif // OS_POSIX_Console_HPP diff --git a/Os/Posix/DefaultConsole.cpp b/Os/Posix/DefaultConsole.cpp new file mode 100644 index 0000000000..8a3b8f75cc --- /dev/null +++ b/Os/Posix/DefaultConsole.cpp @@ -0,0 +1,13 @@ +// ====================================================================== +// \title Os/Posix/DefaultConsole.cpp +// \brief sets default Os::Console to posix implementation via linker +// ====================================================================== +#include "Os/Console.hpp" +#include "Os/Posix/Console.hpp" +#include "Os/Delegate.hpp" + +namespace Os { +ConsoleInterface* ConsoleInterface::getDelegate(HandleStorage& aligned_new_memory, const ConsoleInterface* to_copy) { + return Os::Delegate::makeDelegate(aligned_new_memory, to_copy); +} +} diff --git a/Os/Posix/Task.cpp b/Os/Posix/Task.cpp index 2e29f7b29b..b7e007f33b 100644 --- a/Os/Posix/Task.cpp +++ b/Os/Posix/Task.cpp @@ -35,32 +35,32 @@ namespace Task { // Check for stack size multiple of page size long page_size = sysconf(_SC_PAGESIZE); if (page_size <= 0) { - Fw::Logger::logMsg( + Fw::Logger::log( "[WARNING] %s could not determine page size %s. Skipping stack-size check.\n", - reinterpret_cast(const_cast(arguments.m_name.toChar())), - reinterpret_cast(strerror(errno)) + const_cast(arguments.m_name.toChar()), + strerror(errno) ); } else if ((stack % static_cast(page_size)) != 0) { // Round-down to nearest page size multiple FwSizeType rounded = (stack / static_cast(page_size)) * static_cast(page_size); - Fw::Logger::logMsg( + Fw::Logger::log( "[WARNING] %s stack size of %" PRI_FwSizeType " is not multiple of page size %ld, rounding to %" PRI_FwSizeType "\n", - reinterpret_cast(const_cast(arguments.m_name.toChar())), - static_cast(stack), - static_cast(page_size), - static_cast(rounded) + const_cast(arguments.m_name.toChar()), + stack, + page_size, + rounded ); stack = rounded; } // Clamp invalid stack sizes if (stack <= static_cast(PTHREAD_STACK_MIN)) { - Fw::Logger::logMsg( + Fw::Logger::log( "[WARNING] %s stack size of %" PRI_FwSizeType " is too small, clamping to %" PRI_FwSizeType "\n", - reinterpret_cast(const_cast(arguments.m_name.toChar())), - static_cast(stack), - static_cast(static_cast(PTHREAD_STACK_MIN)) + const_cast(arguments.m_name.toChar()), + stack, + static_cast(PTHREAD_STACK_MIN) ); stack = static_cast(PTHREAD_STACK_MIN); } @@ -75,18 +75,18 @@ namespace Task { FwSizeType priority = arguments.m_priority; // Clamp to minimum priority if (priority < min_priority) { - Fw::Logger::logMsg("[WARNING] %s low task priority of %" PRI_FwSizeType " clamped to %" PRI_FwSizeType "\n", - reinterpret_cast(const_cast(arguments.m_name.toChar())), - static_cast(priority), - static_cast(min_priority)); + Fw::Logger::log("[WARNING] %s low task priority of %" PRI_FwSizeType " clamped to %" PRI_FwSizeType "\n", + const_cast(arguments.m_name.toChar()), + priority, + min_priority); priority = min_priority; } // Clamp to maximum priority else if (priority > max_priority) { - Fw::Logger::logMsg("[WARNING] %s high task priority of %" PRI_FwSizeType " clamped to %" PRI_FwSizeType "\n", - reinterpret_cast(const_cast(arguments.m_name.toChar())), - static_cast(priority), - static_cast(max_priority)); + Fw::Logger::log("[WARNING] %s high task priority of %" PRI_FwSizeType " clamped to %" PRI_FwSizeType "\n", + const_cast(arguments.m_name.toChar()), + priority, + max_priority); priority = max_priority; } @@ -117,8 +117,8 @@ namespace Task { status = pthread_attr_setaffinity_np(&attributes, sizeof(cpu_set_t), &cpu_set); status = (status == PosixTaskHandle::SUCCESS) ? status : errno; #else - Fw::Logger::logMsg("[WARNING] %s setting CPU affinity is only available with GNU pthreads\n", - reinterpret_cast(const_cast(arguments.m_name.toChar()))); + Fw::Logger::log("[WARNING] %s setting CPU affinity is only available with GNU pthreads\n", + const_cast(arguments.m_name.toChar())); #endif return status; } @@ -163,24 +163,24 @@ namespace Task { // Failure due to permission automatically retried if (status == Os::Task::Status::ERROR_PERMISSION) { if (not PosixTask::s_permissions_reported) { - Fw::Logger::logMsg("\n"); - Fw::Logger::logMsg("[NOTE] Task Permissions:\n"); - Fw::Logger::logMsg("[NOTE]\n"); - Fw::Logger::logMsg("[NOTE] You have insufficient permissions to create a task with priority and/or cpu affinity.\n"); - Fw::Logger::logMsg("[NOTE] A task without priority and affinity will be created.\n"); - Fw::Logger::logMsg("[NOTE]\n"); - Fw::Logger::logMsg("[NOTE] There are three possible resolutions:\n"); - Fw::Logger::logMsg("[NOTE] 1. Use tasks without priority and affinity using parameterless start()\n"); - Fw::Logger::logMsg("[NOTE] 2. Run this executable as a user with task priority permission\n"); - Fw::Logger::logMsg("[NOTE] 3. Grant capability with \"setcap 'cap_sys_nice=eip'\" or equivalent\n"); - Fw::Logger::logMsg("\n"); + Fw::Logger::log("\n"); + Fw::Logger::log("[NOTE] Task Permissions:\n"); + Fw::Logger::log("[NOTE]\n"); + Fw::Logger::log("[NOTE] You have insufficient permissions to create a task with priority and/or cpu affinity.\n"); + Fw::Logger::log("[NOTE] A task without priority and affinity will be created.\n"); + Fw::Logger::log("[NOTE]\n"); + Fw::Logger::log("[NOTE] There are three possible resolutions:\n"); + Fw::Logger::log("[NOTE] 1. Use tasks without priority and affinity using parameterless start()\n"); + Fw::Logger::log("[NOTE] 2. Run this executable as a user with task priority permission\n"); + Fw::Logger::log("[NOTE] 3. Grant capability with \"setcap 'cap_sys_nice=eip'\" or equivalent\n"); + Fw::Logger::log("\n"); PosixTask::s_permissions_reported = true; } // Fallback with no permission status = this->create(arguments, PermissionExpectation::EXPECT_NO_PERMISSION); } else if (status != Os::Task::Status::OP_OK) { - Fw::Logger::logMsg("[ERROR] Failed to create task with status: %d", - static_cast(static_cast(status))); + Fw::Logger::log("[ERROR] Failed to create task with status: %d", + static_cast(status)); } return status; } diff --git a/Os/Posix/test/ut/PosixConsoleTests.cpp b/Os/Posix/test/ut/PosixConsoleTests.cpp new file mode 100644 index 0000000000..b790e2305a --- /dev/null +++ b/Os/Posix/test/ut/PosixConsoleTests.cpp @@ -0,0 +1,29 @@ +// ====================================================================== +// \title Os/Posix/test/ut/PosixFileTests.cpp +// \brief tests for posix implementation for Os::File +// ====================================================================== +#include +#include "Os/Console.hpp" +#include "Os/Posix/Console.hpp" + + +TEST(Nominal, SwitchStream) { + Os::Posix::Console::PosixConsole posix_console; + ASSERT_EQ(reinterpret_cast(posix_console.getHandle())->m_file_descriptor, + stdout); + posix_console.setOutputStream(Os::Posix::Console::PosixConsole::Stream::STANDARD_ERROR); + ASSERT_EQ(reinterpret_cast(posix_console.getHandle())->m_file_descriptor, + stderr); + posix_console.setOutputStream(Os::Posix::Console::PosixConsole::Stream::STANDARD_OUT); + ASSERT_EQ(reinterpret_cast(posix_console.getHandle())->m_file_descriptor, + stdout); +} +TEST(OffNominal, SwitchStream) { + Os::Posix::Console::PosixConsole posix_console; + ASSERT_DEATH(posix_console.setOutputStream(static_cast(3)), "Posix/|\\Console.cpp:33"); +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/Os/Pthreads/MaxHeap/MaxHeap.cpp b/Os/Pthreads/MaxHeap/MaxHeap.cpp index 347566f95a..42e1c0c502 100644 --- a/Os/Pthreads/MaxHeap/MaxHeap.cpp +++ b/Os/Pthreads/MaxHeap/MaxHeap.cpp @@ -125,7 +125,7 @@ namespace Os { // This will put the smallest value in the // heap on the top, violating the heap property. NATIVE_UINT_TYPE index = this->m_size-1; - // Fw::Logger::logMsg("Putting on top: i: %u v: %d\n", index, this->m_heap[index].value); + // Fw::Logger::log("Putting on top: i: %u v: %d\n", index, this->m_heap[index].value); this->m_heap[0]= this->m_heap[index]; --this->m_size; @@ -202,7 +202,7 @@ namespace Os { } // Swap the largest node with the current node: - // Fw::Logger::logMsg("Swapping: i: %u v: %d with i: %u v: %d\n", + // Fw::Logger::log("Swapping: i: %u v: %d with i: %u v: %d\n", // index, this->m_heap[index].value, // largest, this->m_heap[largest].value); this->swap(index, largest); @@ -263,25 +263,25 @@ namespace Os { NATIVE_UINT_TYPE index = 0; NATIVE_UINT_TYPE left; NATIVE_UINT_TYPE right; - Fw::Logger::logMsg("Printing Heap of Size: %d\n", this->m_size); + Fw::Logger::log("Printing Heap of Size: %d\n", this->m_size); while(index < this->m_size) { left = LCHILD(index); right = RCHILD(index); if( left >= m_size && index == 0) { - Fw::Logger::logMsg("i: %u v: %d d: %u -> (NULL, NULL)\n", - index, static_cast(this->m_heap[index].value), this->m_heap[index].id); + Fw::Logger::log("i: %u v: %d d: %u -> (NULL, NULL)\n", + index, this->m_heap[index].value, this->m_heap[index].id); } else if( right >= m_size && left < m_size ) { - Fw::Logger::logMsg("i: %u v: %d d: %u -> (i: %u v: %d d: %u, NULL)\n", - index, static_cast(this->m_heap[index].value), this->m_heap[index].id, - left, static_cast(this->m_heap[left].value), this->m_heap[left].id); + Fw::Logger::log("i: %u v: %d d: %u -> (i: %u v: %d d: %u, NULL)\n", + index, this->m_heap[index].value, this->m_heap[index].id, + left, this->m_heap[left].value, this->m_heap[left].id); } else if( right < m_size && left < m_size ) { - Fw::Logger::logMsg("i: %u v: %d d: %u -> (i: %u v: %d d: %u, i: %u v: %d d: %u)\n", - index, static_cast(this->m_heap[index].value), this->m_heap[index].id, - left, static_cast(this->m_heap[left].value),this->m_heap[left].id, - right, static_cast(this->m_heap[right].value), this->m_heap[right].id); + Fw::Logger::log("i: %u v: %d d: %u -> (i: %u v: %d d: %u, i: %u v: %d d: %u)\n", + index, this->m_heap[index].value, this->m_heap[index].id, + left, this->m_heap[left].value,this->m_heap[left].id, + right, this->m_heap[right].value, this->m_heap[right].id); } ++index; diff --git a/Os/Stub/CMakeLists.txt b/Os/Stub/CMakeLists.txt index 0d793eeb29..75b9271f2b 100644 --- a/Os/Stub/CMakeLists.txt +++ b/Os/Stub/CMakeLists.txt @@ -50,6 +50,32 @@ set(UT_MOD_DEPS choose_fprime_implementation(Os/File Os_File_Test_Stub) register_fprime_ut(StubFileTest) +#### Console Stub Testing #### +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/Console.cpp" +) +set(HEADER_FILES + "${CMAKE_CURRENT_LIST_DIR}/Console.hpp" +) +set(MOD_DEPS) +register_fprime_module(Os_Console_Stub) +register_fprime_implementation(Os/Console Os_Console_Stub "${CMAKE_CURRENT_LIST_DIR}/DefaultConsole.cpp") + +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/test/Console.cpp" +) +set(MOD_DEPS) +register_fprime_module(Os_Console_Test_Stub) +register_fprime_implementation(Os/Console Os_Console_Test_Stub "${CMAKE_CURRENT_LIST_DIR}/test/DefaultConsole.cpp") + +set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/test/ut/StubConsoleTests.cpp" +) +set(UT_MOD_DEPS) +choose_fprime_implementation(Os/Console Os_Console_Test_Stub) +register_fprime_ut(StubConsoleTest) + + #### Task Stub Testing #### set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/test/Task.cpp" diff --git a/Os/Stub/Console.cpp b/Os/Stub/Console.cpp new file mode 100644 index 0000000000..d8cc0d35fb --- /dev/null +++ b/Os/Stub/Console.cpp @@ -0,0 +1,23 @@ +// ====================================================================== +// \title Os/Stub/Console.cpp +// \brief stub implementation for Os::Console +// ====================================================================== +#include + +namespace Os { +namespace Stub { +namespace Console { + + +void StubConsole::writeMessage(const CHAR *message, const FwSizeType size) { +} + +ConsoleHandle* StubConsole::getHandle() { + return &this->m_handle; +} + + + +} // namespace Console +} // namespace Stub +} // namespace Os diff --git a/Os/Stub/Console.hpp b/Os/Stub/Console.hpp new file mode 100644 index 0000000000..2d70b77b4e --- /dev/null +++ b/Os/Stub/Console.hpp @@ -0,0 +1,68 @@ +// ====================================================================== +// \title Os/Stub/Console.hpp +// \brief stub implementation for Os::Console, header and test definitions +// ====================================================================== +#include +#include +#ifndef OS_Stub_Console_HPP +#define OS_Stub_Console_HPP + +namespace Os { +namespace Stub { +namespace Console { + +//! ConsoleHandle class definition for stub implementations. +//! +struct StubConsoleHandle : public ConsoleHandle { +}; + +//! \brief stub implementation of Os::ConsoleInterface +//! +//! Stub implementation of `ConsoleInterface` for use as a delegate class handling stub console operations. +//! +class StubConsole : public ConsoleInterface { + public: + //! \brief constructor + //! + StubConsole() = default; + + //! \brief copy constructor + StubConsole(const StubConsole& other) = default; + + //! \brief default copy assignment + StubConsole& operator=(const StubConsole& other) = default; + + //! \brief destructor + //! + ~StubConsole() override = default; + + // ------------------------------------ + // Functions overrides + // ------------------------------------ + + //! \brief write message to console + //! + //! Write a message to the console with a bounded size. This will use the active file descriptor as the output + //! destination. + //! + //! \param message: raw message to write + //! \param size: size of the message to write to the console + void writeMessage(const CHAR *message, const FwSizeType size) override; + + //! \brief returns the raw console handle + //! + //! Gets the raw console handle from the implementation. Note: users must include the implementation specific + //! header to make any real use of this handle. Otherwise it will be as an opaque type. + //! + //! \return raw console handle + //! + ConsoleHandle *getHandle() override; + private: + //! File handle for PosixFile + StubConsoleHandle m_handle; +}; +} // namespace Console +} // namespace Stub +} // namespace Os + +#endif // OS_Stub_Console_HPP diff --git a/Os/Stub/DefaultConsole.cpp b/Os/Stub/DefaultConsole.cpp new file mode 100644 index 0000000000..91b11a1f66 --- /dev/null +++ b/Os/Stub/DefaultConsole.cpp @@ -0,0 +1,13 @@ +// ====================================================================== +// \title Os/Stub/DefaultConsole.cpp +// \brief sets default Os::Console to stub implementation via linker +// ====================================================================== +#include "Os/Console.hpp" +#include "Os/Stub/Console.hpp" +#include "Os/Delegate.hpp" + +namespace Os { +ConsoleInterface* ConsoleInterface::getDelegate(HandleStorage& aligned_new_memory, const ConsoleInterface* to_copy) { + return Os::Delegate::makeDelegate(aligned_new_memory, to_copy); +} +} diff --git a/Os/Stub/test/Console.cpp b/Os/Stub/test/Console.cpp new file mode 100644 index 0000000000..7d83e3833e --- /dev/null +++ b/Os/Stub/test/Console.cpp @@ -0,0 +1,41 @@ +// ====================================================================== +// \title Os/Stub/Console.cpp +// \brief stub implementation for Os::Console +// ====================================================================== +#include + +namespace Os { +namespace Stub { +namespace Console { +namespace Test { + +StaticData StaticData::data; + +TestConsole::TestConsole() { + StaticData::data.lastCalled = StaticData::LastFn::CONSTRUCT_FN; +} + +TestConsole::~TestConsole() { + StaticData::data.lastCalled = StaticData::LastFn::DESTRUCT_FN; +} + +TestConsole::TestConsole(const Os::Stub::Console::Test::TestConsole& other) { + StaticData::data.lastCalled = StaticData::LastFn::CONSTRUCT_COPY_FN; + StaticData::data.copyObject = &other; + this->m_handle = other.m_handle; +} + +void TestConsole::writeMessage(const CHAR* message, const FwSizeType size) { + StaticData::data.message = message; + StaticData::data.size = size; + StaticData::data.lastCalled = StaticData::LastFn::WRITE_FN; +} + +ConsoleHandle* TestConsole::getHandle() { + return &this->m_handle; +} + +} // namespace Test +} // namespace Console +} // namespace Stub +} // namespace Os diff --git a/Os/Stub/test/Console.hpp b/Os/Stub/test/Console.hpp new file mode 100644 index 0000000000..9ef135afa3 --- /dev/null +++ b/Os/Stub/test/Console.hpp @@ -0,0 +1,98 @@ +// ====================================================================== +// \title Os/Stub/test/Console.hpp +// \brief test stub implementation for Os::Console, header and test definitions +// ====================================================================== +#include +#include +#ifndef OS_Stub_Test_Console_HPP +#define OS_Stub_Test_Console_HPP + +namespace Os { +namespace Stub { +namespace Console { +namespace Test { + +class TestConsole; + +//! Data that supports the stubbed File implementation. +//!/ +struct StaticData { + enum LastFn { + NONE_FN, + CONSTRUCT_FN, + CONSTRUCT_COPY_FN, + COPY_FN, + DESTRUCT_FN, + WRITE_FN, + }; + //! Last function called + LastFn lastCalled = NONE_FN; + //! Copy object + const TestConsole* copyObject; + + //! Last message passed + const CHAR* message = nullptr; + //! Last size passed + FwSizeType size = 0; + + // Singleton data + static StaticData data; +}; + +//! ConsoleHandle class definition for stub implementations. +//! +struct TestConsoleHandle : public ConsoleHandle { +}; + +//! \brief stub implementation of Os::ConsoleInterface +//! +//! Stub implementation of `ConsoleInterface` for use as a delegate class handling stub console operations. +//! +class TestConsole : public ConsoleInterface { + public: + //! \brief constructor + //! + TestConsole(); + + //! \brief copy constructor + TestConsole(const TestConsole& other); + + //! \brief assignment operator that copies the internal representation + TestConsole& operator=(const TestConsole& other) = delete; + + //! \brief destructor + //! + ~TestConsole() override; + + // ------------------------------------ + // Functions overrides + // ------------------------------------ + + //! \brief write message to console + //! + //! Write a message to the console with a bounded size. This will use the active file descriptor as the output + //! destination. + //! + //! \param message: raw message to write + //! \param size: size of the message to write to the console + void writeMessage(const CHAR* message, const FwSizeType size) override; + + //! \brief returns the raw console handle + //! + //! Gets the raw console handle from the implementation. Note: users must include the implementation specific + //! header to make any real use of this handle. Otherwise it will be as an opaque type. + //! + //! \return raw console handle + //! + ConsoleHandle* getHandle() override; + + private: + //! File handle for PosixFile + TestConsoleHandle m_handle; +}; +} // namespace Test +} // namespace Console +} // namespace Stub +} // namespace Os + +#endif // OS_Stub_Test_Console_HPP diff --git a/Os/Stub/test/DefaultConsole.cpp b/Os/Stub/test/DefaultConsole.cpp new file mode 100644 index 0000000000..21a9f57f01 --- /dev/null +++ b/Os/Stub/test/DefaultConsole.cpp @@ -0,0 +1,13 @@ +// ====================================================================== +// \title Os/Stub/test/DefaultConsole.cpp +// \brief sets default Os::Console to stub test implementation via linker +// ====================================================================== +#include "Os/Console.hpp" +#include "Os/Stub/test/Console.hpp" +#include "Os/Delegate.hpp" + +namespace Os { +ConsoleInterface* ConsoleInterface::getDelegate(HandleStorage& aligned_new_memory, const ConsoleInterface* to_copy) { + return Os::Delegate::makeDelegate(aligned_new_memory, to_copy); +} +} diff --git a/Os/Stub/test/ut/StubConsoleTests.cpp b/Os/Stub/test/ut/StubConsoleTests.cpp new file mode 100644 index 0000000000..61bae28618 --- /dev/null +++ b/Os/Stub/test/ut/StubConsoleTests.cpp @@ -0,0 +1,53 @@ +// ====================================================================== +// \title Os/Stub/test/ut/StubFileTests.cpp +// \brief tests using stub implementation for Os::File interface testing +// ====================================================================== +#include +#include "Os/Console.hpp" +#include "Os/Stub/test/Console.hpp" + + +TEST(Interface, Construction) { + Os::Console console; + ASSERT_EQ(Os::Stub::Console::Test::StaticData::data.lastCalled, Os::Stub::Console::Test::StaticData::CONSTRUCT_FN); +} +TEST(Interface, ConstructionCopy) { + Os::Console console; + ASSERT_EQ(Os::Stub::Console::Test::StaticData::data.lastCalled, Os::Stub::Console::Test::StaticData::CONSTRUCT_FN); + Os::Console console2(console); + ASSERT_EQ(const_cast(Os::Stub::Console::Test::StaticData::data.copyObject)->getHandle(), + console.getHandle()); + ASSERT_EQ(Os::Stub::Console::Test::StaticData::data.lastCalled, Os::Stub::Console::Test::StaticData::CONSTRUCT_COPY_FN); + + +} +TEST(Interface, Copy) { + Os::Console console; + Os::Console console2; + ASSERT_EQ(Os::Stub::Console::Test::StaticData::data.lastCalled, Os::Stub::Console::Test::StaticData::CONSTRUCT_FN); + console2 = console; + ASSERT_EQ(const_cast(Os::Stub::Console::Test::StaticData::data.copyObject)->getHandle(), + console.getHandle()); + ASSERT_EQ(Os::Stub::Console::Test::StaticData::data.lastCalled, Os::Stub::Console::Test::StaticData::CONSTRUCT_COPY_FN); +} + +TEST(Interface, Destruction) { + delete (new Os::Console); + ASSERT_EQ(Os::Stub::Console::Test::StaticData::data.lastCalled, Os::Stub::Console::Test::StaticData::DESTRUCT_FN); +} + +TEST(Interface, Write) { + Os::Console console; + const char* message = "hello"; + ASSERT_EQ(Os::Stub::Console::Test::StaticData::data.lastCalled, Os::Stub::Console::Test::StaticData::CONSTRUCT_FN); + console.write(message, 6); + ASSERT_EQ(Os::Stub::Console::Test::StaticData::data.lastCalled, Os::Stub::Console::Test::StaticData::WRITE_FN); + ASSERT_EQ(Os::Stub::Console::Test::StaticData::data.message, message); + ASSERT_EQ(Os::Stub::Console::Test::StaticData::data.size, 6); + +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/RPI/Main.cpp b/RPI/Main.cpp index ab032f7d08..f4b6955e81 100644 --- a/RPI/Main.cpp +++ b/RPI/Main.cpp @@ -7,8 +7,6 @@ #include RPI::TopologyState state; -// Enable the console logging provided by Os::Log -Os::Log logger; void print_usage(const char* app) { (void) printf("Usage: ./%s [options]\n-p\tport_number\n-a\thostname/IP address\n",app); @@ -22,6 +20,7 @@ static void sighandler(int signum) { } int main(int argc, char* argv[]) { + Os::Console::init(); I32 option = 0; while ((option = getopt(argc, argv, "hp:a:")) != -1){ diff --git a/RPI/Top/RPITopologyDefs.hpp b/RPI/Top/RPITopologyDefs.hpp index cdbf9e5f5d..f434f2e9b0 100644 --- a/RPI/Top/RPITopologyDefs.hpp +++ b/RPI/Top/RPITopologyDefs.hpp @@ -2,7 +2,7 @@ #define RPITopologyDefs_HPP #include "Fw/Types/MallocAllocator.hpp" -#include "Os/Log.hpp" +#include "Os/Console.hpp" #include "RPI/Top/FppConstantsAc.hpp" #include "Svc/FramingProtocol/FprimeProtocol.hpp" #include "Svc/LinuxTimer/LinuxTimer.hpp" diff --git a/RPI/Top/instances.fpp b/RPI/Top/instances.fpp index b162f33687..992aced0cc 100644 --- a/RPI/Top/instances.fpp +++ b/RPI/Top/instances.fpp @@ -315,7 +315,7 @@ module RPI { 1024 ); if (!status) { - Fw::Logger::logMsg("[ERROR] Could not open UART driver\\n"); + Fw::Logger::log("[ERROR] Could not open UART driver\\n"); Init::status = false; } } @@ -326,7 +326,7 @@ module RPI { uartDrv.start(); } else { - Fw::Logger::logMsg("[ERROR] Initialization failed; not starting UART driver\\n"); + Fw::Logger::log("[ERROR] Initialization failed; not starting UART driver\\n"); } """ @@ -343,7 +343,7 @@ module RPI { { const bool status = ledDrv.open(21, Drv::LinuxGpioDriverComponentImpl::GPIO_OUT); if (!status) { - Fw::Logger::logMsg("[ERROR] Could not open LED driver\\n"); + Fw::Logger::log("[ERROR] Could not open LED driver\\n"); Init::status = false; } } @@ -358,7 +358,7 @@ module RPI { { const bool status = gpio23Drv.open(23, Drv::LinuxGpioDriverComponentImpl::GPIO_OUT); if (!status) { - Fw::Logger::logMsg("[ERROR] Could not open GPIO 23 driver\\n"); + Fw::Logger::log("[ERROR] Could not open GPIO 23 driver\\n"); Init::status = false; } } @@ -373,7 +373,7 @@ module RPI { { const bool status = gpio24Drv.open(24, Drv::LinuxGpioDriverComponentImpl::GPIO_OUT); if (!status) { - Fw::Logger::logMsg("[ERROR] Could not open GPIO 24 driver\\n"); + Fw::Logger::log("[ERROR] Could not open GPIO 24 driver\\n"); Init::status = false; } } @@ -388,7 +388,7 @@ module RPI { { const bool status = gpio25Drv.open(25, Drv::LinuxGpioDriverComponentImpl::GPIO_IN); if (!status) { - Fw::Logger::logMsg("[ERROR] Could not open GPIO 25 driver\\n"); + Fw::Logger::log("[ERROR] Could not open GPIO 25 driver\\n"); Init::status = false; } } @@ -403,7 +403,7 @@ module RPI { { const bool status = gpio17Drv.open(17, Drv::LinuxGpioDriverComponentImpl::GPIO_IN); if (!status) { - Fw::Logger::logMsg("[ERROR] Could not open GPIO 17 driver\\n"); + Fw::Logger::log("[ERROR] Could not open GPIO 17 driver\\n"); Init::status = false; } } @@ -418,7 +418,7 @@ module RPI { { const bool status = spiDrv.open(0, 0, Drv::SPI_FREQUENCY_1MHZ); if (!status) { - Fw::Logger::logMsg("[ERROR] Could not open SPI driver\\n"); + Fw::Logger::log("[ERROR] Could not open SPI driver\\n"); Init::status = false; } } diff --git a/Ref/Main.cpp b/Ref/Main.cpp index cff59cf6c9..0cd5895787 100644 --- a/Ref/Main.cpp +++ b/Ref/Main.cpp @@ -16,6 +16,9 @@ #include // Used for printf functions #include +// Used to get the Os::Console +#include + /** * \brief print commandline help message @@ -51,6 +54,7 @@ static void signalHandler(int signum) { * @return: 0 on success, something else on failure */ int main(int argc, char* argv[]) { + Os::Console::init(); U32 port_number = 0; I32 option = 0; char* hostname = nullptr; diff --git a/Ref/RecvBuffApp/RecvBuffComponentImpl.cpp b/Ref/RecvBuffApp/RecvBuffComponentImpl.cpp index 3ac4ca37cd..e67da07baa 100644 --- a/Ref/RecvBuffApp/RecvBuffComponentImpl.cpp +++ b/Ref/RecvBuffApp/RecvBuffComponentImpl.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/Ref/SendBuffApp/SendBuffComponentImpl.cpp b/Ref/SendBuffApp/SendBuffComponentImpl.cpp index a9335252bf..5b17c95c2d 100644 --- a/Ref/SendBuffApp/SendBuffComponentImpl.cpp +++ b/Ref/SendBuffApp/SendBuffComponentImpl.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include diff --git a/Ref/Top/RefTopology.cpp b/Ref/Top/RefTopology.cpp index cc08a20570..9cfd30cffd 100644 --- a/Ref/Top/RefTopology.cpp +++ b/Ref/Top/RefTopology.cpp @@ -14,7 +14,7 @@ // Necessary project-specified types #include -#include +#include #include // Used for 1Hz synthetic cycling @@ -23,8 +23,8 @@ // Allows easy reference to objects in FPP/autocoder required namespaces using namespace Ref; -// Instantiate a system logger that will handle Fw::Logger::logMsg calls -Os::Log logger; +// Instantiate a system logger that will handle Fw::Logger::log calls +Os::Console logger; // The reference topology uses a malloc-based allocator for components that need to allocate memory during the // initialization phase. diff --git a/Svc/ActiveRateGroup/ActiveRateGroup.cpp b/Svc/ActiveRateGroup/ActiveRateGroup.cpp index 2d94b7e030..bed4355d01 100644 --- a/Svc/ActiveRateGroup/ActiveRateGroup.cpp +++ b/Svc/ActiveRateGroup/ActiveRateGroup.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include namespace Svc { diff --git a/Svc/ActiveTextLogger/ActiveTextLogger.cpp b/Svc/ActiveTextLogger/ActiveTextLogger.cpp index d1dab9dc00..b6af87dda1 100644 --- a/Svc/ActiveTextLogger/ActiveTextLogger.cpp +++ b/Svc/ActiveTextLogger/ActiveTextLogger.cpp @@ -121,7 +121,7 @@ namespace Svc { { // Print to console: - Fw::Logger::logMsg(text.toChar(),0,0,0,0,0,0,0,0,0); + Fw::Logger::log(text); // Print to file if there is one: (void) this->m_log_file.write_to_log(text.toChar(), text.length()); // Ignoring return status diff --git a/Svc/ActiveTextLogger/LogFile.cpp b/Svc/ActiveTextLogger/LogFile.cpp index d53bb30664..927762f46f 100644 --- a/Svc/ActiveTextLogger/LogFile.cpp +++ b/Svc/ActiveTextLogger/LogFile.cpp @@ -89,7 +89,7 @@ namespace Svc { } // If file name is too large, return failure: - U32 fileNameSize = Fw::StringUtils::string_length(fileName, Fw::String::STRING_SIZE); + FwSizeType fileNameSize = Fw::StringUtils::string_length(fileName, static_cast(Fw::String::STRING_SIZE)); if (fileNameSize == Fw::String::STRING_SIZE) { return false; } diff --git a/Svc/ActiveTextLogger/test/ut/ActiveTextLoggerTester.cpp b/Svc/ActiveTextLogger/test/ut/ActiveTextLoggerTester.cpp index e01ba068d7..01314bac68 100644 --- a/Svc/ActiveTextLogger/test/ut/ActiveTextLoggerTester.cpp +++ b/Svc/ActiveTextLogger/test/ut/ActiveTextLoggerTester.cpp @@ -107,7 +107,7 @@ namespace Svc { "EVENT: (%d) (%d:%d,%d) %s: %s", id,timeTag.getTimeBase(),timeTag.getSeconds(),timeTag.getUSeconds(),severityString,text.toChar()); ASSERT_EQ(0,strcmp(textStr,buf)); - (void) Fw::StringUtils::string_copy(oldLine, buf, sizeof(oldLine)); + (void) Fw::StringUtils::string_copy(oldLine, buf, static_cast(sizeof(oldLine))); } } stream1.close(); @@ -210,7 +210,7 @@ namespace Svc { "EVENT: (%d) (%d:%d,%d) %s: %s", id,timeTag.getTimeBase(),timeTag.getSeconds(),timeTag.getUSeconds(),severityString,text.toChar()); ASSERT_EQ(0,strcmp(textStr,buf)); - (void) Fw::StringUtils::string_copy(oldLine, buf, sizeof(oldLine)); + (void) Fw::StringUtils::string_copy(oldLine, buf, static_cast(sizeof(oldLine))); } } stream1.close(); diff --git a/Svc/AssertFatalAdapter/AssertFatalAdapterComponentImpl.cpp b/Svc/AssertFatalAdapter/AssertFatalAdapterComponentImpl.cpp index 3bf3faab67..818c0dceed 100644 --- a/Svc/AssertFatalAdapter/AssertFatalAdapterComponentImpl.cpp +++ b/Svc/AssertFatalAdapter/AssertFatalAdapterComponentImpl.cpp @@ -85,7 +85,7 @@ namespace Svc { arg1,arg2,arg3,arg4,arg5,arg6); } else { // Can't assert, what else can we do? Maybe somebody will see it. - Fw::Logger::logMsg("Svc::AssertFatalAdapter not registered!\n"); + Fw::Logger::log("Svc::AssertFatalAdapter not registered!\n"); assert(0); } } diff --git a/Svc/AssertFatalAdapter/test/ut/AssertFatalAdapterTester.cpp b/Svc/AssertFatalAdapter/test/ut/AssertFatalAdapterTester.cpp index 01b5139374..217546cd13 100644 --- a/Svc/AssertFatalAdapter/test/ut/AssertFatalAdapterTester.cpp +++ b/Svc/AssertFatalAdapter/test/ut/AssertFatalAdapterTester.cpp @@ -61,7 +61,7 @@ namespace Svc { #else fileString = __FILE__; #endif - (void) Fw::StringUtils::string_copy(file, fileString.toChar(), sizeof(file)); + (void) Fw::StringUtils::string_copy(file, fileString.toChar(), static_cast(sizeof(file))); // FW_ASSERT_0 diff --git a/Svc/ComLogger/ComLogger.cpp b/Svc/ComLogger/ComLogger.cpp index c6b8c27c81..7db091a964 100644 --- a/Svc/ComLogger/ComLogger.cpp +++ b/Svc/ComLogger/ComLogger.cpp @@ -67,11 +67,11 @@ namespace Svc { FW_ASSERT(maxFileSize > sizeof(U16), static_cast(maxFileSize)); } - FW_ASSERT(Fw::StringUtils::string_length(incomingFilePrefix, sizeof(this->m_filePrefix)) < sizeof(this->m_filePrefix), - static_cast(Fw::StringUtils::string_length(incomingFilePrefix, sizeof(this->m_filePrefix))), + FW_ASSERT(Fw::StringUtils::string_length(incomingFilePrefix, static_cast(sizeof(this->m_filePrefix))) < sizeof(this->m_filePrefix), + static_cast(Fw::StringUtils::string_length(incomingFilePrefix, static_cast(sizeof(this->m_filePrefix)))), static_cast(sizeof(this->m_filePrefix))); // ensure that file prefix is not too big - (void)Fw::StringUtils::string_copy(this->m_filePrefix, incomingFilePrefix, sizeof(this->m_filePrefix)); + (void)Fw::StringUtils::string_copy(this->m_filePrefix, incomingFilePrefix, static_cast(sizeof(this->m_filePrefix))); this->m_initialized = true; } diff --git a/Svc/Deframer/Deframer.cpp b/Svc/Deframer/Deframer.cpp index 3005aa6f99..8ed542dec5 100644 --- a/Svc/Deframer/Deframer.cpp +++ b/Svc/Deframer/Deframer.cpp @@ -140,7 +140,7 @@ void Deframer ::route(Fw::Buffer& packetBuffer) { comOut_out(0, com, 0); } else { - Fw::Logger::logMsg( + Fw::Logger::log( "[ERROR] Serializing com buffer failed with status %d\n", status ); @@ -170,7 +170,7 @@ void Deframer ::route(Fw::Buffer& packetBuffer) { } } else { - Fw::Logger::logMsg( + Fw::Logger::log( "[ERROR] Deserializing packet type failed with status %d\n", status ); @@ -301,7 +301,7 @@ void Deframer ::processRing() { // Log checksum errors // This is likely a real error, not an artifact of other data corruption if (status == DeframingProtocol::DEFRAMING_INVALID_CHECKSUM) { - Fw::Logger::logMsg("[ERROR] Deframing checksum validation failed\n"); + Fw::Logger::log("[ERROR] Deframing checksum validation failed\n"); } } } diff --git a/Svc/Deframer/test/ut-fprime-protocol/DeframerTestMain.cpp b/Svc/Deframer/test/ut-fprime-protocol/DeframerTestMain.cpp index 94c731f866..da7091a50e 100644 --- a/Svc/Deframer/test/ut-fprime-protocol/DeframerTestMain.cpp +++ b/Svc/Deframer/test/ut-fprime-protocol/DeframerTestMain.cpp @@ -6,7 +6,7 @@ #include "Fw/Test/UnitTest.hpp" #include "GenerateFrames.hpp" -#include "Os/Log.hpp" +#include "Os/Console.hpp" #include "STest/Scenario/BoundedScenario.hpp" #include "STest/Scenario/RandomScenario.hpp" #include "STest/Scenario/Scenario.hpp" diff --git a/Svc/FatalHandler/FatalHandlerComponentBaremetalImpl.cpp b/Svc/FatalHandler/FatalHandlerComponentBaremetalImpl.cpp index e62f4535ec..b92ca49965 100644 --- a/Svc/FatalHandler/FatalHandlerComponentBaremetalImpl.cpp +++ b/Svc/FatalHandler/FatalHandlerComponentBaremetalImpl.cpp @@ -5,7 +5,7 @@ // ====================================================================== #include -#include +#include #include #include @@ -19,7 +19,7 @@ namespace Svc { const NATIVE_INT_TYPE portNum, FwEventIdType Id) { // for **nix, delay then exit with error code - Os::Log::logMsg("FATAL %d handled.\n",Id,0,0,0,0,0); + Os::Log::log("FATAL %d handled.\n",Id); while (true) {} // Returning might be bad } diff --git a/Svc/FatalHandler/FatalHandlerComponentLinuxImpl.cpp b/Svc/FatalHandler/FatalHandlerComponentLinuxImpl.cpp index f95329de61..cb51088160 100644 --- a/Svc/FatalHandler/FatalHandlerComponentLinuxImpl.cpp +++ b/Svc/FatalHandler/FatalHandlerComponentLinuxImpl.cpp @@ -27,9 +27,9 @@ namespace Svc { const NATIVE_INT_TYPE portNum, FwEventIdType Id) { // for **nix, delay then exit with error code - Fw::Logger::logMsg("FATAL %d handled.\n",Id,0,0,0,0,0); + Fw::Logger::log("FATAL %d handled.\n",Id); (void)Os::Task::delay(Fw::Time(1, 0)); - Fw::Logger::logMsg("Exiting with abort signal and core dump file.\n",0,0,0,0,0,0); + Fw::Logger::log("Exiting with abort signal and core dump file.\n"); (void)raise( SIGABRT ); exit(1); } diff --git a/Svc/FatalHandler/FatalHandlerComponentVxWorksImpl.cpp b/Svc/FatalHandler/FatalHandlerComponentVxWorksImpl.cpp index 25a8e689b1..0341f07ce2 100644 --- a/Svc/FatalHandler/FatalHandlerComponentVxWorksImpl.cpp +++ b/Svc/FatalHandler/FatalHandlerComponentVxWorksImpl.cpp @@ -20,7 +20,7 @@ namespace Svc { void FatalHandlerComponentImpl::FatalReceive_handler( const NATIVE_INT_TYPE portNum, FwEventIdType Id) { - Fw::Logger::logMsg("FATAL %d handled.\n",Id,0,0,0,0,0); + Fw::Logger::log("FATAL %d handled.\n",Id,0,0,0,0,0); taskSuspend(0); } diff --git a/Svc/FileDownlink/FileDownlink.cpp b/Svc/FileDownlink/FileDownlink.cpp index d52ef0737e..baac26209a 100644 --- a/Svc/FileDownlink/FileDownlink.cpp +++ b/Svc/FileDownlink/FileDownlink.cpp @@ -167,8 +167,8 @@ namespace Svc { FW_ASSERT(sourceFilename.length() < sizeof(entry.srcFilename)); FW_ASSERT(destFilename.length() < sizeof(entry.destFilename)); - (void) Fw::StringUtils::string_copy(entry.srcFilename, sourceFilename.toChar(), sizeof(entry.srcFilename)); - (void) Fw::StringUtils::string_copy(entry.destFilename, destFilename.toChar(), sizeof(entry.destFilename)); + (void) Fw::StringUtils::string_copy(entry.srcFilename, sourceFilename.toChar(), static_cast(sizeof(entry.srcFilename))); + (void) Fw::StringUtils::string_copy(entry.destFilename, destFilename.toChar(), static_cast(sizeof(entry.destFilename))); Os::Queue::QueueStatus status = m_fileQueue.send(reinterpret_cast(&entry), sizeof(entry), 0, Os::Queue::QUEUE_NONBLOCKING); @@ -240,8 +240,8 @@ namespace Svc { FW_ASSERT(sourceFilename.length() < sizeof(entry.srcFilename)); FW_ASSERT(destFilename.length() < sizeof(entry.destFilename)); - (void) Fw::StringUtils::string_copy(entry.srcFilename, sourceFilename.toChar(), sizeof(entry.srcFilename)); - (void) Fw::StringUtils::string_copy(entry.destFilename, destFilename.toChar(), sizeof(entry.destFilename)); + (void) Fw::StringUtils::string_copy(entry.srcFilename, sourceFilename.toChar(), static_cast(sizeof(entry.srcFilename))); + (void) Fw::StringUtils::string_copy(entry.destFilename, destFilename.toChar(), static_cast(sizeof(entry.destFilename))); Os::Queue::QueueStatus status = m_fileQueue.send(reinterpret_cast(&entry), sizeof(entry), 0, Os::Queue::QUEUE_NONBLOCKING); @@ -273,8 +273,8 @@ namespace Svc { FW_ASSERT(sourceFilename.length() < sizeof(entry.srcFilename)); FW_ASSERT(destFilename.length() < sizeof(entry.destFilename)); - (void) Fw::StringUtils::string_copy(entry.srcFilename, sourceFilename.toChar(), sizeof(entry.srcFilename)); - (void) Fw::StringUtils::string_copy(entry.destFilename, destFilename.toChar(), sizeof(entry.destFilename)); + (void) Fw::StringUtils::string_copy(entry.srcFilename, sourceFilename.toChar(), static_cast(sizeof(entry.srcFilename))); + (void) Fw::StringUtils::string_copy(entry.destFilename, destFilename.toChar(), static_cast(sizeof(entry.destFilename))); Os::Queue::QueueStatus status = m_fileQueue.send(reinterpret_cast(&entry), sizeof(entry), 0, Os::Queue::QUEUE_NONBLOCKING); diff --git a/Svc/Framer/Framer.cpp b/Svc/Framer/Framer.cpp index 3ec1cf8f1e..0061be08b5 100644 --- a/Svc/Framer/Framer.cpp +++ b/Svc/Framer/Framer.cpp @@ -78,7 +78,7 @@ void Framer ::send(Fw::Buffer& outgoing) { // Note: if there is a data sending problem, an EVR likely wouldn't // make it down. Log the issue in hopes that // someone will see it. - Fw::Logger::logMsg("[ERROR] Failed to send framed data: %d\n", sendStatus.e); + Fw::Logger::log("[ERROR] Failed to send framed data: %d\n", sendStatus.e); } this->m_frame_sent = true; // A frame was sent } diff --git a/Svc/Framer/docs/sdd.md b/Svc/Framer/docs/sdd.md index 229c601e7e..5b6ad1021e 100644 --- a/Svc/Framer/docs/sdd.md +++ b/Svc/Framer/docs/sdd.md @@ -155,7 +155,7 @@ _B_ representing framed data and does the following: 1. Check the return status of the invocation. If the return status is not `Drv::SendStatus::SEND_OK`, then -use `Fw::Logger::logMsg` to log an error message. +use `Fw::Logger::log` to log an error message. Don't send an event report in this case, because downlink is apparently not working. diff --git a/Svc/Framer/test/ut/FramerTestMain.cpp b/Svc/Framer/test/ut/FramerTestMain.cpp index 8e87e79d1b..b0c0189f9b 100644 --- a/Svc/Framer/test/ut/FramerTestMain.cpp +++ b/Svc/Framer/test/ut/FramerTestMain.cpp @@ -3,11 +3,11 @@ // ---------------------------------------------------------------------- #include "Fw/Test/UnitTest.hpp" -#include "Os/Log.hpp" +#include "Os/Console.hpp" #include "FramerTester.hpp" // Enable the console logging provided by Os::Log -Os::Log logger; +Os::Console logger; TEST(Nominal, Com) { COMMENT("Send one Fw::Com buffer to the framer (nominal behavior)"); diff --git a/Svc/LinuxTimer/LinuxTimerComponentImplTimerFd.cpp b/Svc/LinuxTimer/LinuxTimerComponentImplTimerFd.cpp index fe53fa5b70..aeaac6deaa 100644 --- a/Svc/LinuxTimer/LinuxTimerComponentImplTimerFd.cpp +++ b/Svc/LinuxTimer/LinuxTimerComponentImplTimerFd.cpp @@ -38,7 +38,7 @@ namespace Svc { unsigned long long missed; int ret = static_cast(read (fd, &missed, sizeof (missed))); if (-1 == ret) { - Fw::Logger::logMsg("timer read error: %s\n", reinterpret_cast(strerror(errno))); + Fw::Logger::log("timer read error: %s\n", strerror(errno)); } this->m_mutex.lock(); bool quit = this->m_quit; diff --git a/Svc/PassiveConsoleTextLogger/ConsoleTextLoggerImplCommon.cpp b/Svc/PassiveConsoleTextLogger/ConsoleTextLoggerImplCommon.cpp index bb27536235..c7c0ed0991 100644 --- a/Svc/PassiveConsoleTextLogger/ConsoleTextLoggerImplCommon.cpp +++ b/Svc/PassiveConsoleTextLogger/ConsoleTextLoggerImplCommon.cpp @@ -43,7 +43,7 @@ namespace Svc { severityString = "SEVERITY ERROR"; break; } - Fw::Logger::logMsg("EVENT: (%" PRI_FwEventIdType ") (%" PRI_FwTimeBaseStoreType ":%" PRIu32 ",%" PRIu32 ") %s: %s\n", + Fw::Logger::log("EVENT: (%" PRI_FwEventIdType ") (%" PRI_FwTimeBaseStoreType ":%" PRIu32 ",%" PRIu32 ") %s: %s\n", id, static_cast(timeTag.getTimeBase()), timeTag.getSeconds(), timeTag.getUSeconds(), reinterpret_cast(severityString), reinterpret_cast(text.toChar())); } diff --git a/Svc/PassiveRateGroup/PassiveRateGroup.cpp b/Svc/PassiveRateGroup/PassiveRateGroup.cpp index d9e62107d8..5436340557 100644 --- a/Svc/PassiveRateGroup/PassiveRateGroup.cpp +++ b/Svc/PassiveRateGroup/PassiveRateGroup.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include #include namespace Svc { diff --git a/Utils/Types/CircularBuffer.cpp b/Utils/Types/CircularBuffer.cpp index b4fe9daec4..0eac02c513 100644 --- a/Utils/Types/CircularBuffer.cpp +++ b/Utils/Types/CircularBuffer.cpp @@ -169,12 +169,12 @@ void CircularBuffer ::clear_high_water_mark() { #ifdef CIRCULAR_DEBUG void CircularBuffer :: print() { NATIVE_UINT_TYPE idx = m_head_idx; - Os::Log::logMsg("Ring: ", 0, 0, 0, 0, 0, 0); + Os::Log::log("Ring: "); for (NATIVE_UINT_TYPE i = 0; i < m_allocated_size; ++i) { - Os::Log::logMsg("%c", m_store[idx], 0, 0, 0, 0, 0); + Os::Log::log("%c", m_store[idx]); idx = advance_idx(idx); } - Os::Log::logMsg("\n", 0, 0, 0, 0, 0, 0); + Os::Log::log("\n"); } #endif } //End Namespace Types diff --git a/cmake/platform/Darwin.cmake b/cmake/platform/Darwin.cmake index a51674248b..efb41dd128 100644 --- a/cmake/platform/Darwin.cmake +++ b/cmake/platform/Darwin.cmake @@ -19,6 +19,7 @@ if (NOT DEFINED FPRIME_USE_BAREMETAL_SCHEDULER) FIND_PACKAGE ( Threads REQUIRED ) endif() choose_fprime_implementation(Os/File Os/File/Posix) +choose_fprime_implementation(Os/Console Os/Console/Posix) choose_fprime_implementation(Os/Task Os/Task/Posix) choose_fprime_implementation(Os/Mutex Os/Mutex/Posix) diff --git a/cmake/platform/Linux.cmake b/cmake/platform/Linux.cmake index 3b19460ee4..14bd5146db 100644 --- a/cmake/platform/Linux.cmake +++ b/cmake/platform/Linux.cmake @@ -10,6 +10,7 @@ if (NOT DEFINED FPRIME_USE_BAREMETAL_SCHEDULER) FIND_PACKAGE ( Threads REQUIRED ) endif() choose_fprime_implementation(Os/File Os/File/Posix) +choose_fprime_implementation(Os/Console Os/Console/Posix) choose_fprime_implementation(Os/Task Os/Task/Posix) choose_fprime_implementation(Os/Mutex Os/Mutex/Posix) diff --git a/config/FpConfig.h b/config/FpConfig.h index 3d59e7ad4c..5e4bde9d65 100644 --- a/config/FpConfig.h +++ b/config/FpConfig.h @@ -171,6 +171,14 @@ typedef FwIndexType FwQueueSizeType; 0 //!< Indicates whether or not a baremetal scheduler should be used. Alternatively the Os scheduler is used. #endif +// On some systems, use of *printf family functions (snprintf, printf, etc) require a prohibitive amount of program +// space. Setting this to `0` indicates that the Fw/String methods should stop using these functions to conserve +// program size. However, this comes at the expense of discarding format parameters. i.e. the format string is returned +// unchanged. +#ifndef FW_USE_PRINTF_FAMILY_FUNCTIONS_IN_STRING_FORMATTING +#define FW_USE_PRINTF_FAMILY_FUNCTIONS_IN_STRING_FORMATTING 1 +#endif + // Port Facilities // This allows tracing calls through ports for debugging diff --git a/docs/Tutorials/GpsTutorial/Tutorial.md b/docs/Tutorials/GpsTutorial/Tutorial.md index ba2da79544..2a8a2b3889 100644 --- a/docs/Tutorials/GpsTutorial/Tutorial.md +++ b/docs/Tutorials/GpsTutorial/Tutorial.md @@ -538,7 +538,7 @@ namespace GpsApp { char* pointer = reinterpret_cast(serBuffer.getData()); // Check for invalid read status, log an error, return buffer and abort if there is a problem if (serial_status != Drv::SER_OK) { - Fw::Logger::logMsg("[WARNING] Received buffer with bad packet: %d\n", serial_status); + Fw::Logger::log("[WARNING] Received buffer with bad packet: %d\n", serial_status); // We MUST return the buffer or the serial driver won't be able to reuse it. The same buffer send call is used // as we did in "preamble". Since the buffer's size was overwritten to hold the actual data size, we need to // reset it to the full data block size before returning it. @@ -581,7 +581,7 @@ namespace GpsApp { } // If we found some of the message but not all of the message, then log an error, return the buffer and exit. else if (status != 9) { - Fw::Logger::logMsg("[ERROR] GPS parsing failed: %d\n", status); + Fw::Logger::log("[ERROR] GPS parsing failed: %d\n", status); // We MUST return the buffer or the serial driver won't be able to reuse it. The same buffer send call is used // as we did in "preamble". Since the buffer's size was overwritten to hold the actual data size, we need to // reset it to the full data block size before returning it. diff --git a/docs/UsersGuide/dev/os-docs.md b/docs/UsersGuide/dev/os-docs.md index f0f662f2a7..a61dcc80ff 100644 --- a/docs/UsersGuide/dev/os-docs.md +++ b/docs/UsersGuide/dev/os-docs.md @@ -1,5 +1,9 @@ # Operating System Abstraction Layer (OSAL) + +> [!WARNING] +> This document is out of date and will be updated shortly. + The framework incorporates an OSAL providing service abstraction classes of a fictitious operating system that can perform all the operations of a real operating system. This layer shows the user an abstraction of the common functionality provided by all real-time operating systems (RTEMS, VxWorks, Azure ThreadX, QNX, FreeRTOS, Zephyr,...) or not (Linux, macOS, WinCE,...). We find the following services: From 7bb161f2d48e68ef40ff15ba97d06ea20d117a1f Mon Sep 17 00:00:00 2001 From: Johan Bertrand <6369937+JohanBertrand@users.noreply.github.com> Date: Fri, 16 Aug 2024 03:55:18 +0200 Subject: [PATCH 03/10] Fix double-promotion in fprime codebase (#2818) --- CMakeLists.txt | 4 +++- Fw/Types/PolyType.cpp | 8 ++++++-- Fw/Types/StringUtils.cpp | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a6064926d..8657806093 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,12 +24,14 @@ add_compile_options( -Wno-unused-parameter ) -# Add -Wshadow and -pedantic only for framework code, not the unit tests +# Add -Wshadow, -Wconversion and -pedantic only for framework code, not the unit tests +# TODO: uncomment -Wdouble-promotion once fpp is fixed if (NOT BUILD_TESTING) add_compile_options( -Wshadow -pedantic -Wconversion +# -Wdouble-promotion ) endif() diff --git a/Fw/Types/PolyType.cpp b/Fw/Types/PolyType.cpp index fc42e8b174..30c04196bd 100644 --- a/Fw/Types/PolyType.cpp +++ b/Fw/Types/PolyType.cpp @@ -639,12 +639,16 @@ void PolyType::toString(StringBase& dest, bool append) const { #endif #if FW_HAS_F64 case TYPE_F64: - (void)snprintf(valString, sizeof(valString), "%lg ", this->m_val.f64Val); + (void)snprintf(valString, sizeof(valString), "%g ", this->m_val.f64Val); break; -#endif + case TYPE_F32: + (void)snprintf(valString, sizeof(valString), "%g ", static_cast(this->m_val.f32Val)); + break; +#else case TYPE_F32: (void)snprintf(valString, sizeof(valString), "%g ", this->m_val.f32Val); break; +#endif case TYPE_BOOL: (void)snprintf(valString, sizeof(valString), "%s ", this->m_val.boolVal ? "T" : "F"); break; diff --git a/Fw/Types/StringUtils.cpp b/Fw/Types/StringUtils.cpp index f865836d36..08e9fbd332 100644 --- a/Fw/Types/StringUtils.cpp +++ b/Fw/Types/StringUtils.cpp @@ -64,7 +64,7 @@ FwSignedSizeType Fw::StringUtils::substring_find(const CHAR* source_string, return -1; } // Confirm that the output type can hold the range of valid results - FW_ASSERT((source_size - sub_size) <= std::numeric_limits::max()); + FW_ASSERT(static_cast(source_size - sub_size) <= std::numeric_limits::max()); // Loop from zero to source_size - sub_size (inclusive) for (FwSizeType source_index = 0; From fd117428d2a52beaaaf5ecc9a6aca2e2dae66500 Mon Sep 17 00:00:00 2001 From: Maurice Prather Date: Wed, 21 Aug 2024 15:52:53 -0700 Subject: [PATCH 04/10] Updated troubleshooting md (#2843) * Updated troubleshooting md Improved 'fprime-util: command not found' section. Related to #2837 * Corrected typo --- docs/UsersGuide/guide.md | 1 + docs/troubleshooting.md | 25 ++++++++++++++++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/docs/UsersGuide/guide.md b/docs/UsersGuide/guide.md index 1c6297b1da..460f977ec6 100644 --- a/docs/UsersGuide/guide.md +++ b/docs/UsersGuide/guide.md @@ -40,6 +40,7 @@ This section is divided into four sub-sections: - [Data Types and Data Structures: Primitive Types, Enums, Arrays, and Serializables](user/enum-arr-ser.md) - [Data Constructs: Commands, Events, Channels, and Parameters](user/cmd-evt-chn-prm.md) - [Unit Testing F´ Components](./user/unit-testing.md) + - [Troubleshooting FAQ](../troubleshooting.md) - F´ Best Practices: helpful patterns when developing F´ software - [F´ Development Process](./best/development-practice.md) - [Application, Manager, Driver Pattern](./best/app-man-drv.md) diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 73595c9564..f72a7e7bff 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -23,11 +23,26 @@ Some of the F´ Python packages are built in a way that it is recommended to ins ## fprime-util: command not found -If the user is using a virtual environment and receives the ‘command not found’, the problem is likely caused by the environment not being sourced in a new terminal. Make sure to source the environment before running: -``` -. /fprime-venv/bin/activate -``` -If installing without a virtual environment, PIP occasionally uses `$HOME/.local/bin` as a place to install user tools. Users running without virtual environments should add this directory to the path. +There are at least three common reasons for this error. + +1. If the user is using a virtual environment and receives the ‘command not found’, the problem is likely caused by the environment not being sourced in a new terminal. Make sure to source the environment before running: + ```sh + # In MyProject + . fprime-venv/bin/activate + ``` + +1. If the project folder was moved after the virtual environment was provisioned (e.g. project was originally setup in `/folderA/MyProject` and moved to `/someOtherFolder/MyProject`), various files in the original `fprime-venv` folder will contain references to the original path. The easiest resolution is to remove and reprovision the virtual environment with the following: + ```sh + # In MyProject + rm -rf fprime-venv + python -m venv fprime-venv + . fprime-venv/bin/activate + pip install -r fprime/requirements.txt + ``` + + > Some projects ship their own `requirements.txt`. Install using that file if it exists. + +1. If installing without a virtual environment, PIP occasionally uses `$HOME/.local/bin` as a place to install user tools. Users running without virtual environments should add this directory to the path. ## Helper script ‘fpp-redirect-helper’ exited with reason: Permission denied This error can occur when the helper-script, (`fprime/cmake/autocoder/fpp-wrapper/fpp-redirect-helper`) loses its execution permission. From 4476828cb388a4a240ae7c56e37d76443f85ab15 Mon Sep 17 00:00:00 2001 From: Alex Mariano <65744075+Lex-ari@users.noreply.github.com> Date: Mon, 26 Aug 2024 15:14:53 -0700 Subject: [PATCH 05/10] Update CI to use Json dictionaries (#2806) * Change CI to use Json dictionaries * Bumping to gds/tools for alpha release of JSON dictionary * Change Workflow RPI Dictionary to JSON * Install requirements.txt on RPIs for integration tests --------- Co-authored-by: M Starch Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com> --- .github/workflows/build-test-rpi.yml | 15 +++++++++++++-- .github/workflows/ext-raspberry-led-blinker.yml | 8 ++++++-- RPI/README.md | 2 +- ci/tests/fputil.bash | 2 +- docs/UsersGuide/gds/gds-cli.md | 8 ++++---- docs/UsersGuide/gds/seqgen.md | 2 +- requirements.txt | 4 ++-- 7 files changed, 28 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build-test-rpi.yml b/.github/workflows/build-test-rpi.yml index 7bc8c850f4..ac20ce5c17 100644 --- a/.github/workflows/build-test-rpi.yml +++ b/.github/workflows/build-test-rpi.yml @@ -17,7 +17,7 @@ on: - '.github/ISSUE_TEMPLATE/**' env: RPI_TOOLCHAIN_DIR: /tmp/rpi-toolchain - DICTIONARY_PATH: build-artifacts/raspberrypi/RPI/dict/RPITopologyAppDictionary.xml + DICTIONARY_PATH: build-artifacts/raspberrypi/RPI/dict/RPITopologyDictionary.json # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: RPI: @@ -55,12 +55,23 @@ jobs: runs-on: self-hosted needs: RPI steps: + - uses: actions/checkout@v4 + with: + sparse-checkout: 'requirements.txt' + - name: "Setup environment" + run: | + python -m venv venv + . venv/bin/activate + pip install -r requirements.txt - name: RPI Build Download uses: actions/download-artifact@v3 with: name: rpi-build - name: RPI Integration Tests - run: chmod +x RPI/build-artifacts/raspberrypi/RPI/bin/RPI; /bin/bash ci/tests/RPI-Ints.bash + run: | + chmod +x RPI/build-artifacts/raspberrypi/RPI/bin/RPI + . venv/bin/activate + /bin/bash ci/tests/RPI-Ints.bash # Archive the outputs - name: 'Archive Logs' uses: actions/upload-artifact@v3 diff --git a/.github/workflows/ext-raspberry-led-blinker.yml b/.github/workflows/ext-raspberry-led-blinker.yml index 28de393026..04a49ddf59 100644 --- a/.github/workflows/ext-raspberry-led-blinker.yml +++ b/.github/workflows/ext-raspberry-led-blinker.yml @@ -70,11 +70,15 @@ jobs: runs-on: self-hosted needs: cross-compilation steps: + - name: "Checkout F´ Repository" + uses: actions/checkout@v4 + with: + sparse-checkout: 'requirements.txt' - name: "Setup environment" run: | python -m venv venv . venv/bin/activate - pip install fprime-gds + pip install -r requirements.txt - name: "Artifacts Download" uses: actions/download-artifact@v3 with: @@ -86,7 +90,7 @@ jobs: chmod +x ./build-artifacts/raspberrypi/LedBlinker/bin/LedBlinker fprime-gds --ip-client -d ./build-artifacts/raspberrypi/LedBlinker --logs ./ci-logs & sleep 10 - pytest --dictionary ./build-artifacts/raspberrypi/LedBlinker/dict/LedBlinkerTopologyAppDictionary.xml ./int/led_integration_tests.py + pytest --dictionary ./build-artifacts/raspberrypi/LedBlinker/dict/LedBlinkerTopologyDictionary.json ./int/led_integration_tests.py - name: 'Archive logs' uses: actions/upload-artifact@v3 if: always() diff --git a/RPI/README.md b/RPI/README.md index af22c23d84..fb76c4577f 100644 --- a/RPI/README.md +++ b/RPI/README.md @@ -83,7 +83,7 @@ home network where the pi and the user's computer are connected to the same netw ``` cd fprime/RPI -fprime-gds -n --dictionary ./build-artifacts/raspberrypi/dict/RPITopologyAppDictionary.xml +fprime-gds -n --dictionary ./build-artifacts/raspberrypi/dict/RPITopologyDictionary.json ``` The ground station should now appear in the user's default browser. Should the user wish to terminate the ground system, return to that terminal and press CTRL-C to shut it down. Please allow it a few moments to finalize and exit. The user may then kill the browser tab displaying the GUI. diff --git a/ci/tests/fputil.bash b/ci/tests/fputil.bash index 4e2ec64dff..c86b4fc9fd 100755 --- a/ci/tests/fputil.bash +++ b/ci/tests/fputil.bash @@ -69,7 +69,7 @@ function integration_test_run { mkdir -p "${LOG_DIR}/gds-logs" # Start the GDS layer and give it time to run echo "[INFO] Starting headless GDS layer" - fprime-gds -n --dictionary "${ROOTDIR}/"*"/${BINARY}/dict/${BINARY}TopologyAppDictionary.xml" -g none -l "${LOG_DIR}/gds-logs" 1>${LOG_DIR}/gds-logs/fprime-gds.stdout.log 2>${LOG_DIR}/gds-logs/fprime-gds.stderr.log & + fprime-gds -n --dictionary "${ROOTDIR}/"*"/${BINARY}/dict/${BINARY}TopologyDictionary.json" -g none -l "${LOG_DIR}/gds-logs" 1>${LOG_DIR}/gds-logs/fprime-gds.stdout.log 2>${LOG_DIR}/gds-logs/fprime-gds.stderr.log & GDS_PID=$! # run the app with valgrind in the background if command -v valgrind &> /dev/null diff --git a/docs/UsersGuide/gds/gds-cli.md b/docs/UsersGuide/gds/gds-cli.md index 82591934d9..ba642eb17c 100644 --- a/docs/UsersGuide/gds/gds-cli.md +++ b/docs/UsersGuide/gds/gds-cli.md @@ -152,12 +152,12 @@ Retrieval Options: As mentioned, these CLI commands let you interact with the GDS through events and commands, and telemetry channels. Through a *project F´ dictionary* the CLI can understand what commands, events and telemetry channels are available. -Every F´ project deployment will have a `*Dictionary.xml` file that's created when the project's deployment is built -In the `Ref` example project, it'll be the `Ref/Top/RefTopologyAppDictionary.xml` file. By reading this file, the CLI +Every F´ project deployment will have a `*Dictionary.json` file that's created when the project's deployment is built +In the `Ref` example project, it'll be the `Ref/Top/RefTopologyDictionary.json` file. By reading this file, the CLI tool knows what to look for when it's reading or sending data to the GDS. If it doesn't know where the dictionary is, then the CLI tool can't do much beyond printing out help messages. -When you run one of the CLI commands, the tool will automatically look for files ending in `Dictionary.xml` in your +When you run one of the CLI commands, the tool will automatically look for files ending in `Dictionary.json` in your current working directory and use the first one it can find. This behavior is similar to how `fprime-gds` searches for dictionaries it uses to construct the browser GUI. If it can't find any dictionaries, it will print out an error message like this: @@ -168,7 +168,7 @@ fprime-cli: error: No valid project dictionary found Running commands from your project folder (e.g. inside `fprime/Ref`) should work to find a dictionary, but if you want to run commands for a different deployment or project, you can specify the dictionary file exactly using the -`--dictionary` option with the file's path. `fprime-cli command-send --dictionary Ref/Top/RefTopologyAppDictionary.xml`. +`--dictionary` option with the file's path. `fprime-cli command-send --dictionary Ref/Top/RefTopologyDictionary.json`. ### Using the Tools diff --git a/docs/UsersGuide/gds/seqgen.md b/docs/UsersGuide/gds/seqgen.md index 9f05f71417..1d6464ce41 100644 --- a/docs/UsersGuide/gds/seqgen.md +++ b/docs/UsersGuide/gds/seqgen.md @@ -37,7 +37,7 @@ Below is an example of how to run the sample example sequence with the Ref dicti dictionary will not be generated. ``` -fprime-seqgen fprime/Gds/examples/simple_sequence.seq -d fprime/Ref/build-artifacts/*/dict/RefTopologyAppDictionary.xml +fprime-seqgen fprime/Gds/examples/simple_sequence.seq -d fprime/Ref/build-artifacts/*/dict/RefTopologyDictionary.json ``` Here the output file is not specified, so it will be a new file in the same directory as the sequence but ending with diff --git a/requirements.txt b/requirements.txt index a512e7db45..1915d23228 100644 --- a/requirements.txt +++ b/requirements.txt @@ -30,8 +30,8 @@ fprime-fpp-to-cpp==2.1.0 fprime-fpp-to-dict==2.1.0 fprime-fpp-to-json==2.1.0 fprime-fpp-to-xml==2.1.0 -fprime-gds==3.4.3 -fprime-tools==3.4.4 +fprime-gds==v3.4.4a2 +fprime-tools==v3.4.5a1 fprime-visual==1.0.2 gcovr==6.0 idna==3.4 From 7a7f116c272c2bd253b33b85e9c038ed70180459 Mon Sep 17 00:00:00 2001 From: M Starch Date: Tue, 3 Sep 2024 16:39:26 -0700 Subject: [PATCH 06/10] Adding `fflush` call to posix console (#2857) --- Os/Posix/Console.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Os/Posix/Console.cpp b/Os/Posix/Console.cpp index 477495ab45..46e53d85fe 100644 --- a/Os/Posix/Console.cpp +++ b/Os/Posix/Console.cpp @@ -19,6 +19,7 @@ void PosixConsole::writeMessage(const CHAR *message, const FwSizeType size) { FwSizeType capped_size = (size <= std::numeric_limits::max()) ? size : std::numeric_limits::max(); if (message != nullptr) { (void)::fwrite(message, sizeof(CHAR), static_cast(capped_size), this->m_handle.m_file_descriptor); + (void)::fflush(this->m_handle.m_file_descriptor); } } From 66d5128c718543c773939ca711b513b88904628a Mon Sep 17 00:00:00 2001 From: Richard Date: Wed, 4 Sep 2024 14:31:42 -0700 Subject: [PATCH 07/10] Fix Random UT Failure: PosixFile (#2835) (#2860) * Fix UT failing FinalizeCrc test when crc calculation miss match. Miss match due to file crc and shadow being out of sync when both are not reinialized at the same time. * Update File::open in File.ccp to match shadow operation in FileRules.cpp to only reset crc when status is OP_OK. * Update FileRules.cpp to print out rule name during test. * Remove changing file mode in shadow_open() in FileRules.cpp to OPEN_NO_MODE when status is not OP_OK. --- Os/File.cpp | 5 +++-- Os/test/ut/file/FileRules.cpp | 38 ++++++++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/Os/File.cpp b/Os/File.cpp index 4d8c1aab8a..26e3a27f73 100644 --- a/Os/File.cpp +++ b/Os/File.cpp @@ -60,9 +60,10 @@ File::Status File::open(const CHAR* filepath, File::Mode requested_mode, File::O if (status == File::Status::OP_OK) { this->m_mode = requested_mode; this->m_path = filepath; + // Reset any open CRC calculations + this->m_crc = File::INITIAL_CRC; } - // Reset any open CRC calculations - this->m_crc = File::INITIAL_CRC; + return status; } diff --git a/Os/test/ut/file/FileRules.cpp b/Os/test/ut/file/FileRules.cpp index 868c4053f0..e708ec9569 100644 --- a/Os/test/ut/file/FileRules.cpp +++ b/Os/test/ut/file/FileRules.cpp @@ -2,7 +2,7 @@ // \title Os/test/ut/file/MyRules.cpp // \brief rule implementations for common testing // ====================================================================== - +#include #include "RulesHeaders.hpp" #include "STest/Pick/Pick.hpp" extern "C" { @@ -20,8 +20,8 @@ Os::File::Status Os::Test::File::Tester::shadow_open(const std::string &path, Os this->m_independent_crc = Os::File::INITIAL_CRC; } else { this->m_current_path.clear(); - this->m_mode = Os::File::Mode::OPEN_NO_MODE; } + return status; } @@ -127,6 +127,8 @@ void Os::Test::File::Tester::assert_valid_mode_status(Os::File::Status &status) void Os::Test::File::Tester::assert_file_consistent() { // Ensure file mode ASSERT_EQ(this->m_mode, this->m_file.m_mode); + // Ensure CRC match + ASSERT_EQ(this->m_file.m_crc, this->m_independent_crc); if (this->m_file.m_path == nullptr) { ASSERT_EQ(this->m_current_path, std::string("")); } else { @@ -256,6 +258,7 @@ bool Os::Test::File::Tester::OpenBaseRule::precondition(const Os::Test::File::Te void Os::Test::File::Tester::OpenBaseRule::action(Os::Test::File::Tester &state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); // Initial variables used for this test std::shared_ptr filename = state.get_filename(this->m_random); @@ -344,6 +347,7 @@ bool Os::Test::File::Tester::CloseFile::precondition(const Os::Test::File::Teste void Os::Test::File::Tester::CloseFile::action(Os::Test::File::Tester &state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); // Make sure test state and file state synchronized state.assert_file_consistent(); state.assert_file_opened(state.m_current_path); @@ -375,6 +379,7 @@ bool Os::Test::File::Tester::Read::precondition( void Os::Test::File::Tester::Read::action( Os::Test::File::Tester &state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); U8 buffer[FILE_DATA_MAXIMUM]; state.assert_file_consistent(); FileState original_file_state = state.current_file_state(); @@ -411,6 +416,7 @@ bool Os::Test::File::Tester::Write::precondition( void Os::Test::File::Tester::Write::action( Os::Test::File::Tester &state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); U8 buffer[FILE_DATA_MAXIMUM]; state.assert_file_consistent(); FwSignedSizeType size_desired = static_cast(STest::Pick::lowerUpper(0, FILE_DATA_MAXIMUM)); @@ -448,6 +454,7 @@ bool Os::Test::File::Tester::Seek::precondition( void Os::Test::File::Tester::Seek::action( Os::Test::File::Tester &state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); FwSignedSizeType seek_offset = 0; state.assert_file_consistent(); FileState original_file_state = state.current_file_state(); @@ -486,6 +493,7 @@ bool Os::Test::File::Tester::Preallocate::precondition( void Os::Test::File::Tester::Preallocate::action( Os::Test::File::Tester &state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); state.assert_file_consistent(); FileState original_file_state = state.current_file_state(); FwSignedSizeType offset = static_cast(STest::Pick::lowerUpper(0, FILE_DATA_MAXIMUM)); @@ -519,6 +527,7 @@ bool Os::Test::File::Tester::Flush::precondition( void Os::Test::File::Tester::Flush::action( Os::Test::File::Tester &state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); state.assert_file_consistent(); FileState original_file_state = state.current_file_state(); Os::File::Status status = state.m_file.flush(); @@ -549,6 +558,7 @@ bool Os::Test::File::Tester::OpenInvalidModes::precondition(const Os::Test::File void Os::Test::File::Tester::OpenInvalidModes::action(Os::Test::File::Tester &state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); state.assert_file_consistent(); FileState original_file_state = state.current_file_state(); // Check initial file state @@ -580,6 +590,7 @@ bool Os::Test::File::Tester::PreallocateWithoutOpen::precondition( void Os::Test::File::Tester::PreallocateWithoutOpen::action(Os::Test::File::Tester &state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); state.assert_file_consistent(); // Check initial file state state.assert_file_closed(); @@ -606,6 +617,7 @@ bool Os::Test::File::Tester::SeekWithoutOpen::precondition(const Os::Test::File: void Os::Test::File::Tester::SeekWithoutOpen::action(Os::Test::File::Tester &state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); state.assert_file_consistent(); // Check initial file state state.assert_file_closed(); @@ -632,6 +644,7 @@ bool Os::Test::File::Tester::SeekInvalidSize::precondition(const Os::Test::File: void Os::Test::File::Tester::SeekInvalidSize::action(Os::Test::File::Tester &state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); state.assert_file_consistent(); FileState original_file_state = state.current_file_state(); // Open file of given filename @@ -662,6 +675,7 @@ bool Os::Test::File::Tester::FlushInvalidModes::precondition(const Os::Test::Fil void Os::Test::File::Tester::FlushInvalidModes::action(Os::Test::File::Tester &state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); state.assert_file_consistent(); FileState original_file_state = state.current_file_state(); ASSERT_TRUE(Os::File::Mode::OPEN_NO_MODE == state.m_file.m_mode || Os::File::Mode::OPEN_READ == state.m_file.m_mode); @@ -689,6 +703,7 @@ bool Os::Test::File::Tester::ReadInvalidModes::precondition(const Os::Test::File void Os::Test::File::Tester::ReadInvalidModes::action(Os::Test::File::Tester &state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); U8 buffer[10]; FwSignedSizeType size = sizeof buffer; state.assert_file_consistent(); @@ -720,6 +735,7 @@ bool Os::Test::File::Tester::WriteInvalidModes::precondition(const Os::Test::Fil void Os::Test::File::Tester::WriteInvalidModes::action(Os::Test::File::Tester &state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); U8 buffer[10]; FwSignedSizeType size = sizeof buffer; state.assert_file_consistent(); @@ -756,6 +772,7 @@ Os::Test::File::Tester::OpenIllegalPath::OpenIllegalPath() : Os::Test::File::Tes void Os::Test::File::Tester::OpenIllegalPath::action(Os::Test::File::Tester &state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); state.assert_file_consistent(); Os::File::Mode random_mode = static_cast(STest::Pick::lowerUpper(Os::File::Mode::OPEN_READ, @@ -777,6 +794,7 @@ Os::Test::File::Tester::OpenIllegalMode::OpenIllegalMode() : Os::Test::File::Tes void Os::Test::File::Tester::OpenIllegalMode::action(Os::Test::File::Tester &state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); state.assert_file_consistent(); std::shared_ptr random_filename = state.get_filename(true); U32 mode = STest::Pick::lowerUpper(0, 1); @@ -799,6 +817,7 @@ Os::Test::File::Tester::PreallocateIllegalOffset::PreallocateIllegalOffset() void Os::Test::File::Tester::PreallocateIllegalOffset::action(Os::Test::File::Tester &state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); state.assert_file_consistent(); FwSignedSizeType length = static_cast(STest::Pick::any()); FwSignedSizeType invalid_offset = @@ -818,6 +837,7 @@ Os::Test::File::Tester::PreallocateIllegalLength::PreallocateIllegalLength() void Os::Test::File::Tester::PreallocateIllegalLength::action(Os::Test::File::Tester &state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); state.assert_file_consistent(); FwSignedSizeType offset = static_cast(STest::Pick::any()); FwSignedSizeType invalid_length = @@ -836,6 +856,7 @@ Os::Test::File::Tester::SeekIllegal::SeekIllegal() : Os::Test::File::Tester::Ass void Os::Test::File::Tester::SeekIllegal::action(Os::Test::File::Tester &state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); state.assert_file_consistent(); ASSERT_DEATH_IF_SUPPORTED(state.m_file.seek(-1, Os::File::SeekType::ABSOLUTE), Os::Test::File::Tester::ASSERT_IN_FILE_CPP); state.assert_file_consistent(); @@ -851,6 +872,7 @@ Os::Test::File::Tester::ReadIllegalBuffer::ReadIllegalBuffer() void Os::Test::File::Tester::ReadIllegalBuffer::action(Os::Test::File::Tester &state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); state.assert_file_consistent(); FwSignedSizeType size = static_cast(STest::Pick::any()); bool random_wait = static_cast(STest::Pick::lowerUpper(0, 1)); @@ -869,6 +891,7 @@ Os::Test::File::Tester::ReadIllegalSize::ReadIllegalSize() : Os::Test::File::Tes void Os::Test::File::Tester::ReadIllegalSize::action(Os::Test::File::Tester &state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); U8 buffer[10] = {}; state.assert_file_consistent(); FwSignedSizeType invalid_size = -1 * static_cast(STest::Pick::lowerUpper(0, std::numeric_limits::max())); @@ -890,6 +913,7 @@ Os::Test::File::Tester::WriteIllegalBuffer::WriteIllegalBuffer() void Os::Test::File::Tester::WriteIllegalBuffer::action(Os::Test::File::Tester &state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); state.assert_file_consistent(); FwSignedSizeType size = static_cast(STest::Pick::any()); bool random_wait = static_cast(STest::Pick::lowerUpper(0, 1)); @@ -908,6 +932,7 @@ Os::Test::File::Tester::WriteIllegalSize::WriteIllegalSize() : Os::Test::File::T void Os::Test::File::Tester::WriteIllegalSize::action(Os::Test::File::Tester &state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); U8 buffer[10] = {}; state.assert_file_consistent(); FwSignedSizeType invalid_size = -1 * static_cast(STest::Pick::lowerUpper(0, std::numeric_limits::max())); @@ -935,6 +960,7 @@ bool Os::Test::File::Tester::CopyAssignment::precondition(const Os::Test::File:: void Os::Test::File::Tester::CopyAssignment::action(Os::Test::File::Tester& state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); state.assert_file_consistent(); Os::File temp = state.m_file; state.assert_file_consistent(); // Prevents optimization @@ -959,6 +985,7 @@ bool Os::Test::File::Tester::CopyConstruction::precondition(const Os::Test::File void Os::Test::File::Tester::CopyConstruction::action(Os::Test::File::Tester& state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); state.assert_file_consistent(); Os::File temp(state.m_file); state.assert_file_consistent(); // Interim check to ensure original file did not change @@ -984,6 +1011,7 @@ bool Os::Test::File::Tester::FullCrc::precondition( void Os::Test::File::Tester::FullCrc::action( Os::Test::File::Tester& state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); U32 crc = 1; U32 shadow_crc = 2; state.assert_file_consistent(); @@ -1013,6 +1041,7 @@ bool Os::Test::File::Tester::IncrementalCrc::precondition( void Os::Test::File::Tester::IncrementalCrc::action( Os::Test::File::Tester& state //!< The test state ){ + printf("--> Rule: %s \n", this->getName()); state.assert_file_consistent(); FwSignedSizeType size_desired = static_cast(STest::Pick::lowerUpper(0, FW_FILE_CHUNK_SIZE)); FwSignedSizeType shadow_size = size_desired; @@ -1041,10 +1070,11 @@ bool Os::Test::File::Tester::FinalizeCrc::precondition( void Os::Test::File::Tester::FinalizeCrc::action( Os::Test::File::Tester& state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); U32 crc = 1; U32 shadow_crc = 2; state.assert_file_consistent(); - Os::File::Status status = state.m_file.finalizeCrc(crc); + Os::File::Status status = state.m_file.finalizeCrc(crc); state.shadow_finalize(shadow_crc); ASSERT_EQ(status, Os::File::Status::OP_OK); ASSERT_EQ(crc, shadow_crc); @@ -1069,6 +1099,7 @@ bool Os::Test::File::Tester::FullCrcInvalidModes::precondition( void Os::Test::File::Tester::FullCrcInvalidModes::action( Os::Test::File::Tester& state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); state.assert_file_consistent(); FileState original_file_state = state.current_file_state(); ASSERT_TRUE(Os::File::Mode::OPEN_READ != state.m_file.m_mode); @@ -1102,6 +1133,7 @@ bool Os::Test::File::Tester::IncrementalCrcInvalidModes::precondition( void Os::Test::File::Tester::IncrementalCrcInvalidModes::action( Os::Test::File::Tester& state //!< The test state ) { + printf("--> Rule: %s \n", this->getName()); state.assert_file_consistent(); FileState original_file_state = state.current_file_state(); ASSERT_TRUE(Os::File::Mode::OPEN_READ != state.m_file.m_mode); From 672538de32d4546005c3f8c2e84aa795209b1319 Mon Sep 17 00:00:00 2001 From: Justine West <35715959+jwest115@users.noreply.github.com> Date: Wed, 4 Sep 2024 14:48:25 -0700 Subject: [PATCH 08/10] Update Ref and RPI for compatibility with FPP #349 (fully qualified component instance names) (#2823) * updated ref and rpi integration tests * fix component qualifiers * FPP v2.2.0a1 * fix py file formatting * add new line * remove newline * file py file formatting * fprime-gds v3.4.4a3 * fix typo in integration test command name --------- Co-authored-by: jawest --- RPI/Top/RPITopologyDefs.hpp | 18 +++--- RPI/Top/instances.fpp | 94 ++++++++++++++-------------- RPI/test/int/rpi_integration_test.py | 24 ++++--- RPI/test/int/test_seq.seq | 4 +- Ref/Top/RefTopology.cpp | 28 ++++----- Ref/Top/RefTopologyDefs.hpp | 28 ++++----- Ref/test/int/ref_integration_test.py | 49 ++++++++------- Ref/test/int/test_seq.seq | 4 +- requirements.txt | 28 ++++----- 9 files changed, 142 insertions(+), 135 deletions(-) diff --git a/RPI/Top/RPITopologyDefs.hpp b/RPI/Top/RPITopologyDefs.hpp index f434f2e9b0..50ec1d1c84 100644 --- a/RPI/Top/RPITopologyDefs.hpp +++ b/RPI/Top/RPITopologyDefs.hpp @@ -46,15 +46,15 @@ namespace RPI { // Health ping entries namespace PingEntries { - namespace rateGroup10HzComp { enum { WARN = 3, FATAL = 5 }; } - namespace rateGroup1HzComp { enum { WARN = 3, FATAL = 5 }; } - namespace cmdDisp { enum { WARN = 3, FATAL = 5 }; } - namespace cmdSeq { enum { WARN = 3, FATAL = 5 }; } - namespace chanTlm { enum { WARN = 3, FATAL = 5 }; } - namespace eventLogger { enum { WARN = 3, FATAL = 5 }; } - namespace prmDb { enum { WARN = 3, FATAL = 5 }; } - namespace fileDownlink { enum { WARN = 3, FATAL = 5 }; } - namespace fileUplink { enum { WARN = 3, FATAL = 5 }; } + namespace RPI_rateGroup10HzComp { enum { WARN = 3, FATAL = 5 }; } + namespace RPI_rateGroup1HzComp { enum { WARN = 3, FATAL = 5 }; } + namespace RPI_cmdDisp { enum { WARN = 3, FATAL = 5 }; } + namespace RPI_cmdSeq { enum { WARN = 3, FATAL = 5 }; } + namespace RPI_chanTlm { enum { WARN = 3, FATAL = 5 }; } + namespace RPI_eventLogger { enum { WARN = 3, FATAL = 5 }; } + namespace RPI_prmDb { enum { WARN = 3, FATAL = 5 }; } + namespace RPI_fileDownlink { enum { WARN = 3, FATAL = 5 }; } + namespace RPI_fileUplink { enum { WARN = 3, FATAL = 5 }; } } } diff --git a/RPI/Top/instances.fpp b/RPI/Top/instances.fpp index 992aced0cc..79b7531fe1 100644 --- a/RPI/Top/instances.fpp +++ b/RPI/Top/instances.fpp @@ -27,9 +27,9 @@ module RPI { """ phase Fpp.ToCpp.Phases.configComponents """ - rateGroup10HzComp.configure( - ConfigObjects::rateGroup10HzComp::context, - FW_NUM_ARRAY_ELEMENTS(ConfigObjects::rateGroup10HzComp::context) + RPI::rateGroup10HzComp.configure( + ConfigObjects::RPI_rateGroup10HzComp::context, + FW_NUM_ARRAY_ELEMENTS(ConfigObjects::RPI_rateGroup10HzComp::context) ); """ @@ -51,8 +51,8 @@ module RPI { priority 20 \ { phase Fpp.ToCpp.Phases.readParameters """ - prmDb.configure("PrmDb.dat"); - prmDb.readParamFile(); + RPI::prmDb.configure("PrmDb.dat"); + RPI::prmDb.readParamFile(); """ } @@ -72,18 +72,18 @@ module RPI { phase Fpp.ToCpp.Phases.configComponents """ { - using namespace ConfigConstants::cmdSeq; - cmdSeq.allocateBuffer( + using namespace ConfigConstants::RPI_cmdSeq; + RPI::cmdSeq.allocateBuffer( 0, Allocation::mallocator, - ConfigConstants::cmdSeq::BUFFER_SIZE + ConfigConstants::RPI_cmdSeq::BUFFER_SIZE ); - cmdSeq.setTimeout(TIMEOUT); + RPI::cmdSeq.setTimeout(TIMEOUT); } """ phase Fpp.ToCpp.Phases.tearDownComponents """ - cmdSeq.deallocateBuffer(Allocation::mallocator); + RPI::cmdSeq.deallocateBuffer(Allocation::mallocator); """ } @@ -104,9 +104,9 @@ module RPI { """ phase Fpp.ToCpp.Phases.configComponents """ - rateGroup1HzComp.configure( - ConfigObjects::rateGroup1HzComp::context, - FW_NUM_ARRAY_ELEMENTS(ConfigObjects::rateGroup1HzComp::context) + RPI::rateGroup1HzComp.configure( + ConfigObjects::RPI_rateGroup1HzComp::context, + FW_NUM_ARRAY_ELEMENTS(ConfigObjects::RPI_rateGroup1HzComp::context) ); """ @@ -133,11 +133,11 @@ module RPI { """ phase Fpp.ToCpp.Phases.configComponents """ - fileDownlink.configure( - ConfigConstants::fileDownlink::TIMEOUT, - ConfigConstants::fileDownlink::COOLDOWN, - ConfigConstants::fileDownlink::CYCLE_TIME, - ConfigConstants::fileDownlink::FILE_QUEUE_DEPTH + RPI::fileDownlink.configure( + ConfigConstants::RPI_fileDownlink::TIMEOUT, + ConfigConstants::RPI_fileDownlink::COOLDOWN, + ConfigConstants::RPI_fileDownlink::CYCLE_TIME, + ConfigConstants::RPI_fileDownlink::FILE_QUEUE_DEPTH ); """ @@ -163,10 +163,10 @@ module RPI { """ phase Fpp.ToCpp.Phases.configComponents """ - health.setPingEntries( - ConfigObjects::health::pingEntries, - FW_NUM_ARRAY_ELEMENTS(ConfigObjects::health::pingEntries), - ConfigConstants::health::WATCHDOG_CODE + RPI::health.setPingEntries( + ConfigObjects::RPI_health::pingEntries, + FW_NUM_ARRAY_ELEMENTS(ConfigObjects::RPI_health::pingEntries), + ConfigConstants::RPI_health::WATCHDOG_CODE ); """ @@ -193,10 +193,10 @@ module RPI { { Svc::BufferManager::BufferBins bufferBins; memset(&bufferBins, 0, sizeof(bufferBins)); - using namespace ConfigConstants::fileUplinkBufferManager; + using namespace ConfigConstants::RPI_fileUplinkBufferManager; bufferBins.bins[0].bufferSize = STORE_SIZE; bufferBins.bins[0].numBuffers = QUEUE_SIZE; - fileUplinkBufferManager.setup( + RPI::fileUplinkBufferManager.setup( MGR_ID, 0, Allocation::mallocator, @@ -207,7 +207,7 @@ module RPI { """ phase Fpp.ToCpp.Phases.tearDownComponents """ - fileUplinkBufferManager.cleanup(); + RPI::fileUplinkBufferManager.cleanup(); """ } @@ -224,7 +224,7 @@ module RPI { """ phase Fpp.ToCpp.Phases.configComponents """ - downlink.setup(ConfigObjects::downlink::framing); + RPI::downlink.setup(ConfigObjects::RPI_downlink::framing); """ } @@ -237,7 +237,7 @@ module RPI { """ phase Fpp.ToCpp.Phases.configComponents """ - uplink.setup(ConfigObjects::uplink::deframing); + RPI::uplink.setup(ConfigObjects::RPI_uplink::deframing); """ } @@ -257,21 +257,21 @@ module RPI { if (state.hostName != nullptr && state.portNumber != 0) { Os::TaskString name("ReceiveTask"); // Uplink is configured for receive so a socket task is started - comm.configure(state.hostName, state.portNumber); - comm.start( + RPI::comm.configure(state.hostName, state.portNumber); + RPI::comm.start( name, - ConfigConstants::comm::PRIORITY, - ConfigConstants::comm::STACK_SIZE + ConfigConstants::RPI_comm::PRIORITY, + ConfigConstants::RPI_comm::STACK_SIZE ); } """ phase Fpp.ToCpp.Phases.stopTasks """ - comm.stop(); + RPI::comm.stop(); """ phase Fpp.ToCpp.Phases.freeThreads """ - (void) comm.join(); + (void) RPI::comm.join(); """ } @@ -282,7 +282,7 @@ module RPI { { phase Fpp.ToCpp.Phases.stopTasks """ - linuxTimer.quit(); + RPI::linuxTimer.quit(); """ } @@ -295,8 +295,8 @@ module RPI { """ phase Fpp.ToCpp.Phases.configComponents """ - rateGroupDriverComp.configure( - ConfigObjects::rateGroupDriverComp::rgDivs + RPI::rateGroupDriverComp.configure( + ConfigObjects::RPI_rateGroupDriverComp::rgDivs ); """ } @@ -323,7 +323,7 @@ module RPI { phase Fpp.ToCpp.Phases.startTasks """ if (Init::status) { - uartDrv.start(); + RPI::uartDrv.start(); } else { Fw::Logger::log("[ERROR] Initialization failed; not starting UART driver\\n"); @@ -331,7 +331,7 @@ module RPI { """ phase Fpp.ToCpp.Phases.stopTasks """ - uartDrv.quitReadThread(); + RPI::uartDrv.quitReadThread(); """ } @@ -341,7 +341,7 @@ module RPI { phase Fpp.ToCpp.Phases.configComponents """ { - const bool status = ledDrv.open(21, Drv::LinuxGpioDriverComponentImpl::GPIO_OUT); + const bool status = RPI::ledDrv.open(21, Drv::LinuxGpioDriverComponentImpl::GPIO_OUT); if (!status) { Fw::Logger::log("[ERROR] Could not open LED driver\\n"); Init::status = false; @@ -356,7 +356,7 @@ module RPI { phase Fpp.ToCpp.Phases.configComponents """ { - const bool status = gpio23Drv.open(23, Drv::LinuxGpioDriverComponentImpl::GPIO_OUT); + const bool status = RPI::gpio23Drv.open(23, Drv::LinuxGpioDriverComponentImpl::GPIO_OUT); if (!status) { Fw::Logger::log("[ERROR] Could not open GPIO 23 driver\\n"); Init::status = false; @@ -371,7 +371,7 @@ module RPI { phase Fpp.ToCpp.Phases.configComponents """ { - const bool status = gpio24Drv.open(24, Drv::LinuxGpioDriverComponentImpl::GPIO_OUT); + const bool status = RPI::gpio24Drv.open(24, Drv::LinuxGpioDriverComponentImpl::GPIO_OUT); if (!status) { Fw::Logger::log("[ERROR] Could not open GPIO 24 driver\\n"); Init::status = false; @@ -386,7 +386,7 @@ module RPI { phase Fpp.ToCpp.Phases.configComponents """ { - const bool status = gpio25Drv.open(25, Drv::LinuxGpioDriverComponentImpl::GPIO_IN); + const bool status = RPI::gpio25Drv.open(25, Drv::LinuxGpioDriverComponentImpl::GPIO_IN); if (!status) { Fw::Logger::log("[ERROR] Could not open GPIO 25 driver\\n"); Init::status = false; @@ -401,7 +401,7 @@ module RPI { phase Fpp.ToCpp.Phases.configComponents """ { - const bool status = gpio17Drv.open(17, Drv::LinuxGpioDriverComponentImpl::GPIO_IN); + const bool status = RPI::gpio17Drv.open(17, Drv::LinuxGpioDriverComponentImpl::GPIO_IN); if (!status) { Fw::Logger::log("[ERROR] Could not open GPIO 17 driver\\n"); Init::status = false; @@ -416,7 +416,7 @@ module RPI { phase Fpp.ToCpp.Phases.configComponents """ { - const bool status = spiDrv.open(0, 0, Drv::SPI_FREQUENCY_1MHZ); + const bool status = RPI::spiDrv.open(0, 0, Drv::SPI_FREQUENCY_1MHZ); if (!status) { Fw::Logger::log("[ERROR] Could not open SPI driver\\n"); Init::status = false; @@ -441,10 +441,10 @@ module RPI { { Svc::BufferManager::BufferBins bufferBins; memset(&bufferBins, 0, sizeof(bufferBins)); - using namespace ConfigConstants::uartBufferManager; + using namespace ConfigConstants::RPI_uartBufferManager; bufferBins.bins[0].bufferSize = STORE_SIZE; bufferBins.bins[0].numBuffers = QUEUE_SIZE; - uartBufferManager.setup( + RPI::uartBufferManager.setup( MGR_ID, 0, Allocation::mallocator, @@ -455,7 +455,7 @@ module RPI { """ phase Fpp.ToCpp.Phases.tearDownComponents """ - uartBufferManager.cleanup(); + RPI::uartBufferManager.cleanup(); """ } diff --git a/RPI/test/int/rpi_integration_test.py b/RPI/test/int/rpi_integration_test.py index dec78dfe13..a77df6408a 100644 --- a/RPI/test/int/rpi_integration_test.py +++ b/RPI/test/int/rpi_integration_test.py @@ -33,7 +33,7 @@ def set_event_filter(fprime_test_api, severity, enabled): severity = FilterSeverity[severity].name try: fprime_test_api.send_command( - "eventLogger.SET_EVENT_FILTER", + "RPI.eventLogger.SET_EVENT_FILTER", [severity, enabled], ) return True @@ -61,21 +61,25 @@ def test_is_streaming(fprime_test_api): def test_send_command(fprime_test_api): - fprime_test_api.send_and_assert_command("cmdDisp.CMD_NO_OP", max_delay=0.1) + fprime_test_api.send_and_assert_command("RPI.cmdDisp.CMD_NO_OP", max_delay=0.1) assert fprime_test_api.get_command_test_history().size() == 1 - fprime_test_api.send_and_assert_command("cmdDisp.CMD_NO_OP", max_delay=0.1) + fprime_test_api.send_and_assert_command("RPI.cmdDisp.CMD_NO_OP", max_delay=0.1) assert fprime_test_api.get_command_test_history().size() == 2 def test_send_and_assert_no_op(fprime_test_api): length = 100 failed = 0 - evr_seq = ["OpCodeDispatched", "NoOpReceived", "OpCodeCompleted"] + evr_seq = [ + "RPI.cmdDisp.OpCodeDispatched", + "RPI.cmdDisp.NoOpReceived", + "RPI.cmdDisp.OpCodeCompleted", + ] any_reordered = False dropped = False for i in range(0, length): results = fprime_test_api.send_and_await_event( - "cmdDisp.CMD_NO_OP", events=evr_seq, timeout=25 + "RPI.cmdDisp.CMD_NO_OP", events=evr_seq, timeout=25 ) msg = "Send and assert NO_OP Trial #{}".format(i) if not fprime_test_api.test_assert(len(results) == 3, msg, True): @@ -129,8 +133,8 @@ def test_active_logger_filter(fprime_test_api): # Drain time for dispatch events time.sleep(10) - fprime_test_api.send_and_assert_command("cmdDisp.CMD_NO_OP") - fprime_test_api.send_and_assert_command("cmdDisp.CMD_NO_OP") + fprime_test_api.send_and_assert_command("RPI.cmdDisp.CMD_NO_OP") + fprime_test_api.send_and_assert_command("RPI.cmdDisp.CMD_NO_OP") time.sleep(0.5) @@ -141,8 +145,8 @@ def test_active_logger_filter(fprime_test_api): # Drain time for dispatch events time.sleep(10) fprime_test_api.clear_histories() - fprime_test_api.send_command("cmdDisp.CMD_NO_OP") - fprime_test_api.send_command("cmdDisp.CMD_NO_OP") + fprime_test_api.send_command("RPI.cmdDisp.CMD_NO_OP") + fprime_test_api.send_command("RPI.cmdDisp.CMD_NO_OP") time.sleep(0.5) @@ -168,5 +172,5 @@ def test_seqgen(fprime_test_api): == 0 ), "Failed to run fprime-seqgen" fprime_test_api.send_and_assert_command( - "cmdSeq.CS_RUN", args=["/tmp/ref_test_int.bin", "BLOCK"], max_delay=5 + "RPI.cmdSeq.CS_RUN", args=["/tmp/ref_test_int.bin", "BLOCK"], max_delay=5 ) diff --git a/RPI/test/int/test_seq.seq b/RPI/test/int/test_seq.seq index 480ef0b32f..bda0e6df23 100644 --- a/RPI/test/int/test_seq.seq +++ b/RPI/test/int/test_seq.seq @@ -1,6 +1,6 @@ ; A test sequence ; -R00:00:00 cmdDisp.CMD_NO_OP +R00:00:00 RPI.cmdDisp.CMD_NO_OP ; Let's try out some commands with arguments -R00:00:01.050 cmdDisp.CMD_NO_OP_STRING "Awesome string!"; \ No newline at end of file +R00:00:01.050 RPI.cmdDisp.CMD_NO_OP_STRING "Awesome string!"; \ No newline at end of file diff --git a/Ref/Top/RefTopology.cpp b/Ref/Top/RefTopology.cpp index 9cfd30cffd..07d6434981 100644 --- a/Ref/Top/RefTopology.cpp +++ b/Ref/Top/RefTopology.cpp @@ -64,20 +64,20 @@ enum TopologyConstants { // Ping entries are autocoded, however; this code is not properly exported. Thus, it is copied here. Svc::Health::PingEntry pingEntries[] = { - {PingEntries::blockDrv::WARN, PingEntries::blockDrv::FATAL, "blockDrv"}, - {PingEntries::tlmSend::WARN, PingEntries::tlmSend::FATAL, "chanTlm"}, - {PingEntries::cmdDisp::WARN, PingEntries::cmdDisp::FATAL, "cmdDisp"}, - {PingEntries::cmdSeq::WARN, PingEntries::cmdSeq::FATAL, "cmdSeq"}, - {PingEntries::eventLogger::WARN, PingEntries::eventLogger::FATAL, "eventLogger"}, - {PingEntries::fileDownlink::WARN, PingEntries::fileDownlink::FATAL, "fileDownlink"}, - {PingEntries::fileManager::WARN, PingEntries::fileManager::FATAL, "fileManager"}, - {PingEntries::fileUplink::WARN, PingEntries::fileUplink::FATAL, "fileUplink"}, - {PingEntries::pingRcvr::WARN, PingEntries::pingRcvr::FATAL, "pingRcvr"}, - {PingEntries::prmDb::WARN, PingEntries::prmDb::FATAL, "prmDb"}, - {PingEntries::rateGroup1Comp::WARN, PingEntries::rateGroup1Comp::FATAL, "rateGroup1Comp"}, - {PingEntries::rateGroup2Comp::WARN, PingEntries::rateGroup2Comp::FATAL, "rateGroup2Comp"}, - {PingEntries::rateGroup3Comp::WARN, PingEntries::rateGroup3Comp::FATAL, "rateGroup3Comp"}, - {PingEntries::dpCat::WARN, PingEntries::dpCat::FATAL, "rateGroup3Comp"}, + {PingEntries::Ref_blockDrv::WARN, PingEntries::Ref_blockDrv::FATAL, "blockDrv"}, + {PingEntries::Ref_tlmSend::WARN, PingEntries::Ref_tlmSend::FATAL, "chanTlm"}, + {PingEntries::Ref_cmdDisp::WARN, PingEntries::Ref_cmdDisp::FATAL, "cmdDisp"}, + {PingEntries::Ref_cmdSeq::WARN, PingEntries::Ref_cmdSeq::FATAL, "cmdSeq"}, + {PingEntries::Ref_eventLogger::WARN, PingEntries::Ref_eventLogger::FATAL, "eventLogger"}, + {PingEntries::Ref_fileDownlink::WARN, PingEntries::Ref_fileDownlink::FATAL, "fileDownlink"}, + {PingEntries::Ref_fileManager::WARN, PingEntries::Ref_fileManager::FATAL, "fileManager"}, + {PingEntries::Ref_fileUplink::WARN, PingEntries::Ref_fileUplink::FATAL, "fileUplink"}, + {PingEntries::Ref_pingRcvr::WARN, PingEntries::Ref_pingRcvr::FATAL, "pingRcvr"}, + {PingEntries::Ref_prmDb::WARN, PingEntries::Ref_prmDb::FATAL, "prmDb"}, + {PingEntries::Ref_rateGroup1Comp::WARN, PingEntries::Ref_rateGroup1Comp::FATAL, "rateGroup1Comp"}, + {PingEntries::Ref_rateGroup2Comp::WARN, PingEntries::Ref_rateGroup2Comp::FATAL, "rateGroup2Comp"}, + {PingEntries::Ref_rateGroup3Comp::WARN, PingEntries::Ref_rateGroup3Comp::FATAL, "rateGroup3Comp"}, + {PingEntries::Ref_dpCat::WARN, PingEntries::Ref_dpCat::FATAL, "rateGroup3Comp"}, }; /** diff --git a/Ref/Top/RefTopologyDefs.hpp b/Ref/Top/RefTopologyDefs.hpp index 20ad9bd5d8..ede301899c 100644 --- a/Ref/Top/RefTopologyDefs.hpp +++ b/Ref/Top/RefTopologyDefs.hpp @@ -53,46 +53,46 @@ struct TopologyState { * ``` */ namespace PingEntries { -namespace blockDrv { +namespace Ref_blockDrv { enum { WARN = 3, FATAL = 5 }; } -namespace tlmSend { +namespace Ref_tlmSend { enum { WARN = 3, FATAL = 5 }; } -namespace cmdDisp { +namespace Ref_cmdDisp { enum { WARN = 3, FATAL = 5 }; } -namespace cmdSeq { +namespace Ref_cmdSeq { enum { WARN = 3, FATAL = 5 }; } -namespace eventLogger { +namespace Ref_eventLogger { enum { WARN = 3, FATAL = 5 }; } -namespace fileDownlink { +namespace Ref_fileDownlink { enum { WARN = 3, FATAL = 5 }; } -namespace fileManager { +namespace Ref_fileManager { enum { WARN = 3, FATAL = 5 }; } -namespace fileUplink { +namespace Ref_fileUplink { enum { WARN = 3, FATAL = 5 }; } -namespace pingRcvr { +namespace Ref_pingRcvr { enum { WARN = 3, FATAL = 5 }; } -namespace prmDb { +namespace Ref_prmDb { enum { WARN = 3, FATAL = 5 }; } -namespace rateGroup1Comp { +namespace Ref_rateGroup1Comp { enum { WARN = 3, FATAL = 5 }; } -namespace rateGroup2Comp { +namespace Ref_rateGroup2Comp { enum { WARN = 3, FATAL = 5 }; } -namespace rateGroup3Comp { +namespace Ref_rateGroup3Comp { enum { WARN = 3, FATAL = 5 }; } -namespace dpCat { +namespace Ref_dpCat { enum { WARN = 3, FATAL = 5 }; } } // namespace PingEntries diff --git a/Ref/test/int/ref_integration_test.py b/Ref/test/int/ref_integration_test.py index 6682fa2882..8523e42e01 100644 --- a/Ref/test/int/ref_integration_test.py +++ b/Ref/test/int/ref_integration_test.py @@ -2,6 +2,7 @@ A set of integration tests to apply to the Ref app. This is intended to be a reference of integration testing. """ + import subprocess import time from enum import Enum @@ -24,14 +25,14 @@ def test_is_streaming(fprime_test_api): """Test flight software is streaming Tests that the flight software is streaming by looking for 5 telemetry items in 10 seconds. Additionally, - "sendBuffComp.SendState" is verified to be SEND_IDLE. + "Ref.sendBuffComp.SendState" is verified to be SEND_IDLE. """ results = fprime_test_api.assert_telemetry_count(5, timeout=10) for result in results: msg = "received channel {} update: {}".format(result.get_id(), result.get_str()) print(msg) fprime_test_api.assert_telemetry( - "sendBuffComp.SendState", value="SEND_IDLE", timeout=3 + "Ref.sendBuffComp.SendState", value="SEND_IDLE", timeout=3 ) @@ -56,7 +57,7 @@ def set_event_filter(fprime_test_api, severity, enabled): severity = FilterSeverity[severity].name try: fprime_test_api.send_command( - "eventLogger.SET_EVENT_FILTER", + "Ref.eventLogger.SET_EVENT_FILTER", [severity, enabled], ) return True @@ -79,9 +80,9 @@ def test_send_command(fprime_test_api): Tests command send, dispatch, and receipt using send_and_assert command with a pair of NO-OP commands. """ - fprime_test_api.send_and_assert_command("cmdDisp.CMD_NO_OP", max_delay=0.1) + fprime_test_api.send_and_assert_command("Ref.cmdDisp.CMD_NO_OP", max_delay=0.1) assert fprime_test_api.get_command_test_history().size() == 1 - fprime_test_api.send_and_assert_command("cmdDisp.CMD_NO_OP", max_delay=0.1) + fprime_test_api.send_and_assert_command("Ref.cmdDisp.CMD_NO_OP", max_delay=0.1) assert fprime_test_api.get_command_test_history().size() == 2 @@ -91,9 +92,11 @@ def test_send_command_args(fprime_test_api): Tests command send, dispatch, and receipt using send_and_assert command with a pair of NO-OP string commands. """ for count, value in enumerate(["Test String 1", "Some other string"], 1): - events = [fprime_test_api.get_event_pred("cmdDisp.NoOpStringReceived", [value])] + events = [ + fprime_test_api.get_event_pred("Ref.cmdDisp.NoOpStringReceived", [value]) + ] fprime_test_api.send_and_assert_command( - "cmdDisp.CMD_NO_OP_STRING", + "Ref.cmdDisp.CMD_NO_OP_STRING", [ value, ], @@ -112,15 +115,15 @@ def test_send_and_assert_no_op(fprime_test_api): length = 100 failed = 0 evr_seq = [ - "cmdDisp.OpCodeDispatched", - "cmdDisp.NoOpReceived", - "cmdDisp.OpCodeCompleted", + "Ref.cmdDisp.OpCodeDispatched", + "Ref.cmdDisp.NoOpReceived", + "Ref.cmdDisp.OpCodeCompleted", ] any_reordered = False dropped = False for i in range(0, length): results = fprime_test_api.send_and_await_event( - "cmdDisp.CMD_NO_OP", events=evr_seq, timeout=25 + "Ref.cmdDisp.CMD_NO_OP", events=evr_seq, timeout=25 ) msg = "Send and assert NO_OP Trial #{}".format(i) if not fprime_test_api.test_assert(len(results) == 3, msg, True): @@ -167,7 +170,7 @@ def test_bd_cycles_ascending(fprime_test_api): length = 60 count_pred = predicates.greater_than(length - 1) results = fprime_test_api.await_telemetry_count( - count_pred, "blockDrv.BD_Cycles", timeout=length + count_pred, "Ref.blockDrv.BD_Cycles", timeout=length ) last = None reordered = False @@ -227,8 +230,8 @@ def test_active_logger_filter(fprime_test_api): # Drain time for dispatch events time.sleep(10) - fprime_test_api.send_and_assert_command("cmdDisp.CMD_NO_OP") - fprime_test_api.send_and_assert_command("cmdDisp.CMD_NO_OP") + fprime_test_api.send_and_assert_command("Ref.cmdDisp.CMD_NO_OP") + fprime_test_api.send_and_assert_command("Ref.cmdDisp.CMD_NO_OP") time.sleep(0.5) @@ -239,8 +242,8 @@ def test_active_logger_filter(fprime_test_api): # Drain time for dispatch events time.sleep(10) fprime_test_api.clear_histories() - fprime_test_api.send_command("cmdDisp.CMD_NO_OP") - fprime_test_api.send_command("cmdDisp.CMD_NO_OP") + fprime_test_api.send_command("Ref.cmdDisp.CMD_NO_OP") + fprime_test_api.send_command("Ref.cmdDisp.CMD_NO_OP") time.sleep(0.5) @@ -253,17 +256,17 @@ def test_active_logger_filter(fprime_test_api): def test_signal_generation(fprime_test_api): """Tests the behavior of signal gen component""" fprime_test_api.send_and_assert_command( - "SG4.SignalGen_Settings", [1, 5, 0, "SQUARE"] + "Ref.SG4.SignalGen_Settings", [1, 5, 0, "SQUARE"] ) # First telemetry item should fill only the first slot of the history history = [0, 0, 0, 5] pair_history = [{"time": 0, "value": value} for value in history] info = {"type": "SQUARE", "history": history, "pairHistory": pair_history} - fprime_test_api.send_and_assert_command("SG4.SignalGen_Toggle") - fprime_test_api.assert_telemetry("SG4.History", history, timeout=6) - fprime_test_api.assert_telemetry("SG4.PairHistory", pair_history, timeout=1) - fprime_test_api.assert_telemetry("SG4.Info", info, timeout=1) - fprime_test_api.send_and_assert_command("SG4.SignalGen_Toggle") + fprime_test_api.send_and_assert_command("Ref.SG4.SignalGen_Toggle") + fprime_test_api.assert_telemetry("Ref.SG4.History", history, timeout=6) + fprime_test_api.assert_telemetry("Ref.SG4.PairHistory", pair_history, timeout=1) + fprime_test_api.assert_telemetry("Ref.SG4.Info", info, timeout=1) + fprime_test_api.send_and_assert_command("Ref.SG4.SignalGen_Toggle") def test_seqgen(fprime_test_api): @@ -282,5 +285,5 @@ def test_seqgen(fprime_test_api): == 0 ), "Failed to run fprime-seqgen" fprime_test_api.send_and_assert_command( - "cmdSeq.CS_RUN", args=["/tmp/ref_test_int.bin", "BLOCK"], max_delay=5 + "Ref.cmdSeq.CS_RUN", args=["/tmp/ref_test_int.bin", "BLOCK"], max_delay=5 ) diff --git a/Ref/test/int/test_seq.seq b/Ref/test/int/test_seq.seq index 480ef0b32f..c80b1f5578 100644 --- a/Ref/test/int/test_seq.seq +++ b/Ref/test/int/test_seq.seq @@ -1,6 +1,6 @@ ; A test sequence ; -R00:00:00 cmdDisp.CMD_NO_OP +R00:00:00 Ref.cmdDisp.CMD_NO_OP ; Let's try out some commands with arguments -R00:00:01.050 cmdDisp.CMD_NO_OP_STRING "Awesome string!"; \ No newline at end of file +R00:00:01.050 Ref.cmdDisp.CMD_NO_OP_STRING "Awesome string!"; \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 1915d23228..0d1607c003 100644 --- a/requirements.txt +++ b/requirements.txt @@ -18,20 +18,20 @@ fprime-fpl-convert-xml==1.0.3 fprime-fpl-extract-xml==1.0.3 fprime-fpl-layout==1.0.3 fprime-fpl-write-pic==1.0.3 -fprime-fpp-check==2.1.0 -fprime-fpp-depend==2.1.0 -fprime-fpp-filenames==2.1.0 -fprime-fpp-format==2.1.0 -fprime-fpp-from-xml==2.1.0 -fprime-fpp-locate-defs==2.1.0 -fprime-fpp-locate-uses==2.1.0 -fprime-fpp-syntax==2.1.0 -fprime-fpp-to-cpp==2.1.0 -fprime-fpp-to-dict==2.1.0 -fprime-fpp-to-json==2.1.0 -fprime-fpp-to-xml==2.1.0 -fprime-gds==v3.4.4a2 -fprime-tools==v3.4.5a1 +fprime-fpp-check==2.2.0a1 +fprime-fpp-depend==2.2.0a1 +fprime-fpp-filenames==2.2.0a1 +fprime-fpp-format==2.2.0a1 +fprime-fpp-from-xml==2.2.0a1 +fprime-fpp-locate-defs==2.2.0a1 +fprime-fpp-locate-uses==2.2.0a1 +fprime-fpp-syntax==2.2.0a1 +fprime-fpp-to-cpp==2.2.0a1 +fprime-fpp-to-dict==2.2.0a1 +fprime-fpp-to-json==2.2.0a1 +fprime-fpp-to-xml==2.2.0a1 +fprime-gds==3.4.4a3 +fprime-tools==3.4.4 fprime-visual==1.0.2 gcovr==6.0 idna==3.4 From e27598db481cf60a18895c82681ec54720e6a93f Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Thu, 5 Sep 2024 14:40:34 -0700 Subject: [PATCH 09/10] Fix requirements.txt --- requirements.txt | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/requirements.txt b/requirements.txt index 4fc39590a2..9d6cde7894 100644 --- a/requirements.txt +++ b/requirements.txt @@ -18,18 +18,18 @@ fprime-fpl-convert-xml==1.0.3 fprime-fpl-extract-xml==1.0.3 fprime-fpl-layout==1.0.3 fprime-fpl-write-pic==1.0.3 -fprime-fpp-check==v2.2.0a3 -fprime-fpp-depend==v2.2.0a3 -fprime-fpp-filenames==v2.2.0a3 -fprime-fpp-format==v2.2.0a3 -fprime-fpp-from-xml==v2.2.0a3 -fprime-fpp-locate-defs==v2.2.0a3 -fprime-fpp-locate-uses==v2.2.0a3 -fprime-fpp-syntax==v2.2.0a3 -fprime-fpp-to-cpp==v2.2.0a3 -fprime-fpp-to-dict==v2.2.0a3 -fprime-fpp-to-json==v2.2.0a3 -fprime-fpp-to-xml==v2.2.0a3 +fprime-fpp-check==2.2.0a3 +fprime-fpp-depend==2.2.0a3 +fprime-fpp-filenames==2.2.0a3 +fprime-fpp-format==2.2.0a3 +fprime-fpp-from-xml==2.2.0a3 +fprime-fpp-locate-defs==2.2.0a3 +fprime-fpp-locate-uses==2.2.0a3 +fprime-fpp-syntax==2.2.0a3 +fprime-fpp-to-cpp==2.2.0a3 +fprime-fpp-to-dict==2.2.0a3 +fprime-fpp-to-json==2.2.0a3 +fprime-fpp-to-xml==2.2.0a3 fprime-gds==3.4.3 fprime-tools==3.4.4 fprime-visual==1.0.2 From ae5727b9e4b00e641c1605099392609193a3cdfb Mon Sep 17 00:00:00 2001 From: Rob Bocchino Date: Thu, 5 Sep 2024 15:07:29 -0700 Subject: [PATCH 10/10] Fix requirements.txt --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 9d6cde7894..00fc186b57 100644 --- a/requirements.txt +++ b/requirements.txt @@ -30,7 +30,7 @@ fprime-fpp-to-cpp==2.2.0a3 fprime-fpp-to-dict==2.2.0a3 fprime-fpp-to-json==2.2.0a3 fprime-fpp-to-xml==2.2.0a3 -fprime-gds==3.4.3 +fprime-gds==3.4.4a3 fprime-tools==3.4.4 fprime-visual==1.0.2 gcovr==6.0