From 92df69218a6ec595dc786fcc48e4822f6c85a4a5 Mon Sep 17 00:00:00 2001 From: M Starch Date: Mon, 25 Nov 2024 13:36:22 -0800 Subject: [PATCH] Add in Svc::ChronoTime for C++11 std::chrono implementation (#3049) * Add in Svc::ChronoTime for C++11 std::chrono implementation. Fixes: nasa/fprime#3048 * Fix test name * Fixing spelling problems --- .github/actions/spelling/expect.txt | 1 + Svc/CMakeLists.txt | 3 +- Svc/ChronoTime/CMakeLists.txt | 26 +++++++ Svc/ChronoTime/ChronoTime.cpp | 33 +++++++++ Svc/ChronoTime/ChronoTime.fpp | 6 ++ Svc/ChronoTime/ChronoTime.hpp | 42 ++++++++++++ Svc/ChronoTime/docs/sdd.md | 45 ++++++++++++ Svc/ChronoTime/test/ut/ChronoTimeTestMain.cpp | 17 +++++ Svc/ChronoTime/test/ut/ChronoTimeTester.cpp | 54 +++++++++++++++ Svc/ChronoTime/test/ut/ChronoTimeTester.hpp | 68 +++++++++++++++++++ Svc/LinuxTimer/CMakeLists.txt | 6 -- docs/UsersGuide/dev/os-docs.md | 4 +- docs/UsersGuide/user/full-intro.md | 4 +- 13 files changed, 298 insertions(+), 11 deletions(-) create mode 100644 Svc/ChronoTime/CMakeLists.txt create mode 100644 Svc/ChronoTime/ChronoTime.cpp create mode 100644 Svc/ChronoTime/ChronoTime.fpp create mode 100644 Svc/ChronoTime/ChronoTime.hpp create mode 100644 Svc/ChronoTime/docs/sdd.md create mode 100644 Svc/ChronoTime/test/ut/ChronoTimeTestMain.cpp create mode 100644 Svc/ChronoTime/test/ut/ChronoTimeTester.cpp create mode 100644 Svc/ChronoTime/test/ut/ChronoTimeTester.hpp diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 65b9766c64..8f1434d85f 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -952,6 +952,7 @@ Thhmmss thiscol thisdirdoesnotexist thisfiledoesnotexist +Thu timebase timerfd timetag diff --git a/Svc/CMakeLists.txt b/Svc/CMakeLists.txt index 2ab95efc03..49de3f43aa 100644 --- a/Svc/CMakeLists.txt +++ b/Svc/CMakeLists.txt @@ -17,6 +17,7 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/BufferAccumulator/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/BufferManager/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/BufferLogger/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/BufferRepeater/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ChronoTime/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ComLogger/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ComQueue/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ComSplitter/") @@ -58,4 +59,4 @@ endif() add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/PosixTime/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/LinuxTimer/") -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Version/") \ No newline at end of file +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Version/") diff --git a/Svc/ChronoTime/CMakeLists.txt b/Svc/ChronoTime/CMakeLists.txt new file mode 100644 index 0000000000..01dff82fa1 --- /dev/null +++ b/Svc/ChronoTime/CMakeLists.txt @@ -0,0 +1,26 @@ +#### +# FPrime CMakeLists.txt: +# +# SOURCE_FILES: combined list of source and autocoding files +# MOD_DEPS: (optional) module dependencies +# UT_SOURCE_FILES: list of source files for unit tests +# +# More information in the F´ CMake API documentation: +# https://nasa.github.io/fprime/UsersGuide/api/cmake/API.html +# +#### + +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/ChronoTime.fpp" + "${CMAKE_CURRENT_LIST_DIR}/ChronoTime.cpp" +) + +register_fprime_module() + +set(UT_AUTO_HELPERS ON) +set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/ChronoTime.fpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/ChronoTimeTester.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/ChronoTimeTestMain.cpp" +) +register_fprime_ut() \ No newline at end of file diff --git a/Svc/ChronoTime/ChronoTime.cpp b/Svc/ChronoTime/ChronoTime.cpp new file mode 100644 index 0000000000..4587125fd3 --- /dev/null +++ b/Svc/ChronoTime/ChronoTime.cpp @@ -0,0 +1,33 @@ +// ====================================================================== +// \title ChronoTime.cpp +// \author mstarch +// \brief cpp file for ChronoTime component implementation class +// ====================================================================== + +#include "Svc/ChronoTime/ChronoTime.hpp" +#include +#include "FpConfig.hpp" + +namespace Svc { + +// ---------------------------------------------------------------------- +// Component construction and destruction +// ---------------------------------------------------------------------- + +ChronoTime ::ChronoTime(const char* const compName) : ChronoTimeComponentBase(compName) {} + +ChronoTime ::~ChronoTime() {} + +// ---------------------------------------------------------------------- +// Handler implementations for user-defined typed input ports +// ---------------------------------------------------------------------- + +void ChronoTime ::timeGetPort_handler(FwIndexType portNum, Fw::Time& time) { + const auto time_now = std::chrono::system_clock::now(); + time.set(TimeBase::TB_WORKSTATION_TIME, + static_cast(std::chrono::duration_cast(time_now.time_since_epoch()).count()), + static_cast( + std::chrono::duration_cast(time_now.time_since_epoch()).count() % 1000000)); +} + +} // namespace Svc diff --git a/Svc/ChronoTime/ChronoTime.fpp b/Svc/ChronoTime/ChronoTime.fpp new file mode 100644 index 0000000000..fccb91b780 --- /dev/null +++ b/Svc/ChronoTime/ChronoTime.fpp @@ -0,0 +1,6 @@ +module Svc { + @ A time component using C++11 chrono library + passive component ChronoTime { + include "../Interfaces/TimeInterface.fppi" + } +} \ No newline at end of file diff --git a/Svc/ChronoTime/ChronoTime.hpp b/Svc/ChronoTime/ChronoTime.hpp new file mode 100644 index 0000000000..bd0d904ab1 --- /dev/null +++ b/Svc/ChronoTime/ChronoTime.hpp @@ -0,0 +1,42 @@ +// ====================================================================== +// \title ChronoTime.hpp +// \author mstarch +// \brief hpp file for ChronoTime component implementation class +// ====================================================================== + +#ifndef Svc_ChronoTime_HPP +#define Svc_ChronoTime_HPP + +#include "Svc/ChronoTime/ChronoTimeComponentAc.hpp" + +namespace Svc { + +class ChronoTime : public ChronoTimeComponentBase { + public: + // ---------------------------------------------------------------------- + // Component construction and destruction + // ---------------------------------------------------------------------- + + //! Construct ChronoTime object + ChronoTime(const char* const compName //!< The component name + ); + + //! Destroy ChronoTime object + ~ChronoTime(); + + PRIVATE: + // ---------------------------------------------------------------------- + // Handler implementations for user-defined typed input ports + // ---------------------------------------------------------------------- + + //! Handler implementation for timeGetPort + //! + //! Port to retrieve time + void timeGetPort_handler(FwIndexType portNum, //!< The port number + Fw::Time& time //!< Reference to Time object + ) override; +}; + +} // namespace Svc + +#endif diff --git a/Svc/ChronoTime/docs/sdd.md b/Svc/ChronoTime/docs/sdd.md new file mode 100644 index 0000000000..0259732277 --- /dev/null +++ b/Svc/ChronoTime/docs/sdd.md @@ -0,0 +1,45 @@ +# Svc::ChronoTime + +As an F Prime project matures, a custom time component will likely be developed soliciting time in the project directed +way. For reference projects and projects in an early phase of development, this custom time component does not exist. +This miss-match was historically filled by Svc::PosixTime (formerly Svc::LinuxTime), however; this requires a project to +support posix. + +The std::chrono library provided by C++11 is a language feature and as such can implement time without the need for +posix. + +This is a C++11 implementation of the TimeInterface used to supply time to the various parts of the system. + +## Requirements + +The following requirements describe the behavior of Svc::ChronoTime. + +| Name | Description | Validation | +|---------------------|--------------------------------------------------------------------------|------------| +| SVC_CHRONO_TIME_001 | Svc::ChronoTime shall be implemented using only C++11 language features. | Inspection | +| SVC_CHRONO_TIME_002 | Svc::ChronoTime shall implement the Svc.TimeInterface. | Unit-Test | +| SVC_CHRONO_TIME_003 | Svc::ChronoTime shall provide time with resolution to microseconds. | Unit-Test | + + +## Usage Examples + +In order to use this component, projects must supply `TimeBase::TB_WORKSTATION_TIME` in their `TimeBase` enumeration. + +To use Svc::ChronoTime in your project, make sure to set the time service with the following lines in your topology: + +**Add the instance to the instance list:** +``` + instance chronoTime: Svc.PosixTime base id 0x4500 +``` + +**Use the instance to supply time:** +``` + time connections instance chronoTime +``` + +> Since an implementation of the time interface comes with he standard topology template, projects should replace it. + +## Change Log +| Date | Description | +|------------|---------------| +| 2024-11-25 | Initial Draft | \ No newline at end of file diff --git a/Svc/ChronoTime/test/ut/ChronoTimeTestMain.cpp b/Svc/ChronoTime/test/ut/ChronoTimeTestMain.cpp new file mode 100644 index 0000000000..0ed6f5e3cb --- /dev/null +++ b/Svc/ChronoTime/test/ut/ChronoTimeTestMain.cpp @@ -0,0 +1,17 @@ +// ====================================================================== +// \title ChronoTimeTestMain.cpp +// \author mstarch +// \brief cpp file for ChronoTime component test main function +// ====================================================================== + +#include "ChronoTimeTester.hpp" + +TEST(Nominal, TestBasicTime) { + Svc::ChronoTimeTester tester; + tester.test_basic_time(); +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/Svc/ChronoTime/test/ut/ChronoTimeTester.cpp b/Svc/ChronoTime/test/ut/ChronoTimeTester.cpp new file mode 100644 index 0000000000..59de7aac7a --- /dev/null +++ b/Svc/ChronoTime/test/ut/ChronoTimeTester.cpp @@ -0,0 +1,54 @@ +// ====================================================================== +// \title ChronoTimeTester.cpp +// \author mstarch +// \brief cpp file for ChronoTime component test harness implementation class +// ====================================================================== + +#include "ChronoTimeTester.hpp" +#include +#include +namespace Svc { + +// ---------------------------------------------------------------------- +// Construction and destruction +// ---------------------------------------------------------------------- + +ChronoTimeTester ::ChronoTimeTester() + : ChronoTimeGTestBase("ChronoTimeTester", ChronoTimeTester::MAX_HISTORY_SIZE), component("ChronoTime") { + this->initComponents(); + this->connectPorts(); +} + +ChronoTimeTester ::~ChronoTimeTester() {} + +// ---------------------------------------------------------------------- +// Tests +// ---------------------------------------------------------------------- + +void ChronoTimeTester ::test_basic_time() { + const U32 SECONDS_SINCE_EPOCH_2024_11_25 = 1732492800ull; // Time since epoch as of date of writing + const std::string expected_epoch_time("Thu Jan 1 00:00:00 1970\n"); //std::asctime adds \n + + // Calculate the system_clock epoch. This test is only valid when the system_clock uses unix epoch. + const auto epoch = std::chrono::time_point{}; + std::time_t epoch_time = std::chrono::system_clock::to_time_t(epoch); + const std::string reported_epoch_time(std::asctime(std::gmtime(&epoch_time))); + + // Skip test when epoch is not the unix epoch + if (expected_epoch_time != reported_epoch_time) { + GTEST_SKIP() << "Cannot run std::chrono test with non-unix epoch of: " << reported_epoch_time; + } + + REQUIREMENT("SVC_CHRONO_TIME_002"); + REQUIREMENT("SVC_CHRONO_TIME_003"); + + // Invoke port + Fw::Time time; + this->invoke_to_timeGetPort(0, time); + ASSERT_GT(time.getSeconds(), SECONDS_SINCE_EPOCH_2024_11_25); + // Check for correct use of milliseconds + ASSERT_GE(time.getUSeconds(), 0U); + ASSERT_LE(time.getUSeconds(), 999999U); +} + +} // namespace Svc diff --git a/Svc/ChronoTime/test/ut/ChronoTimeTester.hpp b/Svc/ChronoTime/test/ut/ChronoTimeTester.hpp new file mode 100644 index 0000000000..71f9565c5f --- /dev/null +++ b/Svc/ChronoTime/test/ut/ChronoTimeTester.hpp @@ -0,0 +1,68 @@ +// ====================================================================== +// \title ChronoTimeTester.hpp +// \author mstarch +// \brief hpp file for ChronoTime component test harness implementation class +// ====================================================================== + +#ifndef Svc_ChronoTimeTester_HPP +#define Svc_ChronoTimeTester_HPP + +#include "Svc/ChronoTime/ChronoTime.hpp" +#include "Svc/ChronoTime/ChronoTimeGTestBase.hpp" + +namespace Svc { + +class ChronoTimeTester : public ChronoTimeGTestBase { + public: + // ---------------------------------------------------------------------- + // Constants + // ---------------------------------------------------------------------- + + // Maximum size of histories storing events, telemetry, and port outputs + static const FwSizeType MAX_HISTORY_SIZE = 10; + + // Instance ID supplied to the component instance under test + static const FwEnumStoreType TEST_INSTANCE_ID = 0; + + public: + // ---------------------------------------------------------------------- + // Construction and destruction + // ---------------------------------------------------------------------- + + //! Construct object ChronoTimeTester + ChronoTimeTester(); + + //! Destroy object ChronoTimeTester + ~ChronoTimeTester(); + + public: + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- + + //! To do + void test_basic_time(); + + private: + // ---------------------------------------------------------------------- + // Helper functions + // ---------------------------------------------------------------------- + + //! Connect ports + void connectPorts(); + + //! Initialize components + void initComponents(); + + private: + // ---------------------------------------------------------------------- + // Member variables + // ---------------------------------------------------------------------- + + //! The component under test + ChronoTime component; +}; + +} // namespace Svc + +#endif diff --git a/Svc/LinuxTimer/CMakeLists.txt b/Svc/LinuxTimer/CMakeLists.txt index 1a1547f8eb..aac80ceb6f 100644 --- a/Svc/LinuxTimer/CMakeLists.txt +++ b/Svc/LinuxTimer/CMakeLists.txt @@ -20,12 +20,6 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") "${CMAKE_CURRENT_LIST_DIR}/LinuxTimerComponentImplTimerFd.cpp" "${CMAKE_CURRENT_LIST_DIR}/LinuxTimerComponentImplCommon.cpp" ) -elseif(${CMAKE_SYSTEM_NAME} STREQUAL "RTEMS5") - set(SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/LinuxTimer.fpp" - "${CMAKE_CURRENT_LIST_DIR}/LinuxTimerComponentImplTaskDelay.cpp" - "${CMAKE_CURRENT_LIST_DIR}/LinuxTimerComponentImplCommon.cpp" - ) else() set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/LinuxTimer.fpp" diff --git a/docs/UsersGuide/dev/os-docs.md b/docs/UsersGuide/dev/os-docs.md index a61dcc80ff..ce4528cf97 100644 --- a/docs/UsersGuide/dev/os-docs.md +++ b/docs/UsersGuide/dev/os-docs.md @@ -5,7 +5,7 @@ > 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: +This layer shows the user an abstraction of the common functionality provided by all real-time operating systems (VxWorks, Azure ThreadX, QNX, FreeRTOS, Zephyr,...) or not (Linux, macOS, WinCE,...). We find the following services: 1. multitasking management with prioritization ; 2. synchronization ; @@ -236,4 +236,4 @@ Table 30 provides the methods and their descriptions. | logMsg | Log a text message. The arguments are: | | | | **Argument** | **Description** | | | fmt | Format string to fill and print. | -| | a1 to a6 | Values to be printed. They will be inserted into the format string based on the format string specifiers. The type of the argument is POINTER\_CAST (normally an integer), but a typical usage is to cast the values to display to POINTER\_CAST and allow the format string extraction to get the correct value. This can include strings (char\*), but the location in memory that holds the string must persist since the format string may be printed on another task in the system. | \ No newline at end of file +| | a1 to a6 | Values to be printed. They will be inserted into the format string based on the format string specifiers. The type of the argument is POINTER\_CAST (normally an integer), but a typical usage is to cast the values to display to POINTER\_CAST and allow the format string extraction to get the correct value. This can include strings (char\*), but the location in memory that holds the string must persist since the format string may be printed on another task in the system. | diff --git a/docs/UsersGuide/user/full-intro.md b/docs/UsersGuide/user/full-intro.md index 823962bade..028aacc46c 100644 --- a/docs/UsersGuide/user/full-intro.md +++ b/docs/UsersGuide/user/full-intro.md @@ -88,5 +88,5 @@ required. See: [F´ On Baremetal and Multi-Core Systems](../dev/baremetal-multi ## Conclusion The F′ software framework is released as open source and has been ported to Linux, macOS, Windows (WSL), VxWorks, ARINC - 653, RTEMS, Baremetal(No OS), PPC, Leon3, x86, ARM (A15/A7), and MSP430. Mature sets of CD&H components are available -following flight process, such as code inspections, static analysis, and full-coverage unit testing. \ No newline at end of file + 653, Baremetal(No OS), PPC, Leon3, x86, ARM (A15/A7), and MSP430. Mature sets of CD&H components are available +following flight process, such as code inspections, static analysis, and full-coverage unit testing.