From 410e401e64b046fde9e9dbfde3ac655f47b0c3be Mon Sep 17 00:00:00 2001 From: Thog Date: Mon, 15 Jul 2019 18:01:04 +0200 Subject: [PATCH] Implement IsStandardNetworkSystemClockAccuracySufficient Also use signed values for offsets and TimeSpanType --- Ryujinx.HLE/HOS/Horizon.cs | 7 ++++ .../HOS/Services/Time/Clock/ClockTypes.cs | 34 +++++++++++++++---- .../Clock/StandardNetworkSystemClockCore.cs | 26 +++++++++++++- .../Services/Time/Clock/SteadyClockCore.cs | 4 +-- .../HOS/Services/Time/IStaticService.cs | 9 +++++ Ryujinx.HLE/HOS/Services/Time/ISystemClock.cs | 4 +-- 6 files changed, 73 insertions(+), 11 deletions(-) diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs index d81ea6f5e2..01b87b425d 100644 --- a/Ryujinx.HLE/HOS/Horizon.cs +++ b/Ryujinx.HLE/HOS/Horizon.cs @@ -201,6 +201,13 @@ namespace Ryujinx.HLE.HOS // TODO: use "time!standard_steady_clock_rtc_update_interval_minutes" and implement a worker thread to be accurate. SteadyClockCore.Instance.ConfigureSetupValue(); + if (Services.Set.NxSettings.Settings.TryGetValue("time!standard_network_clock_sufficient_accuracy_minutes", out object standardNetworkClockSufficientAccuracyMinutes)) + { + TimeSpanType standardNetworkClockSufficientAccuracy = new TimeSpanType((int)standardNetworkClockSufficientAccuracyMinutes * 60000000000); + + StandardNetworkSystemClockCore.Instance.SetStandardNetworkClockSufficientAccuracy(standardNetworkClockSufficientAccuracy); + } + } public void LoadCart(string exeFsDir, string romFsFile = null) diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs index 1e527c002e..3354cce5a9 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs @@ -1,4 +1,5 @@ using Ryujinx.HLE.Utilities; +using System; using System.Runtime.InteropServices; namespace Ryujinx.HLE.HOS.Services.Time.Clock @@ -6,35 +7,56 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock [StructLayout(LayoutKind.Sequential)] struct TimeSpanType { - public ulong NanoSeconds; + public long NanoSeconds; - public TimeSpanType(ulong nanoSeconds) + public TimeSpanType(long nanoSeconds) { NanoSeconds = nanoSeconds; } - public ulong ToSeconds() + public long ToSeconds() { return NanoSeconds / 1000000000; } public static TimeSpanType FromTicks(ulong ticks, ulong frequency) { - return new TimeSpanType(ticks * 1000000000 / frequency); + return new TimeSpanType((long)ticks * 1000000000 / (long)frequency); } } [StructLayout(LayoutKind.Sequential)] struct SteadyClockTimePoint { - public ulong TimePoint; + public long TimePoint; public UInt128 ClockSourceId; + + public ResultCode GetSpanBetween(SteadyClockTimePoint other, out long outSpan) + { + outSpan = 0; + + if (ClockSourceId == other.ClockSourceId) + { + try + { + outSpan = checked(other.TimePoint - TimePoint); + + return ResultCode.Success; + } + catch (OverflowException) + { + return ResultCode.Overflow; + } + } + + return ResultCode.Overflow; + } } [StructLayout(LayoutKind.Sequential)] struct SystemClockContext { - public ulong Offset; + public long Offset; public SteadyClockTimePoint SteadyTimePoint; } } diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs index 59bc822ceb..ca5a9bbf31 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs @@ -1,4 +1,5 @@ -using Ryujinx.HLE.HOS.Kernel.Threading; +using System; +using Ryujinx.HLE.HOS.Kernel.Threading; namespace Ryujinx.HLE.HOS.Services.Time.Clock { @@ -6,6 +7,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock { private SteadyClockCore _steadyClockCore; private SystemClockContext _context; + private TimeSpanType _standardNetworkClockSufficientAccuracy; private static StandardNetworkSystemClockCore instance; @@ -28,6 +30,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock _context = new SystemClockContext(); _context.SteadyTimePoint.ClockSourceId = steadyClockCore.GetClockSourceId(); + _standardNetworkClockSufficientAccuracy = new TimeSpanType(0); } public override ResultCode Flush(SystemClockContext context) @@ -55,5 +58,26 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock return ResultCode.Success; } + + public bool IsStandardNetworkSystemClockAccuracySufficient(KThread thread) + { + SteadyClockCore steadyClockCore = GetSteadyClockCore(); + + SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(thread); + + bool isStandardNetworkClockSufficientAccuracy = false; + + if (_context.SteadyTimePoint.GetSpanBetween(currentTimePoint, out long outSpan) == ResultCode.Success) + { + isStandardNetworkClockSufficientAccuracy = outSpan * 1000000000 < _standardNetworkClockSufficientAccuracy.NanoSeconds; + } + + return isStandardNetworkClockSufficientAccuracy; + } + + public void SetStandardNetworkClockSufficientAccuracy(TimeSpanType standardNetworkClockSufficientAccuracy) + { + _standardNetworkClockSufficientAccuracy = standardNetworkClockSufficientAccuracy; + } } } diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs index b16ffb97a5..e661ab5380 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs @@ -7,7 +7,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock { class SteadyClockCore { - private ulong _setupValue; + private long _setupValue; private ResultCode _setupResultCode; private bool _isRtcResetDetected; private TimeSpanType _testOffset; @@ -118,7 +118,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock if (result == ResultCode.Success) { - _setupValue = rtcValue; + _setupValue = (long)rtcValue; break; } diff --git a/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs b/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs index 10c659c5cc..8c5ae65c6c 100644 --- a/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs +++ b/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs @@ -106,6 +106,15 @@ namespace Ryujinx.HLE.HOS.Services.Time return StandardUserSystemClockCore.Instance.SetAutomaticCorrectionEnabled(context.Thread, autoCorrectionEnabled); } + [Command(200)] // 3.0.0+ + // IsStandardNetworkSystemClockAccuracySufficient() -> bool + public ResultCode IsStandardNetworkSystemClockAccuracySufficient(ServiceCtx context) + { + context.ResponseData.Write(StandardNetworkSystemClockCore.Instance.IsStandardNetworkSystemClockAccuracySufficient(context.Thread)); + + return ResultCode.Success; + } + [Command(300)] // 4.0.0+ // CalculateMonotonicSystemClockBaseTimePoint(nn::time::SystemClockContext) -> u64 public ResultCode CalculateMonotonicSystemClockBaseTimePoint(ServiceCtx context) diff --git a/Ryujinx.HLE/HOS/Services/Time/ISystemClock.cs b/Ryujinx.HLE/HOS/Services/Time/ISystemClock.cs index ddd67a4214..d496dcdc39 100644 --- a/Ryujinx.HLE/HOS/Services/Time/ISystemClock.cs +++ b/Ryujinx.HLE/HOS/Services/Time/ISystemClock.cs @@ -29,7 +29,7 @@ namespace Ryujinx.HLE.HOS.Services.Time if (currentTimePoint.ClockSourceId == clockContext.SteadyTimePoint.ClockSourceId) { - ulong posixTime = clockContext.Offset + currentTimePoint.TimePoint; + long posixTime = clockContext.Offset + currentTimePoint.TimePoint; context.ResponseData.Write(posixTime); @@ -49,7 +49,7 @@ namespace Ryujinx.HLE.HOS.Services.Time return ResultCode.PermissionDenied; } - ulong posixTime = context.RequestData.ReadUInt64(); + long posixTime = context.RequestData.ReadInt64(); SteadyClockCore steadyClockCore = _clockCore.GetSteadyClockCore(); SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(context.Thread);