diff --git a/ControlPad/Arduino/ArduinoController.cs b/ControlPad/Arduino/ArduinoController.cs index 853eeee..26f76a3 100644 --- a/ControlPad/Arduino/ArduinoController.cs +++ b/ControlPad/Arduino/ArduinoController.cs @@ -61,7 +61,7 @@ public static void Initialize(MainWindow mainWindow, EventHandler eventHandler) private static async Task TryOpenAsync() { - string? port = await Task.Run(() => ArduinoPortFinder.FindFirstArduinoPort()); + var (port, deviceId) = await Task.Run(() => ArduinoPortFinder.FindFirstArduinoPort()); if (port == null) { await _mainWindow.Dispatcher.InvokeAsync(() => @@ -99,11 +99,16 @@ await _mainWindow.Dispatcher.InvokeAsync(() => _readCts = new CancellationTokenSource(); _ = Task.Run(() => ReadLoopAsync(sp, _readCts.Token)); + string? serial = ArduinoPortFinder.ExtractSerial(deviceId); + BadgeType badge = await SubscriptionService.GetBadgeTypeAsync(serial); + _lastBadgeType = badge; + await _mainWindow.Dispatcher.InvokeAsync(() => { _mainWindow.BoardDisconnectedInfoBar.IsOpen = false; if (_mainWindow.NVI_Home.IsActive) _mainWindow.MainContentFrame.Navigate(_mainWindow._homeUserControl); _mainWindow.NVI_EditMode.Visibility = Visibility.Visible; + _mainWindow.UpdateBadgeType(badge); IsConnected = true; }); } diff --git a/ControlPad/Arduino/ArduinoPortFinder.cs b/ControlPad/Arduino/ArduinoPortFinder.cs index d1868f9..5a0ee54 100644 --- a/ControlPad/Arduino/ArduinoPortFinder.cs +++ b/ControlPad/Arduino/ArduinoPortFinder.cs @@ -12,8 +12,8 @@ public static class ArduinoPortFinder "VID_0403" // FTDI-basierte Klone (ältere Duemilanove usw.) }; - /// Gibt z. B. "COM7" zurück oder null, wenn kein Arduino gefunden wurde. - public static string FindFirstArduinoPort() + /// Returns the COM port and PNPDeviceID, or (null, null) if no Arduino was found. + public static (string? port, string? deviceId) FindFirstArduinoPort() { foreach (string port in SerialPort.GetPortNames()) // 1. alle Ports holen { @@ -28,14 +28,25 @@ public static string FindFirstArduinoPort() // 2a) Originale melden sich mit "Arduino XY (COMn)" if (name.IndexOf("Arduino", StringComparison.OrdinalIgnoreCase) >= 0) - return port; + return (port, id); // 2b) Klone: auf Vendor-ID prüfen if (Array.Exists(KnownVids, vid => id.IndexOf(vid, StringComparison.OrdinalIgnoreCase) >= 0)) - return port; + return (port, id); } } - return null; // nichts gefunden + return (null, null); // nichts gefunden + } + + /// Extracts the serial number segment from a PNPDeviceID string (e.g. USB\VID_2341&PID_0043\SERIAL). + public static string? ExtractSerial(string? pnpDeviceId) + { + if (string.IsNullOrEmpty(pnpDeviceId)) + return null; + + // PNPDeviceID format: USB\VID_XXXX&PID_XXXX\SERIAL + var parts = pnpDeviceId.Split('\\'); + return parts.Length >= 3 ? parts[2] : null; } } diff --git a/ControlPad/SubscriptionService.cs b/ControlPad/SubscriptionService.cs new file mode 100644 index 0000000..f887d7d --- /dev/null +++ b/ControlPad/SubscriptionService.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Net.Http; +using System.Text.Json; +using System.Threading.Tasks; + +namespace ControlPad +{ + public static class SubscriptionService + { + private const string SubscriptionsUrl = + "https://raw.githubusercontent.com/ControlPad/App/main/subscriptions.json"; + + private static readonly HttpClient _httpClient = new() { Timeout = TimeSpan.FromSeconds(10) }; + private static readonly Dictionary _cache = new(StringComparer.OrdinalIgnoreCase); + + /// + /// Fetches the subscriptions file from GitHub and returns the badge type + /// for the given device serial number. + /// + public static async Task GetBadgeTypeAsync(string? serial) + { + if (string.IsNullOrEmpty(serial)) + return BadgeType.None; + + if (_cache.TryGetValue(serial, out var cached)) + return cached; + + try + { + string json = await _httpClient.GetStringAsync(SubscriptionsUrl); + var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; + var data = JsonSerializer.Deserialize(json, options); + if (data?.Subscriptions == null) + return BadgeType.None; + + foreach (var entry in data.Subscriptions) + { + if (Enum.IsDefined(typeof(BadgeType), entry.BadgeType)) + { + var badge = (BadgeType)entry.BadgeType; + _cache[entry.SerialNumber] = badge; + + if (string.Equals(entry.SerialNumber, serial, StringComparison.OrdinalIgnoreCase)) + return badge; + } + } + } + catch (Exception ex) + { + Debug.WriteLine($"Subscription fetch failed: {ex.Message}"); + } + + return BadgeType.None; + } + + private class SubscriptionsData + { + public List? Subscriptions { get; set; } + } + + private class SubscriptionEntry + { + public string SerialNumber { get; set; } = ""; + public int BadgeType { get; set; } + } + } +} diff --git a/subscriptions.json b/subscriptions.json new file mode 100644 index 0000000..59ecbf4 --- /dev/null +++ b/subscriptions.json @@ -0,0 +1,3 @@ +{ + "subscriptions": [] +}