private void performDs4Input()
        {
            firstActive = DateTime.UtcNow;
            System.Timers.Timer readTimeout = new System.Timers.Timer(); // Await 30 seconds for the initial packet, then 3 seconds thereafter.
            readTimeout.Elapsed += delegate { HidDevice.CancelIO(); };
            List <long> Latency = new List <long>();
            long        oldtime = 0;
            Stopwatch   sw      = new Stopwatch();

            sw.Start();
            while (true)
            {
                PS4Controller.Enabled = true;

                string currerror = string.Empty;
                Latency.Add(sw.ElapsedMilliseconds - oldtime);
                oldtime = sw.ElapsedMilliseconds;

                if (Latency.Count > 100)
                {
                    Latency.RemoveAt(0);
                }

                this.Latency = Latency.Average();

                if (this.Latency > 10 && !warn && sw.ElapsedMilliseconds > 4000)
                {
                    warn = true;
                    //System.Diagnostics.Trace.WriteLine(System.DateTime.UtcNow.ToString("o") + "> " + "Controller " + /*this.DeviceNum*/ + 1 + " (" + this.MacAddress + ") is experiencing latency issues. Currently at " + Math.Round(this.Latency, 2).ToString() + "ms of recomended maximum 10ms");
                }
                else if (this.Latency <= 10 && warn)
                {
                    warn = false;
                }

                if (readTimeout.Interval != 3000.0)
                {
                    if (readTimeout.Interval != 30000.0)
                    {
                        readTimeout.Interval = 30000.0;
                    }
                    else
                    {
                        readTimeout.Interval = 3000.0;
                    }
                }
                readTimeout.Enabled = true;

                if (conType != ConnectionType.USB)
                {
                    HidDevice.ReadStatus res = hDevice.ReadFile(btInputReport);
                    readTimeout.Enabled = false;
                    if (res == HidDevice.ReadStatus.Success)
                    {
                        Array.Copy(btInputReport, 2, inputReport, 0, inputReport.Length);
                    }
                    else
                    {
                        Console.WriteLine(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "> disconnect due to read failure: " + Marshal.GetLastWin32Error());
                        sendOutputReport(true); // Kick Windows into noticing the disconnection.
                        StopOutputUpdate();
                        IsDisconnecting = true;
                        if (Removal != null)
                        {
                            Removal(this, EventArgs.Empty);
                        }
                        return;
                    }
                }
                else
                {
                    HidDevice.ReadStatus res = hDevice.ReadFile(inputReport);
                    readTimeout.Enabled = false;
                    if (res != HidDevice.ReadStatus.Success)
                    {
                        Console.WriteLine(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "> disconnect due to read failure: " + Marshal.GetLastWin32Error());
                        StopOutputUpdate();
                        IsDisconnecting = true;
                        if (Removal != null)
                        {
                            Removal(this, EventArgs.Empty);
                        }
                        return;
                    }
                }
                if (ConnectionType == ConnectionType.BT && btInputReport[0] != 0x11)
                {
                    //Received incorrect report, skip it
                    continue;
                }

                DateTime utcNow = System.DateTime.UtcNow; // timestamp with UTC in case system time zone changes
                resetHapticState();
                cState.ReportTimeStamp = utcNow;
                cState.LX = inputReport[1];
                cState.LY = inputReport[2];
                cState.RX = inputReport[3];
                cState.RY = inputReport[4];
                cState.L2 = inputReport[8];
                cState.R2 = inputReport[9];

                cState.Triangle  = ((byte)inputReport[5] & (1 << 7)) != 0;
                cState.Circle    = ((byte)inputReport[5] & (1 << 6)) != 0;
                cState.Cross     = ((byte)inputReport[5] & (1 << 5)) != 0;
                cState.Square    = ((byte)inputReport[5] & (1 << 4)) != 0;
                cState.DpadUp    = ((byte)inputReport[5] & (1 << 3)) != 0;
                cState.DpadDown  = ((byte)inputReport[5] & (1 << 2)) != 0;
                cState.DpadLeft  = ((byte)inputReport[5] & (1 << 1)) != 0;
                cState.DpadRight = ((byte)inputReport[5] & (1 << 0)) != 0;



                PS4Controller.Inputs = inputReport;

                #region f**k boi status
                for (int i = 0; i < inputReport.Length; i++)
                {
                    //Console.Write(inputReport[i] + ", ");
                }

                //Console.WriteLine();
                #endregion



                //Convert dpad into individual On/Off bits instead of a clock representation
                byte dpad_state = 0;

                dpad_state = (byte)(
                    ((cState.DpadRight ? 1 : 0) << 0) |
                    ((cState.DpadLeft ? 1 : 0) << 1) |
                    ((cState.DpadDown ? 1 : 0) << 2) |
                    ((cState.DpadUp ? 1 : 0) << 3));

                switch (dpad_state)
                {
                case 0: cState.DpadUp = true; cState.DpadDown = false; cState.DpadLeft = false; cState.DpadRight = false; break;

                case 1: cState.DpadUp = true; cState.DpadDown = false; cState.DpadLeft = false; cState.DpadRight = true; break;

                case 2: cState.DpadUp = false; cState.DpadDown = false; cState.DpadLeft = false; cState.DpadRight = true; break;

                case 3: cState.DpadUp = false; cState.DpadDown = true; cState.DpadLeft = false; cState.DpadRight = true; break;

                case 4: cState.DpadUp = false; cState.DpadDown = true; cState.DpadLeft = false; cState.DpadRight = false; break;

                case 5: cState.DpadUp = false; cState.DpadDown = true; cState.DpadLeft = true; cState.DpadRight = false; break;

                case 6: cState.DpadUp = false; cState.DpadDown = false; cState.DpadLeft = true; cState.DpadRight = false; break;

                case 7: cState.DpadUp = true; cState.DpadDown = false; cState.DpadLeft = true; cState.DpadRight = false; break;

                case 8: cState.DpadUp = false; cState.DpadDown = false; cState.DpadLeft = false; cState.DpadRight = false; break;
                }

                cState.R3      = ((byte)inputReport[6] & (1 << 7)) != 0;
                cState.L3      = ((byte)inputReport[6] & (1 << 6)) != 0;
                cState.Options = ((byte)inputReport[6] & (1 << 5)) != 0;
                cState.Share   = ((byte)inputReport[6] & (1 << 4)) != 0;
                cState.R1      = ((byte)inputReport[6] & (1 << 1)) != 0;
                cState.L1      = ((byte)inputReport[6] & (1 << 0)) != 0;

                cState.PS           = ((byte)inputReport[7] & (1 << 0)) != 0;
                cState.TouchButton  = (inputReport[7] & (1 << 2 - 1)) != 0;
                cState.FrameCounter = (byte)(inputReport[7] >> 2);

                // Store Gyro and Accel values
                Array.Copy(inputReport, 14, accel, 0, 6);
                Array.Copy(inputReport, 20, gyro, 0, 6);
                sixAxis.handleSixaxis(gyro, accel, cState);

                try
                {
                    charging       = (inputReport[30] & 0x10) != 0;
                    battery        = (inputReport[30] & 0x0f) * 10;
                    cState.Battery = (byte)battery;
                    if (inputReport[30] != priorInputReport30)
                    {
                        priorInputReport30 = inputReport[30];
                        Console.WriteLine(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "> power subsystem octet: 0x" + inputReport[30].ToString("x02"));
                    }
                }
                catch { currerror = "Index out of bounds: battery"; }
                // XXX DS4State mapping needs fixup, turn touches into an array[4] of structs.  And include the touchpad details there instead.
                try
                {
                    for (int touches = inputReport[-1 + DS4Touchpad.TOUCHPAD_DATA_OFFSET - 1], touchOffset = 0; touches > 0; touches--, touchOffset += 9)
                    {
                        cState.TouchPacketCounter = inputReport[-1 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset];
                        cState.Touch1             = (inputReport[0 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] >> 7) != 0 ? false : true; // >= 1 touch detected
                        cState.Touch1Identifier   = (byte)(inputReport[0 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] & 0x7f);
                        cState.Touch2             = (inputReport[4 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] >> 7) != 0 ? false : true; // 2 touches detected
                        cState.Touch2Identifier   = (byte)(inputReport[4 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] & 0x7f);
                        cState.TouchLeft          = (inputReport[1 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] + ((inputReport[2 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] & 0xF) * 255) >= 1920 * 2 / 5) ? false : true;
                        cState.TouchRight         = (inputReport[1 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] + ((inputReport[2 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] & 0xF) * 255) < 1920 * 2 / 5) ? false : true;
                        // Even when idling there is still a touch packet indicating no touch 1 or 2
                        touchpad.handleTouchpad(inputReport, cState, touchOffset);
                    }
                }
                catch { currerror = "Index out of bounds: touchpad"; }

                /* Debug output of incoming HID data:
                 * if (cState.L2 == 0xff && cState.R2 == 0xff)
                 * {
                 *  Console.Write(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + ">");
                 *  for (int i = 0; i < inputReport.Length; i++)
                 *      Console.Write(" " + inputReport[i].ToString("x2"));
                 *  Console.WriteLine();
                 * } */
                if (!isDS4Idle())
                {
                    lastActive = utcNow;
                }
                if (conType == ConnectionType.BT)
                {
                    bool shouldDisconnect = false;
                    if (IdleTimeout > 0)
                    {
                        if (isDS4Idle())
                        {
                            DateTime timeout = lastActive + TimeSpan.FromSeconds(IdleTimeout);
                            if (!Charging)
                            {
                                shouldDisconnect = utcNow >= timeout;
                            }
                        }
                    }
                    if (shouldDisconnect && DisconnectBT())
                    {
                        return; // all done
                    }
                }
                // XXX fix initialization ordering so the null checks all go away
                if (Report != null)
                {
                    Report(this, EventArgs.Empty);
                }
                sendOutputReport(false);
                if (!string.IsNullOrEmpty(error))
                {
                    error = string.Empty;
                }
                if (!string.IsNullOrEmpty(currerror))
                {
                    error = currerror;
                }
                cState.CopyTo(pState);
            }
        }
Example #2
0
        private void performEAll4Input()
        {
            firstActive = DateTime.UtcNow;
            System.Timers.Timer readTimeout = new System.Timers.Timer(); // Await 30 seconds for the initial packet, then 3 seconds thereafter.
            readTimeout.Elapsed += delegate { HidDevice.CancelIO(); };
            List <long> Latency = new List <long>();
            long        oldtime = 0;
            Stopwatch   sw      = new Stopwatch();

            sw.Start();
            while (true)
            {
                string currerror = string.Empty;
                Latency.Add(sw.ElapsedMilliseconds - oldtime);
                oldtime = sw.ElapsedMilliseconds;

                if (Latency.Count > 100)
                {
                    Latency.RemoveAt(0);
                }

                this.Latency = Latency.Average();

                if (this.Latency > 10 && !warn && sw.ElapsedMilliseconds > 4000)
                {
                    warn = true;
                    //System.Diagnostics.Trace.WriteLine(System.DateTime.UtcNow.ToString("o") + "> " + "Controller " + /*this.DeviceNum*/ + 1 + " (" + this.MacAddress + ") is experiencing latency issues. Currently at " + Math.Round(this.Latency, 2).ToString() + "ms of recomended maximum 10ms");
                }
                else if (this.Latency <= 10 && warn)
                {
                    warn = false;
                }

                if (readTimeout.Interval != 3000.0)
                {
                    if (readTimeout.Interval != 30000.0)
                    {
                        readTimeout.Interval = 30000.0;
                    }
                    else
                    {
                        readTimeout.Interval = 3000.0;
                    }
                }
                readTimeout.Enabled = true;
                if (conType != ConnectionType.USB)
                {
                    HidDevice.ReadStatus res = hDevice.ReadFile(btInputReport);
                    readTimeout.Enabled = false;
                    if (res == HidDevice.ReadStatus.Success)
                    {
                        Array.Copy(btInputReport, 0, inputReport, 0, inputReport.Length);
                    }
                    //else
                    //{
                    //    Console.WriteLine(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "> disconnect due to read failure: " + Marshal.GetLastWin32Error());
                    //    sendOutputReport(true); // Kick Windows into noticing the disconnection.
                    //    StopOutputUpdate();
                    //    IsDisconnecting = true;
                    //    if (Removal != null)
                    //        Removal(this, EventArgs.Empty);
                    //    return;

                    //}
                }
                else
                {
                    HidDevice.ReadStatus res = hDevice.ReadFile(inputReport);
                    readTimeout.Enabled = false;
                    if (res != HidDevice.ReadStatus.Success)
                    {
                        Console.WriteLine(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "> disconnect due to read failure: " + Marshal.GetLastWin32Error());
                        StopOutputUpdate();
                        IsDisconnecting = true;
                        if (Removal != null)
                        {
                            Removal(this, EventArgs.Empty);
                        }
                        return;
                    }
                }
                //if (ConnectionType == ConnectionType.BT && btInputReport[0] != 0x11)
                //{
                //    //Received incorrect report, skip it
                //    continue;
                //}
                DateTime utcNow = System.DateTime.UtcNow; // timestamp with UTC in case system time zone changes
                //resetHapticState();
                cState.ReportTimeStamp = utcNow;
                cState.LX = inputReport[5];
                cState.LY = inputReport[6];
                cState.RX = inputReport[7];
                cState.RY = inputReport[8];
                cState.LT = inputReport[11];
                cState.RT = inputReport[12];

                cState.A = ((byte)inputReport[1] & Convert.ToByte(1)) != 0;
                cState.B = ((byte)inputReport[1] & Convert.ToByte(2)) != 0;
                cState.X = ((byte)inputReport[1] & Convert.ToByte(8)) != 0;
                cState.Y = ((byte)inputReport[1] & Convert.ToByte(16)) != 0;
                switch (inputReport[4])
                {
                case 0: cState.DpadUp = true; cState.DpadDown = false; cState.DpadLeft = false; cState.DpadRight = false; break;

                case 1: cState.DpadUp = true; cState.DpadDown = false; cState.DpadLeft = false; cState.DpadRight = true; break;

                case 2: cState.DpadUp = false; cState.DpadDown = false; cState.DpadLeft = false; cState.DpadRight = true; break;

                case 3: cState.DpadUp = false; cState.DpadDown = true; cState.DpadLeft = false; cState.DpadRight = true; break;

                case 4: cState.DpadUp = false; cState.DpadDown = true; cState.DpadLeft = false; cState.DpadRight = false; break;

                case 5: cState.DpadUp = false; cState.DpadDown = true; cState.DpadLeft = true; cState.DpadRight = false; break;

                case 6: cState.DpadUp = false; cState.DpadDown = false; cState.DpadLeft = true; cState.DpadRight = false; break;

                case 7: cState.DpadUp = true; cState.DpadDown = false; cState.DpadLeft = true; cState.DpadRight = false; break;

                default: cState.DpadUp = false; cState.DpadDown = false; cState.DpadLeft = false; cState.DpadRight = false; break;
                }

                cState.RS = ((byte)inputReport[2] & Convert.ToByte(64)) != 0;
                var leftStick = ((byte)inputReport[2] & Convert.ToByte(32)) != 0;
                cState.LS = leftStick;
                var menu = ((byte)inputReport[2] & Convert.ToByte(8)) != 0;
                var back = ((byte)inputReport[2] & Convert.ToByte(4)) != 0;
                cState.Start = menu;
                cState.Back  = back;
                cState.LB    = ((byte)inputReport[1] & Convert.ToByte(64)) != 0;
                cState.RB    = ((byte)inputReport[1] & Convert.ToByte(128)) != 0;

                cState.Guide = menu && leftStick;
                // XXX fix initialization ordering so the null checks all go away
                if (Report != null)
                {
                    Report(this, EventArgs.Empty);
                }
                //sendOutputReport(false);
                if (!string.IsNullOrEmpty(error))
                {
                    error = string.Empty;
                }
                if (!string.IsNullOrEmpty(currerror))
                {
                    error = currerror;
                }
                cState.CopyTo(pState);
            }
        }
Example #3
0
        private void performDs4Input()
        {
            firstActive = DateTime.UtcNow;
            NativeMethods.HidD_SetNumInputBuffers(hDevice.safeReadHandle.DangerousGetHandle(), 2);
            //List<long> latencyList = new List<long>(51); // Set capacity at max + 1 to avoid any list resizing
            Queue <long> latencyQueue     = new Queue <long>(51); // Set capacity at max + 1 to avoid any resizing
            int          tempLatencyCount = 0;
            long         oldtime          = 0;
            string       currerror        = string.Empty;
            long         curtime          = 0;
            Stopwatch    sw = new Stopwatch();

            sw.Start();
            timeoutEvent = false;

            int maxBatteryValue = 0;
            int tempBattery     = 0;

            while (!exitInputThread)
            {
                oldCharging          = charging;
                currerror            = string.Empty;
                curtime              = sw.ElapsedMilliseconds;
                this.lastTimeElapsed = curtime - oldtime;
                //latencyList.Add(this.lastTimeElapsed);
                latencyQueue.Enqueue(this.lastTimeElapsed);
                tempLatencyCount++;
                oldtime = curtime;

                if (tempLatencyCount > 50)
                {
                    //latencyList.RemoveAt(0);
                    latencyQueue.Dequeue();
                    tempLatencyCount--;
                }

                //Latency = latencyList.Average();
                //latencyList.Average();
                Latency = latencyQueue.Average();

                if (conType == ConnectionType.BT)
                {
                    //HidDevice.ReadStatus res = hDevice.ReadFile(btInputReport);
                    //HidDevice.ReadStatus res = hDevice.ReadAsyncWithFileStream(btInputReport, READ_STREAM_TIMEOUT);
                    HidDevice.ReadStatus res = hDevice.ReadWithFileStream(btInputReport);
                    timeoutEvent = false;
                    //HidDevice.ReadStatus res = hDevice.ReadFileOverlapped(btInputReport, READ_STREAM_TIMEOUT);
                    if (res == HidDevice.ReadStatus.Success)
                    {
                        Array.Copy(btInputReport, 2, inputReport, 0, inputReport.Length);
                    }
                    else
                    {
                        if (res == HidDevice.ReadStatus.WaitTimedOut)
                        {
                            Log.LogToGui(Mac.ToString() + " disconnected due to timeout", true);
                        }
                        else
                        {
                            int winError = Marshal.GetLastWin32Error();
                            Console.WriteLine(Mac.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "> disconnect due to read failure: " + winError);
                            //Log.LogToGui(Mac.ToString() + " disconnected due to read failure: " + winError, true);
                        }

                        sendOutputReport(true); // Kick Windows into noticing the disconnection.
                        StopOutputUpdate();
                        isDisconnecting = true;
                        uiContext.Send(new SendOrPostCallback(delegate(object state4)
                        {
                            Removal?.Invoke(this, EventArgs.Empty);
                        }), null);

                        //System.Threading.Tasks.Task.Factory.StartNew(() => { Removal?.Invoke(this, EventArgs.Empty); });
                        //Removal?.Invoke(this, EventArgs.Empty);

                        timeoutExecuted = true;
                        return;
                    }
                }
                else
                {
                    //HidDevice.ReadStatus res = hDevice.ReadFile(inputReport);
                    //Array.Clear(inputReport, 0, inputReport.Length);
                    //HidDevice.ReadStatus res = hDevice.ReadAsyncWithFileStream(inputReport, READ_STREAM_TIMEOUT);
                    HidDevice.ReadStatus res = hDevice.ReadWithFileStream(inputReport);
                    //HidDevice.ReadStatus res = hDevice.ReadFileOverlapped(inputReport, READ_STREAM_TIMEOUT);
                    if (res != HidDevice.ReadStatus.Success)
                    {
                        if (res == HidDevice.ReadStatus.WaitTimedOut)
                        {
                            Log.LogToGui(Mac.ToString() + " disconnected due to timeout", true);
                        }
                        else
                        {
                            int winError = Marshal.GetLastWin32Error();
                            Console.WriteLine(Mac.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "> disconnect due to read failure: " + winError);
                            //Log.LogToGui(Mac.ToString() + " disconnected due to read failure: " + winError, true);
                        }

                        StopOutputUpdate();
                        isDisconnecting = true;
                        uiContext.Send(new SendOrPostCallback(delegate(object state4)
                        {
                            Removal?.Invoke(this, EventArgs.Empty);
                        }), null);

                        //System.Threading.Tasks.Task.Factory.StartNew(() => { Removal?.Invoke(this, EventArgs.Empty); });
                        //Removal?.Invoke(this, EventArgs.Empty);

                        timeoutExecuted = true;
                        return;
                    }
                    else
                    {
                        //Array.Copy(inputReport2, 0, inputReport, 0, inputReport.Length);
                    }
                }

                if (conType == ConnectionType.BT && btInputReport[0] != 0x11)
                {
                    //Received incorrect report, skip it
                    continue;
                }

                DateTime utcNow = DateTime.UtcNow; // timestamp with UTC in case system time zone changes
                resetHapticState();
                cState.ReportTimeStamp = utcNow;
                cState.LX = inputReport[1];
                cState.LY = inputReport[2];
                cState.RX = inputReport[3];
                cState.RY = inputReport[4];
                cState.L2 = inputReport[8];
                cState.R2 = inputReport[9];

                cState.Triangle = (inputReport[5] & (1 << 7)) != 0;
                cState.Circle   = (inputReport[5] & (1 << 6)) != 0;
                cState.Cross    = (inputReport[5] & (1 << 5)) != 0;
                cState.Square   = (inputReport[5] & (1 << 4)) != 0;

                // First 4 bits denote dpad state. Clock representation
                // with 8 meaning centered and 0 meaning DpadUp.
                byte dpad_state = (byte)(inputReport[5] & 0x0F);

                switch (dpad_state)
                {
                case 0: cState.DpadUp = true; cState.DpadDown = false; cState.DpadLeft = false; cState.DpadRight = false; break;

                case 1: cState.DpadUp = true; cState.DpadDown = false; cState.DpadLeft = false; cState.DpadRight = true; break;

                case 2: cState.DpadUp = false; cState.DpadDown = false; cState.DpadLeft = false; cState.DpadRight = true; break;

                case 3: cState.DpadUp = false; cState.DpadDown = true; cState.DpadLeft = false; cState.DpadRight = true; break;

                case 4: cState.DpadUp = false; cState.DpadDown = true; cState.DpadLeft = false; cState.DpadRight = false; break;

                case 5: cState.DpadUp = false; cState.DpadDown = true; cState.DpadLeft = true; cState.DpadRight = false; break;

                case 6: cState.DpadUp = false; cState.DpadDown = false; cState.DpadLeft = true; cState.DpadRight = false; break;

                case 7: cState.DpadUp = true; cState.DpadDown = false; cState.DpadLeft = true; cState.DpadRight = false; break;

                case 8:
                default: cState.DpadUp = false; cState.DpadDown = false; cState.DpadLeft = false; cState.DpadRight = false; break;
                }

                cState.R3      = (inputReport[6] & (1 << 7)) != 0;
                cState.L3      = (inputReport[6] & (1 << 6)) != 0;
                cState.Options = (inputReport[6] & (1 << 5)) != 0;
                cState.Share   = (inputReport[6] & (1 << 4)) != 0;
                cState.R1      = (inputReport[6] & (1 << 1)) != 0;
                cState.L1      = (inputReport[6] & (1 << 0)) != 0;

                cState.PS           = (inputReport[7] & (1 << 0)) != 0;
                cState.TouchButton  = (inputReport[7] & (1 << 2 - 1)) != 0;
                cState.FrameCounter = (byte)(inputReport[7] >> 2);

                // Store Gyro and Accel values
                Array.Copy(inputReport, 14, accel, 0, 6);
                Array.Copy(inputReport, 20, gyro, 0, 6);
                sixAxis.handleSixaxis(gyro, accel, cState);

                try
                {
                    charging        = (inputReport[30] & 0x10) != 0;
                    maxBatteryValue = charging ? BATTERY_MAX_USB : BATTERY_MAX;
                    tempBattery     = (inputReport[30] & 0x0f) * 100 / maxBatteryValue;
                    battery         = Math.Min((byte)tempBattery, (byte)100);
                    cState.Battery  = (byte)battery;
                    //System.Diagnostics.Debug.WriteLine("CURRENT BATTERY: " + (inputReport[30] & 0x0f) + " | " + tempBattery + " | " + battery);
                    if (inputReport[30] != priorInputReport30)
                    {
                        priorInputReport30 = inputReport[30];
                        //Console.WriteLine(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "> power subsystem octet: 0x" + inputReport[30].ToString("x02"));
                    }
                }
                catch { currerror = "Index out of bounds: battery"; }

                // XXX DS4State mapping needs fixup, turn touches into an array[4] of structs.  And include the touchpad details there instead.
                try
                {
                    // Only care if one touch packet is detected. Other touch packets
                    // don't seem to contain relevant data. ds4drv does not use them either.
                    for (int touches = Math.Max((int)(inputReport[-1 + DS4Touchpad.TOUCHPAD_DATA_OFFSET - 1]), 1), touchOffset = 0; touches > 0; touches--, touchOffset += 9)
                    //for (int touches = inputReport[-1 + DS4Touchpad.TOUCHPAD_DATA_OFFSET - 1], touchOffset = 0; touches > 0; touches--, touchOffset += 9)
                    {
                        cState.TouchPacketCounter = inputReport[-1 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset];
                        cState.Touch1             = (inputReport[0 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] >> 7) != 0 ? false : true; // >= 1 touch detected
                        cState.Touch1Identifier   = (byte)(inputReport[0 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] & 0x7f);
                        cState.Touch2             = (inputReport[4 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] >> 7) != 0 ? false : true; // 2 touches detected
                        cState.Touch2Identifier   = (byte)(inputReport[4 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] & 0x7f);
                        cState.TouchLeft          = (inputReport[1 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] + ((inputReport[2 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] & 0xF) * 255) >= 1920 * 2 / 5) ? false : true;
                        cState.TouchRight         = (inputReport[1 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] + ((inputReport[2 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] & 0xF) * 255) < 1920 * 2 / 5) ? false : true;
                        // Even when idling there is still a touch packet indicating no touch 1 or 2
                        touchpad.handleTouchpad(inputReport, cState, touchOffset);
                    }
                }
                catch { currerror = "Index out of bounds: touchpad"; }

                /* Debug output of incoming HID data:
                 * if (cState.L2 == 0xff && cState.R2 == 0xff)
                 * {
                 *  Console.Write(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + ">");
                 *  for (int i = 0; i < inputReport.Length; i++)
                 *      Console.Write(" " + inputReport[i].ToString("x2"));
                 *  Console.WriteLine();
                 * } */

                if (conType == ConnectionType.SONYWA)
                {
                    bool controllerSynced = inputReport[31] == 0;
                    if (controllerSynced != synced)
                    {
                        synced = controllerSynced;
                        SyncChange?.Invoke(this, EventArgs.Empty);
                    }
                }

                bool ds4Idle = cState.FrameCounter == pState.FrameCounter;
                if (!ds4Idle)
                {
                    isRemoved = false;
                }

                if (conType == ConnectionType.USB)
                {
                    lastActive = utcNow;
                }
                else
                {
                    bool shouldDisconnect = false;
                    int  idleTime         = idleTimeout;
                    if (!isRemoved && idleTime > 0)
                    {
                        bool idleInput = isDS4Idle();
                        if (idleInput)
                        {
                            DateTime timeout = lastActive + TimeSpan.FromSeconds(idleTime);
                            if (!charging)
                            {
                                shouldDisconnect = utcNow >= timeout;
                            }
                        }
                        else
                        {
                            lastActive = utcNow;
                        }
                    }
                    else
                    {
                        lastActive = utcNow;
                    }

                    if (shouldDisconnect)
                    {
                        Log.LogToGui(Mac.ToString() + " disconnecting due to idle disconnect", false);

                        if (conType == ConnectionType.BT)
                        {
                            if (DisconnectBT(true))
                            {
                                timeoutExecuted = true;
                                return; // all done
                            }
                        }
                        else if (conType == ConnectionType.SONYWA)
                        {
                            DisconnectDongle();
                        }
                    }
                }

                if (oldCharging != charging && conType == ConnectionType.BT)
                {
                    if (Global.getQuickCharge() && charging)
                    {
                        DisconnectBT(true);
                        timeoutExecuted = true;
                        return;
                    }
                }

                if (Report != null)
                {
                    Report(this, EventArgs.Empty);
                }

                bool syncWriteReport = true;
                if (conType == ConnectionType.BT)
                {
                    syncWriteReport = false;
                }
                sendOutputReport(syncWriteReport);

                if (!string.IsNullOrEmpty(currerror))
                {
                    error = currerror;
                }
                else if (!string.IsNullOrEmpty(error))
                {
                    error = string.Empty;
                }

                cState.CopyTo(pState);

                lock (eventQueueLock)
                {
                    Action tempAct = null;
                    for (int actInd = 0, actLen = eventQueue.Count; actInd < actLen; actInd++)
                    //foreach (Action tempAct in eventQueue)
                    {
                        tempAct = eventQueue.Dequeue();
                        tempAct.Invoke();
                    }

                    //eventQueue.Clear();
                }
            }

            timeoutExecuted = true;
        }
Example #4
0
        private void InputListener()
        {
            //if (settings.getSetting("Low latency mode"))
            //    inputReport = new byte[10];

            byte[] accel = new byte[6];
            byte[] gyro  = new byte[6];

            Thread.Sleep(500);
            sendHaptic();
            bool isResponding = true;

            lastReport.Start();
            while (isResponding)
            {
                if (!isDeviceResponding(hDevice))
                {
                    Dispose();
                }

                if (DeviceConnectionType == ConnectionTypes.BT)
                {
                    HidDevice.ReadStatus readStatus = hDevice.ReadFile(btInputReport);
                    if (readStatus == HidDevice.ReadStatus.Success)
                    {
                        Array.Copy(btInputReport, 2, inputReport, 0, inputReport.Length);
                    }
                    else
                    {
                        isResponding = false;
                    }
                }
                else if (DeviceConnectionType == ConnectionTypes.USB)
                {
                    HidDevice.ReadStatus readStatus = hDevice.ReadFile(inputReport);
                    if (readStatus != HidDevice.ReadStatus.Success)
                    {
                        isResponding = false;
                    }
                }
                if (isResponding)
                {
                    lastReport.Restart();
                }

                deviceClass.LSx.Value = SafeStickValue(inputReport[1] - 127) / 127f;
                deviceClass.LSy.Value = SafeStickValue(inputReport[2] - 127) / 127f;
                deviceClass.RSx.Value = SafeStickValue(inputReport[3] - 127) / 127f;
                deviceClass.RSy.Value = SafeStickValue(inputReport[4] - 127) / 127f;
                deviceClass.L2.Value  = inputReport[8] / 255f;
                deviceClass.R2.Value  = inputReport[9] / 255f;

                deviceClass.Triangle.Value = ((byte)inputReport[5] & (1 << 7)) != 0;
                deviceClass.Circle.Value   = ((byte)inputReport[5] & (1 << 6)) != 0;
                deviceClass.Cross.Value    = ((byte)inputReport[5] & (1 << 5)) != 0;
                deviceClass.Square.Value   = ((byte)inputReport[5] & (1 << 4)) != 0;
                bool RDpadUp    = ((byte)inputReport[5] & (1 << 3)) != 0;
                bool RDpadDown  = ((byte)inputReport[5] & (1 << 2)) != 0;
                bool RDpadLeft  = ((byte)inputReport[5] & (1 << 1)) != 0;
                bool RDpadRight = ((byte)inputReport[5] & (1 << 0)) != 0;

                byte dpad_state = 0;

                dpad_state = (byte)(
                    ((RDpadRight ? 1 : 0) << 0) |
                    ((RDpadLeft ? 1 : 0) << 1) |
                    ((RDpadDown ? 1 : 0) << 2) |
                    ((RDpadUp ? 1 : 0) << 3));

                switch (dpad_state)
                {
                case 0: deviceClass.DUp.Value = true; deviceClass.DDown.Value = false; deviceClass.DLeft.Value = false; deviceClass.DRight.Value = false; break;

                case 1: deviceClass.DUp.Value = true; deviceClass.DDown.Value = false; deviceClass.DLeft.Value = false; deviceClass.DRight.Value = true; break;

                case 2: deviceClass.DUp.Value = false; deviceClass.DDown.Value = false; deviceClass.DLeft.Value = false; deviceClass.DRight.Value = true; break;

                case 3: deviceClass.DUp.Value = false; deviceClass.DDown.Value = true; deviceClass.DLeft.Value = false; deviceClass.DRight.Value = true; break;

                case 4: deviceClass.DUp.Value = false; deviceClass.DDown.Value = true; deviceClass.DLeft.Value = false; deviceClass.DRight.Value = false; break;

                case 5: deviceClass.DUp.Value = false; deviceClass.DDown.Value = true; deviceClass.DLeft.Value = true; deviceClass.DRight.Value = false; break;

                case 6: deviceClass.DUp.Value = false; deviceClass.DDown.Value = false; deviceClass.DLeft.Value = true; deviceClass.DRight.Value = false; break;

                case 7: deviceClass.DUp.Value = true; deviceClass.DDown.Value = false; deviceClass.DLeft.Value = true; deviceClass.DRight.Value = false; break;

                case 8: deviceClass.DUp.Value = false; deviceClass.DDown.Value = false; deviceClass.DLeft.Value = false; deviceClass.DRight.Value = false; break;
                }

                deviceClass.R3.Value      = ((byte)inputReport[6] & (1 << 7)) != 0;
                deviceClass.L3.Value      = ((byte)inputReport[6] & (1 << 6)) != 0;
                deviceClass.Options.Value = ((byte)inputReport[6] & (1 << 5)) != 0;
                deviceClass.Share.Value   = ((byte)inputReport[6] & (1 << 4)) != 0;
                deviceClass.R1.Value      = ((byte)inputReport[6] & (1 << 1)) != 0;
                deviceClass.L1.Value      = ((byte)inputReport[6] & (1 << 0)) != 0;

                deviceClass.PS.Value             = ((byte)inputReport[7] & (1 << 0)) != 0;
                deviceClass.TouchpadButton.Value = (inputReport[7] & (1 << 2 - 1)) != 0;

                Array.Copy(inputReport, 14, accel, 0, 6);
                Array.Copy(inputReport, 20, gyro, 0, 6);

                bool  charging = (inputReport[30] & 0x10) != 0;
                float battery  = (inputReport[30] & 0x0f) / 10;
                if (!charging)
                {
                    battery += 10;
                }
                battery = Math.Max(battery, 0f);
                battery = Math.Min(battery, 1f);
                deviceClass.Charging.Value = charging;
                deviceClass.Battery.Value  = battery;

                deviceClass.AccelX.Value = (Int16)((UInt16)(accel[0] << 8) | accel[1]) / 65535f;
                deviceClass.AccelY.Value = (Int16)((UInt16)(accel[2] << 8) | accel[3]) / 65535f;
                deviceClass.AccelZ.Value = (Int16)((UInt16)(accel[4] << 8) | accel[5]) / 65535f;

                deviceClass.GyroX.Value = (Int16)((UInt16)(gyro[0] << 8) | gyro[1]) / 65535f;
                deviceClass.GyroY.Value = (Int16)((UInt16)(gyro[2] << 8) | gyro[3]) / 65535f;
                deviceClass.GyroZ.Value = (Int16)((UInt16)(gyro[4] << 8) | gyro[5]) / 65535f;

                for (int touches = inputReport[-1 + TOUCHPAD_DATA_OFFSET - 1], touchOffset = 0; touches > 0; touches--, touchOffset += 9)
                {
                    //TouchPacketCounter = inputReport[-1 + TOUCHPAD_DATA_OFFSET + touchOffset];
                    deviceClass.TouchpadTouchOne.Value = (inputReport[0 + TOUCHPAD_DATA_OFFSET + touchOffset] >> 7) != 0 ? false : true; // >= 1 touch detected

                    //Touch1Identifier = (byte)(inputReport[0 + TOUCHPAD_DATA_OFFSET + touchOffset] & 0x7f);
                    deviceClass.TouchpadTouchTwo.Value = (inputReport[4 + TOUCHPAD_DATA_OFFSET + touchOffset] >> 7) != 0 ? false : true; // 2 touches detected
                    //Touch2Identifier = (byte)(inputReport[4 + TOUCHPAD_DATA_OFFSET + touchOffset] & 0x7f);

                    byte touchID1 = (byte)(inputReport[0 + TOUCHPAD_DATA_OFFSET + touchOffset] & 0x7F);
                    byte touchID2 = (byte)(inputReport[4 + TOUCHPAD_DATA_OFFSET + touchOffset] & 0x7F);
                    deviceClass.TouchpadTouchOneX.Value = (inputReport[1 + TOUCHPAD_DATA_OFFSET + touchOffset] + ((inputReport[2 + TOUCHPAD_DATA_OFFSET + touchOffset] & 0xF) * 255)) / 1920f;
                    deviceClass.TouchpadTouchOneY.Value = (((inputReport[2 + TOUCHPAD_DATA_OFFSET + touchOffset] & 0xF0) >> 4) + (inputReport[3 + TOUCHPAD_DATA_OFFSET + touchOffset] * 16)) / 950f;
                    deviceClass.TouchpadTouchTwoX.Value = (inputReport[5 + TOUCHPAD_DATA_OFFSET + touchOffset] + ((inputReport[6 + TOUCHPAD_DATA_OFFSET + touchOffset] & 0xF) * 255)) / 1920f;
                    deviceClass.TouchpadTouchTwoY.Value = (((inputReport[6 + TOUCHPAD_DATA_OFFSET + touchOffset] & 0xF0) >> 4) + (inputReport[7 + TOUCHPAD_DATA_OFFSET + touchOffset] * 16)) / 950f;

                    //if (cState.Touch1)
                    //{
                    //    cState.TouchLeft = (inputReport[1 + TOUCHPAD_DATA_OFFSET + touchOffset] + ((inputReport[2 + TOUCHPAD_DATA_OFFSET + touchOffset] & 0xF) * 255) >= 1920 * 2 / 5) ? false : true;
                    //    cState.TouchRight = (inputReport[1 + TOUCHPAD_DATA_OFFSET + touchOffset] + ((inputReport[2 + TOUCHPAD_DATA_OFFSET + touchOffset] & 0xF) * 255) < 1920 * 2 / 5) ? false : true;
                    //}
                    // Even when idling there is still a touch packet indicating no touch 1 or 2
                    //touchpad.handleTouchpad(inputReport, cState, touchOffset);
                }



                //Console.WriteLine((((byte)255 << 8) | (byte)255));
            }
            Dispose();
        }