From 627ee5f2f803cd36eaca1f9edf428ada2f0576d9 Mon Sep 17 00:00:00 2001 From: Butterscotch! Date: Tue, 6 Aug 2024 09:37:33 -0400 Subject: [PATCH] Show version & add error popup --- SlimeVrOta.Gui/MainWindow.axaml | 51 ++++++++++++++++- SlimeVrOta.Gui/MainWindow.axaml.cs | 89 +++++++++++++++++++++++++----- SlimeVrOta/Constants.cs | 7 +++ SlimeVrOta/Program.cs | 2 + 4 files changed, 131 insertions(+), 18 deletions(-) create mode 100644 SlimeVrOta/Constants.cs diff --git a/SlimeVrOta.Gui/MainWindow.axaml b/SlimeVrOta.Gui/MainWindow.axaml index 53ec271..07a7dc1 100644 --- a/SlimeVrOta.Gui/MainWindow.axaml +++ b/SlimeVrOta.Gui/MainWindow.axaml @@ -6,6 +6,7 @@ Title="SlimeVR OTA Tool" Icon="/Assets/icon.png" SizeToContent="WidthAndHeight" + WindowStartupLocation="CenterScreen" Padding="8" Background="{DynamicResource BackgroundBrush}"> @@ -15,12 +16,14 @@ WhiteSmoke #e2d8eb + #706080 1 1 8 2 #c5c5c5 #d080ff #252525 #383442 + #908892 1 1 8 2 #161616 #a070d0 @@ -28,7 +31,48 @@ - + + + + + + + + Unknown error. + + + + + + + + - - diff --git a/SlimeVrOta.Gui/MainWindow.axaml.cs b/SlimeVrOta.Gui/MainWindow.axaml.cs index 37a9ef3..55da7fc 100644 --- a/SlimeVrOta.Gui/MainWindow.axaml.cs +++ b/SlimeVrOta.Gui/MainWindow.axaml.cs @@ -27,7 +27,7 @@ public enum FlashState Error } - public FilePickerFileType ZipFileType = + public static readonly FilePickerFileType ZipFileType = new("ZIP archive") { Patterns = ["*.zip"], @@ -35,7 +35,7 @@ public enum FlashState MimeTypes = ["application/zip", "x-zip-compressed"], }; - public FilePickerFileType BinFileType = + public static readonly FilePickerFileType BinFileType = new("Firmware binary") { Patterns = ["*.bin"], @@ -43,12 +43,25 @@ public enum FlashState MimeTypes = ["application/octet-stream"], }; + public static readonly FilePickerFileType FirmwareFileType = + new("Firmware ZIP or binary") + { + Patterns = [.. ZipFileType.Patterns, .. BinFileType.Patterns], + AppleUniformTypeIdentifiers = + [ + .. ZipFileType.AppleUniformTypeIdentifiers, + .. BinFileType.AppleUniformTypeIdentifiers + ], + MimeTypes = [.. ZipFileType.MimeTypes, .. BinFileType.MimeTypes], + }; + private IStorageFile? _firmwareFile; private static readonly int _port = 6969; private readonly byte[] _udpBuffer = new byte[65535]; private static readonly IPEndPoint _localEndPoint = new(IPAddress.Any, _port); + private bool _runDiscoveryOnClose = false; private Socket? _socket; private IPEndPoint _endPoint = new(IPAddress.Any, _port); @@ -75,12 +88,11 @@ public MainWindow() { InitializeComponent(); + CloseErrorButton.Click += CloseError; FirmwareDropBox.AddHandler(DragDrop.DropEvent, SelectFirmwareDrop); SelectFileButton.Click += SelectFirmwareBrowse; RemoveTrackerButton.Click += RemoveTracker; FlashButton.Click += FlashFirmware; - - _ = ReceiveHandshake(); } protected override void OnLoaded(RoutedEventArgs e) @@ -90,8 +102,10 @@ protected override void OnLoaded(RoutedEventArgs e) MinWidth = Width + 100; MinHeight = Height; MaxHeight = Height; - SizeToContent = SizeToContent.Manual; + Title = $"SlimeVR OTA Tool v{Constants.Version}"; + + _ = ReceiveHandshake(); } protected override void OnClosed(EventArgs e) @@ -102,6 +116,24 @@ protected override void OnClosed(EventArgs e) _socket = null; } + private void ShowError(string text) + { + ErrorText.Text = text; + ErrorPopup.IsOpen = true; + } + + public void CloseError(object? sender, RoutedEventArgs e) + { + ErrorText.Text = "Unknown error."; + ErrorPopup.IsOpen = false; + + if (_runDiscoveryOnClose && CurrentState == FlashState.Connecting) + { + _ = ReceiveHandshake(5000); + } + _runDiscoveryOnClose = false; + } + private void UpdateFileStatus() { if (CanAcceptFile) @@ -163,7 +195,7 @@ public async void SelectFirmwareBrowse(object? sender, RoutedEventArgs e) new FilePickerOpenOptions() { Title = "Select firmware file...", - FileTypeFilter = [ZipFileType, BinFileType], + FileTypeFilter = [FirmwareFileType], AllowMultiple = false, } ); @@ -190,16 +222,42 @@ private void UpdateTrackerStatus() } } - public async Task ReceiveHandshake(CancellationToken cancelToken = default) + public async Task ReceiveHandshake(int delay = 0, CancellationToken cancelToken = default) { - if (_socket == null) + if (delay > 0) { - _socket = new Socket( - AddressFamily.InterNetwork, - SocketType.Dgram, - ProtocolType.Udp - ); - _socket.Bind(_localEndPoint); + try + { + await Task.Delay(delay, cancelToken); + } + catch + { + if (cancelToken.IsCancellationRequested) + return; + } + } + + if (_socket == null || _socket?.IsBound != true) + { + try + { + _socket?.Dispose(); + _socket = new Socket( + AddressFamily.InterNetwork, + SocketType.Dgram, + ProtocolType.Udp + ); + _socket.Bind(_localEndPoint); + } + catch (Exception ex) + { + Debug.WriteLine(ex); + _runDiscoveryOnClose = true; + ShowError( + $"Error while binding socket, make sure SlimeVR isn't running and port {_port} is not in use!\n\n{ex}" + ); + return; + } } while (!cancelToken.IsCancellationRequested && _socket.IsBound) @@ -366,7 +424,7 @@ public async void FlashFirmware(object? sender, RoutedEventArgs e) CurrentState = FlashState.Waiting; using var cancelSrc = new CancellationTokenSource(); - var handshake = ReceiveHandshake(cancelSrc.Token); + var handshake = ReceiveHandshake(cancelToken: cancelSrc.Token); // 45 second timeout, it should not take that long cancelSrc.CancelAfter(45000); @@ -398,6 +456,7 @@ public async void FlashFirmware(object? sender, RoutedEventArgs e) catch (Exception ex) { Debug.WriteLine(ex); + ShowError(ex.ToString()); CurrentState = FlashState.Error; } } diff --git a/SlimeVrOta/Constants.cs b/SlimeVrOta/Constants.cs new file mode 100644 index 0000000..1acb0a1 --- /dev/null +++ b/SlimeVrOta/Constants.cs @@ -0,0 +1,7 @@ +namespace SlimeVrOta +{ + public static class Constants + { + public static readonly string Version = "0.3.0"; + } +} diff --git a/SlimeVrOta/Program.cs b/SlimeVrOta/Program.cs index f2b85bb..1bf891d 100644 --- a/SlimeVrOta/Program.cs +++ b/SlimeVrOta/Program.cs @@ -5,6 +5,8 @@ try { + Console.WriteLine($"SlimeVR OTA Tool v{Constants.Version}"); + var file = new FileInfo("firmware-part-0.bin"); if (!file.Exists) {