mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-08-31 10:58:28 +00:00
feat(mock-routing): add IHasNamedRoutingSlots support to MockRoutingMidpoint
This commit is contained in:
parent
527262d514
commit
fec59d2149
2 changed files with 127 additions and 7 deletions
|
|
@ -11,14 +11,15 @@ using Serilog.Events;
|
||||||
namespace PepperDash.Essentials.Devices.Common.Routing;
|
namespace PepperDash.Essentials.Devices.Common.Routing;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A mock midpoint routing device (e.g. a matrix switcher) that implements <see cref="IRoutingMidpointWithFeedback"/>
|
/// A mock midpoint routing device (e.g. a matrix switcher) that implements <see cref="IHasNamedRoutingSlots"/>
|
||||||
/// without any real hardware communication. Its input and output ports are configured via
|
/// without any real hardware communication. Its input and output ports are configured via
|
||||||
/// <see cref="MockRoutingMidpointPropertiesConfig"/>, each with a name, signal type, and physical port
|
/// <see cref="MockRoutingMidpointPropertiesConfig"/>, each with a name, signal type, and physical port
|
||||||
/// (connection) type - so it can stand in for a real switching device (such as a StreamSync matrix) for
|
/// (connection) type - so it can stand in for a real switching device (such as a DM chassis or a StreamSync
|
||||||
/// development and testing of routing logic.
|
/// matrix) for development and testing of routing logic, including named-routing-slot UI that a bare
|
||||||
|
/// <see cref="IRoutingMidpointWithFeedback"/> device cannot support.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Description("A mock routing midpoint (e.g. matrix switcher) device for testing routing logic without real hardware")]
|
[Description("A mock routing midpoint (e.g. matrix switcher) device for testing routing logic without real hardware")]
|
||||||
public class MockRoutingMidpoint : EssentialsDevice, IRoutingMidpointWithFeedback
|
public class MockRoutingMidpoint : EssentialsDevice, IHasNamedRoutingSlots
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The configuration properties for this device.
|
/// The configuration properties for this device.
|
||||||
|
|
@ -37,6 +38,14 @@ public class MockRoutingMidpoint : EssentialsDevice, IRoutingMidpointWithFeedbac
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public event RouteChangedEventHandler RouteChanged;
|
public event RouteChangedEventHandler RouteChanged;
|
||||||
|
|
||||||
|
private readonly Dictionary<string, MockRoutingOutputSlotInfo> _outputSlotsByKey = new Dictionary<string, MockRoutingOutputSlotInfo>();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IReadOnlyDictionary<string, IRoutingSlotInfo> InputSlots { get; private set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IReadOnlyDictionary<string, IRoutingOutputSlotInfo> OutputSlots { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="MockRoutingMidpoint"/> class from a <see cref="DeviceConfig"/>.
|
/// Initializes a new instance of the <see cref="MockRoutingMidpoint"/> class from a <see cref="DeviceConfig"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -56,14 +65,20 @@ public class MockRoutingMidpoint : EssentialsDevice, IRoutingMidpointWithFeedbac
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Builds the input and output ports from <see cref="PropertiesConfig"/>. Each port's Key and Selector
|
/// Builds the input and output ports (and their <see cref="IHasNamedRoutingSlots"/> slot info) from
|
||||||
/// are both set to the configured port name, so selectors passed to <see cref="ExecuteSwitch"/> and
|
/// <see cref="PropertiesConfig"/>. Each port's Key and Selector are both set to the configured port
|
||||||
/// <see cref="ClearRoute"/> can simply be looked up by matching against the port's Selector.
|
/// name, so selectors passed to <see cref="ExecuteSwitch"/> and <see cref="ClearRoute"/> can simply be
|
||||||
|
/// looked up by matching against the port's Selector. Slot number is the 1-based position of the port
|
||||||
|
/// within its input/output list.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void BuildPorts()
|
private void BuildPorts()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
var inputSlots = new Dictionary<string, IRoutingSlotInfo>();
|
||||||
|
var outputSlots = new Dictionary<string, IRoutingOutputSlotInfo>();
|
||||||
|
var slotNumber = 0;
|
||||||
|
|
||||||
foreach (var portConfig in PropertiesConfig.InputPorts)
|
foreach (var portConfig in PropertiesConfig.InputPorts)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(portConfig.Name))
|
if (string.IsNullOrEmpty(portConfig.Name))
|
||||||
|
|
@ -74,8 +89,13 @@ public class MockRoutingMidpoint : EssentialsDevice, IRoutingMidpointWithFeedbac
|
||||||
|
|
||||||
var port = new RoutingInputPort(portConfig.Name, portConfig.SignalType, portConfig.PortType, portConfig.Name, this);
|
var port = new RoutingInputPort(portConfig.Name, portConfig.SignalType, portConfig.PortType, portConfig.Name, this);
|
||||||
InputPorts.Add(port);
|
InputPorts.Add(port);
|
||||||
|
|
||||||
|
slotNumber++;
|
||||||
|
inputSlots[portConfig.Name] = new MockRoutingSlotInfo(
|
||||||
|
portConfig.Name, portConfig.Label ?? portConfig.Name, slotNumber, portConfig.SignalType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
slotNumber = 0;
|
||||||
foreach (var portConfig in PropertiesConfig.OutputPorts)
|
foreach (var portConfig in PropertiesConfig.OutputPorts)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(portConfig.Name))
|
if (string.IsNullOrEmpty(portConfig.Name))
|
||||||
|
|
@ -86,8 +106,17 @@ public class MockRoutingMidpoint : EssentialsDevice, IRoutingMidpointWithFeedbac
|
||||||
|
|
||||||
var port = new RoutingOutputPort(portConfig.Name, portConfig.SignalType, portConfig.PortType, portConfig.Name, this);
|
var port = new RoutingOutputPort(portConfig.Name, portConfig.SignalType, portConfig.PortType, portConfig.Name, this);
|
||||||
OutputPorts.Add(port);
|
OutputPorts.Add(port);
|
||||||
|
|
||||||
|
slotNumber++;
|
||||||
|
var outputSlot = new MockRoutingOutputSlotInfo(
|
||||||
|
portConfig.Name, portConfig.Label ?? portConfig.Name, slotNumber, portConfig.SignalType);
|
||||||
|
_outputSlotsByKey[portConfig.Name] = outputSlot;
|
||||||
|
outputSlots[portConfig.Name] = outputSlot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InputSlots = inputSlots;
|
||||||
|
OutputSlots = outputSlots;
|
||||||
|
|
||||||
this.LogInformation("Built {inputCount} input port(s) and {outputCount} output port(s) for mock midpoint {key}",
|
this.LogInformation("Built {inputCount} input port(s) and {outputCount} output port(s) for mock midpoint {key}",
|
||||||
InputPorts.Count, OutputPorts.Count, Key);
|
InputPorts.Count, OutputPorts.Count, Key);
|
||||||
}
|
}
|
||||||
|
|
@ -121,6 +150,11 @@ public class MockRoutingMidpoint : EssentialsDevice, IRoutingMidpointWithFeedbac
|
||||||
{
|
{
|
||||||
this.LogInformation("Clearing route to output {output} on {key}", outputPort.Key, Key);
|
this.LogInformation("Clearing route to output {output} on {key}", outputPort.Key, Key);
|
||||||
|
|
||||||
|
if (_outputSlotsByKey.TryGetValue(outputPort.Key, out var clearedSlot))
|
||||||
|
{
|
||||||
|
clearedSlot.ClearRoute(signalType);
|
||||||
|
}
|
||||||
|
|
||||||
var clearedDescriptor = new RouteSwitchDescriptor(outputPort, null);
|
var clearedDescriptor = new RouteSwitchDescriptor(outputPort, null);
|
||||||
RouteChanged?.Invoke(this, clearedDescriptor);
|
RouteChanged?.Invoke(this, clearedDescriptor);
|
||||||
return;
|
return;
|
||||||
|
|
@ -137,6 +171,11 @@ public class MockRoutingMidpoint : EssentialsDevice, IRoutingMidpointWithFeedbac
|
||||||
var descriptor = new RouteSwitchDescriptor(outputPort, inputPort);
|
var descriptor = new RouteSwitchDescriptor(outputPort, inputPort);
|
||||||
CurrentRoutes.Add(descriptor);
|
CurrentRoutes.Add(descriptor);
|
||||||
|
|
||||||
|
if (_outputSlotsByKey.TryGetValue(outputPort.Key, out var routedSlot))
|
||||||
|
{
|
||||||
|
routedSlot.SetRoute(signalType, inputPort.Key);
|
||||||
|
}
|
||||||
|
|
||||||
this.LogInformation("Executed switch: {input} -> {output} ({signalType}) on {key}",
|
this.LogInformation("Executed switch: {input} -> {output} ({signalType}) on {key}",
|
||||||
inputPort.Key, outputPort.Key, signalType, Key);
|
inputPort.Key, outputPort.Key, signalType, Key);
|
||||||
|
|
||||||
|
|
@ -155,6 +194,79 @@ public class MockRoutingMidpoint : EssentialsDevice, IRoutingMidpointWithFeedbac
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Named routing slot info for a <see cref="MockRoutingMidpoint"/> input or output port.
|
||||||
|
/// </summary>
|
||||||
|
class MockRoutingSlotInfo : IRoutingSlotInfo
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Key { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public int SlotNumber { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public eRoutingSignalType SupportedSignalTypes { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="MockRoutingSlotInfo"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public MockRoutingSlotInfo(string key, string name, int slotNumber, eRoutingSignalType supportedSignalTypes)
|
||||||
|
{
|
||||||
|
Key = key;
|
||||||
|
Name = name;
|
||||||
|
SlotNumber = slotNumber;
|
||||||
|
SupportedSignalTypes = supportedSignalTypes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Named output routing slot info for a <see cref="MockRoutingMidpoint"/> output port, tracking the
|
||||||
|
/// currently routed input key per signal type since the mock's flat <see cref="MockRoutingMidpoint.CurrentRoutes"/>
|
||||||
|
/// list does not carry signal type.
|
||||||
|
/// </summary>
|
||||||
|
class MockRoutingOutputSlotInfo : MockRoutingSlotInfo, IRoutingOutputSlotInfo
|
||||||
|
{
|
||||||
|
private readonly Dictionary<eRoutingSignalType, string> _currentRouteInputKeys = new Dictionary<eRoutingSignalType, string>();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IReadOnlyDictionary<eRoutingSignalType, string> CurrentRouteInputKeys => _currentRouteInputKeys;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public event EventHandler OutputSlotChanged;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="MockRoutingOutputSlotInfo"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public MockRoutingOutputSlotInfo(string key, string name, int slotNumber, eRoutingSignalType supportedSignalTypes)
|
||||||
|
: base(key, name, slotNumber, supportedSignalTypes)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Records the input key routed to this output for the given signal type and raises <see cref="OutputSlotChanged"/>.
|
||||||
|
/// </summary>
|
||||||
|
public void SetRoute(eRoutingSignalType signalType, string inputKey)
|
||||||
|
{
|
||||||
|
_currentRouteInputKeys[signalType] = inputKey;
|
||||||
|
OutputSlotChanged?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears the routed input key for the given signal type and raises <see cref="OutputSlotChanged"/> if it changed.
|
||||||
|
/// </summary>
|
||||||
|
public void ClearRoute(eRoutingSignalType signalType)
|
||||||
|
{
|
||||||
|
if (_currentRouteInputKeys.Remove(signalType))
|
||||||
|
{
|
||||||
|
OutputSlotChanged?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Factory for building <see cref="MockRoutingMidpoint"/> devices.
|
/// Factory for building <see cref="MockRoutingMidpoint"/> devices.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -50,4 +50,12 @@ public class MockRoutingMidpointPortConfig
|
||||||
[JsonProperty("portType")]
|
[JsonProperty("portType")]
|
||||||
[JsonConverter(typeof(StringEnumConverter))]
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
public eRoutingPortConnectionType PortType { get; set; } = eRoutingPortConnectionType.Hdmi;
|
public eRoutingPortConnectionType PortType { get; set; } = eRoutingPortConnectionType.Hdmi;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Optional friendly display name for this port (e.g. "Rm A Codec"), surfaced via
|
||||||
|
/// <see cref="IHasNamedRoutingSlots"/> for named-routing-slot UI. Defaults to <see cref="Name"/> if
|
||||||
|
/// not specified.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("label", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
|
public string Label { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue