Clean up ITimeZoneService
Add error codes and simplify parsing
This commit is contained in:
parent
10c74182ba
commit
9aa4d2ba6b
3 changed files with 206 additions and 53 deletions
|
@ -1,3 +1,4 @@
|
|||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using System;
|
||||
|
@ -22,18 +23,21 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
{
|
||||
{ 0, GetDeviceLocationName },
|
||||
{ 1, SetDeviceLocationName },
|
||||
{ 2, GetTotalLocationNameCount },
|
||||
{ 3, LoadLocationNameList },
|
||||
{ 4, LoadTimeZoneRule },
|
||||
{ 100, ToCalendarTime },
|
||||
{ 101, ToCalendarTimeWithMyRule },
|
||||
{ 201, ToPosixTime },
|
||||
{ 202, ToPosixTimeWithMyRule }
|
||||
{ 0, GetDeviceLocationName },
|
||||
{ 1, SetDeviceLocationName },
|
||||
{ 2, GetTotalLocationNameCount },
|
||||
{ 3, LoadLocationNameList },
|
||||
{ 4, LoadTimeZoneRule },
|
||||
//{ 5, GetTimeZoneRuleVersion }, // 2.0.0+
|
||||
//{ 6, GetDeviceLocationNameAndUpdatedTime }, // 5.0.0+
|
||||
{ 100, ToCalendarTime },
|
||||
{ 101, ToCalendarTimeWithMyRule },
|
||||
{ 201, ToPosixTime },
|
||||
{ 202, ToPosixTimeWithMyRule }
|
||||
};
|
||||
}
|
||||
|
||||
// GetDeviceLocationName() -> nn::time::LocationName
|
||||
public long GetDeviceLocationName(ServiceCtx context)
|
||||
{
|
||||
char[] tzName = _timeZone.Id.ToCharArray();
|
||||
|
@ -50,6 +54,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||
return 0;
|
||||
}
|
||||
|
||||
// SetDeviceLocationName(nn::time::LocationName)
|
||||
public long SetDeviceLocationName(ServiceCtx context)
|
||||
{
|
||||
byte[] locationName = context.RequestData.ReadBytes(0x24);
|
||||
|
@ -64,12 +69,13 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||
}
|
||||
catch (TimeZoneNotFoundException)
|
||||
{
|
||||
resultCode = MakeError(ErrorModule.Time, 0x3dd);
|
||||
resultCode = MakeError(ErrorModule.Time, TimeError.TimeZoneNotFound);
|
||||
}
|
||||
|
||||
return resultCode;
|
||||
}
|
||||
|
||||
// GetTotalLocationNameCount() -> u32
|
||||
public long GetTotalLocationNameCount(ServiceCtx context)
|
||||
{
|
||||
context.ResponseData.Write(TimeZoneInfo.GetSystemTimeZones().Count);
|
||||
|
@ -77,8 +83,11 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||
return 0;
|
||||
}
|
||||
|
||||
// LoadLocationNameList(u32 index) -> (u32 outCount, buffer<nn::time::LocationName, 6>)
|
||||
public long LoadLocationNameList(ServiceCtx context)
|
||||
{
|
||||
// TODO: fix logic to use index
|
||||
uint index = context.RequestData.ReadUInt32();
|
||||
long bufferPosition = context.Response.SendBuff[0].Position;
|
||||
long bufferSize = context.Response.SendBuff[0].Size;
|
||||
|
||||
|
@ -92,7 +101,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||
|
||||
int padding = 0x24 - tzData.Length;
|
||||
|
||||
for (int index = 0; index < padding; index++)
|
||||
for (int i = 0; i < padding; i++)
|
||||
{
|
||||
context.ResponseData.Write((byte)0);
|
||||
}
|
||||
|
@ -103,6 +112,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||
return 0;
|
||||
}
|
||||
|
||||
// LoadTimeZoneRule(nn::time::LocationName locationName) -> buffer<nn::time::TimeZoneRule, 0x16>
|
||||
public long LoadTimeZoneRule(ServiceCtx context)
|
||||
{
|
||||
long bufferPosition = context.Request.ReceiveBuff[0].Position;
|
||||
|
@ -134,34 +144,13 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||
{
|
||||
Logger.PrintWarning(LogClass.ServiceTime, $"Timezone not found for string: {tzId} (len: {tzId.Length})");
|
||||
|
||||
resultCode = MakeError(ErrorModule.Time, 0x3dd);
|
||||
resultCode = MakeError(ErrorModule.Time, TimeError.TimeZoneNotFound);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// ToCalendarTime(nn::time::PosixTime time, buffer<nn::time::TimeZoneRule, 0x15> rules) -> (nn::time::CalendarTime, nn::time::sf::CalendarAdditionalInfo)
|
||||
public long ToCalendarTime(ServiceCtx context)
|
||||
{
|
||||
long posixTime = context.RequestData.ReadInt64();
|
||||
|
@ -178,7 +167,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||
|
||||
string tzId = Encoding.ASCII.GetString(tzData).TrimEnd('\0');
|
||||
|
||||
long resultCode = 0;
|
||||
long resultCode;
|
||||
|
||||
// Check if the Time Zone exists, otherwise error out.
|
||||
try
|
||||
|
@ -191,12 +180,13 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||
{
|
||||
Logger.PrintWarning(LogClass.ServiceTime, $"Timezone not found for string: {tzId} (len: {tzId.Length})");
|
||||
|
||||
resultCode = MakeError(ErrorModule.Time, 0x3dd);
|
||||
resultCode = MakeError(ErrorModule.Time, TimeError.TimeZoneNotFound);
|
||||
}
|
||||
|
||||
return resultCode;
|
||||
}
|
||||
|
||||
// ToCalendarTimeWithMyRule(nn::time::PosixTime) -> (nn::time::CalendarTime, nn::time::sf::CalendarAdditionalInfo)
|
||||
public long ToCalendarTimeWithMyRule(ServiceCtx context)
|
||||
{
|
||||
long posixTime = context.RequestData.ReadInt64();
|
||||
|
@ -204,19 +194,15 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||
return ToCalendarTimeWithTz(context, posixTime, _timeZone);
|
||||
}
|
||||
|
||||
// ToPosixTime(nn::time::CalendarTime calendarTime, buffer<nn::time::TimeZoneRule, 0x15> rules) -> (u32 outCount, buffer<nn::time::PosixTime, 0xa>)
|
||||
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();
|
||||
CalendarTime calendarTime = context.RequestData.ReadStruct<CalendarTime>();
|
||||
|
||||
DateTime calendarTime = new DateTime(year, month, day, hour, minute, second);
|
||||
DateTime dateTime = new DateTime(calendarTime.year, calendarTime.month, calendarTime.day, calendarTime.hour, calendarTime.minute, calendarTime.second, DateTimeKind.Local);
|
||||
|
||||
if (bufferSize != 0x4000)
|
||||
{
|
||||
|
@ -235,30 +221,26 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||
{
|
||||
TimeZoneInfo info = TimeZoneInfo.FindSystemTimeZoneById(tzId);
|
||||
|
||||
return ToPosixTimeWithTz(context, calendarTime, info);
|
||||
return ToPosixTimeWithTz(context, dateTime, info);
|
||||
}
|
||||
catch (TimeZoneNotFoundException)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.ServiceTime, $"Timezone not found for string: {tzId} (len: {tzId.Length})");
|
||||
|
||||
resultCode = MakeError(ErrorModule.Time, 0x3dd);
|
||||
resultCode = MakeError(ErrorModule.Time, TimeError.TimeZoneNotFound);
|
||||
}
|
||||
|
||||
return resultCode;
|
||||
}
|
||||
|
||||
// ToPosixTimeWithMyRule(nn::time::CalendarTime calendarTime) -> (u32 outCount, buffer<nn::time::PosixTime, 0xa>)
|
||||
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();
|
||||
CalendarTime calendarTime = context.RequestData.ReadStruct<CalendarTime>();
|
||||
|
||||
DateTime calendarTime = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Local);
|
||||
DateTime dateTime = new DateTime(calendarTime.year, calendarTime.month, calendarTime.day, calendarTime.hour, calendarTime.minute, calendarTime.second, DateTimeKind.Local);
|
||||
|
||||
return ToPosixTimeWithTz(context, calendarTime, _timeZone);
|
||||
return ToPosixTimeWithTz(context, dateTime, _timeZone);
|
||||
}
|
||||
|
||||
private long ToPosixTimeWithTz(ServiceCtx context, DateTime calendarTime, TimeZoneInfo info)
|
||||
|
@ -276,5 +258,37 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private long ToCalendarTimeWithTz(ServiceCtx context, long posixTime, TimeZoneInfo info)
|
||||
{
|
||||
DateTime currentTime = Epoch.AddSeconds(posixTime);
|
||||
|
||||
currentTime = TimeZoneInfo.ConvertTimeFromUtc(currentTime, info);
|
||||
|
||||
CalendarInfo calendar = new CalendarInfo()
|
||||
{
|
||||
time = new CalendarTime()
|
||||
{
|
||||
year = (short)currentTime.Year,
|
||||
month = (sbyte)currentTime.Month,
|
||||
day = (sbyte)currentTime.Day,
|
||||
hour = (sbyte)currentTime.Hour,
|
||||
minute = (sbyte)currentTime.Minute,
|
||||
second = (sbyte)currentTime.Second,
|
||||
},
|
||||
additionalInfo = new CalendarAdditionalInfo()
|
||||
{
|
||||
dayOfWeek = (uint)currentTime.DayOfWeek,
|
||||
dayOfYear = (uint)(currentTime.DayOfYear - 1),
|
||||
isDaySavingTime = currentTime.IsDaylightSavingTime(),
|
||||
gmtOffset = info.GetUtcOffset(currentTime).Seconds,
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
context.ResponseData.WriteStruct(calendar);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
128
Ryujinx.HLE/HOS/Services/Time/ITimeZoneServiceTypes.cs
Normal file
128
Ryujinx.HLE/HOS/Services/Time/ITimeZoneServiceTypes.cs
Normal file
|
@ -0,0 +1,128 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Time
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 4)]
|
||||
public 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)]
|
||||
public struct TimeZoneRule
|
||||
{
|
||||
public const int TZ_MAX_TYPES = 128;
|
||||
public const int TZ_MAX_CHARS = 50;
|
||||
public const int TZ_MAX_LEAPS = 50;
|
||||
public const int TZ_MAX_TIMES = 1000;
|
||||
public const int TZNAME_MAX = 255;
|
||||
public const int TZ_NAME_MAX = 2 * (TZNAME_MAX + 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 = TZ_MAX_TIMES)]
|
||||
public long[] ats;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TZ_MAX_TIMES)]
|
||||
public byte[] types;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TZ_MAX_TYPES)]
|
||||
public TimeTypeInfo[] ttis;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TZ_NAME_MAX)]
|
||||
public char[] chars;
|
||||
|
||||
public int defaultType;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 0x4, Size = 0x2C)]
|
||||
public 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)]
|
||||
public 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)]
|
||||
public 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)]
|
||||
public struct CalendarInfo
|
||||
{
|
||||
public CalendarTime time;
|
||||
public CalendarAdditionalInfo additionalInfo;
|
||||
}
|
||||
}
|
11
Ryujinx.HLE/HOS/Services/Time/TimeError.cs
Normal file
11
Ryujinx.HLE/HOS/Services/Time/TimeError.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Time
|
||||
{
|
||||
static class TimeError
|
||||
{
|
||||
public const int TimeNotFound = 200;
|
||||
public const int Overflow = 201;
|
||||
public const int OutOfRange = 902;
|
||||
public const int TimeZoneConversionFailed = 903;
|
||||
public const int TimeZoneNotFound = 989;
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue