From e1f6812e1b0a049bf8a471a8201b61a5cf0c5c36 Mon Sep 17 00:00:00 2001 From: andyvorld Date: Wed, 1 Jul 2020 13:04:19 +1000 Subject: [PATCH 1/2] Add PID fallback for wired devices --- LGSTrayBattery/LogiDevice.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/LGSTrayBattery/LogiDevice.cs b/LGSTrayBattery/LogiDevice.cs index 3eaf550..08aa0e7 100644 --- a/LGSTrayBattery/LogiDevice.cs +++ b/LGSTrayBattery/LogiDevice.cs @@ -2,12 +2,14 @@ using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; +using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using Device.Net; using Device.Net.Exceptions; +using Hid.Net.Windows; using PropertyChanged; namespace LGSTrayBattery @@ -176,8 +178,16 @@ private void ReadLoop() { while (_hidDevices[20].IsInitialized) { - var resData = _hidDevices[20].ReadAsync().Result; - ParseReport(resData); + try + { + var resData = _hidDevices[20].ReadAsync().Result; + ParseReport(resData); + } + catch (IOException e) + { + Debug.WriteLine(e.Message); + return; + } } } @@ -295,7 +305,7 @@ private async Task GetWPidAsync() } catch (Exception) { - _wpid = 0; + _wpid = (ushort) (_hidDevices[20].ConnectedDeviceDefinition.ProductId ?? 0); } } From e2689a16a57000f1c032a899196440028441601d Mon Sep 17 00:00:00 2001 From: andyvorld Date: Wed, 1 Jul 2020 16:41:59 +1000 Subject: [PATCH 2/2] Feature/read write dev (#1) * reorganised exceptions and listen * added crash dumping * Disconnection logic --- LGSTrayBattery/LGSTrayBattery.csproj | 1 + LGSTrayBattery/LogiDevice.cs | 197 +++++++++++++++----------- LGSTrayBattery/LogiDeviceException.cs | 16 +++ LGSTrayBattery/MainWindow.xaml.cs | 19 +++ LGSTrayBattery/MainWindowViewModel.cs | 16 ++- 5 files changed, 157 insertions(+), 92 deletions(-) create mode 100644 LGSTrayBattery/LogiDeviceException.cs diff --git a/LGSTrayBattery/LGSTrayBattery.csproj b/LGSTrayBattery/LGSTrayBattery.csproj index e550ad8..fef0096 100644 --- a/LGSTrayBattery/LGSTrayBattery.csproj +++ b/LGSTrayBattery/LGSTrayBattery.csproj @@ -88,6 +88,7 @@ Code + MainWindow.xaml diff --git a/LGSTrayBattery/LogiDevice.cs b/LGSTrayBattery/LogiDevice.cs index 08aa0e7..5228e52 100644 --- a/LGSTrayBattery/LogiDevice.cs +++ b/LGSTrayBattery/LogiDevice.cs @@ -69,7 +69,7 @@ private set private ushort _wpid; - private Thread _readThread; + private bool _listen = false; public LogiDevice(IEnumerable devices, string usbSerialId, out bool valid) { @@ -104,22 +104,15 @@ public LogiDevice(IEnumerable devices, string usbSerialId, out bool val if (_hidDevices.ContainsKey(7) && _hidDevices.ContainsKey(20)) { - try - { - _protocolVer = GetProtocolVer().Result; + _protocolVer = GetProtocolVer().Result; - if (_protocolVer >= 2.0) - { - valid = true; - } - else - { - Debug.WriteLine("HID++ 1.0 not supported"); - } + if (_protocolVer >= 2.0) + { + valid = true; } - catch (Exception) + else { - Debug.WriteLine("Device not paired"); + Debug.WriteLine("HID++ 1.0 not supported"); } } } @@ -130,25 +123,35 @@ public LogiDevice(IEnumerable devices, string usbSerialId, out bool val { hidDevice.Close(); } + + StopListen(); } - public async void UpdateBatteryPercentage() + public async Task UpdateBatteryPercentage() { - if (_featureList.ContainsKey("BATTERY_STATUS")) + try { - await WriteRequestAsync(7, 0x01, _featureList["BATTERY_STATUS"]); + if (_featureList.ContainsKey("BATTERY_STATUS")) + { + await WriteRequestAsync(7, 0x01, _featureList["BATTERY_STATUS"]).ConfigureAwait(false); + } + else + { + _ = UpdateBatteryVoltage(); + } } - else + catch (ApiException) { - UpdateBatteryVoltage(); + BatteryPercentage = Double.NaN; + BatteryVoltage = Double.NaN; } } - private async void UpdateBatteryVoltage() + private async Task UpdateBatteryVoltage() { if (_featureList.ContainsKey("BATTERY_VOLTAGE")) { - await WriteRequestAsync(7, 0x01, _featureList["BATTERY_VOLTAGE"]); + await WriteRequestAsync(7, 0x01, _featureList["BATTERY_VOLTAGE"]).ConfigureAwait(false); } } @@ -159,34 +162,47 @@ public async Task LoadDevice() await GetWPidAsync(); } - public async void Listen() + public async Task Listen() { + await _hidDevices[7].InitializeAsync(); await _hidDevices[20].InitializeAsync(); - _readThread = new Thread(ReadLoop); - _readThread.Start(); + //_readThread = new Thread(ReadLoop); + //_readThread.Start(); - UpdateBatteryPercentage(); + _listen = true; + + ReadLoopAsync(7); + ReadLoopAsync(20); } public void StopListen() { - _readThread?.Abort(); + _listen = false; } - private void ReadLoop() + private async void ReadLoopAsync(int hidNum) { - while (_hidDevices[20].IsInitialized) + while (_listen) { try { - var resData = _hidDevices[20].ReadAsync().Result; + await _hidDevices[hidNum].InitializeAsync(); + var resData = await _hidDevices[hidNum].ReadAsync().ConfigureAwait(false); ParseReport(resData); } + catch (ApiException e) + { + //Debug.WriteLine(e.Message); + BatteryPercentage = Double.NaN; + BatteryVoltage = Double.NaN; + await Task.Delay(500); + } catch (IOException e) { - Debug.WriteLine(e.Message); - return; + BatteryPercentage = Double.NaN; + BatteryVoltage = Double.NaN; + await Task.Delay(500); } } } @@ -196,24 +212,28 @@ private void ParseReport(byte[] resData) byte deviceId = resData[1]; byte functionIdx = resData[2]; + DebugParse(resData, 2); + + // Magic disconnect string + if (deviceId == 0x01 & functionIdx == 0x8F) + { + if (_featureList.ContainsValue(resData[3])) + { + Debug.WriteLine("Device disconnected"); + BatteryVoltage = Double.NaN; + } + } + if ((resData[3] & 0x0F) != _randSwid) { - Debug.WriteLine("Not our SWID"); + Debug.WriteLine("^^^Not our SWID^^^"); + return; } else { _randSwid = 0xFF; } - DebugParse(resData, 2); - - // Magic disconnect string - if (deviceId == 0xFF & functionIdx == 0x83 & resData[3] == 0xB5 & resData[4] == 0x30) - { - Debug.WriteLine("Device disconnected"); - BatteryVoltage = Double.NaN; - } - if ((_featureList.ContainsKey("BATTERY_VOLTAGE")) && (functionIdx == _featureList["BATTERY_VOLTAGE"])) { BatteryVoltage = 0.001 * ((resData[4] << 8) + resData[5]); @@ -303,25 +323,50 @@ private async Task GetWPidAsync() byte[] resData = await WriteReadRequestAsync(7, 0xFF, 0x83, 0xB5, new byte[] {0x20,}); _wpid = (UInt16)(((UInt16)resData[7] << 8) + resData[8]); } - catch (Exception) + catch (LogiDeviceException e) { _wpid = (ushort) (_hidDevices[20].ConnectedDeviceDefinition.ProductId ?? 0); + Debug.WriteLine(e.Message); } } private async Task GetProtocolVer() { - var resData = await WriteReadRequestAsync(7, 0x01, 0x00, 0x10, new byte[] { 0x00, 0x00, 0x88 }).ConfigureAwait(false); + try + { + var resData = await WriteReadRequestAsync(7, 0x01, 0x00, 0x10, new byte[] {0x00, 0x00, 0x88}); - if (resData[2] == 0x8F) + string verStr = $"{resData[4]:X}.{resData[5]:X}"; + + return double.Parse(verStr); + } + catch (LogiDeviceException e) { return 1.0; } - else + } + + private async Task WriteRequestAsync(int length, byte deviceId, byte featureIndex, byte functionId = 0x00, byte[] paramsBytes = null) + { + _randSwid = (byte)_rand.Next(1, 16); + + if (featureIndex < 0x80) { - string verStr = $"{resData[4]:X}.{resData[5]:X}"; + functionId |= _randSwid; + } - return double.Parse(verStr); + byte[] request = CreatePacket(length, deviceId, featureIndex, functionId, paramsBytes); + DebugParse(request, 1); + + try + { + await _hidDevices[7].InitializeAsync(); + await _hidDevices[7].WriteAsync(request); + } + catch (ApiException e) + { + BatteryPercentage = Double.NaN; + BatteryVoltage = Double.NaN; } } @@ -342,14 +387,24 @@ private async Task WriteReadRequestAsync(int length, byte deviceId, byte byte[] request = CreatePacket(length, deviceId, featureIndex, functionId, paramsBytes); DebugParse(request, 1); - var reportReturnShort = _hidDevices[7].ReadAsync(); - var reportReturnLong = _hidDevices[20].ReadAsync(); - await _hidDevices[7].WriteAsync(request); + byte[] resData; - var reportReturn = await await Task.WhenAny(reportReturnLong, reportReturnShort); + do + { + var reportReturnShort = _hidDevices[7].ReadAsync(); + var reportReturnLong = _hidDevices[20].ReadAsync(); + + var reportReturn = await await Task.WhenAny(reportReturnLong, reportReturnShort); + + resData = reportReturn; - byte[] resData = reportReturn.Data; + if (resData[2] == 0x8F) + { + throw new LogiDeviceException("HID++ 1.0 Error"); + } + + } while (featureIndex < 0x80 && (resData[3] & 0x0F) != randSwid); DebugParse(resData, 2); @@ -357,29 +412,17 @@ private async Task WriteReadRequestAsync(int length, byte deviceId, byte { if (resData[1] != deviceId) { - throw new Exception("Device ID mismatch"); + throw new LogiDeviceException("Device ID mismatch"); } if (resData[2] != featureIndex) { - throw new Exception("Feature Index mismatch"); + throw new LogiDeviceException("Feature Index mismatch"); } - //if ((resData[3] & 0xF0) != (featureIndex & 0xF0)) - //{ - // throw new Exception("Function ID mismatch"); - //} - - if ((resData[3] & 0x0F) != randSwid) - { - throw new Exception("SW ID mismatch"); - } - } - else - { - if (resData[2] == 0x8F) + if ((resData[3] & 0xF0) != (functionId & 0xF0)) { - throw new Exception("HID++ 1.0 Error"); + throw new LogiDeviceException("Function ID mismatch"); } } @@ -392,22 +435,6 @@ private async Task WriteReadRequestAsync(int length, byte deviceId, byte } } - private async Task WriteRequestAsync(int length, byte deviceId, byte featureIndex, byte functionId = 0x00, byte[] paramsBytes = null) - { - _randSwid = (byte)_rand.Next(1, 16); - - if (featureIndex < 0x80) - { - functionId |= _randSwid; - } - - byte[] request = CreatePacket(length, deviceId, featureIndex, functionId, paramsBytes); - DebugParse(request, 1); - - await _hidDevices[7].InitializeAsync(); - await _hidDevices[7].WriteAsync(request); - } - private byte[] CreatePacket(int length, byte deviceId, byte featureIndex, byte functionId = 0x00, byte[] paramsBytes = null) { byte[] output; @@ -423,7 +450,7 @@ private byte[] CreatePacket(int length, byte deviceId, byte featureIndex, byte f output[0] = 0x11; break; default: - throw new Exception("Invalid HID packet length."); + throw new LogiDeviceException("Invalid HID packet length."); } output[1] = deviceId; diff --git a/LGSTrayBattery/LogiDeviceException.cs b/LGSTrayBattery/LogiDeviceException.cs new file mode 100644 index 0000000..07462d7 --- /dev/null +++ b/LGSTrayBattery/LogiDeviceException.cs @@ -0,0 +1,16 @@ +using System; + +namespace LGSTrayBattery +{ + public class LogiDeviceException : Exception + { + public LogiDeviceException() + { + } + + public LogiDeviceException(string message) : base(message) + { + + } + } +} \ No newline at end of file diff --git a/LGSTrayBattery/MainWindow.xaml.cs b/LGSTrayBattery/MainWindow.xaml.cs index f321dc5..a03b413 100644 --- a/LGSTrayBattery/MainWindow.xaml.cs +++ b/LGSTrayBattery/MainWindow.xaml.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Diagnostics; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -27,6 +29,9 @@ public partial class MainWindow : Window public MainWindow() { InitializeComponent(); + + AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CrashHandler); + this.DataContext = viewModel; this.TaskbarIcon.Icon = LGSTrayBattery.Properties.Resources.Discovery; @@ -35,6 +40,11 @@ public MainWindow() worker.DoWork += new DoWorkEventHandler((s,e) => viewModel.LoadViewModel().Wait()); worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler((s, e) => { + if (e.Error != null) + { + throw e.Error; + } + TaskbarIcon.Icon = LGSTrayBattery.Properties.Resources.Unknown; viewModel.LoadLastSelected(); }); @@ -42,6 +52,15 @@ public MainWindow() worker.RunWorkerAsync(); } + private void CrashHandler(object sender, UnhandledExceptionEventArgs args) + { + Exception e = (Exception) args.ExceptionObject; + using (StreamWriter writer = new StreamWriter("./Crashlog.log", false)) + { + writer.WriteLine(e.ToString()); + } + } + private void ExitButton_OnClick(object sender, RoutedEventArgs e) { Environment.Exit(0); diff --git a/LGSTrayBattery/MainWindowViewModel.cs b/LGSTrayBattery/MainWindowViewModel.cs index d69fdf7..c005b57 100644 --- a/LGSTrayBattery/MainWindowViewModel.cs +++ b/LGSTrayBattery/MainWindowViewModel.cs @@ -43,6 +43,7 @@ private set UpdateThread?.Abort(); UpdateThread = new Thread(UpdateSelectedBattery); UpdateThread.Start(); + _selectedDevice = value; Properties.Settings.Default.LastUSBSerial = _selectedDevice.UsbSerialId; @@ -81,7 +82,7 @@ public async Task LoadViewModel() }; //Get the first available device and connect to it - var devices = DeviceManager.Current.GetDevicesAsync(deviceDefinitions).Result; + var devices = await DeviceManager.Current.GetDevicesAsync(deviceDefinitions).ConfigureAwait(false); var usbSerialRegex = new Regex(@"#.+?#(.+)&"); @@ -91,8 +92,8 @@ public async Task LoadViewModel() { string usbSerial = usbSerialRegex.Match(device.DeviceId).Groups[1].ToString(); - Debug.WriteLine(device.DeviceId); - Debug.WriteLine(usbSerial); + //Debug.WriteLine(device.DeviceId); + //Debug.WriteLine(usbSerial); if (hidDeviceGroups.ContainsKey(usbSerial)) { @@ -149,7 +150,8 @@ public void UpdateSelectedDevice(LogiDevice selectedDevice) SelectedDevice = selectedDevice; SelectedDevice.IsChecked = true; - SelectedDevice.Listen(); + _ = SelectedDevice.Listen(); + _ = SelectedDevice.UpdateBatteryPercentage(); } public void UpdateSelectedPollInterval(PollInterval selectedpollInterval) @@ -163,7 +165,7 @@ public void UpdateSelectedPollInterval(PollInterval selectedpollInterval) SelectedPollInterval.IsChecked = true; } - private void UpdateSelectedBattery() + private async void UpdateSelectedBattery() { while (true) { @@ -172,8 +174,8 @@ private void UpdateSelectedBattery() return; } - SelectedDevice.UpdateBatteryPercentage(); - Task.Delay(SelectedPollInterval.delayTime).Wait(); + await SelectedDevice.UpdateBatteryPercentage().ConfigureAwait(false); + await Task.Delay(SelectedPollInterval.delayTime).ConfigureAwait(false); } } }