ITimeZoneService.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. using ChocolArm64.Memory;
  2. using Ryujinx.Common;
  3. using Ryujinx.Common.Logging;
  4. using Ryujinx.HLE.HOS.Services.Time.TimeZone;
  5. using System;
  6. using System.Text;
  7. namespace Ryujinx.HLE.HOS.Services.Time
  8. {
  9. class ITimeZoneService : IpcService
  10. {
  11. public ITimeZoneService() { }
  12. [Command(0)]
  13. // GetDeviceLocationName() -> nn::time::LocationName
  14. public ResultCode GetDeviceLocationName(ServiceCtx context)
  15. {
  16. char[] tzName = TimeZoneManager.Instance.GetDeviceLocationName().ToCharArray();
  17. int padding = 0x24 - tzName.Length;
  18. if (padding < 0)
  19. {
  20. return ResultCode.LocationNameTooLong;
  21. }
  22. context.ResponseData.Write(tzName);
  23. for (int index = 0; index < padding; index++)
  24. {
  25. context.ResponseData.Write((byte)0);
  26. }
  27. return ResultCode.Success;
  28. }
  29. [Command(1)]
  30. // SetDeviceLocationName(nn::time::LocationName)
  31. public ResultCode SetDeviceLocationName(ServiceCtx context)
  32. {
  33. string locationName = Encoding.ASCII.GetString(context.RequestData.ReadBytes(0x24)).TrimEnd('\0');
  34. return TimeZoneManager.Instance.SetDeviceLocationName(locationName);
  35. }
  36. [Command(2)]
  37. // GetTotalLocationNameCount() -> u32
  38. public ResultCode GetTotalLocationNameCount(ServiceCtx context)
  39. {
  40. context.ResponseData.Write(TimeZoneManager.Instance.GetTotalLocationNameCount());
  41. return ResultCode.Success;
  42. }
  43. [Command(3)]
  44. // LoadLocationNameList(u32 index) -> (u32 outCount, buffer<nn::time::LocationName, 6>)
  45. public ResultCode LoadLocationNameList(ServiceCtx context)
  46. {
  47. // TODO: fix logic to use index
  48. uint index = context.RequestData.ReadUInt32();
  49. long bufferPosition = context.Request.ReceiveBuff[0].Position;
  50. long bufferSize = context.Request.ReceiveBuff[0].Size;
  51. ResultCode errorCode = TimeZoneManager.Instance.LoadLocationNameList(index, out string[] locationNameArray, (uint)bufferSize / 0x24);
  52. if (errorCode == 0)
  53. {
  54. uint offset = 0;
  55. foreach (string locationName in locationNameArray)
  56. {
  57. int padding = 0x24 - locationName.Length;
  58. if (padding < 0)
  59. {
  60. return ResultCode.LocationNameTooLong;
  61. }
  62. context.Memory.WriteBytes(bufferPosition + offset, Encoding.ASCII.GetBytes(locationName));
  63. MemoryHelper.FillWithZeros(context.Memory, bufferPosition + offset + locationName.Length, padding);
  64. offset += 0x24;
  65. }
  66. context.ResponseData.Write((uint)locationNameArray.Length);
  67. }
  68. return errorCode;
  69. }
  70. [Command(4)]
  71. // LoadTimeZoneRule(nn::time::LocationName locationName) -> buffer<nn::time::TimeZoneRule, 0x16>
  72. public ResultCode LoadTimeZoneRule(ServiceCtx context)
  73. {
  74. long bufferPosition = context.Request.ReceiveBuff[0].Position;
  75. long bufferSize = context.Request.ReceiveBuff[0].Size;
  76. if (bufferSize != 0x4000)
  77. {
  78. // TODO: find error code here
  79. Logger.PrintError(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{bufferSize:x} (expected 0x4000)");
  80. throw new InvalidOperationException();
  81. }
  82. string locationName = Encoding.ASCII.GetString(context.RequestData.ReadBytes(0x24)).TrimEnd('\0');
  83. ResultCode resultCode = TimeZoneManager.Instance.LoadTimeZoneRules(out TimeZoneRule rules, locationName);
  84. // Write TimeZoneRule if success
  85. if (resultCode == 0)
  86. {
  87. MemoryHelper.Write(context.Memory, bufferPosition, rules);
  88. }
  89. return resultCode;
  90. }
  91. [Command(100)]
  92. // ToCalendarTime(nn::time::PosixTime time, buffer<nn::time::TimeZoneRule, 0x15> rules) -> (nn::time::CalendarTime, nn::time::sf::CalendarAdditionalInfo)
  93. public ResultCode ToCalendarTime(ServiceCtx context)
  94. {
  95. long posixTime = context.RequestData.ReadInt64();
  96. long bufferPosition = context.Request.SendBuff[0].Position;
  97. long bufferSize = context.Request.SendBuff[0].Size;
  98. if (bufferSize != 0x4000)
  99. {
  100. // TODO: find error code here
  101. Logger.PrintError(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{bufferSize:x} (expected 0x4000)");
  102. throw new InvalidOperationException();
  103. }
  104. TimeZoneRule rules = MemoryHelper.Read<TimeZoneRule>(context.Memory, bufferPosition);
  105. ResultCode resultCode = TimeZoneManager.ToCalendarTime(rules, posixTime, out CalendarInfo calendar);
  106. if (resultCode == 0)
  107. {
  108. context.ResponseData.WriteStruct(calendar);
  109. }
  110. return resultCode;
  111. }
  112. [Command(101)]
  113. // ToCalendarTimeWithMyRule(nn::time::PosixTime) -> (nn::time::CalendarTime, nn::time::sf::CalendarAdditionalInfo)
  114. public ResultCode ToCalendarTimeWithMyRule(ServiceCtx context)
  115. {
  116. long posixTime = context.RequestData.ReadInt64();
  117. ResultCode resultCode = TimeZoneManager.Instance.ToCalendarTimeWithMyRules(posixTime, out CalendarInfo calendar);
  118. if (resultCode == 0)
  119. {
  120. context.ResponseData.WriteStruct(calendar);
  121. }
  122. return resultCode;
  123. }
  124. [Command(201)]
  125. // ToPosixTime(nn::time::CalendarTime calendarTime, buffer<nn::time::TimeZoneRule, 0x15> rules) -> (u32 outCount, buffer<nn::time::PosixTime, 0xa>)
  126. public ResultCode ToPosixTime(ServiceCtx context)
  127. {
  128. long inBufferPosition = context.Request.SendBuff[0].Position;
  129. long inBufferSize = context.Request.SendBuff[0].Size;
  130. CalendarTime calendarTime = context.RequestData.ReadStruct<CalendarTime>();
  131. if (inBufferSize != 0x4000)
  132. {
  133. // TODO: find error code here
  134. Logger.PrintError(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{inBufferSize:x} (expected 0x4000)");
  135. throw new InvalidOperationException();
  136. }
  137. TimeZoneRule rules = MemoryHelper.Read<TimeZoneRule>(context.Memory, inBufferPosition);
  138. ResultCode resultCode = TimeZoneManager.ToPosixTime(rules, calendarTime, out long posixTime);
  139. if (resultCode == 0)
  140. {
  141. long outBufferPosition = context.Request.RecvListBuff[0].Position;
  142. long outBufferSize = context.Request.RecvListBuff[0].Size;
  143. context.Memory.WriteInt64(outBufferPosition, posixTime);
  144. context.ResponseData.Write(1);
  145. }
  146. return resultCode;
  147. }
  148. [Command(202)]
  149. // ToPosixTimeWithMyRule(nn::time::CalendarTime calendarTime) -> (u32 outCount, buffer<nn::time::PosixTime, 0xa>)
  150. public ResultCode ToPosixTimeWithMyRule(ServiceCtx context)
  151. {
  152. CalendarTime calendarTime = context.RequestData.ReadStruct<CalendarTime>();
  153. ResultCode resultCode = TimeZoneManager.Instance.ToPosixTimeWithMyRules(calendarTime, out long posixTime);
  154. if (resultCode == 0)
  155. {
  156. long outBufferPosition = context.Request.RecvListBuff[0].Position;
  157. long outBufferSize = context.Request.RecvListBuff[0].Size;
  158. context.Memory.WriteInt64(outBufferPosition, posixTime);
  159. // There could be only one result on one calendar as leap seconds aren't supported.
  160. context.ResponseData.Write(1);
  161. }
  162. return resultCode;
  163. }
  164. }
  165. }