Files
Denso/srcs/RobotNet10/Commons/RobotNet10.Realtime/RealtimeClock.cs
2026-07-03 16:31:37 +07:00

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