From 7951379b07b1e96831f87c5ebcff3034c8c5c214 Mon Sep 17 00:00:00 2001 From: David Khachaturov Date: Tue, 9 Jun 2020 09:26:11 +0100 Subject: [PATCH] Revert "only send rumble command when rumble data has changed (#408)" This reverts commit e9e7cefcdcf50fc2fee75dbc5f82119e7b9a673b. --- BetterJoyForCemu/Joycon.cs | 90 +++++++++++++++++++------------------ BetterJoyForCemu/Program.cs | 9 ++++ 2 files changed, 56 insertions(+), 43 deletions(-) diff --git a/BetterJoyForCemu/Joycon.cs b/BetterJoyForCemu/Joycon.cs index 075641d..720c069 100644 --- a/BetterJoyForCemu/Joycon.cs +++ b/BetterJoyForCemu/Joycon.cs @@ -13,6 +13,8 @@ using Nefarius.ViGEm.Client.Targets.Xbox360; namespace BetterJoyForCemu { public class Joycon { + float timing = 120.0f; + public string path = String.Empty; public bool isPro = false; public bool isSnes = false; @@ -125,50 +127,40 @@ namespace BetterJoyForCemu { private struct Rumble { private float h_f, l_f; - public float amp, fullamp; - public bool controller_informed; - public long end_rumble_time_milliseconds; + public float t, amp, fullamp; + public bool timed_rumble; - public void set_vals(float low_freq, float high_freq, float amplitude, int rumble_duration_microseconds = 0) { + public void set_vals(float low_freq, float high_freq, float amplitude, int time = 0) { h_f = high_freq; amp = amplitude; fullamp = amplitude; l_f = low_freq; - if (rumble_duration_microseconds != 0) { - end_rumble_time_milliseconds = DateTimeOffset.Now.ToUnixTimeMilliseconds() + rumble_duration_microseconds / 1000; - } else { - end_rumble_time_milliseconds = 0; + timed_rumble = false; + t = 0; + if (time != 0) { + t = time / 1000f; + timed_rumble = true; } - - controller_informed = false; } - public Rumble(float low_freq, float high_freq, float amplitude, int rumble_duration_microseconds = 0) { + public Rumble(float low_freq, float high_freq, float amplitude, int time = 0) { h_f = high_freq; amp = amplitude; fullamp = amplitude; l_f = low_freq; - if (rumble_duration_microseconds != 0) { - end_rumble_time_milliseconds = DateTimeOffset.Now.ToUnixTimeMilliseconds() + rumble_duration_microseconds / 1000; - } else { - end_rumble_time_milliseconds = 0; + timed_rumble = false; + t = 0; + if (time != 0) { + t = time / 1000f; + timed_rumble = true; } - controller_informed = false; } private float clamp(float x, float min, float max) { if (x < min) return min; if (x > max) return max; return x; } - public void Update() { - if (end_rumble_time_milliseconds != 0 && DateTimeOffset.Now.ToUnixTimeMilliseconds() > end_rumble_time_milliseconds) { - controller_informed = false; - end_rumble_time_milliseconds = 0; - amp = 0; - } - } public byte[] GetData() { byte[] rumble_data = new byte[8]; - if (amp == 0.0f) { rumble_data[0] = 0x0; rumble_data[1] = 0x1; @@ -345,6 +337,7 @@ namespace BetterJoyForCemu { a[0] = 0x1; dump_calibration_data(); } else { + Subcommand(0x03, new byte[] { 0x3f }, 1, false); a = Enumerable.Repeat((byte)0, 64).ToArray(); form.AppendTextBox("Using USB.\r\n"); @@ -352,9 +345,9 @@ namespace BetterJoyForCemu { a[0] = 0x80; a[1] = 0x1; HIDapi.hid_write(handle, a, new UIntPtr(2)); - HIDapi.hid_read_timeout(handle, a, new UIntPtr(64), 100); + HIDapi.hid_read(handle, a, new UIntPtr(64)); - if (a[3] == 0x3) { + if (a[2] != 0x3) { PadMacAddress = new PhysicalAddress(new byte[] { a[9], a[8], a[7], a[6], a[5], a[4] }); } @@ -362,19 +355,15 @@ namespace BetterJoyForCemu { a = Enumerable.Repeat((byte)0, 64).ToArray(); a[0] = 0x80; a[1] = 0x2; // Handshake HIDapi.hid_write(handle, a, new UIntPtr(2)); - HIDapi.hid_read_timeout(handle, a, new UIntPtr(64), 100); a[0] = 0x80; a[1] = 0x3; // 3Mbit baud rate HIDapi.hid_write(handle, a, new UIntPtr(2)); - HIDapi.hid_read_timeout(handle, a, new UIntPtr(64), 100); a[0] = 0x80; a[1] = 0x2; // Handshake at new baud rate HIDapi.hid_write(handle, a, new UIntPtr(2)); - HIDapi.hid_read_timeout(handle, a, new UIntPtr(64), 100); a[0] = 0x80; a[1] = 0x4; // Prevent HID timeout HIDapi.hid_write(handle, a, new UIntPtr(2)); // doesn't actually prevent timout... - HIDapi.hid_read_timeout(handle, a, new UIntPtr(64), 100); dump_calibration_data(); } @@ -392,15 +381,19 @@ namespace BetterJoyForCemu { a[0] = leds_; Subcommand(0x30, a, 1); Subcommand(0x40, new byte[] { (imu_enabled ? (byte)0x1 : (byte)0x0) }, 1, true); + Subcommand(0x3, new byte[] { 0x30 }, 1, true); Subcommand(0x48, new byte[] { 0x01 }, 1, true); Subcommand(0x41, new byte[] { 0x03, 0x00, 0x00, 0x01 }, 4, false); // higher gyro performance rate - Subcommand(0x3, new byte[] { 0x30 }, 1, true); DebugPrint("Done with init.", DebugType.COMMS); HIDapi.hid_set_nonblocking(handle, 1); + // send ping to USB to not time out instantly + if (isUSB) + SendRumble(rumble_obj.GetData()); + return 0; } @@ -503,11 +496,9 @@ namespace BetterJoyForCemu { private byte ts_en; private int ReceiveRaw() { if (handle == IntPtr.Zero) return -2; + HIDapi.hid_set_nonblocking(handle, 1); byte[] raw_buf = new byte[report_len]; int ret = HIDapi.hid_read_timeout(handle, raw_buf, new UIntPtr(report_len), 5); - - - if (ret > 0) { // Process packets as soon as they come for (int n = 0; n < 3; n++) { @@ -731,20 +722,20 @@ namespace BetterJoyForCemu { private Thread PollThreadObj; // pro times out over time randomly if it was USB and then bluetooth?? private void Poll() { int attempts = 0; + while (!stop_polling & state > state_.NO_JOYCONS) { - rumble_obj.Update(); - if (!rumble_obj.controller_informed) { + if (!isSnes && (rumble_obj.t > 0)) SendRumble(rumble_obj.GetData()); - rumble_obj.controller_informed = true; - } + int a = ReceiveRaw(); if (a > 0 && state > state_.DROPPED) { - - state = state_.IMU_DATA_OK; attempts = 0; + // Needed for USB to not time out; I think USB requires a reply message after every packet sent + if (isUSB) + SendRumble(rumble_obj.GetData()); } else if (attempts > 240) { state = state_.DROPPED; form.AppendTextBox("Dropped.\r\n"); @@ -763,6 +754,19 @@ namespace BetterJoyForCemu { } } + public void Update() { + if (state > state_.NO_JOYCONS) { + if (rumble_obj.timed_rumble) { + if (rumble_obj.t < 0) { + rumble_obj.set_vals(lowFreq, highFreq, 0, 0); + } else { + rumble_obj.t -= (1 / timing); + //rumble_obj.amp = (float) Math.Sin(((timing - rumble_obj.t * 1000f) / timing) * Math.PI) * rumble_obj.fullamp; + } + } + } + } + public float[] otherStick = { 0, 0 }; bool swapAB = Boolean.Parse(ConfigurationManager.AppSettings["SwapAB"]); @@ -1002,9 +1006,9 @@ namespace BetterJoyForCemu { return (byte)Math.Max(Byte.MinValue, Math.Min(Byte.MaxValue, 127 - stick_value * Byte.MaxValue)); } - public void SetRumble(float low_freq, float high_freq, float amp, int rumble_duration_microseconds = 0) { + public void SetRumble(float low_freq, float high_freq, float amp, int time = 0) { if (state <= Joycon.state_.ATTACHED) return; - rumble_obj.set_vals(low_freq, high_freq, amp, rumble_duration_microseconds); + rumble_obj.set_vals(low_freq, high_freq, amp, time); } private void SendRumble(byte[] buf) { @@ -1030,7 +1034,7 @@ namespace BetterJoyForCemu { else ++global_count; if (print) { PrintArray(buf_, DebugType.COMMS, len, 11, "Subcommand 0x" + string.Format("{0:X2}", sc) + " sent. Data: 0x{0:S}"); }; HIDapi.hid_write(handle, buf_, new UIntPtr(len + 11)); - int res = HIDapi.hid_read_timeout(handle, response, new UIntPtr(report_len), 100); + int res = HIDapi.hid_read_timeout(handle, response, new UIntPtr(report_len), 50); if (res < 1) DebugPrint("No response.", DebugType.COMMS); else if (print) { PrintArray(response, DebugType.COMMS, report_len - 1, 1, "Response ID 0x" + string.Format("{0:X2}", response[0]) + ". Data: 0x{0:S}"); } return response; diff --git a/BetterJoyForCemu/Program.cs b/BetterJoyForCemu/Program.cs index e7ef199..8771cbf 100644 --- a/BetterJoyForCemu/Program.cs +++ b/BetterJoyForCemu/Program.cs @@ -289,6 +289,11 @@ namespace BetterJoyForCemu { } } + public void Update() { + for (int i = 0; i < j.Count; ++i) + j[i].Update(); + } + public void OnApplicationQuit() { foreach (Joycon v in j) { if (Boolean.Parse(ConfigurationManager.AppSettings["AutoPowerOff"])) @@ -359,6 +364,7 @@ namespace BetterJoyForCemu { private static readonly HttpClient client = new HttpClient(); public static JoyconManager mgr; + static HighResTimer timer; static string pid; static MainForm form; @@ -435,6 +441,8 @@ namespace BetterJoyForCemu { server.form = form; server.Start(IPAddress.Parse(ConfigurationManager.AppSettings["IP"]), Int32.Parse(ConfigurationManager.AppSettings["Port"])); + timer = new HighResTimer(pollsPerSecond, new HighResTimer.ActionDelegate(mgr.Update)); + timer.Start(); // Capture keyboard + mouse events for binding's sake keyboard = WindowsInput.Capture.Global.KeyboardAsync(); @@ -508,6 +516,7 @@ namespace BetterJoyForCemu { keyboard.Dispose(); mouse.Dispose(); server.Stop(); + timer.Stop(); mgr.OnApplicationQuit(); }