From cb8f7b0ce0939725ae9c03c46d6b8737eee7daf0 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Mon, 29 Jun 2026 09:55:41 +0200 Subject: [PATCH 1/2] Add TimestampProvider Abstraction to prevent application code use BSP directly --- CMakeLists.txt | 1 + libs/bsw/CMakeLists.txt | 1 + libs/bsw/time/BUILD.bazel | 26 ++++++++++ libs/bsw/time/CMakeLists.txt | 5 ++ .../bsw/time/include/time/TimestampProvider.h | 49 +++++++++++++++++++ libs/bsw/time/module.spec | 1 + libs/bsw/time/src/time/TimestampProvider.cpp | 25 ++++++++++ libs/bsw/time/test/CMakeLists.txt | 5 ++ .../test/src/time/TimestampProviderTest.cpp | 35 +++++++++++++ 9 files changed, 148 insertions(+) create mode 100644 libs/bsw/time/BUILD.bazel create mode 100644 libs/bsw/time/CMakeLists.txt create mode 100644 libs/bsw/time/include/time/TimestampProvider.h create mode 100644 libs/bsw/time/module.spec create mode 100644 libs/bsw/time/src/time/TimestampProvider.cpp create mode 100644 libs/bsw/time/test/CMakeLists.txt create mode 100644 libs/bsw/time/test/src/time/TimestampProviderTest.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 840515f077c..e430152e912 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -173,6 +173,7 @@ if (BUILD_EXECUTABLE STREQUAL "unitTest") add_subdirectory(libs/bsw/platform/test) add_subdirectory(libs/bsw/runtime/test) add_subdirectory(libs/bsw/storage/test) + add_subdirectory(libs/bsw/time/test) add_subdirectory(libs/bsw/timer/test) add_subdirectory(libs/bsw/transport/test) add_subdirectory(libs/bsw/transportRouterSimple/test) diff --git a/libs/bsw/CMakeLists.txt b/libs/bsw/CMakeLists.txt index 9443e86689b..8b81f1ddae0 100644 --- a/libs/bsw/CMakeLists.txt +++ b/libs/bsw/CMakeLists.txt @@ -29,6 +29,7 @@ add_subdirectory(lifecycle) add_subdirectory(logger) add_subdirectory(platform) add_subdirectory(stdioConsoleInput) +add_subdirectory(time) add_subdirectory(timer) add_subdirectory(util) diff --git a/libs/bsw/time/BUILD.bazel b/libs/bsw/time/BUILD.bazel new file mode 100644 index 00000000000..152170da93e --- /dev/null +++ b/libs/bsw/time/BUILD.bazel @@ -0,0 +1,26 @@ +# ******************************************************************************* +# Copyright (c) 2026 BMW AG +# +# 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 +# ******************************************************************************* + +load("@rules_cc//cc:cc_library.bzl", "cc_library") + +cc_library( + name = "time", + srcs = [ + "src/time/TimestampProvider.cpp", + ], + hdrs = [ + "include/time/TimestampProvider.h", + ], + strip_include_prefix = "include", + visibility = ["//visibility:public"], + deps = [ + "//libs/bsw/bsp", + ], +) diff --git a/libs/bsw/time/CMakeLists.txt b/libs/bsw/time/CMakeLists.txt new file mode 100644 index 00000000000..a93e1c3f336 --- /dev/null +++ b/libs/bsw/time/CMakeLists.txt @@ -0,0 +1,5 @@ +add_library(time src/time/TimestampProvider.cpp) + +target_include_directories(time PUBLIC include) + +target_link_libraries(time PUBLIC bsp) diff --git a/libs/bsw/time/include/time/TimestampProvider.h b/libs/bsw/time/include/time/TimestampProvider.h new file mode 100644 index 00000000000..bf7183b0755 --- /dev/null +++ b/libs/bsw/time/include/time/TimestampProvider.h @@ -0,0 +1,49 @@ +/******************************************************************************** + * Copyright (c) 2026 BMW AG + * + * 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 + ********************************************************************************/ + +#pragma once + +#include + +namespace bsw +{ +namespace time +{ + +/** + * A class for providing timestamps. + * + * Uses underlying BSP / BSW functionality. + */ +class TimestampProvider +{ +public: + /** + * Provides a 32 bit CPU local and relative timestamp in micro seconds resolution. + * + * Will overflow after about 71 minutes. Therefore only suitable for short term measurements. + * + * A 32 bit timestamp is less expensive compared to a 64 bit timestamp, at least on 32 bit + * platforms. Therefore prefer 32 bit timestamp if feasible. + * + * \return 32 bit CPU local timestamp micro seconds. + */ + static uint32_t getTimestampUs32Bit(); + + /** + * Provides a 64 bit CPU local and relative timestamp in micro seconds resolution. + * + * \return 64 bit CPU local timestamp micro seconds. + */ + static uint64_t getTimestampUs64Bit(); +}; + +} // namespace time +} // namespace bsw diff --git a/libs/bsw/time/module.spec b/libs/bsw/time/module.spec new file mode 100644 index 00000000000..87faef85b71 --- /dev/null +++ b/libs/bsw/time/module.spec @@ -0,0 +1 @@ +oss: true diff --git a/libs/bsw/time/src/time/TimestampProvider.cpp b/libs/bsw/time/src/time/TimestampProvider.cpp new file mode 100644 index 00000000000..c302c873e3d --- /dev/null +++ b/libs/bsw/time/src/time/TimestampProvider.cpp @@ -0,0 +1,25 @@ +/******************************************************************************** + * Copyright (c) 2026 BMW AG + * + * 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 + ********************************************************************************/ + +#include "time/TimestampProvider.h" + +#include + +namespace bsw +{ +namespace time +{ + +uint32_t TimestampProvider::getTimestampUs32Bit() { return getSystemTimeUs32Bit(); } + +uint64_t TimestampProvider::getTimestampUs64Bit() { return getSystemTimeUs(); } + +} // namespace time +} // namespace bsw diff --git a/libs/bsw/time/test/CMakeLists.txt b/libs/bsw/time/test/CMakeLists.txt new file mode 100644 index 00000000000..20f72f4a6e4 --- /dev/null +++ b/libs/bsw/time/test/CMakeLists.txt @@ -0,0 +1,5 @@ +add_executable(timeTest src/time/TimestampProviderTest.cpp) + +target_link_libraries(timeTest PRIVATE time bspMock gmock_main) + +gtest_discover_tests(timeTest PROPERTIES LABELS "timeTest") diff --git a/libs/bsw/time/test/src/time/TimestampProviderTest.cpp b/libs/bsw/time/test/src/time/TimestampProviderTest.cpp new file mode 100644 index 00000000000..b7d6df0bd2b --- /dev/null +++ b/libs/bsw/time/test/src/time/TimestampProviderTest.cpp @@ -0,0 +1,35 @@ +/******************************************************************************** + * Copyright (c) 2026 BMW AG + * + * 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 + ********************************************************************************/ + +#include "time/TimestampProvider.h" + +#include "bsp/timer/SystemTimerMock.h" + +#include + +using namespace ::testing; + +TEST(TimestampProviderTest, getTimestampUs32Bit_returns_system_time) +{ + StrictMock timer; + + EXPECT_CALL(timer, getSystemTimeUs32Bit()).WillOnce(Return(42U)); + + EXPECT_EQ(42U, ::bsw::time::TimestampProvider::getTimestampUs32Bit()); +} + +TEST(TimestampProviderTest, getTimestampUs64Bit_returns_system_time) +{ + StrictMock timer; + + EXPECT_CALL(timer, getSystemTimeUs()).WillOnce(Return(0x1'0000'0042ULL)); + + EXPECT_EQ(0x1'0000'0042ULL, ::bsw::time::TimestampProvider::getTimestampUs64Bit()); +} From b4c2aa330e2a17173f0f8c920d5f566288592af4 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Mon, 29 Jun 2026 10:34:35 +0200 Subject: [PATCH 2/2] Rename getSystemTimeUs to getSystemTimeUs64Bit for consistency --- .../bspConfiguration/src/bsp/SystemTimer/SystemTimer.cpp | 8 +++++--- libs/bsw/bsp/include/bsp/timer/SystemTimer.h | 2 +- libs/bsw/bsp/include/bsp/timer/isEqualAfterTimeout.h | 4 ++-- libs/bsw/bsp/mock/include/bsp/timer/SystemTimerMock.h | 4 ++-- libs/bsw/bsp/mock/src/bsp/timer/SystemTimerMock.cpp | 2 +- .../bsp/test/src/bsp/timer/IsEqualAfterTimeoutTest.cpp | 4 ++-- libs/bsw/time/src/time/TimestampProvider.cpp | 2 +- libs/bsw/time/test/src/time/TimestampProviderTest.cpp | 2 +- .../posix/bsp/bspSystemTime/src/bsp/time/systemTimer.cpp | 2 +- platforms/s32k1xx/etlImpl/src/clocks.cpp | 2 +- 10 files changed, 17 insertions(+), 15 deletions(-) diff --git a/executables/referenceApp/platforms/s32k148evb/bspConfiguration/src/bsp/SystemTimer/SystemTimer.cpp b/executables/referenceApp/platforms/s32k148evb/bspConfiguration/src/bsp/SystemTimer/SystemTimer.cpp index bb7f5142aec..2f46b01acef 100644 --- a/executables/referenceApp/platforms/s32k148evb/bspConfiguration/src/bsp/SystemTimer/SystemTimer.cpp +++ b/executables/referenceApp/platforms/s32k148evb/bspConfiguration/src/bsp/SystemTimer/SystemTimer.cpp @@ -87,7 +87,7 @@ uint32_t getSystemTicks32Bit(void) { return static_cast(updateTicks()) uint64_t getSystemTimeNs(void) { return updateTicks() * 1000U / TICK_FREQ_MHZ; } -uint64_t getSystemTimeUs(void) { return updateTicks() / TICK_FREQ_MHZ; } +uint64_t getSystemTimeUs64Bit(void) { return updateTicks() / TICK_FREQ_MHZ; } uint32_t getSystemTimeUs32Bit(void) { return static_cast(updateTicks() / TICK_FREQ_MHZ); } @@ -112,8 +112,10 @@ uint32_t getFastTicksPerSecond(void) void sysDelayUs(uint32_t const delay) { - uint64_t const start = getSystemTimeUs(); - while (getSystemTimeUs() < start + delay) {} + uint32_t const start = getSystemTimeUs32Bit(); + // Use unsigned wraparound: (now - start) yields the elapsed microseconds modulo 2^32, which is + // correct as long as the real elapsed time is < 2^32 us (~71.6 min) and we poll often enough. + while ((getSystemTimeUs32Bit() - start) < delay) {} } } // extern "C" diff --git a/libs/bsw/bsp/include/bsp/timer/SystemTimer.h b/libs/bsw/bsp/include/bsp/timer/SystemTimer.h index 0a5513ee108..1ac5f029cc7 100644 --- a/libs/bsw/bsp/include/bsp/timer/SystemTimer.h +++ b/libs/bsw/bsp/include/bsp/timer/SystemTimer.h @@ -54,7 +54,7 @@ uint64_t getSystemTimeNs(void); * Returns the Time in Us since startup of the CPU. * \return Systemtime in Us. */ -uint64_t getSystemTimeUs(void); +uint64_t getSystemTimeUs64Bit(void); /** * Returns the Time in Ms since startup of the CPU. diff --git a/libs/bsw/bsp/include/bsp/timer/isEqualAfterTimeout.h b/libs/bsw/bsp/include/bsp/timer/isEqualAfterTimeout.h index 17f2b2e2e37..8256ad34a50 100644 --- a/libs/bsw/bsp/include/bsp/timer/isEqualAfterTimeout.h +++ b/libs/bsw/bsp/include/bsp/timer/isEqualAfterTimeout.h @@ -29,9 +29,9 @@ namespace bsp template bool isEqualAfterTimeout(T const* const ptr, T const mask, T const value, uint32_t const timeout) { - uint64_t const endTime = getSystemTimeUs() + timeout; + uint64_t const endTime = getSystemTimeUs64Bit() + timeout; - while (((*ptr & mask) == (value & mask)) && (getSystemTimeUs() <= endTime)) {} + while (((*ptr & mask) == (value & mask)) && (getSystemTimeUs64Bit() <= endTime)) {} return (*ptr & mask) == (value & mask); } diff --git a/libs/bsw/bsp/mock/include/bsp/timer/SystemTimerMock.h b/libs/bsw/bsp/mock/include/bsp/timer/SystemTimerMock.h index 4db9df5d591..893a205bc2b 100644 --- a/libs/bsw/bsp/mock/include/bsp/timer/SystemTimerMock.h +++ b/libs/bsw/bsp/mock/include/bsp/timer/SystemTimerMock.h @@ -68,9 +68,9 @@ class SystemTimerMock : public ::etl::singleton_base MOCK_METHOD(uint64_t, getSystemTimeNs, ()); /** - * \see getSystemTimeUs(void) + * \see getSystemTimeUs64Bit(void) */ - MOCK_METHOD(uint64_t, getSystemTimeUs, ()); + MOCK_METHOD(uint64_t, getSystemTimeUs64Bit, ()); /** * \see getSystemTimeMs(void) diff --git a/libs/bsw/bsp/mock/src/bsp/timer/SystemTimerMock.cpp b/libs/bsw/bsp/mock/src/bsp/timer/SystemTimerMock.cpp index 6f04c06cd06..f9d35037739 100644 --- a/libs/bsw/bsp/mock/src/bsp/timer/SystemTimerMock.cpp +++ b/libs/bsw/bsp/mock/src/bsp/timer/SystemTimerMock.cpp @@ -28,7 +28,7 @@ uint32_t getSystemTicks32Bit(void) { return SystemTimerMock::instance().getSyste uint64_t getSystemTimeNs(void) { return SystemTimerMock::instance().getSystemTimeNs(); } -uint64_t getSystemTimeUs(void) { return SystemTimerMock::instance().getSystemTimeUs(); } +uint64_t getSystemTimeUs64Bit(void) { return SystemTimerMock::instance().getSystemTimeUs64Bit(); } uint64_t getSystemTimeMs(void) { return SystemTimerMock::instance().getSystemTimeMs(); } diff --git a/libs/bsw/bsp/test/src/bsp/timer/IsEqualAfterTimeoutTest.cpp b/libs/bsw/bsp/test/src/bsp/timer/IsEqualAfterTimeoutTest.cpp index 026040ac4aa..fe89cb6911f 100644 --- a/libs/bsw/bsp/test/src/bsp/timer/IsEqualAfterTimeoutTest.cpp +++ b/libs/bsw/bsp/test/src/bsp/timer/IsEqualAfterTimeoutTest.cpp @@ -20,12 +20,12 @@ TEST(IsEqualAfterTimeoutTest, Check) { StrictMock timer; - EXPECT_CALL(timer, getSystemTimeUs()).Times(1).WillOnce(Return(11U)); + EXPECT_CALL(timer, getSystemTimeUs64Bit()).Times(1).WillOnce(Return(11U)); uint32_t address = 0x000000FFU; EXPECT_FALSE(::bsp::isEqualAfterTimeout(&address, 0xFFFFFF00U, 0x0000FFFFU, 10U)); - EXPECT_CALL(timer, getSystemTimeUs()) + EXPECT_CALL(timer, getSystemTimeUs64Bit()) .Times(3) .WillOnce(Return(12U)) .WillOnce(Return(20U)) diff --git a/libs/bsw/time/src/time/TimestampProvider.cpp b/libs/bsw/time/src/time/TimestampProvider.cpp index c302c873e3d..ca5362c6789 100644 --- a/libs/bsw/time/src/time/TimestampProvider.cpp +++ b/libs/bsw/time/src/time/TimestampProvider.cpp @@ -19,7 +19,7 @@ namespace time uint32_t TimestampProvider::getTimestampUs32Bit() { return getSystemTimeUs32Bit(); } -uint64_t TimestampProvider::getTimestampUs64Bit() { return getSystemTimeUs(); } +uint64_t TimestampProvider::getTimestampUs64Bit() { return getSystemTimeUs64Bit(); } } // namespace time } // namespace bsw diff --git a/libs/bsw/time/test/src/time/TimestampProviderTest.cpp b/libs/bsw/time/test/src/time/TimestampProviderTest.cpp index b7d6df0bd2b..e4c98084986 100644 --- a/libs/bsw/time/test/src/time/TimestampProviderTest.cpp +++ b/libs/bsw/time/test/src/time/TimestampProviderTest.cpp @@ -29,7 +29,7 @@ TEST(TimestampProviderTest, getTimestampUs64Bit_returns_system_time) { StrictMock timer; - EXPECT_CALL(timer, getSystemTimeUs()).WillOnce(Return(0x1'0000'0042ULL)); + EXPECT_CALL(timer, getSystemTimeUs64Bit()).WillOnce(Return(0x1'0000'0042ULL)); EXPECT_EQ(0x1'0000'0042ULL, ::bsw::time::TimestampProvider::getTimestampUs64Bit()); } diff --git a/platforms/posix/bsp/bspSystemTime/src/bsp/time/systemTimer.cpp b/platforms/posix/bsp/bspSystemTime/src/bsp/time/systemTimer.cpp index b46c9dbeda0..f1cb7557a7d 100644 --- a/platforms/posix/bsp/bspSystemTime/src/bsp/time/systemTimer.cpp +++ b/platforms/posix/bsp/bspSystemTime/src/bsp/time/systemTimer.cpp @@ -20,7 +20,7 @@ uint64_t getSystemTimeNs() return duration_cast(steady_clock::now() - startTime).count(); } -uint64_t getSystemTimeUs() +uint64_t getSystemTimeUs64Bit() { return duration_cast(steady_clock::now() - startTime).count(); } diff --git a/platforms/s32k1xx/etlImpl/src/clocks.cpp b/platforms/s32k1xx/etlImpl/src/clocks.cpp index fbf373fc86c..3e2b188f98e 100644 --- a/platforms/s32k1xx/etlImpl/src/clocks.cpp +++ b/platforms/s32k1xx/etlImpl/src/clocks.cpp @@ -20,7 +20,7 @@ etl::chrono::high_resolution_clock::rep etl_get_high_resolution_clock() etl::chrono::system_clock::rep etl_get_system_clock() { - return etl::chrono::system_clock::rep(static_cast(getSystemTimeUs())); + return etl::chrono::system_clock::rep(static_cast(getSystemTimeUs64Bit())); } etl::chrono::steady_clock::rep etl_get_steady_clock()