diff --git a/BUILD b/BUILD index cfb90305..937a17b2 100644 --- a/BUILD +++ b/BUILD @@ -24,7 +24,7 @@ docs( data = [ "@score_process//:needs_json", ], - source_dir = "docs", + source_dir = ".", ) copyright_checker( diff --git a/docs/conf.py b/conf.py similarity index 91% rename from docs/conf.py rename to conf.py index a834ad1f..1f15db24 100644 --- a/docs/conf.py +++ b/conf.py @@ -42,6 +42,14 @@ "score_metrics", ] +include_patterns = [ + "index.rst", + "docs/**", + "score/time/docs/**", + "score/time_slave/docs/**", + "score/time_daemon/docs/**", +] + exclude_patterns = [ # The following entries are not required when building the documentation via 'bazel # build //docs:docs', as that command runs in a sandboxed environment. However, when @@ -51,7 +59,7 @@ ".venv_docs", ] -templates_path = ["templates"] +templates_path = ["docs/templates"] # Enable numref numfig = True diff --git a/docs/manuals/.gitkeep b/docs/manuals/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/docs/manuals/index.rst b/docs/manuals/index.rst new file mode 100644 index 00000000..d31147d5 --- /dev/null +++ b/docs/manuals/index.rst @@ -0,0 +1,21 @@ +.. + # ******************************************************************************* + # Copyright (c) 2026 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # This program and the accompanying materials are made available under the + # terms of the Apache License Version 2.0 which is available at + # https://www.apache.org/licenses/LICENSE-2.0 + # + # SPDX-License-Identifier: Apache-2.0 + # ******************************************************************************* + +Manuals +####### + +.. toctree:: + :titlesonly: + + user_manual diff --git a/docs/manuals/troubleshooting_guide.rst b/docs/manuals/troubleshooting_guide.rst new file mode 100644 index 00000000..cf236eb1 --- /dev/null +++ b/docs/manuals/troubleshooting_guide.rst @@ -0,0 +1,83 @@ +.. + # ******************************************************************************* + # Copyright (c) 2026 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # This program and the accompanying materials are made available under the + # terms of the Apache License Version 2.0 which is available at + # https://www.apache.org/licenses/LICENSE-2.0 + # + # SPDX-License-Identifier: Apache-2.0 + # ******************************************************************************* + +.. _manual_time_troubleshooting: + +********************* +Troubleshooting Guide +********************* + +This guide provides solutions to common problems encountered when using or integrating the S-CORE ``time`` module. + +Clock is Not Reliable or Not Available +====================================== + +**Symptom:** +Your application calls ``clock.Now()``, but ``snapshot.Status().IsReliable()`` always returns `false`. Or, ``clock.WaitUntilAvailable()`` runs into a timeout. + +**Potential Causes and Solutions:** + +1. **TimeSlave Not Running or Not Synchronized:** + * **Check:** Is the `time_slave` process running on the ECU? + * **Check:** Is there a PTP Grandmaster Clock active on the network, in the same PTP domain as the `time_slave` (default domain: 0)? + * **Solution:** Ensure the `time_slave` is started correctly and that a PTP master is present and reachable on the specified network interface. Check the logs of the `time_slave` for messages related to master detection. + +2. **TimeDaemon Not Running:** + * **Check:** Is the `time_daemon` process running on the ECU? The `time_slave` can run, but if the `time_daemon` isn't there to process the data, client applications will not receive reliable time. + * **Solution:** Ensure the `time_daemon` process is started. + +3. **IPC Channel Mismatch:** + * **Check:** The `time_slave` and `time_daemon` communicate via a POSIX shared memory file. By default, this is ``/gptp_ptp_info``. + * **Solution:** Verify that this file exists in the shared memory file system (e.g., under `/dev/shm/` on Linux). Check for permission issues that might prevent one of the processes from accessing the file. + +4. **Sync Timeout:** + * **Check:** The `time_slave` has a built-in timeout (`sync_timeout_ms`, default: 3300 ms). If it doesn't receive PTP Sync messages within this period, it declares a timeout. + * **Solution:** Check the network for packet loss. If you are in a simulated environment (QEMU, Docker), ensure the virtual network bridge is configured correctly. + +"Permission Denied" on TimeSlave Startup +======================================== + +**Symptom:** +The `time_slave` process fails to start with an error message similar to "Permission denied", "Operation not permitted", or a socket creation error. + +**Cause & Solution:** + +The `time_slave` requires elevated network privileges to open a raw PTP socket on the specified network interface. + +* **On Linux:** Grant the ``CAP_NET_RAW`` capability to the ``time_slave`` binary instead of running it as root: + + .. code-block:: bash + + sudo setcap cap_net_raw+ep /path/to/time_slave + +* **On QNX:** The ``time_slave`` opens ``/dev/bpf`` (Berkeley Packet Filter device) to capture raw PTP frames. Ensure the process user has read/write permission on ``/dev/bpf``. If a PHC device is configured (``phc_device`` option), the process also needs read/write access to that device node. +* **Shared memory access:** If the error refers to ``/gptp_ptp_info``, verify that the user running ``time_slave`` has read/write permission on the shared memory path (``/dev/shm/`` on Linux). Adjust the file permissions or run both ``time_slave`` and ``time_daemon`` under the same user/group. + +Understanding Log Messages +========================== + +The `time` module components use specific logging contexts to identify the source of a message. This can help you pinpoint where a problem is occurring. + +.. list-table:: Logging Contexts + :widths: 20 80 + :header-rows: 1 + + * - Context ID + - Description + * - ``[TSAP]`` + - **Time Slave Application.** Relates to the main lifecycle (Initialize/Run) of the ``time_slave`` process. + * - ``[GTPS]`` + - **GPTP Slave.** Relates to the core gPTP protocol engine within the ``time_slave`` (e.g., parsing PTP messages, state machines). + * - ``[GPTP]`` + - **GPTP Machine Adapter.** Relates to the component within the ``time_daemon`` that receives and processes the data from shared memory. diff --git a/docs/manuals/user_manual.rst b/docs/manuals/user_manual.rst new file mode 100644 index 00000000..2a425c96 --- /dev/null +++ b/docs/manuals/user_manual.rst @@ -0,0 +1,161 @@ +.. + # ******************************************************************************* + # Copyright (c) 2026 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # This program and the accompanying materials are made available under the + # terms of the Apache License Version 2.0 which is available at + # https://www.apache.org/licenses/LICENSE-2.0 + # + # SPDX-License-Identifier: Apache-2.0 + # ******************************************************************************* + +.. _user_manual: + +User Manual +########### + +.. document:: User Manual Time Module + :id: doc__user_manual_time + :status: draft + :version: 1 + :safety: QM + :security: NO + :realizes: wp__training_path[version==1] + +Overview +======== + +This user manual provides comprehensive guidance for integrating and deploying the S-CORE ``time`` module from a system integrator perspective. + +The S-CORE ``time`` module provides a robust, high-precision time base for applications on an ECU, +synchronized to a network-wide PTP (Precision Time Protocol) Grandmaster Clock. The module consists of three components: + +* **Client Library** (``score::time``): C++ API for accessing synchronized time +* **TimeSlave**: System daemon that synchronizes with the PTP Grandmaster over the network +* **TimeDaemon**: System daemon that provides quality-assured time to client applications + +This module manual covers module-level integration, deployment, and troubleshooting. For component-specific usage and configuration, refer to the component manuals below. + +For build and test of the module itself, please refer to the main documentation. + +.. _component_manuals: + +Component Manuals +----------------- + +For detailed component-specific user manuals: + +.. toctree:: + :maxdepth: 1 + + /score/time/docs/manuals/user_manual + /score/time_slave/docs/manuals/user_manual + /score/time_daemon/docs/manuals/user_manual + +Environment Needs +================= + +Basic needed software environment for the module: + +* **C++**: C++17 or later +* **Build System**: Bazel 6.0 or later +* **Operating Systems**: Linux, QNX + +Dependencies +------------ + +* Standard library (STL/Core) +* PTP Grandmaster Clock (external network time source) +* POSIX shared memory support +* Network hardware with PHC (PTP Hardware Clock) support + +See also MODULE.bazel files for more details on dependencies. + +Performance Considerations +========================== + +The ``time`` module is designed for high-performance, low-latency time access in automotive ECUs: + +* **VehicleTime access**: Sub-microsecond latency via POSIX shared memory with seqlock +* **Lock-free IPC**: TimeDaemon reads from TimeSlave without blocking +* **Hardware clock sync**: Direct PHC adjustment for nanosecond-precision synchronization +* **Minimal overhead**: Singleton pattern, zero allocations in time-critical paths + +For detailed performance analysis and benchmarks, this information will be added in future releases. + +Integration Guidelines +====================== + +Integrating with Your Project +------------------------------ + +1. Add the module to your Bazel workspace: + + .. code-block:: python + + # In your MODULE.bazel + bazel_dep(name = "score_time", version = "1.0") + +2. Reference in your build files: + + .. code-block:: python + + cc_library( + name = "my_target", + deps = ["@score_time//score/time/vehicle_time:vehicle_time"], + ) + +3. Include headers and compile your code + +System Services Deployment +--------------------------- + +The ``time`` module requires two system daemons to be running. These processes must be managed by the system's service manager (e.g., `systemd` on Linux, or a launch script on QNX). + +.. For detailed configuration of each daemon (OS privileges, network configuration, command-line arguments), refer to the :ref:`component_manuals` linked above. + +Version History, Compatibility, and Troubleshooting +=================================================== + +For comprehensive information on the following topics: + +* Version history and changes +* Compatibility notes and upgrade instructions +* Known issues and limitations +* Troubleshooting tips and solutions +* Security vulnerabilities (CVEs) + +.. toctree:: + :maxdepth: 1 + + troubleshooting_guide + +Safety and Security +=================== + +**Safety Classification**: QM (Quality Managed) + +This module is designed for Quality Managed (QM) applications. For safety-critical usage requirements and guidelines, refer to the safety manual (to be added in future releases). + +**Security Considerations**: + +* The ``time`` module assumes a trusted network for PTP communication +* No authentication or encryption is provided for PTP messages (per IEEE 1588 standard) +* OS-level security (Linux Capabilities) limits attack surface for TimeSlave daemon + +For detailed security aspects and requirements, refer to the security manual (to be added in future releases). + +License +======= + +This module is licensed under the Apache License Version 2.0. +See the LICENSE file in the repository for full license text. + +Feedback and Contributions +========================== + +Your feedback and contributions are welcome! Please report issues or suggestions through the +project's issue tracker or contribute directly to the repository. diff --git a/docs/index.rst b/index.rst similarity index 94% rename from docs/index.rst rename to index.rst index e35c841d..3afba0ed 100644 --- a/docs/index.rst +++ b/index.rst @@ -36,13 +36,20 @@ The main responsibilities of time_daemon include: - **Providing diagnostic information** for system monitoring - **Supporting additional verification mechanisms** such as QualifiedVehicleTime (QVT) for safety-critical applications -For a detailed concept and architectural design, please refer to the :doc:`time_daemon Concept Documentation `. +For a detailed concept and architectural design, please refer to the :doc:`time_daemon Concept Documentation `. .. toctree:: :maxdepth: 2 :caption: Contents: - features/index + docs/features/index + docs/manuals/index + +.. toctree:: + :maxdepth: 1 + :caption: Component Documentation: + + score/time_slave/docs/index Project Layout -------------- diff --git a/score/time/docs/manuals/api_description/advanced_api.rst b/score/time/docs/manuals/api_description/advanced_api.rst new file mode 100644 index 00000000..679e53d7 --- /dev/null +++ b/score/time/docs/manuals/api_description/advanced_api.rst @@ -0,0 +1,122 @@ +.. + # ******************************************************************************* + # Copyright (c) 2026 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # This program and the accompanying materials are made available under the + # terms of the Apache License Version 2.0 which is available at + # https://www.apache.org/licenses/LICENSE-2.0 + # + # SPDX-License-Identifier: Apache-2.0 + # ******************************************************************************* + +.. _manual_time_advanced_api: + +Advanced API Usage: Subscribing to PTP Protocol Events +====================================================== + +For advanced use cases, such as diagnostics, network monitoring, or detailed performance analysis, the ``score::time`` framework allows applications to subscribe directly to low-level PTP protocol data events. Instead of polling for the final, processed time, an application can register a callback function that is invoked asynchronously whenever new data arrives from the ``TimeSlave``. + +.. warning:: + + This is an advanced feature. Most applications should use the simpler polling mechanism described in the previous chapter, as it provides the fully quality-assured time. Subscribing to raw PTP data bypasses some of the quality checks performed by the ``TimeDaemon``. + +Available Data Subscriptions +---------------------------- + +Two types of data events can be subscribed to: + +1. **`TimeSlaveSyncData`**: + This event is triggered whenever the ``TimeSlave`` successfully processes a PTP Sync/Follow-Up message pair from the Time Master. The data contains raw offset and rate correction information, as well as the underlying hardware and software timestamps. + +2. **`PDelayMeasurementData`**: + This event is triggered after the ``TimeSlave`` completes a peer-delay measurement cycle (PDelay_Req/Resp/FUp exchange). The data contains the calculated path delay to the communication partner. + +Subscribing to Events +--------------------- + +The following code example demonstrates how to register, handle, and unregister callbacks for these events. + +.. code-block:: cpp + + #include "score/time/clock.h" + #include "score/time/vehicle_time.h" + #include + #include + #include + + // A thread-safe data handler for our application + class PtpDataLogger + { + public: + void HandleSyncData(const score::time::TimeSlaveSyncData& data) + { + std::lock_guard lock(mutex_); + std::cout << "PTP Sync Event: Offset = " << data.offset_ns + << " ns, Rate Ratio = " << data.rate_ratio << std::endl; + // Further processing of the data... + } + + void HandlePDelayData(const score::time::PDelayMeasurementData& data) + { + std::lock_guard lock(mutex_); + std::cout << "PTP PDelay Event: Path Delay = " << data.path_delay_ns << " ns" << std::endl; + // Further processing of the data... + } + + private: + std::mutex mutex_; + }; + + /** + * @brief Demonstrates how to subscribe to and unsubscribe from PTP protocol events. + */ + void subscribe_to_ptp_events() + { + auto& clock = score::time::Clock::GetInstance(); + PtpDataLogger logger; + + // 1. Subscribe to Sync data events using a lambda that calls our thread-safe handler. + // The returned handle is used later to unsubscribe. + auto sync_subscription = clock.Subscribe>( + [&logger](const auto& data) { logger.HandleSyncData(data); }); + + std::cout << "Subscribed to TimeSlaveSyncData events." << std::endl; + + + // 2. Subscribe to Peer-Delay data events. + auto pdelay_subscription = clock.Subscribe>( + [&logger](const auto& data) { logger.HandlePDelayData(data); }); + + std::cout << "Subscribed to PDelayMeasurementData events." << std::endl; + + // ... application runs and receives callbacks asynchronously ... + std::this_thread::sleep_for(std::chrono::seconds(10)); + + + // 3. Unsubscribe when the data is no longer needed. + // The subscription handle is moved into the Unsubscribe call. + clock.Unsubscribe(std::move(sync_subscription)); + std::cout << "Unsubscribed from TimeSlaveSyncData events." << std::endl; + + clock.Unsubscribe(std::move(pdelay_subscription)); + std::cout << "Unsubscribed from PDelayMeasurementData events." << std::endl; + } + + +Threading and Safety Considerations +----------------------------------- + +.. attention:: + + Callback functions are executed on a **backend thread** owned by the ``score::time`` framework, not on the application's main thread. Therefore, all callback handlers **must be thread-safe**. + +* **Data Protection**: Use mutexes, atomics, or other synchronization primitives to protect any shared data that is accessed or modified within the callback. +* **Keep it Short**: Callbacks should be lightweight and non-blocking. Offload any time-consuming processing to a separate application-owned thread to avoid delaying the ``score::time`` backend. + +Unsubscribing +------------- + +It is crucial to unsubscribe from events when they are no longer needed to prevent resource leaks and dangling callbacks. The ``Subscribe`` method returns a handle object which must be passed to the ``Unsubscribe`` method. The handle is invalidated upon unsubscription. diff --git a/score/time/docs/manuals/api_description/api_usage.rst b/score/time/docs/manuals/api_description/api_usage.rst new file mode 100644 index 00000000..bcca5b8f --- /dev/null +++ b/score/time/docs/manuals/api_description/api_usage.rst @@ -0,0 +1,75 @@ +.. + # ******************************************************************************* + # Copyright (c) 2026 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # This program and the accompanying materials are made available under the + # terms of the Apache License Version 2.0 which is available at + # https://www.apache.org/licenses/LICENSE-2.0 + # + # SPDX-License-Identifier: Apache-2.0 + # ******************************************************************************* + +.. _manual_time_api_usage: + +API Usage: Accessing Vehicle Time +================================= + +The primary interface for applications to access synchronized time is the ``score::time`` client library. It provides a simple, robust, and testable way to get the current time without dealing with the underlying complexities of PTP and IPC. + +This section describes the most common use case: polling the current Vehicle Time. + +Polling the Current Time +------------------------ + +This method involves actively requesting the current time from the ``score::time`` framework. It is the simplest way to get a timepoint when needed. + +.. code-block:: cpp + + #include "score/time/clock.h" + #include "score/time/vehicle_time.h" + #include + #include + + /** + * @brief Demonstrates how to poll the current Vehicle Time and check its status. + */ + void poll_vehicle_time() + { + // 1. Get a handle to the VehicleClock singleton instance. + auto& clock = score::time::Clock::GetInstance(); + + // 2. Request the current time snapshot. + // This call retrieves the latest time information from the TimeDaemon via IPC. + const auto snapshot = clock.Now(); + + // 3. Check the status of the snapshot. + // The IsReliable() flag indicates if the time is currently synchronized + // to a master and has passed all quality checks in the TimeDaemon. + if (snapshot.Status().IsReliable()) + { + // 4. Use the timepoint. + // The timepoint is a std::chrono::time_point. + const auto current_time = snapshot.TimePoint(); + const auto ns_since_epoch = std::chrono::duration_cast( + current_time.time_since_epoch()).count(); + + std::cout << "Successfully retrieved reliable Vehicle Time: " + << ns_since_epoch << " ns since epoch." << std::endl; + } + else + { + // 5. Handle the "not synchronized" case. + // If the time is not reliable, applications must not use the timepoint value. + // This can happen during startup or if the connection to the Time Master is lost. + // The application should implement a retry-logic or fallback. + std::cerr << "Warning: Vehicle Time is not synchronized or not reliable. " + << "Retrying later..." << std::endl; + } + } + +.. attention:: + + Never use the ``TimePoint`` from a ``ClockSnapshot`` without first verifying that ``Status().IsReliable()`` is true. Using an unreliable timepoint can lead to incorrect or inconsistent behavior in safety-critical applications. diff --git a/score/time/docs/manuals/api_description/lifecycle.rst b/score/time/docs/manuals/api_description/lifecycle.rst new file mode 100644 index 00000000..cddf8987 --- /dev/null +++ b/score/time/docs/manuals/api_description/lifecycle.rst @@ -0,0 +1,116 @@ +.. + # ******************************************************************************* + # Copyright (c) 2026 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # This program and the accompanying materials are made available under the + # terms of the Apache License Version 2.0 which is available at + # https://www.apache.org/licenses/LICENSE-2.0 + # + # SPDX-License-Identifier: Apache-2.0 + # ******************************************************************************* + +.. _manual_time_lifecycle: + +Clock Lifecycle Management +========================== + +Before an application can read reliable time from clocks like ``VehicleClock``, the underlying backend service must be initialized and ready. The ``Clock`` API provides several functions to manage this lifecycle gracefully. + +.. attention:: + These lifecycle functions are primarily relevant for clocks that depend on external services, like ``VehicleClock``. Simpler clocks such as ``SystemClock`` or ``SteadyClock`` are always available and do not require these steps. + +Initializing the Clock +---------------------- + +The ``Init()`` method must be called once to establish the connection to the backend service (e.g., the ``TimeDaemon``). Until ``Init()`` succeeds, any call to ``Now()`` will return a snapshot with a "not ready" or "unknown" status. + +.. code-block:: cpp + + #include "score/time/clock.h" + #include "score/time/vehicle_time.h" + #include + + void initialize_clock() + { + auto& clock = score::time::Clock::GetInstance(); + + // Attempt to initialize the connection to the backend. + // This can be retried if it fails (e.g., if the TimeDaemon is not yet running). + if (clock.Init()) + { + std::cout << "Clock backend initialized successfully." << std::endl; + } + else + { + std::cerr << "Clock backend initialization failed. Please retry." << std::endl; + } + } + +Waiting for Availability +------------------------ + +After initialization, the clock might still not be "reliable" because the ``TimeDaemon`` itself is waiting for synchronization with the PTP master. Instead of polling in a loop, applications can use ``WaitUntilAvailable()`` to block efficiently until the clock is ready. + +This is the recommended approach for applications that cannot proceed without a valid time source at startup. + +.. code-block:: cpp + + #include "score/time/clock.h" + #include "score/time/vehicle_time.h" + #include + #include + #include + + void wait_for_reliable_time(const score::cpp::stop_token& stop_token) + { + auto& clock = score::time::Clock::GetInstance(); + + if (!clock.Init()) { + std::cerr << "Initialization failed. Cannot wait for time." << std::endl; + return; + } + + // Wait for a maximum of 30 seconds for the clock to become available. + // The wait will be interrupted if the application's stop_token is triggered. + const auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(30); + + std::cout << "Waiting for VehicleTime to become available..." << std::endl; + + if (clock.WaitUntilAvailable(stop_token, deadline)) + { + std::cout << "VehicleTime is now available and synchronized!" << std::endl; + + // Now it is safe to start polling or using the time. + const auto snapshot = clock.Now(); + if (snapshot.Status().IsReliable()) { + // ... proceed with application logic ... + } + } + else + { + std::cerr << "Timed out waiting for VehicleTime. Is the TimeSlave running and synchronized?" << std::endl; + } + } + + +Checking Availability (Non-Blocking) +------------------------------------ + +For applications that need to perform other tasks while waiting for time, the non-blocking ``IsAvailable()`` method can be used to periodically check the status. + +.. code-block:: cpp + + // Inside an application's main loop + auto& clock = score::time::Clock::GetInstance(); + + if (clock.IsAvailable()) + { + // Time is ready, perform time-sensitive tasks. + } + else + { + // Time is not yet ready, perform other tasks. + } diff --git a/score/time/docs/manuals/api_description/testing_guide.rst b/score/time/docs/manuals/api_description/testing_guide.rst new file mode 100644 index 00000000..dbd0b81c --- /dev/null +++ b/score/time/docs/manuals/api_description/testing_guide.rst @@ -0,0 +1,153 @@ +.. + # ******************************************************************************* + # Copyright (c) 2026 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # This program and the accompanying materials are made available under the + # terms of the Apache License Version 2.0 which is available at + # https://www.apache.org/licenses/LICENSE-2.0 + # + # SPDX-License-Identifier: Apache-2.0 + # ******************************************************************************* + +.. _manual_time_testing: + +Unit-Testing Time-Dependent Code +================================ + +Testing application logic that depends on time can be challenging. To solve this, the ``score::time`` framework provides a powerful mechanism to replace the real-time clock with a controllable "fake" clock during unit tests. This is achieved using the ``ScopedClockOverride`` helper. + +A Helper for Controllable Time: The `ClockTestFactory` +====================================================== + +To make tests cleaner and more readable, it is a recommended practice to create a small test factory helper class. This class encapsulates the creation of the fake clock and provides a simple API to control the time within a test. + +Here is a minimal implementation of such a factory. You can add this helper to your own test utilities. + +**`clock_test_factory.h` (Example Implementation):** + +.. code-block:: cpp + + #include "score/time/clock/src/clock_backend_mock.h" + #include "score/time/vehicle_time.h" + #include + #include + + // A helper class to manage a fake clock backend in tests. + class ClockTestFactory { + public: + // Creates the backend and returns a shared_ptr to it. + // This backend is then passed to the ScopedClockOverride. + std::shared_ptr> + CreateFakeClock() { + fake_clock_backend_ = std::make_shared>(); + return fake_clock_backend_; + } + + // Advances the time on the created fake clock. + void AdvanceTime(std::chrono::nanoseconds duration) { + // We simulate a monotonic clock by shifting the offset of the mock + // to return a progressively advanced timestamp on every subsequent call. + current_time_ += duration; + ON_CALL(*fake_clock_backend_, Now()) + .WillByDefault(testing::Return(score::time::TimeSnapshot( + score::time::VehicleTime::time_point(current_time_)))); + } + + private: + std::shared_ptr> fake_clock_backend_; + std::chrono::nanoseconds current_time_{0}; + }; + + +Example: Testing a Timeout Handler +================================== + +This example demonstrates how to use the custom `ClockTestFactory` helper to test a component that performs an action once a specific timeout duration has elapsed. + +**Component to be tested (`my_component.h`):** + +.. code-block:: cpp + + #include "score/time/clock.h" + #include "score/time/vehicle_time.h" + #include + + class MyTimeoutHandler { + public: + MyTimeoutHandler() + : clock_{score::time::Clock::GetInstance()} + , start_time_{clock_.Now().TimePoint()} {} + + bool HasTimedOut(std::chrono::seconds timeout_duration) { + const auto now = clock_.Now().TimePoint(); + return (now - start_time_) > timeout_duration; + } + + private: + score::time::Clock clock_; + score::time::VehicleTime::time_point start_time_; + }; + +**Unit Test (`my_component_test.cpp`):** + +.. code-block:: cpp + + #include "my_component.h" + #include "clock_test_factory.h" // Our custom helper + #include "score/time/clock/src/scoped_clock_override.h" + #include + + TEST(MyTimeoutHandlerTest, DetectsTimeoutCorrectly) + { + // 1. Create our test factory helper. + ClockTestFactory test_factory; + auto fake_clock_backend = test_factory.CreateFakeClock(); + + // 2. Activate the override with the backend from our factory. + auto clock_override = score::time::test_utils::ScopedClockOverride( + fake_clock_backend); + + // 3. Instantiate the component-under-test. It will now automatically use the fake clock. + MyTimeoutHandler handler; + const auto timeout = std::chrono::seconds{10}; + + // 4. Initially, no timeout should be detected. + EXPECT_FALSE(handler.HasTimedOut(timeout)); + + // 5. Advance the fake clock's time via our factory helper by 9 seconds. + test_factory.AdvanceTime(std::chrono::seconds{9}); + EXPECT_FALSE(handler.HasTimedOut(timeout)); + + // 6. Advance the time past the 10 seconds timeout threshold (Total: 11 seconds). + test_factory.AdvanceTime(std::chrono::seconds{2}); + EXPECT_TRUE(handler.HasTimedOut(timeout)); + + } // <-- 7. Here, `clock_override` is destroyed, and the real clock backend is automatically restored. + + +Bazel BUILD Setup +================= + +Because ``ScopedClockOverride`` modifies global state (the active backend for a given clock tag), tests utilizing it must be configured carefully in Bazel. + +To prevent parallel tests from overriding the clock simultaneously and interfering with each other, you **must** mark your test targets with the ``exclusive`` tag. + +.. code-block:: python + + cc_test( + name = "my_component_test", + srcs = [ + "my_component_test.cpp", + "clock_test_factory.h" + ], + tags = ["exclusive", "unit"], # "exclusive" prevents parallel execution conflicts + deps = [ + ":my_component", + "//score/time/vehicle_time:vehicle_time_mock", + "@googletest//:gtest", + "@googletest//:gtest_main", + ], + ) diff --git a/score/time/docs/manuals/examples/basic_clocks.rst b/score/time/docs/manuals/examples/basic_clocks.rst new file mode 100644 index 00000000..47d900e0 --- /dev/null +++ b/score/time/docs/manuals/examples/basic_clocks.rst @@ -0,0 +1,280 @@ +.. ******************************************************************************* + Copyright (c) 2026 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Apache License Version 2.0 which is available at + https://www.apache.org/licenses/LICENSE-2.0 + + SPDX-License-Identifier: Apache-2.0 + ******************************************************************************* + +Basic Clock Examples +==================== + +Overview +-------- + +Three examples demonstrate the basic SCORE clock types: ``system_time``, ``steady_time``, +and ``high_res_steady_time``. All follow an identical pattern - a periodic time printer +that outputs time values once per second until interrupted. + +These examples show the fundamental pattern for using SCORE time APIs and can serve as +starting points for applications requiring simple time reading. + +Common Implementation Pattern +----------------------------- + +All three examples share the same structure: + +**Handler Class** + Wrapper around ``Clock::GetInstance()`` that provides a clean ``GetCurrentTime()`` + method returning a ``TimeReport`` struct. + +**Main Program** + - Signal handling for graceful shutdown (SIGINT/SIGTERM) + - Loop reading time every second + - Simple text output with sequence numbers + - Consistent error handling + +**Unit Tests** + Demonstrate mocking with ``ScopedClockOverride`` for dependency injection. + +Building and Running +-------------------- + +.. code-block:: bash + + # Build any of the basic examples + bazel build //examples/time/system_time + bazel build //examples/time/steady_time + bazel build //examples/time/high_res_steady_time + + # Run examples + bazel run //examples/time/system_time + bazel run //examples/time/steady_time + bazel run //examples/time/high_res_steady_time + + # Run tests + bazel test //examples/time/system_time/src:system_time_handler_test + bazel test //examples/time/steady_time/src:steady_time_handler_test + bazel test //examples/time/high_res_steady_time/src:high_res_steady_time_handler_test + +Example Output +-------------- + +Each example prints time in a similar format: + +**System Time:** + +.. code-block:: text + + SystemTime printer started. Press Ctrl+C to stop. + [0] unix=1720184400.123456789 s + [1] unix=1720184401.234567890 s + [2] unix=1720184402.345678901 s + ... + +**Steady Time:** + +.. code-block:: text + + SteadyTime printer started. Press Ctrl+C to stop. + [0] monotonic=12345.123456789 s + [1] monotonic=12346.234567890 s + [2] monotonic=12347.345678901 s + ... + +**High-Resolution Steady Time:** + +.. code-block:: text + + HighResSteadyTime printer started. Press Ctrl+C to stop. + [0] time=12345.123456789 s + [1] time=12346.234567890 s + [2] time=12347.345678901 s + ... + +Code Structure +-------------- + +Each example follows this pattern: + +**Handler Header** (``*_time_handler.h``): + +.. code-block:: cpp + + struct TimeReport { + std::int64_t time_field_ns{0}; // Field name varies by clock type + }; + + class TimeHandler { + public: + TimeReport GetCurrentTime() const noexcept { + const auto snapshot = ClockType::GetInstance().Now(); + return TimeReport{snapshot.TimePointNs().count()}; + } + }; + +**Main Program** (``main.cpp``): + +.. code-block:: cpp + + volatile std::sig_atomic_t gShutdownRequested{0}; + extern "C" void HandleSignal(int) noexcept { gShutdownRequested = 1; } + + int main() { + signal(SIGINT, HandleSignal); + signal(SIGTERM, HandleSignal); + + HandlerType handler; + std::uint64_t seq{0}; + + while (gShutdownRequested == 0) { + const auto report = handler.GetCurrentTime(); + PrintReport(report, seq++); + std::this_thread::sleep_for(std::chrono::seconds{1}); + } + return 0; + } + +Testing Pattern +--------------- + +All examples use the same mocking approach: + +.. code-block:: cpp + + TEST(HandlerTest, GetCurrentTime) { + auto mock = std::make_shared(); + score::time::test_utils::ScopedClockOverride guard{mock}; + + EXPECT_CALL(*mock, Now()).WillOnce(Return(test_snapshot)); + + HandlerType handler; + const auto report = handler.GetCurrentTime(); + + EXPECT_EQ(expected_value, report.time_field_ns); + } + +.. note:: + + Tests using ``ScopedClockOverride`` must declare ``tags = ["exclusive", "unit"]`` + in their Bazel BUILD file to prevent parallel execution conflicts. + +Bazel Build Setup +----------------- + +Understanding the dependency structure helps when adapting these examples for your application. + +Target Structure +~~~~~~~~~~~~~~~~ + +Each example has three Bazel targets in ``examples/time//src/BUILD``: + +.. code-block:: python + + cc_library( + name = "time_handler", + hdrs = ["system_time_handler.h"], + deps = ["//score/time/system_time:interface"], # Header-only dep + ) + + cc_binary( + name = "system_time", + srcs = ["main.cpp"], + deps = [ + ":time_handler", + "//score/time/system_time", # Production backend + ], + ) + + cc_test( + name = "system_time_handler_test", + srcs = ["system_time_handler_test.cpp"], + tags = ["exclusive", "unit"], # Required for ScopedClockOverride + deps = [ + ":time_handler", + "//score/time/system_time:system_time_mock", # Mock backend + "@googletest//:gtest", + "@googletest//:gtest_main", + ], + ) + +Dependency Layers +~~~~~~~~~~~~~~~~~ + +**Handler Library** (``time_handler``): + - Header-only wrapper around SCORE clock API + - Depends on ``:interface`` target (types only, no implementation) + - Can be tested without linking production backend + +**Binary** (``system_time``, ``steady_time``, ``high_res_steady_time``): + - Links production backend (``//score/time/``) + - Depends on handler library + - Minimal dependencies for deployment + +**Test** (``*_handler_test``): + - Links mock backend (``//score/time/:*_mock``) + - Uses ``ScopedClockOverride`` for dependency injection + - **Must** have ``tags = ["exclusive", "unit"]`` to prevent parallel test conflicts + +Key Dependency Targets +~~~~~~~~~~~~~~~~~~~~~~ + +For each clock type (``system_time``, ``steady_time``, ``high_res_steady_time``): + +.. list-table:: + :header-rows: 1 + :widths: 50 50 + + * - Target + - Purpose + * - ``//score/time/:interface`` + - Header-only, types and tag definitions + * - ``//score/time/`` + - Production backend implementation + * - ``//score/time/:_mock`` + - GMock test double for unit testing + +Adapting for Your Application +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To use these patterns in your code: + +1. **Production code** depends on ``:interface`` for headers, production target for binary: + + .. code-block:: python + + cc_library( + name = "my_component", + hdrs = ["my_component.h"], + deps = ["//score/time/steady_time:interface"], + ) + + cc_binary( + name = "my_app", + deps = [ + ":my_component", + "//score/time/steady_time", # Link production backend + ], + ) + +2. **Tests** depend on ``:interface`` and ``*_mock``: + + .. code-block:: python + + cc_test( + name = "my_component_test", + tags = ["exclusive", "unit"], # Required! + deps = [ + ":my_component", + "//score/time/steady_time:steady_time_mock", + "@googletest//:gtest_main", + ], + ) + +This layering keeps compile times fast (interface-only deps) and enables testing without +runtime dependencies. diff --git a/score/time/docs/manuals/examples/index.rst b/score/time/docs/manuals/examples/index.rst new file mode 100644 index 00000000..2c05373b --- /dev/null +++ b/score/time/docs/manuals/examples/index.rst @@ -0,0 +1,64 @@ +.. + # ******************************************************************************* + # Copyright (c) 2026 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # This program and the accompanying materials are made available under the + # terms of the Apache License Version 2.0 which is available at + # https://www.apache.org/licenses/LICENSE-2.0 + # + # SPDX-License-Identifier: Apache-2.0 + # ******************************************************************************* + +Examples User Manual +==================== + +This manual explains the examples included in the ``examples/time/`` subdirectory and how they +can be used as patterns for building applications with the SCORE time library. + +Overview +-------- + +The ``examples/time/`` directory contains four working examples that demonstrate how to use +different SCORE time sources: + +- **Basic Clock Examples** (system_time, steady_time, high_res_steady_time): Simple periodic time printers showing the common pattern for reading time from SCORE clocks +- **Vehicle Time Example** (vehicle_time): More complex example showing PTP-synchronized time with initialization, status monitoring, and dual time sources + +All examples follow consistent patterns and can be used as starting points for real applications. + +Building and Running Examples +------------------------------ + +All examples use Bazel: + +.. code-block:: bash + + # Build all examples + bazel build //examples/... + + # Run specific example + bazel run //examples/time/system_time + + # Run tests + bazel test //examples/time/system_time/src:system_time_handler_test + +Common Patterns +--------------- + +All examples share these implementation patterns: + +- **Handler wrapper classes** providing clean APIs over SCORE Clock types +- **TimeReport structs** containing time data with consistent field naming +- **Signal handling** for graceful shutdown on SIGINT/SIGTERM +- **Unit test patterns** using ScopedClockOverride for dependency injection +- **Nanosecond precision** throughout all time calculations + +.. toctree:: + :maxdepth: 2 + :caption: Examples: + + basic_clocks + vehicle_time diff --git a/score/time/docs/manuals/examples/vehicle_time.rst b/score/time/docs/manuals/examples/vehicle_time.rst new file mode 100644 index 00000000..ec2b1d71 --- /dev/null +++ b/score/time/docs/manuals/examples/vehicle_time.rst @@ -0,0 +1,289 @@ +.. ******************************************************************************* + Copyright (c) 2026 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Apache License Version 2.0 which is available at + https://www.apache.org/licenses/LICENSE-2.0 + + SPDX-License-Identifier: Apache-2.0 + ******************************************************************************* + +Vehicle Time Example +==================== + +Overview +-------- + +The ``vehicle_time`` example demonstrates how to use the SCORE library's VehicleClock +in combination with HighResSteadyClock. This example shows how to work with +PTP-synchronized vehicle time alongside local monotonic time, which is essential +for automotive applications requiring distributed time synchronization. + +What it does +------------ + +This example creates a ``VehicleTimeHandler`` wrapper class that: + +- Provides access to both SCORE ``VehicleClock`` and ``HighResSteadyClock`` +- Returns combined time reports with status information +- Demonstrates initialization patterns for vehicle time backends +- Shows how to monitor time synchronization quality +- Can be unit tested with independent clock mocks + +The main program: + +- Initializes the vehicle time backend +- Runs a loop reading both time sources simultaneously +- Displays time values, reliability, and synchronization status +- Handles SIGINT/SIGTERM for clean shutdown + +Building and Running +-------------------- + +To build and run the example: + +.. code-block:: bash + + # Build the example + bazel build //examples/time/vehicle_time + + # Run the example + bazel run //examples/time/vehicle_time + + # Or run the built binary directly + ./bazel-bin/examples/time/vehicle_time/src/vehicle_time + +**Note**: The vehicle time backend requires proper initialization. The example will +exit with error code 1 if initialization fails (e.g., no PTP service available). + +Output Format +------------- + +The program outputs lines in this format: + +.. code-block:: text + + VehicleTime + HighResSteadyTime printer started. Press Ctrl+C to stop. + [0] vehicle=1720184400.123456789 s hirs=12345.234567890 s is_reliable=yes is_consistent=yes rate_deviation=1.23e-09 + [1] vehicle=1720184401.234567890 s hirs=12346.345678901 s is_reliable=yes is_consistent=yes rate_deviation=1.24e-09 + ... + Shutdown requested. Exiting. + +Where: +- ``vehicle=`` shows the PTP-synchronized time in seconds.nanoseconds +- ``hirs=`` shows the local high-resolution steady time +- ``is_reliable=`` indicates if the vehicle time is synchronized and fault-free +- ``is_consistent=`` indicates if status flags are internally consistent +- ``rate_deviation=`` shows local clock deviation relative to PTP Grand Master + +Code Structure +-------------- + +VehicleTimeHandler Class +~~~~~~~~~~~~~~~~~~~~~~~~ + +Located in ``examples/time/vehicle_time/src/vehicle_time_handler.h``: + +.. code-block:: cpp + + class VehicleTimeHandler { + public: + bool Init() noexcept; + TimeReport GetCurrentTime() const noexcept; + void RegisterStatusCallback(VehicleTime::StatusChangedCallback callback) noexcept; + }; + + struct TimeReport { + std::int64_t vehicle_time_ns{0}; // PTP-synchronized time + std::int64_t high_res_steady_time_ns{0}; // Local monotonic time + bool is_reliable{false}; // Time sync quality + bool is_consistent{false}; // Status flag consistency + double rate_deviation{0.0}; // Clock drift rate + }; + +Key features: +- **Dual time sources**: Both vehicle and local time in single call +- **Status monitoring**: Reliability and consistency flags +- **Rate tracking**: Clock deviation measurement +- **Callback support**: Status change notifications (future feature) + +Main Program +~~~~~~~~~~~~ + +Located in ``examples/time/vehicle_time/src/main.cpp``: + +Key features: +- Initialization error handling with early exit +- Combined time display showing both sources +- Status information formatting for monitoring +- Same signal handling pattern as other examples + +Testing +------- + +Run the unit tests: + +.. code-block:: bash + + bazel test //examples/time/vehicle_time/src:vehicle_time_handler_test + +The test shows how to mock both time sources independently: + +.. code-block:: cpp + + auto vehicle_mock = std::make_shared(); + auto hirs_mock = std::make_shared(); + + score::time::test_utils::ScopedClockOverride vg{vehicle_mock}; + score::time::test_utils::ScopedClockOverride hg{hirs_mock}; + + EXPECT_CALL(*vehicle_mock, Init()).WillOnce(Return(true)); + EXPECT_CALL(*vehicle_mock, Now()).WillOnce(Return(...)); + EXPECT_CALL(*hirs_mock, Now()).WillOnce(Return(...)); + +Bazel Build Setup +----------------- + +The vehicle_time example has more complex dependencies due to dual time sources and initialization. + +Target Structure +~~~~~~~~~~~~~~~~ + +From ``examples/time/vehicle_time/src/BUILD``: + +.. code-block:: python + + cc_library( + name = "time_handler", + hdrs = ["vehicle_time_handler.h"], + deps = [ + "//score/time/vehicle_time:interface", + "//score/time/high_res_steady_time:interface", + ], + ) + + cc_binary( + name = "vehicle_time", + srcs = ["main.cpp"], + deps = [ + ":time_handler", + "//score/time/vehicle_time", # VehicleTime production backend + "//score/time/high_res_steady_time", # HIRS production backend + "@score_baselibs//score/mw/log:console_only_backend", + ], + ) + + cc_test( + name = "vehicle_time_handler_test", + srcs = ["vehicle_time_handler_test.cpp"], + tags = ["exclusive", "unit"], # Required for ScopedClockOverride + deps = [ + ":time_handler", + "//score/time/vehicle_time:vehicle_time_mock", + "//score/time/high_res_steady_time:high_res_steady_time_mock", + "@googletest//:gtest_main", + ], + ) + +Dual Clock Dependencies +~~~~~~~~~~~~~~~~~~~~~~~ + +The handler depends on **two** clock interfaces: + +- ``//score/time/vehicle_time:interface`` - VehicleTime tag and status types +- ``//score/time/high_res_steady_time:interface`` - HighResSteadyTime tag + +The binary links **both** production backends, while tests link **both** mocks. + +Key Targets +~~~~~~~~~~~ + +.. list-table:: + :header-rows: 1 + :widths: 50 50 + + * - Target + - Purpose + * - ``//score/time/vehicle_time:interface`` + - VehicleTime types, status flags, callback signatures + * - ``//score/time/vehicle_time`` + - Production backend with TimeDaemon IPC + * - ``//score/time/vehicle_time:vehicle_time_mock`` + - Mock for Init/Now/Subscribe testing + * - ``//score/time/high_res_steady_time:interface`` + - HighResSteadyTime tag + * - ``//score/time/high_res_steady_time`` + - Production HIRS clock backend + * - ``//score/time/high_res_steady_time:high_res_steady_time_mock`` + - Mock for HIRS in tests + +Testing with Dual Mocks +~~~~~~~~~~~~~~~~~~~~~~~ + +The test demonstrates independent mock control: + +.. code-block:: cpp + + auto vehicle_mock = std::make_shared(); + auto hirs_mock = std::make_shared(); + + ScopedClockOverride vg{vehicle_mock}; + ScopedClockOverride hg{hirs_mock}; + + EXPECT_CALL(*vehicle_mock, Init()).WillOnce(Return(true)); + EXPECT_CALL(*vehicle_mock, Now()).WillOnce(Return(vehicle_snapshot)); + EXPECT_CALL(*hirs_mock, Now()).WillOnce(Return(hirs_snapshot)); + +Each clock can be mocked separately with different return values and expectations. + +Adapting for Your Application +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When building components that use VehicleTime: + +1. **Header-only dependencies** use ``:interface``: + + .. code-block:: python + + cc_library( + name = "my_sync_component", + hdrs = ["my_sync_component.h"], + deps = [ + "//score/time/vehicle_time:interface", + "//score/time/high_res_steady_time:interface", + ], + ) + +2. **Binaries** link production backends: + + .. code-block:: python + + cc_binary( + name = "my_app", + deps = [ + ":my_sync_component", + "//score/time/vehicle_time", + "//score/time/high_res_steady_time", + ], + ) + +3. **Tests** link mocks and require exclusive tag: + + .. code-block:: python + + cc_test( + name = "my_sync_component_test", + tags = ["exclusive", "unit"], + deps = [ + ":my_sync_component", + "//score/time/vehicle_time:vehicle_time_mock", + "//score/time/high_res_steady_time:high_res_steady_time_mock", + "@googletest//:gtest_main", + ], + ) + +The layered dependency structure keeps compile times minimal while enabling comprehensive +testing with independent clock control. diff --git a/score/time/docs/manuals/user_manual.rst b/score/time/docs/manuals/user_manual.rst new file mode 100644 index 00000000..e3b366e4 --- /dev/null +++ b/score/time/docs/manuals/user_manual.rst @@ -0,0 +1,150 @@ +.. + # ******************************************************************************* + # Copyright (c) 2026 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # This program and the accompanying materials are made available under the + # terms of the Apache License Version 2.0 which is available at + # https://www.apache.org/licenses/LICENSE-2.0 + # + # SPDX-License-Identifier: Apache-2.0 + # ******************************************************************************* + +.. _time_component_user_manual: + +Time Library User Manual +######################## + +.. document:: User Manual Time Library Component + :id: doc__user_manual_time_lib + :status: draft + :version: 1 + :safety: QM + :security: NO + :realizes: wp__training_path[version==1] + +Overview +======== + +This user manual covers the ``score::time`` client library - the C++ API for accessing synchronized time in your applications. + +The library provides multiple clock types (``VehicleTime``, ``SystemTime``, ``SteadyTime``, ``HighResSteadyTime``) with a unified interface for time access, lifecycle management, and testing. + +For module-level integration and deployment information, see the main module manual. + +Choosing the Right Clock +========================= + +The S-CORE ``time`` module provides several clock types, each designed for a specific use case. Understanding their differences is crucial for writing robust and correct applications. + +In general, you should **always prefer ``VehicleTime``** unless you have a specific reason to measure a local time interval or need a simple wall-clock timestamp for purely informational purposes. + +.. list-table:: Clock Types Overview + :widths: 20 40 40 + :header-rows: 1 + + * - Clock Type + - Key Characteristic + - Typical Use Case + * - ``VehicleTime`` + - High-precision, PTP-synchronized, quality-assured network time. **This is the recommended clock for almost all applications.** + - Synchronized logging across ECUs, event timestamping, any logic that depends on a common time base in the vehicle. + * - ``SystemTime`` + - The system's "wall clock" time (Unix time). Can jump forwards or backwards (e.g., due to NTP correction or manual changes). + - Displaying human-readable timestamps. Creating log entries where absolute time is more important than monotonic progression. + * - ``SteadyTime`` + - A clock that is guaranteed to only ever move forward (monotonic). Its starting point is arbitrary (e.g., system boot time). + - Measuring time intervals, implementing timeouts, scheduling tasks where guaranteed monotonic progression is essential. + * - ``HighResSteadyTime`` + - A monotonic clock that provides the highest possible resolution the underlying hardware can offer. + - High-precision performance measurements and profiling, or very short-interval timing. + +API Usage +========= + +This section covers how to use the ``score::time`` client library in your applications: + +.. toctree:: + :maxdepth: 2 + + api_description/api_usage + api_description/lifecycle + api_description/testing_guide + api_description/advanced_api + +.. note:: + For a complete C++ API reference with full class and function documentation, + please refer to the generated Doxygen documentation (to be added in future releases). + +Examples +======== + +Practical examples and tutorials for using the time library: + +.. toctree:: + :maxdepth: 2 + + examples/index + +Build Integration +================= + +To use the ``score::time`` library in your application: + +1. Add the module to your Bazel workspace: + + .. code-block:: python + + # In your MODULE.bazel + bazel_dep(name = "score_time", version = "1.0") + +2. Reference the clock type you need in your build files: + + .. code-block:: python + + cc_library( + name = "my_target", + deps = [ + "@score_time//score/time/vehicle_time:vehicle_time", # For VehicleTime + # OR + "@score_time//score/time/system_time:system_time", # For SystemTime + # OR + "@score_time//score/time/steady_time:steady_time", # For SteadyTime + # OR + "@score_time//score/time/high_res_steady_time:high_res_steady_time", # For HighResSteadyTime + ], + ) + + For testing, use the mock variants: + + .. code-block:: python + + cc_test( + name = "my_test", + deps = [ + "@score_time//score/time/vehicle_time:vehicle_time_mock", + ], + ) + +3. Include headers in your code: + + .. code-block:: cpp + + #include "score/time/clock.h" + #include "score/time/vehicle_time.h" + + // Example usage + auto& clock = score::time::Clock::GetInstance(); + auto snapshot = clock.Now(); + if (snapshot.Status().IsReliable()) { + // Use snapshot.TimePoint() + } + +Runtime Requirements +==================== + +The ``score::time`` library requires the ``TimeSlave`` and ``TimeDaemon`` system services to be running. +For deployment and configuration of these services, refer to the module manual and component manuals for +:doc:`/score/time_slave/docs/manuals/user_manual` and :doc:`/score/time_daemon/docs/manuals/user_manual`. diff --git a/score/time_daemon/docs/manuals/config/configuration_guide.rst b/score/time_daemon/docs/manuals/config/configuration_guide.rst new file mode 100644 index 00000000..ecc450da --- /dev/null +++ b/score/time_daemon/docs/manuals/config/configuration_guide.rst @@ -0,0 +1,30 @@ +.. + # ******************************************************************************* + # Copyright (c) 2026 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # This program and the accompanying materials are made available under the + # terms of the Apache License Version 2.0 which is available at + # https://www.apache.org/licenses/LICENSE-2.0 + # + # SPDX-License-Identifier: Apache-2.0 + # ******************************************************************************* + +.. _time_daemon_configuration: + +TimeDaemon Configuration +========================= + +The ``TimeDaemon`` process currently operates **without any external configuration**. It relies on default, built-in settings for IPC communication. + +Shared Memory Configuration +---------------------------- + +The daemon reads from the shared memory segment published by ``TimeSlave``: + +* **Shared memory path**: ``/gptp_ptp_info`` +* **IPC mechanism**: POSIX shared memory with seqlock protection + +No runtime configuration options are exposed at this time. All settings are compiled into the binary. diff --git a/score/time_daemon/docs/manuals/user_manual.rst b/score/time_daemon/docs/manuals/user_manual.rst new file mode 100644 index 00000000..81d38097 --- /dev/null +++ b/score/time_daemon/docs/manuals/user_manual.rst @@ -0,0 +1,50 @@ +.. + # ******************************************************************************* + # Copyright (c) 2026 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # This program and the accompanying materials are made available under the + # terms of the Apache License Version 2.0 which is available at + # https://www.apache.org/licenses/LICENSE-2.0 + # + # SPDX-License-Identifier: Apache-2.0 + # ******************************************************************************* + +.. _time_daemon_user_manual: + +Time Daemon User Manual +####################### + +.. document:: User Manual Time Daemon Component + :id: doc__user_manual_time_daemon + :status: draft + :version: 1 + :safety: QM + :security: NO + :realizes: wp__training_path[version==1] + +Overview +======== + +The ``TimeDaemon`` component is a system daemon responsible for quality assurance and providing synchronized time to local applications on the ECU. It reads raw synchronization data from shared memory (published by ``TimeSlave``), performs quality checks and plausibility assessments, and provides the final ``score::time`` API to client applications. + +For module-level integration and deployment information, see the main module manual. + +Configuration +============= + +.. toctree:: + :maxdepth: 2 + + config/configuration_guide + +Runtime Requirements +==================== + +The ``TimeDaemon`` requires: + +* ``TimeSlave`` must be running and publishing data to shared memory +* Access to POSIX shared memory segment (``/gptp_ptp_info``) +* Managed by system service manager (e.g., `systemd` on Linux, launch script on QNX) diff --git a/score/time_slave/docs/index.rst b/score/time_slave/docs/index.rst index 6e07edcd..27df135f 100644 --- a/score/time_slave/docs/index.rst +++ b/score/time_slave/docs/index.rst @@ -19,9 +19,3 @@ time_slave Component :maxdepth: 1 component_classification - architecture/index - detailed_design/index - requirements/index - manuals/index - safety_analysis/index - security_analysis/index diff --git a/score/time_slave/docs/manuals/.gitkeep b/score/time_slave/docs/manuals/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/score/time_slave/docs/manuals/config/configuration_guide.rst b/score/time_slave/docs/manuals/config/configuration_guide.rst new file mode 100644 index 00000000..8ea3c983 --- /dev/null +++ b/score/time_slave/docs/manuals/config/configuration_guide.rst @@ -0,0 +1,83 @@ +.. + # ******************************************************************************* + # Copyright (c) 2026 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # This program and the accompanying materials are made available under the + # terms of the Apache License Version 2.0 which is available at + # https://www.apache.org/licenses/LICENSE-2.0 + # + # SPDX-License-Identifier: Apache-2.0 + # ******************************************************************************* + +.. _time_slave_configuration: + +TimeSlave Configuration +======================= + +The behavior of the ``TimeSlave`` is controlled by the ``GptpEngineOptions`` structure. Currently, only a subset of these options can be overridden at runtime via command-line arguments. For all other options, the hard-coded default values are used. + +Command-Line Arguments +----------------------- + +The following argument is available to configure the ``TimeSlave`` at runtime: + +.. list-table:: + :widths: 25 15 60 + :header-rows: 1 + + * - Argument + - Overrides + - Description + * - ``-i, --interface `` + - ``iface_name`` + - **Mandatory Runtime Parameter.** Specifies the Ethernet network interface. Although the internal default is "emac0", this **must** be set correctly at runtime to match the target hardware. + + +Default Configuration (`GptpEngineOptions`) +-------------------------------------------- + +The following table lists all available options and their default values as defined in the source code. Currently, only ``iface_name`` can be changed without recompiling the application. + +.. list-table:: GptpEngineOptions Default Values + :widths: 25 15 60 + :header-rows: 1 + + * - Option + - Default Value + - Description + * - ``iface_name`` + - ``"emac0"`` + - The network interface to use for gPTP traffic. + * - ``pdelay_interval_ms`` + - ``1000`` + - The interval in milliseconds for sending Peer-Delay measurement requests. + * - ``pdelay_warmup_ms`` + - ``2000`` + - The initial delay in milliseconds before the first Peer-Delay request is sent. + * - ``sync_timeout_ms`` + - ``3300`` + - The time in milliseconds without receiving a PTP Sync message before a timeout is declared and the clock is considered unreliable. + * - ``jump_future_threshold_ns`` + - ``500'000'000`` + - The threshold in nanoseconds (500 ms) for detecting a significant forward time jump. + * - ``domain_number`` + - ``0`` + - The gPTP domain number. The TimeSlave will only interact with a PTP master in the same domain. + * - ``phc_config`` + - ``disabled`` + - Configuration for hardware clock (PHC) adjustments. Disabled by default. + + +Example Invocation +------------------ + +.. code-block:: bash + + # Start the TimeSlave, overriding the default interface name "emac0" + ./time_slave --interface eth1 + +.. attention:: + The command-line parsing is currently incomplete. To change parameters other than the interface name, you must modify the default values in the ``GptpEngineOptions`` structure and recompile the application. A comprehensive configuration mechanism (e.g., via a JSON file) is planned for future versions. diff --git a/score/time_slave/docs/manuals/user_manual.rst b/score/time_slave/docs/manuals/user_manual.rst new file mode 100644 index 00000000..6fcf6462 --- /dev/null +++ b/score/time_slave/docs/manuals/user_manual.rst @@ -0,0 +1,64 @@ +.. + # ******************************************************************************* + # Copyright (c) 2026 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # This program and the accompanying materials are made available under the + # terms of the Apache License Version 2.0 which is available at + # https://www.apache.org/licenses/LICENSE-2.0 + # + # SPDX-License-Identifier: Apache-2.0 + # ******************************************************************************* + +.. _time_slave_user_manual: + +Time Slave User Manual +###################### + +.. document:: User Manual Time Slave Component + :id: doc__user_manual_time_slave + :status: draft + :version: 1 + :safety: QM + :security: NO + :realizes: wp__training_path[version==1] + +Overview +======== + +The ``TimeSlave`` component is a system daemon responsible for synchronizing with the PTP Grandmaster Clock over the network. It adjusts the hardware clock (PHC) and publishes synchronization data to shared memory for consumption by the ``TimeDaemon``. + +For module-level integration and deployment information, see the main module manual. + +Configuration +============= + +.. toctree:: + :maxdepth: 2 + + config/configuration_guide + +Runtime Requirements +==================== + +Operating System Privileges +--------------------------- + +The ``TimeSlave`` executable (``time_slave``) requires elevated privileges to access raw network sockets and control the hardware clock. It is strongly recommended **not** to run this process as the `root` user. Instead, grant the required Linux Capabilities to the executable: + +.. code-block:: bash + + sudo setcap cap_net_admin,cap_net_raw,cap_sys_time+eip /path/to/time_slave + +* ``cap_net_admin``: For network interface configuration. +* ``cap_net_raw``: For the use of raw sockets to listen to PTP traffic. +* ``cap_sys_time``: For adjusting the system's hardware clock. + +Network Requirements +-------------------- + +* The network interface used for PTP communication **must** be provided via the ``-i, --interface `` command-line argument. +* The ECU must have network connectivity to the PTP Grandmaster clock on this interface. +* Network hardware must support PHC (PTP Hardware Clock).