diff --git a/ArtNetSharp.sln b/ArtNetSharp.sln index fe4c8e0..a882a0c 100644 --- a/ArtNetSharp.sln +++ b/ArtNetSharp.sln @@ -15,6 +15,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NodeInputExample", "Example EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlerRDMExample", "Examples\ControlerRDMExample\ControlerRDMExample.csproj", "{90BF6833-7425-4D6B-A8F9-8487A60F1B78}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConfigExample", "Examples\ConfigExample\ConfigExample.csproj", "{DF3AFD9A-0629-43C9-AAC6-5EF22728C5E8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -45,6 +47,10 @@ Global {90BF6833-7425-4D6B-A8F9-8487A60F1B78}.Debug|Any CPU.Build.0 = Debug|Any CPU {90BF6833-7425-4D6B-A8F9-8487A60F1B78}.Release|Any CPU.ActiveCfg = Release|Any CPU {90BF6833-7425-4D6B-A8F9-8487A60F1B78}.Release|Any CPU.Build.0 = Release|Any CPU + {DF3AFD9A-0629-43C9-AAC6-5EF22728C5E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DF3AFD9A-0629-43C9-AAC6-5EF22728C5E8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DF3AFD9A-0629-43C9-AAC6-5EF22728C5E8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DF3AFD9A-0629-43C9-AAC6-5EF22728C5E8}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ArtNetSharp/ArtNetSharp.csproj b/ArtNetSharp/ArtNetSharp.csproj index dfe3f2e..8193684 100644 --- a/ArtNetSharp/ArtNetSharp.csproj +++ b/ArtNetSharp/ArtNetSharp.csproj @@ -2,7 +2,7 @@ netstandard2.0;net6.0;net7.0;net8.0 LICENSE - 0.0.26 + 0.0.27 https://github.com/DMXControl/ArtNetSharp $(RepositoryUrl) RDM; ArtNet; E1.20; E1.33; E1.37-1; E1.37-2; E1.37-7 diff --git a/ArtNetSharp/Communication/AbstractInstance.cs b/ArtNetSharp/Communication/AbstractInstance.cs index 0c23c47..e06392c 100644 --- a/ArtNetSharp/Communication/AbstractInstance.cs +++ b/ArtNetSharp/Communication/AbstractInstance.cs @@ -239,7 +239,7 @@ public void Dispose() private readonly ConcurrentDictionary remoteClients = new ConcurrentDictionary(); private readonly ConcurrentDictionary remoteClientsTimeouted = new ConcurrentDictionary(); public IReadOnlyCollection RemoteClients { get; private set; } = new List(); - public IReadOnlyCollection RemoteClientsPorts { get { return remoteClients.SelectMany(rc => rc.Value.Ports).ToList().AsReadOnly(); } } + public IReadOnlyCollection RemoteClientsPorts { get { return remoteClients?.Where(rc => rc.Value?.Ports != null).SelectMany(rc => rc.Value.Ports).ToList().AsReadOnly(); } } public event EventHandler DMXReceived; public event EventHandler SyncReceived; @@ -581,7 +581,7 @@ private async Task sendAllArtDMX() try { - var ports = RemoteClientsPorts.Where(port => port.OutputPortAddress.HasValue && !port.Timouted()).ToList(); + var ports = RemoteClientsPorts?.Where(port => port.OutputPortAddress.HasValue && !port.Timouted())?.ToList(); int sended = 0; foreach (var port in ports) @@ -590,13 +590,23 @@ private async Task sendAllArtDMX() if (sendDMXBuffer.TryGetValue(port.OutputPortAddress.Value, out DMXSendBag bag)) if ((bag.Updated && (DateTime.UtcNow - bag.LastSended).TotalMilliseconds >= dmxRefreshTime) || (DateTime.UtcNow - bag.LastSended).TotalMilliseconds >= dmxKeepAliveTime) { - bag.LastSended = DateTime.UtcNow; - PortConfig config = portConfigs.FirstOrDefault(pc => PortAddress.Equals(pc.PortAddress, port.OutputPortAddress)); - byte sourcePort = config?.PortNumber ?? 0; - await sendArtDMX(port, sourcePort, bag.Data, bag.GetSequence(), config?.ForceBroadcast ?? false); - sended++; - if (config == null) + PortConfig config = null; + byte sourcePort = 0; + try + { + bag.LastSended = DateTime.UtcNow; + config = portConfigs?.FirstOrDefault(pc => PortAddress.Equals(pc.PortAddress, port.OutputPortAddress)); + sourcePort = config?.PortNumber ?? 0; + await sendArtDMX(port, sourcePort, bag.Data, bag.GetSequence(), config?.ForceBroadcast ?? false); + sended++; + if (config == null) + return; + } + catch (Exception e) + { + Logger.LogError(e, "Inner Block"); return; + } foreach (IPv4Address ip in config?.AdditionalIPEndpoints) { await sendArtDMX(ip, config.PortAddress, sourcePort, bag.Data, bag.GetSequence()); @@ -605,7 +615,7 @@ private async Task sendAllArtDMX() bag.LastSended = DateTime.UtcNow; } } - catch (Exception e) { Logger.LogError(e); } + catch (Exception e) { Logger.LogError(e, "Outer Block"); } if (EnableSync && sended != 0) await sendArtSync(); diff --git a/Examples/ConfigExample/ConfigExample.csproj b/Examples/ConfigExample/ConfigExample.csproj new file mode 100644 index 0000000..c7e3b32 --- /dev/null +++ b/Examples/ConfigExample/ConfigExample.csproj @@ -0,0 +1,14 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + diff --git a/Examples/ConfigExample/GlobalSuppressions.cs b/Examples/ConfigExample/GlobalSuppressions.cs new file mode 100644 index 0000000..406d3da --- /dev/null +++ b/Examples/ConfigExample/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0090:\"new(...)\" verwenden", Justification = "")] diff --git a/Examples/ConfigExample/Program.cs b/Examples/ConfigExample/Program.cs new file mode 100644 index 0000000..0873733 --- /dev/null +++ b/Examples/ConfigExample/Program.cs @@ -0,0 +1,52 @@ +using ArtNetSharp; +using ArtNetSharp.Communication; + +Console.WriteLine("Config Example!"); + +//Add Logging +//ArtNet.SetLoggerFectory(YOUR_LOGGER_FACTORY); + +//Set Networkinterfaces +//var broadcastIp = new IPAddress(new byte[] { 2, 255, 255, 255 }); +//ArtNet.Instance.NetworkClients.ToList().ForEach(ncb => ncb.Enabled = IPAddress.Equals(broadcastIp, ncb.BroadcastIpAddress)); + +// Create Instance +ConfigInstance controllerInstance = new ConfigInstance(ArtNet.Instance); +controllerInstance.Name = controllerInstance.ShortName = "Config Example"; + +// Configure Ports +//for (byte i = 1; i <= 32; i++) +// controllerInstance.AddPortConfig(new PortConfig(i, new PortAddress((ushort)(i - 1)), false, true) { PortNumber = (byte)i, Type = EPortType.InputToArtNet | EPortType.ArtNet }); + +// Add Instance +ArtNet.Instance.AddInstance(controllerInstance); +controllerInstance.RemoteClientDiscovered += (o, e) => +{ + Console.WriteLine($"Discovered: {e.IpAddress}"); + e.PortDiscovered += (o1, e1) => + { + e1.PropertyChanged += (o2, e2) => + { + if (e2.PropertyName?.Equals(nameof(RemoteClientPort.LastSeen)) ?? true) + return; + + Console.WriteLine($"{e.IpAddress}/{e1.PortIndex}:{e2.PropertyName} changed"); + }; + }; +}; controllerInstance.RemoteClientTimedOut += (o, e) => +{ + Console.WriteLine($"TimedOuted: {e.IpAddress}"); +}; +Console.ReadLine(); + +// Genrerate some DMX-Data +//byte[] data = new byte[512]; +//while (true) +//{ +// await Task.Delay(200); +// for (short k = 0; k < 512; k++) +// data[k]++; + +// for (ushort i = 0; i < 32; i++) +// controllerInstance.WriteDMXValues(i, data); +//} \ No newline at end of file diff --git a/Examples/ConfigExample/Usings.cs b/Examples/ConfigExample/Usings.cs new file mode 100644 index 0000000..8749f32 --- /dev/null +++ b/Examples/ConfigExample/Usings.cs @@ -0,0 +1 @@ +global using org.dmxc.wkdt.Light.ArtNet; \ No newline at end of file