fix: pre-built routes now respect source ports for finding routes

This commit is contained in:
Andrew Welker 2026-04-17 10:27:54 -05:00
parent db14a614bc
commit 2197dc489d
5 changed files with 94 additions and 66 deletions

View file

@ -3,10 +3,8 @@ using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using Crestron.SimplSharpPro.Keypads;
using PepperDash.Essentials.Core.Queues; using PepperDash.Essentials.Core.Queues;
using PepperDash.Essentials.Core.Routing; using PepperDash.Essentials.Core.Routing;
using Serilog.Events;
using Debug = PepperDash.Core.Debug; using Debug = PepperDash.Core.Debug;
@ -69,7 +67,7 @@ namespace PepperDash.Essentials.Core
{ {
try try
{ {
Debug.LogMessage(LogEventLevel.Information, "Indexing TieLines for faster route discovery"); Debug.LogInformation("Indexing TieLines for faster route discovery");
_tieLinesByDestination = TieLineCollection.Default _tieLinesByDestination = TieLineCollection.Default
.GroupBy(t => t.DestinationPort.ParentDevice.Key) .GroupBy(t => t.DestinationPort.ParentDevice.Key)
@ -79,8 +77,8 @@ namespace PepperDash.Essentials.Core
.GroupBy(t => t.SourcePort.ParentDevice.Key) .GroupBy(t => t.SourcePort.ParentDevice.Key)
.ToDictionary(g => g.Key, g => g.ToList()); .ToDictionary(g => g.Key, g => g.ToList());
Debug.LogMessage(LogEventLevel.Information, "TieLine indexing complete. {0} destination keys, {1} source keys", Debug.LogInformation("TieLine indexing complete. {0} destination keys, {1} source keys",
null, _tieLinesByDestination.Count, _tieLinesBySource.Count); _tieLinesByDestination.Count, _tieLinesBySource.Count);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -128,11 +126,13 @@ namespace PepperDash.Essentials.Core
/// </summary> /// </summary>
/// <param name="sourceKey">Source device key</param> /// <param name="sourceKey">Source device key</param>
/// <param name="destKey">Destination device key</param> /// <param name="destKey">Destination device key</param>
/// <param name="sourcePortKey">Source port key</param>
/// <param name="destinationPortKey">Destination port key</param>
/// <param name="type">Signal type</param> /// <param name="type">Signal type</param>
/// <returns>Cache key string</returns> /// <returns>Cache key string</returns>
private static string GetRouteKey(string sourceKey, string destKey, eRoutingSignalType type) private static string GetRouteKey(string sourceKey, string destKey, string sourcePortKey, string destinationPortKey, eRoutingSignalType type)
{ {
return string.Format("{0}|{1}|{2}", sourceKey, destKey, type); return $"{sourceKey}|{destKey}|{sourcePortKey}|{destinationPortKey}|{type}";
} }
/// <summary> /// <summary>
@ -141,7 +141,7 @@ namespace PepperDash.Essentials.Core
public static void ClearImpossibleRoutesCache() public static void ClearImpossibleRoutesCache()
{ {
_impossibleRoutes.Clear(); _impossibleRoutes.Clear();
Debug.LogMessage(LogEventLevel.Information, "Impossible routes cache cleared"); Debug.LogInformation("Impossible routes cache cleared");
} }
/// <summary> /// <summary>
@ -153,7 +153,7 @@ namespace PepperDash.Essentials.Core
{ {
// Remove this line before committing!!!!! // Remove this line before committing!!!!!
var frame = new StackFrame(1, true); var frame = new StackFrame(1, true);
Debug.LogMessage(LogEventLevel.Information, "ReleaseAndMakeRoute Called from {method} with params {destinationKey}:{sourceKey}:{signalType}:{destinationPortKey}:{sourcePortKey}", frame.GetMethod().Name, destination.Key, source.Key, signalType.ToString(), destinationPortKey, sourcePortKey); Debug.LogInformation("ReleaseAndMakeRoute Called from {method} with params {destinationKey}:{sourceKey}:{signalType}:{destinationPortKey}:{sourcePortKey}", frame.GetMethod().Name, destination.Key, source.Key, signalType.ToString(), destinationPortKey, sourcePortKey);
var inputPort = string.IsNullOrEmpty(destinationPortKey) ? null : destination.InputPorts.FirstOrDefault(p => p.Key == destinationPortKey); var inputPort = string.IsNullOrEmpty(destinationPortKey) ? null : destination.InputPorts.FirstOrDefault(p => p.Key == destinationPortKey);
var outputPort = string.IsNullOrEmpty(sourcePortKey) ? null : source.OutputPorts.FirstOrDefault(p => p.Key == sourcePortKey); var outputPort = string.IsNullOrEmpty(sourcePortKey) ? null : source.OutputPorts.FirstOrDefault(p => p.Key == sourcePortKey);
@ -211,13 +211,13 @@ namespace PepperDash.Essentials.Core
/// <param name="destinationKey">destination device key</param> /// <param name="destinationKey">destination device key</param>
public static void RemoveRouteRequestForDestination(string destinationKey) public static void RemoveRouteRequestForDestination(string destinationKey)
{ {
Debug.LogMessage(LogEventLevel.Information, "Removing route request for {destination}", null, destinationKey); Debug.LogInformation("Removing route request for {destination}", destinationKey);
var result = RouteRequests.Remove(destinationKey); var result = RouteRequests.Remove(destinationKey);
var messageTemplate = result ? "Route Request for {destination} removed" : "Route Request for {destination} not found"; var messageTemplate = result ? "Route Request for {destination} removed" : "Route Request for {destination} not found";
Debug.LogMessage(LogEventLevel.Information, messageTemplate, null, destinationKey); Debug.LogInformation(messageTemplate, destinationKey);
} }
/// <summary> /// <summary>
@ -233,8 +233,8 @@ namespace PepperDash.Essentials.Core
if (!signalType.HasFlag(eRoutingSignalType.AudioVideo) && if (!signalType.HasFlag(eRoutingSignalType.AudioVideo) &&
!(signalType.HasFlag(eRoutingSignalType.Video) && signalType.HasFlag(eRoutingSignalType.SecondaryAudio))) !(signalType.HasFlag(eRoutingSignalType.Video) && signalType.HasFlag(eRoutingSignalType.SecondaryAudio)))
{ {
var singleTypeRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, signalType); var singleTypeRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, sourcePort, signalType);
Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {sourceKey} of type {type}", destination, source.Key, signalType); Debug.LogDebug(destination, "Attempting to build source route from {sourceKey} of type {type}", source.Key, signalType);
if (!destination.GetRouteToSource(source, null, null, signalType, 0, singleTypeRouteDescriptor, destinationPort, sourcePort)) if (!destination.GetRouteToSource(source, null, null, signalType, 0, singleTypeRouteDescriptor, destinationPort, sourcePort))
singleTypeRouteDescriptor = null; singleTypeRouteDescriptor = null;
@ -242,46 +242,46 @@ namespace PepperDash.Essentials.Core
var routes = singleTypeRouteDescriptor?.Routes ?? new List<RouteSwitchDescriptor>(); var routes = singleTypeRouteDescriptor?.Routes ?? new List<RouteSwitchDescriptor>();
foreach (var route in routes) foreach (var route in routes)
{ {
Debug.LogMessage(LogEventLevel.Verbose, "Route for device: {route}", destination, route.ToString()); Debug.LogVerbose(destination, "Route for device: {route}", route.ToString());
} }
return (singleTypeRouteDescriptor, null); return (singleTypeRouteDescriptor, null);
} }
// otherwise, audioVideo needs to be handled as two steps. // otherwise, audioVideo needs to be handled as two steps.
Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {destinationKey} to {sourceKey} of type {type}", destination, source.Key, signalType); Debug.LogDebug(destination, "Attempting to build source route from {destinationKey} to {sourceKey} of type {type}", source.Key, signalType);
RouteDescriptor audioRouteDescriptor; RouteDescriptor audioRouteDescriptor;
if (signalType.HasFlag(eRoutingSignalType.SecondaryAudio)) if (signalType.HasFlag(eRoutingSignalType.SecondaryAudio))
{ {
audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.SecondaryAudio); audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, sourcePort, eRoutingSignalType.SecondaryAudio);
} }
else else
{ {
audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.Audio); audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, sourcePort, eRoutingSignalType.Audio);
} }
var audioSuccess = destination.GetRouteToSource(source, null, null, signalType.HasFlag(eRoutingSignalType.SecondaryAudio) ? eRoutingSignalType.SecondaryAudio : eRoutingSignalType.Audio, 0, audioRouteDescriptor, destinationPort, sourcePort); var audioSuccess = destination.GetRouteToSource(source, null, null, signalType.HasFlag(eRoutingSignalType.SecondaryAudio) ? eRoutingSignalType.SecondaryAudio : eRoutingSignalType.Audio, 0, audioRouteDescriptor, destinationPort, sourcePort);
if (!audioSuccess) if (!audioSuccess)
Debug.LogMessage(LogEventLevel.Debug, "Cannot find audio route to {0}", destination, source.Key); Debug.LogDebug(destination, "Cannot find audio route to {0}", source.Key);
var videoRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.Video); var videoRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, sourcePort, eRoutingSignalType.Video);
var videoSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Video, 0, videoRouteDescriptor, destinationPort, sourcePort); var videoSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Video, 0, videoRouteDescriptor, destinationPort, sourcePort);
if (!videoSuccess) if (!videoSuccess)
Debug.LogMessage(LogEventLevel.Debug, "Cannot find video route to {0}", destination, source.Key); Debug.LogDebug(destination, "Cannot find video route to {0}", source.Key);
foreach (var route in audioRouteDescriptor.Routes) foreach (var route in audioRouteDescriptor.Routes)
{ {
Debug.LogMessage(LogEventLevel.Verbose, "Audio route for device: {route}", destination, route.ToString()); Debug.LogVerbose(destination, "Audio route for device: {route}", route.ToString());
} }
foreach (var route in videoRouteDescriptor.Routes) foreach (var route in videoRouteDescriptor.Routes)
{ {
Debug.LogMessage(LogEventLevel.Verbose, "Video route for device: {route}", destination, route.ToString()); Debug.LogVerbose(destination, "Video route for device: {route}", route.ToString());
} }
@ -306,8 +306,8 @@ namespace PepperDash.Essentials.Core
{ {
if (destination == null) throw new ArgumentNullException(nameof(destination)); if (destination == null) throw new ArgumentNullException(nameof(destination));
if (source == null) throw new ArgumentNullException(nameof(source)); if (source == null) throw new ArgumentNullException(nameof(source));
if (destinationPort == null) Debug.LogMessage(LogEventLevel.Information, "Destination port is null"); if (destinationPort == null) Debug.LogDebug("Destination port is null");
if (sourcePort == null) Debug.LogMessage(LogEventLevel.Information, "Source port is null"); if (sourcePort == null) Debug.LogDebug("Source port is null");
var routeRequest = new RouteRequest var routeRequest = new RouteRequest
{ {
@ -329,7 +329,7 @@ namespace PepperDash.Essentials.Core
RouteRequests[destination.Key] = routeRequest; RouteRequests[destination.Key] = routeRequest;
Debug.LogMessage(LogEventLevel.Information, "Device: {destination} is cooling down and already has a routing request stored. Storing new route request to route to source key: {sourceKey}", null, destination.Key, routeRequest.Source.Key); Debug.LogInformation("Device: {destination} is cooling down and already has a routing request stored. Storing new route request to route to source key: {sourceKey}", destination.Key, routeRequest.Source.Key);
return; return;
} }
@ -341,7 +341,7 @@ namespace PepperDash.Essentials.Core
RouteRequests.Add(destination.Key, routeRequest); RouteRequests.Add(destination.Key, routeRequest);
Debug.LogMessage(LogEventLevel.Information, "Device: {destination} is cooling down. Storing route request to route to source key: {sourceKey}", null, destination.Key, routeRequest.Source.Key); Debug.LogInformation("Device: {destination} is cooling down. Storing route request to route to source key: {sourceKey}", destination.Key, routeRequest.Source.Key);
return; return;
} }
@ -353,7 +353,7 @@ namespace PepperDash.Essentials.Core
RouteRequests.Remove(destination.Key); RouteRequests.Remove(destination.Key);
Debug.LogMessage(LogEventLevel.Information, "Device: {destination} is NOT cooling down. Removing stored route request and routing to source key: {sourceKey}", null, destination.Key, routeRequest.Source.Key); Debug.LogInformation("Device: {destination} is NOT cooling down. Removing stored route request and routing to source key: {sourceKey}", destination.Key, routeRequest.Source.Key);
} }
routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination, destinationPort?.Key ?? string.Empty, false)); routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination, destinationPort?.Key ?? string.Empty, false));
@ -469,7 +469,8 @@ namespace PepperDash.Essentials.Core
audioOrSingleRoute = audioCollection.Descriptors.FirstOrDefault(d => audioOrSingleRoute = audioCollection.Descriptors.FirstOrDefault(d =>
d.Source.Key == request.Source.Key && d.Source.Key == request.Source.Key &&
d.Destination.Key == request.Destination.Key && d.Destination.Key == request.Destination.Key &&
(request.DestinationPort == null || d.InputPort?.Key == request.DestinationPort.Key)); (request.DestinationPort == null || d.InputPort?.Key == request.DestinationPort.Key) &&
(request.SourcePort == null || d.OutputPort?.Key == request.SourcePort.Key));
} }
if (RouteDescriptors.TryGetValue(eRoutingSignalType.Video, out RouteDescriptorCollection videoCollection)) if (RouteDescriptors.TryGetValue(eRoutingSignalType.Video, out RouteDescriptorCollection videoCollection))
@ -477,7 +478,8 @@ namespace PepperDash.Essentials.Core
videoRoute = videoCollection.Descriptors.FirstOrDefault(d => videoRoute = videoCollection.Descriptors.FirstOrDefault(d =>
d.Source.Key == request.Source.Key && d.Source.Key == request.Source.Key &&
d.Destination.Key == request.Destination.Key && d.Destination.Key == request.Destination.Key &&
(request.DestinationPort == null || d.InputPort?.Key == request.DestinationPort.Key)); (request.DestinationPort == null || d.InputPort?.Key == request.DestinationPort.Key) &&
(request.SourcePort == null || d.OutputPort?.Key == request.SourcePort.Key));
} }
} }
else else
@ -492,14 +494,15 @@ namespace PepperDash.Essentials.Core
audioOrSingleRoute = collection.Descriptors.FirstOrDefault(d => audioOrSingleRoute = collection.Descriptors.FirstOrDefault(d =>
d.Source.Key == request.Source.Key && d.Source.Key == request.Source.Key &&
d.Destination.Key == request.Destination.Key && d.Destination.Key == request.Destination.Key &&
(request.DestinationPort == null || d.InputPort?.Key == request.DestinationPort.Key)); (request.DestinationPort == null || d.InputPort?.Key == request.DestinationPort.Key) &&
(request.SourcePort == null || d.OutputPort?.Key == request.SourcePort.Key));
} }
} }
// If no pre-loaded route found, build it dynamically // If no pre-loaded route found, build it dynamically
if (audioOrSingleRoute == null && videoRoute == null) if (audioOrSingleRoute == null && videoRoute == null)
{ {
Debug.LogMessage(LogEventLevel.Debug, "No pre-loaded route found, building dynamically", request.Destination); Debug.LogDebug(request.Destination, "No pre-loaded route found, building dynamically");
(audioOrSingleRoute, videoRoute) = request.Destination.GetRouteToSource(request.Source, request.SignalType, request.DestinationPort, request.SourcePort); (audioOrSingleRoute, videoRoute) = request.Destination.GetRouteToSource(request.Source, request.SignalType, request.DestinationPort, request.SourcePort);
} }
@ -513,14 +516,15 @@ namespace PepperDash.Essentials.Core
RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(videoRoute); RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(videoRoute);
} }
Debug.LogMessage(LogEventLevel.Verbose, "Executing full route", request.Destination); Debug.LogVerbose(request.Destination, "Executing full route");
audioOrSingleRoute.ExecuteRoutes(); audioOrSingleRoute.ExecuteRoutes();
videoRoute?.ExecuteRoutes(); videoRoute?.ExecuteRoutes();
} }
catch (Exception ex) catch (Exception ex)
{ {
Debug.LogMessage(ex, "Exception Running Route Request {request}", null, request); Debug.LogError("Exception Running Route Request {request}: {exception}", request, ex.Message);
Debug.LogDebug(ex, "Stack Trace: ");
} }
} }
@ -534,7 +538,7 @@ namespace PepperDash.Essentials.Core
{ {
try try
{ {
Debug.LogMessage(LogEventLevel.Information, "Release route for '{destination}':'{inputPortKey}'", destination?.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); Debug.LogInformation(destination, "Release route for '{destination}':'{inputPortKey}'", destination?.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey);
if (RouteRequests.TryGetValue(destination.Key, out RouteRequest existingRequest) && destination is IWarmingCooling) if (RouteRequests.TryGetValue(destination.Key, out RouteRequest existingRequest) && destination is IWarmingCooling)
{ {
@ -548,13 +552,14 @@ namespace PepperDash.Essentials.Core
var current = RouteDescriptorCollection.DefaultCollection.RemoveRouteDescriptor(destination, inputPortKey); var current = RouteDescriptorCollection.DefaultCollection.RemoveRouteDescriptor(destination, inputPortKey);
if (current != null) if (current != null)
{ {
Debug.LogMessage(LogEventLevel.Information, "Releasing current route: {0}", destination, current.Source.Key); Debug.LogInformation(destination, "Releasing current route: {0}", current.Source.Key);
current.ReleaseRoutes(clearRoute); current.ReleaseRoutes(clearRoute);
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Debug.LogMessage(ex, "Exception releasing route for '{destination}':'{inputPortKey}'", null, destination?.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); Debug.LogError("Exception releasing route for '{destination}':'{inputPortKey}': {exception}", destination?.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey, ex.Message);
Debug.LogDebug(ex, "Stack Trace: ");
} }
} }
@ -580,14 +585,14 @@ namespace PepperDash.Essentials.Core
cycle++; cycle++;
// Check if this route has already been determined to be impossible // Check if this route has already been determined to be impossible
var routeKey = GetRouteKey(source.Key, destination.Key, signalType); var routeKey = GetRouteKey(source.Key, destination.Key, sourcePort?.Key ?? "auto", destinationPort?.Key ?? "auto", signalType);
if (_impossibleRoutes.ContainsKey(routeKey)) if (_impossibleRoutes.ContainsKey(routeKey))
{ {
Debug.LogMessage(LogEventLevel.Verbose, "Route {0} is cached as impossible, skipping", null, routeKey); Debug.LogVerbose("Route {0} is cached as impossible, skipping", routeKey);
return false; return false;
} }
Debug.LogMessage(LogEventLevel.Verbose, "GetRouteToSource: {cycle} {sourceKey}:{sourcePortKey}--> {destinationKey}:{destinationPortKey} {type}", null, cycle, source.Key, sourcePort?.Key ?? "auto", destination.Key, destinationPort?.Key ?? "auto", signalType.ToString()); Debug.LogVerbose("GetRouteToSource: {cycle} {sourceKey}:{sourcePortKey}--> {destinationKey}:{destinationPortKey} {type}", null, cycle, source.Key, sourcePort?.Key ?? "auto", destination.Key, destinationPort?.Key ?? "auto", signalType.ToString());
RoutingInputPort goodInputPort = null; RoutingInputPort goodInputPort = null;
@ -635,7 +640,7 @@ namespace PepperDash.Essentials.Core
} }
else // no direct-connect. Walk back devices. else // no direct-connect. Walk back devices.
{ {
Debug.LogMessage(LogEventLevel.Verbose, "is not directly connected to {sourceKey}. Walking down tie lines", destination, source.Key); Debug.LogVerbose(destination, "is not directly connected to {sourceKey}. Walking down tie lines", source.Key);
// No direct tie? Run back out on the inputs' attached devices... // No direct tie? Run back out on the inputs' attached devices...
// Only the ones that are routing devices // Only the ones that are routing devices
@ -653,13 +658,13 @@ namespace PepperDash.Essentials.Core
// Check if this previous device has already been walked // Check if this previous device has already been walked
if (alreadyCheckedDevices.Contains(midpointDevice)) if (alreadyCheckedDevices.Contains(midpointDevice))
{ {
Debug.LogMessage(LogEventLevel.Verbose, "Skipping input {midpointDeviceKey} on {destinationKey}, this was already checked", destination, midpointDevice.Key, destination.Key); Debug.LogVerbose(destination, "Skipping input {midpointDeviceKey} on {destinationKey}, this was already checked", midpointDevice.Key, destination.Key);
continue; continue;
} }
var midpointOutputPort = tieLine.SourcePort; var midpointOutputPort = tieLine.SourcePort;
Debug.LogMessage(LogEventLevel.Verbose, "Trying to find route on {midpointDeviceKey}", destination, midpointDevice.Key); Debug.LogVerbose(destination, "Trying to find route on {midpointDeviceKey}", midpointDevice.Key);
// haven't seen this device yet. Do it. Pass the output port to the next // haven't seen this device yet. Do it. Pass the output port to the next
// level to enable switching on success // level to enable switching on success
@ -668,9 +673,9 @@ namespace PepperDash.Essentials.Core
if (upstreamRoutingSuccess) if (upstreamRoutingSuccess)
{ {
Debug.LogMessage(LogEventLevel.Verbose, "Upstream device route found", destination); Debug.LogVerbose(destination, "Upstream device route found");
Debug.LogMessage(LogEventLevel.Verbose, "Route found on {midpointDeviceKey}", destination, midpointDevice.Key); Debug.LogVerbose(destination, "Route found on {midpointDeviceKey}", midpointDevice.Key);
Debug.LogMessage(LogEventLevel.Verbose, "TieLine: SourcePort: {SourcePort} DestinationPort: {DestinationPort}", destination, tieLine.SourcePort, tieLine.DestinationPort); Debug.LogVerbose(destination, "TieLine: SourcePort: {SourcePort} DestinationPort: {DestinationPort}", tieLine.SourcePort, tieLine.DestinationPort);
goodInputPort = tieLine.DestinationPort; goodInputPort = tieLine.DestinationPort;
break; // Stop looping the inputs in this cycle break; // Stop looping the inputs in this cycle
} }
@ -680,7 +685,7 @@ namespace PepperDash.Essentials.Core
if (goodInputPort == null) if (goodInputPort == null)
{ {
Debug.LogMessage(LogEventLevel.Verbose, "No route found to {0}", destination, source.Key); Debug.LogVerbose(destination, "No route found to {0}", source.Key);
// Cache this as an impossible route // Cache this as an impossible route
_impossibleRoutes.TryAdd(routeKey, 0); _impossibleRoutes.TryAdd(routeKey, 0);
@ -700,7 +705,7 @@ namespace PepperDash.Essentials.Core
routeTable.Routes.Add(new RouteSwitchDescriptor(outputPortToUse, goodInputPort)); routeTable.Routes.Add(new RouteSwitchDescriptor(outputPortToUse, goodInputPort));
} }
else // device is merely IRoutingInputOutputs else // device is merely IRoutingInputOutputs
Debug.LogMessage(LogEventLevel.Verbose, "No routing. Passthrough device", destination); Debug.LogVerbose(destination, "No routing. Passthrough device");
return true; return true;
} }

View file

@ -20,22 +20,27 @@ namespace PepperDash.Essentials.Core
public IRoutingInputs Destination { get; private set; } public IRoutingInputs Destination { get; private set; }
/// <summary> /// <summary>
/// Gets or sets the InputPort /// The InputPort on the destination device for this route, if applicable. May be null if the route is not for a specific input port.
/// </summary> /// </summary>
public RoutingInputPort InputPort { get; private set; } public RoutingInputPort InputPort { get; private set; }
/// <summary> /// <summary>
/// Gets or sets the Source /// Gets the source device (sink or midpoint) for the route.
/// </summary> /// </summary>
public IRoutingOutputs Source { get; private set; } public IRoutingOutputs Source { get; private set; }
/// <summary> /// <summary>
/// Gets or sets the SignalType /// Gets the OutputPort on the source device for this route, if applicable. May be null if the route is not for a specific output port.
/// </summary>
public RoutingOutputPort OutputPort { get; private set; }
/// <summary>
/// Gets the signal type for this route.
/// </summary> /// </summary>
public eRoutingSignalType SignalType { get; private set; } public eRoutingSignalType SignalType { get; private set; }
/// <summary> /// <summary>
/// Gets or sets the Routes /// Gets the collection of route switch descriptors for this route.
/// </summary> /// </summary>
public List<RouteSwitchDescriptor> Routes { get; private set; } public List<RouteSwitchDescriptor> Routes { get; private set; }
@ -56,11 +61,24 @@ namespace PepperDash.Essentials.Core
/// <param name="destination">The destination device.</param> /// <param name="destination">The destination device.</param>
/// <param name="inputPort">The destination input port (optional).</param> /// <param name="inputPort">The destination input port (optional).</param>
/// <param name="signalType">The signal type for this route.</param> /// <param name="signalType">The signal type for this route.</param>
public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, RoutingInputPort inputPort, eRoutingSignalType signalType) public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, RoutingInputPort inputPort, eRoutingSignalType signalType) : this(source, destination, inputPort, null, signalType)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="RouteDescriptor"/> class for a route with specific destination input and source output ports.
/// </summary>
/// <param name="source"></param>
/// <param name="destination"></param>
/// <param name="inputPort"></param>
/// <param name="outputPort"></param>
/// <param name="signalType"></param>
public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, RoutingInputPort inputPort, RoutingOutputPort outputPort, eRoutingSignalType signalType)
{ {
Destination = destination; Destination = destination;
InputPort = inputPort; InputPort = inputPort;
Source = source; Source = source;
OutputPort = outputPort;
SignalType = signalType; SignalType = signalType;
Routes = new List<RouteSwitchDescriptor>(); Routes = new List<RouteSwitchDescriptor>();
} }
@ -72,7 +90,7 @@ namespace PepperDash.Essentials.Core
{ {
foreach (var route in Routes) foreach (var route in Routes)
{ {
Debug.LogMessage(LogEventLevel.Verbose, "ExecuteRoutes: {0}", null, route.ToString()); Debug.LogVerbose("ExecuteRoutes: {0}", route.ToString());
if (route.SwitchingDevice is IRoutingSinkWithSwitching sink) if (route.SwitchingDevice is IRoutingSinkWithSwitching sink)
{ {
@ -86,7 +104,7 @@ namespace PepperDash.Essentials.Core
route.OutputPort.InUseTracker.AddUser(Destination, "destination-" + 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); Debug.LogVerbose("Output port {0} routing. Count={1}", route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue);
} }
} }
} }
@ -112,6 +130,7 @@ namespace PepperDash.Essentials.Core
catch (Exception e) catch (Exception e)
{ {
Debug.LogError("Error executing switch: {exception}", e.Message); Debug.LogError("Error executing switch: {exception}", e.Message);
Debug.LogDebug(e, "Stack Trace: ");
} }
} }
@ -123,11 +142,11 @@ namespace PepperDash.Essentials.Core
if (route.OutputPort.InUseTracker != null) if (route.OutputPort.InUseTracker != null)
{ {
route.OutputPort.InUseTracker.RemoveUser(Destination, "destination-" + SignalType); 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); Debug.LogVerbose("Port {0} releasing. Count={1}", route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue);
} }
else else
{ {
Debug.LogMessage(LogEventLevel.Error, "InUseTracker is null for OutputPort {0}", null, route.OutputPort.Key); Debug.LogVerbose("InUseTracker is null for OutputPort {0}", route.OutputPort.Key);
} }
} }
} }

View file

@ -51,20 +51,25 @@ namespace PepperDash.Essentials.Core
t.Destination == descriptor.Destination && t.Destination == descriptor.Destination &&
t.SignalType == descriptor.SignalType && t.SignalType == descriptor.SignalType &&
((t.InputPort == null && descriptor.InputPort == null) || ((t.InputPort == null && descriptor.InputPort == null) ||
(t.InputPort != null && descriptor.InputPort != null && t.InputPort.Key == descriptor.InputPort.Key))); (t.InputPort != null && descriptor.InputPort != null && t.InputPort.Key == descriptor.InputPort.Key)) &&
((t.OutputPort == null && descriptor.OutputPort == null) ||
(t.OutputPort != null && descriptor.OutputPort != null && t.OutputPort.Key == descriptor.OutputPort.Key)));
if (existingRoute != null) if (existingRoute != null)
{ {
Debug.LogMessage(LogEventLevel.Information, descriptor.Destination, Debug.LogInformation(descriptor.Destination,
"Route from {0} to {1}:{2} ({3}) already exists in this collection", "Route from {source}:{outputPort} to {destination}:{inputPort} ({signalType}) already exists in this collection",
descriptor?.Source?.Key, descriptor?.Source?.Key,
descriptor?.OutputPort?.Key ?? "auto",
descriptor?.Destination?.Key, descriptor?.Destination?.Key,
descriptor?.InputPort?.Key ?? "auto", descriptor?.InputPort?.Key ?? "auto",
descriptor?.SignalType); descriptor?.SignalType
);
return; return;
} }
Debug.LogMessage(LogEventLevel.Verbose, "Adding route descriptor: {0} -> {1}:{2} ({3})", Debug.LogVerbose("Adding route descriptor: {source}:{outputPort} -> {destination}:{inputPort} ({signalType})",
descriptor?.Source?.Key, descriptor?.Source?.Key,
descriptor?.OutputPort?.Key ?? "auto",
descriptor?.Destination?.Key, descriptor?.Destination?.Key,
descriptor?.InputPort?.Key ?? "auto", descriptor?.InputPort?.Key ?? "auto",
descriptor?.SignalType); descriptor?.SignalType);

View file

@ -257,7 +257,7 @@ namespace PepperDash.Essentials.Core.Web
} }
/// <summary> /// <summary>
/// Print the available pahts /// Print the available paths
/// </summary> /// </summary>
/// <example> /// <example>
/// http(s)://{ipaddress}/cws/{basePath} /// http(s)://{ipaddress}/cws/{basePath}

View file

@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.IO.Compression; using System.IO.Compression;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
@ -462,7 +461,7 @@ namespace PepperDash.Essentials
{ {
try try
{ {
if (args.Contains("?")) if (!string.IsNullOrEmpty(args) && args.Contains("?"))
{ {
CrestronConsole.ConsoleCommandResponse("Usage: listtielines [signaltype]\r\n"); CrestronConsole.ConsoleCommandResponse("Usage: listtielines [signaltype]\r\n");
CrestronConsole.ConsoleCommandResponse("Signal types: Audio, Video, SecondaryAudio, AudioVideo, UsbInput, UsbOutput\r\n"); CrestronConsole.ConsoleCommandResponse("Signal types: Audio, Video, SecondaryAudio, AudioVideo, UsbInput, UsbOutput\r\n");
@ -508,7 +507,7 @@ namespace PepperDash.Essentials
{ {
try try
{ {
if (args.Contains("?")) if (!string.IsNullOrEmpty(args) && args.Contains("?"))
{ {
CrestronConsole.ConsoleCommandResponse("Usage: visualizeroutes [signaltype] [-s source] [-d destination]\r\n"); CrestronConsole.ConsoleCommandResponse("Usage: visualizeroutes [signaltype] [-s source] [-d destination]\r\n");
CrestronConsole.ConsoleCommandResponse(" signaltype: Audio, Video, AudioVideo, etc.\r\n"); CrestronConsole.ConsoleCommandResponse(" signaltype: Audio, Video, AudioVideo, etc.\r\n");
@ -557,7 +556,7 @@ namespace PepperDash.Essentials
{ {
try try
{ {
if (args.Contains("?")) if (!string.IsNullOrEmpty(args) && args.Contains("?"))
{ {
CrestronConsole.ConsoleCommandResponse("Usage: visualizecurrentroutes [signaltype] [-s source] [-d destination]\r\n"); CrestronConsole.ConsoleCommandResponse("Usage: visualizecurrentroutes [signaltype] [-s source] [-d destination]\r\n");
CrestronConsole.ConsoleCommandResponse(" signaltype: Audio, Video, AudioVideo, etc.\r\n"); CrestronConsole.ConsoleCommandResponse(" signaltype: Audio, Video, AudioVideo, etc.\r\n");