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: