aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Guillemard <thog@protonmail.com>2018-07-13 23:35:19 +0200
committerAc_K <Acoustik666@gmail.com>2018-07-13 23:35:19 +0200
commit37bf02f0572ff5535695ffa9527b1e651d0a1b7d (patch)
tree433dbe5512b987fd1b61363bf707f2cdc8e978fa
parent3b00333b0ce21538e5ff361e3e41d89bee586d36 (diff)
TimeZone implements cmd 0, 1, 2, 3, 4 and 100 (#250)
The implementation of the TimezoneRule isn't matching hardware but doesn't need to be accurate (games are only passing the value)
-rw-r--r--Ryujinx.HLE/OsHle/Services/Time/ITimeZoneService.cs172
1 files changed, 145 insertions, 27 deletions
diff --git a/Ryujinx.HLE/OsHle/Services/Time/ITimeZoneService.cs b/Ryujinx.HLE/OsHle/Services/Time/ITimeZoneService.cs
index 39454d43..a2206a12 100644
--- a/Ryujinx.HLE/OsHle/Services/Time/ITimeZoneService.cs
+++ b/Ryujinx.HLE/OsHle/Services/Time/ITimeZoneService.cs
@@ -2,6 +2,7 @@ using Ryujinx.HLE.Logging;
using Ryujinx.HLE.OsHle.Ipc;
using System;
using System.Collections.Generic;
+using System.Text;
namespace Ryujinx.HLE.OsHle.Services.Time
{
@@ -13,20 +14,31 @@ namespace Ryujinx.HLE.OsHle.Services.Time
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 },
- { 101, ToCalendarTimeWithMyRule }
+ { 0, GetDeviceLocationName },
+ { 1, SetDeviceLocationName },
+ { 2, GetTotalLocationNameCount },
+ { 3, LoadLocationNameList },
+ { 4, LoadTimeZoneRule },
+ { 100, ToCalendarTime },
+ { 101, ToCalendarTimeWithMyRule }
};
}
public long GetDeviceLocationName(ServiceCtx Context)
{
- Context.Ns.Log.PrintStub(LogClass.ServiceTime, "Stubbed.");
+ char[] TzName = TimeZone.Id.ToCharArray();
+
+ Context.ResponseData.Write(TzName);
+
+ int Padding = 0x24 - TzName.Length;
- for (int Index = 0; Index < 0x24; Index++)
+ for (int Index = 0; Index < Padding; Index++)
{
Context.ResponseData.Write((byte)0);
}
@@ -34,11 +46,94 @@ namespace Ryujinx.HLE.OsHle.Services.Time
return 0;
}
- public long ToCalendarTimeWithMyRule(ServiceCtx Context)
+ public long SetDeviceLocationName(ServiceCtx Context)
{
- long PosixTime = Context.RequestData.ReadInt64();
+ byte[] LocationName = Context.RequestData.ReadBytes(0x24);
+ string TzID = Encoding.ASCII.GetString(LocationName).TrimEnd('\0');
+
+ long ResultCode = 0;
+
+ try
+ {
+ TimeZone = TimeZoneInfo.FindSystemTimeZoneById(TzID);
+ }
+ catch (TimeZoneNotFoundException e)
+ {
+ ResultCode = 0x7BA74;
+ }
+
+ 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 i = 0;
+ foreach (TimeZoneInfo info in TimeZoneInfo.GetSystemTimeZones())
+ {
+ byte[] TzData = Encoding.ASCII.GetBytes(info.Id);
+
+ Context.Memory.WriteBytes(BufferPosition + i, TzData);
+
+ int Padding = 0x24 - TzData.Length;
+
+ for (int Index = 0; Index < Padding; Index++)
+ {
+ Context.ResponseData.Write((byte)0);
+ }
+
+ i += 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.Ns.Log.PrintWarning(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{BufferSize:x} (expected 0x4000)");
+ }
- DateTime CurrentTime = Epoch.AddSeconds(PosixTime).ToLocalTime();
+ 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 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 e)
+ {
+ Context.Ns.Log.PrintWarning(LogClass.ServiceTime, $"Timezone not found for string: {TzID} (len: {TzID.Length})");
+ ResultCode = 0x7BA74;
+ }
+
+ 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);
@@ -46,31 +141,54 @@ namespace Ryujinx.HLE.OsHle.Services.Time
Context.ResponseData.Write((byte)CurrentTime.Hour);
Context.ResponseData.Write((byte)CurrentTime.Minute);
Context.ResponseData.Write((byte)CurrentTime.Second);
- Context.ResponseData.Write((byte)0);
-
- /* Thanks to TuxSH
- struct CalendarAdditionalInfo {
- u32 tm_wday; //day of week [0,6] (Sunday = 0)
- s32 tm_yday; //day of year [0,365]
- struct timezone {
- char[8] tz_name;
- bool isDaylightSavingTime;
- s32 utcOffsetSeconds;
- };
- };
- */
+ 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);
- //TODO: Find out the names used.
- Context.ResponseData.Write(new byte[8]);
+ return 0;
+ }
- Context.ResponseData.Write((byte)(CurrentTime.IsDaylightSavingTime() ? 1 : 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;
- Context.ResponseData.Write((int)TimeZoneInfo.Local.GetUtcOffset(CurrentTime).TotalSeconds);
+ if (BufferSize != 0x4000)
+ {
+ Context.Ns.Log.PrintWarning(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{BufferSize:x} (expected 0x4000)");
+ }
- return 0;
+ // 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 e)
+ {
+ Context.Ns.Log.PrintWarning(LogClass.ServiceTime, $"Timezone not found for string: {TzID} (len: {TzID.Length})");
+ ResultCode = 0x7BA74;
+ }
+
+ return ResultCode;
+ }
+
+ public long ToCalendarTimeWithMyRule(ServiceCtx Context)
+ {
+ long PosixTime = Context.RequestData.ReadInt64();
+
+ return ToCalendarTimeWithTz(Context, PosixTime, TimeZone);
}
}
-} \ No newline at end of file
+}