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,
}