From 826b7fd6d5dab86bde061451f09f848c35dace45 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 15 May 2024 15:30:54 -0500 Subject: [PATCH 01/24] fix: add factory for mock display in Devices.Common --- .../Displays/MockDisplay.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs b/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs index a1241821..bcbbaa5a 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs @@ -6,6 +6,7 @@ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; +using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Core.Routing; using Serilog.Events; @@ -251,4 +252,18 @@ namespace PepperDash.Essentials.Devices.Common.Displays } + + public class MockDisplayFactory : EssentialsDeviceFactory + { + public MockDisplayFactory() + { + TypeNames = new List() { "mockdisplay2" }; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Mock Display Device"); + return new MockDisplay(dc.Key, dc.Name); + } + } } \ No newline at end of file From 4d19ecde00054b2f813c270248fc0a2e5b8aacbc Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Thu, 16 May 2024 00:32:02 -0500 Subject: [PATCH 02/24] build: update PD Core and dependencies --- .../PepperDash.Essentials.Core.csproj | 4 ++-- .../PepperDash.Essentials.Devices.Common.csproj | 4 ++-- src/PepperDash.Essentials/PepperDash.Essentials.csproj | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj index da717cb4..3cb80324 100644 --- a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj +++ b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj @@ -22,8 +22,8 @@ pdbonly - - + + diff --git a/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj b/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj index abfcd9c2..34433189 100644 --- a/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj +++ b/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj @@ -26,7 +26,7 @@ - - + + \ No newline at end of file diff --git a/src/PepperDash.Essentials/PepperDash.Essentials.csproj b/src/PepperDash.Essentials/PepperDash.Essentials.csproj index e10707c2..885a0970 100644 --- a/src/PepperDash.Essentials/PepperDash.Essentials.csproj +++ b/src/PepperDash.Essentials/PepperDash.Essentials.csproj @@ -46,8 +46,8 @@ - - + + From 5820c9d282f25d9f32f7e6be56d4f83dfea313cb Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Thu, 16 May 2024 00:38:02 -0500 Subject: [PATCH 03/24] fix: set error log level to to verbose on VC-4 Update catch log methods to use updated LogMessage method --- .../Comm and IR/GenericHttpClient.cs | 1 - src/PepperDash.Essentials/ControlSystem.cs | 10 ++++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/PepperDash.Essentials.Core/Comm and IR/GenericHttpClient.cs b/src/PepperDash.Essentials.Core/Comm and IR/GenericHttpClient.cs index fa6c298a..0347da80 100644 --- a/src/PepperDash.Essentials.Core/Comm and IR/GenericHttpClient.cs +++ b/src/PepperDash.Essentials.Core/Comm and IR/GenericHttpClient.cs @@ -5,7 +5,6 @@ using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharp.Net.Http; using PepperDash.Core; -using PepperDash.Core.DebugThings; namespace PepperDash.Essentials.Core { diff --git a/src/PepperDash.Essentials/ControlSystem.cs b/src/PepperDash.Essentials/ControlSystem.cs index 84bf12ec..af87158b 100644 --- a/src/PepperDash.Essentials/ControlSystem.cs +++ b/src/PepperDash.Essentials/ControlSystem.cs @@ -34,6 +34,8 @@ namespace PepperDash.Essentials SecretsManager.Initialize(); SystemMonitor.ProgramInitialization.ProgramInitializationUnderUserControl = true; + Debug.SetErrorLogMinimumDebugLevel(CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance ? LogEventLevel.Warning : LogEventLevel.Verbose); + // AppDomain.CurrentDomain.AssemblyResolve += CurrentDomainOnAssemblyResolve; } @@ -162,7 +164,7 @@ namespace PepperDash.Essentials { try { - Debug.LogMessage(LogEventLevel.Information, "Determining Platform..."); + Debug.LogMessage(LogEventLevel.Information, "Determining Platform..."); string filePathPrefix; @@ -240,7 +242,7 @@ namespace PepperDash.Essentials } catch (Exception e) { - Debug.LogMessage(LogEventLevel.Error, "Unable to determin platform due to exception: {exception}", e.Message); + Debug.LogMessage(e, "Unable to determine platform due to exception"); } } @@ -296,7 +298,7 @@ namespace PepperDash.Essentials } catch (Exception e) { - Debug.LogMessage(LogEventLevel.Information, "FATAL INITIALIZE ERROR. System is in an inconsistent state: {exception}", e); + Debug.LogMessage(e, "FATAL INITIALIZE ERROR. System is in an inconsistent state"); } finally { @@ -428,7 +430,7 @@ namespace PepperDash.Essentials } catch (Exception e) { - Debug.LogMessage(LogEventLevel.Information, "ERROR: Creating device {deviceKey:l}. Skipping device. \r\n{exception}", devConf.Key, e); + Debug.LogMessage(e, "ERROR: Creating device {deviceKey:l}. Skipping device.",args: new[] { devConf.Key }); } } Debug.LogMessage(LogEventLevel.Information, "All Devices Loaded."); From 06a6b1caa2f61284b991c35889d8a80b11b806ac Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 8 May 2024 08:37:24 -0500 Subject: [PATCH 04/24] refactor: move routing interfaces into their own files --- .../PepperDash.Essentials.Core.csproj | 7 +- .../Routing/Extensions.cs | 252 +++++++++++ .../Routing/GenericExtensions.cs | 261 +++++++++++ .../Routing/IHasCurrentSourceInfoChange.cs | 30 ++ .../Routing/IInputSync.cs | 2 +- .../Routing/IRmcRouting.cs | 10 + .../Routing/IRmcRoutingWithFeedback.cs | 11 + .../Routing/IRouting.cs | 21 + .../Routing/IRoutingFeedback.cs | 16 + .../IRoutingHasVideoInputSyncFeedbacks.cs | 19 + .../Routing/IRoutingInputs.cs | 18 + .../Routing/IRoutingInputsExtensions.cs | 426 ------------------ .../Routing/IRoutingInputsOutputs.cs | 16 + .../Routing/IRoutingNumeric.cs | 7 + .../Routing/IRoutingNumericWithFeedback.cs | 9 + .../Routing/IRoutingOutputs.cs | 19 + .../Routing/IRoutingSink.cs | 22 + .../Routing/IRoutingSinkWithSwitching.cs | 20 + .../Routing/IRoutingSource.cs | 9 + .../Routing/IRoutingWithClear.cs | 12 + .../Routing/ITxRouting.cs | 8 + .../Routing/ITxRoutingWithFeedback.cs | 9 + .../Routing/RouteDescriptor.cs | 152 +++++++ .../Routing/RouteDescriptorCollection.cs | 123 +++++ .../Routing/RouteRequest.cs | 44 ++ .../Routing/RouteSwitchDescriptor.cs | 60 +++ .../Routing/RoutingInputPort.cs | 77 ++++ .../RoutingInputPortWithVideoStatuses.cs | 30 ++ .../Routing/RoutingInterfaces.cs | 203 --------- .../Routing/RoutingNumericEventArgs.cs | 43 ++ .../Routing/RoutingOutputPort.cs | 75 +++ .../Routing/RoutingPort.cs | 201 +-------- .../Routing/RoutingPortCollection.cs | 17 + .../Routing/eRoutingPortConnectionType.cs | 8 + .../Routing/eRoutingSignalType.cs | 16 + 35 files changed, 1442 insertions(+), 811 deletions(-) create mode 100644 src/PepperDash.Essentials.Core/Routing/Extensions.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/GenericExtensions.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/IHasCurrentSourceInfoChange.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/IRmcRouting.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/IRmcRoutingWithFeedback.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/IRouting.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/IRoutingFeedback.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/IRoutingHasVideoInputSyncFeedbacks.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/IRoutingInputs.cs delete mode 100644 src/PepperDash.Essentials.Core/Routing/IRoutingInputsExtensions.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/IRoutingInputsOutputs.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/IRoutingNumeric.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/IRoutingNumericWithFeedback.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/IRoutingOutputs.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithSwitching.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/IRoutingSource.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/IRoutingWithClear.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/ITxRouting.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/ITxRoutingWithFeedback.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/RouteDescriptor.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/RouteDescriptorCollection.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/RouteRequest.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/RouteSwitchDescriptor.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/RoutingInputPort.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/RoutingInputPortWithVideoStatuses.cs delete mode 100644 src/PepperDash.Essentials.Core/Routing/RoutingInterfaces.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/RoutingNumericEventArgs.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/RoutingOutputPort.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/eRoutingPortConnectionType.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/eRoutingSignalType.cs diff --git a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj index 3cb80324..c38c0fbd 100644 --- a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj +++ b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj @@ -22,8 +22,11 @@ pdbonly - - + + + + + diff --git a/src/PepperDash.Essentials.Core/Routing/Extensions.cs b/src/PepperDash.Essentials.Core/Routing/Extensions.cs new file mode 100644 index 00000000..4d33ed4a --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/Extensions.cs @@ -0,0 +1,252 @@ +using PepperDash.Core; +using Serilog.Events; +using System.Collections.Generic; +using System.Linq; + + +namespace PepperDash.Essentials.Core +{ + + /// + /// Extensions added to any IRoutingInputs classes to provide discovery-based routing + /// on those destinations. + /// + public static class Extensions + { + private static readonly Dictionary RouteRequests = new Dictionary(); + /// + /// Gets any existing RouteDescriptor for a destination, clears it using ReleaseRoute + /// and then attempts a new Route and if sucessful, stores that RouteDescriptor + /// in RouteDescriptorCollection.DefaultCollection + /// + public static void ReleaseAndMakeRoute(this IRoutingSink destination, IRoutingOutputs source, eRoutingSignalType signalType) + { + var routeRequest = new RouteRequest { + Destination = destination, + Source = source, + SignalType = signalType + }; + + var coolingDevice = destination as IWarmingCooling; + + + //We already have a route request for this device, and it's a cooling device and is cooling + if (RouteRequests.TryGetValue(destination.Key, out RouteRequest existingRouteRequest) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true) + { + coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRouteRequest.HandleCooldown; + + coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown; + + RouteRequests[destination.Key] = routeRequest; + + Debug.LogMessage(LogEventLevel.Verbose, "Device: {0} is cooling down and already has a routing request stored. Storing new route request to route to source key: {1}", null, destination.Key, routeRequest.Source.Key); + + return; + } + + //New Request + if (coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true) + { + coolingDevice.IsCoolingDownFeedback.OutputChange -= routeRequest.HandleCooldown; + + coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown; + + RouteRequests.Add(destination.Key, routeRequest); + + Debug.LogMessage(LogEventLevel.Verbose, "Device: {0} is cooling down. Storing route request to route to source key: {1}", null, destination.Key, routeRequest.Source.Key); + return; + } + + if (RouteRequests.ContainsKey(destination.Key) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == false) + { + RouteRequests.Remove(destination.Key); + Debug.LogMessage(LogEventLevel.Verbose, "Device: {0} is NOT cooling down. Removing stored route request and routing to source key: {1}", null, destination.Key, routeRequest.Source.Key); + } + + destination.ReleaseRoute(); + + RunRouteRequest(routeRequest); + } + + private static void RunRouteRequest(RouteRequest request) + { + if (request.Source == null) + return; + + var newRoute = request.Destination.GetRouteToSource(request.Source, request.SignalType); + + if (newRoute == null) + return; + + RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(newRoute); + + Debug.LogMessage(LogEventLevel.Verbose, "Executing full route", request.Destination); + + newRoute.ExecuteRoutes(); + } + + /// + /// Will release the existing route on the destination, if it is found in + /// RouteDescriptorCollection.DefaultCollection + /// + /// + public static void ReleaseRoute(this IRoutingSink destination) + { + + if (RouteRequests.TryGetValue(destination.Key, out RouteRequest existingRequest) && destination is IWarmingCooling) + { + var coolingDevice = destination as IWarmingCooling; + + coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRequest.HandleCooldown; + } + + RouteRequests.Remove(destination.Key); + + var current = RouteDescriptorCollection.DefaultCollection.RemoveRouteDescriptor(destination); + if (current != null) + { + Debug.LogMessage(LogEventLevel.Debug, "Releasing current route: {0}", destination, current.Source.Key); + current.ReleaseRoutes(); + } + } + + /// + /// Builds a RouteDescriptor that contains the steps necessary to make a route between devices. + /// Routes of type AudioVideo will be built as two separate routes, audio and video. If + /// a route is discovered, a new RouteDescriptor is returned. If one or both parts + /// of an audio/video route are discovered a route descriptor is returned. If no route is + /// discovered, then null is returned + /// + public static RouteDescriptor GetRouteToSource(this IRoutingSink destination, IRoutingOutputs source, eRoutingSignalType signalType) + { + var routeDescriptor = new RouteDescriptor(source, destination, signalType); + + // if it's a single signal type, find the route + if (!signalType.HasFlag(eRoutingSignalType.AudioVideo)) + { + Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {0}", null, source.Key); + + if (!destination.GetRouteToSource(source, null, null, signalType, 0, routeDescriptor)) + routeDescriptor = null; + + return routeDescriptor; + } + // otherwise, audioVideo needs to be handled as two steps. + + Debug.LogMessage(LogEventLevel.Debug, "Attempting to build audio and video routes from {0}", destination, source.Key); + + var audioSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Audio, 0, routeDescriptor); + + if (!audioSuccess) + Debug.LogMessage(LogEventLevel.Debug, "Cannot find audio route to {0}", destination, source.Key); + + var videoSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Video, 0, routeDescriptor); + + if (!videoSuccess) + Debug.LogMessage(LogEventLevel.Debug, "Cannot find video route to {0}", destination, source.Key); + + if (!audioSuccess && !videoSuccess) + routeDescriptor = null; + + + return routeDescriptor; + } + + /// + /// The recursive part of this. Will stop on each device, search its inputs for the + /// desired source and if not found, invoke this function for the each input port + /// hoping to find the source. + /// + /// + /// + /// The RoutingOutputPort whose link is being checked for a route + /// Prevents Devices from being twice-checked + /// This recursive function should not be called with AudioVideo + /// Just an informational counter + /// The RouteDescriptor being populated as the route is discovered + /// true if source is hit + static bool GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source, + RoutingOutputPort outputPortToUse, List alreadyCheckedDevices, + eRoutingSignalType signalType, int cycle, RouteDescriptor routeTable) + { + + cycle++; + + Debug.LogMessage(LogEventLevel.Verbose, "GetRouteToSource: {0} {1}--> {2}", null, cycle, source.Key, destination.Key); + + RoutingInputPort goodInputPort = null; + + var destDevInputTies = TieLineCollection.Default.Where(t => + t.DestinationPort.ParentDevice == destination && (t.Type == signalType || t.Type.HasFlag(eRoutingSignalType.AudioVideo))); + + // find a direct tie + var directTie = destDevInputTies.FirstOrDefault( + t => t.DestinationPort.ParentDevice == destination + && t.SourcePort.ParentDevice == source); + if (directTie != null) // Found a tie directly to the source + { + goodInputPort = directTie.DestinationPort; + } + else // no direct-connect. Walk back devices. + { + Debug.LogMessage(LogEventLevel.Verbose, "is not directly connected to {0}. Walking down tie lines", destination, source.Key); + + // No direct tie? Run back out on the inputs' attached devices... + // Only the ones that are routing devices + var attachedMidpoints = destDevInputTies.Where(t => t.SourcePort.ParentDevice is IRoutingInputsOutputs); + + //Create a list for tracking already checked devices to avoid loops, if it doesn't already exist from previous iteration + if (alreadyCheckedDevices == null) + alreadyCheckedDevices = new List(); + alreadyCheckedDevices.Add(destination as IRoutingInputsOutputs); + + foreach (var inputTieToTry in attachedMidpoints) + { + var upstreamDeviceOutputPort = inputTieToTry.SourcePort; + var upstreamRoutingDevice = upstreamDeviceOutputPort.ParentDevice as IRoutingInputsOutputs; + Debug.LogMessage(LogEventLevel.Verbose, "Trying to find route on {0}", destination, upstreamRoutingDevice.Key); + + // Check if this previous device has already been walked + if (alreadyCheckedDevices.Contains(upstreamRoutingDevice)) + { + Debug.LogMessage(LogEventLevel.Verbose, "Skipping input {0} on {1}, this was already checked", destination, upstreamRoutingDevice.Key, destination.Key); + continue; + } + // haven't seen this device yet. Do it. Pass the output port to the next + // level to enable switching on success + var upstreamRoutingSuccess = upstreamRoutingDevice.GetRouteToSource(source, upstreamDeviceOutputPort, + alreadyCheckedDevices, signalType, cycle, routeTable); + if (upstreamRoutingSuccess) + { + Debug.LogMessage(LogEventLevel.Verbose, "Upstream device route found", destination); + goodInputPort = inputTieToTry.DestinationPort; + break; // Stop looping the inputs in this cycle + } + } + } + + + if (goodInputPort == null) + { + Debug.LogMessage(LogEventLevel.Verbose, "No route found to {0}", destination, source.Key); + return false; + } + + // we have a route on corresponding inputPort. *** Do the route *** + + if (outputPortToUse == null) + { + // it's a sink device + routeTable.Routes.Add(new RouteSwitchDescriptor(goodInputPort)); + } + else if (destination is IRouting) + { + routeTable.Routes.Add(new RouteSwitchDescriptor(outputPortToUse, goodInputPort)); + } + else // device is merely IRoutingInputOutputs + Debug.LogMessage(LogEventLevel.Verbose, "No routing. Passthrough device", destination); + + return true; + } + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/GenericExtensions.cs b/src/PepperDash.Essentials.Core/Routing/GenericExtensions.cs new file mode 100644 index 00000000..4406d14f --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/GenericExtensions.cs @@ -0,0 +1,261 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro; +using Crestron.SimplSharpPro.DM; + +using PepperDash.Core; +using Serilog.Events; + + +namespace PepperDash.Essentials.Core +{ + + /// + /// Extensions added to any IRoutingInputs classes to provide discovery-based routing + /// on those destinations. + /// + public static class GenericExtensions + { + //private static readonly Dictionary> RouteRequests = new(); + + /// + /// Gets any existing RouteDescriptor for a destination, clears it using ReleaseRoute + /// and then attempts a new Route and if sucessful, stores that RouteDescriptor + /// in RouteDescriptorCollection.DefaultCollection + /// + public static void ReleaseAndMakeRoute(this IRoutingSink destination, IRoutingOutputs source, eRoutingSignalType signalType) + { + var routeRequest = new RouteRequest { + Destination = destination, + Source = source, + SignalType = signalType + }; + + var coolingDevice = destination as IWarmingCooling; + var existingRouteRequest = destination.GetRouteRequest(); + + //We already have a route request for this device, and it's a cooling device and is cooling + if (existingRouteRequest != null && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true) + { + coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRouteRequest.HandleCooldown; + + coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown; + + destination.UpdateRouteRequest(routeRequest); + + Debug.LogMessage(LogEventLevel.Verbose, "Device: {0} is cooling down and already has a routing request stored. Storing new route request to route to source key: {1}", null, destination.Key, routeRequest.Source.Key); + + return; + } + + //New Request + if (coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true) + { + coolingDevice.IsCoolingDownFeedback.OutputChange -= routeRequest.HandleCooldown; + + coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown; + + destination.UpdateRouteRequest(routeRequest); + + Debug.LogMessage(LogEventLevel.Verbose, "Device: {0} is cooling down. Storing route request to route to source key: {1}", null, destination.Key, routeRequest.Source.Key); + return; + } + + if (existingRouteRequest != null && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == false) + { + destination.UpdateRouteRequest(null); + + Debug.LogMessage(LogEventLevel.Verbose, "Device: {0} is NOT cooling down. Removing stored route request and routing to source key: {1}", null, destination.Key, routeRequest.Source.Key); + } + + destination.ReleaseRoute(); + + RunRouteRequest(routeRequest); + } + + public static void RunRouteRequest(RouteRequest request) + { + if (request.Source == null) + return; + + var newRoute = request.Destination.GetRouteToSource(request.Source, request.SignalType); + + if (newRoute == null) + return; + + RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(newRoute); + + Debug.LogMessage(LogEventLevel.Verbose, "Executing full route", request.Destination); + + newRoute.ExecuteRoutes(); + } + + /// + /// Will release the existing route on the destination, if it is found in + /// RouteDescriptorCollection.DefaultCollection + /// + /// + public static void ReleaseRoute(this IRoutingSink destination) + { + var existingRouteRequest = destination.GetRouteRequest(); + + if (existingRouteRequest != null && destination is IWarmingCooling) + { + var coolingDevice = destination as IWarmingCooling; + + coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRouteRequest.HandleCooldown; + } + + destination.UpdateRouteRequest(null); + + var current = RouteDescriptorCollection.DefaultCollection.RemoveRouteDescriptor(destination); + if (current != null) + { + Debug.LogMessage(LogEventLevel.Debug, "Releasing current route: {0}", destination, current.Source.Key); + current.ReleaseRoutes(); + } + } + + /// + /// Builds a RouteDescriptor that contains the steps necessary to make a route between devices. + /// Routes of type AudioVideo will be built as two separate routes, audio and video. If + /// a route is discovered, a new RouteDescriptor is returned. If one or both parts + /// of an audio/video route are discovered a route descriptor is returned. If no route is + /// discovered, then null is returned + /// + public static RouteDescriptor GetRouteToSource(this IRoutingSink destination, IRoutingOutputs source, eRoutingSignalType signalType) + { + var routeDescriptor = new RouteDescriptor(source, destination, signalType); + + // if it's a single signal type, find the route + if (!signalType.HasFlag(eRoutingSignalType.AudioVideo)) + { + Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {0}", null, source.Key); + + if (!destination.GetRouteToSource(source, null, null, signalType, 0, routeDescriptor)) + routeDescriptor = null; + + return routeDescriptor; + } + // otherwise, audioVideo needs to be handled as two steps. + + Debug.LogMessage(LogEventLevel.Debug, "Attempting to build audio and video routes from {0}", destination, source.Key); + + var audioSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Audio, 0, routeDescriptor); + + if (!audioSuccess) + Debug.LogMessage(LogEventLevel.Debug, "Cannot find audio route to {0}", destination, source.Key); + + var videoSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Video, 0, routeDescriptor); + + if (!videoSuccess) + Debug.LogMessage(LogEventLevel.Debug, "Cannot find video route to {0}", destination, source.Key); + + if (!audioSuccess && !videoSuccess) + routeDescriptor = null; + + + return routeDescriptor; + } + + /// + /// The recursive part of this. Will stop on each device, search its inputs for the + /// desired source and if not found, invoke this function for the each input port + /// hoping to find the source. + /// + /// + /// + /// The RoutingOutputPort whose link is being checked for a route + /// Prevents Devices from being twice-checked + /// This recursive function should not be called with AudioVideo + /// Just an informational counter + /// The RouteDescriptor being populated as the route is discovered + /// true if source is hit + static bool GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source, + RoutingOutputPort outputPortToUse, List> alreadyCheckedDevices, + eRoutingSignalType signalType, int cycle, RouteDescriptor routeTable) + { + + cycle++; + + Debug.LogMessage(LogEventLevel.Verbose, "GetRouteToSource: {0} {1}--> {2}", null, cycle, source.Key, destination.Key); + + RoutingInputPort goodInputPort = null; + + var destDevInputTies = TieLineCollection.Default.Where(t => + t.DestinationPort.ParentDevice == destination && (t.Type == signalType || t.Type.HasFlag(eRoutingSignalType.AudioVideo))); + + // find a direct tie + var directTie = destDevInputTies.FirstOrDefault( + t => t.DestinationPort.ParentDevice == destination + && t.SourcePort.ParentDevice == source); + if (directTie != null) // Found a tie directly to the source + { + goodInputPort = directTie.DestinationPort; + } + else // no direct-connect. Walk back devices. + { + Debug.LogMessage(LogEventLevel.Verbose, "is not directly connected to {0}. Walking down tie lines", destination, source.Key); + + // No direct tie? Run back out on the inputs' attached devices... + // Only the ones that are routing devices + var attachedMidpoints = destDevInputTies.Where(t => t.SourcePort.ParentDevice is IRoutingInputsOutputs); + + //Create a list for tracking already checked devices to avoid loops, if it doesn't already exist from previous iteration + if (alreadyCheckedDevices == null) + alreadyCheckedDevices = new List>(); + alreadyCheckedDevices.Add(destination as IRoutingInputsOutputs); + + foreach (var inputTieToTry in attachedMidpoints) + { + var upstreamDeviceOutputPort = inputTieToTry.SourcePort; + var upstreamRoutingDevice = upstreamDeviceOutputPort.ParentDevice as IRoutingInputsOutputs; + Debug.LogMessage(LogEventLevel.Verbose, "Trying to find route on {0}", destination, upstreamRoutingDevice.Key); + + // Check if this previous device has already been walked + if (alreadyCheckedDevices.Contains(upstreamRoutingDevice)) + { + Debug.LogMessage(LogEventLevel.Verbose, "Skipping input {0} on {1}, this was already checked", destination, upstreamRoutingDevice.Key, destination.Key); + continue; + } + // haven't seen this device yet. Do it. Pass the output port to the next + // level to enable switching on success + var upstreamRoutingSuccess = upstreamRoutingDevice.GetRouteToSource(source, upstreamDeviceOutputPort, + alreadyCheckedDevices, signalType, cycle, routeTable); + if (upstreamRoutingSuccess) + { + Debug.LogMessage(LogEventLevel.Verbose, "Upstream device route found", destination); + goodInputPort = inputTieToTry.DestinationPort; + break; // Stop looping the inputs in this cycle + } + } + } + + + if (goodInputPort == null) + { + Debug.LogMessage(LogEventLevel.Verbose, "No route found to {0}", destination, source.Key); + return false; + } + + // we have a route on corresponding inputPort. *** Do the route *** + + if (outputPortToUse == null) + { + // it's a sink device + routeTable.Routes.Add(new RouteSwitchDescriptor(goodInputPort)); + } + else if (destination is IRouting) + { + routeTable.Routes.Add(new RouteSwitchDescriptor(outputPortToUse, goodInputPort)); + } + else // device is merely IRoutingInputOutputs + Debug.LogMessage(LogEventLevel.Verbose, "No routing. Passthrough device", destination); + + return true; + } + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IHasCurrentSourceInfoChange.cs b/src/PepperDash.Essentials.Core/Routing/IHasCurrentSourceInfoChange.cs new file mode 100644 index 00000000..20b46520 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/IHasCurrentSourceInfoChange.cs @@ -0,0 +1,30 @@ +/* Unmerged change from project 'PepperDash.Essentials.Core (net6)' +Before: +namespace PepperDash.Essentials.Core.Routing.Interfaces +After: +using PepperDash; +using PepperDash.Essentials; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Routing; +using PepperDash.Essentials.Core.Routing; +using PepperDash.Essentials.Core.Routing.Interfaces +*/ +namespace PepperDash.Essentials.Core.Routing +{ + /// + /// The handler type for a Room's SourceInfoChange + /// + public delegate void SourceInfoChangeHandler(SourceListItem info, ChangeType type); + //******************************************************************************************* + // Interfaces + + /// + /// For rooms with a single presentation source, change event + /// + public interface IHasCurrentSourceInfoChange + { + string CurrentSourceInfoKey { get; set; } + SourceListItem CurrentSourceInfo { get; set; } + event SourceInfoChangeHandler CurrentSourceChange; + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IInputSync.cs b/src/PepperDash.Essentials.Core/Routing/IInputSync.cs index 465b48a2..accb70a7 100644 --- a/src/PepperDash.Essentials.Core/Routing/IInputSync.cs +++ b/src/PepperDash.Essentials.Core/Routing/IInputSync.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; namespace PepperDash.Essentials.Core.Routing { - public interface IVideoSync: IKeyed + public interface IVideoSync : IKeyed { bool VideoSyncDetected { get; } diff --git a/src/PepperDash.Essentials.Core/Routing/IRmcRouting.cs b/src/PepperDash.Essentials.Core/Routing/IRmcRouting.cs new file mode 100644 index 00000000..bddcbcf7 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/IRmcRouting.cs @@ -0,0 +1,10 @@ +namespace PepperDash.Essentials.Core.Routing +{ + /// + /// Defines a receiver that has internal routing (DM-RMC-4K-Z-SCALER-C) + /// + public interface IRmcRouting : IRoutingNumeric + { + IntFeedback AudioVideoSourceNumericFeedback { get; } + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRmcRoutingWithFeedback.cs b/src/PepperDash.Essentials.Core/Routing/IRmcRoutingWithFeedback.cs new file mode 100644 index 00000000..3648204c --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/IRmcRoutingWithFeedback.cs @@ -0,0 +1,11 @@ +using PepperDash.Essentials.Core.Routing; + +namespace PepperDash.Essentials.Core +{ + /// + /// Defines an IRmcRouting with a feedback event + /// + public interface IRmcRoutingWithFeedback : IRmcRouting + { + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRouting.cs b/src/PepperDash.Essentials.Core/Routing/IRouting.cs new file mode 100644 index 00000000..e3231858 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/IRouting.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; + +namespace PepperDash.Essentials.Core +{ + /// + /// Defines a midpoint device as have internal routing. Any devices in the middle of the + /// signal chain, that do switching, must implement this for routing to work otherwise + /// the routing algorithm will treat the IRoutingInputsOutputs device as a passthrough + /// device. + /// + public interface IRouting : IRoutingInputsOutputs + { + void ExecuteSwitch(object inputSelector, object outputSelector, eRoutingSignalType signalType); + } + + /*public interface IRouting : IRoutingInputsOutputs + { + void ExecuteSwitch(TInputSelector inputSelector, TOutputSelector outputSelector, eRoutingSignalType signalType); + }*/ +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingFeedback.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingFeedback.cs new file mode 100644 index 00000000..b8b22915 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingFeedback.cs @@ -0,0 +1,16 @@ +using System; + +using PepperDash.Core; + + +namespace PepperDash.Essentials.Core +{ + /// + /// Defines an event structure for reporting output route data + /// + public interface IRoutingFeedback : IKeyName + { + event EventHandler NumericSwitchChange; + //void OnSwitchChange(RoutingNumericEventArgs e); + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingHasVideoInputSyncFeedbacks.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingHasVideoInputSyncFeedbacks.cs new file mode 100644 index 00000000..0f6d7834 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingHasVideoInputSyncFeedbacks.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro; +using Crestron.SimplSharpPro.DM; + +using PepperDash.Core; + + +namespace PepperDash.Essentials.Core +{ + + public interface IRoutingHasVideoInputSyncFeedbacks + { + FeedbackCollection VideoInputSyncFeedbacks { get; } + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingInputs.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingInputs.cs new file mode 100644 index 00000000..ff96fded --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingInputs.cs @@ -0,0 +1,18 @@ +using PepperDash.Core; + + +namespace PepperDash.Essentials.Core +{ + /// + /// Defines a class that has a collection of RoutingInputPorts + /// + public interface IRoutingInputs : IKeyed + { + RoutingPortCollection InputPorts { get; } + } + +/* public interface IRoutingInputs : IKeyed + { + RoutingPortCollection, TSelector> InputPorts { get; } + }*/ +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingInputsExtensions.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingInputsExtensions.cs deleted file mode 100644 index 605569d2..00000000 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingInputsExtensions.cs +++ /dev/null @@ -1,426 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro; -using Crestron.SimplSharpPro.DM; - -using PepperDash.Core; -using Serilog.Events; - - -namespace PepperDash.Essentials.Core -{ - public class RouteRequest - { - public IRoutingSink Destination {get; set;} - public IRoutingOutputs Source {get; set;} - public eRoutingSignalType SignalType {get; set;} - - public void HandleCooldown(object sender, FeedbackEventArgs args) - { - var coolingDevice = sender as IWarmingCooling; - - if(args.BoolValue == false) - { - Destination.ReleaseAndMakeRoute(Source, SignalType); - - if(sender == null) return; - - coolingDevice.IsCoolingDownFeedback.OutputChange -= HandleCooldown; - } - } - } - - /// - /// Extensions added to any IRoutingInputs classes to provide discovery-based routing - /// on those destinations. - /// - public static class IRoutingInputsExtensions - { - private static Dictionary RouteRequests = new Dictionary(); - /// - /// Gets any existing RouteDescriptor for a destination, clears it using ReleaseRoute - /// and then attempts a new Route and if sucessful, stores that RouteDescriptor - /// in RouteDescriptorCollection.DefaultCollection - /// - public static void ReleaseAndMakeRoute(this IRoutingSink destination, IRoutingOutputs source, eRoutingSignalType signalType) - { - var routeRequest = new RouteRequest { - Destination = destination, - Source = source, - SignalType = signalType - }; - - var coolingDevice = destination as IWarmingCooling; - - RouteRequest existingRouteRequest; - - //We already have a route request for this device, and it's a cooling device and is cooling - if (RouteRequests.TryGetValue(destination.Key, out existingRouteRequest) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true) - { - coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRouteRequest.HandleCooldown; - - coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown; - - RouteRequests[destination.Key] = routeRequest; - - Debug.LogMessage(LogEventLevel.Verbose, "******************************************************** Device: {0} is cooling down and already has a routing request stored. Storing new route request to route to source key: {1}", destination.Key, routeRequest.Source.Key); - - return; - } - - //New Request - if (coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true) - { - coolingDevice.IsCoolingDownFeedback.OutputChange -= routeRequest.HandleCooldown; - - coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown; - - RouteRequests.Add(destination.Key, routeRequest); - - Debug.LogMessage(LogEventLevel.Verbose, "******************************************************** Device: {0} is cooling down. Storing route request to route to source key: {1}", destination.Key, routeRequest.Source.Key); - return; - } - - if (RouteRequests.ContainsKey(destination.Key) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == false) - { - RouteRequests.Remove(destination.Key); - Debug.LogMessage(LogEventLevel.Verbose, "******************************************************** Device: {0} is NOT cooling down. Removing stored route request and routing to source key: {1}", destination.Key, routeRequest.Source.Key); - } - - destination.ReleaseRoute(); - - RunRouteRequest(routeRequest); - } - - public static void RunRouteRequest(RouteRequest request) - { - if (request.Source == null) return; - var newRoute = request.Destination.GetRouteToSource(request.Source, request.SignalType); - if (newRoute == null) return; - RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(newRoute); - Debug.LogMessage(LogEventLevel.Verbose, request.Destination, "Executing full route"); - newRoute.ExecuteRoutes(); - } - - /// - /// Will release the existing route on the destination, if it is found in - /// RouteDescriptorCollection.DefaultCollection - /// - /// - public static void ReleaseRoute(this IRoutingSink destination) - { - RouteRequest existingRequest; - - if (RouteRequests.TryGetValue(destination.Key, out existingRequest) && destination is IWarmingCooling) - { - var coolingDevice = destination as IWarmingCooling; - - coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRequest.HandleCooldown; - } - - RouteRequests.Remove(destination.Key); - - var current = RouteDescriptorCollection.DefaultCollection.RemoveRouteDescriptor(destination); - if (current != null) - { - Debug.LogMessage(LogEventLevel.Debug, destination, "Releasing current route: {0}", current.Source.Key); - current.ReleaseRoutes(); - } - } - - /// - /// Builds a RouteDescriptor that contains the steps necessary to make a route between devices. - /// Routes of type AudioVideo will be built as two separate routes, audio and video. If - /// a route is discovered, a new RouteDescriptor is returned. If one or both parts - /// of an audio/video route are discovered a route descriptor is returned. If no route is - /// discovered, then null is returned - /// - public static RouteDescriptor GetRouteToSource(this IRoutingSink destination, IRoutingOutputs source, eRoutingSignalType signalType) - { - var routeDescr = new RouteDescriptor(source, destination, signalType); - // if it's a single signal type, find the route - if ((signalType & (eRoutingSignalType.Audio & eRoutingSignalType.Video)) == (eRoutingSignalType.Audio & eRoutingSignalType.Video)) - { - Debug.LogMessage(LogEventLevel.Debug, destination, "Attempting to build source route from {0}", source.Key); - if (!destination.GetRouteToSource(source, null, null, signalType, 0, routeDescr)) - routeDescr = null; - } - // otherwise, audioVideo needs to be handled as two steps. - else - { - Debug.LogMessage(LogEventLevel.Debug, destination, "Attempting to build audio and video routes from {0}", source.Key); - var audioSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Audio, 0, routeDescr); - if (!audioSuccess) - Debug.LogMessage(LogEventLevel.Debug, destination, "Cannot find audio route to {0}", source.Key); - var videoSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Video, 0, routeDescr); - if (!videoSuccess) - Debug.LogMessage(LogEventLevel.Debug, destination, "Cannot find video route to {0}", source.Key); - if (!audioSuccess && !videoSuccess) - routeDescr = null; - } - - //Debug.LogMessage(LogEventLevel.Debug, destination, "Route{0} discovered", routeDescr == null ? " NOT" : ""); - return routeDescr; - } - - /// - /// The recursive part of this. Will stop on each device, search its inputs for the - /// desired source and if not found, invoke this function for the each input port - /// hoping to find the source. - /// - /// - /// - /// The RoutingOutputPort whose link is being checked for a route - /// Prevents Devices from being twice-checked - /// This recursive function should not be called with AudioVideo - /// Just an informational counter - /// The RouteDescriptor being populated as the route is discovered - /// true if source is hit - static bool GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source, - RoutingOutputPort outputPortToUse, List alreadyCheckedDevices, - eRoutingSignalType signalType, int cycle, RouteDescriptor routeTable) - { - cycle++; - Debug.LogMessage(LogEventLevel.Verbose, "GetRouteToSource: {0} {1}--> {2}", cycle, source.Key, destination.Key); - - RoutingInputPort goodInputPort = null; - var destDevInputTies = TieLineCollection.Default.Where(t => - t.DestinationPort.ParentDevice == destination && (t.Type == signalType || (t.Type & (eRoutingSignalType.Audio | eRoutingSignalType.Video)) == (eRoutingSignalType.Audio | eRoutingSignalType.Video))); - - // find a direct tie - var directTie = destDevInputTies.FirstOrDefault( - t => t.DestinationPort.ParentDevice == destination - && t.SourcePort.ParentDevice == source); - if (directTie != null) // Found a tie directly to the source - { - goodInputPort = directTie.DestinationPort; - } - else // no direct-connect. Walk back devices. - { - Debug.LogMessage(LogEventLevel.Verbose, destination, "is not directly connected to {0}. Walking down tie lines", source.Key); - - // No direct tie? Run back out on the inputs' attached devices... - // Only the ones that are routing devices - var attachedMidpoints = destDevInputTies.Where(t => t.SourcePort.ParentDevice is IRoutingInputsOutputs); - - //Create a list for tracking already checked devices to avoid loops, if it doesn't already exist from previous iteration - if (alreadyCheckedDevices == null) - alreadyCheckedDevices = new List(); - alreadyCheckedDevices.Add(destination as IRoutingInputsOutputs); - - foreach (var inputTieToTry in attachedMidpoints) - { - var upstreamDeviceOutputPort = inputTieToTry.SourcePort; - var upstreamRoutingDevice = upstreamDeviceOutputPort.ParentDevice as IRoutingInputsOutputs; - Debug.LogMessage(LogEventLevel.Verbose, destination, "Trying to find route on {0}", upstreamRoutingDevice.Key); - - // Check if this previous device has already been walked - if (alreadyCheckedDevices.Contains(upstreamRoutingDevice)) - { - Debug.LogMessage(LogEventLevel.Verbose, destination, "Skipping input {0} on {1}, this was already checked", upstreamRoutingDevice.Key, destination.Key); - continue; - } - // haven't seen this device yet. Do it. Pass the output port to the next - // level to enable switching on success - var upstreamRoutingSuccess = upstreamRoutingDevice.GetRouteToSource(source, upstreamDeviceOutputPort, - alreadyCheckedDevices, signalType, cycle, routeTable); - if (upstreamRoutingSuccess) - { - Debug.LogMessage(LogEventLevel.Verbose, destination, "Upstream device route found"); - goodInputPort = inputTieToTry.DestinationPort; - break; // Stop looping the inputs in this cycle - } - } - } - - // we have a route on corresponding inputPort. *** Do the route *** - if (goodInputPort != null) - { - //Debug.LogMessage(LogEventLevel.Verbose, destination, "adding RouteDescriptor"); - if (outputPortToUse == null) - { - // it's a sink device - routeTable.Routes.Add(new RouteSwitchDescriptor(goodInputPort)); - } - else if (destination is IRouting) - { - routeTable.Routes.Add(new RouteSwitchDescriptor (outputPortToUse, goodInputPort)); - } - else // device is merely IRoutingInputOutputs - Debug.LogMessage(LogEventLevel.Verbose, destination, " No routing. Passthrough device"); - //Debug.LogMessage(LogEventLevel.Verbose, destination, "Exiting cycle {0}", cycle); - return true; - } - - Debug.LogMessage(LogEventLevel.Verbose, destination, "No route found to {0}", source.Key); - return false; - } - } - - - - - - // MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE - - - /// - /// A collection of RouteDescriptors - typically the static DefaultCollection is used - /// - public class RouteDescriptorCollection - { - public static RouteDescriptorCollection DefaultCollection - { - get - { - if (_DefaultCollection == null) - _DefaultCollection = new RouteDescriptorCollection(); - return _DefaultCollection; - } - } - static RouteDescriptorCollection _DefaultCollection; - - List RouteDescriptors = new List(); - - /// - /// Adds a RouteDescriptor to the list. If an existing RouteDescriptor for the - /// destination exists already, it will not be added - in order to preserve - /// proper route releasing. - /// - /// - public void AddRouteDescriptor(RouteDescriptor descriptor) - { - if (RouteDescriptors.Any(t => t.Destination == descriptor.Destination)) - { - Debug.LogMessage(LogEventLevel.Debug, descriptor.Destination, - "Route to [{0}] already exists in global routes table", descriptor.Source.Key); - return; - } - RouteDescriptors.Add(descriptor); - } - - /// - /// Gets the RouteDescriptor for a destination - /// - /// null if no RouteDescriptor for a destination exists - public RouteDescriptor GetRouteDescriptorForDestination(IRoutingInputs destination) - { - return RouteDescriptors.FirstOrDefault(rd => rd.Destination == destination); - } - - /// - /// Returns the RouteDescriptor for a given destination AND removes it from collection. - /// Returns null if no route with the provided destination exists. - /// - public RouteDescriptor RemoveRouteDescriptor(IRoutingInputs destination) - { - var descr = GetRouteDescriptorForDestination(destination); - if (descr != null) - RouteDescriptors.Remove(descr); - return descr; - } - } - - /// - /// Represents an collection of individual route steps between Source and Destination - /// - public class RouteDescriptor - { - public IRoutingInputs Destination { get; private set; } - public IRoutingOutputs Source { get; private set; } - public eRoutingSignalType SignalType { get; private set; } - public List Routes { get; private set; } - - - public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, eRoutingSignalType signalType) - { - Destination = destination; - Source = source; - SignalType = signalType; - Routes = new List(); - } - - /// - /// Executes all routes described in this collection. Typically called via - /// extension method IRoutingInputs.ReleaseAndMakeRoute() - /// - public void ExecuteRoutes() - { - foreach (var route in Routes) - { - Debug.LogMessage(LogEventLevel.Verbose, "ExecuteRoutes: {0}", route.ToString()); - if (route.SwitchingDevice is IRoutingSink) - { - var device = route.SwitchingDevice as IRoutingSinkWithSwitching; - if (device == null) - continue; - - device.ExecuteSwitch(route.InputPort.Selector); - } - else if (route.SwitchingDevice is IRouting) - { - (route.SwitchingDevice as IRouting).ExecuteSwitch(route.InputPort.Selector, route.OutputPort.Selector, SignalType); - route.OutputPort.InUseTracker.AddUser(Destination, "destination-" + SignalType); - Debug.LogMessage(LogEventLevel.Verbose, "Output port {0} routing. Count={1}", route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue); - } - } - } - - /// - /// Releases all routes in this collection. Typically called via - /// extension method IRoutingInputs.ReleaseAndMakeRoute() - /// - public void ReleaseRoutes() - { - foreach (var route in Routes) - { - if (route.SwitchingDevice is IRouting) - { - // Pull the route from the port. Whatever is watching the output's in use tracker is - // responsible for responding appropriately. - route.OutputPort.InUseTracker.RemoveUser(Destination, "destination-" + SignalType); - Debug.LogMessage(LogEventLevel.Verbose, "Port {0} releasing. Count={1}", route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue); - } - } - } - - public override string ToString() - { - var routesText = Routes.Select(r => r.ToString()).ToArray(); - return string.Format("Route table from {0} to {1}:\r{2}", Source.Key, Destination.Key, string.Join("\r", routesText)); - } - } - - /// - /// Represents an individual link for a route - /// - public class RouteSwitchDescriptor - { - public IRoutingInputs SwitchingDevice { get { return InputPort.ParentDevice; } } - public RoutingOutputPort OutputPort { get; set; } - public RoutingInputPort InputPort { get; set; } - - public RouteSwitchDescriptor(RoutingInputPort inputPort) - { - InputPort = inputPort; - } - - public RouteSwitchDescriptor(RoutingOutputPort outputPort, RoutingInputPort inputPort) - { - InputPort = inputPort; - OutputPort = outputPort; - } - - public override string ToString() - { - if(SwitchingDevice is IRouting) - return string.Format("{0} switches output '{1}' to input '{2}'", SwitchingDevice.Key, OutputPort.Selector, InputPort.Selector); - else - return string.Format("{0} switches to input '{1}'", SwitchingDevice.Key, InputPort.Selector); - - } - } -} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingInputsOutputs.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingInputsOutputs.cs new file mode 100644 index 00000000..e202fa3c --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingInputsOutputs.cs @@ -0,0 +1,16 @@ +namespace PepperDash.Essentials.Core +{ + /// + /// For devices like RMCs, baluns, other devices with no switching. + /// + public interface IRoutingInputsOutputs : IRoutingInputs, IRoutingOutputs + { + } + +/* /// + /// For devices like RMCs, baluns, other devices with no switching. + /// + public interface IRoutingInputsOutputs : IRoutingInputs, IRoutingOutputs + { + }*/ +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingNumeric.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingNumeric.cs new file mode 100644 index 00000000..d41909f1 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingNumeric.cs @@ -0,0 +1,7 @@ +namespace PepperDash.Essentials.Core +{ + public interface IRoutingNumeric : IRouting + { + void ExecuteNumericSwitch(ushort input, ushort output, eRoutingSignalType type); + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingNumericWithFeedback.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingNumericWithFeedback.cs new file mode 100644 index 00000000..e278a193 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingNumericWithFeedback.cs @@ -0,0 +1,9 @@ +namespace PepperDash.Essentials.Core +{ + /// + /// Defines an IRoutingNumeric with a feedback event + /// + public interface IRoutingNumericWithFeedback : IRoutingNumeric, IRoutingFeedback + { + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingOutputs.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingOutputs.cs new file mode 100644 index 00000000..d3bc70de --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingOutputs.cs @@ -0,0 +1,19 @@ +using PepperDash.Core; + + +namespace PepperDash.Essentials.Core +{ + /// + /// Defines a class that has a collection of RoutingOutputPorts + /// + + public interface IRoutingOutputs : IKeyed + { + RoutingPortCollection OutputPorts { get; } + } + +/* public interface IRoutingOutputs : IKeyed + { + RoutingPortCollection, TSelector> OutputPorts { get; } + }*/ +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs new file mode 100644 index 00000000..c51ed12f --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs @@ -0,0 +1,22 @@ +using PepperDash.Essentials.Core.Routing; + +namespace PepperDash.Essentials.Core +{ + /// + /// For fixed-source endpoint devices + /// + public interface IRoutingSink : IRoutingInputs, IHasCurrentSourceInfoChange + { + + } + + /*/// + /// For fixed-source endpoint devices + /// + public interface IRoutingSink : IRoutingInputs, IHasCurrentSourceInfoChange + { + void UpdateRouteRequest(RouteRequest request); + + RouteRequest GetRouteRequest(); + }*/ +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithSwitching.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithSwitching.cs new file mode 100644 index 00000000..b31bd973 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithSwitching.cs @@ -0,0 +1,20 @@ +using System; + +namespace PepperDash.Essentials.Core +{ + /// + /// Endpoint device like a display, that selects inputs + /// + public interface IRoutingSinkWithSwitching : IRoutingSink + { + void ExecuteSwitch(object inputSelector); + } + +/* /// + /// Endpoint device like a display, that selects inputs + /// + public interface IRoutingSinkWithSwitching : IRoutingSink + { + void ExecuteSwitch(TSelector inputSelector); + }*/ +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingSource.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingSource.cs new file mode 100644 index 00000000..6ae51a2b --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingSource.cs @@ -0,0 +1,9 @@ +namespace PepperDash.Essentials.Core +{ + /// + /// Defines an IRoutingOutputs devices as being a source - the start of the chain + /// + public interface IRoutingSource : IRoutingOutputs + { + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingWithClear.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingWithClear.cs new file mode 100644 index 00000000..077d4ecd --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingWithClear.cs @@ -0,0 +1,12 @@ +namespace PepperDash.Essentials.Core +{ + public interface IRoutingWithClear : IRouting + { + /// + /// Clears a route to an output, however a device needs to do that + /// + /// Output to clear + /// signal type to clear + void ClearRoute(object outputSelector, eRoutingSignalType signalType); + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/ITxRouting.cs b/src/PepperDash.Essentials.Core/Routing/ITxRouting.cs new file mode 100644 index 00000000..0950e6a6 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/ITxRouting.cs @@ -0,0 +1,8 @@ +namespace PepperDash.Essentials.Core +{ + public interface ITxRouting : IRoutingNumeric + { + IntFeedback VideoSourceNumericFeedback { get; } + IntFeedback AudioSourceNumericFeedback { get; } + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/ITxRoutingWithFeedback.cs b/src/PepperDash.Essentials.Core/Routing/ITxRoutingWithFeedback.cs new file mode 100644 index 00000000..484fa134 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/ITxRoutingWithFeedback.cs @@ -0,0 +1,9 @@ +namespace PepperDash.Essentials.Core +{ + /// + /// Defines an IRmcRouting with a feedback event + /// + public interface ITxRoutingWithFeedback : ITxRouting + { + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RouteDescriptor.cs b/src/PepperDash.Essentials.Core/Routing/RouteDescriptor.cs new file mode 100644 index 00000000..ebacc809 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/RouteDescriptor.cs @@ -0,0 +1,152 @@ +using System.Collections.Generic; +using System.Linq; +using Crestron.SimplSharpPro; + +using PepperDash.Core; +using Serilog.Events; + + +namespace PepperDash.Essentials.Core +{ + /// + /// Represents an collection of individual route steps between Source and Destination + /// + public class RouteDescriptor + { + public IRoutingInputs Destination { get; private set; } + public IRoutingOutputs Source { get; private set; } + public eRoutingSignalType SignalType { get; private set; } + public List Routes { get; private set; } + + + public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, eRoutingSignalType signalType) + { + Destination = destination; + Source = source; + SignalType = signalType; + Routes = new List(); + } + + /// + /// Executes all routes described in this collection. Typically called via + /// extension method IRoutingInputs.ReleaseAndMakeRoute() + /// + public void ExecuteRoutes() + { + foreach (var route in Routes) + { + Debug.LogMessage(LogEventLevel.Verbose, "ExecuteRoutes: {0}",null, route.ToString()); + + if (route.SwitchingDevice is IRoutingSinkWithSwitching sink) + { + sink.ExecuteSwitch(route.InputPort.Selector); + continue; + } + + if (route.SwitchingDevice is IRouting switchingDevice) + { + switchingDevice.ExecuteSwitch(route.InputPort.Selector, route.OutputPort.Selector, SignalType); + + route.OutputPort.InUseTracker.AddUser(Destination, "destination-" + SignalType); + + Debug.LogMessage(LogEventLevel.Verbose, "Output port {0} routing. Count={1}", null, route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue); + } + } + } + + /// + /// Releases all routes in this collection. Typically called via + /// extension method IRoutingInputs.ReleaseAndMakeRoute() + /// + public void ReleaseRoutes() + { + foreach (var route in Routes) + { + if (route.SwitchingDevice is IRouting) + { + // Pull the route from the port. Whatever is watching the output's in use tracker is + // responsible for responding appropriately. + route.OutputPort.InUseTracker.RemoveUser(Destination, "destination-" + SignalType); + Debug.LogMessage(LogEventLevel.Verbose, "Port {0} releasing. Count={1}",null, route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue); + } + } + } + + public override string ToString() + { + var routesText = Routes.Select(r => r.ToString()).ToArray(); + return string.Format("Route table from {0} to {1}:\r{2}", Source.Key, Destination.Key, string.Join("\r", routesText)); + } + } + + /*/// + /// Represents an collection of individual route steps between Source and Destination + /// + public class RouteDescriptor + { + public IRoutingInputs Destination { get; private set; } + public IRoutingOutputs Source { get; private set; } + public eRoutingSignalType SignalType { get; private set; } + public List> Routes { get; private set; } + + + public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, eRoutingSignalType signalType) + { + Destination = destination; + Source = source; + SignalType = signalType; + Routes = new List>(); + } + + /// + /// Executes all routes described in this collection. Typically called via + /// extension method IRoutingInputs.ReleaseAndMakeRoute() + /// + public void ExecuteRoutes() + { + foreach (var route in Routes) + { + Debug.LogMessage(LogEventLevel.Verbose, "ExecuteRoutes: {0}", null, route.ToString()); + + if (route.SwitchingDevice is IRoutingSinkWithSwitching sink) + { + sink.ExecuteSwitch(route.InputPort.Selector); + continue; + } + + if (route.SwitchingDevice is IRouting switchingDevice) + { + switchingDevice.ExecuteSwitch(route.InputPort.Selector, route.OutputPort.Selector, SignalType); + + route.OutputPort.InUseTracker.AddUser(Destination, "destination-" + SignalType); + + Debug.LogMessage(LogEventLevel.Verbose, "Output port {0} routing. Count={1}", null, route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue); + } + } + } + + /// + /// Releases all routes in this collection. Typically called via + /// extension method IRoutingInputs.ReleaseAndMakeRoute() + /// + public void ReleaseRoutes() + { + foreach (var route in Routes) + { + if (route.SwitchingDevice is IRouting) + { + // Pull the route from the port. Whatever is watching the output's in use tracker is + // responsible for responding appropriately. + route.OutputPort.InUseTracker.RemoveUser(Destination, "destination-" + SignalType); + Debug.LogMessage(LogEventLevel.Verbose, "Port {0} releasing. Count={1}", null, route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue); + } + } + } + + public override string ToString() + { + var routesText = Routes.Select(r => r.ToString()).ToArray(); + return string.Format("Route table from {0} to {1}:\r{2}", Source.Key, Destination.Key, string.Join("\r", routesText)); + } + }*/ +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RouteDescriptorCollection.cs b/src/PepperDash.Essentials.Core/Routing/RouteDescriptorCollection.cs new file mode 100644 index 00000000..c9e3da37 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/RouteDescriptorCollection.cs @@ -0,0 +1,123 @@ +using System.Collections.Generic; +using System.Linq; + +using PepperDash.Core; +using Serilog.Events; + + +namespace PepperDash.Essentials.Core +{ + /// + /// A collection of RouteDescriptors - typically the static DefaultCollection is used + /// + public class RouteDescriptorCollection + { + public static RouteDescriptorCollection DefaultCollection + { + get + { + if (_DefaultCollection == null) + _DefaultCollection = new RouteDescriptorCollection(); + return _DefaultCollection; + } + } + private static RouteDescriptorCollection _DefaultCollection; + + private readonly List RouteDescriptors = new List(); + + /// + /// Adds a RouteDescriptor to the list. If an existing RouteDescriptor for the + /// destination exists already, it will not be added - in order to preserve + /// proper route releasing. + /// + /// + public void AddRouteDescriptor(RouteDescriptor descriptor) + { + if (RouteDescriptors.Any(t => t.Destination == descriptor.Destination)) + { + Debug.LogMessage(LogEventLevel.Debug, descriptor.Destination, + "Route to [{0}] already exists in global routes table", descriptor.Source.Key); + return; + } + RouteDescriptors.Add(descriptor); + } + + /// + /// Gets the RouteDescriptor for a destination + /// + /// null if no RouteDescriptor for a destination exists + public RouteDescriptor GetRouteDescriptorForDestination(IRoutingInputs destination) + { + return RouteDescriptors.FirstOrDefault(rd => rd.Destination == destination); + } + + /// + /// Returns the RouteDescriptor for a given destination AND removes it from collection. + /// Returns null if no route with the provided destination exists. + /// + public RouteDescriptor RemoveRouteDescriptor(IRoutingInputs destination) + { + var descr = GetRouteDescriptorForDestination(destination); + if (descr != null) + RouteDescriptors.Remove(descr); + return descr; + } + } + + /*/// + /// A collection of RouteDescriptors - typically the static DefaultCollection is used + /// + public class RouteDescriptorCollection + { + public static RouteDescriptorCollection DefaultCollection + { + get + { + if (_DefaultCollection == null) + _DefaultCollection = new RouteDescriptorCollection(); + return _DefaultCollection; + } + } + private static RouteDescriptorCollection _DefaultCollection; + + private readonly List RouteDescriptors = new List(); + + /// + /// Adds a RouteDescriptor to the list. If an existing RouteDescriptor for the + /// destination exists already, it will not be added - in order to preserve + /// proper route releasing. + /// + /// + public void AddRouteDescriptor(RouteDescriptor descriptor) + { + if (RouteDescriptors.Any(t => t.Destination == descriptor.Destination)) + { + Debug.LogMessage(LogEventLevel.Debug, descriptor.Destination, + "Route to [{0}] already exists in global routes table", descriptor.Source.Key); + return; + } + RouteDescriptors.Add(descriptor); + } + + /// + /// Gets the RouteDescriptor for a destination + /// + /// null if no RouteDescriptor for a destination exists + public RouteDescriptor GetRouteDescriptorForDestination(IRoutingInputs destination) + { + return RouteDescriptors.FirstOrDefault(rd => rd.Destination == destination); + } + + /// + /// Returns the RouteDescriptor for a given destination AND removes it from collection. + /// Returns null if no route with the provided destination exists. + /// + public RouteDescriptor RemoveRouteDescriptor(IRoutingInputs destination) + { + var descr = GetRouteDescriptorForDestination(destination); + if (descr != null) + RouteDescriptors.Remove(descr); + return descr; + } + }*/ +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RouteRequest.cs b/src/PepperDash.Essentials.Core/Routing/RouteRequest.cs new file mode 100644 index 00000000..f4836c6d --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/RouteRequest.cs @@ -0,0 +1,44 @@ +namespace PepperDash.Essentials.Core +{ + public class RouteRequest + { + public IRoutingSink Destination {get; set;} + public IRoutingOutputs Source {get; set;} + public eRoutingSignalType SignalType {get; set;} + + public void HandleCooldown(object sender, FeedbackEventArgs args) + { + var coolingDevice = sender as IWarmingCooling; + + if(args.BoolValue == false) + { + Destination.ReleaseAndMakeRoute(Source, SignalType); + + if(sender == null) return; + + coolingDevice.IsCoolingDownFeedback.OutputChange -= HandleCooldown; + } + } + } + + /*public class RouteRequest + { + public IRoutingSink Destination { get; set; } + public IRoutingOutputs Source { get; set; } + public eRoutingSignalType SignalType { get; set; } + + public void HandleCooldown(object sender, FeedbackEventArgs args) + { + var coolingDevice = sender as IWarmingCooling; + + if (args.BoolValue == false) + { + Destination.ReleaseAndMakeRoute(Source, SignalType); + + if (sender == null) return; + + coolingDevice.IsCoolingDownFeedback.OutputChange -= HandleCooldown; + } + } + }*/ +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RouteSwitchDescriptor.cs b/src/PepperDash.Essentials.Core/Routing/RouteSwitchDescriptor.cs new file mode 100644 index 00000000..7b9fcabe --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/RouteSwitchDescriptor.cs @@ -0,0 +1,60 @@ +namespace PepperDash.Essentials.Core +{ + /// + /// Represents an individual link for a route + /// + public class RouteSwitchDescriptor + { + public IRoutingInputs SwitchingDevice { get { return InputPort.ParentDevice; } } + public RoutingOutputPort OutputPort { get; set; } + public RoutingInputPort InputPort { get; set; } + + public RouteSwitchDescriptor(RoutingInputPort inputPort) + { + InputPort = inputPort; + } + + public RouteSwitchDescriptor(RoutingOutputPort outputPort, RoutingInputPort inputPort) + { + InputPort = inputPort; + OutputPort = outputPort; + } + + public override string ToString() + { + if(SwitchingDevice is IRouting) + return string.Format("{0} switches output '{1}' to input '{2}'", SwitchingDevice.Key, OutputPort.Selector, InputPort.Selector); + else + return string.Format("{0} switches to input '{1}'", SwitchingDevice.Key, InputPort.Selector); + } + } + + /*/// + /// Represents an individual link for a route + /// + public class RouteSwitchDescriptor + { + public IRoutingInputs SwitchingDevice { get { return InputPort.ParentDevice; } } + public RoutingOutputPort OutputPort { get; set; } + public RoutingInputPort InputPort { get; set; } + + public RouteSwitchDescriptor(RoutingInputPort inputPort) + { + InputPort = inputPort; + } + + public RouteSwitchDescriptor(RoutingOutputPort outputPort, RoutingInputPort inputPort) + { + InputPort = inputPort; + OutputPort = outputPort; + } + + public override string ToString() + { + if (SwitchingDevice is IRouting) + return string.Format("{0} switches output '{1}' to input '{2}'", SwitchingDevice.Key, OutputPort.Selector, InputPort.Selector); + else + return string.Format("{0} switches to input '{1}'", SwitchingDevice.Key, InputPort.Selector); + } + }*/ +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingInputPort.cs b/src/PepperDash.Essentials.Core/Routing/RoutingInputPort.cs new file mode 100644 index 00000000..7da945cb --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/RoutingInputPort.cs @@ -0,0 +1,77 @@ +using System; + + +namespace PepperDash.Essentials.Core +{ + /// + /// Basic RoutingInput with no statuses. + /// + public class RoutingInputPort : RoutingPort + { + /// + /// The IRoutingInputs object this lives on + /// + public IRoutingInputs ParentDevice { get; private set; } + + /// + /// Constructor for a basic RoutingInputPort + /// + /// An object used to refer to this port in the IRouting device's ExecuteSwitch method. + /// May be string, number, whatever + /// The IRoutingInputs object this lives on + public RoutingInputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, + object selector, IRoutingInputs parent) + : this (key, type, connType, selector, parent, false) + { + } + + /// + /// Constructor for a virtual routing input port that lives inside a device. For example + /// the ports that link a DM card to a DM matrix bus + /// + /// true for internal ports + public RoutingInputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, + object selector, IRoutingInputs parent, bool isInternal) + : base(key, type, connType, selector, isInternal) + { + if (parent == null) + throw new ArgumentNullException(nameof(parent)); + ParentDevice = parent; + } + } + + /*/// + /// Basic RoutingInput with no statuses. + /// + public class RoutingInputPort : RoutingPort + { + /// + /// The IRoutingInputs object this lives on + /// + public IRoutingInputs ParentDevice { get; private set; } + + /// + /// Constructor for a basic RoutingInputPort + /// + /// An object used to refer to this port in the IRouting device's ExecuteSwitch method. + /// May be string, number, whatever + /// The IRoutingInputs object this lives on + public RoutingInputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, + TSelector selector, IRoutingInputs parent) + : this(key, type, connType, selector, parent, false) + { + } + + /// + /// Constructor for a virtual routing input port that lives inside a device. For example + /// the ports that link a DM card to a DM matrix bus + /// + /// true for internal ports + public RoutingInputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, + TSelector selector, IRoutingInputs parent, bool isInternal) + : base(key, type, connType, selector, isInternal) + { + ParentDevice = parent ?? throw new ArgumentNullException(nameof(parent)); + } + }*/ +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingInputPortWithVideoStatuses.cs b/src/PepperDash.Essentials.Core/Routing/RoutingInputPortWithVideoStatuses.cs new file mode 100644 index 00000000..bd4dd489 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/RoutingInputPortWithVideoStatuses.cs @@ -0,0 +1,30 @@ +namespace PepperDash.Essentials.Core +{ + /// + /// A RoutingInputPort for devices like DM-TX and DM input cards. + /// Will provide video statistics on connected signals + /// + public class RoutingInputPortWithVideoStatuses : RoutingInputPort + { + /// + /// Video statuses attached to this port + /// + public VideoStatusOutputs VideoStatus { get; private set; } + + /// + /// Constructor + /// + /// An object used to refer to this port in the IRouting device's ExecuteSwitch method. + /// May be string, number, whatever + /// The IRoutingInputs object this lives on + /// A VideoStatusFuncsWrapper used to assign the callback funcs that will get + /// the values for the various stats + public RoutingInputPortWithVideoStatuses(string key, + eRoutingSignalType type, eRoutingPortConnectionType connType, object selector, + IRoutingInputs parent, VideoStatusFuncsWrapper funcs) : + base(key, type, connType, selector, parent) + { + VideoStatus = new VideoStatusOutputs(funcs); + } + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingInterfaces.cs b/src/PepperDash.Essentials.Core/Routing/RoutingInterfaces.cs deleted file mode 100644 index bfaa27db..00000000 --- a/src/PepperDash.Essentials.Core/Routing/RoutingInterfaces.cs +++ /dev/null @@ -1,203 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro; -using Crestron.SimplSharpPro.DM; - -using PepperDash.Core; - - -namespace PepperDash.Essentials.Core -{ - - /// - /// The handler type for a Room's SourceInfoChange - /// - public delegate void SourceInfoChangeHandler(/*EssentialsRoomBase room,*/ SourceListItem info, ChangeType type); - - - //******************************************************************************************* - // Interfaces - - /// - /// For rooms with a single presentation source, change event - /// - public interface IHasCurrentSourceInfoChange - { - string CurrentSourceInfoKey { get; set; } - SourceListItem CurrentSourceInfo { get; set; } - event SourceInfoChangeHandler CurrentSourceChange; - } - - /// - /// Defines a class that has a collection of RoutingInputPorts - /// - public interface IRoutingInputs : IKeyed - { - RoutingPortCollection InputPorts { get; } - } - - /// - /// Defines a class that has a collection of RoutingOutputPorts - /// - - public interface IRoutingOutputs : IKeyed - { - RoutingPortCollection OutputPorts { get; } - } - - /// - /// For fixed-source endpoint devices - /// - public interface IRoutingSink : IRoutingInputs, IHasCurrentSourceInfoChange - { - - } - - /// - /// Endpoint device like a display, that selects inputs - /// - public interface IRoutingSinkWithSwitching : IRoutingSink - { - //void ClearRoute(); - void ExecuteSwitch(object inputSelector); - } - - /// - /// For devices like RMCs, baluns, other devices with no switching. - /// - public interface IRoutingInputsOutputs : IRoutingInputs, IRoutingOutputs - { - } - - /// - /// Defines a midpoint device as have internal routing. Any devices in the middle of the - /// signal chain, that do switching, must implement this for routing to work otherwise - /// the routing algorithm will treat the IRoutingInputsOutputs device as a passthrough - /// device. - /// - public interface IRouting : IRoutingInputsOutputs - { - void ExecuteSwitch(object inputSelector, object outputSelector, eRoutingSignalType signalType); - } - - public interface IRoutingWithClear : IRouting - { - /// - /// Clears a route to an output, however a device needs to do that - /// - /// Output to clear - /// signal type to clear - void ClearRoute(object outputSelector, eRoutingSignalType signalType); - } - - public interface IRoutingNumeric : IRouting - { - void ExecuteNumericSwitch(ushort input, ushort output, eRoutingSignalType type); - } - - public interface ITxRouting : IRoutingNumeric - { - IntFeedback VideoSourceNumericFeedback { get; } - IntFeedback AudioSourceNumericFeedback { get; } - } - - /// - /// Defines a receiver that has internal routing (DM-RMC-4K-Z-SCALER-C) - /// - public interface IRmcRouting : IRoutingNumeric - { - IntFeedback AudioVideoSourceNumericFeedback { get; } - } - - - /// - /// Defines an IRmcRouting with a feedback event - /// - public interface ITxRoutingWithFeedback : ITxRouting - { - } - - /// - /// Defines an IRmcRouting with a feedback event - /// - public interface IRmcRoutingWithFeedback : IRmcRouting - { - } - - /// - /// Defines an IRoutingOutputs devices as being a source - the start of the chain - /// - public interface IRoutingSource : IRoutingOutputs - { - } - - /// - /// Defines an event structure for reporting output route data - /// - public interface IRoutingFeedback : IKeyName - { - event EventHandler NumericSwitchChange; - //void OnSwitchChange(RoutingNumericEventArgs e); - } - - /// - /// Defines an IRoutingNumeric with a feedback event - /// - public interface IRoutingNumericWithFeedback : IRoutingNumeric, IRoutingFeedback - { - } - - /// - /// Defines an IRouting with a feedback event - /// - public interface IRoutingWithFeedback : IRouting, IRoutingFeedback - { - - } - - public class RoutingNumericEventArgs : EventArgs - { - - public uint? Output { get; set; } - public uint? Input { get; set; } - - public eRoutingSignalType SigType { get; set; } - public RoutingInputPort InputPort { get; set; } - public RoutingOutputPort OutputPort { get; set; } - - public RoutingNumericEventArgs(uint output, uint input, eRoutingSignalType sigType) : this(output, input, null, null, sigType) - { - } - - public RoutingNumericEventArgs(RoutingOutputPort outputPort, RoutingInputPort inputPort, - eRoutingSignalType sigType) - : this(null, null, outputPort, inputPort, sigType) - { - } - - public RoutingNumericEventArgs() - : this(null, null, null, null, 0) - { - - } - - public RoutingNumericEventArgs(uint? output, uint? input, RoutingOutputPort outputPort, - RoutingInputPort inputPort, eRoutingSignalType sigType) - { - OutputPort = outputPort; - InputPort = inputPort; - - Output = output; - Input = input; - SigType = sigType; - } - } - - public interface IRoutingHasVideoInputSyncFeedbacks - { - FeedbackCollection VideoInputSyncFeedbacks { get; } - } -} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingNumericEventArgs.cs b/src/PepperDash.Essentials.Core/Routing/RoutingNumericEventArgs.cs new file mode 100644 index 00000000..7ede13c2 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/RoutingNumericEventArgs.cs @@ -0,0 +1,43 @@ +using System; + + +namespace PepperDash.Essentials.Core +{ + public class RoutingNumericEventArgs : EventArgs + { + + public uint? Output { get; set; } + public uint? Input { get; set; } + + public eRoutingSignalType SigType { get; set; } + public RoutingInputPort InputPort { get; set; } + public RoutingOutputPort OutputPort { get; set; } + + public RoutingNumericEventArgs(uint output, uint input, eRoutingSignalType sigType) : this(output, input, null, null, sigType) + { + } + + public RoutingNumericEventArgs(RoutingOutputPort outputPort, RoutingInputPort inputPort, + eRoutingSignalType sigType) + : this(null, null, outputPort, inputPort, sigType) + { + } + + public RoutingNumericEventArgs() + : this(null, null, null, null, 0) + { + + } + + public RoutingNumericEventArgs(uint? output, uint? input, RoutingOutputPort outputPort, + RoutingInputPort inputPort, eRoutingSignalType sigType) + { + OutputPort = outputPort; + InputPort = inputPort; + + Output = output; + Input = input; + SigType = sigType; + } + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingOutputPort.cs b/src/PepperDash.Essentials.Core/Routing/RoutingOutputPort.cs new file mode 100644 index 00000000..445b3072 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/RoutingOutputPort.cs @@ -0,0 +1,75 @@ +using System; + + +namespace PepperDash.Essentials.Core +{ + public class RoutingOutputPort : RoutingPort + { + /// + /// The IRoutingOutputs object this port lives on + /// + public IRoutingOutputs ParentDevice { get; private set; } + + public InUseTracking InUseTracker { get; private set; } + + + /// + /// + /// An object used to refer to this port in the IRouting device's ExecuteSwitch method. + /// May be string, number, whatever + /// The IRoutingOutputs object this port lives on + public RoutingOutputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, + object selector, IRoutingOutputs parent) + : this(key, type, connType, selector, parent, false) + { + } + + public RoutingOutputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, + object selector, IRoutingOutputs parent, bool isInternal) + : base(key, type, connType, selector, isInternal) + { + ParentDevice = parent ?? throw new ArgumentNullException(nameof(parent)); + InUseTracker = new InUseTracking(); + } + + public override string ToString() + { + return ParentDevice.Key + ":" + Key; + } + } + + /*public class RoutingOutputPort : RoutingPort + { + /// + /// The IRoutingOutputs object this port lives on + /// + public IRoutingOutputs ParentDevice { get; private set; } + + public InUseTracking InUseTracker { get; private set; } + + + /// + /// + /// An object used to refer to this port in the IRouting device's ExecuteSwitch method. + /// May be string, number, whatever + /// The IRoutingOutputs object this port lives on + public RoutingOutputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, + TSelector selector, IRoutingOutputs parent) + : this(key, type, connType, selector, parent, false) + { + } + + public RoutingOutputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, + TSelector selector, IRoutingOutputs parent, bool isInternal) + : base(key, type, connType, selector, isInternal) + { + ParentDevice = parent ?? throw new ArgumentNullException(nameof(parent)); + InUseTracker = new InUseTracking(); + } + + public override string ToString() + { + return ParentDevice.Key + ":" + Key; + } + }*/ +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingPort.cs b/src/PepperDash.Essentials.Core/Routing/RoutingPort.cs index b6ef0001..21ab0743 100644 --- a/src/PepperDash.Essentials.Core/Routing/RoutingPort.cs +++ b/src/PepperDash.Essentials.Core/Routing/RoutingPort.cs @@ -6,10 +6,10 @@ using PepperDash.Core; namespace PepperDash.Essentials.Core { - /// - /// Base class for RoutingInput and Output ports - /// - public abstract class RoutingPort : IKeyed + /// + /// Base class for RoutingInput and Output ports + /// + public abstract class RoutingPort : IKeyed { public string Key { get; private set; } public eRoutingSignalType Type { get; private set; } @@ -29,180 +29,23 @@ namespace PepperDash.Essentials.Core } } - [Flags] - public enum eRoutingSignalType - { - Audio = 1, - Video = 2, - AudioVideo = Audio | Video, - UsbOutput = 8, - UsbInput = 16, - SecondaryAudio = 32 - } + /*public abstract class RoutingPort:IKeyed + { + public string Key { get; private set; } + public eRoutingSignalType Type { get; private set; } + public eRoutingPortConnectionType ConnectionType { get; private set; } + public readonly TSelector Selector; + public bool IsInternal { get; private set; } + public object FeedbackMatchObject { get; set; } + public object Port { get; set; } - public enum eRoutingPortConnectionType - { - None, BackplaneOnly, DisplayPort, Dvi, Hdmi, Rgb, Vga, LineAudio, DigitalAudio, Sdi, - Composite, Component, DmCat, DmMmFiber, DmSmFiber, Speaker, Streaming, UsbC, HdBaseT - } - - /// - /// Basic RoutingInput with no statuses. - /// - public class RoutingInputPort : RoutingPort - { - /// - /// The IRoutingInputs object this lives on - /// - public IRoutingInputs ParentDevice { get; private set; } - - /// - /// Constructor for a basic RoutingInputPort - /// - /// An object used to refer to this port in the IRouting device's ExecuteSwitch method. - /// May be string, number, whatever - /// The IRoutingInputs object this lives on - public RoutingInputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, - object selector, IRoutingInputs parent) - : this (key, type, connType, selector, parent, false) - { - } - - /// - /// Constructor for a virtual routing input port that lives inside a device. For example - /// the ports that link a DM card to a DM matrix bus - /// - /// true for internal ports - public RoutingInputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, - object selector, IRoutingInputs parent, bool isInternal) - : base(key, type, connType, selector, isInternal) - { - if (parent == null) - throw new ArgumentNullException("parent"); - ParentDevice = parent; - } - - - - - ///// - ///// Static method to get a named port from a named device - ///// - ///// Returns null if device or port doesn't exist - //public static RoutingInputPort GetDevicePort(string deviceKey, string portKey) - //{ - // var sourceDev = DeviceManager.GetDeviceForKey(deviceKey) as IRoutingInputs; - // if (sourceDev == null) - // return null; - // return sourceDev.InputPorts[portKey]; - //} - - ///// - ///// Static method to get a named port from a card in a named ICardPortsDevice device - ///// Uses ICardPortsDevice.GetChildInputPort - ///// - ///// 'input-N' - ///// null if device, card or port doesn't exist - //public static RoutingInputPort GetDeviceCardPort(string deviceKey, string cardKey, string portKey) - //{ - // var sourceDev = DeviceManager.GetDeviceForKey(deviceKey) as ICardPortsDevice; - // if (sourceDev == null) - // return null; - // return sourceDev.GetChildInputPort(cardKey, portKey); - //} - } - - /// - /// A RoutingInputPort for devices like DM-TX and DM input cards. - /// Will provide video statistics on connected signals - /// - public class RoutingInputPortWithVideoStatuses : RoutingInputPort - { - /// - /// Video statuses attached to this port - /// - public VideoStatusOutputs VideoStatus { get; private set; } - - /// - /// Constructor - /// - /// An object used to refer to this port in the IRouting device's ExecuteSwitch method. - /// May be string, number, whatever - /// The IRoutingInputs object this lives on - /// A VideoStatusFuncsWrapper used to assign the callback funcs that will get - /// the values for the various stats - public RoutingInputPortWithVideoStatuses(string key, - eRoutingSignalType type, eRoutingPortConnectionType connType, object selector, - IRoutingInputs parent, VideoStatusFuncsWrapper funcs) : - base(key, type, connType, selector, parent) - { - VideoStatus = new VideoStatusOutputs(funcs); - } - } - - public class RoutingOutputPort : RoutingPort - { - /// - /// The IRoutingOutputs object this port lives on - /// - public IRoutingOutputs ParentDevice { get; private set; } - - public InUseTracking InUseTracker { get; private set; } - - - /// - /// - /// An object used to refer to this port in the IRouting device's ExecuteSwitch method. - /// May be string, number, whatever - /// The IRoutingOutputs object this port lives on - public RoutingOutputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, - object selector, IRoutingOutputs parent) - : this(key, type, connType, selector, parent, false) - { - } - - public RoutingOutputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, - object selector, IRoutingOutputs parent, bool isInternal) - : base(key, type, connType, selector, isInternal) - { - if (parent == null) - throw new ArgumentNullException("parent"); - ParentDevice = parent; - InUseTracker = new InUseTracking(); - } - - public override string ToString() - { - return ParentDevice.Key + ":" + Key; - } - - ///// - ///// Static method to get a named port from a named device - ///// - ///// Returns null if device or port doesn't exist - //public static RoutingOutputPort GetDevicePort(string deviceKey, string portKey) - //{ - // var sourceDev = DeviceManager.GetDeviceForKey(deviceKey) as IRoutingOutputs; - // if (sourceDev == null) - // return null; - // var port = sourceDev.OutputPorts[portKey]; - // if (port == null) - // Debug.LogMessage(LogEventLevel.Information, "WARNING: Device '{0}' does does not contain output port '{1}'", deviceKey, portKey); - // return port; - //} - - ///// - ///// Static method to get a named port from a card in a named ICardPortsDevice device - ///// Uses ICardPortsDevice.GetChildOutputPort on that device - ///// - ///// 'input-N' or 'output-N' - ///// null if device, card or port doesn't exist - //public static RoutingOutputPort GetDeviceCardPort(string deviceKey, string cardKey, string portKey) - //{ - // var sourceDev = DeviceManager.GetDeviceForKey(deviceKey) as ICardPortsDevice; - // if (sourceDev == null) - // return null; - // var port = sourceDev.GetChildOutputPort(cardKey, portKey); - //} - } + public RoutingPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, TSelector selector, bool isInternal) + { + Key = key; + Type = type; + ConnectionType = connType; + Selector = selector; + IsInternal = isInternal; + }*/ + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingPortCollection.cs b/src/PepperDash.Essentials.Core/Routing/RoutingPortCollection.cs index ba972ab7..0b9d765c 100644 --- a/src/PepperDash.Essentials.Core/Routing/RoutingPortCollection.cs +++ b/src/PepperDash.Essentials.Core/Routing/RoutingPortCollection.cs @@ -23,4 +23,21 @@ namespace PepperDash.Essentials.Core } } } + +/* /// + /// Basically a List , with an indexer to find ports by key name + /// + public class RoutingPortCollection : List where T : RoutingPort + { + /// + /// Case-insensitive port lookup linked to ports' keys + /// + public T this[string key] + { + get + { + return this.FirstOrDefault(i => i.Key.Equals(key, StringComparison.OrdinalIgnoreCase)); + } + } + }*/ } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/eRoutingPortConnectionType.cs b/src/PepperDash.Essentials.Core/Routing/eRoutingPortConnectionType.cs new file mode 100644 index 00000000..436ef9e6 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/eRoutingPortConnectionType.cs @@ -0,0 +1,8 @@ +namespace PepperDash.Essentials.Core +{ + public enum eRoutingPortConnectionType + { + None, BackplaneOnly, DisplayPort, Dvi, Hdmi, Rgb, Vga, LineAudio, DigitalAudio, Sdi, + Composite, Component, DmCat, DmMmFiber, DmSmFiber, Speaker, Streaming, UsbC, HdBaseT + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/eRoutingSignalType.cs b/src/PepperDash.Essentials.Core/Routing/eRoutingSignalType.cs new file mode 100644 index 00000000..b5f3d9f7 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/eRoutingSignalType.cs @@ -0,0 +1,16 @@ +using System; + + +namespace PepperDash.Essentials.Core +{ + [Flags] + public enum eRoutingSignalType + { + Audio = 1, + Video = 2, + AudioVideo = Audio | Video, + UsbOutput = 8, + UsbInput = 16, + SecondaryAudio = 32 + } +} \ No newline at end of file From 528fff569d729b3abb167b7cafbc1be3640becad Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 8 May 2024 08:37:24 -0500 Subject: [PATCH 05/24] refactor: fix namespaces after move --- .../Display/DisplayBase.cs | 12 +++++------- ...entialsHuddleSpaceFusionSystemControllerBase.cs | 9 +++++---- .../Routing/RoutingPort.cs | 9 +++------ .../Displays/DisplayBase.cs | 14 +++++++------- .../Room/IEssentialsHuddleSpaceRoom.cs | 1 + .../Room/IEssentialsHuddleVtc1Room.cs | 1 + 6 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/PepperDash.Essentials.Core/Display/DisplayBase.cs b/src/PepperDash.Essentials.Core/Display/DisplayBase.cs index edfe8f1d..60089651 100644 --- a/src/PepperDash.Essentials.Core/Display/DisplayBase.cs +++ b/src/PepperDash.Essentials.Core/Display/DisplayBase.cs @@ -1,22 +1,20 @@  -using System; -using System.Collections.Generic; -using System.Linq; using Crestron.SimplSharp; using Crestron.SimplSharpPro.DeviceSupport; -using Crestron.SimplSharpPro.DM; -using Crestron.SimplSharpPro.DM.Endpoints; -using Crestron.SimplSharpPro.DM.Endpoints.Transmitters; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core.Bridges; +using PepperDash.Essentials.Core.Routing; using Serilog.Events; +using System; +using System.Collections.Generic; +using System.Linq; namespace PepperDash.Essentials.Core { - [Obsolete("Please use PepperDash.Essentials.Devices.Common, this will be removed in 2.1")] + [Obsolete("Please use PepperDash.Essentials.Devices.Common, this will be removed in 2.1")] public abstract class DisplayBase : EssentialsDevice, IHasFeedback, IRoutingSinkWithSwitching, IHasPowerControl, IWarmingCooling, IUsageTracking { public event SourceInfoChangeHandler CurrentSourceChange; diff --git a/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs b/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs index 050d6cd8..fb8ed645 100644 --- a/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs +++ b/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs @@ -1,9 +1,5 @@  -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharp.CrestronXml; @@ -13,7 +9,12 @@ using Crestron.SimplSharpPro.Fusion; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core.Config; +using PepperDash.Essentials.Core.Routing; using Serilog.Events; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; namespace PepperDash.Essentials.Core.Fusion { diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingPort.cs b/src/PepperDash.Essentials.Core/Routing/RoutingPort.cs index 21ab0743..b687f6fe 100644 --- a/src/PepperDash.Essentials.Core/Routing/RoutingPort.cs +++ b/src/PepperDash.Essentials.Core/Routing/RoutingPort.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; - -using PepperDash.Core; +using PepperDash.Core; namespace PepperDash.Essentials.Core @@ -46,6 +43,6 @@ namespace PepperDash.Essentials.Core ConnectionType = connType; Selector = selector; IsInternal = isInternal; - }*/ - } + } + }*/ } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs b/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs index 1d2d3589..8dfa2f2b 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs @@ -1,15 +1,15 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Crestron.SimplSharp; +using Crestron.SimplSharp; using Crestron.SimplSharpPro.DeviceSupport; +using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; -using Feedback = PepperDash.Essentials.Core.Feedback; -using Newtonsoft.Json; -using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using PepperDash.Essentials.Core.Routing; using Serilog.Events; +using System; +using System.Collections.Generic; +using System.Linq; +using Feedback = PepperDash.Essentials.Core.Feedback; namespace PepperDash.Essentials.Devices.Common.Displays { diff --git a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleSpaceRoom.cs b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleSpaceRoom.cs index 1af09f1c..d55e2f1e 100644 --- a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleSpaceRoom.cs +++ b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleSpaceRoom.cs @@ -1,4 +1,5 @@ using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Routing; using PepperDash.Essentials.Room.Config; namespace PepperDash.Essentials.Devices.Common.Room diff --git a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleVtc1Room.cs b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleVtc1Room.cs index b7f1a619..ff4a19aa 100644 --- a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleVtc1Room.cs +++ b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleVtc1Room.cs @@ -1,4 +1,5 @@ using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Routing; using PepperDash.Essentials.Devices.Common.AudioCodec; using PepperDash.Essentials.Devices.Common.Codec; using PepperDash.Essentials.Devices.Common.VideoCodec; From 577e111f26ffa5bc909237a0628d08cbf49c80d6 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 8 May 2024 08:37:24 -0500 Subject: [PATCH 06/24] feat: add properties to control when sources show --- .../Devices/SourceListItem.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs b/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs index 491f76a9..3f770f91 100644 --- a/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs +++ b/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs @@ -144,6 +144,18 @@ namespace PepperDash.Essentials.Core [JsonProperty("isAudioSource")] public bool IsAudioSource { get; set; } + /// + /// Hide source on UI when Avanced Sharing is enabled + /// + [JsonProperty("disableAdvancedRouting")] + public bool DisableAdvancedRouting { get; set; } + + /// + /// Hide source on UI when Simpl Sharing is enabled + /// + [JsonProperty("disableSimpleRouting")] + public bool DisableSimpleRouting { get; set; } + public SourceListItem() { Icon = "Blank"; From 3823943cd9ec2a86673951ca5381f4add753f95c Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 8 May 2024 08:37:25 -0500 Subject: [PATCH 07/24] feat: add 2 new routing interfaces to allow for getting feedback for routing --- .../Routing/IRoutingSinkWithFeedback.cs | 26 +++++++++++++++++++ .../Routing/IRoutingWithFeedback.cs | 15 +++++++++++ 2 files changed, 41 insertions(+) create mode 100644 src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithFeedback.cs create mode 100644 src/PepperDash.Essentials.Core/Routing/IRoutingWithFeedback.cs diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithFeedback.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithFeedback.cs new file mode 100644 index 00000000..c7e99746 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithFeedback.cs @@ -0,0 +1,26 @@ +using PepperDash.Essentials.Core.Routing; +using System; +using System.Collections.Generic; + +namespace PepperDash.Essentials.Core +{ + /// + /// For fixed-source endpoint devices + /// + public interface IRoutingSinkWithFeedback : IRoutingSinkWithSwitching + { + RouteSwitchDescriptor CurrentRoute { get; } + + event EventHandler InputChanged; + } + +/* /// + /// For fixed-source endpoint devices + /// + public interface IRoutingSinkWithFeedback : IRoutingSinkWithSwitching + { + RouteSwitchDescriptor CurrentRoute { get; } + + event EventHandler InputChanged; + }*/ +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingWithFeedback.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingWithFeedback.cs new file mode 100644 index 00000000..c4abf0c6 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingWithFeedback.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using System; + +namespace PepperDash.Essentials.Core +{ + /// + /// Defines an IRouting with a feedback event + /// + public interface IRoutingWithFeedback : IRouting + { + List CurrentRoutes { get; } + + event EventHandler RoutingChanged; + } +} \ No newline at end of file From dd66de0463c97d485f13f5cc40488336127c4179 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 8 May 2024 08:37:25 -0500 Subject: [PATCH 08/24] feat: implement feedback manager --- .../Devices/SourceListItem.cs | 6 + .../PepperDash.Essentials.Core.csproj | 1 + .../Room/Interfaces.cs | 5 + .../Routing/Extensions.cs | 7 +- .../Routing/IRoutingSink.cs | 2 +- .../Routing/IRoutingSinkWithFeedback.cs | 5 +- .../Routing/IRoutingSinkWithSwitching.cs | 6 +- .../Routing/IRoutingWithFeedback.cs | 3 +- .../Routing/RoutingFeedbackManager.cs | 165 ++++++++++++++++++ .../Routing/TieLine.cs | 2 +- .../Routing/TieLineConfig.cs | 65 ++----- .../Displays/DisplayBase.cs | 18 ++ .../Generic/GenericSource.cs | 2 +- .../SetTopBox/IRSetTopBoxBase.cs | 2 +- .../Sources/InRoomPc.cs | 2 +- .../Sources/Laptop.cs | 2 +- .../Streaming/AppleTV.cs | 2 +- .../Streaming/Roku.cs | 2 +- src/PepperDash.Essentials/ControlSystem.cs | 3 + 19 files changed, 231 insertions(+), 69 deletions(-) create mode 100644 src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs diff --git a/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs b/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs index 3f770f91..afe3ef24 100644 --- a/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs +++ b/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs @@ -169,9 +169,15 @@ namespace PepperDash.Essentials.Core [JsonProperty("sourceKey")] public string SourceKey { get; set; } + [JsonProperty("sourcePortKey")] + public string SourcePortKey { get; set; } + [JsonProperty("destinationKey")] public string DestinationKey { get; set; } + [JsonProperty("destinationPortKey")] + public string DestinationPortKey { get; set; } + [JsonProperty("type")] public eRoutingSignalType Type { get; set; } } diff --git a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj index c38c0fbd..79891444 100644 --- a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj +++ b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj @@ -23,6 +23,7 @@ + diff --git a/src/PepperDash.Essentials.Core/Room/Interfaces.cs b/src/PepperDash.Essentials.Core/Room/Interfaces.cs index 640dc91f..eb0b6f25 100644 --- a/src/PepperDash.Essentials.Core/Room/Interfaces.cs +++ b/src/PepperDash.Essentials.Core/Room/Interfaces.cs @@ -5,6 +5,7 @@ using System.Text; using Crestron.SimplSharp; using PepperDash.Core; +using PepperDash.Essentials.Core.Routing; namespace PepperDash.Essentials.Core @@ -41,6 +42,8 @@ namespace PepperDash.Essentials.Core void RunRouteAction(string routeKey, string sourceListKey); void RunRouteAction(string routeKey, string sourceListKey, Action successCallback); + + RoutingFeedbackManager RoutingFeedbackManager { get; } } /// @@ -49,6 +52,8 @@ namespace PepperDash.Essentials.Core public interface IRunDirectRouteAction { void RunDirectRoute(string sourceKey, string destinationKey, eRoutingSignalType type = eRoutingSignalType.AudioVideo); + + RoutingFeedbackManager RoutingFeedbackManager { get; } } /// diff --git a/src/PepperDash.Essentials.Core/Routing/Extensions.cs b/src/PepperDash.Essentials.Core/Routing/Extensions.cs index 4d33ed4a..03c59bf0 100644 --- a/src/PepperDash.Essentials.Core/Routing/Extensions.cs +++ b/src/PepperDash.Essentials.Core/Routing/Extensions.cs @@ -169,18 +169,17 @@ namespace PepperDash.Essentials.Core RoutingOutputPort outputPortToUse, List alreadyCheckedDevices, eRoutingSignalType signalType, int cycle, RouteDescriptor routeTable) { - cycle++; Debug.LogMessage(LogEventLevel.Verbose, "GetRouteToSource: {0} {1}--> {2}", null, cycle, source.Key, destination.Key); RoutingInputPort goodInputPort = null; - var destDevInputTies = TieLineCollection.Default.Where(t => + var destinationTieLines = TieLineCollection.Default.Where(t => t.DestinationPort.ParentDevice == destination && (t.Type == signalType || t.Type.HasFlag(eRoutingSignalType.AudioVideo))); // find a direct tie - var directTie = destDevInputTies.FirstOrDefault( + var directTie = destinationTieLines.FirstOrDefault( t => t.DestinationPort.ParentDevice == destination && t.SourcePort.ParentDevice == source); if (directTie != null) // Found a tie directly to the source @@ -193,7 +192,7 @@ namespace PepperDash.Essentials.Core // No direct tie? Run back out on the inputs' attached devices... // Only the ones that are routing devices - var attachedMidpoints = destDevInputTies.Where(t => t.SourcePort.ParentDevice is IRoutingInputsOutputs); + var attachedMidpoints = destinationTieLines.Where(t => t.SourcePort.ParentDevice is IRoutingInputsOutputs); //Create a list for tracking already checked devices to avoid loops, if it doesn't already exist from previous iteration if (alreadyCheckedDevices == null) diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs index c51ed12f..773fab77 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs @@ -7,7 +7,7 @@ namespace PepperDash.Essentials.Core /// public interface IRoutingSink : IRoutingInputs, IHasCurrentSourceInfoChange { - + RoutingInputPort CurrentInputPort { get; } } /*/// diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithFeedback.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithFeedback.cs index c7e99746..d3d3e600 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithFeedback.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithFeedback.cs @@ -4,14 +4,13 @@ using System.Collections.Generic; namespace PepperDash.Essentials.Core { + /// /// For fixed-source endpoint devices /// public interface IRoutingSinkWithFeedback : IRoutingSinkWithSwitching { - RouteSwitchDescriptor CurrentRoute { get; } - - event EventHandler InputChanged; + } /* /// diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithSwitching.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithSwitching.cs index b31bd973..68e4632c 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithSwitching.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithSwitching.cs @@ -2,13 +2,17 @@ namespace PepperDash.Essentials.Core { + public delegate void InputChangedEventHandler(IRoutingSinkWithSwitching destination, RoutingInputPort currentPort); + /// /// Endpoint device like a display, that selects inputs /// public interface IRoutingSinkWithSwitching : IRoutingSink { void ExecuteSwitch(object inputSelector); - } + + event InputChangedEventHandler InputChanged; + } /* /// /// Endpoint device like a display, that selects inputs diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingWithFeedback.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingWithFeedback.cs index c4abf0c6..dcf4e423 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingWithFeedback.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingWithFeedback.cs @@ -3,6 +3,7 @@ using System; namespace PepperDash.Essentials.Core { + public delegate void RouteChangedEventHandler(IRoutingWithFeedback midpoint, RouteSwitchDescriptor newRoute); /// /// Defines an IRouting with a feedback event /// @@ -10,6 +11,6 @@ namespace PepperDash.Essentials.Core { List CurrentRoutes { get; } - event EventHandler RoutingChanged; + event RouteChangedEventHandler RouteChanged; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs b/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs new file mode 100644 index 00000000..bf796d5b --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs @@ -0,0 +1,165 @@ +using Org.BouncyCastle.Crypto.Prng; +using PepperDash.Core; +using PepperDash.Essentials.Core.Config; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace PepperDash.Essentials.Core.Routing +{ + public class RoutingFeedbackManager:EssentialsDevice + { + public RoutingFeedbackManager(string key, string name): base(key, name) + { + AddPostActivationAction(SubscribeForMidpointFeedback); + AddPostActivationAction(SubscribeForSinkFeedback); + } + + private void SubscribeForMidpointFeedback() + { + var midpointDevices = DeviceManager.AllDevices.OfType(); + + foreach (var device in midpointDevices) + { + device.RouteChanged += HandleMidpointUpdate; + } + } + + private void SubscribeForSinkFeedback() + { + var sinkDevices = DeviceManager.AllDevices.OfType(); + + foreach (var device in sinkDevices) + { + device.InputChanged += HandleSinkUpdate; + } + } + + private void HandleMidpointUpdate(IRoutingWithFeedback midpoint, RouteSwitchDescriptor newRoute) + { + var devices = DeviceManager.AllDevices.OfType(); + + foreach(var device in devices) + { + UpdateDestination(device, device.CurrentInputPort); + } + } + + private void HandleSinkUpdate(IRoutingSinkWithSwitching sender, RoutingInputPort currentInputPort) + { + UpdateDestination(sender, currentInputPort); + } + + private void UpdateDestination(IRoutingSinkWithSwitching destination, RoutingInputPort inputPort) + { + var tieLines = TieLineCollection.Default; + + var firstTieLine = tieLines.FirstOrDefault(tl => tl.DestinationPort.Key == inputPort.Key); + + if (firstTieLine == null) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No tieline found for inputPort {inputPort}. Clearing current source", this, inputPort); + + destination.CurrentSourceInfo = null; + destination.CurrentSourceInfoKey = string.Empty; + return; + } + + var sourceTieLine = GetRootTieLine(firstTieLine); + + if (sourceTieLine == null) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No route found to source for inputPort {inputPort}. Clearing current source", this, inputPort); + + destination.CurrentSourceInfo = null; + destination.CurrentSourceInfoKey = string.Empty; + } + + + // Does not handle combinable scenarios or other scenarios where a display might be part of multiple rooms yet. + var room = DeviceManager.AllDevices.OfType().FirstOrDefault((r) => { + if(r is IHasMultipleDisplays roomMultipleDisplays) + { + return roomMultipleDisplays.Displays.Any(d => d.Value.Key == destination.Key); + } + + if(r is IHasDefaultDisplay roomDefaultDisplay) + { + return roomDefaultDisplay.DefaultDisplay.Key == destination.Key; + } + + return false; + }) ; + + if(room == null) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "No room found for display {destination}", this, destination.Key); + return; + } + + var sourceList = ConfigReader.ConfigObject.GetSourceListForKey(room.SourceListKey); + + if (sourceList == null) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "No source list found for source list key {key}. Unable to find source for tieLine {sourceTieLine}", this, room.SourceListKey, sourceTieLine); + return; + } + + var sourceListItem = sourceList.FirstOrDefault(sli => sli.Value.SourceKey == sourceTieLine.SourcePort.ParentDevice.Key); + + var source = sourceListItem.Value; + + if (source == null) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No source found for device {key}. Clearing current source on {destination}", this, sourceTieLine.SourcePort.ParentDevice.Key, destination); + + destination.CurrentSourceInfo = null; + destination.CurrentSourceInfoKey = string.Empty; + return; + } + + destination.CurrentSourceInfo = source; + destination.CurrentSourceInfoKey = source.SourceKey; + } + + private TieLine GetRootTieLine(TieLine tieLine) + { + TieLine nextTieLine = null; + + if(tieLine.SourcePort.ParentDevice is IRoutingWithFeedback midpoint) + { + var currentRoute = midpoint.CurrentRoutes.FirstOrDefault(route => route.OutputPort.Key == tieLine.SourcePort.Key); + + if(currentRoute == null) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No route through midpoint {midpoint} for outputPort {outputPort}", this, midpoint.Key, tieLine.SourcePort); + return null; + } + + nextTieLine = TieLineCollection.Default.FirstOrDefault(tl => tl.DestinationPort.Key == currentRoute.InputPort.Key); + + if(tieLine != null) + { + return GetRootTieLine(nextTieLine); + } + + return tieLine; + } + + if(tieLine.SourcePort.ParentDevice is IRoutingSource) //end of the chain + { + return tieLine; + } + + nextTieLine = TieLineCollection.Default.FirstOrDefault(tl => tl.SourcePort.Key == tieLine.SourcePort.Key); + + if(nextTieLine != null) + { + return GetRootTieLine(nextTieLine); + } + + return nextTieLine; + } + } +} diff --git a/src/PepperDash.Essentials.Core/Routing/TieLine.cs b/src/PepperDash.Essentials.Core/Routing/TieLine.cs index 25bf4ea3..65804eb3 100644 --- a/src/PepperDash.Essentials.Core/Routing/TieLine.cs +++ b/src/PepperDash.Essentials.Core/Routing/TieLine.cs @@ -88,7 +88,7 @@ namespace PepperDash.Essentials.Core public override string ToString() { - return string.Format("Tie line: [{0}]{1} --> [{2}]{3}", SourcePort.ParentDevice.Key, SourcePort.Key, + return string.Format("Tie line: {0}:{1} --> {2}:{3}", SourcePort.ParentDevice.Key, SourcePort.Key, DestinationPort.ParentDevice.Key, DestinationPort.Key); } } diff --git a/src/PepperDash.Essentials.Core/Routing/TieLineConfig.cs b/src/PepperDash.Essentials.Core/Routing/TieLineConfig.cs index 1728c20f..922cc61d 100644 --- a/src/PepperDash.Essentials.Core/Routing/TieLineConfig.cs +++ b/src/PepperDash.Essentials.Core/Routing/TieLineConfig.cs @@ -30,7 +30,7 @@ namespace PepperDash.Essentials.Core.Config /// null if config data does not match ports, cards or devices public TieLine GetTieLine() { - Debug.LogMessage(LogEventLevel.Information, "Build TieLine: {0}", this); + Debug.LogMessage(LogEventLevel.Information, "Build TieLine: {0}",null, this); // Get the source device var sourceDev = DeviceManager.GetDeviceForKey(SourceKey) as IRoutingOutputs; if (sourceDev == null) @@ -48,68 +48,29 @@ namespace PepperDash.Essentials.Core.Config } //Get the source port - RoutingOutputPort sourceOutputPort = null; - //// If it's a card-based device, get the card and then the source port - //if (sourceDev is ICardPortsDevice) - //{ - // if (SourceCard == null) - // { - // LogError("Card missing from source device config"); - // return null; - // } - // sourceOutputPort = (sourceDev as ICardPortsDevice).GetChildOutputPort(SourceCard, SourcePort); - // if (sourceOutputPort == null) - // { - // LogError("Source card does not contain port"); - // return null; - // } - //} - //// otherwise it's a normal port device, get the source port - //else - //{ - sourceOutputPort = sourceDev.OutputPorts[SourcePort]; - if (sourceOutputPort == null) - { - LogError("Source does not contain port"); - return null; - } - //} + var sourceOutputPort = sourceDev.OutputPorts[SourcePort]; + if (sourceOutputPort == null) + { + LogError("Source does not contain port"); + return null; + } - //Get the Destination port - RoutingInputPort destinationInputPort = null; - //// If it's a card-based device, get the card and then the Destination port - //if (destDev is ICardPortsDevice) - //{ - // if (DestinationCard == null) - // { - // LogError("Card missing from destination device config"); - // return null; - // } - // destinationInputPort = (destDev as ICardPortsDevice).GetChildInputPort(DestinationCard, DestinationPort); - // if (destinationInputPort == null) - // { - // LogError("Destination card does not contain port"); - // return null; - // } - //} - //// otherwise it's a normal port device, get the Destination port - //else - //{ - destinationInputPort = destDev.InputPorts[DestinationPort]; - if (destinationInputPort == null) + //Get the Destination port + var destinationInputPort = destDev.InputPorts[DestinationPort]; + + if (destinationInputPort == null) { LogError("Destination does not contain port"); return null; - } - //} + } return new TieLine(sourceOutputPort, destinationInputPort); } void LogError(string msg) { - Debug.LogMessage(LogEventLevel.Debug, "WARNING: Cannot create tie line: {0}:\r {1}", msg, this); + Debug.LogMessage(LogEventLevel.Error, "WARNING: Cannot create tie line: {message}:\r {tieLineConfig}",null, msg, this); } public override string ToString() diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs b/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs index 8dfa2f2b..33d5632a 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs @@ -20,6 +20,24 @@ namespace PepperDash.Essentials.Devices.Common.Displays , IWarmingCooling , IUsageTracking { + private RoutingInputPort _currentInputPort; + public RoutingInputPort CurrentInputPort + { + get + { + return _currentInputPort; + } + + private set + { + _currentInputPort = value; + + InputChanged?.Invoke(this, _currentInputPort); + } + } + + public event InputChangedEventHandler InputChanged; + public event SourceInfoChangeHandler CurrentSourceChange; public string CurrentSourceInfoKey { get; set; } diff --git a/src/PepperDash.Essentials.Devices.Common/Generic/GenericSource.cs b/src/PepperDash.Essentials.Devices.Common/Generic/GenericSource.cs index f4062c98..c34f7d12 100644 --- a/src/PepperDash.Essentials.Devices.Common/Generic/GenericSource.cs +++ b/src/PepperDash.Essentials.Devices.Common/Generic/GenericSource.cs @@ -14,7 +14,7 @@ using Serilog.Events; namespace PepperDash.Essentials.Devices.Common { - public class GenericSource : EssentialsDevice, IUiDisplayInfo, IRoutingOutputs, IUsageTracking + public class GenericSource : EssentialsDevice, IUiDisplayInfo, IRoutingSource, IUsageTracking { public uint DisplayUiType { get { return DisplayUiConstants.TypeNoControls; } } diff --git a/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBase.cs b/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBase.cs index 1728939d..9e334244 100644 --- a/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBase.cs @@ -20,7 +20,7 @@ using Serilog.Events; namespace PepperDash.Essentials.Devices.Common { [Description("Wrapper class for an IR Set Top Box")] - public class IRSetTopBoxBase : EssentialsBridgeableDevice, ISetTopBoxControls, IRoutingOutputs, IUsageTracking, IHasPowerControl, ITvPresetsProvider + public class IRSetTopBoxBase : EssentialsBridgeableDevice, ISetTopBoxControls, IRoutingSource, IUsageTracking, IHasPowerControl, ITvPresetsProvider { public IrOutputPortController IrPort { get; private set; } diff --git a/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPc.cs b/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPc.cs index 565956f4..b3d8fbee 100644 --- a/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPc.cs +++ b/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPc.cs @@ -8,7 +8,7 @@ using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.Sources { - public class InRoomPc : EssentialsDevice, IHasFeedback, IRoutingOutputs, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking + public class InRoomPc : EssentialsDevice, IHasFeedback, IRoutingSource, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking { public uint DisplayUiType { get { return DisplayUiConstants.TypeLaptop; } } public string IconName { get; set; } diff --git a/src/PepperDash.Essentials.Devices.Common/Sources/Laptop.cs b/src/PepperDash.Essentials.Devices.Common/Sources/Laptop.cs index 7aac6267..c2ffb726 100644 --- a/src/PepperDash.Essentials.Devices.Common/Sources/Laptop.cs +++ b/src/PepperDash.Essentials.Devices.Common/Sources/Laptop.cs @@ -8,7 +8,7 @@ using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.Sources { - public class Laptop : EssentialsDevice, IHasFeedback, IRoutingOutputs, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking + public class Laptop : EssentialsDevice, IHasFeedback, IRoutingSource, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking { public uint DisplayUiType { get { return DisplayUiConstants.TypeLaptop; } } public string IconName { get; set; } diff --git a/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTV.cs b/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTV.cs index 5c8f9163..c4a9b5a7 100644 --- a/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTV.cs +++ b/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTV.cs @@ -19,7 +19,7 @@ using Serilog.Events; namespace PepperDash.Essentials.Devices.Common { [Description("Wrapper class for an IR-Controlled AppleTV")] - public class AppleTV : EssentialsBridgeableDevice, IDPad, ITransport, IUiDisplayInfo, IRoutingOutputs + public class AppleTV : EssentialsBridgeableDevice, IDPad, ITransport, IUiDisplayInfo, IRoutingSource { public IrOutputPortController IrPort { get; private set; } public const string StandardDriverName = "Apple_AppleTV_4th_Gen_Essentials.ir"; diff --git a/src/PepperDash.Essentials.Devices.Common/Streaming/Roku.cs b/src/PepperDash.Essentials.Devices.Common/Streaming/Roku.cs index 4364610b..9d08f53a 100644 --- a/src/PepperDash.Essentials.Devices.Common/Streaming/Roku.cs +++ b/src/PepperDash.Essentials.Devices.Common/Streaming/Roku.cs @@ -15,7 +15,7 @@ using Serilog.Events; namespace PepperDash.Essentials.Devices.Common { [Description("Wrapper class for an IR-Controlled Roku")] - public class Roku2 : EssentialsDevice, IDPad, ITransport, IUiDisplayInfo, IRoutingOutputs + public class Roku2 : EssentialsDevice, IDPad, ITransport, IUiDisplayInfo, IRoutingSource { [Api] public IrOutputPortController IrPort { get; private set; } diff --git a/src/PepperDash.Essentials/ControlSystem.cs b/src/PepperDash.Essentials/ControlSystem.cs index af87158b..d2b7a2b9 100644 --- a/src/PepperDash.Essentials/ControlSystem.cs +++ b/src/PepperDash.Essentials/ControlSystem.cs @@ -14,6 +14,7 @@ using PepperDash.Essentials.Core.Web; using System; using System.Linq; using Serilog.Events; +using PepperDash.Essentials.Core.Routing; namespace PepperDash.Essentials { @@ -388,6 +389,8 @@ namespace PepperDash.Essentials // Build the processor wrapper class DeviceManager.AddDevice(new Core.Devices.CrestronProcessor("processor")); + DeviceManager.AddDevice(new RoutingFeedbackManager($"routingFeedbackManager", "Routing Feedback Manager")); + // Add global System Monitor device if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance) { From e3e7add5b9b0f9e10f85cc60c91493a483eb2025 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 8 May 2024 08:37:25 -0500 Subject: [PATCH 09/24] fix: correct build issues --- .../Display/DisplayBase.cs | 5 ++- .../Room/Interfaces.cs | 6 +--- .../Audio/GenericAudioOut.cs | 2 ++ .../Generic/GenericSink.cs | 2 ++ .../SoftCodec/BlueJeansPc.cs | 8 +++-- .../SoftCodec/GenericSoftCodec.cs | 35 +++++++++++++++---- 6 files changed, 44 insertions(+), 14 deletions(-) diff --git a/src/PepperDash.Essentials.Core/Display/DisplayBase.cs b/src/PepperDash.Essentials.Core/Display/DisplayBase.cs index 60089651..2e5a2ed1 100644 --- a/src/PepperDash.Essentials.Core/Display/DisplayBase.cs +++ b/src/PepperDash.Essentials.Core/Display/DisplayBase.cs @@ -18,6 +18,7 @@ namespace PepperDash.Essentials.Core public abstract class DisplayBase : EssentialsDevice, IHasFeedback, IRoutingSinkWithSwitching, IHasPowerControl, IWarmingCooling, IUsageTracking { public event SourceInfoChangeHandler CurrentSourceChange; + public event InputChangedEventHandler InputChanged; public string CurrentSourceInfoKey { get; set; } public SourceListItem CurrentSourceInfo @@ -94,7 +95,9 @@ namespace PepperDash.Essentials.Core } } - public abstract void ExecuteSwitch(object selector); + public RoutingInputPort CurrentInputPort => throw new NotImplementedException(); + + public abstract void ExecuteSwitch(object selector); protected void LinkDisplayToApi(DisplayBase displayDevice, BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) diff --git a/src/PepperDash.Essentials.Core/Room/Interfaces.cs b/src/PepperDash.Essentials.Core/Room/Interfaces.cs index eb0b6f25..a8d9c2a9 100644 --- a/src/PepperDash.Essentials.Core/Room/Interfaces.cs +++ b/src/PepperDash.Essentials.Core/Room/Interfaces.cs @@ -41,9 +41,7 @@ namespace PepperDash.Essentials.Core { void RunRouteAction(string routeKey, string sourceListKey); - void RunRouteAction(string routeKey, string sourceListKey, Action successCallback); - - RoutingFeedbackManager RoutingFeedbackManager { get; } + void RunRouteAction(string routeKey, string sourceListKey, Action successCallback); } /// @@ -52,8 +50,6 @@ namespace PepperDash.Essentials.Core public interface IRunDirectRouteAction { void RunDirectRoute(string sourceKey, string destinationKey, eRoutingSignalType type = eRoutingSignalType.AudioVideo); - - RoutingFeedbackManager RoutingFeedbackManager { get; } } /// diff --git a/src/PepperDash.Essentials.Devices.Common/Audio/GenericAudioOut.cs b/src/PepperDash.Essentials.Devices.Common/Audio/GenericAudioOut.cs index e9eeb5b5..207c04be 100644 --- a/src/PepperDash.Essentials.Devices.Common/Audio/GenericAudioOut.cs +++ b/src/PepperDash.Essentials.Devices.Common/Audio/GenericAudioOut.cs @@ -18,6 +18,8 @@ namespace PepperDash.Essentials.Devices.Common /// public class GenericAudioOut : EssentialsDevice, IRoutingSink { + public RoutingInputPort CurrentInputPort => AnyAudioIn; + public event SourceInfoChangeHandler CurrentSourceChange; public string CurrentSourceInfoKey { get; set; } diff --git a/src/PepperDash.Essentials.Devices.Common/Generic/GenericSink.cs b/src/PepperDash.Essentials.Devices.Common/Generic/GenericSink.cs index 940a519e..de7d5174 100644 --- a/src/PepperDash.Essentials.Devices.Common/Generic/GenericSink.cs +++ b/src/PepperDash.Essentials.Devices.Common/Generic/GenericSink.cs @@ -44,6 +44,8 @@ namespace PepperDash.Essentials.Devices.Common.Generic } } + public RoutingInputPort CurrentInputPort => InputPorts[0]; + public event SourceInfoChangeHandler CurrentSourceChange; } diff --git a/src/PepperDash.Essentials.Devices.Common/SoftCodec/BlueJeansPc.cs b/src/PepperDash.Essentials.Devices.Common/SoftCodec/BlueJeansPc.cs index 4dcb663a..52c8d1eb 100644 --- a/src/PepperDash.Essentials.Devices.Common/SoftCodec/BlueJeansPc.cs +++ b/src/PepperDash.Essentials.Devices.Common/SoftCodec/BlueJeansPc.cs @@ -17,6 +17,8 @@ namespace PepperDash.Essentials.Devices.Common.SoftCodec public RoutingInputPort AnyVideoIn { get; private set; } + public RoutingInputPort CurrentInputPort => AnyVideoIn; + #region IRoutingInputs Members public RoutingPortCollection InputPorts { get; private set; } @@ -26,8 +28,10 @@ namespace PepperDash.Essentials.Devices.Common.SoftCodec public BlueJeansPc(string key, string name) : base(key, name) { - InputPorts = new RoutingPortCollection(); - InputPorts.Add(AnyVideoIn = new RoutingInputPort(RoutingPortNames.AnyVideoIn, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.None, 0, this)); + InputPorts = new RoutingPortCollection + { + (AnyVideoIn = new RoutingInputPort(RoutingPortNames.AnyVideoIn, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.None, 0, this)) + }; } #region IRunRouteAction Members diff --git a/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs b/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs index a4155692..ae7acca1 100644 --- a/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs +++ b/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs @@ -2,17 +2,26 @@ using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; +using PepperDash.Essentials.Core.Routing; using Serilog.Events; -using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace PepperDash.Essentials.Devices.Common.SoftCodec { - public class GenericSoftCodec : EssentialsDevice, IRoutingSource, IRoutingSink + public class GenericSoftCodec : EssentialsDevice, IRoutingSource, IRoutingSinkWithSwitching { + private RoutingInputPort _currentInputPort; + public RoutingInputPort CurrentInputPort { + get => _currentInputPort; + set + { + _currentInputPort = value; + + InputChanged?.Invoke(this, _currentInputPort); + } + } + public GenericSoftCodec(string key, string name, GenericSoftCodecProperties props) : base(key, name) { InputPorts = new RoutingPortCollection(); @@ -27,7 +36,7 @@ namespace PepperDash.Essentials.Devices.Common.SoftCodec for(var i = 1; i<= props.ContentInputCount; i++) { - var inputPort = new RoutingInputPort($"{Key}-contentInput{i}", eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, null, this); + var inputPort = new RoutingInputPort($"{Key}-contentInput{i}", eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, $"contentInput{i}", this); InputPorts.Add(inputPort); } @@ -39,7 +48,7 @@ namespace PepperDash.Essentials.Devices.Common.SoftCodec for(var i = 1; i <=props.CameraInputCount; i++) { - var cameraPort = new RoutingInputPort($"{Key}-cameraInput{i}", eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, null, this); + var cameraPort = new RoutingInputPort($"{Key}-cameraInput{i}", eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, $"cameraInput{i}", this); InputPorts.Add(cameraPort); } @@ -74,6 +83,20 @@ namespace PepperDash.Essentials.Devices.Common.SoftCodec SourceListItem _CurrentSourceInfo; public event SourceInfoChangeHandler CurrentSourceChange; + public event InputChangedEventHandler InputChanged; + + public void ExecuteSwitch(object inputSelector) + { + var inputPort = InputPorts.FirstOrDefault(p => p.Selector == inputSelector); + + if(inputPort == null) + { + Debug.LogMessage(LogEventLevel.Warning, "No input port found for selector {inputSelector}", inputSelector); + return; + } + + CurrentInputPort = inputPort; + } } public class GenericSoftCodecProperties From 19bd5723c8e09bbdc0ef778448f6241c9cf02037 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 8 May 2024 08:37:26 -0500 Subject: [PATCH 10/24] feat: add RoutingFeedbackManager RoutingFeedbackManager keeps track of updates from IRoutingSinkWotjFeedbacl devoces & IRoutingWithFeedback devices to allow for walking tieLines and finding a source. --- .../Devices/DeviceJsonApi.cs | 4 +- .../Devices/PC/Laptop.cs | 2 +- .../Devices/SourceListItem.cs | 7 ++- .../Routing/DummyRoutingInputsDevice.cs | 2 +- .../Routing/IRoutingSource.cs | 4 +- .../Routing/RoutingFeedbackManager.cs | 44 ++++++++++++++++--- .../Displays/DisplayBase.cs | 2 +- .../Displays/MockDisplay.cs | 40 +++++++++++++---- .../Generic/GenericSource.cs | 2 +- .../SetTopBox/IRSetTopBoxBase.cs | 2 +- .../SoftCodec/GenericSoftCodec.cs | 2 +- .../Sources/InRoomPc.cs | 2 +- .../Sources/Laptop.cs | 12 +++-- .../Streaming/AppleTV.cs | 5 ++- .../Streaming/Roku.cs | 2 +- 15 files changed, 98 insertions(+), 34 deletions(-) diff --git a/src/PepperDash.Essentials.Core/Devices/DeviceJsonApi.cs b/src/PepperDash.Essentials.Core/Devices/DeviceJsonApi.cs index 691aea55..fcda0730 100644 --- a/src/PepperDash.Essentials.Core/Devices/DeviceJsonApi.cs +++ b/src/PepperDash.Essentials.Core/Devices/DeviceJsonApi.cs @@ -5,6 +5,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; +using System.Threading.Tasks; using Crestron.SimplSharp; using Crestron.SimplSharp.Reflection; using Newtonsoft.Json; @@ -82,7 +83,8 @@ namespace PepperDash.Essentials.Core var convertedParams = mParams .Select((p, i) => ConvertType(action.Params[i], p.ParameterType)) .ToArray(); - method.Invoke(obj, convertedParams); + + Task.Run(() => method.Invoke(obj, convertedParams)); CrestronConsole.ConsoleCommandResponse("Method {0} successfully called on device {1}", method.Name, action.DeviceKey); diff --git a/src/PepperDash.Essentials.Core/Devices/PC/Laptop.cs b/src/PepperDash.Essentials.Core/Devices/PC/Laptop.cs index bfc09292..05cf9e76 100644 --- a/src/PepperDash.Essentials.Core/Devices/PC/Laptop.cs +++ b/src/PepperDash.Essentials.Core/Devices/PC/Laptop.cs @@ -70,7 +70,7 @@ namespace PepperDash.Essentials.Core.Devices { public LaptopFactory() { - TypeNames = new List() { "laptop" }; + TypeNames = new List() { "deprecated" }; } public override EssentialsDevice BuildDevice(DeviceConfig dc) diff --git a/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs b/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs index afe3ef24..b0372b51 100644 --- a/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs +++ b/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs @@ -161,8 +161,11 @@ namespace PepperDash.Essentials.Core Icon = "Blank"; } - - } + public override string ToString() + { + return $"{SourceKey}:{Name}"; + } + } public class SourceRouteListItem { diff --git a/src/PepperDash.Essentials.Core/Routing/DummyRoutingInputsDevice.cs b/src/PepperDash.Essentials.Core/Routing/DummyRoutingInputsDevice.cs index c6f96c74..d8b50a9b 100644 --- a/src/PepperDash.Essentials.Core/Routing/DummyRoutingInputsDevice.cs +++ b/src/PepperDash.Essentials.Core/Routing/DummyRoutingInputsDevice.cs @@ -8,7 +8,7 @@ using PepperDash.Core; namespace PepperDash.Essentials.Core.Routing { - public class DummyRoutingInputsDevice : Device, IRoutingSource + public class DummyRoutingInputsDevice : Device, IRoutingSource, IRoutingOutputs { /// /// A single output port, backplane, audioVideo diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingSource.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingSource.cs index 6ae51a2b..f4705b8d 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingSource.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingSource.cs @@ -3,7 +3,7 @@ /// /// Defines an IRoutingOutputs devices as being a source - the start of the chain /// - public interface IRoutingSource : IRoutingOutputs - { + public interface IRoutingSource + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs b/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs index bf796d5b..ec09e08a 100644 --- a/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs +++ b/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs @@ -5,6 +5,7 @@ using System; using System.Collections; using System.Collections.Generic; using System.Linq; +using System.Reflection; namespace PepperDash.Essentials.Core.Routing { @@ -48,7 +49,14 @@ namespace PepperDash.Essentials.Core.Routing private void HandleSinkUpdate(IRoutingSinkWithSwitching sender, RoutingInputPort currentInputPort) { - UpdateDestination(sender, currentInputPort); + try + { + UpdateDestination(sender, currentInputPort); + } + catch (Exception ex) + { + Debug.LogMessage(ex, "Error handling Sink update from {senderKey}:{Exception}", this, sender.Key, ex); + } } private void UpdateDestination(IRoutingSinkWithSwitching destination, RoutingInputPort inputPort) @@ -66,7 +74,9 @@ namespace PepperDash.Essentials.Core.Routing return; } - var sourceTieLine = GetRootTieLine(firstTieLine); + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Getting source for first TieLine {tieLine}", this, firstTieLine); + + var sourceTieLine = GetRootTieLine(firstTieLine); if (sourceTieLine == null) { @@ -76,6 +86,7 @@ namespace PepperDash.Essentials.Core.Routing destination.CurrentSourceInfoKey = string.Empty; } + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root TieLine {tieLine}", this, sourceTieLine); // Does not handle combinable scenarios or other scenarios where a display might be part of multiple rooms yet. var room = DeviceManager.AllDevices.OfType().FirstOrDefault((r) => { @@ -90,7 +101,7 @@ namespace PepperDash.Essentials.Core.Routing } return false; - }) ; + }); if(room == null) { @@ -98,6 +109,8 @@ namespace PepperDash.Essentials.Core.Routing return; } + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found room {room} for destination {destination}", this, room.Key, destination.Key); + var sourceList = ConfigReader.ConfigObject.GetSourceListForKey(room.SourceListKey); if (sourceList == null) @@ -106,7 +119,18 @@ namespace PepperDash.Essentials.Core.Routing return; } - var sourceListItem = sourceList.FirstOrDefault(sli => sli.Value.SourceKey == sourceTieLine.SourcePort.ParentDevice.Key); + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found sourceList for room {room}", this, room.Key); + + var sourceListItem = sourceList.FirstOrDefault(sli => { + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, + "SourceListItem {sourceListItem}:{sourceKey} tieLine sourceport device key {sourcePortDeviceKey}", + this, + sli.Key, + sli.Value.SourceKey, + sourceTieLine.SourcePort.ParentDevice.Key); + + return sli.Value.SourceKey.Equals(sourceTieLine.SourcePort.ParentDevice.Key,StringComparison.InvariantCultureIgnoreCase); + }); var source = sourceListItem.Value; @@ -119,6 +143,8 @@ namespace PepperDash.Essentials.Core.Routing return; } + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Got Source {source}", this, source); + destination.CurrentSourceInfo = source; destination.CurrentSourceInfoKey = source.SourceKey; } @@ -129,6 +155,8 @@ namespace PepperDash.Essentials.Core.Routing if(tieLine.SourcePort.ParentDevice is IRoutingWithFeedback midpoint) { + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLine Source device is midpoint", this); + var currentRoute = midpoint.CurrentRoutes.FirstOrDefault(route => route.OutputPort.Key == tieLine.SourcePort.Key); if(currentRoute == null) @@ -147,8 +175,12 @@ namespace PepperDash.Essentials.Core.Routing return tieLine; } - if(tieLine.SourcePort.ParentDevice is IRoutingSource) //end of the chain + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLIne Source Device {sourceDeviceKey} is IRoutingSource: {isIRoutingSource}", this,tieLine.SourcePort.ParentDevice.Key, tieLine.SourcePort.ParentDevice is IRoutingSource); + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLine Source Device interfaces: {typeFullName}:{interfaces}",this, tieLine.SourcePort.ParentDevice.GetType().FullName, tieLine.SourcePort.ParentDevice.GetType().GetInterfaces().Select(i => i.Name)); + + if(tieLine.SourcePort.ParentDevice is IRoutingSource || tieLine.SourcePort.ParentDevice is IRoutingOutputs) //end of the chain { + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root: {tieLine}", this, tieLine); return tieLine; } @@ -159,7 +191,7 @@ namespace PepperDash.Essentials.Core.Routing return GetRootTieLine(nextTieLine); } - return nextTieLine; + return null; } } } diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs b/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs index 33d5632a..d5595f5f 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs @@ -28,7 +28,7 @@ namespace PepperDash.Essentials.Devices.Common.Displays return _currentInputPort; } - private set + protected set { _currentInputPort = value; diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs b/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs index bcbbaa5a..db14aa4d 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs @@ -140,18 +140,40 @@ namespace PepperDash.Essentials.Devices.Common.Displays public override void ExecuteSwitch(object selector) { - Debug.LogMessage(LogEventLevel.Verbose, this, "ExecuteSwitch: {0}", selector); + try + { + Debug.LogMessage(LogEventLevel.Verbose, "ExecuteSwitch: {0}", this, selector); - if (!_PowerIsOn) - { - PowerOn(); - } + if (!_PowerIsOn) + { + PowerOn(); + } - if (!Inputs.Items.TryGetValue(selector.ToString(), out var input)) - return; + if (!Inputs.Items.TryGetValue(selector.ToString(), out var input)) + return; - input.Select(); - } + Debug.LogMessage(LogEventLevel.Verbose, "Selected input: {input}", this, input.Key); + input.Select(); + + var inputPort = InputPorts.FirstOrDefault(port => + { + Debug.LogMessage(LogEventLevel.Verbose, "Checking input port {inputPort} with selector {portSelector} against {selector}", this, port, port.Selector, selector); + return port.Selector.ToString() == selector.ToString(); + }); + + if (inputPort == null) + { + Debug.LogMessage(LogEventLevel.Verbose, "Unable to find input port for selector {selector}", this, selector); + return; + } + + Debug.LogMessage(LogEventLevel.Verbose, "Setting current input port to {inputPort}", this, inputPort); + CurrentInputPort = inputPort; + } catch (Exception ex) + { + Debug.LogMessage(ex, "Error making switch: {Exception}", this); + } + } public void SetInput(string selector) { diff --git a/src/PepperDash.Essentials.Devices.Common/Generic/GenericSource.cs b/src/PepperDash.Essentials.Devices.Common/Generic/GenericSource.cs index c34f7d12..16ddaa25 100644 --- a/src/PepperDash.Essentials.Devices.Common/Generic/GenericSource.cs +++ b/src/PepperDash.Essentials.Devices.Common/Generic/GenericSource.cs @@ -14,7 +14,7 @@ using Serilog.Events; namespace PepperDash.Essentials.Devices.Common { - public class GenericSource : EssentialsDevice, IUiDisplayInfo, IRoutingSource, IUsageTracking + public class GenericSource : EssentialsDevice, IUiDisplayInfo, IRoutingSource, IRoutingOutputs, IUsageTracking { public uint DisplayUiType { get { return DisplayUiConstants.TypeNoControls; } } diff --git a/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBase.cs b/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBase.cs index 9e334244..0bc055c8 100644 --- a/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBase.cs @@ -20,7 +20,7 @@ using Serilog.Events; namespace PepperDash.Essentials.Devices.Common { [Description("Wrapper class for an IR Set Top Box")] - public class IRSetTopBoxBase : EssentialsBridgeableDevice, ISetTopBoxControls, IRoutingSource, IUsageTracking, IHasPowerControl, ITvPresetsProvider + public class IRSetTopBoxBase : EssentialsBridgeableDevice, ISetTopBoxControls, IRoutingSource, IRoutingOutputs, IUsageTracking, IHasPowerControl, ITvPresetsProvider { public IrOutputPortController IrPort { get; private set; } diff --git a/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs b/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs index ae7acca1..5a8a3df8 100644 --- a/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs +++ b/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs @@ -9,7 +9,7 @@ using System.Linq; namespace PepperDash.Essentials.Devices.Common.SoftCodec { - public class GenericSoftCodec : EssentialsDevice, IRoutingSource, IRoutingSinkWithSwitching + public class GenericSoftCodec : EssentialsDevice, IRoutingSource, IRoutingOutputs, IRoutingSinkWithSwitching { private RoutingInputPort _currentInputPort; public RoutingInputPort CurrentInputPort { diff --git a/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPc.cs b/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPc.cs index b3d8fbee..3de80549 100644 --- a/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPc.cs +++ b/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPc.cs @@ -8,7 +8,7 @@ using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.Sources { - public class InRoomPc : EssentialsDevice, IHasFeedback, IRoutingSource, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking + public class InRoomPc : EssentialsDevice, IHasFeedback, IRoutingSource, IRoutingOutputs, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking { public uint DisplayUiType { get { return DisplayUiConstants.TypeLaptop; } } public string IconName { get; set; } diff --git a/src/PepperDash.Essentials.Devices.Common/Sources/Laptop.cs b/src/PepperDash.Essentials.Devices.Common/Sources/Laptop.cs index c2ffb726..bf4a8b45 100644 --- a/src/PepperDash.Essentials.Devices.Common/Sources/Laptop.cs +++ b/src/PepperDash.Essentials.Devices.Common/Sources/Laptop.cs @@ -8,7 +8,7 @@ using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.Sources { - public class Laptop : EssentialsDevice, IHasFeedback, IRoutingSource, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking + public class Laptop : EssentialsDevice, IHasFeedback, IRoutingSource, IRoutingOutputs, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking { public uint DisplayUiType { get { return DisplayUiConstants.TypeLaptop; } } public string IconName { get; set; } @@ -29,11 +29,15 @@ namespace PepperDash.Essentials.Devices.Common.Sources : base(key, name) { IconName = "Laptop"; + HasPowerOnFeedback = new BoolFeedback("HasPowerFeedback", () => this.GetVideoStatuses() != VideoStatusOutputs.NoStatus); - OutputPorts = new RoutingPortCollection(); - OutputPorts.Add(AnyVideoOut = new RoutingOutputPort(RoutingPortNames.AnyOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, - eRoutingPortConnectionType.None, 0, this)); + + OutputPorts = new RoutingPortCollection + { + (AnyVideoOut = new RoutingOutputPort(RoutingPortNames.AnyOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, + eRoutingPortConnectionType.None, 0, this)) + }; } #region IHasFeedback Members diff --git a/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTV.cs b/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTV.cs index c4a9b5a7..4d744690 100644 --- a/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTV.cs +++ b/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTV.cs @@ -19,8 +19,9 @@ using Serilog.Events; namespace PepperDash.Essentials.Devices.Common { [Description("Wrapper class for an IR-Controlled AppleTV")] - public class AppleTV : EssentialsBridgeableDevice, IDPad, ITransport, IUiDisplayInfo, IRoutingSource - { + public class AppleTV : EssentialsBridgeableDevice, IDPad, ITransport, IUiDisplayInfo, IRoutingSource, IRoutingOutputs + + { public IrOutputPortController IrPort { get; private set; } public const string StandardDriverName = "Apple_AppleTV_4th_Gen_Essentials.ir"; public uint DisplayUiType { get { return DisplayUiConstants.TypeAppleTv; } } diff --git a/src/PepperDash.Essentials.Devices.Common/Streaming/Roku.cs b/src/PepperDash.Essentials.Devices.Common/Streaming/Roku.cs index 9d08f53a..76284597 100644 --- a/src/PepperDash.Essentials.Devices.Common/Streaming/Roku.cs +++ b/src/PepperDash.Essentials.Devices.Common/Streaming/Roku.cs @@ -15,7 +15,7 @@ using Serilog.Events; namespace PepperDash.Essentials.Devices.Common { [Description("Wrapper class for an IR-Controlled Roku")] - public class Roku2 : EssentialsDevice, IDPad, ITransport, IUiDisplayInfo, IRoutingSource + public class Roku2 : EssentialsDevice, IDPad, ITransport, IUiDisplayInfo, IRoutingSource, IRoutingOutputs { [Api] public IrOutputPortController IrPort { get; private set; } From 888f1b388875181e75ad0e90fee3bc005d394ec6 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 8 May 2024 16:18:51 -0500 Subject: [PATCH 11/24] chore: update PD Core version --- .../PepperDash.Essentials.Core.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj index 79891444..d0524aed 100644 --- a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj +++ b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj @@ -27,7 +27,7 @@ - + From 4bf026601f9457fc3130a5326c40d89f6179fa07 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 14 May 2024 10:23:01 -0500 Subject: [PATCH 12/24] feat: get it working --- .../Routing/RouteSwitchDescriptor.cs | 8 +- .../Routing/RoutingFeedbackManager.cs | 184 ++++++++++++------ .../Routing/RoutingInputPort.cs | 7 +- .../Routing/RoutingOutputPort.cs | 2 +- .../Routing/RoutingPort.cs | 4 +- .../Routing/TieLine.cs | 27 +-- .../Web/EssentialsWebApi.cs | 25 ++- .../RequestHandlers/DevJsonRequestHandler.cs | 11 +- .../DevMethodsRequestHandler.cs | 2 + .../GetTieLinesRequestHandler.cs | 34 ++++ .../Displays/MockDisplay.cs | 2 +- src/PepperDash.Essentials/ControlSystem.cs | 2 + 12 files changed, 216 insertions(+), 92 deletions(-) create mode 100644 src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTieLinesRequestHandler.cs diff --git a/src/PepperDash.Essentials.Core/Routing/RouteSwitchDescriptor.cs b/src/PepperDash.Essentials.Core/Routing/RouteSwitchDescriptor.cs index 7b9fcabe..080b932e 100644 --- a/src/PepperDash.Essentials.Core/Routing/RouteSwitchDescriptor.cs +++ b/src/PepperDash.Essentials.Core/Routing/RouteSwitchDescriptor.cs @@ -22,10 +22,10 @@ public override string ToString() { - if(SwitchingDevice is IRouting) - return string.Format("{0} switches output '{1}' to input '{2}'", SwitchingDevice.Key, OutputPort.Selector, InputPort.Selector); - else - return string.Format("{0} switches to input '{1}'", SwitchingDevice.Key, InputPort.Selector); + if (SwitchingDevice is IRouting) + return $"{SwitchingDevice?.Key} switches output {OutputPort.Key} to input {InputPort.Key}"; + else + return $"{SwitchingDevice.Key} switches to input {InputPort.Key}"; } } diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs b/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs index ec09e08a..dbb2129a 100644 --- a/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs +++ b/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs @@ -1,22 +1,19 @@ -using Org.BouncyCastle.Crypto.Prng; -using PepperDash.Core; +using PepperDash.Core; using PepperDash.Essentials.Core.Config; using System; -using System.Collections; -using System.Collections.Generic; using System.Linq; -using System.Reflection; namespace PepperDash.Essentials.Core.Routing { public class RoutingFeedbackManager:EssentialsDevice { public RoutingFeedbackManager(string key, string name): base(key, name) - { - AddPostActivationAction(SubscribeForMidpointFeedback); - AddPostActivationAction(SubscribeForSinkFeedback); + { + AddPreActivationAction(SubscribeForMidpointFeedback); + AddPreActivationAction(SubscribeForSinkFeedback); } + private void SubscribeForMidpointFeedback() { var midpointDevices = DeviceManager.AllDevices.OfType(); @@ -39,11 +36,18 @@ namespace PepperDash.Essentials.Core.Routing private void HandleMidpointUpdate(IRoutingWithFeedback midpoint, RouteSwitchDescriptor newRoute) { - var devices = DeviceManager.AllDevices.OfType(); - - foreach(var device in devices) + try { - UpdateDestination(device, device.CurrentInputPort); + var devices = DeviceManager.AllDevices.OfType(); + + foreach (var device in devices) + { + UpdateDestination(device, device.CurrentInputPort); + } + } + catch (Exception ex) + { + Debug.LogMessage(ex, "Error handling midpoint update from {midpointKey}:{Exception}", this, midpoint.Key, ex); } } @@ -60,30 +64,68 @@ namespace PepperDash.Essentials.Core.Routing } private void UpdateDestination(IRoutingSinkWithSwitching destination, RoutingInputPort inputPort) - { - var tieLines = TieLineCollection.Default; + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Updating destination {destination} with inputPort {inputPort}", this,destination?.Key, inputPort?.Key); - var firstTieLine = tieLines.FirstOrDefault(tl => tl.DestinationPort.Key == inputPort.Key); - - if (firstTieLine == null) + if(inputPort == null) { - Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No tieline found for inputPort {inputPort}. Clearing current source", this, inputPort); + Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "Destination {destination} has not reported an input port yet", this,destination.Key); + return; + } - destination.CurrentSourceInfo = null; - destination.CurrentSourceInfoKey = string.Empty; + TieLine firstTieLine; + try + { + var tieLines = TieLineCollection.Default; + + firstTieLine = tieLines.FirstOrDefault(tl => tl.DestinationPort.Key == inputPort.Key && tl.DestinationPort.ParentDevice.Key == inputPort.ParentDevice.Key); + + if (firstTieLine == null) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No tieline found for inputPort {inputPort}. Clearing current source", this, inputPort); + + var tempSourceListItem = new SourceListItem + { + SourceKey = "$transient", + Name = inputPort.Key, + }; + + + destination.CurrentSourceInfo = tempSourceListItem; ; + destination.CurrentSourceInfoKey = "$transient"; + return; + } + } catch (Exception ex) + { + Debug.LogMessage(ex, "Error getting first tieline: {Exception}", this, ex); return; } Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Getting source for first TieLine {tieLine}", this, firstTieLine); - var sourceTieLine = GetRootTieLine(firstTieLine); - - if (sourceTieLine == null) + TieLine sourceTieLine; + try { - Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No route found to source for inputPort {inputPort}. Clearing current source", this, inputPort); + sourceTieLine = GetRootTieLine(firstTieLine); - destination.CurrentSourceInfo = null; - destination.CurrentSourceInfoKey = string.Empty; + if (sourceTieLine == null) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No route found to source for inputPort {inputPort}. Clearing current source", this, inputPort); + + var tempSourceListItem = new SourceListItem + { + SourceKey = "$transient", + Name = "None", + }; + + destination.CurrentSourceInfo = tempSourceListItem; + destination.CurrentSourceInfoKey = string.Empty; + return; + } + } catch(Exception ex) + { + Debug.LogMessage(ex, "Error getting sourceTieLine: {Exception}", this, ex); + return; } Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root TieLine {tieLine}", this, sourceTieLine); @@ -136,10 +178,16 @@ namespace PepperDash.Essentials.Core.Routing if (source == null) { - Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No source found for device {key}. Clearing current source on {destination}", this, sourceTieLine.SourcePort.ParentDevice.Key, destination); + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No source found for device {key}. Creating transient source for {destination}", this, sourceTieLine.SourcePort.ParentDevice.Key, destination); - destination.CurrentSourceInfo = null; - destination.CurrentSourceInfoKey = string.Empty; + var tempSourceListItem = new SourceListItem + { + SourceKey = "$transient", + Name = sourceTieLine.SourcePort.Key, + }; + + destination.CurrentSourceInfo = tempSourceListItem; ; + destination.CurrentSourceInfoKey = "$transient"; return; } @@ -152,43 +200,67 @@ namespace PepperDash.Essentials.Core.Routing private TieLine GetRootTieLine(TieLine tieLine) { TieLine nextTieLine = null; - - if(tieLine.SourcePort.ParentDevice is IRoutingWithFeedback midpoint) + try { - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLine Source device is midpoint", this); + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "**Following tieLine {tieLine}**", this, tieLine); - var currentRoute = midpoint.CurrentRoutes.FirstOrDefault(route => route.OutputPort.Key == tieLine.SourcePort.Key); - - if(currentRoute == null) + if (tieLine.SourcePort.ParentDevice is IRoutingWithFeedback midpoint) { - Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No route through midpoint {midpoint} for outputPort {outputPort}", this, midpoint.Key, tieLine.SourcePort); - return null; + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLine Source device {sourceDevice} is midpoint", this, midpoint); + + if(midpoint.CurrentRoutes == null || midpoint.CurrentRoutes.Count == 0) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Midpoint {midpointKey} has no routes",this, midpoint.Key); + return null; + } + + var currentRoute = midpoint.CurrentRoutes.FirstOrDefault(route => { + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Checking {route} against {tieLine}", this, route, tieLine); + + return route.OutputPort.Key == tieLine.SourcePort.Key && route.OutputPort.ParentDevice.Key == tieLine.SourcePort.ParentDevice.Key; + }); + + if (currentRoute == null) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No route through midpoint {midpoint} for outputPort {outputPort}", this, midpoint.Key, tieLine.SourcePort); + return null; + } + + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found currentRoute {currentRoute} through {midpoint}", this, currentRoute, midpoint); + + nextTieLine = TieLineCollection.Default.FirstOrDefault(tl => { + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Checking {route} against {tieLine}", tl.DestinationPort.Key, currentRoute.InputPort.Key); + return tl.DestinationPort.Key == currentRoute.InputPort.Key && tl.DestinationPort.ParentDevice.Key == currentRoute.InputPort.ParentDevice.Key; }); + + if (nextTieLine != null) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found next tieLine {tieLine}. Walking the chain", this, nextTieLine); + return GetRootTieLine(nextTieLine); + } + + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root tieLine {tieLine}", this,nextTieLine); + return nextTieLine; } - nextTieLine = TieLineCollection.Default.FirstOrDefault(tl => tl.DestinationPort.Key == currentRoute.InputPort.Key); + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLIne Source Device {sourceDeviceKey} is IRoutingSource: {isIRoutingSource}", this, tieLine.SourcePort.ParentDevice.Key, tieLine.SourcePort.ParentDevice is IRoutingSource); + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLine Source Device interfaces: {typeFullName}:{interfaces}", this, tieLine.SourcePort.ParentDevice.GetType().FullName, tieLine.SourcePort.ParentDevice.GetType().GetInterfaces().Select(i => i.Name)); - if(tieLine != null) + if (tieLine.SourcePort.ParentDevice is IRoutingSource || tieLine.SourcePort.ParentDevice is IRoutingOutputs) //end of the chain + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root: {tieLine}", this, tieLine); + return tieLine; + } + + nextTieLine = TieLineCollection.Default.FirstOrDefault(tl => tl.DestinationPort.Key == tieLine.SourcePort.Key && tl.DestinationPort.ParentDevice.Key == tieLine.SourcePort.ParentDevice.Key ); + + if (nextTieLine != null) { return GetRootTieLine(nextTieLine); } - - return tieLine; - } - - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLIne Source Device {sourceDeviceKey} is IRoutingSource: {isIRoutingSource}", this,tieLine.SourcePort.ParentDevice.Key, tieLine.SourcePort.ParentDevice is IRoutingSource); - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLine Source Device interfaces: {typeFullName}:{interfaces}",this, tieLine.SourcePort.ParentDevice.GetType().FullName, tieLine.SourcePort.ParentDevice.GetType().GetInterfaces().Select(i => i.Name)); - - if(tieLine.SourcePort.ParentDevice is IRoutingSource || tieLine.SourcePort.ParentDevice is IRoutingOutputs) //end of the chain + } catch (Exception ex) { - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root: {tieLine}", this, tieLine); - return tieLine; - } - - nextTieLine = TieLineCollection.Default.FirstOrDefault(tl => tl.SourcePort.Key == tieLine.SourcePort.Key); - - if(nextTieLine != null) - { - return GetRootTieLine(nextTieLine); + Debug.LogMessage(ex, "Error walking tieLines: {Exception}", this, ex); + return null; } return null; diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingInputPort.cs b/src/PepperDash.Essentials.Core/Routing/RoutingInputPort.cs index 7da945cb..9e3bb1d9 100644 --- a/src/PepperDash.Essentials.Core/Routing/RoutingInputPort.cs +++ b/src/PepperDash.Essentials.Core/Routing/RoutingInputPort.cs @@ -38,7 +38,12 @@ namespace PepperDash.Essentials.Core throw new ArgumentNullException(nameof(parent)); ParentDevice = parent; } - } + + public override string ToString() + { + return $"{ParentDevice.Key}|{Key}|{Type}|{ConnectionType}"; + } + } /*/// /// Basic RoutingInput with no statuses. diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingOutputPort.cs b/src/PepperDash.Essentials.Core/Routing/RoutingOutputPort.cs index 445b3072..bebcb287 100644 --- a/src/PepperDash.Essentials.Core/Routing/RoutingOutputPort.cs +++ b/src/PepperDash.Essentials.Core/Routing/RoutingOutputPort.cs @@ -34,7 +34,7 @@ namespace PepperDash.Essentials.Core public override string ToString() { - return ParentDevice.Key + ":" + Key; + return $"{ParentDevice.Key}|{Key}|{Type}|{ConnectionType}"; } } diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingPort.cs b/src/PepperDash.Essentials.Core/Routing/RoutingPort.cs index b687f6fe..04e804f1 100644 --- a/src/PepperDash.Essentials.Core/Routing/RoutingPort.cs +++ b/src/PepperDash.Essentials.Core/Routing/RoutingPort.cs @@ -23,8 +23,8 @@ namespace PepperDash.Essentials.Core ConnectionType = connType; Selector = selector; IsInternal = isInternal; - } - } + } + } /*public abstract class RoutingPort:IKeyed { diff --git a/src/PepperDash.Essentials.Core/Routing/TieLine.cs b/src/PepperDash.Essentials.Core/Routing/TieLine.cs index 65804eb3..245194a9 100644 --- a/src/PepperDash.Essentials.Core/Routing/TieLine.cs +++ b/src/PepperDash.Essentials.Core/Routing/TieLine.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using Newtonsoft.Json; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DM; @@ -93,19 +94,21 @@ namespace PepperDash.Essentials.Core } } - //******************************************************************************** + //******************************************************************************** - public class TieLineCollection : List - { - public static TieLineCollection Default - { - get - { - if (_Default == null) - _Default = new TieLineCollection(); - return _Default; - } - } + public class TieLineCollection : List + { + public static TieLineCollection Default + { + get + { + if (_Default == null) + _Default = new TieLineCollection(); + return _Default; + } + } + + [JsonIgnore] static TieLineCollection _Default; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/EssentialsWebApi.cs b/src/PepperDash.Essentials.Core/Web/EssentialsWebApi.cs index eb5fee37..0ce6b209 100644 --- a/src/PepperDash.Essentials.Core/Web/EssentialsWebApi.cs +++ b/src/PepperDash.Essentials.Core/Web/EssentialsWebApi.cs @@ -163,6 +163,11 @@ namespace PepperDash.Essentials.Core.Web { Name = "Load Config", RouteHandler = new LoadConfigRequestHandler() + }, + new HttpCwsRoute("getTielines") + { + Name = "Get TieLines", + RouteHandler = new GetTieLinesRequestHandler() } }; @@ -233,32 +238,32 @@ namespace PepperDash.Essentials.Core.Web /// public void GetPaths() { - Debug.LogMessage(LogEventLevel.Verbose, this, "{0}", new String('-', 50)); + Debug.LogMessage(LogEventLevel.Information, this, new string('-', 50)); var currentIp = CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); var hostname = CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0); + + var path = CrestronEnvironment.DevicePlatform == eDevicePlatform.Server + ? $"http(s)://{hostname}/VirtualControl/Rooms/{InitialParametersClass.RoomId}/cws{BasePath}" + : $"http(s)://{currentIp}/cws{BasePath}"; - var path = CrestronEnvironment.DevicePlatform == eDevicePlatform.Server - ? string.Format("http(s)://{0}/VirtualControl/Rooms/{1}/cws{2}", hostname, InitialParametersClass.RoomId, BasePath) - : string.Format("http(s)://{0}/cws{1}", currentIp, BasePath); - - Debug.LogMessage(LogEventLevel.Verbose, this, "Server:{0}", path); + Debug.LogMessage(LogEventLevel.Information, this, "Server:{path:l}", path); var routeCollection = _server.GetRouteCollection(); if (routeCollection == null) { - Debug.LogMessage(LogEventLevel.Verbose, this, "Server route collection is null"); + Debug.LogMessage(LogEventLevel.Information, this, "Server route collection is null"); return; } - Debug.LogMessage(LogEventLevel.Verbose, this, "Configured Routes:"); + Debug.LogMessage(LogEventLevel.Information, this, "Configured Routes:"); foreach (var route in routeCollection) { - Debug.LogMessage(LogEventLevel.Verbose, this, "{0}: {1}/{2}", route.Name, path, route.Url); + Debug.LogMessage(LogEventLevel.Information, this, "{routeName:l}: {routePath:l}/{routeUrl:l}", route.Name, path, route.Url); } - Debug.LogMessage(LogEventLevel.Verbose, this, "{0}", new String('-', 50)); + Debug.LogMessage(LogEventLevel.Information, this, new string('-', 50)); } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevJsonRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevJsonRequestHandler.cs index a78b88ce..3599eb23 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevJsonRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevJsonRequestHandler.cs @@ -1,5 +1,6 @@ using System; using Crestron.SimplSharp.WebScripting; +using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Web.RequestHandlers; using Serilog.Events; @@ -28,7 +29,7 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers if (context.Request.ContentLength < 0) { context.Response.StatusCode = 400; - context.Response.StatusDescription = "Bad Request"; + context.Response.StatusDescription = "Bad Request: no body"; context.Response.End(); return; @@ -38,7 +39,7 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers if (string.IsNullOrEmpty(data)) { context.Response.StatusCode = 400; - context.Response.StatusDescription = "Bad Request"; + context.Response.StatusDescription = "Bad Request: no body"; context.Response.End(); return; @@ -46,6 +47,7 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers try { + var daw = JsonConvert.DeserializeObject(data); DeviceJsonApi.DoDeviceActionWithJson(data); context.Response.StatusCode = 200; @@ -54,12 +56,11 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers } catch (Exception ex) { - Debug.LogMessage(LogEventLevel.Error, "Exception Message: {0}", ex.Message); - Debug.LogMessage(LogEventLevel.Verbose, "Exception Stack Trace: {0}", ex.StackTrace); - if(ex.InnerException != null) Debug.LogMessage(LogEventLevel.Error, "Exception Inner: {0}", ex.InnerException); + Debug.LogMessage(ex, "Error handling device command: {Exception}"); context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; + context.Response.Write(JsonConvert.SerializeObject(new { error = ex.Message }), false); context.Response.End(); } } diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevMethodsRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevMethodsRequestHandler.cs index c08544cb..263eb161 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevMethodsRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevMethodsRequestHandler.cs @@ -1,6 +1,7 @@ using System.Text; using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; +using PepperDash.Core; using PepperDash.Core.Web.RequestHandlers; namespace PepperDash.Essentials.Core.Web.RequestHandlers @@ -25,6 +26,7 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers protected override void HandleGet(HttpCwsContext context) { var routeData = context.Request.RouteData; + Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Getting DevMethods: {@routeData}", routeData); if (routeData == null) { context.Response.StatusCode = 400; diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTieLinesRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTieLinesRequestHandler.cs new file mode 100644 index 00000000..d5de5ad0 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTieLinesRequestHandler.cs @@ -0,0 +1,34 @@ +using Crestron.SimplSharp.WebScripting; +using Newtonsoft.Json; +using PepperDash.Core.Web.RequestHandlers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PepperDash.Essentials.Core.Web.RequestHandlers +{ + public class GetTieLinesRequestHandler:WebApiBaseRequestHandler + { + public GetTieLinesRequestHandler() : base(true) { } + + protected override void HandleGet(HttpCwsContext context) + { + var tieLineString = JsonConvert.SerializeObject(TieLineCollection.Default.Select((tl) => new { + sourceKey = tl.SourcePort.ParentDevice.Key, + sourcePort = tl.SourcePort.Key, + destinationKey = tl.DestinationPort.ParentDevice.Key, + destinationPort = tl.DestinationPort.Key + })); + + context.Response.StatusCode = 200; + context.Response.StatusDescription = "OK"; + context.Response.ContentType = "application/json"; + context.Response.ContentEncoding = Encoding.UTF8; + context.Response.Write(tieLineString, false); + context.Response.End(); + + } + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs b/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs index db14aa4d..bd141ed2 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs @@ -171,7 +171,7 @@ namespace PepperDash.Essentials.Devices.Common.Displays CurrentInputPort = inputPort; } catch (Exception ex) { - Debug.LogMessage(ex, "Error making switch: {Exception}", this); + Debug.LogMessage(ex, "Error making switch: {Exception}", this, ex); } } diff --git a/src/PepperDash.Essentials/ControlSystem.cs b/src/PepperDash.Essentials/ControlSystem.cs index d2b7a2b9..e16e7b6d 100644 --- a/src/PepperDash.Essentials/ControlSystem.cs +++ b/src/PepperDash.Essentials/ControlSystem.cs @@ -92,6 +92,8 @@ namespace PepperDash.Essentials private void StartSystem(object preventInitialization) { + Debug.SetErrorLogMinimumDebugLevel(Serilog.Events.LogEventLevel.Verbose); + DeterminePlatform(); if (Debug.DoNotLoadConfigOnNextBoot) From 8255328be1d37547eef7f36a29bffa451a757e31 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Thu, 23 May 2024 08:44:51 -0500 Subject: [PATCH 13/24] build: update PD Core --- .../PepperDash.Essentials.Core.csproj | 4 ++-- .../PepperDash.Essentials.Devices.Common.csproj | 2 +- src/PepperDash.Essentials/PepperDash.Essentials.csproj | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj index d0524aed..bcdadf7f 100644 --- a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj +++ b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj @@ -26,8 +26,8 @@ - - + + diff --git a/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj b/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj index 34433189..b6b6e7d1 100644 --- a/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj +++ b/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj @@ -27,6 +27,6 @@ - + \ No newline at end of file diff --git a/src/PepperDash.Essentials/PepperDash.Essentials.csproj b/src/PepperDash.Essentials/PepperDash.Essentials.csproj index 885a0970..4f733a5e 100644 --- a/src/PepperDash.Essentials/PepperDash.Essentials.csproj +++ b/src/PepperDash.Essentials/PepperDash.Essentials.csproj @@ -47,7 +47,7 @@ - + From 3c5fe88e5a7a04b9b374e9df25b7c593b824144d Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Thu, 23 May 2024 12:45:47 -0500 Subject: [PATCH 14/24] fix: correct namespaces to allow plugins to load correctly --- src/PepperDash.Essentials.Core/Devices/PC/InRoomPc.cs | 1 - src/PepperDash.Essentials.Core/Devices/PC/Laptop.cs | 1 - src/PepperDash.Essentials.Core/Display/BasicIrDisplay.cs | 1 - src/PepperDash.Essentials.Core/Display/DisplayBase.cs | 1 - src/PepperDash.Essentials.Core/Display/MockDisplay.cs | 1 - .../EssentialsHuddleSpaceFusionSystemControllerBase.cs | 1 - .../PepperDash.Essentials.Core.csproj | 1 + src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs | 2 +- src/PepperDash.Essentials.Core/Room/Interfaces.cs | 1 - .../Routing/IHasCurrentSourceInfoChange.cs | 2 +- src/PepperDash.Essentials.Core/Routing/IRmcRouting.cs | 2 +- .../Routing/IRmcRoutingWithFeedback.cs | 4 +--- src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs | 9 +++++---- .../Routing/IRoutingSinkWithSwitching.cs | 5 ++++- .../Routing/RoutingFeedbackManager.cs | 4 ++-- .../Routing/RoutingPortNames.cs | 2 +- .../Audio/GenericAudioOut.cs | 1 - .../Displays/BasicIrDisplay.cs | 1 - .../Displays/DisplayBase.cs | 1 - .../Displays/MockDisplay.cs | 1 - .../Generic/GenericSink.cs | 1 - .../Generic/GenericSource.cs | 1 - .../PepperDash.Essentials.Devices.Common.csproj | 1 + .../Room/IEssentialsHuddleSpaceRoom.cs | 1 - .../Room/IEssentialsHuddleVtc1Room.cs | 1 - .../SetTopBox/IRSetTopBoxBase.cs | 1 - .../SoftCodec/BlueJeansPc.cs | 1 - .../SoftCodec/GenericSoftCodec.cs | 1 - .../Sources/InRoomPc.cs | 1 - .../Sources/Laptop.cs | 1 - .../Streaming/AppleTV.cs | 1 - .../Streaming/Roku.cs | 1 - .../VideoCodec/VideoCodecBase.cs | 2 +- src/PepperDash.Essentials/PepperDash.Essentials.csproj | 2 +- 34 files changed, 20 insertions(+), 38 deletions(-) diff --git a/src/PepperDash.Essentials.Core/Devices/PC/InRoomPc.cs b/src/PepperDash.Essentials.Core/Devices/PC/InRoomPc.cs index 0b9e5815..31e4be22 100644 --- a/src/PepperDash.Essentials.Core/Devices/PC/InRoomPc.cs +++ b/src/PepperDash.Essentials.Core/Devices/PC/InRoomPc.cs @@ -5,7 +5,6 @@ using Crestron.SimplSharpPro; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Core.Routing; using PepperDash.Core; using Serilog.Events; diff --git a/src/PepperDash.Essentials.Core/Devices/PC/Laptop.cs b/src/PepperDash.Essentials.Core/Devices/PC/Laptop.cs index 05cf9e76..921d52c2 100644 --- a/src/PepperDash.Essentials.Core/Devices/PC/Laptop.cs +++ b/src/PepperDash.Essentials.Core/Devices/PC/Laptop.cs @@ -5,7 +5,6 @@ using Crestron.SimplSharpPro; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Core.Routing; using PepperDash.Core; using Serilog.Events; diff --git a/src/PepperDash.Essentials.Core/Display/BasicIrDisplay.cs b/src/PepperDash.Essentials.Core/Display/BasicIrDisplay.cs index a921f07b..394fa17a 100644 --- a/src/PepperDash.Essentials.Core/Display/BasicIrDisplay.cs +++ b/src/PepperDash.Essentials.Core/Display/BasicIrDisplay.cs @@ -10,7 +10,6 @@ using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Bridges; -using PepperDash.Essentials.Core.Routing; using Serilog.Events; namespace PepperDash.Essentials.Core diff --git a/src/PepperDash.Essentials.Core/Display/DisplayBase.cs b/src/PepperDash.Essentials.Core/Display/DisplayBase.cs index 2e5a2ed1..040e9d84 100644 --- a/src/PepperDash.Essentials.Core/Display/DisplayBase.cs +++ b/src/PepperDash.Essentials.Core/Display/DisplayBase.cs @@ -5,7 +5,6 @@ using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core.Bridges; -using PepperDash.Essentials.Core.Routing; using Serilog.Events; using System; using System.Collections.Generic; diff --git a/src/PepperDash.Essentials.Core/Display/MockDisplay.cs b/src/PepperDash.Essentials.Core/Display/MockDisplay.cs index 7c9f0446..3f3fd2ac 100644 --- a/src/PepperDash.Essentials.Core/Display/MockDisplay.cs +++ b/src/PepperDash.Essentials.Core/Display/MockDisplay.cs @@ -11,7 +11,6 @@ using Crestron.SimplSharpPro.DM.Endpoints.Transmitters; using PepperDash.Core; using PepperDash.Essentials.Core.Bridges; -using PepperDash.Essentials.Core.Routing; using PepperDash.Essentials.Core.Config; using Serilog.Events; diff --git a/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs b/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs index fb8ed645..04f2490a 100644 --- a/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs +++ b/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs @@ -9,7 +9,6 @@ using Crestron.SimplSharpPro.Fusion; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Core.Routing; using Serilog.Events; using System; using System.Collections.Generic; diff --git a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj index bcdadf7f..1298873d 100644 --- a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj +++ b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj @@ -11,6 +11,7 @@ PepperDash.Essentials.Core PepperDash Essentials Core PepperDash.Essentials.Core + $(Version) full diff --git a/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs b/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs index 3e658ea1..022bfd2f 100644 --- a/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs +++ b/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs @@ -59,7 +59,7 @@ namespace PepperDash.Essentials Debug.LogMessage(LogEventLevel.Verbose, "Found {0} Assemblies", assemblyFiles.Length); - foreach (var fi in assemblyFiles) + foreach (var fi in assemblyFiles.Where(fi => fi.Name.Contains("Essentials") || fi.Name.Contains("PepperDash"))) { string version = string.Empty; Assembly assembly = null; diff --git a/src/PepperDash.Essentials.Core/Room/Interfaces.cs b/src/PepperDash.Essentials.Core/Room/Interfaces.cs index a8d9c2a9..c60581d2 100644 --- a/src/PepperDash.Essentials.Core/Room/Interfaces.cs +++ b/src/PepperDash.Essentials.Core/Room/Interfaces.cs @@ -5,7 +5,6 @@ using System.Text; using Crestron.SimplSharp; using PepperDash.Core; -using PepperDash.Essentials.Core.Routing; namespace PepperDash.Essentials.Core diff --git a/src/PepperDash.Essentials.Core/Routing/IHasCurrentSourceInfoChange.cs b/src/PepperDash.Essentials.Core/Routing/IHasCurrentSourceInfoChange.cs index 20b46520..505a8652 100644 --- a/src/PepperDash.Essentials.Core/Routing/IHasCurrentSourceInfoChange.cs +++ b/src/PepperDash.Essentials.Core/Routing/IHasCurrentSourceInfoChange.cs @@ -9,7 +9,7 @@ using PepperDash.Essentials.Core.Routing; using PepperDash.Essentials.Core.Routing; using PepperDash.Essentials.Core.Routing.Interfaces */ -namespace PepperDash.Essentials.Core.Routing +namespace PepperDash.Essentials.Core { /// /// The handler type for a Room's SourceInfoChange diff --git a/src/PepperDash.Essentials.Core/Routing/IRmcRouting.cs b/src/PepperDash.Essentials.Core/Routing/IRmcRouting.cs index bddcbcf7..52290bd2 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRmcRouting.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRmcRouting.cs @@ -1,4 +1,4 @@ -namespace PepperDash.Essentials.Core.Routing +namespace PepperDash.Essentials.Core { /// /// Defines a receiver that has internal routing (DM-RMC-4K-Z-SCALER-C) diff --git a/src/PepperDash.Essentials.Core/Routing/IRmcRoutingWithFeedback.cs b/src/PepperDash.Essentials.Core/Routing/IRmcRoutingWithFeedback.cs index 3648204c..a8e6d5f0 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRmcRoutingWithFeedback.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRmcRoutingWithFeedback.cs @@ -1,6 +1,4 @@ -using PepperDash.Essentials.Core.Routing; - -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core { /// /// Defines an IRmcRouting with a feedback event diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs index 773fab77..b05c7744 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs @@ -1,15 +1,16 @@ -using PepperDash.Essentials.Core.Routing; - -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core { /// /// For fixed-source endpoint devices /// public interface IRoutingSink : IRoutingInputs, IHasCurrentSourceInfoChange + { + } + + public interface IRoutingSinkWithInputPort :IRoutingSink { RoutingInputPort CurrentInputPort { get; } } - /*/// /// For fixed-source endpoint devices /// diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithSwitching.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithSwitching.cs index 68e4632c..d6f97c07 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithSwitching.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithSwitching.cs @@ -9,8 +9,11 @@ namespace PepperDash.Essentials.Core /// public interface IRoutingSinkWithSwitching : IRoutingSink { - void ExecuteSwitch(object inputSelector); + void ExecuteSwitch(object inputSelector); + } + public interface IRoutingSinkWithSwitchingWithInputPort:IRoutingSinkWithSwitching, IRoutingSinkWithInputPort + { event InputChangedEventHandler InputChanged; } diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs b/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs index dbb2129a..28fefa96 100644 --- a/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs +++ b/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs @@ -26,7 +26,7 @@ namespace PepperDash.Essentials.Core.Routing private void SubscribeForSinkFeedback() { - var sinkDevices = DeviceManager.AllDevices.OfType(); + var sinkDevices = DeviceManager.AllDevices.OfType(); foreach (var device in sinkDevices) { @@ -38,7 +38,7 @@ namespace PepperDash.Essentials.Core.Routing { try { - var devices = DeviceManager.AllDevices.OfType(); + var devices = DeviceManager.AllDevices.OfType(); foreach (var device in devices) { diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingPortNames.cs b/src/PepperDash.Essentials.Core/Routing/RoutingPortNames.cs index 7029443b..1605c631 100644 --- a/src/PepperDash.Essentials.Core/Routing/RoutingPortNames.cs +++ b/src/PepperDash.Essentials.Core/Routing/RoutingPortNames.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core.Routing +namespace PepperDash.Essentials.Core { /// /// These should correspond directly with the portNames var in the config tool. diff --git a/src/PepperDash.Essentials.Devices.Common/Audio/GenericAudioOut.cs b/src/PepperDash.Essentials.Devices.Common/Audio/GenericAudioOut.cs index 207c04be..150b7818 100644 --- a/src/PepperDash.Essentials.Devices.Common/Audio/GenericAudioOut.cs +++ b/src/PepperDash.Essentials.Devices.Common/Audio/GenericAudioOut.cs @@ -8,7 +8,6 @@ using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Core.Routing; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/BasicIrDisplay.cs b/src/PepperDash.Essentials.Devices.Common/Displays/BasicIrDisplay.cs index 654b2fcf..d7e19d00 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/BasicIrDisplay.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/BasicIrDisplay.cs @@ -7,7 +7,6 @@ using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Core.Routing; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.Displays diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs b/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs index d5595f5f..541ef80a 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs @@ -4,7 +4,6 @@ using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; -using PepperDash.Essentials.Core.Routing; using Serilog.Events; using System; using System.Collections.Generic; diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs b/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs index bd141ed2..f281992a 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs @@ -8,7 +8,6 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.DeviceTypeInterfaces; -using PepperDash.Essentials.Core.Routing; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.Displays diff --git a/src/PepperDash.Essentials.Devices.Common/Generic/GenericSink.cs b/src/PepperDash.Essentials.Devices.Common/Generic/GenericSink.cs index de7d5174..13878321 100644 --- a/src/PepperDash.Essentials.Devices.Common/Generic/GenericSink.cs +++ b/src/PepperDash.Essentials.Devices.Common/Generic/GenericSink.cs @@ -1,7 +1,6 @@ using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Core.Routing; using Serilog.Events; using System; using System.Collections.Generic; diff --git a/src/PepperDash.Essentials.Devices.Common/Generic/GenericSource.cs b/src/PepperDash.Essentials.Devices.Common/Generic/GenericSource.cs index 16ddaa25..80823156 100644 --- a/src/PepperDash.Essentials.Devices.Common/Generic/GenericSource.cs +++ b/src/PepperDash.Essentials.Devices.Common/Generic/GenericSource.cs @@ -9,7 +9,6 @@ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Core.Routing; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common diff --git a/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj b/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj index b6b6e7d1..7391ceed 100644 --- a/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj +++ b/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj @@ -12,6 +12,7 @@ True PepperDash Essentials Devices Common PepperDash.Essentials.Devices.Common + $(Version) full diff --git a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleSpaceRoom.cs b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleSpaceRoom.cs index d55e2f1e..1af09f1c 100644 --- a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleSpaceRoom.cs +++ b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleSpaceRoom.cs @@ -1,5 +1,4 @@ using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.Routing; using PepperDash.Essentials.Room.Config; namespace PepperDash.Essentials.Devices.Common.Room diff --git a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleVtc1Room.cs b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleVtc1Room.cs index ff4a19aa..b7f1a619 100644 --- a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleVtc1Room.cs +++ b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleVtc1Room.cs @@ -1,5 +1,4 @@ using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.Routing; using PepperDash.Essentials.Devices.Common.AudioCodec; using PepperDash.Essentials.Devices.Common.Codec; using PepperDash.Essentials.Devices.Common.VideoCodec; diff --git a/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBase.cs b/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBase.cs index 0bc055c8..32885aec 100644 --- a/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBase.cs @@ -13,7 +13,6 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Presets; -using PepperDash.Essentials.Core.Routing; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using Serilog.Events; diff --git a/src/PepperDash.Essentials.Devices.Common/SoftCodec/BlueJeansPc.cs b/src/PepperDash.Essentials.Devices.Common/SoftCodec/BlueJeansPc.cs index 52c8d1eb..891f92b1 100644 --- a/src/PepperDash.Essentials.Devices.Common/SoftCodec/BlueJeansPc.cs +++ b/src/PepperDash.Essentials.Devices.Common/SoftCodec/BlueJeansPc.cs @@ -5,7 +5,6 @@ using Crestron.SimplSharp; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Core.Routing; using PepperDash.Essentials.Devices.Common.Sources; using Serilog.Events; diff --git a/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs b/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs index 5a8a3df8..f623c539 100644 --- a/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs +++ b/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs @@ -2,7 +2,6 @@ using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Core.Routing; using Serilog.Events; using System.Collections.Generic; using System.Linq; diff --git a/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPc.cs b/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPc.cs index 3de80549..41ad7a43 100644 --- a/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPc.cs +++ b/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPc.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Core.Routing; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.Sources diff --git a/src/PepperDash.Essentials.Devices.Common/Sources/Laptop.cs b/src/PepperDash.Essentials.Devices.Common/Sources/Laptop.cs index bf4a8b45..38898209 100644 --- a/src/PepperDash.Essentials.Devices.Common/Sources/Laptop.cs +++ b/src/PepperDash.Essentials.Devices.Common/Sources/Laptop.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Core.Routing; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.Sources diff --git a/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTV.cs b/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTV.cs index 4d744690..e19c5c81 100644 --- a/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTV.cs +++ b/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTV.cs @@ -13,7 +13,6 @@ using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Bridges; -using PepperDash.Essentials.Core.Routing; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common diff --git a/src/PepperDash.Essentials.Devices.Common/Streaming/Roku.cs b/src/PepperDash.Essentials.Devices.Common/Streaming/Roku.cs index 76284597..213e5835 100644 --- a/src/PepperDash.Essentials.Devices.Common/Streaming/Roku.cs +++ b/src/PepperDash.Essentials.Devices.Common/Streaming/Roku.cs @@ -9,7 +9,6 @@ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Core.Routing; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/VideoCodecBase.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/VideoCodecBase.cs index b4b2efad..daa9aa0b 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/VideoCodecBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/VideoCodecBase.cs @@ -14,13 +14,13 @@ using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Devices; using PepperDash.Essentials.Core.DeviceTypeInterfaces; -using PepperDash.Essentials.Core.Routing; using PepperDash.Essentials.Devices.Common.Cameras; using PepperDash.Essentials.Devices.Common.Codec; using PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces; using PepperDash.Essentials.Core.Bridges.JoinMaps; using Feedback = PepperDash.Essentials.Core.Feedback; using Serilog.Events; +using PepperDash.Essentials.Core.Routing; namespace PepperDash.Essentials.Devices.Common.VideoCodec { diff --git a/src/PepperDash.Essentials/PepperDash.Essentials.csproj b/src/PepperDash.Essentials/PepperDash.Essentials.csproj index 4f733a5e..33ade9bd 100644 --- a/src/PepperDash.Essentials/PepperDash.Essentials.csproj +++ b/src/PepperDash.Essentials/PepperDash.Essentials.csproj @@ -11,7 +11,7 @@ bin\$(Configuration)\ PepperDash Essentials PepperDashEssentials - $(Version) + $(Version) full From 5afdc2effad5d0e9cbf8e2f2857fff544cba26af Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 24 May 2024 16:11:20 -0500 Subject: [PATCH 15/24] fix: remove Crestron.SimplSharp.Reflection Ran into some odd exceptions loading on a VC-4 instance, and changing to System.Reflection solved them. --- .../Factory/DeviceFactory.cs | 19 ++------- .../ProcessorExtensionDeviceFactory.cs | 4 +- .../Plugins/PluginLoader.cs | 39 +++++++++++-------- .../DeviceFactory.cs | 2 +- .../Factory/DeviceFactory.cs | 2 +- 5 files changed, 31 insertions(+), 35 deletions(-) diff --git a/src/PepperDash.Essentials.Core/Factory/DeviceFactory.cs b/src/PepperDash.Essentials.Core/Factory/DeviceFactory.cs index 65b410e6..f4ce92a0 100644 --- a/src/PepperDash.Essentials.Core/Factory/DeviceFactory.cs +++ b/src/PepperDash.Essentials.Core/Factory/DeviceFactory.cs @@ -1,7 +1,7 @@  using Crestron.SimplSharp; -using Crestron.SimplSharp.Reflection; +using System.Reflection; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core.Config; @@ -14,7 +14,7 @@ namespace PepperDash.Essentials.Core { public class DeviceFactoryWrapper { - public CType CType { get; set; } + public Type CType { get; set; } public string Description { get; set; } public Func FactoryMethod { get; set; } @@ -69,7 +69,7 @@ namespace PepperDash.Essentials.Core DeviceFactory.FactoryMethods.Add(typeName, new DeviceFactoryWrapper() { FactoryMethod = method}); } - public static void AddFactoryForType(string typeName, string description, CType cType, Func method) + public static void AddFactoryForType(string typeName, string description, Type cType, Func method) { //Debug.LogMessage(LogEventLevel.Debug, "Adding factory method for type '{0}'", typeName); @@ -149,18 +149,7 @@ namespace PepperDash.Essentials.Core } catch (Exception ex) { - Debug.LogMessage(LogEventLevel.Error, "Exception occurred while creating device {0}: {1}", dc.Key, ex.Message); - - Debug.LogMessage(LogEventLevel.Verbose, "{0}", ex.StackTrace); - - if (ex.InnerException == null) - { - return null; - } - - Debug.LogMessage(LogEventLevel.Error, "Inner exception while creating device {0}: {1}", dc.Key, - ex.InnerException.Message); - Debug.LogMessage(LogEventLevel.Verbose, "{0}", ex.InnerException.StackTrace); + Debug.LogMessage(ex, "Exception occurred while creating device {0}: {1}", null, dc.Key, ex.Message); return null; } } diff --git a/src/PepperDash.Essentials.Core/Factory/ProcessorExtensionDeviceFactory.cs b/src/PepperDash.Essentials.Core/Factory/ProcessorExtensionDeviceFactory.cs index 68f5dc1f..95e0fb76 100644 --- a/src/PepperDash.Essentials.Core/Factory/ProcessorExtensionDeviceFactory.cs +++ b/src/PepperDash.Essentials.Core/Factory/ProcessorExtensionDeviceFactory.cs @@ -1,5 +1,5 @@  -using Crestron.SimplSharp.Reflection; +using System.Reflection; using PepperDash.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; @@ -55,7 +55,7 @@ namespace PepperDash.Essentials.Core ProcessorExtensionDeviceFactory.ProcessorExtensionFactoryMethods.Add(extensionName, new DeviceFactoryWrapper() { FactoryMethod = method }); } - public static void AddFactoryForType(string extensionName, string description, CType cType, Func method) + public static void AddFactoryForType(string extensionName, string description, Type cType, Func method) { //Debug.LogMessage(LogEventLevel.Debug, "Adding factory method for type '{0}'", typeName); diff --git a/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs b/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs index 022bfd2f..aebd2d22 100644 --- a/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs +++ b/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; -using Crestron.SimplSharp.Reflection; +using System.Reflection; using PepperDash.Core; using PepperDash.Essentials.Core; @@ -119,24 +119,31 @@ namespace PepperDash.Essentials /// static LoadedAssembly LoadAssembly(string filePath) { - //Debug.LogMessage(LogEventLevel.Verbose, "Attempting to load {0}", filePath); - var assembly = Assembly.LoadFrom(filePath); - if (assembly != null) + try { - var assyVersion = GetAssemblyVersion(assembly); + //Debug.LogMessage(LogEventLevel.Verbose, "Attempting to load {0}", filePath); + var assembly = Assembly.LoadFrom(filePath); + if (assembly != null) + { + var assyVersion = GetAssemblyVersion(assembly); - var loadedAssembly = new LoadedAssembly(assembly.GetName().Name, assyVersion, assembly); - LoadedAssemblies.Add(loadedAssembly); - Debug.LogMessage(LogEventLevel.Information, "Loaded assembly '{0}', version {1}", loadedAssembly.Name, loadedAssembly.Version); - return loadedAssembly; - } - else + var loadedAssembly = new LoadedAssembly(assembly.GetName().Name, assyVersion, assembly); + LoadedAssemblies.Add(loadedAssembly); + Debug.LogMessage(LogEventLevel.Information, "Loaded assembly '{0}', version {1}", loadedAssembly.Name, loadedAssembly.Version); + return loadedAssembly; + } + else + { + Debug.LogMessage(LogEventLevel.Information, "Unable to load assembly: '{0}'", filePath); + } + + return null; + } catch(Exception ex) { - Debug.LogMessage(LogEventLevel.Information, "Unable to load assembly: '{0}'", filePath); + Debug.LogMessage(ex, "Error loading assembly from {path}", null, filePath); + return null; } - return null; - } /// @@ -354,7 +361,7 @@ namespace PepperDash.Essentials try { var assy = loadedAssembly.Assembly; - CType[] types = {}; + Type[] types = {}; try { types = assy.GetTypes(); @@ -439,7 +446,7 @@ namespace PepperDash.Essentials /// /// /// - static void LoadCustomLegacyPlugin(CType type, MethodInfo loadPlugin, LoadedAssembly loadedAssembly) + static void LoadCustomLegacyPlugin(Type type, MethodInfo loadPlugin, LoadedAssembly loadedAssembly) { Debug.LogMessage(LogEventLevel.Verbose, "LoadPlugin method found in {0}", type.Name); diff --git a/src/PepperDash.Essentials.Devices.Common/DeviceFactory.cs b/src/PepperDash.Essentials.Devices.Common/DeviceFactory.cs index bd8cf92f..fdb583dc 100644 --- a/src/PepperDash.Essentials.Devices.Common/DeviceFactory.cs +++ b/src/PepperDash.Essentials.Devices.Common/DeviceFactory.cs @@ -2,7 +2,7 @@ using System; using System.Linq; -using Crestron.SimplSharp.Reflection; +using System.Reflection; using PepperDash.Core; using PepperDash.Essentials.Core; using Serilog.Events; diff --git a/src/PepperDash.Essentials/Factory/DeviceFactory.cs b/src/PepperDash.Essentials/Factory/DeviceFactory.cs index 73063e30..c68f0520 100644 --- a/src/PepperDash.Essentials/Factory/DeviceFactory.cs +++ b/src/PepperDash.Essentials/Factory/DeviceFactory.cs @@ -6,7 +6,7 @@ using System.Linq; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharpPro; -using Crestron.SimplSharp.Reflection; +using System.Reflection; using Newtonsoft.Json; using Newtonsoft.Json.Linq; From effefc939cbda9c5487cfe458316b71846bb609e Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 24 May 2024 16:12:50 -0500 Subject: [PATCH 16/24] fix: minor Web API enhancements * changed path for DevJson to include the device key instead of requiring it in the body * Made the `GetRequestBody` method an extension method for the `HttpCwsRequest` class --- .../Web/EssentialsWebApi.cs | 2 +- .../Web/EssentialsWebApiHelpers.cs | 12 +++---- .../RequestHandlers/AppDebugRequestHandler.cs | 2 +- .../RequestHandlers/DevJsonRequestHandler.cs | 34 ++++++++++++++++--- .../RequestHandlers/DevListRequestHandler.cs | 2 +- ...DoNotLoadConfigOnNextBootRequestHandler.cs | 2 +- .../SetDeviceStreamDebugRequestHandler.cs | 2 +- 7 files changed, 41 insertions(+), 15 deletions(-) diff --git a/src/PepperDash.Essentials.Core/Web/EssentialsWebApi.cs b/src/PepperDash.Essentials.Core/Web/EssentialsWebApi.cs index 0ce6b209..a37a78c0 100644 --- a/src/PepperDash.Essentials.Core/Web/EssentialsWebApi.cs +++ b/src/PepperDash.Essentials.Core/Web/EssentialsWebApi.cs @@ -89,7 +89,7 @@ namespace PepperDash.Essentials.Core.Web Name = "DevList", RouteHandler = new DevListRequestHandler() }, - new HttpCwsRoute("deviceCommands") + new HttpCwsRoute("deviceCommands/{deviceKey}") { Name = "DevJson", RouteHandler = new DevJsonRequestHandler() diff --git a/src/PepperDash.Essentials.Core/Web/EssentialsWebApiHelpers.cs b/src/PepperDash.Essentials.Core/Web/EssentialsWebApiHelpers.cs index 89718fcf..cc6d4cd6 100644 --- a/src/PepperDash.Essentials.Core/Web/EssentialsWebApiHelpers.cs +++ b/src/PepperDash.Essentials.Core/Web/EssentialsWebApiHelpers.cs @@ -7,11 +7,11 @@ using PepperDash.Core; namespace PepperDash.Essentials.Core.Web { - public class EssentialsWebApiHelpers + public static class EssentialsWebApiHelpers { - public static string GetRequestBody(HttpCwsRequest request) + public static string GetRequestBody(this HttpCwsRequest request) { - var bytes = new Byte[request.ContentLength]; + var bytes = new byte[request.ContentLength]; request.InputStream.Read(bytes, 0, request.ContentLength); @@ -22,8 +22,8 @@ namespace PepperDash.Essentials.Core.Web { return new { - Name = assembly.Name, - Version = assembly.Version + assembly.Name, + assembly.Version }; } @@ -31,7 +31,7 @@ namespace PepperDash.Essentials.Core.Web { return new { - Key = device.Key, + device.Key, Name = (device is IKeyName) ? (device as IKeyName).Name : "---" diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/AppDebugRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/AppDebugRequestHandler.cs index 1157c5e1..0b7497d2 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/AppDebugRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/AppDebugRequestHandler.cs @@ -52,7 +52,7 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers return; } - var data = EssentialsWebApiHelpers.GetRequestBody(context.Request); + var data = context.Request.GetRequestBody(); if (string.IsNullOrEmpty(data)) { context.Response.StatusCode = 400; diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevJsonRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevJsonRequestHandler.cs index 3599eb23..d14ffb83 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevJsonRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevJsonRequestHandler.cs @@ -26,6 +26,26 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers /// protected override void HandlePost(HttpCwsContext context) { + var routeData = context.Request.RouteData; + + if(routeData == null) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); + + return; + } + + if(!routeData.Values.TryGetValue("deviceKey", out var deviceKey)) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); + + return; + } + if (context.Request.ContentLength < 0) { context.Response.StatusCode = 400; @@ -35,7 +55,8 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers return; } - var data = EssentialsWebApiHelpers.GetRequestBody(context.Request); + var data = context.Request.GetRequestBody(); + if (string.IsNullOrEmpty(data)) { context.Response.StatusCode = 400; @@ -46,9 +67,14 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers } try - { - var daw = JsonConvert.DeserializeObject(data); - DeviceJsonApi.DoDeviceActionWithJson(data); + { + var daw = new DeviceActionWrapper { DeviceKey = (string) deviceKey}; + + JsonConvert.PopulateObject(data, daw); + + Debug.LogMessage(LogEventLevel.Verbose, "Device Action Wrapper: {@wrapper}", null, daw); + + DeviceJsonApi.DoDeviceAction(daw); context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevListRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevListRequestHandler.cs index e9df4347..a83685fb 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevListRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevListRequestHandler.cs @@ -34,7 +34,7 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers return; } - allDevices.Sort((a, b) => System.String.Compare(a.Key, b.Key, System.StringComparison.Ordinal)); + allDevices.Sort((a, b) => string.Compare(a.Key, b.Key, System.StringComparison.Ordinal)); var deviceList = allDevices.Select(d => EssentialsWebApiHelpers.MapToDeviceListObject(d)).ToList(); diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DoNotLoadConfigOnNextBootRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DoNotLoadConfigOnNextBootRequestHandler.cs index 4ec3bc97..fdcad73c 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DoNotLoadConfigOnNextBootRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DoNotLoadConfigOnNextBootRequestHandler.cs @@ -52,7 +52,7 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers return; } - var data = EssentialsWebApiHelpers.GetRequestBody(context.Request); + var data = context.Request.GetRequestBody(); if (string.IsNullOrEmpty(data)) { context.Response.StatusCode = 400; diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/SetDeviceStreamDebugRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/SetDeviceStreamDebugRequestHandler.cs index a08fda2b..6378f1b2 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/SetDeviceStreamDebugRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/SetDeviceStreamDebugRequestHandler.cs @@ -89,7 +89,7 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers return; } - var data = EssentialsWebApiHelpers.GetRequestBody(context.Request); + var data = context.Request.GetRequestBody(); if (data == null) { context.Response.StatusCode = 500; From 35e0662b27a52755d4a75e5e5d323212fe1e9632 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 24 May 2024 16:13:21 -0500 Subject: [PATCH 17/24] fix: only update CurrentInputPort if it has changed --- .../Displays/DisplayBase.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs b/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs index 541ef80a..9796599b 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs @@ -29,6 +29,8 @@ namespace PepperDash.Essentials.Devices.Common.Displays protected set { + if (_currentInputPort == value) return; + _currentInputPort = value; InputChanged?.Invoke(this, _currentInputPort); From f630d3f4100e68d33e879a5f3fedb65c91fc0eac Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 24 May 2024 16:13:35 -0500 Subject: [PATCH 18/24] fix: add missing interfaces --- .../Displays/MockDisplay.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs b/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs index f281992a..ea7f3a5b 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs @@ -12,7 +12,7 @@ using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.Displays { - public class MockDisplay : TwoWayDisplayBase, IBasicVolumeWithFeedback, IBridgeAdvanced, IHasInputs + public class MockDisplay : TwoWayDisplayBase, IBasicVolumeWithFeedback, IBridgeAdvanced, IHasInputs, IRoutingSinkWithSwitchingWithInputPort, IHasPowerControlWithFeedback { public ISelectableItems Inputs { get; private set; } @@ -79,7 +79,7 @@ namespace PepperDash.Essentials.Devices.Common.Displays eRoutingPortConnectionType.Hdmi, "HDMI2", this); var hdmiIn3 = new RoutingInputPort(RoutingPortNames.HdmiIn3, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, "HDMI3", this); - var hdmiIn4 = new RoutingInputPort(RoutingPortNames.ComponentIn, eRoutingSignalType.AudioVideo, + var hdmiIn4 = new RoutingInputPort(RoutingPortNames.HdmiIn4, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, "HDMI4", this); var dpIn = new RoutingInputPort(RoutingPortNames.DisplayPortIn, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.DisplayPort, "DP", this); From c755ecb16cb9780860a21872330ff79a68e06fdd Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 28 May 2024 11:26:25 -0500 Subject: [PATCH 19/24] fix: add correct casing to base touchpanel config --- .../CrestronTouchpanelPropertiesConfig.cs | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/PepperDash.Essentials.Core/Touchpanels/CrestronTouchpanelPropertiesConfig.cs b/src/PepperDash.Essentials.Core/Touchpanels/CrestronTouchpanelPropertiesConfig.cs index 73b66bce..5a42bcd1 100644 --- a/src/PepperDash.Essentials.Core/Touchpanels/CrestronTouchpanelPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Core/Touchpanels/CrestronTouchpanelPropertiesConfig.cs @@ -1,20 +1,49 @@ -namespace PepperDash.Essentials.Core +using Newtonsoft.Json; + +namespace PepperDash.Essentials.Core { public class CrestronTouchpanelPropertiesConfig { + [JsonProperty("ipId")] public string IpId { get; set; } + + [JsonProperty("defaultRoomKey")] public string DefaultRoomKey { get; set; } + + [JsonProperty("roomListKey")] public string RoomListKey { get; set; } + + [JsonProperty("sgdFile")] public string SgdFile { get; set; } + + [JsonProperty("projectName")] public string ProjectName { get; set; } + + [JsonProperty("showVolumeGauge")] public bool ShowVolumeGauge { get; set; } + + [JsonProperty("usesSplashPage")] public bool UsesSplashPage { get; set; } + + [JsonProperty("showDate")] public bool ShowDate { get; set; } + + [JsonProperty("showTime")] public bool ShowTime { get; set; } + + [JsonProperty("setup")] public UiSetupPropertiesConfig Setup { get; set; } + + [JsonProperty("headerStyle")] public string HeaderStyle { get; set; } + + [JsonProperty("includeInFusionRoomHealth")] public bool IncludeInFusionRoomHealth { get; set; } + + [JsonProperty("screenSaverTimeoutMin")] public uint ScreenSaverTimeoutMin { get; set; } + + [JsonProperty("screenSaverMovePositionIntervalMs")] public uint ScreenSaverMovePositionIntervalMs { get; set; } @@ -22,6 +51,7 @@ /// The count of sources that will trigger the "additional" arrows to show on the SRL. /// Defaults to 5 /// + [JsonProperty("sourcesOverflowCount")] public int SourcesOverflowCount { get; set; } public CrestronTouchpanelPropertiesConfig() @@ -49,6 +79,7 @@ /// public class UiSetupPropertiesConfig { + [JsonProperty("isVisible")] public bool IsVisible { get; set; } } } \ No newline at end of file From edc916c9d3446e4f714ffd8e19154919d6d37959 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 28 May 2024 13:28:45 -0500 Subject: [PATCH 20/24] fix: add more json props --- .../Comm and IR/CommFactory.cs | 15 +++++--- .../CrestronTouchpanelPropertiesConfig.cs | 35 ++++++++++--------- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/PepperDash.Essentials.Core/Comm and IR/CommFactory.cs b/src/PepperDash.Essentials.Core/Comm and IR/CommFactory.cs index f54f4bfd..26b29d51 100644 --- a/src/PepperDash.Essentials.Core/Comm and IR/CommFactory.cs +++ b/src/PepperDash.Essentials.Core/Comm and IR/CommFactory.cs @@ -201,23 +201,26 @@ namespace PepperDash.Essentials.Core /// /// /// - public class EssentialsControlPropertiesConfig : - PepperDash.Core.ControlPropertiesConfig + public class EssentialsControlPropertiesConfig : + ControlPropertiesConfig { + [JsonProperty("comParams")] [JsonConverter(typeof(ComSpecJsonConverter))] - public ComPort.ComPortSpec ComParams { get; set; } + public ComPort.ComPortSpec ComParams { get; set; } - public string CresnetId { get; set; } + [JsonProperty("cresnetId")] + public string CresnetId { get; set; } /// /// Attempts to provide uint conversion of string CresnetId /// + [JsonIgnore] public uint CresnetIdInt { get { - try + try { return Convert.ToUInt32(CresnetId, 16); } @@ -228,11 +231,13 @@ namespace PepperDash.Essentials.Core } } + [JsonProperty("infinetId")] public string InfinetId { get; set; } /// /// Attepmts to provide uiont conversion of string InifinetId /// + [JsonIgnore] public uint InfinetIdInt { get diff --git a/src/PepperDash.Essentials.Core/Touchpanels/CrestronTouchpanelPropertiesConfig.cs b/src/PepperDash.Essentials.Core/Touchpanels/CrestronTouchpanelPropertiesConfig.cs index 5a42bcd1..9b6639db 100644 --- a/src/PepperDash.Essentials.Core/Touchpanels/CrestronTouchpanelPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Core/Touchpanels/CrestronTouchpanelPropertiesConfig.cs @@ -4,46 +4,49 @@ namespace PepperDash.Essentials.Core { public class CrestronTouchpanelPropertiesConfig { - [JsonProperty("ipId")] + [JsonProperty("control")] + public EssentialsControlPropertiesConfig ControlProperties { get; set; } + + [JsonProperty("ipId", NullValueHandling = NullValueHandling.Ignore)] public string IpId { get; set; } - [JsonProperty("defaultRoomKey")] + [JsonProperty("defaultRoomKey", NullValueHandling = NullValueHandling.Ignore)] public string DefaultRoomKey { get; set; } - [JsonProperty("roomListKey")] + [JsonProperty("roomListKey", NullValueHandling = NullValueHandling.Ignore)] public string RoomListKey { get; set; } - [JsonProperty("sgdFile")] + [JsonProperty("sgdFile", NullValueHandling = NullValueHandling.Ignore)] public string SgdFile { get; set; } - [JsonProperty("projectName")] + [JsonProperty("projectName", NullValueHandling = NullValueHandling.Ignore)] public string ProjectName { get; set; } - [JsonProperty("showVolumeGauge")] + [JsonProperty("showVolumeGauge", NullValueHandling = NullValueHandling.Ignore)] public bool ShowVolumeGauge { get; set; } - [JsonProperty("usesSplashPage")] + [JsonProperty("usesSplashPage", NullValueHandling = NullValueHandling.Ignore)] public bool UsesSplashPage { get; set; } - [JsonProperty("showDate")] + [JsonProperty("showDate", NullValueHandling = NullValueHandling.Ignore)] public bool ShowDate { get; set; } - [JsonProperty("showTime")] + [JsonProperty("showTime", NullValueHandling = NullValueHandling.Ignore)] public bool ShowTime { get; set; } - [JsonProperty("setup")] + [JsonProperty("setup", NullValueHandling = NullValueHandling.Ignore)] public UiSetupPropertiesConfig Setup { get; set; } - [JsonProperty("headerStyle")] + [JsonProperty("headerStyle", NullValueHandling = NullValueHandling.Ignore)] public string HeaderStyle { get; set; } - [JsonProperty("includeInFusionRoomHealth")] + [JsonProperty("includeInFusionRoomHealth", NullValueHandling = NullValueHandling.Ignore)] public bool IncludeInFusionRoomHealth { get; set; } - [JsonProperty("screenSaverTimeoutMin")] + [JsonProperty("screenSaverTimeoutMin", NullValueHandling = NullValueHandling.Ignore)] public uint ScreenSaverTimeoutMin { get; set; } - [JsonProperty("screenSaverMovePositionIntervalMs")] + [JsonProperty("screenSaverMovePositionIntervalMs", NullValueHandling = NullValueHandling.Ignore)] public uint ScreenSaverMovePositionIntervalMs { get; set; } @@ -51,7 +54,7 @@ namespace PepperDash.Essentials.Core /// The count of sources that will trigger the "additional" arrows to show on the SRL. /// Defaults to 5 /// - [JsonProperty("sourcesOverflowCount")] + [JsonProperty("sourcesOverflowCount", NullValueHandling = NullValueHandling.Ignore)] public int SourcesOverflowCount { get; set; } public CrestronTouchpanelPropertiesConfig() @@ -79,7 +82,7 @@ namespace PepperDash.Essentials.Core /// public class UiSetupPropertiesConfig { - [JsonProperty("isVisible")] + [JsonProperty("isVisible", NullValueHandling = NullValueHandling.Ignore)] public bool IsVisible { get; set; } } } \ No newline at end of file From 00a7b25026390cf15551ffa6ed76518a0d32054c Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 28 May 2024 13:29:03 -0500 Subject: [PATCH 21/24] build: update PD Core --- .../PepperDash.Essentials.Core.csproj | 2 +- .../PepperDash.Essentials.Devices.Common.csproj | 2 +- src/PepperDash.Essentials/PepperDash.Essentials.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj index 1298873d..d8088003 100644 --- a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj +++ b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj @@ -28,7 +28,7 @@ - + diff --git a/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj b/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj index 7391ceed..8d342bb1 100644 --- a/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj +++ b/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj @@ -28,6 +28,6 @@ - + \ No newline at end of file diff --git a/src/PepperDash.Essentials/PepperDash.Essentials.csproj b/src/PepperDash.Essentials/PepperDash.Essentials.csproj index 33ade9bd..dc57fafa 100644 --- a/src/PepperDash.Essentials/PepperDash.Essentials.csproj +++ b/src/PepperDash.Essentials/PepperDash.Essentials.csproj @@ -47,7 +47,7 @@ - + From cc06c7bfd85861b02a8d44333695ee58804441c7 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 28 May 2024 14:43:31 -0500 Subject: [PATCH 22/24] fix: add nullable props where necessary --- .../Comm and IR/ComSpecJsonConverter.cs | 6 ++--- .../Comm and IR/CommFactory.cs | 12 ++++----- .../CrestronTouchpanelPropertiesConfig.cs | 25 +++++++++++-------- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/PepperDash.Essentials.Core/Comm and IR/ComSpecJsonConverter.cs b/src/PepperDash.Essentials.Core/Comm and IR/ComSpecJsonConverter.cs index 62296bd8..bfdccb65 100644 --- a/src/PepperDash.Essentials.Core/Comm and IR/ComSpecJsonConverter.cs +++ b/src/PepperDash.Essentials.Core/Comm and IR/ComSpecJsonConverter.cs @@ -23,12 +23,12 @@ namespace PepperDash.Essentials.Core { public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { - if (objectType == typeof(ComPort.ComPortSpec)) + if (objectType == typeof(ComPort.ComPortSpec?)) { var newSer = new JsonSerializer(); newSer.Converters.Add(new ComSpecPropsJsonConverter()); newSer.ObjectCreationHandling = ObjectCreationHandling.Replace; - return newSer.Deserialize(reader); + return newSer.Deserialize(reader); } return null; } @@ -38,7 +38,7 @@ namespace PepperDash.Essentials.Core /// public override bool CanConvert(Type objectType) { - return objectType == typeof(ComPort.ComPortSpec); + return objectType == typeof(ComPort.ComPortSpec?); } public override bool CanRead { get { return true; } } diff --git a/src/PepperDash.Essentials.Core/Comm and IR/CommFactory.cs b/src/PepperDash.Essentials.Core/Comm and IR/CommFactory.cs index 26b29d51..8fa4076a 100644 --- a/src/PepperDash.Essentials.Core/Comm and IR/CommFactory.cs +++ b/src/PepperDash.Essentials.Core/Comm and IR/CommFactory.cs @@ -51,7 +51,7 @@ namespace PepperDash.Essentials.Core switch (controlConfig.Method) { case eControlMethod.Com: - comm = new ComPortController(deviceConfig.Key + "-com", GetComPort, controlConfig.ComParams, controlConfig); + comm = new ComPortController(deviceConfig.Key + "-com", GetComPort, controlConfig.ComParams.Value, controlConfig); break; case eControlMethod.Cec: comm = new CecPortController(deviceConfig.Key + "-cec", GetCecPort, controlConfig); @@ -115,7 +115,7 @@ namespace PepperDash.Essentials.Core var comPar = config.ComParams; var dev = GetIComPortsDeviceFromManagedDevice(config.ControlPortDevKey); if (dev != null && config.ControlPortNumber <= dev.NumberOfComPorts) - return dev.ComPorts[config.ControlPortNumber]; + return dev.ComPorts[config.ControlPortNumber.Value]; Debug.LogMessage(LogEventLevel.Information, "GetComPort: Device '{0}' does not have com port {1}", config.ControlPortDevKey, config.ControlPortNumber); return null; } @@ -205,11 +205,11 @@ namespace PepperDash.Essentials.Core ControlPropertiesConfig { - [JsonProperty("comParams")] + [JsonProperty("comParams", NullValueHandling = NullValueHandling.Ignore)] [JsonConverter(typeof(ComSpecJsonConverter))] - public ComPort.ComPortSpec ComParams { get; set; } + public ComPort.ComPortSpec? ComParams { get; set; } - [JsonProperty("cresnetId")] + [JsonProperty("cresnetId", NullValueHandling = NullValueHandling.Ignore)] public string CresnetId { get; set; } /// @@ -231,7 +231,7 @@ namespace PepperDash.Essentials.Core } } - [JsonProperty("infinetId")] + [JsonProperty("infinetId", NullValueHandling = NullValueHandling.Ignore)] public string InfinetId { get; set; } /// diff --git a/src/PepperDash.Essentials.Core/Touchpanels/CrestronTouchpanelPropertiesConfig.cs b/src/PepperDash.Essentials.Core/Touchpanels/CrestronTouchpanelPropertiesConfig.cs index 9b6639db..aa4dac6d 100644 --- a/src/PepperDash.Essentials.Core/Touchpanels/CrestronTouchpanelPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Core/Touchpanels/CrestronTouchpanelPropertiesConfig.cs @@ -23,16 +23,16 @@ namespace PepperDash.Essentials.Core public string ProjectName { get; set; } [JsonProperty("showVolumeGauge", NullValueHandling = NullValueHandling.Ignore)] - public bool ShowVolumeGauge { get; set; } + public bool? ShowVolumeGauge { get; set; } [JsonProperty("usesSplashPage", NullValueHandling = NullValueHandling.Ignore)] - public bool UsesSplashPage { get; set; } + public bool? UsesSplashPage { get; set; } [JsonProperty("showDate", NullValueHandling = NullValueHandling.Ignore)] - public bool ShowDate { get; set; } + public bool? ShowDate { get; set; } [JsonProperty("showTime", NullValueHandling = NullValueHandling.Ignore)] - public bool ShowTime { get; set; } + public bool? ShowTime { get; set; } [JsonProperty("setup", NullValueHandling = NullValueHandling.Ignore)] public UiSetupPropertiesConfig Setup { get; set; } @@ -41,13 +41,13 @@ namespace PepperDash.Essentials.Core public string HeaderStyle { get; set; } [JsonProperty("includeInFusionRoomHealth", NullValueHandling = NullValueHandling.Ignore)] - public bool IncludeInFusionRoomHealth { get; set; } + public bool? IncludeInFusionRoomHealth { get; set; } [JsonProperty("screenSaverTimeoutMin", NullValueHandling = NullValueHandling.Ignore)] - public uint ScreenSaverTimeoutMin { get; set; } + public uint? ScreenSaverTimeoutMin { get; set; } [JsonProperty("screenSaverMovePositionIntervalMs", NullValueHandling = NullValueHandling.Ignore)] - public uint ScreenSaverMovePositionIntervalMs { get; set; } + public uint? ScreenSaverMovePositionIntervalMs { get; set; } /// @@ -55,17 +55,20 @@ namespace PepperDash.Essentials.Core /// Defaults to 5 /// [JsonProperty("sourcesOverflowCount", NullValueHandling = NullValueHandling.Ignore)] - public int SourcesOverflowCount { get; set; } + public int? SourcesOverflowCount { get; set; } - public CrestronTouchpanelPropertiesConfig() + public CrestronTouchpanelPropertiesConfig() : this(false) { } + + public CrestronTouchpanelPropertiesConfig(bool setDefaultValues = false) { + if(!setDefaultValues) { return; } SourcesOverflowCount = 5; - HeaderStyle = CrestronTouchpanelPropertiesConfig.Habanero; + HeaderStyle = Habanero; // Default values ScreenSaverTimeoutMin = 5; ScreenSaverMovePositionIntervalMs = 15000; - } + } /// /// "habanero" From a3c1572a77259e52abb5089f65e49584b875a4c3 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 28 May 2024 14:43:39 -0500 Subject: [PATCH 23/24] build: update PD Core --- .../PepperDash.Essentials.Core.csproj | 2 +- .../PepperDash.Essentials.Devices.Common.csproj | 2 +- src/PepperDash.Essentials/PepperDash.Essentials.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj index d8088003..8ae0c0af 100644 --- a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj +++ b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj @@ -28,7 +28,7 @@ - + diff --git a/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj b/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj index 8d342bb1..a591961a 100644 --- a/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj +++ b/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj @@ -28,6 +28,6 @@ - + \ No newline at end of file diff --git a/src/PepperDash.Essentials/PepperDash.Essentials.csproj b/src/PepperDash.Essentials/PepperDash.Essentials.csproj index dc57fafa..9ed182b3 100644 --- a/src/PepperDash.Essentials/PepperDash.Essentials.csproj +++ b/src/PepperDash.Essentials/PepperDash.Essentials.csproj @@ -47,7 +47,7 @@ - + From 0bef5d4b77dd3d4d359bb3439908acf17c36d723 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 28 May 2024 14:57:35 -0500 Subject: [PATCH 24/24] build: update PD Core --- .../PepperDash.Essentials.Core.csproj | 2 +- .../PepperDash.Essentials.Devices.Common.csproj | 2 +- src/PepperDash.Essentials/PepperDash.Essentials.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj index 8ae0c0af..02d13f7d 100644 --- a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj +++ b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj @@ -28,7 +28,7 @@ - + diff --git a/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj b/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj index a591961a..b1abcdb0 100644 --- a/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj +++ b/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj @@ -28,6 +28,6 @@ - + \ No newline at end of file diff --git a/src/PepperDash.Essentials/PepperDash.Essentials.csproj b/src/PepperDash.Essentials/PepperDash.Essentials.csproj index 9ed182b3..0aada6d1 100644 --- a/src/PepperDash.Essentials/PepperDash.Essentials.csproj +++ b/src/PepperDash.Essentials/PepperDash.Essentials.csproj @@ -47,7 +47,7 @@ - +