143 lines
4.2 KiB
C#
143 lines
4.2 KiB
C#
using System;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace RobotNet10.Realtime;
|
|
|
|
/// <summary>
|
|
/// Provides high-resolution clock access for real-time applications.
|
|
/// </summary>
|
|
public class RealtimeClock
|
|
{
|
|
private readonly RealtimeClockType _clockType;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of RealtimeClock.
|
|
/// </summary>
|
|
/// <param name="clockType">Type of clock to use</param>
|
|
public RealtimeClock(RealtimeClockType clockType)
|
|
{
|
|
_clockType = clockType;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the current time from the clock.
|
|
/// </summary>
|
|
/// <returns>Current time</returns>
|
|
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
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the time as a TimeSpan (for monotonic clocks, represents time since boot).
|
|
/// </summary>
|
|
/// <returns>TimeSpan representing the clock time</returns>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the resolution of the clock.
|
|
/// </summary>
|
|
/// <returns>Clock resolution</returns>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the clock time (only for CLOCK_REALTIME).
|
|
/// </summary>
|
|
/// <param name="time">Time to set</param>
|
|
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");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Linux clock types.
|
|
/// </summary>
|
|
public enum RealtimeClockType
|
|
{
|
|
/// <summary>
|
|
/// System-wide real-time clock (wall clock time).
|
|
/// Can be set by root.
|
|
/// </summary>
|
|
Realtime = LinuxNative.CLOCK_REALTIME,
|
|
|
|
/// <summary>
|
|
/// Monotonic clock that cannot be set and represents monotonic time since some unspecified starting point.
|
|
/// Best for measuring elapsed time.
|
|
/// </summary>
|
|
Monotonic = LinuxNative.CLOCK_MONOTONIC,
|
|
|
|
/// <summary>
|
|
/// Monotonic raw clock (not subject to NTP adjustments).
|
|
/// </summary>
|
|
MonotonicRaw = LinuxNative.CLOCK_MONOTONIC_RAW,
|
|
|
|
/// <summary>
|
|
/// Clock that measures CPU time consumed by the calling process.
|
|
/// </summary>
|
|
ProcessCpuTime = LinuxNative.CLOCK_PROCESS_CPUTIME_ID,
|
|
|
|
/// <summary>
|
|
/// Clock that measures CPU time consumed by the calling thread.
|
|
/// </summary>
|
|
ThreadCpuTime = LinuxNative.CLOCK_THREAD_CPUTIME_ID,
|
|
|
|
/// <summary>
|
|
/// Boot time clock (monotonic clock that includes time spent in suspend).
|
|
/// </summary>
|
|
BootTime = LinuxNative.CLOCK_BOOTTIME,
|
|
}
|
|
|