aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Ryujinx.HLE/HOS/Horizon.cs2
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs47
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/Clock/EphemeralNetworkSystemClockCore.cs27
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/Clock/StandardLocalSystemClockCore.cs42
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs42
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs107
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs15
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs113
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockCore.cs30
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/Clock/TickBasedSteadyClockCore.cs40
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/IStaticService.cs211
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs16
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs1
13 files changed, 503 insertions, 190 deletions
diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs
index 01b87b42..f8bb345f 100644
--- a/Ryujinx.HLE/HOS/Horizon.cs
+++ b/Ryujinx.HLE/HOS/Horizon.cs
@@ -199,7 +199,7 @@ namespace Ryujinx.HLE.HOS
// TODO: use set:sys (and set external clock source id from settings)
// TODO: use "time!standard_steady_clock_rtc_update_interval_minutes" and implement a worker thread to be accurate.
- SteadyClockCore.Instance.ConfigureSetupValue();
+ StandardSteadyClockCore.Instance.ConfigureSetupValue();
if (Services.Set.NxSettings.Settings.TryGetValue("time!standard_network_clock_sufficient_accuracy_minutes", out object standardNetworkClockSufficientAccuracyMinutes))
{
diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs
index 860f5ad2..c70819c0 100644
--- a/Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs
@@ -7,6 +7,8 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
[StructLayout(LayoutKind.Sequential)]
struct TimeSpanType
{
+ private const long NanoSecondsPerSecond = 1000000000;
+
public long NanoSeconds;
public TimeSpanType(long nanoSeconds)
@@ -16,12 +18,17 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
public long ToSeconds()
{
- return NanoSeconds / 1000000000;
+ return NanoSeconds / NanoSecondsPerSecond;
+ }
+
+ public static TimeSpanType FromSeconds(long seconds)
+ {
+ return new TimeSpanType(seconds * NanoSecondsPerSecond);
}
public static TimeSpanType FromTicks(ulong ticks, ulong frequency)
{
- return new TimeSpanType((long)ticks * 1000000000 / (long)frequency);
+ return FromSeconds((long)ticks / (long)frequency);
}
}
@@ -59,4 +66,40 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
public long Offset;
public SteadyClockTimePoint SteadyTimePoint;
}
+
+ [StructLayout(LayoutKind.Sequential, Size = 0xD0)]
+ struct ClockSnapshot
+ {
+ public SystemClockContext UserContext;
+ public SystemClockContext NetworkContext;
+ public long UserTime;
+ public long NetworkTime;
+ public CalendarTime UserCalendarTime;
+ public CalendarTime NetworkCalendarTime;
+ public CalendarAdditionalInfo UserCalendarAdditionalTime;
+ public CalendarAdditionalInfo NetworkCalendarAdditionalTime;
+ public SteadyClockTimePoint SteadyClockTimePoint;
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x24)]
+ public char[] LocationName;
+
+ [MarshalAs(UnmanagedType.I1)]
+ public bool IsAutomaticCorrectionEnabled;
+ public byte Type;
+ public ushort Unknown;
+
+ public static ResultCode GetCurrentTime(out long currentTime, SteadyClockTimePoint steadyClockTimePoint, SystemClockContext context)
+ {
+ currentTime = 0;
+
+ if (steadyClockTimePoint.ClockSourceId == context.SteadyTimePoint.ClockSourceId)
+ {
+ currentTime = steadyClockTimePoint.TimePoint + context.Offset;
+
+ return ResultCode.Success;
+ }
+
+ return ResultCode.TimeMismatch;
+ }
+ }
}
diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/EphemeralNetworkSystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/EphemeralNetworkSystemClockCore.cs
new file mode 100644
index 00000000..8e9073a4
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Time/Clock/EphemeralNetworkSystemClockCore.cs
@@ -0,0 +1,27 @@
+namespace Ryujinx.HLE.HOS.Services.Time.Clock
+{
+ class EphemeralNetworkSystemClockCore : SystemClockCore
+ {
+ private static EphemeralNetworkSystemClockCore _instance;
+
+ public static EphemeralNetworkSystemClockCore Instance
+ {
+ get
+ {
+ if (_instance == null)
+ {
+ _instance = new EphemeralNetworkSystemClockCore(TickBasedSteadyClockCore.Instance);
+ }
+
+ return _instance;
+ }
+ }
+
+ public EphemeralNetworkSystemClockCore(SteadyClockCore steadyClockCore) : base(steadyClockCore) { }
+
+ public override ResultCode Flush(SystemClockContext context)
+ {
+ return ResultCode.Success;
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardLocalSystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardLocalSystemClockCore.cs
index 16550199..a1727976 100644
--- a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardLocalSystemClockCore.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardLocalSystemClockCore.cs
@@ -1,34 +1,23 @@
-using Ryujinx.HLE.HOS.Kernel.Threading;
-
-namespace Ryujinx.HLE.HOS.Services.Time.Clock
+namespace Ryujinx.HLE.HOS.Services.Time.Clock
{
class StandardLocalSystemClockCore : SystemClockCore
{
- private SteadyClockCore _steadyClockCore;
- private SystemClockContext _context;
-
- private static StandardLocalSystemClockCore instance;
+ private static StandardLocalSystemClockCore _instance;
public static StandardLocalSystemClockCore Instance
{
get
{
- if (instance == null)
+ if (_instance == null)
{
- instance = new StandardLocalSystemClockCore(SteadyClockCore.Instance);
+ _instance = new StandardLocalSystemClockCore(StandardSteadyClockCore.Instance);
}
- return instance;
+ return _instance;
}
}
- public StandardLocalSystemClockCore(SteadyClockCore steadyClockCore)
- {
- _steadyClockCore = steadyClockCore;
- _context = new SystemClockContext();
-
- _context.SteadyTimePoint.ClockSourceId = steadyClockCore.GetClockSourceId();
- }
+ public StandardLocalSystemClockCore(StandardSteadyClockCore steadyClockCore) : base(steadyClockCore) {}
public override ResultCode Flush(SystemClockContext context)
{
@@ -36,24 +25,5 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
return ResultCode.Success;
}
-
- public override SteadyClockCore GetSteadyClockCore()
- {
- return _steadyClockCore;
- }
-
- public override ResultCode GetSystemClockContext(KThread thread, out SystemClockContext context)
- {
- context = _context;
-
- return ResultCode.Success;
- }
-
- public override ResultCode SetSystemClockContext(SystemClockContext context)
- {
- _context = context;
-
- return ResultCode.Success;
- }
}
}
diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs
index c00f460e..5037fb60 100644
--- a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs
@@ -1,35 +1,28 @@
-using System;
-using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.HLE.HOS.Kernel.Threading;
namespace Ryujinx.HLE.HOS.Services.Time.Clock
{
class StandardNetworkSystemClockCore : SystemClockCore
{
- private SteadyClockCore _steadyClockCore;
- private SystemClockContext _context;
private TimeSpanType _standardNetworkClockSufficientAccuracy;
- private static StandardNetworkSystemClockCore instance;
+ private static StandardNetworkSystemClockCore _instance;
public static StandardNetworkSystemClockCore Instance
{
get
{
- if (instance == null)
+ if (_instance == null)
{
- instance = new StandardNetworkSystemClockCore(SteadyClockCore.Instance);
+ _instance = new StandardNetworkSystemClockCore(StandardSteadyClockCore.Instance);
}
- return instance;
+ return _instance;
}
}
- public StandardNetworkSystemClockCore(SteadyClockCore steadyClockCore)
+ public StandardNetworkSystemClockCore(StandardSteadyClockCore steadyClockCore) : base(steadyClockCore)
{
- _steadyClockCore = steadyClockCore;
- _context = new SystemClockContext();
-
- _context.SteadyTimePoint.ClockSourceId = steadyClockCore.GetClockSourceId();
_standardNetworkClockSufficientAccuracy = new TimeSpanType(0);
}
@@ -40,25 +33,6 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
return ResultCode.Success;
}
- public override SteadyClockCore GetSteadyClockCore()
- {
- return _steadyClockCore;
- }
-
- public override ResultCode GetSystemClockContext(KThread thread, out SystemClockContext context)
- {
- context = _context;
-
- return ResultCode.Success;
- }
-
- public override ResultCode SetSystemClockContext(SystemClockContext context)
- {
- _context = context;
-
- return ResultCode.Success;
- }
-
public bool IsStandardNetworkSystemClockAccuracySufficient(KThread thread)
{
SteadyClockCore steadyClockCore = GetSteadyClockCore();
@@ -66,7 +40,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
bool isStandardNetworkClockSufficientAccuracy = false;
- if (_context.SteadyTimePoint.GetSpanBetween(currentTimePoint, out long outSpan) == ResultCode.Success)
+ ResultCode result = GetSystemClockContext(thread, out SystemClockContext context);
+
+ if (result == ResultCode.Success && context.SteadyTimePoint.GetSpanBetween(currentTimePoint, out long outSpan) == ResultCode.Success)
{
isStandardNetworkClockSufficientAccuracy = outSpan * 1000000000 < _standardNetworkClockSufficientAccuracy.NanoSeconds;
}
diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs
new file mode 100644
index 00000000..fea5bf2f
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs
@@ -0,0 +1,107 @@
+using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.HLE.HOS.Services.Bpc;
+
+namespace Ryujinx.HLE.HOS.Services.Time.Clock
+{
+ class StandardSteadyClockCore : SteadyClockCore
+ {
+ private long _setupValue;
+ private ResultCode _setupResultCode;
+ private bool _isRtcResetDetected;
+ private TimeSpanType _testOffset;
+ private TimeSpanType _internalOffset;
+
+ private static StandardSteadyClockCore _instance;
+
+ public static StandardSteadyClockCore Instance
+ {
+ get
+ {
+ if (_instance == null)
+ {
+ _instance = new StandardSteadyClockCore();
+ }
+
+ return _instance;
+ }
+ }
+
+ private StandardSteadyClockCore()
+ {
+ _testOffset = new TimeSpanType(0);
+ _internalOffset = new TimeSpanType(0);
+ }
+
+ public override SteadyClockTimePoint GetTimePoint(KThread thread)
+ {
+ SteadyClockTimePoint result = new SteadyClockTimePoint
+ {
+ TimePoint = 0,
+ ClockSourceId = GetClockSourceId()
+ };
+
+ TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.ThreadState.CntpctEl0, thread.Context.ThreadState.CntfrqEl0);
+
+ result.TimePoint = _setupValue + ticksTimeSpan.ToSeconds();
+
+ return result;
+ }
+
+ public override TimeSpanType GetTestOffset()
+ {
+ return _testOffset;
+ }
+
+ public override void SetTestOffset(TimeSpanType testOffset)
+ {
+ _testOffset = testOffset;
+ }
+
+ public override ResultCode GetRtcValue(out ulong rtcValue)
+ {
+ return (ResultCode)IRtcManager.GetExternalRtcValue(out rtcValue);
+ }
+
+ public bool IsRtcResetDetected()
+ {
+ return _isRtcResetDetected;
+ }
+
+ public override TimeSpanType GetInternalOffset()
+ {
+ return _internalOffset;
+ }
+
+ public override void SetInternalOffset(TimeSpanType internalOffset)
+ {
+ _internalOffset = internalOffset;
+ }
+
+ public override ResultCode GetSetupResultValue()
+ {
+ return _setupResultCode;
+ }
+
+ public void ConfigureSetupValue()
+ {
+ int retry = 0;
+
+ ResultCode result = ResultCode.Success;
+
+ while (retry < 20)
+ {
+ result = (ResultCode)IRtcManager.GetExternalRtcValue(out ulong rtcValue);
+
+ if (result == ResultCode.Success)
+ {
+ _setupValue = (long)rtcValue;
+ break;
+ }
+
+ retry++;
+ }
+
+ _setupResultCode = result;
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs
index 00f296ad..c98b0064 100644
--- a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs
@@ -8,22 +8,22 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
private StandardNetworkSystemClockCore _networkSystemClockCore;
private bool _autoCorrectionEnabled;
- private static StandardUserSystemClockCore instance;
+ private static StandardUserSystemClockCore _instance;
public static StandardUserSystemClockCore Instance
{
get
{
- if (instance == null)
+ if (_instance == null)
{
- instance = new StandardUserSystemClockCore(StandardLocalSystemClockCore.Instance, StandardNetworkSystemClockCore.Instance);
+ _instance = new StandardUserSystemClockCore(StandardLocalSystemClockCore.Instance, StandardNetworkSystemClockCore.Instance);
}
- return instance;
+ return _instance;
}
}
- public StandardUserSystemClockCore(StandardLocalSystemClockCore localSystemClockCore, StandardNetworkSystemClockCore networkSystemClockCore)
+ public StandardUserSystemClockCore(StandardLocalSystemClockCore localSystemClockCore, StandardNetworkSystemClockCore networkSystemClockCore) : base(localSystemClockCore.GetSteadyClockCore())
{
_localSystemClockCore = localSystemClockCore;
_networkSystemClockCore = networkSystemClockCore;
@@ -35,11 +35,6 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
return ResultCode.NotImplemented;
}
- public override SteadyClockCore GetSteadyClockCore()
- {
- return _localSystemClockCore.GetSteadyClockCore();
- }
-
public override ResultCode GetSystemClockContext(KThread thread, out SystemClockContext context)
{
ResultCode result = ApplyAutomaticCorrection(thread, false);
diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs
index e661ab53..54d9accf 100644
--- a/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs
@@ -1,54 +1,16 @@
using Ryujinx.HLE.HOS.Kernel.Threading;
-using Ryujinx.HLE.HOS.Services.Bpc;
using Ryujinx.HLE.Utilities;
using System;
namespace Ryujinx.HLE.HOS.Services.Time.Clock
{
- class SteadyClockCore
+ abstract class SteadyClockCore
{
- private long _setupValue;
- private ResultCode _setupResultCode;
- private bool _isRtcResetDetected;
- private TimeSpanType _testOffset;
- private TimeSpanType _internalOffset;
- private UInt128 _clockSourceId;
+ private UInt128 _clockSourceId;
- private static SteadyClockCore instance;
-
- public static SteadyClockCore Instance
- {
- get
- {
- if (instance == null)
- {
- instance = new SteadyClockCore();
- }
-
- return instance;
- }
- }
-
- private SteadyClockCore()
- {
- _testOffset = new TimeSpanType(0);
- _internalOffset = new TimeSpanType(0);
- _clockSourceId = new UInt128(Guid.NewGuid().ToByteArray());
- }
-
- private SteadyClockTimePoint GetTimePoint(KThread thread)
+ public SteadyClockCore()
{
- SteadyClockTimePoint result = new SteadyClockTimePoint
- {
- TimePoint = 0,
- ClockSourceId = _clockSourceId
- };
-
- TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.ThreadState.CntpctEl0, thread.Context.ThreadState.CntfrqEl0);
-
- result.TimePoint = _setupValue + ticksTimeSpan.ToSeconds();
-
- return result;
+ _clockSourceId = new UInt128(Guid.NewGuid().ToByteArray());
}
public UInt128 GetClockSourceId()
@@ -56,76 +18,45 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
return _clockSourceId;
}
- public SteadyClockTimePoint GetCurrentTimePoint(KThread thread)
- {
- SteadyClockTimePoint result = GetTimePoint(thread);
-
- result.TimePoint += _testOffset.ToSeconds();
- result.TimePoint += _internalOffset.ToSeconds();
-
- return result;
- }
-
- public TimeSpanType GetTestOffset()
+ public virtual TimeSpanType GetTestOffset()
{
- return _testOffset;
+ return new TimeSpanType(0);
}
- public void SetTestOffset(TimeSpanType testOffset)
- {
- _testOffset = testOffset;
- }
+ public virtual void SetTestOffset(TimeSpanType testOffset) {}
- public ResultCode GetRtcValue(out ulong rtcValue)
+ public virtual ResultCode GetRtcValue(out ulong rtcValue)
{
- return (ResultCode)IRtcManager.GetExternalRtcValue(out rtcValue);
- }
+ rtcValue = 0;
- public bool IsRtcResetDetected()
- {
- return _isRtcResetDetected;
+ return ResultCode.NotImplemented;
}
- public ResultCode GetSetupResultCode()
+ public virtual ResultCode GetSetupResultValue()
{
- return _setupResultCode;
+ return ResultCode.NotImplemented;
}
- public TimeSpanType GetInternalOffset()
+ public virtual TimeSpanType GetInternalOffset()
{
- return _internalOffset;
+ return new TimeSpanType(0);
}
- public void SetInternalOffset(TimeSpanType internalOffset)
- {
- _internalOffset = internalOffset;
- }
+ public virtual void SetInternalOffset(TimeSpanType internalOffset) {}
- public ResultCode GetSetupResultValue()
+ public virtual SteadyClockTimePoint GetTimePoint(KThread thread)
{
- return _setupResultCode;
+ throw new NotImplementedException();
}
- public void ConfigureSetupValue()
+ public SteadyClockTimePoint GetCurrentTimePoint(KThread thread)
{
- int retry = 0;
-
- ResultCode result = ResultCode.Success;
-
- while (retry < 20)
- {
- result = (ResultCode)IRtcManager.GetExternalRtcValue(out ulong rtcValue);
-
- if (result == ResultCode.Success)
- {
- _setupValue = (long)rtcValue;
- break;
- }
+ SteadyClockTimePoint result = GetTimePoint(thread);
- retry++;
- }
+ result.TimePoint += GetTestOffset().ToSeconds();
+ result.TimePoint += GetInternalOffset().ToSeconds();
- _setupResultCode = result;
+ return result;
}
}
}
diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockCore.cs
index d3a056e4..52f3c908 100644
--- a/Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockCore.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockCore.cs
@@ -4,11 +4,35 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
{
abstract class SystemClockCore
{
- public abstract SteadyClockCore GetSteadyClockCore();
+ private SteadyClockCore _steadyClockCore;
+ private SystemClockContext _context;
- public abstract ResultCode GetSystemClockContext(KThread thread, out SystemClockContext context);
+ public SystemClockCore(SteadyClockCore steadyClockCore)
+ {
+ _steadyClockCore = steadyClockCore;
+ _context = new SystemClockContext();
+
+ _context.SteadyTimePoint.ClockSourceId = steadyClockCore.GetClockSourceId();
+ }
- public abstract ResultCode SetSystemClockContext(SystemClockContext context);
+ public virtual SteadyClockCore GetSteadyClockCore()
+ {
+ return _steadyClockCore;
+ }
+
+ public virtual ResultCode GetSystemClockContext(KThread thread, out SystemClockContext context)
+ {
+ context = _context;
+
+ return ResultCode.Success;
+ }
+
+ public virtual ResultCode SetSystemClockContext(SystemClockContext context)
+ {
+ _context = context;
+
+ return ResultCode.Success;
+ }
public abstract ResultCode Flush(SystemClockContext context);
diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/TickBasedSteadyClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/TickBasedSteadyClockCore.cs
new file mode 100644
index 00000000..7a69b014
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Time/Clock/TickBasedSteadyClockCore.cs
@@ -0,0 +1,40 @@
+using Ryujinx.Common;
+using Ryujinx.HLE.HOS.Kernel.Threading;
+
+namespace Ryujinx.HLE.HOS.Services.Time.Clock
+{
+ class TickBasedSteadyClockCore : SteadyClockCore
+ {
+ private static TickBasedSteadyClockCore _instance;
+
+ public static TickBasedSteadyClockCore Instance
+ {
+ get
+ {
+ if (_instance == null)
+ {
+ _instance = new TickBasedSteadyClockCore();
+ }
+
+ return _instance;
+ }
+ }
+
+ private TickBasedSteadyClockCore() {}
+
+ public override SteadyClockTimePoint GetTimePoint(KThread thread)
+ {
+ SteadyClockTimePoint result = new SteadyClockTimePoint
+ {
+ TimePoint = 0,
+ ClockSourceId = GetClockSourceId()
+ };
+
+ TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.ThreadState.CntpctEl0, thread.Context.ThreadState.CntfrqEl0);
+
+ result.TimePoint = ticksTimeSpan.ToSeconds();
+
+ return result;
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs b/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs
index 8c5ae65c..9ee038d5 100644
--- a/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs
@@ -1,7 +1,13 @@
+using Ryujinx.Common;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel.Common;
+using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Time.Clock;
+using Ryujinx.HLE.HOS.Services.Time.TimeZone;
using System;
+using System.Diagnostics;
+using System.IO;
+using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Time
{
@@ -66,6 +72,15 @@ namespace Ryujinx.HLE.HOS.Services.Time
return ResultCode.Success;
}
+ [Command(5)] // 4.0.0+
+ // GetEphemeralNetworkSystemClock() -> object<nn::timesrv::detail::service::ISystemClock>
+ public ResultCode GetEphemeralNetworkSystemClock(ServiceCtx context)
+ {
+ MakeObject(context, new ISystemClock(StandardNetworkSystemClockCore.Instance, false));
+
+ return ResultCode.Success;
+ }
+
[Command(20)] // 6.0.0+
// GetSharedMemoryNativeHandle() -> handle<copy>
public ResultCode GetSharedMemoryNativeHandle(ServiceCtx context)
@@ -116,16 +131,202 @@ namespace Ryujinx.HLE.HOS.Services.Time
}
[Command(300)] // 4.0.0+
- // CalculateMonotonicSystemClockBaseTimePoint(nn::time::SystemClockContext) -> u64
+ // CalculateMonotonicSystemClockBaseTimePoint(nn::time::SystemClockContext) -> s64
public ResultCode CalculateMonotonicSystemClockBaseTimePoint(ServiceCtx context)
{
- // TODO: reimplement this
- long timeOffset = (long)(DateTime.UtcNow - StartupDate).TotalSeconds;
- long systemClockContextEpoch = context.RequestData.ReadInt64();
+ SystemClockContext otherContext = context.RequestData.ReadStruct<SystemClockContext>();
+ SteadyClockTimePoint currentTimePoint = StandardSteadyClockCore.Instance.GetCurrentTimePoint(context.Thread);
+
+ ResultCode result = ResultCode.TimeMismatch;
+
+ if (currentTimePoint.ClockSourceId == otherContext.SteadyTimePoint.ClockSourceId)
+ {
+ TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(context.Thread.Context.ThreadState.CntpctEl0, context.Thread.Context.ThreadState.CntfrqEl0);
+ long baseTimePoint = otherContext.Offset + currentTimePoint.TimePoint - ticksTimeSpan.ToSeconds();
+
+ context.ResponseData.Write(baseTimePoint);
+
+ result = 0;
+ }
+
+ return result;
+ }
+
+ [Command(400)] // 4.0.0+
+ // GetClockSnapshot(u8) -> buffer<nn::time::sf::ClockSnapshot, 0x1a>
+ public ResultCode GetClockSnapshot(ServiceCtx context)
+ {
+ byte type = context.RequestData.ReadByte();
+
+ ResultCode result = StandardUserSystemClockCore.Instance.GetSystemClockContext(context.Thread, out SystemClockContext userContext);
+
+ if (result == ResultCode.Success)
+ {
+ result = StandardNetworkSystemClockCore.Instance.GetSystemClockContext(context.Thread, out SystemClockContext networkContext);
+
+ if (result == ResultCode.Success)
+ {
+ result = GetClockSnapshotFromSystemClockContextInternal(context.Thread, userContext, networkContext, type, out ClockSnapshot clockSnapshot);
+
+ if (result == ResultCode.Success)
+ {
+ WriteClockSnapshotFromBuffer(context, context.Request.RecvListBuff[0], clockSnapshot);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ [Command(401)] // 4.0.0+
+ // GetClockSnapshotFromSystemClockContext(u8, nn::time::SystemClockContext, nn::time::SystemClockContext) -> buffer<nn::time::sf::ClockSnapshot, 0x1a>
+ public ResultCode GetClockSnapshotFromSystemClockContext(ServiceCtx context)
+ {
+ byte type = context.RequestData.ReadByte();
+
+ context.RequestData.BaseStream.Position += 7;
+
+ SystemClockContext userContext = context.RequestData.ReadStruct<SystemClockContext>();
+ SystemClockContext networkContext = context.RequestData.ReadStruct<SystemClockContext>();
- context.ResponseData.Write(timeOffset + systemClockContextEpoch);
+ ResultCode result = GetClockSnapshotFromSystemClockContextInternal(context.Thread, userContext, networkContext, type, out ClockSnapshot clockSnapshot);
+
+ if (result == ResultCode.Success)
+ {
+ WriteClockSnapshotFromBuffer(context, context.Request.RecvListBuff[0], clockSnapshot);
+ }
+
+ return result;
+ }
+
+ [Command(500)] // 4.0.0+
+ // CalculateStandardUserSystemClockDifferenceByUser(buffer<nn::time::sf::ClockSnapshot, 0x19>, buffer<nn::time::sf::ClockSnapshot, 0x19>) -> nn::TimeSpanType
+ public ResultCode CalculateStandardUserSystemClockDifferenceByUser(ServiceCtx context)
+ {
+
+ ClockSnapshot clockSnapshotA = ReadClockSnapshotFromBuffer(context, context.Request.ExchangeBuff[0]);
+ ClockSnapshot clockSnapshotB = ReadClockSnapshotFromBuffer(context, context.Request.ExchangeBuff[1]);
+ TimeSpanType difference = TimeSpanType.FromSeconds(clockSnapshotB.UserContext.Offset - clockSnapshotA.UserContext.Offset);
+
+ if (clockSnapshotB.UserContext.SteadyTimePoint.ClockSourceId != clockSnapshotA.UserContext.SteadyTimePoint.ClockSourceId || (clockSnapshotB.IsAutomaticCorrectionEnabled && clockSnapshotA.IsAutomaticCorrectionEnabled))
+ {
+ difference = new TimeSpanType(0);
+ }
+
+ context.ResponseData.Write(difference.NanoSeconds);
return ResultCode.Success;
}
+
+ [Command(501)] // 4.0.0+
+ // CalculateSpanBetween(buffer<nn::time::sf::ClockSnapshot, 0x19>, buffer<nn::time::sf::ClockSnapshot, 0x19>) -> nn::TimeSpanType
+ public ResultCode CalculateSpanBetween(ServiceCtx context)
+ {
+ ClockSnapshot clockSnapshotA = ReadClockSnapshotFromBuffer(context, context.Request.ExchangeBuff[0]);
+ ClockSnapshot clockSnapshotB = ReadClockSnapshotFromBuffer(context, context.Request.ExchangeBuff[1]);
+
+ TimeSpanType result;
+
+ ResultCode resultCode = clockSnapshotA.SteadyClockTimePoint.GetSpanBetween(clockSnapshotB.SteadyClockTimePoint, out long timeSpan);
+
+ if (resultCode != ResultCode.Success)
+ {
+ resultCode = ResultCode.TimeNotFound;
+
+ if (clockSnapshotA.NetworkTime != 0 && clockSnapshotB.NetworkTime != 0)
+ {
+ result = TimeSpanType.FromSeconds(clockSnapshotB.NetworkTime - clockSnapshotA.NetworkTime);
+ resultCode = ResultCode.Success;
+ }
+ else
+ {
+ return resultCode;
+ }
+ }
+ else
+ {
+ result = TimeSpanType.FromSeconds(timeSpan);
+ }
+
+ context.ResponseData.Write(result.NanoSeconds);
+
+ return resultCode;
+ }
+
+ private ResultCode GetClockSnapshotFromSystemClockContextInternal(KThread thread, SystemClockContext userContext, SystemClockContext networkContext, byte type, out ClockSnapshot clockSnapshot)
+ {
+ clockSnapshot = new ClockSnapshot();
+
+ SteadyClockCore steadyClockCore = StandardSteadyClockCore.Instance;
+ SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(thread);
+
+ clockSnapshot.IsAutomaticCorrectionEnabled = StandardUserSystemClockCore.Instance.IsAutomaticCorrectionEnabled();
+ clockSnapshot.UserContext = userContext;
+ clockSnapshot.NetworkContext = networkContext;
+
+ char[] tzName = TimeZoneManager.Instance.GetDeviceLocationName().ToCharArray();
+ char[] locationName = new char[0x24];
+
+ Array.Copy(tzName, locationName, tzName.Length);
+
+ clockSnapshot.LocationName = locationName;
+
+ ResultCode result = ClockSnapshot.GetCurrentTime(out clockSnapshot.UserTime, currentTimePoint, clockSnapshot.UserContext);
+
+ if (result == ResultCode.Success)
+ {
+ result = TimeZoneManager.Instance.ToCalendarTimeWithMyRules(clockSnapshot.UserTime, out CalendarInfo userCalendarInfo);
+
+ if (result == ResultCode.Success)
+ {
+ clockSnapshot.UserCalendarTime = userCalendarInfo.Time;
+ clockSnapshot.UserCalendarAdditionalTime = userCalendarInfo.AdditionalInfo;
+
+ if (ClockSnapshot.GetCurrentTime(out clockSnapshot.NetworkTime, currentTimePoint, clockSnapshot.NetworkContext) != ResultCode.Success)
+ {
+ clockSnapshot.NetworkTime = 0;
+ }
+
+ result = TimeZoneManager.Instance.ToCalendarTimeWithMyRules(clockSnapshot.NetworkTime, out CalendarInfo networkCalendarInfo);
+
+ if (result == ResultCode.Success)
+ {
+ clockSnapshot.NetworkCalendarTime = networkCalendarInfo.Time;
+ clockSnapshot.NetworkCalendarAdditionalTime = networkCalendarInfo.AdditionalInfo;
+ clockSnapshot.Type = type;
+
+ // Probably a version field?
+ clockSnapshot.Unknown = 0;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private ClockSnapshot ReadClockSnapshotFromBuffer(ServiceCtx context, IpcBuffDesc ipcDesc)
+ {
+ Debug.Assert(ipcDesc.Size == Marshal.SizeOf<ClockSnapshot>());
+
+ using (BinaryReader bufferReader = new BinaryReader(new MemoryStream(context.Memory.ReadBytes(ipcDesc.Position, ipcDesc.Size))))
+ {
+ return bufferReader.ReadStruct<ClockSnapshot>();
+ }
+ }
+
+ private void WriteClockSnapshotFromBuffer(ServiceCtx context, IpcRecvListBuffDesc ipcDesc, ClockSnapshot clockSnapshot)
+ {
+ Debug.Assert(ipcDesc.Size == Marshal.SizeOf<ClockSnapshot>());
+
+ MemoryStream memory = new MemoryStream((int)ipcDesc.Size);
+
+ using (BinaryWriter bufferWriter = new BinaryWriter(memory))
+ {
+ bufferWriter.WriteStruct(clockSnapshot);
+ }
+
+ context.Memory.WriteBytes(ipcDesc.Position, memory.ToArray());
+ memory.Dispose();
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs b/Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs
index 2772b45d..7e3edcef 100644
--- a/Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs
@@ -9,7 +9,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
// GetCurrentTimePoint() -> nn::time::SteadyClockTimePoint
public ResultCode GetCurrentTimePoint(ServiceCtx context)
{
- SteadyClockTimePoint currentTimePoint = SteadyClockCore.Instance.GetCurrentTimePoint(context.Thread);
+ SteadyClockTimePoint currentTimePoint = StandardSteadyClockCore.Instance.GetCurrentTimePoint(context.Thread);
context.ResponseData.WriteStruct(currentTimePoint);
@@ -20,7 +20,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
// GetTestOffset() -> nn::TimeSpanType
public ResultCode GetTestOffset(ServiceCtx context)
{
- context.ResponseData.WriteStruct(SteadyClockCore.Instance.GetTestOffset());
+ context.ResponseData.WriteStruct(StandardSteadyClockCore.Instance.GetTestOffset());
return ResultCode.Success;
}
@@ -31,7 +31,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
{
TimeSpanType testOffset = context.RequestData.ReadStruct<TimeSpanType>();
- SteadyClockCore.Instance.SetTestOffset(testOffset);
+ StandardSteadyClockCore.Instance.SetTestOffset(testOffset);
return 0;
}
@@ -40,7 +40,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
// GetRtcValue() -> u64
public ResultCode GetRtcValue(ServiceCtx context)
{
- ResultCode result = SteadyClockCore.Instance.GetRtcValue(out ulong rtcValue);
+ ResultCode result = StandardSteadyClockCore.Instance.GetRtcValue(out ulong rtcValue);
if (result == ResultCode.Success)
{
@@ -54,7 +54,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
// IsRtcResetDetected() -> bool
public ResultCode IsRtcResetDetected(ServiceCtx context)
{
- context.ResponseData.Write(SteadyClockCore.Instance.IsRtcResetDetected());
+ context.ResponseData.Write(StandardSteadyClockCore.Instance.IsRtcResetDetected());
return ResultCode.Success;
}
@@ -63,7 +63,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
// GetSetupResultValue() -> u32
public ResultCode GetSetupResultValue(ServiceCtx context)
{
- context.ResponseData.Write((uint)SteadyClockCore.Instance.GetSetupResultCode());
+ context.ResponseData.Write((uint)StandardSteadyClockCore.Instance.GetSetupResultValue());
return ResultCode.Success;
}
@@ -72,7 +72,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
// GetInternalOffset() -> nn::TimeSpanType
public ResultCode GetInternalOffset(ServiceCtx context)
{
- context.ResponseData.WriteStruct(SteadyClockCore.Instance.GetInternalOffset());
+ context.ResponseData.WriteStruct(StandardSteadyClockCore.Instance.GetInternalOffset());
return ResultCode.Success;
}
@@ -83,7 +83,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
{
TimeSpanType internalOffset = context.RequestData.ReadStruct<TimeSpanType>();
- SteadyClockCore.Instance.SetInternalOffset(internalOffset);
+ StandardSteadyClockCore.Instance.SetInternalOffset(internalOffset);
return ResultCode.Success;
}
diff --git a/Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs b/Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs
index 74182428..895bb1f3 100644
--- a/Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs
@@ -56,7 +56,6 @@ namespace Ryujinx.HLE.HOS.Services.Time
// LoadLocationNameList(u32 index) -> (u32 outCount, buffer<nn::time::LocationName, 6>)
public ResultCode LoadLocationNameList(ServiceCtx context)
{
- // TODO: fix logic to use index
uint index = context.RequestData.ReadUInt32();
long bufferPosition = context.Request.ReceiveBuff[0].Position;
long bufferSize = context.Request.ReceiveBuff[0].Size;