diff --git a/.gitignore b/.gitignore index 630b0b8a..e22ed867 100644 --- a/.gitignore +++ b/.gitignore @@ -40,7 +40,8 @@ user.bazelrc .ruff_cache # docs:incremental and docs:ide_support build artifacts -/_build +_build +ubproject.toml # Vale - editorial style guide .vale.ini diff --git a/BUILD b/BUILD index 65931225..31ef4bbf 100644 --- a/BUILD +++ b/BUILD @@ -21,9 +21,25 @@ setup_starpls( ) docs( - data = [ - "@score_process//:needs_json", + bundles = [ + { + "bundle": "//score/time_slave:docs_bundle", + "mount_at": "components/time_slave", + }, + { + "bundle": "//score/time_daemon:docs_bundle", + "mount_at": "components/time_daemon", + }, + { + "bundle": "//score/time:docs_bundle", + "mount_at": "components/time", + }, ], + external_needs = [ + "@score_process//:needs_json_file", + ], + project = "S-CORE Time", + project_url = "https://eclipse-score.github.io/time", source_dir = "docs", ) diff --git a/MODULE.bazel b/MODULE.bazel index 4a01c4bc..7c9b06e3 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -12,8 +12,6 @@ # ******************************************************************************* module( name = "score_time", - version = "0.0.0", - compatibility_level = 0, ) ## Configure the C++ toolchain @@ -69,7 +67,7 @@ bazel_dep(name = "score_logging", version = "0.2.1") ### Modules that are used internally within the repository but not exposed as part of the public API -bazel_dep(name = "score_docs_as_code", version = "4.5.0") +bazel_dep(name = "score_docs_as_code", version = "7.1.0") bazel_dep(name = "score_cpp_policies", version = "0.0.1", dev_dependency = True) @@ -81,7 +79,7 @@ git_override( remote = "https://github.com/eclipse-score/score_cpp_policies.git", ) -bazel_dep(name = "score_process", version = "1.6.0", dev_dependency = True) +bazel_dep(name = "score_process", version = "2.0.3", dev_dependency = True) bazel_dep(name = "score_tooling", version = "1.2.0", dev_dependency = True) # cpp support in use_format_targets(languages=[...]) was added after 1.2.0. diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 96859963..9f375b4d 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -539,6 +539,8 @@ "https://bcr.bazel.build/modules/rules_swift/1.18.0/MODULE.bazel": "a6aba73625d0dc64c7b4a1e831549b6e375fbddb9d2dde9d80c9de6ec45b24c9", "https://bcr.bazel.build/modules/rules_swift/2.1.1/MODULE.bazel": "494900a80f944fc7aa61500c2073d9729dff0b764f0e89b824eb746959bc1046", "https://bcr.bazel.build/modules/rules_swift/2.1.1/source.json": "40fc69dfaac64deddbb75bd99cdac55f4427d9ca0afbe408576a65428427a186", + "https://bcr.bazel.build/modules/sphinxdocs/2.2.0/MODULE.bazel": "e046c573919d72605d62c352a08d9223a10aafef3a7cb70d0fe253ebdd97019e", + "https://bcr.bazel.build/modules/sphinxdocs/2.2.0/source.json": "b1da19a3d14a1dd8aa6a9ccaedc42bbe0313c8160a77ba5cca336cca1315298d", "https://bcr.bazel.build/modules/stardoc/0.5.0/MODULE.bazel": "f9f1f46ba8d9c3362648eea571c6f9100680efc44913618811b58cc9c02cd678", "https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": "1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8", "https://bcr.bazel.build/modules/stardoc/0.5.3/MODULE.bazel": "c7f6948dae6999bf0db32c1858ae345f112cacf98f174c7a8bb707e41b974f1c", @@ -1018,8 +1020,10 @@ "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_crates/0.0.6/MODULE.bazel": "da72d24b2afb4456377f7ee13d0d95fb6bfc70dbfb949c7b8676618e661edf61", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_crates/0.0.9/MODULE.bazel": "8f581e0a658a6dab149f381d783443cb00b559f4e9623956f8ff3de06108c550", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_dash_license_checker/0.1.1/MODULE.bazel": "76681dbd2d45b5c540869a2337174086c56c54953aab1d02cd878b59d31d13a5", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_devcontainer/1.10.0/MODULE.bazel": "2a37c7b8107a6dd51f0fe673bf11a6d200bc3c078bc7104bc96eb9d2f6772f66", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_devcontainer/1.10.0/source.json": "3b0e923664da034c9db5564a5fccd31837bcd165cf72ecfb7ae5ff64a00d0883", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_devcontainer/1.7.0/MODULE.bazel": "f9a5971fbd05f0ed14e7a373dbf58af72a5c58d081537a75c314daaf61c92ae9", - "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_devcontainer/1.7.0/source.json": "a3f55522fd9f63fae7a92f3cb5f91c25ae7474a39e9f9c633f0cf797fc0ca8e5", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_devcontainer/1.9.0/MODULE.bazel": "2a04a354eb7a77d478bb43ba20b1dac0758af858172a760e4290621bef1a2f28", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_docs_as_code/0.2.4/MODULE.bazel": "ea4801e96c87e2b8650a0fa9e5fed9b8bdbef05c1bc3e30003ba527d5af60a43", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_docs_as_code/0.2.6/MODULE.bazel": "1af2963e91c6472555e222f0aba3dc2f5492d04598298209a361978ee3e321e3", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_docs_as_code/0.3.3/MODULE.bazel": "95d2b7d44d461c1cf9bd016605f740716fd4ea1303f5f2ed93de3566b90feb1b", @@ -1036,7 +1040,10 @@ "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_docs_as_code/4.0.0/MODULE.bazel": "522dc070354e6be2f984468a4243fe4ab8bec690922df5f31f7f0916ee264e20", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_docs_as_code/4.0.1/MODULE.bazel": "5955f4cf37228a9cdda7f6009b81db0446f005c618f4bc43665bfa45f2673ebc", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_docs_as_code/4.5.0/MODULE.bazel": "4cfe52fe8b8dbeaf7e87500036391da278f72f1c2b41b689ffdd4337196dd8fe", - "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_docs_as_code/4.5.0/source.json": "e01b29a3e9640a0d41d880d7da525e451115649d90f097ed66d09808c9135486", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_docs_as_code/4.6.0/MODULE.bazel": "d5fbfed7b9bd65f10830e2290045dea639a8cfcaf9f9f0f7a1b12888c14e7d2b", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_docs_as_code/6.0.0/MODULE.bazel": "ab2af2d8fab73e4512d2e2bd399a64d10c5c5463388322f7025637b13ec7585c", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_docs_as_code/7.1.0/MODULE.bazel": "7d89729cc6a1cb7a13b9cfbf4bd84ace437451f5eb0873202586ac7cb288eff5", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_docs_as_code/7.1.0/source.json": "2aebac074ccaef8aad11822d04a98e97d9aded5d851812075969618da8cf1996", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_format_checker/0.1.1/MODULE.bazel": "1acc254faa90e9f97b79ac69af25b6c21c561f8d6079914f6352b9b20d26bd37", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_lifecycle_health/0.3.0/MODULE.bazel": "97c3ab10cafe3f519293fb1fab2de3c3970f9d70e55255c72f4dfe87ec55a240", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_lifecycle_health/0.3.0/source.json": "138d840f0ec2c7a915f935803426920b0f344f7e0038db885fe4ebd32829a514", @@ -1057,7 +1064,9 @@ "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_process/1.5.2/MODULE.bazel": "be52d29278d6671221f28921e8f1acfce29c3bfc3e6b4f503f0625ab2c61586f", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_process/1.5.3/MODULE.bazel": "65024b7f23ce5f72bd6ffd455a67c042ecf56d267f0bf63a90330a3241781b7a", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_process/1.6.0/MODULE.bazel": "2496bc24311f69f49449ee85d8bb38e3b970cbfcf10d0a7f19b2d5262ce80e8d", - "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_process/1.6.0/source.json": "093424aa8bfed8705a3d142b21fe1d053258f2dd5eb1944941f6439b2c7157e9", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_process/2.0.1/MODULE.bazel": "88bff0ed46da79d87f8c441a6bf6b760ee7c194b282e7e54a8b7db6ea2354db9", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_process/2.0.3/MODULE.bazel": "d9359f1cb7e460a5eb6b7e5d2185bcc6ed7c9f4a31f560d6a703549ca6366ed7", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_process/2.0.3/source.json": "0ea635f75ded5225494b709a441488f80be0db0ded4a9786367477ecdbcf42b0", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_python_basics/0.3.0/MODULE.bazel": "785ddd5295213e36c31ab86bdc34f29c0f7d1b72e9abd931bb08f42c0e48e2e9", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_python_basics/0.3.1/MODULE.bazel": "99c491109937542e61df090222666a8613ef946fa7bb2b2d5ba648b2baba03ad", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_python_basics/0.3.2/MODULE.bazel": "f25490f64035a0e3a0d53ad9cb6164e8325ce6cf2a7ee68c6ae153840cb2497e", @@ -1067,6 +1076,7 @@ "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_rust_policies/0.0.5/MODULE.bazel": "7de02547bdf121d3dedf5141b97f0fd9a545bd255ff5c7b699056b35816ffad9", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_rust_policies/0.0.5/source.json": "22c8bf0a5cbf7c7b06f774f3f66498e0bc14346a8b2208f7427a8fbb78a42547", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_starpls_lsp/0.1.0/MODULE.bazel": "b2f8c4c8d8e851706255ff9002b448bff6e040b8f0c6adedbde2a09375aa16cc", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/sphinxdocs/2.2.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/stardoc/0.5.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/stardoc/0.5.1/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/stardoc/0.5.3/MODULE.bazel": "not found", @@ -9744,7 +9754,7 @@ "@@score_bazel_cpp_toolchains+//extensions:gcc.bzl%gcc": { "general": { "bzlTransitiveDigest": "dc5MfL+KgiCba7Ie+8RFXMg+QaVnnCWXSXUymx//0GY=", - "usagesDigest": "oQ/75gJwZv01FtGwQfXOe4Hedw0rF/noB1kThRyH6Mw=", + "usagesDigest": "mDKDOXemi2CdHmlhiNI1ecC8kdvL46eDWvO/cll77AI=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, diff --git a/score/time_slave/docs/component_classification.rst b/docs/components/index.rst similarity index 82% rename from score/time_slave/docs/component_classification.rst rename to docs/components/index.rst index bf6b15db..c8b334fe 100644 --- a/score/time_slave/docs/component_classification.rst +++ b/docs/components/index.rst @@ -12,10 +12,12 @@ # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* -Component Classification -======================== +.. _ components:: -:Component: time_slave -:ASIL Level: QM -:Language: C++ -:Platform: Linux, QNX +Components +~~~~~~~~~~ + +.. toctree will be filled by docs_bundle via bazel + +.. toctree:: + :maxdepth: 1 diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index a834ad1f..00000000 --- a/docs/conf.py +++ /dev/null @@ -1,57 +0,0 @@ -# ******************************************************************************* -# 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 -# ******************************************************************************* - -# Configuration file for the Sphinx documentation builder. -# -# For the full list of built-in configuration values, see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - - -# -- Project information ----------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information - -project = "S-CORE Time" -project_url = "https://eclipse-score.github.io/time" -project_prefix = "TIME_" -author = "S-CORE" -version = "0.1" - -# -- General configuration --------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration - - -extensions = [ - "sphinx_design", - "sphinx_needs", - "sphinxcontrib.plantuml", - "score_plantuml", - "score_metamodel", - "score_draw_uml_funcs", - "score_source_code_linker", - "score_layout", - "score_metrics", -] - -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 - # building the documentation via 'bazel run //docs:incremental' or esbonio, these - # entries are required to prevent the build from failing. - "bazel-*", - ".venv_docs", -] - -templates_path = ["templates"] - -# Enable numref -numfig = True diff --git a/docs/index.rst b/docs/index.rst index d7d50f3d..4ead42cb 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -43,6 +43,13 @@ For a detailed concept and architectural design, please refer to the :doc:`time_ :caption: Contents: features/index + module/index + +.. toctree:: + :maxdepth: 1 + :caption: Component Documentation: + + components/index Project Layout -------------- diff --git a/docs/manuals/.gitkeep b/docs/manuals/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/docs/module/index.rst b/docs/module/index.rst new file mode 100644 index 00000000..6b7d7dc1 --- /dev/null +++ b/docs/module/index.rst @@ -0,0 +1,47 @@ +.. + # ******************************************************************************* + # 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 + # ******************************************************************************* + +Module +====== + +The S-CORE ``time`` module provides a unified API for accessing system, steady, high-resolution steady, and PTP-synchronized vehicle time. The module contains four components: a client library for application-facing access, Time Slave for PTP clock synchronization, ``ts_client`` for shared-memory IPC between Time Slave and Time Daemon, and Time Daemon for synchronization quality validation before serving Vehicle Time. + +.. code-block:: rst + + .. mod:: Time + :id: mod__time + :includes: comp__component_name_template + +Module View +----------- + +.. code-block:: rst + + .. mod_view_sta:: Time Module Static View + :id: mod_view_sta__time__time + :includes: comp__component_name_template + + .. needarch:: + :scale: 50 + :align: center + + {{ draw_module(need(), needs) }} + +Module Documents +---------------- + +.. toctree:: + :maxdepth: 1 + + manuals/index diff --git a/docs/module/manuals/api_description/api_usage.rst b/docs/module/manuals/api_description/api_usage.rst new file mode 100644 index 00000000..7b578209 --- /dev/null +++ b/docs/module/manuals/api_description/api_usage.rst @@ -0,0 +1,219 @@ +.. + # ******************************************************************************* + # 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 Supported Time Bases +========================================= + +The primary interface for applications to access time values is the ``score::time`` client library. It provides a simple, robust, and testable way to get current time from all supported time bases. + +This section describes the most common use case: polling current time snapshots. + +Supported time bases in this module: + +* ``std::chrono::system_clock`` via ``score::time::SystemClock`` +* ``std::chrono::steady_clock`` via ``score::time::SteadyClock`` +* ``score::time::HighResSteadyTime`` via ``score::time::HighResSteadyClock`` +* ``score::time::VehicleTime`` via ``score::time::VehicleClock`` + +For more detail, see the :ref:`module user manual`. + +Polling Supported Time Bases +---------------------------- + +All supported clocks use the same API shape: ``GetInstance()`` and ``Now()``. + +.. code-block:: cpp + + #include "score/time/system_time/src/system_clock.h" + #include "score/time/steady_time/src/steady_clock.h" + #include "score/time/high_res_steady_time/src/high_res_steady_clock.h" + #include "score/time/vehicle_time/src/vehicle_clock.h" + + void poll_supported_time_bases() + { + const auto system_snapshot = score::time::SystemClock::GetInstance().Now(); + const auto steady_snapshot = score::time::SteadyClock::GetInstance().Now(); + const auto high_res_snapshot = score::time::HighResSteadyClock::GetInstance().Now(); + const auto vehicle_snapshot = score::time::VehicleClock::GetInstance().Now(); + + // Access the timepoint from every snapshot in the same way. + const auto system_tp = system_snapshot.TimePoint(); + const auto steady_tp = steady_snapshot.TimePoint(); + const auto high_res_tp = high_res_snapshot.TimePoint(); + const auto vehicle_tp = vehicle_snapshot.TimePoint(); + } + +Polling Vehicle Time with Quality Checks +---------------------------------------- + +This method involves actively requesting the current vehicle 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. + // IsConsistent(): status flags are not contradictory. + // HasBeenSynchronized(): clock has synchronized at least once in this lifecycle. + // IsReliable(): synchronized now and no active timeout/leap fault. + const auto status = snapshot.Status(); + if (status.IsConsistent() && status.HasBeenSynchronized() && 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 invalid or currently unusable status. + // Applications must not use TimePoint() if status is inconsistent, + // never synchronized, or currently unreliable. + std::cerr << "Warning: Vehicle Time status is not usable yet. " + << "Retrying later..." << std::endl; + } + } + +.. attention:: + + Never use ``TimePoint`` from ``ClockSnapshot`` before verifying status. + For robust handling, check ``Status().IsConsistent()``, ``Status().HasBeenSynchronized()``, and ``Status().IsReliable()``. + +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/docs/module/manuals/api_description/lifecycle.rst b/docs/module/manuals/api_description/lifecycle.rst new file mode 100644 index 00000000..cddf8987 --- /dev/null +++ b/docs/module/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/docs/module/manuals/api_description/testing_guide.rst b/docs/module/manuals/api_description/testing_guide.rst new file mode 100644 index 00000000..77a94852 --- /dev/null +++ b/docs/module/manuals/api_description/testing_guide.rst @@ -0,0 +1,138 @@ +.. + # ******************************************************************************* + # 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. + +Using Existing Test Utilities +============================= + +The framework provides ``ClockTestFactory`` in +``score/time/clock/src/clock_test_factory.h`` for constructor-based mock injection. + +Use this helper when your component accepts ``Clock`` via constructor or setter injection. + +.. code-block:: cpp + + #include "score/time/clock/src/clock_test_factory.h" + #include "score/time/clock/src/clock_backend_mock.h" + #include "score/time/vehicle_time.h" + #include + + auto backend = std::make_shared>(); + auto clock = score::time::test_utils::ClockTestFactory::Make(backend); + +When code under test calls ``Clock::GetInstance()`` internally, use +``ScopedClockOverride`` as shown below. + + +Example: Testing a Timeout Handler +================================== + +This example demonstrates how 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 "score/time/clock/src/clock_backend_mock.h" + #include "score/time/clock/src/scoped_clock_override.h" + #include + + TEST(MyTimeoutHandlerTest, DetectsTimeoutCorrectly) + { + auto fake_clock_backend = + std::make_shared>(); + score::time::VehicleTime::duration elapsed{0}; + + ON_CALL(*fake_clock_backend, Now()) + .WillByDefault(testing::Invoke([&elapsed]() { + return score::time::TimeSnapshot{ + score::time::VehicleTime::time_point{elapsed}}; + })); + + // 1. Activate override because component uses Clock::GetInstance(). + auto clock_override = score::time::test_utils::ScopedClockOverride( + fake_clock_backend); + + // 2. Instantiate component-under-test. It now uses fake backend. + MyTimeoutHandler handler; + const auto timeout = std::chrono::seconds{10}; + + // 3. Initially, no timeout should be detected. + EXPECT_FALSE(handler.HasTimedOut(timeout)); + + // 4. Advance fake time by 9 seconds. + elapsed += std::chrono::seconds{9}; + EXPECT_FALSE(handler.HasTimedOut(timeout)); + + // 5. Advance past 10-second threshold (total: 11 seconds). + elapsed += std::chrono::seconds{2}; + EXPECT_TRUE(handler.HasTimedOut(timeout)); + + } // clock_override is destroyed here + + +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/docs/module/manuals/examples/basic_clocks.rst b/docs/module/manuals/examples/basic_clocks.rst new file mode 100644 index 00000000..8bdc4853 --- /dev/null +++ b/docs/module/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 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/docs/module/manuals/examples/index.rst b/docs/module/manuals/examples/index.rst new file mode 100644 index 00000000..2c05373b --- /dev/null +++ b/docs/module/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/docs/module/manuals/examples/vehicle_time.rst b/docs/module/manuals/examples/vehicle_time.rst new file mode 100644 index 00000000..ec2b1d71 --- /dev/null +++ b/docs/module/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/docs/module/manuals/index.rst b/docs/module/manuals/index.rst new file mode 100644 index 00000000..34c7e422 --- /dev/null +++ b/docs/module/manuals/index.rst @@ -0,0 +1,22 @@ +.. + # ******************************************************************************* + # 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: + :glob: + + * diff --git a/docs/module/manuals/troubleshooting_guide.rst b/docs/module/manuals/troubleshooting_guide.rst new file mode 100644 index 00000000..cf236eb1 --- /dev/null +++ b/docs/module/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/module/manuals/user_manual.rst b/docs/module/manuals/user_manual.rst new file mode 100644 index 00000000..5d7f91d9 --- /dev/null +++ b/docs/module/manuals/user_manual.rst @@ -0,0 +1,260 @@ +.. + # ******************************************************************************* + # 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: ASIL_B + :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. + +API Description +--------------- + +The primary interface for applications to access synchronized time is the ``score::time`` client library: + +.. toctree:: + :maxdepth: 2 + + api_description/api_usage + api_description/lifecycle + api_description/testing_guide + +.. 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). + +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. + +Select clock type based on use case. No clock type is universally better; each has a different purpose. + +.. 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. + - Cross-ECU correlation, synchronized logging, and decisions that depend on vehicle-wide time consistency (for example: validating whether a vehicle-time-stamped frame is too old and should be discarded). + * - ``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. + +.. _component_manuals: + +Component Manuals +----------------- + +For detailed component-specific user manuals: + +.. toctree:: + :maxdepth: 1 + + /components/time_slave/manuals/user_manual + /components/time_daemon/manuals/user_manual + +Examples +-------- + +Practical examples and tutorials for using the time module: + +.. toctree:: + :maxdepth: 2 + + examples/index + +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", # 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 + ], + ) + +3. Include headers and use the API in your code: + + .. code-block:: cpp + + #include "score/time/clock.h" + #include "score/time/vehicle_time.h" + + auto& clock = score::time::Clock::GetInstance(); + const auto snapshot = clock.Now(); + if (snapshot.Status().IsReliable()) + { + // Safe to use snapshot.TimePoint() + } + +For component tests, use the mock variants where needed, for example: + +.. code-block:: python + + cc_test( + name = "my_test", + deps = [ + "@score_time//score/time/vehicle_time:vehicle_time_mock", + ], + ) + +Runtime Requirements +-------------------- + +If your application uses ``VehicleTime``, both ``TimeSlave`` and ``TimeDaemon`` services must be running. + +``SystemTime``, ``SteadyTime``, and ``HighResSteadyTime`` do not depend on these daemons. + +For service deployment and configuration details, refer to: + +* :doc:`/components/time_slave/manuals/user_manual` +* :doc:`/components/time_daemon/manuals/user_manual` + +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**: ASIL-B (TBC) + +Safety classification details are currently being aligned with ongoing stakeholder and feature requirement clarifications. Current working classification is: + +* ``score::time`` library: ASIL-B (TBC) +* ``TimeDaemon``: ASIL-B +* ``TimeSlave``: QM + +For final safety-critical usage requirements and guidelines, refer to the safety manual updates in upcoming 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 controls limit attack surface for TimeSlave daemon (Linux Capabilities on Linux, equivalent least-privilege process configuration on QNX) + +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/release/.gitkeep b/docs/release/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/docs/safety_mgt/.gitkeep b/docs/safety_mgt/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/docs/security_mgt/.gitkeep b/docs/security_mgt/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/docs/verification_report/.gitkeep b/docs/verification_report/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/score/time/BUILD b/score/time/BUILD index 1048941a..7f707a4b 100644 --- a/score/time/BUILD +++ b/score/time/BUILD @@ -13,6 +13,13 @@ load("@score_baselibs//:bazel/unit_tests.bzl", "cc_unit_test_suites_for_host_and_qnx") load("@score_baselibs//third_party/itf:py_unittest_qnx_test.bzl", "py_unittest_qnx_test") +load("@score_docs_as_code//:docs.bzl", "docs_bundle") + +docs_bundle( + name = "docs_bundle", + source_dir = "docs", + visibility = ["//visibility:public"], +) py_unittest_qnx_test( name = "qnx_unit_test_cases", diff --git a/score/time_daemon/BUILD b/score/time_daemon/BUILD index a1a29bac..c6430a3d 100644 --- a/score/time_daemon/BUILD +++ b/score/time_daemon/BUILD @@ -12,6 +12,13 @@ # ******************************************************************************* load("@score_baselibs//:bazel/unit_tests.bzl", "cc_unit_test_suites_for_host_and_qnx") +load("@score_docs_as_code//:docs.bzl", "docs_bundle") + +docs_bundle( + name = "docs_bundle", + source_dir = "docs", + visibility = ["//visibility:public"], +) cc_unit_test_suites_for_host_and_qnx( name = "unit_test_suite", diff --git a/score/time_daemon/docs/index.rst b/score/time_daemon/docs/index.rst new file mode 100644 index 00000000..ec6791b1 --- /dev/null +++ b/score/time_daemon/docs/index.rst @@ -0,0 +1,26 @@ +.. + # ******************************************************************************* + # 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 +=========== + +System daemon responsible for quality assurance and providing synchronized time to local applications on the ECU. + +Component Detail Information +============================ + +.. toctree:: + :maxdepth: 1 + + 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/BUILD b/score/time_slave/BUILD index 4383af58..59c276e7 100644 --- a/score/time_slave/BUILD +++ b/score/time_slave/BUILD @@ -12,6 +12,13 @@ # ******************************************************************************* load("@score_baselibs//:bazel/unit_tests.bzl", "cc_unit_test_suites_for_host_and_qnx") +load("@score_docs_as_code//:docs.bzl", "docs_bundle") + +docs_bundle( + name = "docs_bundle", + source_dir = "docs", + visibility = ["//visibility:public"], +) cc_unit_test_suites_for_host_and_qnx( name = "unit_test_suite", diff --git a/score/time_slave/docs/architecture/.gitkeep b/score/time_slave/docs/architecture/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/score/time_slave/docs/detailed_design/.gitkeep b/score/time_slave/docs/detailed_design/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/score/time_slave/docs/index.rst b/score/time_slave/docs/index.rst index 6e07edcd..f0dc9ed6 100644 --- a/score/time_slave/docs/index.rst +++ b/score/time_slave/docs/index.rst @@ -12,16 +12,15 @@ # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* -time_slave Component -==================== +Time Slave +========== + +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``. + +Component Detail Information +============================ .. toctree:: :maxdepth: 1 - component_classification - architecture/index - detailed_design/index - requirements/index - manuals/index - safety_analysis/index - security_analysis/index + manuals/user_manual 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..97674aba --- /dev/null +++ b/score/time_slave/docs/manuals/config/configuration_guide.rst @@ -0,0 +1,72 @@ +.. + # ******************************************************************************* + # 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: + + +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 + +.. attention:: + The runtime configuration is currently incomplete. To change parameters, you must modify the default values in the ``GptpEngineOptions`` structure and recompile the application. A comprehensive configuration mechanism (e.g., via a JSON file) will come soon. 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..77f38b86 --- /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 Time Slave 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). diff --git a/score/time_slave/docs/requirements/.gitkeep b/score/time_slave/docs/requirements/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/score/time_slave/docs/safety_analysis/.gitkeep b/score/time_slave/docs/safety_analysis/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/score/time_slave/docs/security_analysis/.gitkeep b/score/time_slave/docs/security_analysis/.gitkeep deleted file mode 100644 index e69de29b..00000000