aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Services/Time
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2018-08-16 20:47:36 -0300
committerGitHub <noreply@github.com>2018-08-16 20:47:36 -0300
commit521751795a1c97c0d97f6f8904a3be69b13d3a9d (patch)
tree942a05899c40e2de6d92a38b93a494bd96ee64b8 /Ryujinx.HLE/HOS/Services/Time
parent182d716867ae477c2b15a5332430dc2641fa1cc3 (diff)
Code style fixes and nits on the HLE project (#355)
* Some style fixes and nits on ITimeZoneService * Remove some unneeded usings * Remove the Ryujinx.HLE.OsHle.Handles namespace * Remove hbmenu automatic load on process exit * Rename Ns to Device, rename Os to System, rename SystemState to State * Move Exceptions and Utilities out of OsHle * Rename OsHle to HOS * Rename OsHle folder to HOS * IManagerDisplayService and ISystemDisplayService style fixes * BsdError shouldn't be public * Add a empty new line before using static * Remove unused file * Some style fixes on NPDM * Exit gracefully when the application is closed * Code style fixes on IGeneralService * Add 0x prefix on values printed as hex * Small improvements on finalization code * Move ProcessId and ThreadId out of AThreadState * Rename VFs to FileSystem * FsAccessHeader shouldn't be public. Also fix file names casing * More case changes on NPDM * Remove unused files * Move using to the correct place on NPDM * Use properties on KernelAccessControlMmio * Address PR feedback
Diffstat (limited to 'Ryujinx.HLE/HOS/Services/Time')
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/IStaticService.cs74
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs53
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/ISystemClock.cs107
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs280
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/SystemClockType.cs10
5 files changed, 524 insertions, 0 deletions
diff --git a/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs b/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs
new file mode 100644
index 00000000..66f16501
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs
@@ -0,0 +1,74 @@
+using Ryujinx.HLE.HOS.Ipc;
+using System;
+using System.Collections.Generic;
+
+namespace Ryujinx.HLE.HOS.Services.Time
+{
+ class IStaticService : IpcService
+ {
+ private Dictionary<int, ServiceProcessRequest> m_Commands;
+
+ public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+
+ private static readonly DateTime StartupDate = DateTime.UtcNow;
+
+ public IStaticService()
+ {
+ m_Commands = new Dictionary<int, ServiceProcessRequest>()
+ {
+ { 0, GetStandardUserSystemClock },
+ { 1, GetStandardNetworkSystemClock },
+ { 2, GetStandardSteadyClock },
+ { 3, GetTimeZoneService },
+ { 4, GetStandardLocalSystemClock },
+ { 300, CalculateMonotonicSystemClockBaseTimePoint }
+ };
+ }
+
+ public long GetStandardUserSystemClock(ServiceCtx Context)
+ {
+ MakeObject(Context, new ISystemClock(SystemClockType.User));
+
+ return 0;
+ }
+
+ public long GetStandardNetworkSystemClock(ServiceCtx Context)
+ {
+ MakeObject(Context, new ISystemClock(SystemClockType.Network));
+
+ return 0;
+ }
+
+ public long GetStandardSteadyClock(ServiceCtx Context)
+ {
+ MakeObject(Context, new ISteadyClock());
+
+ return 0;
+ }
+
+ public long GetTimeZoneService(ServiceCtx Context)
+ {
+ MakeObject(Context, new ITimeZoneService());
+
+ return 0;
+ }
+
+ public long GetStandardLocalSystemClock(ServiceCtx Context)
+ {
+ MakeObject(Context, new ISystemClock(SystemClockType.Local));
+
+ return 0;
+ }
+
+ public long CalculateMonotonicSystemClockBaseTimePoint(ServiceCtx Context)
+ {
+ long TimeOffset = (long)(DateTime.UtcNow - StartupDate).TotalSeconds;
+ long SystemClockContextEpoch = Context.RequestData.ReadInt64();
+
+ Context.ResponseData.Write(TimeOffset + SystemClockContextEpoch);
+
+ return 0;
+ }
+
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs b/Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs
new file mode 100644
index 00000000..e4020bb1
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs
@@ -0,0 +1,53 @@
+using Ryujinx.HLE.HOS.Ipc;
+using System;
+using System.Collections.Generic;
+
+namespace Ryujinx.HLE.HOS.Services.Time
+{
+ class ISteadyClock : IpcService
+ {
+ private Dictionary<int, ServiceProcessRequest> m_Commands;
+
+ public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+
+ private ulong TestOffset;
+
+ public ISteadyClock()
+ {
+ m_Commands = new Dictionary<int, ServiceProcessRequest>()
+ {
+ { 0, GetCurrentTimePoint },
+ { 1, GetTestOffset },
+ { 2, SetTestOffset }
+ };
+
+ TestOffset = 0;
+ }
+
+ public long GetCurrentTimePoint(ServiceCtx Context)
+ {
+ Context.ResponseData.Write((long)(System.Diagnostics.Process.GetCurrentProcess().StartTime - DateTime.Now).TotalSeconds);
+
+ for (int i = 0; i < 0x10; i++)
+ {
+ Context.ResponseData.Write((byte)0);
+ }
+
+ return 0;
+ }
+
+ public long GetTestOffset(ServiceCtx Context)
+ {
+ Context.ResponseData.Write(TestOffset);
+
+ return 0;
+ }
+
+ public long SetTestOffset(ServiceCtx Context)
+ {
+ TestOffset = Context.RequestData.ReadUInt64();
+
+ return 0;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Time/ISystemClock.cs b/Ryujinx.HLE/HOS/Services/Time/ISystemClock.cs
new file mode 100644
index 00000000..f574826a
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Time/ISystemClock.cs
@@ -0,0 +1,107 @@
+using Ryujinx.HLE.HOS.Ipc;
+using System;
+using System.Collections.Generic;
+
+namespace Ryujinx.HLE.HOS.Services.Time
+{
+ class ISystemClock : IpcService
+ {
+ private Dictionary<int, ServiceProcessRequest> m_Commands;
+
+ public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+
+ private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+
+ private SystemClockType ClockType;
+
+ private DateTime SystemClockContextEpoch;
+
+ private long SystemClockTimePoint;
+
+ private byte[] SystemClockContextEnding;
+
+ private long TimeOffset;
+
+ public ISystemClock(SystemClockType ClockType)
+ {
+ m_Commands = new Dictionary<int, ServiceProcessRequest>()
+ {
+ { 0, GetCurrentTime },
+ { 1, SetCurrentTime },
+ { 2, GetSystemClockContext },
+ { 3, SetSystemClockContext }
+ };
+
+ this.ClockType = ClockType;
+ SystemClockContextEpoch = System.Diagnostics.Process.GetCurrentProcess().StartTime;
+ SystemClockContextEnding = new byte[0x10];
+ TimeOffset = 0;
+
+ if (ClockType == SystemClockType.User ||
+ ClockType == SystemClockType.Network)
+ {
+ SystemClockContextEpoch = SystemClockContextEpoch.ToUniversalTime();
+ }
+
+ SystemClockTimePoint = (long)(SystemClockContextEpoch - Epoch).TotalSeconds;
+ }
+
+ public long GetCurrentTime(ServiceCtx Context)
+ {
+ DateTime CurrentTime = DateTime.Now;
+
+ if (ClockType == SystemClockType.User ||
+ ClockType == SystemClockType.Network)
+ {
+ CurrentTime = CurrentTime.ToUniversalTime();
+ }
+
+ Context.ResponseData.Write((long)((CurrentTime - Epoch).TotalSeconds) + TimeOffset);
+
+ return 0;
+ }
+
+ public long SetCurrentTime(ServiceCtx Context)
+ {
+ DateTime CurrentTime = DateTime.Now;
+
+ if (ClockType == SystemClockType.User ||
+ ClockType == SystemClockType.Network)
+ {
+ CurrentTime = CurrentTime.ToUniversalTime();
+ }
+
+ TimeOffset = (Context.RequestData.ReadInt64() - (long)(CurrentTime - Epoch).TotalSeconds);
+
+ return 0;
+ }
+
+ public long GetSystemClockContext(ServiceCtx Context)
+ {
+ Context.ResponseData.Write((long)(SystemClockContextEpoch - Epoch).TotalSeconds);
+
+ // The point in time, TODO: is there a link between epoch and this?
+ Context.ResponseData.Write(SystemClockTimePoint);
+
+ // This seems to be some kind of identifier?
+ for (int i = 0; i < 0x10; i++)
+ {
+ Context.ResponseData.Write(SystemClockContextEnding[i]);
+ }
+
+ return 0;
+ }
+
+ public long SetSystemClockContext(ServiceCtx Context)
+ {
+ long NewSystemClockEpoch = Context.RequestData.ReadInt64();
+ long NewSystemClockTimePoint = Context.RequestData.ReadInt64();
+
+ SystemClockContextEpoch = Epoch.Add(TimeSpan.FromSeconds(NewSystemClockEpoch));
+ SystemClockTimePoint = NewSystemClockTimePoint;
+ SystemClockContextEnding = Context.RequestData.ReadBytes(0x10);
+
+ return 0;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs b/Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs
new file mode 100644
index 00000000..6df28659
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs
@@ -0,0 +1,280 @@
+using Ryujinx.HLE.HOS.Ipc;
+using Ryujinx.HLE.Logging;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+using static Ryujinx.HLE.HOS.ErrorCode;
+
+namespace Ryujinx.HLE.HOS.Services.Time
+{
+ class ITimeZoneService : IpcService
+ {
+ private Dictionary<int, ServiceProcessRequest> m_Commands;
+
+ public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+
+ private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+
+ private TimeZoneInfo TimeZone = TimeZoneInfo.Local;
+
+ public ITimeZoneService()
+ {
+ m_Commands = new Dictionary<int, ServiceProcessRequest>()
+ {
+ { 0, GetDeviceLocationName },
+ { 1, SetDeviceLocationName },
+ { 2, GetTotalLocationNameCount },
+ { 3, LoadLocationNameList },
+ { 4, LoadTimeZoneRule },
+ { 100, ToCalendarTime },
+ { 101, ToCalendarTimeWithMyRule },
+ { 201, ToPosixTime },
+ { 202, ToPosixTimeWithMyRule }
+ };
+ }
+
+ public long GetDeviceLocationName(ServiceCtx Context)
+ {
+ char[] TzName = TimeZone.Id.ToCharArray();
+
+ Context.ResponseData.Write(TzName);
+
+ int Padding = 0x24 - TzName.Length;
+
+ for (int Index = 0; Index < Padding; Index++)
+ {
+ Context.ResponseData.Write((byte)0);
+ }
+
+ return 0;
+ }
+
+ public long SetDeviceLocationName(ServiceCtx Context)
+ {
+ byte[] LocationName = Context.RequestData.ReadBytes(0x24);
+
+ string TzID = Encoding.ASCII.GetString(LocationName).TrimEnd('\0');
+
+ long ResultCode = 0;
+
+ try
+ {
+ TimeZone = TimeZoneInfo.FindSystemTimeZoneById(TzID);
+ }
+ catch (TimeZoneNotFoundException)
+ {
+ ResultCode = MakeError(ErrorModule.Time, 0x3dd);
+ }
+
+ return ResultCode;
+ }
+
+ public long GetTotalLocationNameCount(ServiceCtx Context)
+ {
+ Context.ResponseData.Write(TimeZoneInfo.GetSystemTimeZones().Count);
+
+ return 0;
+ }
+
+ public long LoadLocationNameList(ServiceCtx Context)
+ {
+ long BufferPosition = Context.Response.SendBuff[0].Position;
+ long BufferSize = Context.Response.SendBuff[0].Size;
+
+ int Offset = 0;
+
+ foreach (TimeZoneInfo info in TimeZoneInfo.GetSystemTimeZones())
+ {
+ byte[] TzData = Encoding.ASCII.GetBytes(info.Id);
+
+ Context.Memory.WriteBytes(BufferPosition + Offset, TzData);
+
+ int Padding = 0x24 - TzData.Length;
+
+ for (int Index = 0; Index < Padding; Index++)
+ {
+ Context.ResponseData.Write((byte)0);
+ }
+
+ Offset += 0x24;
+ }
+
+ return 0;
+ }
+
+ public long LoadTimeZoneRule(ServiceCtx Context)
+ {
+ long BufferPosition = Context.Request.ReceiveBuff[0].Position;
+ long BufferSize = Context.Request.ReceiveBuff[0].Size;
+
+ if (BufferSize != 0x4000)
+ {
+ Context.Device.Log.PrintWarning(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{BufferSize:x} (expected 0x4000)");
+ }
+
+ long ResultCode = 0;
+
+ byte[] LocationName = Context.RequestData.ReadBytes(0x24);
+
+ string TzID = Encoding.ASCII.GetString(LocationName).TrimEnd('\0');
+
+ // Check if the Time Zone exists, otherwise error out.
+ try
+ {
+ TimeZoneInfo Info = TimeZoneInfo.FindSystemTimeZoneById(TzID);
+
+ byte[] TzData = Encoding.ASCII.GetBytes(Info.Id);
+
+ // FIXME: This is not in ANY cases accurate, but the games don't care about the content of the buffer, they only pass it.
+ // TODO: Reverse the TZif2 conversion in PCV to make this match with real hardware.
+ Context.Memory.WriteBytes(BufferPosition, TzData);
+ }
+ catch (TimeZoneNotFoundException)
+ {
+ Context.Device.Log.PrintWarning(LogClass.ServiceTime, $"Timezone not found for string: {TzID} (len: {TzID.Length})");
+
+ ResultCode = MakeError(ErrorModule.Time, 0x3dd);
+ }
+
+ return ResultCode;
+ }
+
+ private long ToCalendarTimeWithTz(ServiceCtx Context, long PosixTime, TimeZoneInfo Info)
+ {
+ DateTime CurrentTime = Epoch.AddSeconds(PosixTime);
+
+ CurrentTime = TimeZoneInfo.ConvertTimeFromUtc(CurrentTime, Info);
+
+ Context.ResponseData.Write((ushort)CurrentTime.Year);
+ Context.ResponseData.Write((byte)CurrentTime.Month);
+ Context.ResponseData.Write((byte)CurrentTime.Day);
+ Context.ResponseData.Write((byte)CurrentTime.Hour);
+ Context.ResponseData.Write((byte)CurrentTime.Minute);
+ Context.ResponseData.Write((byte)CurrentTime.Second);
+ Context.ResponseData.Write((byte)0); //MilliSecond ?
+ Context.ResponseData.Write((int)CurrentTime.DayOfWeek);
+ Context.ResponseData.Write(CurrentTime.DayOfYear - 1);
+ Context.ResponseData.Write(new byte[8]); //TODO: Find out the names used.
+ Context.ResponseData.Write((byte)(CurrentTime.IsDaylightSavingTime() ? 1 : 0));
+ Context.ResponseData.Write((int)Info.GetUtcOffset(CurrentTime).TotalSeconds);
+
+ return 0;
+ }
+
+ public long 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)
+ {
+ Context.Device.Log.PrintWarning(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{BufferSize:x} (expected 0x4000)");
+ }
+
+ // TODO: Reverse the TZif2 conversion in PCV to make this match with real hardware.
+ byte[] TzData = Context.Memory.ReadBytes(BufferPosition, 0x24);
+
+ string TzID = Encoding.ASCII.GetString(TzData).TrimEnd('\0');
+
+ long ResultCode = 0;
+
+ // Check if the Time Zone exists, otherwise error out.
+ try
+ {
+ TimeZoneInfo Info = TimeZoneInfo.FindSystemTimeZoneById(TzID);
+
+ ResultCode = ToCalendarTimeWithTz(Context, PosixTime, Info);
+ }
+ catch (TimeZoneNotFoundException)
+ {
+ Context.Device.Log.PrintWarning(LogClass.ServiceTime, $"Timezone not found for string: {TzID} (len: {TzID.Length})");
+
+ ResultCode = MakeError(ErrorModule.Time, 0x3dd);
+ }
+
+ return ResultCode;
+ }
+
+ public long ToCalendarTimeWithMyRule(ServiceCtx Context)
+ {
+ long PosixTime = Context.RequestData.ReadInt64();
+
+ return ToCalendarTimeWithTz(Context, PosixTime, TimeZone);
+ }
+
+ public long ToPosixTime(ServiceCtx Context)
+ {
+ long BufferPosition = Context.Request.SendBuff[0].Position;
+ long BufferSize = Context.Request.SendBuff[0].Size;
+
+ ushort Year = Context.RequestData.ReadUInt16();
+ byte Month = Context.RequestData.ReadByte();
+ byte Day = Context.RequestData.ReadByte();
+ byte Hour = Context.RequestData.ReadByte();
+ byte Minute = Context.RequestData.ReadByte();
+ byte Second = Context.RequestData.ReadByte();
+
+ DateTime CalendarTime = new DateTime(Year, Month, Day, Hour, Minute, Second);
+
+ if (BufferSize != 0x4000)
+ {
+ Context.Device.Log.PrintWarning(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{BufferSize:x} (expected 0x4000)");
+ }
+
+ // TODO: Reverse the TZif2 conversion in PCV to make this match with real hardware.
+ byte[] TzData = Context.Memory.ReadBytes(BufferPosition, 0x24);
+
+ string TzID = Encoding.ASCII.GetString(TzData).TrimEnd('\0');
+
+ long ResultCode = 0;
+
+ // Check if the Time Zone exists, otherwise error out.
+ try
+ {
+ TimeZoneInfo Info = TimeZoneInfo.FindSystemTimeZoneById(TzID);
+
+ return ToPosixTimeWithTz(Context, CalendarTime, Info);
+ }
+ catch (TimeZoneNotFoundException)
+ {
+ Context.Device.Log.PrintWarning(LogClass.ServiceTime, $"Timezone not found for string: {TzID} (len: {TzID.Length})");
+
+ ResultCode = MakeError(ErrorModule.Time, 0x3dd);
+ }
+
+ return ResultCode;
+ }
+
+ public long ToPosixTimeWithMyRule(ServiceCtx Context)
+ {
+ ushort Year = Context.RequestData.ReadUInt16();
+ byte Month = Context.RequestData.ReadByte();
+ byte Day = Context.RequestData.ReadByte();
+ byte Hour = Context.RequestData.ReadByte();
+ byte Minute = Context.RequestData.ReadByte();
+ byte Second = Context.RequestData.ReadByte();
+
+ DateTime CalendarTime = new DateTime(Year, Month, Day, Hour, Minute, Second, DateTimeKind.Local);
+
+ return ToPosixTimeWithTz(Context, CalendarTime, TimeZone);
+ }
+
+ private long ToPosixTimeWithTz(ServiceCtx Context, DateTime CalendarTime, TimeZoneInfo Info)
+ {
+ DateTime CalenderTimeUTC = TimeZoneInfo.ConvertTimeToUtc(CalendarTime, Info);
+
+ long PosixTime = ((DateTimeOffset)CalenderTimeUTC).ToUnixTimeSeconds();
+
+ long Position = Context.Request.RecvListBuff[0].Position;
+ long Size = Context.Request.RecvListBuff[0].Size;
+
+ Context.Memory.WriteInt64(Position, PosixTime);
+
+ Context.ResponseData.Write(1);
+
+ return 0;
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Services/Time/SystemClockType.cs b/Ryujinx.HLE/HOS/Services/Time/SystemClockType.cs
new file mode 100644
index 00000000..54b7df3f
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Time/SystemClockType.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.HLE.HOS.Services.Time
+{
+ enum SystemClockType
+ {
+ User,
+ Network,
+ Local,
+ EphemeralNetwork
+ }
+} \ No newline at end of file