From a0720b5681852f3d786d77bd3793b0359dea321c Mon Sep 17 00:00:00 2001 From: Ac_K Date: Thu, 19 Sep 2019 02:45:11 +0200 Subject: Refactoring HOS folder structure (#771) * Refactoring HOS folder structure Refactoring HOS folder structure: - Added some subfolders when needed (Following structure decided in private). - Added some `Types` folders when needed. - Little cleanup here and there. - Add services placeholders for every HOS services (close #766 and #753). * Remove Types namespaces --- Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs | 105 ---------- .../Time/Clock/StandardNetworkSystemClockCore.cs | 2 +- .../Services/Time/Clock/StandardSteadyClockCore.cs | 2 +- .../Time/Clock/TickBasedSteadyClockCore.cs | 3 +- .../HOS/Services/Time/Clock/Types/ClockSnapshot.cs | 41 ++++ .../Time/Clock/Types/SteadyClockTimePoint.cs | 34 ++++ .../Time/Clock/Types/SystemClockContext.cs | 11 ++ .../HOS/Services/Time/Clock/Types/TimeSpanType.cs | 32 +++ Ryujinx.HLE/HOS/Services/Time/IAlarmService.cs | 8 + .../HOS/Services/Time/IPowerStateRequestHandler.cs | 8 + Ryujinx.HLE/HOS/Services/Time/IStaticService.cs | 2 + Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs | 91 --------- Ryujinx.HLE/HOS/Services/Time/ISystemClock.cs | 107 ---------- .../HOS/Services/Time/ITimeServiceManager.cs | 8 + Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs | 218 --------------------- .../HOS/Services/Time/ITimeZoneServiceTypes.cs | 128 ------------ .../Services/Time/StaticService/ISteadyClock.cs | 91 +++++++++ .../Services/Time/StaticService/ISystemClock.cs | 107 ++++++++++ .../Time/StaticService/ITimeZoneService.cs | 218 +++++++++++++++++++++ Ryujinx.HLE/HOS/Services/Time/TimePermissions.cs | 17 -- Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZone.cs | 12 +- .../HOS/Services/Time/TimeZone/TimeZoneManager.cs | 10 +- .../Time/TimeZone/Types/CalendarAdditionalInfo.cs | 22 +++ .../Services/Time/TimeZone/Types/CalendarInfo.cs | 11 ++ .../Services/Time/TimeZone/Types/CalendarTime.cs | 15 ++ .../Services/Time/TimeZone/Types/TimeTypeInfo.cs | 27 +++ .../Services/Time/TimeZone/Types/TimeZoneRule.cs | 39 ++++ .../HOS/Services/Time/TimeZone/Types/TzifHeader.cs | 34 ++++ .../HOS/Services/Time/Types/TimePermissions.cs | 17 ++ 29 files changed, 739 insertions(+), 681 deletions(-) delete mode 100644 Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/Clock/Types/ClockSnapshot.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/Clock/Types/SteadyClockTimePoint.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/Clock/Types/SystemClockContext.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/Clock/Types/TimeSpanType.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/IAlarmService.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/IPowerStateRequestHandler.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Time/ISystemClock.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Time/ITimeZoneServiceTypes.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/StaticService/ISteadyClock.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/StaticService/ISystemClock.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/StaticService/ITimeZoneService.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Time/TimePermissions.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarAdditionalInfo.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarInfo.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarTime.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeTypeInfo.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeZoneRule.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TzifHeader.cs create mode 100644 Ryujinx.HLE/HOS/Services/Time/Types/TimePermissions.cs (limited to 'Ryujinx.HLE/HOS/Services/Time') diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs deleted file mode 100644 index c70819c0..00000000 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs +++ /dev/null @@ -1,105 +0,0 @@ -using Ryujinx.HLE.Utilities; -using System; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Time.Clock -{ - [StructLayout(LayoutKind.Sequential)] - struct TimeSpanType - { - private const long NanoSecondsPerSecond = 1000000000; - - public long NanoSeconds; - - public TimeSpanType(long nanoSeconds) - { - NanoSeconds = nanoSeconds; - } - - public long ToSeconds() - { - return NanoSeconds / NanoSecondsPerSecond; - } - - public static TimeSpanType FromSeconds(long seconds) - { - return new TimeSpanType(seconds * NanoSecondsPerSecond); - } - - public static TimeSpanType FromTicks(ulong ticks, ulong frequency) - { - return FromSeconds((long)ticks / (long)frequency); - } - } - - [StructLayout(LayoutKind.Sequential)] - struct SteadyClockTimePoint - { - 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 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/StandardNetworkSystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs index 5037fb60..cc21dd9a 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs @@ -4,7 +4,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock { class StandardNetworkSystemClockCore : SystemClockCore { - private TimeSpanType _standardNetworkClockSufficientAccuracy; + private TimeSpanType _standardNetworkClockSufficientAccuracy; private static StandardNetworkSystemClockCore _instance; diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs index 5b2d6c84..1bc5bee7 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs @@ -1,5 +1,5 @@ using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.HLE.HOS.Services.Bpc; +using Ryujinx.HLE.HOS.Services.Pcv.Bpc; namespace Ryujinx.HLE.HOS.Services.Time.Clock { diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/TickBasedSteadyClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/TickBasedSteadyClockCore.cs index 6cd4c80b..e5baba25 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/TickBasedSteadyClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/TickBasedSteadyClockCore.cs @@ -1,5 +1,4 @@ -using Ryujinx.Common; -using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.HLE.HOS.Kernel.Threading; namespace Ryujinx.HLE.HOS.Services.Time.Clock { diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/Types/ClockSnapshot.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/Types/ClockSnapshot.cs new file mode 100644 index 00000000..df1f151f --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/Types/ClockSnapshot.cs @@ -0,0 +1,41 @@ +using Ryujinx.HLE.HOS.Services.Time.TimeZone; +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Time.Clock +{ + [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; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/Types/SteadyClockTimePoint.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/Types/SteadyClockTimePoint.cs new file mode 100644 index 00000000..0055b5ea --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/Types/SteadyClockTimePoint.cs @@ -0,0 +1,34 @@ +using Ryujinx.HLE.Utilities; +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Time.Clock +{ + [StructLayout(LayoutKind.Sequential)] + struct SteadyClockTimePoint + { + 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; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/Types/SystemClockContext.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/Types/SystemClockContext.cs new file mode 100644 index 00000000..38e10480 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/Types/SystemClockContext.cs @@ -0,0 +1,11 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Time.Clock +{ + [StructLayout(LayoutKind.Sequential)] + struct SystemClockContext + { + public long Offset; + public SteadyClockTimePoint SteadyTimePoint; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/Types/TimeSpanType.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/Types/TimeSpanType.cs new file mode 100644 index 00000000..93579709 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/Types/TimeSpanType.cs @@ -0,0 +1,32 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Time.Clock +{ + [StructLayout(LayoutKind.Sequential)] + struct TimeSpanType + { + private const long NanoSecondsPerSecond = 1000000000; + + public long NanoSeconds; + + public TimeSpanType(long nanoSeconds) + { + NanoSeconds = nanoSeconds; + } + + public long ToSeconds() + { + return NanoSeconds / NanoSecondsPerSecond; + } + + public static TimeSpanType FromSeconds(long seconds) + { + return new TimeSpanType(seconds * NanoSecondsPerSecond); + } + + public static TimeSpanType FromTicks(ulong ticks, ulong frequency) + { + return FromSeconds((long)ticks / (long)frequency); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/IAlarmService.cs b/Ryujinx.HLE/HOS/Services/Time/IAlarmService.cs new file mode 100644 index 00000000..092fa8ce --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/IAlarmService.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Time +{ + [Service("time:al")] // 9.0.0+ + class IAlarmService : IpcService + { + public IAlarmService(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/IPowerStateRequestHandler.cs b/Ryujinx.HLE/HOS/Services/Time/IPowerStateRequestHandler.cs new file mode 100644 index 00000000..cb10da47 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/IPowerStateRequestHandler.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Time +{ + [Service("time:m")] // 9.0.0+ + class IPowerStateRequestHandler : IpcService + { + public IPowerStateRequestHandler(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs b/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs index d9c5b4f2..0cfdebcf 100644 --- a/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs +++ b/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs @@ -3,6 +3,7 @@ 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.StaticService; using Ryujinx.HLE.HOS.Services.Time.TimeZone; using System; using System.Diagnostics; @@ -14,6 +15,7 @@ namespace Ryujinx.HLE.HOS.Services.Time [Service("time:a", TimePermissions.Applet)] [Service("time:s", TimePermissions.System)] [Service("time:u", TimePermissions.User)] + [Service("time:p", TimePermissions.System)] // 9.0.0+ - TODO: Fix the permission. class IStaticService : IpcService { private TimePermissions _permissions; diff --git a/Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs b/Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs deleted file mode 100644 index 7e3edcef..00000000 --- a/Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs +++ /dev/null @@ -1,91 +0,0 @@ -using Ryujinx.Common; -using Ryujinx.HLE.HOS.Services.Time.Clock; - -namespace Ryujinx.HLE.HOS.Services.Time -{ - class ISteadyClock : IpcService - { - [Command(0)] - // GetCurrentTimePoint() -> nn::time::SteadyClockTimePoint - public ResultCode GetCurrentTimePoint(ServiceCtx context) - { - SteadyClockTimePoint currentTimePoint = StandardSteadyClockCore.Instance.GetCurrentTimePoint(context.Thread); - - context.ResponseData.WriteStruct(currentTimePoint); - - return ResultCode.Success; - } - - [Command(1)] - // GetTestOffset() -> nn::TimeSpanType - public ResultCode GetTestOffset(ServiceCtx context) - { - context.ResponseData.WriteStruct(StandardSteadyClockCore.Instance.GetTestOffset()); - - return ResultCode.Success; - } - - [Command(2)] - // SetTestOffset(nn::TimeSpanType) - public ResultCode SetTestOffset(ServiceCtx context) - { - TimeSpanType testOffset = context.RequestData.ReadStruct(); - - StandardSteadyClockCore.Instance.SetTestOffset(testOffset); - - return 0; - } - - [Command(100)] // 2.0.0+ - // GetRtcValue() -> u64 - public ResultCode GetRtcValue(ServiceCtx context) - { - ResultCode result = StandardSteadyClockCore.Instance.GetRtcValue(out ulong rtcValue); - - if (result == ResultCode.Success) - { - context.ResponseData.Write(rtcValue); - } - - return result; - } - - [Command(101)] // 2.0.0+ - // IsRtcResetDetected() -> bool - public ResultCode IsRtcResetDetected(ServiceCtx context) - { - context.ResponseData.Write(StandardSteadyClockCore.Instance.IsRtcResetDetected()); - - return ResultCode.Success; - } - - [Command(102)] // 2.0.0+ - // GetSetupResultValue() -> u32 - public ResultCode GetSetupResultValue(ServiceCtx context) - { - context.ResponseData.Write((uint)StandardSteadyClockCore.Instance.GetSetupResultValue()); - - return ResultCode.Success; - } - - [Command(200)] // 3.0.0+ - // GetInternalOffset() -> nn::TimeSpanType - public ResultCode GetInternalOffset(ServiceCtx context) - { - context.ResponseData.WriteStruct(StandardSteadyClockCore.Instance.GetInternalOffset()); - - return ResultCode.Success; - } - - [Command(201)] // 3.0.0-3.0.2 - // SetInternalOffset(nn::TimeSpanType) - public ResultCode SetInternalOffset(ServiceCtx context) - { - TimeSpanType internalOffset = context.RequestData.ReadStruct(); - - StandardSteadyClockCore.Instance.SetInternalOffset(internalOffset); - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/ISystemClock.cs b/Ryujinx.HLE/HOS/Services/Time/ISystemClock.cs deleted file mode 100644 index d496dcdc..00000000 --- a/Ryujinx.HLE/HOS/Services/Time/ISystemClock.cs +++ /dev/null @@ -1,107 +0,0 @@ -using Ryujinx.Common; -using Ryujinx.HLE.HOS.Services.Time.Clock; - -namespace Ryujinx.HLE.HOS.Services.Time -{ - class ISystemClock : IpcService - { - private SystemClockCore _clockCore; - private bool _writePermission; - - public ISystemClock(SystemClockCore clockCore, bool writePermission) - { - _clockCore = clockCore; - _writePermission = writePermission; - } - - [Command(0)] - // GetCurrentTime() -> nn::time::PosixTime - public ResultCode GetCurrentTime(ServiceCtx context) - { - SteadyClockCore steadyClockCore = _clockCore.GetSteadyClockCore(); - SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(context.Thread); - - ResultCode result = _clockCore.GetSystemClockContext(context.Thread, out SystemClockContext clockContext); - - if (result == ResultCode.Success) - { - result = ResultCode.TimeMismatch; - - if (currentTimePoint.ClockSourceId == clockContext.SteadyTimePoint.ClockSourceId) - { - long posixTime = clockContext.Offset + currentTimePoint.TimePoint; - - context.ResponseData.Write(posixTime); - - result = 0; - } - } - - return result; - } - - [Command(1)] - // SetCurrentTime(nn::time::PosixTime) - public ResultCode SetCurrentTime(ServiceCtx context) - { - if (!_writePermission) - { - return ResultCode.PermissionDenied; - } - - long posixTime = context.RequestData.ReadInt64(); - SteadyClockCore steadyClockCore = _clockCore.GetSteadyClockCore(); - SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(context.Thread); - - SystemClockContext clockContext = new SystemClockContext() - { - Offset = posixTime - currentTimePoint.TimePoint, - SteadyTimePoint = currentTimePoint - }; - - ResultCode result = _clockCore.SetSystemClockContext(clockContext); - - if (result == ResultCode.Success) - { - result = _clockCore.Flush(clockContext); - } - - return result; - } - - [Command(2)] - // GetSystemClockContext() -> nn::time::SystemClockContext - public ResultCode GetSystemClockContext(ServiceCtx context) - { - ResultCode result = _clockCore.GetSystemClockContext(context.Thread, out SystemClockContext clockContext); - - if (result == ResultCode.Success) - { - context.ResponseData.WriteStruct(clockContext); - } - - return result; - } - - [Command(3)] - // SetSystemClockContext(nn::time::SystemClockContext) - public ResultCode SetSystemClockContext(ServiceCtx context) - { - if (!_writePermission) - { - return ResultCode.PermissionDenied; - } - - SystemClockContext clockContext = context.RequestData.ReadStruct(); - - ResultCode result = _clockCore.SetSystemClockContext(clockContext); - - if (result == ResultCode.Success) - { - result = _clockCore.Flush(clockContext); - } - - return result; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs b/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs new file mode 100644 index 00000000..514e901e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Time +{ + [Service("time:su")] // 9.0.0+ + class ITimeServiceManager : IpcService + { + public ITimeServiceManager(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs b/Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs deleted file mode 100644 index b820de38..00000000 --- a/Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs +++ /dev/null @@ -1,218 +0,0 @@ -using ARMeilleure.Memory; -using Ryujinx.Common; -using Ryujinx.Common.Logging; -using Ryujinx.HLE.HOS.Services.Time.TimeZone; -using System; -using System.Text; - -namespace Ryujinx.HLE.HOS.Services.Time -{ - class ITimeZoneService : IpcService - { - public ITimeZoneService() { } - - [Command(0)] - // GetDeviceLocationName() -> nn::time::LocationName - public ResultCode GetDeviceLocationName(ServiceCtx context) - { - char[] tzName = TimeZoneManager.Instance.GetDeviceLocationName().ToCharArray(); - - int padding = 0x24 - tzName.Length; - - if (padding < 0) - { - return ResultCode.LocationNameTooLong; - } - - context.ResponseData.Write(tzName); - - for (int index = 0; index < padding; index++) - { - context.ResponseData.Write((byte)0); - } - - return ResultCode.Success; - } - - [Command(1)] - // SetDeviceLocationName(nn::time::LocationName) - public ResultCode SetDeviceLocationName(ServiceCtx context) - { - string locationName = Encoding.ASCII.GetString(context.RequestData.ReadBytes(0x24)).TrimEnd('\0'); - - return TimeZoneManager.Instance.SetDeviceLocationName(locationName); - } - - [Command(2)] - // GetTotalLocationNameCount() -> u32 - public ResultCode GetTotalLocationNameCount(ServiceCtx context) - { - context.ResponseData.Write(TimeZoneManager.Instance.GetTotalLocationNameCount()); - - return ResultCode.Success; - } - - [Command(3)] - // LoadLocationNameList(u32 index) -> (u32 outCount, buffer) - public ResultCode LoadLocationNameList(ServiceCtx context) - { - uint index = context.RequestData.ReadUInt32(); - long bufferPosition = context.Request.ReceiveBuff[0].Position; - long bufferSize = context.Request.ReceiveBuff[0].Size; - - ResultCode errorCode = TimeZoneManager.Instance.LoadLocationNameList(index, out string[] locationNameArray, (uint)bufferSize / 0x24); - - if (errorCode == 0) - { - uint offset = 0; - - foreach (string locationName in locationNameArray) - { - int padding = 0x24 - locationName.Length; - - if (padding < 0) - { - return ResultCode.LocationNameTooLong; - } - - context.Memory.WriteBytes(bufferPosition + offset, Encoding.ASCII.GetBytes(locationName)); - MemoryHelper.FillWithZeros(context.Memory, bufferPosition + offset + locationName.Length, padding); - - offset += 0x24; - } - - context.ResponseData.Write((uint)locationNameArray.Length); - } - - return errorCode; - } - - [Command(4)] - // LoadTimeZoneRule(nn::time::LocationName locationName) -> buffer - public ResultCode LoadTimeZoneRule(ServiceCtx context) - { - long bufferPosition = context.Request.ReceiveBuff[0].Position; - long bufferSize = context.Request.ReceiveBuff[0].Size; - - if (bufferSize != 0x4000) - { - // TODO: find error code here - Logger.PrintError(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{bufferSize:x} (expected 0x4000)"); - - throw new InvalidOperationException(); - } - - - string locationName = Encoding.ASCII.GetString(context.RequestData.ReadBytes(0x24)).TrimEnd('\0'); - - ResultCode resultCode = TimeZoneManager.Instance.LoadTimeZoneRules(out TimeZoneRule rules, locationName); - - // Write TimeZoneRule if success - if (resultCode == 0) - { - MemoryHelper.Write(context.Memory, bufferPosition, rules); - } - - return resultCode; - } - - [Command(100)] - // ToCalendarTime(nn::time::PosixTime time, buffer rules) -> (nn::time::CalendarTime, nn::time::sf::CalendarAdditionalInfo) - public ResultCode ToCalendarTime(ServiceCtx context) - { - long posixTime = context.RequestData.ReadInt64(); - long bufferPosition = context.Request.SendBuff[0].Position; - long bufferSize = context.Request.SendBuff[0].Size; - - if (bufferSize != 0x4000) - { - // TODO: find error code here - Logger.PrintError(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{bufferSize:x} (expected 0x4000)"); - - throw new InvalidOperationException(); - } - - TimeZoneRule rules = MemoryHelper.Read(context.Memory, bufferPosition); - - ResultCode resultCode = TimeZoneManager.ToCalendarTime(rules, posixTime, out CalendarInfo calendar); - - if (resultCode == 0) - { - context.ResponseData.WriteStruct(calendar); - } - - return resultCode; - } - - [Command(101)] - // ToCalendarTimeWithMyRule(nn::time::PosixTime) -> (nn::time::CalendarTime, nn::time::sf::CalendarAdditionalInfo) - public ResultCode ToCalendarTimeWithMyRule(ServiceCtx context) - { - long posixTime = context.RequestData.ReadInt64(); - - ResultCode resultCode = TimeZoneManager.Instance.ToCalendarTimeWithMyRules(posixTime, out CalendarInfo calendar); - - if (resultCode == 0) - { - context.ResponseData.WriteStruct(calendar); - } - - return resultCode; - } - - [Command(201)] - // ToPosixTime(nn::time::CalendarTime calendarTime, buffer rules) -> (u32 outCount, buffer) - public ResultCode ToPosixTime(ServiceCtx context) - { - long inBufferPosition = context.Request.SendBuff[0].Position; - long inBufferSize = context.Request.SendBuff[0].Size; - - CalendarTime calendarTime = context.RequestData.ReadStruct(); - - if (inBufferSize != 0x4000) - { - // TODO: find error code here - Logger.PrintError(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{inBufferSize:x} (expected 0x4000)"); - - throw new InvalidOperationException(); - } - - TimeZoneRule rules = MemoryHelper.Read(context.Memory, inBufferPosition); - - ResultCode resultCode = TimeZoneManager.ToPosixTime(rules, calendarTime, out long posixTime); - - if (resultCode == 0) - { - long outBufferPosition = context.Request.RecvListBuff[0].Position; - long outBufferSize = context.Request.RecvListBuff[0].Size; - - context.Memory.WriteInt64(outBufferPosition, posixTime); - context.ResponseData.Write(1); - } - - return resultCode; - } - - [Command(202)] - // ToPosixTimeWithMyRule(nn::time::CalendarTime calendarTime) -> (u32 outCount, buffer) - public ResultCode ToPosixTimeWithMyRule(ServiceCtx context) - { - CalendarTime calendarTime = context.RequestData.ReadStruct(); - - ResultCode resultCode = TimeZoneManager.Instance.ToPosixTimeWithMyRules(calendarTime, out long posixTime); - - if (resultCode == 0) - { - long outBufferPosition = context.Request.RecvListBuff[0].Position; - long outBufferSize = context.Request.RecvListBuff[0].Size; - - context.Memory.WriteInt64(outBufferPosition, posixTime); - - // There could be only one result on one calendar as leap seconds aren't supported. - context.ResponseData.Write(1); - } - - return resultCode; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/ITimeZoneServiceTypes.cs b/Ryujinx.HLE/HOS/Services/Time/ITimeZoneServiceTypes.cs deleted file mode 100644 index 9a83b82b..00000000 --- a/Ryujinx.HLE/HOS/Services/Time/ITimeZoneServiceTypes.cs +++ /dev/null @@ -1,128 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Time -{ - [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 4)] - struct TimeTypeInfo - { - public int GmtOffset; - - [MarshalAs(UnmanagedType.I1)] - public bool IsDaySavingTime; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - char[] Padding1; - - public int AbbreviationListIndex; - - [MarshalAs(UnmanagedType.I1)] - public bool IsStandardTimeDaylight; - - [MarshalAs(UnmanagedType.I1)] - public bool IsGMT; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - char[] Padding2; - } - - [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 0x4000, CharSet = CharSet.Ansi)] - struct TimeZoneRule - { - public const int TzMaxTypes = 128; - public const int TzMaxChars = 50; - public const int TzMaxLeaps = 50; - public const int TzMaxTimes = 1000; - public const int TzNameMax = 255; - public const int TzCharsArraySize = 2 * (TzNameMax + 1); - - public int TimeCount; - public int TypeCount; - public int CharCount; - - [MarshalAs(UnmanagedType.I1)] - public bool GoBack; - - [MarshalAs(UnmanagedType.I1)] - public bool GoAhead; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = TzMaxTimes)] - public long[] Ats; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = TzMaxTimes)] - public byte[] Types; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = TzMaxTypes)] - public TimeTypeInfo[] Ttis; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = TzCharsArraySize)] - public char[] Chars; - - public int DefaultType; - } - - [StructLayout(LayoutKind.Sequential, Pack = 0x4, Size = 0x2C)] - struct TzifHeader - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public char[] Magic; - - public char Version; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)] - public byte[] Reserved; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public byte[] TtisGMTCount; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public byte[] TtisSTDCount; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public byte[] LeapCount; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public byte[] TimeCount; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public byte[] TypeCount; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public byte[] CharCount; - } - - [StructLayout(LayoutKind.Sequential, Pack = 0x4, Size = 0x8)] - struct CalendarTime - { - public short Year; - public sbyte Month; - public sbyte Day; - public sbyte Hour; - public sbyte Minute; - public sbyte Second; - } - - [StructLayout(LayoutKind.Sequential, Pack = 0x4, Size = 0x18, CharSet = CharSet.Ansi)] - struct CalendarAdditionalInfo - { - public uint DayOfWeek; - public uint DayOfYear; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public char[] TimezoneName; - - [MarshalAs(UnmanagedType.I1)] - public bool IsDaySavingTime; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - char[] Padding; - - public int GmtOffset; - } - - [StructLayout(LayoutKind.Sequential, Pack = 0x4, Size = 0x20, CharSet = CharSet.Ansi)] - struct CalendarInfo - { - public CalendarTime Time; - public CalendarAdditionalInfo AdditionalInfo; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/StaticService/ISteadyClock.cs b/Ryujinx.HLE/HOS/Services/Time/StaticService/ISteadyClock.cs new file mode 100644 index 00000000..31f119df --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/StaticService/ISteadyClock.cs @@ -0,0 +1,91 @@ +using Ryujinx.Common; +using Ryujinx.HLE.HOS.Services.Time.Clock; + +namespace Ryujinx.HLE.HOS.Services.Time.StaticService +{ + class ISteadyClock : IpcService + { + [Command(0)] + // GetCurrentTimePoint() -> nn::time::SteadyClockTimePoint + public ResultCode GetCurrentTimePoint(ServiceCtx context) + { + SteadyClockTimePoint currentTimePoint = StandardSteadyClockCore.Instance.GetCurrentTimePoint(context.Thread); + + context.ResponseData.WriteStruct(currentTimePoint); + + return ResultCode.Success; + } + + [Command(1)] + // GetTestOffset() -> nn::TimeSpanType + public ResultCode GetTestOffset(ServiceCtx context) + { + context.ResponseData.WriteStruct(StandardSteadyClockCore.Instance.GetTestOffset()); + + return ResultCode.Success; + } + + [Command(2)] + // SetTestOffset(nn::TimeSpanType) + public ResultCode SetTestOffset(ServiceCtx context) + { + TimeSpanType testOffset = context.RequestData.ReadStruct(); + + StandardSteadyClockCore.Instance.SetTestOffset(testOffset); + + return 0; + } + + [Command(100)] // 2.0.0+ + // GetRtcValue() -> u64 + public ResultCode GetRtcValue(ServiceCtx context) + { + ResultCode result = StandardSteadyClockCore.Instance.GetRtcValue(out ulong rtcValue); + + if (result == ResultCode.Success) + { + context.ResponseData.Write(rtcValue); + } + + return result; + } + + [Command(101)] // 2.0.0+ + // IsRtcResetDetected() -> bool + public ResultCode IsRtcResetDetected(ServiceCtx context) + { + context.ResponseData.Write(StandardSteadyClockCore.Instance.IsRtcResetDetected()); + + return ResultCode.Success; + } + + [Command(102)] // 2.0.0+ + // GetSetupResultValue() -> u32 + public ResultCode GetSetupResultValue(ServiceCtx context) + { + context.ResponseData.Write((uint)StandardSteadyClockCore.Instance.GetSetupResultValue()); + + return ResultCode.Success; + } + + [Command(200)] // 3.0.0+ + // GetInternalOffset() -> nn::TimeSpanType + public ResultCode GetInternalOffset(ServiceCtx context) + { + context.ResponseData.WriteStruct(StandardSteadyClockCore.Instance.GetInternalOffset()); + + return ResultCode.Success; + } + + [Command(201)] // 3.0.0-3.0.2 + // SetInternalOffset(nn::TimeSpanType) + public ResultCode SetInternalOffset(ServiceCtx context) + { + TimeSpanType internalOffset = context.RequestData.ReadStruct(); + + StandardSteadyClockCore.Instance.SetInternalOffset(internalOffset); + + return ResultCode.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/StaticService/ISystemClock.cs b/Ryujinx.HLE/HOS/Services/Time/StaticService/ISystemClock.cs new file mode 100644 index 00000000..0d866177 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/StaticService/ISystemClock.cs @@ -0,0 +1,107 @@ +using Ryujinx.Common; +using Ryujinx.HLE.HOS.Services.Time.Clock; + +namespace Ryujinx.HLE.HOS.Services.Time.StaticService +{ + class ISystemClock : IpcService + { + private SystemClockCore _clockCore; + private bool _writePermission; + + public ISystemClock(SystemClockCore clockCore, bool writePermission) + { + _clockCore = clockCore; + _writePermission = writePermission; + } + + [Command(0)] + // GetCurrentTime() -> nn::time::PosixTime + public ResultCode GetCurrentTime(ServiceCtx context) + { + SteadyClockCore steadyClockCore = _clockCore.GetSteadyClockCore(); + SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(context.Thread); + + ResultCode result = _clockCore.GetSystemClockContext(context.Thread, out SystemClockContext clockContext); + + if (result == ResultCode.Success) + { + result = ResultCode.TimeMismatch; + + if (currentTimePoint.ClockSourceId == clockContext.SteadyTimePoint.ClockSourceId) + { + long posixTime = clockContext.Offset + currentTimePoint.TimePoint; + + context.ResponseData.Write(posixTime); + + result = 0; + } + } + + return result; + } + + [Command(1)] + // SetCurrentTime(nn::time::PosixTime) + public ResultCode SetCurrentTime(ServiceCtx context) + { + if (!_writePermission) + { + return ResultCode.PermissionDenied; + } + + long posixTime = context.RequestData.ReadInt64(); + SteadyClockCore steadyClockCore = _clockCore.GetSteadyClockCore(); + SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(context.Thread); + + SystemClockContext clockContext = new SystemClockContext() + { + Offset = posixTime - currentTimePoint.TimePoint, + SteadyTimePoint = currentTimePoint + }; + + ResultCode result = _clockCore.SetSystemClockContext(clockContext); + + if (result == ResultCode.Success) + { + result = _clockCore.Flush(clockContext); + } + + return result; + } + + [Command(2)] + // GetSystemClockContext() -> nn::time::SystemClockContext + public ResultCode GetSystemClockContext(ServiceCtx context) + { + ResultCode result = _clockCore.GetSystemClockContext(context.Thread, out SystemClockContext clockContext); + + if (result == ResultCode.Success) + { + context.ResponseData.WriteStruct(clockContext); + } + + return result; + } + + [Command(3)] + // SetSystemClockContext(nn::time::SystemClockContext) + public ResultCode SetSystemClockContext(ServiceCtx context) + { + if (!_writePermission) + { + return ResultCode.PermissionDenied; + } + + SystemClockContext clockContext = context.RequestData.ReadStruct(); + + ResultCode result = _clockCore.SetSystemClockContext(clockContext); + + if (result == ResultCode.Success) + { + result = _clockCore.Flush(clockContext); + } + + return result; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/StaticService/ITimeZoneService.cs b/Ryujinx.HLE/HOS/Services/Time/StaticService/ITimeZoneService.cs new file mode 100644 index 00000000..c65107df --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/StaticService/ITimeZoneService.cs @@ -0,0 +1,218 @@ +using ARMeilleure.Memory; +using Ryujinx.Common; +using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Services.Time.TimeZone; +using System; +using System.Text; + +namespace Ryujinx.HLE.HOS.Services.Time.StaticService +{ + class ITimeZoneService : IpcService + { + public ITimeZoneService() { } + + [Command(0)] + // GetDeviceLocationName() -> nn::time::LocationName + public ResultCode GetDeviceLocationName(ServiceCtx context) + { + char[] tzName = TimeZoneManager.Instance.GetDeviceLocationName().ToCharArray(); + + int padding = 0x24 - tzName.Length; + + if (padding < 0) + { + return ResultCode.LocationNameTooLong; + } + + context.ResponseData.Write(tzName); + + for (int index = 0; index < padding; index++) + { + context.ResponseData.Write((byte)0); + } + + return ResultCode.Success; + } + + [Command(1)] + // SetDeviceLocationName(nn::time::LocationName) + public ResultCode SetDeviceLocationName(ServiceCtx context) + { + string locationName = Encoding.ASCII.GetString(context.RequestData.ReadBytes(0x24)).TrimEnd('\0'); + + return TimeZoneManager.Instance.SetDeviceLocationName(locationName); + } + + [Command(2)] + // GetTotalLocationNameCount() -> u32 + public ResultCode GetTotalLocationNameCount(ServiceCtx context) + { + context.ResponseData.Write(TimeZoneManager.Instance.GetTotalLocationNameCount()); + + return ResultCode.Success; + } + + [Command(3)] + // LoadLocationNameList(u32 index) -> (u32 outCount, buffer) + public ResultCode LoadLocationNameList(ServiceCtx context) + { + uint index = context.RequestData.ReadUInt32(); + long bufferPosition = context.Request.ReceiveBuff[0].Position; + long bufferSize = context.Request.ReceiveBuff[0].Size; + + ResultCode errorCode = TimeZoneManager.Instance.LoadLocationNameList(index, out string[] locationNameArray, (uint)bufferSize / 0x24); + + if (errorCode == 0) + { + uint offset = 0; + + foreach (string locationName in locationNameArray) + { + int padding = 0x24 - locationName.Length; + + if (padding < 0) + { + return ResultCode.LocationNameTooLong; + } + + context.Memory.WriteBytes(bufferPosition + offset, Encoding.ASCII.GetBytes(locationName)); + MemoryHelper.FillWithZeros(context.Memory, bufferPosition + offset + locationName.Length, padding); + + offset += 0x24; + } + + context.ResponseData.Write((uint)locationNameArray.Length); + } + + return errorCode; + } + + [Command(4)] + // LoadTimeZoneRule(nn::time::LocationName locationName) -> buffer + public ResultCode LoadTimeZoneRule(ServiceCtx context) + { + long bufferPosition = context.Request.ReceiveBuff[0].Position; + long bufferSize = context.Request.ReceiveBuff[0].Size; + + if (bufferSize != 0x4000) + { + // TODO: find error code here + Logger.PrintError(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{bufferSize:x} (expected 0x4000)"); + + throw new InvalidOperationException(); + } + + + string locationName = Encoding.ASCII.GetString(context.RequestData.ReadBytes(0x24)).TrimEnd('\0'); + + ResultCode resultCode = TimeZoneManager.Instance.LoadTimeZoneRules(out TimeZoneRule rules, locationName); + + // Write TimeZoneRule if success + if (resultCode == 0) + { + MemoryHelper.Write(context.Memory, bufferPosition, rules); + } + + return resultCode; + } + + [Command(100)] + // ToCalendarTime(nn::time::PosixTime time, buffer rules) -> (nn::time::CalendarTime, nn::time::sf::CalendarAdditionalInfo) + public ResultCode ToCalendarTime(ServiceCtx context) + { + long posixTime = context.RequestData.ReadInt64(); + long bufferPosition = context.Request.SendBuff[0].Position; + long bufferSize = context.Request.SendBuff[0].Size; + + if (bufferSize != 0x4000) + { + // TODO: find error code here + Logger.PrintError(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{bufferSize:x} (expected 0x4000)"); + + throw new InvalidOperationException(); + } + + TimeZoneRule rules = MemoryHelper.Read(context.Memory, bufferPosition); + + ResultCode resultCode = TimeZoneManager.ToCalendarTime(rules, posixTime, out CalendarInfo calendar); + + if (resultCode == 0) + { + context.ResponseData.WriteStruct(calendar); + } + + return resultCode; + } + + [Command(101)] + // ToCalendarTimeWithMyRule(nn::time::PosixTime) -> (nn::time::CalendarTime, nn::time::sf::CalendarAdditionalInfo) + public ResultCode ToCalendarTimeWithMyRule(ServiceCtx context) + { + long posixTime = context.RequestData.ReadInt64(); + + ResultCode resultCode = TimeZoneManager.Instance.ToCalendarTimeWithMyRules(posixTime, out CalendarInfo calendar); + + if (resultCode == 0) + { + context.ResponseData.WriteStruct(calendar); + } + + return resultCode; + } + + [Command(201)] + // ToPosixTime(nn::time::CalendarTime calendarTime, buffer rules) -> (u32 outCount, buffer) + public ResultCode ToPosixTime(ServiceCtx context) + { + long inBufferPosition = context.Request.SendBuff[0].Position; + long inBufferSize = context.Request.SendBuff[0].Size; + + CalendarTime calendarTime = context.RequestData.ReadStruct(); + + if (inBufferSize != 0x4000) + { + // TODO: find error code here + Logger.PrintError(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{inBufferSize:x} (expected 0x4000)"); + + throw new InvalidOperationException(); + } + + TimeZoneRule rules = MemoryHelper.Read(context.Memory, inBufferPosition); + + ResultCode resultCode = TimeZoneManager.ToPosixTime(rules, calendarTime, out long posixTime); + + if (resultCode == 0) + { + long outBufferPosition = context.Request.RecvListBuff[0].Position; + long outBufferSize = context.Request.RecvListBuff[0].Size; + + context.Memory.WriteInt64(outBufferPosition, posixTime); + context.ResponseData.Write(1); + } + + return resultCode; + } + + [Command(202)] + // ToPosixTimeWithMyRule(nn::time::CalendarTime calendarTime) -> (u32 outCount, buffer) + public ResultCode ToPosixTimeWithMyRule(ServiceCtx context) + { + CalendarTime calendarTime = context.RequestData.ReadStruct(); + + ResultCode resultCode = TimeZoneManager.Instance.ToPosixTimeWithMyRules(calendarTime, out long posixTime); + + if (resultCode == 0) + { + long outBufferPosition = context.Request.RecvListBuff[0].Position; + long outBufferSize = context.Request.RecvListBuff[0].Size; + + context.Memory.WriteInt64(outBufferPosition, posixTime); + + // There could be only one result on one calendar as leap seconds aren't supported. + context.ResponseData.Write(1); + } + + return resultCode; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/TimePermissions.cs b/Ryujinx.HLE/HOS/Services/Time/TimePermissions.cs deleted file mode 100644 index 823c8288..00000000 --- a/Ryujinx.HLE/HOS/Services/Time/TimePermissions.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace Ryujinx.HLE.HOS.Services.Time -{ - [Flags] - enum TimePermissions - { - LocalSystemClockWritableMask = 0x1, - UserSystemClockWritableMask = 0x2, - NetworkSystemClockWritableMask = 0x4, - UnknownPermissionMask = 0x8, - - User = 0, - Applet = LocalSystemClockWritableMask | UserSystemClockWritableMask | UnknownPermissionMask, - System = NetworkSystemClockWritableMask - } -} diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZone.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZone.cs index 4b482689..3a98013e 100644 --- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZone.cs +++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZone.cs @@ -1,10 +1,11 @@ -using System; +using Ryujinx.Common; +using Ryujinx.HLE.Utilities; +using System; using System.IO; using System.Runtime.InteropServices; using System.Text; -using Ryujinx.Common; -using Ryujinx.HLE.Utilities; -using static Ryujinx.HLE.HOS.Services.Time.TimeZoneRule; + +using static Ryujinx.HLE.HOS.Services.Time.TimeZone.TimeZoneRule; namespace Ryujinx.HLE.HOS.Services.Time.TimeZone { @@ -238,9 +239,8 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone { seconds = 0; - int num; - bool isValid = GetNum(name, ref namePosition, out num, 0, HoursPerDays * DaysPerWekk - 1); + bool isValid = GetNum(name, ref namePosition, out int num, 0, HoursPerDays * DaysPerWekk - 1); if (!isValid) { return false; diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs index cf27639b..2497f6a3 100644 --- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs +++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs @@ -1,15 +1,15 @@ -using LibHac.Fs.NcaUtils; +using LibHac.Fs; +using LibHac.Fs.NcaUtils; using Ryujinx.Common.Logging; using Ryujinx.HLE.FileSystem; using System; +using System.Collections.Generic; using System.Collections.ObjectModel; -using LibHac.Fs; using System.IO; -using System.Collections.Generic; -using TimeZoneConverter.Posix; using TimeZoneConverter; +using TimeZoneConverter.Posix; -using static Ryujinx.HLE.HOS.Services.Time.TimeZoneRule; +using static Ryujinx.HLE.HOS.Services.Time.TimeZone.TimeZoneRule; namespace Ryujinx.HLE.HOS.Services.Time.TimeZone { diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarAdditionalInfo.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarAdditionalInfo.cs new file mode 100644 index 00000000..ef9b87e7 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarAdditionalInfo.cs @@ -0,0 +1,22 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Time.TimeZone +{ + [StructLayout(LayoutKind.Sequential, Pack = 0x4, Size = 0x18, CharSet = CharSet.Ansi)] + struct CalendarAdditionalInfo + { + public uint DayOfWeek; + public uint DayOfYear; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public char[] TimezoneName; + + [MarshalAs(UnmanagedType.I1)] + public bool IsDaySavingTime; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public char[] Padding; + + public int GmtOffset; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarInfo.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarInfo.cs new file mode 100644 index 00000000..68e6245b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarInfo.cs @@ -0,0 +1,11 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Time.TimeZone +{ + [StructLayout(LayoutKind.Sequential, Pack = 0x4, Size = 0x20, CharSet = CharSet.Ansi)] + struct CalendarInfo + { + public CalendarTime Time; + public CalendarAdditionalInfo AdditionalInfo; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarTime.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarTime.cs new file mode 100644 index 00000000..d594223d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarTime.cs @@ -0,0 +1,15 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Time.TimeZone +{ + [StructLayout(LayoutKind.Sequential, Pack = 0x4, Size = 0x8)] + struct CalendarTime + { + public short Year; + public sbyte Month; + public sbyte Day; + public sbyte Hour; + public sbyte Minute; + public sbyte Second; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeTypeInfo.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeTypeInfo.cs new file mode 100644 index 00000000..399e0700 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeTypeInfo.cs @@ -0,0 +1,27 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Time.TimeZone +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 4)] + struct TimeTypeInfo + { + public int GmtOffset; + + [MarshalAs(UnmanagedType.I1)] + public bool IsDaySavingTime; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public char[] Padding1; + + public int AbbreviationListIndex; + + [MarshalAs(UnmanagedType.I1)] + public bool IsStandardTimeDaylight; + + [MarshalAs(UnmanagedType.I1)] + public bool IsGMT; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public char[] Padding2; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeZoneRule.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeZoneRule.cs new file mode 100644 index 00000000..1af7a81a --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeZoneRule.cs @@ -0,0 +1,39 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Time.TimeZone +{ + [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 0x4000, CharSet = CharSet.Ansi)] + struct TimeZoneRule + { + public const int TzMaxTypes = 128; + public const int TzMaxChars = 50; + public const int TzMaxLeaps = 50; + public const int TzMaxTimes = 1000; + public const int TzNameMax = 255; + public const int TzCharsArraySize = 2 * (TzNameMax + 1); + + public int TimeCount; + public int TypeCount; + public int CharCount; + + [MarshalAs(UnmanagedType.I1)] + public bool GoBack; + + [MarshalAs(UnmanagedType.I1)] + public bool GoAhead; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TzMaxTimes)] + public long[] Ats; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TzMaxTimes)] + public byte[] Types; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TzMaxTypes)] + public TimeTypeInfo[] Ttis; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TzCharsArraySize)] + public char[] Chars; + + public int DefaultType; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TzifHeader.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TzifHeader.cs new file mode 100644 index 00000000..1a033c33 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TzifHeader.cs @@ -0,0 +1,34 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Time.TimeZone +{ + [StructLayout(LayoutKind.Sequential, Pack = 0x4, Size = 0x2C)] + struct TzifHeader + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public char[] Magic; + + public char Version; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)] + public byte[] Reserved; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public byte[] TtisGMTCount; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public byte[] TtisSTDCount; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public byte[] LeapCount; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public byte[] TimeCount; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public byte[] TypeCount; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public byte[] CharCount; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/Types/TimePermissions.cs b/Ryujinx.HLE/HOS/Services/Time/Types/TimePermissions.cs new file mode 100644 index 00000000..823c8288 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Time/Types/TimePermissions.cs @@ -0,0 +1,17 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Time +{ + [Flags] + enum TimePermissions + { + LocalSystemClockWritableMask = 0x1, + UserSystemClockWritableMask = 0x2, + NetworkSystemClockWritableMask = 0x4, + UnknownPermissionMask = 0x8, + + User = 0, + Applet = LocalSystemClockWritableMask | UserSystemClockWritableMask | UnknownPermissionMask, + System = NetworkSystemClockWritableMask + } +} -- cgit v1.2.3