From a820c2c2659cfdc009b5e2e932c48ffd0a9a09b7 Mon Sep 17 00:00:00 2001 From: nzbr Date: Mon, 19 Oct 2020 03:25:00 +0200 Subject: [PATCH 1/5] Add UDP Device --- .../Project-Aurora/Devices/UDP/UDPDevice.cs | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 Project-Aurora/Project-Aurora/Devices/UDP/UDPDevice.cs diff --git a/Project-Aurora/Project-Aurora/Devices/UDP/UDPDevice.cs b/Project-Aurora/Project-Aurora/Devices/UDP/UDPDevice.cs new file mode 100644 index 000000000..0bed7f756 --- /dev/null +++ b/Project-Aurora/Project-Aurora/Devices/UDP/UDPDevice.cs @@ -0,0 +1,150 @@ +using Aurora.Settings; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.Linq; +using System.Net; +using System.Net.Sockets; + +namespace Aurora.Devices.UDP +{ + public class UdpDevice : IDevice + { + public string DeviceName => "UDP"; + public bool IsInitialized { get; private set; } = false; + + private VariableRegistry defaultRegistry = null; + + private Stopwatch redrawWatch = new Stopwatch(); + private Stopwatch updateStopwatch = new Stopwatch(); + private UdpClient udpClient; + + private List endpoints; + private DeviceKeys deviceKey; + private int ledCount; + + private Color lastColor; + private long lastUpdateTime = long.MaxValue; + + public string DeviceDetails => DeviceName + (IsInitialized ? ": Initialized" : ": Not initialized"); + public string DeviceUpdatePerformance => (IsInitialized ? lastUpdateTime + " ms" : ""); + + public VariableRegistry RegisteredVariables + { + get + { + if (defaultRegistry == null) + { + var devKeysEnumAsEnumerable = Enum.GetValues(typeof(DeviceKeys)).Cast(); + + defaultRegistry = new VariableRegistry(); + defaultRegistry.Register($"{DeviceName}_devicekey", DeviceKeys.Peripheral, "Key Color to Use", + devKeysEnumAsEnumerable.Max(), devKeysEnumAsEnumerable.Min()); + defaultRegistry.Register($"{DeviceName}_led_count", 300, "LED Count"); + defaultRegistry.Register($"{DeviceName}_ip", "", "IP Adresses (Comma separated)"); + defaultRegistry.Register($"{DeviceName}_port", 19446, "UDP Port"); + } + + return defaultRegistry; + } + } + + + public bool Initialize() + { + if (IsInitialized) return true; + + deviceKey = Global.Configuration.VarRegistry.GetVariable($"{DeviceName}_devicekey"); + ledCount = Global.Configuration.VarRegistry.GetVariable($"{DeviceName}_led_count"); + + var udpPort = Global.Configuration.VarRegistry.GetVariable($"{DeviceName}_port"); + var ips = Global.Configuration.VarRegistry.GetVariable($"{DeviceName}_ip").Split(','); + + endpoints = new List(); + foreach (var ip in ips) + { + try + { + endpoints.Add(new IPEndPoint(IPAddress.Parse(ip), udpPort)); + } + catch (FormatException) + { + } // Don't crash on malformed IPs + } + + udpClient = new UdpClient(); + lastColor = Color.Black; + redrawWatch.Start(); + + IsInitialized = true; + return true; + } + + + public void Reset() + { + Shutdown(); + Initialize(); + } + + public void Shutdown() + { + endpoints = null; + udpClient.Dispose(); // udpClient is IDisposable + udpClient = null; + redrawWatch.Stop(); + + IsInitialized = false; + } + + public bool UpdateDevice(DeviceColorComposition colorComposition, DoWorkEventArgs e, bool forced = false) + { + return UpdateDevice(colorComposition.keyColors, e, forced); + } + + public bool UpdateDevice(Dictionary keyColors, DoWorkEventArgs e, bool forced = false) + { + if (!IsInitialized) return false; + + if (keyColors.ContainsKey(deviceKey)) + { + updateStopwatch.Restart(); + + var c = keyColors[deviceKey]; + if (redrawWatch.ElapsedMilliseconds < 1000 + ) // Only send the color when it changes or a full second has passed + { + if (c == lastColor && !forced) return true; + } + else + { + redrawWatch.Restart(); + } + + lastColor = c; + + // Build a payload by repeating the color ledCount times + var payload = new byte[3 * ledCount]; + for (var i = 0; i < ledCount * 3; i += 3) + { + payload[i + 0] = c.R; + payload[i + 1] = c.G; + payload[i + 2] = c.B; + } + + // Actually send the payload to each endpoint + foreach (var endpoint in endpoints) + { + udpClient.Send(payload, payload.Length, endpoint); + } + + updateStopwatch.Stop(); + lastUpdateTime = updateStopwatch.ElapsedMilliseconds; + } + + return true; + } + } +} \ No newline at end of file From 7adc8c0d05733d2d2cd2260bd801250f15693540 Mon Sep 17 00:00:00 2001 From: nzbr Date: Tue, 20 Oct 2020 03:26:49 +0200 Subject: [PATCH 2/5] Fix device details string --- Project-Aurora/Project-Aurora/Devices/UDP/UDPDevice.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project-Aurora/Project-Aurora/Devices/UDP/UDPDevice.cs b/Project-Aurora/Project-Aurora/Devices/UDP/UDPDevice.cs index 0bed7f756..2a0b8878c 100644 --- a/Project-Aurora/Project-Aurora/Devices/UDP/UDPDevice.cs +++ b/Project-Aurora/Project-Aurora/Devices/UDP/UDPDevice.cs @@ -28,7 +28,7 @@ public class UdpDevice : IDevice private Color lastColor; private long lastUpdateTime = long.MaxValue; - public string DeviceDetails => DeviceName + (IsInitialized ? ": Initialized" : ": Not initialized"); + public string DeviceDetails => IsInitialized ? "Initialized" : "Not initialized"; public string DeviceUpdatePerformance => (IsInitialized ? lastUpdateTime + " ms" : ""); public VariableRegistry RegisteredVariables From 920bd29a7894f6b8939c89ba9329135186e8b395 Mon Sep 17 00:00:00 2001 From: nzbr Date: Tue, 20 Oct 2020 04:07:26 +0200 Subject: [PATCH 3/5] Extend DefaultDevice instead of IDevice --- .../Project-Aurora/Devices/UDP/UDPDevice.cs | 59 ++++--------------- 1 file changed, 13 insertions(+), 46 deletions(-) diff --git a/Project-Aurora/Project-Aurora/Devices/UDP/UDPDevice.cs b/Project-Aurora/Project-Aurora/Devices/UDP/UDPDevice.cs index 2a0b8878c..bac017dd4 100644 --- a/Project-Aurora/Project-Aurora/Devices/UDP/UDPDevice.cs +++ b/Project-Aurora/Project-Aurora/Devices/UDP/UDPDevice.cs @@ -10,15 +10,12 @@ namespace Aurora.Devices.UDP { - public class UdpDevice : IDevice + public class UdpDevice : DefaultDevice { - public string DeviceName => "UDP"; - public bool IsInitialized { get; private set; } = false; - - private VariableRegistry defaultRegistry = null; + public override string DeviceName => "UDP"; + public override bool IsInitialized { get; protected set; } = false; private Stopwatch redrawWatch = new Stopwatch(); - private Stopwatch updateStopwatch = new Stopwatch(); private UdpClient udpClient; private List endpoints; @@ -26,33 +23,20 @@ public class UdpDevice : IDevice private int ledCount; private Color lastColor; - private long lastUpdateTime = long.MaxValue; - - public string DeviceDetails => IsInitialized ? "Initialized" : "Not initialized"; - public string DeviceUpdatePerformance => (IsInitialized ? lastUpdateTime + " ms" : ""); - public VariableRegistry RegisteredVariables + protected override void RegisterVariables(VariableRegistry variableRegistry) { - get - { - if (defaultRegistry == null) - { - var devKeysEnumAsEnumerable = Enum.GetValues(typeof(DeviceKeys)).Cast(); - - defaultRegistry = new VariableRegistry(); - defaultRegistry.Register($"{DeviceName}_devicekey", DeviceKeys.Peripheral, "Key Color to Use", - devKeysEnumAsEnumerable.Max(), devKeysEnumAsEnumerable.Min()); - defaultRegistry.Register($"{DeviceName}_led_count", 300, "LED Count"); - defaultRegistry.Register($"{DeviceName}_ip", "", "IP Adresses (Comma separated)"); - defaultRegistry.Register($"{DeviceName}_port", 19446, "UDP Port"); - } + var devKeysEnumAsEnumerable = Enum.GetValues(typeof(DeviceKeys)).Cast(); - return defaultRegistry; - } + variableRegistry.Register($"{DeviceName}_devicekey", DeviceKeys.Peripheral, "Key Color to Use", + devKeysEnumAsEnumerable.Max(), devKeysEnumAsEnumerable.Min()); + variableRegistry.Register($"{DeviceName}_led_count", 300, "LED Count"); + variableRegistry.Register($"{DeviceName}_ip", "", "IP Adresses (Comma separated)"); + variableRegistry.Register($"{DeviceName}_port", 19446, "UDP Port"); } - public bool Initialize() + public override bool Initialize() { if (IsInitialized) return true; @@ -82,14 +66,7 @@ public bool Initialize() return true; } - - public void Reset() - { - Shutdown(); - Initialize(); - } - - public void Shutdown() + public override void Shutdown() { endpoints = null; udpClient.Dispose(); // udpClient is IDisposable @@ -99,19 +76,12 @@ public void Shutdown() IsInitialized = false; } - public bool UpdateDevice(DeviceColorComposition colorComposition, DoWorkEventArgs e, bool forced = false) - { - return UpdateDevice(colorComposition.keyColors, e, forced); - } - - public bool UpdateDevice(Dictionary keyColors, DoWorkEventArgs e, bool forced = false) + public override bool UpdateDevice(Dictionary keyColors, DoWorkEventArgs e, bool forced = false) { if (!IsInitialized) return false; if (keyColors.ContainsKey(deviceKey)) { - updateStopwatch.Restart(); - var c = keyColors[deviceKey]; if (redrawWatch.ElapsedMilliseconds < 1000 ) // Only send the color when it changes or a full second has passed @@ -139,9 +109,6 @@ public bool UpdateDevice(Dictionary keyColors, DoWorkEventArg { udpClient.Send(payload, payload.Length, endpoint); } - - updateStopwatch.Stop(); - lastUpdateTime = updateStopwatch.ElapsedMilliseconds; } return true; From f86af05b33a2f3fa7c30662cadf9b2279592b407 Mon Sep 17 00:00:00 2001 From: nzbr Date: Mon, 18 Jan 2021 06:02:38 +0100 Subject: [PATCH 4/5] Don't initialize if no IPs are specified --- .../Project-Aurora/Devices/UDP/UDPDevice.cs | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/Project-Aurora/Project-Aurora/Devices/UDP/UDPDevice.cs b/Project-Aurora/Project-Aurora/Devices/UDP/UDPDevice.cs index bac017dd4..f75790b49 100644 --- a/Project-Aurora/Project-Aurora/Devices/UDP/UDPDevice.cs +++ b/Project-Aurora/Project-Aurora/Devices/UDP/UDPDevice.cs @@ -13,17 +13,20 @@ namespace Aurora.Devices.UDP public class UdpDevice : DefaultDevice { public override string DeviceName => "UDP"; - public override bool IsInitialized { get; protected set; } = false; private Stopwatch redrawWatch = new Stopwatch(); private UdpClient udpClient; + private string[] ips = new string[0]; private List endpoints; private DeviceKeys deviceKey; private int ledCount; + private int udpPort; private Color lastColor; + protected override string DeviceInfo => string.Join(", ", ips); + protected override void RegisterVariables(VariableRegistry variableRegistry) { var devKeysEnumAsEnumerable = Enum.GetValues(typeof(DeviceKeys)).Cast(); @@ -38,13 +41,23 @@ protected override void RegisterVariables(VariableRegistry variableRegistry) public override bool Initialize() { - if (IsInitialized) return true; + if (IsInitialized) return IsInitialized = true; deviceKey = Global.Configuration.VarRegistry.GetVariable($"{DeviceName}_devicekey"); ledCount = Global.Configuration.VarRegistry.GetVariable($"{DeviceName}_led_count"); - var udpPort = Global.Configuration.VarRegistry.GetVariable($"{DeviceName}_port"); - var ips = Global.Configuration.VarRegistry.GetVariable($"{DeviceName}_ip").Split(','); + udpPort = Global.Configuration.VarRegistry.GetVariable($"{DeviceName}_port"); + ips = Global.Configuration.VarRegistry.GetVariable($"{DeviceName}_ip").Split(','); + + if (ips.Length < 2 && ips[0] == "") + { + LogError("UDP has no IP"); + return IsInitialized = false; + } + else + { + LogInfo($"{ips.Length} |{string.Join("|", ips)}|"); + } endpoints = new List(); foreach (var ip in ips) @@ -62,8 +75,7 @@ public override bool Initialize() lastColor = Color.Black; redrawWatch.Start(); - IsInitialized = true; - return true; + return IsInitialized = true; } public override void Shutdown() From 77d644d5d26913466814cb702167da26c6160485 Mon Sep 17 00:00:00 2001 From: nzbr Date: Mon, 18 Jan 2021 06:17:32 +0100 Subject: [PATCH 5/5] Allow specifying port per ip --- .../Project-Aurora/Devices/UDP/UDPDevice.cs | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/Project-Aurora/Project-Aurora/Devices/UDP/UDPDevice.cs b/Project-Aurora/Project-Aurora/Devices/UDP/UDPDevice.cs index f75790b49..fd73ca160 100644 --- a/Project-Aurora/Project-Aurora/Devices/UDP/UDPDevice.cs +++ b/Project-Aurora/Project-Aurora/Devices/UDP/UDPDevice.cs @@ -21,21 +21,21 @@ public class UdpDevice : DefaultDevice private List endpoints; private DeviceKeys deviceKey; private int ledCount; - private int udpPort; private Color lastColor; - protected override string DeviceInfo => string.Join(", ", ips); + private const int defaultPort = 19446; + + protected override string DeviceInfo => string.Join(", ", endpoints.Select(endpoint => endpoint.ToString())); protected override void RegisterVariables(VariableRegistry variableRegistry) { var devKeysEnumAsEnumerable = Enum.GetValues(typeof(DeviceKeys)).Cast(); variableRegistry.Register($"{DeviceName}_devicekey", DeviceKeys.Peripheral, "Key Color to Use", - devKeysEnumAsEnumerable.Max(), devKeysEnumAsEnumerable.Min()); + devKeysEnumAsEnumerable.Max(), devKeysEnumAsEnumerable.Min()); variableRegistry.Register($"{DeviceName}_led_count", 300, "LED Count"); - variableRegistry.Register($"{DeviceName}_ip", "", "IP Adresses (Comma separated)"); - variableRegistry.Register($"{DeviceName}_port", 19446, "UDP Port"); + variableRegistry.Register($"{DeviceName}_ip", "", "Addresses (IP:port - Comma separated)"); } @@ -45,8 +45,6 @@ public override bool Initialize() deviceKey = Global.Configuration.VarRegistry.GetVariable($"{DeviceName}_devicekey"); ledCount = Global.Configuration.VarRegistry.GetVariable($"{DeviceName}_led_count"); - - udpPort = Global.Configuration.VarRegistry.GetVariable($"{DeviceName}_port"); ips = Global.Configuration.VarRegistry.GetVariable($"{DeviceName}_ip").Split(','); if (ips.Length < 2 && ips[0] == "") @@ -64,7 +62,16 @@ public override bool Initialize() { try { - endpoints.Add(new IPEndPoint(IPAddress.Parse(ip), udpPort)); + int udpPort = defaultPort; + var parts = ip.Split(':'); + if (parts.Length > 1) + { + if (!int.TryParse(parts[1], out udpPort)) + { + udpPort = defaultPort; + } + } + endpoints.Add(new IPEndPoint(IPAddress.Parse(parts[0]), udpPort)); } catch (FormatException) { @@ -88,7 +95,8 @@ public override void Shutdown() IsInitialized = false; } - public override bool UpdateDevice(Dictionary keyColors, DoWorkEventArgs e, bool forced = false) + public override bool UpdateDevice(Dictionary keyColors, DoWorkEventArgs e, + bool forced = false) { if (!IsInitialized) return false;