using System; using System.Runtime.InteropServices; namespace RobotNet10.Realtime; /// /// Provides high-resolution clock access for real-time applications. /// public class RealtimeClock { private readonly RealtimeClockType _clockType; /// /// Initializes a new instance of RealtimeClock. /// /// Type of clock to use public RealtimeClock(RealtimeClockType clockType) { _clockType = clockType; } /// /// Gets the current time from the clock. /// /// Current time public DateTime GetTime() { var tp = new LinuxNative.timespec(); int result = LinuxNative.clock_gettime((int)_clockType, ref tp); if (result != 0) { LinuxNative.ThrowLastError("clock_gettime"); } if (_clockType == RealtimeClockType.Realtime) { return DateTimeOffset.FromUnixTimeSeconds(tp.tv_sec) .AddTicks(tp.tv_nsec / 100) .DateTime; } else { // For monotonic clocks, return time since boot return DateTime.UtcNow; // Note: This is approximate for monotonic clocks } } /// /// Gets the time as a TimeSpan (for monotonic clocks, represents time since boot). /// /// TimeSpan representing the clock time public TimeSpan GetTimeSpan() { var tp = new LinuxNative.timespec(); int result = LinuxNative.clock_gettime((int)_clockType, ref tp); if (result != 0) { LinuxNative.ThrowLastError("clock_gettime"); } return TimeSpan.FromSeconds(tp.tv_sec) + TimeSpan.FromTicks(tp.tv_nsec / 100); } /// /// Gets the resolution of the clock. /// /// Clock resolution public TimeSpan GetResolution() { var res = new LinuxNative.timespec(); int result = LinuxNative.clock_getres((int)_clockType, ref res); if (result != 0) { LinuxNative.ThrowLastError("clock_getres"); } return TimeSpan.FromSeconds(res.tv_sec) + TimeSpan.FromTicks(res.tv_nsec / 100); } /// /// Sets the clock time (only for CLOCK_REALTIME). /// /// Time to set public void SetTime(DateTime time) { if (_clockType != RealtimeClockType.Realtime) { throw new InvalidOperationException("Only CLOCK_REALTIME can be set"); } var tp = new LinuxNative.timespec { tv_sec = ((DateTimeOffset)time.ToUniversalTime()).ToUnixTimeSeconds(), tv_nsec = (time.Millisecond % 1000) * 1000000 }; int result = LinuxNative.clock_settime((int)_clockType, ref tp); if (result != 0) { LinuxNative.ThrowLastError("clock_settime"); } } } /// /// Linux clock types. /// public enum RealtimeClockType { /// /// System-wide real-time clock (wall clock time). /// Can be set by root. /// Realtime = LinuxNative.CLOCK_REALTIME, /// /// Monotonic clock that cannot be set and represents monotonic time since some unspecified starting point. /// Best for measuring elapsed time. /// Monotonic = LinuxNative.CLOCK_MONOTONIC, /// /// Monotonic raw clock (not subject to NTP adjustments). /// MonotonicRaw = LinuxNative.CLOCK_MONOTONIC_RAW, /// /// Clock that measures CPU time consumed by the calling process. /// ProcessCpuTime = LinuxNative.CLOCK_PROCESS_CPUTIME_ID, /// /// Clock that measures CPU time consumed by the calling thread. /// ThreadCpuTime = LinuxNative.CLOCK_THREAD_CPUTIME_ID, /// /// Boot time clock (monotonic clock that includes time spent in suspend). /// BootTime = LinuxNative.CLOCK_BOOTTIME, }