chore: move all files to file-scoped namespace

This commit is contained in:
Andrew Welker 2025-07-04 16:02:32 -05:00 committed by Neil Dorin
parent aaa5b0532b
commit 3ece4f0b7b
522 changed files with 39628 additions and 45678 deletions

View file

@ -9,65 +9,66 @@ using PepperDash.Essentials.Core.Bridges;
using PepperDash.Essentials.Core.Config;
using Serilog.Events;
namespace PepperDash.Essentials.Devices.Common.Displays
namespace PepperDash.Essentials.Devices.Common.Displays;
/// <summary>
/// Represents a basic IR controlled display device. This class is intended to be used for simple displays that are controlled via IR and do not have a more robust API. It provides basic power and volume controls, as well as input switching via IR commands.
/// </summary>
public class BasicIrDisplay : DisplayBase, IBasicVolumeControls, IBridgeAdvanced
{
/// <summary>
/// Represents a BasicIrDisplay
/// Gets or sets the IrPort
/// </summary>
public class BasicIrDisplay : DisplayBase, IBasicVolumeControls, IBridgeAdvanced
public IrOutputPortController IrPort { get; private set; }
/// <summary>
/// Gets or sets the IrPulseTime
/// </summary>
public ushort IrPulseTime { get; set; }
/// <summary>
/// Gets the power is on feedback function
/// </summary>
protected Func<bool> PowerIsOnFeedbackFunc
{
/// <summary>
/// Gets or sets the IrPort
/// </summary>
public IrOutputPortController IrPort { get; private set; }
/// <summary>
/// Gets or sets the IrPulseTime
/// </summary>
public ushort IrPulseTime { get; set; }
get { return () => _PowerIsOn; }
}
/// <summary>
/// Gets the power is on feedback function
/// </summary>
protected Func<bool> PowerIsOnFeedbackFunc
{
get { return () => _PowerIsOn; }
}
/// <summary>
/// Gets the is cooling down feedback function
/// </summary>
protected override Func<bool> IsCoolingDownFeedbackFunc
{
get { return () => _IsCoolingDown; }
}
/// <summary>
/// Gets the is warming up feedback function
/// </summary>
protected override Func<bool> IsWarmingUpFeedbackFunc
{
get { return () => _IsWarmingUp; }
}
/// <summary>
/// Gets the is cooling down feedback function
/// </summary>
protected override Func<bool> IsCoolingDownFeedbackFunc
{
get { return () => _IsCoolingDown; }
}
/// <summary>
/// Gets the is warming up feedback function
/// </summary>
protected override Func<bool> IsWarmingUpFeedbackFunc
{
get { return () => _IsWarmingUp; }
}
bool _PowerIsOn;
bool _IsWarmingUp;
bool _IsCoolingDown;
bool _PowerIsOn;
bool _IsWarmingUp;
bool _IsCoolingDown;
/// <summary>
/// Initializes a new instance of the BasicIrDisplay class
/// </summary>
/// <param name="key">The device key</param>
/// <param name="name">The device name</param>
/// <param name="port">The IR output port</param>
/// <param name="irDriverFilepath">The path to the IR driver file</param>
public BasicIrDisplay(string key, string name, IROutputPort port, string irDriverFilepath)
: base(key, name)
{
IrPort = new IrOutputPortController(key + "-ir", port, irDriverFilepath);
DeviceManager.AddDevice(IrPort);
/// <summary>
/// Initializes a new instance of the BasicIrDisplay class
/// </summary>
/// <param name="key">The device key</param>
/// <param name="name">The device name</param>
/// <param name="port">The IR output port</param>
/// <param name="irDriverFilepath">The path to the IR driver file</param>
public BasicIrDisplay(string key, string name, IROutputPort port, string irDriverFilepath)
: base(key, name)
{
IrPort = new IrOutputPortController(key + "-ir", port, irDriverFilepath);
DeviceManager.AddDevice(IrPort);
IsWarmingUpFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Verbose, this, "Warming up={0}", _IsWarmingUp);
IsCoolingDownFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Verbose, this, "Cooling down={0}", _IsCoolingDown);
IsWarmingUpFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Verbose, this, "Warming up={0}", _IsWarmingUp);
IsCoolingDownFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Verbose, this, "Cooling down={0}", _IsCoolingDown);
InputPorts.AddRange(new RoutingPortCollection<RoutingInputPort>
InputPorts.AddRange(new RoutingPortCollection<RoutingInputPort>
{
new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.Audio | eRoutingSignalType.Video,
eRoutingPortConnectionType.Hdmi, new Action(Hdmi1), this, false),
@ -84,224 +85,223 @@ namespace PepperDash.Essentials.Devices.Common.Displays
new RoutingInputPort(RoutingPortNames.AntennaIn, eRoutingSignalType.Audio | eRoutingSignalType.Video,
eRoutingPortConnectionType.Hdmi, new Action(Antenna), this, false),
});
}
/// <summary>
/// Hdmi1 method
/// </summary>
public void Hdmi1()
{
IrPort.Pulse(IROutputStandardCommands.IROut_HDMI_1, IrPulseTime);
}
/// <summary>
/// Hdmi2 method
/// </summary>
public void Hdmi2()
{
IrPort.Pulse(IROutputStandardCommands.IROut_HDMI_2, IrPulseTime);
}
/// <summary>
/// Hdmi3 method
/// </summary>
public void Hdmi3()
{
IrPort.Pulse(IROutputStandardCommands.IROut_HDMI_3, IrPulseTime);
}
/// <summary>
/// Hdmi4 method
/// </summary>
public void Hdmi4()
{
IrPort.Pulse(IROutputStandardCommands.IROut_HDMI_4, IrPulseTime);
}
/// <summary>
/// Component1 method
/// </summary>
public void Component1()
{
IrPort.Pulse(IROutputStandardCommands.IROut_COMPONENT_1, IrPulseTime);
}
/// <summary>
/// Video1 method
/// </summary>
public void Video1()
{
IrPort.Pulse(IROutputStandardCommands.IROut_VIDEO_1, IrPulseTime);
}
/// <summary>
/// Antenna method
/// </summary>
public void Antenna()
{
IrPort.Pulse(IROutputStandardCommands.IROut_ANTENNA, IrPulseTime);
}
#region IPower Members
/// <summary>
/// PowerOn method
/// </summary>
/// <inheritdoc />
public override void PowerOn()
{
IrPort.Pulse(IROutputStandardCommands.IROut_POWER_ON, IrPulseTime);
_PowerIsOn = true;
}
/// <summary>
/// PowerOff method
/// </summary>
public override void PowerOff()
{
_PowerIsOn = false;
IrPort.Pulse(IROutputStandardCommands.IROut_POWER_OFF, IrPulseTime);
}
/// <summary>
/// PowerToggle method
/// </summary>
public override void PowerToggle()
{
_PowerIsOn = false;
IrPort.Pulse(IROutputStandardCommands.IROut_POWER, IrPulseTime);
}
#endregion
#region IBasicVolumeControls Members
/// <summary>
/// VolumeUp method
/// </summary>
public void VolumeUp(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_VOL_PLUS, pressRelease);
}
/// <summary>
/// VolumeDown method
/// </summary>
public void VolumeDown(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_VOL_MINUS, pressRelease);
}
/// <summary>
/// MuteToggle method
/// </summary>
public void MuteToggle()
{
IrPort.Pulse(IROutputStandardCommands.IROut_MUTE, 200);
}
#endregion
void StartWarmingTimer()
{
_IsWarmingUp = true;
IsWarmingUpFeedback.FireUpdate();
new CTimer(o =>
{
_IsWarmingUp = false;
IsWarmingUpFeedback.FireUpdate();
}, 10000);
}
void StartCoolingTimer()
{
_IsCoolingDown = true;
IsCoolingDownFeedback.FireUpdate();
new CTimer(o =>
{
_IsCoolingDown = false;
IsCoolingDownFeedback.FireUpdate();
}, 7000);
}
#region IRoutingSink Members
/// <summary>
/// Typically called by the discovery routing algorithm.
/// </summary>
/// <param name="inputSelector">A delegate containing the input selector method to call</param>
/// <summary>
/// ExecuteSwitch method
/// </summary>
/// <inheritdoc />
public override void ExecuteSwitch(object inputSelector)
{
Debug.LogMessage(LogEventLevel.Verbose, this, "Switching to input '{0}'", (inputSelector as Action).ToString());
Action finishSwitch = () =>
{
var action = inputSelector as Action;
if (action != null)
action();
};
if (!_PowerIsOn)
{
PowerOn();
EventHandler<FeedbackEventArgs> oneTimer = null;
oneTimer = (o, a) =>
{
if (IsWarmingUpFeedback.BoolValue) return; // Only catch done warming
IsWarmingUpFeedback.OutputChange -= oneTimer;
finishSwitch();
};
IsWarmingUpFeedback.OutputChange += oneTimer;
}
else // Do it!
finishSwitch();
}
#endregion
/// <summary>
/// LinkToApi method
/// </summary>
public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge)
{
LinkDisplayToApi(this, trilist, joinStart, joinMapKey, bridge);
}
}
/// <summary>
/// Represents a BasicIrDisplayFactory
/// Hdmi1 method
/// </summary>
public class BasicIrDisplayFactory : EssentialsDeviceFactory<BasicIrDisplay>
public void Hdmi1()
{
/// <summary>
/// Initializes a new instance of the BasicIrDisplayFactory class
/// </summary>
public BasicIrDisplayFactory()
{
TypeNames = new List<string>() { "basicirdisplay" };
}
/// <summary>
/// BuildDevice method
/// </summary>
/// <inheritdoc />
public override EssentialsDevice BuildDevice(DeviceConfig dc)
{
Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new BasicIrDisplay Device");
var ir = IRPortHelper.GetIrPort(dc.Properties);
if (ir != null)
{
var display = new BasicIrDisplay(dc.Key, dc.Name, ir.Port, ir.FileName);
display.IrPulseTime = 200; // Set default pulse time for IR commands.
return display;
}
return null;
}
IrPort.Pulse(IROutputStandardCommands.IROut_HDMI_1, IrPulseTime);
}
/// <summary>
/// Hdmi2 method
/// </summary>
public void Hdmi2()
{
IrPort.Pulse(IROutputStandardCommands.IROut_HDMI_2, IrPulseTime);
}
/// <summary>
/// Hdmi3 method
/// </summary>
public void Hdmi3()
{
IrPort.Pulse(IROutputStandardCommands.IROut_HDMI_3, IrPulseTime);
}
/// <summary>
/// Hdmi4 method
/// </summary>
public void Hdmi4()
{
IrPort.Pulse(IROutputStandardCommands.IROut_HDMI_4, IrPulseTime);
}
/// <summary>
/// Component1 method
/// </summary>
public void Component1()
{
IrPort.Pulse(IROutputStandardCommands.IROut_COMPONENT_1, IrPulseTime);
}
/// <summary>
/// Video1 method
/// </summary>
public void Video1()
{
IrPort.Pulse(IROutputStandardCommands.IROut_VIDEO_1, IrPulseTime);
}
/// <summary>
/// Antenna method
/// </summary>
public void Antenna()
{
IrPort.Pulse(IROutputStandardCommands.IROut_ANTENNA, IrPulseTime);
}
#region IPower Members
/// <summary>
/// PowerOn method
/// </summary>
/// <inheritdoc />
public override void PowerOn()
{
IrPort.Pulse(IROutputStandardCommands.IROut_POWER_ON, IrPulseTime);
_PowerIsOn = true;
}
/// <summary>
/// PowerOff method
/// </summary>
public override void PowerOff()
{
_PowerIsOn = false;
IrPort.Pulse(IROutputStandardCommands.IROut_POWER_OFF, IrPulseTime);
}
/// <summary>
/// PowerToggle method
/// </summary>
public override void PowerToggle()
{
_PowerIsOn = false;
IrPort.Pulse(IROutputStandardCommands.IROut_POWER, IrPulseTime);
}
#endregion
#region IBasicVolumeControls Members
/// <summary>
/// VolumeUp method
/// </summary>
public void VolumeUp(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_VOL_PLUS, pressRelease);
}
/// <summary>
/// VolumeDown method
/// </summary>
public void VolumeDown(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_VOL_MINUS, pressRelease);
}
/// <summary>
/// MuteToggle method
/// </summary>
public void MuteToggle()
{
IrPort.Pulse(IROutputStandardCommands.IROut_MUTE, 200);
}
#endregion
void StartWarmingTimer()
{
_IsWarmingUp = true;
IsWarmingUpFeedback.FireUpdate();
new CTimer(o =>
{
_IsWarmingUp = false;
IsWarmingUpFeedback.FireUpdate();
}, 10000);
}
void StartCoolingTimer()
{
_IsCoolingDown = true;
IsCoolingDownFeedback.FireUpdate();
new CTimer(o =>
{
_IsCoolingDown = false;
IsCoolingDownFeedback.FireUpdate();
}, 7000);
}
#region IRoutingSink Members
/// <summary>
/// Typically called by the discovery routing algorithm.
/// </summary>
/// <param name="inputSelector">A delegate containing the input selector method to call</param>
/// <summary>
/// ExecuteSwitch method
/// </summary>
/// <inheritdoc />
public override void ExecuteSwitch(object inputSelector)
{
Debug.LogMessage(LogEventLevel.Verbose, this, "Switching to input '{0}'", (inputSelector as Action).ToString());
Action finishSwitch = () =>
{
var action = inputSelector as Action;
if (action != null)
action();
};
if (!_PowerIsOn)
{
PowerOn();
EventHandler<FeedbackEventArgs> oneTimer = null;
oneTimer = (o, a) =>
{
if (IsWarmingUpFeedback.BoolValue) return; // Only catch done warming
IsWarmingUpFeedback.OutputChange -= oneTimer;
finishSwitch();
};
IsWarmingUpFeedback.OutputChange += oneTimer;
}
else // Do it!
finishSwitch();
}
#endregion
/// <summary>
/// LinkToApi method
/// </summary>
public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge)
{
LinkDisplayToApi(this, trilist, joinStart, joinMapKey, bridge);
}
}
/// <summary>
/// Factory for creating BasicIrDisplay devices
/// </summary>
public class BasicIrDisplayFactory : EssentialsDeviceFactory<BasicIrDisplay>
{
/// <summary>
/// Initializes a new instance of the BasicIrDisplayFactory class
/// </summary>
public BasicIrDisplayFactory()
{
TypeNames = new List<string>() { "basicirdisplay" };
}
/// <summary>
/// BuildDevice method
/// </summary>
/// <param name="dc"></param>
/// <returns></returns>
public override EssentialsDevice BuildDevice(DeviceConfig dc)
{
Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new BasicIrDisplay Device");
var ir = IRPortHelper.GetIrPort(dc.Properties);
if (ir != null)
{
var display = new BasicIrDisplay(dc.Key, dc.Name, ir.Port, ir.FileName);
display.IrPulseTime = 200; // Set default pulse time for IR commands.
return display;
}
return null;
}
}

View file

@ -13,426 +13,425 @@ using PepperDash.Essentials.Core.Routing;
using Serilog.Events;
using Feedback = PepperDash.Essentials.Core.Feedback;
namespace PepperDash.Essentials.Devices.Common.Displays
namespace PepperDash.Essentials.Devices.Common.Displays;
/// <summary>
/// Abstract base class for display devices that provides common display functionality
/// including power control, input switching, and routing capabilities.
/// </summary>
public abstract class DisplayBase : EssentialsDevice, IDisplay, ICurrentSources, IHasFeedback
{
private RoutingInputPort _currentInputPort;
/// <summary>
/// Abstract base class for display devices that provides common display functionality
/// including power control, input switching, and routing capabilities.
/// Gets or sets the current input port that is selected on the display.
/// </summary>
public abstract class DisplayBase : EssentialsDevice, IDisplay, ICurrentSources, IHasFeedback
public RoutingInputPort CurrentInputPort
{
private RoutingInputPort _currentInputPort;
/// <summary>
/// Gets or sets the current input port that is selected on the display.
/// </summary>
public RoutingInputPort CurrentInputPort
get
{
get
{
return _currentInputPort;
}
protected set
{
if (_currentInputPort == value) return;
_currentInputPort = value;
InputChanged?.Invoke(this, _currentInputPort);
}
return _currentInputPort;
}
/// <summary>
/// Event that is raised when the input changes on the display.
/// </summary>
public event InputChangedEventHandler InputChanged;
/// <summary>
/// Event that is raised when the current source information changes.
/// </summary>
public event SourceInfoChangeHandler CurrentSourceChange;
/// <summary>
/// Gets or sets the CurrentSourceInfoKey
/// </summary>
public string CurrentSourceInfoKey { get; set; }
/// <summary>
/// Gets or sets the current source information for the display.
/// </summary>
public SourceListItem CurrentSourceInfo
protected set
{
get
{
return _CurrentSourceInfo;
}
set
{
if (value == _CurrentSourceInfo) return;
if (_currentInputPort == value) return;
var handler = CurrentSourceChange;
_currentInputPort = value;
handler?.Invoke(_CurrentSourceInfo, ChangeType.WillChange);
_CurrentSourceInfo = value;
handler?.Invoke(_CurrentSourceInfo, ChangeType.DidChange);
}
InputChanged?.Invoke(this, _currentInputPort);
}
SourceListItem _CurrentSourceInfo;
}
/// <inheritdoc/>
public Dictionary<eRoutingSignalType, SourceListItem> CurrentSources { get; private set; }
/// <summary>
/// Event that is raised when the input changes on the display.
/// </summary>
public event InputChangedEventHandler InputChanged;
/// <inheritdoc/>
public Dictionary<eRoutingSignalType, string> CurrentSourceKeys { get; private set; }
/// <summary>
/// Event that is raised when the current source information changes.
/// </summary>
public event SourceInfoChangeHandler CurrentSourceChange;
/// <inheritdoc />
public event EventHandler CurrentSourcesChanged;
/// <summary>
/// Gets or sets the CurrentSourceInfoKey
/// </summary>
public string CurrentSourceInfoKey { get; set; }
/// <summary>
/// Gets feedback indicating whether the display is currently cooling down after being powered off.
/// </summary>
public BoolFeedback IsCoolingDownFeedback { get; protected set; }
/// <summary>
/// Gets or sets the IsWarmingUpFeedback
/// </summary>
public BoolFeedback IsWarmingUpFeedback { get; private set; }
/// <summary>
/// Gets or sets the UsageTracker
/// </summary>
public UsageTracking UsageTracker { get; set; }
/// <summary>
/// Gets or sets the WarmupTime
/// </summary>
public uint WarmupTime { get; set; }
/// <summary>
/// Gets or sets the CooldownTime
/// </summary>
public uint CooldownTime { get; set; }
/// <summary>
/// Abstract function that must be implemented by derived classes to provide the cooling down feedback value.
/// Must be implemented by concrete sub-classes.
/// </summary>
abstract protected Func<bool> IsCoolingDownFeedbackFunc { get; }
/// <summary>
/// Abstract function that must be implemented by derived classes to provide the warming up feedback value.
/// Must be implemented by concrete sub-classes.
/// </summary>
abstract protected Func<bool> IsWarmingUpFeedbackFunc { get; }
/// <summary>
/// Timer used for managing display warmup timing.
/// </summary>
protected CTimer WarmupTimer;
/// <summary>
/// Timer used for managing display cooldown timing.
/// </summary>
protected CTimer CooldownTimer;
#region IRoutingInputs Members
/// <summary>
/// Gets the collection of input ports available on this display device.
/// </summary>
public RoutingPortCollection<RoutingInputPort> InputPorts { get; private set; }
#endregion
/// <summary>
/// Initializes a new instance of the DisplayBase class.
/// </summary>
/// <param name="key">The unique key identifier for this display device.</param>
/// <param name="name">The friendly name for this display device.</param>
protected DisplayBase(string key, string name)
: base(key, name)
/// <summary>
/// Gets or sets the current source information for the display.
/// </summary>
public SourceListItem CurrentSourceInfo
{
get
{
IsCoolingDownFeedback = new BoolFeedback("IsCoolingDown", IsCoolingDownFeedbackFunc);
IsWarmingUpFeedback = new BoolFeedback("IsWarmingUp", IsWarmingUpFeedbackFunc);
return _CurrentSourceInfo;
}
set
{
if (value == _CurrentSourceInfo) return;
Feedbacks.Add(IsCoolingDownFeedback);
Feedbacks.Add(IsWarmingUpFeedback);
var handler = CurrentSourceChange;
InputPorts = new RoutingPortCollection<RoutingInputPort>();
handler?.Invoke(_CurrentSourceInfo, ChangeType.WillChange);
CurrentSources = new Dictionary<eRoutingSignalType, SourceListItem>
_CurrentSourceInfo = value;
handler?.Invoke(_CurrentSourceInfo, ChangeType.DidChange);
}
}
SourceListItem _CurrentSourceInfo;
/// <inheritdoc/>
public Dictionary<eRoutingSignalType, SourceListItem> CurrentSources { get; private set; }
/// <inheritdoc/>
public Dictionary<eRoutingSignalType, string> CurrentSourceKeys { get; private set; }
/// <inheritdoc />
public event EventHandler CurrentSourcesChanged;
/// <summary>
/// Gets feedback indicating whether the display is currently cooling down after being powered off.
/// </summary>
public BoolFeedback IsCoolingDownFeedback { get; protected set; }
/// <summary>
/// Gets or sets the IsWarmingUpFeedback
/// </summary>
public BoolFeedback IsWarmingUpFeedback { get; private set; }
/// <summary>
/// Gets or sets the UsageTracker
/// </summary>
public UsageTracking UsageTracker { get; set; }
/// <summary>
/// Gets or sets the WarmupTime
/// </summary>
public uint WarmupTime { get; set; }
/// <summary>
/// Gets or sets the CooldownTime
/// </summary>
public uint CooldownTime { get; set; }
/// <summary>
/// Abstract function that must be implemented by derived classes to provide the cooling down feedback value.
/// Must be implemented by concrete sub-classes.
/// </summary>
abstract protected Func<bool> IsCoolingDownFeedbackFunc { get; }
/// <summary>
/// Abstract function that must be implemented by derived classes to provide the warming up feedback value.
/// Must be implemented by concrete sub-classes.
/// </summary>
abstract protected Func<bool> IsWarmingUpFeedbackFunc { get; }
/// <summary>
/// Timer used for managing display warmup timing.
/// </summary>
protected CTimer WarmupTimer;
/// <summary>
/// Timer used for managing display cooldown timing.
/// </summary>
protected CTimer CooldownTimer;
#region IRoutingInputs Members
/// <summary>
/// Gets the collection of input ports available on this display device.
/// </summary>
public RoutingPortCollection<RoutingInputPort> InputPorts { get; private set; }
#endregion
/// <summary>
/// Initializes a new instance of the DisplayBase class.
/// </summary>
/// <param name="key">The unique key identifier for this display device.</param>
/// <param name="name">The friendly name for this display device.</param>
protected DisplayBase(string key, string name)
: base(key, name)
{
IsCoolingDownFeedback = new BoolFeedback("IsCoolingDown", IsCoolingDownFeedbackFunc);
IsWarmingUpFeedback = new BoolFeedback("IsWarmingUp", IsWarmingUpFeedbackFunc);
Feedbacks.Add(IsCoolingDownFeedback);
Feedbacks.Add(IsWarmingUpFeedback);
InputPorts = new RoutingPortCollection<RoutingInputPort>();
CurrentSources = new Dictionary<eRoutingSignalType, SourceListItem>
{
{ eRoutingSignalType.Audio, null },
{ eRoutingSignalType.Video, null },
};
CurrentSourceKeys = new Dictionary<eRoutingSignalType, string>
CurrentSourceKeys = new Dictionary<eRoutingSignalType, string>
{
{ eRoutingSignalType.Audio, string.Empty },
{ eRoutingSignalType.Video, string.Empty },
};
}
/// <summary>
/// Powers on the display device. Must be implemented by derived classes.
/// </summary>
public abstract void PowerOn();
/// <summary>
/// Powers off the display device. Must be implemented by derived classes.
/// </summary>
public abstract void PowerOff();
/// <summary>
/// Toggles the power state of the display device. Must be implemented by derived classes.
/// </summary>
public abstract void PowerToggle();
/// <summary>
/// Gets the collection of feedback objects for this display device.
/// </summary>
/// <inheritdoc />
public virtual FeedbackCollection<Feedback> Feedbacks { get; private set; } = new FeedbackCollection<Feedback>();
/// <summary>
/// Executes a switch to the specified input on the display device. Must be implemented by derived classes.
/// </summary>
/// <param name="selector">The selector object that identifies which input to switch to.</param>
public abstract void ExecuteSwitch(object selector);
/// <summary>
/// Links the display device to an API using a trilist, join start, join map key, and bridge.
/// This overload uses serialized join map configuration.
/// </summary>
/// <param name="displayDevice">The display device to link.</param>
/// <param name="trilist">The BasicTriList for communication.</param>
/// <param name="joinStart">The starting join number for the device.</param>
/// <param name="joinMapKey">The key for the join map configuration.</param>
/// <param name="bridge">The EISC API bridge instance.</param>
protected void LinkDisplayToApi(DisplayBase displayDevice, BasicTriList trilist, uint joinStart, string joinMapKey,
EiscApiAdvanced bridge)
{
var joinMap = new DisplayControllerJoinMap(joinStart);
var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey);
if (!string.IsNullOrEmpty(joinMapSerialized))
joinMap = JsonConvert.DeserializeObject<DisplayControllerJoinMap>(joinMapSerialized);
if (bridge != null)
{
bridge.AddJoinMap(Key, joinMap);
}
else
{
Debug.LogMessage(LogEventLevel.Information, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device.");
}
/// <summary>
/// Powers on the display device. Must be implemented by derived classes.
/// </summary>
public abstract void PowerOn();
LinkDisplayToApi(displayDevice, trilist, joinMap);
}
/// <summary>
/// Powers off the display device. Must be implemented by derived classes.
/// </summary>
public abstract void PowerOff();
/// <summary>
/// Links the display device to an API using a trilist and join map.
/// This overload uses a pre-configured join map instance.
/// </summary>
/// <param name="displayDevice">The display device to link.</param>
/// <param name="trilist">The BasicTriList for communication.</param>
/// <param name="joinMap">The join map configuration for the device.</param>
protected void LinkDisplayToApi(DisplayBase displayDevice, BasicTriList trilist, DisplayControllerJoinMap joinMap)
{
this.LogDebug("Linking to Trilist {ipId}", trilist.ID.ToString("X"));
this.LogDebug("Linking to Display: {displayName}", displayDevice.Name);
/// <summary>
/// Toggles the power state of the display device. Must be implemented by derived classes.
/// </summary>
public abstract void PowerToggle();
trilist.StringInput[joinMap.Name.JoinNumber].StringValue = displayDevice.Name;
/// <summary>
/// Gets the collection of feedback objects for this display device.
/// </summary>
/// <inheritdoc />
public virtual FeedbackCollection<Feedback> Feedbacks { get; private set; } = new FeedbackCollection<Feedback>();
/// <summary>
/// Executes a switch to the specified input on the display device. Must be implemented by derived classes.
/// </summary>
/// <param name="selector">The selector object that identifies which input to switch to.</param>
public abstract void ExecuteSwitch(object selector);
/// <summary>
/// Links the display device to an API using a trilist, join start, join map key, and bridge.
/// This overload uses serialized join map configuration.
/// </summary>
/// <param name="displayDevice">The display device to link.</param>
/// <param name="trilist">The BasicTriList for communication.</param>
/// <param name="joinStart">The starting join number for the device.</param>
/// <param name="joinMapKey">The key for the join map configuration.</param>
/// <param name="bridge">The EISC API bridge instance.</param>
protected void LinkDisplayToApi(DisplayBase displayDevice, BasicTriList trilist, uint joinStart, string joinMapKey,
EiscApiAdvanced bridge)
if (displayDevice is ICommunicationMonitor commMonitor)
{
var joinMap = new DisplayControllerJoinMap(joinStart);
var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey);
if (!string.IsNullOrEmpty(joinMapSerialized))
joinMap = JsonConvert.DeserializeObject<DisplayControllerJoinMap>(joinMapSerialized);
if (bridge != null)
{
bridge.AddJoinMap(Key, joinMap);
}
else
{
Debug.LogMessage(LogEventLevel.Information, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device.");
}
LinkDisplayToApi(displayDevice, trilist, joinMap);
commMonitor.CommunicationMonitor.IsOnlineFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline.JoinNumber]);
}
/// <summary>
/// Links the display device to an API using a trilist and join map.
/// This overload uses a pre-configured join map instance.
/// </summary>
/// <param name="displayDevice">The display device to link.</param>
/// <param name="trilist">The BasicTriList for communication.</param>
/// <param name="joinMap">The join map configuration for the device.</param>
protected void LinkDisplayToApi(DisplayBase displayDevice, BasicTriList trilist, DisplayControllerJoinMap joinMap)
// TODO: revisit this as there could be issues with this approach
var inputNumber = 0;
var inputKeys = new List<string>();
var inputNumberFeedback = new IntFeedback("inputNumber", () => inputNumber);
// Add input number feedback to the device feedback collection to keep it around...
Feedbacks.Add(inputNumberFeedback);
// Two way feedbacks
if (displayDevice is TwoWayDisplayBase twoWayDisplay)
{
this.LogDebug("Linking to Trilist {ipId}", trilist.ID.ToString("X"));
this.LogDebug("Linking to Display: {displayName}", displayDevice.Name);
trilist.SetBool(joinMap.IsTwoWayDisplay.JoinNumber, true);
trilist.StringInput[joinMap.Name.JoinNumber].StringValue = displayDevice.Name;
twoWayDisplay.CurrentInputFeedback.OutputChange += (o, a) => this.LogDebug("CurrentInputFeedback_OutputChange {input}", a.StringValue);
if (displayDevice is ICommunicationMonitor commMonitor)
inputNumberFeedback.LinkInputSig(trilist.UShortInput[joinMap.InputSelect.JoinNumber]);
twoWayDisplay.PowerIsOnFeedback.OutputChange += (o, a) =>
{
commMonitor.CommunicationMonitor.IsOnlineFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline.JoinNumber]);
}
// TODO: revisit this as there could be issues with this approach
var inputNumber = 0;
var inputKeys = new List<string>();
var inputNumberFeedback = new IntFeedback("inputNumber", () => inputNumber);
// Add input number feedback to the device feedback collection to keep it around...
Feedbacks.Add(inputNumberFeedback);
// Two way feedbacks
if (displayDevice is TwoWayDisplayBase twoWayDisplay)
{
trilist.SetBool(joinMap.IsTwoWayDisplay.JoinNumber, true);
twoWayDisplay.CurrentInputFeedback.OutputChange += (o, a) => this.LogDebug("CurrentInputFeedback_OutputChange {input}", a.StringValue);
inputNumberFeedback.LinkInputSig(trilist.UShortInput[joinMap.InputSelect.JoinNumber]);
twoWayDisplay.PowerIsOnFeedback.OutputChange += (o, a) =>
if (!a.BoolValue)
{
if (!a.BoolValue)
{
inputNumber = 102;
inputNumberFeedback.FireUpdate();
inputNumber = 102;
inputNumberFeedback.FireUpdate();
}
else
{
inputNumber = 0;
inputNumberFeedback.FireUpdate();
}
};
twoWayDisplay.PowerIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.PowerOff.JoinNumber]);
twoWayDisplay.PowerIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PowerOn.JoinNumber]);
}
// Power Off
trilist.SetSigTrueAction(joinMap.PowerOff.JoinNumber, () =>
{
inputNumber = 102;
inputNumberFeedback.FireUpdate();
displayDevice.PowerOff();
});
// PowerOn
trilist.SetSigTrueAction(joinMap.PowerOn.JoinNumber, () =>
{
inputNumber = 0;
inputNumberFeedback.FireUpdate();
displayDevice.PowerOn();
});
for (int i = 0; i < displayDevice.InputPorts.Count; i++)
{
var localindex = i;
if (localindex >= joinMap.InputNamesOffset.JoinSpan)
{
this.LogWarning("Device has {inputCount} inputs. The Join Map allows up to {joinSpan} inputs. Discarding inputs {discardStart} - {discardEnd} from bridge.",
displayDevice.InputPorts.Count, joinMap.InputNamesOffset.JoinSpan, localindex + 1, displayDevice.InputPorts.Count);
continue;
}
else
{
inputKeys.Add(displayDevice.InputPorts[localindex].Key);
var tempKey = inputKeys.ElementAt(localindex);
trilist.SetSigTrueAction((ushort)(joinMap.InputSelectOffset.JoinNumber + localindex), () => displayDevice.ExecuteSwitch(displayDevice.InputPorts[tempKey].Selector));
this.LogDebug("Setting Input Select Action on Digital Join {joinNumber} to Input: {input}", joinMap.InputSelectOffset.JoinNumber + localindex, displayDevice.InputPorts[tempKey].Key);
trilist.SetString((uint)(joinMap.InputNamesOffset.JoinNumber + localindex), displayDevice.InputPorts[localindex].Key);
}
}
this.LogDebug("Setting Input Select Action on Analog Join {inputSelectJoin}", joinMap.InputSelect);
trilist.SetUShortSigAction(joinMap.InputSelect.JoinNumber, (requestedInput) =>
{
if (requestedInput == 0)
{
displayDevice.PowerOff();
inputNumber = 0;
return;
inputNumberFeedback.FireUpdate();
}
};
// using 1-based indexing for inputs coming from SIMPL, so need to check if the input is <= the count, not <
if (requestedInput > 0 && requestedInput <= displayDevice.InputPorts.Count && requestedInput != inputNumber)
{
displayDevice.ExecuteSwitch(displayDevice.InputPorts.ElementAt(requestedInput - 1).Selector);
inputNumber = requestedInput;
return;
}
if (requestedInput == 102)
{
displayDevice.PowerToggle();
return;
}
if (displayDevice is TwoWayDisplayBase)
{
inputNumberFeedback?.FireUpdate();
}
});
var volumeDisplay = displayDevice as IBasicVolumeControls;
if (volumeDisplay == null) return;
trilist.SetBoolSigAction(joinMap.VolumeUp.JoinNumber, volumeDisplay.VolumeUp);
trilist.SetBoolSigAction(joinMap.VolumeDown.JoinNumber, volumeDisplay.VolumeDown);
trilist.SetSigTrueAction(joinMap.VolumeMute.JoinNumber, volumeDisplay.MuteToggle);
var volumeDisplayWithFeedback = volumeDisplay as IBasicVolumeWithFeedback;
if (volumeDisplayWithFeedback == null) return;
trilist.SetSigTrueAction(joinMap.VolumeMuteOn.JoinNumber, volumeDisplayWithFeedback.MuteOn);
trilist.SetSigTrueAction(joinMap.VolumeMuteOff.JoinNumber, volumeDisplayWithFeedback.MuteOff);
trilist.SetUShortSigAction(joinMap.VolumeLevel.JoinNumber, volumeDisplayWithFeedback.SetVolume);
volumeDisplayWithFeedback.VolumeLevelFeedback.LinkInputSig(trilist.UShortInput[joinMap.VolumeLevel.JoinNumber]);
volumeDisplayWithFeedback.MuteFeedback.LinkInputSig(trilist.BooleanInput[joinMap.VolumeMute.JoinNumber]);
volumeDisplayWithFeedback.MuteFeedback.LinkInputSig(trilist.BooleanInput[joinMap.VolumeMuteOn.JoinNumber]);
volumeDisplayWithFeedback.MuteFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.VolumeMuteOff.JoinNumber]);
twoWayDisplay.PowerIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.PowerOff.JoinNumber]);
twoWayDisplay.PowerIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PowerOn.JoinNumber]);
}
/// <inheritdoc />
public virtual void SetCurrentSource(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem)
// Power Off
trilist.SetSigTrueAction(joinMap.PowerOff.JoinNumber, () =>
{
foreach (eRoutingSignalType type in Enum.GetValues(typeof(eRoutingSignalType)))
{
var flagValue = Convert.ToInt32(type);
// Skip if flagValue is 0 or not a power of two (i.e., not a single-bit flag).
// (flagValue & (flagValue - 1)) != 0 checks if more than one bit is set.
if (flagValue == 0 || (flagValue & (flagValue - 1)) != 0)
{
this.LogDebug("Skipping {type}", type);
continue;
}
inputNumber = 102;
inputNumberFeedback.FireUpdate();
displayDevice.PowerOff();
});
this.LogDebug("setting {type}", type);
if (signalType.HasFlag(type))
{
UpdateCurrentSources(type, sourceListKey, sourceListItem);
}
}
// Raise the CurrentSourcesChanged event
CurrentSourcesChanged?.Invoke(this, EventArgs.Empty);
}
private void UpdateCurrentSources(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem)
// PowerOn
trilist.SetSigTrueAction(joinMap.PowerOn.JoinNumber, () =>
{
if (CurrentSources.ContainsKey(signalType))
inputNumber = 0;
inputNumberFeedback.FireUpdate();
displayDevice.PowerOn();
});
for (int i = 0; i < displayDevice.InputPorts.Count; i++)
{
var localindex = i;
if (localindex >= joinMap.InputNamesOffset.JoinSpan)
{
CurrentSources[signalType] = sourceListItem;
this.LogWarning("Device has {inputCount} inputs. The Join Map allows up to {joinSpan} inputs. Discarding inputs {discardStart} - {discardEnd} from bridge.",
displayDevice.InputPorts.Count, joinMap.InputNamesOffset.JoinSpan, localindex + 1, displayDevice.InputPorts.Count);
continue;
}
else
{
CurrentSources.Add(signalType, sourceListItem);
}
inputKeys.Add(displayDevice.InputPorts[localindex].Key);
// Update the current source key for the specified signal type
if (CurrentSourceKeys.ContainsKey(signalType))
{
CurrentSourceKeys[signalType] = sourceListKey;
}
else
{
CurrentSourceKeys.Add(signalType, sourceListKey);
var tempKey = inputKeys.ElementAt(localindex);
trilist.SetSigTrueAction((ushort)(joinMap.InputSelectOffset.JoinNumber + localindex), () => displayDevice.ExecuteSwitch(displayDevice.InputPorts[tempKey].Selector));
this.LogDebug("Setting Input Select Action on Digital Join {joinNumber} to Input: {input}", joinMap.InputSelectOffset.JoinNumber + localindex, displayDevice.InputPorts[tempKey].Key);
trilist.SetString((uint)(joinMap.InputNamesOffset.JoinNumber + localindex), displayDevice.InputPorts[localindex].Key);
}
}
this.LogDebug("Setting Input Select Action on Analog Join {inputSelectJoin}", joinMap.InputSelect);
trilist.SetUShortSigAction(joinMap.InputSelect.JoinNumber, (requestedInput) =>
{
if (requestedInput == 0)
{
displayDevice.PowerOff();
inputNumber = 0;
return;
}
// using 1-based indexing for inputs coming from SIMPL, so need to check if the input is <= the count, not <
if (requestedInput > 0 && requestedInput <= displayDevice.InputPorts.Count && requestedInput != inputNumber)
{
displayDevice.ExecuteSwitch(displayDevice.InputPorts.ElementAt(requestedInput - 1).Selector);
inputNumber = requestedInput;
return;
}
if (requestedInput == 102)
{
displayDevice.PowerToggle();
return;
}
if (displayDevice is TwoWayDisplayBase)
{
inputNumberFeedback?.FireUpdate();
}
});
var volumeDisplay = displayDevice as IBasicVolumeControls;
if (volumeDisplay == null) return;
trilist.SetBoolSigAction(joinMap.VolumeUp.JoinNumber, volumeDisplay.VolumeUp);
trilist.SetBoolSigAction(joinMap.VolumeDown.JoinNumber, volumeDisplay.VolumeDown);
trilist.SetSigTrueAction(joinMap.VolumeMute.JoinNumber, volumeDisplay.MuteToggle);
var volumeDisplayWithFeedback = volumeDisplay as IBasicVolumeWithFeedback;
if (volumeDisplayWithFeedback == null) return;
trilist.SetSigTrueAction(joinMap.VolumeMuteOn.JoinNumber, volumeDisplayWithFeedback.MuteOn);
trilist.SetSigTrueAction(joinMap.VolumeMuteOff.JoinNumber, volumeDisplayWithFeedback.MuteOff);
trilist.SetUShortSigAction(joinMap.VolumeLevel.JoinNumber, volumeDisplayWithFeedback.SetVolume);
volumeDisplayWithFeedback.VolumeLevelFeedback.LinkInputSig(trilist.UShortInput[joinMap.VolumeLevel.JoinNumber]);
volumeDisplayWithFeedback.MuteFeedback.LinkInputSig(trilist.BooleanInput[joinMap.VolumeMute.JoinNumber]);
volumeDisplayWithFeedback.MuteFeedback.LinkInputSig(trilist.BooleanInput[joinMap.VolumeMuteOn.JoinNumber]);
volumeDisplayWithFeedback.MuteFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.VolumeMuteOff.JoinNumber]);
}
}
/// <inheritdoc />
public virtual void SetCurrentSource(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem)
{
foreach (eRoutingSignalType type in Enum.GetValues(typeof(eRoutingSignalType)))
{
var flagValue = Convert.ToInt32(type);
// Skip if flagValue is 0 or not a power of two (i.e., not a single-bit flag).
// (flagValue & (flagValue - 1)) != 0 checks if more than one bit is set.
if (flagValue == 0 || (flagValue & (flagValue - 1)) != 0)
{
this.LogDebug("Skipping {type}", type);
continue;
}
this.LogDebug("setting {type}", type);
if (signalType.HasFlag(type))
{
UpdateCurrentSources(type, sourceListKey, sourceListItem);
}
}
// Raise the CurrentSourcesChanged event
CurrentSourcesChanged?.Invoke(this, EventArgs.Empty);
}
private void UpdateCurrentSources(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem)
{
if (CurrentSources.ContainsKey(signalType))
{
CurrentSources[signalType] = sourceListItem;
}
else
{
CurrentSources.Add(signalType, sourceListItem);
}
// Update the current source key for the specified signal type
if (CurrentSourceKeys.ContainsKey(signalType))
{
CurrentSourceKeys[signalType] = sourceListKey;
}
else
{
CurrentSourceKeys.Add(signalType, sourceListKey);
}
}
}

View file

@ -1,89 +1,87 @@
using System;
namespace PepperDash.Essentials.Devices.Displays
namespace PepperDash.Essentials.Devices.Displays;
/// <summary>
/// Defines the contract for IInputHdmi1
/// </summary>
[Obsolete()]
public interface IInputHdmi1
{
/// <summary>
/// Defines the contract for IInputHdmi1
/// Switches to HDMI 1 input
/// </summary>
[Obsolete()]
public interface IInputHdmi1
{
/// <summary>
/// Switches to HDMI 1 input
/// </summary>
void InputHdmi1();
}
void InputHdmi1();
}
/// <summary>
/// Defines the contract for IInputHdmi2
/// </summary>
[Obsolete()]
public interface IInputHdmi2
{
/// <summary>
/// Defines the contract for IInputHdmi2
/// Switches to HDMI 2 input
/// </summary>
[Obsolete()]
public interface IInputHdmi2
{
/// <summary>
/// Switches to HDMI 2 input
/// </summary>
void InputHdmi2();
}
void InputHdmi2();
}
/// <summary>
/// Defines the contract for IInputHdmi3
/// </summary>
[Obsolete()]
public interface IInputHdmi3
{
/// <summary>
/// Defines the contract for IInputHdmi3
/// Switches to HDMI 3 input
/// </summary>
[Obsolete()]
public interface IInputHdmi3
{
/// <summary>
/// Switches to HDMI 3 input
/// </summary>
void InputHdmi3();
}
void InputHdmi3();
}
/// <summary>
/// Defines the contract for IInputHdmi4
/// </summary>
[Obsolete()]
public interface IInputHdmi4
{
/// <summary>
/// Defines the contract for IInputHdmi4
/// Switches to HDMI 4 input
/// </summary>
[Obsolete()]
public interface IInputHdmi4
{
/// <summary>
/// Switches to HDMI 4 input
/// </summary>
void InputHdmi4();
}
void InputHdmi4();
}
/// <summary>
/// Defines the contract for IInputDisplayPort1
/// </summary>
[Obsolete()]
public interface IInputDisplayPort1
{
/// <summary>
/// Defines the contract for IInputDisplayPort1
/// Switches to DisplayPort 1 input
/// </summary>
[Obsolete()]
public interface IInputDisplayPort1
{
/// <summary>
/// Switches to DisplayPort 1 input
/// </summary>
void InputDisplayPort1();
}
void InputDisplayPort1();
}
/// <summary>
/// Defines the contract for IInputDisplayPort2
/// </summary>
[Obsolete()]
public interface IInputDisplayPort2
{
/// <summary>
/// Defines the contract for IInputDisplayPort2
/// Switches to DisplayPort 2 input
/// </summary>
[Obsolete()]
public interface IInputDisplayPort2
{
/// <summary>
/// Switches to DisplayPort 2 input
/// </summary>
void InputDisplayPort2();
}
void InputDisplayPort2();
}
/// <summary>
/// Defines the contract for IInputVga1
/// </summary>
[Obsolete()]
public interface IInputVga1
{
/// <summary>
/// Defines the contract for IInputVga1
/// Switches to VGA 1 input
/// </summary>
[Obsolete()]
public interface IInputVga1
{
/// <summary>
/// Switches to VGA 1 input
/// </summary>
void InputVga1();
}
}
void InputVga1();
}

View file

@ -10,82 +10,62 @@ using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
using Serilog.Events;
namespace PepperDash.Essentials.Devices.Common.Displays
namespace PepperDash.Essentials.Devices.Common.Displays;
/// <summary>
/// Represents a mock display device for testing and simulation purposes.
/// </summary>
public class MockDisplay : TwoWayDisplayBase, IBasicVolumeWithFeedback, IBridgeAdvanced, IHasInputs<string>, IRoutingSinkWithSwitchingWithInputPort, IHasPowerControlWithFeedback
{
/// <summary>
/// Represents a MockDisplay
/// </summary>
public class MockDisplay : TwoWayDisplayBase, IBasicVolumeWithFeedback, IBridgeAdvanced, IHasInputs<string>, IRoutingSinkWithSwitchingWithInputPort, IHasPowerControlWithFeedback
public ISelectableItems<string> Inputs { get; private set; }
bool _PowerIsOn;
bool _IsWarmingUp;
bool _IsCoolingDown;
protected override Func<bool> PowerIsOnFeedbackFunc
{
/// <summary>
/// Gets or sets the Inputs
/// </summary>
public ISelectableItems<string> Inputs { get; private set; }
bool _PowerIsOn;
bool _IsWarmingUp;
bool _IsCoolingDown;
/// <summary>
/// Gets the power is on feedback function
/// </summary>
protected override Func<bool> PowerIsOnFeedbackFunc
get
{
get
{
return () =>
{
return _PowerIsOn;
};
}
}
/// <summary>
/// Gets the is cooling down feedback function
/// </summary>
protected override Func<bool> IsCoolingDownFeedbackFunc
{
get
{
return () =>
return () =>
{
return _IsCoolingDown;
return _PowerIsOn;
};
}
}
/// <summary>
/// Gets the is warming up feedback function
/// </summary>
protected override Func<bool> IsWarmingUpFeedbackFunc
}
protected override Func<bool> IsCoolingDownFeedbackFunc
{
get
{
get
return () =>
{
return () =>
{
return _IsWarmingUp;
};
}
return _IsCoolingDown;
};
}
/// <summary>
/// Gets the current input feedback function
/// </summary>
protected override Func<string> CurrentInputFeedbackFunc { get { return () => Inputs.CurrentItem; } }
int VolumeHeldRepeatInterval = 200;
ushort VolumeInterval = 655;
ushort _FakeVolumeLevel = 31768;
bool _IsMuted;
/// <summary>
/// Initializes a new instance of the MockDisplay class
/// </summary>
/// <param name="key">The device key</param>
/// <param name="name">The device name</param>
public MockDisplay(string key, string name)
: base(key, name)
}
protected override Func<bool> IsWarmingUpFeedbackFunc
{
get
{
Inputs = new MockDisplayInputs
return () =>
{
Items = new Dictionary<string, ISelectableItem>
return _IsWarmingUp;
};
}
}
protected override Func<string> CurrentInputFeedbackFunc { get { return () => Inputs.CurrentItem; } }
int VolumeHeldRepeatInterval = 200;
ushort VolumeInterval = 655;
ushort _FakeVolumeLevel = 31768;
bool _IsMuted;
public MockDisplay(string key, string name)
: base(key, name)
{
Inputs = new MockDisplayInputs
{
Items = new Dictionary<string, ISelectableItem>
{
{ "HDMI1", new MockDisplayInput ( "HDMI1", "HDMI 1",this ) },
{ "HDMI2", new MockDisplayInput ("HDMI2", "HDMI 2",this ) },
@ -93,276 +73,239 @@ namespace PepperDash.Essentials.Devices.Common.Displays
{ "HDMI4", new MockDisplayInput ("HDMI4", "HDMI 4",this )},
{ "DP", new MockDisplayInput ("DP", "DisplayPort", this ) }
}
};
};
Inputs.CurrentItemChanged += (o, a) => CurrentInputFeedback.FireUpdate();
Inputs.CurrentItemChanged += (o, a) => CurrentInputFeedback.FireUpdate();
var hdmiIn1 = new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.AudioVideo,
var hdmiIn1 = new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, "HDMI1", this);
var hdmiIn2 = new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, "HDMI2", this);
var hdmiIn3 = new RoutingInputPort(RoutingPortNames.HdmiIn3, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, "HDMI3", this);
var hdmiIn4 = new RoutingInputPort(RoutingPortNames.HdmiIn4, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, "HDMI4", this);
var dpIn = new RoutingInputPort(RoutingPortNames.DisplayPortIn, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.DisplayPort, "DP", this);
InputPorts.AddRange(new[] { hdmiIn1, hdmiIn2, hdmiIn3, hdmiIn4, dpIn });
VolumeLevelFeedback = new IntFeedback("volume", () => { return _FakeVolumeLevel; });
MuteFeedback = new BoolFeedback("muteOn", () => _IsMuted);
WarmupTime = 10000;
CooldownTime = 10000;
}
/// <summary>
/// PowerOn method
/// </summary>
/// <inheritdoc />
public override void PowerOn()
{
if (!PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown)
{
_IsWarmingUp = true;
IsWarmingUpFeedback.InvokeFireUpdate();
// Fake power-up cycle
WarmupTimer = new CTimer(o =>
{
_IsWarmingUp = false;
_PowerIsOn = true;
IsWarmingUpFeedback.InvokeFireUpdate();
PowerIsOnFeedback.InvokeFireUpdate();
}, WarmupTime);
}
}
/// <summary>
/// PowerOff method
/// </summary>
/// <inheritdoc />
public override void PowerOff()
{
// If a display has unreliable-power off feedback, just override this and
// remove this check.
if (PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown)
{
_IsCoolingDown = true;
IsCoolingDownFeedback.InvokeFireUpdate();
// Fake cool-down cycle
CooldownTimer = new CTimer(o =>
{
Debug.LogMessage(LogEventLevel.Verbose, "Cooldown timer ending", this);
_IsCoolingDown = false;
IsCoolingDownFeedback.InvokeFireUpdate();
_PowerIsOn = false;
PowerIsOnFeedback.InvokeFireUpdate();
}, CooldownTime);
}
}
/// <summary>
/// PowerToggle method
/// </summary>
/// <inheritdoc />
public override void PowerToggle()
{
if (PowerIsOnFeedback.BoolValue && !IsWarmingUpFeedback.BoolValue)
PowerOff();
else if (!PowerIsOnFeedback.BoolValue && !IsCoolingDownFeedback.BoolValue)
PowerOn();
}
/// <summary>
/// ExecuteSwitch method
/// </summary>
/// <inheritdoc />
public override void ExecuteSwitch(object selector)
{
try
{
Debug.LogMessage(LogEventLevel.Verbose, "ExecuteSwitch: {0}", this, selector);
if (!_PowerIsOn)
{
PowerOn();
}
if (!Inputs.Items.TryGetValue(selector.ToString(), out var input))
return;
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, ex);
}
}
/// <summary>
/// SetInput method
/// </summary>
public void SetInput(string selector)
{
ISelectableItem currentInput = null;
try
{
currentInput = Inputs.Items.SingleOrDefault(Inputs => Inputs.Value.IsSelected).Value;
}
catch { }
var hdmiIn2 = new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, "HDMI2", this);
var hdmiIn3 = new RoutingInputPort(RoutingPortNames.HdmiIn3, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, "HDMI3", this);
var hdmiIn4 = new RoutingInputPort(RoutingPortNames.HdmiIn4, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, "HDMI4", this);
var dpIn = new RoutingInputPort(RoutingPortNames.DisplayPortIn, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.DisplayPort, "DP", this);
InputPorts.AddRange(new[] { hdmiIn1, hdmiIn2, hdmiIn3, hdmiIn4, dpIn });
if (currentInput != null)
{
Debug.LogMessage(LogEventLevel.Verbose, this, "SetInput: {0}", selector);
currentInput.IsSelected = false;
}
VolumeLevelFeedback = new IntFeedback("volume", () => { return _FakeVolumeLevel; });
MuteFeedback = new BoolFeedback("muteOn", () => _IsMuted);
if (!Inputs.Items.TryGetValue(selector, out var input))
return;
input.IsSelected = true;
Inputs.CurrentItem = selector;
}
#region IBasicVolumeWithFeedback Members
/// <summary>
/// Gets or sets the VolumeLevelFeedback
/// </summary>
public IntFeedback VolumeLevelFeedback { get; private set; }
/// <summary>
/// SetVolume method
/// </summary>
public void SetVolume(ushort level)
{
_FakeVolumeLevel = level;
VolumeLevelFeedback.InvokeFireUpdate();
}
/// <summary>
/// MuteOn method
/// </summary>
public void MuteOn()
{
_IsMuted = true;
MuteFeedback.InvokeFireUpdate();
}
/// <summary>
/// MuteOff method
/// </summary>
public void MuteOff()
{
_IsMuted = false;
MuteFeedback.InvokeFireUpdate();
}
/// <summary>
/// Gets or sets the MuteFeedback
/// </summary>
public BoolFeedback MuteFeedback { get; private set; }
#endregion
#region IBasicVolumeControls Members
/// <summary>
/// VolumeUp method
/// </summary>
public void VolumeUp(bool pressRelease)
{
//while (pressRelease)
//{
Debug.LogMessage(LogEventLevel.Verbose, this, "Volume Down {0}", pressRelease);
if (pressRelease)
{
var newLevel = _FakeVolumeLevel + VolumeInterval;
SetVolume((ushort)newLevel);
CrestronEnvironment.Sleep(VolumeHeldRepeatInterval);
}
//}
}
/// <summary>
/// VolumeDown method
/// </summary>
public void VolumeDown(bool pressRelease)
{
//while (pressRelease)
//{
Debug.LogMessage(LogEventLevel.Verbose, this, "Volume Up {0}", pressRelease);
if (pressRelease)
{
var newLevel = _FakeVolumeLevel - VolumeInterval;
SetVolume((ushort)newLevel);
CrestronEnvironment.Sleep(VolumeHeldRepeatInterval);
}
//}
}
/// <summary>
/// MuteToggle method
/// </summary>
public void MuteToggle()
{
_IsMuted = !_IsMuted;
MuteFeedback.InvokeFireUpdate();
}
#endregion
/// <summary>
/// LinkToApi method
/// </summary>
public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge)
{
LinkDisplayToApi(this, trilist, joinStart, joinMapKey, bridge);
}
WarmupTime = 10000;
CooldownTime = 10000;
}
/// <summary>
/// Represents a MockDisplayFactory
/// PowerOn method
/// </summary>
public class MockDisplayFactory : EssentialsDeviceFactory<MockDisplay>
/// <inheritdoc />
public override void PowerOn()
{
/// <summary>
/// Initializes a new instance of the MockDisplayFactory class
/// </summary>
public MockDisplayFactory()
if (!PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown)
{
TypeNames = new List<string>() { "mockdisplay", "mockdisplay2" };
}
/// <summary>
/// BuildDevice method
/// </summary>
/// <inheritdoc />
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);
_IsWarmingUp = true;
IsWarmingUpFeedback.InvokeFireUpdate();
// Fake power-up cycle
WarmupTimer = new CTimer(o =>
{
_IsWarmingUp = false;
_PowerIsOn = true;
IsWarmingUpFeedback.InvokeFireUpdate();
PowerIsOnFeedback.InvokeFireUpdate();
}, WarmupTime);
}
}
}
public override void PowerOff()
{
// If a display has unreliable-power off feedback, just override this and
// remove this check.
if (PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown)
{
_IsCoolingDown = true;
IsCoolingDownFeedback.InvokeFireUpdate();
// Fake cool-down cycle
CooldownTimer = new CTimer(o =>
{
Debug.LogMessage(LogEventLevel.Verbose, "Cooldown timer ending", this);
_IsCoolingDown = false;
IsCoolingDownFeedback.InvokeFireUpdate();
_PowerIsOn = false;
PowerIsOnFeedback.InvokeFireUpdate();
}, CooldownTime);
}
}
public override void PowerToggle()
{
if (PowerIsOnFeedback.BoolValue && !IsWarmingUpFeedback.BoolValue)
PowerOff();
else if (!PowerIsOnFeedback.BoolValue && !IsCoolingDownFeedback.BoolValue)
PowerOn();
}
public override void ExecuteSwitch(object selector)
{
try
{
Debug.LogMessage(LogEventLevel.Verbose, "ExecuteSwitch: {0}", this, selector);
if (!_PowerIsOn)
{
PowerOn();
}
if (!Inputs.Items.TryGetValue(selector.ToString(), out var input))
return;
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, ex);
}
}
public void SetInput(string selector)
{
ISelectableItem currentInput = null;
if (currentInput != null)
{
Debug.LogMessage(LogEventLevel.Verbose, this, "SetInput: {0}", selector);
currentInput.IsSelected = false;
}
if (!Inputs.Items.TryGetValue(selector, out var input))
return;
input.IsSelected = true;
Inputs.CurrentItem = selector;
}
#region IBasicVolumeWithFeedback Members
public IntFeedback VolumeLevelFeedback { get; private set; }
/// <summary>
/// SetVolume method
/// </summary>
public void SetVolume(ushort level)
{
_FakeVolumeLevel = level;
VolumeLevelFeedback.InvokeFireUpdate();
}
/// <summary>
/// MuteOn method
/// </summary>
public void MuteOn()
{
_IsMuted = true;
MuteFeedback.InvokeFireUpdate();
}
/// <summary>
/// MuteOff method
/// </summary>
public void MuteOff()
{
_IsMuted = false;
MuteFeedback.InvokeFireUpdate();
}
/// <summary>
/// Gets or sets the MuteFeedback
/// </summary>
public BoolFeedback MuteFeedback { get; private set; }
#endregion
#region IBasicVolumeControls Members
public void VolumeUp(bool pressRelease)
{
//while (pressRelease)
//{
Debug.LogMessage(LogEventLevel.Verbose, this, "Volume Down {0}", pressRelease);
if (pressRelease)
{
var newLevel = _FakeVolumeLevel + VolumeInterval;
SetVolume((ushort)newLevel);
CrestronEnvironment.Sleep(VolumeHeldRepeatInterval);
}
//}
}
public void VolumeDown(bool pressRelease)
{
//while (pressRelease)
//{
Debug.LogMessage(LogEventLevel.Verbose, this, "Volume Up {0}", pressRelease);
if (pressRelease)
{
var newLevel = _FakeVolumeLevel - VolumeInterval;
SetVolume((ushort)newLevel);
CrestronEnvironment.Sleep(VolumeHeldRepeatInterval);
}
//}
}
/// <summary>
/// MuteToggle method
/// </summary>
public void MuteToggle()
{
_IsMuted = !_IsMuted;
MuteFeedback.InvokeFireUpdate();
}
#endregion
public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge)
{
LinkDisplayToApi(this, trilist, joinStart, joinMapKey, bridge);
}
}
/// <summary>
/// Represents a MockDisplayFactory
/// </summary>
public class MockDisplayFactory : EssentialsDeviceFactory<MockDisplay>
{
/// <summary>
/// Initializes a new instance of the MockDisplayFactory class
/// </summary>
public MockDisplayFactory()
{
TypeNames = new List<string>() { "mockdisplay", "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);
}
}

View file

@ -2,135 +2,95 @@
using System.Collections.Generic;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
namespace PepperDash.Essentials.Devices.Common.Displays
namespace PepperDash.Essentials.Devices.Common.Displays;
public class MockDisplayInputs : ISelectableItems<string>
{
/// <summary>
/// Represents a MockDisplayInputs
/// </summary>
public class MockDisplayInputs : ISelectableItems<string>
private Dictionary<string, ISelectableItem> _items;
public Dictionary<string, ISelectableItem> Items
{
private Dictionary<string, ISelectableItem> _items;
/// <summary>
/// Gets or sets the collection of selectable items
/// </summary>
public Dictionary<string, ISelectableItem> Items
get
{
get
{
return _items;
}
set
{
if (_items == value)
return;
_items = value;
ItemsUpdated?.Invoke(this, null);
}
return _items;
}
private string _currentItem;
/// <summary>
/// Gets or sets the currently selected item
/// </summary>
public string CurrentItem
set
{
get
{
return _currentItem;
}
set
{
if (_currentItem == value)
return;
if (_items == value)
return;
_currentItem = value;
_items = value;
CurrentItemChanged?.Invoke(this, null);
}
ItemsUpdated?.Invoke(this, null);
}
/// <summary>
/// Occurs when the items collection is updated
/// </summary>
public event EventHandler ItemsUpdated;
/// <summary>
/// Occurs when the current item changes
/// </summary>
public event EventHandler CurrentItemChanged;
}
/// <summary>
/// Represents a MockDisplayInput
/// </summary>
public class MockDisplayInput : ISelectableItem
private string _currentItem;
public string CurrentItem
{
get
{
return _currentItem;
}
set
{
if (_currentItem == value)
return;
_currentItem = value;
CurrentItemChanged?.Invoke(this, null);
}
}
public event EventHandler ItemsUpdated;
public event EventHandler CurrentItemChanged;
}
public class MockDisplayInput : ISelectableItem
{
private MockDisplay _parent;
private bool _isSelected;
public bool IsSelected
{
private MockDisplay _parent;
private bool _isSelected;
/// <summary>
/// Gets or sets a value indicating whether this input is selected
/// </summary>
public bool IsSelected
get
{
get
{
return _isSelected;
}
set
{
if (_isSelected == value)
return;
_isSelected = value;
ItemUpdated?.Invoke(this, null);
}
return _isSelected;
}
/// <summary>
/// Gets or sets the Name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the Key
/// </summary>
public string Key { get; set; }
/// <summary>
/// Occurs when this item is updated
/// </summary>
public event EventHandler ItemUpdated;
/// <summary>
/// Initializes a new instance of the MockDisplayInput class
/// </summary>
/// <param name="key">The input key</param>
/// <param name="name">The input name</param>
/// <param name="parent">The parent mock display</param>
public MockDisplayInput(string key, string name, MockDisplay parent)
set
{
Key = key;
Name = name;
_parent = parent;
if (_isSelected == value)
return;
_isSelected = value;
ItemUpdated?.Invoke(this, null);
}
}
/// <summary>
/// Select method
/// </summary>
public void Select()
public string Name { get; set; }
public string Key { get; set; }
public event EventHandler ItemUpdated;
public MockDisplayInput(string key, string name, MockDisplay parent)
{
Key = key;
Name = name;
_parent = parent;
}
public void Select()
{
if (!_parent.PowerIsOnFeedback.BoolValue) _parent.PowerOn();
foreach(var input in _parent.Inputs.Items)
{
if (!_parent.PowerIsOnFeedback.BoolValue) _parent.PowerOn();
foreach (var input in _parent.Inputs.Items)
{
input.Value.IsSelected = input.Key == this.Key;
}
input.Value.IsSelected = input.Key == this.Key;
}
}
}

View file

@ -434,7 +434,7 @@ namespace PepperDash.Essentials.Devices.Common.Shades
/// <summary>
/// Factory for ScreenLiftController devices
/// </summary>
public class ScreenLiftControllerFactory : EssentialsDeviceFactory<RelayControlledShade>
public class ScreenLiftControllerFactory : EssentialsDeviceFactory<ScreenLiftController>
{
/// <summary>
/// Constructor for ScreenLiftControllerFactory
@ -453,4 +453,4 @@ namespace PepperDash.Essentials.Devices.Common.Shades
return new ScreenLiftController(dc.Key, dc.Name, props);
}
}
}
}