From 11008be55eb44cbca0eaa450a2e7e70f86bd47ec Mon Sep 17 00:00:00 2001 From: mika-n Date: Sat, 2 Nov 2019 21:01:54 +0200 Subject: [PATCH] If reading of hardware serial# (MAC) fails then readSerial function generates a runtime MAC adderss using devicePath value. This solves cases where UDPServer and Cemulator doesn't work with blank serials (and linkToProfile and 360SteeringWheel calibration linking to a certain gamepad). --- DS4Windows/HidLibrary/HidDevice.cs | 56 +++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/DS4Windows/HidLibrary/HidDevice.cs b/DS4Windows/HidLibrary/HidDevice.cs index e65703c..374c7f6 100644 --- a/DS4Windows/HidLibrary/HidDevice.cs +++ b/DS4Windows/HidLibrary/HidDevice.cs @@ -488,10 +488,6 @@ namespace DS4Windows if (readFeatureData(buffer)) serial = String.Format("{0:X02}:{1:X02}:{2:X02}:{3:X02}:{4:X02}:{5:X02}", buffer[6], buffer[5], buffer[4], buffer[3], buffer[2], buffer[1]); - else - serial = BLANK_SERIAL; - - return serial; } else { @@ -507,11 +503,55 @@ namespace DS4Windows MACAddr = $"{MACAddr[0]}{MACAddr[1]}:{MACAddr[2]}{MACAddr[3]}:{MACAddr[4]}{MACAddr[5]}:{MACAddr[6]}{MACAddr[7]}:{MACAddr[8]}{MACAddr[9]}:{MACAddr[10]}{MACAddr[11]}"; serial = MACAddr; } - else - serial = BLANK_SERIAL; - - return serial; } + + // If serial# reading failed then generate a dummy MAC address based on HID device path (WinOS generated runtime unique value based on connected usb port and hub or BT channel). + // The device path remains the same as long the gamepad is always connected to the same usb/BT port, but may be different in other usb ports. Therefore this value is unique + // as long the same device is always connected to the same usb port. + if (serial == null) + { + string MACAddr = string.Empty; + + AppLogger.LogToGui($"WARNING: Failed to read serial# from a gamepad ({this._deviceAttributes.VendorHexId}/{this._deviceAttributes.ProductHexId}). Generating MAC address from a device path. From now on you should connect this gamepad always into the same USB port or BT pairing host to keep the same device path.", true); + + try + { + // Substring: \\?\hid#vid_054c&pid_09cc&mi_03#7&1f882A25&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030} -> \\?\hid#vid_054c&pid_09cc&mi_03#7&1f882A25&0&0001# + int endPos = this.DevicePath.LastIndexOf('{'); + if (endPos < 0) + endPos = this.DevicePath.Length; + + // String array: \\?\hid#vid_054c&pid_09cc&mi_03#7&1f882A25&0&0001# -> [0]=\\?\hidvid_054c, [1]=pid_09cc, [2]=mi_037, [3]=1f882A25, [4]=0, [5]=0001 + string[] devPathItems = this.DevicePath.Substring(0, endPos).Replace("#", "").Replace("-", "").Replace("{", "").Replace("}", "").Split('&'); + + if (devPathItems.Length >= 3) + MACAddr = devPathItems[devPathItems.Length - 3].ToUpper() // 1f882A25 + + devPathItems[devPathItems.Length - 2].ToUpper() // 0 + + devPathItems[devPathItems.Length - 1].TrimStart('0').ToUpper(); // 0001 -> 1 + else if (devPathItems.Length >= 1) + // Device and usb hub and port identifiers missing in devicePath string. Fallback to use vendor and product ID values and + // take a number from the last part of the devicePath. Hopefully the last part is a usb port number as it usually should be. + MACAddr = this._deviceAttributes.VendorId.ToString("X4") + + this._deviceAttributes.ProductId.ToString("X4") + + devPathItems[devPathItems.Length - 1].TrimStart('0').ToUpper(); + + if (!string.IsNullOrEmpty(MACAddr)) + { + MACAddr = MACAddr.PadRight(12, '0'); + serial = $"{MACAddr[0]}{MACAddr[1]}:{MACAddr[2]}{MACAddr[3]}:{MACAddr[4]}{MACAddr[5]}:{MACAddr[6]}{MACAddr[7]}:{MACAddr[8]}{MACAddr[9]}:{MACAddr[10]}{MACAddr[11]}"; + } + else + // Hmm... Shold never come here. Strange format in devicePath because all identifier items of devicePath string are missing. + serial = BLANK_SERIAL; + } + catch (Exception e) + { + AppLogger.LogToGui($"ERROR: Failed to generate runtime MAC address from device path {this.DevicePath}. {e.Message}", true); + serial = BLANK_SERIAL; + } + } + + return serial; } } }