From 1b17d92ee0b6cf917dc3aab4dcbf848150ae6fdf Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 4 Apr 2025 00:03:21 -0500 Subject: [PATCH 1/6] fix: Essentials Routing now checks for `SecondaryAudio` if necessary To support NVX Routing, checking for the SecondaryAudio routing type is necessary to find the correct path through the system for audio. --- .../Routing/Extensions.cs | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/PepperDash.Essentials.Core/Routing/Extensions.cs b/src/PepperDash.Essentials.Core/Routing/Extensions.cs index ae85b1de..d603d121 100644 --- a/src/PepperDash.Essentials.Core/Routing/Extensions.cs +++ b/src/PepperDash.Essentials.Core/Routing/Extensions.cs @@ -1,4 +1,5 @@ -using PepperDash.Essentials.Core.Queues; +using Crestron.SimplSharpPro.Keypads; +using PepperDash.Essentials.Core.Queues; using PepperDash.Essentials.Core.Routing; using Serilog.Events; using System; @@ -88,9 +89,17 @@ namespace PepperDash.Essentials.Core Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {sourceKey} of type {type}", destination, source.Key); - var audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.Audio); + RouteDescriptor audioRouteDescriptor; - var audioSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Audio, 0, audioRouteDescriptor, destinationPort, sourcePort); + if (signalType.HasFlag(eRoutingSignalType.SecondaryAudio)) + { + audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.SecondaryAudio); + } else + { + audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.Audio); + } + + var audioSuccess = destination.GetRouteToSource(source, null, null, signalType.HasFlag(eRoutingSignalType.SecondaryAudio) ? eRoutingSignalType.SecondaryAudio : eRoutingSignalType.Audio, 0, audioRouteDescriptor, destinationPort, sourcePort); if (!audioSuccess) Debug.LogMessage(LogEventLevel.Debug, "Cannot find audio route to {0}", destination, source.Key); @@ -268,13 +277,12 @@ namespace PepperDash.Essentials.Core if (destinationPort == null) { - destinationTieLines = TieLineCollection.Default.Where(t => - t.DestinationPort.ParentDevice.Key == destination.Key && (t.Type == signalType || t.Type.HasFlag(eRoutingSignalType.AudioVideo))); + t.DestinationPort.ParentDevice.Key == destination.Key && (t.Type.HasFlag(signalType))); } else { - destinationTieLines = TieLineCollection.Default.Where(t => t.DestinationPort.ParentDevice.Key == destination.Key && t.DestinationPort.Key == destinationPort.Key && (t.Type == signalType || t.Type.HasFlag(eRoutingSignalType.AudioVideo))); + destinationTieLines = TieLineCollection.Default.Where(t => t.DestinationPort.ParentDevice.Key == destination.Key && t.DestinationPort.Key == destinationPort.Key && (t.Type.HasFlag(signalType))); } // find the TieLine without a port From b531d724ff1c9a928f054a868580f73b3ba9ad97 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 4 Apr 2025 00:04:53 -0500 Subject: [PATCH 2/6] fix: add `OverrideType` property to TieLineConfig The TielineConfig had no property for the `type` property from an Essentials configuration file to be deserialized into. This has been corrected so that the `type` property in a Tieline JSON configuration is now respected and used to build the tieline. --- src/PepperDash.Essentials.Core/Routing/TieLine.cs | 10 ++++++++++ .../Routing/TieLineConfig.cs | 7 ++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/PepperDash.Essentials.Core/Routing/TieLine.cs b/src/PepperDash.Essentials.Core/Routing/TieLine.cs index 0b271272..51968152 100644 --- a/src/PepperDash.Essentials.Core/Routing/TieLine.cs +++ b/src/PepperDash.Essentials.Core/Routing/TieLine.cs @@ -57,6 +57,16 @@ namespace PepperDash.Essentials.Core DestinationPort = destinationPort; } + /// + /// Creates a tie line with an overriding Type. See help for OverrideType property for info + /// + /// The signal type to limit the link to. Overrides DestinationPort.Type + public TieLine(RoutingOutputPort sourcePort, RoutingInputPort destinationPort, eRoutingSignalType? overrideType) : + this(sourcePort, destinationPort) + { + OverrideType = overrideType; + } + /// /// Creates a tie line with an overriding Type. See help for OverrideType property for info /// diff --git a/src/PepperDash.Essentials.Core/Routing/TieLineConfig.cs b/src/PepperDash.Essentials.Core/Routing/TieLineConfig.cs index 922cc61d..e7ffb292 100644 --- a/src/PepperDash.Essentials.Core/Routing/TieLineConfig.cs +++ b/src/PepperDash.Essentials.Core/Routing/TieLineConfig.cs @@ -7,6 +7,7 @@ using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharpPro; using Newtonsoft.Json; +using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; @@ -23,6 +24,10 @@ namespace PepperDash.Essentials.Core.Config public string DestinationCard { get; set; } public string DestinationPort { get; set; } + [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] + [JsonConverter(typeof(StringEnumConverter))] + public eRoutingSignalType? OverrideType { get; set; } + /// /// Returns the appropriate tie line for either a card-based device or /// regular device with ports on-device. @@ -65,7 +70,7 @@ namespace PepperDash.Essentials.Core.Config return null; } - return new TieLine(sourceOutputPort, destinationInputPort); + return new TieLine(sourceOutputPort, destinationInputPort, OverrideType); } void LogError(string msg) From b0920746d182f241d74c62c80d519af35c4cc4b7 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Thu, 3 Apr 2025 17:54:22 -0500 Subject: [PATCH 3/6] feat: check base folder for cplz and ir files In an effort to make things easier for devs and end users, the plugin loading logic will now find .cplz files that are in the `Global.FilePathPrefix` base folder (/user/program{programNumber}/` on an appliance, `/user/` on a server). The same applies for IR files. This should make it so that individual plugin cplzs can be loaded via the VC-4 web interface. --- .../Devices/IrOutputPortController.cs | 23 ++++++++++++++++- .../Plugins/PluginLoader.cs | 25 +++++++++++++------ 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/PepperDash.Essentials.Core/Devices/IrOutputPortController.cs b/src/PepperDash.Essentials.Core/Devices/IrOutputPortController.cs index 45c2d895..edcedfbb 100644 --- a/src/PepperDash.Essentials.Core/Devices/IrOutputPortController.cs +++ b/src/PepperDash.Essentials.Core/Devices/IrOutputPortController.cs @@ -12,6 +12,8 @@ using PepperDash.Essentials.Core.Config; using PepperDash.Core; using Serilog.Events; +using System.IO; +using PepperDash.Core.Logging; namespace PepperDash.Essentials.Core { @@ -69,7 +71,26 @@ namespace PepperDash.Essentials.Core return; } - var filePath = Global.FilePathPrefix + "ir" + Global.DirectorySeparator + config.Properties["control"]["irFile"].Value(); + // var filePath = Global.FilePathPrefix + "ir" + Global.DirectorySeparator + config.Properties["control"]["irFile"].Value(); + + var fileName = config.Properties["control"]["irFile"].Value(); + + var files = Directory.GetFiles(Global.FilePathPrefix, fileName, SearchOption.AllDirectories); + + if(files.Length == 0) + { + this.LogError("IR file {fileName} not found in {path}", fileName, Global.FilePathPrefix); + return; + } + + if(files.Length > 1) + { + this.LogError("IR file {fileName} found in multiple locations: {files}", fileName, files); + return; + } + + var filePath = files[0]; + Debug.LogMessage(LogEventLevel.Debug, "*************Attempting to load IR file: {0}***************", filePath); LoadDriver(filePath); diff --git a/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs b/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs index 4759b2cd..3de08806 100644 --- a/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs +++ b/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs @@ -2,13 +2,14 @@ using System.Collections.Generic; using System.Linq; using Crestron.SimplSharp; -using Crestron.SimplSharp.CrestronIO; +// using Crestron.SimplSharp.CrestronIO; using System.Reflection; using PepperDash.Core; using PepperDash.Essentials.Core; using Serilog.Events; using Newtonsoft.Json; +using System.IO; namespace PepperDash.Essentials { @@ -283,11 +284,21 @@ namespace PepperDash.Essentials /// static void UnzipAndMoveCplzArchives() { - Debug.LogMessage(LogEventLevel.Information, "Looking for .cplz archives from plugins folder..."); - var di = new DirectoryInfo(_pluginDirectory); - var zFiles = di.GetFiles("*.cplz"); + Debug.LogMessage(LogEventLevel.Information, "Looking for .cplz archives from user folder..."); + //var di = new DirectoryInfo(_pluginDirectory); + //var zFiles = di.GetFiles("*.cplz"); - if (zFiles.Length > 0) + //// Find cplz files at the root of the user folder. Makes development/testing easier for VC-4, and helps with mistakes by end users + + //var userDi = new DirectoryInfo(Global.FilePathPrefix); + //var userZFiles = userDi.GetFiles("*.cplz"); + + Debug.LogInformation("Checking {folder} for .cplz files", Global.FilePathPrefix); + var cplzFiles = Directory.GetFiles(Global.FilePathPrefix, "*.cplz", SearchOption.AllDirectories) + .Select(f => new FileInfo(f)) + .ToArray(); + + if (cplzFiles.Length > 0) { if (!Directory.Exists(_loadedPluginsDirectoryPath)) { @@ -295,12 +306,12 @@ namespace PepperDash.Essentials } } - foreach (var zfi in zFiles) + foreach (var zfi in cplzFiles) { Directory.CreateDirectory(_tempDirectory); var tempDi = new DirectoryInfo(_tempDirectory); - Debug.LogMessage(LogEventLevel.Information, "Found cplz: {0}. Unzipping into temp plugins directory", zfi.Name); + Debug.LogMessage(LogEventLevel.Information, "Found cplz: {0}. Unzipping into temp plugins directory", zfi.FullName); var result = CrestronZIP.Unzip(zfi.FullName, tempDi.FullName); Debug.LogMessage(LogEventLevel.Information, "UnZip Result: {0}", result.ToString()); From ef2da21c2ab185d78519537b353ed1ca0bcc5b9e Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Thu, 3 Apr 2025 17:54:49 -0500 Subject: [PATCH 4/6] chore: remove old InRoomPc class class has moved to Devices.Common library --- .../Devices/PC/InRoomPc.cs | 81 ------------------- 1 file changed, 81 deletions(-) delete mode 100644 src/PepperDash.Essentials.Core/Devices/PC/InRoomPc.cs diff --git a/src/PepperDash.Essentials.Core/Devices/PC/InRoomPc.cs b/src/PepperDash.Essentials.Core/Devices/PC/InRoomPc.cs deleted file mode 100644 index 31e4be22..00000000 --- a/src/PepperDash.Essentials.Core/Devices/PC/InRoomPc.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Crestron.SimplSharpPro; - -using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.Config; -using PepperDash.Core; -using Serilog.Events; - -namespace PepperDash.Essentials.Core.Devices -{ - [Obsolete("Please use PepperDash.Essentials.Devices.Common, this will be removed in 2.1")] - public class InRoomPc : EssentialsDevice, IHasFeedback, IRoutingOutputs, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking - { - public uint DisplayUiType { get { return DisplayUiConstants.TypeLaptop; } } - public string IconName { get; set; } - public BoolFeedback HasPowerOnFeedback { get; private set; } - - public RoutingOutputPort AnyVideoOut { get; private set; } - - #region IRoutingOutputs Members - - /// - /// Options: hdmi - /// - public RoutingPortCollection OutputPorts { get; private set; } - - #endregion - - public InRoomPc(string key, string name) - : base(key, name) - { - IconName = "PC"; - HasPowerOnFeedback = new BoolFeedback("HasPowerFeedback", - () => this.GetVideoStatuses() != VideoStatusOutputs.NoStatus); - OutputPorts = new RoutingPortCollection(); - OutputPorts.Add(AnyVideoOut = new RoutingOutputPort(RoutingPortNames.AnyVideoOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, - eRoutingPortConnectionType.None, 0, this)); - } - - #region IHasFeedback Members - - /// - /// Passes through the VideoStatuses list - /// - public FeedbackCollection Feedbacks - { - get - { - var newList = new FeedbackCollection(); - newList.AddRange(this.GetVideoStatuses().ToList()); - return newList; - } - } - - #endregion - - #region IUsageTracking Members - - public UsageTracking UsageTracker { get; set; } - - #endregion - } - - [Obsolete("Please use PepperDash.Essentials.Devices.Common, this will be removed in 2.1")] - public class InRoomPcFactory : EssentialsDeviceFactory - { - public InRoomPcFactory() - { - TypeNames = new List() { "inroompc" }; - } - - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new InRoomPc Device"); - return new InRoomPc(dc.Key, dc.Name); - } - } - -} \ No newline at end of file From c9f10ecb9036163bf26ff7fafc85542366830941 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Thu, 3 Apr 2025 17:55:02 -0500 Subject: [PATCH 5/6] build: delete clz files on build --- src/Directory.Build.targets | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index 93647372..1e7c0909 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -1,5 +1,9 @@ - + + + true + build; + true build; @@ -9,30 +13,41 @@ build; + + $(TargetDir)$(TargetName).$(Version).$(TargetFramework).clz + $(TargetDir)$(TargetName).$(Version).$(TargetFramework).cplz $(TargetDir)$(TargetName).$(Version).$(TargetFramework).cpz - - + + + - - - - - - + + + + + + + + + + + + + From c5403f33c59cb6d93cffac94b9c96d03c9986fa0 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 4 Apr 2025 10:49:04 -0500 Subject: [PATCH 6/6] fix: add previous condition back to the flag check Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/PepperDash.Essentials.Core/Routing/Extensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PepperDash.Essentials.Core/Routing/Extensions.cs b/src/PepperDash.Essentials.Core/Routing/Extensions.cs index d603d121..0d7ce3ca 100644 --- a/src/PepperDash.Essentials.Core/Routing/Extensions.cs +++ b/src/PepperDash.Essentials.Core/Routing/Extensions.cs @@ -278,7 +278,7 @@ namespace PepperDash.Essentials.Core if (destinationPort == null) { destinationTieLines = TieLineCollection.Default.Where(t => - t.DestinationPort.ParentDevice.Key == destination.Key && (t.Type.HasFlag(signalType))); + t.DestinationPort.ParentDevice.Key == destination.Key && (t.Type.HasFlag(signalType) || signalType == eRoutingSignalType.AudioVideo)); } else {