diff options
Diffstat (limited to 'Ryujinx.HLE')
7 files changed, 206 insertions, 43 deletions
diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs index bbc30172..55f8070a 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs @@ -1,7 +1,9 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Runtime.CompilerServices; using Ryujinx.Common; +using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Logging; using Ryujinx.HLE.HOS.Kernel.Threading; using Ryujinx.HLE.HOS.Services.Hid.Types; @@ -20,11 +22,21 @@ namespace Ryujinx.HLE.HOS.Services.Hid private ControllerType[] _configuredTypes; private KEvent[] _styleSetUpdateEvents; private bool[] _supportedPlayers; + private static HidVibrationValue _neutralVibrationValue = new HidVibrationValue + { + AmplitudeLow = 0f, + FrequencyLow = 160f, + AmplitudeHigh = 0f, + FrequencyHigh = 320f + }; internal NpadJoyHoldType JoyHold { get; set; } internal bool SixAxisActive = false; // TODO: link to hidserver when implemented internal ControllerType SupportedStyleSets { get; set; } + public Dictionary<PlayerIndex, ConcurrentQueue<(HidVibrationValue, HidVibrationValue)>> RumbleQueues = new Dictionary<PlayerIndex, ConcurrentQueue<(HidVibrationValue, HidVibrationValue)>>(); + public Dictionary<PlayerIndex, (HidVibrationValue, HidVibrationValue)> LastVibrationValues = new Dictionary<PlayerIndex, (HidVibrationValue, HidVibrationValue)>(); + public NpadDevices(Switch device, bool active = true) : base(device, active) { _configuredTypes = new ControllerType[MaxControllers]; @@ -596,5 +608,49 @@ namespace Ryujinx.HLE.HOS.Services.Hid WriteNewSixInputEntry(ref currentNpad.JoyLeftSixAxisSensor, ref newState); WriteNewSixInputEntry(ref currentNpad.JoyRightSixAxisSensor, ref newState); } + + public void UpdateRumbleQueue(PlayerIndex index, Dictionary<byte, HidVibrationValue> dualVibrationValues) + { + if (RumbleQueues.TryGetValue(index, out ConcurrentQueue<(HidVibrationValue, HidVibrationValue)> currentQueue)) + { + if (!dualVibrationValues.TryGetValue(0, out HidVibrationValue leftVibrationValue)) + { + leftVibrationValue = _neutralVibrationValue; + } + + if (!dualVibrationValues.TryGetValue(1, out HidVibrationValue rightVibrationValue)) + { + rightVibrationValue = _neutralVibrationValue; + } + + if (!LastVibrationValues.TryGetValue(index, out (HidVibrationValue, HidVibrationValue) dualVibrationValue) || !leftVibrationValue.Equals(dualVibrationValue.Item1) || !rightVibrationValue.Equals(dualVibrationValue.Item2)) + { + currentQueue.Enqueue((leftVibrationValue, rightVibrationValue)); + + LastVibrationValues[index] = (leftVibrationValue, rightVibrationValue); + } + } + } + + public HidVibrationValue GetLastVibrationValue(PlayerIndex index, byte position) + { + if (!LastVibrationValues.TryGetValue(index, out (HidVibrationValue, HidVibrationValue) dualVibrationValue)) + { + return _neutralVibrationValue; + } + + return (position == 0) ? dualVibrationValue.Item1 : dualVibrationValue.Item2; + } + + public ConcurrentQueue<(HidVibrationValue, HidVibrationValue)> GetRumbleQueue(PlayerIndex index) + { + if (!RumbleQueues.TryGetValue(index, out ConcurrentQueue<(HidVibrationValue, HidVibrationValue)> rumbleQueue)) + { + rumbleQueue = new ConcurrentQueue<(HidVibrationValue, HidVibrationValue)>(); + _device.Hid.Npads.RumbleQueues[index] = rumbleQueue; + } + + return rumbleQueue; + } } }
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDeviceHandle.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDeviceHandle.cs new file mode 100644 index 00000000..4501c721 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDeviceHandle.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public struct HidVibrationDeviceHandle + { + public byte DeviceType; + public byte PlayerId; + public byte Position; + public byte Reserved; + } +}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDeviceType.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDeviceType.cs index cf9e6498..898384be 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDeviceType.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDeviceType.cs @@ -3,6 +3,7 @@ public enum HidVibrationDeviceType { None, - LinearResonantActuator + LinearResonantActuator, + GcErm } }
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationValue.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationValue.cs index 7211396e..3f45d269 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationValue.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationValue.cs @@ -1,4 +1,7 @@ -namespace Ryujinx.HLE.HOS.Services.Hid +using Ryujinx.HLE.HOS.Tamper; +using System; + +namespace Ryujinx.HLE.HOS.Services.Hid { public struct HidVibrationValue { @@ -6,5 +9,17 @@ public float FrequencyLow; public float AmplitudeHigh; public float FrequencyHigh; + + public override bool Equals(object obj) + { + return obj is HidVibrationValue value && + AmplitudeLow == value.AmplitudeLow && + AmplitudeHigh == value.AmplitudeHigh; + } + + public override int GetHashCode() + { + return HashCode.Combine(AmplitudeLow, AmplitudeHigh); + } } }
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs index 3f2aae35..140545ad 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs @@ -1,10 +1,13 @@ +using Ryujinx.Common; using Ryujinx.Common.Logging; using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Threading; using Ryujinx.HLE.HOS.Services.Hid.HidServer; using Ryujinx.HLE.HOS.Services.Hid.Types; +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad; using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Runtime.InteropServices; @@ -37,7 +40,6 @@ namespace Ryujinx.HLE.HOS.Services.Hid private HidSensorFusionParameters _sensorFusionParams; private HidAccelerometerParameters _accelerometerParams; - private HidVibrationValue _vibrationValue; public IHidServer(ServiceCtx context) : base(context.Device.System.HidServer) { @@ -52,7 +54,6 @@ namespace Ryujinx.HLE.HOS.Services.Hid _sensorFusionParams = new HidSensorFusionParameters(); _accelerometerParams = new HidAccelerometerParameters(); - _vibrationValue = new HidVibrationValue(); // TODO: signal event at right place _xpadIdEvent.ReadableEvent.Signal(); @@ -1025,29 +1026,78 @@ namespace Ryujinx.HLE.HOS.Services.Hid // GetVibrationDeviceInfo(nn::hid::VibrationDeviceHandle) -> nn::hid::VibrationDeviceInfo public ResultCode GetVibrationDeviceInfo(ServiceCtx context) { - int vibrationDeviceHandle = context.RequestData.ReadInt32(); + HidVibrationDeviceHandle deviceHandle = context.RequestData.ReadStruct<HidVibrationDeviceHandle>(); + NpadStyleIndex deviceType = (NpadStyleIndex)deviceHandle.DeviceType; + NpadIdType npadIdType = (NpadIdType)deviceHandle.PlayerId; - HidVibrationDeviceValue deviceInfo = new HidVibrationDeviceValue + if (deviceType < NpadStyleIndex.System || deviceType >= NpadStyleIndex.FullKey) { - DeviceType = HidVibrationDeviceType.None, - Position = HidVibrationDevicePosition.None - }; + if (npadIdType >= (NpadIdType.Player8 + 1) && npadIdType != NpadIdType.Handheld && npadIdType != NpadIdType.Unknown) + { + return ResultCode.InvalidNpadIdType; + } - context.ResponseData.Write((int)deviceInfo.DeviceType); - context.ResponseData.Write((int)deviceInfo.Position); + if (deviceHandle.Position > 1) + { + return ResultCode.InvalidDeviceIndex; + } - Logger.Stub?.PrintStub(LogClass.ServiceHid, new { vibrationDeviceHandle, deviceInfo.DeviceType, deviceInfo.Position }); + HidVibrationDeviceType vibrationDeviceType = HidVibrationDeviceType.None; - return ResultCode.Success; + if (Enum.IsDefined(typeof(NpadStyleIndex), deviceType)) + { + vibrationDeviceType = HidVibrationDeviceType.LinearResonantActuator; + } + else if ((uint)deviceType == 8) + { + vibrationDeviceType = HidVibrationDeviceType.GcErm; + } + + HidVibrationDevicePosition vibrationDevicePosition = HidVibrationDevicePosition.None; + + if (vibrationDeviceType == HidVibrationDeviceType.LinearResonantActuator) + { + if (deviceHandle.Position == 0) + { + vibrationDevicePosition = HidVibrationDevicePosition.Left; + } + else if (deviceHandle.Position == 1) + { + vibrationDevicePosition = HidVibrationDevicePosition.Right; + } + else + { + throw new ArgumentOutOfRangeException(nameof(deviceHandle.Position)); + } + } + + HidVibrationDeviceValue deviceInfo = new HidVibrationDeviceValue + { + DeviceType = vibrationDeviceType, + Position = vibrationDevicePosition + }; + + context.ResponseData.WriteStruct(deviceInfo); + + return ResultCode.Success; + } + + return ResultCode.InvalidNpadDeviceType; } [CommandHipc(201)] // SendVibrationValue(nn::hid::VibrationDeviceHandle, nn::hid::VibrationValue, nn::applet::AppletResourceUserId) public ResultCode SendVibrationValue(ServiceCtx context) { - int vibrationDeviceHandle = context.RequestData.ReadInt32(); + HidVibrationDeviceHandle deviceHandle = new HidVibrationDeviceHandle + { + DeviceType = context.RequestData.ReadByte(), + PlayerId = context.RequestData.ReadByte(), + Position = context.RequestData.ReadByte(), + Reserved = context.RequestData.ReadByte() + }; - _vibrationValue = new HidVibrationValue + HidVibrationValue vibrationValue = new HidVibrationValue { AmplitudeLow = context.RequestData.ReadSingle(), FrequencyLow = context.RequestData.ReadSingle(), @@ -1057,14 +1107,11 @@ namespace Ryujinx.HLE.HOS.Services.Hid long appletResourceUserId = context.RequestData.ReadInt64(); - Logger.Debug?.PrintStub(LogClass.ServiceHid, new { - appletResourceUserId, - vibrationDeviceHandle, - _vibrationValue.AmplitudeLow, - _vibrationValue.FrequencyLow, - _vibrationValue.AmplitudeHigh, - _vibrationValue.FrequencyHigh - }); + Dictionary<byte, HidVibrationValue> dualVibrationValues = new Dictionary<byte, HidVibrationValue>(); + + dualVibrationValues[deviceHandle.Position] = vibrationValue; + + context.Device.Hid.Npads.UpdateRumbleQueue((PlayerIndex)deviceHandle.PlayerId, dualVibrationValues); return ResultCode.Success; } @@ -1073,22 +1120,22 @@ namespace Ryujinx.HLE.HOS.Services.Hid // GetActualVibrationValue(nn::hid::VibrationDeviceHandle, nn::applet::AppletResourceUserId) -> nn::hid::VibrationValue public ResultCode GetActualVibrationValue(ServiceCtx context) { - int vibrationDeviceHandle = context.RequestData.ReadInt32(); + HidVibrationDeviceHandle deviceHandle = new HidVibrationDeviceHandle + { + DeviceType = context.RequestData.ReadByte(), + PlayerId = context.RequestData.ReadByte(), + Position = context.RequestData.ReadByte(), + Reserved = context.RequestData.ReadByte() + }; + long appletResourceUserId = context.RequestData.ReadInt64(); - context.ResponseData.Write(_vibrationValue.AmplitudeLow); - context.ResponseData.Write(_vibrationValue.FrequencyLow); - context.ResponseData.Write(_vibrationValue.AmplitudeHigh); - context.ResponseData.Write(_vibrationValue.FrequencyHigh); + HidVibrationValue vibrationValue = context.Device.Hid.Npads.GetLastVibrationValue((PlayerIndex)deviceHandle.PlayerId, deviceHandle.Position); - Logger.Stub?.PrintStub(LogClass.ServiceHid, new { - appletResourceUserId, - vibrationDeviceHandle, - _vibrationValue.AmplitudeLow, - _vibrationValue.FrequencyLow, - _vibrationValue.AmplitudeHigh, - _vibrationValue.FrequencyHigh - }); + context.ResponseData.Write(vibrationValue.AmplitudeLow); + context.ResponseData.Write(vibrationValue.FrequencyLow); + context.ResponseData.Write(vibrationValue.AmplitudeHigh); + context.ResponseData.Write(vibrationValue.FrequencyHigh); return ResultCode.Success; } @@ -1138,13 +1185,31 @@ namespace Ryujinx.HLE.HOS.Services.Hid context.Memory.Read(context.Request.PtrBuff[1].Position, vibrationValueBuffer); - // TODO: Read all handles and values from buffer. + Span<HidVibrationDeviceHandle> deviceHandles = MemoryMarshal.Cast<byte, HidVibrationDeviceHandle>(vibrationDeviceHandleBuffer); + Span<HidVibrationValue> vibrationValues = MemoryMarshal.Cast<byte, HidVibrationValue>(vibrationValueBuffer); - Logger.Debug?.PrintStub(LogClass.ServiceHid, new { - appletResourceUserId, - VibrationDeviceHandleBufferLength = vibrationDeviceHandleBuffer.Length, - VibrationValueBufferLength = vibrationValueBuffer.Length - }); + if (!deviceHandles.IsEmpty && vibrationValues.Length == deviceHandles.Length) + { + Dictionary<byte, HidVibrationValue> dualVibrationValues = new Dictionary<byte, HidVibrationValue>(); + PlayerIndex currentIndex = (PlayerIndex)deviceHandles[0].PlayerId; + + for (int deviceCounter = 0; deviceCounter < deviceHandles.Length; deviceCounter++) + { + PlayerIndex index = (PlayerIndex)deviceHandles[deviceCounter].PlayerId; + byte position = deviceHandles[deviceCounter].Position; + + if (index != currentIndex || dualVibrationValues.Count == 2) + { + context.Device.Hid.Npads.UpdateRumbleQueue(currentIndex, dualVibrationValues); + dualVibrationValues = new Dictionary<byte, HidVibrationValue>(); + } + + dualVibrationValues[position] = vibrationValues[deviceCounter]; + currentIndex = index; + } + + context.Device.Hid.Npads.UpdateRumbleQueue(currentIndex, dualVibrationValues); + } return ResultCode.Success; } diff --git a/Ryujinx.HLE/HOS/Services/Hid/ResultCode.cs b/Ryujinx.HLE/HOS/Services/Hid/ResultCode.cs index 9b829cc5..9c87ac1d 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/ResultCode.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/ResultCode.cs @@ -7,6 +7,9 @@ Success = 0, - InvalidNpadIdType = (710 << ErrorCodeShift) | ModuleId + InvalidNpadDeviceType = (122 << ErrorCodeShift) | ModuleId, + InvalidNpadIdType = (123 << ErrorCodeShift) | ModuleId, + InvalidDeviceIndex = (124 << ErrorCodeShift) | ModuleId, + InvalidBufferSize = (131 << ErrorCodeShift) | ModuleId } }
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/NpadStyleIndex.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/NpadStyleIndex.cs new file mode 100644 index 00000000..b85681d2 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/NpadStyleIndex.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public enum NpadStyleIndex : byte + { + FullKey = 3, + Handheld = 4, + JoyDual = 5, + JoyLeft = 6, + JoyRight = 7, + SystemExt = 32, + System = 33 + } +} |
