Skip to content

Commit

Permalink
Add in Svc::ChronoTime for C++11 std::chrono implementation (#3049)
Browse files Browse the repository at this point in the history
* Add in Svc::ChronoTime for C++11 std::chrono implementation. Fixes: #3048

* Fix test name

* Fixing spelling problems
  • Loading branch information
LeStarch authored Nov 25, 2024
1 parent b40097e commit 92df692
Show file tree
Hide file tree
Showing 13 changed files with 298 additions and 11 deletions.
1 change: 1 addition & 0 deletions .github/actions/spelling/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -952,6 +952,7 @@ Thhmmss
thiscol
thisdirdoesnotexist
thisfiledoesnotexist
Thu
timebase
timerfd
timetag
Expand Down
3 changes: 2 additions & 1 deletion Svc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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/")
Expand Down Expand Up @@ -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/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Version/")
26 changes: 26 additions & 0 deletions Svc/ChronoTime/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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()
33 changes: 33 additions & 0 deletions Svc/ChronoTime/ChronoTime.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// ======================================================================
// \title ChronoTime.cpp
// \author mstarch
// \brief cpp file for ChronoTime component implementation class
// ======================================================================

#include "Svc/ChronoTime/ChronoTime.hpp"
#include <chrono>
#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<U32>(std::chrono::duration_cast<std::chrono::seconds>(time_now.time_since_epoch()).count()),
static_cast<U32>(
std::chrono::duration_cast<std::chrono::microseconds>(time_now.time_since_epoch()).count() % 1000000));
}

} // namespace Svc
6 changes: 6 additions & 0 deletions Svc/ChronoTime/ChronoTime.fpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Svc {
@ A time component using C++11 chrono library
passive component ChronoTime {
include "../Interfaces/TimeInterface.fppi"
}
}
42 changes: 42 additions & 0 deletions Svc/ChronoTime/ChronoTime.hpp
Original file line number Diff line number Diff line change
@@ -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
45 changes: 45 additions & 0 deletions Svc/ChronoTime/docs/sdd.md
Original file line number Diff line number Diff line change
@@ -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 |
17 changes: 17 additions & 0 deletions Svc/ChronoTime/test/ut/ChronoTimeTestMain.cpp
Original file line number Diff line number Diff line change
@@ -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();
}
54 changes: 54 additions & 0 deletions Svc/ChronoTime/test/ut/ChronoTimeTester.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// ======================================================================
// \title ChronoTimeTester.cpp
// \author mstarch
// \brief cpp file for ChronoTime component test harness implementation class
// ======================================================================

#include "ChronoTimeTester.hpp"
#include <Fw/Test/UnitTest.hpp>
#include <iostream>
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::chrono::system_clock>{};
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
68 changes: 68 additions & 0 deletions Svc/ChronoTime/test/ut/ChronoTimeTester.hpp
Original file line number Diff line number Diff line change
@@ -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
6 changes: 0 additions & 6 deletions Svc/LinuxTimer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 2 additions & 2 deletions docs/UsersGuide/dev/os-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 ;
Expand Down Expand Up @@ -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. |
| | 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. |
4 changes: 2 additions & 2 deletions docs/UsersGuide/user/full-intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
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.

0 comments on commit 92df692

Please sign in to comment.